PKCS7_ISSUER_AND_SERIAL *PKCS7_get_issuer_and_serial(PKCS7 *p7, int idx)
	{
	STACK_OF(PKCS7_RECIP_INFO) *rsk;
	PKCS7_RECIP_INFO *ri;
	int i;

	i=OBJ_obj2nid(p7->type);
	if (i != NID_pkcs7_signedAndEnveloped) return(NULL);
	rsk=p7->d.signed_and_enveloped->recipientinfo;
	ri=sk_PKCS7_RECIP_INFO_value(rsk,0);
	if (sk_PKCS7_RECIP_INFO_num(rsk) <= idx) return(NULL);
	ri=sk_PKCS7_RECIP_INFO_value(rsk,idx);
	return(ri->issuer_and_serial);
	}
Beispiel #2
0
/**
 * functionName : pkcs7_signed_and_envelop_print 
 * @Param : PKCS7_SIGN_ENVELOPE * envelop [ signed and enveloped ]
 * Brief  : 
 *		print signed and enveloped data
 * return :  null
 */
void pkcs7_signed_and_envelop_print(PKCS7_SIGN_ENVELOPE* envelop){

	BIO *out ;
	printf("========================= PKCS7 SIGNED AND ENVELOP ===========================\n");
	asn1_integer_print(envelop->version,"Envelop version");	
	asn1_object_print(envelop->enc_data->content_type,"ENCRYPT_DATA_TYPE");
	printf("ENCRYPT_DATA_ALGORITHM:\t");
	out = BIO_new(BIO_s_file());
	X509_ALGOR_print(out,envelop->enc_data->algorithm);
	BIO_free(out);

	printf("ENCRYPT_DATA_ENC Data:\t");
	asn1_octet_string_print(envelop->enc_data->enc_data);
		
	printf("[STACK] RECIPIENT INFO PRINT\n");
	int num,i,recip_ver;	
	PKCS7_RECIP_INFO *recip;
	num = sk_PKCS7_RECIP_INFO_num(envelop->recipientinfo);
	for(i = 0; i < num; i++){
		//print recipient version
		printf("RECIPIENT-%d:\n",i);
		recip = sk_PKCS7_RECIP_INFO_value(envelop->recipientinfo,i);
		pkcs7_recip_print(recip);
		asn1_integer_print(recip->version,"Envelop stack recipientinfo version");	
	}
	printf("[STACK] RECIPIENT INFO PRINT PRIN  END\n");
	
		
	printf("========================= PKCS7 SIGNED AND ENVELOP ===========================\n");
}
static VALUE
ossl_pkcs7_get_recipient(VALUE self)
{
    PKCS7 *pkcs7;
    STACK_OF(PKCS7_RECIP_INFO) *sk;
    PKCS7_RECIP_INFO *si;
    int num, i;
    VALUE ary;

    GetPKCS7(self, pkcs7);
    if (PKCS7_type_is_enveloped(pkcs7))
	sk = pkcs7->d.enveloped->recipientinfo;
    else if (PKCS7_type_is_signedAndEnveloped(pkcs7))
	sk = pkcs7->d.signed_and_enveloped->recipientinfo;
    else sk = NULL;
    if (!sk) return rb_ary_new();
    if ((num = sk_PKCS7_RECIP_INFO_num(sk)) < 0) {
	ossl_raise(ePKCS7Error, "Negative number of recipient!");
    }
    ary = rb_ary_new2(num);
    for (i=0; i<num; i++) {
	si = sk_PKCS7_RECIP_INFO_value(sk, i);
	rb_ary_push(ary, ossl_pkcs7ri_new(si));
    }

    return ary;
}
Beispiel #4
0
PKCS7_RECIP_INFO * PKI_X509_PKCS7_get_recipient_info ( PKI_X509_PKCS7 *p7,
							int idx ) {

	int type = 0;
	int recipients_num = 0;
	PKCS7_RECIP_INFO *ret = NULL;
	STACK_OF(PKCS7_RECIP_INFO) *r_sk = NULL;
	PKI_X509_PKCS7_VALUE *p7val = NULL;

	if ( !p7 || !p7->value ) return NULL;

	p7val = p7->value;

	if((recipients_num = PKI_X509_PKCS7_get_recipients_num ( p7 )) <= 0 ) {
		return NULL;
	}

	if ( recipients_num < idx ) return NULL;

	type = PKI_X509_PKCS7_get_type ( p7 );
	switch ( type ) {
		case PKI_X509_PKCS7_TYPE_ENCRYPTED:
			r_sk = p7val->d.enveloped->recipientinfo;
			break;
		case PKI_X509_PKCS7_TYPE_SIGNEDANDENCRYPTED:
			r_sk = p7val->d.signed_and_enveloped->recipientinfo;
			break;
		default:
			r_sk = NULL;
	}

	if ( r_sk ) {
		ret = sk_PKCS7_RECIP_INFO_value ( r_sk, idx );
	}

	return ret;
	
}
Beispiel #5
0
/* int */
BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert)
{
    int i, j;
    BIO *out = NULL, *btmp = NULL, *etmp = NULL, *bio = NULL;
    X509_ALGOR *xa;
    ASN1_OCTET_STRING *data_body = NULL;
    const EVP_MD *evp_md;
    const EVP_CIPHER *evp_cipher = NULL;
    EVP_CIPHER_CTX *evp_ctx = NULL;
    X509_ALGOR *enc_alg = NULL;
    STACK_OF(X509_ALGOR) *md_sk = NULL;
    STACK_OF(PKCS7_RECIP_INFO) *rsk = NULL;
    PKCS7_RECIP_INFO *ri = NULL;
    unsigned char *ek = NULL, *tkey = NULL;
    int eklen = 0, tkeylen = 0;

    if (p7 == NULL) {
        PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_INVALID_NULL_POINTER);
        return NULL;
    }

    if (p7->d.ptr == NULL) {
        PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_NO_CONTENT);
        return NULL;
    }

    i = OBJ_obj2nid(p7->type);
    p7->state = PKCS7_S_HEADER;

    switch (i) {
    case NID_pkcs7_signed:
        data_body = PKCS7_get_octet_string(p7->d.sign->contents);
        if (!PKCS7_is_detached(p7) && data_body == NULL) {
            PKCS7err(PKCS7_F_PKCS7_DATADECODE,
                     PKCS7_R_INVALID_SIGNED_DATA_TYPE);
            goto err;
        }
        md_sk = p7->d.sign->md_algs;
        break;
    case NID_pkcs7_signedAndEnveloped:
        rsk = p7->d.signed_and_enveloped->recipientinfo;
        md_sk = p7->d.signed_and_enveloped->md_algs;
        data_body = p7->d.signed_and_enveloped->enc_data->enc_data;
        enc_alg = p7->d.signed_and_enveloped->enc_data->algorithm;
        evp_cipher = EVP_get_cipherbyobj(enc_alg->algorithm);
        if (evp_cipher == NULL) {
            PKCS7err(PKCS7_F_PKCS7_DATADECODE,
                     PKCS7_R_UNSUPPORTED_CIPHER_TYPE);
            goto err;
        }
        break;
    case NID_pkcs7_enveloped:
        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 err;
        }
        break;
    default:
        PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_UNSUPPORTED_CONTENT_TYPE);
        goto err;
    }

    /* We will be checking the signature */
    if (md_sk != NULL) {
        for (i = 0; i < sk_X509_ALGOR_num(md_sk); i++) {
            xa = sk_X509_ALGOR_value(md_sk, i);
            if ((btmp = BIO_new(BIO_f_md())) == NULL) {
                PKCS7err(PKCS7_F_PKCS7_DATADECODE, ERR_R_BIO_LIB);
                goto err;
            }

            j = OBJ_obj2nid(xa->algorithm);
            evp_md = EVP_get_digestbynid(j);
            if (evp_md == NULL) {
                PKCS7err(PKCS7_F_PKCS7_DATADECODE,
                         PKCS7_R_UNKNOWN_DIGEST_TYPE);
                goto err;
            }

            BIO_set_md(btmp, evp_md);
            if (out == NULL)
                out = btmp;
            else
                BIO_push(out, btmp);
            btmp = NULL;
        }
    }

    if (evp_cipher != NULL) {
#if 0
        unsigned char key[EVP_MAX_KEY_LENGTH];
        unsigned char iv[EVP_MAX_IV_LENGTH];
        unsigned char *p;
        int keylen, ivlen;
        int max;
        X509_OBJECT ret;
#endif

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

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

        /*
         * Find the recipientInfo which matches the passed certificate (if
         * any)
         */

        if (pcert) {
            for (i = 0; i < sk_PKCS7_RECIP_INFO_num(rsk); i++) {
                ri = sk_PKCS7_RECIP_INFO_value(rsk, i);
                if (!pkcs7_cmp_ri(ri, pcert))
                    break;
                ri = NULL;
            }
            if (ri == NULL) {
                PKCS7err(PKCS7_F_PKCS7_DATADECODE,
                         PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE);
                goto err;
            }
        }

        /* If we haven't got a certificate try each ri in turn */
        if (pcert == NULL) {
            /*
             * Always attempt to decrypt all rinfo even after sucess as a
             * defence against MMA timing attacks.
             */
            for (i = 0; i < sk_PKCS7_RECIP_INFO_num(rsk); i++) {
                ri = sk_PKCS7_RECIP_INFO_value(rsk, i);

                if (pkcs7_decrypt_rinfo(&ek, &eklen, ri, pkey) < 0)
                    goto err;
                ERR_clear_error();
            }
        } else {
            /* Only exit on fatal errors, not decrypt failure */
            if (pkcs7_decrypt_rinfo(&ek, &eklen, ri, pkey) < 0)
                goto err;
            ERR_clear_error();
        }

        evp_ctx = NULL;
        BIO_get_cipher_ctx(etmp, &evp_ctx);
        if (EVP_CipherInit_ex(evp_ctx, evp_cipher, NULL, NULL, NULL, 0) <= 0)
            goto err;
        if (EVP_CIPHER_asn1_to_param(evp_ctx, enc_alg->parameter) < 0)
            goto err;
        /* Generate random key as MMA defence */
        tkeylen = EVP_CIPHER_CTX_key_length(evp_ctx);
        tkey = OPENSSL_malloc(tkeylen);
        if (!tkey)
            goto err;
        if (EVP_CIPHER_CTX_rand_key(evp_ctx, tkey) <= 0)
            goto err;
        if (ek == NULL) {
            ek = tkey;
            eklen = tkeylen;
            tkey = NULL;
        }

        if (eklen != 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, eklen)) {
                /* Use random key as MMA defence */
                OPENSSL_cleanse(ek, eklen);
                OPENSSL_free(ek);
                ek = tkey;
                eklen = tkeylen;
                tkey = NULL;
            }
        }
        /* Clear errors so we don't leak information useful in MMA */
        ERR_clear_error();
        if (EVP_CipherInit_ex(evp_ctx, NULL, NULL, ek, NULL, 0) <= 0)
            goto err;

        if (ek) {
            OPENSSL_cleanse(ek, eklen);
            OPENSSL_free(ek);
            ek = NULL;
        }
        if (tkey) {
            OPENSSL_cleanse(tkey, tkeylen);
            OPENSSL_free(tkey);
            tkey = NULL;
        }

        if (out == NULL)
            out = etmp;
        else
            BIO_push(out, etmp);
        etmp = NULL;
    }
