Bug Summary

File:src/usr.bin/ssh/ssh-sk-helper/../sk-usbhid.c
Warning:line 1237, column 9
Although the value stored to 'r' is used in the enclosing expression, the value is never actually read from 'r'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name sk-usbhid.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.bin/ssh/ssh-sk-helper/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.bin/ssh/ssh-sk-helper/.. -D WITH_OPENSSL -D WITH_ZLIB -D ENABLE_PKCS11 -D HAVE_DLOPEN -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -fdebug-compilation-dir=/usr/src/usr.bin/ssh/ssh-sk-helper/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.bin/ssh/ssh-sk-helper/../sk-usbhid.c
1/* $OpenBSD: sk-usbhid.c,v 1.37 2021/12/07 22:06:45 djm Exp $ */
2/*
3 * Copyright (c) 2019 Markus Friedl
4 * Copyright (c) 2020 Pedro Martelletto
5 *
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.
9 *
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.
17 */
18
19#include <stdint.h>
20#include <stdlib.h>
21#include <string.h>
22#include <stdio.h>
23#include <stddef.h>
24#include <stdarg.h>
25#include <sha2.h>
26#include <time.h>
27
28#ifdef WITH_OPENSSL1
29#include <openssl/opensslv.h>
30#include <openssl/crypto.h>
31#include <openssl/bn.h>
32#include <openssl/ec.h>
33#include <openssl/ecdsa.h>
34#include <openssl/evp.h>
35#endif /* WITH_OPENSSL */
36
37#include <fido.h>
38#include <fido/credman.h>
39
40#ifndef SK_STANDALONE
41# include "log.h"
42# include "xmalloc.h"
43# include "misc.h"
44/*
45 * If building as part of OpenSSH, then rename exported functions.
46 * This must be done before including sk-api.h.
47 */
48# define sk_api_versionssh_sk_api_version ssh_sk_api_version
49# define sk_enrollssh_sk_enroll ssh_sk_enroll
50# define sk_signssh_sk_sign ssh_sk_sign
51# define sk_load_resident_keysssh_sk_load_resident_keys ssh_sk_load_resident_keys
52#endif /* !SK_STANDALONE */
53
54#include "sk-api.h"
55
56/* #define SK_DEBUG 1 */
57
58#ifdef SK_DEBUG
59#define SSH_FIDO_INIT_ARG0 FIDO_DEBUG0x01
60#else
61#define SSH_FIDO_INIT_ARG0 0
62#endif
63
64#define MAX_FIDO_DEVICES8 8
65#define FIDO_POLL_MS50 50
66#define SELECT_MS15000 15000
67#define POLL_SLEEP_NS200000000 200000000
68
69/* Compatibility with OpenSSH 1.0.x */
70#if (OPENSSL_VERSION_NUMBER0x20000000L < 0x10100000L)
71#define ECDSA_SIG_get0(sig, pr, ps) \
72 do { \
73 (*pr) = sig->r; \
74 (*ps) = sig->s; \
75 } while (0)
76#endif
77#ifndef FIDO_ERR_OPERATION_DENIED0x27
78#define FIDO_ERR_OPERATION_DENIED0x27 0x27
79#endif
80
81struct sk_usbhid {
82 fido_dev_t *dev;
83 char *path;
84};
85
86/* Return the version of the middleware API */
87uint32_t sk_api_versionssh_sk_api_version(void);
88
89/* Enroll a U2F key (private key generation) */
90int sk_enrollssh_sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len,
91 const char *application, uint8_t flags, const char *pin,
92 struct sk_option **options, struct sk_enroll_response **enroll_response);
93
94/* Sign a challenge */
95int sk_signssh_sk_sign(uint32_t alg, const uint8_t *data, size_t data_len,
96 const char *application, const uint8_t *key_handle, size_t key_handle_len,
97 uint8_t flags, const char *pin, struct sk_option **options,
98 struct sk_sign_response **sign_response);
99
100/* Load resident keys */
101int sk_load_resident_keysssh_sk_load_resident_keys(const char *pin, struct sk_option **options,
102 struct sk_resident_key ***rks, size_t *nrks);
103
104static void skdebug(const char *func, const char *fmt, ...)
105 __attribute__((__format__ (printf, 2, 3)));
106
107static void
108skdebug(const char *func, const char *fmt, ...)
109{
110#if !defined(SK_STANDALONE)
111 char *msg;
112 va_list ap;
113
114 va_start(ap, fmt)__builtin_va_start(ap, fmt);
115 xvasprintf(&msg, fmt, ap);
116 va_end(ap)__builtin_va_end(ap);
117 debug("%s: %s", func, msg)sshlog("/usr/src/usr.bin/ssh/ssh-sk-helper/../sk-usbhid.c", __func__
, 117, 0, SYSLOG_LEVEL_DEBUG1, ((void*)0), "%s: %s", func, msg
)
;
118 free(msg);
119#elif defined(SK_DEBUG)
120 va_list ap;
121
122 va_start(ap, fmt)__builtin_va_start(ap, fmt);
123 fprintf(stderr(&__sF[2]), "%s: ", func);
124 vfprintf(stderr(&__sF[2]), fmt, ap);
125 fputc('\n', stderr(&__sF[2]));
126 va_end(ap)__builtin_va_end(ap);
127#else
128 (void)func; /* XXX */
129 (void)fmt; /* XXX */
130#endif
131}
132
133uint32_t
134sk_api_versionssh_sk_api_version(void)
135{
136 return SSH_SK_VERSION_MAJOR0x00090000;
137}
138
139static struct sk_usbhid *
140sk_open(const char *path)
141{
142 struct sk_usbhid *sk;
143 int r;
144
145 if (path == NULL((void*)0)) {
146 skdebug(__func__, "path == NULL");
147 return NULL((void*)0);
148 }
149 if ((sk = calloc(1, sizeof(*sk))) == NULL((void*)0)) {
150 skdebug(__func__, "calloc sk failed");
151 return NULL((void*)0);
152 }
153 if ((sk->path = strdup(path)) == NULL((void*)0)) {
154 skdebug(__func__, "strdup path failed");
155 free(sk);
156 return NULL((void*)0);
157 }
158 if ((sk->dev = fido_dev_new()) == NULL((void*)0)) {
159 skdebug(__func__, "fido_dev_new failed");
160 free(sk->path);
161 free(sk);
162 return NULL((void*)0);
163 }
164 if ((r = fido_dev_open(sk->dev, sk->path)) != FIDO_OK0x00) {
165 skdebug(__func__, "fido_dev_open %s failed: %s", sk->path,
166 fido_strerr(r));
167 fido_dev_free(&sk->dev);
168 free(sk->path);
169 free(sk);
170 return NULL((void*)0);
171 }
172 return sk;
173}
174
175static void
176sk_close(struct sk_usbhid *sk)
177{
178 if (sk == NULL((void*)0))
179 return;
180 fido_dev_cancel(sk->dev); /* cancel any pending operation */
181 fido_dev_close(sk->dev);
182 fido_dev_free(&sk->dev);
183 free(sk->path);
184 free(sk);
185}
186
187static struct sk_usbhid **
188sk_openv(const fido_dev_info_t *devlist, size_t ndevs, size_t *nopen)
189{
190 const fido_dev_info_t *di;
191 struct sk_usbhid **skv;
192 size_t i;
193
194 *nopen = 0;
195 if ((skv = calloc(ndevs, sizeof(*skv))) == NULL((void*)0)) {
196 skdebug(__func__, "calloc skv failed");
197 return NULL((void*)0);
198 }
199 for (i = 0; i < ndevs; i++) {
200 if ((di = fido_dev_info_ptr(devlist, i)) == NULL((void*)0))
201 skdebug(__func__, "fido_dev_info_ptr failed");
202 else if ((skv[*nopen] = sk_open(fido_dev_info_path(di))) == NULL((void*)0))
203 skdebug(__func__, "sk_open failed");
204 else
205 (*nopen)++;
206 }
207 if (*nopen == 0) {
208 for (i = 0; i < ndevs; i++)
209 sk_close(skv[i]);
210 free(skv);
211 skv = NULL((void*)0);
212 }
213
214 return skv;
215}
216
217static void
218sk_closev(struct sk_usbhid **skv, size_t nsk)
219{
220 size_t i;
221
222 for (i = 0; i < nsk; i++)
223 sk_close(skv[i]);
224 free(skv);
225}
226
227static int
228sk_touch_begin(struct sk_usbhid **skv, size_t nsk)
229{
230 size_t i, ok = 0;
231 int r;
232
233 for (i = 0; i < nsk; i++)
234 if ((r = fido_dev_get_touch_begin(skv[i]->dev)) != FIDO_OK0x00)
235 skdebug(__func__, "fido_dev_get_touch_begin %s failed:"
236 " %s", skv[i]->path, fido_strerr(r));
237 else
238 ok++;
239
240 return ok ? 0 : -1;
241}
242
243static int
244sk_touch_poll(struct sk_usbhid **skv, size_t nsk, int *touch, size_t *idx)
245{
246 struct timespec ts_pause;
247 size_t npoll, i;
248 int r;
249
250 ts_pause.tv_sec = 0;
251 ts_pause.tv_nsec = POLL_SLEEP_NS200000000;
252 nanosleep(&ts_pause, NULL((void*)0));
253 npoll = nsk;
254 for (i = 0; i < nsk; i++) {
255 if (skv[i] == NULL((void*)0))
256 continue; /* device discarded */
257 skdebug(__func__, "polling %s", skv[i]->path);
258 if ((r = fido_dev_get_touch_status(skv[i]->dev, touch,
259 FIDO_POLL_MS50)) != FIDO_OK0x00) {
260 skdebug(__func__, "fido_dev_get_touch_status %s: %s",
261 skv[i]->path, fido_strerr(r));
262 sk_close(skv[i]); /* discard device */
263 skv[i] = NULL((void*)0);
264 if (--npoll == 0) {
265 skdebug(__func__, "no device left to poll");
266 return -1;
267 }
268 } else if (*touch) {
269 *idx = i;
270 return 0;
271 }
272 }
273 *touch = 0;
274 return 0;
275}
276
277/* Calculate SHA256(m) */
278static int
279sha256_mem(const void *m, size_t mlen, u_char *d, size_t dlen)
280{
281#ifdef WITH_OPENSSL1
282 u_int mdlen;
283#else
284 SHA2_CTX ctx;
285#endif
286
287 if (dlen != 32)
288 return -1;
289#ifdef WITH_OPENSSL1
290 mdlen = dlen;
291 if (!EVP_Digest(m, mlen, d, &mdlen, EVP_sha256(), NULL((void*)0)))
292 return -1;
293#else
294 SHA256Init(&ctx);
295 SHA256Update(&ctx, (const uint8_t *)m, mlen);
296 SHA256Final(d, &ctx);
297#endif
298 return 0;
299}
300
301/* Check if the specified key handle exists on a given sk. */
302static int
303sk_try(const struct sk_usbhid *sk, const char *application,
304 const uint8_t *key_handle, size_t key_handle_len)
305{
306 fido_assert_t *assert = NULL((void*)0);
307 /* generate an invalid signature on FIDO2 tokens */
308 const char *data = "";
309 uint8_t message[32];
310 int r = FIDO_ERR_INTERNAL-9;
311
312 if (sha256_mem(data, strlen(data), message, sizeof(message)) != 0) {
313 skdebug(__func__, "hash message failed");
314 goto out;
315 }
316 if ((assert = fido_assert_new()) == NULL((void*)0)) {
317 skdebug(__func__, "fido_assert_new failed");
318 goto out;
319 }
320 if ((r = fido_assert_set_clientdata_hash(assert, message,
321 sizeof(message))) != FIDO_OK0x00) {
322 skdebug(__func__, "fido_assert_set_clientdata_hash: %s",
323 fido_strerr(r));
324 goto out;
325 }
326 if ((r = fido_assert_set_rp(assert, application)) != FIDO_OK0x00) {
327 skdebug(__func__, "fido_assert_set_rp: %s", fido_strerr(r));
328 goto out;
329 }
330 if ((r = fido_assert_allow_cred(assert, key_handle,
331 key_handle_len)) != FIDO_OK0x00) {
332 skdebug(__func__, "fido_assert_allow_cred: %s", fido_strerr(r));
333 goto out;
334 }
335 if ((r = fido_assert_set_up(assert, FIDO_OPT_FALSE)) != FIDO_OK0x00) {
336 skdebug(__func__, "fido_assert_up: %s", fido_strerr(r));
337 goto out;
338 }
339 r = fido_dev_get_assert(sk->dev, assert, NULL((void*)0));
340 skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r));
341 if (r == FIDO_ERR_USER_PRESENCE_REQUIRED-8) {
342 /* U2F tokens may return this */
343 r = FIDO_OK0x00;
344 }
345 out:
346 fido_assert_free(&assert);
347
348 return r != FIDO_OK0x00 ? -1 : 0;
349}
350
351static int
352check_sk_options(fido_dev_t *dev, const char *opt, int *ret)
353{
354 fido_cbor_info_t *info;
355 char * const *name;
356 const bool_Bool *value;
357 size_t len, i;
358 int r;
359
360 *ret = -1;
361
362 if (!fido_dev_is_fido2(dev)) {
363 skdebug(__func__, "device is not fido2");
364 return 0;
365 }
366 if ((info = fido_cbor_info_new()) == NULL((void*)0)) {
367 skdebug(__func__, "fido_cbor_info_new failed");
368 return -1;
369 }
370 if ((r = fido_dev_get_cbor_info(dev, info)) != FIDO_OK0x00) {
371 skdebug(__func__, "fido_dev_get_cbor_info: %s", fido_strerr(r));
372 fido_cbor_info_free(&info);
373 return -1;
374 }
375 name = fido_cbor_info_options_name_ptr(info);
376 value = fido_cbor_info_options_value_ptr(info);
377 len = fido_cbor_info_options_len(info);
378 for (i = 0; i < len; i++) {
379 if (!strcmp(name[i], opt)) {
380 *ret = value[i];
381 break;
382 }
383 }
384 fido_cbor_info_free(&info);
385 if (*ret == -1)
386 skdebug(__func__, "option %s is unknown", opt);
387 else
388 skdebug(__func__, "option %s is %s", opt, *ret ? "on" : "off");
389
390 return 0;
391}
392
393static struct sk_usbhid *
394sk_select_by_cred(const fido_dev_info_t *devlist, size_t ndevs,
395 const char *application, const uint8_t *key_handle, size_t key_handle_len)
396{
397 struct sk_usbhid **skv, *sk;
398 size_t skvcnt, i;
399 int internal_uv;
400
401 if ((skv = sk_openv(devlist, ndevs, &skvcnt)) == NULL((void*)0)) {
402 skdebug(__func__, "sk_openv failed");
403 return NULL((void*)0);
404 }
405 if (skvcnt == 1 && check_sk_options(skv[0]->dev, "uv",
406 &internal_uv) == 0 && internal_uv != -1) {
407 sk = skv[0];
408 skv[0] = NULL((void*)0);
409 goto out;
410 }
411 sk = NULL((void*)0);
412 for (i = 0; i < skvcnt; i++) {
413 if (sk_try(skv[i], application, key_handle,
414 key_handle_len) == 0) {
415 sk = skv[i];
416 skv[i] = NULL((void*)0);
417 skdebug(__func__, "found key in %s", sk->path);
418 break;
419 }
420 }
421 out:
422 sk_closev(skv, skvcnt);
423 return sk;
424}
425
426static struct sk_usbhid *
427sk_select_by_touch(const fido_dev_info_t *devlist, size_t ndevs)
428{
429 struct sk_usbhid **skv, *sk;
430 struct timeval tv_start, tv_now, tv_delta;
431 size_t skvcnt, idx;
432 int touch, ms_remain;
433
434 if ((skv = sk_openv(devlist, ndevs, &skvcnt)) == NULL((void*)0)) {
435 skdebug(__func__, "sk_openv failed");
436 return NULL((void*)0);
437 }
438 sk = NULL((void*)0);
439 if (skvcnt < 2) {
440 if (skvcnt == 1) {
441 /* single candidate */
442 sk = skv[0];
443 skv[0] = NULL((void*)0);
444 }
445 goto out;
446 }
447 if (sk_touch_begin(skv, skvcnt) == -1) {
448 skdebug(__func__, "sk_touch_begin failed");
449 goto out;
450 }
451 monotime_tv(&tv_start);
452 do {
453 if (sk_touch_poll(skv, skvcnt, &touch, &idx) == -1) {
454 skdebug(__func__, "sk_touch_poll failed");
455 goto out;
456 }
457 if (touch) {
458 sk = skv[idx];
459 skv[idx] = NULL((void*)0);
460 goto out;
461 }
462 monotime_tv(&tv_now);
463 timersub(&tv_now, &tv_start, &tv_delta)do { (&tv_delta)->tv_sec = (&tv_now)->tv_sec - (
&tv_start)->tv_sec; (&tv_delta)->tv_usec = (&
tv_now)->tv_usec - (&tv_start)->tv_usec; if ((&
tv_delta)->tv_usec < 0) { (&tv_delta)->tv_sec--;
(&tv_delta)->tv_usec += 1000000; } } while (0)
;
464 ms_remain = SELECT_MS15000 - tv_delta.tv_sec * 1000 -
465 tv_delta.tv_usec / 1000;
466 } while (ms_remain >= FIDO_POLL_MS50);
467 skdebug(__func__, "timeout");
468out:
469 sk_closev(skv, skvcnt);
470 return sk;
471}
472
473static struct sk_usbhid *
474sk_probe(const char *application, const uint8_t *key_handle,
475 size_t key_handle_len)
476{
477 struct sk_usbhid *sk;
478 fido_dev_info_t *devlist;
479 size_t ndevs;
480 int r;
481
482 if ((devlist = fido_dev_info_new(MAX_FIDO_DEVICES8)) == NULL((void*)0)) {
483 skdebug(__func__, "fido_dev_info_new failed");
484 return NULL((void*)0);
485 }
486 if ((r = fido_dev_info_manifest(devlist, MAX_FIDO_DEVICES8,
487 &ndevs)) != FIDO_OK0x00) {
488 skdebug(__func__, "fido_dev_info_manifest failed: %s",
489 fido_strerr(r));
490 fido_dev_info_free(&devlist, MAX_FIDO_DEVICES8);
491 return NULL((void*)0);
492 }
493 skdebug(__func__, "%zu device(s) detected", ndevs);
494 if (ndevs == 0) {
495 sk = NULL((void*)0);
496 } else if (application != NULL((void*)0) && key_handle != NULL((void*)0)) {
497 skdebug(__func__, "selecting sk by cred");
498 sk = sk_select_by_cred(devlist, ndevs, application, key_handle,
499 key_handle_len);
500 } else {
501 skdebug(__func__, "selecting sk by touch");
502 sk = sk_select_by_touch(devlist, ndevs);
503 }
504 fido_dev_info_free(&devlist, MAX_FIDO_DEVICES8);
505 return sk;
506}
507
508#ifdef WITH_OPENSSL1
509/*
510 * The key returned via fido_cred_pubkey_ptr() is in affine coordinates,
511 * but the API expects a SEC1 octet string.
512 */
513static int
514pack_public_key_ecdsa(const fido_cred_t *cred,
515 struct sk_enroll_response *response)
516{
517 const uint8_t *ptr;
518 BIGNUM *x = NULL((void*)0), *y = NULL((void*)0);
519 EC_POINT *q = NULL((void*)0);
520 EC_GROUP *g = NULL((void*)0);
521 int ret = -1;
522
523 response->public_key = NULL((void*)0);
524 response->public_key_len = 0;
525
526 if ((x = BN_new()) == NULL((void*)0) ||
527 (y = BN_new()) == NULL((void*)0) ||
528 (g = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1415)) == NULL((void*)0) ||
529 (q = EC_POINT_new(g)) == NULL((void*)0)) {
530 skdebug(__func__, "libcrypto setup failed");
531 goto out;
532 }
533 if ((ptr = fido_cred_pubkey_ptr(cred)) == NULL((void*)0)) {
534 skdebug(__func__, "fido_cred_pubkey_ptr failed");
535 goto out;
536 }
537 if (fido_cred_pubkey_len(cred) != 64) {
538 skdebug(__func__, "bad fido_cred_pubkey_len %zu",
539 fido_cred_pubkey_len(cred));
540 goto out;
541 }
542
543 if (BN_bin2bn(ptr, 32, x) == NULL((void*)0) ||
544 BN_bin2bn(ptr + 32, 32, y) == NULL((void*)0)) {
545 skdebug(__func__, "BN_bin2bn failed");
546 goto out;
547 }
548 if (EC_POINT_set_affine_coordinates_GFp(g, q, x, y, NULL((void*)0)) != 1) {
549 skdebug(__func__, "EC_POINT_set_affine_coordinates_GFp failed");
550 goto out;
551 }
552 response->public_key_len = EC_POINT_point2oct(g, q,
553 POINT_CONVERSION_UNCOMPRESSED, NULL((void*)0), 0, NULL((void*)0));
554 if (response->public_key_len == 0 || response->public_key_len > 2048) {
555 skdebug(__func__, "bad pubkey length %zu",
556 response->public_key_len);
557 goto out;
558 }
559 if ((response->public_key = malloc(response->public_key_len)) == NULL((void*)0)) {
560 skdebug(__func__, "malloc pubkey failed");
561 goto out;
562 }
563 if (EC_POINT_point2oct(g, q, POINT_CONVERSION_UNCOMPRESSED,
564 response->public_key, response->public_key_len, NULL((void*)0)) == 0) {
565 skdebug(__func__, "EC_POINT_point2oct failed");
566 goto out;
567 }
568 /* success */
569 ret = 0;
570 out:
571 if (ret != 0 && response->public_key != NULL((void*)0)) {
572 memset(response->public_key, 0, response->public_key_len);
573 free(response->public_key);
574 response->public_key = NULL((void*)0);
575 }
576 EC_POINT_free(q);
577 EC_GROUP_free(g);
578 BN_clear_free(x);
579 BN_clear_free(y);
580 return ret;
581}
582#endif /* WITH_OPENSSL */
583
584static int
585pack_public_key_ed25519(const fido_cred_t *cred,
586 struct sk_enroll_response *response)
587{
588 const uint8_t *ptr;
589 size_t len;
590 int ret = -1;
591
592 response->public_key = NULL((void*)0);
593 response->public_key_len = 0;
594
595 if ((len = fido_cred_pubkey_len(cred)) != 32) {
596 skdebug(__func__, "bad fido_cred_pubkey_len len %zu", len);
597 goto out;
598 }
599 if ((ptr = fido_cred_pubkey_ptr(cred)) == NULL((void*)0)) {
600 skdebug(__func__, "fido_cred_pubkey_ptr failed");
601 goto out;
602 }
603 response->public_key_len = len;
604 if ((response->public_key = malloc(response->public_key_len)) == NULL((void*)0)) {
605 skdebug(__func__, "malloc pubkey failed");
606 goto out;
607 }
608 memcpy(response->public_key, ptr, len);
609 ret = 0;
610 out:
611 if (ret != 0)
612 free(response->public_key);
613 return ret;
614}
615
616static int
617pack_public_key(uint32_t alg, const fido_cred_t *cred,
618 struct sk_enroll_response *response)
619{
620 switch(alg) {
621#ifdef WITH_OPENSSL1
622 case SSH_SK_ECDSA0x00:
623 return pack_public_key_ecdsa(cred, response);
624#endif /* WITH_OPENSSL */
625 case SSH_SK_ED255190x01:
626 return pack_public_key_ed25519(cred, response);
627 default:
628 return -1;
629 }
630}
631
632static int
633fidoerr_to_skerr(int fidoerr)
634{
635 switch (fidoerr) {
636 case FIDO_ERR_UNSUPPORTED_OPTION0x2b:
637 case FIDO_ERR_UNSUPPORTED_ALGORITHM0x26:
638 return SSH_SK_ERR_UNSUPPORTED-2;
639 case FIDO_ERR_PIN_REQUIRED0x36:
640 case FIDO_ERR_PIN_INVALID0x31:
641 case FIDO_ERR_OPERATION_DENIED0x27:
642 return SSH_SK_ERR_PIN_REQUIRED-3;
643 default:
644 return -1;
645 }
646}
647
648static int
649check_enroll_options(struct sk_option **options, char **devicep,
650 uint8_t *user_id, size_t user_id_len)
651{
652 size_t i;
653
654 if (options == NULL((void*)0))
655 return 0;
656 for (i = 0; options[i] != NULL((void*)0); i++) {
657 if (strcmp(options[i]->name, "device") == 0) {
658 if ((*devicep = strdup(options[i]->value)) == NULL((void*)0)) {
659 skdebug(__func__, "strdup device failed");
660 return -1;
661 }
662 skdebug(__func__, "requested device %s", *devicep);
663 } else if (strcmp(options[i]->name, "user") == 0) {
664 if (strlcpy(user_id, options[i]->value, user_id_len) >=
665 user_id_len) {
666 skdebug(__func__, "user too long");
667 return -1;
668 }
669 skdebug(__func__, "requested user %s",
670 (char *)user_id);
671 } else {
672 skdebug(__func__, "requested unsupported option %s",
673 options[i]->name);
674 if (options[i]->required) {
675 skdebug(__func__, "unknown required option");
676 return -1;
677 }
678 }
679 }
680 return 0;
681}
682
683int
684sk_enrollssh_sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len,
685 const char *application, uint8_t flags, const char *pin,
686 struct sk_option **options, struct sk_enroll_response **enroll_response)
687{
688 fido_cred_t *cred = NULL((void*)0);
689 const uint8_t *ptr;
690 uint8_t user_id[32], chall_hash[32];
691 struct sk_usbhid *sk = NULL((void*)0);
692 struct sk_enroll_response *response = NULL((void*)0);
693 size_t len;
694 int credprot;
695 int internal_uv;
696 int cose_alg;
697 int ret = SSH_SK_ERR_GENERAL-1;
698 int r;
699 char *device = NULL((void*)0);
700
701 fido_init(SSH_FIDO_INIT_ARG0);
702
703 if (enroll_response == NULL((void*)0)) {
704 skdebug(__func__, "enroll_response == NULL");
705 goto out;
706 }
707 *enroll_response = NULL((void*)0);
708 memset(user_id, 0, sizeof(user_id));
709 if (check_enroll_options(options, &device, user_id,
710 sizeof(user_id)) != 0)
711 goto out; /* error already logged */
712
713 switch(alg) {
714#ifdef WITH_OPENSSL1
715 case SSH_SK_ECDSA0x00:
716 cose_alg = COSE_ES256-7;
717 break;
718#endif /* WITH_OPENSSL */
719 case SSH_SK_ED255190x01:
720 cose_alg = COSE_EDDSA-8;
721 break;
722 default:
723 skdebug(__func__, "unsupported key type %d", alg);
724 goto out;
725 }
726 if (device != NULL((void*)0))
727 sk = sk_open(device);
728 else
729 sk = sk_probe(NULL((void*)0), NULL((void*)0), 0);
730 if (sk == NULL((void*)0)) {
731 ret = SSH_SK_ERR_DEVICE_NOT_FOUND-4;
732 skdebug(__func__, "failed to find sk");
733 goto out;
734 }
735 skdebug(__func__, "using device %s", sk->path);
736 if ((cred = fido_cred_new()) == NULL((void*)0)) {
737 skdebug(__func__, "fido_cred_new failed");
738 goto out;
739 }
740 if ((r = fido_cred_set_type(cred, cose_alg)) != FIDO_OK0x00) {
741 skdebug(__func__, "fido_cred_set_type: %s", fido_strerr(r));
742 goto out;
743 }
744 if (sha256_mem(challenge, challenge_len,
745 chall_hash, sizeof(chall_hash)) != 0) {
746 skdebug(__func__, "hash challenge failed");
747 goto out;
748 }
749 if ((r = fido_cred_set_clientdata_hash(cred, chall_hash,
750 sizeof(chall_hash))) != FIDO_OK0x00) {
751 skdebug(__func__, "fido_cred_set_clientdata_hash: %s",
752 fido_strerr(r));
753 goto out;
754 }
755 if ((r = fido_cred_set_rk(cred, (flags & SSH_SK_RESIDENT_KEY0x20) != 0 ?
756 FIDO_OPT_TRUE : FIDO_OPT_OMIT)) != FIDO_OK0x00) {
757 skdebug(__func__, "fido_cred_set_rk: %s", fido_strerr(r));
758 goto out;
759 }
760 if ((r = fido_cred_set_user(cred, user_id, sizeof(user_id),
761 "openssh", "openssh", NULL((void*)0))) != FIDO_OK0x00) {
762 skdebug(__func__, "fido_cred_set_user: %s", fido_strerr(r));
763 goto out;
764 }
765 if ((r = fido_cred_set_rp(cred, application, NULL((void*)0))) != FIDO_OK0x00) {
766 skdebug(__func__, "fido_cred_set_rp: %s", fido_strerr(r));
767 goto out;
768 }
769 if ((flags & (SSH_SK_RESIDENT_KEY0x20|SSH_SK_USER_VERIFICATION_REQD0x04)) != 0) {
770 if (!fido_dev_supports_cred_prot(sk->dev)) {
771 skdebug(__func__, "%s does not support credprot, "
772 "refusing to create unprotected "
773 "resident/verify-required key", sk->path);
774 ret = SSH_SK_ERR_UNSUPPORTED-2;
775 goto out;
776 }
777 if ((flags & SSH_SK_USER_VERIFICATION_REQD0x04))
778 credprot = FIDO_CRED_PROT_UV_REQUIRED0x03;
779 else
780 credprot = FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID0x02;
781
782 if ((r = fido_cred_set_prot(cred, credprot)) != FIDO_OK0x00) {
783 skdebug(__func__, "fido_cred_set_prot: %s",
784 fido_strerr(r));
785 ret = fidoerr_to_skerr(r);
786 goto out;
787 }
788 }
789 if ((r = fido_dev_make_cred(sk->dev, cred, pin)) != FIDO_OK0x00) {
790 skdebug(__func__, "fido_dev_make_cred: %s", fido_strerr(r));
791 ret = fidoerr_to_skerr(r);
792 goto out;
793 }
794 if (fido_cred_x5c_ptr(cred) != NULL((void*)0)) {
795 if ((r = fido_cred_verify(cred)) != FIDO_OK0x00) {
796 skdebug(__func__, "fido_cred_verify: %s",
797 fido_strerr(r));
798 goto out;
799 }
800 } else {
801 skdebug(__func__, "self-attested credential");
802 if ((r = fido_cred_verify_self(cred)) != FIDO_OK0x00) {
803 skdebug(__func__, "fido_cred_verify_self: %s",
804 fido_strerr(r));
805 goto out;
806 }
807 }
808 if ((response = calloc(1, sizeof(*response))) == NULL((void*)0)) {
809 skdebug(__func__, "calloc response failed");
810 goto out;
811 }
812 response->flags = flags;
813 if ((flags & SSH_SK_USER_VERIFICATION_REQD0x04)) {
814 if (check_sk_options(sk->dev, "uv", &internal_uv) == 0 &&
815 internal_uv != -1) {
816 /* user verification handled by token */
817 response->flags &= ~SSH_SK_USER_VERIFICATION_REQD0x04;
818 }
819 }
820 if (pack_public_key(alg, cred, response) != 0) {
821 skdebug(__func__, "pack_public_key failed");
822 goto out;
823 }
824 if ((ptr = fido_cred_id_ptr(cred)) != NULL((void*)0)) {
825 len = fido_cred_id_len(cred);
826 if ((response->key_handle = calloc(1, len)) == NULL((void*)0)) {
827 skdebug(__func__, "calloc key handle failed");
828 goto out;
829 }
830 memcpy(response->key_handle, ptr, len);
831 response->key_handle_len = len;
832 }
833 if ((ptr = fido_cred_sig_ptr(cred)) != NULL((void*)0)) {
834 len = fido_cred_sig_len(cred);
835 if ((response->signature = calloc(1, len)) == NULL((void*)0)) {
836 skdebug(__func__, "calloc signature failed");
837 goto out;
838 }
839 memcpy(response->signature, ptr, len);
840 response->signature_len = len;
841 }
842 if ((ptr = fido_cred_x5c_ptr(cred)) != NULL((void*)0)) {
843 len = fido_cred_x5c_len(cred);
844 skdebug(__func__, "attestation cert len=%zu", len);
845 if ((response->attestation_cert = calloc(1, len)) == NULL((void*)0)) {
846 skdebug(__func__, "calloc attestation cert failed");
847 goto out;
848 }
849 memcpy(response->attestation_cert, ptr, len);
850 response->attestation_cert_len = len;
851 }
852 if ((ptr = fido_cred_authdata_ptr(cred)) != NULL((void*)0)) {
853 len = fido_cred_authdata_len(cred);
854 skdebug(__func__, "authdata len=%zu", len);
855 if ((response->authdata = calloc(1, len)) == NULL((void*)0)) {
856 skdebug(__func__, "calloc authdata failed");
857 goto out;
858 }
859 memcpy(response->authdata, ptr, len);
860 response->authdata_len = len;
861 }
862 *enroll_response = response;
863 response = NULL((void*)0);
864 ret = 0;
865 out:
866 free(device);
867 if (response != NULL((void*)0)) {
868 free(response->public_key);
869 free(response->key_handle);
870 free(response->signature);
871 free(response->attestation_cert);
872 free(response->authdata);
873 free(response);
874 }
875 sk_close(sk);
876 fido_cred_free(&cred);
877 return ret;
878}
879
880#ifdef WITH_OPENSSL1
881static int
882pack_sig_ecdsa(fido_assert_t *assert, struct sk_sign_response *response)
883{
884 ECDSA_SIG *sig = NULL((void*)0);
885 const BIGNUM *sig_r, *sig_s;
886 const unsigned char *cp;
887 size_t sig_len;
888 int ret = -1;
889
890 cp = fido_assert_sig_ptr(assert, 0);
891 sig_len = fido_assert_sig_len(assert, 0);
892 if ((sig = d2i_ECDSA_SIG(NULL((void*)0), &cp, sig_len)) == NULL((void*)0)) {
893 skdebug(__func__, "d2i_ECDSA_SIG failed");
894 goto out;
895 }
896 ECDSA_SIG_get0(sig, &sig_r, &sig_s);
897 response->sig_r_len = BN_num_bytes(sig_r)((BN_num_bits(sig_r)+7)/8);
898 response->sig_s_len = BN_num_bytes(sig_s)((BN_num_bits(sig_s)+7)/8);
899 if ((response->sig_r = calloc(1, response->sig_r_len)) == NULL((void*)0) ||
900 (response->sig_s = calloc(1, response->sig_s_len)) == NULL((void*)0)) {
901 skdebug(__func__, "calloc signature failed");
902 goto out;
903 }
904 BN_bn2bin(sig_r, response->sig_r);
905 BN_bn2bin(sig_s, response->sig_s);
906 ret = 0;
907 out:
908 ECDSA_SIG_free(sig);
909 if (ret != 0) {
910 free(response->sig_r);
911 free(response->sig_s);
912 response->sig_r = NULL((void*)0);
913 response->sig_s = NULL((void*)0);
914 }
915 return ret;
916}
917#endif /* WITH_OPENSSL */
918
919static int
920pack_sig_ed25519(fido_assert_t *assert, struct sk_sign_response *response)
921{
922 const unsigned char *ptr;
923 size_t len;
924 int ret = -1;
925
926 ptr = fido_assert_sig_ptr(assert, 0);
927 len = fido_assert_sig_len(assert, 0);
928 if (len != 64) {
929 skdebug(__func__, "bad length %zu", len);
930 goto out;
931 }
932 response->sig_r_len = len;
933 if ((response->sig_r = calloc(1, response->sig_r_len)) == NULL((void*)0)) {
934 skdebug(__func__, "calloc signature failed");
935 goto out;
936 }
937 memcpy(response->sig_r, ptr, len);
938 ret = 0;
939 out:
940 if (ret != 0) {
941 free(response->sig_r);
942 response->sig_r = NULL((void*)0);
943 }
944 return ret;
945}
946
947static int
948pack_sig(uint32_t alg, fido_assert_t *assert,
949 struct sk_sign_response *response)
950{
951 switch(alg) {
952#ifdef WITH_OPENSSL1
953 case SSH_SK_ECDSA0x00:
954 return pack_sig_ecdsa(assert, response);
955#endif /* WITH_OPENSSL */
956 case SSH_SK_ED255190x01:
957 return pack_sig_ed25519(assert, response);
958 default:
959 return -1;
960 }
961}
962
963/* Checks sk_options for sk_sign() and sk_load_resident_keys() */
964static int
965check_sign_load_resident_options(struct sk_option **options, char **devicep)
966{
967 size_t i;
968
969 if (options == NULL((void*)0))
970 return 0;
971 for (i = 0; options[i] != NULL((void*)0); i++) {
972 if (strcmp(options[i]->name, "device") == 0) {
973 if ((*devicep = strdup(options[i]->value)) == NULL((void*)0)) {
974 skdebug(__func__, "strdup device failed");
975 return -1;
976 }
977 skdebug(__func__, "requested device %s", *devicep);
978 } else {
979 skdebug(__func__, "requested unsupported option %s",
980 options[i]->name);
981 if (options[i]->required) {
982 skdebug(__func__, "unknown required option");
983 return -1;
984 }
985 }
986 }
987 return 0;
988}
989
990int
991sk_signssh_sk_sign(uint32_t alg, const uint8_t *data, size_t datalen,
992 const char *application,
993 const uint8_t *key_handle, size_t key_handle_len,
994 uint8_t flags, const char *pin, struct sk_option **options,
995 struct sk_sign_response **sign_response)
996{
997 fido_assert_t *assert = NULL((void*)0);
998 char *device = NULL((void*)0);
999 struct sk_usbhid *sk = NULL((void*)0);
1000 struct sk_sign_response *response = NULL((void*)0);
1001 uint8_t message[32];
1002 int ret = SSH_SK_ERR_GENERAL-1, internal_uv;
1003 int r;
1004
1005 fido_init(SSH_FIDO_INIT_ARG0);
1006
1007 if (sign_response == NULL((void*)0)) {
1008 skdebug(__func__, "sign_response == NULL");
1009 goto out;
1010 }
1011 *sign_response = NULL((void*)0);
1012 if (check_sign_load_resident_options(options, &device) != 0)
1013 goto out; /* error already logged */
1014 /* hash data to be signed before it goes to the security key */
1015 if ((r = sha256_mem(data, datalen, message, sizeof(message))) != 0) {
1016 skdebug(__func__, "hash message failed");
1017 goto out;
1018 }
1019 if (device != NULL((void*)0))
1020 sk = sk_open(device);
1021 else if (pin != NULL((void*)0) || (flags & SSH_SK_USER_VERIFICATION_REQD0x04))
1022 sk = sk_probe(NULL((void*)0), NULL((void*)0), 0);
1023 else
1024 sk = sk_probe(application, key_handle, key_handle_len);
1025 if (sk == NULL((void*)0)) {
1026 ret = SSH_SK_ERR_DEVICE_NOT_FOUND-4;
1027 skdebug(__func__, "failed to find sk");
1028 goto out;
1029 }
1030 if ((assert = fido_assert_new()) == NULL((void*)0)) {
1031 skdebug(__func__, "fido_assert_new failed");
1032 goto out;
1033 }
1034 if ((r = fido_assert_set_clientdata_hash(assert, message,
1035 sizeof(message))) != FIDO_OK0x00) {
1036 skdebug(__func__, "fido_assert_set_clientdata_hash: %s",
1037 fido_strerr(r));
1038 goto out;
1039 }
1040 if ((r = fido_assert_set_rp(assert, application)) != FIDO_OK0x00) {
1041 skdebug(__func__, "fido_assert_set_rp: %s", fido_strerr(r));
1042 goto out;
1043 }
1044 if ((r = fido_assert_allow_cred(assert, key_handle,
1045 key_handle_len)) != FIDO_OK0x00) {
1046 skdebug(__func__, "fido_assert_allow_cred: %s", fido_strerr(r));
1047 goto out;
1048 }
1049 if ((r = fido_assert_set_up(assert,
1050 (flags & SSH_SK_USER_PRESENCE_REQD0x01) ?
1051 FIDO_OPT_TRUE : FIDO_OPT_FALSE)) != FIDO_OK0x00) {
1052 skdebug(__func__, "fido_assert_set_up: %s", fido_strerr(r));
1053 goto out;
1054 }
1055 if (pin == NULL((void*)0) && (flags & SSH_SK_USER_VERIFICATION_REQD0x04)) {
1056 if (check_sk_options(sk->dev, "uv", &internal_uv) < 0 ||
1057 internal_uv != 1) {
1058 skdebug(__func__, "check_sk_options uv");
1059 ret = SSH_SK_ERR_PIN_REQUIRED-3;
1060 goto out;
1061 }
1062 if ((r = fido_assert_set_uv(assert,
1063 FIDO_OPT_TRUE)) != FIDO_OK0x00) {
1064 skdebug(__func__, "fido_assert_set_uv: %s",
1065 fido_strerr(r));
1066 ret = fidoerr_to_skerr(r);
1067 goto out;
1068 }
1069 }
1070 if ((r = fido_dev_get_assert(sk->dev, assert, pin)) != FIDO_OK0x00) {
1071 skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r));
1072 ret = fidoerr_to_skerr(r);
1073 goto out;
1074 }
1075 if ((response = calloc(1, sizeof(*response))) == NULL((void*)0)) {
1076 skdebug(__func__, "calloc response failed");
1077 goto out;
1078 }
1079 response->flags = fido_assert_flags(assert, 0);
1080 response->counter = fido_assert_sigcount(assert, 0);
1081 if (pack_sig(alg, assert, response) != 0) {
1082 skdebug(__func__, "pack_sig failed");
1083 goto out;
1084 }
1085 *sign_response = response;
1086 response = NULL((void*)0);
1087 ret = 0;
1088 out:
1089 explicit_bzero(message, sizeof(message));
1090 free(device);
1091 if (response != NULL((void*)0)) {
1092 free(response->sig_r);
1093 free(response->sig_s);
1094 free(response);
1095 }
1096 sk_close(sk);
1097 fido_assert_free(&assert);
1098 return ret;
1099}
1100
1101static int
1102read_rks(struct sk_usbhid *sk, const char *pin,
1103 struct sk_resident_key ***rksp, size_t *nrksp)
1104{
1105 int ret = SSH_SK_ERR_GENERAL-1, r = -1, internal_uv;
1106 fido_credman_metadata_t *metadata = NULL((void*)0);
1107 fido_credman_rp_t *rp = NULL((void*)0);
1108 fido_credman_rk_t *rk = NULL((void*)0);
1109 size_t i, j, nrp, nrk, user_id_len;
1110 const fido_cred_t *cred;
1111 const char *rp_id, *rp_name, *user_name;
1112 struct sk_resident_key *srk = NULL((void*)0), **tmp;
1113 const u_char *user_id;
1114
1115 if (pin == NULL((void*)0)) {
1116 skdebug(__func__, "no PIN specified");
1117 ret = SSH_SK_ERR_PIN_REQUIRED-3;
1118 goto out;
1119 }
1120 if ((metadata = fido_credman_metadata_new()) == NULL((void*)0)) {
1121 skdebug(__func__, "alloc failed");
1122 goto out;
1123 }
1124 if (check_sk_options(sk->dev, "uv", &internal_uv) != 0) {
1125 skdebug(__func__, "check_sk_options failed");
1126 goto out;
1127 }
1128
1129 if ((r = fido_credman_get_dev_metadata(sk->dev, metadata, pin)) != 0) {
1130 if (r == FIDO_ERR_INVALID_COMMAND0x01) {
1131 skdebug(__func__, "device %s does not support "
1132 "resident keys", sk->path);
1133 ret = 0;
1134 goto out;
1135 }
1136 skdebug(__func__, "get metadata for %s failed: %s",
1137 sk->path, fido_strerr(r));
1138 ret = fidoerr_to_skerr(r);
1139 goto out;
1140 }
1141 skdebug(__func__, "existing %llu, remaining %llu",
1142 (unsigned long long)fido_credman_rk_existing(metadata),
1143 (unsigned long long)fido_credman_rk_remaining(metadata));
1144 if ((rp = fido_credman_rp_new()) == NULL((void*)0)) {
1145 skdebug(__func__, "alloc rp failed");
1146 goto out;
1147 }
1148 if ((r = fido_credman_get_dev_rp(sk->dev, rp, pin)) != 0) {
1149 skdebug(__func__, "get RPs for %s failed: %s",
1150 sk->path, fido_strerr(r));
1151 goto out;
1152 }
1153 nrp = fido_credman_rp_count(rp);
1154 skdebug(__func__, "Device %s has resident keys for %zu RPs",
1155 sk->path, nrp);
1156
1157 /* Iterate over RP IDs that have resident keys */
1158 for (i = 0; i < nrp; i++) {
1159 rp_id = fido_credman_rp_id(rp, i);
1160 rp_name = fido_credman_rp_name(rp, i);
1161 skdebug(__func__, "rp %zu: name=\"%s\" id=\"%s\" hashlen=%zu",
1162 i, rp_name == NULL((void*)0) ? "(none)" : rp_name,
1163 rp_id == NULL((void*)0) ? "(none)" : rp_id,
1164 fido_credman_rp_id_hash_len(rp, i));
1165
1166 /* Skip non-SSH RP IDs */
1167 if (rp_id == NULL((void*)0) ||
1168 strncasecmp(fido_credman_rp_id(rp, i), "ssh:", 4) != 0)
1169 continue;
1170
1171 fido_credman_rk_free(&rk);
1172 if ((rk = fido_credman_rk_new()) == NULL((void*)0)) {
1173 skdebug(__func__, "alloc rk failed");
1174 goto out;
1175 }
1176 if ((r = fido_credman_get_dev_rk(sk->dev,
1177 fido_credman_rp_id(rp, i), rk, pin)) != 0) {
1178 skdebug(__func__, "get RKs for %s slot %zu failed: %s",
1179 sk->path, i, fido_strerr(r));
1180 goto out;
1181 }
1182 nrk = fido_credman_rk_count(rk);
1183 skdebug(__func__, "RP \"%s\" has %zu resident keys",
1184 fido_credman_rp_id(rp, i), nrk);
1185
1186 /* Iterate over resident keys for this RP ID */
1187 for (j = 0; j < nrk; j++) {
1188 if ((cred = fido_credman_rk(rk, j)) == NULL((void*)0)) {
1189 skdebug(__func__, "no RK in slot %zu", j);
1190 continue;
1191 }
1192 if ((user_name = fido_cred_user_name(cred)) == NULL((void*)0))
1193 user_name = "";
1194 user_id = fido_cred_user_id_ptr(cred);
1195 user_id_len = fido_cred_user_id_len(cred);
1196 skdebug(__func__, "Device %s RP \"%s\" user \"%s\" "
1197 "uidlen %zu slot %zu: type %d flags 0x%02x "
1198 "prot 0x%02x", sk->path, rp_id, user_name,
1199 user_id_len, j, fido_cred_type(cred),
1200 fido_cred_flags(cred), fido_cred_prot(cred));
1201
1202 /* build response entry */
1203 if ((srk = calloc(1, sizeof(*srk))) == NULL((void*)0) ||
1204 (srk->key.key_handle = calloc(1,
1205 fido_cred_id_len(cred))) == NULL((void*)0) ||
1206 (srk->application = strdup(rp_id)) == NULL((void*)0) ||
1207 (user_id_len > 0 &&
1208 (srk->user_id = calloc(1, user_id_len)) == NULL((void*)0))) {
1209 skdebug(__func__, "alloc sk_resident_key");
1210 goto out;
1211 }
1212
1213 srk->key.key_handle_len = fido_cred_id_len(cred);
1214 memcpy(srk->key.key_handle, fido_cred_id_ptr(cred),
1215 srk->key.key_handle_len);
1216 srk->user_id_len = user_id_len;
1217 if (srk->user_id_len != 0)
1218 memcpy(srk->user_id, user_id, srk->user_id_len);
1219
1220 switch (fido_cred_type(cred)) {
1221 case COSE_ES256-7:
1222 srk->alg = SSH_SK_ECDSA0x00;
1223 break;
1224 case COSE_EDDSA-8:
1225 srk->alg = SSH_SK_ED255190x01;
1226 break;
1227 default:
1228 skdebug(__func__, "unsupported key type %d",
1229 fido_cred_type(cred));
1230 goto out; /* XXX free rk and continue */
1231 }
1232
1233 if (fido_cred_prot(cred) == FIDO_CRED_PROT_UV_REQUIRED0x03
1234 && internal_uv == -1)
1235 srk->flags |= SSH_SK_USER_VERIFICATION_REQD0x04;
1236
1237 if ((r = pack_public_key(srk->alg, cred,
Although the value stored to 'r' is used in the enclosing expression, the value is never actually read from 'r'
1238 &srk->key)) != 0) {
1239 skdebug(__func__, "pack public key failed");
1240 goto out;
1241 }
1242 /* append */
1243 if ((tmp = recallocarray(*rksp, *nrksp, (*nrksp) + 1,
1244 sizeof(**rksp))) == NULL((void*)0)) {
1245 skdebug(__func__, "alloc rksp");
1246 goto out;
1247 }
1248 *rksp = tmp;
1249 (*rksp)[(*nrksp)++] = srk;
1250 srk = NULL((void*)0);
1251 }
1252 }
1253 /* Success */
1254 ret = 0;
1255 out:
1256 if (srk != NULL((void*)0)) {
1257 free(srk->application);
1258 freezero(srk->key.public_key, srk->key.public_key_len);
1259 freezero(srk->key.key_handle, srk->key.key_handle_len);
1260 freezero(srk->user_id, srk->user_id_len);
1261 freezero(srk, sizeof(*srk));
1262 }
1263 fido_credman_rp_free(&rp);
1264 fido_credman_rk_free(&rk);
1265 fido_credman_metadata_free(&metadata);
1266 return ret;
1267}
1268
1269int
1270sk_load_resident_keysssh_sk_load_resident_keys(const char *pin, struct sk_option **options,
1271 struct sk_resident_key ***rksp, size_t *nrksp)
1272{
1273 int ret = SSH_SK_ERR_GENERAL-1, r = -1;
1274 size_t i, nrks = 0;
1275 struct sk_resident_key **rks = NULL((void*)0);
1276 struct sk_usbhid *sk = NULL((void*)0);
1277 char *device = NULL((void*)0);
1278
1279 *rksp = NULL((void*)0);
1280 *nrksp = 0;
1281
1282 fido_init(SSH_FIDO_INIT_ARG0);
1283
1284 if (check_sign_load_resident_options(options, &device) != 0)
1285 goto out; /* error already logged */
1286 if (device != NULL((void*)0))
1287 sk = sk_open(device);
1288 else
1289 sk = sk_probe(NULL((void*)0), NULL((void*)0), 0);
1290 if (sk == NULL((void*)0)) {
1291 ret = SSH_SK_ERR_DEVICE_NOT_FOUND-4;
1292 skdebug(__func__, "failed to find sk");
1293 goto out;
1294 }
1295 skdebug(__func__, "trying %s", sk->path);
1296 if ((r = read_rks(sk, pin, &rks, &nrks)) != 0) {
1297 skdebug(__func__, "read_rks failed for %s", sk->path);
1298 ret = r;
1299 goto out;
1300 }
1301 /* success, unless we have no keys but a specific error */
1302 if (nrks > 0 || ret == SSH_SK_ERR_GENERAL-1)
1303 ret = 0;
1304 *rksp = rks;
1305 *nrksp = nrks;
1306 rks = NULL((void*)0);
1307 nrks = 0;
1308 out:
1309 sk_close(sk);
1310 for (i = 0; i < nrks; i++) {
1311 free(rks[i]->application);
1312 freezero(rks[i]->key.public_key, rks[i]->key.public_key_len);
1313 freezero(rks[i]->key.key_handle, rks[i]->key.key_handle_len);
1314 freezero(rks[i]->user_id, rks[i]->user_id_len);
1315 freezero(rks[i], sizeof(*rks[i]));
1316 }
1317 free(rks);
1318 return ret;
1319}
1320