/src/strongswan/src/libstrongswan/plugins/pkcs12/pkcs12_decode.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2013 Tobias Brunner |
3 | | * |
4 | | * Copyright (C) secunet Security Networks AG |
5 | | * |
6 | | * This program is free software; you can redistribute it and/or modify it |
7 | | * under the terms of the GNU General Public License as published by the |
8 | | * Free Software Foundation; either version 2 of the License, or (at your |
9 | | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. |
10 | | * |
11 | | * This program is distributed in the hope that it will be useful, but |
12 | | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
13 | | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
14 | | * for more details. |
15 | | */ |
16 | | |
17 | | #include "pkcs12_decode.h" |
18 | | |
19 | | #include <utils/debug.h> |
20 | | #include <asn1/oid.h> |
21 | | #include <asn1/asn1.h> |
22 | | #include <asn1/asn1_parser.h> |
23 | | #include <credentials/sets/mem_cred.h> |
24 | | |
25 | | typedef struct private_pkcs12_t private_pkcs12_t; |
26 | | |
27 | | /** |
28 | | * Private data of a pkcs12_t object |
29 | | */ |
30 | | struct private_pkcs12_t { |
31 | | |
32 | | /** |
33 | | * Public interface |
34 | | */ |
35 | | pkcs12_t public; |
36 | | |
37 | | /** |
38 | | * Contained credentials |
39 | | */ |
40 | | mem_cred_t *creds; |
41 | | }; |
42 | | |
43 | | METHOD(container_t, get_type, container_type_t, |
44 | | private_pkcs12_t *this) |
45 | 0 | { |
46 | 0 | return CONTAINER_PKCS12; |
47 | 0 | } |
48 | | |
49 | | METHOD(container_t, get_data, bool, |
50 | | private_pkcs12_t *this, chunk_t *data) |
51 | 0 | { |
52 | | /* we could return the content of the outer-most PKCS#7 container (authSafe) |
53 | | * don't really see the point though */ |
54 | 0 | return FALSE; |
55 | 0 | } |
56 | | |
57 | | METHOD(container_t, get_encoding, bool, |
58 | | private_pkcs12_t *this, chunk_t *encoding) |
59 | 0 | { |
60 | | /* similar to get_data() we don't have any use for it at the moment */ |
61 | 0 | return FALSE; |
62 | 0 | } |
63 | | |
64 | | METHOD(pkcs12_t, create_cert_enumerator, enumerator_t*, |
65 | | private_pkcs12_t *this) |
66 | 0 | { |
67 | 0 | return this->creds->set.create_cert_enumerator(&this->creds->set, CERT_ANY, |
68 | 0 | KEY_ANY, NULL, FALSE); |
69 | 0 | } |
70 | | |
71 | | METHOD(pkcs12_t, create_key_enumerator, enumerator_t*, |
72 | | private_pkcs12_t *this) |
73 | 0 | { |
74 | 0 | return this->creds->set.create_private_enumerator(&this->creds->set, |
75 | 0 | KEY_ANY, NULL); |
76 | 0 | } |
77 | | |
78 | | METHOD(container_t, destroy, void, |
79 | | private_pkcs12_t *this) |
80 | 0 | { |
81 | 0 | this->creds->destroy(this->creds); |
82 | 0 | free(this); |
83 | 0 | } |
84 | | |
85 | | static private_pkcs12_t *pkcs12_create() |
86 | 0 | { |
87 | 0 | private_pkcs12_t *this; |
88 | |
|
89 | 0 | INIT(this, |
90 | 0 | .public = { |
91 | 0 | .container = { |
92 | 0 | .get_type = _get_type, |
93 | 0 | .create_signature_enumerator = (void*)enumerator_create_empty, |
94 | 0 | .get_data = _get_data, |
95 | 0 | .get_encoding = _get_encoding, |
96 | 0 | .destroy = _destroy, |
97 | 0 | }, |
98 | 0 | .create_cert_enumerator = _create_cert_enumerator, |
99 | 0 | .create_key_enumerator = _create_key_enumerator, |
100 | 0 | }, |
101 | 0 | .creds = mem_cred_create(), |
102 | 0 | ); |
103 | 0 | return this; |
104 | 0 | } |
105 | | |
106 | | /** |
107 | | * ASN.1 definition of an CertBag structure |
108 | | */ |
109 | | static const asn1Object_t certBagObjects[] = { |
110 | | { 0, "CertBag", ASN1_SEQUENCE, ASN1_BODY }, /* 0 */ |
111 | | { 1, "certId", ASN1_OID, ASN1_BODY }, /* 1 */ |
112 | | { 1, "certValue", ASN1_CONTEXT_C_0, ASN1_BODY }, /* 2 */ |
113 | | { 0, "exit", ASN1_EOC, ASN1_EXIT } |
114 | | }; |
115 | 0 | #define CERT_BAG_ID 1 |
116 | 0 | #define CERT_BAG_VALUE 2 |
117 | | |
118 | | /** |
119 | | * Parse a CertBag structure and extract certificate |
120 | | */ |
121 | | static bool add_certificate(private_pkcs12_t *this, int level0, chunk_t blob) |
122 | 0 | { |
123 | 0 | asn1_parser_t *parser; |
124 | 0 | chunk_t object; |
125 | 0 | int objectID; |
126 | 0 | int oid = OID_UNKNOWN; |
127 | 0 | bool success = FALSE; |
128 | |
|
129 | 0 | parser = asn1_parser_create(certBagObjects, blob); |
130 | 0 | parser->set_top_level(parser, level0); |
131 | |
|
132 | 0 | while (parser->iterate(parser, &objectID, &object)) |
133 | 0 | { |
134 | 0 | switch (objectID) |
135 | 0 | { |
136 | 0 | case CERT_BAG_ID: |
137 | 0 | oid = asn1_known_oid(object); |
138 | 0 | break; |
139 | 0 | case CERT_BAG_VALUE: |
140 | 0 | { |
141 | 0 | if (oid == OID_X509_CERTIFICATE && |
142 | 0 | asn1_parse_simple_object(&object, ASN1_OCTET_STRING, |
143 | 0 | parser->get_level(parser)+1, "x509Certificate")) |
144 | 0 | { |
145 | 0 | certificate_t *cert; |
146 | |
|
147 | 0 | DBG2(DBG_ASN, "-- > parsing certificate from PKCS#12"); |
148 | 0 | cert = lib->creds->create(lib->creds, |
149 | 0 | CRED_CERTIFICATE, CERT_X509, |
150 | 0 | BUILD_BLOB_ASN1_DER, object, |
151 | 0 | BUILD_END); |
152 | 0 | if (cert) |
153 | 0 | { |
154 | 0 | this->creds->add_cert(this->creds, FALSE, cert); |
155 | 0 | DBG2(DBG_ASN, "-- < --"); |
156 | 0 | } |
157 | 0 | else |
158 | 0 | { |
159 | 0 | DBG2(DBG_ASN, "-- < failed parsing certificate from " |
160 | 0 | "PKCS#12"); |
161 | 0 | } |
162 | 0 | } |
163 | 0 | break; |
164 | 0 | } |
165 | 0 | } |
166 | 0 | } |
167 | 0 | success = parser->success(parser); |
168 | 0 | parser->destroy(parser); |
169 | 0 | return success; |
170 | 0 | } |
171 | | |
172 | | /** |
173 | | * ASN.1 definition of an AuthenticatedSafe structure |
174 | | */ |
175 | | static const asn1Object_t safeContentsObjects[] = { |
176 | | { 0, "SafeContents", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ |
177 | | { 1, "SafeBag", ASN1_SEQUENCE, ASN1_BODY }, /* 1 */ |
178 | | { 2, "bagId", ASN1_OID, ASN1_BODY }, /* 2 */ |
179 | | { 2, "bagValue", ASN1_CONTEXT_C_0, ASN1_BODY }, /* 3 */ |
180 | | { 2, "bagAttr", ASN1_SET, ASN1_OPT|ASN1_RAW }, /* 4 */ |
181 | | { 2, "end opt", ASN1_EOC, ASN1_END }, /* 5 */ |
182 | | { 0, "end loop", ASN1_EOC, ASN1_END }, /* 6 */ |
183 | | { 0, "exit", ASN1_EOC, ASN1_EXIT } |
184 | | }; |
185 | 0 | #define SAFE_BAG_ID 2 |
186 | 0 | #define SAFE_BAG_VALUE 3 |
187 | | |
188 | | /** |
189 | | * Parse a SafeContents structure and extract credentials |
190 | | */ |
191 | | static bool parse_safe_contents(private_pkcs12_t *this, int level0, |
192 | | chunk_t blob) |
193 | 0 | { |
194 | 0 | asn1_parser_t *parser; |
195 | 0 | chunk_t object; |
196 | 0 | int objectID; |
197 | 0 | int oid = OID_UNKNOWN; |
198 | 0 | bool success = FALSE; |
199 | |
|
200 | 0 | parser = asn1_parser_create(safeContentsObjects, blob); |
201 | 0 | parser->set_top_level(parser, level0); |
202 | |
|
203 | 0 | while (parser->iterate(parser, &objectID, &object)) |
204 | 0 | { |
205 | 0 | switch (objectID) |
206 | 0 | { |
207 | 0 | case SAFE_BAG_ID: |
208 | 0 | oid = asn1_known_oid(object); |
209 | 0 | break; |
210 | 0 | case SAFE_BAG_VALUE: |
211 | 0 | { |
212 | 0 | switch (oid) |
213 | 0 | { |
214 | 0 | case OID_P12_CERT_BAG: |
215 | 0 | { |
216 | 0 | add_certificate(this, parser->get_level(parser)+1, |
217 | 0 | object); |
218 | 0 | break; |
219 | 0 | } |
220 | 0 | case OID_P12_KEY_BAG: |
221 | 0 | case OID_P12_PKCS8_KEY_BAG: |
222 | 0 | { |
223 | 0 | private_key_t *key; |
224 | |
|
225 | 0 | DBG2(DBG_ASN, "-- > parsing private key from PKCS#12"); |
226 | 0 | key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, |
227 | 0 | KEY_ANY, BUILD_BLOB_ASN1_DER, object, |
228 | 0 | BUILD_END); |
229 | 0 | if (key) |
230 | 0 | { |
231 | 0 | this->creds->add_key(this->creds, key); |
232 | 0 | DBG2(DBG_ASN, "-- < --"); |
233 | 0 | } |
234 | 0 | else |
235 | 0 | { |
236 | 0 | DBG2(DBG_ASN, "-- < failed parsing private key " |
237 | 0 | "from PKCS#12"); |
238 | 0 | } |
239 | 0 | } |
240 | 0 | default: |
241 | 0 | break; |
242 | 0 | } |
243 | 0 | break; |
244 | 0 | } |
245 | 0 | } |
246 | 0 | } |
247 | 0 | success = parser->success(parser); |
248 | 0 | parser->destroy(parser); |
249 | 0 | return success; |
250 | 0 | } |
251 | | |
252 | | /** |
253 | | * ASN.1 definition of an AuthenticatedSafe structure |
254 | | */ |
255 | | static const asn1Object_t authenticatedSafeObjects[] = { |
256 | | { 0, "AuthenticatedSafe", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ |
257 | | { 1, "ContentInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */ |
258 | | { 0, "end loop", ASN1_EOC, ASN1_END }, /* 2 */ |
259 | | { 0, "exit", ASN1_EOC, ASN1_EXIT } |
260 | | }; |
261 | 0 | #define AUTHENTICATED_SAFE_DATA 1 |
262 | | |
263 | | /** |
264 | | * Parse an AuthenticatedSafe structure |
265 | | */ |
266 | | static bool parse_authenticated_safe(private_pkcs12_t *this, chunk_t blob) |
267 | 0 | { |
268 | 0 | asn1_parser_t *parser; |
269 | 0 | chunk_t object; |
270 | 0 | int objectID; |
271 | 0 | bool success = FALSE; |
272 | |
|
273 | 0 | parser = asn1_parser_create(authenticatedSafeObjects, blob); |
274 | |
|
275 | 0 | while (parser->iterate(parser, &objectID, &object)) |
276 | 0 | { |
277 | 0 | switch (objectID) |
278 | 0 | { |
279 | 0 | case AUTHENTICATED_SAFE_DATA: |
280 | 0 | { |
281 | 0 | container_t *container; |
282 | 0 | chunk_t data; |
283 | |
|
284 | 0 | container = lib->creds->create(lib->creds, CRED_CONTAINER, |
285 | 0 | CONTAINER_PKCS7, BUILD_BLOB_ASN1_DER, |
286 | 0 | object, BUILD_END); |
287 | 0 | if (!container) |
288 | 0 | { |
289 | 0 | goto end; |
290 | 0 | } |
291 | 0 | switch (container->get_type(container)) |
292 | 0 | { |
293 | 0 | case CONTAINER_PKCS7_DATA: |
294 | 0 | case CONTAINER_PKCS7_ENCRYPTED_DATA: |
295 | 0 | case CONTAINER_PKCS7_ENVELOPED_DATA: |
296 | 0 | if (container->get_data(container, &data)) |
297 | 0 | { |
298 | 0 | break; |
299 | 0 | } |
300 | | /* fall-through */ |
301 | 0 | default: |
302 | 0 | container->destroy(container); |
303 | 0 | goto end; |
304 | 0 | } |
305 | 0 | container->destroy(container); |
306 | |
|
307 | 0 | if (!parse_safe_contents(this, parser->get_level(parser)+1, |
308 | 0 | data)) |
309 | 0 | { |
310 | 0 | chunk_clear(&data); |
311 | 0 | goto end; |
312 | 0 | } |
313 | 0 | chunk_clear(&data); |
314 | 0 | break; |
315 | 0 | } |
316 | 0 | } |
317 | 0 | } |
318 | 0 | success = parser->success(parser); |
319 | 0 | end: |
320 | 0 | parser->destroy(parser); |
321 | 0 | return success; |
322 | 0 | } |
323 | | |
324 | | /** |
325 | | * Verify the given MAC using the given password. |
326 | | */ |
327 | | static bool verify_mac_pw(signer_t *signer, hash_algorithm_t hash, chunk_t salt, |
328 | | uint64_t iterations, chunk_t data, chunk_t mac, |
329 | | chunk_t pw) |
330 | 0 | { |
331 | 0 | chunk_t key, calculated; |
332 | 0 | bool success = FALSE; |
333 | |
|
334 | 0 | key = chunk_alloca(signer->get_key_size(signer)); |
335 | 0 | calculated = chunk_alloca(signer->get_block_size(signer)); |
336 | |
|
337 | 0 | if (pkcs12_derive_key(hash, pw, salt, iterations, PKCS12_KEY_MAC, key) && |
338 | 0 | signer->set_key(signer, key) && |
339 | 0 | signer->get_signature(signer, data, calculated.ptr) && |
340 | 0 | chunk_equals_const(mac, calculated)) |
341 | 0 | { |
342 | 0 | success = TRUE; |
343 | 0 | } |
344 | 0 | memwipe(key.ptr, key.len); |
345 | 0 | return success; |
346 | 0 | } |
347 | | |
348 | | /** |
349 | | * Verify the given MAC with available passwords. |
350 | | */ |
351 | | static bool verify_mac(hash_algorithm_t hash, chunk_t salt, |
352 | | uint64_t iterations, chunk_t data, chunk_t mac) |
353 | 0 | { |
354 | 0 | enumerator_t *enumerator; |
355 | 0 | shared_key_t *shared; |
356 | 0 | signer_t *signer; |
357 | 0 | bool success = FALSE; |
358 | |
|
359 | 0 | signer = lib->crypto->create_signer(lib->crypto, |
360 | 0 | hasher_algorithm_to_integrity(hash, mac.len)); |
361 | 0 | if (!signer) |
362 | 0 | { |
363 | 0 | return FALSE; |
364 | 0 | } |
365 | | |
366 | | /* try without and with an empty password, which is not the same thing */ |
367 | 0 | if (verify_mac_pw(signer, hash, salt, iterations, data, mac, chunk_empty) || |
368 | 0 | verify_mac_pw(signer, hash, salt, iterations, data, mac, chunk_from_str(""))) |
369 | 0 | { |
370 | 0 | signer->destroy(signer); |
371 | 0 | return TRUE; |
372 | 0 | } |
373 | | |
374 | 0 | enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr, |
375 | 0 | SHARED_PRIVATE_KEY_PASS, NULL, NULL); |
376 | 0 | while (enumerator->enumerate(enumerator, &shared, NULL, NULL)) |
377 | 0 | { |
378 | 0 | if (verify_mac_pw(signer, hash, salt, iterations, data, mac, |
379 | 0 | shared->get_key(shared))) |
380 | 0 | { |
381 | 0 | success = TRUE; |
382 | 0 | break; |
383 | 0 | } |
384 | 0 | } |
385 | 0 | enumerator->destroy(enumerator); |
386 | 0 | signer->destroy(signer); |
387 | 0 | return success; |
388 | 0 | } |
389 | | |
390 | | /** |
391 | | * ASN.1 definition of digestInfo |
392 | | */ |
393 | | static const asn1Object_t digestInfoObjects[] = { |
394 | | { 0, "digestInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ |
395 | | { 1, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 1 */ |
396 | | { 1, "digest", ASN1_OCTET_STRING, ASN1_BODY }, /* 2 */ |
397 | | { 0, "exit", ASN1_EOC, ASN1_EXIT } |
398 | | }; |
399 | 0 | #define DIGEST_INFO_ALGORITHM 1 |
400 | 0 | #define DIGEST_INFO_DIGEST 2 |
401 | | |
402 | | /** |
403 | | * Parse a digestInfo structure |
404 | | */ |
405 | | static bool parse_digest_info(chunk_t blob, int level0, hash_algorithm_t *hash, |
406 | | chunk_t *digest) |
407 | 0 | { |
408 | 0 | asn1_parser_t *parser; |
409 | 0 | chunk_t object; |
410 | 0 | int objectID; |
411 | 0 | bool success; |
412 | |
|
413 | 0 | parser = asn1_parser_create(digestInfoObjects, blob); |
414 | 0 | parser->set_top_level(parser, level0); |
415 | |
|
416 | 0 | while (parser->iterate(parser, &objectID, &object)) |
417 | 0 | { |
418 | 0 | switch (objectID) |
419 | |
|
420 | 0 | { |
421 | 0 | case DIGEST_INFO_ALGORITHM: |
422 | 0 | { |
423 | 0 | int oid = asn1_parse_algorithmIdentifier(object, |
424 | 0 | parser->get_level(parser)+1, NULL); |
425 | |
|
426 | 0 | *hash = hasher_algorithm_from_oid(oid); |
427 | 0 | break; |
428 | 0 | } |
429 | 0 | case DIGEST_INFO_DIGEST: |
430 | 0 | { |
431 | 0 | *digest = object; |
432 | 0 | break; |
433 | 0 | } |
434 | 0 | default: |
435 | 0 | break; |
436 | 0 | } |
437 | 0 | } |
438 | 0 | success = parser->success(parser); |
439 | 0 | parser->destroy(parser); |
440 | 0 | return success; |
441 | 0 | } |
442 | | |
443 | | /** |
444 | | * ASN.1 definition of a PFX structure |
445 | | */ |
446 | | static const asn1Object_t PFXObjects[] = { |
447 | | { 0, "PFX", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ |
448 | | { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */ |
449 | | { 1, "authSafe", ASN1_SEQUENCE, ASN1_OBJ }, /* 2 */ |
450 | | { 1, "macData", ASN1_SEQUENCE, ASN1_OPT|ASN1_BODY }, /* 3 */ |
451 | | { 2, "mac", ASN1_SEQUENCE, ASN1_RAW }, /* 4 */ |
452 | | { 2, "macSalt", ASN1_OCTET_STRING, ASN1_BODY }, /* 5 */ |
453 | | { 2, "iterations", ASN1_INTEGER, ASN1_DEF|ASN1_BODY }, /* 6 */ |
454 | | { 1, "end opt", ASN1_EOC, ASN1_END }, /* 7 */ |
455 | | { 0, "exit", ASN1_EOC, ASN1_EXIT } |
456 | | }; |
457 | 0 | #define PFX_AUTH_SAFE 2 |
458 | 0 | #define PFX_MAC 4 |
459 | 0 | #define PFX_SALT 5 |
460 | 0 | #define PFX_ITERATIONS 6 |
461 | | |
462 | | /** |
463 | | * Parse an ASN.1 encoded PFX structure |
464 | | */ |
465 | | static bool parse_PFX(private_pkcs12_t *this, chunk_t blob) |
466 | 0 | { |
467 | 0 | asn1_parser_t *parser; |
468 | 0 | int objectID; |
469 | 0 | chunk_t object, auth_safe, digest = chunk_empty, salt = chunk_empty, |
470 | 0 | data = chunk_empty; |
471 | 0 | hash_algorithm_t hash = HASH_UNKNOWN; |
472 | 0 | container_t *container = NULL; |
473 | 0 | uint64_t iterations = 0; |
474 | 0 | bool success = FALSE; |
475 | |
|
476 | 0 | parser = asn1_parser_create(PFXObjects, blob); |
477 | |
|
478 | 0 | while (parser->iterate(parser, &objectID, &object)) |
479 | 0 | { |
480 | 0 | switch (objectID) |
481 | 0 | { |
482 | 0 | case PFX_AUTH_SAFE: |
483 | 0 | { |
484 | 0 | auth_safe = object; |
485 | 0 | break; |
486 | 0 | } |
487 | 0 | case PFX_MAC: |
488 | 0 | { |
489 | 0 | if (!parse_digest_info(object, parser->get_level(parser)+1, |
490 | 0 | &hash, &digest)) |
491 | 0 | { |
492 | 0 | goto end_parse; |
493 | 0 | } |
494 | 0 | break; |
495 | 0 | } |
496 | 0 | case PFX_SALT: |
497 | 0 | { |
498 | 0 | salt = object; |
499 | 0 | break; |
500 | 0 | } |
501 | 0 | case PFX_ITERATIONS: |
502 | 0 | { |
503 | 0 | iterations = object.len ? asn1_parse_integer_uint64(object) : 1; |
504 | 0 | break; |
505 | 0 | } |
506 | 0 | } |
507 | 0 | } |
508 | 0 | success = parser->success(parser); |
509 | |
|
510 | 0 | end_parse: |
511 | 0 | parser->destroy(parser); |
512 | 0 | if (!success) |
513 | 0 | { |
514 | 0 | return FALSE; |
515 | 0 | } |
516 | | |
517 | 0 | success = FALSE; |
518 | 0 | DBG2(DBG_ASN, "-- > --"); |
519 | 0 | container = lib->creds->create(lib->creds, CRED_CONTAINER, CONTAINER_PKCS7, |
520 | 0 | BUILD_BLOB_ASN1_DER, auth_safe, BUILD_END); |
521 | 0 | if (container && container->get_data(container, &data)) |
522 | 0 | { |
523 | 0 | if (hash != HASH_UNKNOWN) |
524 | 0 | { |
525 | 0 | if (container->get_type(container) != CONTAINER_PKCS7_DATA) |
526 | 0 | { |
527 | 0 | goto end; |
528 | 0 | } |
529 | 0 | if (!verify_mac(hash, salt, iterations, data, digest)) |
530 | 0 | { |
531 | 0 | DBG1(DBG_ASN, " MAC verification of PKCS#12 container failed"); |
532 | 0 | goto end; |
533 | 0 | } |
534 | 0 | } |
535 | 0 | else |
536 | 0 | { |
537 | 0 | enumerator_t *enumerator; |
538 | 0 | auth_cfg_t *auth; |
539 | |
|
540 | 0 | if (container->get_type(container) != CONTAINER_PKCS7_SIGNED_DATA) |
541 | 0 | { |
542 | 0 | goto end; |
543 | 0 | } |
544 | 0 | enumerator = container->create_signature_enumerator(container); |
545 | 0 | if (!enumerator->enumerate(enumerator, &auth)) |
546 | 0 | { |
547 | 0 | DBG1(DBG_ASN, " signature verification of PKCS#12 container " |
548 | 0 | "failed"); |
549 | 0 | enumerator->destroy(enumerator); |
550 | 0 | goto end; |
551 | 0 | } |
552 | 0 | enumerator->destroy(enumerator); |
553 | 0 | } |
554 | 0 | success = parse_authenticated_safe(this, data); |
555 | 0 | } |
556 | 0 | end: |
557 | 0 | DBG2(DBG_ASN, "-- < --"); |
558 | 0 | DESTROY_IF(container); |
559 | 0 | chunk_free(&data); |
560 | 0 | return success; |
561 | 0 | } |
562 | | |
563 | | /** |
564 | | * See header. |
565 | | */ |
566 | | pkcs12_t *pkcs12_decode(container_type_t type, va_list args) |
567 | 0 | { |
568 | 0 | private_pkcs12_t *this; |
569 | 0 | chunk_t blob = chunk_empty; |
570 | |
|
571 | 0 | while (TRUE) |
572 | 0 | { |
573 | 0 | switch (va_arg(args, builder_part_t)) |
574 | 0 | { |
575 | 0 | case BUILD_BLOB_ASN1_DER: |
576 | 0 | blob = va_arg(args, chunk_t); |
577 | 0 | continue; |
578 | 0 | case BUILD_END: |
579 | 0 | break; |
580 | 0 | default: |
581 | 0 | return NULL; |
582 | 0 | } |
583 | 0 | break; |
584 | 0 | } |
585 | 0 | if (blob.len) |
586 | 0 | { |
587 | 0 | if (blob.len >= 2 && |
588 | 0 | blob.ptr[0] == ASN1_SEQUENCE && blob.ptr[1] == 0x80) |
589 | 0 | { /* looks like infinite length BER encoding, but we can't handle it. |
590 | | */ |
591 | 0 | return NULL; |
592 | 0 | } |
593 | 0 | this = pkcs12_create(); |
594 | 0 | if (parse_PFX(this, blob)) |
595 | 0 | { |
596 | 0 | return &this->public; |
597 | 0 | } |
598 | 0 | destroy(this); |
599 | 0 | } |
600 | 0 | return NULL; |
601 | 0 | } |