diff --git a/src/cbor.c b/src/cbor.c index ab99b34d..c86a4a19 100644 --- a/src/cbor.c +++ b/src/cbor.c @@ -1386,12 +1386,31 @@ cbor_decode_assert_authdata(const cbor_item_t *item, fido_blob_t *authdata_cbor, static int decode_x5c(const cbor_item_t *item, void *arg) { - fido_blob_t *x5c = arg; + fido_blob_array_t *x5c = arg; + fido_blob_t *list_ptr; + fido_blob_t blob; - if (x5c->len) - return (0); /* ignore */ + memset(&blob, 0, sizeof(blob)); - return (fido_blob_decode(item, x5c)); + if (x5c->len == SIZE_MAX) { + fido_log_debug("%s: len", __func__); + return (-1); + } + if (fido_blob_decode(item, &blob) != 0) { + fido_log_debug("%s: fido_blob_decode", __func__); + return (-1); + } + if ((list_ptr = recallocarray(x5c->ptr, x5c->len, x5c->len + 1, + sizeof(blob))) == NULL) { + fido_log_debug("%s: recallocarray", __func__); + fido_blob_reset(&blob); + return (-1); + } + + list_ptr[x5c->len++] = blob; + x5c->ptr = list_ptr; + + return (0); } static int @@ -1427,6 +1446,7 @@ decode_attstmt_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg) goto out; } } else if (!strcmp(name, "x5c")) { + fido_free_blob_array(&attstmt->x5c); /* XXX */ if (cbor_isa_array(val) == false || cbor_array_is_definite(val) == false || cbor_array_iter(val, &attstmt->x5c, decode_x5c) < 0) { diff --git a/src/cred.c b/src/cred.c index 4a7a7257..d63b04cc 100644 --- a/src/cred.c +++ b/src/cred.c @@ -279,20 +279,26 @@ get_signed_hash_u2f(fido_blob_t *dgst, const unsigned char *rp_id, static int verify_attstmt(const fido_blob_t *dgst, const fido_attstmt_t *attstmt) { + const fido_blob_t *blob; BIO *rawcert = NULL; X509 *cert = NULL; EVP_PKEY *pkey = NULL; int ok = -1; + /* XXX: only leaf certificate */ + if ((blob = attstmt->x5c.ptr) == NULL || blob->ptr == NULL) { + fido_log_debug("%s: x5c", __func__); + return (-1); + } + /* openssl needs ints */ - if (attstmt->x5c.len > INT_MAX) { - fido_log_debug("%s: x5c.len=%zu", __func__, attstmt->x5c.len); + if (blob->len > INT_MAX) { + fido_log_debug("%s: blob.len=%zu", __func__, blob->len); return (-1); } /* fetch key from x509 */ - if ((rawcert = BIO_new_mem_buf(attstmt->x5c.ptr, - (int)attstmt->x5c.len)) == NULL || + if ((rawcert = BIO_new_mem_buf(blob->ptr, (int)blob->len)) == NULL || (cert = d2i_X509_bio(rawcert, NULL)) == NULL || (pkey = X509_get_pubkey(cert)) == NULL) { fido_log_debug("%s: x509 key", __func__); @@ -543,7 +549,7 @@ fido_cred_clean_attstmt(fido_attstmt_t *attstmt) fido_blob_reset(&attstmt->certinfo); fido_blob_reset(&attstmt->pubarea); fido_blob_reset(&attstmt->cbor); - fido_blob_reset(&attstmt->x5c); + fido_free_blob_array(&attstmt->x5c); fido_blob_reset(&attstmt->sig); memset(attstmt, 0, sizeof(*attstmt)); @@ -688,9 +694,23 @@ fido_cred_set_id(fido_cred_t *cred, const unsigned char *ptr, size_t len) int fido_cred_set_x509(fido_cred_t *cred, const unsigned char *ptr, size_t len) { - if (fido_blob_set(&cred->attstmt.x5c, ptr, len) < 0) + fido_blob_t blob; + + memset(&blob, 0, sizeof(blob)); + + if (fido_blob_set(&blob, ptr, len) < 0) return (FIDO_ERR_INVALID_ARGUMENT); + /* compat: sets only a leaf certificate */ + fido_free_blob_array(&cred->attstmt.x5c); + if ((cred->attstmt.x5c.ptr = recallocarray(NULL, 0, 1, + sizeof(blob))) == NULL) { + fido_blob_reset(&blob); + return (FIDO_ERR_INTERNAL); + } + cred->attstmt.x5c.ptr[0] = blob; + cred->attstmt.x5c.len = 1; + return (FIDO_OK); } @@ -1027,16 +1047,34 @@ fido_cred_clientdata_hash_len(const fido_cred_t *cred) return (cred->cdh.len); } +const unsigned char * +fido_cred_x5c_cert_ptr(const fido_cred_t *cred, size_t idx) +{ + if (idx >= cred->attstmt.x5c.len) + return NULL; + + return (cred->attstmt.x5c.ptr[idx].ptr); +} + const unsigned char * fido_cred_x5c_ptr(const fido_cred_t *cred) { - return (cred->attstmt.x5c.ptr); + return (fido_cred_x5c_cert_ptr(cred, 0)); +} + +size_t +fido_cred_x5c_cert_len(const fido_cred_t *cred, size_t idx) +{ + if (idx >= cred->attstmt.x5c.len) + return 0; + + return (cred->attstmt.x5c.ptr[idx].len); } size_t fido_cred_x5c_len(const fido_cred_t *cred) { - return (cred->attstmt.x5c.len); + return (fido_cred_x5c_cert_len(cred, 0)); } const unsigned char * diff --git a/src/fido.h b/src/fido.h index 914e3776..11c42603 100644 --- a/src/fido.h +++ b/src/fido.h @@ -124,6 +124,7 @@ const unsigned char *fido_cred_pubkey_ptr(const fido_cred_t *); const unsigned char *fido_cred_sig_ptr(const fido_cred_t *); const unsigned char *fido_cred_user_id_ptr(const fido_cred_t *); const unsigned char *fido_cred_x5c_ptr(const fido_cred_t *); +const unsigned char *fido_cred_x5c_cert_ptr(const fido_cred_t *, size_t); int fido_assert_allow_cred(fido_assert_t *, const unsigned char *, size_t); int fido_assert_empty_allow_list(fido_assert_t *); @@ -226,6 +227,7 @@ size_t fido_cred_pubkey_len(const fido_cred_t *); size_t fido_cred_sig_len(const fido_cred_t *); size_t fido_cred_user_id_len(const fido_cred_t *); size_t fido_cred_x5c_len(const fido_cred_t *); +size_t fido_cred_x5c_cert_len(const fido_cred_t *, size_t); uint8_t fido_assert_flags(const fido_assert_t *, size_t); uint32_t fido_assert_sigcount(const fido_assert_t *, size_t); diff --git a/src/fido/types.h b/src/fido/types.h index 01d68200..0aaa8cb6 100644 --- a/src/fido/types.h +++ b/src/fido/types.h @@ -140,12 +140,12 @@ typedef struct fido_attcred { } fido_attcred_t; typedef struct fido_attstmt { - fido_blob_t certinfo; /* tpm attestation TPMS_ATTEST structure */ - fido_blob_t pubarea; /* tpm attestation TPMT_PUBLIC structure */ - fido_blob_t cbor; /* cbor-encoded attestation statement */ - fido_blob_t x5c; /* attestation certificate */ - fido_blob_t sig; /* attestation signature */ - int alg; /* attestation algorithm (cose) */ + fido_blob_t certinfo; /* tpm attestation TPMS_ATTEST structure */ + fido_blob_t pubarea; /* tpm attestation TPMT_PUBLIC structure */ + fido_blob_t cbor; /* cbor-encoded attestation statement */ + fido_blob_array_t x5c; /* attestation certificate chain */ + fido_blob_t sig; /* attestation signature */ + int alg; /* attestation algorithm (cose) */ } fido_attstmt_t; typedef struct fido_rp {