summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Belyavskiy <beldmit@gmail.com>2020-01-20 18:17:44 +0300
committerDmitry Belyavskiy <beldmit@gmail.com>2020-03-03 16:34:40 +0300
commit71434aed0de274abe8f10768c4dd11a5b3b387e4 (patch)
tree3603b2e31c1b29a09990d028b0d9390b7a5a9fa5
parent88398d2a358fe41e33c61ac02f23ffaeacddcff0 (diff)
Implementation of Russian GOST CMS
Reviewed-by: Shane Lontis <shane.lontis@oracle.com> Reviewed-by: Paul Dale <paul.dale@oracle.com> (Merged from https://github.com/openssl/openssl/pull/10904)
-rw-r--r--apps/cms.c49
-rw-r--r--crypto/cms/cms_env.c137
-rw-r--r--crypto/cms/cms_kari.c93
-rw-r--r--crypto/cms/cms_lib.c4
-rw-r--r--crypto/cms/cms_local.h7
-rw-r--r--crypto/cms/cms_smime.c40
-rw-r--r--crypto/err/openssl.txt4
-rw-r--r--crypto/evp/pmeth_lib.c7
-rw-r--r--include/openssl/cms.h5
-rw-r--r--include/openssl/cmserr.h6
-rw-r--r--include/openssl/evp.h9
-rw-r--r--util/libcrypto.num3
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)
@@ -600,27 +601,36 @@ 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