#if 1
    if (PKCS7_is_detached(p7) || (in_bio != NULL)) {
        bio = in_bio;
    } else {
# if 0
        bio = BIO_new(BIO_s_mem());
        /*
         * We need to set this so that when we have read all the data, the
         * encrypt BIO, if present, will read EOF and encode the last few
         * bytes
         */
        BIO_set_mem_eof_return(bio, 0);

        if (data_body->length > 0)
            BIO_write(bio, (char *)data_body->data, data_body->length);
# else
        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);
        }
        if (bio == NULL)
            goto err;
# endif
    }
    BIO_push(out, bio);
    bio = NULL;
#endif
    if (0) {
 err:
        if (ek) {
            OPENSSL_cleanse(ek, eklen);
            OPENSSL_free(ek);
        }
        if (tkey) {
            OPENSSL_cleanse(tkey, tkeylen);
            OPENSSL_free(tkey);
        }
        if (out != NULL)
            BIO_free_all(out);
        if (btmp != NULL)
            BIO_free_all(btmp);
        if (etmp != NULL)
            BIO_free_all(etmp);
        if (bio != NULL)
            BIO_free_all(bio);
        out = NULL;
    }
    return (out);
}
Beispiel #6
0
BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio)
{
    int i;
    BIO *out = NULL, *btmp = NULL;
    X509_ALGOR *xa = NULL;
    const EVP_CIPHER *evp_cipher = NULL;
    STACK_OF(X509_ALGOR) *md_sk = NULL;
    STACK_OF(PKCS7_RECIP_INFO) *rsk = NULL;
    X509_ALGOR *xalg = NULL;
    PKCS7_RECIP_INFO *ri = NULL;
    ASN1_OCTET_STRING *os = NULL;

    if (p7 == NULL) {
        PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_INVALID_NULL_POINTER);
        return NULL;
    }
    /*
     * The content field in the PKCS7 ContentInfo is optional, but that really
     * only applies to inner content (precisely, detached signatures).
     *
     * When reading content, missing outer content is therefore treated as an
     * error.
     *
     * When creating content, PKCS7_content_new() must be called before
     * calling this method, so a NULL p7->d is always an error.
     */
    if (p7->d.ptr == NULL) {
        PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_NO_CONTENT);
        return NULL;
    }

    i = OBJ_obj2nid(p7->type);
    p7->state = PKCS7_S_HEADER;

    switch (i) {
    case NID_pkcs7_signed:
        md_sk = p7->d.sign->md_algs;
        os = PKCS7_get_octet_string(p7->d.sign->contents);
        break;
    case NID_pkcs7_signedAndEnveloped:
        rsk = p7->d.signed_and_enveloped->recipientinfo;
        md_sk = p7->d.signed_and_enveloped->md_algs;
        xalg = p7->d.signed_and_enveloped->enc_data->algorithm;
        evp_cipher = p7->d.signed_and_enveloped->enc_data->cipher;
        if (evp_cipher == NULL) {
            PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_CIPHER_NOT_INITIALIZED);
            goto err;
        }
        break;
    case NID_pkcs7_enveloped:
        rsk = p7->d.enveloped->recipientinfo;
        xalg = p7->d.enveloped->enc_data->algorithm;
        evp_cipher = p7->d.enveloped->enc_data->cipher;
        if (evp_cipher == NULL) {
            PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_CIPHER_NOT_INITIALIZED);
            goto err;
        }
        break;
    case NID_pkcs7_digest:
        xa = p7->d.digest->md;
        os = PKCS7_get_octet_string(p7->d.digest->contents);
        break;
    case NID_pkcs7_data:
        break;
    default:
        PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_UNSUPPORTED_CONTENT_TYPE);
        goto err;
    }

    for (i = 0; i < sk_X509_ALGOR_num(md_sk); i++)
        if (!PKCS7_bio_add_digest(&out, sk_X509_ALGOR_value(md_sk, i)))
            goto err;

    if (xa && !PKCS7_bio_add_digest(&out, xa))
        goto err;

    if (evp_cipher != NULL) {
        unsigned char key[EVP_MAX_KEY_LENGTH];
        unsigned char iv[EVP_MAX_IV_LENGTH];
        int keylen, ivlen;
        EVP_CIPHER_CTX *ctx;

        if ((btmp = BIO_new(BIO_f_cipher())) == NULL) {
            PKCS7err(PKCS7_F_PKCS7_DATAINIT, ERR_R_BIO_LIB);
            goto err;
        }
        BIO_get_cipher_ctx(btmp, &ctx);
        keylen = EVP_CIPHER_key_length(evp_cipher);
        ivlen = EVP_CIPHER_iv_length(evp_cipher);
        xalg->algorithm = OBJ_nid2obj(EVP_CIPHER_type(evp_cipher));
        if (ivlen > 0)
            if (RAND_pseudo_bytes(iv, ivlen) <= 0)
                goto err;
        if (EVP_CipherInit_ex(ctx, evp_cipher, NULL, NULL, NULL, 1) <= 0)
            goto err;
        if (EVP_CIPHER_CTX_rand_key(ctx, key) <= 0)
            goto err;
        if (EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, 1) <= 0)
            goto err;

        if (ivlen > 0) {
            if (xalg->parameter == NULL) {
                xalg->parameter = ASN1_TYPE_new();
                if (xalg->parameter == NULL)
                    goto err;
            }
            if (EVP_CIPHER_param_to_asn1(ctx, xalg->parameter) < 0)
                goto err;
        }

        /* Lets do the pub key stuff :-) */
        for (i = 0; i < sk_PKCS7_RECIP_INFO_num(rsk); i++) {
            ri = sk_PKCS7_RECIP_INFO_value(rsk, i);
            if (pkcs7_encode_rinfo(ri, key, keylen) <= 0)
                goto err;
        }
        OPENSSL_cleanse(key, keylen);

        if (out == NULL)
            out = btmp;
        else
            BIO_push(out, btmp);
        btmp = NULL;
    }

    if (bio == NULL) {
        if (PKCS7_is_detached(p7))
            bio = BIO_new(BIO_s_null());
        else if (os && os->length > 0)
            bio = BIO_new_mem_buf(os->data, os->length);
        if (bio == NULL) {
            bio = BIO_new(BIO_s_mem());
            if (bio == NULL)
                goto err;
            BIO_set_mem_eof_return(bio, 0);
        }
    }
    if (out)
        BIO_push(out, bio);
    else
        out = bio;
    bio = NULL;
    if (0) {
 err:
        if (out != NULL)
            BIO_free_all(out);
        if (btmp != NULL)
            BIO_free_all(btmp);
        out = NULL;
    }
    return (out);
}
/* int */
BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert)
	{
	int i,j;
	BIO *out=NULL,*btmp=NULL,*etmp=NULL,*bio=NULL;
	unsigned char *tmp=NULL;
	X509_ALGOR *xa;
	ASN1_OCTET_STRING *data_body=NULL;
	const EVP_MD *evp_md;
	const EVP_CIPHER *evp_cipher=NULL;
	EVP_CIPHER_CTX *evp_ctx=NULL;
	X509_ALGOR *enc_alg=NULL;
	STACK_OF(X509_ALGOR) *md_sk=NULL;
	STACK_OF(PKCS7_RECIP_INFO) *rsk=NULL;
	X509_ALGOR *xalg=NULL;
	PKCS7_RECIP_INFO *ri=NULL;

	i=OBJ_obj2nid(p7->type);
	p7->state=PKCS7_S_HEADER;

	switch (i)
		{
	case NID_pkcs7_signed:
		data_body=PKCS7_get_octet_string(p7->d.sign->contents);
		md_sk=p7->d.sign->md_algs;
		break;
	case NID_pkcs7_signedAndEnveloped:
		rsk=p7->d.signed_and_enveloped->recipientinfo;
		md_sk=p7->d.signed_and_enveloped->md_algs;
		data_body=p7->d.signed_and_enveloped->enc_data->enc_data;
		enc_alg=p7->d.signed_and_enveloped->enc_data->algorithm;
		evp_cipher=EVP_get_cipherbyobj(enc_alg->algorithm);
		if (evp_cipher == NULL)
			{
			PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CIPHER_TYPE);
			goto err;
			}
		xalg=p7->d.signed_and_enveloped->enc_data->algorithm;
		break;
	case NID_pkcs7_enveloped:
		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 err;
			}
		xalg=p7->d.enveloped->enc_data->algorithm;
		break;
	default:
		PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CONTENT_TYPE);
	        goto err;
		}

	/* We will be checking the signature */
	if (md_sk != NULL)
		{
		for (i=0; i<sk_X509_ALGOR_num(md_sk); i++)
			{
			xa=sk_X509_ALGOR_value(md_sk,i);
			if ((btmp=BIO_new(BIO_f_md())) == NULL)
				{
				PKCS7err(PKCS7_F_PKCS7_DATADECODE,ERR_R_BIO_LIB);
				goto err;
				}

			j=OBJ_obj2nid(xa->algorithm);
			evp_md=EVP_get_digestbynid(j);
			if (evp_md == NULL)
				{
				PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNKNOWN_DIGEST_TYPE);
				goto err;
				}

			BIO_set_md(btmp,evp_md);
			if (out == NULL)
				out=btmp;
			else
				BIO_push(out,btmp);
			btmp=NULL;
			}
		}

	if (evp_cipher != NULL)
		{
#if 0
		unsigned char key[EVP_MAX_KEY_LENGTH];
		unsigned char iv[EVP_MAX_IV_LENGTH];
		unsigned char *p;
		int keylen,ivlen;
		int max;
		X509_OBJECT ret;
#endif
		int jj;

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

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

		/* Find the recipientInfo which matches the passed certificate
		 * (if any)
		 */

		if (pcert) {
			for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++) {
				ri=sk_PKCS7_RECIP_INFO_value(rsk,i);
				if (!pkcs7_cmp_ri(ri, pcert))
					break;
				ri=NULL;
			}
			if (ri == NULL) {
				PKCS7err(PKCS7_F_PKCS7_DATADECODE,
				      PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE);
				goto err;
			}
		}

		jj=EVP_PKEY_size(pkey);
		tmp=(unsigned char *)OPENSSL_malloc(jj+10);
		if (tmp == NULL)
			{
			PKCS7err(PKCS7_F_PKCS7_DATADECODE,ERR_R_MALLOC_FAILURE);
			goto err;
			}

		/* If we haven't got a certificate try each ri in turn */

		if (pcert == NULL)
			{
			for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++)
				{
				ri=sk_PKCS7_RECIP_INFO_value(rsk,i);
				jj=EVP_PKEY_decrypt(tmp,
					M_ASN1_STRING_data(ri->enc_key),
					M_ASN1_STRING_length(ri->enc_key),
						pkey);
				if (jj > 0)
					break;
				ERR_clear_error();
				ri = NULL;
				}
			if (ri == NULL)
				{
				PKCS7err(PKCS7_F_PKCS7_DATADECODE,
				      PKCS7_R_NO_RECIPIENT_MATCHES_KEY);
				goto err;
				}
			}
		else
			{
			jj=EVP_PKEY_decrypt(tmp,
				M_ASN1_STRING_data(ri->enc_key),
				M_ASN1_STRING_length(ri->enc_key), pkey);
			if (jj <= 0)
				{
				PKCS7err(PKCS7_F_PKCS7_DATADECODE,
								ERR_R_EVP_LIB);
				goto err;
				}
			}

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

		if (jj != 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, jj))
				{
				PKCS7err(PKCS7_F_PKCS7_DATADECODE,
					PKCS7_R_DECRYPTED_KEY_IS_WRONG_LENGTH);
				goto err;
				}
		} 
		if (EVP_CipherInit_ex(evp_ctx,NULL,NULL,tmp,NULL,0) <= 0)
			goto err;

		OPENSSL_cleanse(tmp,jj);

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

