/src/opensc/src/libopensc/pkcs15-cert.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * pkcs15-cert.c: PKCS #15 certificate functions |
3 | | * |
4 | | * Copyright (C) 2001, 2002 Juha Yrjölä <juha.yrjola@iki.fi> |
5 | | * |
6 | | * This library is free software; you can redistribute it and/or |
7 | | * modify it under the terms of the GNU Lesser General Public |
8 | | * License as published by the Free Software Foundation; either |
9 | | * version 2.1 of the License, or (at your option) any later version. |
10 | | * |
11 | | * This library is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | | * Lesser General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU Lesser General Public |
17 | | * License along with this library; if not, write to the Free Software |
18 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
19 | | */ |
20 | | |
21 | | #ifdef HAVE_CONFIG_H |
22 | | #include "config.h" |
23 | | #endif |
24 | | |
25 | | #include <stdlib.h> |
26 | | #include <string.h> |
27 | | #include <stdio.h> |
28 | | #include <sys/stat.h> |
29 | | #ifdef HAVE_UNISTD_H |
30 | | #include <unistd.h> |
31 | | #endif |
32 | | #include <assert.h> |
33 | | |
34 | | #include "internal.h" |
35 | | #include "asn1.h" |
36 | | #include "pkcs15.h" |
37 | | |
38 | | static int |
39 | | parse_x509_cert(sc_context_t *ctx, struct sc_pkcs15_der *der, struct sc_pkcs15_cert *cert) |
40 | 0 | { |
41 | 0 | int r; |
42 | 0 | struct sc_algorithm_id sig_alg = {0}; |
43 | 0 | struct sc_pkcs15_pubkey *pubkey = NULL; |
44 | 0 | unsigned char *serial = NULL, *issuer = NULL, *subject = NULL, *buf = der->value; |
45 | 0 | size_t serial_len = 0, issuer_len = 0, subject_len = 0, data_len = 0, buflen = der->len; |
46 | 0 | struct sc_asn1_entry asn1_version[] = { |
47 | 0 | { "version", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, 0, &cert->version, NULL }, |
48 | 0 | { NULL, 0, 0, 0, NULL, NULL } |
49 | 0 | }; |
50 | 0 | struct sc_asn1_entry asn1_extensions[] = { |
51 | 0 | { "x509v3", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL| SC_ASN1_ALLOC, &cert->extensions, &cert->extensions_len }, |
52 | 0 | { NULL, 0, 0, 0, NULL, NULL } |
53 | 0 | }; |
54 | 0 | struct sc_asn1_entry asn1_tbscert[] = { |
55 | 0 | { "version", SC_ASN1_STRUCT, SC_ASN1_CTX | 0 | SC_ASN1_CONS, SC_ASN1_OPTIONAL, asn1_version, NULL }, |
56 | 0 | { "serialNumber", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_INTEGER, SC_ASN1_ALLOC, &serial, &serial_len }, |
57 | 0 | { "signature", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL }, |
58 | 0 | { "issuer", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_ALLOC, &issuer, &issuer_len }, |
59 | 0 | { "validity", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL }, |
60 | 0 | { "subject", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_ALLOC, &subject, &subject_len }, |
61 | | /* Use a callback to get the algorithm, parameters and pubkey into sc_pkcs15_pubkey */ |
62 | 0 | { "subjectPublicKeyInfo",SC_ASN1_CALLBACK, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, sc_pkcs15_pubkey_from_spki_fields, &pubkey }, |
63 | 0 | { "extensions", SC_ASN1_STRUCT, SC_ASN1_CTX | 3 | SC_ASN1_CONS, SC_ASN1_OPTIONAL, asn1_extensions, NULL }, |
64 | 0 | { NULL, 0, 0, 0, NULL, NULL } |
65 | 0 | }; |
66 | 0 | struct sc_asn1_entry asn1_cert[] = { |
67 | 0 | { "tbsCertificate", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, asn1_tbscert, NULL }, |
68 | 0 | { "signatureAlgorithm", SC_ASN1_ALGORITHM_ID, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, &sig_alg, NULL }, |
69 | 0 | { "signatureValue", SC_ASN1_BIT_STRING, SC_ASN1_TAG_BIT_STRING, 0, NULL, NULL }, |
70 | 0 | { NULL, 0, 0, 0, NULL, NULL } |
71 | 0 | }; |
72 | 0 | struct sc_asn1_entry asn1_serial_number[] = { |
73 | 0 | { "serialNumber", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_INTEGER, SC_ASN1_ALLOC, NULL, NULL }, |
74 | 0 | { NULL, 0, 0, 0, NULL, NULL } |
75 | 0 | }; |
76 | 0 | struct sc_asn1_entry asn1_subject[] = { |
77 | 0 | { "subject", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_ALLOC, NULL, NULL }, |
78 | 0 | { NULL, 0, 0, 0, NULL, NULL } |
79 | 0 | }; |
80 | 0 | struct sc_asn1_entry asn1_issuer[] = { |
81 | 0 | { "issuer", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_ALLOC, NULL, NULL }, |
82 | 0 | { NULL, 0, 0, 0, NULL, NULL } |
83 | 0 | }; |
84 | |
|
85 | 0 | const u8 *obj; |
86 | 0 | size_t objlen; |
87 | |
|
88 | 0 | LOG_FUNC_CALLED(ctx); |
89 | |
|
90 | 0 | memset(cert, 0, sizeof(*cert)); |
91 | 0 | obj = sc_asn1_verify_tag(ctx, buf, buflen, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, &objlen); |
92 | 0 | if (obj == NULL) |
93 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_ASN1_OBJECT, "X.509 certificate not found"); |
94 | | |
95 | 0 | data_len = objlen + (obj - buf); |
96 | 0 | cert->data.value = malloc(data_len); |
97 | 0 | if (!cert->data.value) |
98 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); |
99 | 0 | memcpy(cert->data.value, buf, data_len); |
100 | 0 | cert->data.len = data_len; |
101 | |
|
102 | 0 | r = sc_asn1_decode(ctx, asn1_cert, obj, objlen, NULL, NULL); |
103 | 0 | cert->key = pubkey; |
104 | 0 | cert->version++; |
105 | |
|
106 | 0 | LOG_TEST_GOTO_ERR(ctx, r, "ASN.1 parsing of certificate failed"); |
107 | | |
108 | 0 | if (!pubkey) |
109 | 0 | LOG_TEST_GOTO_ERR(ctx, SC_ERROR_INVALID_ASN1_OBJECT, "Unable to decode subjectPublicKeyInfo from cert"); |
110 | | |
111 | | |
112 | 0 | if (serial && serial_len) { |
113 | 0 | sc_format_asn1_entry(asn1_serial_number + 0, serial, &serial_len, 1); |
114 | 0 | r = sc_asn1_encode(ctx, asn1_serial_number, &cert->serial, &cert->serial_len); |
115 | 0 | LOG_TEST_GOTO_ERR(ctx, r, "ASN.1 encoding of serial failed"); |
116 | 0 | } |
117 | | |
118 | 0 | if (subject && subject_len) { |
119 | 0 | sc_format_asn1_entry(asn1_subject + 0, subject, &subject_len, 1); |
120 | 0 | r = sc_asn1_encode(ctx, asn1_subject, &cert->subject, &cert->subject_len); |
121 | 0 | LOG_TEST_GOTO_ERR(ctx, r, "ASN.1 encoding of subject"); |
122 | 0 | } |
123 | | |
124 | 0 | if (issuer && issuer_len) { |
125 | 0 | sc_format_asn1_entry(asn1_issuer + 0, issuer, &issuer_len, 1); |
126 | 0 | r = sc_asn1_encode(ctx, asn1_issuer, &cert->issuer, &cert->issuer_len); |
127 | 0 | LOG_TEST_GOTO_ERR(ctx, r, "ASN.1 encoding of issuer"); |
128 | 0 | } |
129 | | |
130 | 0 | err: |
131 | | /* not used for anything */ |
132 | 0 | sc_asn1_clear_algorithm_id(&sig_alg); |
133 | 0 | free(serial); |
134 | 0 | free(subject); |
135 | 0 | free(issuer); |
136 | |
|
137 | 0 | LOG_FUNC_RETURN(ctx, r); |
138 | 0 | } |
139 | | |
140 | | |
141 | | /* Get a component of Distinguished Name (e.i. subject or issuer) USING the oid tag. |
142 | | * dn can be either cert->subject or cert->issuer. |
143 | | * dn_len would be cert->subject_len or cert->issuer_len. |
144 | | * |
145 | | * Common types: |
146 | | * CN: struct sc_object_id type = {{2, 5, 4, 3, -1}}; |
147 | | * Country: struct sc_object_id type = {{2, 5, 4, 6, -1}}; |
148 | | * L: struct sc_object_id type = {{2, 5, 4, 7, -1}}; |
149 | | * S: struct sc_object_id type = {{2, 5, 4, 8, -1}}; |
150 | | * O: struct sc_object_id type = {{2, 5, 4, 10, -1}}; |
151 | | * OU: struct sc_object_id type = {{2, 5, 4, 11, -1}}; |
152 | | * |
153 | | * if *name is NULL, sc_pkcs15_get_name_from_dn will allocate space for name. |
154 | | */ |
155 | | int |
156 | | sc_pkcs15_get_name_from_dn(struct sc_context *ctx, const u8 *dn, size_t dn_len, |
157 | | const struct sc_object_id *type, u8 **name, size_t *name_len) |
158 | 0 | { |
159 | 0 | const u8 *rdn = NULL; |
160 | 0 | const u8 *next_ava = NULL; |
161 | 0 | size_t rdn_len = 0; |
162 | 0 | size_t next_ava_len = 0; |
163 | 0 | int rv; |
164 | |
|
165 | 0 | rdn = sc_asn1_skip_tag(ctx, &dn, &dn_len, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, &rdn_len); |
166 | 0 | if (rdn == NULL) |
167 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_ASN1_OBJECT, "ASN.1 decoding of Distinguished Name"); |
168 | | |
169 | 0 | for (next_ava = rdn, next_ava_len = rdn_len; next_ava_len; ) { |
170 | 0 | const u8 *ava, *dummy, *oidp; |
171 | 0 | struct sc_object_id oid; |
172 | 0 | size_t ava_len = 0, dummy_len, oid_len = 0; |
173 | | |
174 | | /* unwrap the set and point to the next ava */ |
175 | 0 | ava = sc_asn1_skip_tag(ctx, &next_ava, &next_ava_len, SC_ASN1_TAG_SET | SC_ASN1_CONS, &ava_len); |
176 | 0 | if (ava == NULL) |
177 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_ASN1_OBJECT, "ASN.1 decoding of AVA"); |
178 | | |
179 | | /* It would be nice to use sc_asn1_decode here to parse the entire AVA, but we are missing 1 critical |
180 | | * function in the templates: the ability to accept any tag for value. This prevents us from just |
181 | | * grabbing the value as is out of the template. AVA's can have tags of PRINTABLE_STRING, |
182 | | * TELETEXSTRING, T61STRING or UTF8_STRING with PRINTABLE_STRING and UTF8_STRING being the most common. |
183 | | * The other feature that would be nice is returning a pointer to our requested data using the space |
184 | | * of the parent (basically what this code is doing here), rather than allocating and copying. |
185 | | */ |
186 | | |
187 | | /* unwrap the sequence */ |
188 | 0 | dummy = ava; dummy_len = ava_len; |
189 | 0 | ava = sc_asn1_skip_tag(ctx, &dummy, &dummy_len, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, &ava_len); |
190 | 0 | if (ava == NULL) |
191 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_ASN1_OBJECT, "ASN.1 decoding of AVA"); |
192 | | |
193 | | /* unwrap the oid */ |
194 | 0 | oidp = sc_asn1_skip_tag(ctx, &ava, &ava_len, SC_ASN1_TAG_OBJECT, &oid_len); |
195 | 0 | if (ava == NULL) |
196 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_ASN1_OBJECT, "ASN.1 decoding of AVA OID"); |
197 | | |
198 | | /* Convert to OID */ |
199 | 0 | rv = sc_asn1_decode_object_id(oidp, oid_len, &oid); |
200 | 0 | if (rv != SC_SUCCESS) |
201 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_ASN1_OBJECT, "ASN.1 decoding of AVA OID"); |
202 | | |
203 | 0 | if (sc_compare_oid(&oid, type) == 0) |
204 | 0 | continue; |
205 | | |
206 | | /* Yes, then return the name */ |
207 | 0 | dummy = sc_asn1_skip_tag(ctx, &ava, &ava_len, ava[0] & SC_ASN1_TAG_PRIMITIVE, &dummy_len); |
208 | 0 | if (dummy == NULL) |
209 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_ASN1_OBJECT, "ASN.1 decoding of AVA name"); |
210 | 0 | if (*name == NULL) { |
211 | 0 | *name = malloc(dummy_len); |
212 | 0 | if (*name == NULL) |
213 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); |
214 | 0 | *name_len = dummy_len; |
215 | 0 | } |
216 | | |
217 | 0 | *name_len = MIN(dummy_len, *name_len); |
218 | 0 | memcpy(*name, dummy, *name_len); |
219 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
220 | 0 | } |
221 | | |
222 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_ASN1_OBJECT_NOT_FOUND); |
223 | 0 | } |
224 | | |
225 | | |
226 | | /* Get a specific extension from the cert. |
227 | | * The extension is identified by it's oid value. |
228 | | * NOTE: extensions can occur in any number or any order, which is why we |
229 | | * can't parse them with a single pass of the asn1 decoder. |
230 | | * If is_critical is supplied, then it is set to 1 if the extension is critical |
231 | | * and 0 if it is not. |
232 | | * The data in the extension is extension specific. |
233 | | * The following are common extension values: |
234 | | * Subject Key ID: struct sc_object_id type = {{2, 5, 29, 14, -1}}; |
235 | | * Key Usage: struct sc_object_id type = {{2, 5, 29, 15, -1}}; |
236 | | * Subject Alt Name: struct sc_object_id type = {{2, 5, 29, 17, -1}}; |
237 | | * Basic Constraints: struct sc_object_id type = {{2, 5, 29, 19, -1}}; |
238 | | * CRL Distribution Points: struct sc_object_id type = {{2, 5, 29, 31, -1}}; |
239 | | * Certificate Policies: struct sc_object_id type = {{2, 5, 29, 32, -1}}; |
240 | | * Extended Key Usage: struct sc_object_id type = {{2, 5, 29, 37, -1}}; |
241 | | * |
242 | | * if *ext_val is NULL, sc_pkcs15_get_extension will allocate space for ext_val. |
243 | | */ |
244 | | int |
245 | | sc_pkcs15_get_extension(struct sc_context *ctx, struct sc_pkcs15_cert *cert, |
246 | | const struct sc_object_id *type, u8 **ext_val, |
247 | | size_t *ext_val_len, int *is_critical) |
248 | 0 | { |
249 | 0 | const u8 *ext = NULL; |
250 | 0 | const u8 *next_ext = NULL; |
251 | 0 | size_t ext_len = 0; |
252 | 0 | size_t next_ext_len = 0; |
253 | 0 | struct sc_object_id oid; |
254 | 0 | u8 *val = NULL; |
255 | 0 | size_t val_len = 0; |
256 | 0 | int critical; |
257 | 0 | int r; |
258 | 0 | struct sc_asn1_entry asn1_cert_ext[] = { |
259 | 0 | { "x509v3 entry OID", SC_ASN1_OBJECT, SC_ASN1_TAG_OBJECT, 0, &oid, 0 }, |
260 | 0 | { "criticalFlag", SC_ASN1_BOOLEAN, SC_ASN1_TAG_BOOLEAN, SC_ASN1_OPTIONAL, &critical, NULL }, |
261 | 0 | { "extensionValue",SC_ASN1_OCTET_STRING, SC_ASN1_TAG_OCTET_STRING, SC_ASN1_ALLOC, &val, &val_len }, |
262 | 0 | { NULL, 0, 0, 0, NULL, NULL } |
263 | 0 | }; |
264 | |
|
265 | 0 | LOG_FUNC_CALLED(ctx); |
266 | |
|
267 | 0 | for (next_ext = cert->extensions, next_ext_len = cert->extensions_len; next_ext_len; ) { |
268 | | /* unwrap the set and point to the next ava */ |
269 | 0 | ext = sc_asn1_skip_tag(ctx, &next_ext, &next_ext_len, |
270 | 0 | SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, &ext_len); |
271 | 0 | if (ext == NULL) |
272 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_ASN1_OBJECT, "ASN.1 decoding of AVA"); |
273 | | |
274 | | /* |
275 | | * use the sc_asn1_decoder for clarity. NOTE it would be more efficient to do this by hand |
276 | | * so we avoid the many malloc/frees here, but one hopes that one day the asn1_decode will allow |
277 | | * a 'static pointer' flag that returns a const pointer to the actual asn1 space so we only need |
278 | | * to make a final copy of the extension value before we return */ |
279 | 0 | critical = 0; |
280 | 0 | r = sc_asn1_decode(ctx, asn1_cert_ext, ext, ext_len, NULL, NULL); |
281 | 0 | if (r < 0) |
282 | 0 | LOG_FUNC_RETURN(ctx, r); |
283 | | |
284 | | /* is it the RN we are looking for */ |
285 | 0 | if (sc_compare_oid(&oid, type) != 0) { |
286 | 0 | if (*ext_val == NULL) { |
287 | 0 | *ext_val = val; |
288 | 0 | val = NULL; |
289 | 0 | *ext_val_len = val_len; |
290 | | /* do not free here -- return the allocated value to caller */ |
291 | 0 | } |
292 | 0 | else { |
293 | 0 | *ext_val_len = MIN(*ext_val_len, val_len); |
294 | 0 | if (val) { |
295 | 0 | memcpy(*ext_val, val, *ext_val_len); |
296 | 0 | free(val); |
297 | 0 | } |
298 | 0 | } |
299 | |
|
300 | 0 | if (is_critical) |
301 | 0 | *is_critical = critical; |
302 | |
|
303 | 0 | r = (int)val_len; |
304 | 0 | LOG_FUNC_RETURN(ctx, r); |
305 | 0 | } |
306 | 0 | if (val) { |
307 | 0 | free(val); |
308 | 0 | val = NULL; |
309 | 0 | } |
310 | 0 | } |
311 | 0 | if (val) |
312 | 0 | free(val); |
313 | |
|
314 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_ASN1_OBJECT_NOT_FOUND); |
315 | 0 | } |
316 | | |
317 | | /* |
318 | | * Get an extension whose value is a bit string. These include keyUsage and extendedKeyUsage. |
319 | | * See above for the other parameters. |
320 | | */ |
321 | | int |
322 | | sc_pkcs15_get_bitstring_extension(struct sc_context *ctx, |
323 | | struct sc_pkcs15_cert *cert, const struct sc_object_id *type, |
324 | | unsigned int *value, int *is_critical) |
325 | 0 | { |
326 | 0 | int r; |
327 | 0 | u8 *bit_string = NULL; |
328 | 0 | size_t bit_string_len=0, val_len = sizeof(*value); |
329 | 0 | struct sc_asn1_entry asn1_bit_string[] = { |
330 | 0 | { "bitString", SC_ASN1_BIT_FIELD, SC_ASN1_TAG_BIT_STRING, 0, value, &val_len }, |
331 | 0 | { NULL, 0, 0, 0, NULL, NULL } |
332 | 0 | }; |
333 | |
|
334 | 0 | LOG_FUNC_CALLED(ctx); |
335 | |
|
336 | 0 | r = sc_pkcs15_get_extension(ctx, cert, type, &bit_string, &bit_string_len, is_critical); |
337 | 0 | LOG_TEST_RET(ctx, r, "Get extension error"); |
338 | | |
339 | 0 | r = sc_asn1_decode(ctx, asn1_bit_string, bit_string, bit_string_len, NULL, NULL); |
340 | 0 | free(bit_string); |
341 | 0 | LOG_TEST_RET(ctx, r, "Decoding extension bit string"); |
342 | | |
343 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
344 | 0 | } |
345 | | |
346 | | |
347 | | int |
348 | | sc_pkcs15_pubkey_from_cert(struct sc_context *ctx, |
349 | | struct sc_pkcs15_der *cert_blob, struct sc_pkcs15_pubkey **out) |
350 | 0 | { |
351 | 0 | int rv; |
352 | 0 | struct sc_pkcs15_cert * cert; |
353 | |
|
354 | 0 | cert = calloc(1, sizeof(struct sc_pkcs15_cert)); |
355 | 0 | if (cert == NULL) |
356 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
357 | | |
358 | 0 | rv = parse_x509_cert(ctx, cert_blob, cert); |
359 | |
|
360 | 0 | *out = cert->key; |
361 | 0 | cert->key = NULL; |
362 | 0 | sc_pkcs15_free_certificate(cert); |
363 | |
|
364 | 0 | LOG_FUNC_RETURN(ctx, rv); |
365 | 0 | } |
366 | | |
367 | | |
368 | | int |
369 | | sc_pkcs15_read_certificate(struct sc_pkcs15_card *p15card, const struct sc_pkcs15_cert_info *info, |
370 | | int private_obj, struct sc_pkcs15_cert **cert_out) |
371 | 0 | { |
372 | 0 | struct sc_context *ctx = NULL; |
373 | 0 | struct sc_pkcs15_cert *cert = NULL; |
374 | 0 | struct sc_pkcs15_der der; |
375 | 0 | int r; |
376 | |
|
377 | 0 | if (p15card == NULL || info == NULL || cert_out == NULL) { |
378 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
379 | 0 | } |
380 | 0 | ctx = p15card->card->ctx; |
381 | 0 | LOG_FUNC_CALLED(ctx); |
382 | |
|
383 | 0 | if (info->value.len && info->value.value) { |
384 | 0 | sc_der_copy(&der, &info->value); |
385 | 0 | } |
386 | 0 | else if (info->path.len) { |
387 | 0 | r = sc_pkcs15_read_file(p15card, &info->path, &der.value, &der.len, private_obj); |
388 | 0 | LOG_TEST_RET(ctx, r, "Unable to read certificate file."); |
389 | 0 | } |
390 | 0 | else { |
391 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_OBJECT_NOT_FOUND); |
392 | 0 | } |
393 | | |
394 | 0 | cert = malloc(sizeof(struct sc_pkcs15_cert)); |
395 | 0 | if (cert == NULL) { |
396 | 0 | free(der.value); |
397 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); |
398 | 0 | } |
399 | 0 | memset(cert, 0, sizeof(struct sc_pkcs15_cert)); |
400 | 0 | if (parse_x509_cert(ctx, &der, cert)) { |
401 | 0 | free(der.value); |
402 | 0 | sc_pkcs15_free_certificate(cert); |
403 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ASN1_OBJECT); |
404 | 0 | } |
405 | 0 | free(der.value); |
406 | |
|
407 | 0 | *cert_out = cert; |
408 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
409 | 0 | } |
410 | | |
411 | | |
412 | | static const struct sc_asn1_entry c_asn1_cred_ident[] = { |
413 | | { "idType", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, 0, NULL, NULL }, |
414 | | { "idValue", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_OCTET_STRING, 0, NULL, NULL }, |
415 | | { NULL, 0, 0, 0, NULL, NULL } |
416 | | }; |
417 | | static const struct sc_asn1_entry c_asn1_com_cert_attr[] = { |
418 | | { "iD", SC_ASN1_PKCS15_ID, SC_ASN1_TAG_OCTET_STRING, 0, NULL, NULL }, |
419 | | { "authority", SC_ASN1_BOOLEAN, SC_ASN1_TAG_BOOLEAN, SC_ASN1_OPTIONAL, NULL, NULL }, |
420 | | { "identifier", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, |
421 | | /* FIXME: Add rest of the optional fields */ |
422 | | { NULL, 0, 0, 0, NULL, NULL } |
423 | | }; |
424 | | static const struct sc_asn1_entry c_asn1_x509_cert_value_choice[] = { |
425 | | { "path", SC_ASN1_PATH, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, |
426 | | { "direct", SC_ASN1_OCTET_STRING, SC_ASN1_CTX | 0 | SC_ASN1_CONS, SC_ASN1_OPTIONAL | SC_ASN1_ALLOC, NULL, NULL }, |
427 | | { NULL, 0, 0, 0, NULL, NULL } |
428 | | }; |
429 | | static const struct sc_asn1_entry c_asn1_x509_cert_attr[] = { |
430 | | { "value", SC_ASN1_CHOICE, 0, 0, NULL, NULL }, |
431 | | { NULL, 0, 0, 0, NULL, NULL } |
432 | | }; |
433 | | static const struct sc_asn1_entry c_asn1_type_cert_attr[] = { |
434 | | { "x509CertificateAttributes", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL }, |
435 | | { NULL, 0, 0, 0, NULL, NULL } |
436 | | }; |
437 | | static const struct sc_asn1_entry c_asn1_cert[] = { |
438 | | { "x509Certificate", SC_ASN1_PKCS15_OBJECT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL }, |
439 | | { NULL, 0, 0, 0, NULL, NULL } |
440 | | }; |
441 | | |
442 | | |
443 | | int |
444 | | sc_pkcs15_decode_cdf_entry(struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *obj, |
445 | | const u8 ** buf, size_t *buflen) |
446 | 0 | { |
447 | 0 | sc_context_t *ctx = p15card->card->ctx; |
448 | 0 | struct sc_pkcs15_cert_info info; |
449 | 0 | struct sc_asn1_entry asn1_cred_ident[3], asn1_com_cert_attr[4], |
450 | 0 | asn1_x509_cert_attr[2], asn1_type_cert_attr[2], |
451 | 0 | asn1_cert[2], asn1_x509_cert_value_choice[3]; |
452 | 0 | struct sc_asn1_pkcs15_object cert_obj = { |
453 | 0 | obj, asn1_com_cert_attr, NULL, |
454 | 0 | asn1_type_cert_attr }; |
455 | 0 | sc_pkcs15_der_t *der = &info.value; |
456 | 0 | u8 id_value[128]; |
457 | 0 | int id_type; |
458 | 0 | size_t id_value_len = sizeof(id_value); |
459 | 0 | int r; |
460 | |
|
461 | 0 | sc_copy_asn1_entry(c_asn1_cred_ident, asn1_cred_ident); |
462 | 0 | sc_copy_asn1_entry(c_asn1_com_cert_attr, asn1_com_cert_attr); |
463 | 0 | sc_copy_asn1_entry(c_asn1_x509_cert_attr, asn1_x509_cert_attr); |
464 | 0 | sc_copy_asn1_entry(c_asn1_x509_cert_value_choice, asn1_x509_cert_value_choice); |
465 | 0 | sc_copy_asn1_entry(c_asn1_type_cert_attr, asn1_type_cert_attr); |
466 | 0 | sc_copy_asn1_entry(c_asn1_cert, asn1_cert); |
467 | |
|
468 | 0 | sc_format_asn1_entry(asn1_cred_ident + 0, &id_type, NULL, 0); |
469 | 0 | sc_format_asn1_entry(asn1_cred_ident + 1, &id_value, &id_value_len, 0); |
470 | 0 | sc_format_asn1_entry(asn1_com_cert_attr + 0, &info.id, NULL, 0); |
471 | 0 | sc_format_asn1_entry(asn1_com_cert_attr + 1, &info.authority, NULL, 0); |
472 | 0 | sc_format_asn1_entry(asn1_com_cert_attr + 2, asn1_cred_ident, NULL, 0); |
473 | 0 | sc_format_asn1_entry(asn1_x509_cert_attr + 0, asn1_x509_cert_value_choice, NULL, 0); |
474 | 0 | sc_format_asn1_entry(asn1_x509_cert_value_choice + 0, &info.path, NULL, 0); |
475 | 0 | sc_format_asn1_entry(asn1_x509_cert_value_choice + 1, &der->value, &der->len, 0); |
476 | 0 | sc_format_asn1_entry(asn1_type_cert_attr + 0, asn1_x509_cert_attr, NULL, 0); |
477 | 0 | sc_format_asn1_entry(asn1_cert + 0, &cert_obj, NULL, 0); |
478 | | |
479 | | /* Fill in defaults */ |
480 | 0 | memset(&info, 0, sizeof(info)); |
481 | 0 | info.authority = 0; |
482 | |
|
483 | 0 | r = sc_asn1_decode(ctx, asn1_cert, *buf, *buflen, buf, buflen); |
484 | | /* In case of error, trash the cert value (direct coding) */ |
485 | 0 | if (r < 0 && der->value) |
486 | 0 | free(der->value); |
487 | 0 | if (r == SC_ERROR_ASN1_END_OF_CONTENTS) |
488 | 0 | return r; |
489 | 0 | LOG_TEST_RET(ctx, r, "ASN.1 decoding failed"); |
490 | | |
491 | 0 | if (!p15card->app || !p15card->app->ddo.aid.len) { |
492 | 0 | if (!p15card->file_app) { |
493 | 0 | free(der->value); |
494 | 0 | return SC_ERROR_INTERNAL; |
495 | 0 | } |
496 | 0 | r = sc_pkcs15_make_absolute_path(&p15card->file_app->path, &info.path); |
497 | 0 | LOG_TEST_RET(ctx, r, "Cannot make absolute path"); |
498 | 0 | } |
499 | 0 | else { |
500 | 0 | info.path.aid = p15card->app->ddo.aid; |
501 | 0 | } |
502 | 0 | sc_log(ctx, "Certificate path '%s'", sc_print_path(&info.path)); |
503 | |
|
504 | 0 | switch (p15card->opts.pin_protected_certificate) { |
505 | 0 | case SC_PKCS15_CARD_OPTS_PRIV_CERT_DECLASSIFY: |
506 | 0 | sc_log(ctx, "Declassifying certificate"); |
507 | 0 | obj->flags &= ~SC_PKCS15_CO_FLAG_PRIVATE; |
508 | 0 | break; |
509 | 0 | case SC_PKCS15_CARD_OPTS_PRIV_CERT_IGNORE: |
510 | 0 | sc_log(ctx, "Ignoring certificate"); |
511 | 0 | free(der->value); |
512 | 0 | return 0; |
513 | 0 | } |
514 | | |
515 | 0 | obj->type = SC_PKCS15_TYPE_CERT_X509; |
516 | 0 | obj->data = malloc(sizeof(info)); |
517 | 0 | if (obj->data == NULL) |
518 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); |
519 | 0 | memcpy(obj->data, &info, sizeof(info)); |
520 | |
|
521 | 0 | return 0; |
522 | 0 | } |
523 | | |
524 | | |
525 | | int |
526 | | sc_pkcs15_encode_cdf_entry(sc_context_t *ctx, const struct sc_pkcs15_object *obj, |
527 | | u8 **buf, size_t *bufsize) |
528 | 0 | { |
529 | 0 | struct sc_asn1_entry asn1_cred_ident[3], asn1_com_cert_attr[4], |
530 | 0 | asn1_x509_cert_attr[2], asn1_type_cert_attr[2], |
531 | 0 | asn1_cert[2], asn1_x509_cert_value_choice[3]; |
532 | 0 | struct sc_pkcs15_cert_info *infop = (sc_pkcs15_cert_info_t *) obj->data; |
533 | 0 | sc_pkcs15_der_t *der = &infop->value; |
534 | 0 | struct sc_asn1_pkcs15_object cert_obj = { (struct sc_pkcs15_object *) obj, |
535 | 0 | asn1_com_cert_attr, NULL, |
536 | 0 | asn1_type_cert_attr }; |
537 | 0 | int r; |
538 | |
|
539 | 0 | sc_copy_asn1_entry(c_asn1_cred_ident, asn1_cred_ident); |
540 | 0 | sc_copy_asn1_entry(c_asn1_com_cert_attr, asn1_com_cert_attr); |
541 | 0 | sc_copy_asn1_entry(c_asn1_x509_cert_attr, asn1_x509_cert_attr); |
542 | 0 | sc_copy_asn1_entry(c_asn1_x509_cert_value_choice, asn1_x509_cert_value_choice); |
543 | 0 | sc_copy_asn1_entry(c_asn1_type_cert_attr, asn1_type_cert_attr); |
544 | 0 | sc_copy_asn1_entry(c_asn1_cert, asn1_cert); |
545 | |
|
546 | 0 | sc_format_asn1_entry(asn1_com_cert_attr + 0, (void *) &infop->id, NULL, 1); |
547 | 0 | if (infop->authority) |
548 | 0 | sc_format_asn1_entry(asn1_com_cert_attr + 1, (void *) &infop->authority, NULL, 1); |
549 | 0 | if (infop->path.len || !der->value) { |
550 | 0 | sc_format_asn1_entry(asn1_x509_cert_value_choice + 0, &infop->path, NULL, 1); |
551 | 0 | } else { |
552 | 0 | sc_format_asn1_entry(asn1_x509_cert_value_choice + 1, der->value, &der->len, 1); |
553 | 0 | } |
554 | 0 | sc_format_asn1_entry(asn1_type_cert_attr + 0, &asn1_x509_cert_value_choice, NULL, 1); |
555 | 0 | sc_format_asn1_entry(asn1_cert + 0, (void *) &cert_obj, NULL, 1); |
556 | |
|
557 | 0 | r = sc_asn1_encode(ctx, asn1_cert, buf, bufsize); |
558 | |
|
559 | 0 | return r; |
560 | 0 | } |
561 | | |
562 | | /* Only certain usages are valid for a given algorithm, return all the usages |
563 | | * that the algorithm supports so we can use it as a filter for all |
564 | | * the public and private key usages |
565 | | */ |
566 | | static unsigned int |
567 | | sc_pkcs15_alg_flags_from_algorithm(unsigned long algorithm) |
568 | 0 | { |
569 | 0 | switch (algorithm) { |
570 | 0 | case SC_ALGORITHM_RSA: |
571 | 0 | return SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_WRAP | |
572 | 0 | SC_PKCS15_PRKEY_USAGE_VERIFY | SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER | |
573 | 0 | SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP | |
574 | 0 | SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_SIGNRECOVER | |
575 | 0 | SC_PKCS15_PRKEY_USAGE_NONREPUDIATION; |
576 | | #ifdef SC_ALGORITHM_DH |
577 | | case SC_ALGORITHM_DH: |
578 | | return SC_PKCS15_PRKEY_USAGE_DERIVE ; |
579 | | #endif |
580 | 0 | case SC_ALGORITHM_EC: |
581 | 0 | return SC_PKCS15_PRKEY_USAGE_DERIVE | SC_PKCS15_PRKEY_USAGE_VERIFY| |
582 | 0 | SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_NONREPUDIATION; |
583 | 0 | case SC_ALGORITHM_GOSTR3410: |
584 | 0 | return SC_PKCS15_PRKEY_USAGE_DERIVE | SC_PKCS15_PRKEY_USAGE_VERIFY| |
585 | 0 | SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_NONREPUDIATION; |
586 | 0 | } |
587 | 0 | return 0; |
588 | 0 | } |
589 | | |
590 | | /* These are the cert key usage bits that map to various PKCS #11 (and thus PKCS #15) flags */ |
591 | | #define SC_PKCS15_X509_USAGE_SIGNATURE \ |
592 | 0 | (SC_X509_DIGITAL_SIGNATURE | \ |
593 | 0 | SC_X509_NON_REPUDIATION | \ |
594 | 0 | SC_X509_KEY_CERT_SIGN | \ |
595 | 0 | SC_X509_CRL_SIGN) |
596 | | #define SC_PKCS15_X509_USAGE_DERIVE \ |
597 | 0 | SC_X509_KEY_AGREEMENT |
598 | | #define SC_PKCS15_X509_USAGE_UNWRAP \ |
599 | 0 | (SC_X509_KEY_ENCIPHERMENT | \ |
600 | 0 | SC_X509_KEY_AGREEMENT) |
601 | | #define SC_PKCS15_X509_USAGE_DECRYPT \ |
602 | 0 | (SC_X509_DATA_ENCIPHERMENT | \ |
603 | 0 | SC_X509_ENCIPHER_ONLY) |
604 | | #define SC_PKCS15_X509_USAGE_NONREPUDIATION \ |
605 | 0 | SC_X509_NON_REPUDIATION |
606 | | |
607 | | /* map a cert usage and algorithm to public and private key usages */ |
608 | | int |
609 | | sc_pkcs15_map_usage(unsigned int cert_usage, unsigned long algorithm, |
610 | | unsigned int *pub_usage_ptr, unsigned int *pr_usage_ptr, |
611 | | int allow_nonrepudiation) |
612 | 0 | { |
613 | 0 | unsigned int pub_usage = 0, pr_usage = 0; |
614 | 0 | unsigned int alg_flags = sc_pkcs15_alg_flags_from_algorithm(algorithm); |
615 | |
|
616 | 0 | if (cert_usage & SC_PKCS15_X509_USAGE_SIGNATURE) { |
617 | 0 | pub_usage |= SC_PKCS15_PRKEY_USAGE_VERIFY|SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER; |
618 | 0 | pr_usage |= SC_PKCS15_PRKEY_USAGE_SIGN|SC_PKCS15_PRKEY_USAGE_SIGNRECOVER; |
619 | 0 | } |
620 | 0 | if (cert_usage & SC_PKCS15_X509_USAGE_DERIVE) { |
621 | 0 | pub_usage |= SC_PKCS15_PRKEY_USAGE_DERIVE; |
622 | 0 | pr_usage |= SC_PKCS15_PRKEY_USAGE_DERIVE; |
623 | 0 | } |
624 | 0 | if (cert_usage & (SC_PKCS15_X509_USAGE_DECRYPT|SC_PKCS15_X509_USAGE_UNWRAP)) { |
625 | 0 | pub_usage |= SC_PKCS15_PRKEY_USAGE_ENCRYPT; |
626 | 0 | pr_usage |= SC_PKCS15_PRKEY_USAGE_DECRYPT; |
627 | 0 | } |
628 | 0 | if (allow_nonrepudiation && (cert_usage & SC_PKCS15_X509_USAGE_NONREPUDIATION)) { |
629 | 0 | pub_usage |= SC_PKCS15_PRKEY_USAGE_NONREPUDIATION; |
630 | 0 | pr_usage |= SC_PKCS15_PRKEY_USAGE_NONREPUDIATION; |
631 | 0 | } |
632 | | /* filter usages algorithm */ |
633 | 0 | if (pub_usage_ptr) { |
634 | 0 | *pub_usage_ptr = pub_usage & alg_flags; |
635 | 0 | } |
636 | 0 | if (pr_usage_ptr) { |
637 | 0 | *pr_usage_ptr = pr_usage & alg_flags; |
638 | 0 | } |
639 | 0 | return SC_SUCCESS; |
640 | 0 | } |
641 | | |
642 | | void |
643 | | sc_pkcs15_free_certificate(struct sc_pkcs15_cert *cert) |
644 | 0 | { |
645 | 0 | if (cert == NULL) { |
646 | 0 | return; |
647 | 0 | } |
648 | | |
649 | 0 | sc_pkcs15_free_pubkey(cert->key); |
650 | 0 | free(cert->subject); |
651 | 0 | free(cert->issuer); |
652 | 0 | free(cert->serial); |
653 | 0 | free(cert->data.value); |
654 | 0 | free(cert->extensions); |
655 | 0 | free(cert); |
656 | 0 | } |
657 | | |
658 | | |
659 | | void |
660 | | sc_pkcs15_free_cert_info(sc_pkcs15_cert_info_t *cert) |
661 | 0 | { |
662 | 0 | if (!cert) |
663 | 0 | return; |
664 | 0 | free(cert->value.value); |
665 | 0 | free(cert); |
666 | 0 | } |