From 5f76803c2582cccacd73cf285267418cb40d9a3d Mon Sep 17 00:00:00 2001 From: Dmitry Belyavskiy Date: Sat, 2 May 2020 18:07:15 +0300 Subject: [PATCH] New Gost CMS support, KARI/KTRI parsing --- e_gost_err.c | 11 ++++ e_gost_err.h | 6 ++ gost.txt | 6 ++ gost_ameth.c | 169 ++++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 190 insertions(+), 2 deletions(-) diff --git a/e_gost_err.c b/e_gost_err.c index b643f11..b7aa855 100644 --- a/e_gost_err.c +++ b/e_gost_err.c @@ -25,6 +25,12 @@ static ERR_STRING_DATA GOST_str_functs[] = { {ERR_PACK(0, GOST_F_GOST89_SET_ASN1_PARAMETERS, 0), "gost89_set_asn1_parameters"}, {ERR_PACK(0, GOST_F_GOST_CIPHER_CTL, 0), "gost_cipher_ctl"}, + {ERR_PACK(0, GOST_F_GOST_CMS_SET_KARI_SHARED_INFO, 0), + "gost_cms_set_kari_shared_info"}, + {ERR_PACK(0, GOST_F_GOST_CMS_SET_KTRI_SHARED_INFO, 0), + "gost_cms_set_ktri_shared_info"}, + {ERR_PACK(0, GOST_F_GOST_CMS_SET_SHARED_INFO, 0), + "gost_cms_set_shared_info"}, {ERR_PACK(0, GOST_F_GOST_EC_COMPUTE_PUBLIC, 0), "gost_ec_compute_public"}, {ERR_PACK(0, GOST_F_GOST_EC_KEYGEN, 0), "gost_ec_keygen"}, {ERR_PACK(0, GOST_F_GOST_EC_SIGN, 0), "gost_ec_sign"}, @@ -102,9 +108,12 @@ static ERR_STRING_DATA GOST_str_reasons[] = { "error computing export keys"}, {ERR_PACK(0, 0, GOST_R_ERROR_COMPUTING_SHARED_KEY), "error computing shared key"}, + {ERR_PACK(0, 0, GOST_R_ERROR_DECODING_PUBLIC_KEY), + "error decoding public key"}, {ERR_PACK(0, 0, GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO), "error parsing key transport info"}, {ERR_PACK(0, 0, GOST_R_ERROR_POINT_MUL), "error point mul"}, + {ERR_PACK(0, 0, GOST_R_ERROR_SETTING_PEER_KEY), "error setting peer key"}, {ERR_PACK(0, 0, GOST_R_INCOMPATIBLE_ALGORITHMS), "incompatible algorithms"}, {ERR_PACK(0, 0, GOST_R_INCOMPATIBLE_PEER_KEY), "incompatible peer key"}, {ERR_PACK(0, 0, GOST_R_INVALID_CIPHER), "invalid cipher"}, @@ -135,6 +144,8 @@ static ERR_STRING_DATA GOST_str_reasons[] = { "unsupported cipher ctl command"}, {ERR_PACK(0, 0, GOST_R_UNSUPPORTED_PARAMETER_SET), "unsupported parameter set"}, + {ERR_PACK(0, 0, GOST_R_UNSUPPORTED_RECIPIENT_INFO), + "unsupported recipient info"}, {0, NULL} }; diff --git a/e_gost_err.h b/e_gost_err.h index 0d7ec94..f656239 100644 --- a/e_gost_err.h +++ b/e_gost_err.h @@ -36,6 +36,9 @@ void ERR_GOST_error(int function, int reason, char *file, int line); # define GOST_F_GOST89_GET_ASN1_PARAMETERS 104 # define GOST_F_GOST89_SET_ASN1_PARAMETERS 105 # define GOST_F_GOST_CIPHER_CTL 106 +# define GOST_F_GOST_CMS_SET_KARI_SHARED_INFO 156 +# define GOST_F_GOST_CMS_SET_KTRI_SHARED_INFO 157 +# define GOST_F_GOST_CMS_SET_SHARED_INFO 155 # define GOST_F_GOST_EC_COMPUTE_PUBLIC 107 # define GOST_F_GOST_EC_KEYGEN 108 # define GOST_F_GOST_EC_SIGN 109 @@ -98,8 +101,10 @@ void ERR_GOST_error(int function, int reason, char *file, int line); # define GOST_R_CTRL_CALL_FAILED 104 # define GOST_R_ERROR_COMPUTING_EXPORT_KEYS 135 # define GOST_R_ERROR_COMPUTING_SHARED_KEY 105 +# define GOST_R_ERROR_DECODING_PUBLIC_KEY 138 # define GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO 106 # define GOST_R_ERROR_POINT_MUL 107 +# define GOST_R_ERROR_SETTING_PEER_KEY 139 # define GOST_R_INCOMPATIBLE_ALGORITHMS 108 # define GOST_R_INCOMPATIBLE_PEER_KEY 109 # define GOST_R_INVALID_CIPHER 134 @@ -125,5 +130,6 @@ void ERR_GOST_error(int function, int reason, char *file, int line); # define GOST_R_UKM_NOT_SET 129 # define GOST_R_UNSUPPORTED_CIPHER_CTL_COMMAND 130 # define GOST_R_UNSUPPORTED_PARAMETER_SET 131 +# define GOST_R_UNSUPPORTED_RECIPIENT_INFO 137 #endif diff --git a/gost.txt b/gost.txt index d56823e..959b99c 100644 --- a/gost.txt +++ b/gost.txt @@ -13,6 +13,9 @@ GOST_F_GET_ENCRYPTION_PARAMS:103:get_encryption_params GOST_F_GOST89_GET_ASN1_PARAMETERS:104:gost89_get_asn1_parameters GOST_F_GOST89_SET_ASN1_PARAMETERS:105:gost89_set_asn1_parameters GOST_F_GOST_CIPHER_CTL:106:gost_cipher_ctl +GOST_F_GOST_CMS_SET_KARI_SHARED_INFO:156:gost_cms_set_kari_shared_info +GOST_F_GOST_CMS_SET_KTRI_SHARED_INFO:157:gost_cms_set_ktri_shared_info +GOST_F_GOST_CMS_SET_SHARED_INFO:155:gost_cms_set_shared_info GOST_F_GOST_EC_COMPUTE_PUBLIC:107:gost_ec_compute_public GOST_F_GOST_EC_KEYGEN:108:gost_ec_keygen GOST_F_GOST_EC_SIGN:109:gost_ec_sign @@ -75,8 +78,10 @@ GOST_R_CIPHER_NOT_FOUND:103:cipher not found GOST_R_CTRL_CALL_FAILED:104:ctrl call failed GOST_R_ERROR_COMPUTING_EXPORT_KEYS:135:error computing export keys GOST_R_ERROR_COMPUTING_SHARED_KEY:105:error computing shared key +GOST_R_ERROR_DECODING_PUBLIC_KEY:138:error decoding public key GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO:106:error parsing key transport info GOST_R_ERROR_POINT_MUL:107:error point mul +GOST_R_ERROR_SETTING_PEER_KEY:139:error setting peer key GOST_R_INCOMPATIBLE_ALGORITHMS:108:incompatible algorithms GOST_R_INCOMPATIBLE_PEER_KEY:109:incompatible peer key GOST_R_INVALID_CIPHER:134:invalid cipher @@ -103,3 +108,4 @@ GOST_R_SIGNATURE_PARTS_GREATER_THAN_Q:128:signature parts greater than q GOST_R_UKM_NOT_SET:129:ukm not set GOST_R_UNSUPPORTED_CIPHER_CTL_COMMAND:130:unsupported cipher ctl command GOST_R_UNSUPPORTED_PARAMETER_SET:131:unsupported parameter set +GOST_R_UNSUPPORTED_RECIPIENT_INFO:137:unsupported recipient info diff --git a/gost_ameth.c b/gost_ameth.c index f13b4ed..92319e7 100644 --- a/gost_ameth.c +++ b/gost_ameth.c @@ -220,6 +220,153 @@ BIGNUM *gost_get0_priv_key(const EVP_PKEY *pkey) return NULL; } +/* + * GOST CMS processing functions + */ +/* FIXME reaarange declarations */ +static int pub_decode_gost_ec(EVP_PKEY *pk, X509_PUBKEY *pub); + +static int gost_cms_set_kari_shared_info(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri) +{ + int ret = 0; + X509_ALGOR *alg; + ASN1_OCTET_STRING *ukm; + + /* Deal with originator */ + X509_ALGOR *pubalg = NULL; + ASN1_BIT_STRING *pubkey = NULL; + + EVP_PKEY *peer_key = NULL; + X509_PUBKEY *tmp = NULL; + + int nid; + unsigned char shared_key[64]; + size_t shared_key_size = 64; + const EVP_CIPHER *cipher = NULL; + + if (CMS_RecipientInfo_kari_get0_alg(ri, &alg, &ukm) == 0) + goto err; + + if (CMS_RecipientInfo_kari_get0_orig_id(ri, &pubalg, &pubkey, NULL, NULL, NULL) == 0) + goto err; + + nid = OBJ_obj2nid(alg->algorithm); + if (alg->parameter->type != V_ASN1_SEQUENCE) + goto err; + + switch (nid) { + case NID_kuznyechik_kexp15: + case NID_magma_kexp15: + cipher = EVP_get_cipherbynid(nid); + break; + } + + if (cipher == NULL) { + GOSTerr(GOST_F_GOST_CMS_SET_KARI_SHARED_INFO, GOST_R_CIPHER_NOT_FOUND); + goto err; + } + + if (EVP_PKEY_CTX_ctrl(pctx, -1, -1, EVP_PKEY_CTRL_SET_IV, + ASN1_STRING_length(ukm), (void *)ASN1_STRING_get0_data(ukm)) <= 0) + goto err; + + if (pubkey != NULL && pubalg != NULL) { + const ASN1_OBJECT *paobj = NULL; + int ptype = 0; + const void *param = NULL; + + peer_key = EVP_PKEY_new(); + tmp = X509_PUBKEY_new(); + + if ((peer_key == NULL) || (tmp == NULL)) { + GOSTerr(GOST_F_GOST_CMS_SET_KARI_SHARED_INFO, ERR_R_MALLOC_FAILURE); + goto err; + } + + X509_ALGOR_get0(&paobj, &ptype, ¶m, pubalg); + + if (X509_PUBKEY_set0_param(tmp, (ASN1_OBJECT *)paobj, + ptype, (void *)param, + (unsigned char *)ASN1_STRING_get0_data(pubkey), + ASN1_STRING_length(pubkey) ) == 0) { + GOSTerr(GOST_F_GOST_CMS_SET_KARI_SHARED_INFO, GOST_R_PUBLIC_KEY_UNDEFINED); + goto err; + } + + if (pub_decode_gost_ec(peer_key, tmp) <= 0) { + GOSTerr(GOST_F_GOST_CMS_SET_KARI_SHARED_INFO, GOST_R_ERROR_DECODING_PUBLIC_KEY); + goto err; + } + + if (EVP_PKEY_derive_set_peer(pctx, peer_key) <= 0) { + GOSTerr(GOST_F_GOST_CMS_SET_KARI_SHARED_INFO, GOST_R_ERROR_SETTING_PEER_KEY); + goto err; + } + } + + if (EVP_PKEY_derive(pctx, shared_key, &shared_key_size) <= 0) { + GOSTerr(GOST_F_GOST_CMS_SET_KARI_SHARED_INFO, GOST_R_ERROR_COMPUTING_SHARED_KEY); + goto err; + } + + EVP_CIPHER_CTX_set_flags(CMS_RecipientInfo_kari_get0_ctx(ri), EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); + if (EVP_DecryptInit_ex(CMS_RecipientInfo_kari_get0_ctx(ri), cipher, NULL, + shared_key, ukm->data+24) == 0) + goto err; + + ret = 1; +err: + EVP_PKEY_free(peer_key); + if (ret == 0) { + X509_PUBKEY_free(tmp); + } + + return ret; +} + +static int gost_cms_set_ktri_shared_info(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri) +{ + X509_ALGOR *alg; + struct gost_pmeth_data *gctx = EVP_PKEY_CTX_get_data(pctx); + + CMS_RecipientInfo_ktri_get0_algs(ri, NULL, NULL, &alg); + + switch (OBJ_obj2nid(alg->algorithm)) { + case NID_kuznyechik_kexp15: + gctx->cipher_nid = NID_kuznyechik_ctr; + break; + + case NID_magma_kexp15: + gctx->cipher_nid = NID_magma_ctr; + break; + + case NID_id_GostR3410_2012_256: + case NID_id_GostR3410_2012_512: + gctx->cipher_nid = NID_id_Gost28147_89; + break; + + default: + GOSTerr(GOST_F_GOST_CMS_SET_KTRI_SHARED_INFO, GOST_R_UNSUPPORTED_RECIPIENT_INFO); + return 0; + } + + return 1; +} + +static int gost_cms_set_shared_info(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri) +{ + switch(CMS_RecipientInfo_type(ri)) { + case CMS_RECIPINFO_AGREE: + return gost_cms_set_kari_shared_info(pctx, ri); + break; + case CMS_RECIPINFO_TRANS: + return gost_cms_set_ktri_shared_info(pctx, ri); + break; + } + + GOSTerr(GOST_F_GOST_CMS_SET_SHARED_INFO, GOST_R_UNSUPPORTED_RECIPIENT_INFO); + return 0; +} /* * Control function */ @@ -263,7 +410,7 @@ static int pkey_ctrl_gost(EVP_PKEY *pkey, int op, long arg1, void *arg2) return 1; #endif case ASN1_PKEY_CTRL_PKCS7_ENCRYPT: - if (arg1 == 0) { + if (arg1 == 0) { /* Encryption */ ASN1_STRING *params = encode_gost_algor_params(pkey); if (!params) { return -1; @@ -271,7 +418,7 @@ static int pkey_ctrl_gost(EVP_PKEY *pkey, int op, long arg1, void *arg2) PKCS7_RECIP_INFO_get0_alg((PKCS7_RECIP_INFO *)arg2, &alg1); X509_ALGOR_set0(alg1, OBJ_nid2obj(EVP_PKEY_id(pkey)), V_ASN1_SEQUENCE, params); - } + } return 1; #ifndef OPENSSL_NO_CMS case ASN1_PKEY_CTRL_CMS_ENVELOPE: @@ -284,8 +431,26 @@ static int pkey_ctrl_gost(EVP_PKEY *pkey, int op, long arg1, void *arg2) NULL, &alg1); X509_ALGOR_set0(alg1, OBJ_nid2obj(EVP_PKEY_id(pkey)), V_ASN1_SEQUENCE, params); + } else { + EVP_PKEY_CTX *pctx; + CMS_RecipientInfo *ri = arg2; + pctx = CMS_RecipientInfo_get0_pkey_ctx(ri); + if (!pctx) + return 0; + return gost_cms_set_shared_info(pctx, ri); } return 1; +#ifdef ASN1_PKEY_CTRL_CMS_RI_TYPE + case ASN1_PKEY_CTRL_CMS_RI_TYPE: + *(int *)arg2 = CMS_RECIPINFO_TRANS; + return 1; + case ASN1_PKEY_CTRL_CMS_IS_RI_TYPE_SUPPORTED: + if (arg1 == CMS_RECIPINFO_AGREE || arg1 == CMS_RECIPINFO_TRANS) + return 1; + else + return 0; + break; +#endif #endif case ASN1_PKEY_CTRL_DEFAULT_MD_NID: *(int *)arg2 = md_nid; -- 2.39.2