libressl/0053-gost-add-support-for-CMS-and-SMIME-enveloped-files.patch

350 lines
11 KiB
Diff
Raw Normal View History

From 39697551e90ec5c96552de4d4666ec00b579dcce Mon Sep 17 00:00:00 2001
From: Dmitry Baryshkov <dbaryshkov@gmail.com>
Date: Sun, 5 Apr 2020 22:58:24 +0300
Subject: [PATCH 53/87] gost: add support for CMS and SMIME enveloped files
Add support for CMS and SMIME files using GOST R 34.10-2012 keys and
GOST R 34.12-2015 (Magma and Kuznyechik) algorithms.
Sponsored by ROSA Linux
Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
---
src/lib/libcrypto/cms/cms_env.c | 2 +-
src/lib/libcrypto/gost/gost_locl.h | 2 +
src/lib/libcrypto/gost/gostr341001_ameth.c | 154 +++++++++++++++++++--
src/lib/libcrypto/gost/gostr341001_pmeth.c | 13 ++
src/lib/libcrypto/objects/obj_mac.num | 4 +
src/lib/libcrypto/objects/objects.txt | 6 +
src/lib/libcrypto/pkcs7/pk7_doit.c | 6 +-
7 files changed, 168 insertions(+), 19 deletions(-)
diff --git a/src/lib/libcrypto/cms/cms_env.c b/src/lib/libcrypto/cms/cms_env.c
index 74d957eee..911f7a8a2 100644
--- a/src/lib/libcrypto/cms/cms_env.c
+++ b/src/lib/libcrypto/cms/cms_env.c
@@ -386,7 +386,7 @@ cms_RecipientInfo_ktri_encrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri)
}
if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_ENCRYPT,
- EVP_PKEY_CTRL_CMS_ENCRYPT, 0, ri) <= 0) {
+ EVP_PKEY_CTRL_CMS_ENCRYPT, EVP_CIPHER_type(ec->cipher), ri) <= 0) {
CMSerror(CMS_R_CTRL_ERROR);
goto err;
}
diff --git a/src/lib/libcrypto/gost/gost_locl.h b/src/lib/libcrypto/gost/gost_locl.h
index 13e9fd459..1cdc18db9 100644
--- a/src/lib/libcrypto/gost/gost_locl.h
+++ b/src/lib/libcrypto/gost/gost_locl.h
@@ -123,6 +123,8 @@ extern BIGNUM *GOST_le2bn(const unsigned char *buf, size_t len, BIGNUM *bn);
extern int GOST_bn2le(BIGNUM *bn, unsigned char *buf, int len);
extern int gost01_VKO_key(EVP_PKEY *pub_key, EVP_PKEY *priv_key, const unsigned char *ukm,
unsigned int ukm_len, int ukm_be, int out_nid, unsigned char *key);
+extern int gost01_smime_encrypt(EVP_PKEY_CTX *ctx, X509_ALGOR *alg, int nid);
+extern int gost01_smime_decrypt(EVP_PKEY_CTX *pctx, X509_ALGOR *alg);
/* GOST R 34.10 parameters */
extern int GostR3410_get_md_digest(int nid);
diff --git a/src/lib/libcrypto/gost/gostr341001_ameth.c b/src/lib/libcrypto/gost/gostr341001_ameth.c
index 2efb001fc..965b36237 100644
--- a/src/lib/libcrypto/gost/gostr341001_ameth.c
+++ b/src/lib/libcrypto/gost/gostr341001_ameth.c
@@ -193,6 +193,41 @@ err:
return params;
}
+static ASN1_STRING *
+encode_gost01_kexp_params(EVP_PKEY *pkey)
+{
+ int digest = GOST_KEY_get_digest(pkey->pkey.gost);
+ ASN1_STRING *params = ASN1_STRING_new();
+ X509_ALGOR p;
+
+ if (params == NULL) {
+ GOSTerror(ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ switch (digest) {
+ case NID_id_tc26_gost3411_2012_256:
+ p.algorithm = OBJ_nid2obj(NID_id_tc26_agreement_gost_3410_12_256);
+ break;
+ case NID_id_tc26_gost3411_2012_512:
+ p.algorithm = OBJ_nid2obj(NID_id_tc26_agreement_gost_3410_12_512);
+ break;
+ default:
+ GOSTerror(ERR_R_INTERNAL_ERROR);
+ break;
+ }
+ p.parameter = NULL;
+
+ params->length = i2d_X509_ALGOR(&p, &params->data);
+ params->type = V_ASN1_SEQUENCE;
+
+ return params;
+err:
+ ASN1_STRING_free(params);
+ params = NULL;
+ return NULL;
+}
+
static int
pub_cmp_gost01(const EVP_PKEY *a, const EVP_PKEY *b)
{
@@ -772,10 +807,110 @@ param_cmp_gost01(const EVP_PKEY *a, const EVP_PKEY *b)
return 1;
}
+int gost01_smime_decrypt(EVP_PKEY_CTX *pctx, X509_ALGOR *alg)
+{
+ int nid = OBJ_obj2nid(alg->algorithm);
+ int format;
+
+ switch (nid) {
+ case NID_id_GostR3410_2001:
+ /* Nothing to do */
+ return 1;
+ case NID_id_tc26_wrap_gostr3412_2015_magma_kexp15:
+ format = GOST_ENC_FORMAT_PSKEY_MAGMA;
+ break;
+ case NID_id_tc26_wrap_gostr3412_2015_kuznyechik_kexp15:
+ format = GOST_ENC_FORMAT_PSKEY_KUZNYECHIK;
+ break;
+ default:
+ GOSTerror(GOST_R_BAD_KEY_PARAMETERS_FORMAT);
+ return 0;
+ }
+ if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DECRYPT,
+ EVP_PKEY_CTRL_GOST_ENC_FORMAT,
+ format, NULL) <= 0) {
+ GOSTerror(ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ return 1;
+}
+
+int gost01_smime_encrypt(EVP_PKEY_CTX *ctx, X509_ALGOR *alg, int enc_nid)
+{
+ EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx);
+ int digest, nid, format;
+ ASN1_STRING *params;
+
+ switch (enc_nid) {
+ case NID_id_Gost28147_89:
+ format = GOST_ENC_FORMAT_4490;
+ nid = NID_id_GostR3410_2001;
+ break;
+ case NID_id_tc26_cipher_gostr3412_2015_magma_ctracpkm:
+ case NID_id_tc26_cipher_gostr3412_2015_magma_ctracpkm_omac:
+ format = GOST_ENC_FORMAT_PSKEY_MAGMA;
+ nid = NID_id_tc26_wrap_gostr3412_2015_magma_kexp15;
+ break;
+ case NID_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm:
+ case NID_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm_omac:
+ format = GOST_ENC_FORMAT_PSKEY_KUZNYECHIK;
+ nid = NID_id_tc26_wrap_gostr3412_2015_kuznyechik_kexp15;
+ break;
+ default:
+ return 0;
+ }
+
+ if (EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_ENCRYPT,
+ EVP_PKEY_CTRL_GOST_ENC_FORMAT, format,
+ NULL) != 1)
+ return 0;
+
+ if (EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_ENCRYPT,
+ EVP_PKEY_CTRL_GOST_GET_DIGEST, 0,
+ &digest) != 1)
+ return 0;
+
+ switch (digest) {
+ case NID_id_GostR3411_94_CryptoProParamSet:
+ if ((params = encode_gost01_algor_params(pkey)) == NULL)
+ return -1;
+ break;
+
+ case NID_id_tc26_gost3411_2012_256:
+ case NID_id_tc26_gost3411_2012_512:
+ if ((params = encode_gost01_kexp_params(pkey)) == NULL)
+ return -1;
+ break;
+
+ default:
+ return 0;
+ }
+ return X509_ALGOR_set0(alg, OBJ_nid2obj(nid), V_ASN1_SEQUENCE, params);
+}
+
+#ifndef OPENSSL_NO_CMS
+static int
+gost01_cms_decrypt(CMS_RecipientInfo *ri)
+{
+ EVP_PKEY_CTX *pkctx;
+ X509_ALGOR *cmsalg;
+
+ pkctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
+ if (pkctx == NULL)
+ return 0;
+
+ if (!CMS_RecipientInfo_ktri_get0_algs(ri, NULL, NULL, &cmsalg))
+ return 0;
+
+ return gost01_smime_decrypt(pkctx, cmsalg);
+}
+#endif
+
static int
pkey_ctrl_gost01(EVP_PKEY *pkey, int op, long arg1, void *arg2)
{
- X509_ALGOR *alg1 = NULL, *alg2 = NULL, *alg3 = NULL;
+ X509_ALGOR *alg1 = NULL, *alg2 = NULL;
int digest = GOST_KEY_get_digest(pkey->pkey.gost);
switch (op) {
@@ -786,8 +921,8 @@ pkey_ctrl_gost01(EVP_PKEY *pkey, int op, long arg1, void *arg2)
&alg1, &alg2);
break;
case ASN1_PKEY_CTRL_CMS_ENVELOPE:
- if (arg1 == 0)
- CMS_RecipientInfo_ktri_get0_algs(arg2, NULL, NULL, &alg3);
+ if (arg1 == 1)
+ return gost01_cms_decrypt(arg2);
break;
#endif
case ASN1_PKEY_CTRL_PKCS7_SIGN:
@@ -795,9 +930,7 @@ pkey_ctrl_gost01(EVP_PKEY *pkey, int op, long arg1, void *arg2)
PKCS7_SIGNER_INFO_get0_algs(arg2, NULL, &alg1, &alg2);
break;
case ASN1_PKEY_CTRL_PKCS7_ENCRYPT:
- if (arg1 == 0)
- PKCS7_RECIP_INFO_get0_alg(arg2, &alg3);
- break;
+ return 1;
case ASN1_PKEY_CTRL_DEFAULT_MD_NID:
*(int *)arg2 = GostR3410_get_md_digest(digest);
return 2;
@@ -810,15 +943,6 @@ pkey_ctrl_gost01(EVP_PKEY *pkey, int op, long arg1, void *arg2)
X509_ALGOR_set0(alg1, OBJ_nid2obj(GostR3410_get_md_digest(digest)), V_ASN1_NULL, 0);
if (alg2)
X509_ALGOR_set0(alg2, OBJ_nid2obj(GostR3410_get_pk_digest(digest)), V_ASN1_NULL, 0);
- if (alg3) {
- ASN1_STRING *params = encode_gost01_algor_params(pkey);
- if (params == NULL) {
- return -1;
- }
- X509_ALGOR_set0(alg3,
- OBJ_nid2obj(GostR3410_get_pk_digest(digest)),
- V_ASN1_SEQUENCE, params);
- }
return 1;
}
diff --git a/src/lib/libcrypto/gost/gostr341001_pmeth.c b/src/lib/libcrypto/gost/gostr341001_pmeth.c
index ce4658b13..07ca4d3a3 100644
--- a/src/lib/libcrypto/gost/gostr341001_pmeth.c
+++ b/src/lib/libcrypto/gost/gostr341001_pmeth.c
@@ -61,6 +61,9 @@
#include <openssl/ec.h>
#include <openssl/ecdsa.h>
#include <openssl/x509.h>
+#ifndef OPENSSL_NO_CMS
+#include <openssl/cms.h>
+#endif
#include "evp_locl.h"
#include "gost_locl.h"
@@ -817,6 +820,7 @@ static int
pkey_gost01_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
{
struct gost_pmeth_data *pctx = EVP_PKEY_CTX_get_data(ctx);
+ X509_ALGOR *alg;
switch (type) {
case EVP_PKEY_CTRL_MD:
@@ -828,11 +832,20 @@ pkey_gost01_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
pctx->md = p2;
return 1;
case EVP_PKEY_CTRL_PKCS7_ENCRYPT:
+ PKCS7_RECIP_INFO_get0_alg(p2, &alg);
+ return gost01_smime_encrypt(ctx, alg, p1);
case EVP_PKEY_CTRL_PKCS7_DECRYPT:
+ PKCS7_RECIP_INFO_get0_alg(p2, &alg);
+ return gost01_smime_decrypt(ctx, alg);
case EVP_PKEY_CTRL_PKCS7_SIGN:
case EVP_PKEY_CTRL_DIGESTINIT:
+ return 1;
+
#ifndef OPENSSL_NO_CMS
case EVP_PKEY_CTRL_CMS_ENCRYPT:
+ if (CMS_RecipientInfo_ktri_get0_algs(p2, NULL, NULL, &alg) <= 0)
+ return 0;
+ return gost01_smime_encrypt(ctx, alg, p1);
case EVP_PKEY_CTRL_CMS_DECRYPT:
case EVP_PKEY_CTRL_CMS_SIGN:
#endif
diff --git a/src/lib/libcrypto/objects/obj_mac.num b/src/lib/libcrypto/objects/obj_mac.num
index 2c0d3356f..188349d71 100644
--- a/src/lib/libcrypto/objects/obj_mac.num
+++ b/src/lib/libcrypto/objects/obj_mac.num
@@ -1016,3 +1016,7 @@ id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm 1015
id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm_omac 1016
id_tc26_cipher_gostr3412_2015_kuznyechik_mgm 1017
kuznyechik_mac 1018
+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
diff --git a/src/lib/libcrypto/objects/objects.txt b/src/lib/libcrypto/objects/objects.txt
index 4bf75f700..0d2af66ac 100644
--- a/src/lib/libcrypto/objects/objects.txt
+++ b/src/lib/libcrypto/objects/objects.txt
@@ -1416,6 +1416,12 @@ tc26 1 5 2 2 : kuznyechik-ctr-acpkm-omac
tc26 1 5 2 3 : kuznyechik-mgm
: kuznyechik-mac
+tc26 1 6 1 : id-tc26-agreement-gost-3410-12-256
+tc26 1 6 2 : id-tc26-agreement-gost-3410-12-512
+
+tc26 1 7 1 1 : id-tc26-wrap-gostr3412-2015-magma-kexp15
+tc26 1 7 2 1 : id-tc26-wrap-gostr3412-2015-kuznyechik-kexp15
+
# Curves from draft-ietf-curdle-pkix-02
1 3 101 110 : X25519
1 3 101 111 : X448
diff --git a/src/lib/libcrypto/pkcs7/pk7_doit.c b/src/lib/libcrypto/pkcs7/pk7_doit.c
index 81a72f681..10cbd348e 100644
--- a/src/lib/libcrypto/pkcs7/pk7_doit.c
+++ b/src/lib/libcrypto/pkcs7/pk7_doit.c
@@ -138,7 +138,7 @@ err:
}
static int
-pkcs7_encode_rinfo(PKCS7_RECIP_INFO *ri, unsigned char *key, int keylen)
+pkcs7_encode_rinfo(PKCS7_RECIP_INFO *ri, unsigned char *key, int keylen, int enc_type)
{
EVP_PKEY_CTX *pctx = NULL;
EVP_PKEY *pkey = NULL;
@@ -158,7 +158,7 @@ pkcs7_encode_rinfo(PKCS7_RECIP_INFO *ri, unsigned char *key, int keylen)
goto err;
if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_ENCRYPT,
- EVP_PKEY_CTRL_PKCS7_ENCRYPT, 0, ri) <= 0) {
+ EVP_PKEY_CTRL_PKCS7_ENCRYPT, enc_type, ri) <= 0) {
PKCS7error(PKCS7_R_CTRL_ERROR);
goto err;
}
@@ -362,7 +362,7 @@ PKCS7_dataInit(PKCS7 *p7, BIO *bio)
/* Lets do the pub key stuff :-) */
for (i = 0; i < sk_PKCS7_RECIP_INFO_num(rsk); i++) {
ri = sk_PKCS7_RECIP_INFO_value(rsk, i);
- if (pkcs7_encode_rinfo(ri, key, keylen) <= 0)
+ if (pkcs7_encode_rinfo(ri, key, keylen, EVP_CIPHER_type(evp_cipher)) <= 0)
goto err;
}
explicit_bzero(key, keylen);
--
2.17.1