From 71434aed0de274abe8f10768c4dd11a5b3b387e4 Mon Sep 17 00:00:00 2001 From: Dmitry Belyavskiy Date: Mon, 20 Jan 2020 18:17:44 +0300 Subject: [PATCH] Implementation of Russian GOST CMS Reviewed-by: Shane Lontis Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/10904) --- apps/cms.c | 49 ++++++++++---- crypto/cms/cms_env.c | 137 ++++++++++++++++++++++++++++++++++----- crypto/cms/cms_kari.c | 93 +++++++++++++++++++++++--- crypto/cms/cms_lib.c | 4 +- crypto/cms/cms_local.h | 7 +- crypto/cms/cms_smime.c | 40 +++++++----- crypto/err/openssl.txt | 4 ++ crypto/evp/pmeth_lib.c | 7 ++ include/openssl/cms.h | 5 ++ include/openssl/cmserr.h | 6 +- include/openssl/evp.h | 9 +++ util/libcrypto.num | 3 + 12 files changed, 307 insertions(+), 57 deletions(-) diff --git a/apps/cms.c b/apps/cms.c index d67116d3fc..9c92e79658 100644 --- a/apps/cms.c +++ b/apps/cms.c @@ -81,10 +81,11 @@ typedef enum OPTION_choice { OPT_PASSIN, OPT_TO, OPT_FROM, OPT_SUBJECT, OPT_SIGNER, OPT_RECIP, OPT_CERTSOUT, OPT_MD, OPT_INKEY, OPT_KEYFORM, OPT_KEYOPT, OPT_RR_FROM, OPT_RR_TO, OPT_AES128_WRAP, OPT_AES192_WRAP, OPT_AES256_WRAP, - OPT_3DES_WRAP, OPT_ENGINE, + OPT_3DES_WRAP, OPT_WRAP, OPT_ENGINE, OPT_R_ENUM, OPT_V_ENUM, - OPT_CIPHER + OPT_CIPHER, + OPT_ORIGINATOR } OPTION_CHOICE; const OPTIONS cms_options[] = { @@ -197,6 +198,7 @@ const OPTIONS cms_options[] = { {"from", OPT_FROM, 's', "From address"}, {"subject", OPT_SUBJECT, 's', "Subject"}, {"signer", OPT_SIGNER, 's', "Signer certificate file"}, + {"originator", OPT_ORIGINATOR, 's', "Originator certificate file"}, {"recip", OPT_RECIP, '<', "Recipient cert file for decryption"}, {"receipt_request_from", OPT_RR_FROM, 's', "Create signed receipt request with specified email address"}, @@ -214,6 +216,7 @@ const OPTIONS cms_options[] = { # ifndef OPENSSL_NO_DES {"des3-wrap", OPT_3DES_WRAP, '-', "Use 3DES-EDE to wrap key"}, # endif + {"wrap", OPT_WRAP, 's', "Any wrap cipher to wrap key"}, OPT_R_OPTIONS, OPT_V_OPTIONS, @@ -236,7 +239,7 @@ int cms_main(int argc, char **argv) STACK_OF(OPENSSL_STRING) *rr_to = NULL, *rr_from = NULL; STACK_OF(OPENSSL_STRING) *sksigners = NULL, *skkeys = NULL; STACK_OF(X509) *encerts = NULL, *other = NULL; - X509 *cert = NULL, *recip = NULL, *signer = NULL; + X509 *cert = NULL, *recip = NULL, *signer = NULL, *originator = NULL; X509_STORE *store = NULL; X509_VERIFY_PARAM *vpm = NULL; char *certfile = NULL, *keyfile = NULL, *contfile = NULL; @@ -244,7 +247,7 @@ int cms_main(int argc, char **argv) char *certsoutfile = NULL; int noCAfile = 0, noCApath = 0, noCAstore = 0; char *infile = NULL, *outfile = NULL, *rctfile = NULL; - char *passinarg = NULL, *passin = NULL, *signerfile = NULL, *recipfile = NULL; + char *passinarg = NULL, *passin = NULL, *signerfile = NULL, *originatorfile = NULL, *recipfile = NULL; char *to = NULL, *from = NULL, *subject = NULL, *prog; cms_key_param *key_first = NULL, *key_param = NULL; int flags = CMS_DETACHED, noout = 0, print = 0, keyidx = -1, vpmtouched = 0; @@ -535,6 +538,9 @@ int cms_main(int argc, char **argv) } signerfile = opt_arg(); break; + case OPT_ORIGINATOR: + originatorfile = opt_arg(); + break; case OPT_INKEY: /* If previous -inkey argument add signer to list */ if (keyfile != NULL) { @@ -629,6 +635,10 @@ int cms_main(int argc, char **argv) case OPT_AES256_WRAP: wrap_cipher = EVP_aes_256_wrap(); break; + case OPT_WRAP: + if (!opt_cipher(opt_unknown(), &wrap_cipher)) + goto end; + break; } } argc = opt_num_rest(); @@ -759,6 +769,14 @@ int cms_main(int argc, char **argv) } } + if (originatorfile != NULL) { + if ((originator = load_cert(originatorfile, FORMAT_PEM, + "originator certificate file")) == NULL) { + ERR_print_errors(bio_err); + goto end; + } + } + if (operation == SMIME_SIGN_RECEIPT) { if ((signer = load_cert(signerfile, FORMAT_PEM, "receipt signer certificate file")) == NULL) { @@ -767,7 +785,7 @@ int cms_main(int argc, char **argv) } } - if (operation == SMIME_DECRYPT) { + if ((operation == SMIME_DECRYPT) || (operation == SMIME_ENCRYPT)) { if (keyfile == NULL) keyfile = recipfile; } else if ((operation == SMIME_SIGN) || (operation == SMIME_SIGN_RECEIPT)) { @@ -877,23 +895,32 @@ int cms_main(int argc, char **argv) for (i = 0; i < sk_X509_num(encerts); i++) { CMS_RecipientInfo *ri; cms_key_param *kparam; - int tflags = flags; + int tflags = flags | CMS_KEY_PARAM; /* This flag enforces allocating the EVP_PKEY_CTX for the recipient here */ + EVP_PKEY_CTX *pctx; X509 *x = sk_X509_value(encerts, i); + int res; + for (kparam = key_first; kparam; kparam = kparam->next) { if (kparam->idx == i) { - tflags |= CMS_KEY_PARAM; break; } } - ri = CMS_add1_recipient_cert(cms, x, tflags); + ri = CMS_add1_recipient(cms, x, key, originator, tflags); if (ri == NULL) goto end; + + pctx = CMS_RecipientInfo_get0_pkey_ctx(ri); if (kparam != NULL) { - EVP_PKEY_CTX *pctx; - pctx = CMS_RecipientInfo_get0_pkey_ctx(ri); if (!cms_set_pkey_param(pctx, kparam->param)) goto end; } + + res = EVP_PKEY_CTX_ctrl(pctx, -1, -1, + EVP_PKEY_CTRL_CIPHER, + EVP_CIPHER_nid(cipher), NULL); + if (res <= 0 && res != -2) + goto end; + if (CMS_RecipientInfo_type(ri) == CMS_RECIPINFO_AGREE && wrap_cipher) { EVP_CIPHER_CTX *wctx; @@ -1039,7 +1066,7 @@ int cms_main(int argc, char **argv) } if (key != NULL) { - if (!CMS_decrypt_set1_pkey(cms, key, recip)) { + if (!CMS_decrypt_set1_pkey_and_peer(cms, key, recip, originator)) { BIO_puts(bio_err, "Error decrypting CMS using private key\n"); goto end; } diff --git a/crypto/cms/cms_env.c b/crypto/cms/cms_env.c index ac34f3efd6..003a406c68 100644 --- a/crypto/cms/cms_env.c +++ b/crypto/cms/cms_env.c @@ -20,6 +20,8 @@ /* CMS EnvelopedData Utilities */ +static void cms_env_set_version(CMS_EnvelopedData *env); + CMS_EnvelopedData *cms_get0_enveloped(CMS_ContentInfo *cms) { if (OBJ_obj2nid(cms->contentType) != NID_pkcs7_enveloped) { @@ -122,6 +124,47 @@ CMS_ContentInfo *CMS_EnvelopedData_create(const EVP_CIPHER *cipher) return NULL; } +int cms_EnvelopedData_final(CMS_ContentInfo *cms, BIO *chain) +{ + CMS_EnvelopedData *env = NULL; + EVP_CIPHER_CTX *ctx = NULL; + BIO *mbio = BIO_find_type(chain, BIO_TYPE_CIPHER); + + env = cms_get0_enveloped(cms); + if (env == NULL) + return 0; + + if (mbio == NULL) { + CMSerr(CMS_F_CMS_ENVELOPEDDATA_FINAL, CMS_R_CONTENT_NOT_FOUND); + return 0; + } + + BIO_get_cipher_ctx(mbio, &ctx); + + /* + * If the selected cipher supports unprotected attributes, + * deal with it using special ctrl function + */ + if (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_CIPHER_WITH_MAC) { + if (cms->d.envelopedData->unprotectedAttrs == NULL) + cms->d.envelopedData->unprotectedAttrs = sk_X509_ATTRIBUTE_new_null(); + + if (cms->d.envelopedData->unprotectedAttrs == NULL) { + CMSerr(CMS_F_CMS_ENVELOPEDDATA_FINAL, ERR_R_MALLOC_FAILURE); + return 0; + } + + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_PROCESS_UNPROTECTED, + 1, env->unprotectedAttrs) <= 0) { + CMSerr(CMS_F_CMS_ENVELOPEDDATA_FINAL, CMS_R_CTRL_FAILURE); + return 0; + } + } + + cms_env_set_version(cms->d.envelopedData); + return 1; +} + /* Key Transport Recipient Info (KTRI) routines */ /* Initialise a ktri based on passed certificate and key */ @@ -176,8 +219,9 @@ static int cms_RecipientInfo_ktri_init(CMS_RecipientInfo *ri, X509 *recip, * Add a recipient certificate using appropriate type of RecipientInfo */ -CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms, - X509 *recip, unsigned int flags) +CMS_RecipientInfo *CMS_add1_recipient(CMS_ContentInfo *cms, X509 *recip, + EVP_PKEY *originatorPrivKey, + X509 *originator, unsigned int flags) { CMS_RecipientInfo *ri = NULL; CMS_EnvelopedData *env; @@ -193,7 +237,7 @@ CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms, pk = X509_get0_pubkey(recip); if (pk == NULL) { - CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT, CMS_R_ERROR_GETTING_PUBLIC_KEY); + CMSerr(CMS_F_CMS_ADD1_RECIPIENT, CMS_R_ERROR_GETTING_PUBLIC_KEY); goto err; } @@ -205,12 +249,12 @@ CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms, break; case CMS_RECIPINFO_AGREE: - if (!cms_RecipientInfo_kari_init(ri, recip, pk, flags)) + if (!cms_RecipientInfo_kari_init(ri, recip, pk, originator, originatorPrivKey, flags)) goto err; break; default: - CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT, + CMSerr(CMS_F_CMS_ADD1_RECIPIENT, CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE); goto err; @@ -222,13 +266,19 @@ CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms, return ri; merr: - CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT, ERR_R_MALLOC_FAILURE); + CMSerr(CMS_F_CMS_ADD1_RECIPIENT, ERR_R_MALLOC_FAILURE); err: M_ASN1_free_of(ri, CMS_RecipientInfo); return NULL; } +CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms, + X509 *recip, unsigned int flags) +{ + return CMS_add1_recipient(cms, recip, NULL, NULL, flags); +} + int CMS_RecipientInfo_ktri_get0_algs(CMS_RecipientInfo *ri, EVP_PKEY **pk, X509 **recip, X509_ALGOR **palg) @@ -894,7 +944,34 @@ static void cms_env_set_version(CMS_EnvelopedData *env) env->version = 0; } -BIO *cms_EnvelopedData_init_bio(const CMS_ContentInfo *cms) +static BIO *cms_EnvelopedData_Decryption_init_bio(CMS_ContentInfo *cms) +{ + CMS_EncryptedContentInfo *ec = cms->d.envelopedData->encryptedContentInfo; + BIO *contentBio = cms_EncryptedContent_init_bio(ec); + EVP_CIPHER_CTX *ctx = NULL; + + if (contentBio == NULL) + return NULL; + + BIO_get_cipher_ctx(contentBio, &ctx); + if (ctx == NULL) { + BIO_free(contentBio); + return NULL; + } +/* + * If the selected cipher supports unprotected attributes, + * deal with it using special ctrl function + */ + if ((EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_CIPHER_WITH_MAC) + && EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_PROCESS_UNPROTECTED, 0, + cms->d.envelopedData->unprotectedAttrs) <= 0) { + BIO_free(contentBio); + return NULL; + } + return contentBio; +} + +static BIO *cms_EnvelopedData_Encryption_init_bio(CMS_ContentInfo *cms) { CMS_EncryptedContentInfo *ec; STACK_OF(CMS_RecipientInfo) *rinfos; @@ -907,22 +984,19 @@ BIO *cms_EnvelopedData_init_bio(const CMS_ContentInfo *cms) ec = cms->d.envelopedData->encryptedContentInfo; ret = cms_EncryptedContent_init_bio(ec); - /* If error or no cipher end of processing */ - - if (!ret || !ec->cipher) + /* If error end of processing */ + if (!ret) return ret; /* Now encrypt content key according to each RecipientInfo type */ - rinfos = cms->d.envelopedData->recipientInfos; for (i = 0; i < sk_CMS_RecipientInfo_num(rinfos); i++) { - ri = sk_CMS_RecipientInfo_value(rinfos, i); - if (CMS_RecipientInfo_encrypt(cms, ri) <= 0) { - CMSerr(CMS_F_CMS_ENVELOPEDDATA_INIT_BIO, - CMS_R_ERROR_SETTING_RECIPIENTINFO); - goto err; - } + ri = sk_CMS_RecipientInfo_value(rinfos, i); + if (CMS_RecipientInfo_encrypt(cms, ri) <= 0) { + CMSerr(0, CMS_R_ERROR_SETTING_RECIPIENTINFO); + goto err; + } } cms_env_set_version(cms->d.envelopedData); @@ -937,7 +1011,17 @@ BIO *cms_EnvelopedData_init_bio(const CMS_ContentInfo *cms) return ret; BIO_free(ret); return NULL; +} + +BIO *cms_EnvelopedData_init_bio(CMS_ContentInfo *cms) +{ + if (cms->d.envelopedData->encryptedContentInfo->cipher != NULL) { + /* If cipher is set it's encryption */ + return cms_EnvelopedData_Encryption_init_bio(cms); + } + /* If cipher is not set it's decryption */ + return cms_EnvelopedData_Decryption_init_bio(cms); } /* @@ -955,3 +1039,22 @@ int cms_pkey_get_ri_type(EVP_PKEY *pk) } return CMS_RECIPINFO_TRANS; } + +int cms_pkey_is_ri_type_supported(EVP_PKEY *pk, int ri_type) +{ + int supportedRiType; + + if (pk->ameth != NULL && pk->ameth->pkey_ctrl != NULL) { + int i, r; + + i = pk->ameth->pkey_ctrl(pk, ASN1_PKEY_CTRL_CMS_IS_RI_TYPE_SUPPORTED, ri_type, &r); + if (i > 0) + return r; + } + + supportedRiType = cms_pkey_get_ri_type(pk); + if (supportedRiType < 0) + return 0; + + return (supportedRiType == ri_type); +} diff --git a/crypto/cms/cms_kari.c b/crypto/cms/cms_kari.c index 6b0a59ebde..3299e9b5f5 100644 --- a/crypto/cms/cms_kari.c +++ b/crypto/cms/cms_kari.c @@ -152,7 +152,7 @@ int CMS_RecipientEncryptedKey_cert_cmp(CMS_RecipientEncryptedKey *rek, return -1; } -int CMS_RecipientInfo_kari_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pk) +int CMS_RecipientInfo_kari_set0_pkey_and_peer(CMS_RecipientInfo *ri, EVP_PKEY *pk, X509 *peer) { EVP_PKEY_CTX *pctx; CMS_KeyAgreeRecipientInfo *kari = ri->d.kari; @@ -161,9 +161,18 @@ int CMS_RecipientInfo_kari_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pk) kari->pctx = NULL; if (pk == NULL) return 1; + pctx = EVP_PKEY_CTX_new(pk, NULL); if (pctx == NULL || EVP_PKEY_derive_init(pctx) <= 0) goto err; + + if (peer != NULL) { + EVP_PKEY *pub_pkey = X509_get0_pubkey(peer); + + if (EVP_PKEY_derive_set_peer(pctx, pub_pkey) <= 0) + goto err; + } + kari->pctx = pctx; return 1; err: @@ -171,6 +180,11 @@ int CMS_RecipientInfo_kari_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pk) return 0; } +int CMS_RecipientInfo_kari_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pk) +{ + return CMS_RecipientInfo_kari_set0_pkey_and_peer(ri, pk, NULL); +} + EVP_CIPHER_CTX *CMS_RecipientInfo_kari_get0_ctx(CMS_RecipientInfo *ri) { if (ri->type == CMS_RECIPINFO_AGREE) @@ -283,10 +297,29 @@ static int cms_kari_create_ephemeral_key(CMS_KeyAgreeRecipientInfo *kari, return rv; } +/* Set originator private key and initialise context based on it */ +static int cms_kari_set_originator_private_key(CMS_KeyAgreeRecipientInfo *kari, EVP_PKEY *originatorPrivKey ) +{ + EVP_PKEY_CTX *pctx = NULL; + int rv = 0; + + pctx = EVP_PKEY_CTX_new(originatorPrivKey, NULL); + if (pctx == NULL) + goto err; + if (EVP_PKEY_derive_init(pctx) <= 0) + goto err; + + kari->pctx = pctx; + rv = 1; + err: + if (rv == 0) + EVP_PKEY_CTX_free(pctx); + return rv; +} + /* Initialise a kari based on passed certificate and key */ -int cms_RecipientInfo_kari_init(CMS_RecipientInfo *ri, X509 *recip, - EVP_PKEY *pk, unsigned int flags) +int cms_RecipientInfo_kari_init(CMS_RecipientInfo *ri, X509 *recip, EVP_PKEY *recipPubKey, X509 * originator, EVP_PKEY *originatorPrivKey, unsigned int flags) { CMS_KeyAgreeRecipientInfo *kari; CMS_RecipientEncryptedKey *rek = NULL; @@ -321,12 +354,36 @@ int cms_RecipientInfo_kari_init(CMS_RecipientInfo *ri, X509 *recip, return 0; } - /* Create ephemeral key */ - if (!cms_kari_create_ephemeral_key(kari, pk)) - return 0; + if (originatorPrivKey == NULL && originator == NULL) { + /* Create ephemeral key */ + if (!cms_kari_create_ephemeral_key(kari, recipPubKey)) + return 0; + } else { + /* Use originator key */ + CMS_OriginatorIdentifierOrKey *oik = ri->d.kari->originator; + + if (originatorPrivKey == NULL && originator == NULL) + return 0; + + if (flags & CMS_USE_ORIGINATOR_KEYID) { + oik->type = CMS_OIK_KEYIDENTIFIER; + oik->d.subjectKeyIdentifier = ASN1_OCTET_STRING_new(); + if (oik->d.subjectKeyIdentifier == NULL) + return 0; + if (!cms_set1_keyid(&oik->d.subjectKeyIdentifier, originator)) + return 0; + } else { + oik->type = CMS_REK_ISSUER_SERIAL; + if (!cms_set1_ias(&oik->d.issuerAndSerialNumber, originator)) + return 0; + } + + if (!cms_kari_set_originator_private_key(kari, originatorPrivKey)) + return 0; + } - EVP_PKEY_up_ref(pk); - rek->pkey = pk; + EVP_PKEY_up_ref(recipPubKey); + rek->pkey = recipPubKey; return 1; } @@ -336,14 +393,30 @@ static int cms_wrap_init(CMS_KeyAgreeRecipientInfo *kari, EVP_CIPHER_CTX *ctx = kari->ctx; const EVP_CIPHER *kekcipher; int keylen = EVP_CIPHER_key_length(cipher); + int ret; + /* If a suitable wrap algorithm is already set nothing to do */ kekcipher = EVP_CIPHER_CTX_cipher(ctx); - - if (kekcipher) { + if (kekcipher != NULL) { if (EVP_CIPHER_CTX_mode(ctx) != EVP_CIPH_WRAP_MODE) return 0; return 1; } + else if (cipher != NULL + && (EVP_CIPHER_flags(cipher) & EVP_CIPH_FLAG_GET_WRAP_CIPHER)) { + ret = EVP_CIPHER_meth_get_ctrl(cipher)(NULL, EVP_CTRL_GET_WRAP_CIPHER, + 0, &kekcipher); + if (ret <= 0) + return 0; + + if (kekcipher != NULL) { + if (EVP_CIPHER_mode(kekcipher) != EVP_CIPH_WRAP_MODE) + return 0; + + return EVP_EncryptInit_ex(ctx, kekcipher, NULL, NULL, NULL); + } + } + /* * Pick a cipher based on content encryption cipher. If it is DES3 use * DES3 wrap otherwise use AES wrap similar to key size. diff --git a/crypto/cms/cms_lib.c b/crypto/cms/cms_lib.c index 245544e3e9..15aba4af52 100644 --- a/crypto/cms/cms_lib.c +++ b/crypto/cms/cms_lib.c @@ -133,12 +133,14 @@ int CMS_dataFinal(CMS_ContentInfo *cms, BIO *cmsbio) switch (OBJ_obj2nid(cms->contentType)) { case NID_pkcs7_data: - case NID_pkcs7_enveloped: case NID_pkcs7_encrypted: case NID_id_smime_ct_compressedData: /* Nothing to do */ return 1; + case NID_pkcs7_enveloped: + return cms_EnvelopedData_final(cms, cmsbio); + case NID_pkcs7_signed: return cms_SignedData_final(cms, cmsbio); diff --git a/crypto/cms/cms_local.h b/crypto/cms/cms_local.h index 6cb31955eb..46956a0947 100644 --- a/crypto/cms/cms_local.h +++ b/crypto/cms/cms_local.h @@ -402,13 +402,16 @@ int cms_Receipt_verify(CMS_ContentInfo *cms, CMS_ContentInfo *req_cms); int cms_msgSigDigest_add1(CMS_SignerInfo *dest, CMS_SignerInfo *src); ASN1_OCTET_STRING *cms_encode_Receipt(CMS_SignerInfo *si); -BIO *cms_EnvelopedData_init_bio(const CMS_ContentInfo *cms); +BIO *cms_EnvelopedData_init_bio(CMS_ContentInfo *cms); +int cms_EnvelopedData_final(CMS_ContentInfo *cms, BIO *chain); CMS_EnvelopedData *cms_get0_enveloped(CMS_ContentInfo *cms); int cms_env_asn1_ctrl(CMS_RecipientInfo *ri, int cmd); int cms_pkey_get_ri_type(EVP_PKEY *pk); +int cms_pkey_is_ri_type_supported(EVP_PKEY *pk, int ri_type); /* KARI routines */ int cms_RecipientInfo_kari_init(CMS_RecipientInfo *ri, X509 *recip, - EVP_PKEY *pk, unsigned int flags); + EVP_PKEY *recipPubKey, X509 *originator, + EVP_PKEY *originatorPrivKey, unsigned int flags); int cms_RecipientInfo_kari_encrypt(const CMS_ContentInfo *cms, CMS_RecipientInfo *ri); diff --git a/crypto/cms/cms_smime.c b/crypto/cms/cms_smime.c index 4ae85c0335..d5112a83ea 100644 --- a/crypto/cms/cms_smime.c +++ b/crypto/cms/cms_smime.c @@ -576,19 +576,20 @@ CMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *data, return NULL; } -static int cms_kari_set1_pkey(CMS_ContentInfo *cms, CMS_RecipientInfo *ri, - EVP_PKEY *pk, X509 *cert) +static int cms_kari_set1_pkey_and_peer(CMS_ContentInfo *cms, CMS_RecipientInfo *ri, + EVP_PKEY *pk, X509 *cert, X509 *peer) { int i; STACK_OF(CMS_RecipientEncryptedKey) *reks; CMS_RecipientEncryptedKey *rek; + reks = CMS_RecipientInfo_kari_get0_reks(ri); for (i = 0; i < sk_CMS_RecipientEncryptedKey_num(reks); i++) { int rv; rek = sk_CMS_RecipientEncryptedKey_value(reks, i); if (cert != NULL && CMS_RecipientEncryptedKey_cert_cmp(rek, cert)) continue; - CMS_RecipientInfo_kari_set0_pkey(ri, pk); + CMS_RecipientInfo_kari_set0_pkey_and_peer(ri, pk, peer); rv = CMS_RecipientInfo_kari_decrypt(cms, ri, rek); CMS_RecipientInfo_kari_set0_pkey(ri, NULL); if (rv > 0) @@ -599,28 +600,37 @@ static int cms_kari_set1_pkey(CMS_ContentInfo *cms, CMS_RecipientInfo *ri, } int CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert) +{ + return CMS_decrypt_set1_pkey_and_peer(cms, pk, cert, NULL); +} + +int CMS_decrypt_set1_pkey_and_peer(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert, X509 *peer) { STACK_OF(CMS_RecipientInfo) *ris; CMS_RecipientInfo *ri; - int i, r, ri_type; + int i, r, cms_pkey_ri_type; int debug = 0, match_ri = 0; ris = CMS_get0_RecipientInfos(cms); if (ris) debug = cms->d.envelopedData->encryptedContentInfo->debug; - ri_type = cms_pkey_get_ri_type(pk); - if (ri_type == CMS_RECIPINFO_NONE) { - CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY, - CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE); - return 0; + + cms_pkey_ri_type = cms_pkey_get_ri_type(pk); + if (cms_pkey_ri_type == CMS_RECIPINFO_NONE) { + CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY_AND_PEER, + CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE); + return 0; } for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) { + int ri_type; + ri = sk_CMS_RecipientInfo_value(ris, i); - if (CMS_RecipientInfo_type(ri) != ri_type) + ri_type = CMS_RecipientInfo_type(ri); + if (!cms_pkey_is_ri_type_supported(pk, ri_type)) continue; match_ri = 1; if (ri_type == CMS_RECIPINFO_AGREE) { - r = cms_kari_set1_pkey(cms, ri, pk, cert); + r = cms_kari_set1_pkey_and_peer(cms, ri, pk, cert, peer); if (r > 0) return 1; if (r < 0) @@ -646,7 +656,7 @@ int CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert) } if (r > 0) return 1; - CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY, CMS_R_DECRYPT_ERROR); + CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY_AND_PEER, CMS_R_DECRYPT_ERROR); return 0; } /* @@ -654,17 +664,17 @@ int CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert) * successful decrypt. Always attempt to decrypt all recipients * to avoid leaking timing of a successful decrypt. */ - else if (r > 0 && debug) + else if (r > 0 && (debug || cms_pkey_ri_type != CMS_RECIPINFO_TRANS)) return 1; } } /* If no cert, key transport and not debugging always return success */ - if (cert == NULL && ri_type == CMS_RECIPINFO_TRANS && match_ri && !debug) { + if (cert == NULL && cms_pkey_ri_type == CMS_RECIPINFO_TRANS && match_ri && !debug) { ERR_clear_error(); return 1; } - CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY, CMS_R_NO_MATCHING_RECIPIENT); + CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY_AND_PEER, CMS_R_NO_MATCHING_RECIPIENT); return 0; } diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index 0a37d5af23..f14acc65b6 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -243,6 +243,7 @@ CMS_F_CMS_ADD0_CERT:164:CMS_add0_cert CMS_F_CMS_ADD0_RECIPIENT_KEY:100:CMS_add0_recipient_key CMS_F_CMS_ADD0_RECIPIENT_PASSWORD:165:CMS_add0_recipient_password CMS_F_CMS_ADD1_RECEIPTREQUEST:158:CMS_add1_ReceiptRequest +CMS_F_CMS_ADD1_RECIPIENT:184: CMS_F_CMS_ADD1_RECIPIENT_CERT:101:CMS_add1_recipient_cert CMS_F_CMS_ADD1_SIGNER:102:CMS_add1_signer CMS_F_CMS_ADD1_SIGNINGTIME:103:cms_add1_signingTime @@ -260,6 +261,7 @@ CMS_F_CMS_DECRYPT:112:CMS_decrypt CMS_F_CMS_DECRYPT_SET1_KEY:113:CMS_decrypt_set1_key CMS_F_CMS_DECRYPT_SET1_PASSWORD:166:CMS_decrypt_set1_password CMS_F_CMS_DECRYPT_SET1_PKEY:114:CMS_decrypt_set1_pkey +CMS_F_CMS_DECRYPT_SET1_PKEY_AND_PEER:185: CMS_F_CMS_DIGESTALGORITHM_FIND_CTX:115:cms_DigestAlgorithm_find_ctx CMS_F_CMS_DIGESTALGORITHM_INIT_BIO:116:cms_DigestAlgorithm_init_bio CMS_F_CMS_DIGESTEDDATA_DO_FINAL:117:cms_DigestedData_do_final @@ -272,6 +274,8 @@ CMS_F_CMS_ENCRYPTEDDATA_DECRYPT:121:CMS_EncryptedData_decrypt CMS_F_CMS_ENCRYPTEDDATA_ENCRYPT:122:CMS_EncryptedData_encrypt CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY:123:CMS_EncryptedData_set1_key CMS_F_CMS_ENVELOPEDDATA_CREATE:124:CMS_EnvelopedData_create +CMS_F_CMS_ENVELOPEDDATA_ENCRYPTION_INIT_BIO:186: +CMS_F_CMS_ENVELOPEDDATA_FINAL:187: CMS_F_CMS_ENVELOPEDDATA_INIT_BIO:125:cms_EnvelopedData_init_bio CMS_F_CMS_ENVELOPED_DATA_INIT:126:cms_enveloped_data_init CMS_F_CMS_ENV_ASN1_CTRL:171:cms_env_asn1_ctrl diff --git a/crypto/evp/pmeth_lib.c b/crypto/evp/pmeth_lib.c index c82a543857..c42897c87d 100644 --- a/crypto/evp/pmeth_lib.c +++ b/crypto/evp/pmeth_lib.c @@ -774,6 +774,13 @@ int EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) static int legacy_ctrl_to_param(EVP_PKEY_CTX *ctx, int keytype, int optype, int cmd, int p1, void *p2) { + /* + * GOST CMS format is different for different cipher algorithms. + * Most of other algorithms don't have such a difference + * so this ctrl is just ignored. + */ + if (cmd == EVP_PKEY_CTRL_CIPHER) + return -2; # ifndef OPENSSL_NO_DH if (keytype == EVP_PKEY_DH) { switch (cmd) { diff --git a/include/openssl/cms.h b/include/openssl/cms.h index 1d502fa457..5f66e6df4b 100644 --- a/include/openssl/cms.h +++ b/include/openssl/cms.h @@ -80,6 +80,7 @@ DECLARE_ASN1_PRINT_FUNCTION(CMS_ContentInfo) # define CMS_KEY_PARAM 0x40000 # define CMS_ASCIICRLF 0x80000 # define CMS_CADES 0x100000 +# define CMS_USE_ORIGINATOR_KEYID 0x200000 const ASN1_OBJECT *CMS_get0_type(const CMS_ContentInfo *cms); @@ -150,6 +151,7 @@ int CMS_decrypt(CMS_ContentInfo *cms, EVP_PKEY *pkey, X509 *cert, BIO *dcont, BIO *out, unsigned int flags); int CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert); +int CMS_decrypt_set1_pkey_and_peer(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert, X509 *peer); int CMS_decrypt_set1_key(CMS_ContentInfo *cms, unsigned char *key, size_t keylen, const unsigned char *id, size_t idlen); @@ -162,6 +164,8 @@ EVP_PKEY_CTX *CMS_RecipientInfo_get0_pkey_ctx(CMS_RecipientInfo *ri); CMS_ContentInfo *CMS_EnvelopedData_create(const EVP_CIPHER *cipher); CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms, X509 *recip, unsigned int flags); +CMS_RecipientInfo *CMS_add1_recipient(CMS_ContentInfo *cms, X509 *recip, + EVP_PKEY *originatorPrivKey, X509 * originator, unsigned int flags); int CMS_RecipientInfo_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pkey); int CMS_RecipientInfo_ktri_cert_cmp(CMS_RecipientInfo *ri, X509 *cert); int CMS_RecipientInfo_ktri_get0_algs(CMS_RecipientInfo *ri, @@ -326,6 +330,7 @@ int CMS_RecipientEncryptedKey_get0_id(CMS_RecipientEncryptedKey *rek, int CMS_RecipientEncryptedKey_cert_cmp(CMS_RecipientEncryptedKey *rek, X509 *cert); int CMS_RecipientInfo_kari_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pk); +int CMS_RecipientInfo_kari_set0_pkey_and_peer(CMS_RecipientInfo *ri, EVP_PKEY *pk, X509 *peer); EVP_CIPHER_CTX *CMS_RecipientInfo_kari_get0_ctx(CMS_RecipientInfo *ri); int CMS_RecipientInfo_kari_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri, diff --git a/include/openssl/cmserr.h b/include/openssl/cmserr.h index 10e0fd6ae8..494ae6191a 100644 --- a/include/openssl/cmserr.h +++ b/include/openssl/cmserr.h @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-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 @@ -39,6 +39,7 @@ int ERR_load_CMS_strings(void); # define CMS_F_CMS_ADD0_RECIPIENT_KEY 0 # define CMS_F_CMS_ADD0_RECIPIENT_PASSWORD 0 # define CMS_F_CMS_ADD1_RECEIPTREQUEST 0 +# define CMS_F_CMS_ADD1_RECIPIENT 0 # define CMS_F_CMS_ADD1_RECIPIENT_CERT 0 # define CMS_F_CMS_ADD1_SIGNER 0 # define CMS_F_CMS_ADD1_SIGNINGTIME 0 @@ -56,6 +57,7 @@ int ERR_load_CMS_strings(void); # define CMS_F_CMS_DECRYPT_SET1_KEY 0 # define CMS_F_CMS_DECRYPT_SET1_PASSWORD 0 # define CMS_F_CMS_DECRYPT_SET1_PKEY 0 +# define CMS_F_CMS_DECRYPT_SET1_PKEY_AND_PEER 0 # define CMS_F_CMS_DIGESTALGORITHM_FIND_CTX 0 # define CMS_F_CMS_DIGESTALGORITHM_INIT_BIO 0 # define CMS_F_CMS_DIGESTEDDATA_DO_FINAL 0 @@ -68,6 +70,8 @@ int ERR_load_CMS_strings(void); # define CMS_F_CMS_ENCRYPTEDDATA_ENCRYPT 0 # define CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY 0 # define CMS_F_CMS_ENVELOPEDDATA_CREATE 0 +# define CMS_F_CMS_ENVELOPEDDATA_ENCRYPTION_INIT_BIO 0 +# define CMS_F_CMS_ENVELOPEDDATA_FINAL 0 # define CMS_F_CMS_ENVELOPEDDATA_INIT_BIO 0 # define CMS_F_CMS_ENVELOPED_DATA_INIT 0 # define CMS_F_CMS_ENV_ASN1_CTRL 0 diff --git a/include/openssl/evp.h b/include/openssl/evp.h index 7aa56b3e93..202675cc70 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -294,6 +294,10 @@ int (*EVP_CIPHER_meth_get_ctrl(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *, # define EVP_CIPH_FLAG_PIPELINE 0X800000 /* For provider implementations that handle ASN1 get/set param themselves */ # define EVP_CIPH_FLAG_CUSTOM_ASN1 0x1000000 +/* For ciphers generating unprotected CMS attributes */ +# define EVP_CIPH_FLAG_CIPHER_WITH_MAC 0x2000000 +/* For supplementary wrap cipher support */ +# define EVP_CIPH_FLAG_GET_WRAP_CIPHER 0x4000000 /* * Cipher context flag to indicate we can handle wrap mode: if allowed in @@ -372,6 +376,10 @@ int (*EVP_CIPHER_meth_get_ctrl(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *, # define EVP_CTRL_GET_IV 0x26 /* Tell the cipher it's doing a speed test (SIV disallows multiple ops) */ # define EVP_CTRL_SET_SPEED 0x27 +/* Get the unprotectedAttrs from cipher ctx */ +# define EVP_CTRL_PROCESS_UNPROTECTED 0x28 +/* Get the supplementary wrap cipher */ +#define EVP_CTRL_GET_WRAP_CIPHER 0x29 /* Padding modes */ #define EVP_PADDING_PKCS7 1 @@ -1259,6 +1267,7 @@ int EVP_PBE_get(int *ptype, int *ppbe_nid, size_t num); # define ASN1_PKEY_CTRL_SET1_TLS_ENCPT 0x9 # define ASN1_PKEY_CTRL_GET1_TLS_ENCPT 0xa # define ASN1_PKEY_CTRL_SUPPORTS_MD_NID 0xb +# define ASN1_PKEY_CTRL_CMS_IS_RI_TYPE_SUPPORTED 0xc int EVP_PKEY_asn1_get_count(void); const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_get0(int idx); diff --git a/util/libcrypto.num b/util/libcrypto.num index fa220d873f..8334b99361 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -4912,6 +4912,9 @@ ASN1_GENERALIZEDTIME_dup ? 3_0_0 EXIST::FUNCTION: RAND_priv_bytes_ex ? 3_0_0 EXIST::FUNCTION: RAND_bytes_ex ? 3_0_0 EXIST::FUNCTION: EVP_PKEY_get_default_digest_name ? 3_0_0 EXIST::FUNCTION: +CMS_decrypt_set1_pkey_and_peer ? 3_0_0 EXIST::FUNCTION:CMS +CMS_add1_recipient ? 3_0_0 EXIST::FUNCTION:CMS +CMS_RecipientInfo_kari_set0_pkey_and_peer ? 3_0_0 EXIST::FUNCTION:CMS PKCS8_pkey_add1_attr ? 3_0_0 EXIST::FUNCTION: PKCS8_pkey_add1_attr_by_OBJ ? 3_0_0 EXIST::FUNCTION: EVP_PKEY_private_check ? 3_0_0 EXIST::FUNCTION: -- 2.34.1