summaryrefslogtreecommitdiff
path: root/ssh-sk.c
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2019-12-30 09:21:16 +0000
committerDamien Miller <djm@mindrot.org>2019-12-30 20:58:19 +1100
commit14cea36df397677b8f8568204300ef654114fd76 (patch)
tree4c9b0bf5108df396f8d9eaff576537e7c9cc50e9 /ssh-sk.c
parent2fe05fcb4a2695f190b4fcf27770b655586ab349 (diff)
upstream: resident keys support in SK API
Adds a sk_load_resident_keys() function to the security key API that accepts a security key provider and a PIN and returns a list of keys. Implement support for this in the usbhid middleware. feedback and ok markus@ OpenBSD-Commit-ID: 67e984e4e87f4999ce447a6178c4249a9174eff0
Diffstat (limited to 'ssh-sk.c')
-rw-r--r--ssh-sk.c116
1 files changed, 112 insertions, 4 deletions
diff --git a/ssh-sk.c b/ssh-sk.c
index 01927669e..d48f34e30 100644
--- a/ssh-sk.c
+++ b/ssh-sk.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-sk.c,v 1.19 2019/12/30 09:20:36 djm Exp $ */ 1/* $OpenBSD: ssh-sk.c,v 1.20 2019/12/30 09:21:16 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2019 Google LLC 3 * Copyright (c) 2019 Google LLC
4 * 4 *
@@ -60,6 +60,10 @@ struct sshsk_provider {
60 const char *application, 60 const char *application,
61 const uint8_t *key_handle, size_t key_handle_len, 61 const uint8_t *key_handle, size_t key_handle_len,
62 uint8_t flags, struct sk_sign_response **sign_response); 62 uint8_t flags, struct sk_sign_response **sign_response);
63
64 /* Enumerate resident keys */
65 int (*sk_load_resident_keys)(const char *pin,
66 struct sk_resident_key ***rks, size_t *nrks);
63}; 67};
64 68
65/* Built-in version */ 69/* Built-in version */
@@ -70,6 +74,8 @@ int ssh_sk_sign(int alg, const uint8_t *message, size_t message_len,
70 const char *application, 74 const char *application,
71 const uint8_t *key_handle, size_t key_handle_len, 75 const uint8_t *key_handle, size_t key_handle_len,
72 uint8_t flags, struct sk_sign_response **sign_response); 76 uint8_t flags, struct sk_sign_response **sign_response);
77int ssh_sk_load_resident_keys(const char *pin,
78 struct sk_resident_key ***rks, size_t *nrks);
73 79
74static void 80static void
75sshsk_free(struct sshsk_provider *p) 81sshsk_free(struct sshsk_provider *p)
@@ -101,6 +107,7 @@ sshsk_open(const char *path)
101#ifdef ENABLE_SK_INTERNAL 107#ifdef ENABLE_SK_INTERNAL
102 ret->sk_enroll = ssh_sk_enroll; 108 ret->sk_enroll = ssh_sk_enroll;
103 ret->sk_sign = ssh_sk_sign; 109 ret->sk_sign = ssh_sk_sign;
110 ret->sk_load_resident_keys = ssh_sk_load_resident_keys;
104#else 111#else
105 error("internal security key support not enabled"); 112 error("internal security key support not enabled");
106#endif 113#endif
@@ -136,6 +143,12 @@ sshsk_open(const char *path)
136 path, dlerror()); 143 path, dlerror());
137 goto fail; 144 goto fail;
138 } 145 }
146 if ((ret->sk_load_resident_keys = dlsym(ret->dlhandle,
147 "sk_load_resident_keys")) == NULL) {
148 error("Security key provider %s dlsym(sk_load_resident_keys) "
149 "failed: %s", path, dlerror());
150 goto fail;
151 }
139 /* success */ 152 /* success */
140 return ret; 153 return ret;
141fail: 154fail:
@@ -264,9 +277,7 @@ sshsk_key_from_response(int alg, const char *application, uint8_t flags,
264 *keyp = NULL; 277 *keyp = NULL;
265 278
266 /* Check response validity */ 279 /* Check response validity */
267 if (resp->public_key == NULL || resp->key_handle == NULL || 280 if (resp->public_key == NULL || resp->key_handle == NULL) {
268 resp->signature == NULL ||
269 (resp->attestation_cert == NULL && resp->attestation_cert_len != 0)) {
270 error("%s: sk_enroll response invalid", __func__); 281 error("%s: sk_enroll response invalid", __func__);
271 r = SSH_ERR_INVALID_FORMAT; 282 r = SSH_ERR_INVALID_FORMAT;
272 goto out; 283 goto out;
@@ -595,4 +606,101 @@ sshsk_sign(const char *provider_path, struct sshkey *key,
595 sshbuf_free(inner_sig); 606 sshbuf_free(inner_sig);
596 return r; 607 return r;
597} 608}
609
610static void
611sshsk_free_sk_resident_keys(struct sk_resident_key **rks, size_t nrks)
612{
613 size_t i;
614
615 if (nrks == 0 || rks == NULL)
616 return;
617 for (i = 0; i < nrks; i++) {
618 free(rks[i]->application);
619 freezero(rks[i]->key.key_handle, rks[i]->key.key_handle_len);
620 freezero(rks[i]->key.public_key, rks[i]->key.public_key_len);
621 freezero(rks[i]->key.signature, rks[i]->key.signature_len);
622 freezero(rks[i]->key.attestation_cert,
623 rks[i]->key.attestation_cert_len);
624 freezero(rks[i], sizeof(**rks));
625 }
626 free(rks);
627}
628
629int
630sshsk_load_resident(const char *provider_path, const char *pin,
631 struct sshkey ***keysp, size_t *nkeysp)
632{
633 struct sshsk_provider *skp = NULL;
634 int r = SSH_ERR_INTERNAL_ERROR;
635 struct sk_resident_key **rks = NULL;
636 size_t i, nrks = 0, nkeys = 0;
637 struct sshkey *key = NULL, **keys = NULL, **tmp;
638 uint8_t flags;
639
640 debug("%s: provider \"%s\"%s", __func__, provider_path,
641 (pin != NULL && *pin != '\0') ? ", have-pin": "");
642
643 if (keysp == NULL || nkeysp == NULL)
644 return SSH_ERR_INVALID_ARGUMENT;
645 *keysp = NULL;
646 *nkeysp = 0;
647
648 if ((skp = sshsk_open(provider_path)) == NULL) {
649 r = SSH_ERR_INVALID_FORMAT; /* XXX sshsk_open return code? */
650 goto out;
651 }
652 if ((r = skp->sk_load_resident_keys(pin, &rks, &nrks)) != 0) {
653 error("Security key provider %s returned failure %d",
654 provider_path, r);
655 r = SSH_ERR_INVALID_FORMAT; /* XXX error codes in API? */
656 goto out;
657 }
658 for (i = 0; i < nrks; i++) {
659 debug3("%s: rk %zu: slot = %zu, alg = %d, application = \"%s\"",
660 __func__, i, rks[i]->slot, rks[i]->alg,
661 rks[i]->application);
662 /* XXX need better filter here */
663 if (strncmp(rks[i]->application, "ssh:", 4) != 0)
664 continue;
665 switch (rks[i]->alg) {
666 case SSH_SK_ECDSA:
667 case SSH_SK_ED25519:
668 break;
669 default:
670 continue;
671 }
672 /* XXX where to get flags? */
673 flags = SSH_SK_USER_PRESENCE_REQD|SSH_SK_RESIDENT_KEY;
674 if ((r = sshsk_key_from_response(rks[i]->alg,
675 rks[i]->application, flags, &rks[i]->key, &key)) != 0)
676 goto out;
677 if ((tmp = recallocarray(keys, nkeys, nkeys + 1,
678 sizeof(*tmp))) == NULL) {
679 error("%s: recallocarray failed", __func__);
680 r = SSH_ERR_ALLOC_FAIL;
681 goto out;
682 }
683 keys = tmp;
684 keys[nkeys++] = key;
685 key = NULL;
686 /* XXX synthesise comment */
687 }
688 /* success */
689 *keysp = keys;
690 *nkeysp = nkeys;
691 keys = NULL;
692 nkeys = 0;
693 r = 0;
694 out:
695 sshsk_free(skp);
696 sshsk_free_sk_resident_keys(rks, nrks);
697 sshkey_free(key);
698 if (nkeys != 0) {
699 for (i = 0; i < nkeys; i++)
700 sshkey_free(keys[i]);
701 free(keys);
702 }
703 return r;
704}
705
598#endif /* ENABLE_SK */ 706#endif /* ENABLE_SK */