diff options
author | Bob Beck <beck@cvs.openbsd.org> | 1999-09-29 04:37:45 +0000 |
---|---|---|
committer | Bob Beck <beck@cvs.openbsd.org> | 1999-09-29 04:37:45 +0000 |
commit | ca679cff5e2a72ad205119c981e695c8cc640970 (patch) | |
tree | 691368331190f762b9f484d059ec119620396521 /lib/libcrypto/pkcs7/pk7_doit.c | |
parent | 30902ef04e4a800063b5f4afdbf1732ad34aa6b3 (diff) |
OpenSSL 0.9.4 merge
Diffstat (limited to 'lib/libcrypto/pkcs7/pk7_doit.c')
-rw-r--r-- | lib/libcrypto/pkcs7/pk7_doit.c | 718 |
1 files changed, 616 insertions, 102 deletions
diff --git a/lib/libcrypto/pkcs7/pk7_doit.c b/lib/libcrypto/pkcs7/pk7_doit.c index b5689b3fe4c..dee81b547ad 100644 --- a/lib/libcrypto/pkcs7/pk7_doit.c +++ b/lib/libcrypto/pkcs7/pk7_doit.c @@ -58,20 +58,23 @@ #include <stdio.h> #include "cryptlib.h" -#include "rand.h" -#include "objects.h" -#include "x509.h" +#include <openssl/rand.h> +#include <openssl/objects.h> +#include <openssl/x509.h> -BIO *PKCS7_dataInit(p7,bio) -PKCS7 *p7; -BIO *bio; +static int add_attribute(STACK_OF(X509_ATTRIBUTE) **sk, int nid, int atrtype, + void *value); +static ASN1_TYPE *get_attribute(STACK_OF(X509_ATTRIBUTE) *sk, int nid); + +BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio) { int i,j; - BIO *out=NULL,*btmp; + BIO *out=NULL,*btmp=NULL; X509_ALGOR *xa; - EVP_MD *evp_md; - EVP_CIPHER *evp_cipher=NULL; - STACK *md_sk=NULL,*rsk=NULL; + 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; @@ -87,13 +90,25 @@ BIO *bio; case NID_pkcs7_signedAndEnveloped: rsk=p7->d.signed_and_enveloped->recipientinfo; md_sk=p7->d.signed_and_enveloped->md_algs; - evp_cipher=EVP_get_cipherbyname(OBJ_nid2sn(OBJ_obj2nid(p7->d.signed_and_enveloped->enc_data->algorithm->algorithm))); + 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_UNSUPPORTED_CIPHER_TYPE); + 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; } - xalg=p7->d.signed_and_enveloped->enc_data->algorithm; break; default: PKCS7err(PKCS7_F_PKCS7_DATAINIT,PKCS7_R_UNSUPPORTED_CONTENT_TYPE); @@ -102,10 +117,14 @@ BIO *bio; if (md_sk != NULL) { - for (i=0; i<sk_num(md_sk); i++) + for (i=0; i<sk_X509_ALGOR_num(md_sk); i++) { - xa=(X509_ALGOR *)sk_value(md_sk,i); - if ((btmp=BIO_new(BIO_f_md())) == NULL) goto err; + 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; + } j=OBJ_obj2nid(xa->algorithm); evp_md=EVP_get_digestbyname(OBJ_nid2sn(j)); @@ -120,6 +139,7 @@ BIO *bio; out=btmp; else BIO_push(out,btmp); + btmp=NULL; } } @@ -130,49 +150,70 @@ BIO *bio; int keylen,ivlen; int jj,max; unsigned char *tmp; + EVP_CIPHER_CTX *ctx; - if ((btmp=BIO_new(BIO_f_cipher())) == NULL) goto err; + 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 (ivlen > 0) - { - ASN1_OCTET_STRING *os; - - RAND_bytes(iv,ivlen); - os=ASN1_OCTET_STRING_new(); - ASN1_OCTET_STRING_set(os,iv,ivlen); - /* ASN1_TYPE_set(xalg->parameter,V_ASN1_OCTET_STRING, - (char *)os); - */ } RAND_bytes(key,keylen); + xalg->algorithm = OBJ_nid2obj(EVP_CIPHER_type(evp_cipher)); + if (ivlen > 0) RAND_bytes(iv,ivlen); + EVP_CipherInit(ctx, evp_cipher, 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_num(rsk); i++) + for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++) { - ri=(PKCS7_RECIP_INFO *)sk_value(rsk,i); - if (ri->cert == NULL) abort(); + 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 *)Malloc(max)) == NULL) abort(); - for (i=0; i<sk_num(rsk); i++) + if ((tmp=(unsigned char *)Malloc(max)) == NULL) { - ri=(PKCS7_RECIP_INFO *)sk_value(rsk,i); + 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); - if (jj <= 0) abort(); + EVP_PKEY_free(pkey); + if (jj <= 0) + { + PKCS7err(PKCS7_F_PKCS7_DATAINIT,ERR_R_EVP_LIB); + Free(tmp); + goto err; + } ASN1_OCTET_STRING_set(ri->enc_key,tmp,jj); } - - BIO_set_cipher(btmp,evp_cipher,key,iv,1); + Free(tmp); + memset(key, 0, keylen); if (out == NULL) out=btmp; else BIO_push(out,btmp); + btmp=NULL; } if (bio == NULL) /* ??????????? */ @@ -182,6 +223,11 @@ BIO *bio; else { 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 (PKCS7_type_is_signed(p7) && PKCS7_type_is_data(p7->d.sign->contents)) { @@ -195,14 +241,222 @@ BIO *bio; } } 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 */ +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; + 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; +/* EVP_PKEY *pkey; */ +#if 0 + X509_STORE_CTX s_ctx; +#endif + + i=OBJ_obj2nid(p7->type); + p7->state=PKCS7_S_HEADER; + + switch (i) + { + case NID_pkcs7_signed: + data_body=p7->d.sign->contents->d.data; + 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_cipherbyname(OBJ_nid2sn(OBJ_obj2nid(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_cipherbyname(OBJ_nid2sn(OBJ_obj2nid(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_digestbyname(OBJ_nid2sn(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) + */ + + for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++) { + ri=sk_PKCS7_RECIP_INFO_value(rsk,i); + if(!X509_NAME_cmp(ri->issuer_and_serial->issuer, + pcert->cert_info->issuer) && + !ASN1_INTEGER_cmp(pcert->cert_info->serialNumber, + ri->issuer_and_serial->serial)) break; + ri=NULL; + } + if (ri == NULL) { + PKCS7err(PKCS7_F_PKCS7_DATADECODE, + PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE); + return(NULL); + } + + jj=EVP_PKEY_size(pkey); + tmp=Malloc(jj+10); + if (tmp == NULL) + { + PKCS7err(PKCS7_F_PKCS7_DATADECODE,ERR_R_MALLOC_FAILURE); + goto err; + } + + jj=EVP_PKEY_decrypt((unsigned char *)tmp, + ASN1_STRING_data(ri->enc_key), + 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); + EVP_CipherInit(evp_ctx,evp_cipher,NULL,NULL,0); + if (EVP_CIPHER_asn1_to_param(evp_ctx,enc_alg->parameter) < 0) + return(NULL); + + if (jj != EVP_CIPHER_CTX_key_length(evp_ctx)) + { + PKCS7err(PKCS7_F_PKCS7_DATADECODE, + PKCS7_R_DECRYPTED_KEY_IS_WRONG_LENGTH); + goto err; + } + EVP_CipherInit(evp_ctx,NULL,(unsigned char *)tmp,NULL,0); + + memset(tmp,0,jj); + + if (out == NULL) + out=etmp; + else + BIO_push(out,etmp); + etmp=NULL; + } + +#if 1 + if (p7->detached || (in_bio != NULL)) + { + bio=in_bio; + } + else + { + 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); + } + BIO_push(out,bio); + bio=NULL; +#endif + if (0) + { err: - return(NULL); + 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) + Free(tmp); + return(out); } -int PKCS7_dataSign(p7,bio) -PKCS7 *p7; -BIO *bio; +int PKCS7_dataFinal(PKCS7 *p7, BIO *bio) { int ret=0; int i,j; @@ -211,7 +465,8 @@ BIO *bio; BUF_MEM *buf=NULL; PKCS7_SIGNER_INFO *si; EVP_MD_CTX *mdc,ctx_tmp; - STACK *sk,*si_sk=NULL; + STACK_OF(X509_ATTRIBUTE) *sk; + STACK_OF(PKCS7_SIGNER_INFO) *si_sk=NULL; unsigned char *p,*pp=NULL; int x; ASN1_OCTET_STRING *os=NULL; @@ -227,22 +482,35 @@ BIO *bio; os=ASN1_OCTET_STRING_new(); p7->d.signed_and_enveloped->enc_data->enc_data=os; break; + case NID_pkcs7_enveloped: + /* XXXXXXXXXXXXXXXX */ + os=ASN1_OCTET_STRING_new(); + p7->d.enveloped->enc_data->enc_data=os; + break; case NID_pkcs7_signed: si_sk=p7->d.sign->signer_info; os=p7->d.sign->contents->d.data; + /* If detached data then the content is excluded */ + if(p7->detached) { + ASN1_OCTET_STRING_free(os); + p7->d.sign->contents->d.data = NULL; + } break; } if (si_sk != NULL) { - if ((buf=BUF_MEM_new()) == NULL) goto err; - for (i=0; i<sk_num(si_sk); i++) + if ((buf=BUF_MEM_new()) == NULL) + { + PKCS7err(PKCS7_F_PKCS7_DATASIGN,ERR_R_BIO_LIB); + goto err; + } + for (i=0; i<sk_PKCS7_SIGNER_INFO_num(si_sk); i++) { - si=(PKCS7_SIGNER_INFO *) - sk_value(si_sk,i); - if (si->pkey == NULL) - continue; - j=OBJ_obj2nid(si->digest_enc_alg->algorithm); + si=sk_PKCS7_SIGNER_INFO_value(si_sk,i); + if (si->pkey == NULL) continue; + + j=OBJ_obj2nid(si->digest_alg->algorithm); btmp=bio; for (;;) @@ -259,7 +527,7 @@ BIO *bio; PKCS7err(PKCS7_F_PKCS7_DATASIGN,PKCS7_R_INTERNAL_ERROR); goto err; } - if (EVP_MD_pkey_type(EVP_MD_CTX_type(mdc)) == j) + if (EVP_MD_type(EVP_MD_CTX_type(mdc)) == j) break; else btmp=btmp->next_bio; @@ -269,75 +537,117 @@ BIO *bio; * signing. */ memcpy(&ctx_tmp,mdc,sizeof(ctx_tmp)); if (!BUF_MEM_grow(buf,EVP_PKEY_size(si->pkey))) + { + PKCS7err(PKCS7_F_PKCS7_DATASIGN,ERR_R_BIO_LIB); goto err; + } sk=si->auth_attr; - if ((sk != NULL) && (sk_num(sk) != 0)) + + /* If there are attributes, we add the digest + * attribute and only sign the attributes */ + if ((sk != NULL) && (sk_X509_ATTRIBUTE_num(sk) != 0)) { - x=i2d_ASN1_SET(sk,NULL,i2d_X509_ATTRIBUTE, - V_ASN1_SET,V_ASN1_UNIVERSAL); - pp=(unsigned char *)Malloc(i); + unsigned char md_data[EVP_MAX_MD_SIZE]; + unsigned int md_len; + ASN1_OCTET_STRING *digest; + ASN1_UTCTIME *sign_time; + const EVP_MD *md_tmp; + + /* Add signing time */ + sign_time=X509_gmtime_adj(NULL,0); + PKCS7_add_signed_attribute(si, + NID_pkcs9_signingTime, + V_ASN1_UTCTIME,sign_time); + + /* Add digest */ + md_tmp=EVP_MD_CTX_type(&ctx_tmp); + EVP_DigestFinal(&ctx_tmp,md_data,&md_len); + digest=ASN1_OCTET_STRING_new(); + ASN1_OCTET_STRING_set(digest,md_data,md_len); + PKCS7_add_signed_attribute(si, + NID_pkcs9_messageDigest, + V_ASN1_OCTET_STRING,digest); + + /* Now sign the mess */ + EVP_SignInit(&ctx_tmp,md_tmp); + x=i2d_ASN1_SET_OF_X509_ATTRIBUTE(sk,NULL, + i2d_X509_ATTRIBUTE, + V_ASN1_SET,V_ASN1_UNIVERSAL,IS_SET); + pp=(unsigned char *)Malloc(x); p=pp; - i2d_ASN1_SET(sk,&p,i2d_X509_ATTRIBUTE, - V_ASN1_SET,V_ASN1_UNIVERSAL); + i2d_ASN1_SET_OF_X509_ATTRIBUTE(sk,&p, + i2d_X509_ATTRIBUTE, + V_ASN1_SET,V_ASN1_UNIVERSAL,IS_SET); EVP_SignUpdate(&ctx_tmp,pp,x); Free(pp); + pp=NULL; } + if (si->pkey->type == EVP_PKEY_DSA) + ctx_tmp.digest=EVP_dss1(); + if (!EVP_SignFinal(&ctx_tmp,(unsigned char *)buf->data, (unsigned int *)&buf->length,si->pkey)) + { + PKCS7err(PKCS7_F_PKCS7_DATASIGN,ERR_R_EVP_LIB); goto err; + } if (!ASN1_STRING_set(si->enc_digest, (unsigned char *)buf->data,buf->length)) - goto err; - } - if (p7->detached) - ASN1_OCTET_STRING_set(os,(unsigned char *)"",0); - else - { - btmp=BIO_find_type(bio,BIO_TYPE_MEM); - if (btmp == NULL) { - PKCS7err(PKCS7_F_PKCS7_DATASIGN,PKCS7_R_UNABLE_TO_FIND_MEM_BIO); + PKCS7err(PKCS7_F_PKCS7_DATASIGN,ERR_R_ASN1_LIB); goto err; } - BIO_get_mem_ptr(btmp,&buf_mem); - ASN1_OCTET_STRING_set(os, - (unsigned char *)buf_mem->data,buf_mem->length); } - if (pp != NULL) Free(pp); - pp=NULL; } + if (!p7->detached) + { + btmp=BIO_find_type(bio,BIO_TYPE_MEM); + if (btmp == NULL) + { + PKCS7err(PKCS7_F_PKCS7_DATASIGN,PKCS7_R_UNABLE_TO_FIND_MEM_BIO); + goto err; + } + BIO_get_mem_ptr(btmp,&buf_mem); + ASN1_OCTET_STRING_set(os, + (unsigned char *)buf_mem->data,buf_mem->length); + } + if (pp != NULL) Free(pp); + pp=NULL; + ret=1; err: if (buf != NULL) BUF_MEM_free(buf); return(ret); } -int PKCS7_dataVerify(cert_store,ctx,bio,p7,si) -X509_STORE *cert_store; -X509_STORE_CTX *ctx; -BIO *bio; -PKCS7 *p7; -PKCS7_SIGNER_INFO *si; +int PKCS7_dataVerify(X509_STORE *cert_store, X509_STORE_CTX *ctx, BIO *bio, + PKCS7 *p7, PKCS7_SIGNER_INFO *si) { - PKCS7_SIGNED *s; - ASN1_OCTET_STRING *os; - EVP_MD_CTX mdc_tmp,*mdc; - unsigned char *pp,*p; PKCS7_ISSUER_AND_SERIAL *ias; - int ret=0,md_type,i; - STACK *sk; - BIO *btmp; + int ret=0,i; + STACK_OF(X509) *cert; X509 *x509; - if (!PKCS7_type_is_signed(p7)) abort(); + if (PKCS7_type_is_signed(p7)) + { + cert=p7->d.sign->cert; + } + else if (PKCS7_type_is_signedAndEnveloped(p7)) + { + cert=p7->d.signed_and_enveloped->cert; + } + else + { + PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,PKCS7_R_WRONG_PKCS7_TYPE); + goto err; + } /* XXXXXXXXXXXXXXXXXXXXXXX */ ias=si->issuer_and_serial; - s=p7->d.sign; - x509=X509_find_by_issuer_and_serial(s->cert,ias->issuer,ias->serial); + x509=X509_find_by_issuer_and_serial(cert,ias->issuer,ias->serial); /* were we able to find the cert in passed to us */ if (x509 == NULL) @@ -347,12 +657,39 @@ PKCS7_SIGNER_INFO *si; } /* Lets verify */ - X509_STORE_CTX_init(ctx,cert_store,x509,s->cert); + X509_STORE_CTX_init(ctx,cert_store,x509,cert); i=X509_verify_cert(ctx); - if (i <= 0) goto err; + if (i <= 0) + { + PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,ERR_R_X509_LIB); + goto err; + } X509_STORE_CTX_cleanup(ctx); - /* So we like 'x509', lets check the signature. */ + return PKCS7_signatureVerify(bio, p7, si, x509); + err: + return ret; + } + +int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si, + X509 *x509) + { + ASN1_OCTET_STRING *os; + EVP_MD_CTX mdc_tmp,*mdc; + unsigned char *pp,*p; + int ret=0,i; + int md_type; + STACK_OF(X509_ATTRIBUTE) *sk; + BIO *btmp; + EVP_PKEY *pkey; + + if (!PKCS7_type_is_signed(p7) && + !PKCS7_type_is_signedAndEnveloped(p7)) { + PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, + PKCS7_R_WRONG_PKCS7_TYPE); + goto err; + } + md_type=OBJ_obj2nid(si->digest_alg->algorithm); btmp=bio; @@ -361,13 +698,15 @@ PKCS7_SIGNER_INFO *si; if ((btmp == NULL) || ((btmp=BIO_find_type(btmp,BIO_TYPE_MD)) == NULL)) { - PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST); + PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, + PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST); goto err; } BIO_get_md_ctx(btmp,&mdc); if (mdc == NULL) { - PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,PKCS7_R_INTERNAL_ERROR); + PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, + PKCS7_R_INTERNAL_ERROR); goto err; } if (EVP_MD_type(EVP_MD_CTX_type(mdc)) == md_type) @@ -375,28 +714,68 @@ PKCS7_SIGNER_INFO *si; btmp=btmp->next_bio; } - /* mdc is the digest ctx that we want */ + /* mdc is the digest ctx that we want, unless there are attributes, + * in which case the digest is the signed attributes */ memcpy(&mdc_tmp,mdc,sizeof(mdc_tmp)); sk=si->auth_attr; - if ((sk != NULL) && (sk_num(sk) != 0)) + if ((sk != NULL) && (sk_X509_ATTRIBUTE_num(sk) != 0)) { - i=i2d_ASN1_SET(sk,NULL,i2d_X509_ATTRIBUTE, - V_ASN1_SET,V_ASN1_UNIVERSAL); - pp=(unsigned char *)malloc(i); + unsigned char md_dat[EVP_MAX_MD_SIZE]; + unsigned int md_len; + ASN1_OCTET_STRING *message_digest; + + EVP_DigestFinal(&mdc_tmp,md_dat,&md_len); + message_digest=PKCS7_digest_from_attributes(sk); + if (!message_digest) + { + PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, + PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST); + goto err; + } + if ((message_digest->length != (int)md_len) || + (memcmp(message_digest->data,md_dat,md_len))) + { +#if 0 +{ +int ii; +for (ii=0; ii<message_digest->length; ii++) + printf("%02X",message_digest->data[ii]); printf(" sent\n"); +for (ii=0; ii<md_len; ii++) printf("%02X",md_dat[ii]); printf(" calc\n"); +} +#endif + PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, + PKCS7_R_DIGEST_FAILURE); + ret= -1; + goto err; + } + + EVP_VerifyInit(&mdc_tmp,EVP_get_digestbynid(md_type)); + /* Note: when forming the encoding of the attributes we + * shouldn't reorder them or this will break the signature. + * This is done by using the IS_SEQUENCE flag. + */ + i=i2d_ASN1_SET_OF_X509_ATTRIBUTE(sk,NULL,i2d_X509_ATTRIBUTE, + V_ASN1_SET,V_ASN1_UNIVERSAL, IS_SEQUENCE); + pp=Malloc(i); p=pp; - i2d_ASN1_SET(sk,&p,i2d_X509_ATTRIBUTE, - V_ASN1_SET,V_ASN1_UNIVERSAL); + i2d_ASN1_SET_OF_X509_ATTRIBUTE(sk,&p,i2d_X509_ATTRIBUTE, + V_ASN1_SET,V_ASN1_UNIVERSAL, IS_SEQUENCE); EVP_VerifyUpdate(&mdc_tmp,pp,i); - free(pp); + + Free(pp); } os=si->enc_digest; - i=EVP_VerifyFinal(&mdc_tmp,os->data,os->length, - X509_get_pubkey(x509)); + pkey = X509_get_pubkey(x509); + if(pkey->type == EVP_PKEY_DSA) mdc_tmp.digest=EVP_dss1(); + + i=EVP_VerifyFinal(&mdc_tmp,os->data,os->length, pkey); + EVP_PKEY_free(pkey); if (i <= 0) { - PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,PKCS7_R_SIGNATURE_FAILURE); + PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, + PKCS7_R_SIGNATURE_FAILURE); ret= -1; goto err; } @@ -406,3 +785,138 @@ err: return(ret); } +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); + } + +ASN1_TYPE *PKCS7_get_signed_attribute(PKCS7_SIGNER_INFO *si, int nid) + { + return(get_attribute(si->auth_attr,nid)); + } + +ASN1_TYPE *PKCS7_get_attribute(PKCS7_SIGNER_INFO *si, int nid) + { + return(get_attribute(si->unauth_attr,nid)); + } + +static ASN1_TYPE *get_attribute(STACK_OF(X509_ATTRIBUTE) *sk, int nid) + { + int i; + X509_ATTRIBUTE *xa; + ASN1_OBJECT *o; + + o=OBJ_nid2obj(nid); + if (!o || !sk) return(NULL); + for (i=0; i<sk_X509_ATTRIBUTE_num(sk); i++) + { + xa=sk_X509_ATTRIBUTE_value(sk,i); + if (OBJ_cmp(xa->object,o) == 0) + { + if (xa->set && sk_ASN1_TYPE_num(xa->value.set)) + return(sk_ASN1_TYPE_value(xa->value.set,0)); + else + return(NULL); + } + } + return(NULL); + } + +ASN1_OCTET_STRING *PKCS7_digest_from_attributes(STACK_OF(X509_ATTRIBUTE) *sk) +{ + ASN1_TYPE *astype; + if(!(astype = get_attribute(sk, NID_pkcs9_messageDigest))) return NULL; + return astype->value.octet_string; +} + +int PKCS7_set_signed_attributes(PKCS7_SIGNER_INFO *p7si, + STACK_OF(X509_ATTRIBUTE) *sk) + { + int i; + + if (p7si->auth_attr != NULL) + sk_X509_ATTRIBUTE_pop_free(p7si->auth_attr,X509_ATTRIBUTE_free); + p7si->auth_attr=sk_X509_ATTRIBUTE_dup(sk); + for (i=0; i<sk_X509_ATTRIBUTE_num(sk); i++) + { + if ((sk_X509_ATTRIBUTE_set(p7si->auth_attr,i, + X509_ATTRIBUTE_dup(sk_X509_ATTRIBUTE_value(sk,i)))) + == NULL) + return(0); + } + return(1); + } + +int PKCS7_set_attributes(PKCS7_SIGNER_INFO *p7si, STACK_OF(X509_ATTRIBUTE) *sk) + { + int i; + + if (p7si->unauth_attr != NULL) + sk_X509_ATTRIBUTE_pop_free(p7si->unauth_attr, + X509_ATTRIBUTE_free); + p7si->unauth_attr=sk_X509_ATTRIBUTE_dup(sk); + for (i=0; i<sk_X509_ATTRIBUTE_num(sk); i++) + { + if ((sk_X509_ATTRIBUTE_set(p7si->unauth_attr,i, + X509_ATTRIBUTE_dup(sk_X509_ATTRIBUTE_value(sk,i)))) + == NULL) + return(0); + } + return(1); + } + +int PKCS7_add_signed_attribute(PKCS7_SIGNER_INFO *p7si, int nid, int atrtype, + void *value) + { + return(add_attribute(&(p7si->auth_attr),nid,atrtype,value)); + } + +int PKCS7_add_attribute(PKCS7_SIGNER_INFO *p7si, int nid, int atrtype, + void *value) + { + return(add_attribute(&(p7si->unauth_attr),nid,atrtype,value)); + } + +static int add_attribute(STACK_OF(X509_ATTRIBUTE) **sk, int nid, int atrtype, + void *value) + { + X509_ATTRIBUTE *attr=NULL; + + if (*sk == NULL) + { + *sk = sk_X509_ATTRIBUTE_new(NULL); +new_attrib: + attr=X509_ATTRIBUTE_create(nid,atrtype,value); + sk_X509_ATTRIBUTE_push(*sk,attr); + } + else + { + int i; + + for (i=0; i<sk_X509_ATTRIBUTE_num(*sk); i++) + { + attr=sk_X509_ATTRIBUTE_value(*sk,i); + if (OBJ_obj2nid(attr->object) == nid) + { + X509_ATTRIBUTE_free(attr); + attr=X509_ATTRIBUTE_create(nid,atrtype,value); + sk_X509_ATTRIBUTE_set(*sk,i,attr); + goto end; + } + } + goto new_attrib; + } +end: + return(1); + } + |