summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/CMakeLists.txt8
-rw-r--r--src/bio.c11
-rw-r--r--src/cbor.c105
-rw-r--r--src/cred.c108
-rw-r--r--src/credman.c11
-rw-r--r--src/dev.c11
-rw-r--r--src/export.gnu4
-rw-r--r--src/export.llvm4
-rw-r--r--src/export.msvc4
-rw-r--r--src/extern.h24
-rw-r--r--src/fido.h4
-rw-r--r--src/fido/param.h2
-rw-r--r--src/fido/types.h12
-rw-r--r--src/hid_linux.c36
-rw-r--r--src/hid_netbsd.c6
-rw-r--r--src/hid_osx.c40
-rw-r--r--src/pin.c2
-rw-r--r--src/rs1.c53
-rw-r--r--src/rs256.c53
-rw-r--r--src/winhello.c50
20 files changed, 342 insertions, 206 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 73493b1..4c54198 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -151,8 +151,6 @@ endif()
install(FILES fido.h DESTINATION include)
install(DIRECTORY fido DESTINATION include)
-if(NOT MSVC)
- configure_file(libfido2.pc.in libfido2.pc @ONLY)
- install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libfido2.pc"
- DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
-endif()
+configure_file(libfido2.pc.in libfido2.pc @ONLY)
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libfido2.pc"
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
diff --git a/src/bio.c b/src/bio.c
index 57db85f..3d73bf0 100644
--- a/src/bio.c
+++ b/src/bio.c
@@ -57,6 +57,15 @@ fail:
return (ok);
}
+static uint8_t
+bio_get_cmd(const fido_dev_t *dev)
+{
+ if (dev->flags & (FIDO_DEV_BIO_SET|FIDO_DEV_BIO_UNSET))
+ return (CTAP_CBOR_BIO_ENROLL);
+
+ return (CTAP_CBOR_BIO_ENROLL_PRE);
+}
+
static int
bio_tx(fido_dev_t *dev, uint8_t subcmd, cbor_item_t **sub_argv, size_t sub_argc,
const char *pin, const fido_blob_t *token, int *ms)
@@ -66,7 +75,7 @@ bio_tx(fido_dev_t *dev, uint8_t subcmd, cbor_item_t **sub_argv, size_t sub_argc,
fido_blob_t *ecdh = NULL;
fido_blob_t f;
fido_blob_t hmac;
- const uint8_t cmd = CTAP_CBOR_BIO_ENROLL_PRE;
+ const uint8_t cmd = bio_get_cmd(dev);
int r = FIDO_ERR_INTERNAL;
memset(&f, 0, sizeof(f));
diff --git a/src/cbor.c b/src/cbor.c
index ab99b34..b242cfa 100644
--- a/src/cbor.c
+++ b/src/cbor.c
@@ -1133,6 +1133,64 @@ fail:
}
static int
+decode_attobj(const cbor_item_t *key, const cbor_item_t *val, void *arg)
+{
+ fido_cred_t *cred = arg;
+ char *name = NULL;
+ int ok = -1;
+
+ if (cbor_string_copy(key, &name) < 0) {
+ fido_log_debug("%s: cbor type", __func__);
+ ok = 0; /* ignore */
+ goto fail;
+ }
+
+ if (!strcmp(name, "fmt")) {
+ if (cbor_decode_fmt(val, &cred->fmt) < 0) {
+ fido_log_debug("%s: cbor_decode_fmt", __func__);
+ goto fail;
+ }
+ } else if (!strcmp(name, "attStmt")) {
+ if (cbor_decode_attstmt(val, &cred->attstmt) < 0) {
+ fido_log_debug("%s: cbor_decode_attstmt", __func__);
+ goto fail;
+ }
+ } else if (!strcmp(name, "authData")) {
+ if (fido_blob_decode(val, &cred->authdata_raw) < 0) {
+ fido_log_debug("%s: fido_blob_decode", __func__);
+ goto fail;
+ }
+ if (cbor_decode_cred_authdata(val, cred->type,
+ &cred->authdata_cbor, &cred->authdata, &cred->attcred,
+ &cred->authdata_ext) < 0) {
+ fido_log_debug("%s: cbor_decode_cred_authdata",
+ __func__);
+ goto fail;
+ }
+ }
+
+ ok = 0;
+fail:
+ free(name);
+
+ return (ok);
+}
+
+/* XXX introduce fido_attobj_t? */
+int
+cbor_decode_attobj(const cbor_item_t *item, fido_cred_t *cred)
+{
+ if (cbor_isa_map(item) == false ||
+ cbor_map_is_definite(item) == false ||
+ cbor_map_iter(item, cred, decode_attobj) < 0) {
+ fido_log_debug("%s: cbor type", __func__);
+ return (-1);
+ }
+
+ return (0);
+}
+
+static int
decode_cred_extension(const cbor_item_t *key, const cbor_item_t *val, void *arg)
{
fido_cred_ext_t *authdata_ext = arg;
@@ -1386,12 +1444,47 @@ 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 = NULL;
+ fido_blob_t x5c_blob;
+
+ memset(&x5c_blob, 0, sizeof(x5c_blob));
+
+ if (fido_blob_decode(item, &x5c_blob) < 0) {
+ fido_log_debug("%s: fido_blob_decode", __func__);
+ return (-1);
+ }
+
+ if (x5c->len == SIZE_MAX) {
+ fido_blob_reset(&x5c_blob);
+ return (-1);
+ }
+
+ if ((list_ptr = recallocarray(x5c->ptr, x5c->len,
+ x5c->len + 1, sizeof(x5c_blob))) == NULL) {
+ fido_blob_reset(&x5c_blob);
+ return (-1);
+ }
+
+ list_ptr[x5c->len++] = x5c_blob;
+ x5c->ptr = list_ptr;
- if (x5c->len)
- return (0); /* ignore */
+ return (0);
+}
- return (fido_blob_decode(item, x5c));
+static int
+decode_x5c_array(const cbor_item_t *item, fido_blob_array_t *arr)
+{
+ if (arr->len) {
+ fido_log_debug("%s: dup", __func__);
+ return (-1);
+ }
+ if (cbor_isa_array(item) == false ||
+ cbor_array_is_definite(item) == false) {
+ fido_log_debug("%s: cbor", __func__);
+ return (-1);
+ }
+ return (cbor_array_iter(item, arr, decode_x5c));
}
static int
@@ -1427,9 +1520,7 @@ decode_attstmt_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg)
goto out;
}
} else if (!strcmp(name, "x5c")) {
- if (cbor_isa_array(val) == false ||
- cbor_array_is_definite(val) == false ||
- cbor_array_iter(val, &attstmt->x5c, decode_x5c) < 0) {
+ if (decode_x5c_array(val, &attstmt->x5c)) {
fido_log_debug("%s: x5c", __func__);
goto out;
}
diff --git a/src/cred.c b/src/cred.c
index 4a7a725..2e52d2b 100644
--- a/src/cred.c
+++ b/src/cred.c
@@ -284,15 +284,21 @@ verify_attstmt(const fido_blob_t *dgst, const fido_attstmt_t *attstmt)
EVP_PKEY *pkey = NULL;
int ok = -1;
- /* openssl needs ints */
- if (attstmt->x5c.len > INT_MAX) {
+ if (!attstmt->x5c.len) {
fido_log_debug("%s: x5c.len=%zu", __func__, attstmt->x5c.len);
return (-1);
}
+ /* openssl needs ints */
+ if (attstmt->x5c.ptr[0].len > INT_MAX) {
+ fido_log_debug("%s: x5c[0].len=%zu", __func__,
+ attstmt->x5c.ptr[0].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(attstmt->x5c.ptr[0].ptr,
+ (int)attstmt->x5c.ptr[0].len)) == NULL ||
(cert = d2i_X509_bio(rawcert, NULL)) == NULL ||
(pkey = X509_get_pubkey(cert)) == NULL) {
fido_log_debug("%s: x509 key", __func__);
@@ -543,12 +549,21 @@ 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));
}
+static void
+fido_cred_clean_attobj(fido_cred_t *cred)
+{
+ free(cred->fmt);
+ cred->fmt = NULL;
+ fido_cred_clean_authdata(cred);
+ fido_cred_clean_attstmt(&cred->attstmt);
+}
+
void
fido_cred_reset_tx(fido_cred_t *cred)
{
@@ -576,10 +591,7 @@ fido_cred_reset_tx(fido_cred_t *cred)
void
fido_cred_reset_rx(fido_cred_t *cred)
{
- free(cred->fmt);
- cred->fmt = NULL;
- fido_cred_clean_authdata(cred);
- fido_cred_clean_attstmt(&cred->attstmt);
+ fido_cred_clean_attobj(cred);
fido_blob_reset(&cred->largeblob_key);
}
@@ -688,8 +700,29 @@ 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 x5c_blob;
+ fido_blob_t *list_ptr = NULL;
+
+ memset(&x5c_blob, 0, sizeof(x5c_blob));
+ fido_free_blob_array(&cred->attstmt.x5c);
+
+ if (fido_blob_set(&x5c_blob, ptr, len) < 0)
+ return (FIDO_ERR_INVALID_ARGUMENT);
+
+ if (cred->attstmt.x5c.len == SIZE_MAX) {
+ fido_blob_reset(&x5c_blob);
return (FIDO_ERR_INVALID_ARGUMENT);
+ }
+
+ if ((list_ptr = recallocarray(cred->attstmt.x5c.ptr,
+ cred->attstmt.x5c.len, cred->attstmt.x5c.len + 1,
+ sizeof(x5c_blob))) == NULL) {
+ fido_blob_reset(&x5c_blob);
+ return (FIDO_ERR_INTERNAL);
+ }
+
+ list_ptr[cred->attstmt.x5c.len++] = x5c_blob;
+ cred->attstmt.x5c.ptr = list_ptr;
return (FIDO_OK);
}
@@ -737,6 +770,35 @@ fail:
}
int
+fido_cred_set_attobj(fido_cred_t *cred, const unsigned char *ptr, size_t len)
+{
+ cbor_item_t *item = NULL;
+ struct cbor_load_result cbor;
+ int r = FIDO_ERR_INVALID_ARGUMENT;
+
+ fido_cred_clean_attobj(cred);
+
+ if (ptr == NULL || len == 0)
+ goto fail;
+
+ if ((item = cbor_load(ptr, len, &cbor)) == NULL) {
+ fido_log_debug("%s: cbor_load", __func__);
+ goto fail;
+ }
+ if (cbor_decode_attobj(item, cred) != 0) {
+ fido_log_debug("%s: cbor_decode_attobj", __func__);
+ goto fail;
+ }
+
+ r = FIDO_OK;
+fail:
+ if (item != NULL)
+ cbor_decref(&item);
+
+ return (r);
+}
+
+int
fido_cred_exclude(fido_cred_t *cred, const unsigned char *id_ptr, size_t id_len)
{
fido_blob_t id_blob;
@@ -1030,16 +1092,40 @@ fido_cred_clientdata_hash_len(const fido_cred_t *cred)
const unsigned char *
fido_cred_x5c_ptr(const fido_cred_t *cred)
{
- return (cred->attstmt.x5c.ptr);
+ return (fido_cred_x5c_list_ptr(cred, 0));
}
size_t
fido_cred_x5c_len(const fido_cred_t *cred)
{
+ return (fido_cred_x5c_list_len(cred, 0));
+}
+
+size_t
+fido_cred_x5c_list_count(const fido_cred_t *cred)
+{
return (cred->attstmt.x5c.len);
}
const unsigned char *
+fido_cred_x5c_list_ptr(const fido_cred_t *cred, size_t i)
+{
+ if (i >= cred->attstmt.x5c.len)
+ return (NULL);
+
+ return (cred->attstmt.x5c.ptr[i].ptr);
+}
+
+size_t
+fido_cred_x5c_list_len(const fido_cred_t *cred, size_t i)
+{
+ if (i >= cred->attstmt.x5c.len)
+ return (0);
+
+ return (cred->attstmt.x5c.ptr[i].len);
+}
+
+const unsigned char *
fido_cred_sig_ptr(const fido_cred_t *cred)
{
return (cred->attstmt.sig.ptr);
diff --git a/src/credman.c b/src/credman.c
index c364242..898de14 100644
--- a/src/credman.c
+++ b/src/credman.c
@@ -111,6 +111,15 @@ fail:
return (ok);
}
+static uint8_t
+credman_get_cmd(const fido_dev_t *dev)
+{
+ if (dev->flags & FIDO_DEV_CREDMAN)
+ return (CTAP_CBOR_CRED_MGMT);
+
+ return (CTAP_CBOR_CRED_MGMT_PRE);
+}
+
static int
credman_tx(fido_dev_t *dev, uint8_t subcmd, const void *param, const char *pin,
const char *rp_id, fido_opt_t uv, int *ms)
@@ -120,7 +129,7 @@ credman_tx(fido_dev_t *dev, uint8_t subcmd, const void *param, const char *pin,
fido_blob_t hmac;
es256_pk_t *pk = NULL;
cbor_item_t *argv[4];
- const uint8_t cmd = CTAP_CBOR_CRED_MGMT_PRE;
+ const uint8_t cmd = credman_get_cmd(dev);
int r = FIDO_ERR_INTERNAL;
memset(&f, 0, sizeof(f));
diff --git a/src/dev.c b/src/dev.c
index 2d662a6..e9e26e7 100644
--- a/src/dev.c
+++ b/src/dev.c
@@ -46,16 +46,21 @@ fido_dev_set_option_flags(fido_dev_t *dev, const fido_cbor_info_t *info)
if (strcmp(ptr[i], "clientPin") == 0) {
dev->flags |= val[i] ?
FIDO_DEV_PIN_SET : FIDO_DEV_PIN_UNSET;
- } else if (strcmp(ptr[i], "credMgmt") == 0 ||
- strcmp(ptr[i], "credentialMgmtPreview") == 0) {
+ } else if (strcmp(ptr[i], "credMgmt") == 0) {
if (val[i])
dev->flags |= FIDO_DEV_CREDMAN;
+ } else if (strcmp(ptr[i], "credentialMgmtPreview") == 0) {
+ if (val[i])
+ dev->flags |= FIDO_DEV_CREDMAN_PRE;
} else if (strcmp(ptr[i], "uv") == 0) {
dev->flags |= val[i] ?
FIDO_DEV_UV_SET : FIDO_DEV_UV_UNSET;
} else if (strcmp(ptr[i], "pinUvAuthToken") == 0) {
if (val[i])
dev->flags |= FIDO_DEV_TOKEN_PERMS;
+ } else if (strcmp(ptr[i], "bioEnroll") == 0) {
+ dev->flags |= val[i] ?
+ FIDO_DEV_BIO_SET : FIDO_DEV_BIO_UNSET;
}
}
@@ -538,7 +543,7 @@ fido_dev_supports_cred_prot(const fido_dev_t *dev)
bool
fido_dev_supports_credman(const fido_dev_t *dev)
{
- return (dev->flags & FIDO_DEV_CREDMAN);
+ return (dev->flags & (FIDO_DEV_CREDMAN|FIDO_DEV_CREDMAN_PRE));
}
bool
diff --git a/src/export.gnu b/src/export.gnu
index ea6ca7d..134dcf0 100644
--- a/src/export.gnu
+++ b/src/export.gnu
@@ -169,6 +169,7 @@
fido_cred_rp_id;
fido_cred_rp_name;
fido_cred_set_attstmt;
+ fido_cred_set_attobj;
fido_cred_set_authdata;
fido_cred_set_authdata_raw;
fido_cred_set_blob;
@@ -196,6 +197,9 @@
fido_cred_verify;
fido_cred_verify_self;
fido_cred_x5c_len;
+ fido_cred_x5c_list_count;
+ fido_cred_x5c_list_len;
+ fido_cred_x5c_list_ptr;
fido_cred_x5c_ptr;
fido_dev_build;
fido_dev_cancel;
diff --git a/src/export.llvm b/src/export.llvm
index 2a92381..fa1a809 100644
--- a/src/export.llvm
+++ b/src/export.llvm
@@ -167,6 +167,7 @@ _fido_cred_pubkey_ptr
_fido_cred_rp_id
_fido_cred_rp_name
_fido_cred_set_attstmt
+_fido_cred_set_attobj
_fido_cred_set_authdata
_fido_cred_set_authdata_raw
_fido_cred_set_blob
@@ -194,6 +195,9 @@ _fido_cred_user_name
_fido_cred_verify
_fido_cred_verify_self
_fido_cred_x5c_len
+_fido_cred_x5c_list_count
+_fido_cred_x5c_list_len
+_fido_cred_x5c_list_ptr
_fido_cred_x5c_ptr
_fido_dev_build
_fido_dev_cancel
diff --git a/src/export.msvc b/src/export.msvc
index c5b2edc..241b17f 100644
--- a/src/export.msvc
+++ b/src/export.msvc
@@ -168,6 +168,7 @@ fido_cred_pubkey_ptr
fido_cred_rp_id
fido_cred_rp_name
fido_cred_set_attstmt
+fido_cred_set_attobj
fido_cred_set_authdata
fido_cred_set_authdata_raw
fido_cred_set_blob
@@ -195,6 +196,9 @@ fido_cred_user_name
fido_cred_verify
fido_cred_verify_self
fido_cred_x5c_len
+fido_cred_x5c_list_count
+fido_cred_x5c_list_len
+fido_cred_x5c_list_ptr
fido_cred_x5c_ptr
fido_dev_build
fido_dev_cancel
diff --git a/src/extern.h b/src/extern.h
index 1bc95b2..93b209d 100644
--- a/src/extern.h
+++ b/src/extern.h
@@ -58,6 +58,7 @@ cbor_item_t *es256_pk_encode(const es256_pk_t *, int);
/* cbor decoding functions */
int cbor_decode_attstmt(const cbor_item_t *, fido_attstmt_t *);
+int cbor_decode_attobj(const cbor_item_t *, fido_cred_t *);
int cbor_decode_bool(const cbor_item_t *, bool *);
int cbor_decode_cred_authdata(const cbor_item_t *, int, fido_blob_t *,
fido_authdata_t *, fido_attcred_t *, fido_cred_ext_t *);
@@ -249,16 +250,19 @@ uint32_t uniform_random(uint32_t);
#endif
/* internal device capability flags */
-#define FIDO_DEV_PIN_SET 0x001
-#define FIDO_DEV_PIN_UNSET 0x002
-#define FIDO_DEV_CRED_PROT 0x004
-#define FIDO_DEV_CREDMAN 0x008
-#define FIDO_DEV_PIN_PROTOCOL1 0x010
-#define FIDO_DEV_PIN_PROTOCOL2 0x020
-#define FIDO_DEV_UV_SET 0x040
-#define FIDO_DEV_UV_UNSET 0x080
-#define FIDO_DEV_TOKEN_PERMS 0x100
-#define FIDO_DEV_WINHELLO 0x200
+#define FIDO_DEV_PIN_SET 0x0001
+#define FIDO_DEV_PIN_UNSET 0x0002
+#define FIDO_DEV_CRED_PROT 0x0004
+#define FIDO_DEV_CREDMAN 0x0008
+#define FIDO_DEV_PIN_PROTOCOL1 0x0010
+#define FIDO_DEV_PIN_PROTOCOL2 0x0020
+#define FIDO_DEV_UV_SET 0x0040
+#define FIDO_DEV_UV_UNSET 0x0080
+#define FIDO_DEV_TOKEN_PERMS 0x0100
+#define FIDO_DEV_WINHELLO 0x0200
+#define FIDO_DEV_CREDMAN_PRE 0x0400
+#define FIDO_DEV_BIO_SET 0x0800
+#define FIDO_DEV_BIO_UNSET 0x1000
/* miscellanea */
#define FIDO_DUMMY_CLIENTDATA ""
diff --git a/src/fido.h b/src/fido.h
index 914e377..ef1d3d3 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_list_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 *);
@@ -151,6 +152,7 @@ int fido_cred_empty_exclude_list(fido_cred_t *);
int fido_cred_exclude(fido_cred_t *, const unsigned char *, size_t);
int fido_cred_prot(const fido_cred_t *);
int fido_cred_set_attstmt(fido_cred_t *, const unsigned char *, size_t);
+int fido_cred_set_attobj(fido_cred_t *, const unsigned char *, size_t);
int fido_cred_set_authdata(fido_cred_t *, const unsigned char *, size_t);
int fido_cred_set_authdata_raw(fido_cred_t *, const unsigned char *, size_t);
int fido_cred_set_blob(fido_cred_t *, const unsigned char *, size_t);
@@ -226,6 +228,8 @@ 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_list_count(const fido_cred_t *);
+size_t fido_cred_x5c_list_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/param.h b/src/fido/param.h
index 511370b..fb66abf 100644
--- a/src/fido/param.h
+++ b/src/fido/param.h
@@ -53,6 +53,8 @@
#define CTAP_CBOR_CLIENT_PIN 0x06
#define CTAP_CBOR_RESET 0x07
#define CTAP_CBOR_NEXT_ASSERT 0x08
+#define CTAP_CBOR_BIO_ENROLL 0x09
+#define CTAP_CBOR_CRED_MGMT 0x0a
#define CTAP_CBOR_LARGEBLOB 0x0c
#define CTAP_CBOR_CONFIG 0x0d
#define CTAP_CBOR_BIO_ENROLL_PRE 0x40
diff --git a/src/fido/types.h b/src/fido/types.h
index 01d6820..0aaa8cb 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 {
diff --git a/src/hid_linux.c b/src/hid_linux.c
index 841a95b..cc6957a 100644
--- a/src/hid_linux.c
+++ b/src/hid_linux.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019-2022 Yubico AB. All rights reserved.
+ * Copyright (c) 2019-2024 Yubico AB. All rights reserved.
* Use of this source code is governed by a BSD-style
* license that can be found in the LICENSE file.
* SPDX-License-Identifier: BSD-2-Clause
@@ -77,12 +77,13 @@ out:
static int
parse_uevent(const char *uevent, int *bus, int16_t *vendor_id,
- int16_t *product_id)
+ int16_t *product_id, char **hid_name)
{
char *cp;
char *p;
char *s;
- int ok = -1;
+ bool found_id = false;
+ bool found_name = false;
short unsigned int x;
short unsigned int y;
short unsigned int z;
@@ -91,20 +92,25 @@ parse_uevent(const char *uevent, int *bus, int16_t *vendor_id,
return (-1);
while ((p = strsep(&cp, "\n")) != NULL && *p != '\0') {
- if (strncmp(p, "HID_ID=", 7) == 0) {
+ if (!found_id && strncmp(p, "HID_ID=", 7) == 0) {
if (sscanf(p + 7, "%hx:%hx:%hx", &x, &y, &z) == 3) {
*bus = (int)x;
*vendor_id = (int16_t)y;
*product_id = (int16_t)z;
- ok = 0;
- break;
+ found_id = true;
}
+ } else if (!found_name && strncmp(p, "HID_NAME=", 9) == 0) {
+ if ((*hid_name = strdup(p + 9)) != NULL)
+ found_name = true;
}
}
free(s);
- return (ok);
+ if (!found_name || !found_id)
+ return (-1);
+
+ return (0);
}
static char *
@@ -137,6 +143,7 @@ copy_info(fido_dev_info_t *di, struct udev *udev,
char *uevent = NULL;
struct udev_device *dev = NULL;
int bus = 0;
+ char *hid_name = NULL;
int ok = -1;
memset(di, 0, sizeof(*di));
@@ -148,7 +155,8 @@ copy_info(fido_dev_info_t *di, struct udev *udev,
goto fail;
if ((uevent = get_parent_attr(dev, "hid", NULL, "uevent")) == NULL ||
- parse_uevent(uevent, &bus, &di->vendor_id, &di->product_id) < 0) {
+ parse_uevent(uevent, &bus, &di->vendor_id, &di->product_id,
+ &hid_name) < 0) {
fido_log_debug("%s: uevent", __func__);
goto fail;
}
@@ -161,9 +169,16 @@ copy_info(fido_dev_info_t *di, struct udev *udev,
#endif
di->path = strdup(path);
- if ((di->manufacturer = get_usb_attr(dev, "manufacturer")) == NULL)
+ di->manufacturer = get_usb_attr(dev, "manufacturer");
+ di->product = get_usb_attr(dev, "product");
+
+ if (di->manufacturer == NULL && di->product == NULL) {
+ di->product = hid_name; /* fallback */
+ hid_name = NULL;
+ }
+ if (di->manufacturer == NULL)
di->manufacturer = strdup("");
- if ((di->product = get_usb_attr(dev, "product")) == NULL)
+ if (di->product == NULL)
di->product = strdup("");
if (di->path == NULL || di->manufacturer == NULL || di->product == NULL)
goto fail;
@@ -174,6 +189,7 @@ fail:
udev_device_unref(dev);
free(uevent);
+ free(hid_name);
if (ok < 0) {
free(di->path);
diff --git a/src/hid_netbsd.c b/src/hid_netbsd.c
index d5b9fad..df85282 100644
--- a/src/hid_netbsd.c
+++ b/src/hid_netbsd.c
@@ -127,14 +127,14 @@ fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
char path[64];
size_t i;
+ if (devlist == NULL || olen == NULL)
+ return (FIDO_ERR_INVALID_ARGUMENT);
+
*olen = 0;
if (ilen == 0)
return (FIDO_OK); /* nothing to do */
- if (devlist == NULL || olen == NULL)
- return (FIDO_ERR_INVALID_ARGUMENT);
-
for (i = *olen = 0; i < MAX_UHID && *olen < ilen; i++) {
snprintf(path, sizeof(path), "/dev/uhid%zu", i);
if (copy_info(&devlist[*olen], path) == 0) {
diff --git a/src/hid_osx.c b/src/hid_osx.c
index 9309762..41e9d17 100644
--- a/src/hid_osx.c
+++ b/src/hid_osx.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019-2022 Yubico AB. All rights reserved.
+ * Copyright (c) 2019-2023 Yubico AB. All rights reserved.
* Use of this source code is governed by a BSD-style
* license that can be found in the LICENSE file.
* SPDX-License-Identifier: BSD-2-Clause
@@ -523,6 +523,21 @@ fido_hid_set_sigmask(void *handle, const fido_sigset_t *sigmask)
return (FIDO_ERR_INTERNAL);
}
+static void
+schedule_io_loop(struct hid_osx *ctx, int ms)
+{
+ IOHIDDeviceScheduleWithRunLoop(ctx->ref, CFRunLoopGetCurrent(),
+ ctx->loop_id);
+
+ if (ms == -1)
+ ms = 5000; /* wait 5 seconds by default */
+
+ CFRunLoopRunInMode(ctx->loop_id, (double)ms/1000.0, true);
+
+ IOHIDDeviceUnscheduleFromRunLoop(ctx->ref, CFRunLoopGetCurrent(),
+ ctx->loop_id);
+}
+
int
fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms)
{
@@ -537,20 +552,19 @@ fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms)
return (-1);
}
- IOHIDDeviceScheduleWithRunLoop(ctx->ref, CFRunLoopGetCurrent(),
- ctx->loop_id);
-
- if (ms == -1)
- ms = 5000; /* wait 5 seconds by default */
-
- CFRunLoopRunInMode(ctx->loop_id, (double)ms/1000.0, true);
+ /* check for pending frame */
+ if ((r = read(ctx->report_pipe[0], buf, len)) == -1) {
+ if (errno != EAGAIN && errno != EWOULDBLOCK) {
+ fido_log_error(errno, "%s: read", __func__);
+ return (-1);
+ }
- IOHIDDeviceUnscheduleFromRunLoop(ctx->ref, CFRunLoopGetCurrent(),
- ctx->loop_id);
+ schedule_io_loop(ctx, ms);
- if ((r = read(ctx->report_pipe[0], buf, len)) == -1) {
- fido_log_error(errno, "%s: read", __func__);
- return (-1);
+ if ((r = read(ctx->report_pipe[0], buf, len)) == -1) {
+ fido_log_error(errno, "%s: read", __func__);
+ return (-1);
+ }
}
if (r < 0 || (size_t)r != len) {
diff --git a/src/pin.c b/src/pin.c
index c3dd927..7f7df00 100644
--- a/src/pin.c
+++ b/src/pin.c
@@ -131,12 +131,14 @@ encode_uv_permission(uint8_t cmd)
case CTAP_CBOR_ASSERT:
return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_ASSERT));
case CTAP_CBOR_BIO_ENROLL_PRE:
+ case CTAP_CBOR_BIO_ENROLL:
return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_BIO));
case CTAP_CBOR_CONFIG:
return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_CONFIG));
case CTAP_CBOR_MAKECRED:
return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_MAKECRED));
case CTAP_CBOR_CRED_MGMT_PRE:
+ case CTAP_CBOR_CRED_MGMT:
return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_CRED_MGMT));
case CTAP_CBOR_LARGEBLOB:
return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_LARGEBLOB));
diff --git a/src/rs1.c b/src/rs1.c
index 03636b5..7db7f83 100644
--- a/src/rs1.c
+++ b/src/rs1.c
@@ -10,54 +10,20 @@
#include "fido.h"
-#if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3050200fL
-static EVP_MD *
-rs1_get_EVP_MD(void)
-{
- const EVP_MD *from;
- EVP_MD *to = NULL;
-
- if ((from = EVP_sha1()) != NULL && (to = malloc(sizeof(*to))) != NULL)
- memcpy(to, from, sizeof(*to));
-
- return (to);
-}
-
-static void
-rs1_free_EVP_MD(EVP_MD *md)
-{
- freezero(md, sizeof(*md));
-}
-#elif OPENSSL_VERSION_NUMBER >= 0x30000000
-static EVP_MD *
-rs1_get_EVP_MD(void)
-{
- return (EVP_MD_fetch(NULL, "SHA-1", NULL));
-}
-
-static void
-rs1_free_EVP_MD(EVP_MD *md)
-{
- EVP_MD_free(md);
-}
+#if defined(__GNUC__)
+#define PRAGMA(s) _Pragma(s)
#else
+#define PRAGMA(s)
+#endif
+
static EVP_MD *
rs1_get_EVP_MD(void)
{
- const EVP_MD *md;
-
- if ((md = EVP_sha1()) == NULL)
- return (NULL);
-
- return (EVP_MD_meth_dup(md));
-}
-
-static void
-rs1_free_EVP_MD(EVP_MD *md)
-{
- EVP_MD_meth_free(md);
+PRAGMA("GCC diagnostic push")
+PRAGMA("GCC diagnostic ignored \"-Wcast-qual\"")
+ return ((EVP_MD *)EVP_sha1());
+PRAGMA("GCC diagnostic pop")
}
-#endif /* LIBRESSL_VERSION_NUMBER */
int
rs1_verify_sig(const fido_blob_t *dgst, EVP_PKEY *pkey,
@@ -94,7 +60,6 @@ rs1_verify_sig(const fido_blob_t *dgst, EVP_PKEY *pkey,
ok = 0;
fail:
EVP_PKEY_CTX_free(pctx);
- rs1_free_EVP_MD(md);
return (ok);
}
diff --git a/src/rs256.c b/src/rs256.c
index 59ceb94..8873db4 100644
--- a/src/rs256.c
+++ b/src/rs256.c
@@ -18,54 +18,20 @@
#define get0_RSA(x) EVP_PKEY_get0((x))
#endif
-#if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3050200fL
-static EVP_MD *
-rs256_get_EVP_MD(void)
-{
- const EVP_MD *from;
- EVP_MD *to = NULL;
-
- if ((from = EVP_sha256()) != NULL && (to = malloc(sizeof(*to))) != NULL)
- memcpy(to, from, sizeof(*to));
-
- return (to);
-}
-
-static void
-rs256_free_EVP_MD(EVP_MD *md)
-{
- freezero(md, sizeof(*md));
-}
-#elif OPENSSL_VERSION_NUMBER >= 0x30000000
-static EVP_MD *
-rs256_get_EVP_MD(void)
-{
- return (EVP_MD_fetch(NULL, "SHA2-256", NULL));
-}
-
-static void
-rs256_free_EVP_MD(EVP_MD *md)
-{
- EVP_MD_free(md);
-}
+#if defined(__GNUC__)
+#define PRAGMA(s) _Pragma(s)
#else
+#define PRAGMA(s)
+#endif
+
static EVP_MD *
rs256_get_EVP_MD(void)
{
- const EVP_MD *md;
-
- if ((md = EVP_sha256()) == NULL)
- return (NULL);
-
- return (EVP_MD_meth_dup(md));
-}
-
-static void
-rs256_free_EVP_MD(EVP_MD *md)
-{
- EVP_MD_meth_free(md);
+PRAGMA("GCC diagnostic push")
+PRAGMA("GCC diagnostic ignored \"-Wcast-qual\"")
+ return ((EVP_MD *)EVP_sha256());
+PRAGMA("GCC diagnostic pop")
}
-#endif /* LIBRESSL_VERSION_NUMBER */
static int
decode_bignum(const cbor_item_t *item, void *ptr, size_t len)
@@ -290,7 +256,6 @@ rs256_verify_sig(const fido_blob_t *dgst, EVP_PKEY *pkey,
ok = 0;
fail:
EVP_PKEY_CTX_free(pctx);
- rs256_free_EVP_MD(md);
return (ok);
}
diff --git a/src/winhello.c b/src/winhello.c
index ff969a4..2b2a5d1 100644
--- a/src/winhello.c
+++ b/src/winhello.c
@@ -740,50 +740,6 @@ translate_fido_cred(struct winhello_cred *ctx, const fido_cred_t *cred,
}
static int
-decode_attobj(const cbor_item_t *key, const cbor_item_t *val, void *arg)
-{
- fido_cred_t *cred = arg;
- char *name = NULL;
- int ok = -1;
-
- if (cbor_string_copy(key, &name) < 0) {
- fido_log_debug("%s: cbor type", __func__);
- ok = 0; /* ignore */
- goto fail;
- }
-
- if (!strcmp(name, "fmt")) {
- if (cbor_decode_fmt(val, &cred->fmt) < 0) {
- fido_log_debug("%s: cbor_decode_fmt", __func__);
- goto fail;
- }
- } else if (!strcmp(name, "attStmt")) {
- if (cbor_decode_attstmt(val, &cred->attstmt) < 0) {
- fido_log_debug("%s: cbor_decode_attstmt", __func__);
- goto fail;
- }
- } else if (!strcmp(name, "authData")) {
- if (fido_blob_decode(val, &cred->authdata_raw) < 0) {
- fido_log_debug("%s: fido_blob_decode", __func__);
- goto fail;
- }
- if (cbor_decode_cred_authdata(val, cred->type,
- &cred->authdata_cbor, &cred->authdata, &cred->attcred,
- &cred->authdata_ext) < 0) {
- fido_log_debug("%s: cbor_decode_cred_authdata",
- __func__);
- goto fail;
- }
- }
-
- ok = 0;
-fail:
- free(name);
-
- return (ok);
-}
-
-static int
translate_winhello_cred(fido_cred_t *cred,
const WEBAUTHN_CREDENTIAL_ATTESTATION *att)
{
@@ -800,10 +756,8 @@ translate_winhello_cred(fido_cred_t *cred,
fido_log_debug("%s: cbor_load", __func__);
goto fail;
}
- if (cbor_isa_map(item) == false ||
- cbor_map_is_definite(item) == false ||
- cbor_map_iter(item, cred, decode_attobj) < 0) {
- fido_log_debug("%s: cbor type", __func__);
+ if (cbor_decode_attobj(item, cred) != 0) {
+ fido_log_debug("%s: cbor_decode_attobj", __func__);
goto fail;
}