/src/opensc/src/libopensc/pkcs15-idprime.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * partial PKCS15 emulation for IDPrime cards. |
3 | | * |
4 | | * We can not use the ISO code, since the EF.DIR and EF.ATR for |
5 | | * object discovery are missing |
6 | | * |
7 | | * Copyright (C) 2019, Red Hat, Inc. |
8 | | * |
9 | | * Author: Jakub Jelen <jjelen@redhat.com> |
10 | | * This library is free software; you can redistribute it and/or |
11 | | * modify it under the terms of the GNU Lesser General Public |
12 | | * License as published by the Free Software Foundation; either |
13 | | * version 2.1 of the License, or (at your option) any later version. |
14 | | * |
15 | | * This library is distributed in the hope that it will be useful, |
16 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
18 | | * Lesser General Public License for more details. |
19 | | * |
20 | | * You should have received a copy of the GNU Lesser General Public |
21 | | * License along with this library; if not, write to the Free Software |
22 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
23 | | */ |
24 | | |
25 | | #ifdef HAVE_CONFIG_H |
26 | | #include "config.h" |
27 | | #endif |
28 | | |
29 | | #include <string.h> |
30 | | #include <stdlib.h> |
31 | | #include "internal.h" |
32 | | #include "cardctl.h" |
33 | | #include "pkcs15.h" |
34 | | |
35 | 0 | #define CERT_LABEL_TEMPLATE "Certificate %d" |
36 | 0 | #define PUBKEY_LABEL_TEMPLATE "Public key %d" |
37 | 0 | #define PRIVKEY_LABEL_TEMPLATE "Private key %d" |
38 | | |
39 | | static int idprime_detect_card(sc_pkcs15_card_t *p15card) |
40 | 2 | { |
41 | 2 | sc_card_t *card = p15card->card; |
42 | | |
43 | 2 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
44 | | |
45 | 2 | if (card->type < SC_CARD_TYPE_IDPRIME_BASE |
46 | 2 | || card->type >= SC_CARD_TYPE_IDPRIME_BASE+1000) |
47 | 2 | return SC_ERROR_INVALID_CARD; |
48 | 0 | return SC_SUCCESS; |
49 | 2 | } |
50 | | |
51 | | static int sc_pkcs15emu_idprime_init(sc_pkcs15_card_t *p15card) |
52 | 0 | { |
53 | 0 | int r, i; |
54 | 0 | sc_card_t *card = p15card->card; |
55 | 0 | sc_serial_number_t serial; |
56 | 0 | char buf[SC_MAX_SERIALNR * 2 + 1]; |
57 | 0 | int count; |
58 | 0 | char *token_name = NULL; |
59 | 0 | struct sc_pkcs15_auth_info pin_info; |
60 | 0 | struct sc_pkcs15_object pin_obj; |
61 | 0 | const char pin_label[] = "PIN"; |
62 | 0 | const char *pin_id = "11"; |
63 | 0 | const char sig_pin_label[] = "Digital Signature PIN"; |
64 | 0 | const char *sig_pin_id = "83"; |
65 | | |
66 | | /* oid for key usage */ |
67 | 0 | static const struct sc_object_id usage_type = {{ 2, 5, 29, 15, -1 }}; |
68 | 0 | unsigned int usage; |
69 | |
|
70 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
71 | | |
72 | | /* could read this off card if needed */ |
73 | 0 | set_string(&p15card->tokeninfo->label, "IDPrime"); |
74 | 0 | set_string(&p15card->tokeninfo->manufacturer_id, "Gemalto"); |
75 | | |
76 | | /* |
77 | | * get serial number |
78 | | */ |
79 | 0 | memset(&serial, 0, sizeof(serial)); |
80 | 0 | r = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serial); |
81 | 0 | if (r < 0) { |
82 | 0 | sc_log(card->ctx, "sc_card_ctl rc=%d", r); |
83 | 0 | set_string(&p15card->tokeninfo->serial_number, "00000000"); |
84 | 0 | } else { |
85 | 0 | sc_bin_to_hex(serial.value, serial.len, buf, sizeof(buf), 0); |
86 | 0 | set_string(&p15card->tokeninfo->serial_number, buf); |
87 | 0 | } |
88 | | /* set pin */ |
89 | 0 | sc_log(card->ctx, "IDPrime adding pin..."); |
90 | 0 | memset(&pin_info, 0, sizeof(pin_info)); |
91 | 0 | memset(&pin_obj, 0, sizeof(pin_obj)); |
92 | |
|
93 | 0 | pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN; |
94 | 0 | sc_pkcs15_format_id(pin_id, &pin_info.auth_id); |
95 | 0 | pin_info.attrs.pin.reference = 0x11; |
96 | 0 | pin_info.attrs.pin.flags = SC_PKCS15_PIN_FLAG_INITIALIZED; |
97 | 0 | pin_info.attrs.pin.type = SC_PKCS15_PIN_TYPE_ASCII_NUMERIC; |
98 | 0 | pin_info.attrs.pin.min_length = 4; |
99 | 0 | pin_info.attrs.pin.stored_length = 0; |
100 | 0 | pin_info.attrs.pin.max_length = 16; |
101 | 0 | pin_info.tries_left = -1; |
102 | |
|
103 | 0 | if (card->type == SC_CARD_TYPE_IDPRIME_840 |
104 | 0 | || card->type == SC_CARD_TYPE_IDPRIME_940 |
105 | 0 | || card->type == SC_CARD_TYPE_IDPRIME_GENERIC) { |
106 | 0 | pin_info.attrs.pin.flags |= SC_PKCS15_PIN_FLAG_NEEDS_PADDING; |
107 | 0 | pin_info.attrs.pin.stored_length = 16; |
108 | 0 | pin_info.attrs.pin.pad_char = 0x00; |
109 | 0 | } |
110 | |
|
111 | 0 | sc_log(card->ctx, "IDPrime Adding pin with label=%s", pin_label); |
112 | 0 | strncpy(pin_obj.label, pin_label, SC_PKCS15_MAX_LABEL_SIZE - 1); |
113 | 0 | pin_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE; |
114 | |
|
115 | 0 | r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info); |
116 | 0 | LOG_TEST_GOTO_ERR(card->ctx, r, "Can not add pin object"); |
117 | | |
118 | | /* set signature pin for 940 cards */ |
119 | 0 | if (card->type == SC_CARD_TYPE_IDPRIME_940) { |
120 | 0 | sc_log(card->ctx, "IDPrime adding Digital Signature pin..."); |
121 | 0 | memset(&pin_info, 0, sizeof(pin_info)); |
122 | 0 | memset(&pin_obj, 0, sizeof(pin_obj)); |
123 | |
|
124 | 0 | pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN; |
125 | 0 | sc_pkcs15_format_id(sig_pin_id, &pin_info.auth_id); |
126 | 0 | pin_info.attrs.pin.reference = 0x83; |
127 | 0 | pin_info.attrs.pin.flags = SC_PKCS15_PIN_FLAG_INITIALIZED; |
128 | 0 | pin_info.attrs.pin.type = SC_PKCS15_PIN_TYPE_ASCII_NUMERIC; |
129 | 0 | pin_info.attrs.pin.min_length = 4; |
130 | 0 | pin_info.attrs.pin.stored_length = 0; |
131 | 0 | pin_info.attrs.pin.max_length = 16; |
132 | 0 | pin_info.tries_left = -1; |
133 | |
|
134 | 0 | pin_info.attrs.pin.flags |= SC_PKCS15_PIN_FLAG_NEEDS_PADDING; |
135 | 0 | pin_info.attrs.pin.stored_length = 16; |
136 | 0 | pin_info.attrs.pin.pad_char = 0x00; |
137 | |
|
138 | 0 | sc_log(card->ctx, "IDPrime Adding Digital Signature pin with label=%s", sig_pin_label); |
139 | 0 | strncpy(pin_obj.label, sig_pin_label, SC_PKCS15_MAX_LABEL_SIZE - 1); |
140 | 0 | pin_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE; |
141 | |
|
142 | 0 | r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info); |
143 | 0 | LOG_TEST_GOTO_ERR(card->ctx, r, "Can not add Digital Signature pin object"); |
144 | 0 | } |
145 | | |
146 | | /* |
147 | | * get token name if provided |
148 | | */ |
149 | 0 | r = sc_card_ctl(card, SC_CARDCTL_IDPRIME_GET_TOKEN_NAME, &token_name); |
150 | 0 | if (r < 0) { |
151 | | /* On failure we will get the token name from certificates later */ |
152 | 0 | sc_log(card->ctx, "sc_card_ctl rc=%d", r); |
153 | 0 | } else { |
154 | 0 | free(p15card->tokeninfo->label); |
155 | 0 | p15card->tokeninfo->label = token_name; |
156 | 0 | sc_log(card->ctx, "IDPrime setting token label = %s", token_name); |
157 | 0 | } |
158 | | /* |
159 | | * certs, pubkeys and priv keys are related and we assume |
160 | | * they are in order |
161 | | * We need to read the cert, get modulus and keylen |
162 | | * We use those for the pubkey, and priv key objects. |
163 | | */ |
164 | 0 | sc_log(card->ctx, "IDPrime adding certs, pub and priv keys..."); |
165 | 0 | r = (card->ops->card_ctl)(card, SC_CARDCTL_IDPRIME_INIT_GET_OBJECTS, &count); |
166 | 0 | LOG_TEST_GOTO_ERR(card->ctx, r, "Can not initiate cert objects."); |
167 | | |
168 | 0 | for (i = 0; i < count; i++) { |
169 | 0 | struct sc_pkcs15_prkey_info prkey_info; |
170 | 0 | struct sc_pkcs15_cert_info cert_info; |
171 | 0 | struct sc_pkcs15_pubkey_info pubkey_info; |
172 | 0 | struct sc_pkcs15_object cert_obj; |
173 | 0 | struct sc_pkcs15_object pubkey_obj; |
174 | 0 | struct sc_pkcs15_object prkey_obj; |
175 | 0 | sc_pkcs15_der_t cert_der; |
176 | 0 | sc_pkcs15_cert_t *cert_out = NULL; |
177 | 0 | const char *pin_id = NULL; |
178 | |
|
179 | 0 | r = (card->ops->card_ctl)(card, SC_CARDCTL_IDPRIME_GET_PIN_ID, (void *) &pin_id); |
180 | 0 | LOG_TEST_GOTO_ERR(card->ctx, r, "Can not get PIN id of next object "); |
181 | 0 | r = (card->ops->card_ctl)(card, SC_CARDCTL_IDPRIME_GET_NEXT_OBJECT, &prkey_info); |
182 | 0 | LOG_TEST_GOTO_ERR(card->ctx, r, "Can not get next object"); |
183 | | |
184 | 0 | memset(&cert_info, 0, sizeof(cert_info)); |
185 | 0 | memset(&pubkey_info, 0, sizeof(pubkey_info)); |
186 | | /* prkey_info cleaned by the card_ctl call */ |
187 | 0 | memset(&cert_obj, 0, sizeof(cert_obj)); |
188 | 0 | memset(&pubkey_obj, 0, sizeof(pubkey_obj)); |
189 | 0 | memset(&prkey_obj, 0, sizeof(prkey_obj)); |
190 | |
|
191 | 0 | cert_info.id = prkey_info.id; |
192 | 0 | pubkey_info.id = prkey_info.id; |
193 | 0 | cert_info.path = prkey_info.path; |
194 | | /* For private keys, we no longer care for the path, just |
195 | | * the key reference later used in the security environment */ |
196 | 0 | prkey_info.path.len = 0; |
197 | 0 | prkey_info.path.aid.len = 0; |
198 | 0 | pubkey_info.key_reference = prkey_info.key_reference; |
199 | 0 | sc_log(card->ctx, "Key ref r=%x", prkey_info.key_reference); |
200 | |
|
201 | 0 | pubkey_info.native = 1; |
202 | 0 | prkey_info.native = 1; |
203 | |
|
204 | 0 | snprintf(cert_obj.label, SC_PKCS15_MAX_LABEL_SIZE, CERT_LABEL_TEMPLATE, i+1); |
205 | 0 | snprintf(pubkey_obj.label, SC_PKCS15_MAX_LABEL_SIZE, PUBKEY_LABEL_TEMPLATE, i+1); |
206 | 0 | snprintf(prkey_obj.label, SC_PKCS15_MAX_LABEL_SIZE, PRIVKEY_LABEL_TEMPLATE, i+1); |
207 | 0 | prkey_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE; |
208 | | |
209 | | /* Differentiate between objects accessible with normal and with digital signature pin */ |
210 | 0 | sc_pkcs15_format_id(pin_id, &prkey_obj.auth_id); |
211 | 0 | sc_log(card->ctx, "Pin ID r=%s", pin_id); |
212 | |
|
213 | 0 | if (memcmp(pin_id, sig_pin_id, 2) == 0) |
214 | 0 | prkey_obj.user_consent = 1; |
215 | |
|
216 | 0 | r = sc_pkcs15_read_file(p15card, &cert_info.path, &cert_der.value, &cert_der.len, 0); |
217 | |
|
218 | 0 | if (r) { |
219 | 0 | sc_log(card->ctx, "No cert found,i=%d", i); |
220 | 0 | continue; |
221 | 0 | } |
222 | 0 | cert_info.path.count = (int)cert_der.len; |
223 | |
|
224 | 0 | sc_log(card->ctx, |
225 | 0 | "cert len=%"SC_FORMAT_LEN_SIZE_T"u, cert_info.path.count=%d r=%d\n", |
226 | 0 | cert_der.len, cert_info.path.count, r); |
227 | 0 | sc_log_hex(card->ctx, "cert", cert_der.value, cert_der.len); |
228 | | |
229 | | /* cache it using the PKCS15 emulation objects */ |
230 | | /* as it does not change */ |
231 | 0 | if (cert_der.value) { |
232 | 0 | cert_info.value.value = cert_der.value; |
233 | 0 | cert_info.value.len = cert_der.len; |
234 | 0 | cert_info.path.len = 0; /* use in mem cert from now on */ |
235 | 0 | } |
236 | | |
237 | | /* following will find the cached cert in cert_info */ |
238 | 0 | r = sc_pkcs15_read_certificate(p15card, &cert_info, 0, &cert_out); |
239 | 0 | if (r < 0 || cert_out->key == NULL) { |
240 | 0 | sc_log(card->ctx, "Failed to read/parse the certificate r=%d",r); |
241 | 0 | if (cert_out != NULL) |
242 | 0 | sc_pkcs15_free_certificate(cert_out); |
243 | 0 | free(cert_der.value); |
244 | 0 | continue; |
245 | 0 | } |
246 | | |
247 | 0 | r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info); |
248 | 0 | if (r < 0) { |
249 | 0 | sc_log(card->ctx, " Failed to add cert obj r=%d",r); |
250 | 0 | sc_pkcs15_free_certificate(cert_out); |
251 | 0 | free(cert_der.value); |
252 | 0 | continue; |
253 | 0 | } |
254 | | /* set the token name to the name of the CN of the first certificate */ |
255 | 0 | if (!token_name) { |
256 | 0 | u8 * cn_name = NULL; |
257 | 0 | size_t cn_len = 0; |
258 | 0 | static const struct sc_object_id cn_oid = {{ 2, 5, 4, 3, -1 }}; |
259 | 0 | r = sc_pkcs15_get_name_from_dn(card->ctx, cert_out->subject, |
260 | 0 | cert_out->subject_len, &cn_oid, &cn_name, &cn_len); |
261 | 0 | if (r == SC_SUCCESS) { |
262 | 0 | token_name = malloc (cn_len+1); |
263 | 0 | if (!token_name) { |
264 | 0 | free(cn_name); |
265 | 0 | r = SC_ERROR_OUT_OF_MEMORY; |
266 | 0 | goto fail; |
267 | 0 | } |
268 | 0 | memcpy(token_name, cn_name, cn_len); |
269 | 0 | free(cn_name); |
270 | 0 | token_name[cn_len] = '\0'; |
271 | 0 | free(p15card->tokeninfo->label); |
272 | 0 | p15card->tokeninfo->label = token_name; |
273 | 0 | } |
274 | 0 | } |
275 | | |
276 | | |
277 | 0 | r = sc_pkcs15_encode_pubkey_as_spki(card->ctx, cert_out->key, |
278 | 0 | &pubkey_info.direct.spki.value, &pubkey_info.direct.spki.len); |
279 | 0 | if (r < 0) |
280 | 0 | goto fail; |
281 | 0 | pubkey_obj.emulated = cert_out->key; |
282 | |
|
283 | 0 | r = sc_pkcs15_get_bitstring_extension(card->ctx, cert_out, &usage_type, &usage, NULL); |
284 | 0 | if (r < 0) { |
285 | 0 | usage = SC_X509_DATA_ENCIPHERMENT|SC_X509_DIGITAL_SIGNATURE; /* basic default usage */ |
286 | 0 | } |
287 | 0 | sc_pkcs15_map_usage(usage, cert_out->key->algorithm, &pubkey_info.usage, &prkey_info.usage, 1); |
288 | 0 | sc_log(card->ctx, "cert %s: cert_usage=0x%x, pub_usage=0x%x priv_usage=0x%x\n", |
289 | 0 | sc_dump_hex(cert_info.id.value, cert_info.id.len), |
290 | 0 | usage, pubkey_info.usage, prkey_info.usage); |
291 | |
|
292 | 0 | if (cert_out->key->algorithm == SC_ALGORITHM_RSA) { |
293 | 0 | pubkey_info.modulus_length = cert_out->key->u.rsa.modulus.len * 8; |
294 | 0 | prkey_info.modulus_length = cert_out->key->u.rsa.modulus.len * 8; |
295 | 0 | sc_log(card->ctx, "adding rsa public key r=%d usage=%x", r, pubkey_info.usage); |
296 | 0 | r = sc_pkcs15emu_add_rsa_pubkey(p15card, &pubkey_obj, &pubkey_info); |
297 | 0 | if (r < 0) { |
298 | 0 | free(pubkey_info.direct.spki.value); |
299 | 0 | goto fail; |
300 | 0 | } |
301 | 0 | pubkey_info.direct.spki.value = NULL; /* moved to the pubkey object on p15card */ |
302 | 0 | pubkey_info.direct.spki.len = 0; |
303 | 0 | if (prkey_info.key_reference >= 0) { |
304 | 0 | sc_log(card->ctx, "adding rsa private key r=%d usage=%x", r, prkey_info.usage); |
305 | 0 | r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info); |
306 | 0 | } else { |
307 | 0 | sc_log(card->ctx, "missing rsa private key r=%d usage=%x", r, prkey_info.usage); |
308 | 0 | } |
309 | 0 | if (r < 0) |
310 | 0 | goto fail; |
311 | 0 | } else if (cert_out->key->algorithm == SC_ALGORITHM_EC) { |
312 | 0 | pubkey_info.field_length = cert_out->key->u.ec.params.field_length; |
313 | 0 | prkey_info.field_length = cert_out->key->u.ec.params.field_length; |
314 | 0 | sc_log(card->ctx, "adding ec public key r=%d usage=%x", r, pubkey_info.usage); |
315 | 0 | r = sc_pkcs15emu_add_ec_pubkey(p15card, &pubkey_obj, &pubkey_info); |
316 | 0 | if (r < 0) { |
317 | 0 | free(pubkey_info.direct.spki.value); |
318 | 0 | goto fail; |
319 | 0 | } |
320 | 0 | pubkey_info.direct.spki.value = NULL; |
321 | 0 | pubkey_info.direct.spki.len = 0; |
322 | 0 | if (prkey_info.key_reference >= 0) { |
323 | 0 | sc_log(card->ctx, "adding ec private key r=%d usage=%x", r, prkey_info.usage); |
324 | 0 | r = sc_pkcs15emu_add_ec_prkey(p15card, &prkey_obj, &prkey_info); |
325 | 0 | } else { |
326 | 0 | sc_log(card->ctx, "missing ec private key r=%d usage=%x", r, prkey_info.usage); |
327 | 0 | } |
328 | 0 | if (r < 0) |
329 | 0 | goto fail; |
330 | 0 | } else { |
331 | 0 | sc_log(card->ctx, "unsupported key.algorithm %lu", cert_out->key->algorithm); |
332 | 0 | sc_pkcs15_free_certificate(cert_out); |
333 | 0 | free(pubkey_info.direct.spki.value); |
334 | 0 | continue; |
335 | 0 | } |
336 | | |
337 | 0 | cert_out->key = NULL; |
338 | 0 | fail: |
339 | 0 | sc_pkcs15_free_certificate(cert_out); |
340 | 0 | if (r < 0) { |
341 | 0 | (card->ops->card_ctl)(card, SC_CARDCTL_IDPRIME_FINAL_GET_OBJECTS, &count); |
342 | 0 | LOG_TEST_GOTO_ERR(card->ctx, r, "Failed to add object."); |
343 | 0 | } |
344 | |
|
345 | 0 | } |
346 | 0 | r = (card->ops->card_ctl)(card, SC_CARDCTL_IDPRIME_FINAL_GET_OBJECTS, &count); |
347 | 0 | LOG_TEST_GOTO_ERR(card->ctx, r, "Can not finalize cert objects."); |
348 | | |
349 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
350 | | |
351 | 0 | err: |
352 | 0 | sc_pkcs15_card_clear(p15card); |
353 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
354 | 0 | } |
355 | | |
356 | | int sc_pkcs15emu_idprime_init_ex(sc_pkcs15_card_t *p15card, |
357 | | struct sc_aid *aid) |
358 | 2 | { |
359 | 2 | sc_card_t *card = p15card->card; |
360 | 2 | sc_context_t *ctx = card->ctx; |
361 | | |
362 | 2 | LOG_FUNC_CALLED(ctx); |
363 | | |
364 | 2 | if (idprime_detect_card(p15card)) |
365 | 2 | return SC_ERROR_WRONG_CARD; |
366 | 0 | return sc_pkcs15emu_idprime_init(p15card); |
367 | 2 | } |