#if 1
	if (PKCS7_is_detached(p7) || (in_bio != NULL))
		{
		bio=in_bio;
		}
	else 
		{
#if 0
		bio=BIO_new(BIO_s_mem());
		/* We need to set this so that when we have read all
		 * the data, the encrypt BIO, if present, will read
		 * EOF and encode the last few bytes */
		BIO_set_mem_eof_return(bio,0);

		if (data_body->length > 0)
			BIO_write(bio,(char *)data_body->data,data_body->length);
#else
		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);
		}
#endif
		}
	BIO_push(out,bio);
	bio=NULL;
#endif
	if (0)
		{
err:
		if (out != NULL) BIO_free_all(out);
		if (btmp != NULL) BIO_free_all(btmp);
		if (etmp != NULL) BIO_free_all(etmp);
		if (bio != NULL) BIO_free_all(bio);
		out=NULL;
		}
	if (tmp != NULL)
		OPENSSL_free(tmp);
	return(out);
	}
BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio)
	{
	int i;
	BIO *out=NULL,*btmp=NULL;
	X509_ALGOR *xa = NULL;
	const EVP_CIPHER *evp_cipher=NULL;
	STACK_OF(X509_ALGOR) *md_sk=NULL;
	STACK_OF(PKCS7_RECIP_INFO) *rsk=NULL;
	X509_ALGOR *xalg=NULL;
	PKCS7_RECIP_INFO *ri=NULL;
	EVP_PKEY *pkey;
	ASN1_OCTET_STRING *os=NULL;

	i=OBJ_obj2nid(p7->type);
	p7->state=PKCS7_S_HEADER;

	switch (i)
		{
	case NID_pkcs7_signed:
		md_sk=p7->d.sign->md_algs;
		os = PKCS7_get_octet_string(p7->d.sign->contents);
		break;
	case NID_pkcs7_signedAndEnveloped:
		rsk=p7->d.signed_and_enveloped->recipientinfo;
		md_sk=p7->d.signed_and_enveloped->md_algs;
		xalg=p7->d.signed_and_enveloped->enc_data->algorithm;
		evp_cipher=p7->d.signed_and_enveloped->enc_data->cipher;
		if (evp_cipher == NULL)
			{
			PKCS7err(PKCS7_F_PKCS7_DATAINIT,
						PKCS7_R_CIPHER_NOT_INITIALIZED);
			goto err;
			}
		break;
	case NID_pkcs7_enveloped:
		rsk=p7->d.enveloped->recipientinfo;
		xalg=p7->d.enveloped->enc_data->algorithm;
		evp_cipher=p7->d.enveloped->enc_data->cipher;
		if (evp_cipher == NULL)
			{
			PKCS7err(PKCS7_F_PKCS7_DATAINIT,
						PKCS7_R_CIPHER_NOT_INITIALIZED);
			goto err;
			}
		break;
	case NID_pkcs7_digest:
		xa = p7->d.digest->md;
		os = PKCS7_get_octet_string(p7->d.digest->contents);
		break;
	default:
		PKCS7err(PKCS7_F_PKCS7_DATAINIT,PKCS7_R_UNSUPPORTED_CONTENT_TYPE);
	        goto err;
		}

	for (i=0; i<sk_X509_ALGOR_num(md_sk); i++)
		if (!PKCS7_bio_add_digest(&out, sk_X509_ALGOR_value(md_sk, i)))
			goto err;

	if (xa && !PKCS7_bio_add_digest(&out, xa))
			goto err;

	if (evp_cipher != NULL)
		{
		unsigned char key[EVP_MAX_KEY_LENGTH];
		unsigned char iv[EVP_MAX_IV_LENGTH];
		int keylen,ivlen;
		int jj,max;
		unsigned char *tmp;
		EVP_CIPHER_CTX *ctx;

		if ((btmp=BIO_new(BIO_f_cipher())) == NULL)
			{
			PKCS7err(PKCS7_F_PKCS7_DATAINIT,ERR_R_BIO_LIB);
			goto err;
			}
		BIO_get_cipher_ctx(btmp, &ctx);
		keylen=EVP_CIPHER_key_length(evp_cipher);
		ivlen=EVP_CIPHER_iv_length(evp_cipher);
		xalg->algorithm = OBJ_nid2obj(EVP_CIPHER_type(evp_cipher));
		if (ivlen > 0) RAND_pseudo_bytes(iv,ivlen);
		if (EVP_CipherInit_ex(ctx, evp_cipher, NULL, NULL, NULL, 1)<=0)
			goto err;
		if (EVP_CIPHER_CTX_rand_key(ctx, key) <= 0)
			goto err;
		if (EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, 1) <= 0)
			goto err;

		if (ivlen > 0) {
			if (xalg->parameter == NULL) 
						xalg->parameter=ASN1_TYPE_new();
			if(EVP_CIPHER_param_to_asn1(ctx, xalg->parameter) < 0)
								       goto err;
		}

		/* Lets do the pub key stuff :-) */
		max=0;
		for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++)
			{
			ri=sk_PKCS7_RECIP_INFO_value(rsk,i);
			if (ri->cert == NULL)
				{
				PKCS7err(PKCS7_F_PKCS7_DATAINIT,PKCS7_R_MISSING_CERIPEND_INFO);
				goto err;
				}
			pkey=X509_get_pubkey(ri->cert);
			jj=EVP_PKEY_size(pkey);
			EVP_PKEY_free(pkey);
			if (max < jj) max=jj;
			}
		if ((tmp=(unsigned char *)OPENSSL_malloc(max)) == NULL)
			{
			PKCS7err(PKCS7_F_PKCS7_DATAINIT,ERR_R_MALLOC_FAILURE);
			goto err;
			}
		for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++)
			{
			ri=sk_PKCS7_RECIP_INFO_value(rsk,i);
			pkey=X509_get_pubkey(ri->cert);
			jj=EVP_PKEY_encrypt(tmp,key,keylen,pkey);
			EVP_PKEY_free(pkey);
			if (jj <= 0)
				{
				PKCS7err(PKCS7_F_PKCS7_DATAINIT,ERR_R_EVP_LIB);
				OPENSSL_free(tmp);
				goto err;
				}
			if (!M_ASN1_OCTET_STRING_set(ri->enc_key,tmp,jj))
				{
				PKCS7err(PKCS7_F_PKCS7_DATAINIT,
					ERR_R_MALLOC_FAILURE);
				OPENSSL_free(tmp);
				goto err;
				}
			}
		OPENSSL_free(tmp);
		OPENSSL_cleanse(key, keylen);

		if (out == NULL)
			out=btmp;
		else
			BIO_push(out,btmp);
		btmp=NULL;
		}

	if (bio == NULL)
		{
		if (PKCS7_is_detached(p7))
			bio=BIO_new(BIO_s_null());
		else if (os && os->length > 0)
			bio = BIO_new_mem_buf(os->data, os->length);
		if(bio == NULL)
			{
			bio=BIO_new(BIO_s_mem());
			BIO_set_mem_eof_return(bio,0);
			}
		}
	BIO_push(out,bio);
	bio=NULL;
	if (0)
		{
err:
		if (out != NULL)
			BIO_free_all(out);
		if (btmp != NULL)
			BIO_free_all(btmp);
		out=NULL;
		}
	return(out);
	}
