/*
 * build attribute type
 */
static chunk_t
build_attribute_type(const chunk_t type, chunk_t content)
{
    return asn1_wrap(ASN1_SEQUENCE, "cm"
		, type
		, asn1_wrap(ASN1_SET, "m", content));
}
/*
 * build authorityKeyIdentifier
 */
static chunk_t
build_authorityKeyID(x509cert_t *signer)
{
    chunk_t keyIdentifier = (signer->subjectKeyID.ptr == NULL)
			? empty_chunk
			: asn1_simple_object(ASN1_CONTEXT_S_0
				, signer->subjectKeyID);

    chunk_t authorityCertIssuer = build_directoryName(ASN1_CONTEXT_C_1
				, signer->issuer);

    chunk_t authorityCertSerialNumber = asn1_simple_object(ASN1_CONTEXT_S_2
				, signer->serialNumber);

    return asn1_wrap(ASN1_SEQUENCE, "cm"
		, ASN1_authorityKeyIdentifier_oid
		, asn1_wrap(ASN1_OCTET_STRING, "m"
		    , asn1_wrap(ASN1_SEQUENCE, "mmm"
			, keyIdentifier
			, authorityCertIssuer
			, authorityCertSerialNumber
		      )
		  )
	   );
}
Example #3
0
/**
 * @brief Builds a contentType attribute
 *
 * @return ASN.1 encoded contentType attribute
 */
chunk_t pkcs7_contentType_attribute(void)
{
	return asn1_wrap(ASN1_SEQUENCE, "mm",
						asn1_build_known_oid(OID_PKCS9_CONTENT_TYPE),
						asn1_wrap(ASN1_SET, "m",
							asn1_build_known_oid(OID_PKCS7_DATA)));
}
Example #4
0
File: ocsp.c Project: eworm-de/ipxe
/**
 * Build OCSP request
 *
 * @v ocsp		OCSP check
 * @ret rc		Return status code
 */
static int ocsp_request ( struct ocsp_check *ocsp ) {
	struct digest_algorithm *digest = &ocsp_digest_algorithm;
	struct asn1_builder *builder = &ocsp->request.builder;
	struct asn1_cursor *cert_id_tail = &ocsp->request.cert_id_tail;
	uint8_t digest_ctx[digest->ctxsize];
	uint8_t name_digest[digest->digestsize];
	uint8_t pubkey_digest[digest->digestsize];
	int rc;

	/* Generate digests */
	digest_init ( digest, digest_ctx );
	digest_update ( digest, digest_ctx, ocsp->cert->issuer.raw.data,
			ocsp->cert->issuer.raw.len );
	digest_final ( digest, digest_ctx, name_digest );
	digest_init ( digest, digest_ctx );
	digest_update ( digest, digest_ctx,
			ocsp->issuer->subject.public_key.raw_bits.data,
			ocsp->issuer->subject.public_key.raw_bits.len );
	digest_final ( digest, digest_ctx, pubkey_digest );

	/* Construct request */
	if ( ( rc = ( asn1_prepend_raw ( builder, ocsp->cert->serial.raw.data,
					 ocsp->cert->serial.raw.len ),
		      asn1_prepend ( builder, ASN1_OCTET_STRING,
				     pubkey_digest, sizeof ( pubkey_digest ) ),
		      asn1_prepend ( builder, ASN1_OCTET_STRING,
				     name_digest, sizeof ( name_digest ) ),
		      asn1_prepend ( builder, ASN1_SEQUENCE,
				     ocsp_algorithm_id,
				     sizeof ( ocsp_algorithm_id ) ),
		      asn1_wrap ( builder, ASN1_SEQUENCE ),
		      asn1_wrap ( builder, ASN1_SEQUENCE ),
		      asn1_wrap ( builder, ASN1_SEQUENCE ),
		      asn1_wrap ( builder, ASN1_SEQUENCE ),
		      asn1_wrap ( builder, ASN1_SEQUENCE ) ) ) != 0 ) {
		DBGC ( ocsp, "OCSP %p \"%s\" could not build request: %s\n",
		       ocsp, x509_name ( ocsp->cert ), strerror ( rc ) );
		return rc;
	}
	DBGC2 ( ocsp, "OCSP %p \"%s\" request is:\n",
		ocsp, x509_name ( ocsp->cert ) );
	DBGC2_HDA ( ocsp, 0, builder->data, builder->len );

	/* Parse certificate ID for comparison with response */
	cert_id_tail->data = builder->data;
	cert_id_tail->len = builder->len;
	if ( ( rc = ( asn1_enter ( cert_id_tail, ASN1_SEQUENCE ),
		      asn1_enter ( cert_id_tail, ASN1_SEQUENCE ),
		      asn1_enter ( cert_id_tail, ASN1_SEQUENCE ),
		      asn1_enter ( cert_id_tail, ASN1_SEQUENCE ),
		      asn1_enter ( cert_id_tail, ASN1_SEQUENCE ),
		      asn1_skip ( cert_id_tail, ASN1_SEQUENCE ) ) ) != 0 ) {
		DBGC ( ocsp, "OCSP %p \"%s\" could not locate certID: %s\n",
		       ocsp, x509_name ( ocsp->cert ), strerror ( rc ) );
		return rc;
	}

	return 0;
}
Example #5
0
/**
 * Builds a transId attribute
 */
