From 39697551e90ec5c96552de4d4666ec00b579dcce Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov 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 --- 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, ¶ms->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 #include #include +#ifndef OPENSSL_NO_CMS +#include +#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