libressl/0028-gostr341001-support-unwrapped-private-keys-support.patch

260 lines
6.9 KiB
Diff
Raw Permalink Normal View History

From b24d8544474981c74fcd13630a811ada98e8743d Mon Sep 17 00:00:00 2001
From: Dmitry Baryshkov <dbaryshkov@gmail.com>
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 <dbaryshkov@gmail.com>
---
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