- {
- int i;
- BIO *out=NULL,*btmp=NULL;
- X509_ALGOR *xa;
- const EVP_MD *evp_md;
- 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;
-
- i=OBJ_obj2nid(p7->type);
- p7->state=PKCS7_S_HEADER;
-
- switch (i)
- {
- case NID_pkcs7_signed:
- 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;
- 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;
- default:
- PKCS7err(PKCS7_F_PKCS7_DATAINIT,PKCS7_R_UNSUPPORTED_CONTENT_TYPE);
- goto err;
- }
-
- 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_DATAINIT,ERR_R_BIO_LIB);
- goto err;
- }
-
- evp_md=EVP_get_digestbyobj(xa->algorithm);
- if (evp_md == NULL)
- {
- PKCS7err(PKCS7_F_PKCS7_DATAINIT,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)
- {
- 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);
- if (RAND_bytes(key,keylen) <= 0)
- goto err;
- xalg->algorithm = OBJ_nid2obj(EVP_CIPHER_type(evp_cipher));
- if (ivlen > 0) RAND_pseudo_bytes(iv,ivlen);
- EVP_CipherInit_ex(ctx, evp_cipher, NULL, key, iv, 1);
-
- 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;
- }
- M_ASN1_OCTET_STRING_set(ri->enc_key,tmp,jj);
- }
- 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
- {
- ASN1_OCTET_STRING *os;
- os = PKCS7_get_octet_string(p7->d.sign->contents);
- 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);
- }
+{
+ 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_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);
+ } else {
+ bio = BIO_new(BIO_s_mem());
+ if (bio == NULL)
+ goto err;
+ BIO_set_mem_eof_return(bio, 0);
+ }
+ if (bio == NULL)
+ goto err;
+ }
+ 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);
+}
+
+static int pkcs7_cmp_ri(PKCS7_RECIP_INFO *ri, X509 *pcert)
+{
+ int ret;
+ ret = X509_NAME_cmp(ri->issuer_and_serial->issuer,
+ pcert->cert_info->issuer);
+ if (ret)
+ return ret;
+ return M_ASN1_INTEGER_cmp(pcert->cert_info->serialNumber,
+ ri->issuer_and_serial->serial);
+}