1 /* $OpenBSD: sk-usbhid.c,v 1.47 2024/12/03 08:31:49 djm Exp $ */
3 * Copyright (c) 2019 Markus Friedl
4 * Copyright (c) 2020 Pedro Martelletto
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 #ifdef ENABLE_SK_INTERNAL
37 * Almost every use of OpenSSL in this file is for ECDSA-NISTP256.
38 * This is strictly a larger hammer than necessary, but it reduces changes
41 #ifndef OPENSSL_HAS_ECC
46 #include <openssl/opensslv.h>
47 #include <openssl/crypto.h>
48 #include <openssl/bn.h>
49 #include <openssl/ec.h>
50 #include <openssl/ecdsa.h>
51 #include <openssl/evp.h>
52 #endif /* WITH_OPENSSL */
55 #include <fido/credman.h>
57 /* backwards compat for libfido2 */
58 #ifndef HAVE_FIDO_CRED_PROT
59 #define fido_cred_prot(x) (0)
61 #ifndef HAVE_FIDO_CRED_SET_PROT
62 #define fido_cred_set_prot(x, y) (FIDO_ERR_UNSUPPORTED_OPTION)
64 #ifndef HAVE_FIDO_DEV_SUPPORTS_CRED_PROT
65 #define fido_dev_supports_cred_prot(x) (0)
67 #ifndef HAVE_FIDO_DEV_GET_TOUCH_BEGIN
68 #define fido_dev_get_touch_begin(x) (FIDO_ERR_UNSUPPORTED_OPTION)
70 #ifndef HAVE_FIDO_DEV_GET_TOUCH_STATUS
71 #define fido_dev_get_touch_status(x, y, z) (FIDO_ERR_UNSUPPORTED_OPTION)
73 #ifndef FIDO_CRED_PROT_UV_REQUIRED
74 #define FIDO_CRED_PROT_UV_REQUIRED 0
76 #ifndef FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID
77 #define FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID 0
86 * If building as part of OpenSSH, then rename exported functions.
87 * This must be done before including sk-api.h.
89 # define sk_api_version ssh_sk_api_version
90 # define sk_enroll ssh_sk_enroll
91 # define sk_sign ssh_sk_sign
92 # define sk_load_resident_keys ssh_sk_load_resident_keys
93 #endif /* !SK_STANDALONE */
97 /* #define SK_DEBUG 1 */
100 #define SSH_FIDO_INIT_ARG FIDO_DEBUG
102 #define SSH_FIDO_INIT_ARG 0
105 #define MAX_FIDO_DEVICES 8
106 #define FIDO_POLL_MS 50
107 #define SELECT_MS 15000
108 #define POLL_SLEEP_NS 200000000
110 #ifndef FIDO_ERR_OPERATION_DENIED
111 #define FIDO_ERR_OPERATION_DENIED 0x27
119 /* Return the version of the middleware API */
120 uint32_t sk_api_version(void);
122 /* Enroll a U2F key (private key generation) */
123 int sk_enroll(uint32_t alg
, const uint8_t *challenge
, size_t challenge_len
,
124 const char *application
, uint8_t flags
, const char *pin
,
125 struct sk_option
**options
, struct sk_enroll_response
**enroll_response
);
127 /* Sign a challenge */
128 int sk_sign(uint32_t alg
, const uint8_t *data
, size_t data_len
,
129 const char *application
, const uint8_t *key_handle
, size_t key_handle_len
,
130 uint8_t flags
, const char *pin
, struct sk_option
**options
,
131 struct sk_sign_response
**sign_response
);
133 /* Load resident keys */
134 int sk_load_resident_keys(const char *pin
, struct sk_option
**options
,
135 struct sk_resident_key
***rks
, size_t *nrks
);
137 static void skdebug(const char *func
, const char *fmt
, ...)
138 __attribute__((__format__ (printf
, 2, 3)));
141 skdebug(const char *func
, const char *fmt
, ...)
143 #if !defined(SK_STANDALONE)
148 xvasprintf(&msg
, fmt
, ap
);
150 debug("%s: %s", func
, msg
);
152 #elif defined(SK_DEBUG)
156 fprintf(stderr
, "%s: ", func
);
157 vfprintf(stderr
, fmt
, ap
);
161 (void)func
; /* XXX */
169 return SSH_SK_VERSION_MAJOR
;
172 static struct sk_usbhid
*
173 sk_open(const char *path
)
175 struct sk_usbhid
*sk
;
179 skdebug(__func__
, "path == NULL");
182 if ((sk
= calloc(1, sizeof(*sk
))) == NULL
) {
183 skdebug(__func__
, "calloc sk failed");
186 if ((sk
->path
= strdup(path
)) == NULL
) {
187 skdebug(__func__
, "strdup path failed");
191 if ((sk
->dev
= fido_dev_new()) == NULL
) {
192 skdebug(__func__
, "fido_dev_new failed");
197 if ((r
= fido_dev_open(sk
->dev
, sk
->path
)) != FIDO_OK
) {
198 skdebug(__func__
, "fido_dev_open %s failed: %s", sk
->path
,
200 fido_dev_free(&sk
->dev
);
209 sk_close(struct sk_usbhid
*sk
)
213 fido_dev_cancel(sk
->dev
); /* cancel any pending operation */
214 fido_dev_close(sk
->dev
);
215 fido_dev_free(&sk
->dev
);
220 static struct sk_usbhid
**
221 sk_openv(const fido_dev_info_t
*devlist
, size_t ndevs
, size_t *nopen
)
223 const fido_dev_info_t
*di
;
224 struct sk_usbhid
**skv
;
228 if ((skv
= calloc(ndevs
, sizeof(*skv
))) == NULL
) {
229 skdebug(__func__
, "calloc skv failed");
232 for (i
= 0; i
< ndevs
; i
++) {
233 if ((di
= fido_dev_info_ptr(devlist
, i
)) == NULL
)
234 skdebug(__func__
, "fido_dev_info_ptr failed");
235 else if ((skv
[*nopen
] = sk_open(fido_dev_info_path(di
))) == NULL
)
236 skdebug(__func__
, "sk_open failed");
241 for (i
= 0; i
< ndevs
; i
++)
251 sk_closev(struct sk_usbhid
**skv
, size_t nsk
)
255 for (i
= 0; i
< nsk
; i
++)
261 sk_touch_begin(struct sk_usbhid
**skv
, size_t nsk
)
266 for (i
= 0; i
< nsk
; i
++)
267 if ((r
= fido_dev_get_touch_begin(skv
[i
]->dev
)) != FIDO_OK
)
268 skdebug(__func__
, "fido_dev_get_touch_begin %s failed:"
269 " %s", skv
[i
]->path
, fido_strerr(r
));
277 sk_touch_poll(struct sk_usbhid
**skv
, size_t nsk
, int *touch
, size_t *idx
)
279 struct timespec ts_pause
;
284 ts_pause
.tv_nsec
= POLL_SLEEP_NS
;
285 nanosleep(&ts_pause
, NULL
);
287 for (i
= 0; i
< nsk
; i
++) {
289 continue; /* device discarded */
290 skdebug(__func__
, "polling %s", skv
[i
]->path
);
291 if ((r
= fido_dev_get_touch_status(skv
[i
]->dev
, touch
,
292 FIDO_POLL_MS
)) != FIDO_OK
) {
293 skdebug(__func__
, "fido_dev_get_touch_status %s: %s",
294 skv
[i
]->path
, fido_strerr(r
));
295 sk_close(skv
[i
]); /* discard device */
298 skdebug(__func__
, "no device left to poll");
310 #if !defined(HAVE_FIDO_ASSERT_SET_CLIENTDATA) || \
311 !defined(HAVE_FIDO_CRED_SET_CLIENTDATA)
312 /* Calculate SHA256(m) */
314 sha256_mem(const void *m
, size_t mlen
, u_char
*d
, size_t dlen
)
326 if (!EVP_Digest(m
, mlen
, d
, &mdlen
, EVP_sha256(), NULL
))
330 SHA256Update(&ctx
, (const uint8_t *)m
, mlen
);
331 SHA256Final(d
, &ctx
);
335 #endif /* !HAVE_FIDO_ASSERT_SET_CLIENTDATA || !HAVE_FIDO_CRED_SET_CLIENTDATA */
337 #ifndef HAVE_FIDO_CRED_SET_CLIENTDATA
339 fido_cred_set_clientdata(fido_cred_t
*cred
, const u_char
*ptr
, size_t len
)
344 if (sha256_mem(ptr
, len
, d
, sizeof(d
)) != 0) {
345 skdebug(__func__
, "hash challenge failed");
346 return FIDO_ERR_INTERNAL
;
348 r
= fido_cred_set_clientdata_hash(cred
, d
, sizeof(d
));
349 explicit_bzero(d
, sizeof(d
));
351 skdebug(__func__
, "fido_cred_set_clientdata_hash failed: %s",
356 #endif /* HAVE_FIDO_CRED_SET_CLIENTDATA */
358 #ifndef HAVE_FIDO_ASSERT_SET_CLIENTDATA
360 fido_assert_set_clientdata(fido_assert_t
*assert, const u_char
*ptr
, size_t len
)
365 if (sha256_mem(ptr
, len
, d
, sizeof(d
)) != 0) {
366 skdebug(__func__
, "hash challenge failed");
367 return FIDO_ERR_INTERNAL
;
369 r
= fido_assert_set_clientdata_hash(assert, d
, sizeof(d
));
370 explicit_bzero(d
, sizeof(d
));
372 skdebug(__func__
, "fido_assert_set_clientdata_hash failed: %s",
377 #endif /* HAVE_FIDO_ASSERT_SET_CLIENTDATA */
379 #ifndef HAVE_FIDO_DEV_IS_WINHELLO
381 fido_dev_is_winhello(const fido_dev_t
*fdev
)
385 #endif /* HAVE_FIDO_DEV_IS_WINHELLO */
387 /* Check if the specified key handle exists on a given sk. */
389 sk_try(const struct sk_usbhid
*sk
, const char *application
,
390 const uint8_t *key_handle
, size_t key_handle_len
)
392 fido_assert_t
*assert = NULL
;
393 int r
= FIDO_ERR_INTERNAL
;
396 memset(message
, '\0', sizeof(message
));
397 if ((assert = fido_assert_new()) == NULL
) {
398 skdebug(__func__
, "fido_assert_new failed");
401 /* generate an invalid signature on FIDO2 tokens */
402 if ((r
= fido_assert_set_clientdata(assert, message
,
403 sizeof(message
))) != FIDO_OK
) {
404 skdebug(__func__
, "fido_assert_set_clientdata: %s",
408 if ((r
= fido_assert_set_rp(assert, application
)) != FIDO_OK
) {
409 skdebug(__func__
, "fido_assert_set_rp: %s", fido_strerr(r
));
412 if ((r
= fido_assert_allow_cred(assert, key_handle
,
413 key_handle_len
)) != FIDO_OK
) {
414 skdebug(__func__
, "fido_assert_allow_cred: %s", fido_strerr(r
));
417 if ((r
= fido_assert_set_up(assert, FIDO_OPT_FALSE
)) != FIDO_OK
) {
418 skdebug(__func__
, "fido_assert_up: %s", fido_strerr(r
));
421 r
= fido_dev_get_assert(sk
->dev
, assert, NULL
);
422 skdebug(__func__
, "fido_dev_get_assert: %s", fido_strerr(r
));
423 if (r
== FIDO_ERR_USER_PRESENCE_REQUIRED
) {
424 /* U2F tokens may return this */
428 fido_assert_free(&assert);
430 return r
!= FIDO_OK
? -1 : 0;
434 check_sk_options(fido_dev_t
*dev
, const char *opt
, int *ret
)
436 fido_cbor_info_t
*info
;
444 if (!fido_dev_is_fido2(dev
)) {
445 skdebug(__func__
, "device is not fido2");
448 if ((info
= fido_cbor_info_new()) == NULL
) {
449 skdebug(__func__
, "fido_cbor_info_new failed");
452 if ((r
= fido_dev_get_cbor_info(dev
, info
)) != FIDO_OK
) {
453 skdebug(__func__
, "fido_dev_get_cbor_info: %s", fido_strerr(r
));
454 fido_cbor_info_free(&info
);
457 name
= fido_cbor_info_options_name_ptr(info
);
458 value
= fido_cbor_info_options_value_ptr(info
);
459 len
= fido_cbor_info_options_len(info
);
460 for (i
= 0; i
< len
; i
++) {
461 if (!strcmp(name
[i
], opt
)) {
466 fido_cbor_info_free(&info
);
468 skdebug(__func__
, "option %s is unknown", opt
);
470 skdebug(__func__
, "option %s is %s", opt
, *ret
? "on" : "off");
475 static struct sk_usbhid
*
476 sk_select_by_cred(const fido_dev_info_t
*devlist
, size_t ndevs
,
477 const char *application
, const uint8_t *key_handle
, size_t key_handle_len
)
479 struct sk_usbhid
**skv
, *sk
;
483 if ((skv
= sk_openv(devlist
, ndevs
, &skvcnt
)) == NULL
) {
484 skdebug(__func__
, "sk_openv failed");
487 if (skvcnt
== 1 && check_sk_options(skv
[0]->dev
, "uv",
488 &internal_uv
) == 0 && internal_uv
!= -1) {
494 for (i
= 0; i
< skvcnt
; i
++) {
495 if (sk_try(skv
[i
], application
, key_handle
,
496 key_handle_len
) == 0) {
499 skdebug(__func__
, "found key in %s", sk
->path
);
504 sk_closev(skv
, skvcnt
);
508 static struct sk_usbhid
*
509 sk_select_by_touch(const fido_dev_info_t
*devlist
, size_t ndevs
)
511 struct sk_usbhid
**skv
, *sk
;
512 struct timeval tv_start
, tv_now
, tv_delta
;
514 int touch
, ms_remain
;
516 if ((skv
= sk_openv(devlist
, ndevs
, &skvcnt
)) == NULL
) {
517 skdebug(__func__
, "sk_openv failed");
523 /* single candidate */
529 #ifndef HAVE_FIDO_DEV_GET_TOUCH_STATUS
530 skdebug(__func__
, "libfido2 version does not support a feature needed for multiple tokens. Please upgrade to >=1.5.0");
534 if (sk_touch_begin(skv
, skvcnt
) == -1) {
535 skdebug(__func__
, "sk_touch_begin failed");
538 monotime_tv(&tv_start
);
540 if (sk_touch_poll(skv
, skvcnt
, &touch
, &idx
) == -1) {
541 skdebug(__func__
, "sk_touch_poll failed");
549 monotime_tv(&tv_now
);
550 timersub(&tv_now
, &tv_start
, &tv_delta
);
551 ms_remain
= SELECT_MS
- tv_delta
.tv_sec
* 1000 -
552 tv_delta
.tv_usec
/ 1000;
553 } while (ms_remain
>= FIDO_POLL_MS
);
554 skdebug(__func__
, "timeout");
556 sk_closev(skv
, skvcnt
);
560 static struct sk_usbhid
*
561 sk_probe(const char *application
, const uint8_t *key_handle
,
562 size_t key_handle_len
, int probe_resident
)
564 struct sk_usbhid
*sk
;
565 fido_dev_info_t
*devlist
;
570 if (!probe_resident
&& (sk
= sk_open("windows://hello")) != NULL
)
572 #endif /* HAVE_CYGWIN */
573 if ((devlist
= fido_dev_info_new(MAX_FIDO_DEVICES
)) == NULL
) {
574 skdebug(__func__
, "fido_dev_info_new failed");
577 if ((r
= fido_dev_info_manifest(devlist
, MAX_FIDO_DEVICES
,
578 &ndevs
)) != FIDO_OK
) {
579 skdebug(__func__
, "fido_dev_info_manifest failed: %s",
581 fido_dev_info_free(&devlist
, MAX_FIDO_DEVICES
);
584 skdebug(__func__
, "%zu device(s) detected", ndevs
);
587 } else if (application
!= NULL
&& key_handle
!= NULL
) {
588 skdebug(__func__
, "selecting sk by cred");
589 sk
= sk_select_by_cred(devlist
, ndevs
, application
, key_handle
,
592 skdebug(__func__
, "selecting sk by touch");
593 sk
= sk_select_by_touch(devlist
, ndevs
);
595 fido_dev_info_free(&devlist
, MAX_FIDO_DEVICES
);
601 * The key returned via fido_cred_pubkey_ptr() is in affine coordinates,
602 * but the API expects a SEC1 octet string.
605 pack_public_key_ecdsa(const fido_cred_t
*cred
,
606 struct sk_enroll_response
*response
)
609 BIGNUM
*x
= NULL
, *y
= NULL
;
614 response
->public_key
= NULL
;
615 response
->public_key_len
= 0;
617 if ((x
= BN_new()) == NULL
||
618 (y
= BN_new()) == NULL
||
619 (g
= EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1
)) == NULL
||
620 (q
= EC_POINT_new(g
)) == NULL
) {
621 skdebug(__func__
, "libcrypto setup failed");
624 if ((ptr
= fido_cred_pubkey_ptr(cred
)) == NULL
) {
625 skdebug(__func__
, "fido_cred_pubkey_ptr failed");
628 if (fido_cred_pubkey_len(cred
) != 64) {
629 skdebug(__func__
, "bad fido_cred_pubkey_len %zu",
630 fido_cred_pubkey_len(cred
));
634 if (BN_bin2bn(ptr
, 32, x
) == NULL
||
635 BN_bin2bn(ptr
+ 32, 32, y
) == NULL
) {
636 skdebug(__func__
, "BN_bin2bn failed");
639 if (EC_POINT_set_affine_coordinates_GFp(g
, q
, x
, y
, NULL
) != 1) {
640 skdebug(__func__
, "EC_POINT_set_affine_coordinates_GFp failed");
643 response
->public_key_len
= EC_POINT_point2oct(g
, q
,
644 POINT_CONVERSION_UNCOMPRESSED
, NULL
, 0, NULL
);
645 if (response
->public_key_len
== 0 || response
->public_key_len
> 2048) {
646 skdebug(__func__
, "bad pubkey length %zu",
647 response
->public_key_len
);
650 if ((response
->public_key
= malloc(response
->public_key_len
)) == NULL
) {
651 skdebug(__func__
, "malloc pubkey failed");
654 if (EC_POINT_point2oct(g
, q
, POINT_CONVERSION_UNCOMPRESSED
,
655 response
->public_key
, response
->public_key_len
, NULL
) == 0) {
656 skdebug(__func__
, "EC_POINT_point2oct failed");
662 if (ret
!= 0 && response
->public_key
!= NULL
) {
663 memset(response
->public_key
, 0, response
->public_key_len
);
664 free(response
->public_key
);
665 response
->public_key
= NULL
;
673 #endif /* WITH_OPENSSL */
676 pack_public_key_ed25519(const fido_cred_t
*cred
,
677 struct sk_enroll_response
*response
)
683 response
->public_key
= NULL
;
684 response
->public_key_len
= 0;
686 if ((len
= fido_cred_pubkey_len(cred
)) != 32) {
687 skdebug(__func__
, "bad fido_cred_pubkey_len len %zu", len
);
690 if ((ptr
= fido_cred_pubkey_ptr(cred
)) == NULL
) {
691 skdebug(__func__
, "fido_cred_pubkey_ptr failed");
694 response
->public_key_len
= len
;
695 if ((response
->public_key
= malloc(response
->public_key_len
)) == NULL
) {
696 skdebug(__func__
, "malloc pubkey failed");
699 memcpy(response
->public_key
, ptr
, len
);
703 free(response
->public_key
);
708 pack_public_key(uint32_t alg
, const fido_cred_t
*cred
,
709 struct sk_enroll_response
*response
)
714 return pack_public_key_ecdsa(cred
, response
);
715 #endif /* WITH_OPENSSL */
717 return pack_public_key_ed25519(cred
, response
);
724 fidoerr_to_skerr(int fidoerr
)
727 case FIDO_ERR_UNSUPPORTED_OPTION
:
728 case FIDO_ERR_UNSUPPORTED_ALGORITHM
:
729 return SSH_SK_ERR_UNSUPPORTED
;
730 case FIDO_ERR_PIN_REQUIRED
:
731 case FIDO_ERR_PIN_INVALID
:
732 case FIDO_ERR_OPERATION_DENIED
:
733 return SSH_SK_ERR_PIN_REQUIRED
;
740 check_enroll_options(struct sk_option
**options
, char **devicep
,
741 uint8_t *user_id
, size_t user_id_len
)
747 for (i
= 0; options
[i
] != NULL
; i
++) {
748 if (strcmp(options
[i
]->name
, "device") == 0) {
749 if ((*devicep
= strdup(options
[i
]->value
)) == NULL
) {
750 skdebug(__func__
, "strdup device failed");
753 skdebug(__func__
, "requested device %s", *devicep
);
754 } else if (strcmp(options
[i
]->name
, "user") == 0) {
755 if (strlcpy(user_id
, options
[i
]->value
, user_id_len
) >=
757 skdebug(__func__
, "user too long");
760 skdebug(__func__
, "requested user %s",
763 skdebug(__func__
, "requested unsupported option %s",
765 if (options
[i
]->required
) {
766 skdebug(__func__
, "unknown required option");
775 key_lookup(fido_dev_t
*dev
, const char *application
, const uint8_t *user_id
,
776 size_t user_id_len
, const char *pin
)
778 fido_assert_t
*assert = NULL
;
780 int r
= FIDO_ERR_INTERNAL
;
781 int sk_supports_uv
, uv
;
784 memset(message
, '\0', sizeof(message
));
785 if ((assert = fido_assert_new()) == NULL
) {
786 skdebug(__func__
, "fido_assert_new failed");
789 /* generate an invalid signature on FIDO2 tokens */
790 if ((r
= fido_assert_set_clientdata(assert, message
,
791 sizeof(message
))) != FIDO_OK
) {
792 skdebug(__func__
, "fido_assert_set_clientdata: %s",
796 if ((r
= fido_assert_set_rp(assert, application
)) != FIDO_OK
) {
797 skdebug(__func__
, "fido_assert_set_rp: %s", fido_strerr(r
));
800 if ((r
= fido_assert_set_up(assert, FIDO_OPT_FALSE
)) != FIDO_OK
) {
801 skdebug(__func__
, "fido_assert_set_up: %s", fido_strerr(r
));
805 if (pin
== NULL
&& check_sk_options(dev
, "uv", &sk_supports_uv
) == 0 &&
806 sk_supports_uv
!= -1)
808 if ((r
= fido_assert_set_uv(assert, uv
)) != FIDO_OK
) {
809 skdebug(__func__
, "fido_assert_set_uv: %s", fido_strerr(r
));
812 if ((r
= fido_dev_get_assert(dev
, assert, pin
)) != FIDO_OK
) {
813 skdebug(__func__
, "fido_dev_get_assert: %s", fido_strerr(r
));
816 r
= FIDO_ERR_NO_CREDENTIALS
;
817 skdebug(__func__
, "%zu signatures returned", fido_assert_count(assert));
818 for (i
= 0; i
< fido_assert_count(assert); i
++) {
819 if (fido_assert_user_id_len(assert, i
) == user_id_len
&&
820 memcmp(fido_assert_user_id_ptr(assert, i
), user_id
,
822 skdebug(__func__
, "credential exists");
828 fido_assert_free(&assert);
834 sk_enroll(uint32_t alg
, const uint8_t *challenge
, size_t challenge_len
,
835 const char *application
, uint8_t flags
, const char *pin
,
836 struct sk_option
**options
, struct sk_enroll_response
**enroll_response
)
838 fido_cred_t
*cred
= NULL
;
841 struct sk_usbhid
*sk
= NULL
;
842 struct sk_enroll_response
*response
= NULL
;
846 int ret
= SSH_SK_ERR_GENERAL
;
850 fido_init(SSH_FIDO_INIT_ARG
);
852 if (enroll_response
== NULL
) {
853 skdebug(__func__
, "enroll_response == NULL");
856 *enroll_response
= NULL
;
857 memset(user_id
, 0, sizeof(user_id
));
858 if (check_enroll_options(options
, &device
, user_id
,
859 sizeof(user_id
)) != 0)
860 goto out
; /* error already logged */
865 cose_alg
= COSE_ES256
;
867 #endif /* WITH_OPENSSL */
869 cose_alg
= COSE_EDDSA
;
872 skdebug(__func__
, "unsupported key type %d", alg
);
876 sk
= sk_open(device
);
878 sk
= sk_probe(NULL
, NULL
, 0, 0);
880 ret
= SSH_SK_ERR_DEVICE_NOT_FOUND
;
881 skdebug(__func__
, "failed to find sk");
884 skdebug(__func__
, "using device %s", sk
->path
);
885 if ((flags
& SSH_SK_RESIDENT_KEY
) != 0 &&
886 (flags
& SSH_SK_FORCE_OPERATION
) == 0 &&
887 (r
= key_lookup(sk
->dev
, application
, user_id
, sizeof(user_id
),
888 pin
)) != FIDO_ERR_NO_CREDENTIALS
) {
890 ret
= fidoerr_to_skerr(r
);
891 skdebug(__func__
, "key_lookup failed");
893 ret
= SSH_SK_ERR_CREDENTIAL_EXISTS
;
894 skdebug(__func__
, "key exists");
898 if ((cred
= fido_cred_new()) == NULL
) {
899 skdebug(__func__
, "fido_cred_new failed");
902 if ((r
= fido_cred_set_type(cred
, cose_alg
)) != FIDO_OK
) {
903 skdebug(__func__
, "fido_cred_set_type: %s", fido_strerr(r
));
906 if ((r
= fido_cred_set_clientdata(cred
,
907 challenge
, challenge_len
)) != FIDO_OK
) {
908 skdebug(__func__
, "fido_cred_set_clientdata: %s",
912 if ((r
= fido_cred_set_rk(cred
, (flags
& SSH_SK_RESIDENT_KEY
) != 0 ?
913 FIDO_OPT_TRUE
: FIDO_OPT_OMIT
)) != FIDO_OK
) {
914 skdebug(__func__
, "fido_cred_set_rk: %s", fido_strerr(r
));
917 if ((r
= fido_cred_set_user(cred
, user_id
, sizeof(user_id
),
918 "openssh", "openssh", NULL
)) != FIDO_OK
) {
919 skdebug(__func__
, "fido_cred_set_user: %s", fido_strerr(r
));
922 if ((r
= fido_cred_set_rp(cred
, application
, NULL
)) != FIDO_OK
) {
923 skdebug(__func__
, "fido_cred_set_rp: %s", fido_strerr(r
));
926 if ((flags
& (SSH_SK_RESIDENT_KEY
|SSH_SK_USER_VERIFICATION_REQD
)) != 0) {
927 #if !defined(HAVE_FIDO_DEV_SUPPORTS_CRED_PROT) || \
928 !defined(HAVE_FIDO_CRED_SET_PROT)
929 skdebug(__func__
, "libfido2 version does not support a feature required for this operation. Please upgrade to >=1.5.0");
930 ret
= SSH_SK_ERR_UNSUPPORTED
;
932 credprot
= 0; (void)credprot
; /* avoid warning */
934 if (!fido_dev_supports_cred_prot(sk
->dev
)) {
935 skdebug(__func__
, "%s does not support credprot, "
936 "refusing to create unprotected "
937 "resident/verify-required key", sk
->path
);
938 ret
= SSH_SK_ERR_UNSUPPORTED
;
941 if ((flags
& SSH_SK_USER_VERIFICATION_REQD
))
942 credprot
= FIDO_CRED_PROT_UV_REQUIRED
;
944 credprot
= FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID
;
946 if ((r
= fido_cred_set_prot(cred
, credprot
)) != FIDO_OK
) {
947 skdebug(__func__
, "fido_cred_set_prot: %s",
949 ret
= fidoerr_to_skerr(r
);
953 if ((r
= fido_dev_make_cred(sk
->dev
, cred
, pin
)) != FIDO_OK
) {
954 skdebug(__func__
, "fido_dev_make_cred: %s", fido_strerr(r
));
955 ret
= fidoerr_to_skerr(r
);
958 if (fido_cred_x5c_ptr(cred
) != NULL
) {
959 if ((r
= fido_cred_verify(cred
)) != FIDO_OK
) {
960 skdebug(__func__
, "fido_cred_verify: %s",
964 } else if (strcmp(fido_cred_fmt(cred
), "none") != 0) {
965 skdebug(__func__
, "self-attested credential");
966 if ((r
= fido_cred_verify_self(cred
)) != FIDO_OK
) {
967 skdebug(__func__
, "fido_cred_verify_self: %s",
972 skdebug(__func__
, "no attestation data");
974 if ((response
= calloc(1, sizeof(*response
))) == NULL
) {
975 skdebug(__func__
, "calloc response failed");
978 response
->flags
= flags
;
979 if (pack_public_key(alg
, cred
, response
) != 0) {
980 skdebug(__func__
, "pack_public_key failed");
983 if ((ptr
= fido_cred_id_ptr(cred
)) != NULL
) {
984 len
= fido_cred_id_len(cred
);
985 if ((response
->key_handle
= calloc(1, len
)) == NULL
) {
986 skdebug(__func__
, "calloc key handle failed");
989 memcpy(response
->key_handle
, ptr
, len
);
990 response
->key_handle_len
= len
;
992 if ((ptr
= fido_cred_sig_ptr(cred
)) != NULL
) {
993 len
= fido_cred_sig_len(cred
);
994 if ((response
->signature
= calloc(1, len
)) == NULL
) {
995 skdebug(__func__
, "calloc signature failed");
998 memcpy(response
->signature
, ptr
, len
);
999 response
->signature_len
= len
;
1001 if ((ptr
= fido_cred_x5c_ptr(cred
)) != NULL
) {
1002 len
= fido_cred_x5c_len(cred
);
1003 skdebug(__func__
, "attestation cert len=%zu", len
);
1004 if ((response
->attestation_cert
= calloc(1, len
)) == NULL
) {
1005 skdebug(__func__
, "calloc attestation cert failed");
1008 memcpy(response
->attestation_cert
, ptr
, len
);
1009 response
->attestation_cert_len
= len
;
1011 if ((ptr
= fido_cred_authdata_ptr(cred
)) != NULL
) {
1012 len
= fido_cred_authdata_len(cred
);
1013 skdebug(__func__
, "authdata len=%zu", len
);
1014 if ((response
->authdata
= calloc(1, len
)) == NULL
) {
1015 skdebug(__func__
, "calloc authdata failed");
1018 memcpy(response
->authdata
, ptr
, len
);
1019 response
->authdata_len
= len
;
1021 *enroll_response
= response
;
1026 if (response
!= NULL
) {
1027 free(response
->public_key
);
1028 free(response
->key_handle
);
1029 free(response
->signature
);
1030 free(response
->attestation_cert
);
1031 free(response
->authdata
);
1035 fido_cred_free(&cred
);
1041 pack_sig_ecdsa(fido_assert_t
*assert, struct sk_sign_response
*response
)
1043 ECDSA_SIG
*sig
= NULL
;
1044 const BIGNUM
*sig_r
, *sig_s
;
1045 const unsigned char *cp
;
1049 cp
= fido_assert_sig_ptr(assert, 0);
1050 sig_len
= fido_assert_sig_len(assert, 0);
1051 if ((sig
= d2i_ECDSA_SIG(NULL
, &cp
, sig_len
)) == NULL
) {
1052 skdebug(__func__
, "d2i_ECDSA_SIG failed");
1055 ECDSA_SIG_get0(sig
, &sig_r
, &sig_s
);
1056 response
->sig_r_len
= BN_num_bytes(sig_r
);
1057 response
->sig_s_len
= BN_num_bytes(sig_s
);
1058 if ((response
->sig_r
= calloc(1, response
->sig_r_len
)) == NULL
||
1059 (response
->sig_s
= calloc(1, response
->sig_s_len
)) == NULL
) {
1060 skdebug(__func__
, "calloc signature failed");
1063 BN_bn2bin(sig_r
, response
->sig_r
);
1064 BN_bn2bin(sig_s
, response
->sig_s
);
1067 ECDSA_SIG_free(sig
);
1069 free(response
->sig_r
);
1070 free(response
->sig_s
);
1071 response
->sig_r
= NULL
;
1072 response
->sig_s
= NULL
;
1076 #endif /* WITH_OPENSSL */
1079 pack_sig_ed25519(fido_assert_t
*assert, struct sk_sign_response
*response
)
1081 const unsigned char *ptr
;
1085 ptr
= fido_assert_sig_ptr(assert, 0);
1086 len
= fido_assert_sig_len(assert, 0);
1088 skdebug(__func__
, "bad length %zu", len
);
1091 response
->sig_r_len
= len
;
1092 if ((response
->sig_r
= calloc(1, response
->sig_r_len
)) == NULL
) {
1093 skdebug(__func__
, "calloc signature failed");
1096 memcpy(response
->sig_r
, ptr
, len
);
1100 free(response
->sig_r
);
1101 response
->sig_r
= NULL
;
1107 pack_sig(uint32_t alg
, fido_assert_t
*assert,
1108 struct sk_sign_response
*response
)
1113 return pack_sig_ecdsa(assert, response
);
1114 #endif /* WITH_OPENSSL */
1115 case SSH_SK_ED25519
:
1116 return pack_sig_ed25519(assert, response
);
1122 /* Checks sk_options for sk_sign() and sk_load_resident_keys() */
1124 check_sign_load_resident_options(struct sk_option
**options
, char **devicep
)
1128 if (options
== NULL
)
1130 for (i
= 0; options
[i
] != NULL
; i
++) {
1131 if (strcmp(options
[i
]->name
, "device") == 0) {
1132 if ((*devicep
= strdup(options
[i
]->value
)) == NULL
) {
1133 skdebug(__func__
, "strdup device failed");
1136 skdebug(__func__
, "requested device %s", *devicep
);
1138 skdebug(__func__
, "requested unsupported option %s",
1140 if (options
[i
]->required
) {
1141 skdebug(__func__
, "unknown required option");
1150 sk_sign(uint32_t alg
, const uint8_t *data
, size_t datalen
,
1151 const char *application
,
1152 const uint8_t *key_handle
, size_t key_handle_len
,
1153 uint8_t flags
, const char *pin
, struct sk_option
**options
,
1154 struct sk_sign_response
**sign_response
)
1156 fido_assert_t
*assert = NULL
;
1157 char *device
= NULL
;
1158 struct sk_usbhid
*sk
= NULL
;
1159 struct sk_sign_response
*response
= NULL
;
1160 int ret
= SSH_SK_ERR_GENERAL
, internal_uv
;
1163 fido_init(SSH_FIDO_INIT_ARG
);
1165 if (sign_response
== NULL
) {
1166 skdebug(__func__
, "sign_response == NULL");
1169 *sign_response
= NULL
;
1170 if (check_sign_load_resident_options(options
, &device
) != 0)
1171 goto out
; /* error already logged */
1173 sk
= sk_open(device
);
1174 else if (pin
!= NULL
|| (flags
& SSH_SK_USER_VERIFICATION_REQD
))
1175 sk
= sk_probe(NULL
, NULL
, 0, 0);
1177 sk
= sk_probe(application
, key_handle
, key_handle_len
, 0);
1179 ret
= SSH_SK_ERR_DEVICE_NOT_FOUND
;
1180 skdebug(__func__
, "failed to find sk");
1183 if ((assert = fido_assert_new()) == NULL
) {
1184 skdebug(__func__
, "fido_assert_new failed");
1187 if ((r
= fido_assert_set_clientdata(assert,
1188 data
, datalen
)) != FIDO_OK
) {
1189 skdebug(__func__
, "fido_assert_set_clientdata: %s",
1193 if ((r
= fido_assert_set_rp(assert, application
)) != FIDO_OK
) {
1194 skdebug(__func__
, "fido_assert_set_rp: %s", fido_strerr(r
));
1197 if ((r
= fido_assert_allow_cred(assert, key_handle
,
1198 key_handle_len
)) != FIDO_OK
) {
1199 skdebug(__func__
, "fido_assert_allow_cred: %s", fido_strerr(r
));
1202 if ((r
= fido_assert_set_up(assert,
1203 (flags
& SSH_SK_USER_PRESENCE_REQD
) ?
1204 FIDO_OPT_TRUE
: FIDO_OPT_FALSE
)) != FIDO_OK
) {
1205 skdebug(__func__
, "fido_assert_set_up: %s", fido_strerr(r
));
1209 * WinHello requests the PIN by default. Make "uv" request explicit
1210 * to allow keys with and without -O verify-required to make sense.
1212 if (pin
== NULL
&& fido_dev_is_winhello (sk
->dev
) &&
1213 (r
= fido_assert_set_uv(assert, FIDO_OPT_FALSE
)) != FIDO_OK
) {
1214 skdebug(__func__
, "fido_assert_set_uv: %s", fido_strerr(r
));
1216 if (pin
== NULL
&& (flags
& SSH_SK_USER_VERIFICATION_REQD
)) {
1217 if (check_sk_options(sk
->dev
, "uv", &internal_uv
) < 0 ||
1219 skdebug(__func__
, "check_sk_options uv");
1220 ret
= SSH_SK_ERR_PIN_REQUIRED
;
1223 if ((r
= fido_assert_set_uv(assert,
1224 FIDO_OPT_TRUE
)) != FIDO_OK
) {
1225 skdebug(__func__
, "fido_assert_set_uv: %s",
1227 ret
= fidoerr_to_skerr(r
);
1231 if ((r
= fido_dev_get_assert(sk
->dev
, assert, pin
)) != FIDO_OK
) {
1232 skdebug(__func__
, "fido_dev_get_assert: %s", fido_strerr(r
));
1233 ret
= fidoerr_to_skerr(r
);
1236 if ((response
= calloc(1, sizeof(*response
))) == NULL
) {
1237 skdebug(__func__
, "calloc response failed");
1240 response
->flags
= fido_assert_flags(assert, 0);
1241 response
->counter
= fido_assert_sigcount(assert, 0);
1242 if (pack_sig(alg
, assert, response
) != 0) {
1243 skdebug(__func__
, "pack_sig failed");
1246 *sign_response
= response
;
1251 if (response
!= NULL
) {
1252 free(response
->sig_r
);
1253 free(response
->sig_s
);
1257 fido_assert_free(&assert);
1262 read_rks(struct sk_usbhid
*sk
, const char *pin
,
1263 struct sk_resident_key
***rksp
, size_t *nrksp
)
1265 int ret
= SSH_SK_ERR_GENERAL
, r
= -1, internal_uv
;
1266 fido_credman_metadata_t
*metadata
= NULL
;
1267 fido_credman_rp_t
*rp
= NULL
;
1268 fido_credman_rk_t
*rk
= NULL
;
1269 size_t i
, j
, nrp
, nrk
, user_id_len
;
1270 const fido_cred_t
*cred
;
1271 const char *rp_id
, *rp_name
, *user_name
;
1272 struct sk_resident_key
*srk
= NULL
, **tmp
;
1273 const u_char
*user_id
;
1276 skdebug(__func__
, "no PIN specified");
1277 ret
= SSH_SK_ERR_PIN_REQUIRED
;
1280 if ((metadata
= fido_credman_metadata_new()) == NULL
) {
1281 skdebug(__func__
, "alloc failed");
1284 if (check_sk_options(sk
->dev
, "uv", &internal_uv
) != 0) {
1285 skdebug(__func__
, "check_sk_options failed");
1289 if ((r
= fido_credman_get_dev_metadata(sk
->dev
, metadata
, pin
)) != 0) {
1290 if (r
== FIDO_ERR_INVALID_COMMAND
) {
1291 skdebug(__func__
, "device %s does not support "
1292 "resident keys", sk
->path
);
1296 skdebug(__func__
, "get metadata for %s failed: %s",
1297 sk
->path
, fido_strerr(r
));
1298 ret
= fidoerr_to_skerr(r
);
1301 skdebug(__func__
, "existing %llu, remaining %llu",
1302 (unsigned long long)fido_credman_rk_existing(metadata
),
1303 (unsigned long long)fido_credman_rk_remaining(metadata
));
1304 if ((rp
= fido_credman_rp_new()) == NULL
) {
1305 skdebug(__func__
, "alloc rp failed");
1308 if ((r
= fido_credman_get_dev_rp(sk
->dev
, rp
, pin
)) != 0) {
1309 skdebug(__func__
, "get RPs for %s failed: %s",
1310 sk
->path
, fido_strerr(r
));
1313 nrp
= fido_credman_rp_count(rp
);
1314 skdebug(__func__
, "Device %s has resident keys for %zu RPs",
1317 /* Iterate over RP IDs that have resident keys */
1318 for (i
= 0; i
< nrp
; i
++) {
1319 rp_id
= fido_credman_rp_id(rp
, i
);
1320 rp_name
= fido_credman_rp_name(rp
, i
);
1321 skdebug(__func__
, "rp %zu: name=\"%s\" id=\"%s\" hashlen=%zu",
1322 i
, rp_name
== NULL
? "(none)" : rp_name
,
1323 rp_id
== NULL
? "(none)" : rp_id
,
1324 fido_credman_rp_id_hash_len(rp
, i
));
1326 /* Skip non-SSH RP IDs */
1327 if (rp_id
== NULL
||
1328 strncasecmp(fido_credman_rp_id(rp
, i
), "ssh:", 4) != 0)
1331 fido_credman_rk_free(&rk
);
1332 if ((rk
= fido_credman_rk_new()) == NULL
) {
1333 skdebug(__func__
, "alloc rk failed");
1336 if ((r
= fido_credman_get_dev_rk(sk
->dev
,
1337 fido_credman_rp_id(rp
, i
), rk
, pin
)) != 0) {
1338 skdebug(__func__
, "get RKs for %s slot %zu failed: %s",
1339 sk
->path
, i
, fido_strerr(r
));
1342 nrk
= fido_credman_rk_count(rk
);
1343 skdebug(__func__
, "RP \"%s\" has %zu resident keys",
1344 fido_credman_rp_id(rp
, i
), nrk
);
1346 /* Iterate over resident keys for this RP ID */
1347 for (j
= 0; j
< nrk
; j
++) {
1348 if ((cred
= fido_credman_rk(rk
, j
)) == NULL
) {
1349 skdebug(__func__
, "no RK in slot %zu", j
);
1352 if ((user_name
= fido_cred_user_name(cred
)) == NULL
)
1354 user_id
= fido_cred_user_id_ptr(cred
);
1355 user_id_len
= fido_cred_user_id_len(cred
);
1356 skdebug(__func__
, "Device %s RP \"%s\" user \"%s\" "
1357 "uidlen %zu slot %zu: type %d flags 0x%02x "
1358 "prot 0x%02x", sk
->path
, rp_id
, user_name
,
1359 user_id_len
, j
, fido_cred_type(cred
),
1360 fido_cred_flags(cred
), fido_cred_prot(cred
));
1362 /* build response entry */
1363 if ((srk
= calloc(1, sizeof(*srk
))) == NULL
||
1364 (srk
->key
.key_handle
= calloc(1,
1365 fido_cred_id_len(cred
))) == NULL
||
1366 (srk
->application
= strdup(rp_id
)) == NULL
||
1368 (srk
->user_id
= calloc(1, user_id_len
)) == NULL
)) {
1369 skdebug(__func__
, "alloc sk_resident_key");
1373 srk
->key
.key_handle_len
= fido_cred_id_len(cred
);
1374 memcpy(srk
->key
.key_handle
, fido_cred_id_ptr(cred
),
1375 srk
->key
.key_handle_len
);
1376 srk
->user_id_len
= user_id_len
;
1377 if (srk
->user_id_len
!= 0)
1378 memcpy(srk
->user_id
, user_id
, srk
->user_id_len
);
1380 switch (fido_cred_type(cred
)) {
1382 srk
->alg
= SSH_SK_ECDSA
;
1385 srk
->alg
= SSH_SK_ED25519
;
1388 skdebug(__func__
, "unsupported key type %d",
1389 fido_cred_type(cred
));
1390 goto out
; /* XXX free rk and continue */
1393 if (fido_cred_prot(cred
) == FIDO_CRED_PROT_UV_REQUIRED
1394 && internal_uv
== -1)
1395 srk
->flags
|= SSH_SK_USER_VERIFICATION_REQD
;
1397 if ((r
= pack_public_key(srk
->alg
, cred
,
1399 skdebug(__func__
, "pack public key failed");
1403 if ((tmp
= recallocarray(*rksp
, *nrksp
, (*nrksp
) + 1,
1404 sizeof(**rksp
))) == NULL
) {
1405 skdebug(__func__
, "alloc rksp");
1409 (*rksp
)[(*nrksp
)++] = srk
;
1417 free(srk
->application
);
1418 freezero(srk
->key
.public_key
, srk
->key
.public_key_len
);
1419 freezero(srk
->key
.key_handle
, srk
->key
.key_handle_len
);
1420 freezero(srk
->user_id
, srk
->user_id_len
);
1421 freezero(srk
, sizeof(*srk
));
1423 fido_credman_rp_free(&rp
);
1424 fido_credman_rk_free(&rk
);
1425 fido_credman_metadata_free(&metadata
);
1430 sk_load_resident_keys(const char *pin
, struct sk_option
**options
,
1431 struct sk_resident_key
***rksp
, size_t *nrksp
)
1433 int ret
= SSH_SK_ERR_GENERAL
, r
= -1;
1435 struct sk_resident_key
**rks
= NULL
;
1436 struct sk_usbhid
*sk
= NULL
;
1437 char *device
= NULL
;
1442 fido_init(SSH_FIDO_INIT_ARG
);
1444 if (check_sign_load_resident_options(options
, &device
) != 0)
1445 goto out
; /* error already logged */
1447 sk
= sk_open(device
);
1449 sk
= sk_probe(NULL
, NULL
, 0, 1);
1451 ret
= SSH_SK_ERR_DEVICE_NOT_FOUND
;
1452 skdebug(__func__
, "failed to find sk");
1455 skdebug(__func__
, "trying %s", sk
->path
);
1456 if ((r
= read_rks(sk
, pin
, &rks
, &nrks
)) != 0) {
1457 skdebug(__func__
, "read_rks failed for %s", sk
->path
);
1461 /* success, unless we have no keys but a specific error */
1462 if (nrks
> 0 || ret
== SSH_SK_ERR_GENERAL
)
1470 for (i
= 0; i
< nrks
; i
++) {
1471 free(rks
[i
]->application
);
1472 freezero(rks
[i
]->key
.public_key
, rks
[i
]->key
.public_key_len
);
1473 freezero(rks
[i
]->key
.key_handle
, rks
[i
]->key
.key_handle_len
);
1474 freezero(rks
[i
]->user_id
, rks
[i
]->user_id_len
);
1475 freezero(rks
[i
], sizeof(*rks
[i
]));
1482 #endif /* ENABLE_SK_INTERNAL */