From c79050aa44b8836d836c5dd22a383a073c28b74b Mon Sep 17 00:00:00 2001 From: nicoo Date: Wed, 12 Feb 2020 13:42:22 +0100 Subject: Import upstream release 1.3.0 Closes: #951184 --- src/info.c | 410 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 410 insertions(+) create mode 100644 src/info.c (limited to 'src/info.c') diff --git a/src/info.c b/src/info.c new file mode 100644 index 0000000..e896503 --- /dev/null +++ b/src/info.c @@ -0,0 +1,410 @@ +/* + * Copyright (c) 2018 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. + */ + +#include +#include "fido.h" + +static int +decode_version(const cbor_item_t *item, void *arg) +{ + fido_str_array_t *v = arg; + const size_t i = v->len; + + /* keep ptr[x] and len consistent */ + if (cbor_string_copy(item, &v->ptr[i]) < 0) { + fido_log_debug("%s: cbor_string_copy", __func__); + return (-1); + } + + v->len++; + + return (0); +} + +static int +decode_versions(const cbor_item_t *item, fido_str_array_t *v) +{ + v->ptr = NULL; + v->len = 0; + + if (cbor_isa_array(item) == false || + cbor_array_is_definite(item) == false) { + fido_log_debug("%s: cbor type", __func__); + return (-1); + } + + v->ptr = calloc(cbor_array_size(item), sizeof(char *)); + if (v->ptr == NULL) + return (-1); + + if (cbor_array_iter(item, v, decode_version) < 0) { + fido_log_debug("%s: decode_version", __func__); + return (-1); + } + + return (0); +} + +static int +decode_extension(const cbor_item_t *item, void *arg) +{ + fido_str_array_t *e = arg; + const size_t i = e->len; + + /* keep ptr[x] and len consistent */ + if (cbor_string_copy(item, &e->ptr[i]) < 0) { + fido_log_debug("%s: cbor_string_copy", __func__); + return (-1); + } + + e->len++; + + return (0); +} + +static int +decode_extensions(const cbor_item_t *item, fido_str_array_t *e) +{ + e->ptr = NULL; + e->len = 0; + + if (cbor_isa_array(item) == false || + cbor_array_is_definite(item) == false) { + fido_log_debug("%s: cbor type", __func__); + return (-1); + } + + e->ptr = calloc(cbor_array_size(item), sizeof(char *)); + if (e->ptr == NULL) + return (-1); + + if (cbor_array_iter(item, e, decode_extension) < 0) { + fido_log_debug("%s: decode_extension", __func__); + return (-1); + } + + return (0); +} + +static int +decode_aaguid(const cbor_item_t *item, unsigned char *aaguid, size_t aaguid_len) +{ + if (cbor_isa_bytestring(item) == false || + cbor_bytestring_is_definite(item) == false || + cbor_bytestring_length(item) != aaguid_len) { + fido_log_debug("%s: cbor type", __func__); + return (-1); + } + + memcpy(aaguid, cbor_bytestring_handle(item), aaguid_len); + + return (0); +} + +static int +decode_option(const cbor_item_t *key, const cbor_item_t *val, void *arg) +{ + fido_opt_array_t *o = arg; + const size_t i = o->len; + + if (cbor_isa_float_ctrl(val) == false || + cbor_float_get_width(val) != CBOR_FLOAT_0 || + cbor_is_bool(val) == false) { + fido_log_debug("%s: cbor type", __func__); + return (0); /* ignore */ + } + + if (cbor_string_copy(key, &o->name[i]) < 0) { + fido_log_debug("%s: cbor_string_copy", __func__); + return (0); /* ignore */ + } + + /* keep name/value and len consistent */ + o->value[i] = cbor_ctrl_value(val) == CBOR_CTRL_TRUE; + o->len++; + + return (0); +} + +static int +decode_options(const cbor_item_t *item, fido_opt_array_t *o) +{ + o->name = NULL; + o->value = NULL; + o->len = 0; + + if (cbor_isa_map(item) == false || + cbor_map_is_definite(item) == false) { + fido_log_debug("%s: cbor type", __func__); + return (-1); + } + + o->name = calloc(cbor_map_size(item), sizeof(char *)); + o->value = calloc(cbor_map_size(item), sizeof(bool)); + if (o->name == NULL || o->value == NULL) + return (-1); + + return (cbor_map_iter(item, o, decode_option)); +} + +static int +decode_protocol(const cbor_item_t *item, void *arg) +{ + fido_byte_array_t *p = arg; + const size_t i = p->len; + + if (cbor_isa_uint(item) == false || + cbor_int_get_width(item) != CBOR_INT_8) { + fido_log_debug("%s: cbor type", __func__); + return (-1); + } + + /* keep ptr[x] and len consistent */ + p->ptr[i] = cbor_get_uint8(item); + p->len++; + + return (0); +} + +static int +decode_protocols(const cbor_item_t *item, fido_byte_array_t *p) +{ + p->ptr = NULL; + p->len = 0; + + if (cbor_isa_array(item) == false || + cbor_array_is_definite(item) == false) { + fido_log_debug("%s: cbor type", __func__); + return (-1); + } + + p->ptr = calloc(cbor_array_size(item), sizeof(uint8_t)); + if (p->ptr == NULL) + return (-1); + + if (cbor_array_iter(item, p, decode_protocol) < 0) { + fido_log_debug("%s: decode_protocol", __func__); + return (-1); + } + + return (0); +} + +static int +parse_reply_element(const cbor_item_t *key, const cbor_item_t *val, void *arg) +{ + fido_cbor_info_t *ci = arg; + + if (cbor_isa_uint(key) == false || + cbor_int_get_width(key) != CBOR_INT_8) { + fido_log_debug("%s: cbor type", __func__); + return (0); /* ignore */ + } + + switch (cbor_get_uint8(key)) { + case 1: /* versions */ + return (decode_versions(val, &ci->versions)); + case 2: /* extensions */ + return (decode_extensions(val, &ci->extensions)); + case 3: /* aaguid */ + return (decode_aaguid(val, ci->aaguid, sizeof(ci->aaguid))); + case 4: /* options */ + return (decode_options(val, &ci->options)); + case 5: /* maxMsgSize */ + return (cbor_decode_uint64(val, &ci->maxmsgsiz)); + case 6: /* pinProtocols */ + return (decode_protocols(val, &ci->protocols)); + default: /* ignore */ + fido_log_debug("%s: cbor type", __func__); + return (0); + } +} + +static int +fido_dev_get_cbor_info_tx(fido_dev_t *dev) +{ + const unsigned char cbor[] = { CTAP_CBOR_GETINFO }; + const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; + + fido_log_debug("%s: dev=%p", __func__, (void *)dev); + + if (fido_tx(dev, cmd, cbor, sizeof(cbor)) < 0) { + fido_log_debug("%s: fido_tx", __func__); + return (FIDO_ERR_TX); + } + + return (FIDO_OK); +} + +static int +fido_dev_get_cbor_info_rx(fido_dev_t *dev, fido_cbor_info_t *ci, int ms) +{ + const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; + unsigned char reply[512]; + int reply_len; + + fido_log_debug("%s: dev=%p, ci=%p, ms=%d", __func__, (void *)dev, + (void *)ci, ms); + + memset(ci, 0, sizeof(*ci)); + + if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { + fido_log_debug("%s: fido_rx", __func__); + return (FIDO_ERR_RX); + } + + return (cbor_parse_reply(reply, (size_t)reply_len, ci, + parse_reply_element)); +} + +static int +fido_dev_get_cbor_info_wait(fido_dev_t *dev, fido_cbor_info_t *ci, int ms) +{ + int r; + + if ((r = fido_dev_get_cbor_info_tx(dev)) != FIDO_OK || + (r = fido_dev_get_cbor_info_rx(dev, ci, ms)) != FIDO_OK) + return (r); + + return (FIDO_OK); +} + +int +fido_dev_get_cbor_info(fido_dev_t *dev, fido_cbor_info_t *ci) +{ + return (fido_dev_get_cbor_info_wait(dev, ci, -1)); +} + +/* + * get/set functions for fido_cbor_info_t; always at the end of the file + */ + +fido_cbor_info_t * +fido_cbor_info_new(void) +{ + return (calloc(1, sizeof(fido_cbor_info_t))); +} + +static void +free_str_array(fido_str_array_t *sa) +{ + for (size_t i = 0; i < sa->len; i++) + free(sa->ptr[i]); + + free(sa->ptr); + sa->ptr = NULL; + sa->len = 0; +} + +static void +free_opt_array(fido_opt_array_t *oa) +{ + for (size_t i = 0; i < oa->len; i++) + free(oa->name[i]); + + free(oa->name); + free(oa->value); + oa->name = NULL; + oa->value = NULL; +} + +static void +free_byte_array(fido_byte_array_t *ba) +{ + free(ba->ptr); + + ba->ptr = NULL; + ba->len = 0; +} + +void +fido_cbor_info_free(fido_cbor_info_t **ci_p) +{ + fido_cbor_info_t *ci; + + if (ci_p == NULL || (ci = *ci_p) == NULL) + return; + + free_str_array(&ci->versions); + free_str_array(&ci->extensions); + free_opt_array(&ci->options); + free_byte_array(&ci->protocols); + free(ci); + + *ci_p = NULL; +} + +char ** +fido_cbor_info_versions_ptr(const fido_cbor_info_t *ci) +{ + return (ci->versions.ptr); +} + +size_t +fido_cbor_info_versions_len(const fido_cbor_info_t *ci) +{ + return (ci->versions.len); +} + +char ** +fido_cbor_info_extensions_ptr(const fido_cbor_info_t *ci) +{ + return (ci->extensions.ptr); +} + +size_t +fido_cbor_info_extensions_len(const fido_cbor_info_t *ci) +{ + return (ci->extensions.len); +} + +const unsigned char * +fido_cbor_info_aaguid_ptr(const fido_cbor_info_t *ci) +{ + return (ci->aaguid); +} + +size_t +fido_cbor_info_aaguid_len(const fido_cbor_info_t *ci) +{ + return (sizeof(ci->aaguid)); +} + +char ** +fido_cbor_info_options_name_ptr(const fido_cbor_info_t *ci) +{ + return (ci->options.name); +} + +const bool * +fido_cbor_info_options_value_ptr(const fido_cbor_info_t *ci) +{ + return (ci->options.value); +} + +size_t +fido_cbor_info_options_len(const fido_cbor_info_t *ci) +{ + return (ci->options.len); +} + +uint64_t +fido_cbor_info_maxmsgsiz(const fido_cbor_info_t *ci) +{ + return (ci->maxmsgsiz); +} + +const uint8_t * +fido_cbor_info_protocols_ptr(const fido_cbor_info_t *ci) +{ + return (ci->protocols.ptr); +} + +size_t +fido_cbor_info_protocols_len(const fido_cbor_info_t *ci) +{ + return (ci->protocols.len); +} -- cgit v1.2.3