1 /*
2 * Copyright (c) 2014-2020 Yubico AB
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following
14 * disclaimer in the documentation and/or other materials provided
15 * with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 */
30
31 #include <stdlib.h>
32 #include <string.h>
33 #include <stdio.h>
34 #include <stdint.h>
35 #include <ctype.h>
36 #include <time.h>
37
38 #include "internal.h"
39 #include "ykpiv.h"
40
41 #define MAX(a,b) (a) > (b) ? (a) : (b)
42 #define MIN(a,b) (a) < (b) ? (a) : (b)
43
44 /*
45 * Format defined in SP-800-73-4, Appendix A, Table 9
46 *
47 * FASC-N containing S9999F9999F999999F0F1F0000000000300001E encoded in
48 * 4-bit BCD with 1 bit parity. run through the tools/fasc.pl script to get
49 * bytes. This CHUID has an expiry of 2030-01-01.
50 *
51 * Defined fields:
52 * - 0x30: FASC-N (hard-coded)
53 * - 0x34: Card UUID / GUID (settable)
54 * - 0x35: Exp. Date (hard-coded)
55 * - 0x3e: Signature (hard-coded, empty)
56 * - 0xfe: Error Detection Code (hard-coded)
57 */
58 const uint8_t CHUID_TMPL[] = {
59 0x30, 0x19, 0xd4, 0xe7, 0x39, 0xda, 0x73, 0x9c, 0xed, 0x39, 0xce, 0x73, 0x9d,
60 0x83, 0x68, 0x58, 0x21, 0x08, 0x42, 0x10, 0x84, 0x21, 0xc8, 0x42, 0x10, 0xc3,
61 0xeb, 0x34, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
62 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0x08, 0x32, 0x30, 0x33, 0x30, 0x30,
63 0x31, 0x30, 0x31, 0x3e, 0x00, 0xfe, 0x00,
64 };
65 #define CHUID_GUID_OFFS 29
66 #define TAG_CHUID_UUID 0x34
67
68 // f0: Card Identifier
69 // - 0xa000000116 == GSC-IS RID
70 // - 0xff == Manufacturer ID (dummy)
71 // - 0x02 == Card type (javaCard)
72 // - next 14 bytes: card ID
73 const uint8_t CCC_TMPL[] = {
74 0xf0, 0x15, 0xa0, 0x00, 0x00, 0x01, 0x16, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00,
75 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x01, 0x21,
76 0xf2, 0x01, 0x21, 0xf3, 0x00, 0xf4, 0x01, 0x00, 0xf5, 0x01, 0x10, 0xf6, 0x00,
77 0xf7, 0x00, 0xfa, 0x00, 0xfb, 0x00, 0xfc, 0x00, 0xfd, 0x00, 0xfe, 0x00
78 };
79 #define CCC_ID_OFFS 9
80
81 static ykpiv_rc _read_certificate(ykpiv_state *state, uint8_t slot, uint8_t *buf, size_t *buf_len);
82 static ykpiv_rc _write_certificate(ykpiv_state *state, uint8_t slot, uint8_t *data, size_t data_len, uint8_t certinfo);
83
84 static ykpiv_rc _read_metadata(ykpiv_state *state, uint8_t tag, uint8_t* data, size_t* pcb_data);
85 static ykpiv_rc _write_metadata(ykpiv_state *state, uint8_t tag, uint8_t *data, size_t cb_data);
86 static ykpiv_rc _get_metadata_item(uint8_t *data, size_t cb_data, uint8_t tag, uint8_t **pp_item, size_t *pcb_item);
87 static ykpiv_rc _set_metadata_item(uint8_t *data, size_t *pcb_data, size_t cb_data_max, uint8_t tag, uint8_t *p_item, size_t cb_item);
88
_obj_size_max(ykpiv_state * state)89 static size_t _obj_size_max(ykpiv_state *state) {
90 return (state && state->model == DEVTYPE_NEOr3) ? CB_OBJ_MAX_NEO : CB_OBJ_MAX;
91 }
92
93 /*
94 ** YKPIV Utility API - aggregate functions and slightly nicer interface
95 */
96
ykpiv_util_get_cardid(ykpiv_state * state,ykpiv_cardid * cardid)97 ykpiv_rc ykpiv_util_get_cardid(ykpiv_state *state, ykpiv_cardid *cardid) {
98 ykpiv_rc res = YKPIV_OK;
99 uint8_t buf[CB_OBJ_MAX] = {0};
100 unsigned long len = sizeof(buf);
101 uint8_t *p_temp = NULL;
102 size_t offs, cb_temp = 0;
103 uint8_t tag = 0;
104
105 if (!cardid) return YKPIV_GENERIC_ERROR;
106
107 if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res;
108 if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
109
110 if ((res = _ykpiv_fetch_object(state, YKPIV_OBJ_CHUID, buf, &len)) == YKPIV_OK) {
111 p_temp = buf;
112
113 while (p_temp < (buf + len)) {
114 tag = *p_temp++;
115
116 offs = _ykpiv_get_length(p_temp, buf + len, &cb_temp);
117 if (!offs) {
118 res = YKPIV_PARSE_ERROR;
119 goto Cleanup;
120 }
121
122 p_temp += offs;
123
124 if (tag == TAG_CHUID_UUID) {
125 /* found card uuid */
126 if (cb_temp < YKPIV_CARDID_SIZE || p_temp + YKPIV_CARDID_SIZE > buf + len) {
127 res = YKPIV_SIZE_ERROR;
128 goto Cleanup;
129 }
130
131 res = YKPIV_OK;
132 memcpy(cardid->data, p_temp, YKPIV_CARDID_SIZE);
133 goto Cleanup;
134 }
135
136 p_temp += cb_temp;
137 }
138
139 /* not found, not malformed */
140 res = YKPIV_GENERIC_ERROR;
141 }
142
143 Cleanup:
144
145 _ykpiv_end_transaction(state);
146 return res;
147 }
148
ykpiv_util_set_cardid(ykpiv_state * state,const ykpiv_cardid * cardid)149 ykpiv_rc ykpiv_util_set_cardid(ykpiv_state *state, const ykpiv_cardid *cardid) {
150 ykpiv_rc res = YKPIV_OK;
151 uint8_t id[YKPIV_CARDID_SIZE] = {0};
152 uint8_t buf[sizeof(CHUID_TMPL)] = {0};
153 size_t len = 0;
154
155 if (!state) return YKPIV_GENERIC_ERROR;
156
157 if (!cardid) {
158 if (PRNG_OK != _ykpiv_prng_generate(id, sizeof(id))) {
159 return YKPIV_RANDOMNESS_ERROR;
160 }
161 }
162 else {
163 memcpy(id, cardid->data, sizeof(id));
164 }
165
166 if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res;
167 if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
168
169 memcpy(buf, CHUID_TMPL, sizeof(CHUID_TMPL));
170 memcpy(buf + CHUID_GUID_OFFS, id, sizeof(id));
171 len = sizeof(CHUID_TMPL);
172
173 res = _ykpiv_save_object(state, YKPIV_OBJ_CHUID, buf, len);
174
175 Cleanup:
176
177 _ykpiv_end_transaction(state);
178 return res;
179 }
180
ykpiv_util_get_cccid(ykpiv_state * state,ykpiv_cccid * ccc)181 ykpiv_rc ykpiv_util_get_cccid(ykpiv_state *state, ykpiv_cccid *ccc) {
182 ykpiv_rc res = YKPIV_OK;
183 uint8_t buf[CB_OBJ_MAX] = {0};
184 unsigned long len = sizeof(buf);
185
186 if (!ccc) return YKPIV_GENERIC_ERROR;
187
188 if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res;
189 if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
190
191 res = _ykpiv_fetch_object(state, YKPIV_OBJ_CAPABILITY, buf, &len);
192 if (YKPIV_OK == res) {
193 if (len != sizeof(CCC_TMPL)) {
194 res = YKPIV_GENERIC_ERROR;
195 }
196 else {
197 memcpy(ccc->data, buf + CCC_ID_OFFS, YKPIV_CCCID_SIZE);
198 }
199 }
200
201 Cleanup:
202
203 _ykpiv_end_transaction(state);
204 return res;
205 }
206
ykpiv_util_set_cccid(ykpiv_state * state,const ykpiv_cccid * ccc)207 ykpiv_rc ykpiv_util_set_cccid(ykpiv_state *state, const ykpiv_cccid *ccc) {
208 ykpiv_rc res = YKPIV_OK;
209 uint8_t id[YKPIV_CCCID_SIZE] = {0};
210 uint8_t buf[sizeof(CCC_TMPL)] = {0};
211 size_t len = 0;
212
213 if (!state) return YKPIV_GENERIC_ERROR;
214
215 if (!ccc) {
216 if (PRNG_OK != _ykpiv_prng_generate(id, sizeof(id))) {
217 return YKPIV_RANDOMNESS_ERROR;
218 }
219 }
220 else {
221 memcpy(id, ccc->data, sizeof(id));
222 }
223
224 if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res;
225 if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
226
227 len = sizeof(CCC_TMPL);
228 memcpy(buf, CCC_TMPL, len);
229 memcpy(buf + CCC_ID_OFFS, id, YKPIV_CCCID_SIZE);
230 res = _ykpiv_save_object(state, YKPIV_OBJ_CAPABILITY, buf, len);
231
232 Cleanup:
233 _ykpiv_end_transaction(state);
234 return res;
235 }
236
ykpiv_util_devicemodel(ykpiv_state * state)237 ykpiv_devmodel ykpiv_util_devicemodel(ykpiv_state *state) {
238 if (!state || !state->context || (state->context == (SCARDCONTEXT)-1)) {
239 return DEVTYPE_UNKNOWN;
240 }
241 return state->model;
242 }
243
ykpiv_util_list_keys(ykpiv_state * state,uint8_t * key_count,ykpiv_key ** data,size_t * data_len)244 ykpiv_rc ykpiv_util_list_keys(ykpiv_state *state, uint8_t *key_count, ykpiv_key **data, size_t *data_len) {
245 ykpiv_rc res = YKPIV_OK;
246 ykpiv_key *pKey = NULL;
247 uint8_t *pData = NULL;
248 uint8_t *pTemp = NULL;
249 size_t cbData = 0;
250 size_t offset = 0;
251 uint8_t buf[CB_BUF_MAX] = {0};
252 size_t cbBuf = 0;
253 size_t i = 0;
254 size_t cbRealloc = 0;
255
256 const size_t CB_PAGE = 4096;
257
258 const uint8_t SLOTS[] = {
259 YKPIV_KEY_AUTHENTICATION,
260 YKPIV_KEY_SIGNATURE,
261 YKPIV_KEY_KEYMGM,
262 YKPIV_KEY_RETIRED1,
263 YKPIV_KEY_RETIRED2,
264 YKPIV_KEY_RETIRED3,
265 YKPIV_KEY_RETIRED4,
266 YKPIV_KEY_RETIRED5,
267 YKPIV_KEY_RETIRED6,
268 YKPIV_KEY_RETIRED7,
269 YKPIV_KEY_RETIRED8,
270 YKPIV_KEY_RETIRED9,
271 YKPIV_KEY_RETIRED10,
272 YKPIV_KEY_RETIRED11,
273 YKPIV_KEY_RETIRED12,
274 YKPIV_KEY_RETIRED13,
275 YKPIV_KEY_RETIRED14,
276 YKPIV_KEY_RETIRED15,
277 YKPIV_KEY_RETIRED16,
278 YKPIV_KEY_RETIRED17,
279 YKPIV_KEY_RETIRED18,
280 YKPIV_KEY_RETIRED19,
281 YKPIV_KEY_RETIRED20,
282 YKPIV_KEY_CARDAUTH
283 };
284
285 if ((NULL == data) || (NULL == data_len) || (NULL == key_count)) { return YKPIV_GENERIC_ERROR; }
286
287 if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res;
288 if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
289
290 // init return parameters
291 *key_count = 0;
292 *data = NULL;
293 *data_len = 0;
294
295 // allocate initial page of buffer
296 if (NULL == (pData = _ykpiv_alloc(state, CB_PAGE))) {
297 res = YKPIV_MEMORY_ERROR;
298 goto Cleanup;
299 }
300
301 cbData = CB_PAGE;
302
303 for (i = 0; i < sizeof(SLOTS); i++) {
304 cbBuf = sizeof(buf);
305 res = _read_certificate(state, SLOTS[i], buf, &cbBuf);
306
307 if ((res == YKPIV_OK) && (cbBuf > 0)) {
308 // add current slot to result, grow result buffer if necessary
309
310 cbRealloc = (sizeof(ykpiv_key) + cbBuf - 1) > (cbData - offset) ? MAX((sizeof(ykpiv_key) + cbBuf - 1) - (cbData - offset), CB_PAGE) : 0;
311
312 if (0 != cbRealloc) {
313 if (!(pTemp = _ykpiv_realloc(state, pData, cbData + cbRealloc))) {
314 /* realloc failed, pData will be freed in cleanup */
315 res = YKPIV_MEMORY_ERROR;
316 goto Cleanup;
317 }
318 pData = pTemp;
319 pTemp = NULL;
320 }
321
322 cbData += cbRealloc;
323
324 // If ykpiv_key is misaligned or results in padding, this causes problems
325 // in the array we return. If this becomes a problem, we'll probably want
326 // to go with a flat byte array.
327
328 pKey = (ykpiv_key*)(pData + offset);
329
330 pKey->slot = SLOTS[i];
331 pKey->cert_len = (uint16_t)cbBuf;
332 memcpy(pKey->cert, buf, cbBuf);
333
334 offset += sizeof(ykpiv_key) + cbBuf - 1;
335 (*key_count)++;
336 }
337 }
338
339 *data = (ykpiv_key*)pData;
340 pData = NULL;
341
342 if (data_len) {
343 *data_len = offset;
344 }
345
346 res = YKPIV_OK;
347
348 Cleanup:
349
350 if (pData) { _ykpiv_free(state, pData); }
351
352 _ykpiv_end_transaction(state);
353 return res;
354 }
355
ykpiv_util_free(ykpiv_state * state,void * data)356 ykpiv_rc ykpiv_util_free(ykpiv_state *state, void *data) {
357 if (!data) return YKPIV_OK;
358 if (!state || (!(state->allocator.pfn_free))) return YKPIV_GENERIC_ERROR;
359
360 _ykpiv_free(state, data);
361
362 return YKPIV_OK;
363 }
364
ykpiv_util_read_cert(ykpiv_state * state,uint8_t slot,uint8_t ** data,size_t * data_len)365 ykpiv_rc ykpiv_util_read_cert(ykpiv_state *state, uint8_t slot, uint8_t **data, size_t *data_len) {
366 ykpiv_rc res = YKPIV_OK;
367 uint8_t buf[CB_BUF_MAX] = {0};
368 size_t cbBuf = sizeof(buf);
369
370 if ((NULL == data )|| (NULL == data_len)) return YKPIV_GENERIC_ERROR;
371
372 if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res;
373 if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
374
375 *data = 0;
376 *data_len = 0;
377
378 if (YKPIV_OK == (res = _read_certificate(state, slot, buf, &cbBuf))) {
379
380 /* handle those who write empty certificate blobs to PIV objects */
381 if (cbBuf == 0) {
382 *data = NULL;
383 *data_len = 0;
384 goto Cleanup;
385 }
386
387 if (!(*data = _ykpiv_alloc(state, cbBuf))) {
388 res = YKPIV_MEMORY_ERROR;
389 goto Cleanup;
390 }
391
392 memcpy(*data, buf, cbBuf);
393
394 *data_len = cbBuf;
395 }
396
397 Cleanup:
398
399 _ykpiv_end_transaction(state);
400 return res;
401 }
402
ykpiv_util_write_cert(ykpiv_state * state,uint8_t slot,uint8_t * data,size_t data_len,uint8_t certinfo)403 ykpiv_rc ykpiv_util_write_cert(ykpiv_state *state, uint8_t slot, uint8_t *data, size_t data_len, uint8_t certinfo) {
404 ykpiv_rc res = YKPIV_OK;
405
406 if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res;
407 if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
408
409 res = _write_certificate(state, slot, data, data_len, certinfo);
410
411 Cleanup:
412
413 _ykpiv_end_transaction(state);
414 return res;
415 }
416
ykpiv_util_delete_cert(ykpiv_state * state,uint8_t slot)417 ykpiv_rc ykpiv_util_delete_cert(ykpiv_state *state, uint8_t slot) {
418 return ykpiv_util_write_cert(state, slot, NULL, 0, 0);
419 }
420
ykpiv_util_block_puk(ykpiv_state * state)421 ykpiv_rc ykpiv_util_block_puk(ykpiv_state *state) {
422 ykpiv_rc res = YKPIV_OK;
423 uint8_t puk[] = { 0x30, 0x42, 0x41, 0x44, 0x46, 0x30, 0x30, 0x44 };
424 int tries = -1;
425 uint8_t data[CB_BUF_MAX] = {0};
426 size_t cb_data = sizeof(data);
427 uint8_t *p_item = NULL;
428 size_t cb_item = 0;
429 uint8_t flags = 0;
430
431 if (NULL == state) return YKPIV_GENERIC_ERROR;
432
433 if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res;
434 if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
435
436 while (tries != 0) {
437 if (YKPIV_OK == (res = ykpiv_change_puk(state, (const char*)puk, sizeof(puk), (const char*)puk, sizeof(puk), &tries))) {
438 /* did we accidentally choose the correct PUK?, change our puk and try again */
439 puk[0]++;
440 }
441 else {
442 /* depending on the firmware, tries may not be set to zero when the PUK is blocked, */
443 /* instead, the return code will be PIN_LOCKED and tries will be unset */
444 if (YKPIV_PIN_LOCKED == res) {
445 tries = 0;
446 res = YKPIV_OK;
447 }
448 }
449 }
450
451 /* attempt to set the puk blocked flag in admin data */
452
453 if (YKPIV_OK == _read_metadata(state, TAG_ADMIN, data, &cb_data)) {
454 if (YKPIV_OK == _get_metadata_item(data, cb_data, TAG_ADMIN_FLAGS_1, &p_item, &cb_item)) {
455 if (sizeof(flags) == cb_item) {
456 memcpy(&flags, p_item, cb_item);
457 }
458 else {
459 if (state->verbose) { fprintf(stderr, "admin flags exist, but are incorrect size = %lu", (unsigned long)cb_item); }
460 }
461 }
462 }
463
464 flags |= ADMIN_FLAGS_1_PUK_BLOCKED;
465
466 if (YKPIV_OK != _set_metadata_item(data, &cb_data, CB_OBJ_MAX, TAG_ADMIN_FLAGS_1, (uint8_t*)&flags, sizeof(flags))) {
467 if (state->verbose) { fprintf(stderr, "could not set admin flags"); }
468 }
469 else {
470 if (YKPIV_OK != _write_metadata(state, TAG_ADMIN, data, cb_data)) {
471 if (state->verbose) { fprintf(stderr, "could not write admin metadata"); }
472 }
473 }
474
475 Cleanup:
476
477 _ykpiv_end_transaction(state);
478 return res;
479 }
480
ykpiv_util_read_mscmap(ykpiv_state * state,ykpiv_container ** containers,size_t * n_containers)481 ykpiv_rc ykpiv_util_read_mscmap(ykpiv_state *state, ykpiv_container **containers, size_t *n_containers) {
482 ykpiv_rc res = YKPIV_OK;
483 uint8_t buf[CB_BUF_MAX] = {0};
484 unsigned long cbBuf = sizeof(buf);
485 size_t offs, len = 0;
486 uint8_t *ptr = NULL;
487
488 if ((NULL == containers) || (NULL == n_containers)) { res = YKPIV_GENERIC_ERROR; goto Cleanup; }
489 if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res;
490 if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
491
492 *containers = 0;
493 *n_containers = 0;
494
495 if (YKPIV_OK == (res = _ykpiv_fetch_object(state, YKPIV_OBJ_MSCMAP, buf, &cbBuf))) {
496 ptr = buf;
497
498 /* check that object contents are at least large enough to read the header */
499 if (cbBuf < CB_OBJ_TAG_MIN) {
500 res = YKPIV_OK;
501 goto Cleanup;
502 }
503
504 if (*ptr++ == TAG_MSCMAP) {
505 offs = _ykpiv_get_length(ptr, buf + cbBuf, &len);
506 if(!offs) {
507 res = YKPIV_OK;
508 goto Cleanup;
509 }
510 ptr += offs;
511
512 if (NULL == (*containers = _ykpiv_alloc(state, len))) {
513 res = YKPIV_MEMORY_ERROR;
514 goto Cleanup;
515 }
516
517 /* should check if container map isn't corrupt */
518
519 memcpy(*containers, ptr, len);
520 *n_containers = len / sizeof(ykpiv_container);
521 }
522 }
523
524 Cleanup:
525
526 _ykpiv_end_transaction(state);
527 return res;
528 }
529
ykpiv_util_write_mscmap(ykpiv_state * state,ykpiv_container * containers,size_t n_containers)530 ykpiv_rc ykpiv_util_write_mscmap(ykpiv_state *state, ykpiv_container *containers, size_t n_containers) {
531 ykpiv_rc res = YKPIV_OK;
532 uint8_t buf[CB_OBJ_MAX] = {0};
533 size_t offset = 0;
534 size_t req_len = 0;
535 size_t data_len = n_containers * sizeof(ykpiv_container);
536
537 if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res;
538 if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
539
540 // check if data and data_len are zero, this means that
541 // we intend to delete the object
542 if ((NULL == containers) || (0 == n_containers)) {
543
544 // if either containers or n_containers are non-zero, return an error,
545 // that we only delete strictly when both are set properly
546 if ((NULL != containers) || (0 != n_containers)) {
547 res = YKPIV_GENERIC_ERROR;
548 }
549 else {
550 res = _ykpiv_save_object(state, YKPIV_OBJ_MSCMAP, NULL, 0);
551 }
552
553 goto Cleanup;
554 }
555
556 // encode object data for storage
557
558 // calculate the required length of the encoded object
559 req_len = 1 /* data tag */ + (unsigned long)_ykpiv_set_length(buf, data_len) + data_len;
560
561 if (req_len > _obj_size_max(state)) {
562 res = YKPIV_SIZE_ERROR;
563 goto Cleanup;
564 }
565
566 buf[offset++] = TAG_MSCMAP;
567 offset += _ykpiv_set_length(buf + offset, data_len);
568 memcpy(buf + offset, (uint8_t*)containers, data_len);
569 offset += data_len;
570
571 // write onto device
572 res = _ykpiv_save_object(state, YKPIV_OBJ_MSCMAP, buf, offset);
573
574 Cleanup:
575
576 _ykpiv_end_transaction(state);
577 return res;
578 }
579
ykpiv_util_read_msroots(ykpiv_state * state,uint8_t ** data,size_t * data_len)580 ykpiv_rc ykpiv_util_read_msroots(ykpiv_state *state, uint8_t **data, size_t *data_len) {
581 ykpiv_rc res = YKPIV_OK;
582 uint8_t buf[CB_BUF_MAX] = {0};
583 unsigned long cbBuf = sizeof(buf);
584 size_t offs, len = 0;
585 uint8_t *ptr = NULL;
586 int object_id = 0;
587 uint8_t tag = 0;
588 uint8_t *pData = NULL;
589 uint8_t *pTemp = NULL;
590 size_t cbData = 0;
591 size_t cbRealloc = 0;
592 size_t offset = 0;
593
594 if (!data || !data_len) return YKPIV_GENERIC_ERROR;
595
596 if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res;
597 if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
598
599 *data = 0;
600 *data_len = 0;
601
602 // allocate first page
603 cbData = _obj_size_max(state);
604 if (NULL == (pData = _ykpiv_alloc(state, cbData))) { res = YKPIV_MEMORY_ERROR; goto Cleanup; }
605
606 for (object_id = YKPIV_OBJ_MSROOTS1; object_id <= YKPIV_OBJ_MSROOTS5; object_id++) {
607 cbBuf = sizeof(buf);
608
609 if (YKPIV_OK != (res = _ykpiv_fetch_object(state, object_id, buf, &cbBuf))) {
610 goto Cleanup;
611 }
612
613 ptr = buf;
614
615 if (cbBuf < CB_OBJ_TAG_MIN) {
616 res = YKPIV_OK;
617 goto Cleanup;
618 }
619
620 tag = *ptr++;
621
622 if (((TAG_MSROOTS_MID != tag) && (TAG_MSROOTS_END != tag)) ||
623 ((YKPIV_OBJ_MSROOTS5 == object_id) && (TAG_MSROOTS_END != tag))) {
624 // the current object doesn't contain a valid part of a msroots file
625 res = YKPIV_OK; // treat condition as object isn't found
626 goto Cleanup;
627 }
628
629 offs = _ykpiv_get_length(ptr, buf + cbBuf, &len);
630 if(!offs) {
631 res = YKPIV_OK;
632 goto Cleanup;
633 }
634 ptr += offs;
635
636 cbRealloc = len > (cbData - offset) ? len - (cbData - offset) : 0;
637
638 if (0 != cbRealloc) {
639 if (!(pTemp = _ykpiv_realloc(state, pData, cbData + cbRealloc))) {
640 /* realloc failed, pData will be freed in cleanup */
641 res = YKPIV_MEMORY_ERROR;
642 goto Cleanup;
643 }
644 pData = pTemp;
645 pTemp = NULL;
646 }
647
648 cbData += cbRealloc;
649
650 memcpy(pData + offset, ptr, len);
651 offset += len;
652
653 if (TAG_MSROOTS_END == tag) {
654 break;
655 }
656 }
657
658 // return data
659 *data = pData;
660 pData = NULL;
661 *data_len = offset;
662
663 res = YKPIV_OK;
664
665 Cleanup:
666
667 if (pData) { _ykpiv_free(state, pData); }
668
669 _ykpiv_end_transaction(state);
670 return res;
671 }
672
ykpiv_util_write_msroots(ykpiv_state * state,uint8_t * data,size_t data_len)673 ykpiv_rc ykpiv_util_write_msroots(ykpiv_state *state, uint8_t *data, size_t data_len) {
674 ykpiv_rc res = YKPIV_OK;
675 uint8_t buf[CB_OBJ_MAX] = {0};
676 size_t offset = 0;
677 size_t data_offset = 0;
678 size_t data_chunk = 0;
679 size_t n_objs = 0;
680 unsigned int i = 0;
681 size_t cb_obj_max = _obj_size_max(state);
682
683 if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res;
684 if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
685
686 // check if either data and data_len are zero, this means that
687 // we intend to delete the object
688 if ((NULL == data) || (0 == data_len)) {
689
690 // if either data or data_len are non-zero, return an error,
691 // that we only delete strictly when both are set properly
692 if ((NULL != data) || (0 != data_len)) {
693 res = YKPIV_GENERIC_ERROR;
694 }
695 else {
696 // it should be sufficient to just delete the first object, though
697 // to be complete we should erase all of the MSROOTS objects
698 res = _ykpiv_save_object(state, YKPIV_OBJ_MSROOTS1, NULL, 0);
699 }
700
701 goto Cleanup;
702 }
703
704 // calculate number of objects required to store blob
705 n_objs = (data_len / (cb_obj_max - CB_OBJ_TAG_MAX)) + 1;
706
707 // we're allowing 5 objects to be used to span the msroots file
708 if (n_objs > 5) {
709 res = YKPIV_SIZE_ERROR;
710 goto Cleanup;
711 }
712
713 for (i = 0; i < n_objs; i++) {
714 offset = 0;
715 data_chunk = MIN(cb_obj_max - CB_OBJ_TAG_MAX, data_len - data_offset);
716
717 /* encode object data for storage */
718 buf[offset++] = (i == (n_objs - 1)) ? TAG_MSROOTS_END : TAG_MSROOTS_MID;
719 offset += _ykpiv_set_length(buf + offset, data_chunk);
720 memcpy(buf + offset, data + data_offset, data_chunk);
721 offset += data_chunk;
722
723 /* write onto device */
724 res = _ykpiv_save_object(state, (int)(YKPIV_OBJ_MSROOTS1 + i), buf, offset);
725
726 if (YKPIV_OK != res) {
727 goto Cleanup;
728 }
729
730 data_offset += data_chunk;
731 }
732
733 Cleanup:
734
735 _ykpiv_end_transaction(state);
736 return res;
737 }
738
ykpiv_util_generate_key(ykpiv_state * state,uint8_t slot,uint8_t algorithm,uint8_t pin_policy,uint8_t touch_policy,uint8_t ** modulus,size_t * modulus_len,uint8_t ** exp,size_t * exp_len,uint8_t ** point,size_t * point_len)739 ykpiv_rc ykpiv_util_generate_key(ykpiv_state *state, uint8_t slot, uint8_t algorithm, uint8_t pin_policy, uint8_t touch_policy, uint8_t **modulus, size_t *modulus_len, uint8_t **exp, size_t *exp_len, uint8_t **point, size_t *point_len) {
740 ykpiv_rc res = YKPIV_OK;
741 unsigned char in_data[11] = {0};
742 unsigned char *in_ptr = in_data;
743 unsigned char data[1024] = {0};
744 unsigned char templ[] = { 0, YKPIV_INS_GENERATE_ASYMMETRIC, 0, 0 };
745 unsigned long recv_len = sizeof(data);
746 int sw;
747 uint8_t *ptr_modulus = NULL;
748 size_t cb_modulus = 0;
749 uint8_t *ptr_exp = NULL;
750 size_t cb_exp = 0;
751 uint8_t *ptr_point = NULL;
752 size_t cb_point = 0;
753 size_t offs;
754
755 setting_bool_t setting_roca = { 0 };
756 const char sz_setting_roca[] = "Enable_Unsafe_Keygen_ROCA";
757 const char sz_roca_format[] = "YubiKey serial number %u is affected by vulnerability "
758 "CVE-2017-15361 (ROCA) and should be replaced. On-chip key generation %s "
759 "See YSA-2017-01 <https://www.yubico.com/support/security-advisories/ysa-2017-01/> "
760 "for additional information on device replacement and mitigation assistance.\n";
761 const char sz_roca_allow_user[] = "was permitted by an end-user configuration setting, but is not recommended.";
762 const char sz_roca_allow_admin[] = "was permitted by an administrator configuration setting, but is not recommended.";
763 const char sz_roca_block_user[] = "was blocked due to an end-user configuration setting.";
764 const char sz_roca_block_admin[] = "was blocked due to an administrator configuration setting.";
765 const char sz_roca_default[] = "was permitted by default, but is not recommended. "
766 "The default behavior will change in a future Yubico release.";
767
768 if (!state) return YKPIV_ARGUMENT_ERROR;
769
770 if (ykpiv_util_devicemodel(state) == DEVTYPE_YK4 && (algorithm == YKPIV_ALGO_RSA1024 || algorithm == YKPIV_ALGO_RSA2048)) {
771 if ((state->ver.major == 4) && (state->ver.minor < 3 || ((state->ver.minor == 3) && (state->ver.patch < 5)))) {
772 const char *psz_msg = NULL;
773 setting_roca = setting_get_bool(sz_setting_roca, true);
774
775 switch (setting_roca.source) {
776 case SETTING_SOURCE_ADMIN:
777 psz_msg = setting_roca.value ? sz_roca_allow_admin : sz_roca_block_admin;
778 break;
779
780 case SETTING_SOURCE_USER:
781 psz_msg = setting_roca.value ? sz_roca_allow_user : sz_roca_block_user;
782 break;
783
784 default:
785 case SETTING_SOURCE_DEFAULT:
786 psz_msg = sz_roca_default;
787 break;
788 }
789
790 fprintf(stderr, sz_roca_format, state->serial, psz_msg);
791 yc_log_event(1, setting_roca.value ? YC_LOG_LEVEL_WARN : YC_LOG_LEVEL_ERROR, sz_roca_format, state->serial, psz_msg);
792
793 if (!setting_roca.value) {
794 return YKPIV_NOT_SUPPORTED;
795 }
796 }
797 }
798
799 switch (algorithm) {
800 case YKPIV_ALGO_RSA1024:
801 case YKPIV_ALGO_RSA2048:
802 if (!modulus || !modulus_len || !exp || !exp_len) {
803 if (state->verbose) { fprintf(stderr, "Invalid output parameter for RSA algorithm"); }
804 return YKPIV_GENERIC_ERROR;
805 }
806 *modulus = NULL;
807 *modulus_len = 0;
808 *exp = NULL;
809 *exp_len = 0;
810 break;
811
812 case YKPIV_ALGO_ECCP256:
813 case YKPIV_ALGO_ECCP384:
814 if (!point || !point_len) {
815 if (state->verbose) { fprintf(stderr, "Invalid output parameter for ECC algorithm"); }
816 return YKPIV_GENERIC_ERROR;
817 }
818 *point = NULL;
819 *point_len = 0;
820 break;
821
822 default:
823 if (state->verbose) { fprintf(stderr, "Invalid algorithm specified"); }
824 return YKPIV_GENERIC_ERROR;
825 }
826
827 if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res;
828 if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
829
830 templ[3] = slot;
831
832 *in_ptr++ = 0xac;
833 *in_ptr++ = 3;
834 *in_ptr++ = YKPIV_ALGO_TAG;
835 *in_ptr++ = 1;
836 *in_ptr++ = algorithm;
837
838 if (in_data[4] == 0) {
839 res = YKPIV_ALGORITHM_ERROR;
840 if (state->verbose) { fprintf(stderr, "Unexpected algorithm.\n"); }
841 goto Cleanup;
842 }
843
844 if (pin_policy != YKPIV_PINPOLICY_DEFAULT) {
845 in_data[1] += 3;
846 *in_ptr++ = YKPIV_PINPOLICY_TAG;
847 *in_ptr++ = 1;
848 *in_ptr++ = pin_policy;
849 }
850
851 if (touch_policy != YKPIV_TOUCHPOLICY_DEFAULT) {
852 in_data[1] += 3;
853 *in_ptr++ = YKPIV_TOUCHPOLICY_TAG;
854 *in_ptr++ = 1;
855 *in_ptr++ = touch_policy;
856 }
857
858 if (YKPIV_OK != (res = _ykpiv_transfer_data(state, templ, in_data, (long)(in_ptr - in_data), data, &recv_len, &sw))) {
859 if (state->verbose) { fprintf(stderr, "Failed to communicate.\n"); }
860 goto Cleanup;
861 }
862 else if (sw != SW_SUCCESS) {
863 if (state->verbose) { fprintf(stderr, "Failed to generate new key ("); }
864
865 if (sw == SW_ERR_INCORRECT_SLOT) {
866 res = YKPIV_KEY_ERROR;
867 if (state->verbose) { fprintf(stderr, "incorrect slot)\n"); }
868 }
869 else if (sw == SW_ERR_INCORRECT_PARAM) {
870 res = YKPIV_ALGORITHM_ERROR;
871
872 if (state->verbose) {
873 if (pin_policy != YKPIV_PINPOLICY_DEFAULT) {
874 fprintf(stderr, "pin policy not supported?)\n");
875 }
876 else if (touch_policy != YKPIV_TOUCHPOLICY_DEFAULT) {
877 fprintf(stderr, "touch policy not supported?)\n");
878 }
879 else {
880 fprintf(stderr, "algorithm not supported?)\n");
881 }
882 }
883 }
884 else if (sw == SW_ERR_SECURITY_STATUS) {
885 res = YKPIV_AUTHENTICATION_ERROR;
886 if (state->verbose) { fprintf(stderr, "not authenticated)\n"); }
887 }
888 else {
889 res = YKPIV_GENERIC_ERROR;
890 if (state->verbose) { fprintf(stderr, "error %x)\n", sw); }
891 }
892
893 goto Cleanup;
894 }
895
896 if ((YKPIV_ALGO_RSA1024 == algorithm) || (YKPIV_ALGO_RSA2048 == algorithm)) {
897 size_t len;
898 unsigned char *data_ptr = data + 2 + _ykpiv_get_length(data + 2, data + recv_len, &len);
899
900 if (*data_ptr != TAG_RSA_MODULUS) {
901 if (state->verbose) { fprintf(stderr, "Failed to parse public key structure (modulus).\n"); }
902 res = YKPIV_PARSE_ERROR;
903 goto Cleanup;
904 }
905
906 data_ptr++;
907 offs = _ykpiv_get_length(data_ptr, data + recv_len, &len);
908 if(!offs) {
909 if (state->verbose) { fprintf(stderr, "Failed to parse public key structure (modulus length).\n"); }
910 res = YKPIV_PARSE_ERROR;
911 goto Cleanup;
912 }
913 data_ptr += offs;
914
915 cb_modulus = len;
916 if (NULL == (ptr_modulus = _ykpiv_alloc(state, cb_modulus))) {
917 if (state->verbose) { fprintf(stderr, "Failed to allocate memory for modulus.\n"); }
918 res = YKPIV_MEMORY_ERROR;
919 goto Cleanup;
920 }
921
922 memcpy(ptr_modulus, data_ptr, cb_modulus);
923
924 data_ptr += len;
925
926 if (*data_ptr != TAG_RSA_EXP) {
927 if (state->verbose) { fprintf(stderr, "Failed to parse public key structure (public exponent).\n"); }
928 res = YKPIV_PARSE_ERROR;
929 goto Cleanup;
930 }
931
932 data_ptr++;
933 offs = _ykpiv_get_length(data_ptr, data + recv_len, &len);
934 if(!offs) {
935 if (state->verbose) { fprintf(stderr, "Failed to parse public key structure (public exponent length).\n"); }
936 res = YKPIV_PARSE_ERROR;
937 goto Cleanup;
938 }
939 data_ptr += offs;
940
941 cb_exp = len;
942 if (NULL == (ptr_exp = _ykpiv_alloc(state, cb_exp))) {
943 if (state->verbose) { fprintf(stderr, "Failed to allocate memory for public exponent.\n"); }
944 res = YKPIV_MEMORY_ERROR;
945 goto Cleanup;
946 }
947
948 memcpy(ptr_exp, data_ptr, cb_exp);
949
950 // set output parameters
951
952 *modulus = ptr_modulus;
953 ptr_modulus = NULL;
954 *modulus_len = cb_modulus;
955 *exp = ptr_exp;
956 ptr_exp = NULL;
957 *exp_len = cb_exp;
958 }
959 else if ((YKPIV_ALGO_ECCP256 == algorithm) || (YKPIV_ALGO_ECCP384 == algorithm)) {
960 unsigned char *data_ptr = data + 3;
961 size_t len;
962
963 if (YKPIV_ALGO_ECCP256 == algorithm) {
964 len = CB_ECC_POINTP256;
965 }
966 else {
967 len = CB_ECC_POINTP384;
968 }
969
970 if (*data_ptr++ != TAG_ECC_POINT) {
971 if (state->verbose) { fprintf(stderr, "Failed to parse public key structure.\n"); }
972 res = YKPIV_PARSE_ERROR;
973 goto Cleanup;
974 }
975
976 if (*data_ptr++ != len) { /* the curve point should always be determined by the curve */
977 if (state->verbose) { fprintf(stderr, "Unexpected length.\n"); }
978 res = YKPIV_ALGORITHM_ERROR;
979 goto Cleanup;
980 }
981
982 cb_point = len;
983 if (NULL == (ptr_point = _ykpiv_alloc(state, cb_point))) {
984 if (state->verbose) { fprintf(stderr, "Failed to allocate memory for public point.\n"); }
985 res = YKPIV_MEMORY_ERROR;
986 goto Cleanup;
987 }
988
989 memcpy(ptr_point, data_ptr, cb_point);
990
991 // set output parameters
992
993 *point = ptr_point;
994 ptr_point = NULL;
995 *point_len = cb_point;
996 }
997 else {
998 if (state->verbose) { fprintf(stderr, "Wrong algorithm.\n"); }
999 res = YKPIV_ALGORITHM_ERROR;
1000 goto Cleanup;
1001 }
1002
1003 Cleanup:
1004
1005 if (ptr_modulus) { _ykpiv_free(state, ptr_modulus); }
1006 if (ptr_exp) { _ykpiv_free(state, ptr_exp); }
1007 if (ptr_point) { _ykpiv_free(state, ptr_point); }
1008
1009 _ykpiv_end_transaction(state);
1010 return res;
1011 }
1012
ykpiv_util_get_config(ykpiv_state * state,ykpiv_config * config)1013 ykpiv_rc ykpiv_util_get_config(ykpiv_state *state, ykpiv_config *config) {
1014 ykpiv_rc res = YKPIV_OK;
1015 uint8_t data[CB_BUF_MAX] = { 0 };
1016 size_t cb_data = sizeof(data);
1017 uint8_t *p_item = NULL;
1018 size_t cb_item = 0;
1019
1020 if (NULL == state) return YKPIV_GENERIC_ERROR;
1021 if (NULL == config) return YKPIV_GENERIC_ERROR;
1022
1023 // initialize default values
1024
1025 config->puk_blocked = false;
1026 config->puk_noblock_on_upgrade = false;
1027 config->pin_last_changed = 0;
1028 config->mgm_type = YKPIV_CONFIG_MGM_MANUAL;
1029
1030 if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res;
1031 if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
1032
1033 /* recover admin data */
1034 if (YKPIV_OK == _read_metadata(state, TAG_ADMIN, data, &cb_data)) {
1035 if (YKPIV_OK == _get_metadata_item(data, cb_data, TAG_ADMIN_FLAGS_1, &p_item, &cb_item)) {
1036 if (*p_item & ADMIN_FLAGS_1_PUK_BLOCKED) config->puk_blocked = true;
1037 if (*p_item & ADMIN_FLAGS_1_PROTECTED_MGM) config->mgm_type = YKPIV_CONFIG_MGM_PROTECTED;
1038 }
1039
1040 if (YKPIV_OK == _get_metadata_item(data, cb_data, TAG_ADMIN_SALT, &p_item, &cb_item)) {
1041 if (config->mgm_type != YKPIV_CONFIG_MGM_MANUAL) {
1042 if (state->verbose) {
1043 fprintf(stderr, "conflicting types of mgm key administration configured\n");
1044 config->mgm_type = YKPIV_CONFIG_MGM_INVALID;
1045 }
1046 }
1047 else {
1048 config->mgm_type = YKPIV_CONFIG_MGM_DERIVED;
1049 }
1050 }
1051
1052 if (YKPIV_OK == _get_metadata_item(data, cb_data, TAG_ADMIN_TIMESTAMP, &p_item, &cb_item)) {
1053 if (CB_ADMIN_TIMESTAMP != cb_item) {
1054 if (state->verbose) {
1055 fprintf(stderr, "pin timestamp in admin metadata is an invalid size");
1056 }
1057 }
1058 else {
1059 memcpy(&(config->pin_last_changed), p_item, cb_item);
1060 }
1061 }
1062 }
1063
1064 /* recover protected data */
1065 cb_data = sizeof(data);
1066
1067 if (YKPIV_OK == _read_metadata(state, TAG_PROTECTED, data, &cb_data)) {
1068
1069 if (YKPIV_OK == _get_metadata_item(data, cb_data, TAG_PROTECTED_FLAGS_1, &p_item, &cb_item)) {
1070 if (*p_item & PROTECTED_FLAGS_1_PUK_NOBLOCK) config->puk_noblock_on_upgrade = true;
1071 }
1072
1073 if (YKPIV_OK == _get_metadata_item(data, cb_data, TAG_PROTECTED_MGM, &p_item, &cb_item)) {
1074 if(sizeof(config->mgm_key) == cb_item) {
1075 memcpy(config->mgm_key, p_item, cb_item);
1076 if (config->mgm_type != YKPIV_CONFIG_MGM_PROTECTED) {
1077 if (state->verbose) fprintf(stderr, "conflicting types of mgm key administration configured - protected mgm exists\n");
1078 config->mgm_type = YKPIV_CONFIG_MGM_PROTECTED;
1079 }
1080 } else {
1081 if (state->verbose) fprintf(stderr, "protected data contains mgm, but is the wrong size = %lu\n", (unsigned long)cb_item);
1082 config->mgm_type = YKPIV_CONFIG_MGM_INVALID;
1083 }
1084 }
1085 }
1086 else {
1087 if (config->mgm_type == YKPIV_CONFIG_MGM_PROTECTED) {
1088 if (state->verbose) fprintf(stderr, "admin data indicates protected mgm present, but the object cannot be read\n");
1089 config->mgm_type = YKPIV_CONFIG_MGM_INVALID;
1090 }
1091 }
1092
1093 Cleanup:
1094
1095 _ykpiv_end_transaction(state);
1096 return res;
1097 }
1098
ykpiv_util_set_pin_last_changed(ykpiv_state * state)1099 ykpiv_rc ykpiv_util_set_pin_last_changed(ykpiv_state *state) {
1100 ykpiv_rc res = YKPIV_OK;
1101 ykpiv_rc ykrc = YKPIV_OK;
1102 uint8_t data[CB_BUF_MAX] = { 0 };
1103 size_t cb_data = sizeof(data);
1104 time_t tnow = 0;
1105
1106 if (NULL == state) return YKPIV_GENERIC_ERROR;
1107
1108 if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res;
1109 if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
1110
1111 /* recover admin data */
1112 if (YKPIV_OK != (ykrc = _read_metadata(state, TAG_ADMIN, data, &cb_data))) {
1113 cb_data = 0; /* set current metadata blob size to zero, we'll add the timestamp to the blank blob */
1114 }
1115
1116 tnow = time(NULL);
1117
1118 if (YKPIV_OK != (res = _set_metadata_item(data, &cb_data, CB_OBJ_MAX, TAG_ADMIN_TIMESTAMP, (uint8_t*)&tnow, CB_ADMIN_TIMESTAMP))) {
1119 if (state->verbose) fprintf(stderr, "could not set pin timestamp, err = %d\n", res);
1120 }
1121 else {
1122 if (YKPIV_OK != (res = _write_metadata(state, TAG_ADMIN, data, cb_data))) {
1123 /* Note: this can fail if authenticate() wasn't called previously - expected behavior */
1124 if (state->verbose) fprintf(stderr, "could not write admin data, err = %d\n", res);
1125 }
1126 }
1127
1128 Cleanup:
1129
1130 _ykpiv_end_transaction(state);
1131 return res;
1132 }
1133
ykpiv_util_get_derived_mgm(ykpiv_state * state,const uint8_t * pin,const size_t pin_len,ykpiv_mgm * mgm)1134 ykpiv_rc ykpiv_util_get_derived_mgm(ykpiv_state *state, const uint8_t *pin, const size_t pin_len, ykpiv_mgm *mgm) {
1135 ykpiv_rc res = YKPIV_OK;
1136 pkcs5_rc p5rc = PKCS5_OK;
1137 uint8_t data[CB_BUF_MAX] = { 0 };
1138 size_t cb_data = sizeof(data);
1139 uint8_t *p_item = NULL;
1140 size_t cb_item = 0;
1141
1142 if (NULL == state) return YKPIV_GENERIC_ERROR;
1143 if ((NULL == pin) || (0 == pin_len) || (NULL == mgm)) return YKPIV_GENERIC_ERROR;
1144
1145 if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res;
1146 if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
1147
1148 /* recover management key */
1149 if (YKPIV_OK == (res = _read_metadata(state, TAG_ADMIN, data, &cb_data))) {
1150 if (YKPIV_OK == (res = _get_metadata_item(data, cb_data, TAG_ADMIN_SALT, &p_item, &cb_item))) {
1151 if (cb_item != CB_ADMIN_SALT) {
1152 if (state->verbose) fprintf(stderr, "derived mgm salt exists, but is incorrect size = %lu\n", (unsigned long)cb_item);
1153 res = YKPIV_GENERIC_ERROR;
1154 goto Cleanup;
1155 }
1156
1157 if (PKCS5_OK != (p5rc = pkcs5_pbkdf2_sha1(pin, pin_len, p_item, cb_item, ITER_MGM_PBKDF2, mgm->data, member_size(ykpiv_mgm, data)))) {
1158 if (state->verbose) fprintf(stderr, "pbkdf2 failure, err = %d\n", p5rc);
1159 res = YKPIV_GENERIC_ERROR;
1160 goto Cleanup;
1161 }
1162 }
1163 }
1164
1165 Cleanup:
1166
1167 _ykpiv_end_transaction(state);
1168 return res;
1169 }
1170
ykpiv_util_get_protected_mgm(ykpiv_state * state,ykpiv_mgm * mgm)1171 ykpiv_rc ykpiv_util_get_protected_mgm(ykpiv_state *state, ykpiv_mgm *mgm) {
1172 ykpiv_rc res = YKPIV_OK;
1173 uint8_t data[CB_BUF_MAX] = { 0 };
1174 size_t cb_data = sizeof(data);
1175 uint8_t *p_item = NULL;
1176 size_t cb_item = 0;
1177
1178 if (NULL == state) return YKPIV_GENERIC_ERROR;
1179 if (NULL == mgm) return YKPIV_GENERIC_ERROR;
1180
1181 if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res;
1182 if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
1183
1184 if (YKPIV_OK != (res = _read_metadata(state, TAG_PROTECTED, data, &cb_data))) {
1185 if (state->verbose) fprintf(stderr, "could not read protected data, err = %d\n", res);
1186 goto Cleanup;
1187 }
1188
1189 if (YKPIV_OK != (res = _get_metadata_item(data, cb_data, TAG_PROTECTED_MGM, &p_item, &cb_item))) {
1190 if (state->verbose) fprintf(stderr, "could not read protected mgm from metadata, err = %d\n", res);
1191 goto Cleanup;
1192 }
1193
1194 if (cb_item != member_size(ykpiv_mgm, data)) {
1195 if (state->verbose) fprintf(stderr, "protected data contains mgm, but is the wrong size = %lu\n", (unsigned long)cb_item);
1196 res = YKPIV_AUTHENTICATION_ERROR;
1197 goto Cleanup;
1198 }
1199
1200 memcpy(mgm->data, p_item, cb_item);
1201
1202 Cleanup:
1203
1204 yc_memzero(data, sizeof(data));
1205
1206 _ykpiv_end_transaction(state);
1207 return res;
1208
1209 }
1210
1211 /* to set a generated mgm, pass NULL for mgm, or set mgm.data to all zeroes */
ykpiv_util_set_protected_mgm(ykpiv_state * state,ykpiv_mgm * mgm)1212 ykpiv_rc ykpiv_util_set_protected_mgm(ykpiv_state *state, ykpiv_mgm *mgm) {
1213 ykpiv_rc res = YKPIV_OK;
1214 ykpiv_rc ykrc = YKPIV_OK;
1215 prng_rc prngrc = PRNG_OK;
1216 bool fGenerate = false;
1217 uint8_t mgm_key[member_size(ykpiv_mgm, data)] = { 0 };
1218 size_t i = 0;
1219 uint8_t data[CB_BUF_MAX] = { 0 };
1220 size_t cb_data = sizeof(data);
1221 uint8_t *p_item = NULL;
1222 size_t cb_item = 0;
1223 uint8_t flags_1 = 0;
1224
1225 if (NULL == state) return YKPIV_GENERIC_ERROR;
1226
1227 if (!mgm) {
1228 fGenerate = true;
1229 }
1230 else {
1231 fGenerate = true;
1232 memcpy(mgm_key, mgm->data, sizeof(mgm_key));
1233
1234 for (i = 0; i < sizeof(mgm_key); i++) {
1235 if (mgm_key[i] != 0) {
1236 fGenerate = false;
1237 break;
1238 }
1239 }
1240 }
1241
1242 if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) goto Cleanup;
1243 if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
1244
1245 /* try to set the mgm key as long as we don't encounter a fatal error */
1246 do {
1247 if (fGenerate) {
1248 /* generate a new mgm key */
1249 if (PRNG_OK != (prngrc = _ykpiv_prng_generate(mgm_key, sizeof(mgm_key)))) {
1250 if (state->verbose) fprintf(stderr, "could not generate new mgm, err = %d\n", prngrc);
1251 res = YKPIV_RANDOMNESS_ERROR;
1252 goto Cleanup;
1253 }
1254 }
1255
1256 if (YKPIV_OK != (ykrc = ykpiv_set_mgmkey(state, mgm_key))) {
1257 /*
1258 ** if _set_mgmkey fails with YKPIV_KEY_ERROR, it means the generated key is weak
1259 ** otherwise, log a warning, since the device mgm key is corrupt or we're in
1260 ** a state where we can't set the mgm key
1261 */
1262 if (YKPIV_KEY_ERROR != ykrc) {
1263 if (state->verbose) fprintf(stderr, "could not set new derived mgm key, err = %d\n", ykrc);
1264 res = ykrc;
1265 goto Cleanup;
1266 }
1267 }
1268 else {
1269 /* _set_mgmkey succeeded, stop generating */
1270 fGenerate = false;
1271 }
1272 } while (fGenerate);
1273
1274 /* set output mgm */
1275 if (mgm) {
1276 memcpy(mgm->data, mgm_key, sizeof(mgm_key));
1277 }
1278
1279 /* after this point, we've set the mgm key, so the function should succeed, regardless of being able to set the metadata */
1280
1281 /* set the new mgm key in protected data */
1282 if (YKPIV_OK != (ykrc = _read_metadata(state, TAG_PROTECTED, data, &cb_data))) {
1283 cb_data = 0; /* set current metadata blob size to zero, we'll add to the blank blob */
1284 }
1285
1286 if (YKPIV_OK != (ykrc = _set_metadata_item(data, &cb_data, CB_OBJ_MAX, TAG_PROTECTED_MGM, mgm_key, sizeof(mgm_key)))) {
1287 if (state->verbose) fprintf(stderr, "could not set protected mgm item, err = %d\n", ykrc);
1288 }
1289 else {
1290 if (YKPIV_OK != (ykrc = _write_metadata(state, TAG_PROTECTED, data, cb_data))) {
1291 if (state->verbose) fprintf(stderr, "could not write protected data, err = %d\n", ykrc);
1292 goto Cleanup;
1293 }
1294 }
1295
1296 /* set the protected mgm flag in admin data */
1297 cb_data = sizeof(data);
1298
1299 if (YKPIV_OK != (ykrc = _read_metadata(state, TAG_ADMIN, data, &cb_data))) {
1300 cb_data = 0;
1301 }
1302 else {
1303
1304 if (YKPIV_OK != (ykrc = _get_metadata_item(data, cb_data, TAG_ADMIN_FLAGS_1, &p_item, &cb_item))) {
1305 /* flags are not set */
1306 if (state->verbose) fprintf(stderr, "admin data exists, but flags are not present\n");
1307 }
1308
1309 if (cb_item == sizeof(flags_1)) {
1310 memcpy(&flags_1, p_item, cb_item);
1311 }
1312 else {
1313 if (state->verbose) fprintf(stderr, "admin data flags are an incorrect size = %lu\n", (unsigned long)cb_item);
1314 }
1315
1316 /* remove any existing salt */
1317 if (YKPIV_OK != (ykrc = _set_metadata_item(data, &cb_data, CB_OBJ_MAX, TAG_ADMIN_SALT, NULL, 0))) {
1318 if (state->verbose) fprintf(stderr, "could not unset derived mgm salt, err = %d\n", ykrc);
1319 }
1320 }
1321
1322 flags_1 |= ADMIN_FLAGS_1_PROTECTED_MGM;
1323
1324 if (YKPIV_OK != (ykrc = _set_metadata_item(data, &cb_data, CB_OBJ_MAX, TAG_ADMIN_FLAGS_1, &flags_1, sizeof(flags_1)))) {
1325 if (state->verbose) fprintf(stderr, "could not set admin flags item, err = %d\n", ykrc);
1326 }
1327 else {
1328 if (YKPIV_OK != (ykrc = _write_metadata(state, TAG_ADMIN, data, cb_data))) {
1329 if (state->verbose) fprintf(stderr, "could not write admin data, err = %d\n", ykrc);
1330 goto Cleanup;
1331 }
1332 }
1333
1334
1335 Cleanup:
1336
1337 yc_memzero(data, sizeof(data));
1338 yc_memzero(mgm_key, sizeof(mgm_key));
1339
1340 _ykpiv_end_transaction(state);
1341 return res;
1342 }
1343
ykpiv_util_reset(ykpiv_state * state)1344 ykpiv_rc ykpiv_util_reset(ykpiv_state *state) {
1345 unsigned char templ[] = {0, YKPIV_INS_RESET, 0, 0};
1346 unsigned char data[0xff] = {0};
1347 unsigned long recv_len = sizeof(data);
1348 ykpiv_rc res;
1349 int sw;
1350
1351 /* note: the reset function is only available when both pins are blocked. */
1352 res = ykpiv_transfer_data(state, templ, NULL, 0, data, &recv_len, &sw);
1353 if (YKPIV_OK == res && SW_SUCCESS == sw) {
1354 return YKPIV_OK;
1355 }
1356 return YKPIV_GENERIC_ERROR;
1357 }
1358
ykpiv_util_slot_object(uint8_t slot)1359 uint32_t ykpiv_util_slot_object(uint8_t slot) {
1360 int object_id = -1;
1361
1362 switch (slot) {
1363 case YKPIV_KEY_AUTHENTICATION:
1364 object_id = YKPIV_OBJ_AUTHENTICATION;
1365 break;
1366
1367 case YKPIV_KEY_SIGNATURE:
1368 object_id = YKPIV_OBJ_SIGNATURE;
1369 break;
1370
1371 case YKPIV_KEY_KEYMGM:
1372 object_id = YKPIV_OBJ_KEY_MANAGEMENT;
1373 break;
1374
1375 case YKPIV_KEY_CARDAUTH:
1376 object_id = YKPIV_OBJ_CARD_AUTH;
1377 break;
1378
1379 case YKPIV_KEY_ATTESTATION:
1380 object_id = YKPIV_OBJ_ATTESTATION;
1381 break;
1382
1383 default:
1384 if ((slot >= YKPIV_KEY_RETIRED1) && (slot <= YKPIV_KEY_RETIRED20)) {
1385 object_id = YKPIV_OBJ_RETIRED1 + (slot - YKPIV_KEY_RETIRED1);
1386 }
1387 break;
1388 }
1389
1390 return (uint32_t)object_id;
1391 }
1392
_read_certificate(ykpiv_state * state,uint8_t slot,uint8_t * buf,size_t * buf_len)1393 static ykpiv_rc _read_certificate(ykpiv_state *state, uint8_t slot, uint8_t *buf, size_t *buf_len) {
1394 ykpiv_rc res = YKPIV_OK;
1395 uint8_t *ptr = NULL;
1396 unsigned long ul_len = (unsigned long)*buf_len;
1397 int object_id = (int)ykpiv_util_slot_object(slot);
1398 size_t offs, len = 0;
1399
1400 if (-1 == object_id) return YKPIV_INVALID_OBJECT;
1401
1402 if (YKPIV_OK == (res = _ykpiv_fetch_object(state, object_id, buf, &ul_len))) {
1403 ptr = buf;
1404
1405 // check that object contents are at least large enough to read the tag
1406 if (ul_len < CB_OBJ_TAG_MIN) {
1407 *buf_len = 0;
1408 return YKPIV_OK;
1409 }
1410
1411 // check that first byte indicates "certificate" type
1412
1413 if (*ptr++ == TAG_CERT) {
1414 offs = _ykpiv_get_length(ptr, buf + ul_len, &len);
1415 if(!offs) {
1416 *buf_len = 0;
1417 return YKPIV_OK;
1418 }
1419 ptr += offs;
1420
1421 memmove(buf, ptr, len);
1422 *buf_len = len;
1423 }
1424 }
1425 else {
1426 *buf_len = 0;
1427 }
1428
1429 return res;
1430 }
1431
_write_certificate(ykpiv_state * state,uint8_t slot,uint8_t * data,size_t data_len,uint8_t certinfo)1432 static ykpiv_rc _write_certificate(ykpiv_state *state, uint8_t slot, uint8_t *data, size_t data_len, uint8_t certinfo) {
1433 uint8_t buf[CB_OBJ_MAX] = {0};
1434 int object_id = (int)ykpiv_util_slot_object(slot);
1435 size_t offset = 0;
1436 size_t req_len = 0;
1437
1438 if (-1 == object_id) return YKPIV_INVALID_OBJECT;
1439
1440 // check if data or data_len are zero, this means that we intend to delete the object
1441 if ((NULL == data) || (0 == data_len)) {
1442
1443 // if either data or data_len are non-zero, return an error,
1444 // that we only delete strictly when both are set properly
1445 if ((NULL != data) || (0 != data_len)) {
1446 return YKPIV_GENERIC_ERROR;
1447 }
1448
1449 return _ykpiv_save_object(state, object_id, NULL, 0);
1450 }
1451
1452 // encode certificate data for storage
1453
1454 // calculate the required length of the encoded object
1455 req_len = 1 /* cert tag */ + 3 /* compression tag + data*/ + 2 /* lrc */;
1456 req_len += _ykpiv_set_length(buf, data_len);
1457 req_len += data_len;
1458
1459 if (req_len < data_len) return YKPIV_SIZE_ERROR; /* detect overflow of unsigned size_t */
1460 if (req_len > _obj_size_max(state)) return YKPIV_SIZE_ERROR; /* obj_size_max includes limits for TLV encoding */
1461
1462 buf[offset++] = TAG_CERT;
1463 offset += _ykpiv_set_length(buf + offset, data_len);
1464 memcpy(buf + offset, data, data_len);
1465 offset += data_len;
1466
1467 // write compression info and LRC trailer
1468 buf[offset++] = TAG_CERT_COMPRESS;
1469 buf[offset++] = 0x01;
1470 buf[offset++] = certinfo == YKPIV_CERTINFO_GZIP ? 0x01 : 0x00;
1471 buf[offset++] = TAG_CERT_LRC;
1472 buf[offset++] = 00;
1473
1474 // write onto device
1475 return _ykpiv_save_object(state, object_id, buf, offset);
1476 }
1477
1478 /*
1479 ** PIV Manager data helper functions
1480 **
1481 ** These functions allow the PIV Manager to extend the YKPIV_OBJ_ADMIN_DATA object without having to change
1482 ** this implementation. New items may be added without modifying these functions. Data items are picked
1483 ** from the pivman_data buffer by tag, and replaced either in place if length allows or the data object is
1484 ** expanded to fit a new/updated data item.
1485 */
1486
1487 /*
1488 ** _get_metadata_item
1489 **
1490 ** Parses the metadata blob, specified by data, looking for the specified tag. If found, the item is
1491 ** returned in pp_item and its size in pcb_item.
1492 **
1493 ** If the item is not found, this function returns YKPIV_GENERIC_ERROR.
1494 */
_get_metadata_item(uint8_t * data,size_t cb_data,uint8_t tag,uint8_t ** pp_item,size_t * pcb_item)1495 static ykpiv_rc _get_metadata_item(uint8_t *data, size_t cb_data, uint8_t tag, uint8_t **pp_item, size_t *pcb_item) {
1496 uint8_t *p_temp = data;
1497 size_t offs, cb_temp = 0;
1498 uint8_t tag_temp = 0;
1499 bool found = false;
1500
1501 if (!data || !pp_item || !pcb_item) return YKPIV_GENERIC_ERROR;
1502
1503 *pp_item = NULL;
1504 *pcb_item = 0;
1505
1506 while (p_temp < (data + cb_data)) {
1507 tag_temp = *p_temp++;
1508
1509 offs = _ykpiv_get_length(p_temp, data + cb_data, &cb_temp);
1510 if (!offs) {
1511 return YKPIV_PARSE_ERROR;
1512 }
1513
1514 p_temp += offs;
1515
1516 if (tag_temp == tag) {
1517 // found tag
1518 found = true;
1519 break;
1520 }
1521
1522 p_temp += cb_temp;
1523 }
1524
1525 if (found) {
1526 *pp_item = p_temp;
1527 *pcb_item = cb_temp;
1528 }
1529
1530 return found ? YKPIV_OK : YKPIV_GENERIC_ERROR;
1531 }
1532
ykpiv_util_parse_metadata(uint8_t * data,size_t data_len,ykpiv_metadata * metadata)1533 ykpiv_rc ykpiv_util_parse_metadata(uint8_t *data, size_t data_len, ykpiv_metadata *metadata) {
1534 uint8_t *p;
1535 size_t cb;
1536
1537 ykpiv_rc rc = _get_metadata_item(data, data_len, YKPIV_METADATA_ALGORITHM_TAG, &p, &cb);
1538 if(rc != YKPIV_OK)
1539 return rc;
1540 if(cb != 1)
1541 return YKPIV_PARSE_ERROR;
1542 metadata->algorithm = p[0];
1543
1544 rc = _get_metadata_item(data, data_len, YKPIV_METADATA_POLICY_TAG, &p, &cb);
1545 if(rc != YKPIV_OK)
1546 return rc;
1547 if(cb != 2)
1548 return YKPIV_PARSE_ERROR;
1549 metadata->pin_policy = p[0];
1550 metadata->touch_policy = p[1];
1551
1552 rc = _get_metadata_item(data, data_len, YKPIV_METADATA_ORIGIN_TAG, &p, &cb);
1553 if(rc != YKPIV_OK)
1554 return rc;
1555 if(cb != 1)
1556 return YKPIV_PARSE_ERROR;
1557 metadata->origin = p[0];
1558
1559 rc = _get_metadata_item(data, data_len, YKPIV_METADATA_PUBKEY_TAG, &p, &cb);
1560 if(rc != YKPIV_OK)
1561 return rc;
1562 if(cb > sizeof(metadata->pubkey))
1563 return YKPIV_PARSE_ERROR;
1564
1565 metadata->pubkey_len = cb;
1566 memcpy(metadata->pubkey, p, cb);
1567
1568 return YKPIV_OK;
1569 }
1570
1571 /*
1572 ** _set_metadata_item
1573 **
1574 ** Adds or replaces a data item encoded in a metadata blob, specified by tag to the existing
1575 ** metadata blob (data) until it reaches the a maximum buffer size (cb_data_max).
1576 **
1577 ** If adding/replacing the item would exceed cb_data_max, this function returns YKPIV_GENERIC_ERROR.
1578 **
1579 ** The new size of the blob is returned in pcb_data.
1580 */
_set_metadata_item(uint8_t * data,size_t * pcb_data,size_t cb_data_max,uint8_t tag,uint8_t * p_item,size_t cb_item)1581 static ykpiv_rc _set_metadata_item(uint8_t *data, size_t *pcb_data, size_t cb_data_max, uint8_t tag, uint8_t *p_item, size_t cb_item) {
1582 uint8_t *p_temp = data;
1583 size_t cb_temp = 0;
1584 uint8_t tag_temp = 0;
1585 size_t cb_len = 0;
1586 uint8_t *p_next = NULL;
1587 long cb_moved = 0; /* must be signed to have negative offsets */
1588
1589 if (!data || !pcb_data) return YKPIV_GENERIC_ERROR;
1590
1591 while (p_temp < (data + *pcb_data)) {
1592 tag_temp = *p_temp++;
1593 cb_len = _ykpiv_get_length(p_temp, data + *pcb_data, &cb_temp);
1594 if(!cb_len) {
1595 return YKPIV_PARSE_ERROR;
1596 }
1597 p_temp += cb_len;
1598
1599 if (tag_temp == tag) {
1600 /* found tag */
1601
1602 /* check length, if it matches, overwrite */
1603 if (cb_temp == cb_item) {
1604 memcpy(p_temp, p_item, cb_item);
1605 return YKPIV_OK;
1606 }
1607
1608 /* length doesn't match, expand/shrink to fit */
1609 p_next = p_temp + cb_temp;
1610 cb_moved = (long)cb_item - (long)cb_temp +
1611 ((long)(cb_item != 0 ? (long)_ykpiv_get_length_size(cb_item) : -1l /* for tag, if deleting */) -
1612 (long)cb_len); /* accounts for different length encoding */
1613
1614 /* length would cause buffer overflow, return error */
1615 if ((size_t)(*pcb_data + cb_moved) > cb_data_max) {
1616 return YKPIV_GENERIC_ERROR;
1617 }
1618
1619 /* move remaining data */
1620 memmove(p_next + cb_moved, p_next, *pcb_data - (size_t)(p_next - data));
1621 *pcb_data += cb_moved;
1622
1623 /* re-encode item and insert */
1624 if (cb_item != 0) {
1625 p_temp -= cb_len;
1626 p_temp += _ykpiv_set_length(p_temp, cb_item);
1627 memcpy(p_temp, p_item, cb_item);
1628 }
1629
1630 return YKPIV_OK;
1631 } /* if tag found */
1632
1633 p_temp += cb_temp;
1634 }
1635
1636 if (cb_item == 0) {
1637 /* we've been asked to delete an existing item that isn't in the blob */
1638 return YKPIV_OK;
1639 }
1640
1641 // we did not find an existing tag, append
1642 p_temp = data + *pcb_data;
1643 cb_len = _ykpiv_get_length_size(cb_item);
1644
1645 // length would cause buffer overflow, return error
1646 if (*pcb_data + cb_len + cb_item > cb_data_max) {
1647 return YKPIV_GENERIC_ERROR;
1648 }
1649
1650 *p_temp++ = tag;
1651 p_temp += _ykpiv_set_length(p_temp, cb_item);
1652 memcpy(p_temp, p_item, cb_item);
1653 *pcb_data += 1 + cb_len + cb_item;
1654
1655 return YKPIV_OK;
1656 }
1657
1658 /*
1659 ** _read_metadata
1660 **
1661 ** Reads admin or protected data (specified by tag) from its associated object.
1662 **
1663 ** The data stored in the object is parsed to ensure it has the correct tag and valid length.
1664 **
1665 ** data must point to a buffer of at least CB_BUF_MAX bytes, and pcb_data should point to
1666 ** the size of data.
1667 **
1668 ** To read from protected data, the pin must be verified prior to calling this function.
1669 */
_read_metadata(ykpiv_state * state,uint8_t tag,uint8_t * data,size_t * pcb_data)1670 static ykpiv_rc _read_metadata(ykpiv_state *state, uint8_t tag, uint8_t* data, size_t* pcb_data) {
1671 ykpiv_rc res = YKPIV_OK;
1672 uint8_t *p_temp = NULL;
1673 unsigned long cb_temp = 0;
1674 size_t offs;
1675 int obj_id = 0;
1676
1677 if (!data || !pcb_data || (CB_BUF_MAX > *pcb_data)) return YKPIV_GENERIC_ERROR;
1678
1679 switch (tag) {
1680 case TAG_ADMIN: obj_id = YKPIV_OBJ_ADMIN_DATA; break;
1681 case TAG_PROTECTED: obj_id = YKPIV_OBJ_PRINTED; break;
1682 default: return YKPIV_INVALID_OBJECT;
1683 }
1684
1685 cb_temp = (unsigned long)*pcb_data;
1686 *pcb_data = 0;
1687
1688 if (YKPIV_OK != (res = _ykpiv_fetch_object(state, obj_id, data, &cb_temp))) {
1689 return res;
1690 }
1691
1692 if (cb_temp < CB_OBJ_TAG_MIN) return YKPIV_PARSE_ERROR;
1693
1694 p_temp = data;
1695
1696 if (tag != *p_temp++) return YKPIV_PARSE_ERROR;
1697
1698 offs = _ykpiv_get_length(p_temp, data + cb_temp, pcb_data);
1699 if (!offs) {
1700 *pcb_data = 0;
1701 return YKPIV_PARSE_ERROR;
1702 }
1703
1704 p_temp += offs;
1705
1706 memmove(data, p_temp, *pcb_data);
1707
1708 return YKPIV_OK;
1709 }
1710
1711 /*
1712 ** _write_metadata
1713 **
1714 ** Writes admin/protected data, specified by tag to its associated object.
1715 **
1716 ** To delete the metadata, set data to NULL and cb_data to 0.
1717 **
1718 ** To write protected data, the pin must be verified prior to calling this function.
1719 */
_write_metadata(ykpiv_state * state,uint8_t tag,uint8_t * data,size_t cb_data)1720 static ykpiv_rc _write_metadata(ykpiv_state *state, uint8_t tag, uint8_t *data, size_t cb_data) {
1721 ykpiv_rc res = YKPIV_OK;
1722 uint8_t buf[CB_OBJ_MAX] = { 0 };
1723 uint8_t *pTemp = buf;
1724 int obj_id = 0;
1725
1726 if (cb_data > (_obj_size_max(state) - CB_OBJ_TAG_MAX)) {
1727 return YKPIV_GENERIC_ERROR;
1728 }
1729
1730 switch (tag) {
1731 case TAG_ADMIN: obj_id = YKPIV_OBJ_ADMIN_DATA; break;
1732 case TAG_PROTECTED: obj_id = YKPIV_OBJ_PRINTED; break;
1733 default: return YKPIV_INVALID_OBJECT;
1734 }
1735
1736 if (!data || (0 == cb_data)) {
1737 // deleting metadata
1738 res = _ykpiv_save_object(state, obj_id, NULL, 0);
1739 }
1740 else {
1741 *pTemp++ = tag;
1742 pTemp += _ykpiv_set_length(pTemp, cb_data);
1743
1744 memcpy(pTemp, data, cb_data);
1745 pTemp += cb_data;
1746
1747 res = _ykpiv_save_object(state, obj_id, buf, (size_t)(pTemp - buf));
1748 }
1749
1750 return res;
1751 }
1752