/src/opensc/src/libopensc/pkcs15-piv.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * partial PKCS15 emulation for PIV-II cards |
3 | | * only minimal use of the authentication cert and key |
4 | | * |
5 | | * Copyright (C) 2005,2006,2007,2008,2009,2010 |
6 | | * Douglas E. Engert <deengert@anl.gov> |
7 | | * Copyright (C) 2020 Douglas E. Engert <deengert@gmail.com> |
8 | | * 2004, Nils Larsch <larsch@trustcenter.de> |
9 | | * Copyright (C) 2006, Identity Alliance, |
10 | | * Thomas Harning <thomas.harning@identityalliance.com> |
11 | | * Copyright (C) 2007, EMC, Russell Larner <rlarner@rsa.com> |
12 | | * |
13 | | * This library is free software; you can redistribute it and/or |
14 | | * modify it under the terms of the GNU Lesser General Public |
15 | | * License as published by the Free Software Foundation; either |
16 | | * version 2.1 of the License, or (at your option) any later version. |
17 | | * |
18 | | * This library is distributed in the hope that it will be useful, |
19 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
20 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
21 | | * Lesser General Public License for more details. |
22 | | * |
23 | | * You should have received a copy of the GNU Lesser General Public |
24 | | * License along with this library; if not, write to the Free Software |
25 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
26 | | */ |
27 | | |
28 | | #ifdef HAVE_CONFIG_H |
29 | | #include "config.h" |
30 | | #endif |
31 | | |
32 | | #include <stdlib.h> |
33 | | #include <string.h> |
34 | | #include <stdio.h> |
35 | | #include <ctype.h> |
36 | | |
37 | | #include "internal.h" |
38 | | #include "cardctl.h" |
39 | | #include "asn1.h" |
40 | | #include "pkcs15.h" |
41 | | |
42 | 0 | #define MANU_ID "piv_II " |
43 | | |
44 | | typedef struct objdata_st { |
45 | | const char *id; |
46 | | const char *label; |
47 | | const char *aoid; |
48 | | const char *auth_id; |
49 | | const char *path; |
50 | | int obj_flags; |
51 | | } objdata; |
52 | | |
53 | | typedef struct cdata_st { |
54 | | const char *id; |
55 | | const char *label; |
56 | | const char *path; |
57 | | int authority; |
58 | | int obj_flags; |
59 | | } cdata; |
60 | | |
61 | | typedef struct pdata_st { |
62 | | const char *id; |
63 | | const char *label; |
64 | | const char *path; |
65 | | int ref; |
66 | | int type; |
67 | | unsigned int maxlen; |
68 | | unsigned int minlen; |
69 | | unsigned int storedlen; |
70 | | int flags; |
71 | | int tries_left; |
72 | | const unsigned char pad_char; |
73 | | int obj_flags; |
74 | | int cardmod; /* only use with cardmod minidriver */ |
75 | | } pindata; |
76 | | |
77 | | typedef struct pubdata_st { |
78 | | const char *id; |
79 | | const char *label; |
80 | | int usage_rsa; |
81 | | int usage_ec; |
82 | | const char *path; |
83 | | int ref; |
84 | | const char *auth_id; |
85 | | int obj_flags; |
86 | | const char *getenvname; |
87 | | } pubdata; |
88 | | |
89 | | typedef struct prdata_st { |
90 | | const char *id; |
91 | | const char *label; |
92 | | int usage_rsa; |
93 | | int usage_ec; |
94 | | const char *path; |
95 | | int ref; |
96 | | const char *auth_id; |
97 | | int obj_flags; |
98 | | int user_consent; |
99 | | } prdata; |
100 | | |
101 | | typedef struct common_key_info_st { |
102 | | int cert_found; |
103 | | int pubkey_found; |
104 | | int pubkey_from_file; |
105 | | unsigned long key_alg; |
106 | | size_t pubkey_len; |
107 | | unsigned int cert_keyUsage; /* x509 key usage as defined in certificate */ |
108 | | int cert_keyUsage_present; /* 1 if keyUsage found in certificate */ |
109 | | int pub_usage; |
110 | | int priv_usage; |
111 | | struct sc_pkcs15_pubkey *pubkey_from_cert; |
112 | | int not_present; |
113 | | } common_key_info; |
114 | | |
115 | | |
116 | | /* |
117 | | * The PIV applet has no serial number, and so the either the FASC-N |
118 | | * is used, or the GUID is used as a serial number. |
119 | | * We need to return a GUID like value for each object |
120 | | * But this needs to be some what unique. |
121 | | * So we will use two different methods, depending |
122 | | * on the size of the serial number. |
123 | | * If it is 25 bytes, then it was from a FASCN. If 16 bytes |
124 | | * its from a GUID. |
125 | | * If neither, we will uase the default method. |
126 | | */ |
127 | | |
128 | | static int piv_get_guid(struct sc_pkcs15_card *p15card, const struct sc_pkcs15_object *obj, |
129 | | unsigned char *out, size_t *out_size) |
130 | 0 | { |
131 | 0 | struct sc_serial_number serialnr; |
132 | 0 | struct sc_pkcs15_id id; |
133 | 0 | unsigned char guid_bin[SC_PKCS15_MAX_ID_SIZE + SC_MAX_SERIALNR]; |
134 | 0 | size_t bin_size, offs, tlen, i; |
135 | 0 | int r; |
136 | 0 | unsigned char fbit, fbits, fbyte, fbyte2, fnibble; |
137 | 0 | unsigned char *f5p, *f8p; |
138 | |
|
139 | 0 | if (!p15card || !obj || !out || *out_size < 3) |
140 | 0 | return SC_ERROR_INCORRECT_PARAMETERS; |
141 | | |
142 | 0 | r = sc_pkcs15_get_object_id(obj, &id); |
143 | 0 | if (r) |
144 | 0 | return r; |
145 | | |
146 | 0 | r = sc_card_ctl(p15card->card, SC_CARDCTL_GET_SERIALNR, &serialnr); |
147 | 0 | if (r) |
148 | 0 | return r; |
149 | 0 | if (serialnr.len > SC_MAX_SERIALNR) |
150 | 0 | return SC_ERROR_INTERNAL; |
151 | | |
152 | 0 | memset(guid_bin, 0, sizeof(guid_bin)); |
153 | 0 | memset(out, 0, *out_size); |
154 | |
|
155 | 0 | if (id.len == 1 && serialnr.len == 25) { |
156 | | |
157 | | /* It is from a FASCN, and we need to shorten it but keep |
158 | | * as much uniqueness as possible. |
159 | | * FASC-N is stored like a ISO 7811 Magnetic Strip Card |
160 | | * Using the ANSI/ISO BCD Data Format |
161 | | * 4 data bit + 1 parity bit (odd) least significant bit first. |
162 | | * It starts with the Start Sentinel 0x0b ";" |
163 | | * Fields are separated by 0x0d "=" |
164 | | * Ends with End Sentinel 0x0f "?" |
165 | | * Its 39 characters + the LRC |
166 | | * http://www.dataip.co.uk/Reference/MagneticCardBCD.php |
167 | | * 0x0a, 0x0c, 0x0e are some type of control |
168 | | * the FASCN has a lot of extra bits, with only 32 digits. |
169 | | */ |
170 | 0 | f5p = serialnr.value; |
171 | 0 | f8p = guid_bin; |
172 | 0 | fbyte = 0; |
173 | 0 | fbyte2 = 0; |
174 | 0 | fnibble = 0; |
175 | 0 | fbits = 0; |
176 | 0 | for (i = 0; i < 25*8; i++) { |
177 | 0 | if (i%8 == 0) { |
178 | 0 | fbyte=*f5p++; |
179 | 0 | } |
180 | 0 | fbit = (fbyte & 0x80) ? 1:0; |
181 | 0 | fbyte <<= 1; |
182 | 0 | fbits = (fbits >> 1) + (fbit << 4); |
183 | | /* reversed with parity */ |
184 | 0 | if ((i - 4)%5 == 0) { |
185 | 0 | fbits = fbits & 0x0f; /* drop parity */ |
186 | 0 | if (fbits <= 9) { /* only save digits, drop control codes */ |
187 | 0 | fbyte2 = (fbyte2 << 4) | fbits; |
188 | 0 | if (fnibble) { |
189 | 0 | *f8p = fbyte2; |
190 | 0 | f8p++; |
191 | 0 | fbyte2 = 0; |
192 | 0 | fnibble = 0; |
193 | 0 | } else |
194 | 0 | fnibble = 1; |
195 | 0 | } |
196 | 0 | fbits = 0; |
197 | 0 | } |
198 | 0 | } |
199 | | |
200 | | /* overwrite two insignificant digits in middle with id */ |
201 | 0 | memcpy(guid_bin + 7, id.value, id.len); |
202 | 0 | tlen = 16; |
203 | 0 | } |
204 | 0 | else if (id.len == 1 && serialnr.len == 16) { |
205 | | /* its from a GUID, we will overwrite the |
206 | | * first byte with id.value, as this preserves most |
207 | | * of the uniqueness. |
208 | | */ |
209 | 0 | memcpy(guid_bin, id.value, id.len); |
210 | 0 | memcpy(guid_bin + id.len, serialnr.value + 1, serialnr.len - 1); |
211 | |
|
212 | 0 | tlen = id.len + serialnr.len - 1; /* i.e. 16 */ |
213 | 0 | } else { |
214 | | /* not what was expected... use default */ |
215 | |
|
216 | 0 | memcpy(guid_bin, serialnr.value, serialnr.len); |
217 | 0 | memcpy(guid_bin + serialnr.len, id.value, id.len); |
218 | |
|
219 | 0 | tlen = id.len + serialnr.len; |
220 | 0 | } |
221 | | |
222 | | /* reserve one byte for the 'C' line ending */ |
223 | 0 | bin_size = (*out_size - 1)/2; |
224 | 0 | if (bin_size > tlen) |
225 | 0 | bin_size = tlen; |
226 | |
|
227 | 0 | offs = tlen - bin_size; |
228 | |
|
229 | 0 | for (i=0; i<bin_size; i++) |
230 | 0 | sprintf((char *) out + i*2, "%02x", guid_bin[offs + i]); |
231 | |
|
232 | 0 | return SC_SUCCESS; |
233 | 0 | } |
234 | | |
235 | | |
236 | | static int piv_detect_card(sc_pkcs15_card_t *p15card) |
237 | 0 | { |
238 | 0 | sc_card_t *card = p15card->card; |
239 | |
|
240 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
241 | 0 | if (card->type < SC_CARD_TYPE_PIV_II_BASE |
242 | 0 | || card->type >= SC_CARD_TYPE_PIV_II_BASE + 1000) |
243 | 0 | return SC_ERROR_INVALID_CARD; |
244 | 0 | return SC_SUCCESS; |
245 | 0 | } |
246 | | |
247 | | |
248 | | static int sc_pkcs15emu_piv_init(sc_pkcs15_card_t *p15card) |
249 | 0 | { |
250 | | |
251 | | /* The cert objects will return all the data */ |
252 | | /* Note: pkcs11 objects do not have CK_ID values */ |
253 | | |
254 | | // clang-format off |
255 | 0 | static const objdata objects[] = { |
256 | 0 | {"01", "Card Capability Container", |
257 | 0 | "2.16.840.1.101.3.7.1.219.0", NULL, "DB00", 0}, |
258 | 0 | {"02", "Card Holder Unique Identifier", |
259 | 0 | "2.16.840.1.101.3.7.2.48.0", NULL, "3000", 0}, |
260 | 0 | {"03", "Unsigned Card Holder Unique Identifier", |
261 | 0 | "2.16.840.1.101.3.7.2.48.2", NULL, "3010", 0}, |
262 | 0 | {"04", "X.509 Certificate for PIV Authentication", |
263 | 0 | "2.16.840.1.101.3.7.2.1.1", NULL, "0101", 0}, |
264 | 0 | {"05", "Cardholder Fingerprints", |
265 | 0 | "2.16.840.1.101.3.7.2.96.16", "01", "6010", SC_PKCS15_CO_FLAG_PRIVATE}, |
266 | 0 | {"06", "Printed Information", |
267 | 0 | "2.16.840.1.101.3.7.2.48.1", "01", "3001", SC_PKCS15_CO_FLAG_PRIVATE}, |
268 | 0 | {"07", "Cardholder Facial Image", |
269 | 0 | "2.16.840.1.101.3.7.2.96.48", "01", "6030", SC_PKCS15_CO_FLAG_PRIVATE}, |
270 | 0 | {"08", "X.509 Certificate for Digital Signature", |
271 | 0 | "2.16.840.1.101.3.7.2.1.0", NULL, "0100", 0}, |
272 | 0 | {"09", "X.509 Certificate for Key Management", |
273 | 0 | "2.16.840.1.101.3.7.2.1.2", NULL, "0102", 0}, |
274 | 0 | {"10","X.509 Certificate for Card Authentication", |
275 | 0 | "2.16.840.1.101.3.7.2.5.0", NULL, "0500", 0}, |
276 | 0 | {"11", "Security Object", |
277 | 0 | "2.16.840.1.101.3.7.2.144.0", NULL, "9000", 0}, |
278 | 0 | {"12", "Discovery Object", |
279 | 0 | "2.16.840.1.101.3.7.2.96.80", NULL, "6050", 0}, |
280 | 0 | {"13", "Key History Object", |
281 | 0 | "2.16.840.1.101.3.7.2.96.96", NULL, "6060", 0}, |
282 | 0 | {"14", "Cardholder Iris Image", |
283 | 0 | "2.16.840.1.101.3.7.2.16.21", NULL, "1015", SC_PKCS15_CO_FLAG_PRIVATE}, |
284 | |
|
285 | 0 | {"15", "Retired X.509 Certificate for Key Management 1", |
286 | 0 | "2.16.840.1.101.3.7.2.16.1", NULL, "1001", 0}, |
287 | 0 | {"16", "Retired X.509 Certificate for Key Management 2", |
288 | 0 | "2.16.840.1.101.3.7.2.16.2", NULL, "1002", 0}, |
289 | 0 | {"17", "Retired X.509 Certificate for Key Management 3", |
290 | 0 | "2.16.840.1.101.3.7.2.16.3", NULL, "1003", 0}, |
291 | 0 | {"18", "Retired X.509 Certificate for Key Management 4", |
292 | 0 | "2.16.840.1.101.3.7.2.16.4", NULL, "1004", 0}, |
293 | 0 | {"19", "Retired X.509 Certificate for Key Management 5", |
294 | 0 | "2.16.840.1.101.3.7.2.16.5", NULL, "1005", 0}, |
295 | 0 | {"20", "Retired X.509 Certificate for Key Management 6", |
296 | 0 | "2.16.840.1.101.3.7.2.16.6", NULL, "1006", 0}, |
297 | 0 | {"21", "Retired X.509 Certificate for Key Management 7", |
298 | 0 | "2.16.840.1.101.3.7.2.16.7", NULL, "1007", 0}, |
299 | 0 | {"22", "Retired X.509 Certificate for Key Management 8", |
300 | 0 | "2.16.840.1.101.3.7.2.16.8", NULL, "1008", 0}, |
301 | 0 | {"23", "Retired X.509 Certificate for Key Management 9", |
302 | 0 | "2.16.840.1.101.3.7.2.16.9", NULL, "1009", 0}, |
303 | 0 | {"24", "Retired X.509 Certificate for Key Management 10", |
304 | 0 | "2.16.840.1.101.3.7.2.16.10", NULL, "100A", 0}, |
305 | 0 | {"25", "Retired X.509 Certificate for Key Management 11", |
306 | 0 | "2.16.840.1.101.3.7.2.16.11", NULL, "100B", 0}, |
307 | 0 | {"26", "Retired X.509 Certificate for Key Management 12", |
308 | 0 | "2.16.840.1.101.3.7.2.16.12", NULL, "100C", 0}, |
309 | 0 | {"27", "Retired X.509 Certificate for Key Management 13", |
310 | 0 | "2.16.840.1.101.3.7.2.16.13", NULL, "100D", 0}, |
311 | 0 | {"28", "Retired X.509 Certificate for Key Management 14", |
312 | 0 | "2.16.840.1.101.3.7.2.16.14", NULL, "100E", 0}, |
313 | 0 | {"29", "Retired X.509 Certificate for Key Management 15", |
314 | 0 | "2.16.840.1.101.3.7.2.16.15", NULL, "100F", 0}, |
315 | 0 | {"30", "Retired X.509 Certificate for Key Management 16", |
316 | 0 | "2.16.840.1.101.3.7.2.16.16", NULL, "1010", 0}, |
317 | 0 | {"31", "Retired X.509 Certificate for Key Management 17", |
318 | 0 | "2.16.840.1.101.3.7.2.16.17", NULL, "1011", 0}, |
319 | 0 | {"32", "Retired X.509 Certificate for Key Management 18", |
320 | 0 | "2.16.840.1.101.3.7.2.16.18", NULL, "1012", 0}, |
321 | 0 | {"33", "Retired X.509 Certificate for Key Management 19", |
322 | 0 | "2.16.840.1.101.3.7.2.16.19", NULL, "1013", 0}, |
323 | 0 | {"34", "Retired X.509 Certificate for Key Management 20", |
324 | 0 | "2.16.840.1.101.3.7.2.16.20", NULL, "1014", 0}, |
325 | | /* new in 800-73-4 */ |
326 | 0 | {"35", "Biometric Information Templates Group Template", |
327 | 0 | "2.16.840.1.101.3.7.2.16.22", NULL, "1016", 0}, |
328 | 0 | {"36", "Secure Messaging Certificate Signer", |
329 | 0 | "2.16.840.1.101.3.7.2.16.23", NULL, "1017", 0}, |
330 | 0 | {"37", "Pairing Code Reference Data Container", |
331 | 0 | "2.16.840.1.101.3.7.2.16.24", NULL, "1018", SC_PKCS15_CO_FLAG_PRIVATE}, |
332 | 0 | {NULL, NULL, NULL, NULL, NULL, 0} |
333 | 0 | }; |
334 | | // clang-format on |
335 | | /* NIST 800-73-1 lifted the restriction on |
336 | | * requiring pin protected certs. Thus the default is to |
337 | | * not require this. |
338 | | * |
339 | | * Certs will be pulled out from the cert objects |
340 | | * But there may be extra certs (SM Signer cert) that do |
341 | | * not have a private keys on the card. These certs must be last |
342 | | */ |
343 | | |
344 | | /* Any certs on card without private key must be last */ |
345 | 0 | #define PIV_NUM_CERTS 25 |
346 | 0 | #define PIV_NUM_KEYS 24 |
347 | | |
348 | | // clang-format off |
349 | 0 | static const cdata certs[PIV_NUM_CERTS] = { |
350 | 0 | {"01", "Certificate for PIV Authentication", "0101cece", 0, 0}, |
351 | 0 | {"02", "Certificate for Digital Signature", "0100cece", 0, 0}, |
352 | 0 | {"03", "Certificate for Key Management", "0102cece", 0, 0}, |
353 | 0 | {"04", "Certificate for Card Authentication", "0500cece", 0, 0}, |
354 | 0 | {"05", "Retired Certificate for Key Management 1", "1001cece", 0, 0}, |
355 | 0 | {"06", "Retired Certificate for Key Management 2", "1002cece", 0, 0}, |
356 | 0 | {"07", "Retired Certificate for Key Management 3", "1003cece", 0, 0}, |
357 | 0 | {"08", "Retired Certificate for Key Management 4", "1004cece", 0, 0}, |
358 | 0 | {"09", "Retired Certificate for Key Management 5", "1005cece", 0, 0}, |
359 | 0 | {"10", "Retired Certificate for Key Management 6", "1006cece", 0, 0}, |
360 | 0 | {"11", "Retired Certificate for Key Management 7", "1007cece", 0, 0}, |
361 | 0 | {"12", "Retired Certificate for Key Management 8", "1008cece", 0, 0}, |
362 | 0 | {"13", "Retired Certificate for Key Management 9", "1009cece", 0, 0}, |
363 | 0 | {"14", "Retired Certificate for Key Management 10", "100Acece", 0, 0}, |
364 | 0 | {"15", "Retired Certificate for Key Management 11", "100Bcece", 0, 0}, |
365 | 0 | {"16", "Retired Certificate for Key Management 12", "100Ccece", 0, 0}, |
366 | 0 | {"17", "Retired Certificate for Key Management 13", "100Dcece", 0, 0}, |
367 | 0 | {"18", "Retired Certificate for Key Management 14", "100Ecece", 0, 0}, |
368 | 0 | {"19", "Retired Certificate for Key Management 15", "100Fcece", 0, 0}, |
369 | 0 | {"20", "Retired Certificate for Key Management 16", "1010cece", 0, 0}, |
370 | 0 | {"21", "Retired Certificate for Key Management 17", "1011cece", 0, 0}, |
371 | 0 | {"22", "Retired Certificate for Key Management 18", "1012cece", 0, 0}, |
372 | 0 | {"23", "Retired Certificate for Key Management 19", "1013cece", 0, 0}, |
373 | 0 | {"24", "Retired Certificate for Key Management 20", "1014cece", 0, 0}, |
374 | | /* Yubikey Attestation uses "25" but not read via GET_DATA */ |
375 | 0 | {"81", "Secure Messaging Certificate Signer", "1017cece", 0, 0} /* no keys on card */ |
376 | 0 | }; |
377 | | // clang-format on |
378 | | |
379 | | // clang-format off |
380 | 0 | static const pindata pins[] = { |
381 | 0 | { "01", "PIN", "", 0x80, |
382 | | /* label, flag and ref will change if using global pin */ |
383 | 0 | SC_PKCS15_PIN_TYPE_ASCII_NUMERIC, |
384 | 0 | 8, 4, 8, |
385 | 0 | SC_PKCS15_PIN_FLAG_NEEDS_PADDING | |
386 | 0 | SC_PKCS15_PIN_FLAG_INITIALIZED | |
387 | 0 | SC_PKCS15_PIN_FLAG_LOCAL, |
388 | 0 | -1, 0xFF, |
389 | 0 | SC_PKCS15_CO_FLAG_PRIVATE, 0}, |
390 | |
|
391 | 0 | { "02", "PIV PUK", "", 0x81, |
392 | 0 | SC_PKCS15_PIN_TYPE_ASCII_NUMERIC, |
393 | 0 | 8, 4, 8, |
394 | 0 | SC_PKCS15_PIN_FLAG_NEEDS_PADDING | |
395 | 0 | SC_PKCS15_PIN_FLAG_INITIALIZED | |
396 | 0 | SC_PKCS15_PIN_FLAG_SO_PIN | |
397 | 0 | SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN, |
398 | 0 | -1, 0xFF, |
399 | 0 | SC_PKCS15_CO_FLAG_PRIVATE, 0}, |
400 | | |
401 | | /* only used with minidriver */ |
402 | 0 | { "03", "PIN", "", 0x80, |
403 | | /* used in minidriver as the sign key and for 9C key */ |
404 | | /* label, flag and ref will change if using global pin */ |
405 | 0 | SC_PKCS15_PIN_TYPE_ASCII_NUMERIC, |
406 | 0 | 8, 4, 8, |
407 | 0 | SC_PKCS15_PIN_FLAG_NEEDS_PADDING | |
408 | 0 | SC_PKCS15_PIN_FLAG_INITIALIZED | |
409 | 0 | SC_PKCS15_PIN_FLAG_LOCAL, |
410 | 0 | -1, 0xFF, |
411 | 0 | SC_PKCS15_CO_FLAG_PRIVATE, 1}, /* only use if cardmod */ |
412 | 0 | { NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} |
413 | 0 | }; |
414 | | // clang-format on |
415 | | |
416 | | |
417 | | /* |
418 | | * The size of the key or the algid is not really known |
419 | | * but can be derived from the certificates. |
420 | | * the cert, pubkey and privkey are a set. |
421 | | * Key usages bits taken from pkcs15v1_1 Table 2 |
422 | | * RSA and EC have different sets of usage |
423 | | */ |
424 | | // clang-format off |
425 | 0 | static const pubdata pubkeys[PIV_NUM_KEYS] = { |
426 | 0 | { "01", "PIV AUTH pubkey", |
427 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_ENCRYPT | |
428 | 0 | SC_PKCS15_PRKEY_USAGE_WRAP | |
429 | 0 | SC_PKCS15_PRKEY_USAGE_VERIFY | |
430 | 0 | SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER, |
431 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_VERIFY, |
432 | 0 | "9A06", 0x9A, NULL, 0, "PIV_9A_KEY"}, |
433 | 0 | { "02", "SIGN pubkey", |
434 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_ENCRYPT | |
435 | 0 | SC_PKCS15_PRKEY_USAGE_VERIFY | |
436 | 0 | SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER | |
437 | 0 | SC_PKCS15_PRKEY_USAGE_NONREPUDIATION, |
438 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_VERIFY | |
439 | 0 | SC_PKCS15_PRKEY_USAGE_NONREPUDIATION, |
440 | 0 | "9C06", 0x9C, NULL, 0, "PIV_9C_KEY"}, |
441 | 0 | { "03", "KEY MAN pubkey", |
442 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_ENCRYPT| SC_PKCS15_PRKEY_USAGE_WRAP, |
443 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
444 | 0 | "9D06", 0x9D, NULL, 0, "PIV_9D_KEY"}, |
445 | 0 | { "04", "CARD AUTH pubkey", |
446 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_VERIFY | |
447 | 0 | SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER, |
448 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_VERIFY, |
449 | 0 | "9E06", 0x9E, NULL, 0, "PIV_9E_KEY"}, /* no pin, and avail in contactless */ |
450 | |
|
451 | 0 | { "05", "Retired KEY MAN 1", |
452 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_WRAP, |
453 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
454 | 0 | "8206", 0x82, NULL, 0, NULL}, |
455 | 0 | { "06", "Retired KEY MAN 2", |
456 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_WRAP, |
457 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
458 | 0 | "8306", 0x83, NULL, 0, NULL}, |
459 | 0 | { "07", "Retired KEY MAN 3", |
460 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_WRAP, |
461 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
462 | 0 | "8406", 0x84, NULL, 0, NULL}, |
463 | 0 | { "08", "Retired KEY MAN 4", |
464 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_WRAP, |
465 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
466 | 0 | "8506", 0x85, NULL, 0, NULL}, |
467 | 0 | { "09", "Retired KEY MAN 5", |
468 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_WRAP, |
469 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
470 | 0 | "8606", 0x86, NULL, 0, NULL}, |
471 | 0 | { "10", "Retired KEY MAN 6", |
472 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_WRAP, |
473 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
474 | 0 | "8706", 0x87, NULL, 0, NULL}, |
475 | 0 | { "11", "Retired KEY MAN 7", |
476 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_WRAP, |
477 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
478 | 0 | "8806", 0x88, NULL, 0, NULL}, |
479 | 0 | { "12", "Retired KEY MAN 8", |
480 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_WRAP, |
481 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
482 | 0 | "8906", 0x89, NULL, 0, NULL}, |
483 | 0 | { "13", "Retired KEY MAN 9", |
484 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_WRAP, |
485 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
486 | 0 | "8A06", 0x8A, NULL, 0, NULL}, |
487 | 0 | { "14", "Retired KEY MAN 10", |
488 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_WRAP, |
489 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
490 | 0 | "8B06", 0x8B, NULL, 0, NULL}, |
491 | 0 | { "15", "Retired KEY MAN 11", |
492 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_WRAP, |
493 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
494 | 0 | "8C06", 0x8C, NULL, 0, NULL}, |
495 | 0 | { "16", "Retired KEY MAN 12", |
496 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_WRAP, |
497 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
498 | 0 | "8D06", 0x8D, NULL, 0, NULL}, |
499 | 0 | { "17", "Retired KEY MAN 13", |
500 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_WRAP, |
501 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
502 | 0 | "8E06", 0x8E, NULL, 0, NULL}, |
503 | 0 | { "18", "Retired KEY MAN 14", |
504 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_WRAP, |
505 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
506 | 0 | "8F06", 0x8F, NULL, 0, NULL}, |
507 | 0 | { "19", "Retired KEY MAN 15", |
508 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_WRAP, |
509 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
510 | 0 | "9006", 0x90, NULL, 0, NULL}, |
511 | 0 | { "20", "Retired KEY MAN 16", |
512 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_WRAP, |
513 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
514 | 0 | "9106", 0x91, NULL, 0, NULL}, |
515 | 0 | { "21", "Retired KEY MAN 17", |
516 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_WRAP, |
517 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
518 | 0 | "9206", 0x92, NULL, 0, NULL}, |
519 | 0 | { "22", "Retired KEY MAN 18", |
520 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_WRAP, |
521 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
522 | 0 | "9306", 0x93, NULL, 0, NULL}, |
523 | 0 | { "23", "Retired KEY MAN 19", |
524 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_WRAP, |
525 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
526 | 0 | "9406", 0x94, NULL, 0, NULL}, |
527 | 0 | { "24", "Retired KEY MAN 20", |
528 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_WRAP, |
529 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
530 | 0 | "9506", 0x95, NULL, 0, NULL} |
531 | 0 | }; |
532 | | // clang-format on |
533 | | |
534 | | /* |
535 | | * Note some of the SC_PKCS15_PRKEY values are dependent |
536 | | * on the key algorithm, and will be reset. |
537 | | |
538 | | * No SM Signer private Key on card |
539 | | * The 04 SM ECC CVC pubkey is in response to SELECT AID |
540 | | */ |
541 | | // clang-format off |
542 | 0 | static const prdata prkeys[PIV_NUM_KEYS] = { |
543 | 0 | { "01", "PIV AUTH key", |
544 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | |
545 | 0 | SC_PKCS15_PRKEY_USAGE_UNWRAP | |
546 | 0 | SC_PKCS15_PRKEY_USAGE_SIGN | |
547 | 0 | SC_PKCS15_PRKEY_USAGE_SIGNRECOVER, |
548 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_SIGN, |
549 | 0 | "", 0x9A, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, |
550 | 0 | { "02", "SIGN key", |
551 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | |
552 | 0 | SC_PKCS15_PRKEY_USAGE_SIGN | |
553 | 0 | SC_PKCS15_PRKEY_USAGE_SIGNRECOVER | |
554 | 0 | SC_PKCS15_PRKEY_USAGE_NONREPUDIATION, |
555 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_SIGN | |
556 | 0 | SC_PKCS15_PRKEY_USAGE_NONREPUDIATION, |
557 | 0 | "", 0x9C, "01", SC_PKCS15_CO_FLAG_PRIVATE, 1}, /* use sign pin and user_consent */ |
558 | 0 | { "03", "KEY MAN key", |
559 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, |
560 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
561 | 0 | "", 0x9D, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, |
562 | 0 | { "04", "CARD AUTH key", |
563 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_SIGN | |
564 | 0 | SC_PKCS15_PRKEY_USAGE_SIGNRECOVER, |
565 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_SIGN, |
566 | 0 | "", 0x9E, NULL, 0, 0}, /* no PIN needed, works with wireless */ |
567 | 0 | { "05", "Retired KEY MAN 1", |
568 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, |
569 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
570 | 0 | "", 0x82, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, |
571 | 0 | { "06", "Retired KEY MAN 2", |
572 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, |
573 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
574 | 0 | "", 0x83, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, |
575 | 0 | { "07", "Retired KEY MAN 3", |
576 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, |
577 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
578 | 0 | "", 0x84, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, |
579 | 0 | { "08", "Retired KEY MAN 4", |
580 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, |
581 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
582 | 0 | "", 0x85, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, |
583 | 0 | { "09", "Retired KEY MAN 5", |
584 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, |
585 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
586 | 0 | "", 0x86, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, |
587 | 0 | { "10", "Retired KEY MAN 6", |
588 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, |
589 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
590 | 0 | "", 0x87, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, |
591 | 0 | { "11", "Retired KEY MAN 7", |
592 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, |
593 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
594 | 0 | "", 0x88, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, |
595 | 0 | { "12", "Retired KEY MAN 8", |
596 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, |
597 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
598 | 0 | "", 0x89, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, |
599 | 0 | { "13", "Retired KEY MAN 9", |
600 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, |
601 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
602 | 0 | "", 0x8A, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, |
603 | 0 | { "14", "Retired KEY MAN 10", |
604 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, |
605 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
606 | 0 | "", 0x8B, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, |
607 | 0 | { "15", "Retired KEY MAN 11", |
608 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, |
609 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
610 | 0 | "", 0x8C, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, |
611 | 0 | { "16", "Retired KEY MAN 12", |
612 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, |
613 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
614 | 0 | "", 0x8D, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, |
615 | 0 | { "17", "Retired KEY MAN 13", |
616 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, |
617 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
618 | 0 | "", 0x8E, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, |
619 | 0 | { "18", "Retired KEY MAN 14", |
620 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, |
621 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
622 | 0 | "", 0x8F, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, |
623 | 0 | { "19", "Retired KEY MAN 15", |
624 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, |
625 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
626 | 0 | "", 0x90, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, |
627 | 0 | { "20", "Retired KEY MAN 16", |
628 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, |
629 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
630 | 0 | "", 0x91, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, |
631 | 0 | { "21", "Retired KEY MAN 17", |
632 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, |
633 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
634 | 0 | "", 0x92, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, |
635 | 0 | { "22", "Retired KEY MAN 18", |
636 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, |
637 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
638 | 0 | "", 0x93, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, |
639 | 0 | { "23", "Retired KEY MAN 19", |
640 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, |
641 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
642 | 0 | "", 0x94, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0}, |
643 | 0 | { "24", "Retired KEY MAN 20", |
644 | 0 | /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP, |
645 | 0 | /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE, |
646 | 0 | "", 0x95, "01", SC_PKCS15_CO_FLAG_PRIVATE, 0} |
647 | | /* SM Signer certificate does not have private key on card */ |
648 | 0 | }; |
649 | | // clang-format on |
650 | |
|
651 | 0 | int r, i; |
652 | 0 | sc_card_t *card = p15card->card; |
653 | 0 | sc_serial_number_t serial; |
654 | 0 | char buf[SC_MAX_SERIALNR * 2 + 1]; |
655 | 0 | common_key_info ckis[PIV_NUM_CERTS]; |
656 | 0 | int follows_nist_fascn = 0; |
657 | 0 | char *token_name = NULL; |
658 | |
|
659 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
660 | |
|
661 | 0 | memset(&serial, 0, sizeof(serial)); |
662 | | |
663 | | /* could read this off card if needed */ |
664 | | |
665 | | /* CSP does not like a - in the name */ |
666 | 0 | set_string(&p15card->tokeninfo->label, "PIV_II"); |
667 | 0 | set_string(&p15card->tokeninfo->manufacturer_id, MANU_ID); |
668 | | |
669 | | /* |
670 | | * get serial number |
671 | | * We will use the FASC-N from the CHUID |
672 | | * Note we are not verifying CHUID, belongs to this card |
673 | | * but need serial number for Mac tokend |
674 | | */ |
675 | |
|
676 | 0 | r = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serial); |
677 | 0 | if (r < 0) { |
678 | 0 | sc_log(card->ctx, "sc_card_ctl rc=%d",r); |
679 | 0 | set_string(&p15card->tokeninfo->serial_number, "00000000"); |
680 | 0 | } else { |
681 | 0 | sc_bin_to_hex(serial.value, serial.len, buf, sizeof(buf), 0); |
682 | 0 | set_string(&p15card->tokeninfo->serial_number, buf); |
683 | 0 | } |
684 | | /* US gov issued PIVs have CHUID with a FASCN that does not start with 9999 */ |
685 | 0 | if (serial.len == 25 && !(serial.value[0] == 0xD4 && serial.value[1] == 0xE7 && serial.value[2] == 0x39 && (serial.value[3] | 0x7F) == 0xFF)) { |
686 | 0 | follows_nist_fascn = 1; |
687 | 0 | } |
688 | |
|
689 | 0 | sc_log(card->ctx, "PIV-II adding objects..."); |
690 | | |
691 | | /* set other objects */ |
692 | 0 | for (i = 0; objects[i].label; i++) { |
693 | 0 | struct sc_pkcs15_data_info obj_info; |
694 | 0 | struct sc_pkcs15_object obj_obj; |
695 | |
|
696 | 0 | memset(&obj_info, 0, sizeof(obj_info)); |
697 | 0 | memset(&obj_obj, 0, sizeof(obj_obj)); |
698 | 0 | sc_pkcs15_format_id(objects[i].id, &obj_info.id); |
699 | 0 | sc_format_path(objects[i].path, &obj_info.path); |
700 | | |
701 | | /* See if the object can not be present on the card */ |
702 | 0 | r = sc_card_ctl(card, SC_CARDCTL_PIV_OBJECT_PRESENT, &obj_info.path); |
703 | 0 | if (r == 1) |
704 | 0 | continue; /* Not on card, do not define the object */ |
705 | | |
706 | 0 | strncpy(obj_info.app_label, objects[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1); |
707 | 0 | r = sc_format_oid(&obj_info.app_oid, objects[i].aoid); |
708 | 0 | if (r != SC_SUCCESS) |
709 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
710 | | |
711 | | /* We can not read all the objects, as some need the PIN! */ |
712 | 0 | if (objects[i].auth_id) |
713 | 0 | sc_pkcs15_format_id(objects[i].auth_id, &obj_obj.auth_id); |
714 | |
|
715 | 0 | strncpy(obj_obj.label, objects[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1); |
716 | 0 | obj_obj.flags = objects[i].obj_flags; |
717 | |
|
718 | 0 | r = sc_pkcs15emu_object_add(p15card, SC_PKCS15_TYPE_DATA_OBJECT, |
719 | 0 | &obj_obj, &obj_info); |
720 | |
|
721 | 0 | if (r < 0) |
722 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
723 | 0 | } |
724 | | |
725 | | /* |
726 | | * certs, pubkeys and priv keys are related and we assume |
727 | | * they are in order |
728 | | * We need to read the cert, get modulus and keylen |
729 | | * We use those for the pubkey, and priv key objects. |
730 | | * If no cert, then see if pubkey (i.e. we are initializing, |
731 | | * and the pubkey is in a file,) then add pubkey and privkey |
732 | | * If no cert and no pubkey, skip adding them. |
733 | | |
734 | | */ |
735 | | /* set certs */ |
736 | 0 | sc_log(card->ctx, "PIV-II adding certs..."); |
737 | 0 | for (i = 0; i < PIV_NUM_CERTS; i++) { |
738 | 0 | struct sc_pkcs15_cert_info cert_info; |
739 | 0 | struct sc_pkcs15_object cert_obj; |
740 | 0 | sc_pkcs15_der_t cert_der; |
741 | 0 | sc_pkcs15_cert_t *cert_out = NULL; |
742 | 0 | int private_obj; |
743 | |
|
744 | 0 | ckis[i].cert_found = 0; |
745 | 0 | ckis[i].key_alg = -1; |
746 | 0 | ckis[i].pubkey_found = 0; |
747 | 0 | ckis[i].pubkey_from_file = 0; |
748 | 0 | ckis[i].pubkey_len = 0; |
749 | 0 | ckis[i].pubkey_from_cert = NULL; |
750 | 0 | ckis[i].cert_keyUsage = 0; |
751 | 0 | ckis[i].cert_keyUsage_present = 0; |
752 | 0 | ckis[i].pub_usage = 0; |
753 | 0 | ckis[i].priv_usage = 0; |
754 | |
|
755 | 0 | memset(&cert_info, 0, sizeof(cert_info)); |
756 | 0 | memset(&cert_obj, 0, sizeof(cert_obj)); |
757 | |
|
758 | 0 | sc_pkcs15_format_id(certs[i].id, &cert_info.id); |
759 | 0 | cert_info.authority = certs[i].authority; |
760 | 0 | sc_format_path(certs[i].path, &cert_info.path); |
761 | |
|
762 | 0 | strncpy(cert_obj.label, certs[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1); |
763 | 0 | cert_obj.flags = certs[i].obj_flags; |
764 | | |
765 | | /* See if the cert might be present or not. */ |
766 | 0 | r = sc_card_ctl(card, SC_CARDCTL_PIV_OBJECT_PRESENT, &cert_info.path); |
767 | 0 | if (r == 1) { |
768 | 0 | sc_log(card->ctx, "Cert can not be present,i=%d", i); |
769 | 0 | continue; |
770 | 0 | } |
771 | | |
772 | 0 | private_obj = cert_obj.flags & SC_PKCS15_CO_FLAG_PRIVATE; |
773 | 0 | r = sc_pkcs15_read_file(p15card, &cert_info.path, &cert_der.value, &cert_der.len, private_obj); |
774 | |
|
775 | 0 | if (r) { |
776 | 0 | sc_log(card->ctx, "No cert found,i=%d", i); |
777 | 0 | continue; |
778 | 0 | } |
779 | | |
780 | 0 | ckis[i].cert_found = 1; |
781 | | /* cache it using the PKCS15 emulation objects */ |
782 | | /* as it does not change */ |
783 | 0 | if (cert_der.value) { |
784 | 0 | cert_info.value.value = cert_der.value; |
785 | 0 | cert_info.value.len = cert_der.len; |
786 | 0 | if (!p15card->opts.use_file_cache |
787 | 0 | || (private_obj && !(p15card->opts.use_file_cache & SC_PKCS15_OPTS_CACHE_ALL_FILES))) { |
788 | 0 | cert_info.path.len = 0; /* use in mem cert from now on */ |
789 | 0 | } |
790 | 0 | } |
791 | | /* following will find the cached cert in cert_info */ |
792 | 0 | r = sc_pkcs15_read_certificate(p15card, &cert_info, private_obj, &cert_out); |
793 | 0 | if (r < 0 || cert_out == NULL || cert_out->key == NULL) { |
794 | 0 | sc_log(card->ctx, "Failed to read/parse the certificate r=%d",r); |
795 | 0 | if (cert_out != NULL) |
796 | 0 | sc_pkcs15_free_certificate(cert_out); |
797 | 0 | free(cert_der.value); |
798 | 0 | continue; |
799 | 0 | } |
800 | | |
801 | | /* set the token name to the name of the CN of the first certificate */ |
802 | 0 | if (!token_name) { |
803 | 0 | u8 * cn_name = NULL; |
804 | 0 | size_t cn_len = 0; |
805 | 0 | static const struct sc_object_id cn_oid = {{ 2, 5, 4, 3, -1 }}; |
806 | 0 | r = sc_pkcs15_get_name_from_dn(card->ctx, cert_out->subject, |
807 | 0 | cert_out->subject_len, &cn_oid, &cn_name, &cn_len); |
808 | 0 | if (r == SC_SUCCESS) { |
809 | 0 | token_name = malloc (cn_len+1); |
810 | 0 | if (!token_name) { |
811 | 0 | sc_pkcs15_free_certificate(cert_out); |
812 | 0 | free(cn_name); |
813 | 0 | r = SC_ERROR_OUT_OF_MEMORY; |
814 | 0 | LOG_TEST_GOTO_ERR(card->ctx, r, |
815 | 0 | "Failed to allocate memory"); |
816 | 0 | } |
817 | 0 | memcpy(token_name, cn_name, cn_len); |
818 | 0 | free(cn_name); |
819 | 0 | token_name[cn_len] = 0; |
820 | 0 | free(p15card->tokeninfo->label); |
821 | 0 | p15card->tokeninfo->label = token_name; |
822 | 0 | } |
823 | 0 | } |
824 | | |
825 | | /* |
826 | | * get keyUsage if present save in ckis[i] |
827 | | * Will only use it if this in a non FED issued card |
828 | | * which has a CHUID with FASC-N not starting with 9999 |
829 | | */ |
830 | | |
831 | 0 | if (follows_nist_fascn == 0) { |
832 | 0 | struct sc_object_id keyUsage_oid={{2,5,29,15,-1}}; |
833 | 0 | int r = 0; |
834 | |
|
835 | 0 | r = sc_pkcs15_get_bitstring_extension(card->ctx, cert_out, |
836 | 0 | &keyUsage_oid, |
837 | 0 | &ckis[i].cert_keyUsage, NULL); |
838 | 0 | if ( r >= 0) |
839 | 0 | ckis[i].cert_keyUsage_present = 1; |
840 | | /* TODO if no key usage, we could set all uses */ |
841 | 0 | } |
842 | | |
843 | |
|
844 | 0 | ckis[i].key_alg = cert_out->key->algorithm; |
845 | 0 | switch (cert_out->key->algorithm) { |
846 | 0 | case SC_ALGORITHM_RSA: |
847 | | /* save pubkey_len for pub and priv */ |
848 | 0 | ckis[i].pubkey_len = cert_out->key->u.rsa.modulus.len * 8; |
849 | | /* See RFC 5280 and PKCS#11 V2.40 */ |
850 | 0 | if (ckis[i].cert_keyUsage_present) { |
851 | 0 | if (ckis[i].cert_keyUsage & SC_X509_DIGITAL_SIGNATURE) { |
852 | 0 | ckis[i].pub_usage |= SC_PKCS15_PRKEY_USAGE_ENCRYPT /* extra*/ |
853 | 0 | |SC_PKCS15_PRKEY_USAGE_WRAP |
854 | 0 | |SC_PKCS15_PRKEY_USAGE_VERIFY |
855 | 0 | |SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER; |
856 | 0 | ckis[i].priv_usage |= SC_PKCS15_PRKEY_USAGE_DECRYPT /*extra */ |
857 | 0 | |SC_PKCS15_PRKEY_USAGE_UNWRAP |
858 | 0 | |SC_PKCS15_PRKEY_USAGE_SIGN |
859 | 0 | |SC_PKCS15_PRKEY_USAGE_SIGNRECOVER; |
860 | 0 | } |
861 | 0 | if (ckis[i].cert_keyUsage & SC_X509_NON_REPUDIATION) { |
862 | 0 | ckis[i].pub_usage |= SC_PKCS15_PRKEY_USAGE_ENCRYPT /* extra */ |
863 | 0 | |SC_PKCS15_PRKEY_USAGE_NONREPUDIATION |
864 | 0 | |SC_PKCS15_PRKEY_USAGE_VERIFY |
865 | 0 | |SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER; |
866 | 0 | ckis[i].priv_usage |= SC_PKCS15_PRKEY_USAGE_DECRYPT /*extra*/ |
867 | 0 | |SC_PKCS15_PRKEY_USAGE_NONREPUDIATION |
868 | 0 | |SC_PKCS15_PRKEY_USAGE_SIGN |
869 | 0 | |SC_PKCS15_PRKEY_USAGE_SIGNRECOVER; |
870 | 0 | } |
871 | 0 | if (ckis[i].cert_keyUsage & SC_X509_KEY_ENCIPHERMENT) { |
872 | 0 | ckis[i].pub_usage |= SC_PKCS15_PRKEY_USAGE_ENCRYPT| SC_PKCS15_PRKEY_USAGE_WRAP; |
873 | 0 | ckis[i].priv_usage |= SC_PKCS15_PRKEY_USAGE_DECRYPT| SC_PKCS15_PRKEY_USAGE_UNWRAP; |
874 | 0 | } |
875 | 0 | if (ckis[i].cert_keyUsage & SC_X509_DATA_ENCIPHERMENT) { |
876 | 0 | ckis[i].pub_usage |= SC_PKCS15_PRKEY_USAGE_ENCRYPT; |
877 | 0 | ckis[i].priv_usage |= SC_PKCS15_PRKEY_USAGE_DECRYPT; |
878 | 0 | } |
879 | 0 | if (ckis[i].cert_keyUsage & SC_X509_KEY_AGREEMENT) { |
880 | 0 | ckis[i].pub_usage |= SC_PKCS15_PRKEY_USAGE_DERIVE; |
881 | 0 | ckis[i].priv_usage |= SC_PKCS15_PRKEY_USAGE_DERIVE; |
882 | 0 | } |
883 | 0 | if (ckis[i].cert_keyUsage & SC_X509_KEY_CERT_SIGN) { |
884 | 0 | ckis[i].pub_usage |= SC_PKCS15_PRKEY_USAGE_VERIFY|SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER; |
885 | 0 | ckis[i].priv_usage |= SC_PKCS15_PRKEY_USAGE_SIGN; |
886 | 0 | } |
887 | 0 | if (ckis[i].cert_keyUsage & SC_X509_CRL_SIGN) { |
888 | 0 | ckis[i].pub_usage |= SC_PKCS15_PRKEY_USAGE_VERIFY|SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER; |
889 | 0 | ckis[i].priv_usage |= SC_PKCS15_PRKEY_USAGE_SIGN; |
890 | 0 | } |
891 | 0 | if (ckis[i].cert_keyUsage & SC_X509_ENCIPHER_ONLY) { |
892 | 0 | ckis[i].pub_usage |= SC_PKCS15_PRKEY_USAGE_ENCRYPT|SC_PKCS15_PRKEY_USAGE_WRAP; |
893 | 0 | ckis[i].priv_usage |= SC_PKCS15_PRKEY_USAGE_DECRYPT|SC_PKCS15_PRKEY_USAGE_UNWRAP; |
894 | 0 | } |
895 | 0 | if (ckis[i].cert_keyUsage & SC_X509_DECIPHER_ONLY) { /* TODO is this correct */ |
896 | 0 | ckis[i].pub_usage |= SC_PKCS15_PRKEY_USAGE_DECRYPT|SC_PKCS15_PRKEY_USAGE_UNWRAP; |
897 | 0 | ckis[i].priv_usage |= SC_PKCS15_PRKEY_USAGE_ENCRYPT|SC_PKCS15_PRKEY_USAGE_WRAP; |
898 | 0 | } |
899 | 0 | } |
900 | 0 | break; |
901 | | |
902 | 0 | case SC_ALGORITHM_EC: |
903 | 0 | case SC_ALGORITHM_EDDSA: |
904 | 0 | case SC_ALGORITHM_XEDDSA: |
905 | 0 | ckis[i].pubkey_len = cert_out->key->u.ec.params.field_length; |
906 | 0 | if (ckis[i].cert_keyUsage_present) { |
907 | 0 | if (ckis[i].cert_keyUsage & SC_X509_DIGITAL_SIGNATURE) { |
908 | 0 | ckis[i].pub_usage |= SC_PKCS15_PRKEY_USAGE_VERIFY; |
909 | 0 | ckis[i].priv_usage |= SC_PKCS15_PRKEY_USAGE_SIGN; |
910 | 0 | } |
911 | 0 | if (ckis[i].cert_keyUsage & SC_X509_NON_REPUDIATION) { |
912 | 0 | ckis[i].pub_usage |= SC_PKCS15_PRKEY_USAGE_NONREPUDIATION; |
913 | 0 | ckis[i].priv_usage |= SC_PKCS15_PRKEY_USAGE_NONREPUDIATION; |
914 | 0 | } |
915 | 0 | if (ckis[i].cert_keyUsage & SC_X509_KEY_ENCIPHERMENT) { |
916 | 0 | ckis[i].pub_usage |= 0; |
917 | 0 | ckis[i].priv_usage |= 0; |
918 | 0 | } |
919 | 0 | if (ckis[i].cert_keyUsage & SC_X509_DATA_ENCIPHERMENT) { |
920 | 0 | ckis[i].pub_usage |= 0; |
921 | 0 | ckis[i].priv_usage |= 0; |
922 | 0 | } |
923 | 0 | if (ckis[i].cert_keyUsage & SC_X509_KEY_AGREEMENT) { |
924 | 0 | ckis[i].pub_usage |= SC_PKCS15_PRKEY_USAGE_DERIVE; |
925 | 0 | ckis[i].priv_usage |= SC_PKCS15_PRKEY_USAGE_DERIVE; |
926 | 0 | } |
927 | 0 | if (ckis[i].cert_keyUsage & SC_X509_KEY_CERT_SIGN) { |
928 | 0 | ckis[i].pub_usage |= SC_PKCS15_PRKEY_USAGE_VERIFY; |
929 | 0 | ckis[i].priv_usage |= SC_PKCS15_PRKEY_USAGE_SIGN; |
930 | 0 | } |
931 | 0 | if (ckis[i].cert_keyUsage & SC_X509_CRL_SIGN) { |
932 | 0 | ckis[i].pub_usage |= SC_PKCS15_PRKEY_USAGE_VERIFY; |
933 | 0 | ckis[i].priv_usage |= SC_PKCS15_PRKEY_USAGE_SIGN; |
934 | 0 | } |
935 | 0 | if (ckis[i].cert_keyUsage & SC_X509_ENCIPHER_ONLY) { |
936 | 0 | ckis[i].pub_usage |= 0; |
937 | 0 | ckis[i].priv_usage |= 0; |
938 | 0 | } |
939 | 0 | if (ckis[i].cert_keyUsage & SC_X509_DECIPHER_ONLY) { |
940 | 0 | ckis[i].pub_usage |= 0; |
941 | 0 | ckis[i].priv_usage |= 0; |
942 | 0 | } |
943 | 0 | } |
944 | 0 | break; |
945 | | |
946 | 0 | default: |
947 | 0 | sc_log(card->ctx, "Unsupported key.algorithm %lu", cert_out->key->algorithm); |
948 | 0 | ckis[i].pubkey_len = 0; /* set some value for now */ |
949 | 0 | } |
950 | 0 | if (i < PIV_NUM_KEYS) { /* Only save pub key if card can have private key */ |
951 | 0 | ckis[i].pubkey_from_cert = cert_out->key; |
952 | 0 | cert_out->key = NULL; |
953 | 0 | } |
954 | 0 | sc_pkcs15_free_certificate(cert_out); |
955 | |
|
956 | 0 | r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info); |
957 | 0 | if (r < 0) { |
958 | 0 | sc_log(card->ctx, " Failed to add cert obj r=%d",r); |
959 | 0 | continue; |
960 | 0 | } |
961 | 0 | } |
962 | | |
963 | | /* set pins */ |
964 | 0 | sc_log(card->ctx, "PIV-II adding pins..."); |
965 | 0 | for (i = 0; pins[i].label; i++) { |
966 | 0 | struct sc_pkcs15_auth_info pin_info; |
967 | 0 | struct sc_pkcs15_object pin_obj; |
968 | 0 | const char * label; |
969 | 0 | int pin_ref; |
970 | | |
971 | | /* the SignPIN is only used with minidriver */ |
972 | 0 | if (pins[i].cardmod && (strcmp(card->ctx->app_name, "cardmod") != 0)) |
973 | 0 | continue; |
974 | | |
975 | 0 | memset(&pin_info, 0, sizeof(pin_info)); |
976 | 0 | memset(&pin_obj, 0, sizeof(pin_obj)); |
977 | |
|
978 | 0 | pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN; |
979 | 0 | sc_pkcs15_format_id(pins[i].id, &pin_info.auth_id); |
980 | 0 | pin_info.attrs.pin.reference = pins[i].ref; |
981 | 0 | pin_info.attrs.pin.flags = pins[i].flags; |
982 | 0 | pin_info.attrs.pin.type = pins[i].type; |
983 | 0 | pin_info.attrs.pin.min_length = pins[i].minlen; |
984 | 0 | pin_info.attrs.pin.stored_length = pins[i].storedlen; |
985 | 0 | pin_info.attrs.pin.max_length = pins[i].maxlen; |
986 | 0 | pin_info.attrs.pin.pad_char = pins[i].pad_char; |
987 | 0 | pin_info.tries_left = pins[i].tries_left; |
988 | 0 | sc_format_path(pins[i].path, &pin_info.path); |
989 | |
|
990 | 0 | label = pins[i].label; |
991 | 0 | if ((i == 0 || pins[i].cardmod) && |
992 | 0 | sc_card_ctl(card, SC_CARDCTL_PIV_PIN_PREFERENCE, |
993 | 0 | &pin_ref) == 0 && |
994 | 0 | pin_ref == 0x00) { /* must be 80 for PIV pin, or 00 for Global PIN */ |
995 | 0 | pin_info.attrs.pin.reference = pin_ref; |
996 | 0 | label = "Global PIN"; |
997 | 0 | } |
998 | |
|
999 | 0 | strncpy(pin_obj.label, label, SC_PKCS15_MAX_LABEL_SIZE - 1); |
1000 | 0 | pin_obj.flags = pins[i].obj_flags; |
1001 | 0 | if ((i == 0 || pins[i].cardmod)) { |
1002 | | /* |
1003 | | * according to description of "RESET RETRY COUNTER" |
1004 | | * command in specs PUK can only unblock PIV PIN |
1005 | | */ |
1006 | 0 | pin_obj.auth_id.len = 1; |
1007 | 0 | pin_obj.auth_id.value[0] = 2; |
1008 | 0 | } |
1009 | |
|
1010 | 0 | r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info); |
1011 | 0 | LOG_TEST_GOTO_ERR(card->ctx, r, "Failed to add PIN"); |
1012 | 0 | } |
1013 | | |
1014 | | /* set public keys */ |
1015 | | /* We may only need this during initialization when genkey |
1016 | | * gets the pubkey, but it can not be read from the card |
1017 | | * at a later time. The piv-tool can stash pubkey in file |
1018 | | */ |
1019 | 0 | sc_log(card->ctx, "PIV-II adding pub keys..."); |
1020 | 0 | for (i = 0; i < PIV_NUM_KEYS; i++) { |
1021 | 0 | struct sc_pkcs15_pubkey_info pubkey_info; |
1022 | 0 | struct sc_pkcs15_object pubkey_obj; |
1023 | 0 | struct sc_pkcs15_pubkey *p15_key = NULL; |
1024 | |
|
1025 | 0 | memset(&pubkey_info, 0, sizeof(pubkey_info)); |
1026 | 0 | memset(&pubkey_obj, 0, sizeof(pubkey_obj)); |
1027 | | |
1028 | |
|
1029 | 0 | sc_pkcs15_format_id(pubkeys[i].id, &pubkey_info.id); |
1030 | 0 | pubkey_info.native = 1; |
1031 | 0 | pubkey_info.key_reference = pubkeys[i].ref; |
1032 | | |
1033 | | // sc_format_path(pubkeys[i].path, &pubkey_info.path); |
1034 | |
|
1035 | 0 | strncpy(pubkey_obj.label, pubkeys[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1); |
1036 | |
|
1037 | 0 | pubkey_obj.flags = pubkeys[i].obj_flags; |
1038 | |
|
1039 | 0 | if (pubkeys[i].auth_id) |
1040 | 0 | sc_pkcs15_format_id(pubkeys[i].auth_id, &pubkey_obj.auth_id); |
1041 | | |
1042 | | /* If no cert found, piv-tool may have stashed the pubkey |
1043 | | * so we can use it when generating a certificate request |
1044 | | * The file is a OpenSSL DER EVP_KEY, which looks like |
1045 | | * a certificate subjectPublicKeyInfo. |
1046 | | * |
1047 | | */ |
1048 | 0 | if (ckis[i].cert_found == 0 ) { /* no cert found */ |
1049 | 0 | char * filename = NULL; |
1050 | |
|
1051 | 0 | sc_log(card->ctx, "No cert for this pub key i=%d",i); |
1052 | | |
1053 | | /* |
1054 | | * If we used the piv-tool to generate a key, |
1055 | | * we would have saved the public key as a file. |
1056 | | * This code is only used while signing a request |
1057 | | * After the certificate is loaded on the card, |
1058 | | * the public key is extracted from the certificate. |
1059 | | */ |
1060 | | |
1061 | |
|
1062 | 0 | sc_log(card->ctx, "DEE look for env %s", |
1063 | 0 | pubkeys[i].getenvname?pubkeys[i].getenvname:"NULL"); |
1064 | |
|
1065 | 0 | if (pubkeys[i].getenvname == NULL) |
1066 | 0 | continue; |
1067 | | |
1068 | 0 | filename = getenv(pubkeys[i].getenvname); |
1069 | 0 | sc_log(card->ctx, "DEE look for file %s", filename?filename:"NULL"); |
1070 | 0 | if (filename == NULL) |
1071 | 0 | continue; |
1072 | | |
1073 | 0 | sc_log(card->ctx, "Adding pubkey from file %s",filename); |
1074 | |
|
1075 | 0 | r = sc_pkcs15_pubkey_from_spki_file(card->ctx, filename, &p15_key); |
1076 | 0 | if (r < 0) { |
1077 | 0 | free(p15_key); |
1078 | 0 | continue; |
1079 | 0 | } |
1080 | | |
1081 | | /* Lets also try another method. */ |
1082 | 0 | r = sc_pkcs15_encode_pubkey_as_spki(card->ctx, p15_key, &pubkey_info.direct.spki.value, &pubkey_info.direct.spki.len); |
1083 | 0 | LOG_TEST_GOTO_ERR(card->ctx, r, "SPKI encode public key error"); |
1084 | | |
1085 | | /* Only get here if no cert, and the the above found the |
1086 | | * pub key file (actually the SPKI version). This only |
1087 | | * happens when trying initializing a card and have set |
1088 | | * env PIV_9A_KEY or 9C, 9D, 9E to point at the file. |
1089 | | * |
1090 | | * We will cache it using the PKCS15 emulation objects |
1091 | | */ |
1092 | | |
1093 | 0 | pubkey_info.path.len = 0; |
1094 | |
|
1095 | 0 | ckis[i].key_alg = p15_key->algorithm; |
1096 | 0 | switch (p15_key->algorithm) { |
1097 | 0 | case SC_ALGORITHM_RSA: |
1098 | | /* save pubkey_len in pub and priv */ |
1099 | 0 | ckis[i].pubkey_len = p15_key->u.rsa.modulus.len * 8; |
1100 | 0 | ckis[i].pubkey_found = 1; |
1101 | 0 | ckis[i].pubkey_from_file = 1; |
1102 | 0 | break; |
1103 | 0 | case SC_ALGORITHM_EC: |
1104 | 0 | case SC_ALGORITHM_EDDSA: |
1105 | 0 | case SC_ALGORITHM_XEDDSA: |
1106 | 0 | ckis[i].key_alg = p15_key->algorithm; |
1107 | 0 | ckis[i].pubkey_len = p15_key->u.ec.params.field_length; |
1108 | 0 | ckis[i].pubkey_found = 1; |
1109 | 0 | ckis[i].pubkey_from_file = 1; |
1110 | 0 | break; |
1111 | 0 | default: |
1112 | 0 | sc_log(card->ctx, "Unsupported key_alg %lu", p15_key->algorithm); |
1113 | 0 | continue; |
1114 | 0 | } |
1115 | 0 | pubkey_obj.emulated = p15_key; |
1116 | 0 | p15_key = NULL; |
1117 | 0 | } |
1118 | 0 | else if (ckis[i].pubkey_from_cert) { |
1119 | 0 | r = sc_pkcs15_encode_pubkey_as_spki(card->ctx, ckis[i].pubkey_from_cert, |
1120 | 0 | &pubkey_info.direct.spki.value, &pubkey_info.direct.spki.len); |
1121 | 0 | LOG_TEST_GOTO_ERR(card->ctx, r, "SPKI encode public key error"); |
1122 | | |
1123 | 0 | pubkey_obj.emulated = ckis[i].pubkey_from_cert; |
1124 | 0 | ckis[i].pubkey_from_cert = NULL; |
1125 | 0 | } |
1126 | | |
1127 | 0 | sc_log(card->ctx, "adding pubkey for %d keyalg=%lu", i, ckis[i].key_alg); |
1128 | 0 | switch (ckis[i].key_alg) { |
1129 | 0 | case SC_ALGORITHM_RSA: |
1130 | 0 | if (ckis[i].cert_keyUsage_present) { |
1131 | 0 | pubkey_info.usage = ckis[i].pub_usage; |
1132 | 0 | } else { |
1133 | 0 | pubkey_info.usage = pubkeys[i].usage_rsa; |
1134 | 0 | } |
1135 | 0 | pubkey_info.modulus_length = ckis[i].pubkey_len; |
1136 | 0 | strncpy(pubkey_obj.label, pubkeys[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1); |
1137 | | |
1138 | | /* should not fail */ |
1139 | 0 | r = sc_pkcs15emu_add_rsa_pubkey(p15card, &pubkey_obj, &pubkey_info); |
1140 | 0 | LOG_TEST_GOTO_ERR(card->ctx, r, "Failed to add RSA pubkey"); |
1141 | | |
1142 | 0 | ckis[i].pubkey_found = 1; |
1143 | 0 | break; |
1144 | 0 | case SC_ALGORITHM_EC: |
1145 | 0 | case SC_ALGORITHM_EDDSA: |
1146 | 0 | case SC_ALGORITHM_XEDDSA: |
1147 | 0 | if (ckis[i].cert_keyUsage_present) { |
1148 | 0 | pubkey_info.usage = ckis[i].pub_usage; |
1149 | 0 | } else { |
1150 | 0 | pubkey_info.usage = pubkeys[i].usage_ec; |
1151 | 0 | } |
1152 | |
|
1153 | 0 | pubkey_info.field_length = ckis[i].pubkey_len; |
1154 | 0 | strncpy(pubkey_obj.label, pubkeys[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1); |
1155 | | |
1156 | | /* should not fail */ |
1157 | |
|
1158 | 0 | if (ckis[i].key_alg == SC_ALGORITHM_EDDSA) |
1159 | 0 | r = sc_pkcs15emu_add_eddsa_pubkey(p15card, &pubkey_obj, &pubkey_info); |
1160 | 0 | else if (ckis[i].key_alg == SC_ALGORITHM_XEDDSA) |
1161 | 0 | r = sc_pkcs15emu_add_xeddsa_pubkey(p15card, &pubkey_obj, &pubkey_info); |
1162 | 0 | else |
1163 | 0 | r = sc_pkcs15emu_add_ec_pubkey(p15card, &pubkey_obj, &pubkey_info); |
1164 | |
|
1165 | 0 | LOG_TEST_GOTO_ERR(card->ctx, r, "Failed to add EC pubkey"); |
1166 | | |
1167 | 0 | ckis[i].pubkey_found = 1; |
1168 | 0 | break; |
1169 | 0 | default: |
1170 | 0 | sc_log(card->ctx, "key_alg %lu not supported", ckis[i].key_alg); |
1171 | 0 | continue; |
1172 | 0 | } |
1173 | 0 | sc_log(card->ctx, "USAGE: cert_keyUsage_present:%d usage:0x%8.8x", |
1174 | 0 | ckis[i].cert_keyUsage_present, pubkey_info.usage); |
1175 | 0 | } |
1176 | | |
1177 | | |
1178 | | /* set private keys */ |
1179 | 0 | sc_log(card->ctx, "PIV-II adding private keys..."); |
1180 | 0 | for (i = 0; i < PIV_NUM_KEYS; i++) { |
1181 | 0 | struct sc_pkcs15_prkey_info prkey_info; |
1182 | 0 | struct sc_pkcs15_object prkey_obj; |
1183 | |
|
1184 | 0 | memset(&prkey_info, 0, sizeof(prkey_info)); |
1185 | 0 | memset(&prkey_obj, 0, sizeof(prkey_obj)); |
1186 | |
|
1187 | 0 | if (ckis[i].cert_found == 0 && ckis[i].pubkey_found == 0) |
1188 | 0 | continue; /* i.e. no cert or pubkey */ |
1189 | | |
1190 | 0 | sc_pkcs15_format_id(prkeys[i].id, &prkey_info.id); |
1191 | 0 | prkey_info.native = 1; |
1192 | 0 | prkey_info.key_reference = prkeys[i].ref; |
1193 | 0 | sc_format_path(prkeys[i].path, &prkey_info.path); |
1194 | |
|
1195 | 0 | strncpy(prkey_obj.label, prkeys[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1); |
1196 | 0 | prkey_obj.flags = prkeys[i].obj_flags; |
1197 | 0 | prkey_obj.user_consent = prkeys[i].user_consent; /* only Sign key */ |
1198 | |
|
1199 | 0 | if (prkeys[i].auth_id) |
1200 | 0 | sc_pkcs15_format_id(prkeys[i].auth_id, &prkey_obj.auth_id); |
1201 | | |
1202 | | /* If using minidriver, use Sign PIN for 9C key */ |
1203 | 0 | if (prkey_obj.user_consent && (strcmp(card->ctx->app_name, "cardmod") == 0)) |
1204 | 0 | sc_pkcs15_format_id("03", &prkey_obj.auth_id); |
1205 | | |
1206 | | /* |
1207 | | * When no cert is present and a pubkey in a file was found, |
1208 | | * means the caller is initializing a card. A sign operation |
1209 | | * will be required to sign a certificate request even if |
1210 | | * normal usage would not allow it. Set SC_PKCS15_PRKEY_USAGE_SIGN |
1211 | | * TODO if code is added to allow key generation and request |
1212 | | * sign in the same session, similar code will be needed. |
1213 | | */ |
1214 | |
|
1215 | 0 | if (ckis[i].pubkey_from_file == 1) { |
1216 | 0 | prkey_info.usage = SC_PKCS15_PRKEY_USAGE_SIGN; |
1217 | 0 | sc_log(card->ctx, "Adding SC_PKCS15_PRKEY_USAGE_SIGN"); |
1218 | 0 | } |
1219 | |
|
1220 | 0 | switch (ckis[i].key_alg) { |
1221 | 0 | case SC_ALGORITHM_RSA: |
1222 | 0 | if(ckis[i].cert_keyUsage_present) { |
1223 | 0 | prkey_info.usage |= ckis[i].priv_usage; |
1224 | | /* If retired key and non gov cert has NONREPUDIATION, treat as user_consent */ |
1225 | 0 | if (i >= 4 && (ckis[i].priv_usage & SC_PKCS15_PRKEY_USAGE_NONREPUDIATION)) { |
1226 | 0 | prkey_obj.user_consent = 1; |
1227 | 0 | } |
1228 | 0 | } else { |
1229 | 0 | prkey_info.usage |= prkeys[i].usage_rsa; |
1230 | 0 | } |
1231 | 0 | prkey_info.modulus_length= ckis[i].pubkey_len; |
1232 | 0 | r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info); |
1233 | 0 | break; |
1234 | 0 | case SC_ALGORITHM_EC: |
1235 | 0 | case SC_ALGORITHM_EDDSA: |
1236 | 0 | case SC_ALGORITHM_XEDDSA: |
1237 | 0 | if (ckis[i].cert_keyUsage_present) { |
1238 | 0 | prkey_info.usage |= ckis[i].priv_usage; |
1239 | | /* If retired key and non gov cert has NONREPUDIATION, treat as user_consent */ |
1240 | 0 | if (i >= 4 && (ckis[i].priv_usage & SC_PKCS15_PRKEY_USAGE_NONREPUDIATION)) { |
1241 | 0 | prkey_obj.user_consent = 1; |
1242 | 0 | } |
1243 | 0 | } else { |
1244 | 0 | prkey_info.usage |= prkeys[i].usage_ec; |
1245 | 0 | } |
1246 | 0 | prkey_info.field_length = ckis[i].pubkey_len; |
1247 | 0 | sc_log(card->ctx, "DEE added key_alg %2.2lx prkey_obj.flags %8.8x", |
1248 | 0 | ckis[i].key_alg, prkey_obj.flags); |
1249 | |
|
1250 | 0 | if (ckis[i].key_alg == SC_ALGORITHM_EDDSA) |
1251 | 0 | r = sc_pkcs15emu_add_eddsa_prkey(p15card, &prkey_obj, &prkey_info); |
1252 | 0 | else if (ckis[i].key_alg == SC_ALGORITHM_XEDDSA) |
1253 | 0 | r = sc_pkcs15emu_add_xeddsa_prkey(p15card, &prkey_obj, &prkey_info); |
1254 | 0 | else |
1255 | 0 | r = sc_pkcs15emu_add_ec_prkey(p15card, &prkey_obj, &prkey_info); |
1256 | 0 | break; |
1257 | 0 | default: |
1258 | 0 | sc_log(card->ctx, "Unsupported key_alg %lu", ckis[i].key_alg); |
1259 | 0 | r = 0; /* we just skip this one */ |
1260 | 0 | } |
1261 | 0 | sc_log(card->ctx, "USAGE: cert_keyUsage_present:%d usage:0x%8.8x", ckis[i].cert_keyUsage_present, prkey_info.usage); |
1262 | 0 | LOG_TEST_GOTO_ERR(card->ctx, r, "Failed to add Private key"); |
1263 | 0 | } |
1264 | | |
1265 | 0 | p15card->ops.get_guid = piv_get_guid; |
1266 | |
|
1267 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
1268 | 0 | err: |
1269 | 0 | for (i = 0; i < PIV_NUM_CERTS; i++) { |
1270 | 0 | sc_pkcs15_free_pubkey(ckis[i].pubkey_from_cert); |
1271 | 0 | } |
1272 | 0 | sc_pkcs15_card_clear(p15card); |
1273 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
1274 | 0 | } |
1275 | | |
1276 | | int sc_pkcs15emu_piv_init_ex(sc_pkcs15_card_t *p15card, |
1277 | | struct sc_aid *aid) |
1278 | 0 | { |
1279 | 0 | sc_card_t *card = p15card->card; |
1280 | 0 | sc_context_t *ctx = card->ctx; |
1281 | |
|
1282 | 0 | SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); |
1283 | |
|
1284 | 0 | if (piv_detect_card(p15card)) |
1285 | 0 | return SC_ERROR_WRONG_CARD; |
1286 | 0 | return sc_pkcs15emu_piv_init(p15card); |
1287 | 0 | } |