Return to pkcs7_signed_data.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libstrongswan / plugins / pkcs7 |
1.1 misho 1: /* 2: * Copyright (C) 2012 Martin Willi 3: * Copyright (C) 2012 revosec AG 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 "pkcs7_signed_data.h" 17: #include "pkcs7_attributes.h" 18: 19: #include <time.h> 20: 21: #include <utils/debug.h> 22: #include <asn1/oid.h> 23: #include <asn1/asn1.h> 24: #include <asn1/asn1_parser.h> 25: #include <credentials/sets/mem_cred.h> 26: #include <credentials/certificates/x509.h> 27: #include <credentials/keys/private_key.h> 28: 29: typedef struct private_pkcs7_signed_data_t private_pkcs7_signed_data_t; 30: 31: /** 32: * Private data of a PKCS#7 signed-data container. 33: */ 34: struct private_pkcs7_signed_data_t { 35: 36: /** 37: * Implements pkcs7_t. 38: */ 39: pkcs7_t public; 40: 41: /** 42: * Signed content data 43: */ 44: container_t *content; 45: 46: /** 47: * Encoded PKCS#7 signed-data 48: */ 49: chunk_t encoding; 50: 51: /** 52: * list of signerInfos, signerinfo_t 53: */ 54: linked_list_t *signerinfos; 55: 56: /** 57: * Contained certificates 58: */ 59: mem_cred_t *creds; 60: }; 61: 62: /** 63: * A single signerInfo 64: */ 65: typedef struct { 66: 67: /** 68: * Signed attributes of signerInfo 69: */ 70: pkcs7_attributes_t *attributes; 71: 72: /** 73: * Serial of signing certificate 74: */ 75: identification_t *serial; 76: 77: /** 78: * Issuer of signing certificate 79: */ 80: identification_t *issuer; 81: 82: /** 83: * EncryptedDigest 84: */ 85: chunk_t encrypted_digest; 86: 87: /** 88: * Digesting algorithm OID 89: */ 90: int digest_alg; 91: 92: /** 93: * Public key encryption algorithm OID 94: */ 95: int enc_alg; 96: 97: } signerinfo_t; 98: 99: /** 100: * Destroy a signerinfo_t entry 101: */ 102: void signerinfo_destroy(signerinfo_t *this) 103: { 104: DESTROY_IF(this->attributes); 105: DESTROY_IF(this->serial); 106: DESTROY_IF(this->issuer); 107: free(this->encrypted_digest.ptr); 108: free(this); 109: } 110: 111: /** 112: * ASN.1 definition of the PKCS#7 signedData type 113: */ 114: static const asn1Object_t signedDataObjects[] = { 115: { 0, "signedData", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ 116: { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */ 117: { 1, "digestAlgorithms", ASN1_SET, ASN1_LOOP }, /* 2 */ 118: { 2, "algorithm", ASN1_EOC, ASN1_RAW }, /* 3 */ 119: { 1, "end loop", ASN1_EOC, ASN1_END }, /* 4 */ 120: { 1, "contentInfo", ASN1_EOC, ASN1_RAW }, /* 5 */ 121: { 1, "certificates", ASN1_CONTEXT_C_0, ASN1_OPT | 122: ASN1_LOOP }, /* 6 */ 123: { 2, "certificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 7 */ 124: { 1, "end opt or loop", ASN1_EOC, ASN1_END }, /* 8 */ 125: { 1, "crls", ASN1_CONTEXT_C_1, ASN1_OPT | 126: ASN1_LOOP }, /* 9 */ 127: { 2, "crl", ASN1_SEQUENCE, ASN1_OBJ }, /* 10 */ 128: { 1, "end opt or loop", ASN1_EOC, ASN1_END }, /* 11 */ 129: { 1, "signerInfos", ASN1_SET, ASN1_LOOP }, /* 12 */ 130: { 2, "signerInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 13 */ 131: { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 14 */ 132: { 3, "issuerAndSerialNumber", ASN1_SEQUENCE, ASN1_BODY }, /* 15 */ 133: { 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 16 */ 134: { 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 17 */ 135: { 3, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 18 */ 136: { 3, "authenticatedAttributes", ASN1_CONTEXT_C_0, ASN1_OPT | 137: ASN1_OBJ }, /* 19 */ 138: { 3, "end opt", ASN1_EOC, ASN1_END }, /* 20 */ 139: { 3, "digestEncryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 21 */ 140: { 3, "encryptedDigest", ASN1_OCTET_STRING, ASN1_BODY }, /* 22 */ 141: { 3, "unauthenticatedAttributes", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 23 */ 142: { 3, "end opt", ASN1_EOC, ASN1_END }, /* 24 */ 143: { 1, "end loop", ASN1_EOC, ASN1_END }, /* 25 */ 144: { 0, "exit", ASN1_EOC, ASN1_EXIT } 145: }; 146: #define PKCS7_VERSION 1 147: #define PKCS7_DIGEST_ALG 3 148: #define PKCS7_CONTENT_INFO 5 149: #define PKCS7_CERT 7 150: #define PKCS7_SIGNER_INFO 13 151: #define PKCS7_SIGNER_INFO_VERSION 14 152: #define PKCS7_ISSUER 16 153: #define PKCS7_SERIAL_NUMBER 17 154: #define PKCS7_DIGEST_ALGORITHM 18 155: #define PKCS7_AUTH_ATTRIBUTES 19 156: #define PKCS7_DIGEST_ENC_ALGORITHM 21 157: #define PKCS7_ENCRYPTED_DIGEST 22 158: 159: METHOD(container_t, get_type, container_type_t, 160: private_pkcs7_signed_data_t *this) 161: { 162: return CONTAINER_PKCS7_SIGNED_DATA; 163: } 164: 165: /** 166: * Signature enumerator implementation 167: */ 168: typedef struct { 169: /** implements enumerator */ 170: enumerator_t public; 171: /** inner signerinfos enumerator */ 172: enumerator_t *inner; 173: /** currently enumerated auth_cfg */ 174: auth_cfg_t *auth; 175: /** currently enumerating signerinfo */ 176: signerinfo_t *info; 177: /** reference to container */ 178: private_pkcs7_signed_data_t *this; 179: } signature_enumerator_t; 180: 181: METHOD(enumerator_t, enumerate, bool, 182: signature_enumerator_t *this, va_list args) 183: { 184: signerinfo_t *info; 185: signature_scheme_t scheme; 186: hash_algorithm_t algorithm; 187: enumerator_t *enumerator; 188: certificate_t *cert; 189: public_key_t *key; 190: auth_cfg_t *auth, **out; 191: chunk_t chunk, hash, content; 192: hasher_t *hasher; 193: bool valid; 194: 195: VA_ARGS_VGET(args, out); 196: 197: while (this->inner->enumerate(this->inner, &info)) 198: { 199: /* clean up previous round */ 200: DESTROY_IF(this->auth); 201: this->auth = NULL; 202: 203: scheme = signature_scheme_from_oid(info->digest_alg); 204: if (scheme == SIGN_UNKNOWN) 205: { 206: DBG1(DBG_LIB, "unsupported signature scheme"); 207: continue; 208: } 209: if (!info->attributes) 210: { 211: DBG1(DBG_LIB, "no authenticatedAttributes object found"); 212: continue; 213: } 214: if (info->enc_alg != OID_RSA_ENCRYPTION) 215: { 216: DBG1(DBG_LIB, "only RSA digest encryption supported"); 217: continue; 218: } 219: 220: enumerator = lib->credmgr->create_trusted_enumerator(lib->credmgr, 221: KEY_RSA, info->serial, FALSE); 222: while (enumerator->enumerate(enumerator, &cert, &auth)) 223: { 224: if (info->issuer->equals(info->issuer, cert->get_issuer(cert))) 225: { 226: key = cert->get_public_key(cert); 227: if (key) 228: { 229: chunk = info->attributes->get_encoding(info->attributes); 230: if (key->verify(key, scheme, NULL, chunk, 231: info->encrypted_digest)) 232: { 233: this->auth = auth->clone(auth); 234: key->destroy(key); 235: break; 236: } 237: key->destroy(key); 238: } 239: } 240: } 241: enumerator->destroy(enumerator); 242: 243: if (!this->auth) 244: { 245: DBG1(DBG_LIB, "unable to verify pkcs7 attributes signature"); 246: continue; 247: } 248: 249: chunk = info->attributes->get_attribute(info->attributes, 250: OID_PKCS9_MESSAGE_DIGEST); 251: if (!chunk.len) 252: { 253: DBG1(DBG_LIB, "messageDigest attribute not found"); 254: continue; 255: } 256: if (!this->this->content->get_data(this->this->content, &content)) 257: { 258: continue; 259: } 260: 261: algorithm = hasher_algorithm_from_oid(info->digest_alg); 262: hasher = lib->crypto->create_hasher(lib->crypto, algorithm); 263: if (!hasher || !hasher->allocate_hash(hasher, content, &hash)) 264: { 265: free(content.ptr); 266: DESTROY_IF(hasher); 267: DBG1(DBG_LIB, "hash algorithm %N not supported", 268: hash_algorithm_names, algorithm); 269: continue; 270: } 271: free(content.ptr); 272: hasher->destroy(hasher); 273: DBG3(DBG_LIB, "hash: %B", &hash); 274: 275: valid = chunk_equals_const(chunk, hash); 276: free(hash.ptr); 277: if (!valid) 278: { 279: DBG1(DBG_LIB, "invalid messageDigest"); 280: continue; 281: } 282: *out = this->auth; 283: this->info = info; 284: return TRUE; 285: } 286: this->info = NULL; 287: return FALSE; 288: } 289: 290: METHOD(enumerator_t, enumerator_destroy, void, 291: signature_enumerator_t *this) 292: { 293: lib->credmgr->remove_local_set(lib->credmgr, &this->this->creds->set); 294: this->inner->destroy(this->inner); 295: DESTROY_IF(this->auth); 296: free(this); 297: } 298: 299: METHOD(container_t, create_signature_enumerator, enumerator_t*, 300: private_pkcs7_signed_data_t *this) 301: { 302: signature_enumerator_t *enumerator; 303: 304: INIT(enumerator, 305: .public = { 306: .enumerate = enumerator_enumerate_default, 307: .venumerate = _enumerate, 308: .destroy = _enumerator_destroy, 309: }, 310: .inner = this->signerinfos->create_enumerator(this->signerinfos), 311: .this = this, 312: ); 313: 314: lib->credmgr->add_local_set(lib->credmgr, &this->creds->set, FALSE); 315: return &enumerator->public; 316: } 317: 318: METHOD(pkcs7_t, get_attribute, bool, 319: private_pkcs7_signed_data_t *this, int oid, enumerator_t *enumerator, chunk_t *value) 320: { 321: signature_enumerator_t *e; 322: chunk_t chunk; 323: 324: e = (signature_enumerator_t*)enumerator; 325: if (e->info) 326: { 327: chunk = e->info->attributes->get_attribute(e->info->attributes, oid); 328: if (chunk.len) 329: { 330: *value = chunk_clone(chunk); 331: return TRUE; 332: } 333: } 334: return FALSE; 335: } 336: 337: METHOD(pkcs7_t, create_cert_enumerator, enumerator_t*, 338: private_pkcs7_signed_data_t *this) 339: { 340: return this->creds->set.create_cert_enumerator(&this->creds->set, 341: CERT_ANY, KEY_ANY, NULL, FALSE); 342: } 343: 344: METHOD(container_t, get_data, bool, 345: private_pkcs7_signed_data_t *this, chunk_t *data) 346: { 347: if (this->content) 348: { 349: return this->content->get_data(this->content, data); 350: } 351: return FALSE; 352: } 353: 354: METHOD(container_t, get_encoding, bool, 355: private_pkcs7_signed_data_t *this, chunk_t *data) 356: { 357: *data = chunk_clone(this->encoding); 358: return TRUE; 359: } 360: 361: METHOD(container_t, destroy, void, 362: private_pkcs7_signed_data_t *this) 363: { 364: this->creds->destroy(this->creds); 365: this->signerinfos->destroy_function(this->signerinfos, 366: (void*)signerinfo_destroy); 367: DESTROY_IF(this->content); 368: free(this->encoding.ptr); 369: free(this); 370: } 371: 372: /** 373: * Create an empty PKCS#7 signed-data container. 374: */ 375: static private_pkcs7_signed_data_t* create_empty() 376: { 377: private_pkcs7_signed_data_t *this; 378: 379: INIT(this, 380: .public = { 381: .container = { 382: .get_type = _get_type, 383: .create_signature_enumerator = _create_signature_enumerator, 384: .get_data = _get_data, 385: .get_encoding = _get_encoding, 386: .destroy = _destroy, 387: }, 388: .get_attribute = _get_attribute, 389: .create_cert_enumerator = _create_cert_enumerator, 390: }, 391: .creds = mem_cred_create(), 392: .signerinfos = linked_list_create(), 393: ); 394: 395: return this; 396: } 397: 398: /** 399: * Parse PKCS#7 signed data 400: */ 401: static bool parse(private_pkcs7_signed_data_t *this, chunk_t content) 402: { 403: asn1_parser_t *parser; 404: chunk_t object; 405: int objectID, version; 406: signerinfo_t *info = NULL; 407: bool success = FALSE; 408: 409: parser = asn1_parser_create(signedDataObjects, content); 410: parser->set_top_level(parser, 0); 411: while (parser->iterate(parser, &objectID, &object)) 412: { 413: u_int level = parser->get_level(parser); 414: 415: switch (objectID) 416: { 417: case PKCS7_VERSION: 418: version = object.len ? (int)*object.ptr : 0; 419: DBG2(DBG_LIB, " v%d", version); 420: break; 421: case PKCS7_CONTENT_INFO: 422: this->content = lib->creds->create(lib->creds, 423: CRED_CONTAINER, CONTAINER_PKCS7, 424: BUILD_BLOB_ASN1_DER, object, BUILD_END); 425: break; 426: case PKCS7_CERT: 427: { 428: certificate_t *cert; 429: 430: DBG2(DBG_LIB, " parsing pkcs7-wrapped certificate"); 431: cert = lib->creds->create(lib->creds, 432: CRED_CERTIFICATE, CERT_X509, 433: BUILD_BLOB_ASN1_DER, object, 434: BUILD_END); 435: if (cert) 436: { 437: this->creds->add_cert(this->creds, FALSE, cert); 438: } 439: break; 440: } 441: case PKCS7_SIGNER_INFO: 442: INIT(info, 443: .digest_alg = OID_UNKNOWN, 444: .enc_alg = OID_UNKNOWN, 445: ); 446: this->signerinfos->insert_last(this->signerinfos, info); 447: break; 448: case PKCS7_SIGNER_INFO_VERSION: 449: version = object.len ? (int)*object.ptr : 0; 450: DBG2(DBG_LIB, " v%d", version); 451: break; 452: case PKCS7_ISSUER: 453: info->issuer = identification_create_from_encoding( 454: ID_DER_ASN1_DN, object); 455: break; 456: case PKCS7_SERIAL_NUMBER: 457: info->serial = identification_create_from_encoding( 458: ID_KEY_ID, object); 459: break; 460: case PKCS7_AUTH_ATTRIBUTES: 461: *object.ptr = ASN1_SET; 462: info->attributes = pkcs7_attributes_create_from_chunk( 463: object, level+1); 464: *object.ptr = ASN1_CONTEXT_C_0; 465: break; 466: case PKCS7_DIGEST_ALGORITHM: 467: info->digest_alg = asn1_parse_algorithmIdentifier(object, 468: level, NULL); 469: break; 470: case PKCS7_DIGEST_ENC_ALGORITHM: 471: info->enc_alg = asn1_parse_algorithmIdentifier(object, 472: level, NULL); 473: break; 474: case PKCS7_ENCRYPTED_DIGEST: 475: info->encrypted_digest = chunk_clone(object); 476: break; 477: } 478: } 479: success = parser->success(parser); 480: parser->destroy(parser); 481: 482: return success; 483: } 484: 485: /** 486: * See header. 487: */ 488: pkcs7_t *pkcs7_signed_data_load(chunk_t encoding, chunk_t content) 489: { 490: private_pkcs7_signed_data_t *this = create_empty(); 491: 492: this->encoding = chunk_clone(encoding); 493: if (!parse(this, content)) 494: { 495: destroy(this); 496: return NULL; 497: } 498: return &this->public; 499: } 500: 501: /** 502: * build a DER-encoded issuerAndSerialNumber object 503: */ 504: static chunk_t build_issuerAndSerialNumber(certificate_t *cert) 505: { 506: identification_t *issuer = cert->get_issuer(cert); 507: chunk_t serial = chunk_empty; 508: 509: if (cert->get_type(cert) == CERT_X509) 510: { 511: x509_t *x509 = (x509_t*)cert; 512: serial = x509->get_serial(x509); 513: } 514: 515: return asn1_wrap(ASN1_SEQUENCE, "cm", 516: issuer->get_encoding(issuer), 517: asn1_integer("c", serial)); 518: } 519: 520: /** 521: * Generate a new PKCS#7 signed-data container 522: */ 523: static bool generate(private_pkcs7_signed_data_t *this, private_key_t *key, 524: certificate_t *cert, hash_algorithm_t alg, 525: pkcs7_attributes_t *pkcs9) 526: { 527: chunk_t authenticatedAttributes = chunk_empty; 528: chunk_t encryptedDigest = chunk_empty; 529: chunk_t data, signerInfo, encoding = chunk_empty; 530: chunk_t messageDigest, signingTime, attributes; 531: signature_scheme_t scheme; 532: hasher_t *hasher; 533: time_t now; 534: int digest_oid; 535: 536: digest_oid = hasher_algorithm_to_oid(alg); 537: scheme = signature_scheme_from_oid(digest_oid); 538: 539: if (!this->content->get_data(this->content, &data)) 540: { 541: return FALSE; 542: } 543: 544: hasher = lib->crypto->create_hasher(lib->crypto, alg); 545: if (!hasher || !hasher->allocate_hash(hasher, data, &messageDigest)) 546: { 547: DESTROY_IF(hasher); 548: DBG1(DBG_LIB, " hash algorithm %N not support", 549: hash_algorithm_names, alg); 550: free(data.ptr); 551: return FALSE; 552: } 553: hasher->destroy(hasher); 554: pkcs9->add_attribute(pkcs9, 555: OID_PKCS9_MESSAGE_DIGEST, 556: asn1_wrap(ASN1_OCTET_STRING, "m", messageDigest)); 557: 558: /* take the current time as signingTime */ 559: now = time(NULL); 560: signingTime = asn1_from_time(&now, ASN1_UTCTIME); 561: pkcs9->add_attribute(pkcs9, OID_PKCS9_SIGNING_TIME, signingTime); 562: pkcs9->add_attribute(pkcs9, OID_PKCS9_CONTENT_TYPE, 563: asn1_build_known_oid(OID_PKCS7_DATA)); 564: 565: attributes = pkcs9->get_encoding(pkcs9); 566: 567: if (!key->sign(key, scheme, NULL, attributes, &encryptedDigest)) 568: { 569: free(data.ptr); 570: return FALSE; 571: } 572: authenticatedAttributes = chunk_clone(attributes); 573: *authenticatedAttributes.ptr = ASN1_CONTEXT_C_0; 574: 575: free(data.ptr); 576: if (encryptedDigest.ptr) 577: { 578: encryptedDigest = asn1_wrap(ASN1_OCTET_STRING, "m", encryptedDigest); 579: } 580: signerInfo = asn1_wrap(ASN1_SEQUENCE, "cmmmmm", 581: ASN1_INTEGER_1, 582: build_issuerAndSerialNumber(cert), 583: asn1_algorithmIdentifier(digest_oid), 584: authenticatedAttributes, 585: asn1_algorithmIdentifier(OID_RSA_ENCRYPTION), 586: encryptedDigest); 587: 588: if (!cert->get_encoding(cert, CERT_ASN1_DER, &encoding)) 589: { 590: free(signerInfo.ptr); 591: return FALSE; 592: } 593: if (!this->content->get_encoding(this->content, &data)) 594: { 595: free(encoding.ptr); 596: free(signerInfo.ptr); 597: return FALSE; 598: } 599: 600: this->encoding = asn1_wrap(ASN1_SEQUENCE, "mm", 601: asn1_build_known_oid(OID_PKCS7_SIGNED_DATA), 602: asn1_wrap(ASN1_CONTEXT_C_0, "m", 603: asn1_wrap(ASN1_SEQUENCE, "cmmmm", 604: ASN1_INTEGER_1, 605: asn1_wrap(ASN1_SET, "m", asn1_algorithmIdentifier(digest_oid)), 606: data, 607: asn1_wrap(ASN1_CONTEXT_C_0, "m", encoding), 608: asn1_wrap(ASN1_SET, "m", signerInfo)))); 609: 610: 611: pkcs9->destroy(pkcs9); 612: /* TODO: create signerInfos entry */ 613: return TRUE; 614: } 615: 616: /** 617: * See header. 618: */ 619: pkcs7_t *pkcs7_signed_data_gen(container_type_t type, va_list args) 620: { 621: private_pkcs7_signed_data_t *this; 622: chunk_t blob = chunk_empty; 623: hash_algorithm_t alg = HASH_SHA1; 624: private_key_t *key = NULL; 625: certificate_t *cert = NULL; 626: pkcs7_attributes_t *pkcs9; 627: chunk_t value; 628: int oid; 629: 630: pkcs9 = pkcs7_attributes_create(); 631: 632: while (TRUE) 633: { 634: switch (va_arg(args, builder_part_t)) 635: { 636: case BUILD_SIGNING_KEY: 637: key = va_arg(args, private_key_t*); 638: continue; 639: case BUILD_SIGNING_CERT: 640: cert = va_arg(args, certificate_t*); 641: continue; 642: case BUILD_DIGEST_ALG: 643: alg = va_arg(args, int); 644: continue; 645: case BUILD_BLOB: 646: blob = va_arg(args, chunk_t); 647: continue; 648: case BUILD_PKCS7_ATTRIBUTE: 649: oid = va_arg(args, int); 650: value = va_arg(args, chunk_t); 651: pkcs9->add_attribute(pkcs9, oid, chunk_clone(value)); 652: continue; 653: case BUILD_END: 654: break; 655: default: 656: pkcs9->destroy(pkcs9); 657: return NULL; 658: } 659: break; 660: } 661: if (blob.len && key && cert) 662: { 663: this = create_empty(); 664: 665: this->creds->add_cert(this->creds, FALSE, cert->get_ref(cert)); 666: this->content = lib->creds->create(lib->creds, 667: CRED_CONTAINER, CONTAINER_PKCS7_DATA, 668: BUILD_BLOB, blob, BUILD_END); 669: 670: if (this->content && generate(this, key, cert, alg, pkcs9)) 671: { 672: return &this->public; 673: } 674: pkcs9->destroy(pkcs9); 675: destroy(this); 676: } 677: else 678: { 679: pkcs9->destroy(pkcs9); 680: } 681: return NULL; 682: }