chunk_t scep_transId_attribute(chunk_t transID)
{
	return asn1_wrap(ASN1_SEQUENCE, "cm"
				, ASN1_transId_oid
				, asn1_wrap(ASN1_SET, "m"
					, asn1_simple_object(ASN1_PRINTABLESTRING, transID)
				  )
			  );
}
/*
 * build holder
 */
static chunk_t
build_holder(void)
{
    return asn1_wrap(ASN1_SEQUENCE, "mm"
		, asn1_wrap(ASN1_CONTEXT_C_0, "mm"
		    , build_directoryName(ASN1_SEQUENCE, user->issuer)
		    , asn1_simple_object(ASN1_INTEGER, user->serialNumber)
		  )
		, build_directoryName(ASN1_CONTEXT_C_1, user->subject));
}
Example #7
0
/**
 * Builds a messageType attribute
 */
chunk_t scep_messageType_attribute(scep_msg_t m)
{
	chunk_t msgType = {
		(u_char*)msgType_values[m],
		strlen(msgType_values[m])
	};

	return asn1_wrap(ASN1_SEQUENCE, "cm"
				, ASN1_messageType_oid
				, asn1_wrap(ASN1_SET, "m"
					, asn1_simple_object(ASN1_PRINTABLESTRING, msgType)
				  )
			  );
}
Example #8
0
/**
 * Parse an EC domain parameter identifier as defined in RFC 5656
 */
static chunk_t parse_ec_identifier(chunk_t identifier)
{
	chunk_t oid = chunk_empty;

	if (chunk_equals(identifier, chunk_from_str("nistp256")))
	{
		oid = asn1_build_known_oid(OID_PRIME256V1);
	}
	else if (chunk_equals(identifier, chunk_from_str("nistp384")))
	{
		oid = asn1_build_known_oid(OID_SECT384R1);
	}
	else if (chunk_equals(identifier, chunk_from_str("nistp521")))
	{
		oid = asn1_build_known_oid(OID_SECT521R1);
	}
	else
	{
		char ascii[64];

		if (snprintf(ascii, sizeof(ascii), "%.*s", (int)identifier.len,
					 identifier.ptr) < sizeof(ascii))
		{
			oid = asn1_wrap(ASN1_OID, "m", asn1_oid_from_string(ascii));
		}
	}
	return oid;
}
/*
 * build extensions
 */
static chunk_t
build_extensions(void)
{
    return asn1_wrap(ASN1_SEQUENCE, "mc"
		, build_authorityKeyID(signer)
		, ASN1_noRevAvail_ext);
}
/*
 * build attributes
 */
static chunk_t
build_attributes(void)
{
     return asn1_wrap(ASN1_SEQUENCE, "m"
		, build_attribute_type(ASN1_group_oid
		    , build_ietfAttributes(groups)));
}
/*
 * build attrCertValidityPeriod
 */
