diff options
-rw-r--r-- | apps/pkcs7.c | 17 | ||||
-rw-r--r-- | apps/smime.c | 32 | ||||
-rw-r--r-- | crypto/pkcs7/pk7_asn1.c | 48 | ||||
-rw-r--r-- | crypto/pkcs7/pk7_doit.c | 101 | ||||
-rw-r--r-- | crypto/pkcs7/pk7_lib.c | 69 | ||||
-rw-r--r-- | crypto/pkcs7/pk7_local.h | 14 | ||||
-rw-r--r-- | crypto/pkcs7/pk7_mime.c | 24 | ||||
-rw-r--r-- | crypto/pkcs7/pk7_smime.c | 85 | ||||
-rw-r--r-- | crypto/x509/x_all.c | 15 | ||||
-rw-r--r-- | doc/man1/openssl-smime.pod.in | 3 | ||||
-rw-r--r-- | doc/man3/PKCS7_encrypt.pod | 25 | ||||
-rw-r--r-- | doc/man3/PKCS7_sign.pod | 25 | ||||
-rw-r--r-- | doc/man3/SMIME_read_PKCS7.pod | 18 | ||||
-rw-r--r-- | doc/man3/X509_dup.pod | 15 | ||||
-rw-r--r-- | include/crypto/pkcs7.h | 10 | ||||
-rw-r--r-- | include/openssl/pkcs7.h | 17 |
16 files changed, 419 insertions, 99 deletions
diff --git a/apps/pkcs7.c b/apps/pkcs7.c index 2416584dd6..95d3ca0845 100644 --- a/apps/pkcs7.c +++ b/apps/pkcs7.c @@ -57,12 +57,14 @@ const OPTIONS pkcs7_options[] = { int pkcs7_main(int argc, char **argv) { ENGINE *e = NULL; - PKCS7 *p7 = NULL; + PKCS7 *p7 = NULL, *p7i; BIO *in = NULL, *out = NULL; int informat = FORMAT_PEM, outformat = FORMAT_PEM; char *infile = NULL, *outfile = NULL, *prog; int i, print_certs = 0, text = 0, noout = 0, p7_print = 0, ret = 1; OPTION_CHOICE o; + OPENSSL_CTX *libctx = app_get0_libctx(); + const char *propq = app_get0_propq(); prog = opt_init(argc, argv, pkcs7_options); while ((o = opt_next()) != OPT_EOF) { @@ -119,11 +121,18 @@ int pkcs7_main(int argc, char **argv) if (in == NULL) goto end; + p7 = PKCS7_new_with_libctx(libctx, propq); + if (p7 == NULL) { + BIO_printf(bio_err, "unable to allocate PKCS7 object\n"); + ERR_print_errors(bio_err); + goto end; + } + if (informat == FORMAT_ASN1) - p7 = d2i_PKCS7_bio(in, NULL); + p7i = d2i_PKCS7_bio(in, &p7); else - p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL); - if (p7 == NULL) { + p7i = PEM_read_bio_PKCS7(in, &p7, NULL, NULL); + if (p7i == NULL) { BIO_printf(bio_err, "unable to load PKCS7 object\n"); ERR_print_errors(bio_err); goto end; diff --git a/apps/smime.c b/apps/smime.c index 6b7d51b76a..4dfc80d440 100644 --- a/apps/smime.c +++ b/apps/smime.c @@ -45,7 +45,7 @@ typedef enum OPTION_choice { OPT_TO, OPT_FROM, OPT_SUBJECT, OPT_SIGNER, OPT_RECIP, OPT_MD, OPT_CIPHER, OPT_INKEY, OPT_KEYFORM, OPT_CERTFILE, OPT_CAFILE, OPT_CAPATH, OPT_CASTORE, OPT_NOCAFILE, OPT_NOCAPATH, OPT_NOCASTORE, - OPT_R_ENUM, OPT_PROV_ENUM, + OPT_R_ENUM, OPT_PROV_ENUM, OPT_CONFIG, OPT_V_ENUM, OPT_IN, OPT_INFORM, OPT_OUT, OPT_OUTFORM, OPT_CONTENT @@ -70,6 +70,7 @@ const OPTIONS smime_options[] = { {"stream", OPT_STREAM, '-', "Enable CMS streaming" }, {"indef", OPT_INDEF, '-', "Same as -stream" }, {"noindef", OPT_NOINDEF, '-', "Disable CMS streaming"}, + OPT_CONFIG_OPTION, OPT_SECTION("Action"), {"encrypt", OPT_ENCRYPT, '-', "Encrypt message"}, @@ -133,6 +134,7 @@ const OPTIONS smime_options[] = { int smime_main(int argc, char **argv) { + CONF *conf = NULL; BIO *in = NULL, *out = NULL, *indata = NULL; EVP_PKEY *key = NULL; PKCS7 *p7 = NULL; @@ -155,6 +157,8 @@ int smime_main(int argc, char **argv) int vpmtouched = 0, rv = 0; ENGINE *e = NULL; const char *mime_eol = "\n"; + OPENSSL_CTX *libctx = app_get0_libctx(); + const char *propq = app_get0_propq(); if ((vpm = X509_VERIFY_PARAM_new()) == NULL) return 1; @@ -252,6 +256,11 @@ int smime_main(int argc, char **argv) if (!opt_provider(o)) goto end; break; + case OPT_CONFIG: + conf = app_load_config_modules(opt_arg()); + if (conf == NULL) + goto end; + break; case OPT_ENGINE: e = setup_engine(opt_arg(), 0); break; @@ -476,18 +485,25 @@ int smime_main(int argc, char **argv) goto end; if (operation & SMIME_IP) { + PKCS7 *p7_in = NULL; + + p7 = PKCS7_new_with_libctx(libctx, propq); + if (p7 == NULL) { + BIO_printf(bio_err, "Error allocating PKCS7 object\n"); + goto end; + } if (informat == FORMAT_SMIME) { - p7 = SMIME_read_PKCS7(in, &indata); + p7_in = SMIME_read_PKCS7_ex(in, &indata, &p7); } else if (informat == FORMAT_PEM) { - p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL); + p7_in = PEM_read_bio_PKCS7(in, &p7, NULL, NULL); } else if (informat == FORMAT_ASN1) { - p7 = d2i_PKCS7_bio(in, NULL); + p7_in = d2i_PKCS7_bio(in, &p7); } else { BIO_printf(bio_err, "Bad input format for PKCS#7 file\n"); goto end; } - if (p7 == NULL) { + if (p7_in == NULL) { BIO_printf(bio_err, "Error reading S/MIME message\n"); goto end; } @@ -518,7 +534,7 @@ int smime_main(int argc, char **argv) if (operation == SMIME_ENCRYPT) { if (indef) flags |= PKCS7_STREAM; - p7 = PKCS7_encrypt(encerts, in, cipher, flags); + p7 = PKCS7_encrypt_with_libctx(encerts, in, cipher, flags, libctx, propq); } else if (operation & SMIME_SIGNERS) { int i; /* @@ -533,7 +549,8 @@ int smime_main(int argc, char **argv) flags |= PKCS7_STREAM; } flags |= PKCS7_PARTIAL; - p7 = PKCS7_sign(NULL, NULL, other, in, flags); + p7 = PKCS7_sign_with_libctx(NULL, NULL, other, in, flags, libctx, + propq); if (p7 == NULL) goto end; if (flags & PKCS7_NOCERTS) { @@ -643,6 +660,7 @@ int smime_main(int argc, char **argv) BIO_free(indata); BIO_free_all(out); OPENSSL_free(passin); + NCONF_free(conf); return ret; } diff --git a/crypto/pkcs7/pk7_asn1.c b/crypto/pkcs7/pk7_asn1.c index 08852418cc..f04e4b34ce 100644 --- a/crypto/pkcs7/pk7_asn1.c +++ b/crypto/pkcs7/pk7_asn1.c @@ -12,6 +12,7 @@ #include <openssl/asn1t.h> #include <openssl/pkcs7.h> #include <openssl/x509.h> +#include "pk7_local.h" /* PKCS#7 ASN1 module */ @@ -62,7 +63,52 @@ ASN1_NDEF_SEQUENCE_cb(PKCS7, pk7_cb) = { ASN1_ADB_OBJECT(PKCS7) }ASN1_NDEF_SEQUENCE_END_cb(PKCS7, PKCS7) -IMPLEMENT_ASN1_FUNCTIONS(PKCS7) +PKCS7 *d2i_PKCS7(PKCS7 **a, const unsigned char **in, long len) +{ + PKCS7 *ret; + + ret = (PKCS7 *)ASN1_item_d2i((ASN1_VALUE **)a, in, len, (PKCS7_it())); + if (ret != NULL && a != NULL) + pkcs7_resolve_libctx(ret); + return ret; +} + +int i2d_PKCS7(const PKCS7 *a, unsigned char **out) +{ + return ASN1_item_i2d((const ASN1_VALUE *)a, out, (PKCS7_it()));\ +} + +PKCS7 *PKCS7_new(void) +{ + return (PKCS7 *)ASN1_item_new(ASN1_ITEM_rptr(PKCS7)); +} + +PKCS7 *PKCS7_new_with_libctx(OPENSSL_CTX *libctx, const char *propq) +{ + PKCS7 *pkcs7 = PKCS7_new(); + + if (pkcs7 != NULL) { + pkcs7->ctx.libctx = libctx; + pkcs7->ctx.propq = NULL; + if (propq != NULL) { + pkcs7->ctx.propq = OPENSSL_strdup(propq); + if (pkcs7->ctx.propq == NULL) { + PKCS7_free(pkcs7); + pkcs7 = NULL; + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + } + } + } + return pkcs7; +} + +void PKCS7_free(PKCS7 *p7) +{ + if (p7 != NULL) { + OPENSSL_free(p7->ctx.propq); + ASN1_item_free((ASN1_VALUE *)p7, ASN1_ITEM_rptr(PKCS7)); + } +} IMPLEMENT_ASN1_NDEF_FUNCTION(PKCS7) diff --git a/crypto/pkcs7/pk7_doit.c b/crypto/pkcs7/pk7_doit.c index b815a4a77b..1d2a1eb898 100644 --- a/crypto/pkcs7/pk7_doit.c +++ b/crypto/pkcs7/pk7_doit.c @@ -14,6 +14,7 @@ #include <openssl/x509.h> #include <openssl/x509v3.h> #include <openssl/err.h> +#include "pk7_local.h" DEFINE_STACK_OF(X509_ALGOR) DEFINE_STACK_OF(X509_ATTRIBUTE) @@ -57,22 +58,27 @@ static ASN1_OCTET_STRING *PKCS7_get_octet_string(PKCS7 *p7) return NULL; } -static int PKCS7_bio_add_digest(BIO **pbio, X509_ALGOR *alg) +static int pkcs7_bio_add_digest(BIO **pbio, X509_ALGOR *alg, + const PKCS7_CTX *ctx) { BIO *btmp; - const EVP_MD *md; + const char *name; + EVP_MD *fetched = NULL; + if ((btmp = BIO_new(BIO_f_md())) == NULL) { PKCS7err(PKCS7_F_PKCS7_BIO_ADD_DIGEST, ERR_R_BIO_LIB); goto err; } - md = EVP_get_digestbyobj(alg->algorithm); - if (md == NULL) { + name = OBJ_nid2sn(OBJ_obj2nid(alg->algorithm)); + fetched = EVP_MD_fetch(ctx->libctx, name, ctx->propq); + if (fetched == NULL) { PKCS7err(PKCS7_F_PKCS7_BIO_ADD_DIGEST, PKCS7_R_UNKNOWN_DIGEST_TYPE); goto err; } - BIO_set_md(btmp, md); + BIO_set_md(btmp, fetched); + EVP_MD_free(fetched); if (*pbio == NULL) *pbio = btmp; else if (!BIO_push(*pbio, btmp)) { @@ -86,7 +92,6 @@ static int PKCS7_bio_add_digest(BIO **pbio, X509_ALGOR *alg) err: BIO_free(btmp); return 0; - } static int pkcs7_encode_rinfo(PKCS7_RECIP_INFO *ri, @@ -97,12 +102,13 @@ static int pkcs7_encode_rinfo(PKCS7_RECIP_INFO *ri, unsigned char *ek = NULL; int ret = 0; size_t eklen; + const PKCS7_CTX *ctx = ri->ctx; pkey = X509_get0_pubkey(ri->cert); if (pkey == NULL) return 0; - pctx = EVP_PKEY_CTX_new(pkey, NULL); + pctx = EVP_PKEY_CTX_new_from_pkey(ctx->libctx, pkey, ctx->propq); if (pctx == NULL) return 0; @@ -148,8 +154,9 @@ static int pkcs7_decrypt_rinfo(unsigned char **pek, int *peklen, unsigned char *ek = NULL; size_t eklen; int ret = -1; + const PKCS7_CTX *ctx = ri->ctx; - pctx = EVP_PKEY_CTX_new(pkey, NULL); + pctx = EVP_PKEY_CTX_new_from_pkey(ctx->libctx, pkey, ctx->propq); if (pctx == NULL) return -1; @@ -201,17 +208,21 @@ BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio) int i; BIO *out = NULL, *btmp = NULL; X509_ALGOR *xa = NULL; + EVP_CIPHER *fetched_cipher = 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; + const PKCS7_CTX *p7_ctx; if (p7 == NULL) { PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_INVALID_NULL_POINTER); return NULL; } + p7_ctx = pkcs7_get0_ctx(p7); + /* * The content field in the PKCS7 ContentInfo is optional, but that really * only applies to inner content (precisely, detached signatures). @@ -266,10 +277,10 @@ BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio) } for (i = 0; i < sk_X509_ALGOR_num(md_sk); i++) - if (!PKCS7_bio_add_digest(&out, sk_X509_ALGOR_value(md_sk, i))) + if (!pkcs7_bio_add_digest(&out, sk_X509_ALGOR_value(md_sk, i), p7_ctx)) goto err; - if (xa && !PKCS7_bio_add_digest(&out, xa)) + if (xa && !pkcs7_bio_add_digest(&out, xa, p7_ctx)) goto err; if (evp_cipher != NULL) { @@ -287,10 +298,21 @@ BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio) 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) + if (RAND_bytes_ex(p7_ctx->libctx, iv, ivlen) <= 0) goto err; - if (EVP_CipherInit_ex(ctx, evp_cipher, NULL, NULL, NULL, 1) <= 0) + + fetched_cipher = EVP_CIPHER_fetch(p7_ctx->libctx, + EVP_CIPHER_name(evp_cipher), + p7_ctx->propq); + if (fetched_cipher == NULL) goto err; + + if (EVP_CipherInit_ex(ctx, fetched_cipher, NULL, NULL, NULL, 1) <= 0) + goto err; + + EVP_CIPHER_free(fetched_cipher); + fetched_cipher = NULL; + if (EVP_CIPHER_CTX_rand_key(ctx, key) <= 0) goto err; if (EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, 1) <= 0) @@ -342,6 +364,7 @@ BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio) return out; err: + EVP_CIPHER_free(fetched_cipher); BIO_free_all(out); BIO_free_all(btmp); return NULL; @@ -361,12 +384,12 @@ static int pkcs7_cmp_ri(PKCS7_RECIP_INFO *ri, X509 *pcert) /* int */ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert) { - int i, j, len; + int i, len; 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_MD *evp_md = NULL; + EVP_CIPHER *evp_cipher = NULL; EVP_CIPHER_CTX *evp_ctx = NULL; X509_ALGOR *enc_alg = NULL; STACK_OF(X509_ALGOR) *md_sk = NULL; @@ -374,12 +397,16 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert) PKCS7_RECIP_INFO *ri = NULL; unsigned char *ek = NULL, *tkey = NULL; int eklen = 0, tkeylen = 0; + const char *name; + const PKCS7_CTX *p7_ctx; if (p7 == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_INVALID_NULL_POINTER); return NULL; } + p7_ctx = pkcs7_get0_ctx(p7); + if (p7->d.ptr == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_NO_CONTENT); return NULL; @@ -410,7 +437,9 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert) /* 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); + + name = OBJ_nid2sn(OBJ_obj2nid(enc_alg->algorithm)); + evp_cipher = EVP_CIPHER_fetch(p7_ctx->libctx, name, p7_ctx->propq); if (evp_cipher == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_UNSUPPORTED_CIPHER_TYPE); @@ -422,7 +451,8 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert) 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); + name = OBJ_nid2sn(OBJ_obj2nid(enc_alg->algorithm)); + evp_cipher = EVP_CIPHER_fetch(p7_ctx->libctx, name, p7_ctx->propq); if (evp_cipher == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_UNSUPPORTED_CIPHER_TYPE); @@ -449,8 +479,8 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert) goto err; } - j = OBJ_obj2nid(xa->algorithm); - evp_md = EVP_get_digestbynid(j); + name = OBJ_nid2sn(OBJ_obj2nid(xa->algorithm)); + evp_md = EVP_MD_fetch(p7_ctx->libctx, name, p7_ctx->propq); if (evp_md == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_UNKNOWN_DIGEST_TYPE); @@ -458,6 +488,7 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert) } BIO_set_md(btmp, evp_md); + EVP_MD_free(evp_md); if (out == NULL) out = btmp; else @@ -504,13 +535,14 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert) */ for (i = 0; i < sk_PKCS7_RECIP_INFO_num(rsk); i++) { ri = sk_PKCS7_RECIP_INFO_value(rsk, i); - + ri->ctx = p7_ctx; if (pkcs7_decrypt_rinfo(&ek, &eklen, ri, pkey, EVP_CIPHER_key_length(evp_cipher)) < 0) goto err; ERR_clear_error(); } } else { + ri->ctx = p7_ctx; /* Only exit on fatal errors, not decrypt failure */ if (pkcs7_decrypt_rinfo(&ek, &eklen, ri, pkey, 0) < 0) goto err; @@ -585,9 +617,11 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert) } BIO_push(out, bio); bio = NULL; + EVP_CIPHER_free(evp_cipher); return out; err: + EVP_CIPHER_free(evp_cipher); OPENSSL_clear_free(ek, eklen); OPENSSL_clear_free(tkey, tkeylen); BIO_free_all(out); @@ -658,12 +692,15 @@ int PKCS7_dataFinal(PKCS7 *p7, BIO *bio) STACK_OF(X509_ATTRIBUTE) *sk; STACK_OF(PKCS7_SIGNER_INFO) *si_sk = NULL; ASN1_OCTET_STRING *os = NULL; + const PKCS7_CTX *p7_ctx; if (p7 == NULL) { PKCS7err(PKCS7_F_PKCS7_DATAFINAL, PKCS7_R_INVALID_NULL_POINTER); return 0; } + p7_ctx = pkcs7_get0_ctx(p7); + if (p7->d.ptr == NULL) { PKCS7err(PKCS7_F_PKCS7_DATAFINAL, PKCS7_R_NO_CONTENT); return 0; @@ -771,7 +808,8 @@ int PKCS7_dataFinal(PKCS7 *p7, BIO *bio) if (abuf == NULL) goto err; - if (!EVP_SignFinal(ctx_tmp, abuf, &abuflen, si->pkey)) { + if (!EVP_SignFinal_with_libctx(ctx_tmp, abuf, &abuflen, si->pkey, + p7_ctx->libctx, p7_ctx->propq)) { OPENSSL_free(abuf); PKCS7err(PKCS7_F_PKCS7_DATAFINAL, ERR_R_EVP_LIB); goto err; @@ -830,6 +868,7 @@ int PKCS7_SIGNER_INFO_sign(PKCS7_SIGNER_INFO *si) int alen; size_t siglen; const EVP_MD *md = NULL; + const PKCS7_CTX *ctx = si->ctx; md = EVP_get_digestbyobj(si->digest_alg->algorithm); if (md == NULL) @@ -837,11 +876,13 @@ int PKCS7_SIGNER_INFO_sign(PKCS7_SIGNER_INFO *si) mctx = EVP_MD_CTX_new(); if (mctx == NULL) { - PKCS7err(PKCS7_F_PKCS7_SIGNER_INFO_SIGN, ERR_R_MALLOC_FAILURE); + PKCS7err(0, ERR_R_MALLOC_FAILURE); goto err; } - if (EVP_DigestSignInit(mctx, &pctx, md, NULL, si->pkey) <= 0) + if (EVP_DigestSignInit_with_libctx(mctx, &pctx, + EVP_MD_name(md), ctx->libctx, ctx->propq, + si->pkey) <= 0) goto err; /* @@ -863,7 +904,7 @@ int PKCS7_SIGNER_INFO_sign(PKCS7_SIGNER_INFO *si) #if 0 if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN, EVP_PKEY_CTRL_PKCS7_SIGN, 0, si) <= 0) { - PKCS7err(PKCS7_F_PKCS7_SIGNER_INFO_SIGN, PKCS7_R_CTRL_ERROR); + PKCS7err(0, PKCS7_R_CTRL_ERROR); goto err; } #endif @@ -903,7 +944,7 @@ int PKCS7_SIGNER_INFO_sign(PKCS7_SIGNER_INFO *si) #if 0 if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN, EVP_PKEY_CTRL_PKCS7_SIGN, 1, si) <= 0) { - PKCS7err(PKCS7_F_PKCS7_SIGNER_INFO_SIGN, PKCS7_R_CTRL_ERROR); + PKCS7err(0, PKCS7_R_CTRL_ERROR); goto err; } #endif @@ -918,7 +959,6 @@ int PKCS7_SIGNER_INFO_sign(PKCS7_SIGNER_INFO *si) OPENSSL_free(abuf); EVP_MD_CTX_free(mctx); return 0; - } int PKCS7_dataVerify(X509_STORE *cert_store, X509_STORE_CTX *ctx, BIO *bio, @@ -983,11 +1023,13 @@ int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si, { ASN1_OCTET_STRING *os; EVP_MD_CTX *mdc_tmp, *mdc; + EVP_MD *fetched_md = NULL; int ret = 0, i; int md_type; STACK_OF(X509_ATTRIBUTE) *sk; BIO *btmp; EVP_PKEY *pkey; + const PKCS7_CTX *ctx = pkcs7_get0_ctx(p7); mdc_tmp = EVP_MD_CTX_new(); if (mdc_tmp == NULL) { @@ -1055,7 +1097,8 @@ int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si, goto err; } - if (!EVP_VerifyInit_ex(mdc_tmp, EVP_get_digestbynid(md_type), NULL)) + fetched_md = EVP_MD_fetch(ctx->libctx, OBJ_nid2sn(md_type), ctx->propq); + if (fetched_md == NULL || !EVP_VerifyInit_ex(mdc_tmp, fetched_md, NULL)) goto err; alen = ASN1_item_i2d((ASN1_VALUE *)sk, &abuf, @@ -1078,7 +1121,8 @@ int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si, goto err; } - i = EVP_VerifyFinal(mdc_tmp, os->data, os->length, pkey); + i = EVP_VerifyFinal_with_libctx(mdc_tmp, os->data, os->length, pkey, + ctx->libctx, ctx->propq); if (i <= 0) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_SIGNATURE_FAILURE); ret = -1; @@ -1087,6 +1131,7 @@ int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si, ret = 1; err: EVP_MD_CTX_free(mdc_tmp); + EVP_MD_free(fetched_md); return ret; } diff --git a/crypto/pkcs7/pk7_lib.c b/crypto/pkcs7/pk7_lib.c index cb8c67b65a..abe3570c68 100644 --- a/crypto/pkcs7/pk7_lib.c +++ b/crypto/pkcs7/pk7_lib.c @@ -13,6 +13,8 @@ #include <openssl/x509.h> #include "crypto/asn1.h" #include "crypto/evp.h" +#include "crypto/x509.h" +#include "pk7_local.h" DEFINE_STACK_OF(X509) DEFINE_STACK_OF(X509_CRL) @@ -236,6 +238,7 @@ int PKCS7_add_signer(PKCS7 *p7, PKCS7_SIGNER_INFO *psi) } } + psi->ctx = pkcs7_get0_ctx(p7); if (!sk_PKCS7_SIGNER_INFO_push(signer_sk, psi)) return 0; return 1; @@ -380,6 +383,70 @@ PKCS7_SIGNER_INFO *PKCS7_add_signature(PKCS7 *p7, X509 *x509, EVP_PKEY *pkey, return NULL; } +static STACK_OF(X509) *pkcs7_get_signer_certs(const PKCS7 *p7) +{ + if (PKCS7_type_is_signed(p7)) + return p7->d.sign->cert; + if (PKCS7_type_is_signedAndEnveloped(p7)) + return p7->d.signed_and_enveloped->cert; + return NULL; +} + +static STACK_OF(PKCS7_RECIP_INFO) *pkcs7_get_recipient_info(const PKCS7 *p7) +{ + if (PKCS7_type_is_signedAndEnveloped(p7)) + return p7->d.signed_and_enveloped->recipientinfo; + if (PKCS7_type_is_enveloped(p7)) + return p7->d.enveloped->recipientinfo; + return NULL; +} + +/* + * Set up the library context into any loaded structure that needs it. + * i.e loaded X509 objects. + */ +void pkcs7_resolve_libctx(PKCS7 *p7) +{ + int i; + const PKCS7_CTX *ctx = pkcs7_get0_ctx(p7); + STACK_OF(PKCS7_RECIP_INFO) *rinfos = pkcs7_get_recipient_info(p7); + STACK_OF(PKCS7_SIGNER_INFO) *sinfos = PKCS7_get_signer_info(p7); + STACK_OF(X509) *certs = pkcs7_get_signer_certs(p7); + + if (ctx == NULL) + return; + + for (i = 0; i < sk_X509_num(certs); i++) + x509_set0_libctx(sk_X509_value(certs, i), ctx->libctx, ctx->propq); + + for (i = 0; i < sk_PKCS7_RECIP_INFO_num(rinfos); i++) { + PKCS7_RECIP_INFO *ri = sk_PKCS7_RECIP_INFO_value(rinfos, i); + + x509_set0_libctx(ri->cert, ctx->libctx, ctx->propq); + } + + for (i = 0; i < sk_PKCS7_SIGNER_INFO_num(sinfos); i++) { + PKCS7_SIGNER_INFO *si = sk_PKCS7_SIGNER_INFO_value(sinfos, i); + + if (si != NULL) + si->ctx = ctx; + } +} + +const PKCS7_CTX *pkcs7_get0_ctx(const PKCS7 *p7) +{ + return p7 != NULL ? &p7->ctx : NULL; +} + +OPENSSL_CTX *pkcs7_ctx_get0_libctx(const PKCS7_CTX *ctx) +{ + return ctx != NULL ? ctx->libctx : NULL; +} +const char *pkcs7_ctx_get0_propq(const PKCS7_CTX *ctx) +{ + return ctx != NULL ? ctx->propq : NULL; +} + int PKCS7_set_digest(PKCS7 *p7, const EVP_MD *md) { if (PKCS7_type_is_digest(p7)) { @@ -435,6 +502,7 @@ PKCS7_RECIP_INFO *PKCS7_add_recipient(PKCS7 *p7, X509 *x509) goto err; if (!PKCS7_add_recipient_info(p7, ri)) goto err; + ri->ctx = pkcs7_get0_ctx(p7); return ri; err: PKCS7_RECIP_INFO_free(ri); @@ -547,6 +615,7 @@ int PKCS7_set_cipher(PKCS7 *p7, const EVP_CIPHER *cipher) } ec->cipher = cipher; + ec->ctx = pkcs7_get0_ctx(p7); return 1; } diff --git a/crypto/pkcs7/pk7_local.h b/crypto/pkcs7/pk7_local.h new file mode 100644 index 0000000000..b9f9c35340 --- /dev/null +++ b/crypto/pkcs7/pk7_local.h @@ -0,0 +1,14 @@ +/* + * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "crypto/pkcs7.h" + +const PKCS7_CTX *pkcs7_get0_ctx(const PKCS7 *p7); +OPENSSL_CTX *pkcs7_ctx_get0_libctx(const PKCS7_CTX *ctx); +const char *pkcs7_ctx_get0_propq(const PKCS7_CTX *ctx); diff --git a/crypto/pkcs7/pk7_mime.c b/crypto/pkcs7/pk7_mime.c index 6f3981ec6b..2099e8d9ef 100644 --- a/crypto/pkcs7/pk7_mime.c +++ b/crypto/pkcs7/pk7_mime.c @@ -11,6 +11,7 @@ #include "internal/cryptlib.h" #include <openssl/x509.h> #include <openssl/asn1.h> +#include "pk7_local.h" /* PKCS#7 wrappers round generalised stream and MIME routines */ @@ -30,6 +31,8 @@ int SMIME_write_PKCS7(BIO *bio, PKCS7 *p7, BIO *data, int flags) { STACK_OF(X509_ALGOR) *mdalgs; int ctype_nid = OBJ_obj2nid(p7->type); + const PKCS7_CTX *ctx = pkcs7_get0_ctx(p7); + if (ctype_nid == NID_pkcs7_signed) mdalgs = p7->d.sign->md_algs; else @@ -37,12 +40,25 @@ int SMIME_write_PKCS7(BIO *bio, PKCS7 *p7, BIO *data, int flags) flags ^= SMIME_OLDMIME; - return SMIME_write_ASN1(bio, (ASN1_VALUE *)p7, data, flags, - ctype_nid, NID_undef, mdalgs, - ASN1_ITEM_rptr(PKCS7)); + return SMIME_write_ASN1_with_libctx(bio, (ASN1_VALUE *)p7, data, flags, + ctype_nid, NID_undef, mdalgs, + ASN1_ITEM_rptr(PKCS7), + pkcs7_ctx_get0_libctx(ctx), + pkcs7_ctx_get0_propq(ctx)); +} + +PKCS7 *SMIME_read_PKCS7_ex(BIO *bio, BIO **bcont, PKCS7 **p7) +{ + PKCS7 *ret; + + ret = (PKCS7 *)SMIME_read_ASN1_ex(bio, bcont, ASN1_ITEM_rptr(PKCS7), + (ASN1_VALUE **)p7); + if (ret != NULL && p7 != NULL) + pkcs7_resolve_libctx(ret); + return ret; } PKCS7 *SMIME_read_PKCS7(BIO *bio, BIO **bcont) { - return (PKCS7 *)SMIME_read_ASN1(bio, bcont, ASN1_ITEM_rptr(PKCS7)); + return SMIME_read_PKCS7_ex(bio, bcont, NULL); } diff --git a/crypto/pkcs7/pk7_smime.c b/crypto/pkcs7/pk7_smime.c index 385b4af42e..1dfdd69e51 100644 --- a/crypto/pkcs7/pk7_smime.c +++ b/crypto/pkcs7/pk7_smime.c @@ -13,6 +13,7 @@ #include "internal/cryptlib.h" #include <openssl/x509.h> #include <openssl/x509v3.h> +#include "pk7_local.h" #define BUFFERSIZE 4096 @@ -23,14 +24,15 @@ DEFINE_STACK_OF(PKCS7_SIGNER_INFO) static int pkcs7_copy_existing_digest(PKCS7 *p7, PKCS7_SIGNER_INFO *si); -PKCS7 *PKCS7_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs, - BIO *data, int flags) +PKCS7 *PKCS7_sign_with_libctx(X509 *signcert, EVP_PKEY *pkey, + STACK_OF(X509) *certs, BIO *data, int flags, + OPENSSL_CTX *libctx, const char *propq) { PKCS7 *p7; int i; - if ((p7 = PKCS7_new()) == NULL) { - PKCS7err(PKCS7_F_PKCS7_SIGN, ERR_R_MALLOC_FAILURE); + if ((p7 = PKCS7_new_with_libctx(libctx, propq)) == NULL) { + PKCS7err(0, ERR_R_MALLOC_FAILURE); return NULL; } @@ -41,7 +43,7 @@ PKCS7 *PKCS7_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs, goto err; if (pkey && !PKCS7_sign_add_signer(p7, signcert, pkey, NULL, flags)) { - PKCS7err(PKCS7_F_PKCS7_SIGN, PKCS7_R_PKCS7_ADD_SIGNER_ERROR); + PKCS7err(0, PKCS7_R_PKCS7_ADD_SIGNER_ERROR); goto err; } @@ -66,6 +68,13 @@ PKCS7 *PKCS7_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs, return NULL; } +PKCS7 *PKCS7_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs, + BIO *data, int flags) +{ + return PKCS7_sign_with_libctx(signcert, pkey, certs, data, flags, NULL, NULL); +} + + int PKCS7_final(PKCS7 *p7, BIO *data, int flags) { BIO *p7bio; @@ -84,10 +93,8 @@ int PKCS7_final(PKCS7 *p7, BIO *data, int flags) PKCS7err(PKCS7_F_PKCS7_FINAL, PKCS7_R_PKCS7_DATASIGN); goto err; } - ret = 1; - - err: +err: BIO_free_all(p7bio); return ret; @@ -116,6 +123,7 @@ PKCS7_SIGNER_INFO *PKCS7_sign_add_signer(PKCS7 *p7, X509 *signcert, { PKCS7_SIGNER_INFO *si = NULL; STACK_OF(X509_ALGOR) *smcap = NULL; + if (!X509_check_private_key(signcert, pkey)) { PKCS7err(PKCS7_F_PKCS7_SIGN_ADD_SIGNER, PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE); @@ -128,6 +136,7 @@ PKCS7_SIGNER_INFO *PKCS7_sign_add_signer(PKCS7 *p7, X509 *signcert, return NULL; } + si->ctx = pkcs7_get0_ctx(p7); if (!(flags & PKCS7_NOCERTS)) { if (!PKCS7_add_certificate(p7, signcert)) goto err; @@ -162,7 +171,8 @@ PKCS7_SIGNER_INFO *PKCS7_sign_add_signer(PKCS7 *p7, X509 *signcert, if (flags & PKCS7_REUSE_DIGEST) { if (!pkcs7_copy_existing_digest(p7, si)) goto err; - if (!(flags & PKCS7_PARTIAL) && !PKCS7_SIGNER_INFO_sign(si)) + if (!(flags & PKCS7_PARTIAL) + && !PKCS7_SIGNER_INFO_sign(si)) goto err; } } @@ -197,7 +207,7 @@ static int pkcs7_copy_existing_digest(PKCS7 *p7, PKCS7_SIGNER_INFO *si) } - if (osdig) + if (osdig != NULL) return PKCS7_add1_attrib_digest(si, osdig->data, osdig->length); PKCS7err(PKCS7_F_PKCS7_COPY_EXISTING_DIGEST, @@ -217,20 +227,21 @@ int PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store, int i, j = 0, k, ret = 0; BIO *p7bio = NULL; BIO *tmpin = NULL, *tmpout = NULL; + const PKCS7_CTX *p7_ctx; if (p7 == NULL) { - PKCS7err(PKCS7_F_PKCS7_VERIFY, PKCS7_R_INVALID_NULL_POINTER); + PKCS7err(0, PKCS7_R_INVALID_NULL_POINTER); return 0; } if (!PKCS7_type_is_signed(p7)) { - PKCS7err(PKCS7_F_PKCS7_VERIFY, PKCS7_R_WRONG_CONTENT_TYPE); + PKCS7err(0, PKCS7_R_WRONG_CONTENT_TYPE); return 0; } /* Check for no data and no content: no data to verify signature */ if (PKCS7_get_detached(p7) && !indata) { - PKCS7err(PKCS7_F_PKCS7_VERIFY, PKCS7_R_NO_CONTENT); + PKCS7err(0, PKCS7_R_NO_CONTENT); return 0; } @@ -243,7 +254,7 @@ int PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store, * process is different, but the existing PKCs7 verification works. */ if (!PKCS7_get_detached(p7) && indata) { - PKCS7err(PKCS7_F_PKCS7_VERIFY, PKCS7_R_CONTENT_AND_DATA_PRESENT); + PKCS7err(0, PKCS7_R_CONTENT_AND_DATA_PRESENT); return 0; } } @@ -251,17 +262,17 @@ int PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store, sinfos = PKCS7_get_signer_info(p7); if (!sinfos || !sk_PKCS7_SIGNER_INFO_num(sinfos)) { - PKCS7err(PKCS7_F_PKCS7_VERIFY, PKCS7_R_NO_SIGNATURES_ON_DATA); + PKCS7err(0, PKCS7_R_NO_SIGNATURES_ON_DATA |