Return to openssl_pkcs7.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libstrongswan / plugins / openssl |
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 <openssl/opensslv.h> 17: #include <openssl/opensslconf.h> 18: 19: #if OPENSSL_VERSION_NUMBER >= 0x0090807fL 20: #ifndef OPENSSL_NO_CMS 21: 22: #include "openssl_pkcs7.h" 23: #include "openssl_util.h" 24: 25: #include <library.h> 26: #include <utils/debug.h> 27: #include <asn1/oid.h> 28: #include <credentials/sets/mem_cred.h> 29: 30: #include <openssl/cms.h> 31: 32: #if OPENSSL_VERSION_NUMBER < 0x10100000L 33: #define X509_ATTRIBUTE_get0_object(attr) ({ (attr)->object; }) 34: #endif 35: 36: typedef struct private_openssl_pkcs7_t private_openssl_pkcs7_t; 37: 38: /** 39: * Private data of an openssl_pkcs7_t object. 40: */ 41: struct private_openssl_pkcs7_t { 42: 43: /** 44: * Public pkcs7_t interface. 45: */ 46: pkcs7_t public; 47: 48: /** 49: * Type of this container 50: */ 51: container_type_t type; 52: 53: /** 54: * OpenSSL CMS structure 55: */ 56: CMS_ContentInfo *cms; 57: }; 58: 59: /** 60: * OpenSSL does not allow us to read the signature to verify it with our own 61: * crypto API. We define the internal CMS_SignerInfo structure here to get it. 62: */ 63: struct CMS_SignerInfo_st { 64: long version; 65: void *sid; 66: X509_ALGOR *digestAlgorithm; 67: STACK_OF(X509_ATTRIBUTE) *signedAttrs; 68: X509_ALGOR *signatureAlgorithm; 69: ASN1_OCTET_STRING *signature; 70: /* and more... */ 71: }; 72: 73: /** 74: * And we also need access to the wrappend CMS_KeyTransRecipientInfo to 75: * read the encrypted key 76: */ 77: struct CMS_KeyTransRecipientInfo_st { 78: long version; 79: void *rid; 80: X509_ALGOR *keyEncryptionAlgorithm; 81: ASN1_OCTET_STRING *encryptedKey; 82: }; 83: 84: struct CMS_RecipientInfo_st { 85: int type; 86: struct CMS_KeyTransRecipientInfo_st *ktri; 87: /* and more in union... */ 88: }; 89: 90: struct CMS_EncryptedContentInfo_st { 91: ASN1_OBJECT *contentType; 92: X509_ALGOR *contentEncryptionAlgorithm; 93: ASN1_OCTET_STRING *encryptedContent; 94: /* and more... */ 95: }; 96: 97: struct CMS_EnvelopedData_st { 98: long version; 99: void *originatorInfo; 100: STACK_OF(CMS_RecipientInfo) *recipientInfos; 101: struct CMS_EncryptedContentInfo_st *encryptedContentInfo; 102: /* and more... */ 103: }; 104: 105: struct CMS_ContentInfo_st { 106: ASN1_OBJECT *contentType; 107: struct CMS_EnvelopedData_st *envelopedData; 108: /* and more in union... */ 109: }; 110: 111: /** 112: * We can't include asn1.h, declare function prototypes directly 113: */ 114: chunk_t asn1_wrap(int, const char *mode, ...); 115: int asn1_unwrap(chunk_t*, chunk_t*); 116: 117: /** 118: * Enumerator over certificates 119: */ 120: typedef struct { 121: /** implements enumerator_t */ 122: enumerator_t public; 123: /** Stack of X509 certificates */ 124: STACK_OF(X509) *certs; 125: /** current enumerator position in certificates */ 126: int i; 127: /** currently enumerating certificate_t */ 128: certificate_t *cert; 129: } cert_enumerator_t; 130: 131: METHOD(enumerator_t, cert_destroy, void, 132: cert_enumerator_t *this) 133: { 134: DESTROY_IF(this->cert); 135: free(this); 136: } 137: 138: METHOD(enumerator_t, cert_enumerate, bool, 139: cert_enumerator_t *this, va_list args) 140: { 141: certificate_t **out; 142: 143: VA_ARGS_VGET(args, out); 144: 145: if (!this->certs) 146: { 147: return FALSE; 148: } 149: while (this->i < sk_X509_num(this->certs)) 150: { 151: chunk_t encoding; 152: X509 *x509; 153: 154: /* clean up previous round */ 155: DESTROY_IF(this->cert); 156: this->cert = NULL; 157: 158: x509 = sk_X509_value(this->certs, this->i++); 159: encoding = openssl_i2chunk(X509, x509); 160: this->cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, 161: BUILD_BLOB_ASN1_DER, encoding, 162: BUILD_END); 163: free(encoding.ptr); 164: if (!this->cert) 165: { 166: continue; 167: } 168: *out = this->cert; 169: return TRUE; 170: } 171: return FALSE; 172: } 173: 174: METHOD(pkcs7_t, create_cert_enumerator, enumerator_t*, 175: private_openssl_pkcs7_t *this) 176: { 177: cert_enumerator_t *enumerator; 178: 179: if (this->type == CONTAINER_PKCS7_SIGNED_DATA) 180: { 181: INIT(enumerator, 182: .public = { 183: .enumerate = enumerator_enumerate_default, 184: .venumerate = _cert_enumerate, 185: .destroy = _cert_destroy, 186: }, 187: .certs = CMS_get1_certs(this->cms), 188: ); 189: return &enumerator->public; 190: } 191: return enumerator_create_empty(); 192: } 193: 194: /** 195: * Enumerator for signatures 196: */ 197: typedef struct { 198: /** implements enumerator_t */ 199: enumerator_t public; 200: /** Stack of signerinfos */ 201: STACK_OF(CMS_SignerInfo) *signers; 202: /** current enumerator position in signers */ 203: int i; 204: /** currently enumerating auth config */ 205: auth_cfg_t *auth; 206: /** full CMS */ 207: CMS_ContentInfo *cms; 208: /** credential set containing wrapped certificates */ 209: mem_cred_t *creds; 210: } signature_enumerator_t; 211: 212: /** 213: * Verify signerInfo signature 214: */ 215: static auth_cfg_t *verify_signature(CMS_SignerInfo *si, int hash_oid) 216: { 217: enumerator_t *enumerator; 218: public_key_t *key; 219: certificate_t *cert; 220: auth_cfg_t *auth, *found = NULL; 221: identification_t *issuer, *serial; 222: chunk_t attrs = chunk_empty, sig, attr; 223: X509_NAME *name; 224: ASN1_INTEGER *snr; 225: int i; 226: 227: if (CMS_SignerInfo_get0_signer_id(si, NULL, &name, &snr) != 1) 228: { 229: return NULL; 230: } 231: issuer = openssl_x509_name2id(name); 232: if (!issuer) 233: { 234: return NULL; 235: } 236: serial = identification_create_from_encoding( 237: ID_KEY_ID, openssl_asn1_str2chunk(snr)); 238: 239: /* reconstruct DER encoded attributes to verify signature */ 240: for (i = 0; i < CMS_signed_get_attr_count(si); i++) 241: { 242: attr = openssl_i2chunk(X509_ATTRIBUTE, CMS_signed_get_attr(si, i)); 243: attrs = chunk_cat("mm", attrs, attr); 244: } 245: /* wrap in a ASN1_SET */ 246: attrs = asn1_wrap(0x31, "m", attrs); 247: 248: /* TODO: find a better way to access and verify the signature */ 249: sig = openssl_asn1_str2chunk(si->signature); 250: enumerator = lib->credmgr->create_trusted_enumerator(lib->credmgr, 251: KEY_RSA, serial, FALSE); 252: while (enumerator->enumerate(enumerator, &cert, &auth)) 253: { 254: if (issuer->equals(issuer, cert->get_issuer(cert))) 255: { 256: key = cert->get_public_key(cert); 257: if (key) 258: { 259: if (key->verify(key, signature_scheme_from_oid(hash_oid), NULL, 260: attrs, sig)) 261: { 262: found = auth->clone(auth); 263: key->destroy(key); 264: break; 265: } 266: key->destroy(key); 267: } 268: } 269: } 270: enumerator->destroy(enumerator); 271: issuer->destroy(issuer); 272: serial->destroy(serial); 273: free(attrs.ptr); 274: 275: return found; 276: } 277: 278: /** 279: * Verify the message digest in the signerInfo attributes 280: */ 281: static bool verify_digest(CMS_ContentInfo *cms, CMS_SignerInfo *si, int hash_oid) 282: { 283: ASN1_OCTET_STRING *os, **osp; 284: hash_algorithm_t hash_alg; 285: chunk_t digest, content, hash; 286: hasher_t *hasher; 287: 288: os = CMS_signed_get0_data_by_OBJ(si, 289: OBJ_nid2obj(NID_pkcs9_messageDigest), -3, V_ASN1_OCTET_STRING); 290: if (!os) 291: { 292: return FALSE; 293: } 294: digest = openssl_asn1_str2chunk(os); 295: osp = CMS_get0_content(cms); 296: if (!osp) 297: { 298: return FALSE; 299: } 300: content = openssl_asn1_str2chunk(*osp); 301: 302: hash_alg = hasher_algorithm_from_oid(hash_oid); 303: hasher = lib->crypto->create_hasher(lib->crypto, hash_alg); 304: if (!hasher) 305: { 306: DBG1(DBG_LIB, "hash algorithm %N not supported", 307: hash_algorithm_names, hash_alg); 308: return FALSE; 309: } 310: if (!hasher->allocate_hash(hasher, content, &hash)) 311: { 312: hasher->destroy(hasher); 313: return FALSE; 314: } 315: hasher->destroy(hasher); 316: 317: if (!chunk_equals_const(digest, hash)) 318: { 319: free(hash.ptr); 320: DBG1(DBG_LIB, "invalid messageDigest"); 321: return FALSE; 322: } 323: free(hash.ptr); 324: return TRUE; 325: } 326: 327: METHOD(enumerator_t, signature_enumerate, bool, 328: signature_enumerator_t *this, va_list args) 329: { 330: auth_cfg_t **out; 331: 332: VA_ARGS_VGET(args, out); 333: 334: if (!this->signers) 335: { 336: return FALSE; 337: } 338: while (this->i < sk_CMS_SignerInfo_num(this->signers)) 339: { 340: CMS_SignerInfo *si; 341: X509_ALGOR *digest, *sig; 342: int hash_oid; 343: 344: /* clean up previous round */ 345: DESTROY_IF(this->auth); 346: this->auth = NULL; 347: 348: si = sk_CMS_SignerInfo_value(this->signers, this->i++); 349: 350: CMS_SignerInfo_get0_algs(si, NULL, NULL, &digest, &sig); 351: hash_oid = openssl_asn1_known_oid(digest->algorithm); 352: if (openssl_asn1_known_oid(sig->algorithm) != OID_RSA_ENCRYPTION) 353: { 354: DBG1(DBG_LIB, "only RSA digest encryption supported"); 355: continue; 356: } 357: this->auth = verify_signature(si, hash_oid); 358: if (!this->auth) 359: { 360: DBG1(DBG_LIB, "unable to verify pkcs7 attributes signature"); 361: continue; 362: } 363: if (!verify_digest(this->cms, si, hash_oid)) 364: { 365: continue; 366: } 367: *out = this->auth; 368: return TRUE; 369: } 370: return FALSE; 371: } 372: 373: METHOD(enumerator_t, signature_destroy, void, 374: signature_enumerator_t *this) 375: { 376: lib->credmgr->remove_local_set(lib->credmgr, &this->creds->set); 377: this->creds->destroy(this->creds); 378: DESTROY_IF(this->auth); 379: free(this); 380: } 381: 382: METHOD(container_t, create_signature_enumerator, enumerator_t*, 383: private_openssl_pkcs7_t *this) 384: { 385: signature_enumerator_t *enumerator; 386: 387: if (this->type == CONTAINER_PKCS7_SIGNED_DATA) 388: { 389: enumerator_t *certs; 390: certificate_t *cert; 391: 392: INIT(enumerator, 393: .public = { 394: .enumerate = enumerator_enumerate_default, 395: .venumerate = _signature_enumerate, 396: .destroy = _signature_destroy, 397: }, 398: .cms = this->cms, 399: .signers = CMS_get0_SignerInfos(this->cms), 400: .creds = mem_cred_create(), 401: ); 402: 403: /* make available wrapped certs during signature checking */ 404: certs = create_cert_enumerator(this); 405: while (certs->enumerate(certs, &cert)) 406: { 407: enumerator->creds->add_cert(enumerator->creds, FALSE, 408: cert->get_ref(cert)); 409: } 410: certs->destroy(certs); 411: 412: lib->credmgr->add_local_set(lib->credmgr, &enumerator->creds->set, 413: FALSE); 414: 415: return &enumerator->public; 416: } 417: return enumerator_create_empty(); 418: } 419: 420: 421: METHOD(container_t, get_type, container_type_t, 422: private_openssl_pkcs7_t *this) 423: { 424: return this->type; 425: } 426: 427: METHOD(pkcs7_t, get_attribute, bool, 428: private_openssl_pkcs7_t *this, int oid, 429: enumerator_t *enumerator, chunk_t *value) 430: { 431: signature_enumerator_t *e; 432: CMS_SignerInfo *si; 433: X509_ATTRIBUTE *attr; 434: ASN1_TYPE *type; 435: chunk_t chunk, wrapped; 436: int i; 437: 438: e = (signature_enumerator_t*)enumerator; 439: if (e->i <= 0) 440: { 441: return FALSE; 442: } 443: 444: /* "i" gets incremented after enumerate(), hence read from previous */ 445: si = sk_CMS_SignerInfo_value(e->signers, e->i - 1); 446: for (i = 0; i < CMS_signed_get_attr_count(si); i++) 447: { 448: attr = CMS_signed_get_attr(si, i); 449: if (X509_ATTRIBUTE_count(attr) == 1 && 450: openssl_asn1_known_oid(X509_ATTRIBUTE_get0_object(attr)) == oid) 451: { 452: /* get first value in SET */ 453: type = X509_ATTRIBUTE_get0_type(attr, 0); 454: chunk = wrapped = openssl_i2chunk(ASN1_TYPE, type); 455: if (asn1_unwrap(&chunk, &chunk) != 0x100 /* ASN1_INVALID */) 456: { 457: *value = chunk_clone(chunk); 458: free(wrapped.ptr); 459: return TRUE; 460: } 461: free(wrapped.ptr); 462: } 463: } 464: return FALSE; 465: } 466: 467: /** 468: * Find a private key for issuerAndSerialNumber 469: */ 470: static private_key_t *find_private(identification_t *issuer, 471: identification_t *serial) 472: { 473: enumerator_t *enumerator; 474: certificate_t *cert; 475: public_key_t *public; 476: private_key_t *private = NULL; 477: identification_t *id; 478: chunk_t fp; 479: 480: enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr, 481: CERT_X509, KEY_RSA, serial, FALSE); 482: while (enumerator->enumerate(enumerator, &cert)) 483: { 484: if (issuer->equals(issuer, cert->get_issuer(cert))) 485: { 486: public = cert->get_public_key(cert); 487: if (public) 488: { 489: if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &fp)) 490: { 491: id = identification_create_from_encoding(ID_KEY_ID, fp); 492: private = lib->credmgr->get_private(lib->credmgr, 493: KEY_ANY, id, NULL); 494: id->destroy(id); 495: } 496: public->destroy(public); 497: } 498: } 499: if (private) 500: { 501: break; 502: } 503: } 504: enumerator->destroy(enumerator); 505: return private; 506: } 507: 508: /** 509: * Decrypt enveloped-data with a decrypted symmetric key 510: */ 511: static bool decrypt_symmetric(private_openssl_pkcs7_t *this, chunk_t key, 512: chunk_t encrypted, chunk_t *plain) 513: { 514: encryption_algorithm_t encr; 515: X509_ALGOR *alg; 516: crypter_t *crypter; 517: chunk_t iv; 518: size_t key_size; 519: 520: /* read encryption algorithm from internal structures; TODO fixup */ 521: alg = this->cms->envelopedData->encryptedContentInfo-> 522: contentEncryptionAlgorithm; 523: encr = encryption_algorithm_from_oid(openssl_asn1_known_oid(alg->algorithm), 524: &key_size); 525: if (alg->parameter->type != V_ASN1_OCTET_STRING) 526: { 527: return FALSE; 528: } 529: iv = openssl_asn1_str2chunk(alg->parameter->value.octet_string); 530: 531: crypter = lib->crypto->create_crypter(lib->crypto, encr, key_size / 8); 532: if (!crypter) 533: { 534: DBG1(DBG_LIB, "crypter %N-%d not available", 535: encryption_algorithm_names, alg, key_size); 536: return FALSE; 537: } 538: if (key.len != crypter->get_key_size(crypter)) 539: { 540: DBG1(DBG_LIB, "symmetric key length is wrong"); 541: crypter->destroy(crypter); 542: return FALSE; 543: } 544: if (iv.len != crypter->get_iv_size(crypter)) 545: { 546: DBG1(DBG_LIB, "IV length is wrong"); 547: crypter->destroy(crypter); 548: return FALSE; 549: } 550: if (!crypter->set_key(crypter, key) || 551: !crypter->decrypt(crypter, encrypted, iv, plain)) 552: { 553: crypter->destroy(crypter); 554: return FALSE; 555: } 556: crypter->destroy(crypter); 557: return TRUE; 558: } 559: 560: /** 561: * Remove enveloped-data PKCS#7 padding from plain data 562: */ 563: static bool remove_padding(chunk_t *data) 564: { 565: u_char *pos; 566: u_char pattern; 567: size_t padding; 568: 569: if (!data->len) 570: { 571: return FALSE; 572: } 573: pos = data->ptr + data->len - 1; 574: padding = pattern = *pos; 575: 576: if (padding > data->len) 577: { 578: DBG1(DBG_LIB, "padding greater than data length"); 579: return FALSE; 580: } 581: data->len -= padding; 582: 583: while (padding-- > 0) 584: { 585: if (*pos-- != pattern) 586: { 587: DBG1(DBG_LIB, "wrong padding pattern"); 588: return FALSE; 589: } 590: } 591: return TRUE; 592: } 593: 594: /** 595: * Decrypt PKCS#7 enveloped-data 596: */ 597: static bool decrypt(private_openssl_pkcs7_t *this, 598: chunk_t encrypted, chunk_t *plain) 599: { 600: STACK_OF(CMS_RecipientInfo) *ris; 601: CMS_RecipientInfo *ri; 602: chunk_t chunk, key = chunk_empty; 603: int i; 604: 605: ris = CMS_get0_RecipientInfos(this->cms); 606: for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) 607: { 608: ri = sk_CMS_RecipientInfo_value(ris, i); 609: if (CMS_RecipientInfo_type(ri) == CMS_RECIPINFO_TRANS) 610: { 611: identification_t *serial, *issuer; 612: private_key_t *private; 613: X509_ALGOR *alg; 614: X509_NAME *name; 615: ASN1_INTEGER *sn; 616: u_char zero = 0; 617: int oid; 618: 619: if (CMS_RecipientInfo_ktri_get0_algs(ri, NULL, NULL, &alg) == 1 && 620: CMS_RecipientInfo_ktri_get0_signer_id(ri, NULL, &name, &sn) == 1) 621: { 622: oid = openssl_asn1_known_oid(alg->algorithm); 623: if (oid != OID_RSA_ENCRYPTION) 624: { 625: DBG1(DBG_LIB, "only RSA encryption supported in PKCS#7"); 626: continue; 627: } 628: issuer = openssl_x509_name2id(name); 629: if (!issuer) 630: { 631: continue; 632: } 633: chunk = openssl_asn1_str2chunk(sn); 634: if (chunk.len && chunk.ptr[0] & 0x80) 635: { /* if MSB is set, append a zero to make it non-negative */ 636: chunk = chunk_cata("cc", chunk_from_thing(zero), chunk); 637: } 638: serial = identification_create_from_encoding(ID_KEY_ID, chunk); 639: private = find_private(issuer, serial); 640: issuer->destroy(issuer); 641: serial->destroy(serial); 642: 643: if (private) 644: { 645: /* get encryptedKey from internal structure; TODO fixup */ 646: chunk = openssl_asn1_str2chunk(ri->ktri->encryptedKey); 647: if (private->decrypt(private, ENCRYPT_RSA_PKCS1, 648: chunk, &key)) 649: { 650: private->destroy(private); 651: break; 652: } 653: private->destroy(private); 654: } 655: } 656: } 657: } 658: if (!key.len) 659: { 660: DBG1(DBG_LIB, "no private key found to decrypt PKCS#7"); 661: return FALSE; 662: } 663: if (!decrypt_symmetric(this, key, encrypted, plain)) 664: { 665: chunk_clear(&key); 666: return FALSE; 667: } 668: chunk_clear(&key); 669: if (!remove_padding(plain)) 670: { 671: free(plain->ptr); 672: return FALSE; 673: } 674: return TRUE; 675: } 676: 677: METHOD(container_t, get_data, bool, 678: private_openssl_pkcs7_t *this, chunk_t *data) 679: { 680: ASN1_OCTET_STRING **os; 681: chunk_t chunk; 682: 683: os = CMS_get0_content(this->cms); 684: if (os) 685: { 686: chunk = openssl_asn1_str2chunk(*os); 687: switch (this->type) 688: { 689: case CONTAINER_PKCS7_DATA: 690: case CONTAINER_PKCS7_SIGNED_DATA: 691: *data = chunk_clone(chunk); 692: return TRUE; 693: case CONTAINER_PKCS7_ENVELOPED_DATA: 694: return decrypt(this, chunk, data); 695: default: 696: break; 697: } 698: } 699: return FALSE; 700: } 701: 702: METHOD(container_t, get_encoding, bool, 703: private_openssl_pkcs7_t *this, chunk_t *data) 704: { 705: return FALSE; 706: } 707: 708: METHOD(container_t, destroy, void, 709: private_openssl_pkcs7_t *this) 710: { 711: CMS_ContentInfo_free(this->cms); 712: free(this); 713: } 714: 715: /** 716: * Generic constructor 717: */ 718: static private_openssl_pkcs7_t* create_empty() 719: { 720: private_openssl_pkcs7_t *this; 721: 722: INIT(this, 723: .public = { 724: .container = { 725: .get_type = _get_type, 726: .create_signature_enumerator = _create_signature_enumerator, 727: .get_data = _get_data, 728: .get_encoding = _get_encoding, 729: .destroy = _destroy, 730: }, 731: .get_attribute = _get_attribute, 732: .create_cert_enumerator = _create_cert_enumerator, 733: }, 734: ); 735: 736: return this; 737: } 738: 739: /** 740: * Parse a PKCS#7 container 741: */ 742: static bool parse(private_openssl_pkcs7_t *this, chunk_t blob) 743: { 744: BIO *bio; 745: 746: bio = BIO_new_mem_buf(blob.ptr, blob.len); 747: this->cms = d2i_CMS_bio(bio, NULL); 748: BIO_free(bio); 749: 750: if (!this->cms) 751: { 752: return FALSE; 753: } 754: switch (openssl_asn1_known_oid((ASN1_OBJECT*)CMS_get0_type(this->cms))) 755: { 756: case OID_PKCS7_DATA: 757: this->type = CONTAINER_PKCS7_DATA; 758: break; 759: case OID_PKCS7_SIGNED_DATA: 760: this->type = CONTAINER_PKCS7_SIGNED_DATA; 761: break; 762: case OID_PKCS7_ENVELOPED_DATA: 763: this->type = CONTAINER_PKCS7_ENVELOPED_DATA; 764: break; 765: default: 766: return FALSE; 767: } 768: 769: return TRUE; 770: } 771: 772: /** 773: * See header 774: */ 775: pkcs7_t *openssl_pkcs7_load(container_type_t type, va_list args) 776: { 777: chunk_t blob = chunk_empty; 778: private_openssl_pkcs7_t *this; 779: 780: while (TRUE) 781: { 782: switch (va_arg(args, builder_part_t)) 783: { 784: case BUILD_BLOB_ASN1_DER: 785: blob = va_arg(args, chunk_t); 786: continue; 787: case BUILD_END: 788: break; 789: default: 790: return NULL; 791: } 792: break; 793: } 794: if (blob.len) 795: { 796: this = create_empty(); 797: if (parse(this, blob)) 798: { 799: return &this->public; 800: } 801: destroy(this); 802: } 803: return NULL; 804: } 805: 806: #endif /* OPENSSL_NO_CMS */ 807: #endif /* OPENSSL_VERSION_NUMBER */