static chunk_t
build_attr_cert_validity(void)
{
    return asn1_wrap(ASN1_SEQUENCE, "mm"
		, timetoasn1(&notBefore, ASN1_GENERALIZEDTIME) 
		, timetoasn1(&notAfter,  ASN1_GENERALIZEDTIME));
}
Example #12
0
/**
 * @brief Builds a messageDigest attribute
 *
 *
 * @param[in] blob content to create digest of
 * @param[in] digest_alg digest algorithm to be used
 * @return ASN.1 encoded messageDigest attribute
 *
 */
chunk_t pkcs7_messageDigest_attribute(chunk_t content, int digest_alg)
{
	chunk_t digest;
	hash_algorithm_t hash_alg;
	hasher_t *hasher;

	hash_alg = hasher_algorithm_from_oid(digest_alg);
	hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
	hasher->allocate_hash(hasher, content, &digest);
	hasher->destroy(hasher);

	return asn1_wrap(ASN1_SEQUENCE, "mm",
				asn1_build_known_oid(OID_PKCS9_MESSAGE_DIGEST),
				asn1_wrap(ASN1_SET, "m",
					asn1_wrap(ASN1_OCTET_STRING, "m", digest)));
}
/*
 * builds a senderNonce attribute
 */
chunk_t
scep_senderNonce_attribute(void)
{
    const size_t nonce_len = 16;
    u_char nonce_buf[nonce_len];
    chunk_t senderNonce = { nonce_buf, nonce_len };

    get_rnd_bytes(nonce_buf, nonce_len);
 
    return asn1_wrap(ASN1_SEQUENCE, "cm"
		, ASN1_senderNonce_oid
		, asn1_wrap(ASN1_SET, "m"
		    , asn1_simple_object(ASN1_OCTET_STRING, senderNonce)
		  )
	      );
}
Example #14
0
/**
 * build a DER-encoded contentInfo object
 */
static chunk_t pkcs7_build_contentInfo(contentInfo_t *cInfo)
{
	return (cInfo->content.ptr) ?
				asn1_wrap(ASN1_SEQUENCE, "mm",
					asn1_build_known_oid(cInfo->type),
					asn1_simple_object(ASN1_CONTEXT_C_0, cInfo->content)) :
				asn1_build_known_oid(cInfo->type);
}
Example #15
0
/**
 * build issuerAndSerialNumber object
 */
chunk_t pkcs7_build_issuerAndSerialNumber(certificate_t *cert)
{
	identification_t *issuer = cert->get_issuer(cert);
	x509_t *x509 = (x509_t*)cert;

	return asn1_wrap(ASN1_SEQUENCE, "cm",
					 issuer->get_encoding(issuer),
					 asn1_integer("c", x509->get_serial(x509)));
}
Example #16
0
/**
 * Builds a senderNonce attribute
 */
chunk_t scep_senderNonce_attribute(void)
{
	const size_t nonce_len = 16;
	u_char nonce_buf[nonce_len];
	chunk_t senderNonce = { nonce_buf, nonce_len };
	rng_t *rng;

	rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
	rng->get_bytes(rng, nonce_len, nonce_buf);
	rng->destroy(rng);

	return asn1_wrap(ASN1_SEQUENCE, "cm"
				, ASN1_senderNonce_oid
				, asn1_wrap(ASN1_SET, "m"
					, asn1_simple_object(ASN1_OCTET_STRING, senderNonce)
				  )
			  );
}
/*
 * build an X.509 attribute certificate
 */
chunk_t
build_attr_cert(void)
{
    chunk_t attributeCertificateInfo = build_attr_cert_info();
    chunk_t signatureValue = pkcs1_build_signature(attributeCertificateInfo
				, OID_SHA1, signerkey, TRUE);

    return asn1_wrap(ASN1_SEQUENCE, "mcm"
		, attributeCertificateInfo
		, ASN1_sha1WithRSA_id
		, signatureValue);
}
Example #18
0
/**
 * create a signed pkcs7 contentInfo object
 */
