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