libressl/0054-cms-add-support-for-using-AEAD-ciphers-in-CMS-files.patch
Mikhail Novosyolov faac7d3eaa Add gost-new patches sponsored by ROSA Linux
TODO: add tests
2020-08-05 12:58:06 +03:00

224 lines
8 KiB
Diff

From c07aac0a0dced669f5291aad98c453f3d47eab10 Mon Sep 17 00:00:00 2001
From: Dmitry Baryshkov <dbaryshkov@gmail.com>
Date: Tue, 7 Apr 2020 16:36:32 +0300
Subject: [PATCH 54/87] cms: add support for using AEAD ciphers in CMS files
Russian standards body has added definition for special unprotected
attribute (id-cms-mac-attr) used together with AEAD ciphers (primarily
CTR-ACKM-OMAC) to store MAC value together with encrypted data.
Sponsored by ROSA Linux
Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
---
src/lib/libcrypto/cms/cms_enc.c | 66 ++++++++++++++++++++++++++-
src/lib/libcrypto/cms/cms_env.c | 15 +++++-
src/lib/libcrypto/cms/cms_lcl.h | 7 ++-
src/lib/libcrypto/cms/cms_lib.c | 8 +++-
src/lib/libcrypto/objects/obj_mac.num | 1 +
src/lib/libcrypto/objects/objects.txt | 1 +
6 files changed, 92 insertions(+), 6 deletions(-)
diff --git a/src/lib/libcrypto/cms/cms_enc.c b/src/lib/libcrypto/cms/cms_enc.c
index fd2df99c6..2b8f9c5b8 100644
--- a/src/lib/libcrypto/cms/cms_enc.c
+++ b/src/lib/libcrypto/cms/cms_enc.c
@@ -68,7 +68,8 @@
/* Return BIO based on EncryptedContentInfo and key */
BIO *
-cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo *ec)
+cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo *ec,
+ STACK_OF(X509_ATTRIBUTE) *unprotectedAttrs)
{
BIO *b;
EVP_CIPHER_CTX *ctx;
@@ -189,6 +190,23 @@ cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo *ec)
ASN1_TYPE_free(calg->parameter);
calg->parameter = NULL;
}
+ } else if (ciph->flags & EVP_CIPH_FLAG_AEAD_CIPHER) {
+ int idx = X509at_get_attr_by_NID(unprotectedAttrs, NID_id_cms_mac_attr, -1);
+ X509_ATTRIBUTE *attr;
+ ASN1_TYPE *type;
+
+ if (idx == -1 ||
+ (attr = X509at_get_attr(unprotectedAttrs, idx)) == NULL ||
+ attr->single != 0 ||
+ sk_ASN1_TYPE_num(attr->value.set) != 1 ||
+ (type = sk_ASN1_TYPE_value(attr->value.set, 0)) == NULL ||
+ type->type != V_ASN1_OCTET_STRING ||
+ !EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG,
+ type->value.octet_string->length,
+ type->value.octet_string->data)) {
+ CMSerror(CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
+ goto err;
+ }
}
ok = 1;
@@ -204,6 +222,43 @@ cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo *ec)
return NULL;
}
+int cms_EncryptedContent_final(CMS_EncryptedContentInfo *ec,
+ BIO *chain, STACK_OF(X509_ATTRIBUTE) **unprotectedAttrs)
+{
+ EVP_CIPHER_CTX *ctx = NULL;
+ BIO *mbio = BIO_find_type(chain, BIO_TYPE_CIPHER);
+
+ if (mbio == NULL) {
+ CMSerror(CMS_R_CONTENT_NOT_FOUND);
+ return 0;
+ }
+
+ BIO_get_cipher_ctx(mbio, &ctx);
+ if (EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER) {
+ unsigned char tag[EVP_MAX_MD_SIZE];
+ int taglen;
+ int nid = EVP_CIPHER_CTX_nid(ctx);
+
+ /* Most of the AEAD ciphers have 16-bit tags except Magma ciphers */
+ if (nid == NID_id_tc26_cipher_gostr3412_2015_magma_ctracpkm_omac ||
+ nid == NID_id_tc26_cipher_gostr3412_2015_magma_mgm)
+ taglen = 8;
+ else
+ taglen = 16;
+
+ if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG,
+ taglen, tag) <= 0) {
+ CMSerror(CMS_R_CTRL_FAILURE);
+ return 0;
+ }
+
+ if (!X509at_add1_attr_by_NID(unprotectedAttrs, NID_id_cms_mac_attr, V_ASN1_OCTET_STRING, tag, taglen))
+ return 0;
+ }
+
+ return 1;
+}
+
int
cms_EncryptedContent_init(CMS_EncryptedContentInfo *ec,
const EVP_CIPHER *cipher, const unsigned char *key, size_t keylen)
@@ -258,5 +313,12 @@ cms_EncryptedData_init_bio(CMS_ContentInfo *cms)
if (enc->encryptedContentInfo->cipher && enc->unprotectedAttrs)
enc->version = 2;
- return cms_EncryptedContent_init_bio(enc->encryptedContentInfo);
+ return cms_EncryptedContent_init_bio(enc->encryptedContentInfo, enc->unprotectedAttrs);
+}
+
+int cms_EncryptedData_final(CMS_ContentInfo *cms, BIO *chain)
+{
+ CMS_EncryptedData *enc = cms->d.encryptedData;
+
+ return cms_EncryptedContent_final(enc->encryptedContentInfo, chain, &enc->unprotectedAttrs);
}
diff --git a/src/lib/libcrypto/cms/cms_env.c b/src/lib/libcrypto/cms/cms_env.c
index 911f7a8a2..f5e9280d4 100644
--- a/src/lib/libcrypto/cms/cms_env.c
+++ b/src/lib/libcrypto/cms/cms_env.c
@@ -927,7 +927,7 @@ cms_EnvelopedData_init_bio(CMS_ContentInfo *cms)
/* Get BIO first to set up key */
ec = cms->d.envelopedData->encryptedContentInfo;
- ret = cms_EncryptedContent_init_bio(ec);
+ ret = cms_EncryptedContent_init_bio(ec, cms->d.envelopedData->unprotectedAttrs);
/* If error or no cipher end of processing */
@@ -960,6 +960,19 @@ cms_EnvelopedData_init_bio(CMS_ContentInfo *cms)
return NULL;
}
+int cms_EnvelopedData_final(CMS_ContentInfo *cms, BIO *chain)
+{
+ CMS_EnvelopedData *env = NULL;
+
+ env = cms_get0_enveloped(cms);
+ if (env == NULL) {
+ CMSerror(CMS_R_CONTENT_TYPE_NOT_ENVELOPED_DATA);
+ return 0;
+ }
+
+ return cms_EncryptedContent_final(env->encryptedContentInfo, chain, &env->unprotectedAttrs);
+}
+
/*
* Get RecipientInfo type (if any) supported by a key (public or private). To
* retain compatibility with previous behaviour if the ctrl value isn't
diff --git a/src/lib/libcrypto/cms/cms_lcl.h b/src/lib/libcrypto/cms/cms_lcl.h
index 8083e5537..fdfd12160 100644
--- a/src/lib/libcrypto/cms/cms_lcl.h
+++ b/src/lib/libcrypto/cms/cms_lcl.h
@@ -442,16 +442,21 @@ int cms_keyid_cert_cmp(ASN1_OCTET_STRING *keyid, X509 *cert);
int cms_set1_ias(CMS_IssuerAndSerialNumber **pias, X509 *cert);
int cms_set1_keyid(ASN1_OCTET_STRING **pkeyid, X509 *cert);
-BIO *cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo *ec);
+BIO *cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo *ec,
+ STACK_OF(X509_ATTRIBUTE) *unprotectedAttrs);
BIO *cms_EncryptedData_init_bio(CMS_ContentInfo *cms);
+int cms_EncryptedData_final(CMS_ContentInfo *cms, BIO *chain);
int cms_EncryptedContent_init(CMS_EncryptedContentInfo *ec,
const EVP_CIPHER *cipher, const unsigned char *key, size_t keylen);
+int cms_EncryptedContent_final(CMS_EncryptedContentInfo *ec,
+ BIO *chain, STACK_OF(X509_ATTRIBUTE) **unprotectedAttrs);
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(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);
diff --git a/src/lib/libcrypto/cms/cms_lib.c b/src/lib/libcrypto/cms/cms_lib.c
index b6580dd6f..787a8f99e 100644
--- a/src/lib/libcrypto/cms/cms_lib.c
+++ b/src/lib/libcrypto/cms/cms_lib.c
@@ -215,12 +215,16 @@ 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_encrypted:
+ return cms_EncryptedData_final(cms, cmsbio);
+
case NID_pkcs7_signed:
return cms_SignedData_final(cms, cmsbio);
diff --git a/src/lib/libcrypto/objects/obj_mac.num b/src/lib/libcrypto/objects/obj_mac.num
index 188349d71..6e494cb92 100644
--- a/src/lib/libcrypto/objects/obj_mac.num
+++ b/src/lib/libcrypto/objects/obj_mac.num
@@ -1020,3 +1020,4 @@ id_tc26_agreement_gost_3410_12_256 1019
id_tc26_agreement_gost_3410_12_512 1020
id_tc26_wrap_gostr3412_2015_magma_kexp15 1021
id_tc26_wrap_gostr3412_2015_kuznyechik_kexp15 1022
+id_cms_mac_attr 1023
diff --git a/src/lib/libcrypto/objects/objects.txt b/src/lib/libcrypto/objects/objects.txt
index 0d2af66ac..3f810dcf8 100644
--- a/src/lib/libcrypto/objects/objects.txt
+++ b/src/lib/libcrypto/objects/objects.txt
@@ -1368,6 +1368,7 @@ brainpool 1 14 : brainpoolP512t1
: gost89-cbc
member-body 643 7 1 : tc26
+tc26 0 6 1 1 : id-cms-mac-attr
!Cname id-tc26-gost3411-2012-256
tc26 1 2 2 : streebog256 : GOST R 34.11-2012 (256 bit)
!Cname id-tc26-gost3411-2012-512
--
2.17.1