chunk_t pkcs7_build_signedData(chunk_t data, chunk_t attributes,
							   certificate_t *cert, int digest_alg,
							   private_key_t *key)
{
	contentInfo_t pkcs7Data, signedData;
	chunk_t authenticatedAttributes = chunk_empty;
	chunk_t encryptedDigest = chunk_empty;
	chunk_t signerInfo, cInfo, signature, encoding = chunk_empty;;
	signature_scheme_t scheme = signature_scheme_from_oid(digest_alg);

	if (attributes.ptr)
	{
		if (key->sign(key, scheme, attributes, &signature))
		{
			encryptedDigest = asn1_wrap(ASN1_OCTET_STRING, "m", signature);
			authenticatedAttributes = chunk_clone(attributes);
			*authenticatedAttributes.ptr = ASN1_CONTEXT_C_0;
		}
	}
	else if (data.ptr)
	{
		if (key->sign(key, scheme, data, &signature))
		{
			encryptedDigest = asn1_wrap(ASN1_OCTET_STRING, "m", signature);
		}
	}
	signerInfo = asn1_wrap(ASN1_SEQUENCE, "cmmmmm"
				, ASN1_INTEGER_1
				, pkcs7_build_issuerAndSerialNumber(cert)
				, asn1_algorithmIdentifier(digest_alg)
				, authenticatedAttributes
				, asn1_algorithmIdentifier(OID_RSA_ENCRYPTION)
				, encryptedDigest);

	pkcs7Data.type    = OID_PKCS7_DATA;
	pkcs7Data.content = (data.ptr == NULL)? chunk_empty
				: asn1_simple_object(ASN1_OCTET_STRING, data);

	cert->get_encoding(cert, CERT_ASN1_DER, &encoding);
	signedData.type = OID_PKCS7_SIGNED_DATA;
	signedData.content = asn1_wrap(ASN1_SEQUENCE, "cmmmm"
				, ASN1_INTEGER_1
				, asn1_wrap(ASN1_SET, "m", asn1_algorithmIdentifier(digest_alg))
				, pkcs7_build_contentInfo(&pkcs7Data)
				, asn1_wrap(ASN1_CONTEXT_C_0, "m", encoding)
				, asn1_wrap(ASN1_SET, "m", signerInfo));

	cInfo = pkcs7_build_contentInfo(&signedData);
	DBG3(DBG_LIB, "signedData %B", &cInfo);

	free(pkcs7Data.content.ptr);
	free(signedData.content.ptr);
	return cInfo;
}
/*
 * build attributeCertificateInfo
 */
static chunk_t
build_attr_cert_info(void)
{
    return asn1_wrap(ASN1_SEQUENCE, "cmmcmmmm"
		, ASN1_INTEGER_1
		, build_holder()
		, build_v2_form()
		, ASN1_sha1WithRSA_id
		, asn1_simple_object(ASN1_INTEGER, serial)
		, build_attr_cert_validity()
		, build_attributes()
		, build_extensions());
}
Example #20
0
END_TEST

/*******************************************************************************
 * parse_algorithm_identifier
 */

START_TEST(test_asn1_parse_algorithmIdentifier)
{
	typedef struct {
		int alg;
		bool empty;
		chunk_t parameters;
	} testdata_t;

	testdata_t test[] = {
		{ OID_ECDSA_WITH_SHA1, TRUE,  chunk_empty },
		{ OID_SHA1_WITH_RSA,   TRUE,  chunk_from_chars(0x05, 0x00) },
		{ OID_3DES_EDE_CBC,    FALSE, chunk_from_chars(0x04, 0x01, 0xaa) },
		{ OID_PBKDF2,          FALSE, chunk_from_chars(0x30, 0x01, 0xaa) }
	};

	chunk_t algid, parameters;
	int i, alg;

	for (i = 0; i < countof(test); i++)
	{
		algid = asn1_wrap(ASN1_SEQUENCE, "mc",
					 asn1_build_known_oid(test[i].alg), test[i].parameters);
		parameters = chunk_empty;
		if (i == 2)
		{
			alg = asn1_parse_algorithmIdentifier(algid, 0, NULL);
		}
		else
		{
			alg = asn1_parse_algorithmIdentifier(algid, 0, &parameters);
			if (test[i].empty)
			{
				ck_assert(parameters.len == 0 && parameters.ptr == NULL);
			}
				else
			{
				ck_assert(chunk_equals(parameters, test[i].parameters));
			}
		}
		ck_assert(alg == test[i].alg);
		chunk_free(&algid);
	}
}
/*
 * build attributes
 */
