summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2015-09-12 15:47:38 +0200
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2015-09-12 16:22:48 +0200
commit6c8702587943c426e06d5b545af4f143ae17c670 (patch)
tree8a8184b82ccd40564456390f4ab580970a431763
parent9b89f76fc789fd8f8e3bb3c418f25b97b9e71920 (diff)
downloadgnutls-6c8702587943c426e06d5b545af4f143ae17c670.tar.gz
Added API to generate private keys from a given seed
Currently it is restricted to RSA and FIPS 186-4 key generation with SHA384. Relates to #34
-rw-r--r--lib/crypto-backend.h8
-rw-r--r--lib/gnutls.asn12
-rw-r--r--lib/gnutls_int.h3
-rw-r--r--lib/includes/gnutls/abstract.h9
-rw-r--r--lib/includes/gnutls/x509.h7
-rw-r--r--lib/libgnutls.map4
-rw-r--r--lib/nettle/Makefile.am6
-rw-r--r--lib/nettle/int/dsa-fips.h2
-rw-r--r--lib/nettle/int/rsa-fips.h2
-rw-r--r--lib/nettle/int/rsa-keygen-fips186.c23
-rw-r--r--lib/nettle/pk.c37
-rw-r--r--lib/pk.c7
-rw-r--r--lib/privkey.c64
-rw-r--r--lib/x509/key_encode.c33
-rw-r--r--lib/x509/privkey.c108
15 files changed, 293 insertions, 32 deletions
diff --git a/lib/crypto-backend.h b/lib/crypto-backend.h
index 5f6c228fb4..3aba11a842 100644
--- a/lib/crypto-backend.h
+++ b/lib/crypto-backend.h
@@ -173,6 +173,11 @@ typedef struct {
bigint_t params[GNUTLS_MAX_PK_PARAMS];
unsigned int params_nr; /* the number of parameters */
unsigned int flags;
+
+ unsigned int seed_size;
+ uint8_t seed[MAX_PVP_SEED_SIZE];
+ gnutls_digest_algorithm_t palgo;
+
gnutls_pk_algorithm_t algo;
} gnutls_pk_params_st;
@@ -183,7 +188,8 @@ typedef struct {
* Enumeration of public-key flag.
*/
typedef enum {
- GNUTLS_PK_FLAG_NONE = 0
+ GNUTLS_PK_FLAG_NONE = 0,
+ GNUTLS_PK_FLAG_PROVABLE = 1
} gnutls_pk_flag_t;
diff --git a/lib/gnutls.asn b/lib/gnutls.asn
index 9eaae4e158..5a68d8067c 100644
--- a/lib/gnutls.asn
+++ b/lib/gnutls.asn
@@ -26,7 +26,17 @@ RSAPrivateKey ::= SEQUENCE {
exponent1 INTEGER, -- (Usually large) d mod (p-1)
exponent2 INTEGER, -- (Usually large) d mod (q-1)
coefficient INTEGER, -- (Usually large) (inverse of q) mod p
- otherPrimeInfos OtherPrimeInfos OPTIONAL
+ otherInfo RSAOtherInfo OPTIONAL
+}
+
+RSASeed ::= SEQUENCE {
+ algorithm OBJECT IDENTIFIER,
+ seed OCTET STRING
+}
+
+RSAOtherInfo ::= CHOICE {
+ otherPrimeInfos OtherPrimeInfos, -- the hash algorithm OID used for FIPS186-4 generation
+ seed [1] RSASeed
}
OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index 49dcd575f3..fbdee50691 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -178,6 +178,9 @@ typedef enum record_flush_t {
#define HANDSHAKE_HEADER_SIZE(session) (IS_DTLS(session) ? DTLS_HANDSHAKE_HEADER_SIZE : TLS_HANDSHAKE_HEADER_SIZE)
#define MAX_HANDSHAKE_HEADER_SIZE DTLS_HANDSHAKE_HEADER_SIZE
+/* Maximum seed size for provable parameters */
+#define MAX_PVP_SEED_SIZE 256
+
/* This is the maximum handshake message size we send without
fragmentation. This currently ignores record layer overhead. */
#define DTLS_DEFAULT_MTU 1200
diff --git a/lib/includes/gnutls/abstract.h b/lib/includes/gnutls/abstract.h
index c915d7a035..6ebd2ea3bd 100644
--- a/lib/includes/gnutls/abstract.h
+++ b/lib/includes/gnutls/abstract.h
@@ -244,6 +244,12 @@ int
gnutls_privkey_generate (gnutls_privkey_t key,
gnutls_pk_algorithm_t algo, unsigned int bits,
unsigned int flags);
+int
+gnutls_privkey_generate2(gnutls_privkey_t pkey,
+ gnutls_pk_algorithm_t algo, unsigned int bits,
+ unsigned int flags, void *seed, unsigned seed_size);
+
+int gnutls_privkey_get_seed(gnutls_privkey_t key, gnutls_digest_algorithm_t*, void *seed, size_t *seed_size);
int gnutls_privkey_verify_params(gnutls_privkey_t key);
@@ -270,7 +276,8 @@ typedef enum gnutls_privkey_flags {
GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE = 1,
GNUTLS_PRIVKEY_IMPORT_COPY = 1 << 1,
GNUTLS_PRIVKEY_DISABLE_CALLBACKS = 1 << 2,
- GNUTLS_PRIVKEY_SIGN_FLAG_TLS1_RSA = 1 << 4
+ GNUTLS_PRIVKEY_SIGN_FLAG_TLS1_RSA = 1 << 4,
+ GNUTLS_PRIVKEY_FLAG_PROVABLE = 1 << 5
} gnutls_privkey_flags_t;
int gnutls_privkey_import_pkcs11(gnutls_privkey_t pkey,
diff --git a/lib/includes/gnutls/x509.h b/lib/includes/gnutls/x509.h
index 73b98e85a9..beb619522e 100644
--- a/lib/includes/gnutls/x509.h
+++ b/lib/includes/gnutls/x509.h
@@ -1055,6 +1055,13 @@ int gnutls_x509_privkey_get_key_id(gnutls_x509_privkey_t key,
int gnutls_x509_privkey_generate(gnutls_x509_privkey_t key,
gnutls_pk_algorithm_t algo,
unsigned int bits, unsigned int flags);
+int
+gnutls_x509_privkey_generate2(gnutls_x509_privkey_t key,
+ gnutls_pk_algorithm_t algo, unsigned int bits,
+ unsigned int flags, void *seed, unsigned size_size);
+
+int gnutls_x509_privkey_get_seed(gnutls_x509_privkey_t key, gnutls_digest_algorithm_t*, void *seed, size_t *seed_size);
+
int gnutls_x509_privkey_verify_params(gnutls_x509_privkey_t key);
int gnutls_x509_privkey_export(gnutls_x509_privkey_t key,
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index a4f9a3d57b..f17f2bdd14 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -1056,6 +1056,10 @@ GNUTLS_3_4
gnutls_session_set_verify_cert;
gnutls_session_set_verify_cert2;
gnutls_session_get_verify_cert_status;
+ gnutls_privkey_generate2;
+ gnutls_x509_privkey_generate2;
+ gnutls_privkey_get_seed;
+ gnutls_x509_privkey_get_seed;
local:
*;
};
diff --git a/lib/nettle/Makefile.am b/lib/nettle/Makefile.am
index e84ed1f6f4..eaaae17fc5 100644
--- a/lib/nettle/Makefile.am
+++ b/lib/nettle/Makefile.am
@@ -40,10 +40,10 @@ noinst_LTLIBRARIES = libcrypto.la
libcrypto_la_SOURCES = pk.c mpi.c mac.c cipher.c init.c egd.c egd.h \
gnettle.h rnd-common.h rnd-common.c \
- rnd.c
+ rnd.c int/rsa-fips.h int/rsa-keygen-fips186.c int/provable-prime.c
if ENABLE_FIPS140
libcrypto_la_SOURCES += rnd-fips.c int/drbg-aes-self-test.c \
- int/dsa-fips.h int/dsa-keygen-fips186.c int/dsa-validate.c int/provable-prime.c \
- int/drbg-aes.c int/drbg-aes.h int/rsa-fips.h int/rsa-keygen-fips186.c
+ int/dsa-fips.h int/dsa-keygen-fips186.c int/dsa-validate.c \
+ int/drbg-aes.c int/drbg-aes.h
endif
diff --git a/lib/nettle/int/dsa-fips.h b/lib/nettle/int/dsa-fips.h
index e1edfb5125..9d1e4c06d4 100644
--- a/lib/nettle/int/dsa-fips.h
+++ b/lib/nettle/int/dsa-fips.h
@@ -29,8 +29,6 @@
#include <nettle/sha2.h>
#include <fips.h>
-#define MAX_PVP_SEED_SIZE 256
-
#define div_ceil(x,y) ((x+(y)-1)/(y))
struct dss_params_validation_seeds {
diff --git a/lib/nettle/int/rsa-fips.h b/lib/nettle/int/rsa-fips.h
index 6f349909fa..7b1cf701d2 100644
--- a/lib/nettle/int/rsa-fips.h
+++ b/lib/nettle/int/rsa-fips.h
@@ -41,6 +41,8 @@ rsa_generate_fips186_4_keypair(struct rsa_public_key *pub,
void *random_ctx, nettle_random_func * random,
void *progress_ctx,
nettle_progress_func * progress,
+ unsigned *rseed_size,
+ void *rseed,
/* Desired size of modulo, in bits */
unsigned n_size);
diff --git a/lib/nettle/int/rsa-keygen-fips186.c b/lib/nettle/int/rsa-keygen-fips186.c
index 624aa36535..711c2004ea 100644
--- a/lib/nettle/int/rsa-keygen-fips186.c
+++ b/lib/nettle/int/rsa-keygen-fips186.c
@@ -270,12 +270,17 @@ _rsa_generate_fips186_4_keypair(struct rsa_public_key *pub,
if (n_size == 2048) {
if (seed_length != 14 * 2) {
+ _gnutls_debug_log("Seed length must be 28 bytes\n");
return 0;
}
- } else {
+ } else if (n_size == 3072) {
if (seed_length != 16 * 2) {
+ _gnutls_debug_log("Seed length must be 32 bytes\n");
return 0;
}
+ } else {
+ _gnutls_debug_log("Unsupported size for modulus\n");
+ return 0;
}
if (!mpz_tstbit(pub->e, 0)) {
@@ -333,7 +338,6 @@ _rsa_generate_fips186_4_keypair(struct rsa_public_key *pub,
} while (mpz_cmp(t, r) <= 0);
memset(&cert, 0, sizeof(cert));
- memset(seed, 0, seed_length);
mpz_mul(pub->n, key->p, key->q);
@@ -385,11 +389,14 @@ rsa_generate_fips186_4_keypair(struct rsa_public_key *pub,
void *random_ctx, nettle_random_func * random,
void *progress_ctx,
nettle_progress_func * progress,
+ unsigned *rseed_size,
+ void *rseed,
/* Desired size of modulo, in bits */
unsigned n_size)
{
uint8_t seed[32];
unsigned seed_length;
+ int ret;
if (n_size != 2048 && n_size != 3072) {
return 0;
@@ -402,6 +409,16 @@ rsa_generate_fips186_4_keypair(struct rsa_public_key *pub,
random(random_ctx, seed_length, seed);
- return _rsa_generate_fips186_4_keypair(pub, key, seed_length, seed,
+ if (rseed && rseed_size) {
+ if (*rseed_size < seed_length) {
+ return 0;
+ }
+ memcpy(rseed, seed, seed_length);
+ *rseed_size = seed_length;
+ }
+
+ ret = _rsa_generate_fips186_4_keypair(pub, key, seed_length, seed,
progress_ctx, progress, n_size);
+ gnutls_memset(seed, 0, seed_length);
+ return ret;
}
diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c
index 98621ec87b..0d9869a300 100644
--- a/lib/nettle/pk.c
+++ b/lib/nettle/pk.c
@@ -40,8 +40,8 @@
#include <nettle/dsa.h>
#ifdef ENABLE_FIPS140
# include <dsa-fips.h>
-# include <rsa-fips.h>
#endif
+#include <rsa-fips.h>
#include <nettle/rsa.h>
#include <gnutls/crypto.h>
#include <nettle/bignum.h>
@@ -1132,6 +1132,9 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
switch (algo) {
case GNUTLS_PK_DSA:
+ if (params->flags & GNUTLS_PK_FLAG_PROVABLE)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
#ifdef ENABLE_FIPS140
if (_gnutls_fips_mode_enabled() != 0) {
struct dsa_params pub;
@@ -1176,6 +1179,9 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
}
#endif
case GNUTLS_PK_DH:
+ if (params->flags & GNUTLS_PK_FLAG_PROVABLE)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
{
struct dsa_params pub;
mpz_t r;
@@ -1258,15 +1264,23 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
mpz_set_ui(pub.e, 65537);
-#ifdef ENABLE_FIPS140
- if (_gnutls_fips_mode_enabled() != 0) {
- ret =
- rsa_generate_fips186_4_keypair(&pub, &priv, NULL,
- rnd_func, NULL, NULL,
- level);
- } else
-#endif
- {
+ if ((params->flags & GNUTLS_PK_FLAG_PROVABLE) || _gnutls_fips_mode_enabled() != 0) {
+ params->flags |= GNUTLS_PK_FLAG_PROVABLE;
+ params->palgo = GNUTLS_DIG_SHA384;
+
+ if (params->seed_size) {
+ ret = _rsa_generate_fips186_4_keypair(&pub, &priv,
+ params->seed_size, params->seed,
+ NULL, NULL, level);
+ } else {
+ params->seed_size = sizeof(params->seed);
+ ret =
+ rsa_generate_fips186_4_keypair(&pub, &priv, NULL,
+ rnd_func, NULL, NULL,
+ &params->seed_size, params->seed,
+ level);
+ }
+ } else {
ret =
rsa_generate_keypair(&pub, &priv, NULL,
rnd_func, NULL, NULL,
@@ -1309,6 +1323,9 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
break;
}
case GNUTLS_PK_EC:
+ if (params->flags & GNUTLS_PK_FLAG_PROVABLE)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
{
struct ecc_scalar key;
struct ecc_point pub;
diff --git a/lib/pk.c b/lib/pk.c
index 94c89247e0..5bef8b9697 100644
--- a/lib/pk.c
+++ b/lib/pk.c
@@ -186,6 +186,11 @@ int _gnutls_pk_params_copy(gnutls_pk_params_st * dst,
dst->params_nr++;
}
+ if (src->seed_size) {
+ dst->seed_size = src->seed_size;
+ memcpy(dst->seed, src->seed, src->seed_size);
+ }
+
return 0;
fail:
@@ -215,6 +220,8 @@ void gnutls_pk_params_clear(gnutls_pk_params_st * p)
if (p->params[i] != NULL)
_gnutls_mpi_clear(p->params[i]);
}
+ gnutls_memset(p->seed, 0, p->seed_size);
+ p->seed_size = 0;
}
/* Writes the digest information and the digest in a DER encoded
diff --git a/lib/privkey.c b/lib/privkey.c
index 6394a9000e..cb1b88c43a 100644
--- a/lib/privkey.c
+++ b/lib/privkey.c
@@ -62,6 +62,29 @@ gnutls_privkey_type_t gnutls_privkey_get_type(gnutls_privkey_t key)
}
/**
+ * gnutls_privkey_get_seed:
+ * @key: should contain a #gnutls_privkey_t type
+ * @digest: if non-NULL it will contain the digest algorithm used for key generation (if applicable)
+ * @seed: where seed will be copied to
+ * @seed_size: originally holds the size of @seed, will be updated with actual size
+ *
+ * This function will return the seed that was used to generate the
+ * given private key. That function will succeed only if the key was generated
+ * as a provable key.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
+ * negative error value.
+ *
+ * Since: 3.5.0
+ **/
+int gnutls_privkey_get_seed(gnutls_privkey_t key, gnutls_digest_algorithm_t *digest, void *seed, size_t *seed_size)
+{
+ if (key->type != GNUTLS_PRIVKEY_X509)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+ return gnutls_x509_privkey_get_seed(key->key.x509, digest, seed, seed_size);
+}
+
+/**
* gnutls_privkey_get_pk_algorithm:
* @key: should contain a #gnutls_privkey_t type
* @bits: If set will return the number of bits of the parameters (may be NULL)
@@ -735,10 +758,12 @@ gnutls_privkey_export_x509(gnutls_privkey_t pkey,
* @pkey: The private key
* @algo: is one of the algorithms in #gnutls_pk_algorithm_t.
* @bits: the size of the modulus
- * @flags: unused for now. Must be 0.
+ * @flags: Must be zero or flags from #gnutls_privkey_flags_t.
*
* This function will generate a random private key. Note that this
- * function must be called on an empty private key.
+ * function must be called on an empty private key. The flag %GNUTLS_PRIVKEY_FLAG_PROVABLE
+ * instructs the key generation process to use algorithms which generate
+ * provable parameters out of a seed.
*
* Note that when generating an elliptic curve key, the curve
* can be substituted in the place of the bits parameter using the
@@ -756,13 +781,46 @@ gnutls_privkey_generate(gnutls_privkey_t pkey,
gnutls_pk_algorithm_t algo, unsigned int bits,
unsigned int flags)
{
+ return gnutls_privkey_generate2(pkey, algo, bits, flags, NULL, 0);
+}
+
+/**
+ * gnutls_privkey_generate2:
+ * @pkey: The private key
+ * @algo: is one of the algorithms in #gnutls_pk_algorithm_t.
+ * @bits: the size of the modulus
+ * @flags: Must be zero or flags from #gnutls_privkey_flags_t.
+ * @seed: The seed to be used in case of %GNUTLS_PRIVKEY_FLAG_PROVABLE flag
+ * @seed_size: The size of the seed
+ *
+ * This function will generate a random private key. Note that this
+ * function must be called on an empty private key. The flag %GNUTLS_PRIVKEY_FLAG_PROVABLE
+ * instructs the key generation process to use algorithms which generate
+ * provable parameters out of a seed.
+ *
+ * Note that when generating an elliptic curve key, the curve
+ * can be substituted in the place of the bits parameter using the
+ * GNUTLS_CURVE_TO_BITS() macro.
+ *
+ * Do not set the number of bits directly, use gnutls_sec_param_to_pk_bits().
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
+ * negative error value.
+ *
+ * Since: 3.5.0
+ **/
+int
+gnutls_privkey_generate2(gnutls_privkey_t pkey,
+ gnutls_pk_algorithm_t algo, unsigned int bits,
+ unsigned int flags, void *seed, unsigned seed_size)
+{
int ret;
ret = gnutls_x509_privkey_init(&pkey->key.x509);
if (ret < 0)
return gnutls_assert_val(ret);
- ret = gnutls_x509_privkey_generate(pkey->key.x509, algo, bits, flags);
+ ret = gnutls_x509_privkey_generate2(pkey->key.x509, algo, bits, flags, seed, seed_size);
if (ret < 0) {
gnutls_x509_privkey_deinit(pkey->key.x509);
pkey->key.x509 = NULL;
diff --git a/lib/x509/key_encode.c b/lib/x509/key_encode.c
index 7da4cbef2d..99490b0be5 100644
--- a/lib/x509/key_encode.c
+++ b/lib/x509/key_encode.c
@@ -442,11 +442,34 @@ _gnutls_asn1_encode_rsa(ASN1_TYPE * c2, gnutls_pk_params_st * params)
goto cleanup;
}
- if ((result = asn1_write_value(*c2, "otherPrimeInfos",
- NULL, 0)) != ASN1_SUCCESS) {
- gnutls_assert();
- ret = _gnutls_asn2err(result);
- goto cleanup;
+ if (params->flags & GNUTLS_PK_FLAG_PROVABLE && params->seed_size > 0) {
+ if ((result = asn1_write_value(*c2, "otherInfo",
+ "seed", 1)) != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ if ((result = asn1_write_value(*c2, "otherInfo.seed.seed",
+ params->seed, params->seed_size)) != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ if ((result = asn1_write_value(*c2, "otherInfo.seed.algorithm",
+ gnutls_digest_get_oid(params->palgo), 1)) != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+ } else {
+ if ((result = asn1_write_value(*c2, "otherInfo",
+ NULL, 0)) != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(result);
+ goto cleanup;
+ }
}
if ((result =
diff --git a/lib/x509/privkey.c b/lib/x509/privkey.c
index f97477cf9c..9af576cd3c 100644
--- a/lib/x509/privkey.c
+++ b/lib/x509/privkey.c
@@ -134,6 +134,8 @@ _gnutls_privkey_decode_pkcs1_rsa_key(const gnutls_datum_t * raw_key,
{
int result;
ASN1_TYPE pkey_asn;
+ char tmp[64];
+ int tmp_size;
gnutls_pk_params_init(&pkey->params);
@@ -228,6 +230,29 @@ _gnutls_privkey_decode_pkcs1_rsa_key(const gnutls_datum_t * raw_key,
pkey->params.params_nr = RSA_PRIVATE_PARAMS;
+ tmp_size = sizeof(tmp);
+ result = asn1_read_value(pkey_asn, "otherInfo", tmp, &tmp_size);
+ if (result == ASN1_SUCCESS && strcmp(tmp, "seed") == 0) {
+ gnutls_datum_t v;
+ char oid[MAX_OID_SIZE];
+ int oid_size;
+
+ oid_size = sizeof(oid);
+ result = asn1_read_value(pkey_asn, "otherInfo.seed.algorithm", oid, &oid_size);
+ if (result >= 0) {
+ pkey->params.palgo = gnutls_oid_to_digest(oid);
+ }
+
+ result = _gnutls_x509_read_value(pkey_asn, "otherInfo.seed.seed", &v);
+ if (result >= 0) {
+ if (v.size <= sizeof(pkey->params.seed)) {
+ memcpy(pkey->params.seed, v.data, v.size);
+ pkey->params.seed_size = v.size;
+ }
+ gnutls_free(v.data);
+ }
+ }
+
return pkey_asn;
error:
@@ -1482,10 +1507,12 @@ cleanup:
* @key: a key
* @algo: is one of the algorithms in #gnutls_pk_algorithm_t.
* @bits: the size of the modulus
- * @flags: unused for now. Must be 0.
+ * @flags: Must be zero or flags from #gnutls_privkey_flags_t.
*
* This function will generate a random private key. Note that this
- * function must be called on an empty private key.
+ * function must be called on an empty private key. The flag %GNUTLS_PRIVKEY_FLAG_PROVABLE
+ * instructs the key generation process to use algorithms which generate
+ * provable parameters out of a seed.
*
* Note that when generating an elliptic curve key, the curve
* can be substituted in the place of the bits parameter using the
@@ -1504,6 +1531,40 @@ gnutls_x509_privkey_generate(gnutls_x509_privkey_t key,
gnutls_pk_algorithm_t algo, unsigned int bits,
unsigned int flags)
{
+ return gnutls_x509_privkey_generate2(key, algo, bits, flags, NULL, 0);
+}
+
+/**
+ * gnutls_x509_privkey_generate2:
+ * @key: a key
+ * @algo: is one of the algorithms in #gnutls_pk_algorithm_t.
+ * @bits: the size of the modulus
+ * @flags: Must be zero or flags from #gnutls_privkey_flags_t.
+ * @seed: The seed to be used in case of %GNUTLS_PRIVKEY_FLAG_PROVABLE flag
+ * @seed_size: The size of the seed
+ *
+ * This function will generate a random private key. Note that this
+ * function must be called on an empty private key. The flag %GNUTLS_PRIVKEY_FLAG_PROVABLE
+ * instructs the key generation process to use algorithms which generate
+ * provable parameters out of a seed.
+ *
+ * Note that when generating an elliptic curve key, the curve
+ * can be substituted in the place of the bits parameter using the
+ * GNUTLS_CURVE_TO_BITS() macro.
+ *
+ * For DSA keys, if the subgroup size needs to be specified check
+ * the GNUTLS_SUBGROUP_TO_BITS() macro.
+ *
+ * Do not set the number of bits directly, use gnutls_sec_param_to_pk_bits().
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
+ * negative error value.
+ **/
+int
+gnutls_x509_privkey_generate2(gnutls_x509_privkey_t key,
+ gnutls_pk_algorithm_t algo, unsigned int bits,
+ unsigned int flags, void *seed, unsigned seed_size)
+{
int ret;
if (key == NULL) {
@@ -1520,6 +1581,14 @@ gnutls_x509_privkey_generate(gnutls_x509_privkey_t key,
bits = _gnutls_ecc_bits_to_curve(bits);
}
+ if (flags & GNUTLS_PRIVKEY_FLAG_PROVABLE) {
+ key->params.flags |= GNUTLS_PK_FLAG_PROVABLE;
+ if (seed && seed_size < sizeof(key->params.seed)) {
+ key->params.seed_size = seed_size;
+ memcpy(key->params.seed, seed, seed_size);
+ }
+ }
+
ret = _gnutls_pk_generate_params(algo, bits, &key->params);
if (ret < 0) {
gnutls_assert();
@@ -1531,7 +1600,6 @@ gnutls_x509_privkey_generate(gnutls_x509_privkey_t key,
gnutls_assert();
goto cleanup;
}
-
#ifndef ENABLE_FIPS140
ret = _gnutls_pk_verify_priv_params(algo, &key->params);
#else
@@ -1560,6 +1628,40 @@ gnutls_x509_privkey_generate(gnutls_x509_privkey_t key,
}
/**
+ * gnutls_x509_privkey_get_seed:
+ * @key: should contain a #gnutls_x509_privkey_t type
+ * @digest: if non-NULL it will contain the digest algorithm used for key generation (if applicable)
+ * @seed: where seed will be copied to
+ * @seed_size: originally holds the size of @seed, will be updated with actual size
+ *
+ * This function will return the seed that was used to generate the
+ * given private key. That function will succeed only if the key was generated
+ * as a provable key.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
+ * negative error value.
+ *
+ * Since: 3.5.0
+ **/
+int gnutls_x509_privkey_get_seed(gnutls_x509_privkey_t key, gnutls_digest_algorithm_t *digest, void *seed, size_t *seed_size)
+{
+ if (key->params.seed_size == 0)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ if (*seed_size < key->params.seed_size) {
+ *seed_size = key->params.seed_size;
+ return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
+ }
+
+ if (digest)
+ *digest = key->params.palgo;
+
+ memcpy(seed, key->params.seed, key->params.seed_size);
+ *seed_size = key->params.seed_size;
+ return 0;
+}
+
+/**
* gnutls_x509_privkey_verify_params:
* @key: a key
*