| Line | Count | Source | 
| 1 |  | /* | 
| 2 |  |  * Copyright (c) 2018-2022 Yubico AB. All rights reserved. | 
| 3 |  |  * Use of this source code is governed by a BSD-style | 
| 4 |  |  * license that can be found in the LICENSE file. | 
| 5 |  |  * SPDX-License-Identifier: BSD-2-Clause | 
| 6 |  |  */ | 
| 7 |  |  | 
| 8 |  | #include <openssl/hmac.h> | 
| 9 |  | #include <openssl/sha.h> | 
| 10 |  | #include "fido.h" | 
| 11 |  |  | 
| 12 |  | static int | 
| 13 |  | check_key_type(cbor_item_t *item) | 
| 14 | 3.73M | { | 
| 15 | 3.73M |         if (item->type == CBOR_TYPE_UINT || item->type == CBOR_TYPE_NEGINT || | 
| 16 | 3.73M |             item->type == CBOR_TYPE_STRING) | 
| 17 | 3.73M |                 return (0); | 
| 18 |  |  | 
| 19 | 3.51k |         fido_log_debug("%s: invalid type: %d", __func__, item->type); | 
| 20 |  |  | 
| 21 | 3.51k |         return (-1); | 
| 22 | 3.73M | } | 
| 23 |  |  | 
| 24 |  | /* | 
| 25 |  |  * Validate CTAP2 canonical CBOR encoding rules for maps. | 
| 26 |  |  */ | 
| 27 |  | static int | 
| 28 |  | ctap_check_cbor(cbor_item_t *prev, cbor_item_t *curr) | 
| 29 | 1.86M | { | 
| 30 | 1.86M |         size_t  curr_len; | 
| 31 | 1.86M |         size_t  prev_len; | 
| 32 |  |  | 
| 33 | 1.86M |         if (check_key_type(prev) < 0 || check_key_type(curr) < 0) | 
| 34 | 3.51k |                 return (-1); | 
| 35 |  |  | 
| 36 | 1.86M |         if (prev->type != curr->type) { | 
| 37 | 106k |                 if (prev->type < curr->type) | 
| 38 | 97.3k |                         return (0); | 
| 39 | 8.91k |                 fido_log_debug("%s: unsorted types", __func__); | 
| 40 | 8.91k |                 return (-1); | 
| 41 | 106k |         } | 
| 42 |  |  | 
| 43 | 1.75M |         if (curr->type == CBOR_TYPE_UINT || curr->type == CBOR_TYPE_NEGINT) { | 
| 44 | 1.08M |                 if (cbor_int_get_width(curr) >= cbor_int_get_width(prev) && | 
| 45 | 1.08M |                     cbor_get_int(curr) > cbor_get_int(prev)) | 
| 46 | 1.08M |                         return (0); | 
| 47 | 1.08M |         } else { | 
| 48 | 671k |                 curr_len = cbor_string_length(curr); | 
| 49 | 671k |                 prev_len = cbor_string_length(prev); | 
| 50 |  |  | 
| 51 | 671k |                 if (curr_len > prev_len || (curr_len == prev_len && | 
| 52 | 169k |                     memcmp(cbor_string_handle(prev), cbor_string_handle(curr), | 
| 53 | 168k |                     curr_len) < 0)) | 
| 54 | 662k |                         return (0); | 
| 55 | 671k |         } | 
| 56 |  |  | 
| 57 | 13.5k |         fido_log_debug("%s: invalid cbor", __func__); | 
| 58 |  |  | 
| 59 | 13.5k |         return (-1); | 
| 60 | 1.75M | } | 
| 61 |  |  | 
| 62 |  | int | 
| 63 |  | cbor_map_iter(const cbor_item_t *item, void *arg, int(*f)(const cbor_item_t *, | 
| 64 |  |     const cbor_item_t *, void *)) | 
| 65 | 545k | { | 
| 66 | 545k |         struct cbor_pair        *v; | 
| 67 | 545k |         size_t                   n; | 
| 68 |  |  | 
| 69 | 545k |         if ((v = cbor_map_handle(item)) == NULL) { | 
| 70 | 1.25k |                 fido_log_debug("%s: cbor_map_handle", __func__); | 
| 71 | 1.25k |                 return (-1); | 
| 72 | 1.25k |         } | 
| 73 |  |  | 
| 74 | 544k |         n = cbor_map_size(item); | 
| 75 |  |  | 
| 76 | 2.90M |         for (size_t i = 0; i < n; i++) { | 
| 77 | 2.40M |                 if (v[i].key == NULL || v[i].value == NULL) { | 
| 78 | 0 |                         fido_log_debug("%s: key=%p, value=%p for i=%zu", | 
| 79 | 0 |                             __func__, (void *)v[i].key, (void *)v[i].value, i); | 
| 80 | 0 |                         return (-1); | 
| 81 | 0 |                 } | 
| 82 | 2.40M |                 if (i && ctap_check_cbor(v[i - 1].key, v[i].key) < 0) { | 
| 83 | 26.0k |                         fido_log_debug("%s: ctap_check_cbor", __func__); | 
| 84 | 26.0k |                         return (-1); | 
| 85 | 26.0k |                 } | 
| 86 | 2.38M |                 if (f(v[i].key, v[i].value, arg) < 0) { | 
| 87 | 23.3k |                         fido_log_debug("%s: iterator < 0 on i=%zu", __func__, | 
| 88 | 23.3k |                             i); | 
| 89 | 23.3k |                         return (-1); | 
| 90 | 23.3k |                 } | 
| 91 | 2.38M |         } | 
| 92 |  |  | 
| 93 | 495k |         return (0); | 
| 94 | 544k | } | 
| 95 |  |  | 
| 96 |  | int | 
| 97 |  | cbor_array_iter(const cbor_item_t *item, void *arg, int(*f)(const cbor_item_t *, | 
| 98 |  |     void *)) | 
| 99 | 389k | { | 
| 100 | 389k |         cbor_item_t     **v; | 
| 101 | 389k |         size_t            n; | 
| 102 |  |  | 
| 103 | 389k |         if ((v = cbor_array_handle(item)) == NULL) { | 
| 104 | 103 |                 fido_log_debug("%s: cbor_array_handle", __func__); | 
| 105 | 103 |                 return (-1); | 
| 106 | 103 |         } | 
| 107 |  |  | 
| 108 | 389k |         n = cbor_array_size(item); | 
| 109 |  |  | 
| 110 | 1.20M |         for (size_t i = 0; i < n; i++) | 
| 111 | 825k |                 if (v[i] == NULL || f(v[i], arg) < 0) { | 
| 112 | 5.56k |                         fido_log_debug("%s: iterator < 0 on i=%zu,%p", | 
| 113 | 5.56k |                             __func__, i, (void *)v[i]); | 
| 114 | 5.56k |                         return (-1); | 
| 115 | 5.56k |                 } | 
| 116 |  |  | 
| 117 | 384k |         return (0); | 
| 118 | 389k | } | 
| 119 |  |  | 
| 120 |  | int | 
| 121 |  | cbor_parse_reply(const unsigned char *blob, size_t blob_len, void *arg, | 
| 122 |  |     int(*parser)(const cbor_item_t *, const cbor_item_t *, void *)) | 
| 123 | 279k | { | 
| 124 | 279k |         cbor_item_t             *item = NULL; | 
| 125 | 279k |         struct cbor_load_result  cbor; | 
| 126 | 279k |         int                      r; | 
| 127 |  |  | 
| 128 | 279k |         if (blob_len < 1) { | 
| 129 | 53.2k |                 fido_log_debug("%s: blob_len=%zu", __func__, blob_len); | 
| 130 | 53.2k |                 r = FIDO_ERR_RX; | 
| 131 | 53.2k |                 goto fail; | 
| 132 | 53.2k |         } | 
| 133 |  |  | 
| 134 | 226k |         if (blob[0] != FIDO_OK) { | 
| 135 | 9.95k |                 fido_log_debug("%s: blob[0]=0x%02x", __func__, blob[0]); | 
| 136 | 9.95k |                 r = blob[0]; | 
| 137 | 9.95k |                 goto fail; | 
| 138 | 9.95k |         } | 
| 139 |  |  | 
| 140 | 216k |         if ((item = cbor_load(blob + 1, blob_len - 1, &cbor)) == NULL) { | 
| 141 | 10.8k |                 fido_log_debug("%s: cbor_load", __func__); | 
| 142 | 10.8k |                 r = FIDO_ERR_RX_NOT_CBOR; | 
| 143 | 10.8k |                 goto fail; | 
| 144 | 10.8k |         } | 
| 145 |  |  | 
| 146 | 205k |         if (cbor_isa_map(item) == false || | 
| 147 | 205k |             cbor_map_is_definite(item) == false) { | 
| 148 | 3.40k |                 fido_log_debug("%s: cbor type", __func__); | 
| 149 | 3.40k |                 r = FIDO_ERR_RX_INVALID_CBOR; | 
| 150 | 3.40k |                 goto fail; | 
| 151 | 3.40k |         } | 
| 152 |  |  | 
| 153 | 202k |         if (cbor_map_iter(item, arg, parser) < 0) { | 
| 154 | 36.7k |                 fido_log_debug("%s: cbor_map_iter", __func__); | 
| 155 | 36.7k |                 r = FIDO_ERR_RX_INVALID_CBOR; | 
| 156 | 36.7k |                 goto fail; | 
| 157 | 36.7k |         } | 
| 158 |  |  | 
| 159 | 165k |         r = FIDO_OK; | 
| 160 | 279k | fail: | 
| 161 | 279k |         if (item != NULL) | 
| 162 | 205k |                 cbor_decref(&item); | 
| 163 |  |  | 
| 164 | 279k |         return (r); | 
| 165 | 165k | } | 
| 166 |  |  | 
| 167 |  | void | 
| 168 |  | cbor_vector_free(cbor_item_t **item, size_t len) | 
| 169 | 400k | { | 
| 170 | 1.82M |         for (size_t i = 0; i < len; i++) | 
| 171 | 1.42M |                 if (item[i] != NULL) | 
| 172 | 652k |                         cbor_decref(&item[i]); | 
| 173 | 400k | } | 
| 174 |  |  | 
| 175 |  | int | 
| 176 |  | cbor_bytestring_copy(const cbor_item_t *item, unsigned char **buf, size_t *len) | 
| 177 | 99.2k | { | 
| 178 | 99.2k |         if (*buf != NULL || *len != 0) { | 
| 179 | 3 |                 fido_log_debug("%s: dup", __func__); | 
| 180 | 3 |                 return (-1); | 
| 181 | 3 |         } | 
| 182 |  |  | 
| 183 | 99.2k |         if (cbor_isa_bytestring(item) == false || | 
| 184 | 99.2k |             cbor_bytestring_is_definite(item) == false) { | 
| 185 | 283 |                 fido_log_debug("%s: cbor type", __func__); | 
| 186 | 283 |                 return (-1); | 
| 187 | 283 |         } | 
| 188 |  |  | 
| 189 | 98.9k |         *len = cbor_bytestring_length(item); | 
| 190 | 98.9k |         if ((*buf = malloc(*len)) == NULL) { | 
| 191 | 339 |                 *len = 0; | 
| 192 | 339 |                 return (-1); | 
| 193 | 339 |         } | 
| 194 |  |  | 
| 195 | 98.6k |         memcpy(*buf, cbor_bytestring_handle(item), *len); | 
| 196 |  |  | 
| 197 | 98.6k |         return (0); | 
| 198 | 98.9k | } | 
| 199 |  |  | 
| 200 |  | int | 
| 201 |  | cbor_string_copy(const cbor_item_t *item, char **str) | 
| 202 | 1.52M | { | 
| 203 | 1.52M |         size_t len; | 
| 204 |  |  | 
| 205 | 1.52M |         if (*str != NULL) { | 
| 206 | 5 |                 fido_log_debug("%s: dup", __func__); | 
| 207 | 5 |                 return (-1); | 
| 208 | 5 |         } | 
| 209 |  |  | 
| 210 | 1.52M |         if (cbor_isa_string(item) == false || | 
| 211 | 1.52M |             cbor_string_is_definite(item) == false) { | 
| 212 | 6.50k |                 fido_log_debug("%s: cbor type", __func__); | 
| 213 | 6.50k |                 return (-1); | 
| 214 | 6.50k |         } | 
| 215 |  |  | 
| 216 | 1.52M |         if ((len = cbor_string_length(item)) == SIZE_MAX || | 
| 217 | 1.52M |             (*str = malloc(len + 1)) == NULL) | 
| 218 | 2.59k |                 return (-1); | 
| 219 |  |  | 
| 220 | 1.51M |         memcpy(*str, cbor_string_handle(item), len); | 
| 221 | 1.51M |         (*str)[len] = '\0'; | 
| 222 |  |  | 
| 223 | 1.51M |         return (0); | 
| 224 | 1.52M | } | 
| 225 |  |  | 
| 226 |  | int | 
| 227 |  | cbor_add_bytestring(cbor_item_t *item, const char *key, | 
| 228 |  |     const unsigned char *value, size_t value_len) | 
| 229 | 200k | { | 
| 230 | 200k |         struct cbor_pair pair; | 
| 231 | 200k |         int ok = -1; | 
| 232 |  |  | 
| 233 | 200k |         memset(&pair, 0, sizeof(pair)); | 
| 234 |  |  | 
| 235 | 200k |         if ((pair.key = cbor_build_string(key)) == NULL || | 
| 236 | 200k |             (pair.value = cbor_build_bytestring(value, value_len)) == NULL) { | 
| 237 | 203 |                 fido_log_debug("%s: cbor_build", __func__); | 
| 238 | 203 |                 goto fail; | 
| 239 | 203 |         } | 
| 240 |  |  | 
| 241 | 199k |         if (!cbor_map_add(item, pair)) { | 
| 242 | 143 |                 fido_log_debug("%s: cbor_map_add", __func__); | 
| 243 | 143 |                 goto fail; | 
| 244 | 143 |         } | 
| 245 |  |  | 
| 246 | 199k |         ok = 0; | 
| 247 | 200k | fail: | 
| 248 | 200k |         if (pair.key) | 
| 249 | 200k |                 cbor_decref(&pair.key); | 
| 250 | 200k |         if (pair.value) | 
| 251 | 199k |                 cbor_decref(&pair.value); | 
| 252 |  |  | 
| 253 | 200k |         return (ok); | 
| 254 | 199k | } | 
| 255 |  |  | 
| 256 |  | int | 
| 257 |  | cbor_add_string(cbor_item_t *item, const char *key, const char *value) | 
| 258 | 230k | { | 
| 259 | 230k |         struct cbor_pair pair; | 
| 260 | 230k |         int ok = -1; | 
| 261 |  |  | 
| 262 | 230k |         memset(&pair, 0, sizeof(pair)); | 
| 263 |  |  | 
| 264 | 230k |         if ((pair.key = cbor_build_string(key)) == NULL || | 
| 265 | 230k |             (pair.value = cbor_build_string(value)) == NULL) { | 
| 266 | 275 |                 fido_log_debug("%s: cbor_build", __func__); | 
| 267 | 275 |                 goto fail; | 
| 268 | 275 |         } | 
| 269 |  |  | 
| 270 | 229k |         if (!cbor_map_add(item, pair)) { | 
| 271 | 113 |                 fido_log_debug("%s: cbor_map_add", __func__); | 
| 272 | 113 |                 goto fail; | 
| 273 | 113 |         } | 
| 274 |  |  | 
| 275 | 229k |         ok = 0; | 
| 276 | 230k | fail: | 
| 277 | 230k |         if (pair.key) | 
| 278 | 230k |                 cbor_decref(&pair.key); | 
| 279 | 230k |         if (pair.value) | 
| 280 | 229k |                 cbor_decref(&pair.value); | 
| 281 |  |  | 
| 282 | 230k |         return (ok); | 
| 283 | 229k | } | 
| 284 |  |  | 
| 285 |  | int | 
| 286 |  | cbor_add_bool(cbor_item_t *item, const char *key, fido_opt_t value) | 
| 287 | 9.16k | { | 
| 288 | 9.16k |         struct cbor_pair pair; | 
| 289 | 9.16k |         int ok = -1; | 
| 290 |  |  | 
| 291 | 9.16k |         memset(&pair, 0, sizeof(pair)); | 
| 292 |  |  | 
| 293 | 9.16k |         if ((pair.key = cbor_build_string(key)) == NULL || | 
| 294 | 9.16k |             (pair.value = cbor_build_bool(value == FIDO_OPT_TRUE)) == NULL) { | 
| 295 | 36 |                 fido_log_debug("%s: cbor_build", __func__); | 
| 296 | 36 |                 goto fail; | 
| 297 | 36 |         } | 
| 298 |  |  | 
| 299 | 9.12k |         if (!cbor_map_add(item, pair)) { | 
| 300 | 17 |                 fido_log_debug("%s: cbor_map_add", __func__); | 
| 301 | 17 |                 goto fail; | 
| 302 | 17 |         } | 
| 303 |  |  | 
| 304 | 9.11k |         ok = 0; | 
| 305 | 9.16k | fail: | 
| 306 | 9.16k |         if (pair.key) | 
| 307 | 9.15k |                 cbor_decref(&pair.key); | 
| 308 | 9.16k |         if (pair.value) | 
| 309 | 9.12k |                 cbor_decref(&pair.value); | 
| 310 |  |  | 
| 311 | 9.16k |         return (ok); | 
| 312 | 9.11k | } | 
| 313 |  |  | 
| 314 |  | static int | 
| 315 |  | cbor_add_uint8(cbor_item_t *item, const char *key, uint8_t value) | 
| 316 | 2.47k | { | 
| 317 | 2.47k |         struct cbor_pair pair; | 
| 318 | 2.47k |         int ok = -1; | 
| 319 |  |  | 
| 320 | 2.47k |         memset(&pair, 0, sizeof(pair)); | 
| 321 |  |  | 
| 322 | 2.47k |         if ((pair.key = cbor_build_string(key)) == NULL || | 
| 323 | 2.47k |             (pair.value = cbor_build_uint8(value)) == NULL) { | 
| 324 | 16 |                 fido_log_debug("%s: cbor_build", __func__); | 
| 325 | 16 |                 goto fail; | 
| 326 | 16 |         } | 
| 327 |  |  | 
| 328 | 2.45k |         if (!cbor_map_add(item, pair)) { | 
| 329 | 4 |                 fido_log_debug("%s: cbor_map_add", __func__); | 
| 330 | 4 |                 goto fail; | 
| 331 | 4 |         } | 
| 332 |  |  | 
| 333 | 2.45k |         ok = 0; | 
| 334 | 2.47k | fail: | 
| 335 | 2.47k |         if (pair.key) | 
| 336 | 2.46k |                 cbor_decref(&pair.key); | 
| 337 | 2.47k |         if (pair.value) | 
| 338 | 2.45k |                 cbor_decref(&pair.value); | 
| 339 |  |  | 
| 340 | 2.47k |         return (ok); | 
| 341 | 2.45k | } | 
| 342 |  |  | 
| 343 |  | static int | 
| 344 |  | cbor_add_arg(cbor_item_t *item, uint8_t n, cbor_item_t *arg) | 
| 345 | 813k | { | 
| 346 | 813k |         struct cbor_pair pair; | 
| 347 | 813k |         int ok = -1; | 
| 348 |  |  | 
| 349 | 813k |         memset(&pair, 0, sizeof(pair)); | 
| 350 |  |  | 
| 351 | 813k |         if (arg == NULL) | 
| 352 | 285k |                 return (0); /* empty argument */ | 
| 353 |  |  | 
| 354 | 528k |         if ((pair.key = cbor_build_uint8(n)) == NULL) { | 
| 355 | 1.14k |                 fido_log_debug("%s: cbor_build", __func__); | 
| 356 | 1.14k |                 goto fail; | 
| 357 | 1.14k |         } | 
| 358 |  |  | 
| 359 | 527k |         pair.value = arg; | 
| 360 |  |  | 
| 361 | 527k |         if (!cbor_map_add(item, pair)) { | 
| 362 | 1.02k |                 fido_log_debug("%s: cbor_map_add", __func__); | 
| 363 | 1.02k |                 goto fail; | 
| 364 | 1.02k |         } | 
| 365 |  |  | 
| 366 | 526k |         ok = 0; | 
| 367 | 528k | fail: | 
| 368 | 528k |         if (pair.key) | 
| 369 | 527k |                 cbor_decref(&pair.key); | 
| 370 |  |  | 
| 371 | 528k |         return (ok); | 
| 372 | 526k | } | 
| 373 |  |  | 
| 374 |  | cbor_item_t * | 
| 375 |  | cbor_flatten_vector(cbor_item_t *argv[], size_t argc) | 
| 376 | 253k | { | 
| 377 | 253k |         cbor_item_t     *map; | 
| 378 | 253k |         uint8_t          i; | 
| 379 |  |  | 
| 380 | 253k |         if (argc > UINT8_MAX - 1) | 
| 381 | 0 |                 return (NULL); | 
| 382 |  |  | 
| 383 | 253k |         if ((map = cbor_new_definite_map(argc)) == NULL) | 
| 384 | 380 |                 return (NULL); | 
| 385 |  |  | 
| 386 | 1.06M |         for (i = 0; i < argc; i++) | 
| 387 | 813k |                 if (cbor_add_arg(map, (uint8_t)(i + 1), argv[i]) < 0) | 
| 388 | 2.17k |                         break; | 
| 389 |  |  | 
| 390 | 252k |         if (i != argc) { | 
| 391 | 2.17k |                 cbor_decref(&map); | 
| 392 | 2.17k |                 map = NULL; | 
| 393 | 2.17k |         } | 
| 394 |  |  | 
| 395 | 252k |         return (map); | 
| 396 | 253k | } | 
| 397 |  |  | 
| 398 |  | int | 
| 399 |  | cbor_build_frame(uint8_t cmd, cbor_item_t *argv[], size_t argc, fido_blob_t *f) | 
| 400 | 184k | { | 
| 401 | 184k |         cbor_item_t     *flat = NULL; | 
| 402 | 184k |         unsigned char   *cbor = NULL; | 
| 403 | 184k |         size_t           cbor_len; | 
| 404 | 184k |         size_t           cbor_alloc_len; | 
| 405 | 184k |         int              ok = -1; | 
| 406 |  |  | 
| 407 | 184k |         if ((flat = cbor_flatten_vector(argv, argc)) == NULL) | 
| 408 | 1.96k |                 goto fail; | 
| 409 |  |  | 
| 410 | 182k |         cbor_len = cbor_serialize_alloc(flat, &cbor, &cbor_alloc_len); | 
| 411 | 182k |         if (cbor_len == 0 || cbor_len == SIZE_MAX) { | 
| 412 | 375 |                 fido_log_debug("%s: cbor_len=%zu", __func__, cbor_len); | 
| 413 | 375 |                 goto fail; | 
| 414 | 375 |         } | 
| 415 |  |  | 
| 416 | 181k |         if ((f->ptr = malloc(cbor_len + 1)) == NULL) | 
| 417 | 326 |                 goto fail; | 
| 418 |  |  | 
| 419 | 181k |         f->len = cbor_len + 1; | 
| 420 | 181k |         f->ptr[0] = cmd; | 
| 421 | 181k |         memcpy(f->ptr + 1, cbor, f->len - 1); | 
| 422 |  |  | 
| 423 | 181k |         ok = 0; | 
| 424 | 184k | fail: | 
| 425 | 184k |         if (flat != NULL) | 
| 426 | 182k |                 cbor_decref(&flat); | 
| 427 |  |  | 
| 428 | 184k |         free(cbor); | 
| 429 |  |  | 
| 430 | 184k |         return (ok); | 
| 431 | 181k | } | 
| 432 |  |  | 
| 433 |  | cbor_item_t * | 
| 434 |  | cbor_encode_rp_entity(const fido_rp_t *rp) | 
| 435 | 7.08k | { | 
| 436 | 7.08k |         cbor_item_t *item = NULL; | 
| 437 |  |  | 
| 438 | 7.08k |         if ((item = cbor_new_definite_map(2)) == NULL) | 
| 439 | 17 |                 return (NULL); | 
| 440 |  |  | 
| 441 | 7.06k |         if ((rp->id && cbor_add_string(item, "id", rp->id) < 0) || | 
| 442 | 7.06k |             (rp->name && cbor_add_string(item, "name", rp->name) < 0)) { | 
| 443 | 47 |                 cbor_decref(&item); | 
| 444 | 47 |                 return (NULL); | 
| 445 | 47 |         } | 
| 446 |  |  | 
| 447 | 7.01k |         return (item); | 
| 448 | 7.06k | } | 
| 449 |  |  | 
| 450 |  | cbor_item_t * | 
| 451 |  | cbor_encode_user_entity(const fido_user_t *user) | 
| 452 | 10.6k | { | 
| 453 | 10.6k |         cbor_item_t             *item = NULL; | 
| 454 | 10.6k |         const fido_blob_t       *id = &user->id; | 
| 455 | 10.6k |         const char              *display = user->display_name; | 
| 456 |  |  | 
| 457 | 10.6k |         if ((item = cbor_new_definite_map(4)) == NULL) | 
| 458 | 36 |                 return (NULL); | 
| 459 |  |  | 
| 460 | 10.6k |         if ((id->ptr && cbor_add_bytestring(item, "id", id->ptr, id->len) < 0) || | 
| 461 | 10.6k |             (user->icon && cbor_add_string(item, "icon", user->icon) < 0) || | 
| 462 | 10.6k |             (user->name && cbor_add_string(item, "name", user->name) < 0) || | 
| 463 | 10.6k |             (display && cbor_add_string(item, "displayName", display) < 0)) { | 
| 464 | 166 |                 cbor_decref(&item); | 
| 465 | 166 |                 return (NULL); | 
| 466 | 166 |         } | 
| 467 |  |  | 
| 468 | 10.4k |         return (item); | 
| 469 | 10.6k | } | 
| 470 |  |  | 
| 471 |  | cbor_item_t * | 
| 472 |  | cbor_encode_pubkey_param(int cose_alg) | 
| 473 | 6.88k | { | 
| 474 | 6.88k |         cbor_item_t             *item = NULL; | 
| 475 | 6.88k |         cbor_item_t             *body = NULL; | 
| 476 | 6.88k |         struct cbor_pair         alg; | 
| 477 | 6.88k |         int                      ok = -1; | 
| 478 |  |  | 
| 479 | 6.88k |         memset(&alg, 0, sizeof(alg)); | 
| 480 |  |  | 
| 481 | 6.88k |         if ((item = cbor_new_definite_array(1)) == NULL || | 
| 482 | 6.88k |             (body = cbor_new_definite_map(2)) == NULL || | 
| 483 | 6.88k |             cose_alg > -1 || cose_alg < INT16_MIN) | 
| 484 | 47 |                 goto fail; | 
| 485 |  |  | 
| 486 | 6.84k |         alg.key = cbor_build_string("alg"); | 
| 487 |  |  | 
| 488 | 6.84k |         if (-cose_alg - 1 > UINT8_MAX) | 
| 489 | 1.06k |                 alg.value = cbor_build_negint16((uint16_t)(-cose_alg - 1)); | 
| 490 | 5.77k |         else | 
| 491 | 5.77k |                 alg.value = cbor_build_negint8((uint8_t)(-cose_alg - 1)); | 
| 492 |  |  | 
| 493 | 6.84k |         if (alg.key == NULL || alg.value == NULL) { | 
| 494 | 41 |                 fido_log_debug("%s: cbor_build", __func__); | 
| 495 | 41 |                 goto fail; | 
| 496 | 41 |         } | 
| 497 |  |  | 
| 498 | 6.79k |         if (cbor_map_add(body, alg) == false || | 
| 499 | 6.79k |             cbor_add_string(body, "type", "public-key") < 0 || | 
| 500 | 6.79k |             cbor_array_push(item, body) == false) | 
| 501 | 86 |                 goto fail; | 
| 502 |  |  | 
| 503 | 6.71k |         ok  = 0; | 
| 504 | 6.88k | fail: | 
| 505 | 6.88k |         if (ok < 0) { | 
| 506 | 174 |                 if (item != NULL) { | 
| 507 | 157 |                         cbor_decref(&item); | 
| 508 | 157 |                         item = NULL; | 
| 509 | 157 |                 } | 
| 510 | 174 |         } | 
| 511 |  |  | 
| 512 | 6.88k |         if (body != NULL) | 
| 513 | 6.84k |                 cbor_decref(&body); | 
| 514 | 6.88k |         if (alg.key != NULL) | 
| 515 | 6.81k |                 cbor_decref(&alg.key); | 
| 516 | 6.88k |         if (alg.value != NULL) | 
| 517 | 6.82k |                 cbor_decref(&alg.value); | 
| 518 |  |  | 
| 519 | 6.88k |         return (item); | 
| 520 | 6.71k | } | 
| 521 |  |  | 
| 522 |  | cbor_item_t * | 
| 523 |  | cbor_encode_pubkey(const fido_blob_t *pubkey) | 
| 524 | 188k | { | 
| 525 | 188k |         cbor_item_t *cbor_key = NULL; | 
| 526 |  |  | 
| 527 | 188k |         if ((cbor_key = cbor_new_definite_map(2)) == NULL || | 
| 528 | 188k |             cbor_add_bytestring(cbor_key, "id", pubkey->ptr, pubkey->len) < 0 || | 
| 529 | 188k |             cbor_add_string(cbor_key, "type", "public-key") < 0) { | 
| 530 | 571 |                 if (cbor_key) | 
| 531 | 480 |                         cbor_decref(&cbor_key); | 
| 532 | 571 |                 return (NULL); | 
| 533 | 571 |         } | 
| 534 |  |  | 
| 535 | 187k |         return (cbor_key); | 
| 536 | 188k | } | 
| 537 |  |  | 
| 538 |  | cbor_item_t * | 
| 539 |  | cbor_encode_pubkey_list(const fido_blob_array_t *list) | 
| 540 | 5.81k | { | 
| 541 | 5.81k |         cbor_item_t     *array = NULL; | 
| 542 | 5.81k |         cbor_item_t     *key = NULL; | 
| 543 |  |  | 
| 544 | 5.81k |         if ((array = cbor_new_definite_array(list->len)) == NULL) | 
| 545 | 10 |                 goto fail; | 
| 546 |  |  | 
| 547 | 186k |         for (size_t i = 0; i < list->len; i++) { | 
| 548 | 180k |                 if ((key = cbor_encode_pubkey(&list->ptr[i])) == NULL || | 
| 549 | 180k |                     cbor_array_push(array, key) == false) | 
| 550 | 548 |                         goto fail; | 
| 551 | 180k |                 cbor_decref(&key); | 
| 552 | 180k |         } | 
| 553 |  |  | 
| 554 | 5.25k |         return (array); | 
| 555 | 558 | fail: | 
| 556 | 558 |         if (key != NULL) | 
| 557 | 69 |                 cbor_decref(&key); | 
| 558 | 558 |         if (array != NULL) | 
| 559 | 548 |                 cbor_decref(&array); | 
| 560 |  |  | 
| 561 | 558 |         return (NULL); | 
| 562 | 5.80k | } | 
| 563 |  |  | 
| 564 |  | cbor_item_t * | 
| 565 |  | cbor_encode_str_array(const fido_str_array_t *a) | 
| 566 | 13.3k | { | 
| 567 | 13.3k |         cbor_item_t     *array = NULL; | 
| 568 | 13.3k |         cbor_item_t     *entry = NULL; | 
| 569 |  |  | 
| 570 | 13.3k |         if ((array = cbor_new_definite_array(a->len)) == NULL) | 
| 571 | 12 |                 goto fail; | 
| 572 |  |  | 
| 573 | 337k |         for (size_t i = 0; i < a->len; i++) { | 
| 574 | 326k |                 if ((entry = cbor_build_string(a->ptr[i])) == NULL || | 
| 575 | 326k |                     cbor_array_push(array, entry) == false) | 
| 576 | 2.33k |                         goto fail; | 
| 577 | 324k |                 cbor_decref(&entry); | 
| 578 | 324k |         } | 
| 579 |  |  | 
| 580 | 10.9k |         return (array); | 
| 581 | 2.34k | fail: | 
| 582 | 2.34k |         if (entry != NULL) | 
| 583 | 1.08k |                 cbor_decref(&entry); | 
| 584 | 2.34k |         if (array != NULL) | 
| 585 | 2.33k |                 cbor_decref(&array); | 
| 586 |  |  | 
| 587 | 2.34k |         return (NULL); | 
| 588 | 13.2k | } | 
| 589 |  |  | 
| 590 |  | static int | 
| 591 |  | cbor_encode_largeblob_key_ext(cbor_item_t *map) | 
| 592 | 2.33k | { | 
| 593 | 2.33k |         if (map == NULL || | 
| 594 | 2.33k |             cbor_add_bool(map, "largeBlobKey", FIDO_OPT_TRUE) < 0) | 
| 595 | 6 |                 return (-1); | 
| 596 |  |  | 
| 597 | 2.32k |         return (0); | 
| 598 | 2.33k | } | 
| 599 |  |  | 
| 600 |  | cbor_item_t * | 
| 601 |  | cbor_encode_cred_ext(const fido_cred_ext_t *ext, const fido_blob_t *blob) | 
| 602 | 4.15k | { | 
| 603 | 4.15k |         cbor_item_t *item = NULL; | 
| 604 | 4.15k |         size_t size = 0; | 
| 605 |  |  | 
| 606 | 4.15k |         if (ext->mask & FIDO_EXT_CRED_BLOB) | 
| 607 | 1.70k |                 size++; | 
| 608 | 4.15k |         if (ext->mask & FIDO_EXT_HMAC_SECRET) | 
| 609 | 1.85k |                 size++; | 
| 610 | 4.15k |         if (ext->mask & FIDO_EXT_CRED_PROTECT) | 
| 611 | 2.48k |                 size++; | 
| 612 | 4.15k |         if (ext->mask & FIDO_EXT_LARGEBLOB_KEY) | 
| 613 | 1.59k |                 size++; | 
| 614 | 4.15k |         if (ext->mask & FIDO_EXT_MINPINLEN) | 
| 615 | 1.16k |                 size++; | 
| 616 |  |  | 
| 617 | 4.15k |         if (size == 0 || (item = cbor_new_definite_map(size)) == NULL) | 
| 618 | 7 |                 return (NULL); | 
| 619 |  |  | 
| 620 | 4.14k |         if (ext->mask & FIDO_EXT_CRED_BLOB) { | 
| 621 | 1.70k |                 if (cbor_add_bytestring(item, "credBlob", blob->ptr, | 
| 622 | 1.70k |                     blob->len) < 0) { | 
| 623 | 5 |                         cbor_decref(&item); | 
| 624 | 5 |                         return (NULL); | 
| 625 | 5 |                 } | 
| 626 | 1.70k |         } | 
| 627 | 4.14k |         if (ext->mask & FIDO_EXT_CRED_PROTECT) { | 
| 628 | 2.47k |                 if (ext->prot < 0 || ext->prot > UINT8_MAX || | 
| 629 | 2.47k |                     cbor_add_uint8(item, "credProtect", | 
| 630 | 2.47k |                     (uint8_t)ext->prot) < 0) { | 
| 631 | 20 |                         cbor_decref(&item); | 
| 632 | 20 |                         return (NULL); | 
| 633 | 20 |                 } | 
| 634 | 2.47k |         } | 
| 635 | 4.12k |         if (ext->mask & FIDO_EXT_HMAC_SECRET) { | 
| 636 | 1.84k |                 if (cbor_add_bool(item, "hmac-secret", FIDO_OPT_TRUE) < 0) { | 
| 637 | 7 |                         cbor_decref(&item); | 
| 638 | 7 |                         return (NULL); | 
| 639 | 7 |                 } | 
| 640 | 1.84k |         } | 
| 641 | 4.11k |         if (ext->mask & FIDO_EXT_LARGEBLOB_KEY) { | 
| 642 | 1.58k |                 if (cbor_encode_largeblob_key_ext(item) < 0) { | 
| 643 | 3 |                         cbor_decref(&item); | 
| 644 | 3 |                         return (NULL); | 
| 645 | 3 |                 } | 
| 646 | 1.58k |         } | 
| 647 | 4.11k |         if (ext->mask & FIDO_EXT_MINPINLEN) { | 
| 648 | 1.14k |                 if (cbor_add_bool(item, "minPinLength", FIDO_OPT_TRUE) < 0) { | 
| 649 | 5 |                         cbor_decref(&item); | 
| 650 | 5 |                         return (NULL); | 
| 651 | 5 |                 } | 
| 652 | 1.14k |         } | 
| 653 |  |  | 
| 654 | 4.10k |         return (item); | 
| 655 | 4.11k | } | 
| 656 |  |  | 
| 657 |  | cbor_item_t * | 
| 658 |  | cbor_encode_cred_opt(fido_opt_t rk, fido_opt_t uv) | 
| 659 | 1.31k | { | 
| 660 | 1.31k |         cbor_item_t *item = NULL; | 
| 661 |  |  | 
| 662 | 1.31k |         if ((item = cbor_new_definite_map(2)) == NULL) | 
| 663 | 5 |                 return (NULL); | 
| 664 | 1.30k |         if ((rk != FIDO_OPT_OMIT && cbor_add_bool(item, "rk", rk) < 0) || | 
| 665 | 1.30k |             (uv != FIDO_OPT_OMIT && cbor_add_bool(item, "uv", uv) < 0)) { | 
| 666 | 10 |                 cbor_decref(&item); | 
| 667 | 10 |                 return (NULL); | 
| 668 | 10 |         } | 
| 669 |  |  | 
| 670 | 1.29k |         return (item); | 
| 671 | 1.30k | } | 
| 672 |  |  | 
| 673 |  | cbor_item_t * | 
| 674 |  | cbor_encode_assert_opt(fido_opt_t up, fido_opt_t uv) | 
| 675 | 1.06k | { | 
| 676 | 1.06k |         cbor_item_t *item = NULL; | 
| 677 |  |  | 
| 678 | 1.06k |         if ((item = cbor_new_definite_map(2)) == NULL) | 
| 679 | 6 |                 return (NULL); | 
| 680 | 1.06k |         if ((up != FIDO_OPT_OMIT && cbor_add_bool(item, "up", up) < 0) || | 
| 681 | 1.06k |             (uv != FIDO_OPT_OMIT && cbor_add_bool(item, "uv", uv) < 0)) { | 
| 682 | 10 |                 cbor_decref(&item); | 
| 683 | 10 |                 return (NULL); | 
| 684 | 10 |         } | 
| 685 |  |  | 
| 686 | 1.05k |         return (item); | 
| 687 | 1.06k | } | 
| 688 |  |  | 
| 689 |  | cbor_item_t * | 
| 690 |  | cbor_encode_pin_auth(const fido_dev_t *dev, const fido_blob_t *secret, | 
| 691 |  |     const fido_blob_t *data) | 
| 692 | 15.6k | { | 
| 693 | 15.6k |         const EVP_MD    *md = NULL; | 
| 694 | 15.6k |         unsigned char    dgst[SHA256_DIGEST_LENGTH]; | 
| 695 | 15.6k |         unsigned int     dgst_len; | 
| 696 | 15.6k |         size_t           outlen; | 
| 697 | 15.6k |         uint8_t          prot; | 
| 698 | 15.6k |         fido_blob_t      key; | 
| 699 |  |  | 
| 700 | 15.6k |         key.ptr = secret->ptr; | 
| 701 | 15.6k |         key.len = secret->len; | 
| 702 |  |  | 
| 703 | 15.6k |         if ((prot = fido_dev_get_pin_protocol(dev)) == 0) { | 
| 704 | 0 |                 fido_log_debug("%s: fido_dev_get_pin_protocol", __func__); | 
| 705 | 0 |                 return (NULL); | 
| 706 | 0 |         } | 
| 707 |  |  | 
| 708 |  |         /* select hmac portion of the shared secret */ | 
| 709 | 15.6k |         if (prot == CTAP_PIN_PROTOCOL2 && key.len > 32) | 
| 710 | 186 |                 key.len = 32; | 
| 711 |  |  | 
| 712 | 15.6k |         if ((md = EVP_sha256()) == NULL || HMAC(md, key.ptr, | 
| 713 | 15.6k |             (int)key.len, data->ptr, data->len, dgst, | 
| 714 | 15.6k |             &dgst_len) == NULL || dgst_len != SHA256_DIGEST_LENGTH) | 
| 715 | 139 |                 return (NULL); | 
| 716 |  |  | 
| 717 | 15.5k |         outlen = (prot == CTAP_PIN_PROTOCOL1) ? 16 : dgst_len; | 
| 718 |  |  | 
| 719 | 15.5k |         return (cbor_build_bytestring(dgst, outlen)); | 
| 720 | 15.6k | } | 
| 721 |  |  | 
| 722 |  | cbor_item_t * | 
| 723 |  | cbor_encode_pin_opt(const fido_dev_t *dev) | 
| 724 | 138k | { | 
| 725 | 138k |         uint8_t     prot; | 
| 726 |  |  | 
| 727 | 138k |         if ((prot = fido_dev_get_pin_protocol(dev)) == 0) { | 
| 728 | 41.5k |                 fido_log_debug("%s: fido_dev_get_pin_protocol", __func__); | 
| 729 | 41.5k |                 return (NULL); | 
| 730 | 41.5k |         } | 
| 731 |  |  | 
| 732 | 96.6k |         return (cbor_build_uint8(prot)); | 
| 733 | 138k | } | 
| 734 |  |  | 
| 735 |  | cbor_item_t * | 
| 736 |  | cbor_encode_change_pin_auth(const fido_dev_t *dev, const fido_blob_t *secret, | 
| 737 |  |     const fido_blob_t *new_pin_enc, const fido_blob_t *pin_hash_enc) | 
| 738 | 130 | { | 
| 739 | 130 |         unsigned char    dgst[SHA256_DIGEST_LENGTH]; | 
| 740 | 130 |         unsigned int     dgst_len; | 
| 741 | 130 |         cbor_item_t     *item = NULL; | 
| 742 | 130 |         const EVP_MD    *md = NULL; | 
| 743 | 130 |         HMAC_CTX        *ctx = NULL; | 
| 744 | 130 |         fido_blob_t      key; | 
| 745 | 130 |         uint8_t          prot; | 
| 746 | 130 |         size_t           outlen; | 
| 747 |  |  | 
| 748 | 130 |         key.ptr = secret->ptr; | 
| 749 | 130 |         key.len = secret->len; | 
| 750 |  |  | 
| 751 | 130 |         if ((prot = fido_dev_get_pin_protocol(dev)) == 0) { | 
| 752 | 0 |                 fido_log_debug("%s: fido_dev_get_pin_protocol", __func__); | 
| 753 | 0 |                 goto fail; | 
| 754 | 0 |         } | 
| 755 |  |  | 
| 756 | 130 |         if (prot == CTAP_PIN_PROTOCOL2 && key.len > 32) | 
| 757 | 71 |                 key.len = 32; | 
| 758 |  |  | 
| 759 | 130 |         if ((ctx = HMAC_CTX_new()) == NULL || | 
| 760 | 130 |             (md = EVP_sha256())  == NULL || | 
| 761 | 130 |             HMAC_Init_ex(ctx, key.ptr, (int)key.len, md, NULL) == 0 || | 
| 762 | 130 |             HMAC_Update(ctx, new_pin_enc->ptr, new_pin_enc->len) == 0 || | 
| 763 | 130 |             HMAC_Update(ctx, pin_hash_enc->ptr, pin_hash_enc->len) == 0 || | 
| 764 | 130 |             HMAC_Final(ctx, dgst, &dgst_len) == 0 || | 
| 765 | 130 |             dgst_len != SHA256_DIGEST_LENGTH) { | 
| 766 | 33 |                 fido_log_debug("%s: HMAC", __func__); | 
| 767 | 33 |                 goto fail; | 
| 768 | 33 |         } | 
| 769 |  |  | 
| 770 | 97 |         outlen = (prot == CTAP_PIN_PROTOCOL1) ? 16 : dgst_len; | 
| 771 |  |  | 
| 772 | 97 |         if ((item = cbor_build_bytestring(dgst, outlen)) == NULL) { | 
| 773 | 21 |                 fido_log_debug("%s: cbor_build_bytestring", __func__); | 
| 774 | 21 |                 goto fail; | 
| 775 | 21 |         } | 
| 776 |  |  | 
| 777 | 130 | fail: | 
| 778 | 130 |         HMAC_CTX_free(ctx); | 
| 779 |  |  | 
| 780 | 130 |         return (item); | 
| 781 | 97 | } | 
| 782 |  |  | 
| 783 |  | static int | 
| 784 |  | cbor_encode_hmac_secret_param(const fido_dev_t *dev, cbor_item_t *item, | 
| 785 |  |     const fido_blob_t *ecdh, const es256_pk_t *pk, const fido_blob_t *salt) | 
| 786 | 463 | { | 
| 787 | 463 |         cbor_item_t             *param = NULL; | 
| 788 | 463 |         cbor_item_t             *argv[4]; | 
| 789 | 463 |         struct cbor_pair         pair; | 
| 790 | 463 |         fido_blob_t             *enc = NULL; | 
| 791 | 463 |         uint8_t                  prot; | 
| 792 | 463 |         int                      r; | 
| 793 |  |  | 
| 794 | 463 |         memset(argv, 0, sizeof(argv)); | 
| 795 | 463 |         memset(&pair, 0, sizeof(pair)); | 
| 796 |  |  | 
| 797 | 463 |         if (item == NULL || ecdh == NULL || pk == NULL || salt->ptr == NULL) { | 
| 798 | 150 |                 fido_log_debug("%s: ecdh=%p, pk=%p, salt->ptr=%p", __func__, | 
| 799 | 150 |                     (const void *)ecdh, (const void *)pk, | 
| 800 | 150 |                     (const void *)salt->ptr); | 
| 801 | 150 |                 r = FIDO_ERR_INTERNAL; | 
| 802 | 150 |                 goto fail; | 
| 803 | 150 |         } | 
| 804 |  |  | 
| 805 | 313 |         if (salt->len != 32 && salt->len != 64) { | 
| 806 | 0 |                 fido_log_debug("%s: salt->len=%zu", __func__, salt->len); | 
| 807 | 0 |                 r = FIDO_ERR_INTERNAL; | 
| 808 | 0 |                 goto fail; | 
| 809 | 0 |         } | 
| 810 |  |  | 
| 811 | 313 |         if ((enc = fido_blob_new()) == NULL || | 
| 812 | 313 |             aes256_cbc_enc(dev, ecdh, salt, enc) < 0) { | 
| 813 | 8 |                 fido_log_debug("%s: aes256_cbc_enc", __func__); | 
| 814 | 8 |                 r = FIDO_ERR_INTERNAL; | 
| 815 | 8 |                 goto fail; | 
| 816 | 8 |         } | 
| 817 |  |  | 
| 818 | 305 |         if ((prot = fido_dev_get_pin_protocol(dev)) == 0) { | 
| 819 | 0 |                 fido_log_debug("%s: fido_dev_get_pin_protocol", __func__); | 
| 820 | 0 |                 r = FIDO_ERR_INTERNAL; | 
| 821 | 0 |                 goto fail; | 
| 822 | 0 |         } | 
| 823 |  |  | 
| 824 |  |         /* XXX not pin, but salt */ | 
| 825 | 305 |         if ((argv[0] = es256_pk_encode(pk, 1)) == NULL || | 
| 826 | 305 |             (argv[1] = fido_blob_encode(enc)) == NULL || | 
| 827 | 305 |             (argv[2] = cbor_encode_pin_auth(dev, ecdh, enc)) == NULL || | 
| 828 | 305 |             (prot != 1 && (argv[3] = cbor_build_uint8(prot)) == NULL)) { | 
| 829 | 22 |                 fido_log_debug("%s: cbor encode", __func__); | 
| 830 | 22 |                 r = FIDO_ERR_INTERNAL; | 
| 831 | 22 |                 goto fail; | 
| 832 | 22 |         } | 
| 833 |  |  | 
| 834 | 283 |         if ((param = cbor_flatten_vector(argv, nitems(argv))) == NULL) { | 
| 835 | 9 |                 fido_log_debug("%s: cbor_flatten_vector", __func__); | 
| 836 | 9 |                 r = FIDO_ERR_INTERNAL; | 
| 837 | 9 |                 goto fail; | 
| 838 | 9 |         } | 
| 839 |  |  | 
| 840 | 274 |         if ((pair.key = cbor_build_string("hmac-secret")) == NULL) { | 
| 841 | 4 |                 fido_log_debug("%s: cbor_build", __func__); | 
| 842 | 4 |                 r = FIDO_ERR_INTERNAL; | 
| 843 | 4 |                 goto fail; | 
| 844 | 4 |         } | 
| 845 |  |  | 
| 846 | 270 |         pair.value = param; | 
| 847 |  |  | 
| 848 | 270 |         if (!cbor_map_add(item, pair)) { | 
| 849 | 8 |                 fido_log_debug("%s: cbor_map_add", __func__); | 
| 850 | 8 |                 r = FIDO_ERR_INTERNAL; | 
| 851 | 8 |                 goto fail; | 
| 852 | 8 |         } | 
| 853 |  |  | 
| 854 | 262 |         r = FIDO_OK; | 
| 855 |  |  | 
| 856 | 463 | fail: | 
| 857 | 463 |         cbor_vector_free(argv, nitems(argv)); | 
| 858 |  |  | 
| 859 | 463 |         if (param != NULL) | 
| 860 | 274 |                 cbor_decref(¶m); | 
| 861 | 463 |         if (pair.key != NULL) | 
| 862 | 270 |                 cbor_decref(&pair.key); | 
| 863 |  |  | 
| 864 | 463 |         fido_blob_free(&enc); | 
| 865 |  |  | 
| 866 | 463 |         return (r); | 
| 867 | 262 | } | 
| 868 |  |  | 
| 869 |  | cbor_item_t * | 
| 870 |  | cbor_encode_assert_ext(fido_dev_t *dev, const fido_assert_ext_t *ext, | 
| 871 |  |     const fido_blob_t *ecdh, const es256_pk_t *pk) | 
| 872 | 1.67k | { | 
| 873 | 1.67k |         cbor_item_t *item = NULL; | 
| 874 | 1.67k |         size_t size = 0; | 
| 875 |  |  | 
| 876 | 1.67k |         if (ext->mask & FIDO_EXT_CRED_BLOB) | 
| 877 | 1.13k |                 size++; | 
| 878 | 1.67k |         if (ext->mask & FIDO_EXT_HMAC_SECRET) | 
| 879 | 463 |                 size++; | 
| 880 | 1.67k |         if (ext->mask & FIDO_EXT_LARGEBLOB_KEY) | 
| 881 | 858 |                 size++; | 
| 882 | 1.67k |         if (size == 0 || (item = cbor_new_definite_map(size)) == NULL) | 
| 883 | 2 |                 return (NULL); | 
| 884 |  |  | 
| 885 | 1.66k |         if (ext->mask & FIDO_EXT_CRED_BLOB) { | 
| 886 | 1.13k |                 if (cbor_add_bool(item, "credBlob", FIDO_OPT_TRUE) < 0) { | 
| 887 | 15 |                         cbor_decref(&item); | 
| 888 | 15 |                         return (NULL); | 
| 889 | 15 |                 } | 
| 890 | 1.13k |         } | 
| 891 | 1.65k |         if (ext->mask & FIDO_EXT_HMAC_SECRET) { | 
| 892 | 463 |                 if (cbor_encode_hmac_secret_param(dev, item, ecdh, pk, | 
| 893 | 463 |                     &ext->hmac_salt) < 0) { | 
| 894 | 201 |                         cbor_decref(&item); | 
| 895 | 201 |                         return (NULL); | 
| 896 | 201 |                 } | 
| 897 | 463 |         } | 
| 898 | 1.45k |         if (ext->mask & FIDO_EXT_LARGEBLOB_KEY) { | 
| 899 | 751 |                 if (cbor_encode_largeblob_key_ext(item) < 0) { | 
| 900 | 3 |                         cbor_decref(&item); | 
| 901 | 3 |                         return (NULL); | 
| 902 | 3 |                 } | 
| 903 | 751 |         } | 
| 904 |  |  | 
| 905 | 1.44k |         return (item); | 
| 906 | 1.45k | } | 
| 907 |  |  | 
| 908 |  | int | 
| 909 |  | cbor_decode_fmt(const cbor_item_t *item, char **fmt) | 
| 910 | 9.48k | { | 
| 911 | 9.48k |         char    *type = NULL; | 
| 912 |  |  | 
| 913 | 9.48k |         if (cbor_string_copy(item, &type) < 0) { | 
| 914 | 96 |                 fido_log_debug("%s: cbor_string_copy", __func__); | 
| 915 | 96 |                 return (-1); | 
| 916 | 96 |         } | 
| 917 |  |  | 
| 918 | 9.38k |         if (strcmp(type, "packed") && strcmp(type, "fido-u2f") && | 
| 919 | 9.38k |             strcmp(type, "none") && strcmp(type, "tpm")) { | 
| 920 | 407 |                 fido_log_debug("%s: type=%s", __func__, type); | 
| 921 | 407 |                 free(type); | 
| 922 | 407 |                 return (-1); | 
| 923 | 407 |         } | 
| 924 |  |  | 
| 925 | 8.98k |         *fmt = type; | 
| 926 |  |  | 
| 927 | 8.98k |         return (0); | 
| 928 | 9.38k | } | 
| 929 |  |  | 
| 930 |  | struct cose_key { | 
| 931 |  |         int kty; | 
| 932 |  |         int alg; | 
| 933 |  |         int crv; | 
| 934 |  | }; | 
| 935 |  |  | 
| 936 |  | static int | 
| 937 |  | find_cose_alg(const cbor_item_t *key, const cbor_item_t *val, void *arg) | 
| 938 | 88.5k | { | 
| 939 | 88.5k |         struct cose_key *cose_key = arg; | 
| 940 |  |  | 
| 941 | 88.5k |         if (cbor_isa_uint(key) == true && | 
| 942 | 88.5k |             cbor_int_get_width(key) == CBOR_INT_8) { | 
| 943 | 37.7k |                 switch (cbor_get_uint8(key)) { | 
| 944 | 18.8k |                 case 1: | 
| 945 | 18.8k |                         if (cbor_isa_uint(val) == false || | 
| 946 | 18.8k |                             cbor_get_int(val) > INT_MAX || cose_key->kty != 0) { | 
| 947 | 210 |                                 fido_log_debug("%s: kty", __func__); | 
| 948 | 210 |                                 return (-1); | 
| 949 | 210 |                         } | 
| 950 |  |  | 
| 951 | 18.6k |                         cose_key->kty = (int)cbor_get_int(val); | 
| 952 |  |  | 
| 953 | 18.6k |                         break; | 
| 954 | 18.6k |                 case 3: | 
| 955 | 18.6k |                         if (cbor_isa_negint(val) == false || | 
| 956 | 18.6k |                             cbor_get_int(val) > INT_MAX || cose_key->alg != 0) { | 
| 957 | 225 |                                 fido_log_debug("%s: alg", __func__); | 
| 958 | 225 |                                 return (-1); | 
| 959 | 225 |                         } | 
| 960 |  |  | 
| 961 | 18.3k |                         cose_key->alg = -(int)cbor_get_int(val) - 1; | 
| 962 |  |  | 
| 963 | 18.3k |                         break; | 
| 964 | 37.7k |                 } | 
| 965 | 50.7k |         } else if (cbor_isa_negint(key) == true && | 
| 966 | 50.7k |             cbor_int_get_width(key) == CBOR_INT_8) { | 
| 967 | 49.4k |                 if (cbor_get_uint8(key) == 0) { | 
| 968 |  |                         /* get crv if not rsa, otherwise ignore */ | 
| 969 | 17.7k |                         if (cbor_isa_uint(val) == true && | 
| 970 | 17.7k |                             cbor_get_int(val) <= INT_MAX && | 
| 971 | 17.7k |                             cose_key->crv == 0) | 
| 972 | 17.1k |                                 cose_key->crv = (int)cbor_get_int(val); | 
| 973 | 17.7k |                 } | 
| 974 | 49.4k |         } | 
| 975 |  |  | 
| 976 | 88.1k |         return (0); | 
| 977 | 88.5k | } | 
| 978 |  |  | 
| 979 |  | static int | 
| 980 |  | get_cose_alg(const cbor_item_t *item, int *cose_alg) | 
| 981 | 19.4k | { | 
| 982 | 19.4k |         struct cose_key cose_key; | 
| 983 |  |  | 
| 984 | 19.4k |         memset(&cose_key, 0, sizeof(cose_key)); | 
| 985 |  |  | 
| 986 | 19.4k |         *cose_alg = 0; | 
| 987 |  |  | 
| 988 | 19.4k |         if (cbor_isa_map(item) == false || | 
| 989 | 19.4k |             cbor_map_is_definite(item) == false || | 
| 990 | 19.4k |             cbor_map_iter(item, &cose_key, find_cose_alg) < 0) { | 
| 991 | 1.43k |                 fido_log_debug("%s: cbor type", __func__); | 
| 992 | 1.43k |                 return (-1); | 
| 993 | 1.43k |         } | 
| 994 |  |  | 
| 995 | 17.9k |         switch (cose_key.alg) { | 
| 996 | 13.9k |         case COSE_ES256: | 
| 997 | 13.9k |                 if (cose_key.kty != COSE_KTY_EC2 || | 
| 998 | 13.9k |                     cose_key.crv != COSE_P256) { | 
| 999 | 212 |                         fido_log_debug("%s: invalid kty/crv", __func__); | 
| 1000 | 212 |                         return (-1); | 
| 1001 | 212 |                 } | 
| 1002 | 13.7k |                 break; | 
| 1003 | 13.7k |         case COSE_ES384: | 
| 1004 | 792 |                 if (cose_key.kty != COSE_KTY_EC2 || | 
| 1005 | 792 |                     cose_key.crv != COSE_P384) { | 
| 1006 | 22 |                         fido_log_debug("%s: invalid kty/crv", __func__); | 
| 1007 | 22 |                         return (-1); | 
| 1008 | 22 |                 } | 
| 1009 | 770 |                 break; | 
| 1010 | 2.44k |         case COSE_EDDSA: | 
| 1011 | 2.44k |                 if (cose_key.kty != COSE_KTY_OKP || | 
| 1012 | 2.44k |                     cose_key.crv != COSE_ED25519) { | 
| 1013 | 376 |                         fido_log_debug("%s: invalid kty/crv", __func__); | 
| 1014 | 376 |                         return (-1); | 
| 1015 | 376 |                 } | 
| 1016 | 2.07k |                 break; | 
| 1017 | 2.07k |         case COSE_RS256: | 
| 1018 | 577 |                 if (cose_key.kty != COSE_KTY_RSA) { | 
| 1019 | 17 |                         fido_log_debug("%s: invalid kty/crv", __func__); | 
| 1020 | 17 |                         return (-1); | 
| 1021 | 17 |                 } | 
| 1022 | 560 |                 break; | 
| 1023 | 560 |         default: | 
| 1024 | 249 |                 fido_log_debug("%s: unknown alg %d", __func__, cose_key.alg); | 
| 1025 |  |  | 
| 1026 | 249 |                 return (-1); | 
| 1027 | 17.9k |         } | 
| 1028 |  |  | 
| 1029 | 17.1k |         *cose_alg = cose_key.alg; | 
| 1030 |  |  | 
| 1031 | 17.1k |         return (0); | 
| 1032 | 17.9k | } | 
| 1033 |  |  | 
| 1034 |  | int | 
| 1035 |  | cbor_decode_pubkey(const cbor_item_t *item, int *type, void *key) | 
| 1036 | 19.4k | { | 
| 1037 | 19.4k |         if (get_cose_alg(item, type) < 0) { | 
| 1038 | 2.31k |                 fido_log_debug("%s: get_cose_alg", __func__); | 
| 1039 | 2.31k |                 return (-1); | 
| 1040 | 2.31k |         } | 
| 1041 |  |  | 
| 1042 | 17.1k |         switch (*type) { | 
| 1043 | 13.7k |         case COSE_ES256: | 
| 1044 | 13.7k |                 if (es256_pk_decode(item, key) < 0) { | 
| 1045 | 262 |                         fido_log_debug("%s: es256_pk_decode", __func__); | 
| 1046 | 262 |                         return (-1); | 
| 1047 | 262 |                 } | 
| 1048 | 13.4k |                 break; | 
| 1049 | 13.4k |         case COSE_ES384: | 
| 1050 | 770 |                 if (es384_pk_decode(item, key) < 0) { | 
| 1051 | 39 |                         fido_log_debug("%s: es384_pk_decode", __func__); | 
| 1052 | 39 |                         return (-1); | 
| 1053 | 39 |                 } | 
| 1054 | 731 |                 break; | 
| 1055 | 731 |         case COSE_RS256: | 
| 1056 | 560 |                 if (rs256_pk_decode(item, key) < 0) { | 
| 1057 | 56 |                         fido_log_debug("%s: rs256_pk_decode", __func__); | 
| 1058 | 56 |                         return (-1); | 
| 1059 | 56 |                 } | 
| 1060 | 504 |                 break; | 
| 1061 | 2.07k |         case COSE_EDDSA: | 
| 1062 | 2.07k |                 if (eddsa_pk_decode(item, key) < 0) { | 
| 1063 | 155 |                         fido_log_debug("%s: eddsa_pk_decode", __func__); | 
| 1064 | 155 |                         return (-1); | 
| 1065 | 155 |                 } | 
| 1066 | 1.91k |                 break; | 
| 1067 | 1.91k |         default: | 
| 1068 | 0 |                 fido_log_debug("%s: invalid cose_alg %d", __func__, *type); | 
| 1069 | 0 |                 return (-1); | 
| 1070 | 17.1k |         } | 
| 1071 |  |  | 
| 1072 | 16.5k |         return (0); | 
| 1073 | 17.1k | } | 
| 1074 |  |  | 
| 1075 |  | static int | 
| 1076 |  | decode_attcred(const unsigned char **buf, size_t *len, int cose_alg, | 
| 1077 |  |     fido_attcred_t *attcred) | 
| 1078 | 13.7k | { | 
| 1079 | 13.7k |         cbor_item_t             *item = NULL; | 
| 1080 | 13.7k |         struct cbor_load_result  cbor; | 
| 1081 | 13.7k |         uint16_t                 id_len; | 
| 1082 | 13.7k |         int                      ok = -1; | 
| 1083 |  |  | 
| 1084 | 13.7k |         fido_log_xxd(*buf, *len, "%s", __func__); | 
| 1085 |  |  | 
| 1086 | 13.7k |         if (fido_buf_read(buf, len, &attcred->aaguid, | 
| 1087 | 13.7k |             sizeof(attcred->aaguid)) < 0) { | 
| 1088 | 14 |                 fido_log_debug("%s: fido_buf_read aaguid", __func__); | 
| 1089 | 14 |                 return (-1); | 
| 1090 | 14 |         } | 
| 1091 |  |  | 
| 1092 | 13.6k |         if (fido_buf_read(buf, len, &id_len, sizeof(id_len)) < 0) { | 
| 1093 | 8 |                 fido_log_debug("%s: fido_buf_read id_len", __func__); | 
| 1094 | 8 |                 return (-1); | 
| 1095 | 8 |         } | 
| 1096 |  |  | 
| 1097 | 13.6k |         attcred->id.len = (size_t)be16toh(id_len); | 
| 1098 | 13.6k |         if ((attcred->id.ptr = malloc(attcred->id.len)) == NULL) | 
| 1099 | 74 |                 return (-1); | 
| 1100 |  |  | 
| 1101 | 13.6k |         fido_log_debug("%s: attcred->id.len=%zu", __func__, attcred->id.len); | 
| 1102 |  |  | 
| 1103 | 13.6k |         if (fido_buf_read(buf, len, attcred->id.ptr, attcred->id.len) < 0) { | 
| 1104 | 304 |                 fido_log_debug("%s: fido_buf_read id", __func__); | 
| 1105 | 304 |                 return (-1); | 
| 1106 | 304 |         } | 
| 1107 |  |  | 
| 1108 | 13.3k |         if ((item = cbor_load(*buf, *len, &cbor)) == NULL) { | 
| 1109 | 338 |                 fido_log_debug("%s: cbor_load", __func__); | 
| 1110 | 338 |                 goto fail; | 
| 1111 | 338 |         } | 
| 1112 |  |  | 
| 1113 | 12.9k |         if (cbor_decode_pubkey(item, &attcred->type, &attcred->pubkey) < 0) { | 
| 1114 | 1.31k |                 fido_log_debug("%s: cbor_decode_pubkey", __func__); | 
| 1115 | 1.31k |                 goto fail; | 
| 1116 | 1.31k |         } | 
| 1117 |  |  | 
| 1118 | 11.6k |         if (attcred->type != cose_alg) { | 
| 1119 | 1.83k |                 fido_log_debug("%s: cose_alg mismatch (%d != %d)", __func__, | 
| 1120 | 1.83k |                     attcred->type, cose_alg); | 
| 1121 | 1.83k |                 goto fail; | 
| 1122 | 1.83k |         } | 
| 1123 |  |  | 
| 1124 | 9.82k |         *buf += cbor.read; | 
| 1125 | 9.82k |         *len -= cbor.read; | 
| 1126 |  |  | 
| 1127 | 9.82k |         ok = 0; | 
| 1128 | 13.3k | fail: | 
| 1129 | 13.3k |         if (item != NULL) | 
| 1130 | 12.9k |                 cbor_decref(&item); | 
| 1131 |  |  | 
| 1132 | 13.3k |         return (ok); | 
| 1133 | 9.82k | } | 
| 1134 |  |  | 
| 1135 |  | static int | 
| 1136 |  | decode_attobj(const cbor_item_t *key, const cbor_item_t *val, void *arg) | 
| 1137 | 16.2k | { | 
| 1138 | 16.2k |         fido_cred_t *cred = arg; | 
| 1139 | 16.2k |         char *name = NULL; | 
| 1140 | 16.2k |         int ok = -1; | 
| 1141 |  |  | 
| 1142 | 16.2k |         if (cbor_string_copy(key, &name) < 0) { | 
| 1143 | 200 |                 fido_log_debug("%s: cbor type", __func__); | 
| 1144 | 200 |                 ok = 0; /* ignore */ | 
| 1145 | 200 |                 goto fail; | 
| 1146 | 200 |         } | 
| 1147 |  |  | 
| 1148 | 16.0k |         if (!strcmp(name, "fmt")) { | 
| 1149 | 5.91k |                 if (cbor_decode_fmt(val, &cred->fmt) < 0) { | 
| 1150 | 240 |                         fido_log_debug("%s: cbor_decode_fmt", __func__); | 
| 1151 | 240 |                         goto fail; | 
| 1152 | 240 |                 } | 
| 1153 | 10.1k |         } else if (!strcmp(name, "attStmt")) { | 
| 1154 | 5.56k |                 if (cbor_decode_attstmt(val, &cred->attstmt) < 0) { | 
| 1155 | 415 |                         fido_log_debug("%s: cbor_decode_attstmt", __func__); | 
| 1156 | 415 |                         goto fail; | 
| 1157 | 415 |                 } | 
| 1158 | 5.56k |         } else if (!strcmp(name, "authData")) { | 
| 1159 | 3.70k |                 if (fido_blob_decode(val, &cred->authdata_raw) < 0) { | 
| 1160 | 7 |                         fido_log_debug("%s: fido_blob_decode", __func__); | 
| 1161 | 7 |                         goto fail; | 
| 1162 | 7 |                 } | 
| 1163 | 3.69k |                 if (cbor_decode_cred_authdata(val, cred->type, | 
| 1164 | 3.69k |                     &cred->authdata_cbor, &cred->authdata, &cred->attcred, | 
| 1165 | 3.69k |                     &cred->authdata_ext) < 0) { | 
| 1166 | 3.18k |                         fido_log_debug("%s: cbor_decode_cred_authdata", | 
| 1167 | 3.18k |                             __func__); | 
| 1168 | 3.18k |                         goto fail; | 
| 1169 | 3.18k |                 } | 
| 1170 | 3.69k |         } | 
| 1171 |  |  | 
| 1172 | 12.2k |         ok = 0; | 
| 1173 | 16.2k | fail: | 
| 1174 | 16.2k |         free(name); | 
| 1175 |  |  | 
| 1176 | 16.2k |         return (ok); | 
| 1177 | 12.2k | } | 
| 1178 |  |  | 
| 1179 |  | /* XXX introduce fido_attobj_t? */ | 
| 1180 |  | int | 
| 1181 |  | cbor_decode_attobj(const cbor_item_t *item, fido_cred_t *cred) | 
| 1182 | 6.26k | { | 
| 1183 | 6.26k |         if (cbor_isa_map(item) == false || | 
| 1184 | 6.26k |             cbor_map_is_definite(item) == false || | 
| 1185 | 6.26k |             cbor_map_iter(item, cred, decode_attobj) < 0) { | 
| 1186 | 5.35k |                 fido_log_debug("%s: cbor type", __func__); | 
| 1187 | 5.35k |                 return (-1); | 
| 1188 | 5.35k |         } | 
| 1189 |  |  | 
| 1190 | 910 |         return (0); | 
| 1191 | 6.26k | } | 
| 1192 |  |  | 
| 1193 |  | static int | 
| 1194 |  | decode_cred_extension(const cbor_item_t *key, const cbor_item_t *val, void *arg) | 
| 1195 | 377 | { | 
| 1196 | 377 |         fido_cred_ext_t *authdata_ext = arg; | 
| 1197 | 377 |         char            *type = NULL; | 
| 1198 | 377 |         int              ok = -1; | 
| 1199 |  |  | 
| 1200 | 377 |         if (cbor_string_copy(key, &type) < 0) { | 
| 1201 | 76 |                 fido_log_debug("%s: cbor type", __func__); | 
| 1202 | 76 |                 ok = 0; /* ignore */ | 
| 1203 | 76 |                 goto out; | 
| 1204 | 76 |         } | 
| 1205 |  |  | 
| 1206 | 301 |         if (strcmp(type, "hmac-secret") == 0) { | 
| 1207 | 56 |                 if (cbor_decode_bool(val, NULL) < 0) { | 
| 1208 | 8 |                         fido_log_debug("%s: cbor_decode_bool", __func__); | 
| 1209 | 8 |                         goto out; | 
| 1210 | 8 |                 } | 
| 1211 | 48 |                 if (cbor_ctrl_value(val) == CBOR_CTRL_TRUE) | 
| 1212 | 26 |                         authdata_ext->mask |= FIDO_EXT_HMAC_SECRET; | 
| 1213 | 245 |         } else if (strcmp(type, "credProtect") == 0) { | 
| 1214 | 103 |                 if (cbor_isa_uint(val) == false || | 
| 1215 | 103 |                     cbor_int_get_width(val) != CBOR_INT_8) { | 
| 1216 | 32 |                         fido_log_debug("%s: cbor type", __func__); | 
| 1217 | 32 |                         goto out; | 
| 1218 | 32 |                 } | 
| 1219 | 71 |                 authdata_ext->mask |= FIDO_EXT_CRED_PROTECT; | 
| 1220 | 71 |                 authdata_ext->prot = cbor_get_uint8(val); | 
| 1221 | 142 |         } else if (strcmp(type, "credBlob") == 0) { | 
| 1222 | 49 |                 if (cbor_decode_bool(val, NULL) < 0) { | 
| 1223 | 9 |                         fido_log_debug("%s: cbor_decode_bool", __func__); | 
| 1224 | 9 |                         goto out; | 
| 1225 | 9 |                 } | 
| 1226 | 40 |                 if (cbor_ctrl_value(val) == CBOR_CTRL_TRUE) | 
| 1227 | 15 |                         authdata_ext->mask |= FIDO_EXT_CRED_BLOB; | 
| 1228 | 93 |         } else if (strcmp(type, "minPinLength") == 0) { | 
| 1229 | 31 |                 if (cbor_isa_uint(val) == false || | 
| 1230 | 31 |                     cbor_int_get_width(val) != CBOR_INT_8) { | 
| 1231 | 7 |                         fido_log_debug("%s: cbor type", __func__); | 
| 1232 | 7 |                         goto out; | 
| 1233 | 7 |                 } | 
| 1234 | 24 |                 authdata_ext->mask |= FIDO_EXT_MINPINLEN; | 
| 1235 | 24 |                 authdata_ext->minpinlen = cbor_get_uint8(val); | 
| 1236 | 24 |         } | 
| 1237 |  |  | 
| 1238 | 245 |         ok = 0; | 
| 1239 | 377 | out: | 
| 1240 | 377 |         free(type); | 
| 1241 |  |  | 
| 1242 | 377 |         return (ok); | 
| 1243 | 245 | } | 
| 1244 |  |  | 
| 1245 |  | static int | 
| 1246 |  | decode_cred_extensions(const unsigned char **buf, size_t *len, | 
| 1247 |  |     fido_cred_ext_t *authdata_ext) | 
| 1248 | 352 | { | 
| 1249 | 352 |         cbor_item_t             *item = NULL; | 
| 1250 | 352 |         struct cbor_load_result  cbor; | 
| 1251 | 352 |         int                      ok = -1; | 
| 1252 |  |  | 
| 1253 | 352 |         memset(authdata_ext, 0, sizeof(*authdata_ext)); | 
| 1254 |  |  | 
| 1255 | 352 |         fido_log_xxd(*buf, *len, "%s", __func__); | 
| 1256 |  |  | 
| 1257 | 352 |         if ((item = cbor_load(*buf, *len, &cbor)) == NULL) { | 
| 1258 | 34 |                 fido_log_debug("%s: cbor_load", __func__); | 
| 1259 | 34 |                 goto fail; | 
| 1260 | 34 |         } | 
| 1261 |  |  | 
| 1262 | 318 |         if (cbor_isa_map(item) == false || | 
| 1263 | 318 |             cbor_map_is_definite(item) == false || | 
| 1264 | 318 |             cbor_map_iter(item, authdata_ext, decode_cred_extension) < 0) { | 
| 1265 | 92 |                 fido_log_debug("%s: cbor type", __func__); | 
| 1266 | 92 |                 goto fail; | 
| 1267 | 92 |         } | 
| 1268 |  |  | 
| 1269 | 226 |         *buf += cbor.read; | 
| 1270 | 226 |         *len -= cbor.read; | 
| 1271 |  |  | 
| 1272 | 226 |         ok = 0; | 
| 1273 | 352 | fail: | 
| 1274 | 352 |         if (item != NULL) | 
| 1275 | 318 |                 cbor_decref(&item); | 
| 1276 |  |  | 
| 1277 | 352 |         return (ok); | 
| 1278 | 226 | } | 
| 1279 |  |  | 
| 1280 |  | static int | 
| 1281 |  | decode_assert_extension(const cbor_item_t *key, const cbor_item_t *val, | 
| 1282 |  |     void *arg) | 
| 1283 | 1.69k | { | 
| 1284 | 1.69k |         fido_assert_extattr_t   *authdata_ext = arg; | 
| 1285 | 1.69k |         char                    *type = NULL; | 
| 1286 | 1.69k |         int                      ok = -1; | 
| 1287 |  |  | 
| 1288 | 1.69k |         if (cbor_string_copy(key, &type) < 0) { | 
| 1289 | 168 |                 fido_log_debug("%s: cbor type", __func__); | 
| 1290 | 168 |                 ok = 0; /* ignore */ | 
| 1291 | 168 |                 goto out; | 
| 1292 | 168 |         } | 
| 1293 |  |  | 
| 1294 | 1.52k |         if (strcmp(type, "hmac-secret") == 0) { | 
| 1295 | 906 |                 if (fido_blob_decode(val, &authdata_ext->hmac_secret_enc) < 0) { | 
| 1296 | 37 |                         fido_log_debug("%s: fido_blob_decode", __func__); | 
| 1297 | 37 |                         goto out; | 
| 1298 | 37 |                 } | 
| 1299 | 869 |                 authdata_ext->mask |= FIDO_EXT_HMAC_SECRET; | 
| 1300 | 869 |         } else if (strcmp(type, "credBlob") == 0) { | 
| 1301 | 383 |                 if (fido_blob_decode(val, &authdata_ext->blob) < 0) { | 
| 1302 | 4 |                         fido_log_debug("%s: fido_blob_decode", __func__); | 
| 1303 | 4 |                         goto out; | 
| 1304 | 4 |                 } | 
| 1305 | 379 |                 authdata_ext->mask |= FIDO_EXT_CRED_BLOB; | 
| 1306 | 379 |         } | 
| 1307 |  |  | 
| 1308 | 1.48k |         ok = 0; | 
| 1309 | 1.69k | out: | 
| 1310 | 1.69k |         free(type); | 
| 1311 |  |  | 
| 1312 | 1.69k |         return (ok); | 
| 1313 | 1.48k | } | 
| 1314 |  |  | 
| 1315 |  | static int | 
| 1316 |  | decode_assert_extensions(const unsigned char **buf, size_t *len, | 
| 1317 |  |     fido_assert_extattr_t *authdata_ext) | 
| 1318 | 3.21k | { | 
| 1319 | 3.21k |         cbor_item_t             *item = NULL; | 
| 1320 | 3.21k |         struct cbor_load_result  cbor; | 
| 1321 | 3.21k |         int                      ok = -1; | 
| 1322 |  |  | 
| 1323 | 3.21k |         fido_log_xxd(*buf, *len, "%s", __func__); | 
| 1324 |  |  | 
| 1325 | 3.21k |         if ((item = cbor_load(*buf, *len, &cbor)) == NULL) { | 
| 1326 | 751 |                 fido_log_debug("%s: cbor_load", __func__); | 
| 1327 | 751 |                 goto fail; | 
| 1328 | 751 |         } | 
| 1329 |  |  | 
| 1330 | 2.45k |         if (cbor_isa_map(item) == false || | 
| 1331 | 2.45k |             cbor_map_is_definite(item) == false || | 
| 1332 | 2.45k |             cbor_map_iter(item, authdata_ext, decode_assert_extension) < 0) { | 
| 1333 | 925 |                 fido_log_debug("%s: cbor type", __func__); | 
| 1334 | 925 |                 goto fail; | 
| 1335 | 925 |         } | 
| 1336 |  |  | 
| 1337 | 1.53k |         *buf += cbor.read; | 
| 1338 | 1.53k |         *len -= cbor.read; | 
| 1339 |  |  | 
| 1340 | 1.53k |         ok = 0; | 
| 1341 | 3.21k | fail: | 
| 1342 | 3.21k |         if (item != NULL) | 
| 1343 | 2.45k |                 cbor_decref(&item); | 
| 1344 |  |  | 
| 1345 | 3.21k |         return (ok); | 
| 1346 | 1.53k | } | 
| 1347 |  |  | 
| 1348 |  | int | 
| 1349 |  | cbor_decode_cred_authdata(const cbor_item_t *item, int cose_alg, | 
| 1350 |  |     fido_blob_t *authdata_cbor, fido_authdata_t *authdata, | 
| 1351 |  |     fido_attcred_t *attcred, fido_cred_ext_t *authdata_ext) | 
| 1352 | 14.0k | { | 
| 1353 | 14.0k |         const unsigned char     *buf = NULL; | 
| 1354 | 14.0k |         size_t                   len; | 
| 1355 | 14.0k |         size_t                   alloc_len; | 
| 1356 |  |  | 
| 1357 | 14.0k |         if (cbor_isa_bytestring(item) == false || | 
| 1358 | 14.0k |             cbor_bytestring_is_definite(item) == false) { | 
| 1359 | 0 |                 fido_log_debug("%s: cbor type", __func__); | 
| 1360 | 0 |                 return (-1); | 
| 1361 | 0 |         } | 
| 1362 |  |  | 
| 1363 | 14.0k |         if (authdata_cbor->ptr != NULL || | 
| 1364 | 14.0k |             (authdata_cbor->len = cbor_serialize_alloc(item, | 
| 1365 | 14.0k |             &authdata_cbor->ptr, &alloc_len)) == 0) { | 
| 1366 | 225 |                 fido_log_debug("%s: cbor_serialize_alloc", __func__); | 
| 1367 | 225 |                 return (-1); | 
| 1368 | 225 |         } | 
| 1369 |  |  | 
| 1370 | 13.7k |         buf = cbor_bytestring_handle(item); | 
| 1371 | 13.7k |         len = cbor_bytestring_length(item); | 
| 1372 | 13.7k |         fido_log_xxd(buf, len, "%s", __func__); | 
| 1373 |  |  | 
| 1374 | 13.7k |         if (fido_buf_read(&buf, &len, authdata, sizeof(*authdata)) < 0) { | 
| 1375 | 45 |                 fido_log_debug("%s: fido_buf_read", __func__); | 
| 1376 | 45 |                 return (-1); | 
| 1377 | 45 |         } | 
| 1378 |  |  | 
| 1379 | 13.7k |         authdata->sigcount = be32toh(authdata->sigcount); | 
| 1380 |  |  | 
| 1381 | 13.7k |         if (attcred != NULL) { | 
| 1382 | 13.7k |                 if ((authdata->flags & CTAP_AUTHDATA_ATT_CRED) == 0 || | 
| 1383 | 13.7k |                     decode_attcred(&buf, &len, cose_alg, attcred) < 0) | 
| 1384 | 3.91k |                         return (-1); | 
| 1385 | 13.7k |         } | 
| 1386 |  |  | 
| 1387 | 9.82k |         if (authdata_ext != NULL) { | 
| 1388 | 9.82k |                 if ((authdata->flags & CTAP_AUTHDATA_EXT_DATA) != 0 && | 
| 1389 | 9.82k |                     decode_cred_extensions(&buf, &len, authdata_ext) < 0) | 
| 1390 | 126 |                         return (-1); | 
| 1391 | 9.82k |         } | 
| 1392 |  |  | 
| 1393 |  |         /* XXX we should probably ensure that len == 0 at this point */ | 
| 1394 |  |  | 
| 1395 | 9.70k |         return (FIDO_OK); | 
| 1396 | 9.82k | } | 
| 1397 |  |  | 
| 1398 |  | int | 
| 1399 |  | cbor_decode_assert_authdata(const cbor_item_t *item, fido_blob_t *authdata_cbor, | 
| 1400 |  |     fido_authdata_t *authdata, fido_assert_extattr_t *authdata_ext) | 
| 1401 | 13.5k | { | 
| 1402 | 13.5k |         const unsigned char     *buf = NULL; | 
| 1403 | 13.5k |         size_t                   len; | 
| 1404 | 13.5k |         size_t                   alloc_len; | 
| 1405 |  |  | 
| 1406 | 13.5k |         if (cbor_isa_bytestring(item) == false || | 
| 1407 | 13.5k |             cbor_bytestring_is_definite(item) == false) { | 
| 1408 | 0 |                 fido_log_debug("%s: cbor type", __func__); | 
| 1409 | 0 |                 return (-1); | 
| 1410 | 0 |         } | 
| 1411 |  |  | 
| 1412 | 13.5k |         if (authdata_cbor->ptr != NULL || | 
| 1413 | 13.5k |             (authdata_cbor->len = cbor_serialize_alloc(item, | 
| 1414 | 13.5k |             &authdata_cbor->ptr, &alloc_len)) == 0) { | 
| 1415 | 87 |                 fido_log_debug("%s: cbor_serialize_alloc", __func__); | 
| 1416 | 87 |                 return (-1); | 
| 1417 | 87 |         } | 
| 1418 |  |  | 
| 1419 | 13.4k |         buf = cbor_bytestring_handle(item); | 
| 1420 | 13.4k |         len = cbor_bytestring_length(item); | 
| 1421 |  |  | 
| 1422 | 13.4k |         fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)buf, len); | 
| 1423 |  |  | 
| 1424 | 13.4k |         if (fido_buf_read(&buf, &len, authdata, sizeof(*authdata)) < 0) { | 
| 1425 | 41 |                 fido_log_debug("%s: fido_buf_read", __func__); | 
| 1426 | 41 |                 return (-1); | 
| 1427 | 41 |         } | 
| 1428 |  |  | 
| 1429 | 13.4k |         authdata->sigcount = be32toh(authdata->sigcount); | 
| 1430 |  |  | 
| 1431 | 13.4k |         if ((authdata->flags & CTAP_AUTHDATA_EXT_DATA) != 0) { | 
| 1432 | 3.21k |                 if (decode_assert_extensions(&buf, &len, authdata_ext) < 0) { | 
| 1433 | 1.67k |                         fido_log_debug("%s: decode_assert_extensions", | 
| 1434 | 1.67k |                             __func__); | 
| 1435 | 1.67k |                         return (-1); | 
| 1436 | 1.67k |                 } | 
| 1437 | 3.21k |         } | 
| 1438 |  |  | 
| 1439 |  |         /* XXX we should probably ensure that len == 0 at this point */ | 
| 1440 |  |  | 
| 1441 | 11.7k |         return (FIDO_OK); | 
| 1442 | 13.4k | } | 
| 1443 |  |  | 
| 1444 |  | static int | 
| 1445 |  | decode_x5c(const cbor_item_t *item, void *arg) | 
| 1446 | 10.5k | { | 
| 1447 | 10.5k |         fido_blob_array_t *x5c = arg; | 
| 1448 | 10.5k |         fido_blob_t *list_ptr = NULL; | 
| 1449 | 10.5k |         fido_blob_t x5c_blob; | 
| 1450 |  |  | 
| 1451 | 10.5k |         memset(&x5c_blob, 0, sizeof(x5c_blob)); | 
| 1452 |  |  | 
| 1453 | 10.5k |         if (fido_blob_decode(item, &x5c_blob) < 0) { | 
| 1454 | 80 |                 fido_log_debug("%s: fido_blob_decode", __func__); | 
| 1455 | 80 |                 return (-1); | 
| 1456 | 80 |         } | 
| 1457 |  |  | 
| 1458 | 10.4k |         if (x5c->len == SIZE_MAX) { | 
| 1459 | 0 |                 fido_blob_reset(&x5c_blob); | 
| 1460 | 0 |                 return (-1); | 
| 1461 | 0 |         } | 
| 1462 |  |  | 
| 1463 | 10.4k |         if ((list_ptr = recallocarray(x5c->ptr, x5c->len, | 
| 1464 | 10.4k |             x5c->len + 1, sizeof(x5c_blob))) == NULL) { | 
| 1465 | 39 |                 fido_blob_reset(&x5c_blob); | 
| 1466 | 39 |                 return (-1); | 
| 1467 | 39 |         } | 
| 1468 |  |  | 
| 1469 | 10.4k |         list_ptr[x5c->len++] = x5c_blob; | 
| 1470 | 10.4k |         x5c->ptr = list_ptr; | 
| 1471 |  |  | 
| 1472 | 10.4k |         return (0); | 
| 1473 | 10.4k | } | 
| 1474 |  |  | 
| 1475 |  | static int | 
| 1476 |  | decode_x5c_array(const cbor_item_t *item, fido_blob_array_t *arr) | 
| 1477 | 9.83k | { | 
| 1478 | 9.83k |         if (arr->len) { | 
| 1479 | 0 |                 fido_log_debug("%s: dup", __func__); | 
| 1480 | 0 |                 return (-1); | 
| 1481 | 0 |         } | 
| 1482 | 9.83k |         if (cbor_isa_array(item) == false || | 
| 1483 | 9.83k |             cbor_array_is_definite(item) == false) { | 
| 1484 | 30 |                 fido_log_debug("%s: cbor", __func__); | 
| 1485 | 30 |                 return (-1); | 
| 1486 | 30 |         } | 
| 1487 | 9.80k |         return (cbor_array_iter(item, arr, decode_x5c)); | 
| 1488 | 9.83k | } | 
| 1489 |  |  | 
| 1490 |  | static int | 
| 1491 |  | decode_attstmt_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg) | 
| 1492 | 49.1k | { | 
| 1493 | 49.1k |         fido_attstmt_t  *attstmt = arg; | 
| 1494 | 49.1k |         char            *name = NULL; | 
| 1495 | 49.1k |         int              ok = -1; | 
| 1496 |  |  | 
| 1497 | 49.1k |         if (cbor_string_copy(key, &name) < 0) { | 
| 1498 | 866 |                 fido_log_debug("%s: cbor type", __func__); | 
| 1499 | 866 |                 ok = 0; /* ignore */ | 
| 1500 | 866 |                 goto out; | 
| 1501 | 866 |         } | 
| 1502 |  |  | 
| 1503 | 48.3k |         if (!strcmp(name, "alg")) { | 
| 1504 | 13.8k |                 if (cbor_isa_negint(val) == false || | 
| 1505 | 13.8k |                     cbor_get_int(val) > UINT16_MAX) { | 
| 1506 | 99 |                         fido_log_debug("%s: alg", __func__); | 
| 1507 | 99 |                         goto out; | 
| 1508 | 99 |                 } | 
| 1509 | 13.7k |                 attstmt->alg = -(int)cbor_get_int(val) - 1; | 
| 1510 | 13.7k |                 if (attstmt->alg != COSE_ES256 && attstmt->alg != COSE_ES384 && | 
| 1511 | 13.7k |                     attstmt->alg != COSE_RS256 && attstmt->alg != COSE_EDDSA && | 
| 1512 | 13.7k |                     attstmt->alg != COSE_RS1) { | 
| 1513 | 149 |                         fido_log_debug("%s: unsupported attstmt->alg=%d", | 
| 1514 | 149 |                             __func__, attstmt->alg); | 
| 1515 | 149 |                         goto out; | 
| 1516 | 149 |                 } | 
| 1517 | 34.4k |         } else if (!strcmp(name, "sig")) { | 
| 1518 | 13.2k |                 if (fido_blob_decode(val, &attstmt->sig) < 0) { | 
| 1519 | 47 |                         fido_log_debug("%s: sig", __func__); | 
| 1520 | 47 |                         goto out; | 
| 1521 | 47 |                 } | 
| 1522 | 21.1k |         } else if (!strcmp(name, "x5c")) { | 
| 1523 | 9.83k |                 if (decode_x5c_array(val, &attstmt->x5c)) { | 
| 1524 | 175 |                         fido_log_debug("%s: x5c", __func__); | 
| 1525 | 175 |                         goto out; | 
| 1526 | 175 |                 } | 
| 1527 | 11.3k |         } else if (!strcmp(name, "certInfo")) { | 
| 1528 | 2.30k |                 if (fido_blob_decode(val, &attstmt->certinfo) < 0) { | 
| 1529 | 7 |                         fido_log_debug("%s: certinfo", __func__); | 
| 1530 | 7 |                         goto out; | 
| 1531 | 7 |                 } | 
| 1532 | 9.06k |         } else if (!strcmp(name, "pubArea")) { | 
| 1533 | 2.33k |                 if (fido_blob_decode(val, &attstmt->pubarea) < 0) { | 
| 1534 | 7 |                         fido_log_debug("%s: pubarea", __func__); | 
| 1535 | 7 |                         goto out; | 
| 1536 | 7 |                 } | 
| 1537 | 2.33k |         } | 
| 1538 |  |  | 
| 1539 | 47.8k |         ok = 0; | 
| 1540 | 49.1k | out: | 
| 1541 | 49.1k |         free(name); | 
| 1542 |  |  | 
| 1543 | 49.1k |         return (ok); | 
| 1544 | 47.8k | } | 
| 1545 |  |  | 
| 1546 |  | int | 
| 1547 |  | cbor_decode_attstmt(const cbor_item_t *item, fido_attstmt_t *attstmt) | 
| 1548 | 14.7k | { | 
| 1549 | 14.7k |         size_t alloc_len; | 
| 1550 |  |  | 
| 1551 | 14.7k |         if (cbor_isa_map(item) == false || | 
| 1552 | 14.7k |             cbor_map_is_definite(item) == false || | 
| 1553 | 14.7k |             cbor_map_iter(item, attstmt, decode_attstmt_entry) < 0) { | 
| 1554 | 894 |                 fido_log_debug("%s: cbor type", __func__); | 
| 1555 | 894 |                 return (-1); | 
| 1556 | 894 |         } | 
| 1557 |  |  | 
| 1558 | 13.8k |         if (attstmt->cbor.ptr != NULL || | 
| 1559 | 13.8k |             (attstmt->cbor.len = cbor_serialize_alloc(item, | 
| 1560 | 13.8k |             &attstmt->cbor.ptr, &alloc_len)) == 0) { | 
| 1561 | 95 |                 fido_log_debug("%s: cbor_serialize_alloc", __func__); | 
| 1562 | 95 |                 return (-1); | 
| 1563 | 95 |         } | 
| 1564 |  |  | 
| 1565 | 13.7k |         return (0); | 
| 1566 | 13.8k | } | 
| 1567 |  |  | 
| 1568 |  | int | 
| 1569 |  | cbor_decode_uint64(const cbor_item_t *item, uint64_t *n) | 
| 1570 | 345k | { | 
| 1571 | 345k |         if (cbor_isa_uint(item) == false) { | 
| 1572 | 441 |                 fido_log_debug("%s: cbor type", __func__); | 
| 1573 | 441 |                 return (-1); | 
| 1574 | 441 |         } | 
| 1575 |  |  | 
| 1576 | 345k |         *n = cbor_get_int(item); | 
| 1577 |  |  | 
| 1578 | 345k |         return (0); | 
| 1579 | 345k | } | 
| 1580 |  |  | 
| 1581 |  | static int | 
| 1582 |  | decode_cred_id_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg) | 
| 1583 | 19.4k | { | 
| 1584 | 19.4k |         fido_blob_t     *id = arg; | 
| 1585 | 19.4k |         char            *name = NULL; | 
| 1586 | 19.4k |         int              ok = -1; | 
| 1587 |  |  | 
| 1588 | 19.4k |         if (cbor_string_copy(key, &name) < 0) { | 
| 1589 | 1.87k |                 fido_log_debug("%s: cbor type", __func__); | 
| 1590 | 1.87k |                 ok = 0; /* ignore */ | 
| 1591 | 1.87k |                 goto out; | 
| 1592 | 1.87k |         } | 
| 1593 |  |  | 
| 1594 | 17.6k |         if (!strcmp(name, "id")) | 
| 1595 | 6.37k |                 if (fido_blob_decode(val, id) < 0) { | 
| 1596 | 17 |                         fido_log_debug("%s: cbor_bytestring_copy", __func__); | 
| 1597 | 17 |                         goto out; | 
| 1598 | 17 |                 } | 
| 1599 |  |  | 
| 1600 | 17.5k |         ok = 0; | 
| 1601 | 19.4k | out: | 
| 1602 | 19.4k |         free(name); | 
| 1603 |  |  | 
| 1604 | 19.4k |         return (ok); | 
| 1605 | 17.5k | } | 
| 1606 |  |  | 
| 1607 |  | int | 
| 1608 |  | cbor_decode_cred_id(const cbor_item_t *item, fido_blob_t *id) | 
| 1609 | 9.26k | { | 
| 1610 | 9.26k |         if (cbor_isa_map(item) == false || | 
| 1611 | 9.26k |             cbor_map_is_definite(item) == false || | 
| 1612 | 9.26k |             cbor_map_iter(item, id, decode_cred_id_entry) < 0) { | 
| 1613 | 140 |                 fido_log_debug("%s: cbor type", __func__); | 
| 1614 | 140 |                 return (-1); | 
| 1615 | 140 |         } | 
| 1616 |  |  | 
| 1617 | 9.12k |         return (0); | 
| 1618 | 9.26k | } | 
| 1619 |  |  | 
| 1620 |  | static int | 
| 1621 |  | decode_user_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg) | 
| 1622 | 22.8k | { | 
| 1623 | 22.8k |         fido_user_t     *user = arg; | 
| 1624 | 22.8k |         char            *name = NULL; | 
| 1625 | 22.8k |         int              ok = -1; | 
| 1626 |  |  | 
| 1627 | 22.8k |         if (cbor_string_copy(key, &name) < 0) { | 
| 1628 | 436 |                 fido_log_debug("%s: cbor type", __func__); | 
| 1629 | 436 |                 ok = 0; /* ignore */ | 
| 1630 | 436 |                 goto out; | 
| 1631 | 436 |         } | 
| 1632 |  |  | 
| 1633 | 22.3k |         if (!strcmp(name, "icon")) { | 
| 1634 | 146 |                 if (cbor_string_copy(val, &user->icon) < 0) { | 
| 1635 | 9 |                         fido_log_debug("%s: icon", __func__); | 
| 1636 | 9 |                         goto out; | 
| 1637 | 9 |                 } | 
| 1638 | 22.2k |         } else if (!strcmp(name, "name")) { | 
| 1639 | 2.71k |                 if (cbor_string_copy(val, &user->name) < 0) { | 
| 1640 | 9 |                         fido_log_debug("%s: name", __func__); | 
| 1641 | 9 |                         goto out; | 
| 1642 | 9 |                 } | 
| 1643 | 19.5k |         } else if (!strcmp(name, "displayName")) { | 
| 1644 | 1.35k |                 if (cbor_string_copy(val, &user->display_name) < 0) { | 
| 1645 | 3 |                         fido_log_debug("%s: display_name", __func__); | 
| 1646 | 3 |                         goto out; | 
| 1647 | 3 |                 } | 
| 1648 | 18.1k |         } else if (!strcmp(name, "id")) { | 
| 1649 | 5.98k |                 if (fido_blob_decode(val, &user->id) < 0) { | 
| 1650 | 10 |                         fido_log_debug("%s: id", __func__); | 
| 1651 | 10 |                         goto out; | 
| 1652 | 10 |                 } | 
| 1653 | 5.98k |         } | 
| 1654 |  |  | 
| 1655 | 22.3k |         ok = 0; | 
| 1656 | 22.8k | out: | 
| 1657 | 22.8k |         free(name); | 
| 1658 |  |  | 
| 1659 | 22.8k |         return (ok); | 
| 1660 | 22.3k | } | 
| 1661 |  |  | 
| 1662 |  | int | 
| 1663 |  | cbor_decode_user(const cbor_item_t *item, fido_user_t *user) | 
| 1664 | 8.72k | { | 
| 1665 | 8.72k |         if (cbor_isa_map(item) == false || | 
| 1666 | 8.72k |             cbor_map_is_definite(item) == false || | 
| 1667 | 8.72k |             cbor_map_iter(item, user, decode_user_entry) < 0) { | 
| 1668 | 201 |                 fido_log_debug("%s: cbor type", __func__); | 
| 1669 | 201 |                 return (-1); | 
| 1670 | 201 |         } | 
| 1671 |  |  | 
| 1672 | 8.52k |         return (0); | 
| 1673 | 8.72k | } | 
| 1674 |  |  | 
| 1675 |  | static int | 
| 1676 |  | decode_rp_entity_entry(const cbor_item_t *key, const cbor_item_t *val, | 
| 1677 |  |     void *arg) | 
| 1678 | 2.92k | { | 
| 1679 | 2.92k |         fido_rp_t       *rp = arg; | 
| 1680 | 2.92k |         char            *name = NULL; | 
| 1681 | 2.92k |         int              ok = -1; | 
| 1682 |  |  | 
| 1683 | 2.92k |         if (cbor_string_copy(key, &name) < 0) { | 
| 1684 | 264 |                 fido_log_debug("%s: cbor type", __func__); | 
| 1685 | 264 |                 ok = 0; /* ignore */ | 
| 1686 | 264 |                 goto out; | 
| 1687 | 264 |         } | 
| 1688 |  |  | 
| 1689 | 2.66k |         if (!strcmp(name, "id")) { | 
| 1690 | 234 |                 if (cbor_string_copy(val, &rp->id) < 0) { | 
| 1691 | 13 |                         fido_log_debug("%s: id", __func__); | 
| 1692 | 13 |                         goto out; | 
| 1693 | 13 |                 } | 
| 1694 | 2.42k |         } else if (!strcmp(name, "name")) { | 
| 1695 | 7 |                 if (cbor_string_copy(val, &rp->name) < 0) { | 
| 1696 | 3 |                         fido_log_debug("%s: name", __func__); | 
| 1697 | 3 |                         goto out; | 
| 1698 | 3 |                 } | 
| 1699 | 7 |         } | 
| 1700 |  |  | 
| 1701 | 2.64k |         ok = 0; | 
| 1702 | 2.92k | out: | 
| 1703 | 2.92k |         free(name); | 
| 1704 |  |  | 
| 1705 | 2.92k |         return (ok); | 
| 1706 | 2.64k | } | 
| 1707 |  |  | 
| 1708 |  | int | 
| 1709 |  | cbor_decode_rp_entity(const cbor_item_t *item, fido_rp_t *rp) | 
| 1710 | 2.83k | { | 
| 1711 | 2.83k |         if (cbor_isa_map(item) == false || | 
| 1712 | 2.83k |             cbor_map_is_definite(item) == false || | 
| 1713 | 2.83k |             cbor_map_iter(item, rp, decode_rp_entity_entry) < 0) { | 
| 1714 | 84 |                 fido_log_debug("%s: cbor type", __func__); | 
| 1715 | 84 |                 return (-1); | 
| 1716 | 84 |         } | 
| 1717 |  |  | 
| 1718 | 2.75k |         return (0); | 
| 1719 | 2.83k | } | 
| 1720 |  |  | 
| 1721 |  | int | 
| 1722 |  | cbor_decode_bool(const cbor_item_t *item, bool *v) | 
| 1723 | 532k | { | 
| 1724 | 532k |         if (cbor_isa_float_ctrl(item) == false || | 
| 1725 | 532k |             cbor_float_get_width(item) != CBOR_FLOAT_0 || | 
| 1726 | 532k |             cbor_is_bool(item) == false) { | 
| 1727 | 33.1k |                 fido_log_debug("%s: cbor type", __func__); | 
| 1728 | 33.1k |                 return (-1); | 
| 1729 | 33.1k |         } | 
| 1730 |  |  | 
| 1731 | 499k |         if (v != NULL) | 
| 1732 | 6.19k |                 *v = cbor_ctrl_value(item) == CBOR_CTRL_TRUE; | 
| 1733 |  |  | 
| 1734 | 499k |         return (0); | 
| 1735 | 532k | } | 
| 1736 |  |  | 
| 1737 |  | cbor_item_t * | 
| 1738 |  | cbor_build_uint(const uint64_t value) | 
| 1739 | 38.8k | { | 
| 1740 | 38.8k |         if (value <= UINT8_MAX) | 
| 1741 | 24.3k |                 return cbor_build_uint8((uint8_t)value); | 
| 1742 | 14.5k |         else if (value <= UINT16_MAX) | 
| 1743 | 11.5k |                 return cbor_build_uint16((uint16_t)value); | 
| 1744 | 2.95k |         else if (value <= UINT32_MAX) | 
| 1745 | 2.95k |                 return cbor_build_uint32((uint32_t)value); | 
| 1746 |  |  | 
| 1747 | 0 |         return cbor_build_uint64(value); | 
| 1748 | 38.8k | } | 
| 1749 |  |  | 
| 1750 |  | int | 
| 1751 |  | cbor_array_append(cbor_item_t **array, cbor_item_t *item) | 
| 1752 | 1.87k | { | 
| 1753 | 1.87k |         cbor_item_t **v, *ret; | 
| 1754 | 1.87k |         size_t n; | 
| 1755 |  |  | 
| 1756 | 1.87k |         if ((v = cbor_array_handle(*array)) == NULL || | 
| 1757 | 1.87k |             (n = cbor_array_size(*array)) == SIZE_MAX || | 
| 1758 | 1.87k |             (ret = cbor_new_definite_array(n + 1)) == NULL) | 
| 1759 | 26 |                 return -1; | 
| 1760 | 2.68k |         for (size_t i = 0; i < n; i++) { | 
| 1761 | 859 |                 if (cbor_array_push(ret, v[i]) == 0) { | 
| 1762 | 24 |                         cbor_decref(&ret); | 
| 1763 | 24 |                         return -1; | 
| 1764 | 24 |                 } | 
| 1765 | 859 |         } | 
| 1766 | 1.82k |         if (cbor_array_push(ret, item) == 0) { | 
| 1767 | 10 |                 cbor_decref(&ret); | 
| 1768 | 10 |                 return -1; | 
| 1769 | 10 |         } | 
| 1770 | 1.81k |         cbor_decref(array); | 
| 1771 | 1.81k |         *array = ret; | 
| 1772 |  |  | 
| 1773 | 1.81k |         return 0; | 
| 1774 | 1.82k | } | 
| 1775 |  |  | 
| 1776 |  | int | 
| 1777 |  | cbor_array_drop(cbor_item_t **array, size_t idx) | 
| 1778 | 925 | { | 
| 1779 | 925 |         cbor_item_t **v, *ret; | 
| 1780 | 925 |         size_t n; | 
| 1781 |  |  | 
| 1782 | 925 |         if ((v = cbor_array_handle(*array)) == NULL || | 
| 1783 | 925 |             (n = cbor_array_size(*array)) == 0 || idx >= n || | 
| 1784 | 925 |             (ret = cbor_new_definite_array(n - 1)) == NULL) | 
| 1785 | 7 |                 return -1; | 
| 1786 | 1.93k |         for (size_t i = 0; i < n; i++) { | 
| 1787 | 1.02k |                 if (i != idx && cbor_array_push(ret, v[i]) == 0) { | 
| 1788 | 16 |                         cbor_decref(&ret); | 
| 1789 | 16 |                         return -1; | 
| 1790 | 16 |                 } | 
| 1791 | 1.02k |         } | 
| 1792 | 902 |         cbor_decref(array); | 
| 1793 | 902 |         *array = ret; | 
| 1794 |  |  | 
| 1795 | 902 |         return 0; | 
| 1796 | 918 | } |