Annotation of embedaddon/strongswan/src/libstrongswan/plugins/openssl/openssl_pkcs7.c, revision 1.1
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 */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>