pkcs7_dataDecode(krb5_context context,
                 pkinit_identity_crypto_context id_cryptoctx,
                 PKCS7 *p7)
{
    unsigned int eklen=0, tkeylen=0;
    BIO *out=NULL,*etmp=NULL,*bio=NULL;
    unsigned char *ek=NULL, *tkey=NULL;
    ASN1_OCTET_STRING *data_body=NULL;
    const EVP_CIPHER *evp_cipher=NULL;
    EVP_CIPHER_CTX *evp_ctx=NULL;
    X509_ALGOR *enc_alg=NULL;
    STACK_OF(PKCS7_RECIP_INFO) *rsk=NULL;
    PKCS7_RECIP_INFO *ri=NULL;

    p7->state=PKCS7_S_HEADER;

    rsk=p7->d.enveloped->recipientinfo;
    enc_alg=p7->d.enveloped->enc_data->algorithm;
    data_body=p7->d.enveloped->enc_data->enc_data;
    evp_cipher=EVP_get_cipherbyobj(enc_alg->algorithm);
    if (evp_cipher == NULL) {
        PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CIPHER_TYPE);
        goto cleanup;
    }

    if ((etmp=BIO_new(BIO_f_cipher())) == NULL) {
        PKCS7err(PKCS7_F_PKCS7_DATADECODE,ERR_R_BIO_LIB);
        goto cleanup;
    }

    /* It was encrypted, we need to decrypt the secret key
     * with the private key */

    /* RFC 4556 section 3.2.3.2 requires that there be exactly one
     * recipientInfo. */
    if (sk_PKCS7_RECIP_INFO_num(rsk) != 1) {
        pkiDebug("invalid number of EnvelopedData RecipientInfos\n");
        goto cleanup;
    }

    ri = sk_PKCS7_RECIP_INFO_value(rsk, 0);
    (void)pkinit_decode_data(context, id_cryptoctx,
                             ASN1_STRING_get0_data(ri->enc_key),
                             ASN1_STRING_length(ri->enc_key), &ek, &eklen);

    evp_ctx=NULL;
    BIO_get_cipher_ctx(etmp,&evp_ctx);
    if (EVP_CipherInit_ex(evp_ctx,evp_cipher,NULL,NULL,NULL,0) <= 0)
        goto cleanup;
    if (EVP_CIPHER_asn1_to_param(evp_ctx,enc_alg->parameter) < 0)
        goto cleanup;

    /* Generate a random symmetric key to avoid exposing timing data if RSA
     * decryption fails the padding check. */
    tkeylen = EVP_CIPHER_CTX_key_length(evp_ctx);
    tkey = OPENSSL_malloc(tkeylen);
    if (tkey == NULL)
        goto cleanup;
    if (EVP_CIPHER_CTX_rand_key(evp_ctx, tkey) <= 0)
        goto cleanup;
    if (ek == NULL) {
        ek = tkey;
        eklen = tkeylen;
        tkey = NULL;
    }

    if (eklen != (unsigned)EVP_CIPHER_CTX_key_length(evp_ctx)) {
        /* Some S/MIME clients don't use the same key
         * and effective key length. The key length is
         * determined by the size of the decrypted RSA key.
         */
        if (!EVP_CIPHER_CTX_set_key_length(evp_ctx, (int)eklen)) {
            ek = tkey;
            eklen = tkeylen;
            tkey = NULL;
        }
    }
    if (EVP_CipherInit_ex(evp_ctx,NULL,NULL,ek,NULL,0) <= 0)
        goto cleanup;

    if (out == NULL)
        out=etmp;
    else
        BIO_push(out,etmp);
    etmp=NULL;

    if (data_body->length > 0)
        bio = BIO_new_mem_buf(data_body->data, data_body->length);
    else {
        bio=BIO_new(BIO_s_mem());
        BIO_set_mem_eof_return(bio,0);
    }
    BIO_push(out,bio);
    bio=NULL;

    if (0) {
    cleanup:
        if (out != NULL) BIO_free_all(out);
        if (etmp != NULL) BIO_free_all(etmp);
        if (bio != NULL) BIO_free_all(bio);
        out=NULL;
    }
    if (ek != NULL) {
        OPENSSL_cleanse(ek, eklen);
        OPENSSL_free(ek);
    }
    if (tkey != NULL) {
        OPENSSL_cleanse(tkey, tkeylen);
        OPENSSL_free(tkey);
    }
    return(out);
}