Bug Summary

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