Return to pkcs12_decode.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libstrongswan / plugins / pkcs12 |
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: }