From b24d8544474981c74fcd13630a811ada98e8743d Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 19 Mar 2020 18:12:09 +0300 Subject: [PATCH 28/87] gostr341001: support unwrapped private keys support GOST private keys can be wrapped in OCTET STRING, INTEGER or come unwrapped. Support the latter format. Sponsored by ROSA Linux Signed-off-by: Dmitry Baryshkov --- src/lib/libcrypto/gost/gost_asn1.c | 52 ++++++++++ src/lib/libcrypto/gost/gost_asn1.h | 11 ++ src/lib/libcrypto/gost/gostr341001_ameth.c | 115 +++++++++++++++++++-- 3 files changed, 169 insertions(+), 9 deletions(-) diff --git a/src/lib/libcrypto/gost/gost_asn1.c b/src/lib/libcrypto/gost/gost_asn1.c index 703d64070..bfd81faa1 100644 --- a/src/lib/libcrypto/gost/gost_asn1.c +++ b/src/lib/libcrypto/gost/gost_asn1.c @@ -17,6 +17,58 @@ #include "gost_locl.h" #include "gost_asn1.h" +static const ASN1_TEMPLATE MASKED_GOST_KEY_seq_tt[] = { + { + .flags = 0, + .tag = 0, + .offset = offsetof(MASKED_GOST_KEY, masked_priv_key), + .field_name = "masked_priv_key", + .item = &ASN1_OCTET_STRING_it, + }, + { + .flags = 0, + .tag = 0, + .offset = offsetof(MASKED_GOST_KEY, public_key), + .field_name = "public_key", + .item = &ASN1_OCTET_STRING_it, + }, +}; + +const ASN1_ITEM MASKED_GOST_KEY_it = { + .itype = ASN1_ITYPE_NDEF_SEQUENCE, + .utype = V_ASN1_SEQUENCE, + .templates = MASKED_GOST_KEY_seq_tt, + .tcount = sizeof(MASKED_GOST_KEY_seq_tt) / sizeof(ASN1_TEMPLATE), + .funcs = NULL, + .size = sizeof(MASKED_GOST_KEY), + .sname = "MASKED_GOST_KEY", +}; + +MASKED_GOST_KEY * +d2i_MASKED_GOST_KEY(MASKED_GOST_KEY **a, const unsigned char **in, long len) +{ + return (MASKED_GOST_KEY *)ASN1_item_d2i((ASN1_VALUE **)a, in, len, + &MASKED_GOST_KEY_it); +} + +int +i2d_MASKED_GOST_KEY(MASKED_GOST_KEY *a, unsigned char **out) +{ + return ASN1_item_i2d((ASN1_VALUE *)a, out, &MASKED_GOST_KEY_it); +} + +MASKED_GOST_KEY * +MASKED_GOST_KEY_new(void) +{ + return (MASKED_GOST_KEY *)ASN1_item_new(&MASKED_GOST_KEY_it); +} + +void +MASKED_GOST_KEY_free(MASKED_GOST_KEY *a) +{ + ASN1_item_free((ASN1_VALUE *)a, &MASKED_GOST_KEY_it); +} + static const ASN1_TEMPLATE GOST_KEY_TRANSPORT_seq_tt[] = { { .flags = 0, diff --git a/src/lib/libcrypto/gost/gost_asn1.h b/src/lib/libcrypto/gost/gost_asn1.h index 7cabfc79c..cdbda7b98 100644 --- a/src/lib/libcrypto/gost/gost_asn1.h +++ b/src/lib/libcrypto/gost/gost_asn1.h @@ -56,6 +56,17 @@ __BEGIN_HIDDEN_DECLS +typedef struct { + ASN1_OCTET_STRING *masked_priv_key; + ASN1_OCTET_STRING *public_key; +} MASKED_GOST_KEY; + +MASKED_GOST_KEY *MASKED_GOST_KEY_new(void); +void MASKED_GOST_KEY_free(MASKED_GOST_KEY *a); +MASKED_GOST_KEY *d2i_MASKED_GOST_KEY(MASKED_GOST_KEY **a, const unsigned char **in, long len); +int i2d_MASKED_GOST_KEY(MASKED_GOST_KEY *a, unsigned char **out); +extern const ASN1_ITEM MASKED_GOST_KEY_it; + typedef struct { ASN1_OCTET_STRING *encrypted_key; ASN1_OCTET_STRING *imit; diff --git a/src/lib/libcrypto/gost/gostr341001_ameth.c b/src/lib/libcrypto/gost/gostr341001_ameth.c index 7cb70ed42..880c17cea 100644 --- a/src/lib/libcrypto/gost/gostr341001_ameth.c +++ b/src/lib/libcrypto/gost/gostr341001_ameth.c @@ -437,6 +437,70 @@ priv_print_gost01(BIO *out, const EVP_PKEY *pkey, int indent, ASN1_PCTX *pctx) return pub_print_gost01(out, pkey, indent, pctx); } +static BIGNUM *unmask_priv_key(EVP_PKEY *pk, + const unsigned char *buf, int len, int num_masks) +{ + BIGNUM *pknum_masked = NULL, *q, *mask; + const GOST_KEY *key_ptr = pk->pkey.gost; + const EC_GROUP *group = GOST_KEY_get0_group(key_ptr); + const unsigned char *p = buf + num_masks * len; + BN_CTX *ctx; + + pknum_masked = GOST_le2bn(buf, len, NULL); + if (!pknum_masked) { + GOSTerror(ERR_R_MALLOC_FAILURE); + return NULL; + } + + if (num_masks == 0) + return pknum_masked; + + ctx = BN_CTX_new(); + if (ctx == NULL) { + GOSTerror(ERR_R_MALLOC_FAILURE); + goto err; + } + + BN_CTX_start(ctx); + + q = BN_CTX_get(ctx); + if (!q) { + GOSTerror(ERR_R_MALLOC_FAILURE); + goto err; + } + + mask = BN_CTX_get(ctx); + if (!mask) { + GOSTerror(ERR_R_MALLOC_FAILURE); + goto err; + } + + if (EC_GROUP_get_order(group, q, NULL) <= 0) { + GOSTerror(ERR_R_EC_LIB); + goto err; + } + + for (; p != buf; p -= len) { + if (GOST_le2bn(p, len, mask) == NULL || + !BN_mod_mul(pknum_masked, pknum_masked, mask, q, ctx)) { + GOSTerror(ERR_R_BN_LIB); + goto err; + } + } + + BN_CTX_end(ctx); + BN_CTX_free(ctx); + + return pknum_masked; + +err: + BN_CTX_end(ctx); + BN_CTX_free(ctx); + + BN_free(pknum_masked); + return NULL; +} + static int priv_decode_gost01(EVP_PKEY *pk, const PKCS8_PRIV_KEY_INFO *p8inf) { @@ -450,6 +514,7 @@ priv_decode_gost01(EVP_PKEY *pk, const PKCS8_PRIV_KEY_INFO *p8inf) GOST_KEY *ec; int ptype = V_ASN1_UNDEF; ASN1_STRING *pval = NULL; + int expected_key_len; if (PKCS8_pkey_get0(&palg_obj, &pkey_buf, &priv_len, &palg, p8inf) == 0) { GOSTerror(GOST_R_BAD_KEY_PARAMETERS_FORMAT); @@ -467,29 +532,61 @@ priv_decode_gost01(EVP_PKEY *pk, const PKCS8_PRIV_KEY_INFO *p8inf) return 0; } p = pkey_buf; - if (V_ASN1_OCTET_STRING == *p) { + + expected_key_len = (pkey_bits_gost01(pk) + 7) / 8; + if (expected_key_len == 0) { + EVPerror(EVP_R_DECODE_ERROR); + return 0; + } else if (priv_len % expected_key_len == 0) { + /* Key is not wrapped but masked */ + pk_num = unmask_priv_key(pk, pkey_buf, expected_key_len, + priv_len / expected_key_len - 1); + } else if (V_ASN1_OCTET_STRING == *p) { /* New format - Little endian octet string */ ASN1_OCTET_STRING *s = d2i_ASN1_OCTET_STRING(NULL, &p, priv_len); if (s == NULL) { - GOSTerror(EVP_R_DECODE_ERROR); + EVPerror(EVP_R_DECODE_ERROR); ASN1_STRING_free(s); return 0; } pk_num = GOST_le2bn(s->data, s->length, NULL); ASN1_STRING_free(s); - } else { - priv_key = d2i_ASN1_INTEGER(NULL, &p, priv_len); - if (priv_key == NULL) + } else if ((V_ASN1_SEQUENCE | V_ASN1_CONSTRUCTED) == *p) { + /* New format - Structure with masked private and separate public key */ + MASKED_GOST_KEY *s = + d2i_MASKED_GOST_KEY(NULL, &p, priv_len); + + if (s == NULL || + !s->masked_priv_key || + s->masked_priv_key->length % expected_key_len != 0) { + EVPerror(EVP_R_DECODE_ERROR); + MASKED_GOST_KEY_free(s); return 0; - ret = ((pk_num = ASN1_INTEGER_to_BN(priv_key, NULL)) != NULL); - ASN1_INTEGER_free(priv_key); - if (ret == 0) { - GOSTerror(EVP_R_DECODE_ERROR); + } + + pk_num = unmask_priv_key(pk, s->masked_priv_key->data, + expected_key_len, + s->masked_priv_key->length / expected_key_len - 1); + MASKED_GOST_KEY_free(s); + } else if (V_ASN1_INTEGER == *p) { + priv_key = d2i_ASN1_INTEGER(NULL, &p, priv_len); + if (priv_key == NULL) { + EVPerror(EVP_R_DECODE_ERROR); return 0; } + pk_num = ASN1_INTEGER_to_BN(priv_key, NULL); + ASN1_INTEGER_free(priv_key); + } else { + EVPerror(EVP_R_DECODE_ERROR); + return 0; + } + + if (pk_num == NULL) { + EVPerror(EVP_R_DECODE_ERROR); + return 0; } ec = pk->pkey.gost; -- 2.17.1