static chunk_t
build_ietfAttributes(ietfAttrList_t *list)
{
    chunk_t ietfAttributes;
    ietfAttrList_t *item = list;
    size_t size = 0;
    u_char *pos;

    /* precalculate the total size of all values */
    while (item != NULL)
    {
	size_t len = item->attr->value.len;

	size += 1 + (len > 0) + (len >= 128) + (len >= 256) + (len >= 65536) + len;
	item = item->next;
    }
    pos = build_asn1_object(&ietfAttributes, ASN1_SEQUENCE, size);

    while (list != NULL)
    {
	ietfAttr_t *attr = list->attr;
	asn1_t type = ASN1_NULL;

	switch (attr->kind)
	{
	case IETF_ATTRIBUTE_OCTETS:
	    type = ASN1_OCTET_STRING;
	    break;
	case IETF_ATTRIBUTE_STRING:
	    type = ASN1_UTF8STRING;
	    break;
	case IETF_ATTRIBUTE_OID:
	    type = ASN1_OID;
	    break;
	}
	mv_chunk(&pos, asn1_simple_object(type, attr->value));

	list = list->next;
    }

    return asn1_wrap(ASN1_SEQUENCE, "m", ietfAttributes);
}
Example #22
0
/*
 * Defined in header.
 */
chunk_t asn1_algorithmIdentifier(int oid)
{
	chunk_t parameters;

	/* some algorithmIdentifiers have a NULL parameters field and some do not */
	switch (oid)
	{
		case OID_ECDSA_WITH_SHA1:
		case OID_ECDSA_WITH_SHA224:
		case OID_ECDSA_WITH_SHA256:
		case OID_ECDSA_WITH_SHA384:
		case OID_ECDSA_WITH_SHA512:
			parameters = chunk_empty;
			break;
		default:
			parameters = asn1_simple_object(ASN1_NULL, chunk_empty);
			break;
	}
	return asn1_wrap(ASN1_SEQUENCE, "mm", asn1_build_known_oid(oid), parameters);
}
Example #23
0
/**
 * Generate a transaction id as the MD5 hash of an public key
 * the transaction id is also used as a unique serial number
 */
void scep_generate_transaction_id(public_key_t *key, chunk_t *transID,
								  chunk_t *serialNumber)
{
	chunk_t digest = chunk_alloca(HASH_SIZE_MD5);
	chunk_t keyEncoding = chunk_empty, keyInfo;
	hasher_t *hasher;
	bool msb_set;
	u_char *pos;

	key->get_encoding(key, PUBKEY_ASN1_DER, &keyEncoding);

	keyInfo = asn1_wrap(ASN1_SEQUENCE, "mm",
						asn1_algorithmIdentifier(OID_RSA_ENCRYPTION),
						asn1_bitstring("m", keyEncoding));

	hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5);
	if (!hasher || !hasher->get_hash(hasher, keyInfo, digest.ptr))
	{
		memset(digest.ptr, 0, digest.len);
	}
	DESTROY_IF(hasher);
	free(keyInfo.ptr);

	/* is the most significant bit of the digest set? */
	msb_set = (*digest.ptr & 0x80) == 0x80;

	/* allocate space for the serialNumber */
	serialNumber->len = msb_set + digest.len;
	serialNumber->ptr = malloc(serialNumber->len);

	/* the serial number as the two's complement of the digest */
	pos = serialNumber->ptr;
	if (msb_set)
	{
		*pos++ = 0x00;
	}
	memcpy(pos, digest.ptr, digest.len);

	/* the transaction id is the serial number in hex format */
	*transID = chunk_to_hex(digest, NULL, TRUE);
}
Example #24
0
/**
 * Builds a pkcs7 enveloped and signed scep request
 */
