jcs's openbsd hax
openbsd
at jcs 512 lines 11 kB view raw
1/* 2 * Copyright (c) 2018-2021 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 */ 6 7#include "fido.h" 8 9static int 10decode_string(const cbor_item_t *item, void *arg) 11{ 12 fido_str_array_t *a = arg; 13 const size_t i = a->len; 14 15 /* keep ptr[x] and len consistent */ 16 if (cbor_string_copy(item, &a->ptr[i]) < 0) { 17 fido_log_debug("%s: cbor_string_copy", __func__); 18 return (-1); 19 } 20 21 a->len++; 22 23 return (0); 24} 25 26static int 27decode_string_array(const cbor_item_t *item, fido_str_array_t *v) 28{ 29 v->ptr = NULL; 30 v->len = 0; 31 32 if (cbor_isa_array(item) == false || 33 cbor_array_is_definite(item) == false) { 34 fido_log_debug("%s: cbor type", __func__); 35 return (-1); 36 } 37 38 v->ptr = calloc(cbor_array_size(item), sizeof(char *)); 39 if (v->ptr == NULL) 40 return (-1); 41 42 if (cbor_array_iter(item, v, decode_string) < 0) { 43 fido_log_debug("%s: decode_string", __func__); 44 return (-1); 45 } 46 47 return (0); 48} 49 50static int 51decode_aaguid(const cbor_item_t *item, unsigned char *aaguid, size_t aaguid_len) 52{ 53 if (cbor_isa_bytestring(item) == false || 54 cbor_bytestring_is_definite(item) == false || 55 cbor_bytestring_length(item) != aaguid_len) { 56 fido_log_debug("%s: cbor type", __func__); 57 return (-1); 58 } 59 60 memcpy(aaguid, cbor_bytestring_handle(item), aaguid_len); 61 62 return (0); 63} 64 65static int 66decode_option(const cbor_item_t *key, const cbor_item_t *val, void *arg) 67{ 68 fido_opt_array_t *o = arg; 69 const size_t i = o->len; 70 71 if (cbor_isa_float_ctrl(val) == false || 72 cbor_float_get_width(val) != CBOR_FLOAT_0 || 73 cbor_is_bool(val) == false) { 74 fido_log_debug("%s: cbor type", __func__); 75 return (0); /* ignore */ 76 } 77 78 if (cbor_string_copy(key, &o->name[i]) < 0) { 79 fido_log_debug("%s: cbor_string_copy", __func__); 80 return (0); /* ignore */ 81 } 82 83 /* keep name/value and len consistent */ 84 o->value[i] = cbor_ctrl_value(val) == CBOR_CTRL_TRUE; 85 o->len++; 86 87 return (0); 88} 89 90static int 91decode_options(const cbor_item_t *item, fido_opt_array_t *o) 92{ 93 o->name = NULL; 94 o->value = NULL; 95 o->len = 0; 96 97 if (cbor_isa_map(item) == false || 98 cbor_map_is_definite(item) == false) { 99 fido_log_debug("%s: cbor type", __func__); 100 return (-1); 101 } 102 103 o->name = calloc(cbor_map_size(item), sizeof(char *)); 104 o->value = calloc(cbor_map_size(item), sizeof(bool)); 105 if (o->name == NULL || o->value == NULL) 106 return (-1); 107 108 return (cbor_map_iter(item, o, decode_option)); 109} 110 111static int 112decode_protocol(const cbor_item_t *item, void *arg) 113{ 114 fido_byte_array_t *p = arg; 115 const size_t i = p->len; 116 117 if (cbor_isa_uint(item) == false || 118 cbor_int_get_width(item) != CBOR_INT_8) { 119 fido_log_debug("%s: cbor type", __func__); 120 return (-1); 121 } 122 123 /* keep ptr[x] and len consistent */ 124 p->ptr[i] = cbor_get_uint8(item); 125 p->len++; 126 127 return (0); 128} 129 130static int 131decode_protocols(const cbor_item_t *item, fido_byte_array_t *p) 132{ 133 p->ptr = NULL; 134 p->len = 0; 135 136 if (cbor_isa_array(item) == false || 137 cbor_array_is_definite(item) == false) { 138 fido_log_debug("%s: cbor type", __func__); 139 return (-1); 140 } 141 142 p->ptr = calloc(cbor_array_size(item), sizeof(uint8_t)); 143 if (p->ptr == NULL) 144 return (-1); 145 146 if (cbor_array_iter(item, p, decode_protocol) < 0) { 147 fido_log_debug("%s: decode_protocol", __func__); 148 return (-1); 149 } 150 151 return (0); 152} 153 154static int 155decode_algorithm_entry(const cbor_item_t *key, const cbor_item_t *val, 156 void *arg) 157{ 158 fido_algo_t *alg = arg; 159 char *name = NULL; 160 int ok = -1; 161 162 if (cbor_string_copy(key, &name) < 0) { 163 fido_log_debug("%s: cbor type", __func__); 164 ok = 0; /* ignore */ 165 goto out; 166 } 167 168 if (!strcmp(name, "alg")) { 169 if (cbor_isa_negint(val) == false || 170 cbor_get_int(val) > INT_MAX || alg->cose != 0) { 171 fido_log_debug("%s: alg", __func__); 172 goto out; 173 } 174 alg->cose = -(int)cbor_get_int(val) - 1; 175 } else if (!strcmp(name, "type")) { 176 if (cbor_string_copy(val, &alg->type) < 0) { 177 fido_log_debug("%s: type", __func__); 178 goto out; 179 } 180 } 181 182 ok = 0; 183out: 184 free(name); 185 186 return (ok); 187} 188 189static int 190decode_algorithm(const cbor_item_t *item, void *arg) 191{ 192 fido_algo_array_t *aa = arg; 193 const size_t i = aa->len; 194 195 if (cbor_isa_map(item) == false || 196 cbor_map_is_definite(item) == false) { 197 fido_log_debug("%s: cbor type", __func__); 198 return (-1); 199 } 200 201 memset(&aa->ptr[i], 0, sizeof(aa->ptr[i])); 202 203 if (cbor_map_iter(item, &aa->ptr[i], decode_algorithm_entry) < 0) { 204 fido_log_debug("%s: decode_algorithm_entry", __func__); 205 fido_algo_free(&aa->ptr[i]); 206 return (-1); 207 } 208 209 /* keep ptr[x] and len consistent */ 210 aa->len++; 211 212 return (0); 213} 214 215static int 216decode_algorithms(const cbor_item_t *item, fido_algo_array_t *aa) 217{ 218 aa->ptr = NULL; 219 aa->len = 0; 220 221 if (cbor_isa_array(item) == false || 222 cbor_array_is_definite(item) == false) { 223 fido_log_debug("%s: cbor type", __func__); 224 return (-1); 225 } 226 227 aa->ptr = calloc(cbor_array_size(item), sizeof(fido_algo_t)); 228 if (aa->ptr == NULL) 229 return (-1); 230 231 if (cbor_array_iter(item, aa, decode_algorithm) < 0) { 232 fido_log_debug("%s: decode_algorithm", __func__); 233 return (-1); 234 } 235 236 return (0); 237} 238 239static int 240parse_reply_element(const cbor_item_t *key, const cbor_item_t *val, void *arg) 241{ 242 fido_cbor_info_t *ci = arg; 243 244 if (cbor_isa_uint(key) == false || 245 cbor_int_get_width(key) != CBOR_INT_8) { 246 fido_log_debug("%s: cbor type", __func__); 247 return (0); /* ignore */ 248 } 249 250 switch (cbor_get_uint8(key)) { 251 case 1: /* versions */ 252 return (decode_string_array(val, &ci->versions)); 253 case 2: /* extensions */ 254 return (decode_string_array(val, &ci->extensions)); 255 case 3: /* aaguid */ 256 return (decode_aaguid(val, ci->aaguid, sizeof(ci->aaguid))); 257 case 4: /* options */ 258 return (decode_options(val, &ci->options)); 259 case 5: /* maxMsgSize */ 260 return (cbor_decode_uint64(val, &ci->maxmsgsiz)); 261 case 6: /* pinProtocols */ 262 return (decode_protocols(val, &ci->protocols)); 263 case 7: /* maxCredentialCountInList */ 264 return (cbor_decode_uint64(val, &ci->maxcredcntlst)); 265 case 8: /* maxCredentialIdLength */ 266 return (cbor_decode_uint64(val, &ci->maxcredidlen)); 267 case 9: /* transports */ 268 return (decode_string_array(val, &ci->transports)); 269 case 10: /* algorithms */ 270 return (decode_algorithms(val, &ci->algorithms)); 271 case 11: /* maxSerializedLargeBlobArray */ 272 return (cbor_decode_uint64(val, &ci->maxlargeblob)); 273 case 14: /* fwVersion */ 274 return (cbor_decode_uint64(val, &ci->fwversion)); 275 case 15: /* maxCredBlobLen */ 276 return (cbor_decode_uint64(val, &ci->maxcredbloblen)); 277 default: /* ignore */ 278 fido_log_debug("%s: cbor type", __func__); 279 return (0); 280 } 281} 282 283static int 284fido_dev_get_cbor_info_tx(fido_dev_t *dev, int *ms) 285{ 286 const unsigned char cbor[] = { CTAP_CBOR_GETINFO }; 287 288 fido_log_debug("%s: dev=%p", __func__, (void *)dev); 289 290 if (fido_tx(dev, CTAP_CMD_CBOR, cbor, sizeof(cbor), ms) < 0) { 291 fido_log_debug("%s: fido_tx", __func__); 292 return (FIDO_ERR_TX); 293 } 294 295 return (FIDO_OK); 296} 297 298static int 299fido_dev_get_cbor_info_rx(fido_dev_t *dev, fido_cbor_info_t *ci, int *ms) 300{ 301 unsigned char reply[FIDO_MAXMSG]; 302 int reply_len; 303 304 fido_log_debug("%s: dev=%p, ci=%p, ms=%d", __func__, (void *)dev, 305 (void *)ci, *ms); 306 307 fido_cbor_info_reset(ci); 308 309 if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), 310 ms)) < 0) { 311 fido_log_debug("%s: fido_rx", __func__); 312 return (FIDO_ERR_RX); 313 } 314 315 return (cbor_parse_reply(reply, (size_t)reply_len, ci, 316 parse_reply_element)); 317} 318 319int 320fido_dev_get_cbor_info_wait(fido_dev_t *dev, fido_cbor_info_t *ci, int *ms) 321{ 322 int r; 323 324#ifdef USE_WINHELLO 325 if (dev->flags & FIDO_DEV_WINHELLO) 326 return (fido_winhello_get_cbor_info(dev, ci)); 327#endif 328 if ((r = fido_dev_get_cbor_info_tx(dev, ms)) != FIDO_OK || 329 (r = fido_dev_get_cbor_info_rx(dev, ci, ms)) != FIDO_OK) 330 return (r); 331 332 return (FIDO_OK); 333} 334 335int 336fido_dev_get_cbor_info(fido_dev_t *dev, fido_cbor_info_t *ci) 337{ 338 int ms = dev->timeout_ms; 339 340 return (fido_dev_get_cbor_info_wait(dev, ci, &ms)); 341} 342 343/* 344 * get/set functions for fido_cbor_info_t; always at the end of the file 345 */ 346 347fido_cbor_info_t * 348fido_cbor_info_new(void) 349{ 350 return (calloc(1, sizeof(fido_cbor_info_t))); 351} 352 353void 354fido_cbor_info_reset(fido_cbor_info_t *ci) 355{ 356 fido_str_array_free(&ci->versions); 357 fido_str_array_free(&ci->extensions); 358 fido_str_array_free(&ci->transports); 359 fido_opt_array_free(&ci->options); 360 fido_byte_array_free(&ci->protocols); 361 fido_algo_array_free(&ci->algorithms); 362} 363 364void 365fido_cbor_info_free(fido_cbor_info_t **ci_p) 366{ 367 fido_cbor_info_t *ci; 368 369 if (ci_p == NULL || (ci = *ci_p) == NULL) 370 return; 371 fido_cbor_info_reset(ci); 372 free(ci); 373 *ci_p = NULL; 374} 375 376char ** 377fido_cbor_info_versions_ptr(const fido_cbor_info_t *ci) 378{ 379 return (ci->versions.ptr); 380} 381 382size_t 383fido_cbor_info_versions_len(const fido_cbor_info_t *ci) 384{ 385 return (ci->versions.len); 386} 387 388char ** 389fido_cbor_info_extensions_ptr(const fido_cbor_info_t *ci) 390{ 391 return (ci->extensions.ptr); 392} 393 394size_t 395fido_cbor_info_extensions_len(const fido_cbor_info_t *ci) 396{ 397 return (ci->extensions.len); 398} 399 400char ** 401fido_cbor_info_transports_ptr(const fido_cbor_info_t *ci) 402{ 403 return (ci->transports.ptr); 404} 405 406size_t 407fido_cbor_info_transports_len(const fido_cbor_info_t *ci) 408{ 409 return (ci->transports.len); 410} 411 412const unsigned char * 413fido_cbor_info_aaguid_ptr(const fido_cbor_info_t *ci) 414{ 415 return (ci->aaguid); 416} 417 418size_t 419fido_cbor_info_aaguid_len(const fido_cbor_info_t *ci) 420{ 421 return (sizeof(ci->aaguid)); 422} 423 424char ** 425fido_cbor_info_options_name_ptr(const fido_cbor_info_t *ci) 426{ 427 return (ci->options.name); 428} 429 430const bool * 431fido_cbor_info_options_value_ptr(const fido_cbor_info_t *ci) 432{ 433 return (ci->options.value); 434} 435 436size_t 437fido_cbor_info_options_len(const fido_cbor_info_t *ci) 438{ 439 return (ci->options.len); 440} 441 442uint64_t 443fido_cbor_info_maxcredbloblen(const fido_cbor_info_t *ci) 444{ 445 return (ci->maxcredbloblen); 446} 447 448uint64_t 449fido_cbor_info_maxmsgsiz(const fido_cbor_info_t *ci) 450{ 451 return (ci->maxmsgsiz); 452} 453 454uint64_t 455fido_cbor_info_maxcredcntlst(const fido_cbor_info_t *ci) 456{ 457 return (ci->maxcredcntlst); 458} 459 460uint64_t 461fido_cbor_info_maxcredidlen(const fido_cbor_info_t *ci) 462{ 463 return (ci->maxcredidlen); 464} 465 466uint64_t 467fido_cbor_info_maxlargeblob(const fido_cbor_info_t *ci) 468{ 469 return (ci->maxlargeblob); 470} 471 472uint64_t 473fido_cbor_info_fwversion(const fido_cbor_info_t *ci) 474{ 475 return (ci->fwversion); 476} 477 478const uint8_t * 479fido_cbor_info_protocols_ptr(const fido_cbor_info_t *ci) 480{ 481 return (ci->protocols.ptr); 482} 483 484size_t 485fido_cbor_info_protocols_len(const fido_cbor_info_t *ci) 486{ 487 return (ci->protocols.len); 488} 489 490size_t 491fido_cbor_info_algorithm_count(const fido_cbor_info_t *ci) 492{ 493 return (ci->algorithms.len); 494} 495 496const char * 497fido_cbor_info_algorithm_type(const fido_cbor_info_t *ci, size_t idx) 498{ 499 if (idx >= ci->algorithms.len) 500 return (NULL); 501 502 return (ci->algorithms.ptr[idx].type); 503} 504 505int 506fido_cbor_info_algorithm_cose(const fido_cbor_info_t *ci, size_t idx) 507{ 508 if (idx >= ci->algorithms.len) 509 return (0); 510 511 return (ci->algorithms.ptr[idx].cose); 512}