summaryrefslogtreecommitdiff
path: root/src/cred.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cred.c')
-rw-r--r--src/cred.c1034
1 files changed, 1034 insertions, 0 deletions
diff --git a/src/cred.c b/src/cred.c
new file mode 100644
index 0000000..c4e1edb
--- /dev/null
+++ b/src/cred.c
@@ -0,0 +1,1034 @@
1/*
2 * Copyright (c) 2018 Yubico AB. All rights reserved.
3 * Use of this source code is governed by a BSD-style
4 * license that can be found in the LICENSE file.
5 */
6
7#include <openssl/ec.h>
8#include <openssl/evp.h>
9#include <openssl/sha.h>
10#include <openssl/x509.h>
11
12#include <string.h>
13#include "fido.h"
14#include "fido/es256.h"
15
16static int
17parse_makecred_reply(const cbor_item_t *key, const cbor_item_t *val, void *arg)
18{
19 fido_cred_t *cred = arg;
20
21 if (cbor_isa_uint(key) == false ||
22 cbor_int_get_width(key) != CBOR_INT_8) {
23 fido_log_debug("%s: cbor type", __func__);
24 return (0); /* ignore */
25 }
26
27 switch (cbor_get_uint8(key)) {
28 case 1: /* fmt */
29 return (cbor_decode_fmt(val, &cred->fmt));
30 case 2: /* authdata */
31 return (cbor_decode_cred_authdata(val, cred->type,
32 &cred->authdata_cbor, &cred->authdata, &cred->attcred,
33 &cred->authdata_ext));
34 case 3: /* attestation statement */
35 return (cbor_decode_attstmt(val, &cred->attstmt));
36 default: /* ignore */
37 fido_log_debug("%s: cbor type", __func__);
38 return (0);
39 }
40}
41
42static int
43fido_dev_make_cred_tx(fido_dev_t *dev, fido_cred_t *cred, const char *pin)
44{
45 fido_blob_t f;
46 fido_blob_t *ecdh = NULL;
47 es256_pk_t *pk = NULL;
48 cbor_item_t *argv[9];
49 int r;
50
51 memset(&f, 0, sizeof(f));
52 memset(argv, 0, sizeof(argv));
53
54 if (cred->cdh.ptr == NULL || cred->type == 0) {
55 fido_log_debug("%s: cdh=%p, type=%d", __func__,
56 (void *)cred->cdh.ptr, cred->type);
57 r = FIDO_ERR_INVALID_ARGUMENT;
58 goto fail;
59 }
60
61 if ((argv[0] = fido_blob_encode(&cred->cdh)) == NULL ||
62 (argv[1] = cbor_encode_rp_entity(&cred->rp)) == NULL ||
63 (argv[2] = cbor_encode_user_entity(&cred->user)) == NULL ||
64 (argv[3] = cbor_encode_pubkey_param(cred->type)) == NULL) {
65 fido_log_debug("%s: cbor encode", __func__);
66 r = FIDO_ERR_INTERNAL;
67 goto fail;
68 }
69
70 /* excluded credentials */
71 if (cred->excl.len)
72 if ((argv[4] = cbor_encode_pubkey_list(&cred->excl)) == NULL) {
73 fido_log_debug("%s: cbor_encode_pubkey_list", __func__);
74 r = FIDO_ERR_INTERNAL;
75 goto fail;
76 }
77
78 /* extensions */
79 if (cred->ext)
80 if ((argv[5] = cbor_encode_extensions(cred->ext)) == NULL) {
81 fido_log_debug("%s: cbor_encode_extensions", __func__);
82 r = FIDO_ERR_INTERNAL;
83 goto fail;
84 }
85
86 /* options */
87 if (cred->rk != FIDO_OPT_OMIT || cred->uv != FIDO_OPT_OMIT)
88 if ((argv[6] = cbor_encode_options(cred->rk,
89 cred->uv)) == NULL) {
90 fido_log_debug("%s: cbor_encode_options", __func__);
91 r = FIDO_ERR_INTERNAL;
92 goto fail;
93 }
94
95 /* pin authentication */
96 if (pin) {
97 if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) {
98 fido_log_debug("%s: fido_do_ecdh", __func__);
99 goto fail;
100 }
101 if ((r = cbor_add_pin_params(dev, &cred->cdh, pk, ecdh, pin,
102 &argv[7], &argv[8])) != FIDO_OK) {
103 fido_log_debug("%s: cbor_add_pin_params", __func__);
104 goto fail;
105 }
106 }
107
108 /* framing and transmission */
109 if (cbor_build_frame(CTAP_CBOR_MAKECRED, argv, 9, &f) < 0 ||
110 fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
111 fido_log_debug("%s: fido_tx", __func__);
112 r = FIDO_ERR_TX;
113 goto fail;
114 }
115
116 r = FIDO_OK;
117fail:
118 es256_pk_free(&pk);
119 fido_blob_free(&ecdh);
120 cbor_vector_free(argv, nitems(argv));
121 free(f.ptr);
122
123 return (r);
124}
125
126static int
127fido_dev_make_cred_rx(fido_dev_t *dev, fido_cred_t *cred, int ms)
128{
129 const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR;
130 unsigned char reply[2048];
131 int reply_len;
132 int r;
133
134 fido_cred_reset_rx(cred);
135
136 if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) {
137 fido_log_debug("%s: fido_rx", __func__);
138 return (FIDO_ERR_RX);
139 }
140
141 if ((r = cbor_parse_reply(reply, (size_t)reply_len, cred,
142 parse_makecred_reply)) != FIDO_OK) {
143 fido_log_debug("%s: parse_makecred_reply", __func__);
144 return (r);
145 }
146
147 if (cred->fmt == NULL || fido_blob_is_empty(&cred->authdata_cbor) ||
148 fido_blob_is_empty(&cred->attcred.id) ||
149 fido_blob_is_empty(&cred->attstmt.sig)) {
150 fido_cred_reset_rx(cred);
151 return (FIDO_ERR_INVALID_CBOR);
152 }
153
154 return (FIDO_OK);
155}
156
157static int
158fido_dev_make_cred_wait(fido_dev_t *dev, fido_cred_t *cred, const char *pin, int ms)
159{
160 int r;
161
162 if ((r = fido_dev_make_cred_tx(dev, cred, pin)) != FIDO_OK ||
163 (r = fido_dev_make_cred_rx(dev, cred, ms)) != FIDO_OK)
164 return (r);
165
166 return (FIDO_OK);
167}
168
169int
170fido_dev_make_cred(fido_dev_t *dev, fido_cred_t *cred, const char *pin)
171{
172 if (fido_dev_is_fido2(dev) == false) {
173 if (pin != NULL || cred->rk == FIDO_OPT_TRUE || cred->ext != 0)
174 return (FIDO_ERR_UNSUPPORTED_OPTION);
175 return (u2f_register(dev, cred, -1));
176 }
177
178 return (fido_dev_make_cred_wait(dev, cred, pin, -1));
179}
180
181static int
182check_extensions(int authdata_ext, int ext)
183{
184 if (authdata_ext != ext) {
185 fido_log_debug("%s: authdata_ext=0x%x != ext=0x%x", __func__,
186 authdata_ext, ext);
187 return (-1);
188 }
189
190 return (0);
191}
192
193int
194fido_check_rp_id(const char *id, const unsigned char *obtained_hash)
195{
196 unsigned char expected_hash[SHA256_DIGEST_LENGTH];
197
198 explicit_bzero(expected_hash, sizeof(expected_hash));
199
200 if (SHA256((const unsigned char *)id, strlen(id),
201 expected_hash) != expected_hash) {
202 fido_log_debug("%s: sha256", __func__);
203 return (-1);
204 }
205
206 return (timingsafe_bcmp(expected_hash, obtained_hash,
207 SHA256_DIGEST_LENGTH));
208}
209
210static int
211get_signed_hash_packed(fido_blob_t *dgst, const fido_blob_t *clientdata,
212 const fido_blob_t *authdata_cbor)
213{
214 cbor_item_t *item = NULL;
215 unsigned char *authdata_ptr = NULL;
216 size_t authdata_len;
217 struct cbor_load_result cbor;
218 SHA256_CTX ctx;
219 int ok = -1;
220
221 if ((item = cbor_load(authdata_cbor->ptr, authdata_cbor->len,
222 &cbor)) == NULL) {
223 fido_log_debug("%s: cbor_load", __func__);
224 goto fail;
225 }
226
227 if (cbor_isa_bytestring(item) == false ||
228 cbor_bytestring_is_definite(item) == false) {
229 fido_log_debug("%s: cbor type", __func__);
230 goto fail;
231 }
232
233 authdata_ptr = cbor_bytestring_handle(item);
234 authdata_len = cbor_bytestring_length(item);
235
236 if (dgst->len != SHA256_DIGEST_LENGTH || SHA256_Init(&ctx) == 0 ||
237 SHA256_Update(&ctx, authdata_ptr, authdata_len) == 0 ||
238 SHA256_Update(&ctx, clientdata->ptr, clientdata->len) == 0 ||
239 SHA256_Final(dgst->ptr, &ctx) == 0) {
240 fido_log_debug("%s: sha256", __func__);
241 goto fail;
242 }
243
244 ok = 0;
245fail:
246 if (item != NULL)
247 cbor_decref(&item);
248
249 return (ok);
250}
251
252static int
253get_signed_hash_u2f(fido_blob_t *dgst, const unsigned char *rp_id,
254 size_t rp_id_len, const fido_blob_t *clientdata, const fido_blob_t *id,
255 const es256_pk_t *pk)
256{
257 const uint8_t zero = 0;
258 const uint8_t four = 4; /* uncompressed point */
259 SHA256_CTX ctx;
260
261 if (dgst->len != SHA256_DIGEST_LENGTH || SHA256_Init(&ctx) == 0 ||
262 SHA256_Update(&ctx, &zero, sizeof(zero)) == 0 ||
263 SHA256_Update(&ctx, rp_id, rp_id_len) == 0 ||
264 SHA256_Update(&ctx, clientdata->ptr, clientdata->len) == 0 ||
265 SHA256_Update(&ctx, id->ptr, id->len) == 0 ||
266 SHA256_Update(&ctx, &four, sizeof(four)) == 0 ||
267 SHA256_Update(&ctx, pk->x, sizeof(pk->x)) == 0 ||
268 SHA256_Update(&ctx, pk->y, sizeof(pk->y)) == 0 ||
269 SHA256_Final(dgst->ptr, &ctx) == 0) {
270 fido_log_debug("%s: sha256", __func__);
271 return (-1);
272 }
273
274 return (0);
275}
276
277static int
278verify_sig(const fido_blob_t *dgst, const fido_blob_t *x5c,
279 const fido_blob_t *sig)
280{
281 BIO *rawcert = NULL;
282 X509 *cert = NULL;
283 EVP_PKEY *pkey = NULL;
284 EC_KEY *ec;
285 int ok = -1;
286
287 /* openssl needs ints */
288 if (dgst->len > INT_MAX || x5c->len > INT_MAX || sig->len > INT_MAX) {
289 fido_log_debug("%s: dgst->len=%zu, x5c->len=%zu, sig->len=%zu",
290 __func__, dgst->len, x5c->len, sig->len);
291 return (-1);
292 }
293
294 /* fetch key from x509 */
295 if ((rawcert = BIO_new_mem_buf(x5c->ptr, (int)x5c->len)) == NULL ||
296 (cert = d2i_X509_bio(rawcert, NULL)) == NULL ||
297 (pkey = X509_get_pubkey(cert)) == NULL ||
298 (ec = EVP_PKEY_get0_EC_KEY(pkey)) == NULL) {
299 fido_log_debug("%s: x509 key", __func__);
300 goto fail;
301 }
302
303 if (ECDSA_verify(0, dgst->ptr, (int)dgst->len, sig->ptr,
304 (int)sig->len, ec) != 1) {
305 fido_log_debug("%s: ECDSA_verify", __func__);
306 goto fail;
307 }
308
309 ok = 0;
310fail:
311 if (rawcert != NULL)
312 BIO_free(rawcert);
313 if (cert != NULL)
314 X509_free(cert);
315 if (pkey != NULL)
316 EVP_PKEY_free(pkey);
317
318 return (ok);
319}
320
321int
322fido_cred_verify(const fido_cred_t *cred)
323{
324 unsigned char buf[SHA256_DIGEST_LENGTH];
325 fido_blob_t dgst;
326 int r;
327
328 dgst.ptr = buf;
329 dgst.len = sizeof(buf);
330
331 /* do we have everything we need? */
332 if (cred->cdh.ptr == NULL || cred->authdata_cbor.ptr == NULL ||
333 cred->attstmt.x5c.ptr == NULL || cred->attstmt.sig.ptr == NULL ||
334 cred->fmt == NULL || cred->attcred.id.ptr == NULL ||
335 cred->rp.id == NULL) {
336 fido_log_debug("%s: cdh=%p, authdata=%p, x5c=%p, sig=%p, "
337 "fmt=%p id=%p, rp.id=%s", __func__, (void *)cred->cdh.ptr,
338 (void *)cred->authdata_cbor.ptr,
339 (void *)cred->attstmt.x5c.ptr,
340 (void *)cred->attstmt.sig.ptr, (void *)cred->fmt,
341 (void *)cred->attcred.id.ptr, cred->rp.id);
342 r = FIDO_ERR_INVALID_ARGUMENT;
343 goto out;
344 }
345
346 if (fido_check_rp_id(cred->rp.id, cred->authdata.rp_id_hash) != 0) {
347 fido_log_debug("%s: fido_check_rp_id", __func__);
348 r = FIDO_ERR_INVALID_PARAM;
349 goto out;
350 }
351
352 if (fido_check_flags(cred->authdata.flags, FIDO_OPT_TRUE,
353 cred->uv) < 0) {
354 fido_log_debug("%s: fido_check_flags", __func__);
355 r = FIDO_ERR_INVALID_PARAM;
356 goto out;
357 }
358
359 if (check_extensions(cred->authdata_ext, cred->ext) < 0) {
360 fido_log_debug("%s: check_extensions", __func__);
361 r = FIDO_ERR_INVALID_PARAM;
362 goto out;
363 }
364
365 if (!strcmp(cred->fmt, "packed")) {
366 if (get_signed_hash_packed(&dgst, &cred->cdh,
367 &cred->authdata_cbor) < 0) {
368 fido_log_debug("%s: get_signed_hash_packed", __func__);
369 r = FIDO_ERR_INTERNAL;
370 goto out;
371 }
372 } else {
373 if (get_signed_hash_u2f(&dgst, cred->authdata.rp_id_hash,
374 sizeof(cred->authdata.rp_id_hash), &cred->cdh,
375 &cred->attcred.id, &cred->attcred.pubkey.es256) < 0) {
376 fido_log_debug("%s: get_signed_hash_u2f", __func__);
377 r = FIDO_ERR_INTERNAL;
378 goto out;
379 }
380 }
381
382 if (verify_sig(&dgst, &cred->attstmt.x5c, &cred->attstmt.sig) < 0) {
383 fido_log_debug("%s: verify_sig", __func__);
384 r = FIDO_ERR_INVALID_SIG;
385 goto out;
386 }
387
388 r = FIDO_OK;
389out:
390 explicit_bzero(buf, sizeof(buf));
391
392 return (r);
393}
394
395int
396fido_cred_verify_self(const fido_cred_t *cred)
397{
398 unsigned char buf[SHA256_DIGEST_LENGTH];
399 fido_blob_t dgst;
400 int ok = -1;
401 int r;
402
403 dgst.ptr = buf;
404 dgst.len = sizeof(buf);
405
406 /* do we have everything we need? */
407 if (cred->cdh.ptr == NULL || cred->authdata_cbor.ptr == NULL ||
408 cred->attstmt.x5c.ptr != NULL || cred->attstmt.sig.ptr == NULL ||
409 cred->fmt == NULL || cred->attcred.id.ptr == NULL ||
410 cred->rp.id == NULL) {
411 fido_log_debug("%s: cdh=%p, authdata=%p, x5c=%p, sig=%p, "
412 "fmt=%p id=%p, rp.id=%s", __func__, (void *)cred->cdh.ptr,
413 (void *)cred->authdata_cbor.ptr,
414 (void *)cred->attstmt.x5c.ptr,
415 (void *)cred->attstmt.sig.ptr, (void *)cred->fmt,
416 (void *)cred->attcred.id.ptr, cred->rp.id);
417 r = FIDO_ERR_INVALID_ARGUMENT;
418 goto out;
419 }
420
421 if (fido_check_rp_id(cred->rp.id, cred->authdata.rp_id_hash) != 0) {
422 fido_log_debug("%s: fido_check_rp_id", __func__);
423 r = FIDO_ERR_INVALID_PARAM;
424 goto out;
425 }
426
427 if (fido_check_flags(cred->authdata.flags, FIDO_OPT_TRUE,
428 cred->uv) < 0) {
429 fido_log_debug("%s: fido_check_flags", __func__);
430 r = FIDO_ERR_INVALID_PARAM;
431 goto out;
432 }
433
434 if (check_extensions(cred->authdata_ext, cred->ext) < 0) {
435 fido_log_debug("%s: check_extensions", __func__);
436 r = FIDO_ERR_INVALID_PARAM;
437 goto out;
438 }
439
440 if (!strcmp(cred->fmt, "packed")) {
441 if (get_signed_hash_packed(&dgst, &cred->cdh,
442 &cred->authdata_cbor) < 0) {
443 fido_log_debug("%s: get_signed_hash_packed", __func__);
444 r = FIDO_ERR_INTERNAL;
445 goto out;
446 }
447 } else {
448 if (get_signed_hash_u2f(&dgst, cred->authdata.rp_id_hash,
449 sizeof(cred->authdata.rp_id_hash), &cred->cdh,
450 &cred->attcred.id, &cred->attcred.pubkey.es256) < 0) {
451 fido_log_debug("%s: get_signed_hash_u2f", __func__);
452 r = FIDO_ERR_INTERNAL;
453 goto out;
454 }
455 }
456
457 switch (cred->attcred.type) {
458 case COSE_ES256:
459 ok = fido_verify_sig_es256(&dgst, &cred->attcred.pubkey.es256,
460 &cred->attstmt.sig);
461 break;
462 case COSE_RS256:
463 ok = fido_verify_sig_rs256(&dgst, &cred->attcred.pubkey.rs256,
464 &cred->attstmt.sig);
465 break;
466 case COSE_EDDSA:
467 ok = fido_verify_sig_eddsa(&dgst, &cred->attcred.pubkey.eddsa,
468 &cred->attstmt.sig);
469 break;
470 default:
471 fido_log_debug("%s: unsupported cose_alg %d", __func__,
472 cred->attcred.type);
473 r = FIDO_ERR_UNSUPPORTED_OPTION;
474 goto out;
475 }
476
477 if (ok < 0)
478 r = FIDO_ERR_INVALID_SIG;
479 else
480 r = FIDO_OK;
481
482out:
483 explicit_bzero(buf, sizeof(buf));
484
485 return (r);
486}
487
488fido_cred_t *
489fido_cred_new(void)
490{
491 return (calloc(1, sizeof(fido_cred_t)));
492}
493
494static void
495fido_cred_clean_authdata(fido_cred_t *cred)
496{
497 free(cred->authdata_cbor.ptr);
498 free(cred->attcred.id.ptr);
499
500 memset(&cred->authdata_ext, 0, sizeof(cred->authdata_ext));
501 memset(&cred->authdata_cbor, 0, sizeof(cred->authdata_cbor));
502 memset(&cred->authdata, 0, sizeof(cred->authdata));
503 memset(&cred->attcred, 0, sizeof(cred->attcred));
504}
505
506void
507fido_cred_reset_tx(fido_cred_t *cred)
508{
509 free(cred->cdh.ptr);
510 free(cred->rp.id);
511 free(cred->rp.name);
512 free(cred->user.id.ptr);
513 free(cred->user.icon);
514 free(cred->user.name);
515 free(cred->user.display_name);
516 fido_free_blob_array(&cred->excl);
517
518 memset(&cred->cdh, 0, sizeof(cred->cdh));
519 memset(&cred->rp, 0, sizeof(cred->rp));
520 memset(&cred->user, 0, sizeof(cred->user));
521 memset(&cred->excl, 0, sizeof(cred->excl));
522
523 cred->type = 0;
524 cred->ext = 0;
525 cred->rk = FIDO_OPT_OMIT;
526 cred->uv = FIDO_OPT_OMIT;
527}
528
529static void
530fido_cred_clean_x509(fido_cred_t *cred)
531{
532 free(cred->attstmt.x5c.ptr);
533 cred->attstmt.x5c.ptr = NULL;
534 cred->attstmt.x5c.len = 0;
535}
536
537static void
538fido_cred_clean_sig(fido_cred_t *cred)
539{
540 free(cred->attstmt.sig.ptr);
541 cred->attstmt.sig.ptr = NULL;
542 cred->attstmt.sig.len = 0;
543}
544
545void
546fido_cred_reset_rx(fido_cred_t *cred)
547{
548 free(cred->fmt);
549 cred->fmt = NULL;
550
551 fido_cred_clean_authdata(cred);
552 fido_cred_clean_x509(cred);
553 fido_cred_clean_sig(cred);
554}
555
556void
557fido_cred_free(fido_cred_t **cred_p)
558{
559 fido_cred_t *cred;
560
561 if (cred_p == NULL || (cred = *cred_p) == NULL)
562 return;
563
564 fido_cred_reset_tx(cred);
565 fido_cred_reset_rx(cred);
566
567 free(cred);
568
569 *cred_p = NULL;
570}
571
572int
573fido_cred_set_authdata(fido_cred_t *cred, const unsigned char *ptr, size_t len)
574{
575 cbor_item_t *item = NULL;
576 struct cbor_load_result cbor;
577 int r;
578
579 fido_cred_clean_authdata(cred);
580
581 if (ptr == NULL || len == 0) {
582 r = FIDO_ERR_INVALID_ARGUMENT;
583 goto fail;
584 }
585
586 if ((item = cbor_load(ptr, len, &cbor)) == NULL) {
587 fido_log_debug("%s: cbor_load", __func__);
588 r = FIDO_ERR_INVALID_ARGUMENT;
589 goto fail;
590 }
591
592 if (cbor_decode_cred_authdata(item, cred->type, &cred->authdata_cbor,
593 &cred->authdata, &cred->attcred, &cred->authdata_ext) < 0) {
594 fido_log_debug("%s: cbor_decode_cred_authdata", __func__);
595 r = FIDO_ERR_INVALID_ARGUMENT;
596 goto fail;
597 }
598
599 r = FIDO_OK;
600fail:
601 if (item != NULL)
602 cbor_decref(&item);
603
604 if (r != FIDO_OK)
605 fido_cred_clean_authdata(cred);
606
607 return (r);
608
609}
610
611int
612fido_cred_set_authdata_raw(fido_cred_t *cred, const unsigned char *ptr,
613 size_t len)
614{
615 cbor_item_t *item = NULL;
616 int r;
617
618 fido_cred_clean_authdata(cred);
619
620 if (ptr == NULL || len == 0) {
621 r = FIDO_ERR_INVALID_ARGUMENT;
622 goto fail;
623 }
624
625 if ((item = cbor_build_bytestring(ptr, len)) == NULL) {
626 fido_log_debug("%s: cbor_build_bytestring", __func__);
627 r = FIDO_ERR_INTERNAL;
628 goto fail;
629 }
630
631 if (cbor_decode_cred_authdata(item, cred->type, &cred->authdata_cbor,
632 &cred->authdata, &cred->attcred, &cred->authdata_ext) < 0) {
633 fido_log_debug("%s: cbor_decode_cred_authdata", __func__);
634 r = FIDO_ERR_INVALID_ARGUMENT;
635 goto fail;
636 }
637
638 r = FIDO_OK;
639fail:
640 if (item != NULL)
641 cbor_decref(&item);
642
643 if (r != FIDO_OK)
644 fido_cred_clean_authdata(cred);
645
646 return (r);
647
648}
649
650int
651fido_cred_set_x509(fido_cred_t *cred, const unsigned char *ptr, size_t len)
652{
653 unsigned char *x509;
654
655 fido_cred_clean_x509(cred);
656
657 if (ptr == NULL || len == 0)
658 return (FIDO_ERR_INVALID_ARGUMENT);
659 if ((x509 = malloc(len)) == NULL)
660 return (FIDO_ERR_INTERNAL);
661
662 memcpy(x509, ptr, len);
663 cred->attstmt.x5c.ptr = x509;
664 cred->attstmt.x5c.len = len;
665
666 return (FIDO_OK);
667}
668
669int
670fido_cred_set_sig(fido_cred_t *cred, const unsigned char *ptr, size_t len)
671{
672 unsigned char *sig;
673
674 fido_cred_clean_sig(cred);
675
676 if (ptr == NULL || len == 0)
677 return (FIDO_ERR_INVALID_ARGUMENT);
678 if ((sig = malloc(len)) == NULL)
679 return (FIDO_ERR_INTERNAL);
680
681 memcpy(sig, ptr, len);
682 cred->attstmt.sig.ptr = sig;
683 cred->attstmt.sig.len = len;
684
685 return (FIDO_OK);
686}
687
688int
689fido_cred_exclude(fido_cred_t *cred, const unsigned char *id_ptr, size_t id_len)
690{
691 fido_blob_t id_blob;
692 fido_blob_t *list_ptr;
693
694 memset(&id_blob, 0, sizeof(id_blob));
695
696 if (fido_blob_set(&id_blob, id_ptr, id_len) < 0)
697 return (FIDO_ERR_INVALID_ARGUMENT);
698
699 if (cred->excl.len == SIZE_MAX) {
700 free(id_blob.ptr);
701 return (FIDO_ERR_INVALID_ARGUMENT);
702 }
703
704 if ((list_ptr = recallocarray(cred->excl.ptr, cred->excl.len,
705 cred->excl.len + 1, sizeof(fido_blob_t))) == NULL) {
706 free(id_blob.ptr);
707 return (FIDO_ERR_INTERNAL);
708 }
709
710 list_ptr[cred->excl.len++] = id_blob;
711 cred->excl.ptr = list_ptr;
712
713 return (FIDO_OK);
714}
715
716int
717fido_cred_set_clientdata_hash(fido_cred_t *cred, const unsigned char *hash,
718 size_t hash_len)
719{
720 if (fido_blob_set(&cred->cdh, hash, hash_len) < 0)
721 return (FIDO_ERR_INVALID_ARGUMENT);
722
723 return (FIDO_OK);
724}
725
726int
727fido_cred_set_rp(fido_cred_t *cred, const char *id, const char *name)
728{
729 fido_rp_t *rp = &cred->rp;
730
731 if (rp->id != NULL) {
732 free(rp->id);
733 rp->id = NULL;
734 }
735 if (rp->name != NULL) {
736 free(rp->name);
737 rp->name = NULL;
738 }
739
740 if (id != NULL && (rp->id = strdup(id)) == NULL)
741 goto fail;
742 if (name != NULL && (rp->name = strdup(name)) == NULL)
743 goto fail;
744
745 return (FIDO_OK);
746fail:
747 free(rp->id);
748 free(rp->name);
749 rp->id = NULL;
750 rp->name = NULL;
751
752 return (FIDO_ERR_INTERNAL);
753}
754
755int
756fido_cred_set_user(fido_cred_t *cred, const unsigned char *user_id,
757 size_t user_id_len, const char *name, const char *display_name,
758 const char *icon)
759{
760 fido_user_t *up = &cred->user;
761
762 if (up->id.ptr != NULL) {
763 free(up->id.ptr);
764 up->id.ptr = NULL;
765 up->id.len = 0;
766 }
767 if (up->name != NULL) {
768 free(up->name);
769 up->name = NULL;
770 }
771 if (up->display_name != NULL) {
772 free(up->display_name);
773 up->display_name = NULL;
774 }
775 if (up->icon != NULL) {
776 free(up->icon);
777 up->icon = NULL;
778 }
779
780 if (user_id != NULL) {
781 if ((up->id.ptr = malloc(user_id_len)) == NULL)
782 goto fail;
783 memcpy(up->id.ptr, user_id, user_id_len);
784 up->id.len = user_id_len;
785 }
786 if (name != NULL && (up->name = strdup(name)) == NULL)
787 goto fail;
788 if (display_name != NULL &&
789 (up->display_name = strdup(display_name)) == NULL)
790 goto fail;
791 if (icon != NULL && (up->icon = strdup(icon)) == NULL)
792 goto fail;
793
794 return (FIDO_OK);
795fail:
796 free(up->id.ptr);
797 free(up->name);
798 free(up->display_name);
799 free(up->icon);
800
801 up->id.ptr = NULL;
802 up->id.len = 0;
803 up->name = NULL;
804 up->display_name = NULL;
805 up->icon = NULL;
806
807 return (FIDO_ERR_INTERNAL);
808}
809
810int
811fido_cred_set_extensions(fido_cred_t *cred, int ext)
812{
813 if (ext != 0 && ext != FIDO_EXT_HMAC_SECRET)
814 return (FIDO_ERR_INVALID_ARGUMENT);
815
816 cred->ext = ext;
817
818 return (FIDO_OK);
819}
820
821int
822fido_cred_set_options(fido_cred_t *cred, bool rk, bool uv)
823{
824 cred->rk = rk ? FIDO_OPT_TRUE : FIDO_OPT_FALSE;
825 cred->uv = uv ? FIDO_OPT_TRUE : FIDO_OPT_FALSE;
826
827 return (FIDO_OK);
828}
829
830int
831fido_cred_set_rk(fido_cred_t *cred, fido_opt_t rk)
832{
833 cred->rk = rk;
834
835 return (FIDO_OK);
836}
837
838int
839fido_cred_set_uv(fido_cred_t *cred, fido_opt_t uv)
840{
841 cred->uv = uv;
842
843 return (FIDO_OK);
844}
845
846int
847fido_cred_set_fmt(fido_cred_t *cred, const char *fmt)
848{
849 free(cred->fmt);
850 cred->fmt = NULL;
851
852 if (fmt == NULL)
853 return (FIDO_ERR_INVALID_ARGUMENT);
854
855 if (strcmp(fmt, "packed") && strcmp(fmt, "fido-u2f"))
856 return (FIDO_ERR_INVALID_ARGUMENT);
857
858 if ((cred->fmt = strdup(fmt)) == NULL)
859 return (FIDO_ERR_INTERNAL);
860
861 return (FIDO_OK);
862}
863
864int
865fido_cred_set_type(fido_cred_t *cred, int cose_alg)
866{
867 if ((cose_alg != COSE_ES256 && cose_alg != COSE_RS256 &&
868 cose_alg != COSE_EDDSA) || cred->type != 0)
869 return (FIDO_ERR_INVALID_ARGUMENT);
870
871 cred->type = cose_alg;
872
873 return (FIDO_OK);
874}
875
876int
877fido_cred_type(const fido_cred_t *cred)
878{
879 return (cred->type);
880}
881
882uint8_t
883fido_cred_flags(const fido_cred_t *cred)
884{
885 return (cred->authdata.flags);
886}
887
888const unsigned char *
889fido_cred_clientdata_hash_ptr(const fido_cred_t *cred)
890{
891 return (cred->cdh.ptr);
892}
893
894size_t
895fido_cred_clientdata_hash_len(const fido_cred_t *cred)
896{
897 return (cred->cdh.len);
898}
899
900const unsigned char *
901fido_cred_x5c_ptr(const fido_cred_t *cred)
902{
903 return (cred->attstmt.x5c.ptr);
904}
905
906size_t
907fido_cred_x5c_len(const fido_cred_t *cred)
908{
909 return (cred->attstmt.x5c.len);
910}
911
912const unsigned char *
913fido_cred_sig_ptr(const fido_cred_t *cred)
914{
915 return (cred->attstmt.sig.ptr);
916}
917
918size_t
919fido_cred_sig_len(const fido_cred_t *cred)
920{
921 return (cred->attstmt.sig.len);
922}
923
924const unsigned char *
925fido_cred_authdata_ptr(const fido_cred_t *cred)
926{
927 return (cred->authdata_cbor.ptr);
928}
929
930size_t
931fido_cred_authdata_len(const fido_cred_t *cred)
932{
933 return (cred->authdata_cbor.len);
934}
935
936const unsigned char *
937fido_cred_pubkey_ptr(const fido_cred_t *cred)
938{
939 const void *ptr;
940
941 switch (cred->attcred.type) {
942 case COSE_ES256:
943 ptr = &cred->attcred.pubkey.es256;
944 break;
945 case COSE_RS256:
946 ptr = &cred->attcred.pubkey.rs256;
947 break;
948 case COSE_EDDSA:
949 ptr = &cred->attcred.pubkey.eddsa;
950 break;
951 default:
952 ptr = NULL;
953 break;
954 }
955
956 return (ptr);
957}
958
959size_t
960fido_cred_pubkey_len(const fido_cred_t *cred)
961{
962 size_t len;
963
964 switch (cred->attcred.type) {
965 case COSE_ES256:
966 len = sizeof(cred->attcred.pubkey.es256);
967 break;
968 case COSE_RS256:
969 len = sizeof(cred->attcred.pubkey.rs256);
970 break;
971 case COSE_EDDSA:
972 len = sizeof(cred->attcred.pubkey.eddsa);
973 break;
974 default:
975 len = 0;
976 break;
977 }
978
979 return (len);
980}
981
982const unsigned char *
983fido_cred_id_ptr(const fido_cred_t *cred)
984{
985 return (cred->attcred.id.ptr);
986}
987
988size_t
989fido_cred_id_len(const fido_cred_t *cred)
990{
991 return (cred->attcred.id.len);
992}
993
994const char *
995fido_cred_fmt(const fido_cred_t *cred)
996{
997 return (cred->fmt);
998}
999
1000const char *
1001fido_cred_rp_id(const fido_cred_t *cred)
1002{
1003 return (cred->rp.id);
1004}
1005
1006const char *
1007fido_cred_rp_name(const fido_cred_t *cred)
1008{
1009 return (cred->rp.name);
1010}
1011
1012const char *
1013fido_cred_user_name(const fido_cred_t *cred)
1014{
1015 return (cred->user.name);
1016}
1017
1018const char *
1019fido_cred_display_name(const fido_cred_t *cred)
1020{
1021 return (cred->user.display_name);
1022}
1023
1024const unsigned char *
1025fido_cred_user_id_ptr(const fido_cred_t *cred)
1026{
1027 return (cred->user.id.ptr);
1028}
1029
1030size_t
1031fido_cred_user_id_len(const fido_cred_t *cred)
1032{
1033 return (cred->user.id.len);
1034}