Implementation of Russian GOST CMS
authorDmitry Belyavskiy <beldmit@gmail.com>
Mon, 20 Jan 2020 15:17:44 +0000 (18:17 +0300)
committerDmitry Belyavskiy <beldmit@gmail.com>
Tue, 3 Mar 2020 13:34:40 +0000 (16:34 +0300)
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)

12 files changed:
apps/cms.c
crypto/cms/cms_env.c
crypto/cms/cms_kari.c
crypto/cms/cms_lib.c
crypto/cms/cms_local.h
crypto/cms/cms_smime.c
crypto/err/openssl.txt
crypto/evp/pmeth_lib.c
include/openssl/cms.h
include/openssl/cmserr.h
include/openssl/evp.h
util/libcrypto.num

index d67116d..9c92e79 100644 (file)
@@ -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;
             }
index ac34f3e..003a406 100644 (file)
@@ -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);
+}
index 6b0a59e..3299e9b 100644 (file)
@@ -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.
index 245544e..15aba4a 100644 (file)
@@ -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);
 
index 6cb3195..46956a0 100644 (file)
@@ -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);
 
index 4ae85c0..d5112a8 100644 (file)
@@ -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;
 
 }
index 0a37d5a..f14acc6 100644 (file)
@@ -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
index c82a543..c42897c 100644 (file)
@@ -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) {
index 1d502fa..5f66e6d 100644 (file)
@@ -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,
index 10e0fd6..494ae61 100644 (file)
@@ -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
index 7aa56b3..202675c 100644 (file)
@@ -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);
index fa220d8..8334b99 100644 (file)
@@ -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: