Annotation of src/usr.bin/ssh/ssh-sk.c, Revision 1.20
1.20 ! djm 1: /* $OpenBSD: ssh-sk.c,v 1.19 2019/12/30 09:20:36 djm Exp $ */
1.1 djm 2: /*
3: * Copyright (c) 2019 Google LLC
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16: */
17:
18: /* #define DEBUG_SK 1 */
19:
20: #include <dlfcn.h>
21: #include <stddef.h>
22: #include <stdint.h>
23: #include <string.h>
24: #include <stdio.h>
25:
1.15 naddy 26: #ifdef WITH_OPENSSL
1.1 djm 27: #include <openssl/objects.h>
28: #include <openssl/ec.h>
1.15 naddy 29: #endif /* WITH_OPENSSL */
1.1 djm 30:
31: #include "log.h"
32: #include "misc.h"
33: #include "sshbuf.h"
34: #include "sshkey.h"
35: #include "ssherr.h"
36: #include "digest.h"
37:
38: #include "ssh-sk.h"
39: #include "sk-api.h"
1.6 markus 40: #include "crypto_api.h"
1.1 djm 41:
42: struct sshsk_provider {
43: char *path;
44: void *dlhandle;
45:
46: /* Return the version of the middleware API */
47: uint32_t (*sk_api_version)(void);
48:
49: /* Enroll a U2F key (private key generation) */
1.7 markus 50: int (*sk_enroll)(int alg, const uint8_t *challenge,
51: size_t challenge_len, const char *application, uint8_t flags,
1.1 djm 52: struct sk_enroll_response **enroll_response);
53:
54: /* Sign a challenge */
1.7 markus 55: int (*sk_sign)(int alg, const uint8_t *message, size_t message_len,
1.1 djm 56: const char *application,
57: const uint8_t *key_handle, size_t key_handle_len,
58: uint8_t flags, struct sk_sign_response **sign_response);
1.20 ! djm 59:
! 60: /* Enumerate resident keys */
! 61: int (*sk_load_resident_keys)(const char *pin,
! 62: struct sk_resident_key ***rks, size_t *nrks);
1.1 djm 63: };
64:
1.12 djm 65: /* Built-in version */
66: int ssh_sk_enroll(int alg, const uint8_t *challenge,
67: size_t challenge_len, const char *application, uint8_t flags,
68: struct sk_enroll_response **enroll_response);
69: int ssh_sk_sign(int alg, const uint8_t *message, size_t message_len,
70: const char *application,
71: const uint8_t *key_handle, size_t key_handle_len,
72: uint8_t flags, struct sk_sign_response **sign_response);
1.20 ! djm 73: int ssh_sk_load_resident_keys(const char *pin,
! 74: struct sk_resident_key ***rks, size_t *nrks);
1.12 djm 75:
1.1 djm 76: static void
77: sshsk_free(struct sshsk_provider *p)
78: {
79: if (p == NULL)
80: return;
81: free(p->path);
82: if (p->dlhandle != NULL)
83: dlclose(p->dlhandle);
84: free(p);
85: }
86:
87: static struct sshsk_provider *
88: sshsk_open(const char *path)
89: {
90: struct sshsk_provider *ret = NULL;
91: uint32_t version;
92:
93: if ((ret = calloc(1, sizeof(*ret))) == NULL) {
94: error("%s: calloc failed", __func__);
95: return NULL;
96: }
97: if ((ret->path = strdup(path)) == NULL) {
98: error("%s: strdup failed", __func__);
99: goto fail;
1.12 djm 100: }
101: /* Skip the rest if we're using the linked in middleware */
102: if (strcasecmp(ret->path, "internal") == 0) {
103: ret->sk_enroll = ssh_sk_enroll;
104: ret->sk_sign = ssh_sk_sign;
1.20 ! djm 105: ret->sk_load_resident_keys = ssh_sk_load_resident_keys;
1.12 djm 106: return ret;
1.1 djm 107: }
108: if ((ret->dlhandle = dlopen(path, RTLD_NOW)) == NULL) {
109: error("Security key provider %s dlopen failed: %s",
110: path, dlerror());
111: goto fail;
112: }
113: if ((ret->sk_api_version = dlsym(ret->dlhandle,
114: "sk_api_version")) == NULL) {
115: error("Security key provider %s dlsym(sk_api_version) "
116: "failed: %s", path, dlerror());
117: goto fail;
118: }
119: version = ret->sk_api_version();
120: debug("%s: provider %s implements version 0x%08lx", __func__,
121: ret->path, (u_long)version);
122: if ((version & SSH_SK_VERSION_MAJOR_MASK) != SSH_SK_VERSION_MAJOR) {
123: error("Security key provider %s implements unsupported version "
124: "0x%08lx (supported: 0x%08lx)", path, (u_long)version,
125: (u_long)SSH_SK_VERSION_MAJOR);
126: goto fail;
127: }
128: if ((ret->sk_enroll = dlsym(ret->dlhandle, "sk_enroll")) == NULL) {
129: error("Security key provider %s dlsym(sk_enroll) "
130: "failed: %s", path, dlerror());
131: goto fail;
132: }
133: if ((ret->sk_sign = dlsym(ret->dlhandle, "sk_sign")) == NULL) {
134: error("Security key provider %s dlsym(sk_sign) failed: %s",
135: path, dlerror());
136: goto fail;
137: }
1.20 ! djm 138: if ((ret->sk_load_resident_keys = dlsym(ret->dlhandle,
! 139: "sk_load_resident_keys")) == NULL) {
! 140: error("Security key provider %s dlsym(sk_load_resident_keys) "
! 141: "failed: %s", path, dlerror());
! 142: goto fail;
! 143: }
1.1 djm 144: /* success */
145: return ret;
146: fail:
147: sshsk_free(ret);
148: return NULL;
149: }
150:
151: static void
152: sshsk_free_enroll_response(struct sk_enroll_response *r)
153: {
154: if (r == NULL)
155: return;
156: freezero(r->key_handle, r->key_handle_len);
157: freezero(r->public_key, r->public_key_len);
158: freezero(r->signature, r->signature_len);
159: freezero(r->attestation_cert, r->attestation_cert_len);
160: freezero(r, sizeof(*r));
1.17 djm 161: }
1.1 djm 162:
163: static void
164: sshsk_free_sign_response(struct sk_sign_response *r)
165: {
166: if (r == NULL)
167: return;
168: freezero(r->sig_r, r->sig_r_len);
169: freezero(r->sig_s, r->sig_s_len);
170: freezero(r, sizeof(*r));
1.17 djm 171: }
1.1 djm 172:
1.15 naddy 173: #ifdef WITH_OPENSSL
1.2 markus 174: /* Assemble key from response */
175: static int
176: sshsk_ecdsa_assemble(struct sk_enroll_response *resp, struct sshkey **keyp)
177: {
178: struct sshkey *key = NULL;
179: struct sshbuf *b = NULL;
180: EC_POINT *q = NULL;
181: int r;
182:
183: *keyp = NULL;
184: if ((key = sshkey_new(KEY_ECDSA_SK)) == NULL) {
185: error("%s: sshkey_new failed", __func__);
186: r = SSH_ERR_ALLOC_FAIL;
187: goto out;
188: }
189: key->ecdsa_nid = NID_X9_62_prime256v1;
190: if ((key->ecdsa = EC_KEY_new_by_curve_name(key->ecdsa_nid)) == NULL ||
191: (q = EC_POINT_new(EC_KEY_get0_group(key->ecdsa))) == NULL ||
192: (b = sshbuf_new()) == NULL) {
193: error("%s: allocation failed", __func__);
194: r = SSH_ERR_ALLOC_FAIL;
195: goto out;
196: }
197: if ((r = sshbuf_put_string(b,
198: resp->public_key, resp->public_key_len)) != 0) {
199: error("%s: buffer error: %s", __func__, ssh_err(r));
200: goto out;
201: }
202: if ((r = sshbuf_get_ec(b, q, EC_KEY_get0_group(key->ecdsa))) != 0) {
203: error("%s: parse key: %s", __func__, ssh_err(r));
204: r = SSH_ERR_INVALID_FORMAT;
205: goto out;
206: }
207: if (sshkey_ec_validate_public(EC_KEY_get0_group(key->ecdsa), q) != 0) {
208: error("Security key returned invalid ECDSA key");
209: r = SSH_ERR_KEY_INVALID_EC_VALUE;
210: goto out;
211: }
212: if (EC_KEY_set_public_key(key->ecdsa, q) != 1) {
213: /* XXX assume it is a allocation error */
214: error("%s: allocation failed", __func__);
215: r = SSH_ERR_ALLOC_FAIL;
216: goto out;
217: }
218: /* success */
219: *keyp = key;
220: key = NULL; /* transferred */
221: r = 0;
222: out:
223: EC_POINT_free(q);
224: sshkey_free(key);
225: sshbuf_free(b);
226: return r;
227: }
1.15 naddy 228: #endif /* WITH_OPENSSL */
1.2 markus 229:
1.6 markus 230: static int
231: sshsk_ed25519_assemble(struct sk_enroll_response *resp, struct sshkey **keyp)
232: {
233: struct sshkey *key = NULL;
234: int r;
235:
236: *keyp = NULL;
237: if (resp->public_key_len != ED25519_PK_SZ) {
238: error("%s: invalid size: %zu", __func__, resp->public_key_len);
239: r = SSH_ERR_INVALID_FORMAT;
240: goto out;
241: }
242: if ((key = sshkey_new(KEY_ED25519_SK)) == NULL) {
243: error("%s: sshkey_new failed", __func__);
244: r = SSH_ERR_ALLOC_FAIL;
245: goto out;
246: }
247: if ((key->ed25519_pk = malloc(ED25519_PK_SZ)) == NULL) {
248: error("%s: malloc failed", __func__);
249: r = SSH_ERR_ALLOC_FAIL;
250: goto out;
251: }
252: memcpy(key->ed25519_pk, resp->public_key, ED25519_PK_SZ);
253: /* success */
254: *keyp = key;
255: key = NULL; /* transferred */
256: r = 0;
257: out:
258: sshkey_free(key);
259: return r;
260: }
261:
1.19 djm 262: static int
263: sshsk_key_from_response(int alg, const char *application, uint8_t flags,
264: struct sk_enroll_response *resp, struct sshkey **keyp)
265: {
266: struct sshkey *key = NULL;
267: int r = SSH_ERR_INTERNAL_ERROR;
268:
269: *keyp = NULL;
270:
271: /* Check response validity */
1.20 ! djm 272: if (resp->public_key == NULL || resp->key_handle == NULL) {
1.19 djm 273: error("%s: sk_enroll response invalid", __func__);
274: r = SSH_ERR_INVALID_FORMAT;
275: goto out;
276: }
277: switch (alg) {
278: #ifdef WITH_OPENSSL
279: case SSH_SK_ECDSA:
280: if ((r = sshsk_ecdsa_assemble(resp, &key)) != 0)
281: goto out;
282: break;
283: #endif /* WITH_OPENSSL */
284: case SSH_SK_ED25519:
285: if ((r = sshsk_ed25519_assemble(resp, &key)) != 0)
286: goto out;
287: break;
288: default:
289: error("%s: unsupported algorithm %d", __func__, alg);
290: r = SSH_ERR_INVALID_ARGUMENT;
291: goto out;
292: }
293: key->sk_flags = flags;
294: if ((key->sk_key_handle = sshbuf_new()) == NULL ||
295: (key->sk_reserved = sshbuf_new()) == NULL) {
296: error("%s: allocation failed", __func__);
297: r = SSH_ERR_ALLOC_FAIL;
298: goto out;
299: }
300: if ((key->sk_application = strdup(application)) == NULL) {
301: error("%s: strdup application failed", __func__);
302: r = SSH_ERR_ALLOC_FAIL;
303: goto out;
304: }
305: if ((r = sshbuf_put(key->sk_key_handle, resp->key_handle,
306: resp->key_handle_len)) != 0) {
307: error("%s: buffer error: %s", __func__, ssh_err(r));
308: goto out;
309: }
310: /* success */
311: r = 0;
312: *keyp = key;
313: key = NULL;
314: out:
315: sshkey_free(key);
316: return r;
317: }
318:
1.1 djm 319: int
1.6 markus 320: sshsk_enroll(int type, const char *provider_path, const char *application,
1.1 djm 321: uint8_t flags, struct sshbuf *challenge_buf, struct sshkey **keyp,
322: struct sshbuf *attest)
323: {
324: struct sshsk_provider *skp = NULL;
325: struct sshkey *key = NULL;
326: u_char randchall[32];
327: const u_char *challenge;
328: size_t challenge_len;
329: struct sk_enroll_response *resp = NULL;
330: int r = SSH_ERR_INTERNAL_ERROR;
1.7 markus 331: int alg;
1.1 djm 332:
1.13 djm 333: debug("%s: provider \"%s\", application \"%s\", flags 0x%02x, "
334: "challenge len %zu", __func__, provider_path, application,
335: flags, challenge_buf == NULL ? 0 : sshbuf_len(challenge_buf));
336:
1.1 djm 337: *keyp = NULL;
338: if (attest)
339: sshbuf_reset(attest);
1.6 markus 340: switch (type) {
1.15 naddy 341: #ifdef WITH_OPENSSL
1.6 markus 342: case KEY_ECDSA_SK:
1.7 markus 343: alg = SSH_SK_ECDSA;
344: break;
1.15 naddy 345: #endif /* WITH_OPENSSL */
1.6 markus 346: case KEY_ED25519_SK:
1.7 markus 347: alg = SSH_SK_ED25519;
1.6 markus 348: break;
349: default:
350: error("%s: unsupported key type", __func__);
351: r = SSH_ERR_INVALID_ARGUMENT;
352: goto out;
353: }
1.1 djm 354: if (provider_path == NULL) {
355: error("%s: missing provider", __func__);
356: r = SSH_ERR_INVALID_ARGUMENT;
357: goto out;
358: }
359: if (application == NULL || *application == '\0') {
360: error("%s: missing application", __func__);
361: r = SSH_ERR_INVALID_ARGUMENT;
362: goto out;
363: }
364: if (challenge_buf == NULL) {
365: debug("%s: using random challenge", __func__);
366: arc4random_buf(randchall, sizeof(randchall));
367: challenge = randchall;
368: challenge_len = sizeof(randchall);
369: } else if (sshbuf_len(challenge_buf) == 0) {
370: error("Missing enrollment challenge");
371: r = SSH_ERR_INVALID_ARGUMENT;
372: goto out;
373: } else {
374: challenge = sshbuf_ptr(challenge_buf);
375: challenge_len = sshbuf_len(challenge_buf);
376: debug3("%s: using explicit challenge len=%zd",
377: __func__, challenge_len);
378: }
379: if ((skp = sshsk_open(provider_path)) == NULL) {
380: r = SSH_ERR_INVALID_FORMAT; /* XXX sshsk_open return code? */
381: goto out;
382: }
383: /* XXX validate flags? */
384: /* enroll key */
1.7 markus 385: if ((r = skp->sk_enroll(alg, challenge, challenge_len, application,
1.1 djm 386: flags, &resp)) != 0) {
387: error("Security key provider %s returned failure %d",
388: provider_path, r);
389: r = SSH_ERR_INVALID_FORMAT; /* XXX error codes in API? */
390: goto out;
391: }
1.19 djm 392:
393: if ((r = sshsk_key_from_response(alg, application, flags,
394: resp, &key)) != 0)
1.1 djm 395: goto out;
1.19 djm 396:
1.1 djm 397: /* Optionally fill in the attestation information */
398: if (attest != NULL) {
399: if ((r = sshbuf_put_cstring(attest, "sk-attest-v00")) != 0 ||
400: (r = sshbuf_put_u32(attest, 1)) != 0 || /* XXX U2F ver */
401: (r = sshbuf_put_string(attest,
402: resp->attestation_cert, resp->attestation_cert_len)) != 0 ||
403: (r = sshbuf_put_string(attest,
404: resp->signature, resp->signature_len)) != 0 ||
405: (r = sshbuf_put_u32(attest, flags)) != 0 || /* XXX right? */
406: (r = sshbuf_put_string(attest, NULL, 0)) != 0) {
407: error("%s: buffer error: %s", __func__, ssh_err(r));
408: goto out;
409: }
410: }
411: /* success */
412: *keyp = key;
413: key = NULL; /* transferred */
414: r = 0;
415: out:
416: sshsk_free(skp);
417: sshkey_free(key);
418: sshsk_free_enroll_response(resp);
419: explicit_bzero(randchall, sizeof(randchall));
420: return r;
421: }
422:
1.15 naddy 423: #ifdef WITH_OPENSSL
1.3 markus 424: static int
1.9 markus 425: sshsk_ecdsa_sig(struct sk_sign_response *resp, struct sshbuf *sig)
1.3 markus 426: {
427: struct sshbuf *inner_sig = NULL;
428: int r = SSH_ERR_INTERNAL_ERROR;
429:
1.8 markus 430: /* Check response validity */
1.11 markus 431: if (resp->sig_r == NULL || resp->sig_s == NULL) {
1.8 markus 432: error("%s: sk_sign response invalid", __func__);
433: r = SSH_ERR_INVALID_FORMAT;
434: goto out;
435: }
1.3 markus 436: if ((inner_sig = sshbuf_new()) == NULL) {
437: r = SSH_ERR_ALLOC_FAIL;
438: goto out;
439: }
1.9 markus 440: /* Prepare and append inner signature object */
1.3 markus 441: if ((r = sshbuf_put_bignum2_bytes(inner_sig,
442: resp->sig_r, resp->sig_r_len)) != 0 ||
443: (r = sshbuf_put_bignum2_bytes(inner_sig,
1.16 djm 444: resp->sig_s, resp->sig_s_len)) != 0) {
1.3 markus 445: debug("%s: buffer error: %s", __func__, ssh_err(r));
446: goto out;
447: }
1.16 djm 448: if ((r = sshbuf_put_stringb(sig, inner_sig)) != 0 ||
449: (r = sshbuf_put_u8(sig, resp->flags)) != 0 ||
450: (r = sshbuf_put_u32(sig, resp->counter)) != 0) {
1.9 markus 451: debug("%s: buffer error: %s", __func__, ssh_err(r));
452: goto out;
453: }
1.3 markus 454: #ifdef DEBUG_SK
455: fprintf(stderr, "%s: sig_r:\n", __func__);
456: sshbuf_dump_data(resp->sig_r, resp->sig_r_len, stderr);
457: fprintf(stderr, "%s: sig_s:\n", __func__);
458: sshbuf_dump_data(resp->sig_s, resp->sig_s_len, stderr);
1.9 markus 459: fprintf(stderr, "%s: inner:\n", __func__);
460: sshbuf_dump(inner_sig, stderr);
1.5 markus 461: #endif
462: r = 0;
1.9 markus 463: out:
1.5 markus 464: sshbuf_free(inner_sig);
465: return r;
466: }
1.15 naddy 467: #endif /* WITH_OPENSSL */
1.5 markus 468:
469: static int
1.9 markus 470: sshsk_ed25519_sig(struct sk_sign_response *resp, struct sshbuf *sig)
1.5 markus 471: {
472: int r = SSH_ERR_INTERNAL_ERROR;
473:
1.8 markus 474: /* Check response validity */
475: if (resp->sig_r == NULL) {
476: error("%s: sk_sign response invalid", __func__);
477: r = SSH_ERR_INVALID_FORMAT;
478: goto out;
479: }
1.9 markus 480: if ((r = sshbuf_put_string(sig,
1.5 markus 481: resp->sig_r, resp->sig_r_len)) != 0 ||
1.9 markus 482: (r = sshbuf_put_u8(sig, resp->flags)) != 0 ||
483: (r = sshbuf_put_u32(sig, resp->counter)) != 0) {
1.5 markus 484: debug("%s: buffer error: %s", __func__, ssh_err(r));
485: goto out;
486: }
487: #ifdef DEBUG_SK
488: fprintf(stderr, "%s: sig_r:\n", __func__);
489: sshbuf_dump_data(resp->sig_r, resp->sig_r_len, stderr);
1.3 markus 490: #endif
491: r = 0;
1.9 markus 492: out:
493: return 0;
1.3 markus 494: }
495:
1.1 djm 496: int
1.18 djm 497: sshsk_sign(const char *provider_path, struct sshkey *key,
1.1 djm 498: u_char **sigp, size_t *lenp, const u_char *data, size_t datalen,
499: u_int compat)
500: {
501: struct sshsk_provider *skp = NULL;
502: int r = SSH_ERR_INTERNAL_ERROR;
1.7 markus 503: int type, alg;
1.1 djm 504: struct sk_sign_response *resp = NULL;
505: struct sshbuf *inner_sig = NULL, *sig = NULL;
506: uint8_t message[32];
1.13 djm 507:
1.14 djm 508: debug("%s: provider \"%s\", key %s, flags 0x%02x", __func__,
1.13 djm 509: provider_path, sshkey_type(key), key->sk_flags);
1.1 djm 510:
511: if (sigp != NULL)
512: *sigp = NULL;
513: if (lenp != NULL)
514: *lenp = 0;
1.5 markus 515: type = sshkey_type_plain(key->type);
516: switch (type) {
1.15 naddy 517: #ifdef WITH_OPENSSL
1.5 markus 518: case KEY_ECDSA_SK:
1.7 markus 519: alg = SSH_SK_ECDSA;
520: break;
1.15 naddy 521: #endif /* WITH_OPENSSL */
1.5 markus 522: case KEY_ED25519_SK:
1.7 markus 523: alg = SSH_SK_ED25519;
1.5 markus 524: break;
525: default:
526: return SSH_ERR_INVALID_ARGUMENT;
527: }
1.1 djm 528: if (provider_path == NULL ||
529: key->sk_key_handle == NULL ||
530: key->sk_application == NULL || *key->sk_application == '\0') {
531: r = SSH_ERR_INVALID_ARGUMENT;
532: goto out;
533: }
534: if ((skp = sshsk_open(provider_path)) == NULL) {
535: r = SSH_ERR_INVALID_FORMAT; /* XXX sshsk_open return code? */
536: goto out;
537: }
538:
539: /* hash data to be signed before it goes to the security key */
540: if ((r = ssh_digest_memory(SSH_DIGEST_SHA256, data, datalen,
541: message, sizeof(message))) != 0) {
542: error("%s: hash application failed: %s", __func__, ssh_err(r));
543: r = SSH_ERR_INTERNAL_ERROR;
544: goto out;
545: }
1.7 markus 546: if ((r = skp->sk_sign(alg, message, sizeof(message),
1.1 djm 547: key->sk_application,
548: sshbuf_ptr(key->sk_key_handle), sshbuf_len(key->sk_key_handle),
549: key->sk_flags, &resp)) != 0) {
550: debug("%s: sk_sign failed with code %d", __func__, r);
551: goto out;
552: }
1.9 markus 553: /* Assemble signature */
554: if ((sig = sshbuf_new()) == NULL) {
555: r = SSH_ERR_ALLOC_FAIL;
556: goto out;
557: }
558: if ((r = sshbuf_put_cstring(sig, sshkey_ssh_name_plain(key))) != 0) {
559: debug("%s: buffer error (outer): %s", __func__, ssh_err(r));
560: goto out;
561: }
1.5 markus 562: switch (type) {
1.15 naddy 563: #ifdef WITH_OPENSSL
1.5 markus 564: case KEY_ECDSA_SK:
1.9 markus 565: if ((r = sshsk_ecdsa_sig(resp, sig)) != 0)
1.5 markus 566: goto out;
567: break;
1.15 naddy 568: #endif /* WITH_OPENSSL */
1.5 markus 569: case KEY_ED25519_SK:
1.9 markus 570: if ((r = sshsk_ed25519_sig(resp, sig)) != 0)
1.5 markus 571: goto out;
572: break;
573: }
1.1 djm 574: #ifdef DEBUG_SK
1.5 markus 575: fprintf(stderr, "%s: sig_flags = 0x%02x, sig_counter = %u\n",
576: __func__, resp->flags, resp->counter);
1.1 djm 577: fprintf(stderr, "%s: hashed message:\n", __func__);
578: sshbuf_dump_data(message, sizeof(message), stderr);
579: fprintf(stderr, "%s: sigbuf:\n", __func__);
580: sshbuf_dump(sig, stderr);
581: #endif
582: if (sigp != NULL) {
583: if ((*sigp = malloc(sshbuf_len(sig))) == NULL) {
584: r = SSH_ERR_ALLOC_FAIL;
585: goto out;
586: }
587: memcpy(*sigp, sshbuf_ptr(sig), sshbuf_len(sig));
588: }
589: if (lenp != NULL)
590: *lenp = sshbuf_len(sig);
591: /* success */
592: r = 0;
593: out:
594: explicit_bzero(message, sizeof(message));
595: sshsk_free(skp);
596: sshsk_free_sign_response(resp);
597: sshbuf_free(sig);
598: sshbuf_free(inner_sig);
599: return r;
600: }
1.20 ! djm 601:
! 602: static void
! 603: sshsk_free_sk_resident_keys(struct sk_resident_key **rks, size_t nrks)
! 604: {
! 605: size_t i;
! 606:
! 607: if (nrks == 0 || rks == NULL)
! 608: return;
! 609: for (i = 0; i < nrks; i++) {
! 610: free(rks[i]->application);
! 611: freezero(rks[i]->key.key_handle, rks[i]->key.key_handle_len);
! 612: freezero(rks[i]->key.public_key, rks[i]->key.public_key_len);
! 613: freezero(rks[i]->key.signature, rks[i]->key.signature_len);
! 614: freezero(rks[i]->key.attestation_cert,
! 615: rks[i]->key.attestation_cert_len);
! 616: freezero(rks[i], sizeof(**rks));
! 617: }
! 618: free(rks);
! 619: }
! 620:
! 621: int
! 622: sshsk_load_resident(const char *provider_path, const char *pin,
! 623: struct sshkey ***keysp, size_t *nkeysp)
! 624: {
! 625: struct sshsk_provider *skp = NULL;
! 626: int r = SSH_ERR_INTERNAL_ERROR;
! 627: struct sk_resident_key **rks = NULL;
! 628: size_t i, nrks = 0, nkeys = 0;
! 629: struct sshkey *key = NULL, **keys = NULL, **tmp;
! 630: uint8_t flags;
! 631:
! 632: debug("%s: provider \"%s\"%s", __func__, provider_path,
! 633: (pin != NULL && *pin != '\0') ? ", have-pin": "");
! 634:
! 635: if (keysp == NULL || nkeysp == NULL)
! 636: return SSH_ERR_INVALID_ARGUMENT;
! 637: *keysp = NULL;
! 638: *nkeysp = 0;
! 639:
! 640: if ((skp = sshsk_open(provider_path)) == NULL) {
! 641: r = SSH_ERR_INVALID_FORMAT; /* XXX sshsk_open return code? */
! 642: goto out;
! 643: }
! 644: if ((r = skp->sk_load_resident_keys(pin, &rks, &nrks)) != 0) {
! 645: error("Security key provider %s returned failure %d",
! 646: provider_path, r);
! 647: r = SSH_ERR_INVALID_FORMAT; /* XXX error codes in API? */
! 648: goto out;
! 649: }
! 650: for (i = 0; i < nrks; i++) {
! 651: debug3("%s: rk %zu: slot = %zu, alg = %d, application = \"%s\"",
! 652: __func__, i, rks[i]->slot, rks[i]->alg,
! 653: rks[i]->application);
! 654: /* XXX need better filter here */
! 655: if (strncmp(rks[i]->application, "ssh:", 4) != 0)
! 656: continue;
! 657: switch (rks[i]->alg) {
! 658: case SSH_SK_ECDSA:
! 659: case SSH_SK_ED25519:
! 660: break;
! 661: default:
! 662: continue;
! 663: }
! 664: /* XXX where to get flags? */
! 665: flags = SSH_SK_USER_PRESENCE_REQD|SSH_SK_RESIDENT_KEY;
! 666: if ((r = sshsk_key_from_response(rks[i]->alg,
! 667: rks[i]->application, flags, &rks[i]->key, &key)) != 0)
! 668: goto out;
! 669: if ((tmp = recallocarray(keys, nkeys, nkeys + 1,
! 670: sizeof(*tmp))) == NULL) {
! 671: error("%s: recallocarray failed", __func__);
! 672: r = SSH_ERR_ALLOC_FAIL;
! 673: goto out;
! 674: }
! 675: keys = tmp;
! 676: keys[nkeys++] = key;
! 677: key = NULL;
! 678: /* XXX synthesise comment */
! 679: }
! 680: /* success */
! 681: *keysp = keys;
! 682: *nkeysp = nkeys;
! 683: keys = NULL;
! 684: nkeys = 0;
! 685: r = 0;
! 686: out:
! 687: sshsk_free(skp);
! 688: sshsk_free_sk_resident_keys(rks, nrks);
! 689: sshkey_free(key);
! 690: if (nkeys != 0) {
! 691: for (i = 0; i < nkeys; i++)
! 692: sshkey_free(keys[i]);
! 693: free(keys);
! 694: }
! 695: return r;
! 696: }
! 697: