mirror of
https://abf.rosa.ru/djam/libressl.git
synced 2025-02-23 08:02:54 +00:00
411 lines
11 KiB
Diff
411 lines
11 KiB
Diff
From bb3f59aa72cd62dd7fb3f99a36d42b75110f2a94 Mon Sep 17 00:00:00 2001
|
|
From: Dmitry Baryshkov <dbaryshkov@gmail.com>
|
|
Date: Wed, 8 Apr 2020 21:27:46 +0300
|
|
Subject: [PATCH 64/87] gost: add support for decoding KeyAgreement CMS files
|
|
|
|
Sponsored by ROSA Linux
|
|
|
|
Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
|
|
---
|
|
src/lib/libcrypto/gost/gost.h | 1 +
|
|
src/lib/libcrypto/gost/gost_err.c | 1 +
|
|
src/lib/libcrypto/gost/gostr341001_ameth.c | 285 +++++++++++++++++++--
|
|
3 files changed, 263 insertions(+), 24 deletions(-)
|
|
|
|
diff --git a/src/lib/libcrypto/gost/gost.h b/src/lib/libcrypto/gost/gost.h
|
|
index 694906b76..25beb4a8a 100644
|
|
--- a/src/lib/libcrypto/gost/gost.h
|
|
+++ b/src/lib/libcrypto/gost/gost.h
|
|
@@ -301,6 +301,7 @@ void ERR_load_GOST_strings(void);
|
|
#define GOST_R_SIGNATURE_MISMATCH 121
|
|
#define GOST_R_SIGNATURE_PARTS_GREATER_THAN_Q 122
|
|
#define GOST_R_UKM_NOT_SET 123
|
|
+#define GOST_R_NO_ORIGINATOR_CERTIFICATE 124
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
diff --git a/src/lib/libcrypto/gost/gost_err.c b/src/lib/libcrypto/gost/gost_err.c
|
|
index e7111dd34..ea734897c 100644
|
|
--- a/src/lib/libcrypto/gost/gost_err.c
|
|
+++ b/src/lib/libcrypto/gost/gost_err.c
|
|
@@ -96,6 +96,7 @@ static ERR_STRING_DATA GOST_str_reasons[] = {
|
|
{ERR_REASON(GOST_R_SIGNATURE_MISMATCH) ,"signature mismatch"},
|
|
{ERR_REASON(GOST_R_SIGNATURE_PARTS_GREATER_THAN_Q),"signature parts greater than q"},
|
|
{ERR_REASON(GOST_R_UKM_NOT_SET) ,"ukm not set"},
|
|
+ {ERR_REASON(GOST_R_NO_ORIGINATOR_CERTIFICATE), "originator certificate not provided"},
|
|
{0, NULL}
|
|
};
|
|
#endif
|
|
diff --git a/src/lib/libcrypto/gost/gostr341001_ameth.c b/src/lib/libcrypto/gost/gostr341001_ameth.c
|
|
index 965b36237..2b59642fe 100644
|
|
--- a/src/lib/libcrypto/gost/gostr341001_ameth.c
|
|
+++ b/src/lib/libcrypto/gost/gostr341001_ameth.c
|
|
@@ -263,25 +263,24 @@ pkey_bits_gost01(const EVP_PKEY *pk)
|
|
}
|
|
|
|
static int
|
|
-pub_decode_gost01(EVP_PKEY *pk, X509_PUBKEY *pub)
|
|
+pub_decode_gost01_int(EVP_PKEY *pk, X509_ALGOR *palg, const unsigned char *pubkey_buf, int pub_len)
|
|
{
|
|
- X509_ALGOR *palg = NULL;
|
|
- const unsigned char *pubkey_buf = NULL;
|
|
+ const ASN1_OBJECT *poid;
|
|
const unsigned char *p;
|
|
- ASN1_OBJECT *palgobj = NULL;
|
|
- int pub_len;
|
|
BIGNUM *X, *Y;
|
|
ASN1_OCTET_STRING *octet = NULL;
|
|
int len;
|
|
int ret;
|
|
int ptype = V_ASN1_UNDEF;
|
|
ASN1_STRING *pval = NULL;
|
|
+ int nid;
|
|
|
|
- if (X509_PUBKEY_get0_param(&palgobj, &pubkey_buf, &pub_len, &palg, pub)
|
|
- == 0)
|
|
+ X509_ALGOR_get0(&poid, &ptype, (const void **)&pval, palg);
|
|
+ nid = OBJ_obj2nid(poid);
|
|
+ if (nid != NID_id_GostR3410_2001 &&
|
|
+ nid != NID_id_tc26_gost3410_2012_256 &&
|
|
+ nid != NID_id_tc26_gost3410_2012_512)
|
|
return 0;
|
|
- (void)EVP_PKEY_assign_GOST(pk, NULL);
|
|
- X509_ALGOR_get0(NULL, &ptype, (const void **)&pval, palg);
|
|
if (ptype != V_ASN1_SEQUENCE) {
|
|
GOSTerror(GOST_R_BAD_KEY_PARAMETERS_FORMAT);
|
|
return 0;
|
|
@@ -315,26 +314,44 @@ pub_decode_gost01(EVP_PKEY *pk, X509_PUBKEY *pub)
|
|
}
|
|
|
|
static int
|
|
-pub_encode_gost01(X509_PUBKEY *pub, const EVP_PKEY *pk)
|
|
+pub_decode_gost01(EVP_PKEY *pk, X509_PUBKEY *pub)
|
|
+{
|
|
+ X509_ALGOR *palg = NULL;
|
|
+ const unsigned char *pubkey_buf = NULL;
|
|
+ int pub_len;
|
|
+
|
|
+ if (X509_PUBKEY_get0_param(NULL, &pubkey_buf, &pub_len, &palg, pub) == 0)
|
|
+ return 0;
|
|
+ (void)EVP_PKEY_assign_GOST(pk, NULL);
|
|
+
|
|
+ return pub_decode_gost01_int(pk, palg, pubkey_buf, pub_len);
|
|
+}
|
|
+
|
|
+static int
|
|
+pub_encode_gost01_int(const EVP_PKEY *pk, ASN1_OBJECT **palgobj, ASN1_STRING **pparams, unsigned char **pbuf, int *plen)
|
|
{
|
|
ASN1_OBJECT *algobj = NULL;
|
|
ASN1_OCTET_STRING *octet = NULL;
|
|
ASN1_STRING *params = NULL;
|
|
- void *pval = NULL;
|
|
unsigned char *buf = NULL, *sptr;
|
|
int key_size, ret = 0;
|
|
const EC_POINT *pub_key;
|
|
BIGNUM *X = NULL, *Y = NULL;
|
|
const GOST_KEY *ec = pk->pkey.gost;
|
|
- int ptype = V_ASN1_UNDEF;
|
|
+
|
|
+ *palgobj = NULL;
|
|
+ *pparams = NULL;
|
|
+ *pbuf = NULL;
|
|
+ *plen = 0;
|
|
|
|
algobj = OBJ_nid2obj(GostR3410_get_pk_digest(GOST_KEY_get_digest(ec)));
|
|
+ if (algobj == NULL)
|
|
+ return 0;
|
|
+
|
|
if (pk->save_parameters) {
|
|
params = encode_gost01_algor_params(pk);
|
|
if (params == NULL)
|
|
- return 0;
|
|
- pval = params;
|
|
- ptype = V_ASN1_SEQUENCE;
|
|
+ goto err;
|
|
}
|
|
|
|
key_size = GOST_KEY_get_size(ec);
|
|
@@ -375,21 +392,44 @@ pub_encode_gost01(X509_PUBKEY *pub, const EVP_PKEY *pk)
|
|
GOST_bn2le(X, sptr, key_size);
|
|
GOST_bn2le(Y, sptr + key_size, key_size);
|
|
|
|
- BN_free(Y);
|
|
- BN_free(X);
|
|
-
|
|
ret = i2d_ASN1_OCTET_STRING(octet, &buf);
|
|
- ASN1_BIT_STRING_free(octet);
|
|
if (ret < 0)
|
|
- return 0;
|
|
+ goto err;
|
|
|
|
- return X509_PUBKEY_set0_param(pub, algobj, ptype, pval, buf, ret);
|
|
+ *palgobj = algobj;
|
|
+ *pparams = params;
|
|
+ *pbuf = buf;
|
|
+ *plen = ret;
|
|
+
|
|
+ return 1;
|
|
|
|
err:
|
|
BN_free(Y);
|
|
BN_free(X);
|
|
ASN1_BIT_STRING_free(octet);
|
|
ASN1_STRING_free(params);
|
|
+ ASN1_OBJECT_free(algobj);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+pub_encode_gost01(X509_PUBKEY *pub, const EVP_PKEY *pk)
|
|
+{
|
|
+ ASN1_OBJECT *algobj = NULL;
|
|
+ ASN1_STRING *params = NULL;
|
|
+ unsigned char *buf = NULL;
|
|
+ int len;
|
|
+
|
|
+ if (pub_encode_gost01_int(pk, &algobj, ¶ms, &buf, &len) <= 0)
|
|
+ return 0;
|
|
+
|
|
+ if (X509_PUBKEY_set0_param(pub, algobj, V_ASN1_SEQUENCE, params, buf, len) == 1)
|
|
+ return 1;
|
|
+
|
|
+ free(buf);
|
|
+ ASN1_STRING_free(params);
|
|
+ ASN1_OBJECT_free(algobj);
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -890,6 +930,89 @@ int gost01_smime_encrypt(EVP_PKEY_CTX *ctx, X509_ALGOR *alg, int enc_nid)
|
|
}
|
|
|
|
#ifndef OPENSSL_NO_CMS
|
|
+static int
|
|
+gost01_cms_set_peerkey(EVP_PKEY_CTX *pctx, X509_ALGOR *alg,
|
|
+ ASN1_BIT_STRING *pubkey)
|
|
+{
|
|
+ int rv = 0;
|
|
+ EVP_PKEY *pkpeer = NULL;
|
|
+ int ret;
|
|
+
|
|
+ pkpeer = EVP_PKEY_new();
|
|
+ if (pkpeer == NULL)
|
|
+ return 0;
|
|
+ (void)EVP_PKEY_assign_GOST(pkpeer, NULL);
|
|
+
|
|
+ ret = pub_decode_gost01_int(pkpeer, alg, pubkey->data, pubkey->length);
|
|
+ if (ret <= 0)
|
|
+ goto err;
|
|
+
|
|
+ if (EVP_PKEY_derive_set_peer(pctx, pkpeer) > 0)
|
|
+ rv = 1;
|
|
+ err:
|
|
+
|
|
+ EVP_PKEY_free(pkpeer);
|
|
+ return rv;
|
|
+}
|
|
+
|
|
+static int
|
|
+gost01_cms_decrypt_kari(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri)
|
|
+{
|
|
+ EVP_CIPHER_CTX *kekctx;
|
|
+ X509_ALGOR *alg;
|
|
+ ASN1_OCTET_STRING *ukm;
|
|
+ const EVP_CIPHER *kekcipher;
|
|
+
|
|
+ if (!CMS_RecipientInfo_kari_get0_alg(ri, &alg, &ukm))
|
|
+ return 0;
|
|
+
|
|
+ if (ukm == NULL)
|
|
+ return 0;
|
|
+
|
|
+ if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DERIVE,
|
|
+ EVP_PKEY_CTRL_SET_IV, ukm->length, ukm->data) < 0)
|
|
+ return 0;
|
|
+
|
|
+ if (!EVP_PKEY_CTX_get0_peerkey(pctx)) {
|
|
+ ASN1_BIT_STRING *pubkey;
|
|
+ X509_ALGOR *pkalg;
|
|
+
|
|
+ if (!CMS_RecipientInfo_kari_get0_orig_id(ri, &pkalg, &pubkey,
|
|
+ NULL, NULL, NULL))
|
|
+ return 0;
|
|
+ if (!pkalg || !pubkey) {
|
|
+ GOSTerror(GOST_R_NO_ORIGINATOR_CERTIFICATE);
|
|
+ return 0;
|
|
+ }
|
|
+ if (!gost01_cms_set_peerkey(pctx, pkalg, pubkey)) {
|
|
+ GOSTerror(GOST_R_INCOMPATIBLE_PEER_KEY);
|
|
+ return 0;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (alg->parameter->type != V_ASN1_SEQUENCE)
|
|
+ return 0;
|
|
+
|
|
+ kekctx = CMS_RecipientInfo_kari_get0_ctx(ri);
|
|
+ if (!kekctx)
|
|
+ return 0;
|
|
+
|
|
+ kekcipher = EVP_get_cipherbyobj(alg->algorithm);
|
|
+ if (!kekcipher || EVP_CIPHER_mode(kekcipher) != EVP_CIPH_WRAP_MODE)
|
|
+ return 0;
|
|
+ if (!EVP_EncryptInit_ex(kekctx, kekcipher, NULL, NULL, ukm->data))
|
|
+ return 0;
|
|
+
|
|
+ if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DERIVE,
|
|
+ EVP_PKEY_CTRL_GOST_DERIVE_FORMAT,
|
|
+ GOST_DERIVE_FORMAT_KEG, NULL) <= 0) {
|
|
+ GOSTerror(ERR_R_INTERNAL_ERROR);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+
|
|
static int
|
|
gost01_cms_decrypt(CMS_RecipientInfo *ri)
|
|
{
|
|
@@ -899,12 +1022,116 @@ gost01_cms_decrypt(CMS_RecipientInfo *ri)
|
|
pkctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
|
|
if (pkctx == NULL)
|
|
return 0;
|
|
+ switch (CMS_RecipientInfo_type(ri)) {
|
|
+ case CMS_RECIPINFO_TRANS:
|
|
+ if (!CMS_RecipientInfo_ktri_get0_algs(ri, NULL, NULL, &cmsalg))
|
|
+ return 0;
|
|
+ return gost01_smime_decrypt(pkctx, cmsalg);
|
|
+ case CMS_RECIPINFO_AGREE:
|
|
+ return gost01_cms_decrypt_kari(pkctx, ri);
|
|
+ default:
|
|
+ GOSTerror(ERR_R_INTERNAL_ERROR);
|
|
+ return 0;
|
|
+ }
|
|
+}
|
|
+
|
|
+static int
|
|
+gost01_cms_encrypt_kari(CMS_RecipientInfo *ri)
|
|
+{
|
|
+ EVP_PKEY_CTX *pctx;
|
|
+ EVP_PKEY *pkey;
|
|
+ EVP_CIPHER_CTX *ctx;
|
|
+ X509_ALGOR *talg, *wrap_alg = NULL;
|
|
+ ASN1_BIT_STRING *pubkey;
|
|
+ int wrap_nid;
|
|
+ unsigned char iv[32];
|
|
+ ASN1_STRING *params;
|
|
+
|
|
+ pctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
|
|
+ if (!pctx)
|
|
+ return 0;
|
|
|
|
- if (!CMS_RecipientInfo_ktri_get0_algs(ri, NULL, NULL, &cmsalg))
|
|
+ /* Get ephemeral key */
|
|
+ pkey = EVP_PKEY_CTX_get0_pkey(pctx);
|
|
+ if (pkey == NULL)
|
|
return 0;
|
|
|
|
- return gost01_smime_decrypt(pkctx, cmsalg);
|
|
+ if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DERIVE,
|
|
+ EVP_PKEY_CTRL_GOST_DERIVE_FORMAT,
|
|
+ GOST_DERIVE_FORMAT_KEG, NULL) <= 0) {
|
|
+ GOSTerror(ERR_R_INTERNAL_ERROR);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (!CMS_RecipientInfo_kari_get0_orig_id(ri, &talg, &pubkey,
|
|
+ NULL, NULL, NULL))
|
|
+ goto err;
|
|
+
|
|
+ /* Ephemeral key */
|
|
+ if (talg) {
|
|
+ const ASN1_OBJECT *aoid = NULL;
|
|
+
|
|
+ X509_ALGOR_get0(&aoid, NULL, NULL, talg);
|
|
+
|
|
+ /* Is everything uninitialised? */
|
|
+ if (aoid == OBJ_nid2obj(NID_undef)) {
|
|
+ ASN1_OBJECT *algobj = NULL;
|
|
+ ASN1_STRING *params = NULL;
|
|
+ unsigned char *buf = NULL;
|
|
+ int len;
|
|
+
|
|
+ if (pub_encode_gost01_int(pkey, &algobj, ¶ms, &buf, &len) <= 0)
|
|
+ return 0;
|
|
+
|
|
+ X509_ALGOR_set0(talg, algobj, V_ASN1_SEQUENCE, params);
|
|
+ ASN1_STRING_set0(pubkey, buf, len);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Get wrap NID */
|
|
+ ctx = CMS_RecipientInfo_kari_get0_ctx(ri);
|
|
+ wrap_nid = EVP_CIPHER_CTX_type(ctx);
|
|
+
|
|
+ /* Package wrap algorithm in an AlgorithmIdentifier */
|
|
+
|
|
+ if (!CMS_RecipientInfo_kari_get0_alg(ri, &wrap_alg, NULL))
|
|
+ goto err;
|
|
+ if (wrap_alg == NULL)
|
|
+ goto err;
|
|
+ if ((params = encode_gost01_kexp_params(pkey)) == NULL)
|
|
+ goto err;
|
|
+ X509_ALGOR_set0(wrap_alg, OBJ_nid2obj(wrap_nid), V_ASN1_SEQUENCE, params);
|
|
+
|
|
+ arc4random_buf(iv, sizeof(iv));
|
|
+ if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DERIVE,
|
|
+ EVP_PKEY_CTRL_SET_IV, sizeof(iv), iv) < 0)
|
|
+ goto err;
|
|
+
|
|
+ if (!EVP_CipherInit_ex(ctx, NULL, NULL, NULL, iv, -1))
|
|
+ goto err;
|
|
+
|
|
+ if (!CMS_RecipientInfo_kari_set0_ukm(ri, iv, sizeof(iv)))
|
|
+ goto err;
|
|
+
|
|
+ return 1;
|
|
+err:
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+gost01_cms_encrypt(CMS_RecipientInfo *ri)
|
|
+{
|
|
+ switch (CMS_RecipientInfo_type(ri)) {
|
|
+ case CMS_RECIPINFO_TRANS:
|
|
+ /* do nothing, handled in pmeth */
|
|
+ return 1;
|
|
+ case CMS_RECIPINFO_AGREE:
|
|
+ return gost01_cms_encrypt_kari(ri);
|
|
+ default:
|
|
+ return 0;
|
|
+ }
|
|
}
|
|
+
|
|
#endif
|
|
|
|
static int
|
|
@@ -921,9 +1148,19 @@ pkey_ctrl_gost01(EVP_PKEY *pkey, int op, long arg1, void *arg2)
|
|
&alg1, &alg2);
|
|
break;
|
|
case ASN1_PKEY_CTRL_CMS_ENVELOPE:
|
|
- if (arg1 == 1)
|
|
+ if (arg1 == 0)
|
|
+ return gost01_cms_encrypt(arg2);
|
|
+ else if (arg1 == 1)
|
|
return gost01_cms_decrypt(arg2);
|
|
break;
|
|
+ case ASN1_PKEY_CTRL_CMS_RI_TYPE:
|
|
+ if (arg2 != NULL)
|
|
+ *(int *)arg2 = CMS_RECIPINFO_TRANS; /* default */
|
|
+ break;
|
|
+ case ASN1_PKEY_CTRL_CMS_IS_RI_TYPE_SUPPORTED:
|
|
+ if (arg2 != NULL)
|
|
+ *(int *)arg2 = (arg1 == CMS_RECIPINFO_TRANS || arg1 == CMS_RECIPINFO_AGREE);
|
|
+ break;
|
|
#endif
|
|
case ASN1_PKEY_CTRL_PKCS7_SIGN:
|
|
if (arg1 == 0)
|
|
--
|
|
2.17.1
|
|
|