1d75efeb7Sdjm /*
2*ab19a69eSdjm * Copyright (c) 2018-2021 Yubico AB. All rights reserved.
3d75efeb7Sdjm * Use of this source code is governed by a BSD-style
4d75efeb7Sdjm * license that can be found in the LICENSE file.
5d75efeb7Sdjm */
6d75efeb7Sdjm
7d75efeb7Sdjm #include <openssl/hmac.h>
8d75efeb7Sdjm #include <openssl/sha.h>
9d75efeb7Sdjm #include "fido.h"
10d75efeb7Sdjm
11d75efeb7Sdjm static int
check_key_type(cbor_item_t * item)12d75efeb7Sdjm check_key_type(cbor_item_t *item)
13d75efeb7Sdjm {
14d75efeb7Sdjm if (item->type == CBOR_TYPE_UINT || item->type == CBOR_TYPE_NEGINT ||
15d75efeb7Sdjm item->type == CBOR_TYPE_STRING)
16d75efeb7Sdjm return (0);
17d75efeb7Sdjm
1832a20e26Sdjm fido_log_debug("%s: invalid type: %d", __func__, item->type);
19d75efeb7Sdjm
20d75efeb7Sdjm return (-1);
21d75efeb7Sdjm }
22d75efeb7Sdjm
23d75efeb7Sdjm /*
24d75efeb7Sdjm * Validate CTAP2 canonical CBOR encoding rules for maps.
25d75efeb7Sdjm */
26d75efeb7Sdjm static int
ctap_check_cbor(cbor_item_t * prev,cbor_item_t * curr)27d75efeb7Sdjm ctap_check_cbor(cbor_item_t *prev, cbor_item_t *curr)
28d75efeb7Sdjm {
29d75efeb7Sdjm size_t curr_len;
30d75efeb7Sdjm size_t prev_len;
31d75efeb7Sdjm
32d75efeb7Sdjm if (check_key_type(prev) < 0 || check_key_type(curr) < 0)
33d75efeb7Sdjm return (-1);
34d75efeb7Sdjm
35d75efeb7Sdjm if (prev->type != curr->type) {
36d75efeb7Sdjm if (prev->type < curr->type)
37d75efeb7Sdjm return (0);
3832a20e26Sdjm fido_log_debug("%s: unsorted types", __func__);
39d75efeb7Sdjm return (-1);
40d75efeb7Sdjm }
41d75efeb7Sdjm
42d75efeb7Sdjm if (curr->type == CBOR_TYPE_UINT || curr->type == CBOR_TYPE_NEGINT) {
43d75efeb7Sdjm if (cbor_int_get_width(curr) >= cbor_int_get_width(prev) &&
44d75efeb7Sdjm cbor_get_int(curr) > cbor_get_int(prev))
45d75efeb7Sdjm return (0);
46d75efeb7Sdjm } else {
47d75efeb7Sdjm curr_len = cbor_string_length(curr);
48d75efeb7Sdjm prev_len = cbor_string_length(prev);
49d75efeb7Sdjm
50d75efeb7Sdjm if (curr_len > prev_len || (curr_len == prev_len &&
51d75efeb7Sdjm memcmp(cbor_string_handle(prev), cbor_string_handle(curr),
52d75efeb7Sdjm curr_len) < 0))
53d75efeb7Sdjm return (0);
54d75efeb7Sdjm }
55d75efeb7Sdjm
5632a20e26Sdjm fido_log_debug("%s: invalid cbor", __func__);
57d75efeb7Sdjm
58d75efeb7Sdjm return (-1);
59d75efeb7Sdjm }
60d75efeb7Sdjm
61d75efeb7Sdjm int
cbor_map_iter(const cbor_item_t * item,void * arg,int (* f)(const cbor_item_t *,const cbor_item_t *,void *))62d75efeb7Sdjm cbor_map_iter(const cbor_item_t *item, void *arg, int(*f)(const cbor_item_t *,
63d75efeb7Sdjm const cbor_item_t *, void *))
64d75efeb7Sdjm {
65d75efeb7Sdjm struct cbor_pair *v;
66d75efeb7Sdjm size_t n;
67d75efeb7Sdjm
68d75efeb7Sdjm if ((v = cbor_map_handle(item)) == NULL) {
6932a20e26Sdjm fido_log_debug("%s: cbor_map_handle", __func__);
70d75efeb7Sdjm return (-1);
71d75efeb7Sdjm }
72d75efeb7Sdjm
73d75efeb7Sdjm n = cbor_map_size(item);
74d75efeb7Sdjm
75d75efeb7Sdjm for (size_t i = 0; i < n; i++) {
76d75efeb7Sdjm if (v[i].key == NULL || v[i].value == NULL) {
7732a20e26Sdjm fido_log_debug("%s: key=%p, value=%p for i=%zu",
7832a20e26Sdjm __func__, (void *)v[i].key, (void *)v[i].value, i);
79d75efeb7Sdjm return (-1);
80d75efeb7Sdjm }
81d75efeb7Sdjm if (i && ctap_check_cbor(v[i - 1].key, v[i].key) < 0) {
8232a20e26Sdjm fido_log_debug("%s: ctap_check_cbor", __func__);
83d75efeb7Sdjm return (-1);
84d75efeb7Sdjm }
85d75efeb7Sdjm if (f(v[i].key, v[i].value, arg) < 0) {
8632a20e26Sdjm fido_log_debug("%s: iterator < 0 on i=%zu", __func__,
8732a20e26Sdjm i);
88d75efeb7Sdjm return (-1);
89d75efeb7Sdjm }
90d75efeb7Sdjm }
91d75efeb7Sdjm
92d75efeb7Sdjm return (0);
93d75efeb7Sdjm }
94d75efeb7Sdjm
95d75efeb7Sdjm int
cbor_array_iter(const cbor_item_t * item,void * arg,int (* f)(const cbor_item_t *,void *))96d75efeb7Sdjm cbor_array_iter(const cbor_item_t *item, void *arg, int(*f)(const cbor_item_t *,
97d75efeb7Sdjm void *))
98d75efeb7Sdjm {
99d75efeb7Sdjm cbor_item_t **v;
100d75efeb7Sdjm size_t n;
101d75efeb7Sdjm
102d75efeb7Sdjm if ((v = cbor_array_handle(item)) == NULL) {
10332a20e26Sdjm fido_log_debug("%s: cbor_array_handle", __func__);
104d75efeb7Sdjm return (-1);
105d75efeb7Sdjm }
106d75efeb7Sdjm
107d75efeb7Sdjm n = cbor_array_size(item);
108d75efeb7Sdjm
109d75efeb7Sdjm for (size_t i = 0; i < n; i++)
110d75efeb7Sdjm if (v[i] == NULL || f(v[i], arg) < 0) {
11132a20e26Sdjm fido_log_debug("%s: iterator < 0 on i=%zu,%p",
11232a20e26Sdjm __func__, i, (void *)v[i]);
113d75efeb7Sdjm return (-1);
114d75efeb7Sdjm }
115d75efeb7Sdjm
116d75efeb7Sdjm return (0);
117d75efeb7Sdjm }
118d75efeb7Sdjm
119d75efeb7Sdjm int
cbor_parse_reply(const unsigned char * blob,size_t blob_len,void * arg,int (* parser)(const cbor_item_t *,const cbor_item_t *,void *))12032a20e26Sdjm cbor_parse_reply(const unsigned char *blob, size_t blob_len, void *arg,
121d75efeb7Sdjm int(*parser)(const cbor_item_t *, const cbor_item_t *, void *))
122d75efeb7Sdjm {
123d75efeb7Sdjm cbor_item_t *item = NULL;
124d75efeb7Sdjm struct cbor_load_result cbor;
125d75efeb7Sdjm int r;
126d75efeb7Sdjm
127d75efeb7Sdjm if (blob_len < 1) {
12832a20e26Sdjm fido_log_debug("%s: blob_len=%zu", __func__, blob_len);
129d75efeb7Sdjm r = FIDO_ERR_RX;
130d75efeb7Sdjm goto fail;
131d75efeb7Sdjm }
132d75efeb7Sdjm
133d75efeb7Sdjm if (blob[0] != FIDO_OK) {
13432a20e26Sdjm fido_log_debug("%s: blob[0]=0x%02x", __func__, blob[0]);
135d75efeb7Sdjm r = blob[0];
136d75efeb7Sdjm goto fail;
137d75efeb7Sdjm }
138d75efeb7Sdjm
139d75efeb7Sdjm if ((item = cbor_load(blob + 1, blob_len - 1, &cbor)) == NULL) {
14032a20e26Sdjm fido_log_debug("%s: cbor_load", __func__);
141d75efeb7Sdjm r = FIDO_ERR_RX_NOT_CBOR;
142d75efeb7Sdjm goto fail;
143d75efeb7Sdjm }
144d75efeb7Sdjm
145d75efeb7Sdjm if (cbor_isa_map(item) == false ||
146d75efeb7Sdjm cbor_map_is_definite(item) == false) {
14732a20e26Sdjm fido_log_debug("%s: cbor type", __func__);
148d75efeb7Sdjm r = FIDO_ERR_RX_INVALID_CBOR;
149d75efeb7Sdjm goto fail;
150d75efeb7Sdjm }
151d75efeb7Sdjm
152d75efeb7Sdjm if (cbor_map_iter(item, arg, parser) < 0) {
15332a20e26Sdjm fido_log_debug("%s: cbor_map_iter", __func__);
154d75efeb7Sdjm r = FIDO_ERR_RX_INVALID_CBOR;
155d75efeb7Sdjm goto fail;
156d75efeb7Sdjm }
157d75efeb7Sdjm
158d75efeb7Sdjm r = FIDO_OK;
159d75efeb7Sdjm fail:
160d75efeb7Sdjm if (item != NULL)
161d75efeb7Sdjm cbor_decref(&item);
162d75efeb7Sdjm
163d75efeb7Sdjm return (r);
164d75efeb7Sdjm }
165d75efeb7Sdjm
166d75efeb7Sdjm void
cbor_vector_free(cbor_item_t ** item,size_t len)167d75efeb7Sdjm cbor_vector_free(cbor_item_t **item, size_t len)
168d75efeb7Sdjm {
169d75efeb7Sdjm for (size_t i = 0; i < len; i++)
170d75efeb7Sdjm if (item[i] != NULL)
171d75efeb7Sdjm cbor_decref(&item[i]);
172d75efeb7Sdjm }
173d75efeb7Sdjm
174d75efeb7Sdjm int
cbor_bytestring_copy(const cbor_item_t * item,unsigned char ** buf,size_t * len)175d75efeb7Sdjm cbor_bytestring_copy(const cbor_item_t *item, unsigned char **buf, size_t *len)
176d75efeb7Sdjm {
177d75efeb7Sdjm if (*buf != NULL || *len != 0) {
17832a20e26Sdjm fido_log_debug("%s: dup", __func__);
179d75efeb7Sdjm return (-1);
180d75efeb7Sdjm }
181d75efeb7Sdjm
182d75efeb7Sdjm if (cbor_isa_bytestring(item) == false ||
183d75efeb7Sdjm cbor_bytestring_is_definite(item) == false) {
18432a20e26Sdjm fido_log_debug("%s: cbor type", __func__);
185d75efeb7Sdjm return (-1);
186d75efeb7Sdjm }
187d75efeb7Sdjm
188d75efeb7Sdjm *len = cbor_bytestring_length(item);
189d75efeb7Sdjm if ((*buf = malloc(*len)) == NULL) {
190d75efeb7Sdjm *len = 0;
191d75efeb7Sdjm return (-1);
192d75efeb7Sdjm }
193d75efeb7Sdjm
194d75efeb7Sdjm memcpy(*buf, cbor_bytestring_handle(item), *len);
195d75efeb7Sdjm
196d75efeb7Sdjm return (0);
197d75efeb7Sdjm }
198d75efeb7Sdjm
199d75efeb7Sdjm int
cbor_string_copy(const cbor_item_t * item,char ** str)200d75efeb7Sdjm cbor_string_copy(const cbor_item_t *item, char **str)
201d75efeb7Sdjm {
202d75efeb7Sdjm size_t len;
203d75efeb7Sdjm
204d75efeb7Sdjm if (*str != NULL) {
20532a20e26Sdjm fido_log_debug("%s: dup", __func__);
206d75efeb7Sdjm return (-1);
207d75efeb7Sdjm }
208d75efeb7Sdjm
209d75efeb7Sdjm if (cbor_isa_string(item) == false ||
210d75efeb7Sdjm cbor_string_is_definite(item) == false) {
21132a20e26Sdjm fido_log_debug("%s: cbor type", __func__);
212d75efeb7Sdjm return (-1);
213d75efeb7Sdjm }
214d75efeb7Sdjm
215d75efeb7Sdjm if ((len = cbor_string_length(item)) == SIZE_MAX ||
216d75efeb7Sdjm (*str = malloc(len + 1)) == NULL)
217d75efeb7Sdjm return (-1);
218d75efeb7Sdjm
219d75efeb7Sdjm memcpy(*str, cbor_string_handle(item), len);
220d75efeb7Sdjm (*str)[len] = '\0';
221d75efeb7Sdjm
222d75efeb7Sdjm return (0);
223d75efeb7Sdjm }
224d75efeb7Sdjm
225d75efeb7Sdjm int
cbor_add_bytestring(cbor_item_t * item,const char * key,const unsigned char * value,size_t value_len)226d75efeb7Sdjm cbor_add_bytestring(cbor_item_t *item, const char *key,
227d75efeb7Sdjm const unsigned char *value, size_t value_len)
228d75efeb7Sdjm {
229d75efeb7Sdjm struct cbor_pair pair;
230d75efeb7Sdjm int ok = -1;
231d75efeb7Sdjm
232d75efeb7Sdjm memset(&pair, 0, sizeof(pair));
233d75efeb7Sdjm
234d75efeb7Sdjm if ((pair.key = cbor_build_string(key)) == NULL ||
235d75efeb7Sdjm (pair.value = cbor_build_bytestring(value, value_len)) == NULL) {
23632a20e26Sdjm fido_log_debug("%s: cbor_build", __func__);
237d75efeb7Sdjm goto fail;
238d75efeb7Sdjm }
239d75efeb7Sdjm
240d75efeb7Sdjm if (!cbor_map_add(item, pair)) {
24132a20e26Sdjm fido_log_debug("%s: cbor_map_add", __func__);
242d75efeb7Sdjm goto fail;
243d75efeb7Sdjm }
244d75efeb7Sdjm
245d75efeb7Sdjm ok = 0;
246d75efeb7Sdjm fail:
247d75efeb7Sdjm if (pair.key)
248d75efeb7Sdjm cbor_decref(&pair.key);
249d75efeb7Sdjm if (pair.value)
250d75efeb7Sdjm cbor_decref(&pair.value);
251d75efeb7Sdjm
252d75efeb7Sdjm return (ok);
253d75efeb7Sdjm }
254d75efeb7Sdjm
255d75efeb7Sdjm int
cbor_add_string(cbor_item_t * item,const char * key,const char * value)256d75efeb7Sdjm cbor_add_string(cbor_item_t *item, const char *key, const char *value)
257d75efeb7Sdjm {
258d75efeb7Sdjm struct cbor_pair pair;
259d75efeb7Sdjm int ok = -1;
260d75efeb7Sdjm
261d75efeb7Sdjm memset(&pair, 0, sizeof(pair));
262d75efeb7Sdjm
263d75efeb7Sdjm if ((pair.key = cbor_build_string(key)) == NULL ||
264d75efeb7Sdjm (pair.value = cbor_build_string(value)) == NULL) {
26532a20e26Sdjm fido_log_debug("%s: cbor_build", __func__);
266d75efeb7Sdjm goto fail;
267d75efeb7Sdjm }
268d75efeb7Sdjm
269d75efeb7Sdjm if (!cbor_map_add(item, pair)) {
27032a20e26Sdjm fido_log_debug("%s: cbor_map_add", __func__);
271d75efeb7Sdjm goto fail;
272d75efeb7Sdjm }
273d75efeb7Sdjm
274d75efeb7Sdjm ok = 0;
275d75efeb7Sdjm fail:
276d75efeb7Sdjm if (pair.key)
277d75efeb7Sdjm cbor_decref(&pair.key);
278d75efeb7Sdjm if (pair.value)
279d75efeb7Sdjm cbor_decref(&pair.value);
280d75efeb7Sdjm
281d75efeb7Sdjm return (ok);
282d75efeb7Sdjm }
283d75efeb7Sdjm
284d75efeb7Sdjm int
cbor_add_bool(cbor_item_t * item,const char * key,fido_opt_t value)285d75efeb7Sdjm cbor_add_bool(cbor_item_t *item, const char *key, fido_opt_t value)
286d75efeb7Sdjm {
287d75efeb7Sdjm struct cbor_pair pair;
288d75efeb7Sdjm int ok = -1;
289d75efeb7Sdjm
290d75efeb7Sdjm memset(&pair, 0, sizeof(pair));
291d75efeb7Sdjm
292d75efeb7Sdjm if ((pair.key = cbor_build_string(key)) == NULL ||
293d75efeb7Sdjm (pair.value = cbor_build_bool(value == FIDO_OPT_TRUE)) == NULL) {
29432a20e26Sdjm fido_log_debug("%s: cbor_build", __func__);
295d75efeb7Sdjm goto fail;
296d75efeb7Sdjm }
297d75efeb7Sdjm
298d75efeb7Sdjm if (!cbor_map_add(item, pair)) {
29932a20e26Sdjm fido_log_debug("%s: cbor_map_add", __func__);
30032a20e26Sdjm goto fail;
30132a20e26Sdjm }
30232a20e26Sdjm
30332a20e26Sdjm ok = 0;
30432a20e26Sdjm fail:
30532a20e26Sdjm if (pair.key)
30632a20e26Sdjm cbor_decref(&pair.key);
30732a20e26Sdjm if (pair.value)
30832a20e26Sdjm cbor_decref(&pair.value);
30932a20e26Sdjm
31032a20e26Sdjm return (ok);
31132a20e26Sdjm }
31232a20e26Sdjm
31332a20e26Sdjm static int
cbor_add_uint8(cbor_item_t * item,const char * key,uint8_t value)31432a20e26Sdjm cbor_add_uint8(cbor_item_t *item, const char *key, uint8_t value)
31532a20e26Sdjm {
31632a20e26Sdjm struct cbor_pair pair;
31732a20e26Sdjm int ok = -1;
31832a20e26Sdjm
31932a20e26Sdjm memset(&pair, 0, sizeof(pair));
32032a20e26Sdjm
32132a20e26Sdjm if ((pair.key = cbor_build_string(key)) == NULL ||
32232a20e26Sdjm (pair.value = cbor_build_uint8(value)) == NULL) {
32332a20e26Sdjm fido_log_debug("%s: cbor_build", __func__);
32432a20e26Sdjm goto fail;
32532a20e26Sdjm }
32632a20e26Sdjm
32732a20e26Sdjm if (!cbor_map_add(item, pair)) {
32832a20e26Sdjm fido_log_debug("%s: cbor_map_add", __func__);
329d75efeb7Sdjm goto fail;
330d75efeb7Sdjm }
331d75efeb7Sdjm
332d75efeb7Sdjm ok = 0;
333d75efeb7Sdjm fail:
334d75efeb7Sdjm if (pair.key)
335d75efeb7Sdjm cbor_decref(&pair.key);
336d75efeb7Sdjm if (pair.value)
337d75efeb7Sdjm cbor_decref(&pair.value);
338d75efeb7Sdjm
339d75efeb7Sdjm return (ok);
340d75efeb7Sdjm }
341d75efeb7Sdjm
342d75efeb7Sdjm static int
cbor_add_arg(cbor_item_t * item,uint8_t n,cbor_item_t * arg)343d75efeb7Sdjm cbor_add_arg(cbor_item_t *item, uint8_t n, cbor_item_t *arg)
344d75efeb7Sdjm {
345d75efeb7Sdjm struct cbor_pair pair;
346d75efeb7Sdjm int ok = -1;
347d75efeb7Sdjm
348d75efeb7Sdjm memset(&pair, 0, sizeof(pair));
349d75efeb7Sdjm
350d75efeb7Sdjm if (arg == NULL)
351d75efeb7Sdjm return (0); /* empty argument */
352d75efeb7Sdjm
353d75efeb7Sdjm if ((pair.key = cbor_build_uint8(n)) == NULL) {
35432a20e26Sdjm fido_log_debug("%s: cbor_build", __func__);
355d75efeb7Sdjm goto fail;
356d75efeb7Sdjm }
357d75efeb7Sdjm
358d75efeb7Sdjm pair.value = arg;
359d75efeb7Sdjm
360d75efeb7Sdjm if (!cbor_map_add(item, pair)) {
36132a20e26Sdjm fido_log_debug("%s: cbor_map_add", __func__);
362d75efeb7Sdjm goto fail;
363d75efeb7Sdjm }
364d75efeb7Sdjm
365d75efeb7Sdjm ok = 0;
366d75efeb7Sdjm fail:
367d75efeb7Sdjm if (pair.key)
368d75efeb7Sdjm cbor_decref(&pair.key);
369d75efeb7Sdjm
370d75efeb7Sdjm return (ok);
371d75efeb7Sdjm }
372d75efeb7Sdjm
373d75efeb7Sdjm cbor_item_t *
cbor_flatten_vector(cbor_item_t * argv[],size_t argc)374d75efeb7Sdjm cbor_flatten_vector(cbor_item_t *argv[], size_t argc)
375d75efeb7Sdjm {
376d75efeb7Sdjm cbor_item_t *map;
377d75efeb7Sdjm uint8_t i;
378d75efeb7Sdjm
379d75efeb7Sdjm if (argc > UINT8_MAX - 1)
380d75efeb7Sdjm return (NULL);
381d75efeb7Sdjm
382d75efeb7Sdjm if ((map = cbor_new_definite_map(argc)) == NULL)
383d75efeb7Sdjm return (NULL);
384d75efeb7Sdjm
385d75efeb7Sdjm for (i = 0; i < argc; i++)
386739189a3Sdjm if (cbor_add_arg(map, (uint8_t)(i + 1), argv[i]) < 0)
387d75efeb7Sdjm break;
388d75efeb7Sdjm
389d75efeb7Sdjm if (i != argc) {
390d75efeb7Sdjm cbor_decref(&map);
391d75efeb7Sdjm map = NULL;
392d75efeb7Sdjm }
393d75efeb7Sdjm
394d75efeb7Sdjm return (map);
395d75efeb7Sdjm }
396d75efeb7Sdjm
397d75efeb7Sdjm int
cbor_build_frame(uint8_t cmd,cbor_item_t * argv[],size_t argc,fido_blob_t * f)398d75efeb7Sdjm cbor_build_frame(uint8_t cmd, cbor_item_t *argv[], size_t argc, fido_blob_t *f)
399d75efeb7Sdjm {
400d75efeb7Sdjm cbor_item_t *flat = NULL;
401d75efeb7Sdjm unsigned char *cbor = NULL;
402d75efeb7Sdjm size_t cbor_len;
403d75efeb7Sdjm size_t cbor_alloc_len;
404d75efeb7Sdjm int ok = -1;
405d75efeb7Sdjm
406d75efeb7Sdjm if ((flat = cbor_flatten_vector(argv, argc)) == NULL)
407d75efeb7Sdjm goto fail;
408d75efeb7Sdjm
409d75efeb7Sdjm cbor_len = cbor_serialize_alloc(flat, &cbor, &cbor_alloc_len);
410d75efeb7Sdjm if (cbor_len == 0 || cbor_len == SIZE_MAX) {
41132a20e26Sdjm fido_log_debug("%s: cbor_len=%zu", __func__, cbor_len);
412d75efeb7Sdjm goto fail;
413d75efeb7Sdjm }
414d75efeb7Sdjm
415d75efeb7Sdjm if ((f->ptr = malloc(cbor_len + 1)) == NULL)
416d75efeb7Sdjm goto fail;
417d75efeb7Sdjm
418d75efeb7Sdjm f->len = cbor_len + 1;
419d75efeb7Sdjm f->ptr[0] = cmd;
420d75efeb7Sdjm memcpy(f->ptr + 1, cbor, f->len - 1);
421d75efeb7Sdjm
422d75efeb7Sdjm ok = 0;
423d75efeb7Sdjm fail:
424d75efeb7Sdjm if (flat != NULL)
425d75efeb7Sdjm cbor_decref(&flat);
426d75efeb7Sdjm
427d75efeb7Sdjm free(cbor);
428d75efeb7Sdjm
429d75efeb7Sdjm return (ok);
430d75efeb7Sdjm }
431d75efeb7Sdjm
432d75efeb7Sdjm cbor_item_t *
cbor_encode_rp_entity(const fido_rp_t * rp)43332a20e26Sdjm cbor_encode_rp_entity(const fido_rp_t *rp)
434d75efeb7Sdjm {
435d75efeb7Sdjm cbor_item_t *item = NULL;
436d75efeb7Sdjm
437d75efeb7Sdjm if ((item = cbor_new_definite_map(2)) == NULL)
438d75efeb7Sdjm return (NULL);
439d75efeb7Sdjm
440d75efeb7Sdjm if ((rp->id && cbor_add_string(item, "id", rp->id) < 0) ||
441d75efeb7Sdjm (rp->name && cbor_add_string(item, "name", rp->name) < 0)) {
442d75efeb7Sdjm cbor_decref(&item);
443d75efeb7Sdjm return (NULL);
444d75efeb7Sdjm }
445d75efeb7Sdjm
446d75efeb7Sdjm return (item);
447d75efeb7Sdjm }
448d75efeb7Sdjm
449d75efeb7Sdjm cbor_item_t *
cbor_encode_user_entity(const fido_user_t * user)45032a20e26Sdjm cbor_encode_user_entity(const fido_user_t *user)
451d75efeb7Sdjm {
452d75efeb7Sdjm cbor_item_t *item = NULL;
453d75efeb7Sdjm const fido_blob_t *id = &user->id;
454d75efeb7Sdjm const char *display = user->display_name;
455d75efeb7Sdjm
456d75efeb7Sdjm if ((item = cbor_new_definite_map(4)) == NULL)
457d75efeb7Sdjm return (NULL);
458d75efeb7Sdjm
459d75efeb7Sdjm if ((id->ptr && cbor_add_bytestring(item, "id", id->ptr, id->len) < 0) ||
460d75efeb7Sdjm (user->icon && cbor_add_string(item, "icon", user->icon) < 0) ||
461d75efeb7Sdjm (user->name && cbor_add_string(item, "name", user->name) < 0) ||
462d75efeb7Sdjm (display && cbor_add_string(item, "displayName", display) < 0)) {
463d75efeb7Sdjm cbor_decref(&item);
464d75efeb7Sdjm return (NULL);
465d75efeb7Sdjm }
466d75efeb7Sdjm
467d75efeb7Sdjm return (item);
468d75efeb7Sdjm }
469d75efeb7Sdjm
470d75efeb7Sdjm cbor_item_t *
cbor_encode_pubkey_param(int cose_alg)47132a20e26Sdjm cbor_encode_pubkey_param(int cose_alg)
472d75efeb7Sdjm {
473d75efeb7Sdjm cbor_item_t *item = NULL;
474d75efeb7Sdjm cbor_item_t *body = NULL;
475d75efeb7Sdjm struct cbor_pair alg;
476d75efeb7Sdjm int ok = -1;
477d75efeb7Sdjm
478d75efeb7Sdjm memset(&alg, 0, sizeof(alg));
479d75efeb7Sdjm
480d75efeb7Sdjm if ((item = cbor_new_definite_array(1)) == NULL ||
481d75efeb7Sdjm (body = cbor_new_definite_map(2)) == NULL ||
482d75efeb7Sdjm cose_alg > -1 || cose_alg < INT16_MIN)
483d75efeb7Sdjm goto fail;
484d75efeb7Sdjm
485d75efeb7Sdjm alg.key = cbor_build_string("alg");
486d75efeb7Sdjm
487d75efeb7Sdjm if (-cose_alg - 1 > UINT8_MAX)
488d75efeb7Sdjm alg.value = cbor_build_negint16((uint16_t)(-cose_alg - 1));
489d75efeb7Sdjm else
490d75efeb7Sdjm alg.value = cbor_build_negint8((uint8_t)(-cose_alg - 1));
491d75efeb7Sdjm
492d75efeb7Sdjm if (alg.key == NULL || alg.value == NULL) {
49332a20e26Sdjm fido_log_debug("%s: cbor_build", __func__);
494d75efeb7Sdjm goto fail;
495d75efeb7Sdjm }
496d75efeb7Sdjm
497d75efeb7Sdjm if (cbor_map_add(body, alg) == false ||
498d75efeb7Sdjm cbor_add_string(body, "type", "public-key") < 0 ||
499d75efeb7Sdjm cbor_array_push(item, body) == false)
500d75efeb7Sdjm goto fail;
501d75efeb7Sdjm
502d75efeb7Sdjm ok = 0;
503d75efeb7Sdjm fail:
504d75efeb7Sdjm if (ok < 0) {
505d75efeb7Sdjm if (item != NULL) {
506d75efeb7Sdjm cbor_decref(&item);
507d75efeb7Sdjm item = NULL;
508d75efeb7Sdjm }
509d75efeb7Sdjm }
510d75efeb7Sdjm
511d75efeb7Sdjm if (body != NULL)
512d75efeb7Sdjm cbor_decref(&body);
513d75efeb7Sdjm if (alg.key != NULL)
514d75efeb7Sdjm cbor_decref(&alg.key);
515d75efeb7Sdjm if (alg.value != NULL)
516d75efeb7Sdjm cbor_decref(&alg.value);
517d75efeb7Sdjm
518d75efeb7Sdjm return (item);
519d75efeb7Sdjm }
520d75efeb7Sdjm
521d75efeb7Sdjm cbor_item_t *
cbor_encode_pubkey(const fido_blob_t * pubkey)52232a20e26Sdjm cbor_encode_pubkey(const fido_blob_t *pubkey)
523d75efeb7Sdjm {
524d75efeb7Sdjm cbor_item_t *cbor_key = NULL;
525d75efeb7Sdjm
526d75efeb7Sdjm if ((cbor_key = cbor_new_definite_map(2)) == NULL ||
527d75efeb7Sdjm cbor_add_bytestring(cbor_key, "id", pubkey->ptr, pubkey->len) < 0 ||
528d75efeb7Sdjm cbor_add_string(cbor_key, "type", "public-key") < 0) {
529d75efeb7Sdjm if (cbor_key)
530d75efeb7Sdjm cbor_decref(&cbor_key);
531d75efeb7Sdjm return (NULL);
532d75efeb7Sdjm }
533d75efeb7Sdjm
534d75efeb7Sdjm return (cbor_key);
535d75efeb7Sdjm }
536d75efeb7Sdjm
537d75efeb7Sdjm cbor_item_t *
cbor_encode_pubkey_list(const fido_blob_array_t * list)53832a20e26Sdjm cbor_encode_pubkey_list(const fido_blob_array_t *list)
539d75efeb7Sdjm {
540d75efeb7Sdjm cbor_item_t *array = NULL;
541d75efeb7Sdjm cbor_item_t *key = NULL;
542d75efeb7Sdjm
543d75efeb7Sdjm if ((array = cbor_new_definite_array(list->len)) == NULL)
544d75efeb7Sdjm goto fail;
545d75efeb7Sdjm
546d75efeb7Sdjm for (size_t i = 0; i < list->len; i++) {
54732a20e26Sdjm if ((key = cbor_encode_pubkey(&list->ptr[i])) == NULL ||
548d75efeb7Sdjm cbor_array_push(array, key) == false)
549d75efeb7Sdjm goto fail;
550d75efeb7Sdjm cbor_decref(&key);
551d75efeb7Sdjm }
552d75efeb7Sdjm
553d75efeb7Sdjm return (array);
554d75efeb7Sdjm fail:
555d75efeb7Sdjm if (key != NULL)
556d75efeb7Sdjm cbor_decref(&key);
557d75efeb7Sdjm if (array != NULL)
558d75efeb7Sdjm cbor_decref(&array);
559d75efeb7Sdjm
560d75efeb7Sdjm return (NULL);
561d75efeb7Sdjm }
562d75efeb7Sdjm
563*ab19a69eSdjm cbor_item_t *
cbor_encode_str_array(const fido_str_array_t * a)564*ab19a69eSdjm cbor_encode_str_array(const fido_str_array_t *a)
565*ab19a69eSdjm {
566*ab19a69eSdjm cbor_item_t *array = NULL;
567*ab19a69eSdjm cbor_item_t *entry = NULL;
568*ab19a69eSdjm
569*ab19a69eSdjm if ((array = cbor_new_definite_array(a->len)) == NULL)
570*ab19a69eSdjm goto fail;
571*ab19a69eSdjm
572*ab19a69eSdjm for (size_t i = 0; i < a->len; i++) {
573*ab19a69eSdjm if ((entry = cbor_build_string(a->ptr[i])) == NULL ||
574*ab19a69eSdjm cbor_array_push(array, entry) == false)
575*ab19a69eSdjm goto fail;
576*ab19a69eSdjm cbor_decref(&entry);
577*ab19a69eSdjm }
578*ab19a69eSdjm
579*ab19a69eSdjm return (array);
580*ab19a69eSdjm fail:
581*ab19a69eSdjm if (entry != NULL)
582*ab19a69eSdjm cbor_decref(&entry);
583*ab19a69eSdjm if (array != NULL)
584*ab19a69eSdjm cbor_decref(&array);
585*ab19a69eSdjm
586*ab19a69eSdjm return (NULL);
587*ab19a69eSdjm }
588*ab19a69eSdjm
589c4a807edSdjm static int
cbor_encode_largeblob_key_ext(cbor_item_t * map)590c4a807edSdjm cbor_encode_largeblob_key_ext(cbor_item_t *map)
591c4a807edSdjm {
592c4a807edSdjm if (map == NULL ||
593c4a807edSdjm cbor_add_bool(map, "largeBlobKey", FIDO_OPT_TRUE) < 0)
594c4a807edSdjm return (-1);
595c4a807edSdjm
596c4a807edSdjm return (0);
597c4a807edSdjm }
598c4a807edSdjm
599d75efeb7Sdjm cbor_item_t *
cbor_encode_cred_ext(const fido_cred_ext_t * ext,const fido_blob_t * blob)600c4a807edSdjm cbor_encode_cred_ext(const fido_cred_ext_t *ext, const fido_blob_t *blob)
601d75efeb7Sdjm {
602d75efeb7Sdjm cbor_item_t *item = NULL;
60332a20e26Sdjm size_t size = 0;
604d75efeb7Sdjm
605c4a807edSdjm if (ext->mask & FIDO_EXT_CRED_BLOB)
606c4a807edSdjm size++;
60732a20e26Sdjm if (ext->mask & FIDO_EXT_HMAC_SECRET)
60832a20e26Sdjm size++;
60932a20e26Sdjm if (ext->mask & FIDO_EXT_CRED_PROTECT)
61032a20e26Sdjm size++;
611c4a807edSdjm if (ext->mask & FIDO_EXT_LARGEBLOB_KEY)
612c4a807edSdjm size++;
613*ab19a69eSdjm if (ext->mask & FIDO_EXT_MINPINLEN)
614*ab19a69eSdjm size++;
615c4a807edSdjm
61632a20e26Sdjm if (size == 0 || (item = cbor_new_definite_map(size)) == NULL)
617d75efeb7Sdjm return (NULL);
618d75efeb7Sdjm
619c4a807edSdjm if (ext->mask & FIDO_EXT_CRED_BLOB) {
620c4a807edSdjm if (cbor_add_bytestring(item, "credBlob", blob->ptr,
621c4a807edSdjm blob->len) < 0) {
622d75efeb7Sdjm cbor_decref(&item);
623d75efeb7Sdjm return (NULL);
624d75efeb7Sdjm }
62532a20e26Sdjm }
62632a20e26Sdjm if (ext->mask & FIDO_EXT_CRED_PROTECT) {
627739189a3Sdjm if (ext->prot < 0 || ext->prot > UINT8_MAX ||
628739189a3Sdjm cbor_add_uint8(item, "credProtect",
629739189a3Sdjm (uint8_t)ext->prot) < 0) {
63032a20e26Sdjm cbor_decref(&item);
63132a20e26Sdjm return (NULL);
63232a20e26Sdjm }
63332a20e26Sdjm }
634c4a807edSdjm if (ext->mask & FIDO_EXT_HMAC_SECRET) {
635c4a807edSdjm if (cbor_add_bool(item, "hmac-secret", FIDO_OPT_TRUE) < 0) {
636c4a807edSdjm cbor_decref(&item);
637c4a807edSdjm return (NULL);
638c4a807edSdjm }
639c4a807edSdjm }
640c4a807edSdjm if (ext->mask & FIDO_EXT_LARGEBLOB_KEY) {
641c4a807edSdjm if (cbor_encode_largeblob_key_ext(item) < 0) {
642c4a807edSdjm cbor_decref(&item);
643c4a807edSdjm return (NULL);
644c4a807edSdjm }
645c4a807edSdjm }
646*ab19a69eSdjm if (ext->mask & FIDO_EXT_MINPINLEN) {
647*ab19a69eSdjm if (cbor_add_bool(item, "minPinLength", FIDO_OPT_TRUE) < 0) {
648*ab19a69eSdjm cbor_decref(&item);
649*ab19a69eSdjm return (NULL);
650*ab19a69eSdjm }
651*ab19a69eSdjm }
652d75efeb7Sdjm
653d75efeb7Sdjm return (item);
654d75efeb7Sdjm }
655d75efeb7Sdjm
656d75efeb7Sdjm cbor_item_t *
cbor_encode_cred_opt(fido_opt_t rk,fido_opt_t uv)657c4a807edSdjm cbor_encode_cred_opt(fido_opt_t rk, fido_opt_t uv)
658d75efeb7Sdjm {
659d75efeb7Sdjm cbor_item_t *item = NULL;
660d75efeb7Sdjm
661d75efeb7Sdjm if ((item = cbor_new_definite_map(2)) == NULL)
662d75efeb7Sdjm return (NULL);
663d75efeb7Sdjm if ((rk != FIDO_OPT_OMIT && cbor_add_bool(item, "rk", rk) < 0) ||
664d75efeb7Sdjm (uv != FIDO_OPT_OMIT && cbor_add_bool(item, "uv", uv) < 0)) {
665d75efeb7Sdjm cbor_decref(&item);
666d75efeb7Sdjm return (NULL);
667d75efeb7Sdjm }
668d75efeb7Sdjm
669d75efeb7Sdjm return (item);
670d75efeb7Sdjm }
671d75efeb7Sdjm
672d75efeb7Sdjm cbor_item_t *
cbor_encode_assert_opt(fido_opt_t up,fido_opt_t uv)673c4a807edSdjm cbor_encode_assert_opt(fido_opt_t up, fido_opt_t uv)
674d75efeb7Sdjm {
675d75efeb7Sdjm cbor_item_t *item = NULL;
676d75efeb7Sdjm
677d75efeb7Sdjm if ((item = cbor_new_definite_map(2)) == NULL)
678d75efeb7Sdjm return (NULL);
679d75efeb7Sdjm if ((up != FIDO_OPT_OMIT && cbor_add_bool(item, "up", up) < 0) ||
680d75efeb7Sdjm (uv != FIDO_OPT_OMIT && cbor_add_bool(item, "uv", uv) < 0)) {
681d75efeb7Sdjm cbor_decref(&item);
682d75efeb7Sdjm return (NULL);
683d75efeb7Sdjm }
684d75efeb7Sdjm
685d75efeb7Sdjm return (item);
686d75efeb7Sdjm }
687d75efeb7Sdjm
688d75efeb7Sdjm cbor_item_t *
cbor_encode_pin_auth(const fido_dev_t * dev,const fido_blob_t * secret,const fido_blob_t * data)689c4a807edSdjm cbor_encode_pin_auth(const fido_dev_t *dev, const fido_blob_t *secret,
690c4a807edSdjm const fido_blob_t *data)
691d75efeb7Sdjm {
692d75efeb7Sdjm const EVP_MD *md = NULL;
693d75efeb7Sdjm unsigned char dgst[SHA256_DIGEST_LENGTH];
694d75efeb7Sdjm unsigned int dgst_len;
695c4a807edSdjm size_t outlen;
696c4a807edSdjm uint8_t prot;
697c4a807edSdjm fido_blob_t key;
698d75efeb7Sdjm
699c4a807edSdjm key.ptr = secret->ptr;
700c4a807edSdjm key.len = secret->len;
701c4a807edSdjm
702c4a807edSdjm if ((prot = fido_dev_get_pin_protocol(dev)) == 0) {
703c4a807edSdjm fido_log_debug("%s: fido_dev_get_pin_protocol", __func__);
704c4a807edSdjm return (NULL);
705c4a807edSdjm }
706c4a807edSdjm
707c4a807edSdjm /* select hmac portion of the shared secret */
708c4a807edSdjm if (prot == CTAP_PIN_PROTOCOL2 && key.len > 32)
709c4a807edSdjm key.len = 32;
710c4a807edSdjm
711c4a807edSdjm if ((md = EVP_sha256()) == NULL || HMAC(md, key.ptr,
712c4a807edSdjm (int)key.len, data->ptr, data->len, dgst,
713d75efeb7Sdjm &dgst_len) == NULL || dgst_len != SHA256_DIGEST_LENGTH)
714d75efeb7Sdjm return (NULL);
715d75efeb7Sdjm
716c4a807edSdjm outlen = (prot == CTAP_PIN_PROTOCOL1) ? 16 : dgst_len;
717c4a807edSdjm
718c4a807edSdjm return (cbor_build_bytestring(dgst, outlen));
719d75efeb7Sdjm }
720d75efeb7Sdjm
721d75efeb7Sdjm cbor_item_t *
cbor_encode_pin_opt(const fido_dev_t * dev)722c4a807edSdjm cbor_encode_pin_opt(const fido_dev_t *dev)
723d75efeb7Sdjm {
724c4a807edSdjm uint8_t prot;
725d75efeb7Sdjm
726c4a807edSdjm if ((prot = fido_dev_get_pin_protocol(dev)) == 0) {
727c4a807edSdjm fido_log_debug("%s: fido_dev_get_pin_protocol", __func__);
728d75efeb7Sdjm return (NULL);
729d75efeb7Sdjm }
730d75efeb7Sdjm
731c4a807edSdjm return (cbor_build_uint8(prot));
732d75efeb7Sdjm }
733d75efeb7Sdjm
734d75efeb7Sdjm cbor_item_t *
cbor_encode_change_pin_auth(const fido_dev_t * dev,const fido_blob_t * secret,const fido_blob_t * new_pin_enc,const fido_blob_t * pin_hash_enc)735c4a807edSdjm cbor_encode_change_pin_auth(const fido_dev_t *dev, const fido_blob_t *secret,
736c4a807edSdjm const fido_blob_t *new_pin_enc, const fido_blob_t *pin_hash_enc)
737d75efeb7Sdjm {
738d75efeb7Sdjm unsigned char dgst[SHA256_DIGEST_LENGTH];
739d75efeb7Sdjm unsigned int dgst_len;
740d75efeb7Sdjm cbor_item_t *item = NULL;
741d75efeb7Sdjm const EVP_MD *md = NULL;
742d75efeb7Sdjm HMAC_CTX *ctx = NULL;
743c4a807edSdjm fido_blob_t key;
744c4a807edSdjm uint8_t prot;
745c4a807edSdjm size_t outlen;
746d75efeb7Sdjm
747c4a807edSdjm key.ptr = secret->ptr;
748c4a807edSdjm key.len = secret->len;
749d75efeb7Sdjm
750c4a807edSdjm if ((prot = fido_dev_get_pin_protocol(dev)) == 0) {
751c4a807edSdjm fido_log_debug("%s: fido_dev_get_pin_protocol", __func__);
752d75efeb7Sdjm goto fail;
753d75efeb7Sdjm }
754d75efeb7Sdjm
755c4a807edSdjm if (prot == CTAP_PIN_PROTOCOL2 && key.len > 32)
756c4a807edSdjm key.len = 32;
757d75efeb7Sdjm
758d75efeb7Sdjm if ((ctx = HMAC_CTX_new()) == NULL ||
759d75efeb7Sdjm (md = EVP_sha256()) == NULL ||
760c4a807edSdjm HMAC_Init_ex(ctx, key.ptr, (int)key.len, md, NULL) == 0 ||
761c4a807edSdjm HMAC_Update(ctx, new_pin_enc->ptr, new_pin_enc->len) == 0 ||
762c4a807edSdjm HMAC_Update(ctx, pin_hash_enc->ptr, pin_hash_enc->len) == 0 ||
763c4a807edSdjm HMAC_Final(ctx, dgst, &dgst_len) == 0 ||
764c4a807edSdjm dgst_len != SHA256_DIGEST_LENGTH) {
76532a20e26Sdjm fido_log_debug("%s: HMAC", __func__);
766d75efeb7Sdjm goto fail;
767d75efeb7Sdjm }
768d75efeb7Sdjm
769c4a807edSdjm outlen = (prot == CTAP_PIN_PROTOCOL1) ? 16 : dgst_len;
770c4a807edSdjm
771c4a807edSdjm if ((item = cbor_build_bytestring(dgst, outlen)) == NULL) {
77232a20e26Sdjm fido_log_debug("%s: cbor_build_bytestring", __func__);
773d75efeb7Sdjm goto fail;
774d75efeb7Sdjm }
775d75efeb7Sdjm
776d75efeb7Sdjm fail:
777d75efeb7Sdjm HMAC_CTX_free(ctx);
778d75efeb7Sdjm
779d75efeb7Sdjm return (item);
780d75efeb7Sdjm }
781d75efeb7Sdjm
782c4a807edSdjm static int
cbor_encode_hmac_secret_param(const fido_dev_t * dev,cbor_item_t * item,const fido_blob_t * ecdh,const es256_pk_t * pk,const fido_blob_t * salt)783c4a807edSdjm cbor_encode_hmac_secret_param(const fido_dev_t *dev, cbor_item_t *item,
784c4a807edSdjm const fido_blob_t *ecdh, const es256_pk_t *pk, const fido_blob_t *salt)
785d75efeb7Sdjm {
786d75efeb7Sdjm cbor_item_t *param = NULL;
787c4a807edSdjm cbor_item_t *argv[4];
788d75efeb7Sdjm struct cbor_pair pair;
789c4a807edSdjm fido_blob_t *enc = NULL;
790*ab19a69eSdjm uint8_t prot;
791c4a807edSdjm int r;
792d75efeb7Sdjm
793d75efeb7Sdjm memset(argv, 0, sizeof(argv));
794d75efeb7Sdjm memset(&pair, 0, sizeof(pair));
795d75efeb7Sdjm
796c4a807edSdjm if (item == NULL || ecdh == NULL || pk == NULL || salt->ptr == NULL) {
797c4a807edSdjm fido_log_debug("%s: ecdh=%p, pk=%p, salt->ptr=%p", __func__,
798c4a807edSdjm (const void *)ecdh, (const void *)pk,
799c4a807edSdjm (const void *)salt->ptr);
800c4a807edSdjm r = FIDO_ERR_INTERNAL;
801d75efeb7Sdjm goto fail;
802d75efeb7Sdjm }
803d75efeb7Sdjm
804c4a807edSdjm if (salt->len != 32 && salt->len != 64) {
805c4a807edSdjm fido_log_debug("%s: salt->len=%zu", __func__, salt->len);
806c4a807edSdjm r = FIDO_ERR_INTERNAL;
807c4a807edSdjm goto fail;
808c4a807edSdjm }
809c4a807edSdjm
810c4a807edSdjm if ((enc = fido_blob_new()) == NULL ||
811c4a807edSdjm aes256_cbc_enc(dev, ecdh, salt, enc) < 0) {
812c4a807edSdjm fido_log_debug("%s: aes256_cbc_enc", __func__);
813c4a807edSdjm r = FIDO_ERR_INTERNAL;
814d75efeb7Sdjm goto fail;
815d75efeb7Sdjm }
816d75efeb7Sdjm
817*ab19a69eSdjm if ((prot = fido_dev_get_pin_protocol(dev)) == 0) {
818*ab19a69eSdjm fido_log_debug("%s: fido_dev_get_pin_protocol", __func__);
819*ab19a69eSdjm r = FIDO_ERR_INTERNAL;
820*ab19a69eSdjm goto fail;
821*ab19a69eSdjm }
822*ab19a69eSdjm
823d75efeb7Sdjm /* XXX not pin, but salt */
824d75efeb7Sdjm if ((argv[0] = es256_pk_encode(pk, 1)) == NULL ||
825c4a807edSdjm (argv[1] = fido_blob_encode(enc)) == NULL ||
826c4a807edSdjm (argv[2] = cbor_encode_pin_auth(dev, ecdh, enc)) == NULL ||
827*ab19a69eSdjm (prot != 1 && (argv[3] = cbor_build_uint8(prot)) == NULL)) {
82832a20e26Sdjm fido_log_debug("%s: cbor encode", __func__);
829c4a807edSdjm r = FIDO_ERR_INTERNAL;
830d75efeb7Sdjm goto fail;
831d75efeb7Sdjm }
832d75efeb7Sdjm
833c4a807edSdjm if ((param = cbor_flatten_vector(argv, nitems(argv))) == NULL) {
83432a20e26Sdjm fido_log_debug("%s: cbor_flatten_vector", __func__);
835c4a807edSdjm r = FIDO_ERR_INTERNAL;
836d75efeb7Sdjm goto fail;
837d75efeb7Sdjm }
838d75efeb7Sdjm
839d75efeb7Sdjm if ((pair.key = cbor_build_string("hmac-secret")) == NULL) {
84032a20e26Sdjm fido_log_debug("%s: cbor_build", __func__);
841c4a807edSdjm r = FIDO_ERR_INTERNAL;
842d75efeb7Sdjm goto fail;
843d75efeb7Sdjm }
844d75efeb7Sdjm
845d75efeb7Sdjm pair.value = param;
846d75efeb7Sdjm
847d75efeb7Sdjm if (!cbor_map_add(item, pair)) {
84832a20e26Sdjm fido_log_debug("%s: cbor_map_add", __func__);
849c4a807edSdjm r = FIDO_ERR_INTERNAL;
850d75efeb7Sdjm goto fail;
851d75efeb7Sdjm }
852d75efeb7Sdjm
853c4a807edSdjm r = FIDO_OK;
854c4a807edSdjm
855d75efeb7Sdjm fail:
856c4a807edSdjm cbor_vector_free(argv, nitems(argv));
857d75efeb7Sdjm
858d75efeb7Sdjm if (param != NULL)
859d75efeb7Sdjm cbor_decref(¶m);
860d75efeb7Sdjm if (pair.key != NULL)
861d75efeb7Sdjm cbor_decref(&pair.key);
862d75efeb7Sdjm
863c4a807edSdjm fido_blob_free(&enc);
864c4a807edSdjm
865c4a807edSdjm return (r);
866c4a807edSdjm }
867c4a807edSdjm
868c4a807edSdjm cbor_item_t *
cbor_encode_assert_ext(fido_dev_t * dev,const fido_assert_ext_t * ext,const fido_blob_t * ecdh,const es256_pk_t * pk)869c4a807edSdjm cbor_encode_assert_ext(fido_dev_t *dev, const fido_assert_ext_t *ext,
870c4a807edSdjm const fido_blob_t *ecdh, const es256_pk_t *pk)
871c4a807edSdjm {
872c4a807edSdjm cbor_item_t *item = NULL;
873c4a807edSdjm size_t size = 0;
874c4a807edSdjm
875c4a807edSdjm if (ext->mask & FIDO_EXT_CRED_BLOB)
876c4a807edSdjm size++;
877c4a807edSdjm if (ext->mask & FIDO_EXT_HMAC_SECRET)
878c4a807edSdjm size++;
879c4a807edSdjm if (ext->mask & FIDO_EXT_LARGEBLOB_KEY)
880c4a807edSdjm size++;
881c4a807edSdjm if (size == 0 || (item = cbor_new_definite_map(size)) == NULL)
882c4a807edSdjm return (NULL);
883c4a807edSdjm
884c4a807edSdjm if (ext->mask & FIDO_EXT_CRED_BLOB) {
885c4a807edSdjm if (cbor_add_bool(item, "credBlob", FIDO_OPT_TRUE) < 0) {
886c4a807edSdjm cbor_decref(&item);
887c4a807edSdjm return (NULL);
888c4a807edSdjm }
889c4a807edSdjm }
890c4a807edSdjm if (ext->mask & FIDO_EXT_HMAC_SECRET) {
891c4a807edSdjm if (cbor_encode_hmac_secret_param(dev, item, ecdh, pk,
892c4a807edSdjm &ext->hmac_salt) < 0) {
893c4a807edSdjm cbor_decref(&item);
894c4a807edSdjm return (NULL);
895c4a807edSdjm }
896c4a807edSdjm }
897c4a807edSdjm if (ext->mask & FIDO_EXT_LARGEBLOB_KEY) {
898c4a807edSdjm if (cbor_encode_largeblob_key_ext(item) < 0) {
899c4a807edSdjm cbor_decref(&item);
900c4a807edSdjm return (NULL);
901c4a807edSdjm }
902c4a807edSdjm }
903c4a807edSdjm
904d75efeb7Sdjm return (item);
905d75efeb7Sdjm }
906d75efeb7Sdjm
907d75efeb7Sdjm int
cbor_decode_fmt(const cbor_item_t * item,char ** fmt)90832a20e26Sdjm cbor_decode_fmt(const cbor_item_t *item, char **fmt)
909d75efeb7Sdjm {
910d75efeb7Sdjm char *type = NULL;
911d75efeb7Sdjm
912d75efeb7Sdjm if (cbor_string_copy(item, &type) < 0) {
91332a20e26Sdjm fido_log_debug("%s: cbor_string_copy", __func__);
914d75efeb7Sdjm return (-1);
915d75efeb7Sdjm }
916d75efeb7Sdjm
917c4a807edSdjm if (strcmp(type, "packed") && strcmp(type, "fido-u2f") &&
918*ab19a69eSdjm strcmp(type, "none") && strcmp(type, "tpm")) {
91932a20e26Sdjm fido_log_debug("%s: type=%s", __func__, type);
920d75efeb7Sdjm free(type);
921d75efeb7Sdjm return (-1);
922d75efeb7Sdjm }
923d75efeb7Sdjm
924d75efeb7Sdjm *fmt = type;
925d75efeb7Sdjm
926d75efeb7Sdjm return (0);
927d75efeb7Sdjm }
928d75efeb7Sdjm
929d75efeb7Sdjm struct cose_key {
930d75efeb7Sdjm int kty;
931d75efeb7Sdjm int alg;
932d75efeb7Sdjm int crv;
933d75efeb7Sdjm };
934d75efeb7Sdjm
935d75efeb7Sdjm static int
find_cose_alg(const cbor_item_t * key,const cbor_item_t * val,void * arg)936d75efeb7Sdjm find_cose_alg(const cbor_item_t *key, const cbor_item_t *val, void *arg)
937d75efeb7Sdjm {
938d75efeb7Sdjm struct cose_key *cose_key = arg;
939d75efeb7Sdjm
940d75efeb7Sdjm if (cbor_isa_uint(key) == true &&
941d75efeb7Sdjm cbor_int_get_width(key) == CBOR_INT_8) {
942d75efeb7Sdjm switch (cbor_get_uint8(key)) {
943d75efeb7Sdjm case 1:
944d75efeb7Sdjm if (cbor_isa_uint(val) == false ||
945d75efeb7Sdjm cbor_get_int(val) > INT_MAX || cose_key->kty != 0) {
94632a20e26Sdjm fido_log_debug("%s: kty", __func__);
947d75efeb7Sdjm return (-1);
948d75efeb7Sdjm }
949d75efeb7Sdjm
950d75efeb7Sdjm cose_key->kty = (int)cbor_get_int(val);
951d75efeb7Sdjm
952d75efeb7Sdjm break;
953d75efeb7Sdjm case 3:
954d75efeb7Sdjm if (cbor_isa_negint(val) == false ||
955d75efeb7Sdjm cbor_get_int(val) > INT_MAX || cose_key->alg != 0) {
95632a20e26Sdjm fido_log_debug("%s: alg", __func__);
957d75efeb7Sdjm return (-1);
958d75efeb7Sdjm }
959d75efeb7Sdjm
960d75efeb7Sdjm cose_key->alg = -(int)cbor_get_int(val) - 1;
961d75efeb7Sdjm
962d75efeb7Sdjm break;
963d75efeb7Sdjm }
964d75efeb7Sdjm } else if (cbor_isa_negint(key) == true &&
965d75efeb7Sdjm cbor_int_get_width(key) == CBOR_INT_8) {
966d75efeb7Sdjm if (cbor_get_uint8(key) == 0) {
967d75efeb7Sdjm /* get crv if not rsa, otherwise ignore */
968d75efeb7Sdjm if (cbor_isa_uint(val) == true &&
969d75efeb7Sdjm cbor_get_int(val) <= INT_MAX &&
970d75efeb7Sdjm cose_key->crv == 0)
971d75efeb7Sdjm cose_key->crv = (int)cbor_get_int(val);
972d75efeb7Sdjm }
973d75efeb7Sdjm }
974d75efeb7Sdjm
975d75efeb7Sdjm return (0);
976d75efeb7Sdjm }
977d75efeb7Sdjm
978d75efeb7Sdjm static int
get_cose_alg(const cbor_item_t * item,int * cose_alg)979d75efeb7Sdjm get_cose_alg(const cbor_item_t *item, int *cose_alg)
980d75efeb7Sdjm {
981d75efeb7Sdjm struct cose_key cose_key;
982d75efeb7Sdjm
983d75efeb7Sdjm memset(&cose_key, 0, sizeof(cose_key));
984d75efeb7Sdjm
985d75efeb7Sdjm *cose_alg = 0;
986d75efeb7Sdjm
987d75efeb7Sdjm if (cbor_isa_map(item) == false ||
988d75efeb7Sdjm cbor_map_is_definite(item) == false ||
989d75efeb7Sdjm cbor_map_iter(item, &cose_key, find_cose_alg) < 0) {
99032a20e26Sdjm fido_log_debug("%s: cbor type", __func__);
991d75efeb7Sdjm return (-1);
992d75efeb7Sdjm }
993d75efeb7Sdjm
994d75efeb7Sdjm switch (cose_key.alg) {
995d75efeb7Sdjm case COSE_ES256:
996d75efeb7Sdjm if (cose_key.kty != COSE_KTY_EC2 ||
997d75efeb7Sdjm cose_key.crv != COSE_P256) {
99832a20e26Sdjm fido_log_debug("%s: invalid kty/crv", __func__);
999d75efeb7Sdjm return (-1);
1000d75efeb7Sdjm }
1001d75efeb7Sdjm
1002d75efeb7Sdjm break;
1003d75efeb7Sdjm case COSE_EDDSA:
1004d75efeb7Sdjm if (cose_key.kty != COSE_KTY_OKP ||
1005d75efeb7Sdjm cose_key.crv != COSE_ED25519) {
100632a20e26Sdjm fido_log_debug("%s: invalid kty/crv", __func__);
1007d75efeb7Sdjm return (-1);
1008d75efeb7Sdjm }
1009d75efeb7Sdjm
1010d75efeb7Sdjm break;
1011d75efeb7Sdjm case COSE_RS256:
1012d75efeb7Sdjm if (cose_key.kty != COSE_KTY_RSA) {
101332a20e26Sdjm fido_log_debug("%s: invalid kty/crv", __func__);
1014d75efeb7Sdjm return (-1);
1015d75efeb7Sdjm }
1016d75efeb7Sdjm
1017d75efeb7Sdjm break;
1018d75efeb7Sdjm default:
101932a20e26Sdjm fido_log_debug("%s: unknown alg %d", __func__, cose_key.alg);
1020d75efeb7Sdjm
1021d75efeb7Sdjm return (-1);
1022d75efeb7Sdjm }
1023d75efeb7Sdjm
1024d75efeb7Sdjm *cose_alg = cose_key.alg;
1025d75efeb7Sdjm
1026d75efeb7Sdjm return (0);
1027d75efeb7Sdjm }
1028d75efeb7Sdjm
1029d75efeb7Sdjm int
cbor_decode_pubkey(const cbor_item_t * item,int * type,void * key)103032a20e26Sdjm cbor_decode_pubkey(const cbor_item_t *item, int *type, void *key)
1031d75efeb7Sdjm {
1032d75efeb7Sdjm if (get_cose_alg(item, type) < 0) {
103332a20e26Sdjm fido_log_debug("%s: get_cose_alg", __func__);
1034d75efeb7Sdjm return (-1);
1035d75efeb7Sdjm }
1036d75efeb7Sdjm
1037d75efeb7Sdjm switch (*type) {
1038d75efeb7Sdjm case COSE_ES256:
1039d75efeb7Sdjm if (es256_pk_decode(item, key) < 0) {
104032a20e26Sdjm fido_log_debug("%s: es256_pk_decode", __func__);
1041d75efeb7Sdjm return (-1);
1042d75efeb7Sdjm }
1043d75efeb7Sdjm break;
1044d75efeb7Sdjm case COSE_RS256:
1045d75efeb7Sdjm if (rs256_pk_decode(item, key) < 0) {
104632a20e26Sdjm fido_log_debug("%s: rs256_pk_decode", __func__);
1047d75efeb7Sdjm return (-1);
1048d75efeb7Sdjm }
1049d75efeb7Sdjm break;
1050d75efeb7Sdjm case COSE_EDDSA:
1051d75efeb7Sdjm if (eddsa_pk_decode(item, key) < 0) {
105232a20e26Sdjm fido_log_debug("%s: eddsa_pk_decode", __func__);
1053d75efeb7Sdjm return (-1);
1054d75efeb7Sdjm }
1055d75efeb7Sdjm break;
1056d75efeb7Sdjm default:
105732a20e26Sdjm fido_log_debug("%s: invalid cose_alg %d", __func__, *type);
1058d75efeb7Sdjm return (-1);
1059d75efeb7Sdjm }
1060d75efeb7Sdjm
1061d75efeb7Sdjm return (0);
1062d75efeb7Sdjm }
1063d75efeb7Sdjm
1064d75efeb7Sdjm static int
decode_attcred(const unsigned char ** buf,size_t * len,int cose_alg,fido_attcred_t * attcred)1065d75efeb7Sdjm decode_attcred(const unsigned char **buf, size_t *len, int cose_alg,
1066d75efeb7Sdjm fido_attcred_t *attcred)
1067d75efeb7Sdjm {
1068d75efeb7Sdjm cbor_item_t *item = NULL;
1069d75efeb7Sdjm struct cbor_load_result cbor;
1070d75efeb7Sdjm uint16_t id_len;
1071d75efeb7Sdjm int ok = -1;
1072d75efeb7Sdjm
1073c4a807edSdjm fido_log_xxd(*buf, *len, "%s", __func__);
1074d75efeb7Sdjm
107532a20e26Sdjm if (fido_buf_read(buf, len, &attcred->aaguid,
107632a20e26Sdjm sizeof(attcred->aaguid)) < 0) {
107732a20e26Sdjm fido_log_debug("%s: fido_buf_read aaguid", __func__);
1078d75efeb7Sdjm return (-1);
1079d75efeb7Sdjm }
1080d75efeb7Sdjm
108132a20e26Sdjm if (fido_buf_read(buf, len, &id_len, sizeof(id_len)) < 0) {
108232a20e26Sdjm fido_log_debug("%s: fido_buf_read id_len", __func__);
1083d75efeb7Sdjm return (-1);
1084d75efeb7Sdjm }
1085d75efeb7Sdjm
1086d75efeb7Sdjm attcred->id.len = (size_t)be16toh(id_len);
1087d75efeb7Sdjm if ((attcred->id.ptr = malloc(attcred->id.len)) == NULL)
1088d75efeb7Sdjm return (-1);
1089d75efeb7Sdjm
109032a20e26Sdjm fido_log_debug("%s: attcred->id.len=%zu", __func__, attcred->id.len);
1091d75efeb7Sdjm
109232a20e26Sdjm if (fido_buf_read(buf, len, attcred->id.ptr, attcred->id.len) < 0) {
109332a20e26Sdjm fido_log_debug("%s: fido_buf_read id", __func__);
1094d75efeb7Sdjm return (-1);
1095d75efeb7Sdjm }
1096d75efeb7Sdjm
1097d75efeb7Sdjm if ((item = cbor_load(*buf, *len, &cbor)) == NULL) {
109832a20e26Sdjm fido_log_debug("%s: cbor_load", __func__);
1099d75efeb7Sdjm goto fail;
1100d75efeb7Sdjm }
1101d75efeb7Sdjm
110232a20e26Sdjm if (cbor_decode_pubkey(item, &attcred->type, &attcred->pubkey) < 0) {
110332a20e26Sdjm fido_log_debug("%s: cbor_decode_pubkey", __func__);
1104d75efeb7Sdjm goto fail;
1105d75efeb7Sdjm }
1106d75efeb7Sdjm
1107d75efeb7Sdjm if (attcred->type != cose_alg) {
110832a20e26Sdjm fido_log_debug("%s: cose_alg mismatch (%d != %d)", __func__,
1109d75efeb7Sdjm attcred->type, cose_alg);
1110d75efeb7Sdjm goto fail;
1111d75efeb7Sdjm }
1112d75efeb7Sdjm
1113d75efeb7Sdjm *buf += cbor.read;
1114d75efeb7Sdjm *len -= cbor.read;
1115d75efeb7Sdjm
1116d75efeb7Sdjm ok = 0;
1117d75efeb7Sdjm fail:
1118d75efeb7Sdjm if (item != NULL)
1119d75efeb7Sdjm cbor_decref(&item);
1120d75efeb7Sdjm
1121d75efeb7Sdjm return (ok);
1122d75efeb7Sdjm }
1123d75efeb7Sdjm
1124d75efeb7Sdjm static int
decode_cred_extension(const cbor_item_t * key,const cbor_item_t * val,void * arg)1125c4a807edSdjm decode_cred_extension(const cbor_item_t *key, const cbor_item_t *val, void *arg)
1126d75efeb7Sdjm {
112732a20e26Sdjm fido_cred_ext_t *authdata_ext = arg;
1128d75efeb7Sdjm char *type = NULL;
1129d75efeb7Sdjm int ok = -1;
1130d75efeb7Sdjm
113132a20e26Sdjm if (cbor_string_copy(key, &type) < 0) {
113232a20e26Sdjm fido_log_debug("%s: cbor type", __func__);
1133d75efeb7Sdjm ok = 0; /* ignore */
1134d75efeb7Sdjm goto out;
1135d75efeb7Sdjm }
1136d75efeb7Sdjm
113732a20e26Sdjm if (strcmp(type, "hmac-secret") == 0) {
1138d75efeb7Sdjm if (cbor_isa_float_ctrl(val) == false ||
1139d75efeb7Sdjm cbor_float_get_width(val) != CBOR_FLOAT_0 ||
114032a20e26Sdjm cbor_is_bool(val) == false) {
114132a20e26Sdjm fido_log_debug("%s: cbor type", __func__);
1142d75efeb7Sdjm goto out;
1143d75efeb7Sdjm }
1144d75efeb7Sdjm if (cbor_ctrl_value(val) == CBOR_CTRL_TRUE)
114532a20e26Sdjm authdata_ext->mask |= FIDO_EXT_HMAC_SECRET;
114632a20e26Sdjm } else if (strcmp(type, "credProtect") == 0) {
114732a20e26Sdjm if (cbor_isa_uint(val) == false ||
114832a20e26Sdjm cbor_int_get_width(val) != CBOR_INT_8) {
114932a20e26Sdjm fido_log_debug("%s: cbor type", __func__);
115032a20e26Sdjm goto out;
115132a20e26Sdjm }
115232a20e26Sdjm authdata_ext->mask |= FIDO_EXT_CRED_PROTECT;
115332a20e26Sdjm authdata_ext->prot = cbor_get_uint8(val);
1154c4a807edSdjm } else if (strcmp(type, "credBlob") == 0) {
1155c4a807edSdjm if (cbor_isa_float_ctrl(val) == false ||
1156c4a807edSdjm cbor_float_get_width(val) != CBOR_FLOAT_0 ||
1157c4a807edSdjm cbor_is_bool(val) == false) {
1158c4a807edSdjm fido_log_debug("%s: cbor type", __func__);
1159c4a807edSdjm goto out;
1160c4a807edSdjm }
1161c4a807edSdjm if (cbor_ctrl_value(val) == CBOR_CTRL_TRUE)
1162c4a807edSdjm authdata_ext->mask |= FIDO_EXT_CRED_BLOB;
1163*ab19a69eSdjm } else if (strcmp(type, "minPinLength") == 0) {
1164*ab19a69eSdjm if (cbor_isa_uint(val) == false ||
1165*ab19a69eSdjm cbor_int_get_width(val) != CBOR_INT_8) {
1166*ab19a69eSdjm fido_log_debug("%s: cbor type", __func__);
1167*ab19a69eSdjm goto out;
1168*ab19a69eSdjm }
1169*ab19a69eSdjm authdata_ext->mask |= FIDO_EXT_MINPINLEN;
1170*ab19a69eSdjm authdata_ext->minpinlen = cbor_get_uint8(val);
117132a20e26Sdjm }
1172d75efeb7Sdjm
1173d75efeb7Sdjm ok = 0;
1174d75efeb7Sdjm out:
1175d75efeb7Sdjm free(type);
1176d75efeb7Sdjm
1177d75efeb7Sdjm return (ok);
1178d75efeb7Sdjm }
1179d75efeb7Sdjm
1180d75efeb7Sdjm static int
decode_cred_extensions(const unsigned char ** buf,size_t * len,fido_cred_ext_t * authdata_ext)1181c4a807edSdjm decode_cred_extensions(const unsigned char **buf, size_t *len,
118232a20e26Sdjm fido_cred_ext_t *authdata_ext)
1183d75efeb7Sdjm {
1184d75efeb7Sdjm cbor_item_t *item = NULL;
1185d75efeb7Sdjm struct cbor_load_result cbor;
1186d75efeb7Sdjm int ok = -1;
1187d75efeb7Sdjm
118832a20e26Sdjm memset(authdata_ext, 0, sizeof(*authdata_ext));
1189d75efeb7Sdjm
1190c4a807edSdjm fido_log_xxd(*buf, *len, "%s", __func__);
1191c4a807edSdjm
1192d75efeb7Sdjm if ((item = cbor_load(*buf, *len, &cbor)) == NULL) {
119332a20e26Sdjm fido_log_debug("%s: cbor_load", __func__);
1194d75efeb7Sdjm goto fail;
1195d75efeb7Sdjm }
1196d75efeb7Sdjm
1197d75efeb7Sdjm if (cbor_isa_map(item) == false ||
1198d75efeb7Sdjm cbor_map_is_definite(item) == false ||
1199c4a807edSdjm cbor_map_iter(item, authdata_ext, decode_cred_extension) < 0) {
120032a20e26Sdjm fido_log_debug("%s: cbor type", __func__);
1201d75efeb7Sdjm goto fail;
1202d75efeb7Sdjm }
1203d75efeb7Sdjm
1204d75efeb7Sdjm *buf += cbor.read;
1205d75efeb7Sdjm *len -= cbor.read;
1206d75efeb7Sdjm
1207d75efeb7Sdjm ok = 0;
1208d75efeb7Sdjm fail:
1209d75efeb7Sdjm if (item != NULL)
1210d75efeb7Sdjm cbor_decref(&item);
1211d75efeb7Sdjm
1212d75efeb7Sdjm return (ok);
1213d75efeb7Sdjm }
1214d75efeb7Sdjm
1215d75efeb7Sdjm static int
decode_assert_extension(const cbor_item_t * key,const cbor_item_t * val,void * arg)1216c4a807edSdjm decode_assert_extension(const cbor_item_t *key, const cbor_item_t *val,
1217c4a807edSdjm void *arg)
1218d75efeb7Sdjm {
1219c4a807edSdjm fido_assert_extattr_t *authdata_ext = arg;
1220d75efeb7Sdjm char *type = NULL;
1221d75efeb7Sdjm int ok = -1;
1222d75efeb7Sdjm
1223c4a807edSdjm if (cbor_string_copy(key, &type) < 0) {
122432a20e26Sdjm fido_log_debug("%s: cbor type", __func__);
1225d75efeb7Sdjm ok = 0; /* ignore */
1226d75efeb7Sdjm goto out;
1227d75efeb7Sdjm }
1228d75efeb7Sdjm
1229c4a807edSdjm if (strcmp(type, "hmac-secret") == 0) {
1230c4a807edSdjm if (fido_blob_decode(val, &authdata_ext->hmac_secret_enc) < 0) {
1231c4a807edSdjm fido_log_debug("%s: fido_blob_decode", __func__);
1232c4a807edSdjm goto out;
1233c4a807edSdjm }
1234c4a807edSdjm authdata_ext->mask |= FIDO_EXT_HMAC_SECRET;
1235c4a807edSdjm } else if (strcmp(type, "credBlob") == 0) {
1236c4a807edSdjm if (fido_blob_decode(val, &authdata_ext->blob) < 0) {
1237c4a807edSdjm fido_log_debug("%s: fido_blob_decode", __func__);
1238c4a807edSdjm goto out;
1239c4a807edSdjm }
1240c4a807edSdjm authdata_ext->mask |= FIDO_EXT_CRED_BLOB;
1241c4a807edSdjm }
1242c4a807edSdjm
1243c4a807edSdjm ok = 0;
1244d75efeb7Sdjm out:
1245d75efeb7Sdjm free(type);
1246d75efeb7Sdjm
1247d75efeb7Sdjm return (ok);
1248d75efeb7Sdjm }
1249d75efeb7Sdjm
1250d75efeb7Sdjm static int
decode_assert_extensions(const unsigned char ** buf,size_t * len,fido_assert_extattr_t * authdata_ext)1251c4a807edSdjm decode_assert_extensions(const unsigned char **buf, size_t *len,
1252c4a807edSdjm fido_assert_extattr_t *authdata_ext)
1253d75efeb7Sdjm {
1254d75efeb7Sdjm cbor_item_t *item = NULL;
1255d75efeb7Sdjm struct cbor_load_result cbor;
1256d75efeb7Sdjm int ok = -1;
1257d75efeb7Sdjm
1258c4a807edSdjm fido_log_xxd(*buf, *len, "%s", __func__);
1259d75efeb7Sdjm
1260d75efeb7Sdjm if ((item = cbor_load(*buf, *len, &cbor)) == NULL) {
126132a20e26Sdjm fido_log_debug("%s: cbor_load", __func__);
1262d75efeb7Sdjm goto fail;
1263d75efeb7Sdjm }
1264d75efeb7Sdjm
1265d75efeb7Sdjm if (cbor_isa_map(item) == false ||
1266d75efeb7Sdjm cbor_map_is_definite(item) == false ||
1267c4a807edSdjm cbor_map_iter(item, authdata_ext, decode_assert_extension) < 0) {
126832a20e26Sdjm fido_log_debug("%s: cbor type", __func__);
1269d75efeb7Sdjm goto fail;
1270d75efeb7Sdjm }
1271d75efeb7Sdjm
1272d75efeb7Sdjm *buf += cbor.read;
1273d75efeb7Sdjm *len -= cbor.read;
1274d75efeb7Sdjm
1275d75efeb7Sdjm ok = 0;
1276d75efeb7Sdjm fail:
1277d75efeb7Sdjm if (item != NULL)
1278d75efeb7Sdjm cbor_decref(&item);
1279d75efeb7Sdjm
1280d75efeb7Sdjm return (ok);
1281d75efeb7Sdjm }
1282d75efeb7Sdjm
1283d75efeb7Sdjm int
cbor_decode_cred_authdata(const cbor_item_t * item,int cose_alg,fido_blob_t * authdata_cbor,fido_authdata_t * authdata,fido_attcred_t * attcred,fido_cred_ext_t * authdata_ext)128432a20e26Sdjm cbor_decode_cred_authdata(const cbor_item_t *item, int cose_alg,
1285d75efeb7Sdjm fido_blob_t *authdata_cbor, fido_authdata_t *authdata,
128632a20e26Sdjm fido_attcred_t *attcred, fido_cred_ext_t *authdata_ext)
1287d75efeb7Sdjm {
1288d75efeb7Sdjm const unsigned char *buf = NULL;
1289d75efeb7Sdjm size_t len;
1290d75efeb7Sdjm size_t alloc_len;
1291d75efeb7Sdjm
1292d75efeb7Sdjm if (cbor_isa_bytestring(item) == false ||
1293d75efeb7Sdjm cbor_bytestring_is_definite(item) == false) {
129432a20e26Sdjm fido_log_debug("%s: cbor type", __func__);
1295d75efeb7Sdjm return (-1);
1296d75efeb7Sdjm }
1297d75efeb7Sdjm
1298d75efeb7Sdjm if (authdata_cbor->ptr != NULL ||
1299d75efeb7Sdjm (authdata_cbor->len = cbor_serialize_alloc(item,
1300d75efeb7Sdjm &authdata_cbor->ptr, &alloc_len)) == 0) {
130132a20e26Sdjm fido_log_debug("%s: cbor_serialize_alloc", __func__);
1302d75efeb7Sdjm return (-1);
1303d75efeb7Sdjm }
1304d75efeb7Sdjm
1305d75efeb7Sdjm buf = cbor_bytestring_handle(item);
1306d75efeb7Sdjm len = cbor_bytestring_length(item);
1307c4a807edSdjm fido_log_xxd(buf, len, "%s", __func__);
1308d75efeb7Sdjm
130932a20e26Sdjm if (fido_buf_read(&buf, &len, authdata, sizeof(*authdata)) < 0) {
131032a20e26Sdjm fido_log_debug("%s: fido_buf_read", __func__);
1311d75efeb7Sdjm return (-1);
1312d75efeb7Sdjm }
1313d75efeb7Sdjm
1314d75efeb7Sdjm authdata->sigcount = be32toh(authdata->sigcount);
1315d75efeb7Sdjm
1316d75efeb7Sdjm if (attcred != NULL) {
1317d75efeb7Sdjm if ((authdata->flags & CTAP_AUTHDATA_ATT_CRED) == 0 ||
1318d75efeb7Sdjm decode_attcred(&buf, &len, cose_alg, attcred) < 0)
1319d75efeb7Sdjm return (-1);
1320d75efeb7Sdjm }
1321d75efeb7Sdjm
1322d75efeb7Sdjm if (authdata_ext != NULL) {
1323d75efeb7Sdjm if ((authdata->flags & CTAP_AUTHDATA_EXT_DATA) != 0 &&
1324c4a807edSdjm decode_cred_extensions(&buf, &len, authdata_ext) < 0)
1325d75efeb7Sdjm return (-1);
1326d75efeb7Sdjm }
1327d75efeb7Sdjm
1328d75efeb7Sdjm /* XXX we should probably ensure that len == 0 at this point */
1329d75efeb7Sdjm
1330d75efeb7Sdjm return (FIDO_OK);
1331d75efeb7Sdjm }
1332d75efeb7Sdjm
1333d75efeb7Sdjm int
cbor_decode_assert_authdata(const cbor_item_t * item,fido_blob_t * authdata_cbor,fido_authdata_t * authdata,fido_assert_extattr_t * authdata_ext)133432a20e26Sdjm cbor_decode_assert_authdata(const cbor_item_t *item, fido_blob_t *authdata_cbor,
1335c4a807edSdjm fido_authdata_t *authdata, fido_assert_extattr_t *authdata_ext)
1336d75efeb7Sdjm {
1337d75efeb7Sdjm const unsigned char *buf = NULL;
1338d75efeb7Sdjm size_t len;
1339d75efeb7Sdjm size_t alloc_len;
1340d75efeb7Sdjm
1341d75efeb7Sdjm if (cbor_isa_bytestring(item) == false ||
1342d75efeb7Sdjm cbor_bytestring_is_definite(item) == false) {
134332a20e26Sdjm fido_log_debug("%s: cbor type", __func__);
1344d75efeb7Sdjm return (-1);
1345d75efeb7Sdjm }
1346d75efeb7Sdjm
1347d75efeb7Sdjm if (authdata_cbor->ptr != NULL ||
1348d75efeb7Sdjm (authdata_cbor->len = cbor_serialize_alloc(item,
1349d75efeb7Sdjm &authdata_cbor->ptr, &alloc_len)) == 0) {
135032a20e26Sdjm fido_log_debug("%s: cbor_serialize_alloc", __func__);
1351d75efeb7Sdjm return (-1);
1352d75efeb7Sdjm }
1353d75efeb7Sdjm
1354d75efeb7Sdjm buf = cbor_bytestring_handle(item);
1355d75efeb7Sdjm len = cbor_bytestring_length(item);
1356d75efeb7Sdjm
135732a20e26Sdjm fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)buf, len);
1358d75efeb7Sdjm
135932a20e26Sdjm if (fido_buf_read(&buf, &len, authdata, sizeof(*authdata)) < 0) {
136032a20e26Sdjm fido_log_debug("%s: fido_buf_read", __func__);
1361d75efeb7Sdjm return (-1);
1362d75efeb7Sdjm }
1363d75efeb7Sdjm
1364d75efeb7Sdjm authdata->sigcount = be32toh(authdata->sigcount);
1365d75efeb7Sdjm
1366d75efeb7Sdjm if ((authdata->flags & CTAP_AUTHDATA_EXT_DATA) != 0) {
1367c4a807edSdjm if (decode_assert_extensions(&buf, &len, authdata_ext) < 0) {
1368c4a807edSdjm fido_log_debug("%s: decode_assert_extensions",
1369c4a807edSdjm __func__);
1370d75efeb7Sdjm return (-1);
1371d75efeb7Sdjm }
1372d75efeb7Sdjm }
1373d75efeb7Sdjm
1374d75efeb7Sdjm /* XXX we should probably ensure that len == 0 at this point */
1375d75efeb7Sdjm
1376d75efeb7Sdjm return (FIDO_OK);
1377d75efeb7Sdjm }
1378d75efeb7Sdjm
1379d75efeb7Sdjm static int
decode_x5c(const cbor_item_t * item,void * arg)1380d75efeb7Sdjm decode_x5c(const cbor_item_t *item, void *arg)
1381d75efeb7Sdjm {
1382d75efeb7Sdjm fido_blob_t *x5c = arg;
1383d75efeb7Sdjm
1384d75efeb7Sdjm if (x5c->len)
1385d75efeb7Sdjm return (0); /* ignore */
1386d75efeb7Sdjm
1387c4a807edSdjm return (fido_blob_decode(item, x5c));
1388d75efeb7Sdjm }
1389d75efeb7Sdjm
1390d75efeb7Sdjm static int
decode_attstmt_entry(const cbor_item_t * key,const cbor_item_t * val,void * arg)1391d75efeb7Sdjm decode_attstmt_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg)
1392d75efeb7Sdjm {
1393d75efeb7Sdjm fido_attstmt_t *attstmt = arg;
1394d75efeb7Sdjm char *name = NULL;
1395d75efeb7Sdjm int ok = -1;
1396d75efeb7Sdjm
1397d75efeb7Sdjm if (cbor_string_copy(key, &name) < 0) {
139832a20e26Sdjm fido_log_debug("%s: cbor type", __func__);
1399d75efeb7Sdjm ok = 0; /* ignore */
1400d75efeb7Sdjm goto out;
1401d75efeb7Sdjm }
1402d75efeb7Sdjm
1403d75efeb7Sdjm if (!strcmp(name, "alg")) {
1404d75efeb7Sdjm if (cbor_isa_negint(val) == false ||
1405739189a3Sdjm cbor_get_int(val) > UINT16_MAX) {
140632a20e26Sdjm fido_log_debug("%s: alg", __func__);
1407d75efeb7Sdjm goto out;
1408d75efeb7Sdjm }
1409*ab19a69eSdjm attstmt->alg = -(int)cbor_get_int(val) - 1;
1410*ab19a69eSdjm if (attstmt->alg != COSE_ES256 && attstmt->alg != COSE_RS256 &&
1411*ab19a69eSdjm attstmt->alg != COSE_EDDSA && attstmt->alg != COSE_RS1) {
1412*ab19a69eSdjm fido_log_debug("%s: unsupported attstmt->alg=%d",
1413*ab19a69eSdjm __func__, attstmt->alg);
1414739189a3Sdjm goto out;
1415739189a3Sdjm }
1416d75efeb7Sdjm } else if (!strcmp(name, "sig")) {
1417c4a807edSdjm if (fido_blob_decode(val, &attstmt->sig) < 0) {
141832a20e26Sdjm fido_log_debug("%s: sig", __func__);
1419d75efeb7Sdjm goto out;
1420d75efeb7Sdjm }
1421d75efeb7Sdjm } else if (!strcmp(name, "x5c")) {
1422d75efeb7Sdjm if (cbor_isa_array(val) == false ||
1423d75efeb7Sdjm cbor_array_is_definite(val) == false ||
1424d75efeb7Sdjm cbor_array_iter(val, &attstmt->x5c, decode_x5c) < 0) {
142532a20e26Sdjm fido_log_debug("%s: x5c", __func__);
1426d75efeb7Sdjm goto out;
1427d75efeb7Sdjm }
1428*ab19a69eSdjm } else if (!strcmp(name, "certInfo")) {
1429*ab19a69eSdjm if (fido_blob_decode(val, &attstmt->certinfo) < 0) {
1430*ab19a69eSdjm fido_log_debug("%s: certinfo", __func__);
1431*ab19a69eSdjm goto out;
1432*ab19a69eSdjm }
1433*ab19a69eSdjm } else if (!strcmp(name, "pubArea")) {
1434*ab19a69eSdjm if (fido_blob_decode(val, &attstmt->pubarea) < 0) {
1435*ab19a69eSdjm fido_log_debug("%s: pubarea", __func__);
1436*ab19a69eSdjm goto out;
1437*ab19a69eSdjm }
1438d75efeb7Sdjm }
1439d75efeb7Sdjm
1440d75efeb7Sdjm ok = 0;
1441d75efeb7Sdjm out:
1442d75efeb7Sdjm free(name);
1443d75efeb7Sdjm
1444d75efeb7Sdjm return (ok);
1445d75efeb7Sdjm }
1446d75efeb7Sdjm
1447d75efeb7Sdjm int
cbor_decode_attstmt(const cbor_item_t * item,fido_attstmt_t * attstmt)144832a20e26Sdjm cbor_decode_attstmt(const cbor_item_t *item, fido_attstmt_t *attstmt)
1449d75efeb7Sdjm {
1450*ab19a69eSdjm size_t alloc_len;
1451*ab19a69eSdjm
1452d75efeb7Sdjm if (cbor_isa_map(item) == false ||
1453d75efeb7Sdjm cbor_map_is_definite(item) == false ||
1454d75efeb7Sdjm cbor_map_iter(item, attstmt, decode_attstmt_entry) < 0) {
145532a20e26Sdjm fido_log_debug("%s: cbor type", __func__);
1456d75efeb7Sdjm return (-1);
1457d75efeb7Sdjm }
1458d75efeb7Sdjm
1459*ab19a69eSdjm if (attstmt->cbor.ptr != NULL ||
1460*ab19a69eSdjm (attstmt->cbor.len = cbor_serialize_alloc(item,
1461*ab19a69eSdjm &attstmt->cbor.ptr, &alloc_len)) == 0) {
1462*ab19a69eSdjm fido_log_debug("%s: cbor_serialize_alloc", __func__);
1463*ab19a69eSdjm return (-1);
1464*ab19a69eSdjm }
1465*ab19a69eSdjm
1466d75efeb7Sdjm return (0);
1467d75efeb7Sdjm }
1468d75efeb7Sdjm
1469d75efeb7Sdjm int
cbor_decode_uint64(const cbor_item_t * item,uint64_t * n)147032a20e26Sdjm cbor_decode_uint64(const cbor_item_t *item, uint64_t *n)
1471d75efeb7Sdjm {
1472d75efeb7Sdjm if (cbor_isa_uint(item) == false) {
147332a20e26Sdjm fido_log_debug("%s: cbor type", __func__);
1474d75efeb7Sdjm return (-1);
1475d75efeb7Sdjm }
1476d75efeb7Sdjm
1477d75efeb7Sdjm *n = cbor_get_int(item);
1478d75efeb7Sdjm
1479d75efeb7Sdjm return (0);
1480d75efeb7Sdjm }
1481d75efeb7Sdjm
1482d75efeb7Sdjm static int
decode_cred_id_entry(const cbor_item_t * key,const cbor_item_t * val,void * arg)1483d75efeb7Sdjm decode_cred_id_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg)
1484d75efeb7Sdjm {
1485d75efeb7Sdjm fido_blob_t *id = arg;
1486d75efeb7Sdjm char *name = NULL;
1487d75efeb7Sdjm int ok = -1;
1488d75efeb7Sdjm
1489d75efeb7Sdjm if (cbor_string_copy(key, &name) < 0) {
149032a20e26Sdjm fido_log_debug("%s: cbor type", __func__);
1491d75efeb7Sdjm ok = 0; /* ignore */
1492d75efeb7Sdjm goto out;
1493d75efeb7Sdjm }
1494d75efeb7Sdjm
1495d75efeb7Sdjm if (!strcmp(name, "id"))
1496c4a807edSdjm if (fido_blob_decode(val, id) < 0) {
149732a20e26Sdjm fido_log_debug("%s: cbor_bytestring_copy", __func__);
1498d75efeb7Sdjm goto out;
1499d75efeb7Sdjm }
1500d75efeb7Sdjm
1501d75efeb7Sdjm ok = 0;
1502d75efeb7Sdjm out:
1503d75efeb7Sdjm free(name);
1504d75efeb7Sdjm
1505d75efeb7Sdjm return (ok);
1506d75efeb7Sdjm }
1507d75efeb7Sdjm
1508d75efeb7Sdjm int
cbor_decode_cred_id(const cbor_item_t * item,fido_blob_t * id)150932a20e26Sdjm cbor_decode_cred_id(const cbor_item_t *item, fido_blob_t *id)
1510d75efeb7Sdjm {
1511d75efeb7Sdjm if (cbor_isa_map(item) == false ||
1512d75efeb7Sdjm cbor_map_is_definite(item) == false ||
1513d75efeb7Sdjm cbor_map_iter(item, id, decode_cred_id_entry) < 0) {
151432a20e26Sdjm fido_log_debug("%s: cbor type", __func__);
1515d75efeb7Sdjm return (-1);
1516d75efeb7Sdjm }
1517d75efeb7Sdjm
1518d75efeb7Sdjm return (0);
1519d75efeb7Sdjm }
1520d75efeb7Sdjm
1521d75efeb7Sdjm static int
decode_user_entry(const cbor_item_t * key,const cbor_item_t * val,void * arg)1522d75efeb7Sdjm decode_user_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg)
1523d75efeb7Sdjm {
1524d75efeb7Sdjm fido_user_t *user = arg;
1525d75efeb7Sdjm char *name = NULL;
1526d75efeb7Sdjm int ok = -1;
1527d75efeb7Sdjm
1528d75efeb7Sdjm if (cbor_string_copy(key, &name) < 0) {
152932a20e26Sdjm fido_log_debug("%s: cbor type", __func__);
1530d75efeb7Sdjm ok = 0; /* ignore */
1531d75efeb7Sdjm goto out;
1532d75efeb7Sdjm }
1533d75efeb7Sdjm
1534d75efeb7Sdjm if (!strcmp(name, "icon")) {
1535d75efeb7Sdjm if (cbor_string_copy(val, &user->icon) < 0) {
153632a20e26Sdjm fido_log_debug("%s: icon", __func__);
1537d75efeb7Sdjm goto out;
1538d75efeb7Sdjm }
1539d75efeb7Sdjm } else if (!strcmp(name, "name")) {
1540d75efeb7Sdjm if (cbor_string_copy(val, &user->name) < 0) {
154132a20e26Sdjm fido_log_debug("%s: name", __func__);
1542d75efeb7Sdjm goto out;
1543d75efeb7Sdjm }
1544d75efeb7Sdjm } else if (!strcmp(name, "displayName")) {
1545d75efeb7Sdjm if (cbor_string_copy(val, &user->display_name) < 0) {
154632a20e26Sdjm fido_log_debug("%s: display_name", __func__);
1547d75efeb7Sdjm goto out;
1548d75efeb7Sdjm }
1549d75efeb7Sdjm } else if (!strcmp(name, "id")) {
1550c4a807edSdjm if (fido_blob_decode(val, &user->id) < 0) {
155132a20e26Sdjm fido_log_debug("%s: id", __func__);
1552d75efeb7Sdjm goto out;
1553d75efeb7Sdjm }
1554d75efeb7Sdjm }
1555d75efeb7Sdjm
1556d75efeb7Sdjm ok = 0;
1557d75efeb7Sdjm out:
1558d75efeb7Sdjm free(name);
1559d75efeb7Sdjm
1560d75efeb7Sdjm return (ok);
1561d75efeb7Sdjm }
1562d75efeb7Sdjm
1563d75efeb7Sdjm int
cbor_decode_user(const cbor_item_t * item,fido_user_t * user)156432a20e26Sdjm cbor_decode_user(const cbor_item_t *item, fido_user_t *user)
1565d75efeb7Sdjm {
1566d75efeb7Sdjm if (cbor_isa_map(item) == false ||
1567d75efeb7Sdjm cbor_map_is_definite(item) == false ||
1568d75efeb7Sdjm cbor_map_iter(item, user, decode_user_entry) < 0) {
156932a20e26Sdjm fido_log_debug("%s: cbor type", __func__);
1570d75efeb7Sdjm return (-1);
1571d75efeb7Sdjm }
1572d75efeb7Sdjm
1573d75efeb7Sdjm return (0);
1574d75efeb7Sdjm }
1575d75efeb7Sdjm
1576d75efeb7Sdjm static int
decode_rp_entity_entry(const cbor_item_t * key,const cbor_item_t * val,void * arg)1577d75efeb7Sdjm decode_rp_entity_entry(const cbor_item_t *key, const cbor_item_t *val,
1578d75efeb7Sdjm void *arg)
1579d75efeb7Sdjm {
1580d75efeb7Sdjm fido_rp_t *rp = arg;
1581d75efeb7Sdjm char *name = NULL;
1582d75efeb7Sdjm int ok = -1;
1583d75efeb7Sdjm
1584d75efeb7Sdjm if (cbor_string_copy(key, &name) < 0) {
158532a20e26Sdjm fido_log_debug("%s: cbor type", __func__);
1586d75efeb7Sdjm ok = 0; /* ignore */
1587d75efeb7Sdjm goto out;
1588d75efeb7Sdjm }
1589d75efeb7Sdjm
1590d75efeb7Sdjm if (!strcmp(name, "id")) {
1591d75efeb7Sdjm if (cbor_string_copy(val, &rp->id) < 0) {
159232a20e26Sdjm fido_log_debug("%s: id", __func__);
1593d75efeb7Sdjm goto out;
1594d75efeb7Sdjm }
1595d75efeb7Sdjm } else if (!strcmp(name, "name")) {
1596d75efeb7Sdjm if (cbor_string_copy(val, &rp->name) < 0) {
159732a20e26Sdjm fido_log_debug("%s: name", __func__);
1598d75efeb7Sdjm goto out;
1599d75efeb7Sdjm }
1600d75efeb7Sdjm }
1601d75efeb7Sdjm
1602d75efeb7Sdjm ok = 0;
1603d75efeb7Sdjm out:
1604d75efeb7Sdjm free(name);
1605d75efeb7Sdjm
1606d75efeb7Sdjm return (ok);
1607d75efeb7Sdjm }
1608d75efeb7Sdjm
1609d75efeb7Sdjm int
cbor_decode_rp_entity(const cbor_item_t * item,fido_rp_t * rp)161032a20e26Sdjm cbor_decode_rp_entity(const cbor_item_t *item, fido_rp_t *rp)
1611d75efeb7Sdjm {
1612d75efeb7Sdjm if (cbor_isa_map(item) == false ||
1613d75efeb7Sdjm cbor_map_is_definite(item) == false ||
1614d75efeb7Sdjm cbor_map_iter(item, rp, decode_rp_entity_entry) < 0) {
161532a20e26Sdjm fido_log_debug("%s: cbor type", __func__);
1616d75efeb7Sdjm return (-1);
1617d75efeb7Sdjm }
1618d75efeb7Sdjm
1619d75efeb7Sdjm return (0);
1620d75efeb7Sdjm }
1621c4a807edSdjm
1622c4a807edSdjm cbor_item_t *
cbor_build_uint(const uint64_t value)1623c4a807edSdjm cbor_build_uint(const uint64_t value)
1624c4a807edSdjm {
1625c4a807edSdjm if (value <= UINT8_MAX)
1626c4a807edSdjm return cbor_build_uint8((uint8_t)value);
1627c4a807edSdjm else if (value <= UINT16_MAX)
1628c4a807edSdjm return cbor_build_uint16((uint16_t)value);
1629c4a807edSdjm else if (value <= UINT32_MAX)
1630c4a807edSdjm return cbor_build_uint32((uint32_t)value);
1631c4a807edSdjm
1632c4a807edSdjm return cbor_build_uint64(value);
1633c4a807edSdjm }
1634c4a807edSdjm
1635c4a807edSdjm int
cbor_array_append(cbor_item_t ** array,cbor_item_t * item)1636c4a807edSdjm cbor_array_append(cbor_item_t **array, cbor_item_t *item)
1637c4a807edSdjm {
1638c4a807edSdjm cbor_item_t **v, *ret;
1639c4a807edSdjm size_t n;
1640c4a807edSdjm
1641c4a807edSdjm if ((v = cbor_array_handle(*array)) == NULL ||
1642c4a807edSdjm (n = cbor_array_size(*array)) == SIZE_MAX ||
1643c4a807edSdjm (ret = cbor_new_definite_array(n + 1)) == NULL)
1644c4a807edSdjm return -1;
1645c4a807edSdjm for (size_t i = 0; i < n; i++) {
1646c4a807edSdjm if (cbor_array_push(ret, v[i]) == 0) {
1647c4a807edSdjm cbor_decref(&ret);
1648c4a807edSdjm return -1;
1649c4a807edSdjm }
1650c4a807edSdjm }
1651c4a807edSdjm if (cbor_array_push(ret, item) == 0) {
1652c4a807edSdjm cbor_decref(&ret);
1653c4a807edSdjm return -1;
1654c4a807edSdjm }
1655c4a807edSdjm cbor_decref(array);
1656c4a807edSdjm *array = ret;
1657c4a807edSdjm
1658c4a807edSdjm return 0;
1659c4a807edSdjm }
1660c4a807edSdjm
1661c4a807edSdjm int
cbor_array_drop(cbor_item_t ** array,size_t idx)1662c4a807edSdjm cbor_array_drop(cbor_item_t **array, size_t idx)
1663c4a807edSdjm {
1664c4a807edSdjm cbor_item_t **v, *ret;
1665c4a807edSdjm size_t n;
1666c4a807edSdjm
1667c4a807edSdjm if ((v = cbor_array_handle(*array)) == NULL ||
1668c4a807edSdjm (n = cbor_array_size(*array)) == 0 || idx >= n ||
1669c4a807edSdjm (ret = cbor_new_definite_array(n - 1)) == NULL)
1670c4a807edSdjm return -1;
1671c4a807edSdjm for (size_t i = 0; i < n; i++) {
1672c4a807edSdjm if (i != idx && cbor_array_push(ret, v[i]) == 0) {
1673c4a807edSdjm cbor_decref(&ret);
1674c4a807edSdjm return -1;
1675c4a807edSdjm }
1676c4a807edSdjm }
1677c4a807edSdjm cbor_decref(array);
1678c4a807edSdjm *array = ret;
1679c4a807edSdjm
1680c4a807edSdjm return 0;
1681c4a807edSdjm }
1682