summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2019-12-30 09:24:45 +0000
committerDamien Miller <djm@mindrot.org>2019-12-30 21:01:51 +1100
commit43ce96427b76c4918e39af654e2fc9ee18d5d478 (patch)
treedfb3a5b32e02368f9739bb742e0aa858ced03701
parentd433596736a2cd4818f538be11fc94783f5c5236 (diff)
upstream: translate and return error codes; retry on bad PIN
Define some well-known error codes in the SK API and pass them back via ssh-sk-helper. Use the new "wrong PIN" error code to retry PIN prompting during ssh-keygen of resident keys. feedback and ok markus@ OpenBSD-Commit-ID: 9663c6a2bb7a0bc8deaccc6c30d9a2983b481620
-rw-r--r--sk-api.h7
-rw-r--r--sk-usbhid.c49
-rw-r--r--ssh-keygen.c32
-rw-r--r--ssh-sk.c21
-rw-r--r--ssherr.c4
-rw-r--r--ssherr.h3
6 files changed, 82 insertions, 34 deletions
diff --git a/sk-api.h b/sk-api.h
index 4f9f43ee6..dc786d556 100644
--- a/sk-api.h
+++ b/sk-api.h
@@ -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
35struct sk_enroll_response { 40struct 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
68struct sk_enroll_response { 73struct 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
420static int
421fidoerr_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
415int 434int
416sk_enroll(int alg, const uint8_t *challenge, size_t challenge_len, 435sk_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
736read_rks(const char *devpath, const char *pin, 756read_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
891int 906int
892sk_load_resident_keys(const char *pin, 907sk_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");
diff --git a/ssh-sk.c b/ssh-sk.c
index e1fb72cfc..b1d0d6c58 100644
--- a/ssh-sk.c
+++ b/ssh-sk.c
@@ -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
328static int
329skerr_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
328int 342int
329sshsk_enroll(int type, const char *provider_path, const char *application, 343sshsk_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++) {
diff --git a/ssherr.c b/ssherr.c
index 8ad3d5750..38974f51b 100644
--- a/ssherr.c
+++ b/ssherr.c
@@ -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 }
diff --git a/ssherr.h b/ssherr.h
index 348da5a20..520bd4964 100644
--- a/ssherr.h
+++ b/ssherr.h
@@ -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 */
85const char *ssh_err(int n); 86const char *ssh_err(int n);