summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2015-12-18 13:25:10 +0100
committerNikos Mavrogiannopoulos <nmav@redhat.com>2015-12-18 14:43:22 +0100
commit613ccc14ba25beb09d2a81a27348b1793908bae0 (patch)
tree9f4c9f2d7161958da6e132d8151f6856cdee4b5a
parent15127ff7aa674b25827c4017a4584261613d4cc9 (diff)
downloadgnutls-613ccc14ba25beb09d2a81a27348b1793908bae0.tar.gz
Added support for generating and reading EdDSA/Ed25519 keys
This adds support for draft-josefsson-pkix-eddsa-04
-rw-r--r--doc/credentials/x509/Makefile.am3
-rw-r--r--doc/credentials/x509/cert-eddsa.pem16
-rw-r--r--doc/credentials/x509/key-eddsa.pem34
-rw-r--r--lib/algorithms.h23
-rw-r--r--lib/algorithms/ecc.c46
-rw-r--r--lib/algorithms/publickey.c3
-rw-r--r--lib/algorithms/secparams.c4
-rw-r--r--lib/algorithms/sign.c3
-rw-r--r--lib/crypto-backend.h3
-rw-r--r--lib/gnutls.asn6
-rw-r--r--lib/gnutls_asn1_tab.c6
-rw-r--r--lib/includes/gnutls/abstract.h10
-rw-r--r--lib/includes/gnutls/gnutls.h.in16
-rw-r--r--lib/libgnutls.map1
-rw-r--r--lib/nettle/pk.c153
-rw-r--r--lib/pk.c79
-rw-r--r--lib/pkcs11_privkey.c4
-rw-r--r--lib/privkey.c12
-rw-r--r--lib/privkey_raw.c4
-rw-r--r--lib/pubkey.c81
-rw-r--r--lib/x509/key_decode.c67
-rw-r--r--lib/x509/key_encode.c153
-rw-r--r--lib/x509/output.c2
-rw-r--r--lib/x509/privkey.c200
-rw-r--r--lib/x509/x509_int.h12
-rw-r--r--src/certtool-args.def6
-rw-r--r--src/certtool-common.c14
-rw-r--r--src/certtool.c14
-rw-r--r--tests/cert-tests/Makefile.am3
-rwxr-xr-xtests/cert-tests/ed2551981
-rw-r--r--tests/cert-tests/pkcs7-detached.eddsa.sig7
31 files changed, 943 insertions, 123 deletions
diff --git a/doc/credentials/x509/Makefile.am b/doc/credentials/x509/Makefile.am
index b40a52ed52..80529f5588 100644
--- a/doc/credentials/x509/Makefile.am
+++ b/doc/credentials/x509/Makefile.am
@@ -1,2 +1,3 @@
EXTRA_DIST = ca-key.pem ca.pem cert-rsa.pem key-rsa.pem clikey.pem clicert.pem \
- clicert-dsa.pem clikey-dsa.pem cert-dsa.pem key-dsa.pem cert-ecc.pem key-ecc.pem
+ clicert-dsa.pem clikey-dsa.pem cert-dsa.pem key-dsa.pem cert-ecc.pem key-ecc.pem \
+ key-eddsa.pem cert-eddsa.pem
diff --git a/doc/credentials/x509/cert-eddsa.pem b/doc/credentials/x509/cert-eddsa.pem
new file mode 100644
index 0000000000..09d78c25a5
--- /dev/null
+++ b/doc/credentials/x509/cert-eddsa.pem
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE-----
+MIICeDCCATCgAwIBAgIIVgPhnwLsqdgwDQYJKoZIhvcNAQELBQAwGTEXMBUGA1UE
+AxMOR251VExTIFRlc3QgQ0EwIBcNMTUwOTI0MTE0MjIzWhgPOTk5OTEyMzEyMzU5
+NTlaMCwxKjAoBgNVBAMTIVNhbXBsZSBFRERTQS1FZDI1NTE5cCBjZXJ0aWZpY2F0
+ZTAtMAgGAytlZAoBAgMhAOXFSeoir493GDgOl4bRshqYqMhUHCcHmk7ad9P8uMLd
+o3YwdDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1UdDwEB
+/wQFAwMHgAAwHQYDVR0OBBYEFMRMRRGSs7LUJRL6DNAMONoJK3rzMB8GA1UdIwQY
+MBaAFE1Wt2oAWPFnkvSmdVUbjlMBA+/PMA0GCSqGSIb3DQEBCwUAA4IBMQCb+OFV
+XeIHDFW717AyLK6YM5RSPn4wrp63aTx13NYbJjwohj54u49MBlA+0hk+W4N4mrIu
+Yft7bj2lUYbPZbl5r+hH4CuPbDNf7ezOnSZtPWls9lEi6aQHZ1fU5ao5h7tQQ9Vz
+ccOgsaA2vx0CudSMoMnUXIqQ8t4gh9WKJuaH6uS3FYFLFZXhDwgQqtld+kyW0M7d
+dh+GQBOp4pgR9EFA2soYryC8TyclRx7LPFFgUlYzj1R3y4EDS3xxkOzp75qqz2Oy
+MRy11WFeq+FPucSrN4Ma8wPgnYp6b8kFCQKseAOPltA3x95TKZRGgVuO1FyyPTDh
+sBSLXS8q9SNIfpQjiNlGVCNitsgRjUESD+VvrpBy2dtUNMe/Aow5HaFFsNwn4t1Q
+xDe2n5f7Ei0HTh8M
+-----END CERTIFICATE-----
diff --git a/doc/credentials/x509/key-eddsa.pem b/doc/credentials/x509/key-eddsa.pem
new file mode 100644
index 0000000000..8aed6cd6b3
--- /dev/null
+++ b/doc/credentials/x509/key-eddsa.pem
@@ -0,0 +1,34 @@
+Setting log level to 4
+Public Key Info:
+ Public Key Algorithm: EdDSA
+ Key Security Level: High (256 bits)
+
+curve: Ed25519p
+private key:
+ fa:da:b9:f4:db:7b:41:d6:ef:57:25:2a:47:fd:90:e6
+ 75:f8:18:44:0e:ce:a0:87:34:50:79:cf:11:8b:f3:2a
+
+
+x:
+ e5:c5:49:ea:22:af:8f:77:18:38:0e:97:86:d1:b2:1a
+ 98:a8:c8:54:1c:27:07:9a:4e:da:77:d3:fc:b8:c2:dd
+
+
+
+Public Key ID: C4:4C:45:11:92:B3:B2:D4:25:12:FA:0C:D0:0C:38:DA:09:2B:7A:F3
+Public key's random art:
++--[Ed25519p]-----+
+| .o+ ..o+=o |
+|+ .o..++.. |
+|.= .o o+= |
+|+ o +o.o |
+|o .ooS |
+|. o . |
+| . o |
+| E |
+| |
++-----------------+
+
+-----BEGIN EDDSA PRIVATE KEY-----
+MCUKAQEEIPraufTbe0HW71clKkf9kOZ1+BhEDs6ghzRQec8Ri/Mq
+-----END EDDSA PRIVATE KEY-----
diff --git a/lib/algorithms.h b/lib/algorithms.h
index db6dd44535..eea9625e5a 100644
--- a/lib/algorithms.h
+++ b/lib/algorithms.h
@@ -318,6 +318,7 @@ unsigned int _gnutls_pk_bits_to_subgroup_bits(unsigned int pk_bits);
struct gnutls_ecc_curve_entry_st {
const char *name;
const char *oid;
+ gnutls_pk_algorithm_t pk; /* PK_EDDSA, or PK_ECDSA */
gnutls_ecc_curve_t id;
int tls_id; /* The RFC4492 namedCurve ID */
int size; /* the size in bytes */
@@ -329,9 +330,29 @@ const gnutls_ecc_curve_entry_st
gnutls_ecc_curve_t gnutls_ecc_curve_get_id(const char *name);
int _gnutls_tls_id_to_ecc_curve(int num);
int _gnutls_ecc_curve_get_tls_id(gnutls_ecc_curve_t supported_ecc);
-gnutls_ecc_curve_t _gnutls_ecc_bits_to_curve(int bits);
+gnutls_ecc_curve_t _gnutls_ecc_bits_to_curve(gnutls_pk_algorithm_t pk, int bits);
#define MAX_ECC_CURVE_SIZE 66
+inline static int _curve_is_eddsa(const gnutls_ecc_curve_entry_st * e)
+{
+ size_t ret = 0;
+
+ if (unlikely(e == NULL))
+ return ret;
+
+ if (e->pk == GNUTLS_PK_EDDSA)
+ return 1;
+ return 0;
+}
+
+#define algo_is_ecc(x) (((x)==GNUTLS_PK_ECDSA||(x)==GNUTLS_PK_EDDSA)?1:0)
+
+inline static int curve_is_eddsa(gnutls_ecc_curve_t id)
+{
+ const gnutls_ecc_curve_entry_st *e = _gnutls_ecc_curve_get_params(id);
+ return _curve_is_eddsa(e);
+}
+
static inline int _gnutls_kx_is_ecc(gnutls_kx_algorithm_t kx)
{
if (kx == GNUTLS_KX_ECDHE_RSA || kx == GNUTLS_KX_ECDHE_ECDSA ||
diff --git a/lib/algorithms/ecc.c b/lib/algorithms/ecc.c
index b42d95aa4d..5bbfac3660 100644
--- a/lib/algorithms/ecc.c
+++ b/lib/algorithms/ecc.c
@@ -34,6 +34,7 @@ static const gnutls_ecc_curve_entry_st ecc_curves[] = {
.name = "SECP192R1",
.oid = "1.2.840.10045.3.1.1",
.id = GNUTLS_ECC_CURVE_SECP192R1,
+ .pk = GNUTLS_PK_ECDSA,
.tls_id = 19,
.size = 24,
},
@@ -41,6 +42,7 @@ static const gnutls_ecc_curve_entry_st ecc_curves[] = {
.name = "SECP224R1",
.oid = "1.3.132.0.33",
.id = GNUTLS_ECC_CURVE_SECP224R1,
+ .pk = GNUTLS_PK_ECDSA,
.tls_id = 21,
.size = 28,
},
@@ -48,6 +50,7 @@ static const gnutls_ecc_curve_entry_st ecc_curves[] = {
.name = "SECP256R1",
.oid = "1.2.840.10045.3.1.7",
.id = GNUTLS_ECC_CURVE_SECP256R1,
+ .pk = GNUTLS_PK_ECDSA,
.tls_id = 23,
.size = 32,
},
@@ -55,6 +58,7 @@ static const gnutls_ecc_curve_entry_st ecc_curves[] = {
.name = "SECP384R1",
.oid = "1.3.132.0.34",
.id = GNUTLS_ECC_CURVE_SECP384R1,
+ .pk = GNUTLS_PK_ECDSA,
.tls_id = 24,
.size = 48,
},
@@ -62,9 +66,18 @@ static const gnutls_ecc_curve_entry_st ecc_curves[] = {
.name = "SECP521R1",
.oid = "1.3.132.0.35",
.id = GNUTLS_ECC_CURVE_SECP521R1,
+ .pk = GNUTLS_PK_ECDSA,
.tls_id = 25,
.size = 66,
},
+ {
+ .name = "Ed25519ph",
+ .oid = "1.3.101.100", /* shared across all EDDSA curves */
+ .id = GNUTLS_ECC_CURVE_ED25519PH,
+ .pk = GNUTLS_PK_EDDSA,
+ .tls_id = 5, /* draft-josefsson-tls-eddsa2-02 */
+ .size = 32,
+ },
{0, 0, 0}
};
@@ -188,12 +201,17 @@ gnutls_ecc_curve_t gnutls_ecc_curve_get_id(const char *name)
* Returns: return a #gnutls_ecc_curve_t value corresponding to
* the specified bit length, or %GNUTLS_ECC_CURVE_INVALID on error.
-*/
-gnutls_ecc_curve_t _gnutls_ecc_bits_to_curve(int bits)
+gnutls_ecc_curve_t _gnutls_ecc_bits_to_curve(gnutls_pk_algorithm_t pk, int bits)
{
- gnutls_ecc_curve_t ret = GNUTLS_ECC_CURVE_SECP256R1;
+ gnutls_ecc_curve_t ret;
+
+ if (pk == GNUTLS_PK_ECDSA)
+ ret = GNUTLS_ECC_CURVE_SECP256R1;
+ else
+ ret = GNUTLS_ECC_CURVE_ED25519PH;
GNUTLS_ECC_CURVE_LOOP(
- if (8 * p->size >= bits && _gnutls_pk_curve_exists(p->id)) {
+ if (pk == p->pk && 8 * p->size >= bits && _gnutls_pk_curve_exists(p->id)) {
ret = p->id;
break;
}
@@ -298,3 +316,25 @@ int gnutls_ecc_curve_get_size(gnutls_ecc_curve_t curve)
return ret;
}
+
+/**
+ * gnutls_ecc_curve_get_pk:
+ * @curve: is an ECC curve
+ *
+ * Returns: the public key algorithm associated with the named curve or %GNUTLS_PK_UNKNOWN.
+ *
+ * Since: 3.5.0
+ **/
+gnutls_pk_algorithm_t gnutls_ecc_curve_get_pk(gnutls_ecc_curve_t curve)
+{
+ int ret = GNUTLS_PK_UNKNOWN;
+
+ GNUTLS_ECC_CURVE_LOOP(
+ if (p->id == curve) {
+ ret = p->pk;
+ break;
+ }
+ );
+
+ return ret;
+}
diff --git a/lib/algorithms/publickey.c b/lib/algorithms/publickey.c
index 183f436899..70ff31e0e2 100644
--- a/lib/algorithms/publickey.c
+++ b/lib/algorithms/publickey.c
@@ -96,7 +96,8 @@ static const gnutls_pk_entry pk_algorithms[] = {
{"DSA", PK_DSA_OID, GNUTLS_PK_DSA},
{"GOST R 34.10-2001", PK_GOST_R3410_2001_OID, GNUTLS_PK_UNKNOWN},
{"GOST R 34.10-94", PK_GOST_R3410_94_OID, GNUTLS_PK_UNKNOWN},
- {"EC", "1.2.840.10045.2.1", GNUTLS_PK_EC},
+ {"EC", "1.2.840.10045.2.1", GNUTLS_PK_ECDSA},
+ {"EdDSA", "1.3.101.100", GNUTLS_PK_EDDSA},
{0, 0, 0}
};
diff --git a/lib/algorithms/secparams.c b/lib/algorithms/secparams.c
index bb9b90d962..0e207c5510 100644
--- a/lib/algorithms/secparams.c
+++ b/lib/algorithms/secparams.c
@@ -88,7 +88,7 @@ gnutls_sec_param_to_pk_bits(gnutls_pk_algorithm_t algo,
if (p->sec_param == param) {
if (algo == GNUTLS_PK_DSA)
ret = p->dsa_bits;
- else if (algo == GNUTLS_PK_EC)
+ else if (algo == GNUTLS_PK_ECDSA || algo == GNUTLS_PK_EDDSA)
ret = p->ecc_bits;
else
ret = p->pk_bits; break;
@@ -185,7 +185,7 @@ gnutls_pk_bits_to_sec_param(gnutls_pk_algorithm_t algo, unsigned int bits)
if (bits == 0)
return GNUTLS_SEC_PARAM_UNKNOWN;
- if (algo == GNUTLS_PK_EC) {
+ if (algo == GNUTLS_PK_ECDSA || algo == GNUTLS_PK_EDDSA) {
GNUTLS_SEC_PARAM_LOOP(
if (p->ecc_bits > bits) {
break;
diff --git a/lib/algorithms/sign.c b/lib/algorithms/sign.c
index f2ac184667..c42205c8c3 100644
--- a/lib/algorithms/sign.c
+++ b/lib/algorithms/sign.c
@@ -96,6 +96,9 @@ static const gnutls_sign_entry sign_algorithms[] = {
GNUTLS_PK_DSA, GNUTLS_DIG_SHA384, {5, 2}},
{"DSA-SHA512", SIG_DSA_SHA512_OID, GNUTLS_SIGN_DSA_SHA512,
GNUTLS_PK_DSA, GNUTLS_DIG_SHA512, {6, 2}},
+ /* draft-josefsson-tls-eddsa2-01 + draft-josefsson-pkix-eddsa-02 */
+ {"EdDSA-SHA512", "1.3.101.101", GNUTLS_SIGN_EDDSA_SHA512,
+ GNUTLS_PK_EDDSA, GNUTLS_DIG_SHA512, {6, 4}},
{0, 0, 0, 0, 0, TLS_SIGN_AID_UNKNOWN}
};
diff --git a/lib/crypto-backend.h b/lib/crypto-backend.h
index 3aba11a842..34eb7123b5 100644
--- a/lib/crypto-backend.h
+++ b/lib/crypto-backend.h
@@ -267,6 +267,9 @@ void gnutls_pk_params_init(gnutls_pk_params_st * p);
#define ECC_Y 1
#define ECC_K 2
+#define EDDSA_PUB 0
+#define EDDSA_PRIV 1
+
#define DSA_P 0
#define DSA_Q 1
#define DSA_G 2
diff --git a/lib/gnutls.asn b/lib/gnutls.asn
index 6342995330..afaefc8403 100644
--- a/lib/gnutls.asn
+++ b/lib/gnutls.asn
@@ -90,6 +90,12 @@ DSAPrivateKey ::= SEQUENCE {
seed [1] ProvableSeed OPTIONAL
}
+EdDSAParameters ::= ENUMERATED { ed25519 (1), ed25519p (2) }
+EdDSAPrivateKey ::= SEQUENCE {
+ curve EdDSAParameters,
+ priv OCTET STRING
+}
+
-- from PKCS#3
DHParameter ::= SEQUENCE {
prime INTEGER, -- p
diff --git a/lib/gnutls_asn1_tab.c b/lib/gnutls_asn1_tab.c
index 5da8f7d742..f7d2163e80 100644
--- a/lib/gnutls_asn1_tab.c
+++ b/lib/gnutls_asn1_tab.c
@@ -61,6 +61,12 @@ const asn1_static_node gnutls_asn1_tab[] = {
{ "priv", 1073741827, NULL },
{ "seed", 536895490, "ProvableSeed"},
{ NULL, 2056, "1"},
+ { "EdDSAParameters", 1610874901, NULL },
+ { "ed25519", 1073741825, "1"},
+ { "ed25519p", 1, "2"},
+ { "EdDSAPrivateKey", 1610612741, NULL },
+ { "curve", 1073741826, "EdDSAParameters"},
+ { "priv", 7, NULL },
{ "DHParameter", 1610612741, NULL },
{ "prime", 1073741827, NULL },
{ "base", 1073741827, NULL },
diff --git a/lib/includes/gnutls/abstract.h b/lib/includes/gnutls/abstract.h
index 772bd36255..6601fea614 100644
--- a/lib/includes/gnutls/abstract.h
+++ b/lib/includes/gnutls/abstract.h
@@ -154,6 +154,10 @@ int gnutls_pubkey_export_ecc_x962(gnutls_pubkey_t key,
gnutls_datum_t * parameters,
gnutls_datum_t * ecpoint);
+int gnutls_pubkey_export_eddsa_raw(gnutls_pubkey_t key,
+ gnutls_ecc_curve_t * curve,
+ gnutls_datum_t * pub);
+
int gnutls_pubkey_export(gnutls_pubkey_t key,
gnutls_x509_crt_fmt_t format,
void *output_data, size_t * output_data_size);
@@ -430,6 +434,12 @@ gnutls_privkey_export_dsa_raw(gnutls_privkey_t key,
gnutls_datum_t * x);
int
+gnutls_privkey_export_eddsa_raw(gnutls_privkey_t key,
+ gnutls_ecc_curve_t * curve,
+ gnutls_datum_t *pub,
+ gnutls_datum_t *priv);
+
+int
gnutls_privkey_export_ecc_raw(gnutls_privkey_t key,
gnutls_ecc_curve_t * curve,
gnutls_datum_t * x,
diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in
index 91df048b3c..351090f6a8 100644
--- a/lib/includes/gnutls/gnutls.h.in
+++ b/lib/includes/gnutls/gnutls.h.in
@@ -657,13 +657,15 @@ typedef enum gnutls_certificate_print_formats {
} gnutls_certificate_print_formats_t;
#define GNUTLS_PK_ECC GNUTLS_PK_EC
+#define GNUTLS_PK_EC GNUTLS_PK_ECDSA
/**
* gnutls_pk_algorithm_t:
* @GNUTLS_PK_UNKNOWN: Unknown public-key algorithm.
* @GNUTLS_PK_RSA: RSA public-key algorithm.
* @GNUTLS_PK_DSA: DSA public-key algorithm.
* @GNUTLS_PK_DH: Diffie-Hellman algorithm. Used to generate parameters.
- * @GNUTLS_PK_EC: Elliptic curve algorithm. Used to generate parameters.
+ * @GNUTLS_PK_ECDSA: Elliptic curve DSA algorithm.
+ * @GNUTLS_PK_EDDSA: Edwards curve Digital signature algorithm.
*
* Enumeration of different public-key algorithms.
*/
@@ -672,7 +674,8 @@ typedef enum {
GNUTLS_PK_RSA = 1,
GNUTLS_PK_DSA = 2,
GNUTLS_PK_DH = 3,
- GNUTLS_PK_EC = 4
+ GNUTLS_PK_ECDSA = 4,
+ GNUTLS_PK_EDDSA = 5
} gnutls_pk_algorithm_t;
const char *gnutls_pk_algorithm_get_name(gnutls_pk_algorithm_t algorithm);
@@ -700,6 +703,7 @@ const char *gnutls_pk_algorithm_get_name(gnutls_pk_algorithm_t algorithm);
* @GNUTLS_SIGN_ECDSA_SHA384: Digital signature algorithm ECDSA with SHA-384.
* @GNUTLS_SIGN_ECDSA_SHA512: Digital signature algorithm ECDSA with SHA-512.
* @GNUTLS_SIGN_ECDSA_SHA224: Digital signature algorithm ECDSA with SHA-224.
+ * @GNUTLS_SIGN_EDDSA_SHA512: Digital signature algorithm EdDSA with SHA-512.
*
* Enumeration of different digital signature algorithms.
*/
@@ -724,7 +728,8 @@ typedef enum {
GNUTLS_SIGN_ECDSA_SHA384 = 15,
GNUTLS_SIGN_ECDSA_SHA512 = 16,
GNUTLS_SIGN_DSA_SHA384 = 17,
- GNUTLS_SIGN_DSA_SHA512 = 18
+ GNUTLS_SIGN_DSA_SHA512 = 18,
+ GNUTLS_SIGN_EDDSA_SHA512 = 19
} gnutls_sign_algorithm_t;
/**
@@ -735,6 +740,7 @@ typedef enum {
* @GNUTLS_ECC_CURVE_SECP256R1: the SECP256R1 curve
* @GNUTLS_ECC_CURVE_SECP384R1: the SECP384R1 curve
* @GNUTLS_ECC_CURVE_SECP521R1: the SECP521R1 curve
+ * @GNUTLS_ECC_CURVE_ED25519PH: the Ed25519 curve (in prehash mode)
*
* Enumeration of ECC curves.
*/
@@ -744,7 +750,8 @@ typedef enum {
GNUTLS_ECC_CURVE_SECP256R1,
GNUTLS_ECC_CURVE_SECP384R1,
GNUTLS_ECC_CURVE_SECP521R1,
- GNUTLS_ECC_CURVE_SECP192R1
+ GNUTLS_ECC_CURVE_SECP192R1,
+ GNUTLS_ECC_CURVE_ED25519PH
} gnutls_ecc_curve_t;
/* macros to allow specifying a specific curve in gnutls_privkey_generate()
@@ -866,6 +873,7 @@ unsigned int
gnutls_sec_param_to_symmetric_bits(gnutls_sec_param_t param) __GNUTLS_CONST__;
/* Elliptic curves */
+gnutls_pk_algorithm_t gnutls_ecc_curve_get_pk(gnutls_ecc_curve_t curve);
const char *
gnutls_ecc_curve_get_name(gnutls_ecc_curve_t curve) __GNUTLS_CONST__;
const char *
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index 7885153be3..fde4f81b73 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -1072,6 +1072,7 @@ GNUTLS_3_4
gnutls_decode_ber_digest_info;
gnutls_encode_ber_digest_info;
gnutls_pkcs7_get_embedded_data;
+ gnutls_ecc_curve_get_pk;
local:
*;
};
diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c
index c7ef0d78c5..e05a84f4c9 100644
--- a/lib/nettle/pk.c
+++ b/lib/nettle/pk.c
@@ -46,10 +46,11 @@
#include <nettle/ecc.h>
#include <nettle/ecdsa.h>
#include <nettle/ecc-curve.h>
+#include <nettle/eddsa.h>
#include <gnettle.h>
#include <fips.h>
-static inline const struct ecc_curve *get_supported_curve(int curve);
+static inline const struct ecc_curve *get_supported_nist_curve(int curve);
static void rnd_func(void *_ctx, size_t length, uint8_t * data)
{
@@ -251,7 +252,7 @@ dh_cleanup:
out->data = NULL;
- curve = get_supported_curve(priv->flags);
+ curve = get_supported_nist_curve(priv->flags);
if (curve == NULL)
return
gnutls_assert_val
@@ -445,14 +446,44 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo,
const mac_entry_st *me;
switch (algo) {
- case GNUTLS_PK_EC: /* we do ECDSA */
+ case GNUTLS_PK_EDDSA:
+ {
+ uint8_t key[32];
+ uint8_t pub[32];
+ int curve_id = pk_params->flags;
+
+ if (curve_id != GNUTLS_ECC_CURVE_ED25519PH)
+ return
+ gnutls_assert_val
+ (GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+
+ /* curve25519 for now */
+ if (nettle_mpz_sizeinbase_256_u(TOMPZ(pk_params->params[EDDSA_PRIV])) > 32)
+ return gnutls_assert_val(GNUTLS_E_PK_SIGN_FAILED);
+
+ if (nettle_mpz_sizeinbase_256_u(TOMPZ(pk_params->params[EDDSA_PUB])) > 32)
+ return gnutls_assert_val(GNUTLS_E_PK_SIGN_FAILED);
+
+ nettle_mpz_get_str_256(32, key, TOMPZ(pk_params->params[EDDSA_PRIV]));
+ nettle_mpz_get_str_256(32, pub, TOMPZ(pk_params->params[EDDSA_PUB]));
+
+ signature->data = gnutls_malloc(ED25519_SIGNATURE_SIZE);
+ if (signature->data == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ signature->size = ED25519_SIGNATURE_SIZE;
+
+ ed25519_sha512_sign(pub, key, vdata->size, vdata->data, signature->data);
+ break;
+ }
+ case GNUTLS_PK_ECDSA: /* we do ECDSA */
{
struct ecc_scalar priv;
struct dsa_signature sig;
int curve_id = pk_params->flags;
const struct ecc_curve *curve;
- curve = get_supported_curve(curve_id);
+ curve = get_supported_nist_curve(curve_id);
if (curve == NULL)
return
gnutls_assert_val
@@ -599,14 +630,41 @@ _wrap_nettle_pk_verify(gnutls_pk_algorithm_t algo,
bigint_t tmp[2] = { NULL, NULL };
switch (algo) {
- case GNUTLS_PK_EC: /* ECDSA */
+ case GNUTLS_PK_EDDSA: /* EdDSA */
+ {
+ uint8_t pub[32];
+ int curve_id = pk_params->flags;
+
+ if (curve_id != GNUTLS_ECC_CURVE_ED25519PH)
+ return
+ gnutls_assert_val
+ (GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+
+ /* curve25519 for now */
+ if (signature->size != ED25519_SIGNATURE_SIZE)
+ return gnutls_assert_val(GNUTLS_E_PK_SIG_VERIFY_FAILED);
+
+ if (nettle_mpz_sizeinbase_256_u(pk_params->params[EDDSA_PUB]) > 32)
+ return gnutls_assert_val(GNUTLS_E_PK_SIG_VERIFY_FAILED);
+
+ nettle_mpz_get_str_256(32, pub, pk_params->params[EDDSA_PUB]);
+
+ ret = ed25519_sha512_verify(pub, vdata->size, vdata->data, signature->data);
+ if (ret == 0) {
+ gnutls_assert();
+ ret = GNUTLS_E_PK_SIG_VERIFY_FAILED;
+ } else
+ ret = 0;
+ break;
+ }
+ case GNUTLS_PK_ECDSA: /* ECDSA */
{
struct ecc_point pub;
struct dsa_signature sig;
int curve_id = pk_params->flags;
const struct ecc_curve *curve;
- curve = get_supported_curve(curve_id);
+ curve = get_supported_nist_curve(curve_id);
if (curve == NULL)
return
gnutls_assert_val
@@ -724,7 +782,7 @@ _wrap_nettle_pk_verify(gnutls_pk_algorithm_t algo,
return ret;
}
-static inline const struct ecc_curve *get_supported_curve(int curve)
+static inline const struct ecc_curve *get_supported_nist_curve(int curve)
{
switch (curve) {
#ifdef ENABLE_NON_SUITEB_CURVES
@@ -744,15 +802,25 @@ static inline const struct ecc_curve *get_supported_curve(int curve)
}
}
+static inline bool get_supported_ed_curve(int curve)
+{
+ switch (curve) {
+ case GNUTLS_ECC_CURVE_ED25519PH:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
static int _wrap_nettle_pk_curve_exists(gnutls_ecc_curve_t curve)
{
- return ((get_supported_curve(curve)!=NULL)?1:0);
+ return ((get_supported_nist_curve(curve)!=NULL||get_supported_ed_curve(curve))?1:0);
}
/* Generates algorithm's parameters. That is:
* For DSA: p, q, and g are generated.
* For RSA: nothing
- * For ECDSA: just checks the curve is ok
+ * For ECDSA/EDDSA: nothing
*/
static int
wrap_nettle_pk_generate_params(gnutls_pk_algorithm_t algo,
@@ -868,7 +936,8 @@ wrap_nettle_pk_generate_params(gnutls_pk_algorithm_t algo,
break;
}
case GNUTLS_PK_RSA:
- case GNUTLS_PK_EC:
+ case GNUTLS_PK_ECDSA:
+ case GNUTLS_PK_EDDSA:
ret = 0;
break;
default:
@@ -1337,7 +1406,34 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
break;
}
- case GNUTLS_PK_EC:
+ case GNUTLS_PK_EDDSA:
+ {
+ /* one option for now -> curve25519 */
+ uint8_t key[32];
+ uint8_t pub[32];
+
+ if (params->flags & GNUTLS_PK_FLAG_PROVABLE)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ ret = gnutls_rnd(GNUTLS_RND_RANDOM, key, sizeof(key));
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ed25519_sha512_public_key(pub, key);
+
+ ret = _gnutls_mpi_init_multi(&params->params[EDDSA_PRIV], &params->params[EDDSA_PUB], NULL);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ nettle_mpz_set_str_256_u(TOMPZ(params->params[EDDSA_PRIV]), 32, key);
+ nettle_mpz_set_str_256_u(TOMPZ(params->params[EDDSA_PUB]), 32, pub);
+
+ params->flags = GNUTLS_ECC_CURVE_ED25519PH;
+ params->params_nr = 2;
+
+ break;
+ }
+ case GNUTLS_PK_ECDSA:
if (params->flags & GNUTLS_PK_FLAG_PROVABLE)
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
@@ -1346,7 +1442,7 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
struct ecc_point pub;
const struct ecc_curve *curve;
- curve = get_supported_curve(level);
+ curve = get_supported_nist_curve(level);
if (curve == NULL)
return
gnutls_assert_val
@@ -1526,7 +1622,7 @@ wrap_nettle_pk_verify_priv_params(gnutls_pk_algorithm_t algo,
}
break;
- case GNUTLS_PK_EC:
+ case GNUTLS_PK_ECDSA:
{
struct ecc_point r, pub;
struct ecc_scalar priv;
@@ -1538,7 +1634,7 @@ wrap_nettle_pk_verify_priv_params(gnutls_pk_algorithm_t algo,
gnutls_assert_val
(GNUTLS_E_INVALID_REQUEST);
- curve = get_supported_curve(params->flags);
+ curve = get_supported_nist_curve(params->flags);
if (curve == NULL)
return
gnutls_assert_val
@@ -1599,6 +1695,9 @@ wrap_nettle_pk_verify_priv_params(gnutls_pk_algorithm_t algo,
mpz_clear(y2);
}
break;
+ case GNUTLS_PK_EDDSA:
+ ret = 0;
+ break;
default:
ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
}
@@ -1615,8 +1714,9 @@ wrap_nettle_pk_verify_pub_params(gnutls_pk_algorithm_t algo,
switch (algo) {
case GNUTLS_PK_RSA:
case GNUTLS_PK_DSA:
+ case GNUTLS_PK_EDDSA:
return 0;
- case GNUTLS_PK_EC:
+ case GNUTLS_PK_ECDSA:
{
/* just verify that x and y lie on the curve */
struct ecc_point r, pub;
@@ -1627,7 +1727,7 @@ wrap_nettle_pk_verify_pub_params(gnutls_pk_algorithm_t algo,
gnutls_assert_val
(GNUTLS_E_INVALID_REQUEST);
- curve = get_supported_curve(params->flags);
+ curve = get_supported_nist_curve(params->flags);
if (curve == NULL)
return
gnutls_assert_val
@@ -1741,6 +1841,27 @@ wrap_nettle_pk_fixup(gnutls_pk_algorithm_t algo,
params->params_nr = RSA_PRIVATE_PARAMS;
}
+ if (direction == GNUTLS_IMPORT && algo == GNUTLS_PK_EDDSA) {
+ uint8_t key[32];
+ uint8_t pub[32];
+
+ if (params->flags != GNUTLS_ECC_CURVE_ED25519PH)
+ return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+
+ nettle_mpz_get_str_256(32, key, params->params[EDDSA_PRIV]);
+
+ ed25519_sha512_public_key(pub, key);
+
+ zrelease_mpi_key(&params->params[EDDSA_PUB]);
+
+ ret =
+ _gnutls_mpi_init_scan_nz(&params->params[EDDSA_PUB], pub, sizeof(pub));
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ params->params_nr = 2;
+ }
+
return 0;
}
diff --git a/lib/pk.c b/lib/pk.c
index 6864c857e7..70690512d9 100644
--- a/lib/pk.c
+++ b/lib/pk.c
@@ -649,36 +649,63 @@ int _gnutls_params_get_ecc_raw(const gnutls_pk_params_st* params,
if (curve)
*curve = params->flags;
- /* X */
- if (x) {
- ret = _gnutls_mpi_dprint_lz(params->params[ECC_X], x);
- if (ret < 0) {
- gnutls_assert();
- return ret;
+ if (params->algo == GNUTLS_PK_EDDSA) {
+ unsigned size;
+ size = gnutls_ecc_curve_get_size(params->flags);
+
+ if (x) {
+ ret = _gnutls_mpi_dprint_size(params->params[EDDSA_PUB], x, size);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
}
- }
- /* Y */
- if (y) {
- ret = _gnutls_mpi_dprint_lz(params->params[ECC_Y], y);
- if (ret < 0) {
- gnutls_assert();
- _gnutls_free_datum(x);
- return ret;
+ if (y) {
+ y->data = NULL;
+ y->size = 0;
}
- }
+ if (k) {
+ ret = _gnutls_mpi_dprint_size(params->params[EDDSA_PRIV], k, size);
+ if (ret < 0) {
+ gnutls_assert();
+ _gnutls_free_datum(x);
+ return ret;
+ }
+ }
+ } else if (params->algo == GNUTLS_PK_ECDSA) {
+ /* X */
+ if (x) {
+ ret = _gnutls_mpi_dprint_lz(params->params[ECC_X], x);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+ }
- /* K */
- if (k) {
- ret = _gnutls_mpi_dprint_lz(params->params[ECC_K], k);
- if (ret < 0) {
- gnutls_assert();
- _gnutls_free_datum(x);
- _gnutls_free_datum(y);
- return ret;
+ /* Y */
+ if (y) {
+ ret = _gnutls_mpi_dprint_lz(params->params[ECC_Y], y);
+ if (ret < 0) {
+ gnutls_assert();
+ _gnutls_free_datum(x);
+ return ret;
+ }
}
- }
+
+ /* K */
+ if (k) {
+ ret = _gnutls_mpi_dprint_lz(params->params[ECC_K], k);
+ if (ret < 0) {
+ gnutls_assert();
+ _gnutls_free_datum(x);
+ _gnutls_free_datum(y);
+ return ret;
+ }
+ }
+ } else
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
return 0;
@@ -742,7 +769,8 @@ pk_prepare_hash(gnutls_pk_algorithm_t pk,
_gnutls_free_datum(&old_digest);
break;
case GNUTLS_PK_DSA:
- case GNUTLS_PK_EC:
+ case GNUTLS_PK_ECDSA:
+ case GNUTLS_PK_EDDSA:
break;
default:
gnutls_assert();
@@ -751,3 +779,4 @@ pk_prepare_hash(gnutls_pk_algorithm_t pk,
return 0;
}
+
diff --git a/lib/pkcs11_privkey.c b/lib/pkcs11_privkey.c
index 237af98c18..e7430ec211 100644
--- a/lib/pkcs11_privkey.c
+++ b/lib/pkcs11_privkey.c
@@ -835,7 +835,7 @@ gnutls_pkcs11_privkey_generate3(const char *url, gnutls_pk_algorithm_t pk,
a[a_val].value_len = sizeof(_bits);
a_val++;
break;
- case GNUTLS_PK_EC:
+ case GNUTLS_PK_ECDSA:
p[p_val].type = CKA_SIGN;
if (key_usage & GNUTLS_KEY_DIGITAL_SIGNATURE) {
p[p_val].value = (void *) &tval;
@@ -854,7 +854,7 @@ gnutls_pkcs11_privkey_generate3(const char *url, gnutls_pk_algorithm_t pk,
if (GNUTLS_BITS_ARE_CURVE(bits)) {
bits = GNUTLS_BITS_TO_CURVE(bits);
} else {
- bits = _gnutls_ecc_bits_to_curve(bits);
+ bits = _gnutls_ecc_bits_to_curve(pk, bits);
}
ret = _gnutls_x509_write_ecc_params(bits, &der);
diff --git a/lib/privkey.c b/lib/privkey.c
index 90a6304796..addc31938d 100644
--- a/lib/privkey.c
+++ b/lib/privkey.c
@@ -202,6 +202,18 @@ privkey_to_pubkey(gnutls_pk_algorithm_t pk,
}
break;
+ case GNUTLS_PK_EDDSA:
+ pub->params[EDDSA_PUB] = _gnutls_mpi_copy(priv->params[EDDSA_PUB]);
+
+ pub->params_nr = 1;
+
+ if (pub->params[EDDSA_PUB] == NULL) {
+ gnutls_assert();
+ ret = GNUTLS_E_MEMORY_ERROR;
+ goto cleanup;
+ }
+
+ break;
default:
gnutls_assert();
return GNUTLS_E_INVALID_REQUEST;
diff --git a/lib/privkey_raw.c b/lib/privkey_raw.c
index 47754831ee..fe6190b8ce 100644
--- a/lib/privkey_raw.c
+++ b/lib/privkey_raw.c
@@ -127,7 +127,6 @@ int ret;
return ret;
}
-
/**
* gnutls_privkey_export_ecc_raw:
* @key: Holds the public key
@@ -138,7 +137,8 @@ int ret;
*
* This function will export the ECC 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.
+ * gnutls_malloc() and will be stored in the appropriate datum. For
+ * EdDSA keys, the @y value should be %NULL.
*
* Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
*
diff --git a/lib/pubkey.c b/lib/pubkey.c
index 23b0625f5b..331e8991bb 100644
--- a/lib/pubkey.c
+++ b/lib/pubkey.c
@@ -50,7 +50,8 @@ int pubkey_to_bits(gnutls_pk_algorithm_t pk, gnutls_pk_params_st * params)
return _gnutls_mpi_get_nbits(params->params[RSA_MODULUS]);
case GNUTLS_PK_DSA:
return _gnutls_mpi_get_nbits(params->params[DSA_P]);
- case GNUTLS_PK_EC:
+ case GNUTLS_PK_ECDSA:
+ case GNUTLS_PK_EDDSA:
return gnutls_ecc_curve_get_size(params->flags) * 8;
default:
return 0;
@@ -289,14 +290,19 @@ gnutls_pubkey_get_preferred_hash_algorithm(gnutls_pubkey_t key,
if (mand)
*mand = 1;
/* fallthrough */
- case GNUTLS_PK_EC:
-
+ case GNUTLS_PK_ECDSA:
me = _gnutls_dsa_q_to_hash(key->pk_algorithm, &key->params, NULL);
if (hash)
*hash = (gnutls_digest_algorithm_t)me->id;
ret = 0;
break;
+ case GNUTLS_PK_EDDSA:
+ if (hash)
+ *hash = GNUTLS_DIG_SHA512;
+
+ ret = 0;
+ break;
case GNUTLS_PK_RSA:
if (hash)
*hash = GNUTLS_DIG_SHA256;
@@ -952,6 +958,7 @@ gnutls_pubkey_export_dsa_raw(gnutls_pubkey_t key,
* This function will export the ECC public key's parameters found in
* the given key. The new parameters will be allocated using
* gnutls_malloc() and will be stored in the appropriate datum.
+ * For EdDSA public keys, @y will be set to %NULL.
*
* This function allows for %NULL parameters since 3.4.1.
*
@@ -971,7 +978,7 @@ gnutls_pubkey_export_ecc_raw(gnutls_pubkey_t key,
return GNUTLS_E_INVALID_REQUEST;
}
- if (key->pk_algorithm != GNUTLS_PK_EC) {
+ if (key->pk_algorithm != GNUTLS_PK_EDDSA && key->pk_algorithm != GNUTLS_PK_ECDSA) {
gnutls_assert();
return GNUTLS_E_INVALID_REQUEST;
}
@@ -979,6 +986,21 @@ gnutls_pubkey_export_ecc_raw(gnutls_pubkey_t key,
if (curve)
*curve = key->params.flags;
+ if (key->pk_algorithm == GNUTLS_PK_EDDSA) {
+ /* X */
+ if (x) {
+ ret = _gnutls_mpi_dprint_size(key->params.params[EDDSA_PUB], x, gnutls_ecc_curve_get_size(key->params.flags));
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+ }
+
+ return 0;
+ }
+
+ /* ECDSA keys */
+
/* X */
if (x) {
ret = _gnutls_mpi_dprint_lz(key->params.params[ECC_X], x);
@@ -1426,14 +1448,18 @@ gnutls_pubkey_import_ecc_raw(gnutls_pubkey_t key,
}
key->params.params_nr++;
- if (_gnutls_mpi_init_scan_nz
- (&key->params.params[ECC_Y], y->data, y->size)) {
- gnutls_assert();
- ret = GNUTLS_E_MPI_SCAN_FAILED;
- goto cleanup;
+ if (!curve_is_eddsa(curve)) {
+ if (_gnutls_mpi_init_scan_nz
+ (&key->params.params[ECC_Y], y->data, y->size)) {
+ gnutls_assert();
+ ret = GNUTLS_E_MPI_SCAN_FAILED;
+ goto cleanup;
+ }
+ key->params.params_nr++;
+ key->pk_algorithm = GNUTLS_PK_ECDSA;
+ } else {
+ key->pk_algorithm = GNUTLS_PK_EDDSA;
}
- key->params.params_nr++;
- key->pk_algorithm = GNUTLS_PK_EC;
return 0;
@@ -1891,6 +1917,30 @@ dsa_verify_data(gnutls_pk_algorithm_t pk,
return _gnutls_pk_verify(pk, &digest, signature, params);
}
+static int
+eddsa_verify_data(gnutls_pk_algorithm_t pk,
+ const mac_entry_st * algo,
+ const gnutls_datum_t * data,
+ const gnutls_datum_t * signature,
+ gnutls_pk_params_st * params)
+{
+ int ret;
+ uint8_t _digest[MAX_HASH_SIZE];
+ gnutls_datum_t digest;
+
+ if (algo == NULL)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ ret = _gnutls_hash_fast(algo->id, data->data, data->size, _digest);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ digest.data = _digest;
+ digest.size = _gnutls_hash_get_algo_len(algo);
+
+ return _gnutls_pk_verify(pk, &digest, signature, params);
+}
+
/* Verifies the signature data, and returns GNUTLS_E_PK_SIG_VERIFY_FAILED if
* not verified, or 1 otherwise.
*/
@@ -1965,6 +2015,15 @@ pubkey_verify_data(gnutls_pk_algorithm_t pk,
return 1;
break;
+ case GNUTLS_PK_EDDSA:
+ if (eddsa_verify_data(pk, me, data, signature, issuer_params)
+ != 0) {
+ gnutls_assert();
+ return GNUTLS_E_PK_SIG_VERIFY_FAILED;
+ }
+
+ return 1;
+ break;
default:
gnutls_assert();
return GNUTLS_E_INTERNAL_ERROR;
diff --git a/lib/x509/key_decode.c b/lib/x509/key_decode.c
index 049e93a951..11548b22f2 100644
--- a/lib/x509/key_decode.c
+++ b/lib/x509/key_decode.c
@@ -37,6 +37,8 @@ static int _gnutls_x509_read_dsa_pubkey(uint8_t * der, int dersize,
gnutls_pk_params_st * params);
static int _gnutls_x509_read_ecc_pubkey(uint8_t * der, int dersize,
gnutls_pk_params_st * params);
+static int _gnutls_x509_read_eddsa_pubkey(uint8_t * der, int dersize,
+ gnutls_pk_params_st * params);
static int
_gnutls_x509_read_dsa_params(uint8_t * der, int dersize,
@@ -109,6 +111,12 @@ _gnutls_x509_read_ecc_pubkey(uint8_t * der, int dersize,
&params->params[ECC_Y]);
}
+int
+_gnutls_x509_read_eddsa_pubkey(uint8_t * der, int dersize,
+ gnutls_pk_params_st * params)
+{
+ return _gnutls_mpi_init_scan(&params->params[EDDSA_PUB], der, dersize);
+}
/* reads p,q and g
* from the certificate (subjectPublicKey BIT STRING).
@@ -228,7 +236,55 @@ _gnutls_x509_read_ecc_params(uint8_t * der, int dersize,
asn1_delete_structure(&spk);
return ret;
+}
+
+/* params as defined in draft-josefsson-pkix-eddsa-02
+ */
+int
+_gnutls_x509_read_eddsa_params(uint8_t * der, int dersize,
+ unsigned int * curve)
+{
+ int ret;
+ ASN1_TYPE spk = ASN1_TYPE_EMPTY;
+ unsigned int cid;
+ if ((ret = asn1_create_element
+ (_gnutls_get_gnutls_asn(), "GNUTLS.EdDSAParameters",
+ &spk)) != ASN1_SUCCESS) {
+ gnutls_assert();
+ return _gnutls_asn2err(ret);
+ }
+
+ ret = asn1_der_decoding(&spk, der, dersize, NULL);
+ if (ret != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(ret);
+ goto cleanup;
+ }
+
+ /* read the curve */
+ ret = _gnutls_x509_read_uint(spk, "", &cid);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ if (cid != 2) {
+ _gnutls_debug_log("EdDSA curve %u is not supported\n", cid);
+ gnutls_assert();
+ ret = GNUTLS_E_ECC_UNSUPPORTED_CURVE;
+ goto cleanup;
+ }
+
+ *curve = GNUTLS_ECC_CURVE_ED25519PH;
+
+ ret = 0;
+
+ cleanup:
+
+ asn1_delete_structure(&spk);
+
+ return ret;
}
int _gnutls_x509_read_pubkey(gnutls_pk_algorithm_t algo, uint8_t * der,
@@ -247,11 +303,16 @@ int _gnutls_x509_read_pubkey(gnutls_pk_algorithm_t algo, uint8_t * der,
if (ret >= 0)
params->params_nr = DSA_PUBLIC_PARAMS;
break;
- case GNUTLS_PK_EC:
+ case GNUTLS_PK_ECDSA:
ret = _gnutls_x509_read_ecc_pubkey(der, dersize, params);
if (ret >= 0)
params->params_nr = ECC_PUBLIC_PARAMS;
break;
+ case GNUTLS_PK_EDDSA:
+ ret = _gnutls_x509_read_eddsa_pubkey(der, dersize, params);
+ if (ret >= 0)
+ params->params_nr = 1;
+ break;
default:
ret = gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
break;
@@ -268,8 +329,10 @@ int _gnutls_x509_read_pubkey_params(gnutls_pk_algorithm_t algo,
return 0;
case GNUTLS_PK_DSA:
return _gnutls_x509_read_dsa_params(der, dersize, params);
- case GNUTLS_PK_EC:
+ case GNUTLS_PK_ECDSA:
return _gnutls_x509_read_ecc_params(der, dersize, &params->flags);
+ case GNUTLS_PK_EDDSA:
+ return _gnutls_x509_read_eddsa_params(der, dersize, &params->flags);
default:
return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
}
diff --git a/lib/x509/key_encode.c b/lib/x509/key_encode.c
index 8ebc9fabc7..fd0b034bd2 100644
--- a/lib/x509/key_encode.c
+++ b/lib/x509/key_encode.c
@@ -128,6 +128,34 @@ _gnutls_x509_write_ecc_pubkey(gnutls_pk_params_st * params,
return 0;
}
+/*
+ * some x509 certificate functions that relate to MPI parameter
+ * setting. This writes a raw public key.
+ *
+ * Allocates the space used to store the data.
+ */
+int
+_gnutls_x509_write_eddsa_pubkey(gnutls_pk_params_st * params,
+ gnutls_datum_t * raw)
+{
+ int ret;
+
+ raw->data = NULL;
+ raw->size = 0;
+
+ if (params->params_nr < 1)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ if (params->flags != GNUTLS_ECC_CURVE_ED25519PH)
+ return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+
+ ret = _gnutls_mpi_dprint_size(params->params[EDDSA_PUB], raw, 32);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ return 0;
+}
+
int
_gnutls_x509_write_pubkey_params(gnutls_pk_algorithm_t algo,
gnutls_pk_params_st * params,
@@ -144,8 +172,10 @@ _gnutls_x509_write_pubkey_params(gnutls_pk_algorithm_t algo,
memcpy(der->data, ASN1_NULL, ASN1_NULL_SIZE);
der->size = ASN1_NULL_SIZE;
return 0;
- case GNUTLS_PK_EC:
+ case GNUTLS_PK_ECDSA:
return _gnutls_x509_write_ecc_params(params->flags, der);
+ case GNUTLS_PK_EDDSA:
+ return _gnutls_x509_write_eddsa_params(params->flags, der);
default:
return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
}
@@ -161,8 +191,10 @@ _gnutls_x509_write_pubkey(gnutls_pk_algorithm_t algo,
return _gnutls_x509_write_dsa_pubkey(params, der);
case GNUTLS_PK_RSA:
return _gnutls_x509_write_rsa_pubkey(params, der);
- case GNUTLS_PK_EC:
+ case GNUTLS_PK_ECDSA:
return _gnutls_x509_write_ecc_pubkey(params, der);
+ case GNUTLS_PK_EDDSA:
+ return _gnutls_x509_write_eddsa_pubkey(params, der);
default:
return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
}
@@ -286,6 +318,58 @@ _gnutls_x509_write_ecc_params(gnutls_ecc_curve_t curve,
}
/*
+ * This function writes the parameters for EdDSA keys.
+ * That is the EdDSAParameters struct.
+ *
+ * Allocates the space used to store the DER data.
+ */
+int
+_gnutls_x509_write_eddsa_params(gnutls_ecc_curve_t curve,
+ gnutls_datum_t * der)
+{
+ int result;
+ ASN1_TYPE spk = ASN1_TYPE_EMPTY;
+ const uint8_t two = '\x02';
+ const char *oid;
+
+ der->data = NULL;
+ der->size = 0;
+
+ if (curve != GNUTLS_ECC_CURVE_ED25519PH)
+ return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+
+ oid = gnutls_ecc_curve_get_oid(curve);
+ if (oid == NULL)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ if ((result = asn1_create_element
+ (_gnutls_get_gnutls_asn(), "GNUTLS.EdDSAParameters", &spk))
+ != ASN1_SUCCESS) {
+ gnutls_assert();
+ return _gnutls_asn2err(result);
+ }
+
+ if ((result =
+ asn1_write_value(spk, "", &two, 1)) != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ result = _gnutls_x509_der_encode(spk, "", der, 0);
+ if (result < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ result = 0;
+
+ cleanup:
+ asn1_delete_structure(&spk);
+ return result;
+}
+
+/*
* This function writes the public parameters for DSS keys.
* Needs 1 parameter (y).
*
@@ -579,6 +663,69 @@ cleanup:
return ret;
}
+/* Encodes the EDDSA parameters into an ASN.1 ECPrivateKey structure.
+ */
+static int
+_gnutls_asn1_encode_eddsa(ASN1_TYPE * c2, gnutls_pk_params_st * params)
+{
+ int ret;
+ const uint8_t two = '\x01';
+ gnutls_datum_t key = {NULL, 0};
+ const char *oid;
+
+ oid = gnutls_ecc_curve_get_oid(params->flags);
+
+ if (params->params_nr != 2 || oid == NULL)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ if (params->flags != GNUTLS_ECC_CURVE_ED25519PH)
+ return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+
+ ret = _gnutls_mpi_dprint_size(params->params[EDDSA_PRIV], &key, 32);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ /* Ok. Now we have the data. Create the asn1 structures
+ */
+
+ /* 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.EdDSAPrivateKey", c2))
+ != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(ret);
+ goto cleanup;
+ }
+
+ if ((ret =
+ asn1_write_value(*c2, "curve", &two, 1)) != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(ret);
+ goto cleanup;
+ }
+
+ if ((ret =
+ asn1_write_value(*c2, "priv", key.data, key.size)) != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(ret);
+ goto cleanup;
+ }
+
+ _gnutls_free_datum(&key);
+ return 0;
+
+cleanup:
+ asn1_delete_structure2(c2, ASN1_DELETE_FLAG_ZEROIZE);
+ _gnutls_free_datum(&key);
+
+ return ret;
+}
+
/* Encodes the DSA parameters into an ASN.1 DSAPrivateKey structure.
*/
@@ -686,6 +833,8 @@ int _gnutls_asn1_encode_privkey(gnutls_pk_algorithm_t pk, ASN1_TYPE * c2,
return _gnutls_asn1_encode_dsa(c2, params, compat);
case GNUTLS_PK_EC:
return _gnutls_asn1_encode_ecc(c2, params);
+ case GNUTLS_PK_EDDSA:
+ return _gnutls_asn1_encode_eddsa(c2, params);
default:
return GNUTLS_E_UNIMPLEMENTED_FEATURE;
}
diff --git a/lib/x509/output.c b/lib/x509/output.c
index 633d3ee1af..11f2892140 100644
--- a/lib/x509/output.c
+++ b/lib/x509/output.c
@@ -1464,7 +1464,7 @@ static void print_keyid(gnutls_buffer_st * str, gnutls_x509_crt_t cert)
if (err < 0)
return;
- if (err == GNUTLS_PK_EC) {
+ if (err == GNUTLS_PK_ECDSA || err == GNUTLS_PK_EDDSA) {
gnutls_ecc_curve_t curve;
err = gnutls_x509_crt_get_pk_ecc_raw(cert, &curve, NULL, NULL);
diff --git a/lib/x509/privkey.c b/lib/x509/privkey.c
index 3c6b04f73a..a1f9a0bc51 100644
--- a/lib/x509/privkey.c
+++ b/lib/x509/privkey.c
@@ -279,7 +279,7 @@ _gnutls_privkey_decode_ecc_key(ASN1_TYPE* pkey_asn, const gnutls_datum_t * raw_k
gnutls_pk_params_init(&pkey->params);
- pkey->params.algo = GNUTLS_PK_EC;
+ pkey->params.algo = GNUTLS_PK_ECDSA;
if ((ret =
asn1_create_element(_gnutls_get_gnutls_asn(),
"GNUTLS.ECPrivateKey",
@@ -376,6 +376,81 @@ _gnutls_privkey_decode_ecc_key(ASN1_TYPE* pkey_asn, const gnutls_datum_t * raw_k
}
+/* Converts an ECC key to
+ * an internal structure (gnutls_private_key)
+ */
+int
+_gnutls_privkey_decode_eddsa_key(ASN1_TYPE* pkey_asn, const gnutls_datum_t * raw_key,
+ gnutls_x509_privkey_t pkey, gnutls_ecc_curve_t curve)
+{
+ int ret;
+ unsigned int stored_curve;
+
+ gnutls_pk_params_init(&pkey->params);
+
+ pkey->params.algo = GNUTLS_PK_EDDSA;
+ if ((ret =
+ asn1_create_element(_gnutls_get_gnutls_asn(),
+ "GNUTLS.EdDSAPrivateKey",
+ pkey_asn)) != ASN1_SUCCESS) {
+ gnutls_assert();
+ return _gnutls_asn2err(ret);
+ }
+
+ ret =
+ _asn1_strict_der_decode(pkey_asn, raw_key->data, raw_key->size,
+ NULL);
+ if (ret != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(ret);
+ goto error;
+ }
+
+ ret = _gnutls_x509_read_uint(*pkey_asn, "curve", &stored_curve);
+ if (ret < 0) {
+ gnutls_assert();
+ goto error;
+ }
+
+ if (stored_curve != 1) {
+ _gnutls_debug_log
+ ("EdDSA private key algorithm %u is not supported\n",
+ stored_curve);
+ gnutls_assert();
+ ret = GNUTLS_E_ECC_UNSUPPORTED_CURVE;
+ goto error;
+ }
+
+ /* read the curve */
+ pkey->params.flags = GNUTLS_ECC_CURVE_ED25519PH;
+
+ ret =
+ _gnutls_x509_read_key_int(*pkey_asn, "priv",
+ &pkey->params.params[EDDSA_PRIV]);
+ if (ret < 0) {
+ gnutls_assert();
+ goto error;
+ }
+
+ pkey->params.params_nr = 1;
+
+ /* make the public key */
+ ret = _gnutls_pk_fixup(GNUTLS_PK_EDDSA, GNUTLS_IMPORT, &pkey->params);
+ if (ret < 0) {
+ gnutls_assert();
+ goto error;
+ }
+
+ return 0;
+
+ error:
+ asn1_delete_structure2(pkey_asn, ASN1_DELETE_FLAG_ZEROIZE);
+ gnutls_pk_params_clear(&pkey->params);
+ gnutls_pk_params_release(&pkey->params);
+ return ret;
+
+}
+
static ASN1_TYPE
decode_dsa_key(const gnutls_datum_t * raw_key, gnutls_x509_privkey_t pkey)
@@ -477,6 +552,7 @@ decode_dsa_key(const gnutls_datum_t * raw_key, gnutls_x509_privkey_t pkey)
#define PEM_KEY_DSA_PROVABLE "FIPS186-4 DSA PRIVATE KEY"
#define PEM_KEY_RSA_PROVABLE "FIPS186-4 RSA PRIVATE KEY"
#define PEM_KEY_ECC "EC PRIVATE KEY"
+#define PEM_KEY_EDDSA "EDDSA PRIVATE KEY"
#define PEM_KEY_PKCS8 "PRIVATE KEY"
#define MAX_PEM_HEADER_SIZE 25
@@ -556,6 +632,7 @@ gnutls_x509_privkey_import(gnutls_x509_privkey_t key,
if (ptr != NULL) {
IF_CHECK_FOR(PEM_KEY_RSA, GNUTLS_PK_RSA, ptr, begin_ptr, left, key)
else IF_CHECK_FOR(PEM_KEY_ECC, GNUTLS_PK_EC, ptr, begin_ptr, left, key)
+ else IF_CHECK_FOR(PEM_KEY_EDDSA, GNUTLS_PK_EDDSA, ptr, begin_ptr, left, key)
else IF_CHECK_FOR(PEM_KEY_DSA, GNUTLS_PK_DSA, ptr, begin_ptr, left, key)
else IF_CHECK_FOR(PEM_KEY_RSA_PROVABLE, GNUTLS_PK_RSA, ptr, begin_ptr, left, key)
else IF_CHECK_FOR(PEM_KEY_DSA_PROVABLE, GNUTLS_PK_DSA, ptr, begin_ptr, left, key)
@@ -606,12 +683,18 @@ gnutls_x509_privkey_import(gnutls_x509_privkey_t key,
key->key = decode_dsa_key(&_data, key);
if (key->key == NULL)
gnutls_assert();
- } else if (key->pk_algorithm == GNUTLS_PK_EC) {
+ } else if (key->pk_algorithm == GNUTLS_PK_ECDSA) {
result = _gnutls_privkey_decode_ecc_key(&key->key, &_data, key, 0);
if (result < 0) {
gnutls_assert();
key->key = NULL;
}
+ } else if (key->pk_algorithm == GNUTLS_PK_EDDSA) {
+ result = _gnutls_privkey_decode_eddsa_key(&key->key, &_data, key, 0);
+ if (result < 0) {
+ gnutls_assert();
+ key->key = NULL;
+ }
} else {
/* Try decoding each of the keys, and accept the one that
* succeeds.
@@ -624,20 +707,25 @@ gnutls_x509_privkey_import(gnutls_x509_privkey_t key,
key->pk_algorithm = GNUTLS_PK_DSA;
key->key = decode_dsa_key(&_data, key);
if (key->key == NULL) {
- key->pk_algorithm = GNUTLS_PK_EC;
+ key->pk_algorithm = GNUTLS_PK_EDDSA;
result =
- _gnutls_privkey_decode_ecc_key(&key->key, &_data, key, 0);
- if (result < 0) {
+ _gnutls_privkey_decode_eddsa_key(&key->key, &_data, key, 0);
+
+ if (key->key == NULL) {
+ key->pk_algorithm = GNUTLS_PK_EC;
result =
- gnutls_x509_privkey_import_pkcs8(key, data, format,
- NULL,
- GNUTLS_PKCS_PLAIN);
+ _gnutls_privkey_decode_ecc_key(&key->key, &_data, key, 0);
if (result < 0) {
- gnutls_assert();
- key->key = NULL;
+ result =
+ gnutls_x509_privkey_import_pkcs8(key, data, format,
+ NULL,
+ GNUTLS_PKCS_PLAIN);
+ if (result < 0) {
+ gnutls_assert();
+ key->key = NULL;
+ }
}
}
-
}
}
}
@@ -741,9 +829,9 @@ gnutls_x509_privkey_import2(gnutls_x509_privkey_t key,
if (ptr != NULL) {
left = data->size - ((ptrdiff_t)ptr - (ptrdiff_t)data->data);
- if (data->size - left > 15) {
- ptr -= 15;
- left += 15;
+ if (data->size - left > MAX_PEM_HEADER_SIZE) {
+ ptr -= MAX_PEM_HEADER_SIZE;
+ left += MAX_PEM_HEADER_SIZE;
} else {
ptr = (char*)data->data;
left = data->size;
@@ -758,6 +846,7 @@ gnutls_x509_privkey_import2(gnutls_x509_privkey_t key,
if (ptr != NULL && left > sizeof(PEM_KEY_RSA)) {
if (memcmp(ptr, PEM_KEY_RSA, sizeof(PEM_KEY_RSA)-1) == 0 ||
memcmp(ptr, PEM_KEY_ECC, sizeof(PEM_KEY_ECC)-1) == 0 ||
+ memcmp(ptr, PEM_KEY_EDDSA, sizeof(PEM_KEY_EDDSA)-1) == 0 ||
memcmp(ptr, PEM_KEY_DSA, sizeof(PEM_KEY_DSA)-1) == 0) {
head_enc = 0;
}
@@ -1112,32 +1201,54 @@ gnutls_x509_privkey_import_ecc_raw(gnutls_x509_privkey_t key,
}
key->params.flags = curve;
+ if (curve_is_eddsa(curve))
+ key->params.algo = GNUTLS_PK_EDDSA;
+ else
+ key->params.algo = GNUTLS_PK_ECDSA;
- if (_gnutls_mpi_init_scan_nz
- (&key->params.params[ECC_X], x->data, x->size)) {
- gnutls_assert();
- ret = GNUTLS_E_MPI_SCAN_FAILED;
- goto cleanup;
- }
- key->params.params_nr++;
+ if (!curve_is_eddsa(curve)) {
+ if (_gnutls_mpi_init_scan_nz
+ (&key->params.params[ECC_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[ECC_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[ECC_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[ECC_K], k->data, k->size)) {
- gnutls_assert();
- ret = GNUTLS_E_MPI_SCAN_FAILED;
- goto cleanup;
- }
- key->params.params_nr++;
+ if (_gnutls_mpi_init_scan_nz
+ (&key->params.params[ECC_K], k->data, k->size)) {
+ gnutls_assert();
+ ret = GNUTLS_E_MPI_SCAN_FAILED;
+ goto cleanup;
+ }
+ key->params.params_nr++;
+ key->pk_algorithm = GNUTLS_PK_ECDSA;
+ } else {
+ if (_gnutls_mpi_init_scan_nz
+ (&key->params.params[EDDSA_PUB], x->data, x->size)) {
+ gnutls_assert();
+ ret = GNUTLS_E_MPI_SCAN_FAILED;
+ goto cleanup;
+ }
+ key->params.params_nr++;
- key->pk_algorithm = GNUTLS_PK_EC;
+ if (_gnutls_mpi_init_scan_nz
+ (&key->params.params[EDDSA_PRIV], k->data, k->size)) {
+ gnutls_assert();
+ ret = GNUTLS_E_MPI_SCAN_FAILED;
+ goto cleanup;
+ }
+ key->params.params_nr++;
+ key->pk_algorithm = GNUTLS_PK_EDDSA;
+ }
return 0;
@@ -1215,6 +1326,8 @@ static const char *set_msg(gnutls_x509_privkey_t key)
return PEM_KEY_DSA;
} else if (key->pk_algorithm == GNUTLS_PK_EC)
return PEM_KEY_ECC;
+ else if (key->pk_algorithm == GNUTLS_PK_EDDSA)
+ return PEM_KEY_EDDSA;
else
return "UNKNOWN";
}
@@ -1344,6 +1457,7 @@ gnutls_sec_param_t gnutls_x509_privkey_sec_param(gnutls_x509_privkey_t key)
* This function will export the ECC 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.
+ * For EdDSA keys, the @y value should be %NULL.
*
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
* negative error value.
@@ -1456,7 +1570,7 @@ const char const_data[20] = "onetwothreefourfive";
gnutls_datum_t ddata, tmp = {NULL,0};
char* gen_data = NULL;
- if (algo == GNUTLS_PK_DSA || algo == GNUTLS_PK_EC) {
+ if (algo == GNUTLS_PK_DSA || algo == GNUTLS_PK_ECDSA) {
unsigned hash_len;
_gnutls_dsa_q_to_hash(algo, params, &hash_len);
@@ -1503,7 +1617,8 @@ char* gen_data = NULL;
/* Here we don't know the purpose of the key. Check both
* signing and encryption.
*/
- case GNUTLS_PK_EC: /* we only do keys for ECDSA */
+ case GNUTLS_PK_ECDSA: /* we only do keys for ECDSA */
+ case GNUTLS_PK_EDDSA: /* we only do keys for ECDSA */
case GNUTLS_PK_DSA:
ret = _gnutls_pk_sign(algo, &sig, &ddata, params);
if (ret < 0) {
@@ -1618,11 +1733,16 @@ gnutls_x509_privkey_generate2(gnutls_x509_privkey_t key,
}
}
- if (algo == GNUTLS_PK_EC) {
+ if (algo_is_ecc(algo)) {
if (GNUTLS_BITS_ARE_CURVE(bits))
bits = GNUTLS_BITS_TO_CURVE(bits);
else
- bits = _gnutls_ecc_bits_to_curve(bits);
+ bits = _gnutls_ecc_bits_to_curve(algo, bits);
+
+ if (gnutls_ecc_curve_get_pk(bits) != algo) {
+ _gnutls_debug_log("curve is incompatible with public key algorithm\n");
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+ }
}
if (flags & GNUTLS_PRIVKEY_FLAG_PROVABLE) {
diff --git a/lib/x509/x509_int.h b/lib/x509/x509_int.h
index 9d666ee55d..1d23304aaf 100644
--- a/lib/x509/x509_int.h
+++ b/lib/x509/x509_int.h
@@ -219,10 +219,17 @@ int _gnutls_privkey_decode_ecc_key(ASN1_TYPE* pkey_asn, const gnutls_datum_t *
raw_key,
gnutls_x509_privkey_t pkey,
gnutls_ecc_curve_t curve);
+int _gnutls_privkey_decode_eddsa_key(ASN1_TYPE* pkey_asn, const gnutls_datum_t *
+ raw_key,
+ gnutls_x509_privkey_t pkey,
+ gnutls_ecc_curve_t curve);
int
_gnutls_x509_read_ecc_params(uint8_t * der, int dersize,
unsigned int *curve);
+int
+_gnutls_x509_read_eddsa_params(uint8_t * der, int dersize,
+ unsigned int *curve);
int _gnutls_asn1_encode_privkey(gnutls_pk_algorithm_t pk, ASN1_TYPE * c2,
gnutls_pk_params_st * params, unsigned compat);
@@ -297,6 +304,11 @@ int _gnutls_x509_write_ecc_params(gnutls_ecc_curve_t curve,
int _gnutls_x509_write_ecc_pubkey(gnutls_pk_params_st * params,
gnutls_datum_t * der);
+int _gnutls_x509_write_eddsa_params(gnutls_ecc_curve_t curve,
+ gnutls_datum_t * der);
+int _gnutls_x509_write_eddsa_pubkey(gnutls_pk_params_st * params,
+ gnutls_datum_t * der);
+
int
_gnutls_x509_write_pubkey_params(gnutls_pk_algorithm_t algo,
gnutls_pk_params_st * params,
diff --git a/src/certtool-args.def b/src/certtool-args.def
index 95a07b04a8..9ea9f30add 100644
--- a/src/certtool-args.def
+++ b/src/certtool-args.def
@@ -431,6 +431,12 @@ flag = {
};
flag = {
+ name = eddsa;
+ descrip = "Generate EdDSA key";
+ doc = "When combined with --generate-privkey generates an elliptic curve private key to be used with EdDSA.";
+};
+
+flag = {
name = ecc;
descrip = "Generate ECC (ECDSA) key";
doc = "When combined with --generate-privkey generates an elliptic curve private key to be used with ECDSA.";
diff --git a/src/certtool-common.c b/src/certtool-common.c
index 41b1655f19..f4c2a24626 100644
--- a/src/certtool-common.c
+++ b/src/certtool-common.c
@@ -859,14 +859,18 @@ print_ecc_pkey(FILE * outfile, gnutls_ecc_curve_t curve,
fprintf(outfile, "curve:\t%s\n",
gnutls_ecc_curve_get_name(curve));
- if (k) {
+ if (k && k->data) {
print_head(outfile, "private key", k->size, cprint);
print_hex_datum(outfile, k, cprint);
}
- print_head(outfile, "x", x->size, cprint);
- print_hex_datum(outfile, x, cprint);
- print_head(outfile, "y", y->size, cprint);
- print_hex_datum(outfile, y, cprint);
+ if (x && x->data) {
+ print_head(outfile, "x", x->size, cprint);
+ print_hex_datum(outfile, x, cprint);
+ }
+ if (y && y->data) {
+ print_head(outfile, "y", y->size, cprint);
+ print_hex_datum(outfile, y, cprint);
+ }
}
diff --git a/src/certtool.c b/src/certtool.c
index 7fb5f5d8fb..bbde0f4618 100644
--- a/src/certtool.c
+++ b/src/certtool.c
@@ -128,8 +128,12 @@ generate_private_key_int(common_info_st * cinfo)
bits = get_bits(key_type, cinfo->bits, cinfo->sec_param, 1);
- fprintf(stdlog, "Generating a %d bit %s private key...\n",
- bits, gnutls_pk_algorithm_get_name(key_type));
+ if (GNUTLS_BITS_ARE_CURVE(bits))
+ fprintf(stdlog, "Generating an %s private key...\n",
+ gnutls_pk_algorithm_get_name(key_type));
+ else
+ fprintf(stdlog, "Generating a %d bit %s private key...\n",
+ bits, gnutls_pk_algorithm_get_name(key_type));
if (bits < 256 && key_type == GNUTLS_PK_EC)
fprintf(stderr,
@@ -1161,7 +1165,9 @@ static void cmd_parser(int argc, char **argv)
if (HAVE_OPT(DSA))
req_key_type = GNUTLS_PK_DSA;
else if (HAVE_OPT(ECC))
- req_key_type = GNUTLS_PK_ECC;
+ req_key_type = GNUTLS_PK_ECDSA;
+ else if (HAVE_OPT(EDDSA))
+ req_key_type = GNUTLS_PK_EDDSA;
else
req_key_type = GNUTLS_PK_RSA;
@@ -2007,7 +2013,7 @@ static void privkey_info_int(common_info_st * cinfo,
gnutls_free(q.data);
gnutls_free(g.data);
}
- } else if (key_type == GNUTLS_PK_EC) {
+ } else if (key_type == GNUTLS_PK_ECDSA || key_type == GNUTLS_PK_EDDSA) {
gnutls_datum_t y, x, k;
gnutls_ecc_curve_t curve;
diff --git a/tests/cert-tests/Makefile.am b/tests/cert-tests/Makefile.am
index 630d0f1a4d..0e93b20727 100644
--- a/tests/cert-tests/Makefile.am
+++ b/tests/cert-tests/Makefile.am
@@ -38,7 +38,8 @@ EXTRA_DIST = ca-no-pathlen.pem no-ca-or-pathlen.pem aki-cert.pem \
template-unique.tmpl template-unique.pem
dist_check_SCRIPTS = pathlen aki certtool invalid-sig email \
- pkcs7 privkey-import name-constraints certtool-long-cn crl provable-privkey
+ pkcs7 privkey-import name-constraints certtool-long-cn crl provable-privkey \
+ ed25519
if !HAVE_BUGGY_LIBIDN
dist_check_SCRIPTS += certtool-utf8
diff --git a/tests/cert-tests/ed25519 b/tests/cert-tests/ed25519
new file mode 100755
index 0000000000..d442e04e2c
--- /dev/null
+++ b/tests/cert-tests/ed25519
@@ -0,0 +1,81 @@
+#!/bin/sh
+
+# Copyright (C) 2015 Nikos Mavrogiannopoulos
+#
+# This file is part of GnuTLS.
+#
+# GnuTLS is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 3 of the License, or (at
+# your option) any later version.
+#
+# GnuTLS is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GnuTLS; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#set -e
+
+srcdir="${srcdir:-.}"
+CERTTOOL="${CERTTOOL:-../../src/certtool${EXEEXT}}"
+DIFF="${DIFF:-diff}"
+if ! test -z "${VALGRIND}"; then
+ VALGRIND="${LIBTOOL:-libtool} --mode=execute ${VALGRIND} --error-exitcode=15"
+fi
+OUTFILE=out-ed25519.tmp
+OUTFILE2=out2-ed25519.tmp
+
+# Verifying and existing sig
+FILE="shipped-sig-verify"
+${VALGRIND} "${CERTTOOL}" --p7-verify --load-certificate "${srcdir}/../../doc/credentials/x509/cert-eddsa.pem" <"pkcs7-detached.eddsa.sig"
+rc=$?
+if test "${rc}" != "0"; then
+ echo "${FILE}: PKCS7-Ed25519 struct signing failed verification"
+ exit ${rc}
+fi
+
+# Test signing
+FILE="signing"
+${VALGRIND} "${CERTTOOL}" --p7-sign --load-privkey "${srcdir}/../../doc/credentials/x509/key-eddsa.pem" --load-certificate "${srcdir}/../../doc/credentials/x509/cert-eddsa.pem" --infile "${srcdir}/pkcs7-detached.txt" >"${OUTFILE}"
+rc=$?
+
+if test "${rc}" != "0"; then
+ echo "${FILE}: PKCS7-Ed25519 struct signing failed"
+ exit ${rc}
+fi
+
+FILE="signing-verify"
+${VALGRIND} "${CERTTOOL}" --p7-verify --load-certificate "${srcdir}/../../doc/credentials/x509/cert-eddsa.pem" <"${OUTFILE}"
+rc=$?
+
+if test "${rc}" != "0"; then
+ echo "${FILE}: PKCS7-Ed25519 struct signing failed verification"
+ exit ${rc}
+fi
+
+FILE="signing-detached"
+${VALGRIND} "${CERTTOOL}" --p7-detached-sign --load-privkey "${srcdir}/../../doc/credentials/x509/key-eddsa.pem" --load-certificate "${srcdir}/../../doc/credentials/x509/cert-eddsa.pem" --infile "${srcdir}/pkcs7-detached.txt" >"${OUTFILE}"
+rc=$?
+
+if test "${rc}" != "0"; then
+ echo "${FILE}: PKCS7-Ed25519 struct signing-detached failed"
+ exit ${rc}
+fi
+
+FILE="signing-detached-verify"
+${VALGRIND} "${CERTTOOL}" --p7-verify --load-certificate "${srcdir}/../../doc/credentials/x509/cert-eddsa.pem" --load-data "${srcdir}/pkcs7-detached.txt" <"${OUTFILE}"
+rc=$?
+
+if test "${rc}" != "0"; then
+ echo "${FILE}: PKCS7-Ed25519 struct signing-detached failed verification"
+ exit ${rc}
+fi
+
+rm -f "${OUTFILE}"
+rm -f "${OUTFILE2}"
+
+exit 0
diff --git a/tests/cert-tests/pkcs7-detached.eddsa.sig b/tests/cert-tests/pkcs7-detached.eddsa.sig
new file mode 100644
index 0000000000..e72459722e
--- /dev/null
+++ b/tests/cert-tests/pkcs7-detached.eddsa.sig
@@ -0,0 +1,7 @@
+-----BEGIN PKCS7-----
+MIHYBgkqhkiG9w0BBwKggcowgccCAQExDTALBglghkgBZQMEAgMwKQYJKoZIhvcN
+AQcBoBwEGkhlbGxvIHRoZXJlLiBIb3cgYXJlIHlvdT8KoAChADGBgzCBgAIBATAl
+MBkxFzAVBgNVBAMTDkdudVRMUyBUZXN0IENBAghWA+GfAuyp2DALBglghkgBZQME
+AgMwBQYDK2VlBEAHosGIoUwRhvoJsa6aPBu3syH61HFfyl9LEvBAuGag5+A1G9dK
+WsQX3+hmRAMUpVDC1DDgFrYhC22lF/43OLIH
+-----END PKCS7-----