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