summaryrefslogtreecommitdiff
path: root/ssh-sk.c
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2020-01-06 02:00:46 +0000
committerDamien Miller <djm@mindrot.org>2020-01-06 13:12:46 +1100
commitc312ca077cd2a6c15545cd6b4d34ee2f69289174 (patch)
treeb8dd974c55dd0de351dfcbfc4f33fddb935a1c12 /ssh-sk.c
parent2ab335712d084d9ccaf3f53afc3fa9535329da87 (diff)
upstream: Extends the SK API to accept a set of key/value options
for all operations. These are intended to future-proof the API a little by making it easier to specify additional fields for without having to change the API version for each. At present, only two options are defined: one to explicitly specify the device for an operation (rather than accepting the middleware's autoselection) and another to specify the FIDO2 username that may be used when generating a resident key. These new options may be invoked at key generation time via ssh-keygen -O This also implements a suggestion from Markus to avoid "int" in favour of uint32_t for the algorithm argument in the API, to make implementation of ssh-sk-client/helper a little easier. feedback, fixes and ok markus@ OpenBSD-Commit-ID: 973ce11704609022ab36abbdeb6bc23c8001eabc
Diffstat (limited to 'ssh-sk.c')
-rw-r--r--ssh-sk.c121
1 files changed, 104 insertions, 17 deletions
diff --git a/ssh-sk.c b/ssh-sk.c
index b1d0d6c58..0ef52e299 100644
--- a/ssh-sk.c
+++ b/ssh-sk.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-sk.c,v 1.23 2019/12/30 09:24:45 djm Exp $ */ 1/* $OpenBSD: ssh-sk.c,v 1.24 2020/01/06 02:00:47 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2019 Google LLC 3 * Copyright (c) 2019 Google LLC
4 * 4 *
@@ -53,29 +53,32 @@ struct sshsk_provider {
53 /* Enroll a U2F key (private key generation) */ 53 /* Enroll a U2F key (private key generation) */
54 int (*sk_enroll)(int alg, const uint8_t *challenge, 54 int (*sk_enroll)(int alg, const uint8_t *challenge,
55 size_t challenge_len, const char *application, uint8_t flags, 55 size_t challenge_len, const char *application, uint8_t flags,
56 const char *pin, struct sk_enroll_response **enroll_response); 56 const char *pin, struct sk_option **opts,
57 struct sk_enroll_response **enroll_response);
57 58
58 /* Sign a challenge */ 59 /* Sign a challenge */
59 int (*sk_sign)(int alg, const uint8_t *message, size_t message_len, 60 int (*sk_sign)(int alg, const uint8_t *message, size_t message_len,
60 const char *application, 61 const char *application,
61 const uint8_t *key_handle, size_t key_handle_len, 62 const uint8_t *key_handle, size_t key_handle_len,
62 uint8_t flags, const char *pin, 63 uint8_t flags, const char *pin, struct sk_option **opts,
63 struct sk_sign_response **sign_response); 64 struct sk_sign_response **sign_response);
64 65
65 /* Enumerate resident keys */ 66 /* Enumerate resident keys */
66 int (*sk_load_resident_keys)(const char *pin, 67 int (*sk_load_resident_keys)(const char *pin, struct sk_option **opts,
67 struct sk_resident_key ***rks, size_t *nrks); 68 struct sk_resident_key ***rks, size_t *nrks);
68}; 69};
69 70
70/* Built-in version */ 71/* Built-in version */
71int ssh_sk_enroll(int alg, const uint8_t *challenge, 72int ssh_sk_enroll(int alg, const uint8_t *challenge,
72 size_t challenge_len, const char *application, uint8_t flags, 73 size_t challenge_len, const char *application, uint8_t flags,
73 const char *pin, struct sk_enroll_response **enroll_response); 74 const char *pin, struct sk_option **opts,
75 struct sk_enroll_response **enroll_response);
74int ssh_sk_sign(int alg, const uint8_t *message, size_t message_len, 76int ssh_sk_sign(int alg, const uint8_t *message, size_t message_len,
75 const char *application, 77 const char *application,
76 const uint8_t *key_handle, size_t key_handle_len, 78 const uint8_t *key_handle, size_t key_handle_len,
77 uint8_t flags, const char *pin, struct sk_sign_response **sign_response); 79 uint8_t flags, const char *pin, struct sk_option **opts,
78int ssh_sk_load_resident_keys(const char *pin, 80 struct sk_sign_response **sign_response);
81int ssh_sk_load_resident_keys(const char *pin, struct sk_option **opts,
79 struct sk_resident_key ***rks, size_t *nrks); 82 struct sk_resident_key ***rks, size_t *nrks);
80 83
81static void 84static void
@@ -339,9 +342,80 @@ skerr_to_ssherr(int skerr)
339 } 342 }
340} 343}
341 344
345static void
346sshsk_free_options(struct sk_option **opts)
347{
348 size_t i;
349
350 if (opts == NULL)
351 return;
352 for (i = 0; opts[i] != NULL; i++) {
353 free(opts[i]->name);
354 free(opts[i]->value);
355 free(opts[i]);
356 }
357 free(opts);
358}
359
360static int
361sshsk_add_option(struct sk_option ***optsp, size_t *noptsp,
362 const char *name, const char *value, uint8_t required)
363{
364 struct sk_option **opts = *optsp;
365 size_t nopts = *noptsp;
366
367 if ((opts = recallocarray(opts, nopts, nopts + 2, /* extra for NULL */
368 sizeof(*opts))) == NULL) {
369 error("%s: array alloc failed", __func__);
370 return SSH_ERR_ALLOC_FAIL;
371 }
372 *optsp = opts;
373 *noptsp = nopts + 1;
374 if ((opts[nopts] = calloc(1, sizeof(**opts))) == NULL) {
375 error("%s: alloc failed", __func__);
376 return SSH_ERR_ALLOC_FAIL;
377 }
378 if ((opts[nopts]->name = strdup(name)) == NULL ||
379 (opts[nopts]->value = strdup(value)) == NULL) {
380 error("%s: alloc failed", __func__);
381 return SSH_ERR_ALLOC_FAIL;
382 }
383 opts[nopts]->required = required;
384 return 0;
385}
386
387static int
388make_options(const char *device, const char *user_id,
389 struct sk_option ***optsp)
390{
391 struct sk_option **opts = NULL;
392 size_t nopts = 0;
393 int r, ret = SSH_ERR_INTERNAL_ERROR;
394
395 if (device != NULL &&
396 (r = sshsk_add_option(&opts, &nopts, "device", device, 0)) != 0) {
397 ret = r;
398 goto out;
399 }
400 if (user_id != NULL &&
401 (r = sshsk_add_option(&opts, &nopts, "user", user_id, 0)) != 0) {
402 ret = r;
403 goto out;
404 }
405 /* success */
406 *optsp = opts;
407 opts = NULL;
408 nopts = 0;
409 ret = 0;
410 out:
411 sshsk_free_options(opts);
412 return ret;
413}
414
342int 415int
343sshsk_enroll(int type, const char *provider_path, const char *application, 416sshsk_enroll(int type, const char *provider_path, const char *device,
344 uint8_t flags, const char *pin, struct sshbuf *challenge_buf, 417 const char *application, const char *userid, uint8_t flags,
418 const char *pin, struct sshbuf *challenge_buf,
345 struct sshkey **keyp, struct sshbuf *attest) 419 struct sshkey **keyp, struct sshbuf *attest)
346{ 420{
347 struct sshsk_provider *skp = NULL; 421 struct sshsk_provider *skp = NULL;
@@ -350,17 +424,23 @@ sshsk_enroll(int type, const char *provider_path, const char *application,
350 const u_char *challenge; 424 const u_char *challenge;
351 size_t challenge_len; 425 size_t challenge_len;
352 struct sk_enroll_response *resp = NULL; 426 struct sk_enroll_response *resp = NULL;
427 struct sk_option **opts = NULL;
353 int r = SSH_ERR_INTERNAL_ERROR; 428 int r = SSH_ERR_INTERNAL_ERROR;
354 int alg; 429 int alg;
355 430
356 debug("%s: provider \"%s\", application \"%s\", flags 0x%02x, " 431 debug("%s: provider \"%s\", device \"%s\", application \"%s\", "
357 "challenge len %zu%s", __func__, provider_path, application, 432 "userid \"%s\", flags 0x%02x, challenge len %zu%s", __func__,
358 flags, challenge_buf == NULL ? 0 : sshbuf_len(challenge_buf), 433 provider_path, device, application, userid, flags,
434 challenge_buf == NULL ? 0 : sshbuf_len(challenge_buf),
359 (pin != NULL && *pin != '\0') ? " with-pin" : ""); 435 (pin != NULL && *pin != '\0') ? " with-pin" : "");
360 436
361 *keyp = NULL; 437 *keyp = NULL;
362 if (attest) 438 if (attest)
363 sshbuf_reset(attest); 439 sshbuf_reset(attest);
440
441 if ((r = make_options(device, userid, &opts)) != 0)
442 goto out;
443
364 switch (type) { 444 switch (type) {
365#ifdef WITH_OPENSSL 445#ifdef WITH_OPENSSL
366 case KEY_ECDSA_SK: 446 case KEY_ECDSA_SK:
@@ -407,7 +487,7 @@ sshsk_enroll(int type, const char *provider_path, const char *application,
407 /* XXX validate flags? */ 487 /* XXX validate flags? */
408 /* enroll key */ 488 /* enroll key */
409 if ((r = skp->sk_enroll(alg, challenge, challenge_len, application, 489 if ((r = skp->sk_enroll(alg, challenge, challenge_len, application,
410 flags, pin, &resp)) != 0) { 490 flags, pin, opts, &resp)) != 0) {
411 error("Security key provider \"%s\" returned failure %d", 491 error("Security key provider \"%s\" returned failure %d",
412 provider_path, r); 492 provider_path, r);
413 r = skerr_to_ssherr(r); 493 r = skerr_to_ssherr(r);
@@ -437,6 +517,7 @@ sshsk_enroll(int type, const char *provider_path, const char *application,
437 key = NULL; /* transferred */ 517 key = NULL; /* transferred */
438 r = 0; 518 r = 0;
439 out: 519 out:
520 sshsk_free_options(opts);
440 sshsk_free(skp); 521 sshsk_free(skp);
441 sshkey_free(key); 522 sshkey_free(key);
442 sshsk_free_enroll_response(resp); 523 sshsk_free_enroll_response(resp);
@@ -528,6 +609,7 @@ sshsk_sign(const char *provider_path, struct sshkey *key,
528 struct sk_sign_response *resp = NULL; 609 struct sk_sign_response *resp = NULL;
529 struct sshbuf *inner_sig = NULL, *sig = NULL; 610 struct sshbuf *inner_sig = NULL, *sig = NULL;
530 uint8_t message[32]; 611 uint8_t message[32];
612 struct sk_option **opts = NULL;
531 613
532 debug("%s: provider \"%s\", key %s, flags 0x%02x%s", __func__, 614 debug("%s: provider \"%s\", key %s, flags 0x%02x%s", __func__,
533 provider_path, sshkey_type(key), key->sk_flags, 615 provider_path, sshkey_type(key), key->sk_flags,
@@ -571,7 +653,7 @@ sshsk_sign(const char *provider_path, struct sshkey *key,
571 if ((r = skp->sk_sign(alg, message, sizeof(message), 653 if ((r = skp->sk_sign(alg, message, sizeof(message),
572 key->sk_application, 654 key->sk_application,
573 sshbuf_ptr(key->sk_key_handle), sshbuf_len(key->sk_key_handle), 655 sshbuf_ptr(key->sk_key_handle), sshbuf_len(key->sk_key_handle),
574 key->sk_flags, pin, &resp)) != 0) { 656 key->sk_flags, pin, opts, &resp)) != 0) {
575 debug("%s: sk_sign failed with code %d", __func__, r); 657 debug("%s: sk_sign failed with code %d", __func__, r);
576 r = skerr_to_ssherr(r); 658 r = skerr_to_ssherr(r);
577 goto out; 659 goto out;
@@ -617,6 +699,7 @@ sshsk_sign(const char *provider_path, struct sshkey *key,
617 /* success */ 699 /* success */
618 r = 0; 700 r = 0;
619 out: 701 out:
702 sshsk_free_options(opts);
620 explicit_bzero(message, sizeof(message)); 703 explicit_bzero(message, sizeof(message));
621 sshsk_free(skp); 704 sshsk_free(skp);
622 sshsk_free_sign_response(resp); 705 sshsk_free_sign_response(resp);
@@ -645,8 +728,8 @@ sshsk_free_sk_resident_keys(struct sk_resident_key **rks, size_t nrks)
645} 728}
646 729
647int 730int
648sshsk_load_resident(const char *provider_path, const char *pin, 731sshsk_load_resident(const char *provider_path, const char *device,
649 struct sshkey ***keysp, size_t *nkeysp) 732 const char *pin, struct sshkey ***keysp, size_t *nkeysp)
650{ 733{
651 struct sshsk_provider *skp = NULL; 734 struct sshsk_provider *skp = NULL;
652 int r = SSH_ERR_INTERNAL_ERROR; 735 int r = SSH_ERR_INTERNAL_ERROR;
@@ -654,6 +737,7 @@ sshsk_load_resident(const char *provider_path, const char *pin,
654 size_t i, nrks = 0, nkeys = 0; 737 size_t i, nrks = 0, nkeys = 0;
655 struct sshkey *key = NULL, **keys = NULL, **tmp; 738 struct sshkey *key = NULL, **keys = NULL, **tmp;
656 uint8_t flags; 739 uint8_t flags;
740 struct sk_option **opts = NULL;
657 741
658 debug("%s: provider \"%s\"%s", __func__, provider_path, 742 debug("%s: provider \"%s\"%s", __func__, provider_path,
659 (pin != NULL && *pin != '\0') ? ", have-pin": ""); 743 (pin != NULL && *pin != '\0') ? ", have-pin": "");
@@ -663,11 +747,13 @@ sshsk_load_resident(const char *provider_path, const char *pin,
663 *keysp = NULL; 747 *keysp = NULL;
664 *nkeysp = 0; 748 *nkeysp = 0;
665 749
750 if ((r = make_options(device, NULL, &opts)) != 0)
751 goto out;
666 if ((skp = sshsk_open(provider_path)) == NULL) { 752 if ((skp = sshsk_open(provider_path)) == NULL) {
667 r = SSH_ERR_INVALID_FORMAT; /* XXX sshsk_open return code? */ 753 r = SSH_ERR_INVALID_FORMAT; /* XXX sshsk_open return code? */
668 goto out; 754 goto out;
669 } 755 }
670 if ((r = skp->sk_load_resident_keys(pin, &rks, &nrks)) != 0) { 756 if ((r = skp->sk_load_resident_keys(pin, opts, &rks, &nrks)) != 0) {
671 error("Security key provider \"%s\" returned failure %d", 757 error("Security key provider \"%s\" returned failure %d",
672 provider_path, r); 758 provider_path, r);
673 r = skerr_to_ssherr(r); 759 r = skerr_to_ssherr(r);
@@ -710,6 +796,7 @@ sshsk_load_resident(const char *provider_path, const char *pin,
710 nkeys = 0; 796 nkeys = 0;
711 r = 0; 797 r = 0;
712 out: 798 out:
799 sshsk_free_options(opts);
713 sshsk_free(skp); 800 sshsk_free(skp);
714 sshsk_free_sk_resident_keys(rks, nrks); 801 sshsk_free_sk_resident_keys(rks, nrks);
715 sshkey_free(key); 802 sshkey_free(key);