/src/opensc/src/libopensc/pkcs15-cac.c
Line | Count | Source |
1 | | /* |
2 | | * partial PKCS15 emulation for CAC-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 | | * 2004, Nils Larsch <larsch@trustcenter.de> |
8 | | * Copyright (C) 2006, Identity Alliance, |
9 | | * Thomas Harning <thomas.harning@identityalliance.com> |
10 | | * Copyright (C) 2007, EMC, Russell Larner <rlarner@rsa.com> |
11 | | * Copyright (C) 2016, Red Hat, Inc. |
12 | | * |
13 | | * CAC driver author: Robert Relyea <rrelyea@redhat.com> |
14 | | * |
15 | | * This library is free software; you can redistribute it and/or |
16 | | * modify it under the terms of the GNU Lesser General Public |
17 | | * License as published by the Free Software Foundation; either |
18 | | * version 2.1 of the License, or (at your option) any later version. |
19 | | * |
20 | | * This library is distributed in the hope that it will be useful, |
21 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
22 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
23 | | * Lesser General Public License for more details. |
24 | | * |
25 | | * You should have received a copy of the GNU Lesser General Public |
26 | | * License along with this library; if not, write to the Free Software |
27 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
28 | | */ |
29 | | |
30 | | #ifdef HAVE_CONFIG_H |
31 | | #include "config.h" |
32 | | #endif |
33 | | |
34 | | #include <stdlib.h> |
35 | | #include <string.h> |
36 | | #include <stdio.h> |
37 | | #include <ctype.h> |
38 | | |
39 | | #include "internal.h" |
40 | | #include "cardctl.h" |
41 | | #include "pkcs15.h" |
42 | | /* X509 Key Usage flags */ |
43 | | #include "../pkcs15init/pkcs15-init.h" |
44 | | |
45 | | /* probably should get manufacturer ID from cuid */ |
46 | 849 | #define MANU_ID "Common Access Card" |
47 | | |
48 | | |
49 | | typedef struct pdata_st { |
50 | | const char *id; |
51 | | const char *label; |
52 | | const char *path; |
53 | | int ref; |
54 | | int type; |
55 | | unsigned int maxlen; |
56 | | unsigned int minlen; |
57 | | unsigned int storedlen; |
58 | | int flags; |
59 | | int tries_left; |
60 | | const unsigned char pad_char; |
61 | | int obj_flags; |
62 | | } pindata; |
63 | | |
64 | | static int cac_detect_card(sc_pkcs15_card_t *p15card) |
65 | 10.2k | { |
66 | 10.2k | sc_card_t *card = p15card->card; |
67 | | |
68 | 10.2k | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
69 | 10.2k | if (card->type < SC_CARD_TYPE_CAC_GENERIC |
70 | 1.43k | || card->type >= SC_CARD_TYPE_CAC_GENERIC+1000) |
71 | 9.37k | return SC_ERROR_INVALID_CARD; |
72 | 849 | return SC_SUCCESS; |
73 | 10.2k | } |
74 | | |
75 | | #define CAC_NUM_CERTS_AND_KEYS 10 |
76 | | |
77 | | static const char * cac_get_name(int type) |
78 | 849 | { |
79 | 849 | switch (type) { |
80 | 128 | case SC_CARD_TYPE_CAC_I: return ("CAC I"); |
81 | 396 | case SC_CARD_TYPE_CAC_II: return ("CAC II"); |
82 | 325 | case SC_CARD_TYPE_CAC_ALT_HID: return ("CAC ALT HID"); |
83 | 0 | default: break; |
84 | 849 | } |
85 | 0 | return ("CAC"); |
86 | 849 | } |
87 | | |
88 | | static int sc_pkcs15emu_cac_init(sc_pkcs15_card_t *p15card) |
89 | 849 | { |
90 | 849 | static const pindata pins[] = { |
91 | 849 | { "1", "PIN", "", 0x00, |
92 | 849 | SC_PKCS15_PIN_TYPE_ASCII_NUMERIC, |
93 | 849 | 8, 4, 8, |
94 | 849 | SC_PKCS15_PIN_FLAG_NEEDS_PADDING | |
95 | 849 | SC_PKCS15_PIN_FLAG_INITIALIZED , |
96 | 849 | -1, 0xFF, |
97 | 849 | SC_PKCS15_CO_FLAG_PRIVATE }, |
98 | 849 | { NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0} |
99 | 849 | }; |
100 | | /* oid for key usage */ |
101 | 849 | static const struct sc_object_id usage_type = {{ 2, 5, 29, 15, -1 }}; |
102 | 849 | unsigned int usage; |
103 | | |
104 | | |
105 | | /* |
106 | | * The size of the key or the algid is not really known |
107 | | * but can be derived from the certificates. |
108 | | * the cert, pubkey and privkey are a set. |
109 | | * Key usages bits taken from certificate key usage extension. |
110 | | */ |
111 | | |
112 | 849 | int r, i; |
113 | 849 | sc_card_t *card = p15card->card; |
114 | 849 | sc_serial_number_t serial; |
115 | 849 | char buf[SC_MAX_SERIALNR * 2 + 1]; |
116 | 849 | int count; |
117 | 849 | char *token_name = NULL; |
118 | | |
119 | | |
120 | 849 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
121 | | |
122 | 849 | memset(&serial, 0, sizeof(serial)); |
123 | | |
124 | | /* could read this off card if needed */ |
125 | | |
126 | 849 | set_string(&p15card->tokeninfo->label, cac_get_name(card->type)); |
127 | 849 | set_string(&p15card->tokeninfo->manufacturer_id, MANU_ID); |
128 | | |
129 | | /* |
130 | | * get serial number |
131 | | */ |
132 | 849 | r = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serial); |
133 | 849 | if (r < 0) { |
134 | 676 | sc_log(card->ctx, "sc_card_ctl rc=%d",r); |
135 | 676 | set_string(&p15card->tokeninfo->serial_number, "00000000"); |
136 | 676 | } else { |
137 | 173 | sc_bin_to_hex(serial.value, serial.len, buf, sizeof(buf), 0); |
138 | 173 | set_string(&p15card->tokeninfo->serial_number, buf); |
139 | 173 | } |
140 | | |
141 | | /* set pins */ |
142 | | /* TODO we should not create PIN objects if it is not initialized |
143 | | * (opensc-tool -s 0020000000 returns 0x6A 0x88) |
144 | | */ |
145 | 849 | sc_log(card->ctx, "CAC adding pins..."); |
146 | 1.69k | for (i = 0; pins[i].id; i++) { |
147 | 849 | struct sc_pkcs15_auth_info pin_info; |
148 | 849 | struct sc_pkcs15_object pin_obj; |
149 | 849 | const char * label; |
150 | | |
151 | 849 | memset(&pin_info, 0, sizeof(pin_info)); |
152 | 849 | memset(&pin_obj, 0, sizeof(pin_obj)); |
153 | | |
154 | 849 | pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN; |
155 | 849 | sc_pkcs15_format_id(pins[i].id, &pin_info.auth_id); |
156 | 849 | pin_info.attrs.pin.reference = pins[i].ref; |
157 | 849 | pin_info.attrs.pin.flags = pins[i].flags; |
158 | 849 | pin_info.attrs.pin.type = pins[i].type; |
159 | 849 | pin_info.attrs.pin.min_length = pins[i].minlen; |
160 | 849 | pin_info.attrs.pin.stored_length = pins[i].storedlen; |
161 | 849 | pin_info.attrs.pin.max_length = pins[i].maxlen; |
162 | 849 | pin_info.attrs.pin.pad_char = pins[i].pad_char; |
163 | 849 | sc_format_path(pins[i].path, &pin_info.path); |
164 | 849 | pin_info.tries_left = -1; |
165 | | |
166 | 849 | label = pins[i].label; |
167 | 849 | sc_log(card->ctx, "CAC Adding pin %d label=%s",i, label); |
168 | 849 | strncpy(pin_obj.label, label, SC_PKCS15_MAX_LABEL_SIZE - 1); |
169 | 849 | pin_obj.flags = pins[i].obj_flags; |
170 | | |
171 | | /* get the ACA path in case it needs to be selected before PIN verify */ |
172 | 849 | r = sc_card_ctl(card, SC_CARDCTL_CAC_GET_ACA_PATH, &pin_info.path); |
173 | 849 | LOG_TEST_GOTO_ERR(card->ctx, r, "Can not get ACA path."); |
174 | | |
175 | 849 | r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info); |
176 | 849 | LOG_TEST_GOTO_ERR(card->ctx, r, "Can not add pin object."); |
177 | 849 | } |
178 | | |
179 | | /* set other objects */ |
180 | 849 | r = (card->ops->card_ctl)(card, SC_CARDCTL_CAC_INIT_GET_GENERIC_OBJECTS, &count); |
181 | 849 | LOG_TEST_GOTO_ERR(card->ctx, r, "Can not initiate generic objects."); |
182 | | |
183 | 4.02k | for (i = 0; i < count; i++) { |
184 | 3.18k | struct sc_pkcs15_data_info obj_info; |
185 | 3.18k | struct sc_pkcs15_object obj_obj; |
186 | | |
187 | 3.18k | r = (card->ops->card_ctl)(card, SC_CARDCTL_CAC_GET_NEXT_GENERIC_OBJECT, &obj_info); |
188 | 3.18k | LOG_TEST_GOTO_ERR(card->ctx, r, "Can not get next generic object."); |
189 | 3.18k | memset(&obj_obj, 0, sizeof(obj_obj)); |
190 | 3.18k | memcpy(obj_obj.label, obj_info.app_label, sizeof(obj_obj.label)); |
191 | | |
192 | 3.18k | r = sc_pkcs15emu_object_add(p15card, SC_PKCS15_TYPE_DATA_OBJECT, |
193 | 3.18k | &obj_obj, &obj_info); |
194 | 3.18k | LOG_TEST_GOTO_ERR(card->ctx, r, "Can not finalize generic object."); |
195 | 3.18k | } |
196 | 849 | r = (card->ops->card_ctl)(card, SC_CARDCTL_CAC_FINAL_GET_GENERIC_OBJECTS, &count); |
197 | 849 | LOG_TEST_GOTO_ERR(card->ctx, r, "Can not finalize generic objects."); |
198 | | |
199 | | /* |
200 | | * certs, pubkeys and priv keys are related and we assume |
201 | | * they are in order |
202 | | * We need to read the cert, get modulus and keylen |
203 | | * We use those for the pubkey, and priv key objects. |
204 | | */ |
205 | 849 | sc_log(card->ctx, "CAC adding certs, pub and priv keys..."); |
206 | 849 | r = (card->ops->card_ctl)(card, SC_CARDCTL_CAC_INIT_GET_CERT_OBJECTS, &count); |
207 | 849 | LOG_TEST_GOTO_ERR(card->ctx, r, "Can not initiate cert objects."); |
208 | | |
209 | 3.86k | for (i = 0; i < count; i++) { |
210 | 3.01k | struct sc_pkcs15_data_info obj_info; |
211 | 3.01k | struct sc_pkcs15_cert_info cert_info; |
212 | 3.01k | struct sc_pkcs15_pubkey_info pubkey_info; |
213 | 3.01k | struct sc_pkcs15_prkey_info prkey_info; |
214 | 3.01k | struct sc_pkcs15_object cert_obj; |
215 | 3.01k | struct sc_pkcs15_object pubkey_obj; |
216 | 3.01k | struct sc_pkcs15_object prkey_obj; |
217 | 3.01k | sc_pkcs15_der_t cert_der; |
218 | 3.01k | sc_pkcs15_cert_t *cert_out = NULL; |
219 | | |
220 | 3.01k | r = (card->ops->card_ctl)(card, SC_CARDCTL_CAC_GET_NEXT_CERT_OBJECT, &obj_info); |
221 | 3.01k | LOG_TEST_RET(card->ctx, r, "Can not get next object"); |
222 | | |
223 | 3.01k | memset(&cert_info, 0, sizeof(cert_info)); |
224 | 3.01k | memset(&pubkey_info, 0, sizeof(pubkey_info)); |
225 | 3.01k | memset(&prkey_info, 0, sizeof(prkey_info)); |
226 | 3.01k | memset(&cert_obj, 0, sizeof(cert_obj)); |
227 | 3.01k | memset(&pubkey_obj, 0, sizeof(pubkey_obj)); |
228 | 3.01k | memset(&prkey_obj, 0, sizeof(prkey_obj)); |
229 | | |
230 | 3.01k | cert_info.id = obj_info.id; |
231 | 3.01k | pubkey_info.id = obj_info.id; |
232 | 3.01k | prkey_info.id = obj_info.id; |
233 | 3.01k | cert_info.path = obj_info.path; |
234 | 3.01k | prkey_info.path = obj_info.path; |
235 | | /* Add 0x3f00 to the front of prkey_info.path to make sc_key_file happy */ |
236 | | /* only do this if our path.len is 1 or 2 */ |
237 | 3.01k | if (prkey_info.path.len && prkey_info.path.len <= 2) { |
238 | 1.18k | prkey_info.path.value[2] = prkey_info.path.value[0]; |
239 | 1.18k | prkey_info.path.value[3] = prkey_info.path.value[1]; |
240 | 1.18k | prkey_info.path.value[0] = 0x3f; |
241 | 1.18k | prkey_info.path.value[1] = 0x00; |
242 | 1.18k | prkey_info.path.len += 2; |
243 | 1.18k | } |
244 | 3.01k | pubkey_info.native = 1; |
245 | 3.01k | pubkey_info.key_reference = ((int)obj_info.id.value[0]) << 8 | obj_info.id.value[1]; |
246 | 3.01k | prkey_info.key_reference = ((int)obj_info.id.value[0]) << 8 | obj_info.id.value[1]; |
247 | 3.01k | prkey_info.native = 1; |
248 | | |
249 | 3.01k | memcpy(cert_obj.label, obj_info.app_label, sizeof(obj_info.app_label)); |
250 | 3.01k | memcpy(pubkey_obj.label, obj_info.app_label, sizeof(obj_info.app_label)); |
251 | 3.01k | memcpy(prkey_obj.label, obj_info.app_label, sizeof(obj_info.app_label)); |
252 | 3.01k | prkey_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE; |
253 | 3.01k | sc_pkcs15_format_id(pins[0].id, &prkey_obj.auth_id); |
254 | | |
255 | 3.01k | r = sc_pkcs15_read_file(p15card, &cert_info.path, &cert_der.value, &cert_der.len, 0); |
256 | | |
257 | 3.01k | if (r) { |
258 | 2.59k | sc_log(card->ctx, "No cert found,i=%d", i); |
259 | 2.59k | continue; |
260 | 2.59k | } |
261 | 424 | cert_info.path.count = (int)cert_der.len; |
262 | | |
263 | 424 | sc_log(card->ctx, |
264 | 424 | "cert len=%"SC_FORMAT_LEN_SIZE_T"u, cert_info.path.count=%d r=%d\n", |
265 | 424 | cert_der.len, cert_info.path.count, r); |
266 | 424 | sc_log_hex(card->ctx, "cert", cert_der.value, cert_der.len); |
267 | | |
268 | | /* cache it using the PKCS15 emulation objects */ |
269 | | /* as it does not change */ |
270 | 424 | if (cert_der.value) { |
271 | 306 | cert_info.value.value = cert_der.value; |
272 | 306 | cert_info.value.len = cert_der.len; |
273 | 306 | cert_info.path.len = 0; /* use in mem cert from now on */ |
274 | 306 | } |
275 | | |
276 | | /* following will find the cached cert in cert_info */ |
277 | 424 | r = sc_pkcs15_read_certificate(p15card, &cert_info, 0, &cert_out); |
278 | 424 | if (r < 0 || cert_out->key == NULL) { |
279 | 267 | sc_log(card->ctx, "Failed to read/parse the certificate r=%d",r); |
280 | 267 | if (cert_out != NULL) |
281 | 0 | sc_pkcs15_free_certificate(cert_out); |
282 | 267 | free(cert_info.value.value); |
283 | 267 | continue; |
284 | 267 | } |
285 | | |
286 | 157 | r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info); |
287 | 157 | if (r < 0) { |
288 | 0 | sc_log(card->ctx, " Failed to add cert obj r=%d",r); |
289 | 0 | sc_pkcs15_free_certificate(cert_out); |
290 | 0 | free(cert_info.value.value); |
291 | 0 | continue; |
292 | 0 | } |
293 | | /* set the token name to the name of the CN of the first certificate */ |
294 | 157 | if (!token_name) { |
295 | 142 | u8 * cn_name = NULL; |
296 | 142 | size_t cn_len = 0; |
297 | 142 | static const struct sc_object_id cn_oid = {{ 2, 5, 4, 3, -1 }}; |
298 | 142 | r = sc_pkcs15_get_name_from_dn(card->ctx, cert_out->subject, |
299 | 142 | cert_out->subject_len, &cn_oid, &cn_name, &cn_len); |
300 | 142 | if (r == SC_SUCCESS) { |
301 | 13 | token_name = malloc (cn_len+1); |
302 | 13 | if (!token_name) { |
303 | 0 | free(cn_name); |
304 | 0 | r = SC_ERROR_OUT_OF_MEMORY; |
305 | 0 | goto fail; |
306 | 0 | } |
307 | 13 | memcpy(token_name, cn_name, cn_len); |
308 | 13 | free(cn_name); |
309 | 13 | token_name[cn_len] = 0; |
310 | 13 | free(p15card->tokeninfo->label); |
311 | 13 | p15card->tokeninfo->label = token_name; |
312 | 13 | } |
313 | 142 | } |
314 | | |
315 | | |
316 | 157 | r = sc_pkcs15_encode_pubkey_as_spki(card->ctx, cert_out->key, &pubkey_info.direct.spki.value, &pubkey_info.direct.spki.len); |
317 | 157 | if (r < 0) |
318 | 0 | goto fail; |
319 | 157 | pubkey_obj.emulated = cert_out->key; |
320 | | |
321 | 157 | r = sc_pkcs15_get_bitstring_extension(card->ctx, cert_out, &usage_type, &usage, NULL); |
322 | 157 | if (r < 0) { |
323 | 130 | usage = SC_X509_DATA_ENCIPHERMENT|SC_X509_DIGITAL_SIGNATURE; /* basic default usage */ |
324 | 130 | } |
325 | 157 | sc_pkcs15_map_usage(usage, cert_out->key->algorithm, &pubkey_info.usage, &prkey_info.usage, 1); |
326 | 157 | sc_log(card->ctx, "cert %s: cert_usage=0x%x, pub_usage=0x%x priv_usage=0x%x\n", |
327 | 157 | sc_dump_hex(cert_info.id.value, cert_info.id.len), |
328 | 157 | usage, pubkey_info.usage, prkey_info.usage); |
329 | 157 | if (cert_out->key->algorithm != SC_ALGORITHM_RSA) { |
330 | 0 | sc_log(card->ctx, "unsupported key.algorithm %lu", cert_out->key->algorithm); |
331 | 0 | sc_pkcs15_free_certificate(cert_out); |
332 | 0 | free(pubkey_info.direct.spki.value); |
333 | 0 | continue; |
334 | 157 | } else { |
335 | 157 | pubkey_info.modulus_length = cert_out->key->u.rsa.modulus.len * 8; |
336 | 157 | prkey_info.modulus_length = cert_out->key->u.rsa.modulus.len * 8; |
337 | 157 | r = sc_pkcs15emu_add_rsa_pubkey(p15card, &pubkey_obj, &pubkey_info); |
338 | 157 | sc_log(card->ctx, "adding rsa public key r=%d usage=%x",r, pubkey_info.usage); |
339 | 157 | if (r < 0) { |
340 | 0 | free(pubkey_info.direct.spki.value); |
341 | 0 | goto fail; |
342 | 0 | } |
343 | 157 | pubkey_info.direct.spki.value = NULL; /* moved to the pubkey object on p15card */ |
344 | 157 | pubkey_info.direct.spki.len = 0; |
345 | 157 | r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info); |
346 | 157 | if (r < 0) |
347 | 0 | goto fail; |
348 | 157 | sc_log(card->ctx, "adding rsa private key r=%d usage=%x",r, prkey_info.usage); |
349 | 157 | } |
350 | | |
351 | 157 | cert_out->key = NULL; |
352 | 157 | fail: |
353 | 157 | sc_pkcs15_free_certificate(cert_out); |
354 | 157 | if (r < 0) { |
355 | 0 | (card->ops->card_ctl)(card, SC_CARDCTL_CAC_FINAL_GET_CERT_OBJECTS, &count); |
356 | 0 | LOG_TEST_GOTO_ERR(card->ctx, r, "Failed to add object."); |
357 | 0 | } |
358 | | |
359 | 157 | } |
360 | 849 | r = (card->ops->card_ctl)(card, SC_CARDCTL_CAC_FINAL_GET_CERT_OBJECTS, &count); |
361 | 849 | LOG_TEST_GOTO_ERR(card->ctx, r, "Can not finalize cert objects."); |
362 | | |
363 | 849 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
364 | | |
365 | 0 | err: |
366 | 0 | sc_pkcs15_card_clear(p15card); |
367 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
368 | 0 | } |
369 | | |
370 | | int sc_pkcs15emu_cac_init_ex(sc_pkcs15_card_t *p15card, |
371 | | struct sc_aid *aid) |
372 | 10.2k | { |
373 | 10.2k | sc_card_t *card = p15card->card; |
374 | 10.2k | sc_context_t *ctx = card->ctx; |
375 | | |
376 | 10.2k | LOG_FUNC_CALLED(ctx); |
377 | | |
378 | 10.2k | if (cac_detect_card(p15card)) |
379 | 9.37k | return SC_ERROR_WRONG_CARD; |
380 | 849 | return sc_pkcs15emu_cac_init(p15card); |
381 | 10.2k | } |