mirror of
https://abf.rosa.ru/djam/libressl.git
synced 2025-02-23 08:02:54 +00:00
260 lines
6.9 KiB
Diff
260 lines
6.9 KiB
Diff
![]() |
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
|
||
|
|