summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Eremin-Solenikov <dbaryshkov@gmail.com>2016-10-21 17:56:04 +0300
committerDmitry Eremin-Solenikov <dbaryshkov@gmail.com>2017-10-10 11:20:08 +0300
commitf9a40e1aba22810a0813c89fbca8f8ebf2e181c6 (patch)
tree7ee1bf12ec15398714f00bdd1a855c3667bb7814
parent625033d18ef735512aee5d5d451f16b35ed95087 (diff)
downloadgnutls-f9a40e1aba22810a0813c89fbca8f8ebf2e181c6.tar.gz
Add support for importing/exporting GOST private keys
Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
-rw-r--r--doc/Makefile.am10
-rw-r--r--doc/manpages/Makefile.am5
-rw-r--r--lib/includes/gnutls/abstract.h28
-rw-r--r--lib/includes/gnutls/x509.h14
-rw-r--r--lib/libgnutls.map5
-rw-r--r--lib/pk.c65
-rw-r--r--lib/pk.h9
-rw-r--r--lib/privkey_raw.c132
-rw-r--r--lib/x509/key_encode.c44
-rw-r--r--lib/x509/privkey.c121
-rw-r--r--lib/x509/privkey_pkcs8.c185
-rw-r--r--symbols.last5
12 files changed, 623 insertions, 0 deletions
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 643548bcc3..f51da6483b 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -1537,6 +1537,10 @@ FUNCS += functions/gnutls_privkey_export_ecc_raw
FUNCS += functions/gnutls_privkey_export_ecc_raw.short
FUNCS += functions/gnutls_privkey_export_ecc_raw2
FUNCS += functions/gnutls_privkey_export_ecc_raw2.short
+FUNCS += functions/gnutls_privkey_export_gost_raw
+FUNCS += functions/gnutls_privkey_export_gost_raw.short
+FUNCS += functions/gnutls_privkey_export_gost_raw2
+FUNCS += functions/gnutls_privkey_export_gost_raw2.short
FUNCS += functions/gnutls_privkey_export_openpgp
FUNCS += functions/gnutls_privkey_export_openpgp.short
FUNCS += functions/gnutls_privkey_export_pkcs11
@@ -1571,6 +1575,8 @@ FUNCS += functions/gnutls_privkey_import_ext3
FUNCS += functions/gnutls_privkey_import_ext3.short
FUNCS += functions/gnutls_privkey_import_ext4
FUNCS += functions/gnutls_privkey_import_ext4.short
+FUNCS += functions/gnutls_privkey_import_gost_raw
+FUNCS += functions/gnutls_privkey_import_gost_raw.short
FUNCS += functions/gnutls_privkey_import_openpgp
FUNCS += functions/gnutls_privkey_import_openpgp.short
FUNCS += functions/gnutls_privkey_import_openpgp_raw
@@ -2637,6 +2643,8 @@ FUNCS += functions/gnutls_x509_privkey_export_dsa_raw
FUNCS += functions/gnutls_x509_privkey_export_dsa_raw.short
FUNCS += functions/gnutls_x509_privkey_export_ecc_raw
FUNCS += functions/gnutls_x509_privkey_export_ecc_raw.short
+FUNCS += functions/gnutls_x509_privkey_export_gost_raw
+FUNCS += functions/gnutls_x509_privkey_export_gost_raw.short
FUNCS += functions/gnutls_x509_privkey_export_pkcs8
FUNCS += functions/gnutls_x509_privkey_export_pkcs8.short
FUNCS += functions/gnutls_x509_privkey_export_rsa_raw
@@ -2667,6 +2675,8 @@ FUNCS += functions/gnutls_x509_privkey_import_dsa_raw
FUNCS += functions/gnutls_x509_privkey_import_dsa_raw.short
FUNCS += functions/gnutls_x509_privkey_import_ecc_raw
FUNCS += functions/gnutls_x509_privkey_import_ecc_raw.short
+FUNCS += functions/gnutls_x509_privkey_import_gost_raw
+FUNCS += functions/gnutls_x509_privkey_import_gost_raw.short
FUNCS += functions/gnutls_x509_privkey_import_openssl
FUNCS += functions/gnutls_x509_privkey_import_openssl.short
FUNCS += functions/gnutls_x509_privkey_import_pkcs8
diff --git a/doc/manpages/Makefile.am b/doc/manpages/Makefile.am
index 33261509b1..5482a0ccf8 100644
--- a/doc/manpages/Makefile.am
+++ b/doc/manpages/Makefile.am
@@ -564,6 +564,8 @@ APIMANS += gnutls_privkey_export_dsa_raw.3
APIMANS += gnutls_privkey_export_dsa_raw2.3
APIMANS += gnutls_privkey_export_ecc_raw.3
APIMANS += gnutls_privkey_export_ecc_raw2.3
+APIMANS += gnutls_privkey_export_gost_raw.3
+APIMANS += gnutls_privkey_export_gost_raw2.3
APIMANS += gnutls_privkey_export_openpgp.3
APIMANS += gnutls_privkey_export_pkcs11.3
APIMANS += gnutls_privkey_export_rsa_raw.3
@@ -581,6 +583,7 @@ APIMANS += gnutls_privkey_import_ext.3
APIMANS += gnutls_privkey_import_ext2.3
APIMANS += gnutls_privkey_import_ext3.3
APIMANS += gnutls_privkey_import_ext4.3
+APIMANS += gnutls_privkey_import_gost_raw.3
APIMANS += gnutls_privkey_import_openpgp.3
APIMANS += gnutls_privkey_import_openpgp_raw.3
APIMANS += gnutls_privkey_import_pkcs11.3
@@ -1114,6 +1117,7 @@ APIMANS += gnutls_x509_privkey_export2.3
APIMANS += gnutls_x509_privkey_export2_pkcs8.3
APIMANS += gnutls_x509_privkey_export_dsa_raw.3
APIMANS += gnutls_x509_privkey_export_ecc_raw.3
+APIMANS += gnutls_x509_privkey_export_gost_raw.3
APIMANS += gnutls_x509_privkey_export_pkcs8.3
APIMANS += gnutls_x509_privkey_export_rsa_raw.3
APIMANS += gnutls_x509_privkey_export_rsa_raw2.3
@@ -1129,6 +1133,7 @@ APIMANS += gnutls_x509_privkey_import.3
APIMANS += gnutls_x509_privkey_import2.3
APIMANS += gnutls_x509_privkey_import_dsa_raw.3
APIMANS += gnutls_x509_privkey_import_ecc_raw.3
+APIMANS += gnutls_x509_privkey_import_gost_raw.3
APIMANS += gnutls_x509_privkey_import_openssl.3
APIMANS += gnutls_x509_privkey_import_pkcs8.3
APIMANS += gnutls_x509_privkey_import_rsa_raw.3
diff --git a/lib/includes/gnutls/abstract.h b/lib/includes/gnutls/abstract.h
index 63cf55599e..7d9d989e46 100644
--- a/lib/includes/gnutls/abstract.h
+++ b/lib/includes/gnutls/abstract.h
@@ -510,6 +510,14 @@ int gnutls_privkey_import_ecc_raw(gnutls_privkey_t key,
const gnutls_datum_t * y,
const gnutls_datum_t * k);
+int gnutls_privkey_import_gost_raw(gnutls_privkey_t key,
+ gnutls_ecc_curve_t curve,
+ gnutls_digest_algorithm_t digest,
+ gnutls_gost_paramset_t paramset,
+ const gnutls_datum_t * x,
+ const gnutls_datum_t * y,
+ const gnutls_datum_t * k);
+
int gnutls_privkey_sign_data(gnutls_privkey_t signer,
gnutls_digest_algorithm_t hash,
@@ -587,6 +595,26 @@ gnutls_privkey_export_ecc_raw2(gnutls_privkey_t key,
gnutls_datum_t * k,
unsigned flags);
+int
+gnutls_privkey_export_gost_raw(gnutls_privkey_t key,
+ gnutls_ecc_curve_t * curve,
+ gnutls_digest_algorithm_t * digest,
+ gnutls_gost_paramset_t * paramset,
+ gnutls_datum_t * x,
+ gnutls_datum_t * y,
+ gnutls_datum_t * k);
+
+int
+gnutls_privkey_export_gost_raw2(gnutls_privkey_t key,
+ gnutls_ecc_curve_t * curve,
+ gnutls_digest_algorithm_t * digest,
+ gnutls_gost_paramset_t * paramset,
+ gnutls_datum_t * x,
+ gnutls_datum_t * y,
+ gnutls_datum_t * k,
+ unsigned flags);
+
+
int gnutls_x509_crt_privkey_sign(gnutls_x509_crt_t crt,
gnutls_x509_crt_t issuer,
gnutls_privkey_t issuer_key,
diff --git a/lib/includes/gnutls/x509.h b/lib/includes/gnutls/x509.h
index 223ad66cc7..a51ebcacbe 100644
--- a/lib/includes/gnutls/x509.h
+++ b/lib/includes/gnutls/x509.h
@@ -1175,6 +1175,13 @@ int gnutls_x509_privkey_import_ecc_raw(gnutls_x509_privkey_t key,
const gnutls_datum_t * x,
const gnutls_datum_t * y,
const gnutls_datum_t * k);
+int gnutls_x509_privkey_import_gost_raw(gnutls_x509_privkey_t key,
+ gnutls_ecc_curve_t curve,
+ gnutls_digest_algorithm_t digest,
+ gnutls_gost_paramset_t paramset,
+ const gnutls_datum_t * x,
+ const gnutls_datum_t * y,
+ const gnutls_datum_t * k);
int gnutls_x509_privkey_fix(gnutls_x509_privkey_t key);
@@ -1282,6 +1289,13 @@ int gnutls_x509_privkey_export_ecc_raw(gnutls_x509_privkey_t key,
gnutls_datum_t * x,
gnutls_datum_t * y,
gnutls_datum_t * k);
+int gnutls_x509_privkey_export_gost_raw(gnutls_x509_privkey_t key,
+ gnutls_ecc_curve_t * curve,
+ gnutls_digest_algorithm_t * digest,
+ gnutls_gost_paramset_t * paramset,
+ gnutls_datum_t * x,
+ gnutls_datum_t * y,
+ gnutls_datum_t * k);
int gnutls_x509_privkey_sign_data(gnutls_x509_privkey_t key,
gnutls_digest_algorithm_t digest,
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index 995fa1710b..055b24a696 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -1196,6 +1196,11 @@ GNUTLS_3_6_0
gnutls_pubkey_export_gost_raw2;
gnutls_pubkey_import_gost_raw;
gnutls_x509_crt_get_pk_gost_raw;
+ gnutls_x509_privkey_export_gost_raw;
+ gnutls_x509_privkey_import_gost_raw;
+ gnutls_privkey_export_gost_raw;
+ gnutls_privkey_export_gost_raw2;
+ gnutls_privkey_import_gost_raw;
local:
*;
} GNUTLS_3_4;
diff --git a/lib/pk.c b/lib/pk.c
index 4f3d48faa8..7cd7a0e26d 100644
--- a/lib/pk.c
+++ b/lib/pk.c
@@ -1059,6 +1059,71 @@ int _gnutls_params_get_ecc_raw(const gnutls_pk_params_st* params,
}
+int _gnutls_params_get_gost_raw(const gnutls_pk_params_st* params,
+ gnutls_ecc_curve_t * curve,
+ gnutls_digest_algorithm_t * digest,
+ gnutls_gost_paramset_t * paramset,
+ gnutls_datum_t * x,
+ gnutls_datum_t * y,
+ gnutls_datum_t * k,
+ unsigned int flags)
+{
+ int ret;
+ mpi_dprint_func dprint = _gnutls_mpi_dprint_lz;
+
+ if (flags & GNUTLS_EXPORT_FLAG_NO_LZ)
+ dprint = _gnutls_mpi_dprint;
+
+
+ if (params == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ if (curve)
+ *curve = params->curve;
+
+ if (digest)
+ *digest = _gnutls_gost_digest(params->algo);
+
+ if (paramset)
+ *paramset = params->gost_params;
+
+ /* X */
+ if (x) {
+ ret = dprint(params->params[GOST_X], x);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+ }
+
+ /* Y */
+ if (y) {
+ ret = dprint(params->params[GOST_Y], y);
+ if (ret < 0) {
+ gnutls_assert();
+ _gnutls_free_datum(x);
+ return ret;
+ }
+ }
+
+
+ /* K */
+ if (k) {
+ ret = dprint(params->params[GOST_K], k);
+ if (ret < 0) {
+ gnutls_assert();
+ _gnutls_free_datum(x);
+ _gnutls_free_datum(y);
+ return ret;
+ }
+ }
+
+ return 0;
+
+}
+
int
pk_hash_data(gnutls_pk_algorithm_t pk, const mac_entry_st * hash,
gnutls_pk_params_st * params,
diff --git a/lib/pk.h b/lib/pk.h
index cc20bff76e..d14bc531af 100644
--- a/lib/pk.h
+++ b/lib/pk.h
@@ -108,6 +108,15 @@ int _gnutls_params_get_ecc_raw(const gnutls_pk_params_st* params,
gnutls_datum_t * k,
unsigned int flags);
+int _gnutls_params_get_gost_raw(const gnutls_pk_params_st* params,
+ gnutls_ecc_curve_t * curve,
+ gnutls_digest_algorithm_t * digest,
+ gnutls_gost_paramset_t * paramset,
+ gnutls_datum_t * x,
+ gnutls_datum_t * y,
+ gnutls_datum_t * k,
+ unsigned int flags);
+
int pk_prepare_hash(gnutls_pk_algorithm_t pk, const mac_entry_st * hash,
gnutls_datum_t * output);
int pk_hash_data(gnutls_pk_algorithm_t pk, const mac_entry_st * hash,
diff --git a/lib/privkey_raw.c b/lib/privkey_raw.c
index 8e231b1808..fe96126bef 100644
--- a/lib/privkey_raw.c
+++ b/lib/privkey_raw.c
@@ -260,6 +260,86 @@ int ret;
}
/**
+ * gnutls_privkey_export_gost_raw:
+ * @key: Holds the public key
+ * @curve: will hold the curve
+ * @digest: will hold the digest
+ * @x: will hold the x coordinate
+ * @y: will hold the y coordinate
+ * @k: will hold the private key
+ *
+ * This function will export the GOST private key's parameters found
+ * in the given structure. The new parameters will be allocated using
+ * gnutls_malloc() and will be stored in the appropriate datum.
+ *
+ * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
+ *
+ * Since: 3.6.0
+ **/
+int
+gnutls_privkey_export_gost_raw(gnutls_privkey_t key,
+ gnutls_ecc_curve_t * curve,
+ gnutls_digest_algorithm_t * digest,
+ gnutls_gost_paramset_t * paramset,
+ gnutls_datum_t * x,
+ gnutls_datum_t * y,
+ gnutls_datum_t * k)
+{
+ return gnutls_privkey_export_gost_raw2(key, curve, digest,
+ paramset, x, y, k, 0);
+}
+
+/**
+ * gnutls_privkey_export_gost_raw2:
+ * @key: Holds the public key
+ * @curve: will hold the curve
+ * @digest: will hold the digest
+ * @x: will hold the x coordinate
+ * @y: will hold the y coordinate
+ * @k: will hold the private key
+ * @flags: flags from %gnutls_abstract_export_flags_t
+ *
+ * This function will export the GOST private key's parameters found
+ * in the given structure. The new parameters will be allocated using
+ * gnutls_malloc() and will be stored in the appropriate datum.
+ *
+ * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
+ *
+ * Since: 3.6.0
+ **/
+int
+gnutls_privkey_export_gost_raw2(gnutls_privkey_t key,
+ gnutls_ecc_curve_t * curve,
+ gnutls_digest_algorithm_t * digest,
+ gnutls_gost_paramset_t * paramset,
+ gnutls_datum_t * x,
+ gnutls_datum_t * y,
+ gnutls_datum_t * k,
+ unsigned int flags)
+{
+ gnutls_pk_params_st params;
+ int ret;
+
+ if (key == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ gnutls_pk_params_init(&params);
+
+ ret = _gnutls_privkey_get_mpis(key, &params);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret = _gnutls_params_get_gost_raw(&params, curve, digest, paramset,
+ x, y, k, flags);
+
+ gnutls_pk_params_release(&params);
+
+ return ret;
+}
+
+/**
* gnutls_privkey_import_rsa_raw:
* @key: The structure to store the parsed key
* @m: holds the modulus
@@ -415,3 +495,55 @@ error:
return ret;
}
+/**
+ * gnutls_privkey_import_gost_raw:
+ * @key: The key
+ * @curve: holds the curve
+ * @digest: holds the digest
+ * @x: holds the x
+ * @y: holds the y
+ * @k: holds the k
+ *
+ * This function will convert the given GOST private key's parameters to the
+ * native #gnutls_privkey_t format. The output will be stored
+ * in @key.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
+ * negative error value.
+ *
+ * Since: 3.6.0
+ **/
+int
+gnutls_privkey_import_gost_raw(gnutls_privkey_t key,
+ gnutls_ecc_curve_t curve,
+ gnutls_digest_algorithm_t digest,
+ gnutls_gost_paramset_t paramset,
+ const gnutls_datum_t * x,
+ const gnutls_datum_t * y,
+ const gnutls_datum_t * k)
+{
+ int ret;
+ gnutls_x509_privkey_t xkey;
+
+ ret = gnutls_x509_privkey_init(&xkey);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret = gnutls_x509_privkey_import_gost_raw(xkey, curve, digest, paramset, x, y, k);
+ if (ret < 0) {
+ gnutls_assert();
+ goto error;
+ }
+
+ ret = gnutls_privkey_import_x509(key, xkey, GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE);
+ if (ret < 0) {
+ gnutls_assert();
+ goto error;
+ }
+
+ return 0;
+
+error:
+ gnutls_x509_privkey_deinit(xkey);
+ return ret;
+}
diff --git a/lib/x509/key_encode.c b/lib/x509/key_encode.c
index 7663300826..6cd42f2c0f 100644
--- a/lib/x509/key_encode.c
+++ b/lib/x509/key_encode.c
@@ -900,6 +900,46 @@ cleanup:
return ret;
}
+static int
+_gnutls_asn1_encode_gost(ASN1_TYPE * c2, gnutls_pk_params_st * params)
+{
+ int ret;
+ const char *oid;
+
+ oid = gnutls_pk_get_oid(params->algo);
+
+ if (params->params_nr != GOST_PRIVATE_PARAMS || oid == NULL)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ /* first make sure that no previously allocated data are leaked */
+ if (*c2 != ASN1_TYPE_EMPTY) {
+ asn1_delete_structure(c2);
+ *c2 = ASN1_TYPE_EMPTY;
+ }
+
+ if ((ret = asn1_create_element
+ (_gnutls_get_gnutls_asn(), "GNUTLS.GOSTPrivateKey", c2))
+ != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(ret);
+ goto cleanup;
+ }
+
+ ret =
+ _gnutls_x509_write_key_int_le(*c2, "", params->params[GOST_K]);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+
+ return 0;
+
+cleanup:
+ asn1_delete_structure2(c2, ASN1_DELETE_FLAG_ZEROIZE);
+
+ return ret;
+}
/* Encodes the DSA parameters into an ASN.1 DSAPrivateKey structure.
*/
@@ -991,6 +1031,10 @@ int _gnutls_asn1_encode_privkey(ASN1_TYPE * c2,
case GNUTLS_PK_ECDSA:
case GNUTLS_PK_EDDSA_ED25519:
return _gnutls_asn1_encode_ecc(c2, params);
+ case GNUTLS_PK_GOST_01:
+ case GNUTLS_PK_GOST_12_256:
+ case GNUTLS_PK_GOST_12_512:
+ return _gnutls_asn1_encode_gost(c2, params);
default:
return GNUTLS_E_UNIMPLEMENTED_FEATURE;
}
diff --git a/lib/x509/privkey.c b/lib/x509/privkey.c
index 7bf5a9f14a..b83101a9e9 100644
--- a/lib/x509/privkey.c
+++ b/lib/x509/privkey.c
@@ -1173,6 +1173,91 @@ gnutls_x509_privkey_import_ecc_raw(gnutls_x509_privkey_t key,
}
+/**
+ * gnutls_x509_privkey_import_gost_raw:
+ * @key: The data to store the parsed key
+ * @curve: holds the curve
+ * @paramset: holds the parameters id
+ * @x: holds the x
+ * @y: holds the y
+ * @k: holds the k
+ *
+ * This function will convert the given GOST private key's parameters to the
+ * native #gnutls_x509_privkey_t format. The output will be stored
+ * in @key.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
+ * negative error value.
+ *
+ * Since: 3.6.0
+ **/
+int
+gnutls_x509_privkey_import_gost_raw(gnutls_x509_privkey_t key,
+ gnutls_ecc_curve_t curve,
+ gnutls_digest_algorithm_t digest,
+ gnutls_gost_paramset_t paramset,
+ const gnutls_datum_t * x,
+ const gnutls_datum_t * y,
+ const gnutls_datum_t * k)
+{
+ int ret;
+
+ if (key == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ if (paramset < 0) {
+ if (digest == GNUTLS_DIG_GOSTR_94)
+ paramset = GNUTLS_GOST_PARAMSET_CP_A;
+ else
+ paramset = GNUTLS_GOST_PARAMSET_TC26_Z;
+ }
+
+ key->params.curve = curve;
+ key->params.gost_params = paramset;
+ key->params.algo = _gnutls_digest_gost(digest);
+
+ if (_gnutls_mpi_init_scan_nz
+ (&key->params.params[GOST_X], x->data, x->size)) {
+ gnutls_assert();
+ ret = GNUTLS_E_MPI_SCAN_FAILED;
+ goto cleanup;
+ }
+ key->params.params_nr++;
+
+ if (_gnutls_mpi_init_scan_nz
+ (&key->params.params[GOST_Y], y->data, y->size)) {
+ gnutls_assert();
+ ret = GNUTLS_E_MPI_SCAN_FAILED;
+ goto cleanup;
+ }
+ key->params.params_nr++;
+
+ if (_gnutls_mpi_init_scan_nz
+ (&key->params.params[GOST_K], k->data, k->size)) {
+ gnutls_assert();
+ ret = GNUTLS_E_MPI_SCAN_FAILED;
+ goto cleanup;
+ }
+ key->params.params_nr++;
+
+ ret =
+ _gnutls_pk_fixup(key->params.algo, GNUTLS_IMPORT, &key->params);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ return 0;
+
+ cleanup:
+ gnutls_pk_params_clear(&key->params);
+ gnutls_pk_params_release(&key->params);
+ return ret;
+
+}
+
/**
* gnutls_x509_privkey_get_pk_algorithm:
@@ -1456,6 +1541,42 @@ int gnutls_x509_privkey_export_ecc_raw(gnutls_x509_privkey_t key,
}
/**
+ * gnutls_x509_privkey_export_ecc_raw:
+ * @key: a key
+ * @curve: will hold the curve
+ * @digest: will hold the digest
+ * @paramset: will hold the parameters id
+ * @x: will hold the x coordinate
+ * @y: will hold the y coordinate
+ * @k: will hold the private key
+ *
+ * This function will export the GOST private key's parameters found
+ * in the given structure. The new parameters will be allocated using
+ * gnutls_malloc() and will be stored in the appropriate datum.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
+ * negative error value.
+ *
+ * Since: 3.6.0
+ **/
+int gnutls_x509_privkey_export_gost_raw(gnutls_x509_privkey_t key,
+ gnutls_ecc_curve_t * curve,
+ gnutls_digest_algorithm_t * digest,
+ gnutls_gost_paramset_t * paramset,
+ gnutls_datum_t * x,
+ gnutls_datum_t * y,
+ gnutls_datum_t * k)
+{
+ if (key == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ return _gnutls_params_get_gost_raw(&key->params, curve, digest, paramset,
+ x, y, k, 0);
+}
+
+/**
* gnutls_x509_privkey_export_rsa_raw:
* @key: a key
* @m: will hold the modulus
diff --git a/lib/x509/privkey_pkcs8.c b/lib/x509/privkey_pkcs8.c
index 0070288c58..5eeac1371b 100644
--- a/lib/x509/privkey_pkcs8.c
+++ b/lib/x509/privkey_pkcs8.c
@@ -78,6 +78,32 @@ _encode_privkey(gnutls_x509_privkey_t pkey, gnutls_datum_t * raw)
gnutls_assert();
return ret;
+ case GNUTLS_PK_GOST_01:
+ case GNUTLS_PK_GOST_12_256:
+ case GNUTLS_PK_GOST_12_512:
+ if ((ret = asn1_create_element
+ (_gnutls_get_gnutls_asn(), "GNUTLS.GOSTPrivateKey", &spk))
+ != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(ret);
+ goto error;
+ }
+
+ ret = _gnutls_x509_write_key_int_le(spk, "", pkey->params.params[GOST_K]);
+ if (ret < 0) {
+ gnutls_assert();
+ goto error;
+ }
+
+ ret = _gnutls_x509_der_encode(spk, "", raw, 0);
+ if (ret < 0) {
+ gnutls_assert();
+ goto error;
+ }
+
+ asn1_delete_structure2(&spk, ASN1_DELETE_FLAG_ZEROIZE);
+ break;
+
case GNUTLS_PK_RSA:
case GNUTLS_PK_RSA_PSS:
case GNUTLS_PK_ECDSA:
@@ -1101,6 +1127,159 @@ _decode_pkcs8_eddsa_key(ASN1_TYPE pkcs8_asn, gnutls_x509_privkey_t pkey, const c
}
}
+/* Converts a GOST key to
+ * an internal structure (gnutls_private_key)
+ */
+static int
+_privkey_decode_gost_key(const gnutls_datum_t * raw_key,
+ gnutls_x509_privkey_t pkey)
+{
+ int ret;
+
+ if (raw_key->data[0] == ASN1_TAG_INTEGER) {
+ ASN1_TYPE pkey_asn;
+
+ if ((ret = asn1_create_element(_gnutls_get_gnutls_asn(),
+ "GNUTLS.GOSTPrivateKeyOld",
+ &pkey_asn)) != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(ret);
+ goto error;
+ }
+
+ ret = _asn1_strict_der_decode(&pkey_asn,
+ raw_key->data, raw_key->size,
+ NULL);
+ if (ret != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(ret);
+ asn1_delete_structure2(&pkey_asn, ASN1_DELETE_FLAG_ZEROIZE);
+ goto error;
+ }
+
+ ret = _gnutls_x509_read_key_int(pkey_asn, "",
+ &pkey->params.params[GOST_K]);
+ if (ret < 0) {
+ gnutls_assert();
+ asn1_delete_structure2(&pkey_asn, ASN1_DELETE_FLAG_ZEROIZE);
+ goto error;
+ }
+ asn1_delete_structure2(&pkey_asn, ASN1_DELETE_FLAG_ZEROIZE);
+ } else if (raw_key->data[0] == ASN1_TAG_OCTET_STRING) {
+ ASN1_TYPE pkey_asn;
+
+ if ((ret = asn1_create_element(_gnutls_get_gnutls_asn(),
+ "GNUTLS.GOSTPrivateKey",
+ &pkey_asn)) != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(ret);
+ goto error;
+ }
+
+ ret = _asn1_strict_der_decode(&pkey_asn,
+ raw_key->data, raw_key->size,
+ NULL);
+ if (ret != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(ret);
+ asn1_delete_structure2(&pkey_asn, ASN1_DELETE_FLAG_ZEROIZE);
+ goto error;
+ }
+
+ ret = _gnutls_x509_read_key_int_le(pkey_asn, "",
+ &pkey->params.params[GOST_K]);
+ if (ret < 0) {
+ gnutls_assert();
+ asn1_delete_structure2(&pkey_asn, ASN1_DELETE_FLAG_ZEROIZE);
+ goto error;
+ }
+ asn1_delete_structure2(&pkey_asn, ASN1_DELETE_FLAG_ZEROIZE);
+ } else { /* Custom but also used format, no encap */
+ gnutls_assert();
+ ret = GNUTLS_E_PARSING_ERROR;
+ goto error;
+ }
+
+ pkey->params.params_nr++;
+
+ return 0;
+
+ error:
+ return ret;
+
+}
+
+/* Decodes a GOST privateKey from a PKCS8 structure.
+ */
+static int
+_decode_pkcs8_gost_key(ASN1_TYPE pkcs8_asn, gnutls_x509_privkey_t pkey,
+ gnutls_pk_algorithm_t algo)
+{
+ int ret;
+ gnutls_datum_t tmp;
+ unsigned char oid[3 * MAX_OID_SIZE]; /* GOST parameters can have 3 OIDs at most */
+ int len, result;
+
+ gnutls_pk_params_init(&pkey->params);
+
+ len = sizeof(oid);
+ result = asn1_read_value(pkcs8_asn, "privateKeyAlgorithm.parameters",
+ oid, &len);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = GNUTLS_E_PARSING_ERROR;
+ goto error;
+ } else {
+ ret = _gnutls_x509_read_gost_params(oid, len, &pkey->params);
+ if (ret < 0) {
+ gnutls_assert();
+ goto error;
+ }
+ }
+
+ /* Will be fixed later by pk_fixup */
+ ret = _gnutls_mpi_init(&pkey->params.params[GOST_X]);
+ if (ret < 0) {
+ gnutls_assert();
+ goto error;
+ }
+ pkey->params.params_nr++;
+
+ ret = _gnutls_mpi_init(&pkey->params.params[GOST_Y]);
+ if (ret < 0) {
+ gnutls_assert();
+ goto error;
+ }
+ pkey->params.params_nr++;
+
+ _gnutls_mpi_set_ui(pkey->params.params[GOST_X], 0);
+ _gnutls_mpi_set_ui(pkey->params.params[GOST_Y], 0);
+
+ ret = _gnutls_x509_read_value(pkcs8_asn, "privateKey", &tmp);
+ if (ret < 0) {
+ gnutls_assert();
+ goto error;
+ }
+
+ ret = _privkey_decode_gost_key(&tmp, pkey);
+ _gnutls_free_key_datum(&tmp);
+
+ if (ret < 0) {
+ gnutls_assert();
+ goto error;
+ }
+
+ pkey->params.algo = algo;
+
+ return 0;
+
+error:
+ gnutls_pk_params_clear(&pkey->params);
+ gnutls_pk_params_release(&pkey->params);
+
+ return ret;
+}
+
/* Decodes an DSA privateKey and params from a PKCS8 structure.
*/
static int
@@ -1252,6 +1431,12 @@ decode_private_key_info(const gnutls_datum_t * der,
case GNUTLS_PK_EDDSA_ED25519:
result = _decode_pkcs8_eddsa_key(pkcs8_asn, pkey, oid);
break;
+ case GNUTLS_PK_GOST_01:
+ case GNUTLS_PK_GOST_12_256:
+ case GNUTLS_PK_GOST_12_512:
+ result = _decode_pkcs8_gost_key(pkcs8_asn,
+ pkey, pkey->params.algo);
+ break;
default:
result = gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
goto error;
diff --git a/symbols.last b/symbols.last
index f449d52843..b820e41028 100644
--- a/symbols.last
+++ b/symbols.last
@@ -541,6 +541,8 @@ gnutls_privkey_export_dsa_raw2@GNUTLS_3_6_0
gnutls_privkey_export_dsa_raw@GNUTLS_3_4
gnutls_privkey_export_ecc_raw2@GNUTLS_3_6_0
gnutls_privkey_export_ecc_raw@GNUTLS_3_4
+gnutls_privkey_export_gost_raw2@GNUTLS_3_6_0
+gnutls_privkey_export_gost_raw@GNUTLS_3_6_0
gnutls_privkey_export_openpgp@GNUTLS_3_4
gnutls_privkey_export_pkcs11@GNUTLS_3_4
gnutls_privkey_export_rsa_raw2@GNUTLS_3_6_0
@@ -558,6 +560,7 @@ gnutls_privkey_import_ext2@GNUTLS_3_4
gnutls_privkey_import_ext3@GNUTLS_3_4
gnutls_privkey_import_ext4@GNUTLS_3_6_0
gnutls_privkey_import_ext@GNUTLS_3_4
+gnutls_privkey_import_gost_raw@GNUTLS_3_6_0
gnutls_privkey_import_openpgp@GNUTLS_3_4
gnutls_privkey_import_openpgp_raw@GNUTLS_3_4
gnutls_privkey_import_pkcs11@GNUTLS_3_4
@@ -1102,6 +1105,7 @@ gnutls_x509_privkey_export2_pkcs8@GNUTLS_3_4
gnutls_x509_privkey_export@GNUTLS_3_4
gnutls_x509_privkey_export_dsa_raw@GNUTLS_3_4
gnutls_x509_privkey_export_ecc_raw@GNUTLS_3_4
+gnutls_x509_privkey_export_gost_raw@GNUTLS_3_6_0
gnutls_x509_privkey_export_pkcs8@GNUTLS_3_4
gnutls_x509_privkey_export_rsa_raw2@GNUTLS_3_4
gnutls_x509_privkey_export_rsa_raw@GNUTLS_3_4
@@ -1117,6 +1121,7 @@ gnutls_x509_privkey_import2@GNUTLS_3_4
gnutls_x509_privkey_import@GNUTLS_3_4
gnutls_x509_privkey_import_dsa_raw@GNUTLS_3_4
gnutls_x509_privkey_import_ecc_raw@GNUTLS_3_4
+gnutls_x509_privkey_import_gost_raw@GNUTLS_3_6_0
gnutls_x509_privkey_import_openssl@GNUTLS_3_4
gnutls_x509_privkey_import_pkcs8@GNUTLS_3_4
gnutls_x509_privkey_import_rsa_raw2@GNUTLS_3_4