chunk_t scep_build_request(chunk_t data, chunk_t transID, scep_msg_t msg,
						   certificate_t *enc_cert, int enc_alg,
						   certificate_t *signer_cert, int digest_alg,
						   private_key_t *private_key)
{
	chunk_t envelopedData, attributes, request;

	envelopedData = pkcs7_build_envelopedData(data, enc_cert, enc_alg);

	attributes = asn1_wrap(ASN1_SET, "mmmmm"
					, pkcs7_contentType_attribute()
					, pkcs7_messageDigest_attribute(envelopedData
						, digest_alg)
					, scep_transId_attribute(transID)
					, scep_messageType_attribute(msg)
					, scep_senderNonce_attribute());

	request = pkcs7_build_signedData(envelopedData, attributes
					, signer_cert, digest_alg, private_key);
	free(envelopedData.ptr);
	free(attributes.ptr);
	return request;
}
Example #25
0
/**
 * Load a generic public key from an SSH key blob
 */
static sshkey_public_key_t *parse_public_key(chunk_t blob)
{
	bio_reader_t *reader;
	chunk_t format;

	reader = bio_reader_create(blob);
	if (!reader->read_data32(reader, &format))
	{
		DBG1(DBG_LIB, "invalid key format in SSH key");
		reader->destroy(reader);
		return NULL;
	}
	if (chunk_equals(format, chunk_from_str("ssh-rsa")))
	{
		chunk_t n, e;

		if (!reader->read_data32(reader, &e) ||
			!reader->read_data32(reader, &n))
		{
			DBG1(DBG_LIB, "invalid RSA key in SSH key");
			reader->destroy(reader);
			return NULL;
		}
		reader->destroy(reader);
		return lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA,
						BUILD_RSA_MODULUS, n, BUILD_RSA_PUB_EXP, e, BUILD_END);
	}
	else if (format.len > strlen(ECDSA_PREFIX) &&
			 strneq(format.ptr, ECDSA_PREFIX, strlen(ECDSA_PREFIX)))
	{
		chunk_t ec_blob, identifier, q, oid, encoded;
		sshkey_public_key_t *key;

		ec_blob = reader->peek(reader);
		reader->destroy(reader);
		reader = bio_reader_create(ec_blob);
		if (!reader->read_data32(reader, &identifier) ||
			!reader->read_data32(reader, &q))
		{
			DBG1(DBG_LIB, "invalid ECDSA key in SSH key");
			reader->destroy(reader);
			return NULL;
		}
		oid = parse_ec_identifier(identifier);
		if (!oid.ptr)
		{
			DBG1(DBG_LIB, "invalid ECDSA key identifier in SSH key");
			reader->destroy(reader);
			return NULL;
		}
		reader->destroy(reader);
		/* build key from subjectPublicKeyInfo */
		encoded = asn1_wrap(ASN1_SEQUENCE, "mm",
						asn1_wrap(ASN1_SEQUENCE, "mm",
							asn1_build_known_oid(OID_EC_PUBLICKEY), oid),
						asn1_bitstring("c", q));
		key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY,
							KEY_ECDSA, BUILD_BLOB_ASN1_DER, encoded, BUILD_END);
		chunk_free(&encoded);
		return key;
	}
	DBG1(DBG_LIB, "unsupported SSH key format %.*s", (int)format.len,
		 format.ptr);
	reader->destroy(reader);
	return NULL;
}
/*
 * build directoryName
 */
static chunk_t
build_directoryName(asn1_t tag, chunk_t name)
{
    return asn1_wrap(tag, "m"
		, asn1_simple_object(ASN1_CONTEXT_C_4, name));
}
/*
 * build v2Form
 */
static chunk_t
build_v2_form(void)
{
    return asn1_wrap(ASN1_CONTEXT_C_0, "m"
		, build_directoryName(ASN1_SEQUENCE, signer->subject));
}
Example #28
0
static chunk_t
build_attributes (void)
{
  return asn1_wrap (build_attribute_type (ASN1_group_oid,
					  ietfAttr_list_encode (groups)));
}
Example #29
0
void build_attr_cert (void)
{
  asn1_wrap (build_attributes ());
}
Example #30
0
/**
 * create a symmetrically encrypted pkcs7 contentInfo object
 */