/* Load a DER formatted file into internal SCEP_MSG structure */
SCEP_MSG *d2i_SCEP_MSG_bio (BIO *inbio) {

	BIO *outbio = NULL;
	BIO *p7bio = NULL;
	PKCS7 *p7 = NULL;
	// BIO *bio_err = NULL;

	SCEP_MSG *msg = NULL;

	int bytes, length, fd, used;
	int nMessageType = -1, nPkiStatus = -1;

	PKCS7_SIGNER_INFO *si = NULL;
	PKCS7_RECIP_INFO *ri = NULL;

	STACK_OF(X509_ATTRIBUTE) *sig_attribs = NULL;
	PKCS7 *p7env = NULL;

	SCEP_RECIP_INFO *rinfo = NULL;

	char buffer[1024];
	char *data = NULL;
	char *tmp_string = NULL;

	int debug = 0;
	int i;

        // if ((bio_err=BIO_new(BIO_s_file())) != NULL)
	// 	BIO_set_fp(bio_err,stderr,BIO_NOCLOSE|BIO_FP_TEXT);

	msg = (SCEP_MSG *) OPENSSL_malloc ( sizeof(SCEP_MSG));
	if( msg == NULL ) return (NULL);

	/* decode the data */
	p7 = d2i_PKCS7_bio(inbio, NULL);
	if (p7 == NULL) goto err;

	/* make sure this is a signed data PKCS#7			*/
	// if (!PKCS7_type_is_signed(p7)) {
	// 	BIO_printf(bio_err, "%s:%d: supplied PKCS#7 is not signed "
	// 		"data\n", __FILE__, __LINE__);
	// 	goto err;
	// }

	/* create BIOs to read signed content data from			*/
	p7bio = PKCS7_dataInit(p7, NULL);
	if (p7bio == NULL) goto err;

	/* Use an outbio and fill it with data from the p7 */
	outbio = BIO_new(BIO_s_mem());
	used = 0;
	for (;;) {
		bytes = BIO_read(p7bio, buffer, sizeof(buffer));
		used += bytes;
		if (bytes <= 0) break;
		BIO_write(outbio, buffer, bytes);
	}
	BIO_flush(outbio);

	/* there should be exactly one signer info			*/
	msg->sk_signer_info = PKCS7_get_signer_info(p7);
	if (msg->sk_signer_info == NULL) {
		goto err;
	}
	if (sk_PKCS7_SIGNER_INFO_num(msg->sk_signer_info) != 1) {
		goto err;
	}

	si = sk_PKCS7_SIGNER_INFO_value(msg->sk_signer_info, 0);
	msg->signer_ias = si->issuer_and_serial;
	msg->signer_cert = PKCS7_cert_from_signer_info( p7, si );

	/* If msg->signer_cert == NULL there is no signer certificate,
	 * otherwise the certificate is included into the PKCS#7 envelope
	 * this certificate may be self signed, but for the PKCS7_
	 * signatureVerify method, this does not matter */

	/* verify the PKCS#7 using the store just constructed		*/
	if (PKCS7_signatureVerify(p7bio, p7, si, 
				msg->signer_cert) <= 0) {
		// BIO_printf(bio_err, "%s:%d: verification failed\n", __FILE__,
		// 	__LINE__);
		goto err;
	}

	/* extract the signed attributes				*/
	msg->attrs = PKCS7_get_signed_attributes(si);
	if ((msg->attrs == NULL) || (sk_X509_ATTRIBUTE_num(msg->attrs) == 0)){
		goto err;
	}

	tmp_string = (char *) 
		SCEP_get_string_attr_by_name(msg->attrs, "messageType");

	if( tmp_string != NULL ) {
		msg->messageType = atoi( tmp_string );
		free( tmp_string );
		tmp_string = NULL;
	} else {
		msg->messageType = -1;
	}

	/* unpack the internal PKCS#7					*/
	p7env = d2i_PKCS7_bio(outbio, NULL);
	if (p7env == NULL) return msg;

	i=OBJ_obj2nid(p7env->type);
	msg->env_data.NID_p7data = i;
	msg->env_data.p7env = p7env;

	/* use a commodity variable */
	rinfo = &(msg->env_data.recip_info);

	switch(i) {
		case NID_pkcs7_signed:
			break;
		case NID_pkcs7_signedAndEnveloped:
			rinfo->sk_recip_info =
				p7env->d.signed_and_enveloped->recipientinfo;
			break;
		case  NID_pkcs7_enveloped:
			rinfo->sk_recip_info =
				p7env->d.enveloped->recipientinfo;
			break;
		default:
			// BIO_printf( bio_err, "%s:%d: unknown PKCS7 structure\n",
			// 		__FILE__, __LINE__);
			break;
	}

	/* Lets do the pub key stuff :-) */
	// FIXME: usaly only 1, but pix has 4 in structure - to be clarified...
	// so currently set to 4 to get it working with cisco-pix
	if( sk_PKCS7_RECIP_INFO_num(rinfo->sk_recip_info) > 4 ) {
		goto err;
	}

	/* Let's get the recipient info at stack num 0, the first and
	 * hopefully, the only one */
	ri = sk_PKCS7_RECIP_INFO_value( rinfo->sk_recip_info, 0);

	/* Usually certificates are not present, but in case the standard
	 * will be updated... */
	// if (debug && ri->cert == NULL) {
	// 	BIO_printf( bio_err, 
	// 		"%s:%d: Recipient info cert %d missing\n",
	// 		__FILE__, __LINE__, 0);
	// }

	rinfo->ias = ri->issuer_and_serial;
	/*
	if( rinfo->ias != NULL ) {
		BIO_printf(bio_err, "%s:%d: Recip cert issued by ",
			__FILE__, __LINE__);
                X509_NAME_print_ex (bio_err, rinfo->ias->issuer,  
                                    0, XN_FLAG_RFC2253&(~ASN1_STRFLGS_ESC_MSB));
		BIO_printf(bio_err, "\n%s:%d: Recip cert serial: %s\n",
			__FILE__, __LINE__,
			BN_bn2hex(ASN1_INTEGER_to_BN(rinfo->ias->serial,
			NULL)));
	};
	*/

	if( ri->cert ) {
		/* Usually this does not happen to be included in
		 * the pkcs7env data, but in case we just get it */
		sk_X509_push( rinfo->sk_recip_certs, ri->cert );
        /*
		if ( debug ) {
                        BIO_printf(bio_err, "%s:%d: Recipient cert for ",
                              __FILE__, __LINE__);
                        X509_NAME_print_ex (bio_err, X509_get_subject_name(ri->cert),
                                0, XN_FLAG_RFC2253&(~ASN1_STRFLGS_ESC_MSB));	
                        BIO_printf(bio_err, "\n");
		}
        */
	}

	/* perform some consistency checks				*/

	/* UniCert 3.1.2 seems to out the message type, so fudge 	*/
	/* the value of 3 (CertRep) if it is missing (problem pointed	*/
	/* out by Peter Onion						*/
	/*
	if (NULL == req->messageType) {
		BIO_printf(bio_err, "%s:%d: no message type (setting to 3)\n",
			__FILE__, __LINE__);
		req->messageType = "3";	// XXX should we strdup here?
	}
	*/

	/* UniCert doesn't seem to bother to put in a senderNonce,	*/
	/* so don't get upset if it is missing.				*/
	/*
	if (NULL == scep->senderNonce) {
		BIO_printf(bio_err, "%s:%d: senderNonce missing\n",
			__FILE__, __LINE__);
	}

	*/

	/* perform some type/status dependent checks			*/
	/*
	if ((used == 0) && (nMessageType != 3)) {
		BIO_printf(bio_err, "%s:%d: only CertRep message may be "
			"empty\n", __FILE__, __LINE__);
		goto err;
	}
	if ((used == 0) && (nMessageType == 3) && (nPkiStatus == 0)) {
		BIO_printf(bio_err, "%s:%d: CertRep may only be empty for "
			"failure or pending\n", __FILE__, __LINE__);
		goto err;
	}
	*/

	/* no content is only allowed if the message is a CertRep with	*/
	/* a pkiStatus of failure or pending				*/
	/*
	if (used == 0) {
		BIO_printf(bio_err, "%s:%d: empty PKCSReq, must be failure or "
			"pending\n", __FILE__, __LINE__);
		goto signedonly;
	}
	if (debug)
		BIO_printf(bio_err, "%s:%d: working on inner pkcs#7\n",
			__FILE__, __LINE__);

	*/

	BIO_free(outbio);
signedonly:

	/* we were successfull in extracting the telescoping PKCS#7's	*/
	return(msg);
err:
	// if( debug ) ERR_print_errors(bio_err);
	return(NULL);
}
Beispiel #10
0
/* int */
BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert)
{
    int i, j;
    BIO *out = NULL, *btmp = NULL, *etmp = NULL, *bio = NULL;
    X509_ALGOR *xa;
    ASN1_OCTET_STRING *data_body = NULL;
    const EVP_MD *evp_md;
    const EVP_CIPHER *evp_cipher = NULL;
    EVP_CIPHER_CTX *evp_ctx = NULL;
    X509_ALGOR *enc_alg = NULL;
    STACK_OF(X509_ALGOR) *md_sk = NULL;
    STACK_OF(PKCS7_RECIP_INFO) *rsk = NULL;
    PKCS7_RECIP_INFO *ri = NULL;
    uint8_t *ek = NULL, *tkey = NULL;
    int eklen = 0, tkeylen = 0;
    
    if (p7 == NULL) {
        PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_INVALID_NULL_POINTER);
        return NULL;
    }
    
    if (p7->d.ptr == NULL) {
        PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_NO_CONTENT);
        return NULL;
    }

    i = OBJ_obj2nid(p7->type);
    p7->state = PKCS7_S_HEADER;

    switch (i) {
        case NID_pkcs7_signed:
           /*
            * p7->d.sign->contents is a PKCS7 structure consisting of a contentType
            * field and optional content.
            * data_body is NULL if that structure has no (=detached) content
            * or if the contentType is wrong (i.e., not "data").
            */
            data_body = PKCS7_get_octet_string(p7->d.sign->contents);
            if (!PKCS7_is_detached(p7) && data_body == NULL) {
                PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_INVALID_SIGNED_DATA_TYPE);
                goto err;
            }
            md_sk = p7->d.sign->md_algs;
            break;
        case NID_pkcs7_signedAndEnveloped:
            rsk = p7->d.signed_and_enveloped->recipientinfo;
            md_sk = p7->d.signed_and_enveloped->md_algs;
            /* data_body is NULL if the optional EncryptedContent is missing. */
            data_body = p7->d.signed_and_enveloped->enc_data->enc_data;
            enc_alg = p7->d.signed_and_enveloped->enc_data->algorithm;
            evp_cipher = EVP_get_cipherbyobj(enc_alg->algorithm);
            if (evp_cipher == NULL) {
                PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_UNSUPPORTED_CIPHER_TYPE);
                goto err;
            }
            break;
        case NID_pkcs7_enveloped:
            rsk = p7->d.enveloped->recipientinfo;
            enc_alg = p7->d.enveloped->enc_data->algorithm;
            /* data_body is NULL if the optional EncryptedContent is missing. */
            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 err;
            }
            break;
        default:
            PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_UNSUPPORTED_CONTENT_TYPE);
            goto err;
    }

    /* Detached content must be supplied via in_bio instead. */
    if (data_body == NULL && in_bio == NULL) {
        PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_NO_CONTENT);
        goto err;
    }

    /* We will be checking the signature */
    if (md_sk != NULL) {
        for (i = 0; i < sk_X509_ALGOR_num(md_sk); i++) {
            xa = sk_X509_ALGOR_value(md_sk, i);
            if ((btmp = BIO_new(BIO_f_md())) == NULL) {
                PKCS7err(PKCS7_F_PKCS7_DATADECODE, ERR_R_BIO_LIB);
                goto err;
            }

            j = OBJ_obj2nid(xa->algorithm);
            evp_md = EVP_get_digestbynid(j);
            if (evp_md == NULL) {
                PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_UNKNOWN_DIGEST_TYPE);
                goto err;
            }

            BIO_set_md(btmp, evp_md);
            if (out == NULL)
                out = btmp;
            else
                BIO_push(out, btmp);
            btmp = NULL;
        }
    }

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

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

        /* Find the recipientInfo which matches the passed certificate
         * (if any)
         */

        if (pcert) {
            for (i = 0; i < sk_PKCS7_RECIP_INFO_num(rsk); i++) {
                ri = sk_PKCS7_RECIP_INFO_value(rsk, i);
                if (!pkcs7_cmp_ri(ri, pcert))
                    break;
                ri = NULL;
            }
            if (ri == NULL) {
                PKCS7err(PKCS7_F_PKCS7_DATADECODE,
                         PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE);
                goto err;
            }
        }

        /* If we haven't got a certificate try each ri in turn */
        if (pcert == NULL) {
            /* Always attempt to decrypt all rinfo even
             * after sucess as a defence against MMA timing
             * attacks.
             */
            for (i = 0; i < sk_PKCS7_RECIP_INFO_num(rsk); i++) {
                ri = sk_PKCS7_RECIP_INFO_value(rsk, i);

                if (pkcs7_decrypt_rinfo(&ek, &eklen,
                                        ri, pkey) < 0)
                    goto err;
                ERR_clear_error();
            }
        } else {
            /* Only exit on fatal errors, not decrypt failure */
            if (pkcs7_decrypt_rinfo(&ek, &eklen, ri, pkey) < 0)
                goto err;
            ERR_clear_error();
        }

        evp_ctx = NULL;
        BIO_get_cipher_ctx(etmp, &evp_ctx);
        if (EVP_CipherInit_ex(evp_ctx, evp_cipher, NULL, NULL, NULL, 0) <= 0)
            goto err;
        if (EVP_CIPHER_asn1_to_param(evp_ctx, enc_alg->parameter) < 0)
            goto err;
        /* Generate random key as MMA defence */
        tkeylen = EVP_CIPHER_CTX_key_length(evp_ctx);
        tkey = malloc(tkeylen);
        if (!tkey)
            goto err;
        if (EVP_CIPHER_CTX_rand_key(evp_ctx, tkey) <= 0)
            goto err;
        if (ek == NULL) {
            ek = tkey;
            eklen = tkeylen;
            tkey = NULL;
        }

        if (eklen != 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, eklen)) {
                /* Use random key as MMA defence */
                vigortls_zeroize(ek, eklen);
                free(ek);
                ek = tkey;
                eklen = tkeylen;
                tkey = NULL;
            }
        }
        /* Clear errors so we don't leak information useful in MMA */
        ERR_clear_error();
        if (EVP_CipherInit_ex(evp_ctx, NULL, NULL, ek, NULL, 0) <= 0)
            goto err;

        if (ek) {
            vigortls_zeroize(ek, eklen);
            free(ek);
            ek = NULL;
        }
        if (tkey) {
            vigortls_zeroize(tkey, tkeylen);
            free(tkey);
            tkey = NULL;
        }

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

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

    if (0) {
    err:
        if (ek) {
            vigortls_zeroize(ek, eklen);
            free(ek);
        }
        if (tkey) {
            vigortls_zeroize(tkey, tkeylen);
            free(tkey);
        }
        if (out != NULL)
            BIO_free_all(out);
        if (btmp != NULL)
            BIO_free_all(btmp);
        if (etmp != NULL)
            BIO_free_all(etmp);
        if (bio != NULL)
            BIO_free_all(bio);
        out = NULL;
    }
    return (out);
}
Beispiel #11
0
void
format_smime_info(int pass, BODY *body, long msgno, gf_io_t pc)
{
    PKCS7 *p7;
    int    i;
    
    if(body->type == TYPEMULTIPART){
    	PART *p;    

        for(p=body->nested.part; p; p=p->next)
          format_smime_info(pass, &p->body, msgno, pc);
    }
    
    p7 = body->sparep;
    if(p7){

    	if(PKCS7_type_is_signed(p7)){
            STACK_OF(X509) *signers;

    	    switch(pass){
	      case 1:
		gf_puts(_("This message was cryptographically signed."), pc);
		gf_puts(NEWLINE, pc);
		break;

	      case 2:
		signers = PKCS7_get0_signers(p7, NULL, 0);

		if(signers){

		    snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("Certificate%s used for signing"),
			     plural(sk_X509_num(signers)));
		    gf_puts_uline(tmp_20k_buf, pc);
		    gf_puts(NEWLINE, pc);
		    print_separator_line(100, '-', pc);

		    for(i=0; i<sk_X509_num(signers); i++){
			X509 *x = sk_X509_value(signers, i);

			if(x){
			    output_cert_info(x, pc);
			    gf_puts(NEWLINE, pc);
			}
		    }
		}

		sk_X509_free(signers);
		break;
	    }
    	
	}
	else if(PKCS7_type_is_enveloped(p7)){
	
    	    switch(pass){
	      case 1:
		gf_puts(_("This message was encrypted."), pc);
		gf_puts(NEWLINE, pc);
		break;

	      case 2:
		if(p7->d.enveloped && p7->d.enveloped->enc_data){
		    X509_ALGOR *alg = p7->d.enveloped->enc_data->algorithm;
		    STACK_OF(PKCS7_RECIP_INFO) *ris = p7->d.enveloped->recipientinfo;
		    int found = 0;

		    gf_puts(_("The algorithm used to encrypt was "), pc);

		    if(alg){
			char *n = (char *) OBJ_nid2sn( OBJ_obj2nid(alg->algorithm));

			gf_puts(n ? n : "<unknown>", pc);

		    }
		    else
		      gf_puts("<unknown>", pc);

		    gf_puts("." NEWLINE NEWLINE, pc);

		    snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("Certificate%s for decrypting"),
			     plural(sk_PKCS7_RECIP_INFO_num(ris)));
		    gf_puts_uline(tmp_20k_buf, pc);
		    gf_puts(NEWLINE, pc);
		    print_separator_line(100, '-', pc);

		    for(i=0; i<sk_PKCS7_RECIP_INFO_num(ris); i++){
			PKCS7_RECIP_INFO *ri;
			PERSONAL_CERT *pcert;

			ri = sk_PKCS7_RECIP_INFO_value(ris, i);
			if(!ri)
			  continue;

			pcert = find_certificate_matching_recip_info(ri);

			if(pcert){
			    if(found){
				print_separator_line(25, '*', pc);
				gf_puts(NEWLINE, pc);
			    }

			    found = 1;

			    output_cert_info(pcert->cert, pc);
			    gf_puts(NEWLINE, pc);

			}
		    }

		    if(!found){
			gf_puts(_("No certificate capable of decrypting could be found."), pc);
			gf_puts(NEWLINE, pc);
			gf_puts(NEWLINE, pc);
		    }
		}

		break;
	    }
	}
    }
}
Beispiel #12
0
/* int */
BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert)
	{
	int i,j;
	BIO *out=NULL,*btmp=NULL,*etmp=NULL,*bio=NULL;
	unsigned char *tmp=NULL;
	X509_ALGOR *xa;
	ASN1_OCTET_STRING *data_body=NULL;
	const EVP_MD *evp_md;
	const EVP_CIPHER *evp_cipher=NULL;
	EVP_CIPHER_CTX *evp_ctx=NULL;
	X509_ALGOR *enc_alg=NULL;
	STACK_OF(X509_ALGOR) *md_sk=NULL;
	STACK_OF(PKCS7_RECIP_INFO) *rsk=NULL;
	PKCS7_RECIP_INFO *ri=NULL;

	if (p7 == NULL) {
	  PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_INVALID_NULL_POINTER);
	  return NULL;
	}
	
	if (p7->d.ptr == NULL) {
	  PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_NO_CONTENT);
	  return NULL;
	}

	i=OBJ_obj2nid(p7->type);
	p7->state=PKCS7_S_HEADER;

	switch (i)
		{
	case NID_pkcs7_signed:
	  	/*
		 * p7->d.sign->contents is a PKCS7 structure consisting of a contentType
		 * field and optional content.
		 * data_body is NULL if that structure has no (=detached) content
		 * or if the contentType is wrong (i.e., not "data").
		 */
		data_body=PKCS7_get_octet_string(p7->d.sign->contents);
		md_sk=p7->d.sign->md_algs;
		break;
	case NID_pkcs7_signedAndEnveloped:
		rsk=p7->d.signed_and_enveloped->recipientinfo;
		md_sk=p7->d.signed_and_enveloped->md_algs;
		/* data_body is NULL if the optional EncryptedContent is missing. */
		data_body=p7->d.signed_and_enveloped->enc_data->enc_data;
		enc_alg=p7->d.signed_and_enveloped->enc_data->algorithm;
		evp_cipher=EVP_get_cipherbyobj(enc_alg->algorithm);
		if (evp_cipher == NULL)
			{
			PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CIPHER_TYPE);
			goto err;
			}
		break;
	case NID_pkcs7_enveloped:
		rsk=p7->d.enveloped->recipientinfo;
		enc_alg=p7->d.enveloped->enc_data->algorithm;
		/* data_body is NULL if the optional EncryptedContent is missing. */
		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 err;
			}
		break;
	default:
		PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CONTENT_TYPE);
	        goto err;
		}

	/* Detached content must be supplied via in_bio instead. */
	if (data_body == NULL && in_bio == NULL) {
	  PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_NO_CONTENT);
	  goto err;
	}

	/* We will be checking the signature */
	if (md_sk != NULL)
		{
		for (i=0; i<sk_X509_ALGOR_num(md_sk); i++)
			{
			xa=sk_X509_ALGOR_value(md_sk,i);
			if ((btmp=BIO_new(BIO_f_md())) == NULL)
				{
				PKCS7err(PKCS7_F_PKCS7_DATADECODE,ERR_R_BIO_LIB);
				goto err;
				}

			j=OBJ_obj2nid(xa->algorithm);
			evp_md=EVP_get_digestbynid(j);
			if (evp_md == NULL)
				{
				PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNKNOWN_DIGEST_TYPE);
				goto err;
				}

			BIO_set_md(btmp,evp_md);
			if (out == NULL)
				out=btmp;
			else
				BIO_push(out,btmp);
			btmp=NULL;
			}
		}

	if (evp_cipher != NULL)
		{
#if 0
		unsigned char key[EVP_MAX_KEY_LENGTH];
		unsigned char iv[EVP_MAX_IV_LENGTH];
		unsigned char *p;
		int keylen,ivlen;
		int max;
		X509_OBJECT ret;
#endif
		unsigned char *tkey = NULL;
		int tkeylen;
		int jj;

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

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

		/* Find the recipientInfo which matches the passed certificate
		 * (if any)
		 */

		if (pcert) {
			for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++) {
				ri=sk_PKCS7_RECIP_INFO_value(rsk,i);
				if (!pkcs7_cmp_ri(ri, pcert))
					break;
				ri=NULL;
			}
			if (ri == NULL) {
				PKCS7err(PKCS7_F_PKCS7_DATADECODE,
				      PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE);
				goto err;
			}
		}

		jj=EVP_PKEY_size(pkey);
		tmp=(unsigned char *)OPENSSL_malloc(jj+10);
		if (tmp == NULL)
			{
			PKCS7err(PKCS7_F_PKCS7_DATADECODE,ERR_R_MALLOC_FAILURE);
			goto err;
			}

		/* If we haven't got a certificate try each ri in turn */

		if (pcert == NULL)
			{
			/* Temporary storage in case EVP_PKEY_decrypt
			 * overwrites output buffer on error.
			 */
			unsigned char *tmp2;
			tmp2 = OPENSSL_malloc(jj);
			if (!tmp2)
				goto err;
			jj = -1;
			/* Always attempt to decrypt all cases to avoid
			 * leaking timing information about a successful
			 * decrypt.
			 */
			for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++)
				{
				int tret;
				ri=sk_PKCS7_RECIP_INFO_value(rsk,i);
				tret=EVP_PKEY_decrypt(tmp2,
					M_ASN1_STRING_data(ri->enc_key),
					M_ASN1_STRING_length(ri->enc_key),
						pkey);
				if (tret > 0)
					{
					memcpy(tmp, tmp2, tret);
					OPENSSL_cleanse(tmp2, tret);
					jj = tret;
					}
				ERR_clear_error();
				}
			OPENSSL_free(tmp2);
			}
		else
			{
			jj=EVP_PKEY_decrypt(tmp,
				M_ASN1_STRING_data(ri->enc_key),
				M_ASN1_STRING_length(ri->enc_key), pkey);
			ERR_clear_error();
			}

		evp_ctx=NULL;
		BIO_get_cipher_ctx(etmp,&evp_ctx);
		if (EVP_CipherInit_ex(evp_ctx,evp_cipher,NULL,NULL,NULL,0) <= 0)
			goto err;
		if (EVP_CIPHER_asn1_to_param(evp_ctx,enc_alg->parameter) < 0)
			goto err;
		/* Generate random key to counter MMA */
		tkeylen = EVP_CIPHER_CTX_key_length(evp_ctx);
		tkey = OPENSSL_malloc(tkeylen);
		if (!tkey)
			goto err;
		if (EVP_CIPHER_CTX_rand_key(evp_ctx, tkey) <= 0)
			goto err;
		/* If we have no key use random key */
		if (jj <= 0)
			{
			OPENSSL_free(tmp);
			jj = tkeylen;
			tmp = tkey;
			tkey = NULL;
			}

		if (jj != tkeylen) {
			/* 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, jj))
				{
				/* As MMA defence use random key instead */
				OPENSSL_cleanse(tmp, jj);
				OPENSSL_free(tmp);
				jj = tkeylen;
				tmp = tkey;
				tkey = NULL;
				}
		} 
		ERR_clear_error();
		if (EVP_CipherInit_ex(evp_ctx,NULL,NULL,tmp,NULL,0) <= 0)
			goto err;

		OPENSSL_cleanse(tmp,jj);

		if (tkey)
			{
			OPENSSL_cleanse(tkey, tkeylen);
			OPENSSL_free(tkey);
			}

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

#if 1
	if (in_bio != NULL)
		{
		bio=in_bio;
		}
	else 
		{
#if 0
		bio=BIO_new(BIO_s_mem());
		/* We need to set this so that when we have read all
		 * the data, the encrypt BIO, if present, will read
		 * EOF and encode the last few bytes */
		BIO_set_mem_eof_return(bio,0);

		if (data_body->length > 0)
			BIO_write(bio,(char *)data_body->data,data_body->length);
#else
		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);
		}
		if (bio == NULL)
			goto err;
#endif
		}
	BIO_push(out,bio);
	bio=NULL;
#endif
	if (0)
		{
err:
		if (out != NULL) BIO_free_all(out);
		if (btmp != NULL) BIO_free_all(btmp);
		if (etmp != NULL) BIO_free_all(etmp);
		if (bio != NULL) BIO_free_all(bio);
		out=NULL;
		}
	if (tmp != NULL)
		OPENSSL_free(tmp);
	return(out);
	}