diff options
-rw-r--r-- | sk-api.h | 7 | ||||
-rw-r--r-- | sk-usbhid.c | 49 | ||||
-rw-r--r-- | ssh-keygen.c | 32 | ||||
-rw-r--r-- | ssh-sk.c | 21 | ||||
-rw-r--r-- | ssherr.c | 4 | ||||
-rw-r--r-- | ssherr.h | 3 |
6 files changed, 82 insertions, 34 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sk-api.h,v 1.5 2019/12/30 09:23:28 djm Exp $ */ | 1 | /* $OpenBSD: sk-api.h,v 1.6 2019/12/30 09:24:45 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2019 Google LLC | 3 | * Copyright (c) 2019 Google LLC |
4 | * | 4 | * |
@@ -32,6 +32,11 @@ | |||
32 | #define SSH_SK_ECDSA 0x00 | 32 | #define SSH_SK_ECDSA 0x00 |
33 | #define SSH_SK_ED25519 0x01 | 33 | #define SSH_SK_ED25519 0x01 |
34 | 34 | ||
35 | /* Error codes */ | ||
36 | #define SSH_SK_ERR_GENERAL -1 | ||
37 | #define SSH_SK_ERR_UNSUPPORTED -2 | ||
38 | #define SSH_SK_ERR_PIN_REQUIRED -3 | ||
39 | |||
35 | struct sk_enroll_response { | 40 | struct sk_enroll_response { |
36 | uint8_t *public_key; | 41 | uint8_t *public_key; |
37 | size_t public_key_len; | 42 | size_t public_key_len; |
diff --git a/sk-usbhid.c b/sk-usbhid.c index 54ce0bddf..22a4c5df5 100644 --- a/sk-usbhid.c +++ b/sk-usbhid.c | |||
@@ -65,6 +65,11 @@ | |||
65 | #define SK_ECDSA 0x00 | 65 | #define SK_ECDSA 0x00 |
66 | #define SK_ED25519 0x01 | 66 | #define SK_ED25519 0x01 |
67 | 67 | ||
68 | /* Error codes */ | ||
69 | #define SSH_SK_ERR_GENERAL -1 | ||
70 | #define SSH_SK_ERR_UNSUPPORTED -2 | ||
71 | #define SSH_SK_ERR_PIN_REQUIRED -3 | ||
72 | |||
68 | struct sk_enroll_response { | 73 | struct sk_enroll_response { |
69 | uint8_t *public_key; | 74 | uint8_t *public_key; |
70 | size_t public_key_len; | 75 | size_t public_key_len; |
@@ -412,6 +417,20 @@ pack_public_key(int alg, const fido_cred_t *cred, | |||
412 | } | 417 | } |
413 | } | 418 | } |
414 | 419 | ||
420 | static int | ||
421 | fidoerr_to_skerr(int fidoerr) | ||
422 | { | ||
423 | switch (fidoerr) { | ||
424 | case FIDO_ERR_UNSUPPORTED_OPTION: | ||
425 | return SSH_SK_ERR_UNSUPPORTED; | ||
426 | case FIDO_ERR_PIN_REQUIRED: | ||
427 | case FIDO_ERR_PIN_INVALID: | ||
428 | return SSH_SK_ERR_PIN_REQUIRED; | ||
429 | default: | ||
430 | return -1; | ||
431 | } | ||
432 | } | ||
433 | |||
415 | int | 434 | int |
416 | sk_enroll(int alg, const uint8_t *challenge, size_t challenge_len, | 435 | sk_enroll(int alg, const uint8_t *challenge, size_t challenge_len, |
417 | const char *application, uint8_t flags, const char *pin, | 436 | const char *application, uint8_t flags, const char *pin, |
@@ -424,7 +443,7 @@ sk_enroll(int alg, const uint8_t *challenge, size_t challenge_len, | |||
424 | struct sk_enroll_response *response = NULL; | 443 | struct sk_enroll_response *response = NULL; |
425 | size_t len; | 444 | size_t len; |
426 | int cose_alg; | 445 | int cose_alg; |
427 | int ret = -1; | 446 | int ret = SSH_SK_ERR_GENERAL; |
428 | int r; | 447 | int r; |
429 | char *device = NULL; | 448 | char *device = NULL; |
430 | 449 | ||
@@ -491,8 +510,9 @@ sk_enroll(int alg, const uint8_t *challenge, size_t challenge_len, | |||
491 | skdebug(__func__, "fido_dev_open: %s", fido_strerr(r)); | 510 | skdebug(__func__, "fido_dev_open: %s", fido_strerr(r)); |
492 | goto out; | 511 | goto out; |
493 | } | 512 | } |
494 | if ((r = fido_dev_make_cred(dev, cred, NULL)) != FIDO_OK) { | 513 | if ((r = fido_dev_make_cred(dev, cred, pin)) != FIDO_OK) { |
495 | skdebug(__func__, "fido_dev_make_cred: %s", fido_strerr(r)); | 514 | skdebug(__func__, "fido_dev_make_cred: %s", fido_strerr(r)); |
515 | ret = fidoerr_to_skerr(r); | ||
496 | goto out; | 516 | goto out; |
497 | } | 517 | } |
498 | if (fido_cred_x5c_ptr(cred) != NULL) { | 518 | if (fido_cred_x5c_ptr(cred) != NULL) { |
@@ -657,7 +677,7 @@ sk_sign(int alg, const uint8_t *message, size_t message_len, | |||
657 | fido_assert_t *assert = NULL; | 677 | fido_assert_t *assert = NULL; |
658 | fido_dev_t *dev = NULL; | 678 | fido_dev_t *dev = NULL; |
659 | struct sk_sign_response *response = NULL; | 679 | struct sk_sign_response *response = NULL; |
660 | int ret = -1; | 680 | int ret = SSH_SK_ERR_GENERAL; |
661 | int r; | 681 | int r; |
662 | 682 | ||
663 | #ifdef SK_DEBUG | 683 | #ifdef SK_DEBUG |
@@ -736,7 +756,7 @@ static int | |||
736 | read_rks(const char *devpath, const char *pin, | 756 | read_rks(const char *devpath, const char *pin, |
737 | struct sk_resident_key ***rksp, size_t *nrksp) | 757 | struct sk_resident_key ***rksp, size_t *nrksp) |
738 | { | 758 | { |
739 | int r = -1; | 759 | int ret = SSH_SK_ERR_GENERAL, r = -1; |
740 | fido_dev_t *dev = NULL; | 760 | fido_dev_t *dev = NULL; |
741 | fido_credman_metadata_t *metadata = NULL; | 761 | fido_credman_metadata_t *metadata = NULL; |
742 | fido_credman_rp_t *rp = NULL; | 762 | fido_credman_rp_t *rp = NULL; |
@@ -747,16 +767,15 @@ read_rks(const char *devpath, const char *pin, | |||
747 | 767 | ||
748 | if ((dev = fido_dev_new()) == NULL) { | 768 | if ((dev = fido_dev_new()) == NULL) { |
749 | skdebug(__func__, "fido_dev_new failed"); | 769 | skdebug(__func__, "fido_dev_new failed"); |
750 | return -1; | 770 | return ret; |
751 | } | 771 | } |
752 | if ((r = fido_dev_open(dev, devpath)) != FIDO_OK) { | 772 | if ((r = fido_dev_open(dev, devpath)) != FIDO_OK) { |
753 | skdebug(__func__, "fido_dev_open %s failed: %s", | 773 | skdebug(__func__, "fido_dev_open %s failed: %s", |
754 | devpath, fido_strerr(r)); | 774 | devpath, fido_strerr(r)); |
755 | fido_dev_free(&dev); | 775 | fido_dev_free(&dev); |
756 | return -1; | 776 | return ret; |
757 | } | 777 | } |
758 | if ((metadata = fido_credman_metadata_new()) == NULL) { | 778 | if ((metadata = fido_credman_metadata_new()) == NULL) { |
759 | r = -1; | ||
760 | skdebug(__func__, "alloc failed"); | 779 | skdebug(__func__, "alloc failed"); |
761 | goto out; | 780 | goto out; |
762 | } | 781 | } |
@@ -765,7 +784,7 @@ read_rks(const char *devpath, const char *pin, | |||
765 | if (r == FIDO_ERR_INVALID_COMMAND) { | 784 | if (r == FIDO_ERR_INVALID_COMMAND) { |
766 | skdebug(__func__, "device %s does not support " | 785 | skdebug(__func__, "device %s does not support " |
767 | "resident keys", devpath); | 786 | "resident keys", devpath); |
768 | r = 0; | 787 | ret = 0; |
769 | goto out; | 788 | goto out; |
770 | } | 789 | } |
771 | skdebug(__func__, "get metadata for %s failed: %s", | 790 | skdebug(__func__, "get metadata for %s failed: %s", |
@@ -776,7 +795,6 @@ read_rks(const char *devpath, const char *pin, | |||
776 | (unsigned long long)fido_credman_rk_existing(metadata), | 795 | (unsigned long long)fido_credman_rk_existing(metadata), |
777 | (unsigned long long)fido_credman_rk_remaining(metadata)); | 796 | (unsigned long long)fido_credman_rk_remaining(metadata)); |
778 | if ((rp = fido_credman_rp_new()) == NULL) { | 797 | if ((rp = fido_credman_rp_new()) == NULL) { |
779 | r = -1; | ||
780 | skdebug(__func__, "alloc rp failed"); | 798 | skdebug(__func__, "alloc rp failed"); |
781 | goto out; | 799 | goto out; |
782 | } | 800 | } |
@@ -801,7 +819,6 @@ read_rks(const char *devpath, const char *pin, | |||
801 | 819 | ||
802 | fido_credman_rk_free(&rk); | 820 | fido_credman_rk_free(&rk); |
803 | if ((rk = fido_credman_rk_new()) == NULL) { | 821 | if ((rk = fido_credman_rk_new()) == NULL) { |
804 | r = -1; | ||
805 | skdebug(__func__, "alloc rk failed"); | 822 | skdebug(__func__, "alloc rk failed"); |
806 | goto out; | 823 | goto out; |
807 | } | 824 | } |
@@ -831,7 +848,6 @@ read_rks(const char *devpath, const char *pin, | |||
831 | fido_cred_id_len(cred))) == NULL || | 848 | fido_cred_id_len(cred))) == NULL || |
832 | (srk->application = strdup(fido_credman_rp_id(rp, | 849 | (srk->application = strdup(fido_credman_rp_id(rp, |
833 | i))) == NULL) { | 850 | i))) == NULL) { |
834 | r = -1; | ||
835 | skdebug(__func__, "alloc sk_resident_key"); | 851 | skdebug(__func__, "alloc sk_resident_key"); |
836 | goto out; | 852 | goto out; |
837 | } | 853 | } |
@@ -862,7 +878,6 @@ read_rks(const char *devpath, const char *pin, | |||
862 | /* append */ | 878 | /* append */ |
863 | if ((tmp = recallocarray(*rksp, *nrksp, (*nrksp) + 1, | 879 | if ((tmp = recallocarray(*rksp, *nrksp, (*nrksp) + 1, |
864 | sizeof(**rksp))) == NULL) { | 880 | sizeof(**rksp))) == NULL) { |
865 | r = -1; | ||
866 | skdebug(__func__, "alloc rksp"); | 881 | skdebug(__func__, "alloc rksp"); |
867 | goto out; | 882 | goto out; |
868 | } | 883 | } |
@@ -872,7 +887,7 @@ read_rks(const char *devpath, const char *pin, | |||
872 | } | 887 | } |
873 | } | 888 | } |
874 | /* Success */ | 889 | /* Success */ |
875 | r = 0; | 890 | ret = 0; |
876 | out: | 891 | out: |
877 | if (srk != NULL) { | 892 | if (srk != NULL) { |
878 | free(srk->application); | 893 | free(srk->application); |
@@ -885,14 +900,14 @@ read_rks(const char *devpath, const char *pin, | |||
885 | fido_dev_close(dev); | 900 | fido_dev_close(dev); |
886 | fido_dev_free(&dev); | 901 | fido_dev_free(&dev); |
887 | fido_credman_metadata_free(&metadata); | 902 | fido_credman_metadata_free(&metadata); |
888 | return r; | 903 | return ret; |
889 | } | 904 | } |
890 | 905 | ||
891 | int | 906 | int |
892 | sk_load_resident_keys(const char *pin, | 907 | sk_load_resident_keys(const char *pin, |
893 | struct sk_resident_key ***rksp, size_t *nrksp) | 908 | struct sk_resident_key ***rksp, size_t *nrksp) |
894 | { | 909 | { |
895 | int r = -1; | 910 | int ret = SSH_SK_ERR_GENERAL, r = -1; |
896 | fido_dev_info_t *devlist = NULL; | 911 | fido_dev_info_t *devlist = NULL; |
897 | size_t i, ndev = 0, nrks = 0; | 912 | size_t i, ndev = 0, nrks = 0; |
898 | const fido_dev_info_t *di; | 913 | const fido_dev_info_t *di; |
@@ -924,7 +939,7 @@ sk_load_resident_keys(const char *pin, | |||
924 | } | 939 | } |
925 | } | 940 | } |
926 | /* success */ | 941 | /* success */ |
927 | r = 0; | 942 | ret = 0; |
928 | *rksp = rks; | 943 | *rksp = rks; |
929 | *nrksp = nrks; | 944 | *nrksp = nrks; |
930 | rks = NULL; | 945 | rks = NULL; |
@@ -938,7 +953,7 @@ sk_load_resident_keys(const char *pin, | |||
938 | } | 953 | } |
939 | free(rks); | 954 | free(rks); |
940 | fido_dev_info_free(&devlist, MAX_FIDO_DEVICES); | 955 | fido_dev_info_free(&devlist, MAX_FIDO_DEVICES); |
941 | return r; | 956 | return ret; |
942 | } | 957 | } |
943 | 958 | ||
944 | #endif /* ENABLE_SK_INTERNAL */ | 959 | #endif /* ENABLE_SK_INTERNAL */ |
diff --git a/ssh-keygen.c b/ssh-keygen.c index 79e2e92b5..696891e0e 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-keygen.c,v 1.378 2019/12/30 09:23:28 djm Exp $ */ | 1 | /* $OpenBSD: ssh-keygen.c,v 1.379 2019/12/30 09:24:45 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -3361,16 +3361,26 @@ main(int argc, char **argv) | |||
3361 | switch (type) { | 3361 | switch (type) { |
3362 | case KEY_ECDSA_SK: | 3362 | case KEY_ECDSA_SK: |
3363 | case KEY_ED25519_SK: | 3363 | case KEY_ED25519_SK: |
3364 | if (!quiet) { | 3364 | passphrase1 = NULL; |
3365 | printf("You may need to touch your security key " | 3365 | for (i = 0 ; i < 3; i++) { |
3366 | "to authorize key generation.\n"); | 3366 | if (!quiet) { |
3367 | } | 3367 | printf("You may need to touch your security " |
3368 | fflush(stdout); | 3368 | "key to authorize key generation.\n"); |
3369 | if (sshsk_enroll(type, sk_provider, | 3369 | } |
3370 | cert_key_id == NULL ? "ssh:" : cert_key_id, | 3370 | fflush(stdout); |
3371 | sk_flags, NULL, NULL, &private, NULL) != 0) | 3371 | r = sshsk_enroll(type, sk_provider, |
3372 | exit(1); /* error message already printed */ | 3372 | cert_key_id == NULL ? "ssh:" : cert_key_id, |
3373 | break; | 3373 | sk_flags, passphrase1, NULL, &private, NULL); |
3374 | if (r == 0) | ||
3375 | break; | ||
3376 | if (r != SSH_ERR_KEY_WRONG_PASSPHRASE) | ||
3377 | exit(1); /* error message already printed */ | ||
3378 | passphrase1 = read_passphrase("Enter PIN for security " | ||
3379 | "key: ", RP_ALLOW_STDIN); | ||
3380 | } | ||
3381 | if (i > 3) | ||
3382 | fatal("Too many incorrect PINs"); | ||
3383 | break; | ||
3374 | default: | 3384 | default: |
3375 | if ((r = sshkey_generate(type, bits, &private)) != 0) | 3385 | if ((r = sshkey_generate(type, bits, &private)) != 0) |
3376 | fatal("sshkey_generate failed"); | 3386 | fatal("sshkey_generate failed"); |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-sk.c,v 1.22 2019/12/30 09:24:03 djm Exp $ */ | 1 | /* $OpenBSD: ssh-sk.c,v 1.23 2019/12/30 09:24:45 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2019 Google LLC | 3 | * Copyright (c) 2019 Google LLC |
4 | * | 4 | * |
@@ -325,6 +325,20 @@ sshsk_key_from_response(int alg, const char *application, uint8_t flags, | |||
325 | return r; | 325 | return r; |
326 | } | 326 | } |
327 | 327 | ||
328 | static int | ||
329 | skerr_to_ssherr(int skerr) | ||
330 | { | ||
331 | switch (skerr) { | ||
332 | case SSH_SK_ERR_UNSUPPORTED: | ||
333 | return SSH_ERR_FEATURE_UNSUPPORTED; | ||
334 | case SSH_SK_ERR_PIN_REQUIRED: | ||
335 | return SSH_ERR_KEY_WRONG_PASSPHRASE; | ||
336 | case SSH_SK_ERR_GENERAL: | ||
337 | default: | ||
338 | return SSH_ERR_INVALID_FORMAT; | ||
339 | } | ||
340 | } | ||
341 | |||
328 | int | 342 | int |
329 | sshsk_enroll(int type, const char *provider_path, const char *application, | 343 | sshsk_enroll(int type, const char *provider_path, const char *application, |
330 | uint8_t flags, const char *pin, struct sshbuf *challenge_buf, | 344 | uint8_t flags, const char *pin, struct sshbuf *challenge_buf, |
@@ -396,7 +410,7 @@ sshsk_enroll(int type, const char *provider_path, const char *application, | |||
396 | flags, pin, &resp)) != 0) { | 410 | flags, pin, &resp)) != 0) { |
397 | error("Security key provider \"%s\" returned failure %d", | 411 | error("Security key provider \"%s\" returned failure %d", |
398 | provider_path, r); | 412 | provider_path, r); |
399 | r = SSH_ERR_INVALID_FORMAT; /* XXX error codes in API? */ | 413 | r = skerr_to_ssherr(r); |
400 | goto out; | 414 | goto out; |
401 | } | 415 | } |
402 | 416 | ||
@@ -559,6 +573,7 @@ sshsk_sign(const char *provider_path, struct sshkey *key, | |||
559 | sshbuf_ptr(key->sk_key_handle), sshbuf_len(key->sk_key_handle), | 573 | sshbuf_ptr(key->sk_key_handle), sshbuf_len(key->sk_key_handle), |
560 | key->sk_flags, pin, &resp)) != 0) { | 574 | key->sk_flags, pin, &resp)) != 0) { |
561 | debug("%s: sk_sign failed with code %d", __func__, r); | 575 | debug("%s: sk_sign failed with code %d", __func__, r); |
576 | r = skerr_to_ssherr(r); | ||
562 | goto out; | 577 | goto out; |
563 | } | 578 | } |
564 | /* Assemble signature */ | 579 | /* Assemble signature */ |
@@ -655,7 +670,7 @@ sshsk_load_resident(const char *provider_path, const char *pin, | |||
655 | if ((r = skp->sk_load_resident_keys(pin, &rks, &nrks)) != 0) { | 670 | if ((r = skp->sk_load_resident_keys(pin, &rks, &nrks)) != 0) { |
656 | error("Security key provider \"%s\" returned failure %d", | 671 | error("Security key provider \"%s\" returned failure %d", |
657 | provider_path, r); | 672 | provider_path, r); |
658 | r = SSH_ERR_INVALID_FORMAT; /* XXX error codes in API? */ | 673 | r = skerr_to_ssherr(r); |
659 | goto out; | 674 | goto out; |
660 | } | 675 | } |
661 | for (i = 0; i < nrks; i++) { | 676 | for (i = 0; i < nrks; i++) { |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssherr.c,v 1.8 2018/07/03 11:39:54 djm Exp $ */ | 1 | /* $OpenBSD: ssherr.c,v 1.9 2019/12/30 09:24:45 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2011 Damien Miller | 3 | * Copyright (c) 2011 Damien Miller |
4 | * | 4 | * |
@@ -141,6 +141,8 @@ ssh_err(int n) | |||
141 | return "number is too large"; | 141 | return "number is too large"; |
142 | case SSH_ERR_SIGN_ALG_UNSUPPORTED: | 142 | case SSH_ERR_SIGN_ALG_UNSUPPORTED: |
143 | return "signature algorithm not supported"; | 143 | return "signature algorithm not supported"; |
144 | case SSH_ERR_FEATURE_UNSUPPORTED: | ||
145 | return "requested feature not supported"; | ||
144 | default: | 146 | default: |
145 | return "unknown error"; | 147 | return "unknown error"; |
146 | } | 148 | } |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssherr.h,v 1.6 2018/07/03 11:39:54 djm Exp $ */ | 1 | /* $OpenBSD: ssherr.h,v 1.7 2019/12/30 09:24:45 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2011 Damien Miller | 3 | * Copyright (c) 2011 Damien Miller |
4 | * | 4 | * |
@@ -80,6 +80,7 @@ | |||
80 | #define SSH_ERR_KEY_LENGTH -56 | 80 | #define SSH_ERR_KEY_LENGTH -56 |
81 | #define SSH_ERR_NUMBER_TOO_LARGE -57 | 81 | #define SSH_ERR_NUMBER_TOO_LARGE -57 |
82 | #define SSH_ERR_SIGN_ALG_UNSUPPORTED -58 | 82 | #define SSH_ERR_SIGN_ALG_UNSUPPORTED -58 |
83 | #define SSH_ERR_FEATURE_UNSUPPORTED -59 | ||
83 | 84 | ||
84 | /* Translate a numeric error code to a human-readable error string */ | 85 | /* Translate a numeric error code to a human-readable error string */ |
85 | const char *ssh_err(int n); | 86 | const char *ssh_err(int n); |