chunk_t pkcs7_build_envelopedData(chunk_t data, certificate_t *cert, int enc_alg)
{
	encryption_algorithm_t alg;
	size_t alg_key_size;
	chunk_t symmetricKey, protectedKey, iv, in, out;
	crypter_t *crypter;

	alg = encryption_algorithm_from_oid(enc_alg, &alg_key_size);
	crypter = lib->crypto->create_crypter(lib->crypto, alg,
										  alg_key_size/BITS_PER_BYTE);
	if (crypter == NULL)
	{
		DBG1(DBG_LIB, "crypter for %N not available", encryption_algorithm_names, alg);
		return chunk_empty;
	}

	/* generate a true random symmetric encryption key and a pseudo-random iv */
	{
		rng_t *rng;

		rng = lib->crypto->create_rng(lib->crypto, RNG_TRUE);
		rng->allocate_bytes(rng, crypter->get_key_size(crypter), &symmetricKey);
		DBG4(DBG_LIB, "symmetric encryption key %B", &symmetricKey);
		rng->destroy(rng);

		rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
		rng->allocate_bytes(rng, crypter->get_iv_size(crypter), &iv);
		DBG4(DBG_LIB, "initialization vector: %B", &iv);
		rng->destroy(rng);
	}

	/* pad the data to a multiple of the block size */
	{
		size_t block_size = crypter->get_block_size(crypter);
		size_t padding = block_size - data.len % block_size;

		in.len = data.len + padding;
		in.ptr = malloc(in.len);

		DBG2(DBG_LIB, "padding %u bytes of data to multiple block size of %u bytes",
			 data.len, in.len);

		/* copy data */
		memcpy(in.ptr, data.ptr, data.len);
		/* append padding */
		memset(in.ptr + data.len, padding, padding);
	}
	DBG3(DBG_LIB, "padded unencrypted data %B", &in);

	/* symmetric encryption of data object */
	crypter->set_key(crypter, symmetricKey);
	crypter->encrypt(crypter, in, iv, &out);
	crypter->destroy(crypter);
	chunk_clear(&in);
    DBG3(DBG_LIB, "encrypted data %B", &out);

	/* protect symmetric key by public key encryption */
	{
		public_key_t *key = cert->get_public_key(cert);

		if (key == NULL)
		{
			DBG1(DBG_LIB, "public key not found in encryption certificate");
			chunk_clear(&symmetricKey);
			chunk_free(&iv);
			chunk_free(&out);
			return chunk_empty;
		}
		key->encrypt(key, ENCRYPT_RSA_PKCS1, symmetricKey, &protectedKey);
		key->destroy(key);
	}

	/* build pkcs7 enveloped data object */
	{

		chunk_t contentEncryptionAlgorithm = asn1_wrap(ASN1_SEQUENCE, "mm"
					, asn1_build_known_oid(enc_alg)
					, asn1_simple_object(ASN1_OCTET_STRING, iv));

		chunk_t encryptedContentInfo = asn1_wrap(ASN1_SEQUENCE, "mmm"
					, asn1_build_known_oid(OID_PKCS7_DATA)
					, contentEncryptionAlgorithm
					, asn1_wrap(ASN1_CONTEXT_S_0, "m", out));

		chunk_t encryptedKey = asn1_wrap(ASN1_OCTET_STRING, "m"
					, protectedKey);

		chunk_t recipientInfo = asn1_wrap(ASN1_SEQUENCE, "cmmm"
					, ASN1_INTEGER_0
					, pkcs7_build_issuerAndSerialNumber(cert)
					, asn1_algorithmIdentifier(OID_RSA_ENCRYPTION)
					, encryptedKey);

		chunk_t cInfo;
		contentInfo_t envelopedData;

		envelopedData.type = OID_PKCS7_ENVELOPED_DATA;
		envelopedData.content = asn1_wrap(ASN1_SEQUENCE, "cmm"
					, ASN1_INTEGER_0
					, asn1_wrap(ASN1_SET, "m", recipientInfo)
					, encryptedContentInfo);

		cInfo = pkcs7_build_contentInfo(&envelopedData);
		DBG3(DBG_LIB, "envelopedData %B", &cInfo);

		chunk_free(&envelopedData.content);
		chunk_free(&iv);
		chunk_clear(&symmetricKey);
		return cInfo;
	}
}