diff options
author | djm@openbsd.org <djm@openbsd.org> | 2020-08-27 01:06:18 +0000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2020-08-27 11:28:36 +1000 |
commit | 9b8ad93824c682ce841f53f3b5762cef4e7cc4dc (patch) | |
tree | d4523956d4623b19bf5904d1b92afeb2307f69d3 /sk-usbhid.c | |
parent | 1196d7f49d4fbc90f37e550de3056561613b0960 (diff) |
upstream: support for user-verified FIDO keys
FIDO2 supports a notion of "user verification" where the user is
required to demonstrate their identity to the token before particular
operations (e.g. signing). Typically this is done by authenticating
themselves using a PIN that has been set on the token.
This adds support for generating and using user verified keys where
the verification happens via PIN (other options might be added in the
future, but none are in common use now). Practically, this adds
another key generation option "verify-required" that yields a key that
requires a PIN before each authentication.
feedback markus@ and Pedro Martelletto; ok markus@
OpenBSD-Commit-ID: 57fd461e4366f87c47502c5614ec08573e6d6a15
Diffstat (limited to 'sk-usbhid.c')
-rw-r--r-- | sk-usbhid.c | 38 |
1 files changed, 26 insertions, 12 deletions
diff --git a/sk-usbhid.c b/sk-usbhid.c index 2a573caa2..1dd834883 100644 --- a/sk-usbhid.c +++ b/sk-usbhid.c | |||
@@ -163,7 +163,8 @@ pick_first_device(void) | |||
163 | /* Check if the specified key handle exists on a given device. */ | 163 | /* Check if the specified key handle exists on a given device. */ |
164 | static int | 164 | static int |
165 | try_device(fido_dev_t *dev, const uint8_t *message, size_t message_len, | 165 | try_device(fido_dev_t *dev, const uint8_t *message, size_t message_len, |
166 | const char *application, const uint8_t *key_handle, size_t key_handle_len) | 166 | const char *application, const uint8_t *key_handle, size_t key_handle_len, |
167 | uint8_t flags, const char *pin) | ||
167 | { | 168 | { |
168 | fido_assert_t *assert = NULL; | 169 | fido_assert_t *assert = NULL; |
169 | int r = FIDO_ERR_INTERNAL; | 170 | int r = FIDO_ERR_INTERNAL; |
@@ -191,7 +192,7 @@ try_device(fido_dev_t *dev, const uint8_t *message, size_t message_len, | |||
191 | skdebug(__func__, "fido_assert_up: %s", fido_strerr(r)); | 192 | skdebug(__func__, "fido_assert_up: %s", fido_strerr(r)); |
192 | goto out; | 193 | goto out; |
193 | } | 194 | } |
194 | r = fido_dev_get_assert(dev, assert, NULL); | 195 | r = fido_dev_get_assert(dev, assert, pin); |
195 | skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r)); | 196 | skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r)); |
196 | if (r == FIDO_ERR_USER_PRESENCE_REQUIRED) { | 197 | if (r == FIDO_ERR_USER_PRESENCE_REQUIRED) { |
197 | /* U2F tokens may return this */ | 198 | /* U2F tokens may return this */ |
@@ -206,7 +207,8 @@ try_device(fido_dev_t *dev, const uint8_t *message, size_t message_len, | |||
206 | /* Iterate over configured devices looking for a specific key handle */ | 207 | /* Iterate over configured devices looking for a specific key handle */ |
207 | static fido_dev_t * | 208 | static fido_dev_t * |
208 | find_device(const char *path, const uint8_t *message, size_t message_len, | 209 | find_device(const char *path, const uint8_t *message, size_t message_len, |
209 | const char *application, const uint8_t *key_handle, size_t key_handle_len) | 210 | const char *application, const uint8_t *key_handle, size_t key_handle_len, |
211 | uint8_t flags, const char *pin) | ||
210 | { | 212 | { |
211 | fido_dev_info_t *devlist = NULL; | 213 | fido_dev_info_t *devlist = NULL; |
212 | fido_dev_t *dev = NULL; | 214 | fido_dev_t *dev = NULL; |
@@ -260,7 +262,7 @@ find_device(const char *path, const uint8_t *message, size_t message_len, | |||
260 | continue; | 262 | continue; |
261 | } | 263 | } |
262 | if (try_device(dev, message, message_len, application, | 264 | if (try_device(dev, message, message_len, application, |
263 | key_handle, key_handle_len) == 0) { | 265 | key_handle, key_handle_len, flags, pin) == 0) { |
264 | skdebug(__func__, "found key"); | 266 | skdebug(__func__, "found key"); |
265 | break; | 267 | break; |
266 | } | 268 | } |
@@ -570,19 +572,23 @@ sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len, | |||
570 | skdebug(__func__, "fido_dev_open: %s", fido_strerr(r)); | 572 | skdebug(__func__, "fido_dev_open: %s", fido_strerr(r)); |
571 | goto out; | 573 | goto out; |
572 | } | 574 | } |
573 | if ((flags & SSH_SK_RESIDENT_KEY) != 0) { | 575 | if ((flags & (SSH_SK_RESIDENT_KEY|SSH_SK_USER_VERIFICATION_REQD)) != 0) { |
574 | if (check_sk_extensions(dev, "credProtect", &credprot) < 0) { | 576 | if (check_sk_extensions(dev, "credProtect", &credprot) < 0) { |
575 | skdebug(__func__, "check_sk_extensions failed"); | 577 | skdebug(__func__, "check_sk_extensions failed"); |
576 | goto out; | 578 | goto out; |
577 | } | 579 | } |
578 | if (credprot == 0) { | 580 | if (credprot == 0) { |
579 | skdebug(__func__, "refusing to create unprotected " | 581 | skdebug(__func__, "refusing to create unprotected " |
580 | "resident key"); | 582 | "resident/verify-required key"); |
581 | ret = SSH_SK_ERR_UNSUPPORTED; | 583 | ret = SSH_SK_ERR_UNSUPPORTED; |
582 | goto out; | 584 | goto out; |
583 | } | 585 | } |
584 | if ((r = fido_cred_set_prot(cred, | 586 | if ((flags & SSH_SK_USER_VERIFICATION_REQD)) |
585 | FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID)) != FIDO_OK) { | 587 | credprot = FIDO_CRED_PROT_UV_REQUIRED; |
588 | else | ||
589 | credprot = FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID; | ||
590 | |||
591 | if ((r = fido_cred_set_prot(cred, credprot)) != FIDO_OK) { | ||
586 | skdebug(__func__, "fido_cred_set_prot: %s", | 592 | skdebug(__func__, "fido_cred_set_prot: %s", |
587 | fido_strerr(r)); | 593 | fido_strerr(r)); |
588 | ret = fidoerr_to_skerr(r); | 594 | ret = fidoerr_to_skerr(r); |
@@ -826,7 +832,7 @@ sk_sign(uint32_t alg, const uint8_t *data, size_t datalen, | |||
826 | goto out; | 832 | goto out; |
827 | } | 833 | } |
828 | if ((dev = find_device(device, message, sizeof(message), | 834 | if ((dev = find_device(device, message, sizeof(message), |
829 | application, key_handle, key_handle_len)) == NULL) { | 835 | application, key_handle, key_handle_len, flags, pin)) == NULL) { |
830 | skdebug(__func__, "couldn't find device for key handle"); | 836 | skdebug(__func__, "couldn't find device for key handle"); |
831 | goto out; | 837 | goto out; |
832 | } | 838 | } |
@@ -855,8 +861,15 @@ sk_sign(uint32_t alg, const uint8_t *data, size_t datalen, | |||
855 | skdebug(__func__, "fido_assert_set_up: %s", fido_strerr(r)); | 861 | skdebug(__func__, "fido_assert_set_up: %s", fido_strerr(r)); |
856 | goto out; | 862 | goto out; |
857 | } | 863 | } |
858 | if ((r = fido_dev_get_assert(dev, assert, NULL)) != FIDO_OK) { | 864 | if (pin == NULL && (flags & SSH_SK_USER_VERIFICATION_REQD) && |
865 | (r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK) { | ||
866 | skdebug(__func__, "fido_assert_set_uv: %s", fido_strerr(r)); | ||
867 | ret = FIDO_ERR_PIN_REQUIRED; | ||
868 | goto out; | ||
869 | } | ||
870 | if ((r = fido_dev_get_assert(dev, assert, pin)) != FIDO_OK) { | ||
859 | skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r)); | 871 | skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r)); |
872 | ret = fidoerr_to_skerr(r); | ||
860 | goto out; | 873 | goto out; |
861 | } | 874 | } |
862 | if ((response = calloc(1, sizeof(*response))) == NULL) { | 875 | if ((response = calloc(1, sizeof(*response))) == NULL) { |
@@ -978,8 +991,9 @@ read_rks(const char *devpath, const char *pin, | |||
978 | continue; | 991 | continue; |
979 | } | 992 | } |
980 | skdebug(__func__, "Device %s RP \"%s\" slot %zu: " | 993 | skdebug(__func__, "Device %s RP \"%s\" slot %zu: " |
981 | "type %d", devpath, fido_credman_rp_id(rp, i), j, | 994 | "type %d flags 0x%02x prot 0x%02x", devpath, |
982 | fido_cred_type(cred)); | 995 | fido_credman_rp_id(rp, i), j, fido_cred_type(cred), |
996 | fido_cred_flags(cred), fido_cred_prot(cred)); | ||
983 | 997 | ||
984 | /* build response entry */ | 998 | /* build response entry */ |
985 | if ((srk = calloc(1, sizeof(*srk))) == NULL || | 999 | if ((srk = calloc(1, sizeof(*srk))) == NULL || |