diff options
author | Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> | 2016-10-21 17:56:04 +0300 |
---|---|---|
committer | Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> | 2018-06-23 12:20:16 +0300 |
commit | 9a8ae7b205279bd8e6d2c34bdd45750bb294df7e (patch) | |
tree | 71a25080b83134df6c3abdfebeacc14a98c7db33 | |
parent | 6b8051aeeb74efc28eadb344783ab0e79963198a (diff) | |
download | gnutls-9a8ae7b205279bd8e6d2c34bdd45750bb294df7e.tar.gz |
Add support for importing/exporting GOST private keys
Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
-rw-r--r-- | doc/Makefile.am | 8 | ||||
-rw-r--r-- | doc/manpages/Makefile.am | 4 | ||||
-rw-r--r-- | lib/includes/gnutls/abstract.h | 19 | ||||
-rw-r--r-- | lib/includes/gnutls/x509.h | 14 | ||||
-rw-r--r-- | lib/libgnutls.map | 4 | ||||
-rw-r--r-- | lib/pk.c | 65 | ||||
-rw-r--r-- | lib/pk.h | 9 | ||||
-rw-r--r-- | lib/privkey_raw.c | 102 | ||||
-rw-r--r-- | lib/x509/key_encode.c | 44 | ||||
-rw-r--r-- | lib/x509/privkey.c | 121 | ||||
-rw-r--r-- | lib/x509/privkey_pkcs8.c | 185 | ||||
-rw-r--r-- | symbols.last | 4 |
12 files changed, 579 insertions, 0 deletions
diff --git a/doc/Makefile.am b/doc/Makefile.am index 68a2702227..ed6ee8371c 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -1568,6 +1568,8 @@ 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_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 @@ -1602,6 +1604,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 @@ -2676,6 +2680,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 @@ -2706,6 +2712,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 c10719f4f6..7513e610e5 100644 --- a/doc/manpages/Makefile.am +++ b/doc/manpages/Makefile.am @@ -579,6 +579,7 @@ 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_raw2.3 APIMANS += gnutls_privkey_export_openpgp.3 APIMANS += gnutls_privkey_export_pkcs11.3 APIMANS += gnutls_privkey_export_rsa_raw.3 @@ -596,6 +597,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 @@ -1133,6 +1135,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 @@ -1148,6 +1151,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 bd947b7833..5fa0fb99db 100644 --- a/lib/includes/gnutls/abstract.h +++ b/lib/includes/gnutls/abstract.h @@ -506,6 +506,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, @@ -583,6 +591,17 @@ gnutls_privkey_export_ecc_raw2(gnutls_privkey_t key, gnutls_datum_t * k, unsigned flags); +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 ff6fa52822..7f9c29e253 100644 --- a/lib/includes/gnutls/x509.h +++ b/lib/includes/gnutls/x509.h @@ -1183,6 +1183,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); @@ -1290,6 +1297,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 b1b6630ed9..597ebc1ebd 100644 --- a/lib/libgnutls.map +++ b/lib/libgnutls.map @@ -1229,6 +1229,10 @@ GNUTLS_3_6_3 gnutls_pubkey_export_gost_raw2; gnutls_pubkey_import_gost_raw; gnutls_x509_crt_get_pk_gost_raw; + gnutls_privkey_export_gost_raw2; + gnutls_privkey_import_gost_raw; + gnutls_x509_privkey_export_gost_raw; + gnutls_x509_privkey_import_gost_raw; } GNUTLS_3_6_2; GNUTLS_FIPS140_3_4 { @@ -1075,6 +1075,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, @@ -109,6 +109,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..ff3e900394 100644 --- a/lib/privkey_raw.c +++ b/lib/privkey_raw.c @@ -260,6 +260,56 @@ int ret; } /** + * 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.3 + **/ +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(¶ms); + + ret = _gnutls_privkey_get_mpis(key, ¶ms); + if (ret < 0) + return gnutls_assert_val(ret); + + ret = _gnutls_params_get_gost_raw(¶ms, curve, digest, paramset, + x, y, k, flags); + + gnutls_pk_params_release(¶ms); + + return ret; +} + +/** * gnutls_privkey_import_rsa_raw: * @key: The structure to store the parsed key * @m: holds the modulus @@ -415,3 +465,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.3 + **/ +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 d4be99ef05..83bb54c9aa 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.3 + **/ +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.3 + **/ +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 7e58099e45..263dafc265 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 ac98a2a5fc..cadbd97014 100644 --- a/symbols.last +++ b/symbols.last @@ -558,6 +558,7 @@ 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_3 gnutls_privkey_export_openpgp@GNUTLS_3_4 gnutls_privkey_export_pkcs11@GNUTLS_3_4 gnutls_privkey_export_rsa_raw2@GNUTLS_3_6_0 @@ -575,6 +576,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_3 gnutls_privkey_import_openpgp@GNUTLS_3_4 gnutls_privkey_import_openpgp_raw@GNUTLS_3_4 gnutls_privkey_import_pkcs11@GNUTLS_3_4 @@ -1125,6 +1127,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_3 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 @@ -1140,6 +1143,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_3 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 |