diff --git a/CHANGES b/CHANGES
index dac5c45ff2..f3ed2409eb 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,5 @@
+4665. [func] Add Ed25519 support (RFC 8080). [RT #25519]
+
4664. [func] Add a "glue-cache" option to enable or disable the
glue cache. The default is "no" to reduce memory
usage, but enabling this option will improve
diff --git a/bin/dnssec/dnssec-keyfromlabel.c b/bin/dnssec/dnssec-keyfromlabel.c
index 891f31fac5..53834005e0 100644
--- a/bin/dnssec/dnssec-keyfromlabel.c
+++ b/bin/dnssec/dnssec-keyfromlabel.c
@@ -52,7 +52,8 @@ int verbose;
static const char *algs = "RSA | RSAMD5 | DH | DSA | RSASHA1 |"
" NSEC3DSA | NSEC3RSASHA1 |"
" RSASHA256 | RSASHA512 | ECCGOST |"
- " ECDSAP256SHA256 | ECDSAP384SHA384";
+ " ECDSAP256SHA256 | ECDSAP384SHA384 |"
+ " ED25519 | ED448";
ISC_PLATFORM_NORETURN_PRE static void
usage(void) ISC_PLATFORM_NORETURN_POST;
@@ -437,7 +438,8 @@ main(int argc, char **argv) {
alg != DST_ALG_NSEC3DSA && alg != DST_ALG_NSEC3RSASHA1 &&
alg != DST_ALG_RSASHA256 && alg != DST_ALG_RSASHA512 &&
alg != DST_ALG_ECCGOST &&
- alg != DST_ALG_ECDSA256 && alg != DST_ALG_ECDSA384) {
+ alg != DST_ALG_ECDSA256 && alg != DST_ALG_ECDSA384 &&
+ alg != DST_ALG_ED25519 && alg != DST_ALG_ED448) {
fatal("%s is incompatible with NSEC3; "
"do not use the -3 option", algname);
}
diff --git a/bin/dnssec/dnssec-keyfromlabel.docbook b/bin/dnssec/dnssec-keyfromlabel.docbook
index aeaca1add2..2ea188b223 100644
--- a/bin/dnssec/dnssec-keyfromlabel.docbook
+++ b/bin/dnssec/dnssec-keyfromlabel.docbook
@@ -102,7 +102,7 @@
Selects the cryptographic algorithm. The value of
must be one of RSAMD5, RSASHA1,
DSA, NSEC3RSASHA1, NSEC3DSA, RSASHA256, RSASHA512, ECCGOST,
- ECDSAP256SHA256 or ECDSAP384SHA384.
+ ECDSAP256SHA256, ECDSAP384SHA384, ED25519 or ED448.
These values are case insensitive.
diff --git a/bin/dnssec/dnssec-keygen.c b/bin/dnssec/dnssec-keygen.c
index ac4ab87684..1beefa987f 100644
--- a/bin/dnssec/dnssec-keygen.c
+++ b/bin/dnssec/dnssec-keygen.c
@@ -82,7 +82,8 @@ usage(void) {
" | NSEC3DSA |\n");
fprintf(stderr, " RSASHA256 | RSASHA512 | ECCGOST |\n");
fprintf(stderr, " ECDSAP256SHA256 | ECDSAP384SHA384 |\n");
- fprintf(stderr, " DH | HMAC-MD5 | HMAC-SHA1 | HMAC-SHA224 | "
+ fprintf(stderr, " ED25519 | ED448 | DH |\n");
+ fprintf(stderr, " HMAC-MD5 | HMAC-SHA1 | HMAC-SHA224 | "
"HMAC-SHA256 | \n");
fprintf(stderr, " HMAC-SHA384 | HMAC-SHA512\n");
fprintf(stderr, " (default: RSASHA1, or "
@@ -101,6 +102,8 @@ usage(void) {
fprintf(stderr, " ECCGOST:\tignored\n");
fprintf(stderr, " ECDSAP256SHA256:\tignored\n");
fprintf(stderr, " ECDSAP384SHA384:\tignored\n");
+ fprintf(stderr, " ED25519:\tignored\n");
+ fprintf(stderr, " ED448:\tignored\n");
fprintf(stderr, " HMAC-MD5:\t[1..512]\n");
fprintf(stderr, " HMAC-SHA1:\t[1..160]\n");
fprintf(stderr, " HMAC-SHA224:\t[1..224]\n");
@@ -602,7 +605,8 @@ main(int argc, char **argv) {
alg != DST_ALG_NSEC3DSA && alg != DST_ALG_NSEC3RSASHA1 &&
alg != DST_ALG_RSASHA256 && alg!= DST_ALG_RSASHA512 &&
alg != DST_ALG_ECCGOST &&
- alg != DST_ALG_ECDSA256 && alg != DST_ALG_ECDSA384) {
+ alg != DST_ALG_ECDSA256 && alg != DST_ALG_ECDSA384 &&
+ alg != DST_ALG_ED25519 && alg != DST_ALG_ED448) {
fatal("%s is incompatible with NSEC3; "
"do not use the -3 option", algname);
}
@@ -636,7 +640,9 @@ main(int argc, char **argv) {
" to %d\n", size);
} else if (alg != DST_ALG_ECCGOST &&
alg != DST_ALG_ECDSA256 &&
- alg != DST_ALG_ECDSA384)
+ alg != DST_ALG_ECDSA384 &&
+ alg != DST_ALG_ED25519 &&
+ alg != DST_ALG_ED448)
fatal("key size not specified (-b option)");
}
@@ -773,6 +779,12 @@ main(int argc, char **argv) {
case DST_ALG_ECDSA384:
size = 384;
break;
+ case DST_ALG_ED25519:
+ size = 256;
+ break;
+ case DST_ALG_ED448:
+ size = 456;
+ break;
case DST_ALG_HMACMD5:
options |= DST_TYPE_KEY;
if (size < 1 || size > 512)
@@ -906,6 +918,8 @@ main(int argc, char **argv) {
case DST_ALG_ECCGOST:
case DST_ALG_ECDSA256:
case DST_ALG_ECDSA384:
+ case DST_ALG_ED25519:
+ case DST_ALG_ED448:
show_progress = ISC_TRUE;
/* fall through */
diff --git a/bin/dnssec/dnssec-keygen.docbook b/bin/dnssec/dnssec-keygen.docbook
index e398de62ee..6c79e7f016 100644
--- a/bin/dnssec/dnssec-keygen.docbook
+++ b/bin/dnssec/dnssec-keygen.docbook
@@ -114,7 +114,7 @@
Selects the cryptographic algorithm. For DNSSEC keys, the value
of must be one of RSAMD5, RSASHA1,
DSA, NSEC3RSASHA1, NSEC3DSA, RSASHA256, RSASHA512, ECCGOST,
- ECDSAP256SHA256 or ECDSAP384SHA384.
+ ECDSAP256SHA256, ECDSAP384SHA384, ED25519 or ED448.
For TSIG/TKEY, the value must
be DH (Diffie Hellman), HMAC-MD5, HMAC-SHA1, HMAC-SHA224,
HMAC-SHA256, HMAC-SHA384, or HMAC-SHA512. These values are
@@ -186,8 +186,8 @@
If this option is used and no algorithm is explicitly
set on the command line, NSEC3RSASHA1 will be used by
default. Note that RSASHA256, RSASHA512, ECCGOST,
- ECDSAP256SHA256 and ECDSAP384SHA384 algorithms
- are NSEC3-capable.
+ ECDSAP256SHA256, ECDSAP384SHA384, ED25519 and ED448
+ algorithms are NSEC3-capable.
diff --git a/bin/pkcs11/pkcs11-keygen.c b/bin/pkcs11/pkcs11-keygen.c
index 75baa04052..fe314ab409 100644
--- a/bin/pkcs11/pkcs11-keygen.c
+++ b/bin/pkcs11/pkcs11-keygen.c
@@ -73,6 +73,7 @@
#define WANT_DH_PRIMES
#define WANT_ECC_CURVES
#include
+#include
#if !(defined(HAVE_GETPASSPHRASE) || (defined (__SVR4) && defined (__sun)))
#define getpassphrase(x) getpass(x)
@@ -82,13 +83,14 @@
static CK_BBOOL truevalue = TRUE;
static CK_BBOOL falsevalue = FALSE;
-/* Key class: RSA, ECC, DSA, DH, or unknown */
+/* Key class: RSA, ECC, ECX, DSA, DH, or unknown */
typedef enum {
key_unknown,
key_rsa,
key_dsa,
key_dh,
- key_ecc
+ key_ecc,
+ key_ecx
} key_class_t;
/*
@@ -136,7 +138,7 @@ static CK_ATTRIBUTE rsa_template[] = {
};
/*
- * Public key template for ECC keys
+ * Public key template for ECC/ECX keys
*/
#define ECC_LABEL 0
#define ECC_VERIFY 1
@@ -247,6 +249,9 @@ keyclass_fromtext(const char *name) {
else if (strncasecmp(name, "ecc", 3) == 0 ||
strncasecmp(name, "ecdsa", 5) == 0)
return (key_ecc);
+ else if (strncasecmp(name, "ecx", 3) == 0 ||
+ strncasecmp(name, "ed", 2) == 0)
+ return (key_ecx);
else
return (key_unknown);
}
@@ -425,6 +430,39 @@ main(int argc, char *argv[]) {
sizeof(pk11_ecc_secp384r1);
}
+ break;
+ case key_ecx:
+#ifndef CKM_EDDSA_KEY_PAIR_GEN
+ fprintf(stderr, "CKM_EDDSA_KEY_PAIR_GEN is not defined\n");
+ usage();
+#endif
+ op_type = OP_EC;
+ if (bits == 0)
+ bits = 256;
+ else if (bits != 256 && bits != 456) {
+ fprintf(stderr, "ECX keys only support bit sizes of "
+ "256 and 456\n");
+ exit(2);
+ }
+
+ mech.mechanism = CKM_EDDSA_KEY_PAIR_GEN;
+ mech.pParameter = NULL;
+ mech.ulParameterLen = 0;
+
+ public_template = ecc_template;
+ public_attrcnt = ECC_ATTRS;
+ id_offset = ECC_ID;
+
+ if (bits == 256) {
+ public_template[4].pValue = pk11_ecc_ed25519;
+ public_template[4].ulValueLen =
+ sizeof(pk11_ecc_ed25519);
+ } else {
+ public_template[4].pValue = pk11_ecc_ed448;
+ public_template[4].ulValueLen =
+ sizeof(pk11_ecc_ed448);
+ }
+
break;
case key_dsa:
op_type = OP_DSA;
@@ -570,7 +608,7 @@ main(int argc, char *argv[]) {
private_template[5].pValue = &truevalue;
}
- if (keyclass == key_rsa || keyclass == key_ecc)
+ if (keyclass == key_rsa || keyclass == key_ecc || keyclass == key_ecx)
goto generate_keys;
/*
diff --git a/bin/pkcs11/pkcs11-keygen.docbook b/bin/pkcs11/pkcs11-keygen.docbook
index f4ff1316e2..e17c2a17fe 100644
--- a/bin/pkcs11/pkcs11-keygen.docbook
+++ b/bin/pkcs11/pkcs11-keygen.docbook
@@ -71,11 +71,11 @@
Specify the key algorithm class: Supported classes are RSA,
- DSA, DH, and ECC. In addition to these strings, the
+ DSA, DH, ECC and ECX. In addition to these strings, the
can be specified as a DNSSEC
signing algorithm that will be used with this key; for
- example, NSEC3RSASHA1 maps to RSA, and ECDSAP256SHA256 maps
- to ECC. The default class is "RSA".
+ example, NSEC3RSASHA1 maps to RSA, ECDSAP256SHA256 maps
+ to ECC, and ED25519 to ECX. The default class is "RSA".
@@ -86,7 +86,8 @@
Create the key pair with bits of
prime. For ECC keys, the only valid values are 256 and 384,
- and the default is 256.
+ and the default is 256. For ECX kyes, the only valid values
+ are 256 and 456, and the default is 256.
diff --git a/bin/python/isc/dnskey.py.in b/bin/python/isc/dnskey.py.in
index 081ca062be..357fab8bdb 100644
--- a/bin/python/isc/dnskey.py.in
+++ b/bin/python/isc/dnskey.py.in
@@ -30,7 +30,7 @@ class dnskey:
_ALGNAMES = (None, 'RSAMD5', 'DH', 'DSA', 'ECC', 'RSASHA1',
'NSEC3DSA', 'NSEC3RSASHA1', 'RSASHA256', None,
'RSASHA512', None, 'ECCGOST', 'ECDSAP256SHA256',
- 'ECDSAP384SHA384')
+ 'ECDSAP384SHA384', 'ED25519', 'ED448')
def __init__(self, key, directory=None, keyttl=None):
# this makes it possible to use algname as a class or instance method
diff --git a/bin/python/isc/policy.py.in b/bin/python/isc/policy.py.in
index 015fd4f098..9ae3e55427 100644
--- a/bin/python/isc/policy.py.in
+++ b/bin/python/isc/policy.py.in
@@ -68,7 +68,7 @@ class PolicyLex:
return t
def t_ALGNAME(self, t):
- r'(?i)\b(RSAMD5|DH|DSA|NSEC3DSA|ECC|RSASHA1|NSEC3RSASHA1|RSASHA256|RSASHA512|ECCGOST|ECDSAP256SHA256|ECDSAP384SHA384)\b'
+ r'(?i)\b(RSAMD5|DH|DSA|NSEC3DSA|ECC|RSASHA1|NSEC3RSASHA1|RSASHA256|RSASHA512|ECCGOST|ECDSAP256SHA256|ECDSAP384SHA384|ED25519|ED448)\b'
t.value = t.value.upper()
return t
@@ -138,7 +138,9 @@ class Policy:
'RSASHA512': [1024, 4096],
'ECCGOST': None,
'ECDSAP256SHA256': None,
- 'ECDSAP384SHA384': None}
+ 'ECDSAP384SHA384': None,
+ 'ED25519': None,
+ 'ED448': None}
def __init__(self, name=None, algorithm=None, parent=None):
self.name = name
@@ -275,7 +277,9 @@ class Policy:
if self.algorithm in ['ECCGOST', \
'ECDSAP256SHA256', \
- 'ECDSAP384SHA384']:
+ 'ECDSAP384SHA384', \
+ 'ED25519', \
+ 'ED448']:
self.ksk_keysize = None
self.zsk_keysize = None
@@ -378,6 +382,18 @@ class dnssec_policy:
self.alg_policy['ECDSAP384SHA384'].ksk_keysize = None;
self.alg_policy['ECDSAP384SHA384'].zsk_keysize = None;
+ self.alg_policy['ED25519'] = copy(p)
+ self.alg_policy['ED25519'].algorithm = "ED25519"
+ self.alg_policy['ED25519'].name = "ED25519"
+ self.alg_policy['ED25519'].ksk_keysize = None;
+ self.alg_policy['ED25519'].zsk_keysize = None;
+
+ self.alg_policy['ED448'] = copy(p)
+ self.alg_policy['ED448'].algorithm = "ED448"
+ self.alg_policy['ED448'].name = "ED448"
+ self.alg_policy['ED448'].ksk_keysize = None;
+ self.alg_policy['ED448'].zsk_keysize = None;
+
if filename:
self.load(filename)
diff --git a/bin/tests/system/conf.sh.in b/bin/tests/system/conf.sh.in
index 9b1d314dfe..5e09f5d122 100644
--- a/bin/tests/system/conf.sh.in
+++ b/bin/tests/system/conf.sh.in
@@ -76,7 +76,7 @@ SUBDIRS="acl additional addzone allow_query autosign builtin
cacheclean case catz chain
checkconf @CHECKDS@ checknames checkzone cookie @COVERAGE@
database digdelv dlv dlvauto dlz dlzexternal
- dns64 dnssec @DNSTAP@ dscp dsdigest dyndb ecdsa
+ dns64 dnssec @DNSTAP@ dscp dsdigest dyndb ecdsa eddsa
emptyzones fetchlimit filter-aaaa formerr geoip glue gost
inline integrity ixfr keepalive @KEYMGR@ legacy limits
logfileconfig lwresd masterfile masterformat metadata mkeys
diff --git a/bin/tests/system/conf.sh.win32 b/bin/tests/system/conf.sh.win32
index eea45ab364..f85723ddc5 100644
--- a/bin/tests/system/conf.sh.win32
+++ b/bin/tests/system/conf.sh.win32
@@ -61,6 +61,7 @@ MDIG=$TOP/Build/$VSCONF/mdig@EXEEXT@
NZD2NZF=$TOP/Build/$VSCONF/named-nzd2nzf@EXEEXT@
FSTRM_CAPTURE=@FSTRM_CAPTURE@
FEATURETEST=$TOP/Build/$VSCONF/feature-test@EXEEXT@
+# to port WIRETEST=$TOP/Build/$VSCONF/wire_test@EXEEXT@
# this is given as argument to native WIN32 executables
RANDFILE=`cygpath -w $TOP/bin/tests/system/random.data`
@@ -72,14 +73,17 @@ KEYDELETE=$TOP/Build/$VSCONF/keydelete@EXEEXT@
LWTEST=$TOP/Build/$VSCONF/lwtest@EXEEXT@
MAKEJOURNAL=$TOP/Build/$VSCONF/makejournal@EXEEXT@
PIPEQUERIES=$TOP/Build/$VSCONF/pipequeries@EXEEXT@
+# to port SAMPLEUPDATE=$TOP/lib/samples/sample-update
# The "stress" test is not run by default since it creates enough
# load on the machine to make it unusable to other users.
# v6synth
-SUBDIRS="acl additional addzone allow_query autosign builtin cacheclean case
- catz checkconf @CHECKDS@ checknames checkzone cookie @COVERAGE@
- database digdelv dlv dlvauto dlz dlzexternal dname dns64 dnssec
- @DNSTAP@ dscp dsdigest dyndb ecdsa ednscompliance emptyzones
+SUBDIRS="acl additional addzone allow_query autosign builtin
+ cacheclean case catz
+ checkconf @CHECKDS@ checknames checkzone cookie @COVERAGE@
+ database digdelv dlv dlvauto dlz dlzexternal dname
+ dns64 dnssec @DNSTAP@ dscp dsdigest dyndb ecdsa eddsa
+ ednscompliance emptyzones
fetchlimit filter-aaaa formerr forward geoip glue gost inline ixfr
keepalive @KEYMGR@ legacy limits logfileconfig lwresd masterfile
masterformat metadata mkeys names notify nslookup nsupdate
@@ -90,6 +94,9 @@ SUBDIRS="acl additional addzone allow_query autosign builtin cacheclean case
tsiggss unknown upforwd verify views wildcard xfer xferquota
zero zonechecks"
+# missing: chain integrity
+# extra: dname ednscompliance forward
+
#Things that are different on Windows
KILL="/bin/kill -f"
DIFF="diff --strip-trailing-cr"
diff --git a/bin/tests/system/eddsa/clean.sh b/bin/tests/system/eddsa/clean.sh
new file mode 100644
index 0000000000..1c0eac79c1
--- /dev/null
+++ b/bin/tests/system/eddsa/clean.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+#
+# Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+rm -f */K* */dsset-* */*.signed */trusted.conf
+rm -f ns1/root.db
+rm -f ns*/signer.err
+rm -f dig.out*
+rm -f */named.run
+rm -f */named.memstats
+rm -f ns*/named.lock
diff --git a/bin/tests/system/eddsa/ns1/named.conf b/bin/tests/system/eddsa/ns1/named.conf
new file mode 100644
index 0000000000..80c4ea3941
--- /dev/null
+++ b/bin/tests/system/eddsa/ns1/named.conf
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+/* $Id$ */
+
+// NS1
+
+controls { /* empty */ };
+
+options {
+ query-source address 10.53.0.1;
+ notify-source 10.53.0.1;
+ transfer-source 10.53.0.1;
+ port 5300;
+ pid-file "named.pid";
+ listen-on { 10.53.0.1; };
+ listen-on-v6 { none; };
+ recursion no;
+ notify yes;
+ dnssec-enable yes;
+ dnssec-validation yes;
+};
+
+zone "." {
+ type master;
+ file "root.db.signed";
+};
+
+include "trusted.conf";
diff --git a/bin/tests/system/eddsa/ns1/root.db.in b/bin/tests/system/eddsa/ns1/root.db.in
new file mode 100644
index 0000000000..994113cec2
--- /dev/null
+++ b/bin/tests/system/eddsa/ns1/root.db.in
@@ -0,0 +1,18 @@
+; Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+; $Id$
+
+$TTL 300
+. IN SOA fdupont.isc.org. a.root.servers.nil. (
+ 2012040600 ; serial
+ 600 ; refresh
+ 600 ; retry
+ 1200 ; expire
+ 600 ; minimum
+ )
+. NS a.root-servers.nil.
+a.root-servers.nil. A 10.53.0.1
diff --git a/bin/tests/system/eddsa/ns1/sign.sh b/bin/tests/system/eddsa/ns1/sign.sh
new file mode 100644
index 0000000000..9d48efc4c3
--- /dev/null
+++ b/bin/tests/system/eddsa/ns1/sign.sh
@@ -0,0 +1,38 @@
+#!/bin/sh -e
+#
+# Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+SYSTEMTESTTOP=../..
+. $SYSTEMTESTTOP/conf.sh
+
+zone=.
+infile=root.db.in
+zonefile=root.db
+
+key1=`$KEYGEN -q -r $RANDFILE -a ED25519 -n zone $zone`
+key2=`$KEYGEN -q -r $RANDFILE -a ED25519 -n zone -f KSK $zone`
+#key2=`$KEYGEN -q -r $RANDFILE -a ED448 -n zone -f KSK $zone`
+$DSFROMKEY -a sha-256 $key2.key > dsset-256
+
+cat $infile $key1.key $key2.key > $zonefile
+
+$SIGNER -P -g -r $RANDFILE -o $zone $zonefile > /dev/null 2> signer.err || cat signer.err
+
+# Configure the resolving server with a trusted key.
+
+cat $key1.key | grep -v '^; ' | $PERL -n -e '
+local ($dn, $class, $type, $flags, $proto, $alg, @rest) = split;
+local $key = join("", @rest);
+print < trusted.conf
+cp trusted.conf ../ns2/trusted.conf
+
+cd ../ns2 && $SHELL sign.sh
diff --git a/bin/tests/system/eddsa/ns2/Xexample.com.+015+03613.key b/bin/tests/system/eddsa/ns2/Xexample.com.+015+03613.key
new file mode 100644
index 0000000000..ff6d5bfb73
--- /dev/null
+++ b/bin/tests/system/eddsa/ns2/Xexample.com.+015+03613.key
@@ -0,0 +1 @@
+example.com. IN DNSKEY 257 3 15 l02Woi0iS8Aa25FQkUd9RMzZHJpBoRQwAQEX1SxZJA4=
diff --git a/bin/tests/system/eddsa/ns2/Xexample.com.+015+03613.private b/bin/tests/system/eddsa/ns2/Xexample.com.+015+03613.private
new file mode 100644
index 0000000000..788b2d7d94
--- /dev/null
+++ b/bin/tests/system/eddsa/ns2/Xexample.com.+015+03613.private
@@ -0,0 +1,4 @@
+Private-key-format: v1.2
+Algorithm: 15 (ED25519)
+PrivateKey: ODIyNjAzODQ2MjgwODAxMjI2NDUxOTAyMDQxNDIyNjI=
+
diff --git a/bin/tests/system/eddsa/ns2/Xexample.com.+015+35217.key b/bin/tests/system/eddsa/ns2/Xexample.com.+015+35217.key
new file mode 100644
index 0000000000..71e46207e2
--- /dev/null
+++ b/bin/tests/system/eddsa/ns2/Xexample.com.+015+35217.key
@@ -0,0 +1 @@
+example.com. IN DNSKEY 257 3 15 zPnZ/QwEe7S8C5SPz2OfS5RR40ATk2/rYnE9xHIEijs=
diff --git a/bin/tests/system/eddsa/ns2/Xexample.com.+015+35217.private b/bin/tests/system/eddsa/ns2/Xexample.com.+015+35217.private
new file mode 100644
index 0000000000..78ec36df83
--- /dev/null
+++ b/bin/tests/system/eddsa/ns2/Xexample.com.+015+35217.private
@@ -0,0 +1,3 @@
+Private-key-format: v1.2
+Algorithm: 15 (ED25519)
+PrivateKey: DSSF3o0s0f+ElWzj9E/Osxw8hLpk55chkmx0LYN5WiY=
diff --git a/bin/tests/system/eddsa/ns2/example.com.db b/bin/tests/system/eddsa/ns2/example.com.db
new file mode 100644
index 0000000000..e9d53038bc
--- /dev/null
+++ b/bin/tests/system/eddsa/ns2/example.com.db
@@ -0,0 +1,22 @@
+; Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+; $Id$
+
+$TTL 3600
+@ IN SOA fdupont.isc.org. ns.example.com. (
+ 2012040600 ; serial
+ 600 ; refresh
+ 600 ; retry
+ 1200 ; expire
+ 3600 ; minimum
+ )
+ MX 10 mail.example.com.
+ NS ns.example.com.
+ns.example.com. A 10.53.0.3
+;
+$INCLUDE Kexample.com.+015+03613.key
+$INCLUDE Kexample.com.+015+35217.key
diff --git a/bin/tests/system/eddsa/ns2/named.conf b/bin/tests/system/eddsa/ns2/named.conf
new file mode 100644
index 0000000000..b4e911efe9
--- /dev/null
+++ b/bin/tests/system/eddsa/ns2/named.conf
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+/* $Id$ */
+
+// NS2
+
+controls { /* empty */ };
+
+options {
+ query-source address 10.53.0.2;
+ notify-source 10.53.0.2;
+ transfer-source 10.53.0.2;
+ port 5300;
+ pid-file "named.pid";
+ listen-on { 10.53.0.2; };
+ listen-on-v6 { none; };
+ recursion yes;
+ notify yes;
+ dnssec-enable yes;
+ dnssec-validation yes;
+};
+
+zone "." {
+ type hint;
+ file "../../common/root.hint";
+};
+
+include "trusted.conf";
diff --git a/bin/tests/system/eddsa/ns2/sign.sh b/bin/tests/system/eddsa/ns2/sign.sh
new file mode 100644
index 0000000000..19e861a07c
--- /dev/null
+++ b/bin/tests/system/eddsa/ns2/sign.sh
@@ -0,0 +1,23 @@
+#!/bin/sh -e
+#
+# Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+SYSTEMTESTTOP=../..
+. $SYSTEMTESTTOP/conf.sh
+
+zone=example.com.
+zonefile=example.com.db
+starttime=20150729220000
+endtime=20150819220000
+
+for i in Xexample.com.+015+03613.key Xexample.com.+015+03613.private \
+ Xexample.com.+015+35217.key Xexample.com.+015+35217.private
+do
+ cp $i `echo $i | sed s/X/K/`
+done
+
+$SIGNER -P -z -s $starttime -e $endtime -r $RANDFILE -o $zone $zonefile > /dev/null 2> signer.err || cat signer.err
diff --git a/bin/tests/system/eddsa/prereq.sh b/bin/tests/system/eddsa/prereq.sh
new file mode 100644
index 0000000000..c67a067e71
--- /dev/null
+++ b/bin/tests/system/eddsa/prereq.sh
@@ -0,0 +1,12 @@
+#!/bin/sh -e
+#
+# Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+SYSTEMTESTTOP=..
+. $SYSTEMTESTTOP/conf.sh
+
+exec $SHELL ../testcrypto.sh eddsa
diff --git a/bin/tests/system/eddsa/setup.sh b/bin/tests/system/eddsa/setup.sh
new file mode 100644
index 0000000000..74e3e7a1da
--- /dev/null
+++ b/bin/tests/system/eddsa/setup.sh
@@ -0,0 +1,14 @@
+#!/bin/sh -e
+#
+# Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+SYSTEMTESTTOP=..
+. $SYSTEMTESTTOP/conf.sh
+
+test -r $RANDFILE || $GENRANDOM 800 $RANDFILE
+
+cd ns1 && $SHELL sign.sh
diff --git a/bin/tests/system/eddsa/tests.sh b/bin/tests/system/eddsa/tests.sh
new file mode 100644
index 0000000000..fefbff3aa3
--- /dev/null
+++ b/bin/tests/system/eddsa/tests.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+#
+# Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# $Id$
+
+SYSTEMTESTTOP=..
+. $SYSTEMTESTTOP/conf.sh
+
+status=0
+n=0
+
+rm -f dig.out.*
+
+DIGOPTS="+tcp +noau +noadd +nosea +nostat +nocmd +dnssec -p 5300"
+
+# Check the example. domain
+
+echo "I:checking that positive validation works ($n)"
+ret=0
+$DIG $DIGOPTS . @10.53.0.1 soa > dig.out.ns1.test$n || ret=1
+$DIG $DIGOPTS . @10.53.0.2 soa > dig.out.ns2.test$n || ret=1
+$PERL ../digcomp.pl dig.out.ns1.test$n dig.out.ns2.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+# Check test vectors (RFC 8080 + errata)
+
+echo "I:checking that test vectors match ($n)"
+ret=0
+grep 'oL9krJun7xfBOIWcGHi7mag5/hdZrKWw15jP' ns2/example.com.db.signed > /dev/null || ret=1
+grep 'VrbpMngwcrqNAg==' ns2/example.com.db.signed > /dev/null || ret=1
+grep 'zXQ0bkYgQTEFyfLyi9QoiY6D8ZdYo4wyUhVi' ns2/example.com.db.signed > /dev/null || ret=1
+grep 'R0O7KuI5k2pcBg==' ns2/example.com.db.signed > /dev/null || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:exit status: $status"
+[ $status -eq 0 ] || exit 1
diff --git a/bin/tests/system/pkcs11/ns1/named.conf b/bin/tests/system/pkcs11/ns1/named.conf
index c0df9d59bc..e5e06b04f0 100644
--- a/bin/tests/system/pkcs11/ns1/named.conf
+++ b/bin/tests/system/pkcs11/ns1/named.conf
@@ -42,3 +42,9 @@ zone "ecc.example." {
file "ecc.example.db.signed";
allow-update { any; };
};
+
+zone "ecx.example." {
+ type master;
+ file "ecx.example.db.signed";
+ allow-update { any; };
+};
diff --git a/bin/tests/system/pkcs11/prereq.sh b/bin/tests/system/pkcs11/prereq.sh
index e365f78bf3..2b5900a275 100644
--- a/bin/tests/system/pkcs11/prereq.sh
+++ b/bin/tests/system/pkcs11/prereq.sh
@@ -10,18 +10,24 @@ SYSTEMTESTTOP=..
. $SYSTEMTESTTOP/conf.sh
echo "I:(Native PKCS#11)" >&2
-rsafail=0 eccfail=0
+rsafail=0 eccfail=0 ecxfail=0
$SHELL ../testcrypto.sh -q rsa || rsafail=1
$SHELL ../testcrypto.sh -q ecdsa || eccfail=1
+$SHELL ../testcrypto.sh -q eddsa || ecxfail=1
-if [ $rsafail = 0 -a $eccfail = 0 ]; then
- echo both > supported
-elif [ $rsafail = 1 -a $eccfail = 1 ]; then
+if [ $rsafail = 1 -a $eccfail = 1 ]; then
echo "I:This test requires PKCS#11 support for either RSA or ECDSA cryptography." >&2
exit 255
-elif [ $rsafail = 0 ]; then
- echo rsaonly > supported
-else
- echo ecconly > supported
+fi
+rm -f supported
+touch supported
+if [ $rsafail = 0 ]; then
+ echo rsa >> supported
+fi
+if [ $eccfail = 0 ]; then
+ echo ecc >> supported
+fi
+if [ $ecxfail = 0 ]; then
+ echo ecx >> supported
fi
diff --git a/bin/tests/system/pkcs11/setup.sh b/bin/tests/system/pkcs11/setup.sh
index 850034c0c7..d81b5f9750 100644
--- a/bin/tests/system/pkcs11/setup.sh
+++ b/bin/tests/system/pkcs11/setup.sh
@@ -14,11 +14,10 @@ infile=ns1/example.db.in
/bin/echo -n ${HSMPIN:-1234}> pin
PWD=`pwd`
-supported=`cat supported`
-
zone=rsa.example
zonefile=ns1/rsa.example.db
-if [ "$supported" != "ecconly" ]; then
+have_rsa=`grep rsa supported`
+if [ "x$have_rsa" != "x" ]; then
$PK11GEN -a RSA -b 1024 -l robie-rsa-zsk1 -i 01
$PK11GEN -a RSA -b 1024 -l robie-rsa-zsk2 -i 02
$PK11GEN -a RSA -b 2048 -l robie-rsa-ksk
@@ -42,7 +41,8 @@ fi
zone=ecc.example
zonefile=ns1/ecc.example.db
-if [ "$supported" != "rsaonly" ]; then
+have_ecc=`grep ecc supported`
+if [ "x$have_ecc" != "x" ]; then
$PK11GEN -a ECC -b 256 -l robie-ecc-zsk1 -i 03
$PK11GEN -a ECC -b 256 -l robie-ecc-zsk2 -i 04
$PK11GEN -a ECC -b 384 -l robie-ecc-ksk
@@ -64,4 +64,32 @@ else
cp $infile ${zonefile}.signed
fi
+zone=ecx.example
+zonefile=ns1/ecx.example.db
+have_ecx=`grep ecx supported`
+if [ "x$have_ecx" != "x" ]; then
+ $PK11GEN -a ECX -b 256 -l robie-ecx-zsk1 -i 05
+ $PK11GEN -a ECX -b 256 -l robie-ecx-zsk2 -i 06
+ $PK11GEN -a ECX -b 256 -l robie-ecx-ksk
+# $PK11GEN -a ECX -b 456 -l robie-ecx-ksk
+
+ ecxzsk1=`$KEYFRLAB -a ED25519 \
+ -l "object=robie-ecx-zsk1;pin-source=$PWD/pin" ecx.example`
+ ecxzsk2=`$KEYFRLAB -a ED25519 \
+ -l "object=robie-ecx-zsk2;pin-source=$PWD/pin" ecx.example`
+ ecxksk=`$KEYFRLAB -a ED25519 -f ksk \
+ -l "object=robie-ecx-ksk;pin-source=$PWD/pin" ecx.example`
+# ecxksk=`$KEYFRLAB -a ED448 -f ksk \
+# -l "object=robie-ecx-ksk;pin-source=$PWD/pin" ecx.example`
+
+ cat $infile $ecxzsk1.key $ecxksk.key > $zonefile
+ $SIGNER -a -P -g -r $RANDFILE -o $zone $zonefile \
+ > /dev/null 2> signer.err || cat signer.err
+ cp $ecxzsk2.key ns1/ecx.key
+ mv Kecx* ns1
+else
+ # ECX not available and will not be tested; make a placeholder
+ cp $infile ${zonefile}.signed
+fi
+
rm -f signer.err
diff --git a/bin/tests/system/pkcs11/tests.sh b/bin/tests/system/pkcs11/tests.sh
index a5d4a8bd1c..fdf1663ef4 100644
--- a/bin/tests/system/pkcs11/tests.sh
+++ b/bin/tests/system/pkcs11/tests.sh
@@ -16,13 +16,19 @@ DIGOPTS="+tcp +noadd +nosea +nostat +nocmd +dnssec -p 5300"
status=0
ret=0
-supported=`cat supported`
-case $supported in
- rsaonly) algs="rsa" ;;
- ecconly) algs="ecc" ;;
- both) algs="rsa ecc" ;;
-esac
-
+algs=""
+have_rsa=`grep rsa supported`
+if [ "x$have_rsa" != "x" ]; then
+ algs="rsa "
+fi
+have_ecc=`grep ecc supported`
+if [ "x$have_ecc" != "x" ]; then
+ algs=$algs"ecc "
+fi
+have_ecx=`grep ecc supported`
+if [ "x$have_ecx" != "x" ]; then
+ algs=$algs"ecx "
+fi
for alg in $algs; do
zonefile=ns1/$alg.example.db
@@ -66,6 +72,7 @@ END
case $alg in
rsa) id=02 ;;
ecc) id=04 ;;
+ ecx) id=06 ;;
esac
$PK11DEL -i $id -w0 > /dev/null 2>&1 || ret=1
if [ $ret != 0 ]; then echo "I:failed"; fi
diff --git a/bin/tests/system/testcrypto.sh b/bin/tests/system/testcrypto.sh
index 2f8e59cd28..8aad3e04d8 100644
--- a/bin/tests/system/testcrypto.sh
+++ b/bin/tests/system/testcrypto.sh
@@ -39,6 +39,11 @@ while test "$#" -gt 0; do
msg1="ECDSA cryptography"
msg2="--with-ecdsa"
;;
+ eddsa|EDDSA)
+ alg="-a ED25519"
+ msg1="EDDSA cryptography"
+ msg2="--with-eddsa"
+ ;;
*)
echo "${prog}: unknown argument"
exit 1
diff --git a/config.h.in b/config.h.in
index b7befbb5b8..89fdb143fa 100644
--- a/config.h.in
+++ b/config.h.in
@@ -368,6 +368,12 @@ int sigwait(const unsigned int *set, int *sig);
/* Define if your OpenSSL version supports ECDSA. */
#undef HAVE_OPENSSL_ECDSA
+/* Define if your OpenSSL version supports Ed25519. */
+#undef HAVE_OPENSSL_ED25519
+
+/* Define if your OpenSSL version supports Ed448. */
+#undef HAVE_OPENSSL_ED448
+
/* Define if your OpenSSL version supports EVP AES */
#undef HAVE_OPENSSL_EVP_AES
@@ -377,6 +383,12 @@ int sigwait(const unsigned int *set, int *sig);
/* Define if your PKCS11 provider supports ECDSA. */
#undef HAVE_PKCS11_ECDSA
+/* Define if your PKCS11 provider supports Ed25519. */
+#undef HAVE_PKCS11_ED25519
+
+/* Define if your PKCS11 provider supports Ed448. */
+#undef HAVE_PKCS11_ED448
+
/* Define if your PKCS11 provider supports GOST. */
#undef HAVE_PKCS11_GOST
diff --git a/config.h.win32 b/config.h.win32
index 6f3f72484a..9d45f7ba51 100644
--- a/config.h.win32
+++ b/config.h.win32
@@ -328,12 +328,24 @@ typedef __int64 off_t;
/* Define if OpenSSL includes ECDSA support */
@HAVE_OPENSSL_ECDSA@
+/* Define if OpenSSL includes Ed25519 support */
+@HAVE_OPENSSL_ED25519@
+
+/* Define if OpenSSL includes Ed448 support */
+@HAVE_OPENSSL_ED448@
+
/* Define if your OpenSSL version supports GOST. */
@HAVE_OPENSSL_GOST@
/* Define if your PKCS11 provider supports ECDSA. */
@HAVE_PKCS11_ECDSA@
+/* Define if your PKCS11 provider supports Ed25519. */
+@HAVE_PKCS11_ED25519@
+
+/* Define if your PKCS11 provider supports Ed448. */
+@HAVE_PKCS11_ED448@
+
/* Define if your PKCS11 provider supports GOST. */
@HAVE_PKCS11_GOST@
diff --git a/configure b/configure
index e75b6bb325..640d9aa6c3 100755
--- a/configure
+++ b/configure
@@ -821,6 +821,7 @@ NZDTARGETS
NZDSRCS
NZD_TOOLS
PKCS11_TEST
+PKCS11_ED25519
PKCS11_GOST
PKCS11_ECDSA
CRYPTO
@@ -843,11 +844,14 @@ ISC_OPENSSL_INC
ISC_PLATFORM_OPENSSLHASH
ISC_PLATFORM_WANTAES
OPENSSL_GOST
+OPENSSL_ED25519
OPENSSL_ECDSA
OPENSSLLINKSRCS
OPENSSLLINKOBJS
OPENSSLGOSTLINKSRCS
OPENSSLGOSTLINKOBJS
+OPENSSLEDDSALINKSRCS
+OPENSSLEDDSALINKOBJS
DST_OPENSSL_INC
INSTALL_LIBRARY
ISC_THREAD_DIR
@@ -1016,6 +1020,7 @@ with_openssl
with_pkcs11
with_ecdsa
with_gost
+with_eddsa
with_aes
enable_openssl_hash
with_cc_alg
@@ -1748,6 +1753,7 @@ Optional Packages:
(PATH is for the PKCS11 provider)
--with-ecdsa Crypto ECDSA
--with-gost Crypto GOST yes|no|raw|asn1.
+ --with-eddsa Crypto EDDSA yes|all|no.
--with-aes Crypto AES
--with-cc-alg=ALG choose the algorithm for Client Cookie [aes|sha1|sha256]
--with-lmdb=PATH build with LMDB library yes|no|path
@@ -15792,7 +15798,7 @@ fi
#
-# were --with-ecdsa, --with-gost, --with-aes specified
+# were --with-ecdsa, --with-gost, --with-eddsa, --with-aes specified
#
# Check whether --with-ecdsa was given.
@@ -15811,6 +15817,14 @@ else
fi
+# Check whether --with-eddsa was given.
+if test "${with_eddsa+set}" = set; then :
+ withval=$with_eddsa; with_eddsa="$withval"
+else
+ with_eddsa="auto"
+fi
+
+
# Check whether --with-aes was given.
if test "${with_aes+set}" = set; then :
withval=$with_aes; with_aes="$withval"
@@ -15892,6 +15906,7 @@ then
fi
OPENSSL_ECDSA=""
OPENSSL_GOST=""
+OPENSSL_ED25519=""
gosttype="raw"
case "$with_gost" in
raw)
@@ -15917,6 +15932,8 @@ case "$use_openssl" in
$as_echo "disabled because of native PKCS11" >&6; }
DST_OPENSSL_INC=""
CRYPTO="-DPKCS11CRYPTO"
+ OPENSSLEDDSALINKOBJS=""
+ OPENSSLEDDSALINKSRS=""
OPENSSLGOSTLINKOBJS=""
OPENSSLGOSTLINKSRS=""
OPENSSLLINKOBJS=""
@@ -15927,6 +15944,8 @@ $as_echo "disabled because of native PKCS11" >&6; }
$as_echo "no" >&6; }
DST_OPENSSL_INC=""
CRYPTO=""
+ OPENSSLEDDSALINKOBJS=""
+ OPENSSLEDDSALINKSRS=""
OPENSSLGOSTLINKOBJS=""
OPENSSLGOSTLINKSRS=""
OPENSSLLINKOBJS=""
@@ -15935,6 +15954,8 @@ $as_echo "no" >&6; }
auto)
DST_OPENSSL_INC=""
CRYPTO=""
+ OPENSSLEDDSALINKOBJS=""
+ OPENSSLEDDSALINKSRS=""
OPENSSLGOSTLINKOBJS=""
OPENSSLGOSTLINKSRS=""
OPENSSLLINKOBJS=""
@@ -16348,6 +16369,120 @@ $as_echo "#define HAVE_OPENSSL_GOST 1" >>confdefs.h
;;
esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OpenSSL Ed25519 support" >&5
+$as_echo_n "checking for OpenSSL Ed25519 support... " >&6; }
+ have_ed25519=""
+ have_ed448=""
+ if test "$cross_compiling" = yes; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: using --with-eddsa" >&5
+$as_echo "using --with-eddsa" >&6; }
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include
+#include
+int main() {
+ EVP_PKEY_CTX *ctx;
+
+ ctx = EVP_PKEY_CTX_new_id(NID_ED25519, NULL);
+ if (ctx == NULL)
+ return (2);
+ return (0);
+}
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ have_ed25519="yes"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ have_ed25519="no"
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+ case "$with_eddsa" in
+ yes|all)
+ case "$have_ed25519" in
+ no) as_fn_error $? "eddsa not supported" "$LINENO" 5 ;;
+ *) have_ed25519=yes ;;
+ esac
+ ;;
+ no)
+ have_ed25519=no ;;
+ *)
+ case "$have_ed25519" in
+ yes|no) ;;
+ *) as_fn_error $? "need --with-eddsa=[yes, all or no]" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+ case $have_ed25519 in
+ yes)
+ OPENSSL_ED25519="yes"
+ OPENSSLEDDSALINKOBJS='${OPENSSLEDDSALINKOBJS}'
+ OPENSSLEDDSALINKSRCS='${OPENSSLEDDSALINKSRCS}'
+
+$as_echo "#define HAVE_OPENSSL_ED25519 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OpenSSL Ed448 support" >&5
+$as_echo_n "checking for OpenSSL Ed448 support... " >&6; }
+ if test "$cross_compiling" = yes; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: using --with-eddsa" >&5
+$as_echo "using --with-eddsa" >&6; }
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include
+#include
+int main() {
+ EVP_PKEY_CTX *ctx;
+
+ ctx = EVP_PKEY_CTX_new_id(NID_ED448, NULL);
+ if (ctx == NULL)
+ return (2);
+ return (0);
+}
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ have_ed448="yes"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ have_ed448="no"
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+ case $with_eddsa in
+ all)
+ have_ed448=yes ;;
+ *)
+ ;;
+ esac
+ case $have_ed448 in
+ yes)
+
+$as_echo "#define HAVE_OPENSSL_ED448 1" >>confdefs.h
+],
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ *)
+ ;;
+ esac
+
have_aes="no"
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OpenSSL AES support" >&5
$as_echo_n "checking for OpenSSL AES support... " >&6; }
@@ -16440,6 +16575,9 @@ esac
+
+
+
DNS_CRYPTO_LIBS="$DNS_CRYPTO_LIBS $DST_OPENSSL_LIBS"
ISC_PLATFORM_WANTAES="#undef ISC_PLATFORM_WANTAES"
@@ -16694,6 +16832,7 @@ esac
PKCS11_ECDSA=""
PKCS11_GOST=""
+PKCS11_ED25519=""
set_pk11_flavor="no"
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for native PKCS11" >&5
$as_echo_n "checking for native PKCS11... " >&6; }
@@ -16737,6 +16876,37 @@ $as_echo "#define HAVE_PKCS11_GOST 1" >>confdefs.h
$as_echo "disabled" >&6; }
;;
esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PKCS11 Ed25519" >&5
+$as_echo_n "checking for PKCS11 Ed25519... " >&6; }
+ case "$with_eddsa" in
+ yes|all)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: enabled" >&5
+$as_echo "enabled" >&6; }
+ PKCS11_ED25519="yes"
+
+$as_echo "#define HAVE_PKCS11_ED25519 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PKCS11 Ed448" >&5
+$as_echo_n "checking for PKCS11 Ed448... " >&6; }
+ case "$with_eddsa" in
+ all)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: enabled" >&5
+$as_echo "enabled" >&6; }
+
+$as_echo "#define HAVE_PKCS11_ED448 1" >>confdefs.h
+
+ ;;
+ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5
+$as_echo "disabled" >&6; }
+ ;;
+ esac
+ ;;
+ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5
+$as_echo "disabled" >&6; }
+ ;;
+ esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PKCS11 flavor" >&5
$as_echo_n "checking for PKCS11 flavor... " >&6; }
case "$PKCS11_PROVIDER" in
@@ -16797,6 +16967,7 @@ esac
+
# for PKCS11 benchmarks
have_clock_gt=no
@@ -25934,6 +26105,8 @@ report() {
fi
test "yes" = "$OPENSSL_ECDSA" -o "$PKCS11_ECDSA" && \
echo " ECDSA algorithm support (--with-ecdsa)"
+ test "yes" = "$OPENSSL_ED25519" -o "$PKCS11_ED25519" && \
+ echo " EDDSA algorithm support (--with-eddsa)"
test "yes" = "$enable_fixed" && \
echo " Allow 'fixed' rrset-order (--enable-fixed-rrset)"
test "yes" = "$enable_filter" && \
@@ -25995,6 +26168,8 @@ report() {
echo " GOST algorithm support (--with-gost)"
test "X$CRYPTO" = "X" -o "yes" = "$OPENSSL_ECDSA" -o "yes" = "$PKCS11_ECDSA" || \
echo " ECDSA algorithm support (--with-ecdsa)"
+ test "X$CRYPTO" = "X" -o "yes" = "$OPENSSL_ED25519" -o "yes" = "$PKCS11_ED25519" || \
+ echo " EDDSA algorithm support (--with-eddsa)"
test "yes" = "$enable_seccomp" || \
echo " Use libseccomp system call filtering (--enable-seccomp)"
diff --git a/configure.in b/configure.in
index 69f8bdcd74..50dbd40231 100644
--- a/configure.in
+++ b/configure.in
@@ -1443,12 +1443,14 @@ AC_ARG_WITH(pkcs11,
use_pkcs11="$withval", use_pkcs11="auto")
#
-# were --with-ecdsa, --with-gost, --with-aes specified
+# were --with-ecdsa, --with-gost, --with-eddsa, --with-aes specified
#
AC_ARG_WITH(ecdsa, [ --with-ecdsa Crypto ECDSA],
with_ecdsa="$withval", with_ecdsa="auto")
AC_ARG_WITH(gost, [ --with-gost Crypto GOST [yes|no|raw|asn1].],
with_gost="$withval", with_gost="auto")
+AC_ARG_WITH(eddsa, [ --with-eddsa Crypto EDDSA [yes|all|no].],
+ with_eddsa="$withval", with_eddsa="auto")
AC_ARG_WITH(aes, [ --with-aes Crypto AES],
with_aes="$withval", with_aes="checkcc")
@@ -1514,6 +1516,7 @@ then
fi
OPENSSL_ECDSA=""
OPENSSL_GOST=""
+OPENSSL_ED25519=""
gosttype="raw"
case "$with_gost" in
raw)
@@ -1537,6 +1540,8 @@ case "$use_openssl" in
AC_MSG_RESULT(disabled because of native PKCS11)
DST_OPENSSL_INC=""
CRYPTO="-DPKCS11CRYPTO"
+ OPENSSLEDDSALINKOBJS=""
+ OPENSSLEDDSALINKSRS=""
OPENSSLGOSTLINKOBJS=""
OPENSSLGOSTLINKSRS=""
OPENSSLLINKOBJS=""
@@ -1546,6 +1551,8 @@ case "$use_openssl" in
AC_MSG_RESULT(no)
DST_OPENSSL_INC=""
CRYPTO=""
+ OPENSSLEDDSALINKOBJS=""
+ OPENSSLEDDSALINKSRS=""
OPENSSLGOSTLINKOBJS=""
OPENSSLGOSTLINKSRS=""
OPENSSLLINKOBJS=""
@@ -1554,6 +1561,8 @@ case "$use_openssl" in
auto)
DST_OPENSSL_INC=""
CRYPTO=""
+ OPENSSLEDDSALINKOBJS=""
+ OPENSSLEDDSALINKSRS=""
OPENSSLGOSTLINKOBJS=""
OPENSSLGOSTLINKSRS=""
OPENSSLLINKOBJS=""
@@ -1853,6 +1862,86 @@ int main() {
;;
esac
+ AC_MSG_CHECKING(for OpenSSL Ed25519 support)
+ have_ed25519=""
+ have_ed448=""
+ AC_TRY_RUN([
+#include
+#include
+int main() {
+ EVP_PKEY_CTX *ctx;
+
+ ctx = EVP_PKEY_CTX_new_id(NID_ED25519, NULL);
+ if (ctx == NULL)
+ return (2);
+ return (0);
+}
+],
+ [AC_MSG_RESULT(yes)
+ have_ed25519="yes"],
+ [AC_MSG_RESULT(no)
+ have_ed25519="no"],
+ [AC_MSG_RESULT(using --with-eddsa)])
+ case "$with_eddsa" in
+ yes|all)
+ case "$have_ed25519" in
+ no) AC_MSG_ERROR([eddsa not supported]) ;;
+ *) have_ed25519=yes ;;
+ esac
+ ;;
+ no)
+ have_ed25519=no ;;
+ *)
+ case "$have_ed25519" in
+ yes|no) ;;
+ *) AC_MSG_ERROR([need --with-eddsa=[[yes, all or no]]]) ;;
+ esac
+ ;;
+ esac
+ case $have_ed25519 in
+ yes)
+ OPENSSL_ED25519="yes"
+ OPENSSLEDDSALINKOBJS='${OPENSSLEDDSALINKOBJS}'
+ OPENSSLEDDSALINKSRCS='${OPENSSLEDDSALINKSRCS}'
+ AC_DEFINE(HAVE_OPENSSL_ED25519, 1,
+ [Define if your OpenSSL version supports Ed25519.])
+ AC_MSG_CHECKING(for OpenSSL Ed448 support)
+ AC_TRY_RUN([
+#include
+#include
+int main() {
+ EVP_PKEY_CTX *ctx;
+
+ ctx = EVP_PKEY_CTX_new_id(NID_ED448, NULL);
+ if (ctx == NULL)
+ return (2);
+ return (0);
+}
+],
+ [AC_MSG_RESULT(yes)
+ have_ed448="yes"],
+ [AC_MSG_RESULT(no)
+ have_ed448="no"],
+ [AC_MSG_RESULT(using --with-eddsa)])
+ case $with_eddsa in
+ all)
+ have_ed448=yes ;;
+ *)
+ ;;
+ esac
+ case $have_ed448 in
+ yes)
+ AC_DEFINE(HAVE_OPENSSL_ED448, 1,
+ [Define if your OpenSSL version supports Ed448.])],
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ *)
+ ;;
+ esac
+
have_aes="no"
AC_MSG_CHECKING(for OpenSSL AES support)
AC_TRY_RUN([
@@ -1915,11 +2004,14 @@ esac
#
AC_SUBST(DST_OPENSSL_INC)
+AC_SUBST(OPENSSLEDDSALINKOBJS)
+AC_SUBST(OPENSSLEDDSALINKSRCS)
AC_SUBST(OPENSSLGOSTLINKOBJS)
AC_SUBST(OPENSSLGOSTLINKSRCS)
AC_SUBST(OPENSSLLINKOBJS)
AC_SUBST(OPENSSLLINKSRCS)
AC_SUBST(OPENSSL_ECDSA)
+AC_SUBST(OPENSSL_ED25519)
AC_SUBST(OPENSSL_GOST)
DNS_CRYPTO_LIBS="$DNS_CRYPTO_LIBS $DST_OPENSSL_LIBS"
@@ -2138,6 +2230,7 @@ AC_SUBST(PKCS11_PROVIDER)
PKCS11_ECDSA=""
PKCS11_GOST=""
+PKCS11_ED25519=""
set_pk11_flavor="no"
AC_MSG_CHECKING(for native PKCS11)
@@ -2171,6 +2264,29 @@ case "$want_native_pkcs11" in
AC_MSG_RESULT(disabled)
;;
esac
+ AC_MSG_CHECKING(for PKCS11 Ed25519)
+ case "$with_eddsa" in
+ yes|all)
+ AC_MSG_RESULT(enabled)
+ PKCS11_ED25519="yes"
+ AC_DEFINE(HAVE_PKCS11_ED25519, 1,
+ [Define if your PKCS11 provider supports Ed25519.])
+ AC_MSG_CHECKING(for PKCS11 Ed448)
+ case "$with_eddsa" in
+ all)
+ AC_MSG_RESULT(enabled)
+ AC_DEFINE(HAVE_PKCS11_ED448, 1,
+ [Define if your PKCS11 provider supports Ed448.])
+ ;;
+ *)
+ AC_MSG_RESULT(disabled)
+ ;;
+ esac
+ ;;
+ *)
+ AC_MSG_RESULT(disabled)
+ ;;
+ esac
AC_MSG_CHECKING(for PKCS11 flavor)
case "$PKCS11_PROVIDER" in
*nfast*)
@@ -2220,6 +2336,7 @@ AC_SUBST(PKCS11LINKSRCS)
AC_SUBST(CRYPTO)
AC_SUBST(PKCS11_ECDSA)
AC_SUBST(PKCS11_GOST)
+AC_SUBST(PKCS11_ED25519)
AC_SUBST(PKCS11_TEST)
# for PKCS11 benchmarks
@@ -5351,6 +5468,8 @@ report() {
fi
test "yes" = "$OPENSSL_ECDSA" -o "$PKCS11_ECDSA" && \
echo " ECDSA algorithm support (--with-ecdsa)"
+ test "yes" = "$OPENSSL_ED25519" -o "$PKCS11_ED25519" && \
+ echo " EDDSA algorithm support (--with-eddsa)"
test "yes" = "$enable_fixed" && \
echo " Allow 'fixed' rrset-order (--enable-fixed-rrset)"
test "yes" = "$enable_filter" && \
@@ -5412,6 +5531,8 @@ report() {
echo " GOST algorithm support (--with-gost)"
test "X$CRYPTO" = "X" -o "yes" = "$OPENSSL_ECDSA" -o "yes" = "$PKCS11_ECDSA" || \
echo " ECDSA algorithm support (--with-ecdsa)"
+ test "X$CRYPTO" = "X" -o "yes" = "$OPENSSL_ED25519" -o "yes" = "$PKCS11_ED25519" || \
+ echo " EDDSA algorithm support (--with-eddsa)"
test "yes" = "$enable_seccomp" || \
echo " Use libseccomp system call filtering (--enable-seccomp)"
diff --git a/doc/rfc/rfc8080.txt b/doc/rfc/rfc8080.txt
new file mode 100644
index 0000000000..631f9c1a33
--- /dev/null
+++ b/doc/rfc/rfc8080.txt
@@ -0,0 +1,395 @@
+
+
+
+
+
+
+Internet Engineering Task Force (IETF) O. Sury
+Request for Comments: 8080 CZ.NIC
+Category: Standards Track R. Edmonds
+ISSN: 2070-1721 Fastly
+ February 2017
+
+
+ Edwards-Curve Digital Security Algorithm (EdDSA) for DNSSEC
+
+Abstract
+
+ This document describes how to specify Edwards-curve Digital Security
+ Algorithm (EdDSA) keys and signatures in DNS Security (DNSSEC). It
+ uses EdDSA with the choice of two curves: Ed25519 and Ed448.
+
+Status of This Memo
+
+ This is an Internet Standards Track document.
+
+ This document is a product of the Internet Engineering Task Force
+ (IETF). It represents the consensus of the IETF community. It has
+ received public review and has been approved for publication by the
+ Internet Engineering Steering Group (IESG). Further information on
+ Internet Standards is available in Section 2 of RFC 7841.
+
+ Information about the current status of this document, any errata,
+ and how to provide feedback on it may be obtained at
+ http://www.rfc-editor.org/info/rfc8080.
+
+Copyright Notice
+
+ Copyright (c) 2017 IETF Trust and the persons identified as the
+ document authors. All rights reserved.
+
+ This document is subject to BCP 78 and the IETF Trust's Legal
+ Provisions Relating to IETF Documents
+ (http://trustee.ietf.org/license-info) in effect on the date of
+ publication of this document. Please review these documents
+ carefully, as they describe your rights and restrictions with respect
+ to this document. Code Components extracted from this document must
+ include Simplified BSD License text as described in Section 4.e of
+ the Trust Legal Provisions and are provided without warranty as
+ described in the Simplified BSD License.
+
+
+
+
+
+
+
+
+Sury & Edmonds Standards Track [Page 1]
+
+RFC 8080 EdDSA for DNSSEC February 2017
+
+
+Table of Contents
+
+ 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 2
+ 2. Requirements Language . . . . . . . . . . . . . . . . . . . . 2
+ 3. DNSKEY Resource Records . . . . . . . . . . . . . . . . . . . 2
+ 4. RRSIG Resource Records . . . . . . . . . . . . . . . . . . . 3
+ 5. Algorithm Number for DS, DNSKEY, and RRSIG Resource Records . 3
+ 6. Examples . . . . . . . . . . . . . . . . . . . . . . . . . . 3
+ 6.1. Ed25519 Examples . . . . . . . . . . . . . . . . . . . . 3
+ 6.2. Ed448 Examples . . . . . . . . . . . . . . . . . . . . . 4
+ 7. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 5
+ 8. Security Considerations . . . . . . . . . . . . . . . . . . . 5
+ 9. References . . . . . . . . . . . . . . . . . . . . . . . . . 6
+ 9.1. Normative References . . . . . . . . . . . . . . . . . . 6
+ 9.2. Informative References . . . . . . . . . . . . . . . . . 7
+ Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . . 7
+ Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 7
+
+1. Introduction
+
+ DNSSEC, which is broadly defined in [RFC4033], [RFC4034], and
+ [RFC4035], uses cryptographic keys and digital signatures to provide
+ authentication of DNS data. Currently, the most popular signature
+ algorithm in use is RSA. GOST [RFC5933] and NIST-specified elliptic
+ curve cryptography [RFC6605] are also standardized.
+
+ [RFC8032] describes the elliptic curve signature system Edwards-curve
+ Digital Signature Algorithm (EdDSA) and recommends two curves,
+ Ed25519 and Ed448.
+
+ This document defines the use of DNSSEC's DS, DNSKEY, and RRSIG
+ resource records (RRs) with a new signing algorithm, EdDSA, using a
+ choice of two curves: Ed25519 and Ed448.
+
+2. Requirements Language
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in [RFC2119].
+
+3. DNSKEY Resource Records
+
+ An Ed25519 public key consists of a 32-octet value, which is encoded
+ into the Public Key field of a DNSKEY resource record as a simple bit
+ string. The generation of a public key is defined in Section 5.1.5
+ of [RFC8032].
+
+
+
+
+
+Sury & Edmonds Standards Track [Page 2]
+
+RFC 8080 EdDSA for DNSSEC February 2017
+
+
+ An Ed448 public key consists of a 57-octet value, which is encoded
+ into the Public Key field of a DNSKEY resource record as a simple bit
+ string. The generation of a public key is defined in Section 5.2.5
+ of [RFC8032].
+
+4. RRSIG Resource Records
+
+ An Ed25519 signature consists of a 64-octet value, which is encoded
+ into the Signature field of an RRSIG resource record as a simple bit
+ string. The Ed25519 signature algorithm and verification of the
+ Ed25519 signature are described in Sections 5.1.6 and 5.1.7 of
+ [RFC8032], respectively.
+
+ An Ed448 signature consists of a 114-octet value, which is encoded
+ into the Signature field of an RRSIG resource record as a simple bit
+ string. The Ed448 signature algorithm and verification of the Ed448
+ signature are described in Sections 5.2.6 and 5.2.7 of [RFC8032],
+ respectively.
+
+5. Algorithm Number for DS, DNSKEY, and RRSIG Resource Records
+
+ The algorithm number associated with the use of Ed25519 in DS,
+ DNSKEY, and RRSIG resource records is 15. The algorithm number
+ associated with the use of Ed448 in DS, DNSKEY, and RRSIG resource
+ records is 16. This registration is fully defined in the IANA
+ Considerations section.
+
+6. Examples
+
+6.1. Ed25519 Examples
+
+Private-key-format: v1.2
+Algorithm: 15 (ED25519)
+PrivateKey: ODIyNjAzODQ2MjgwODAxMjI2NDUxOTAyMDQxNDIyNjI=
+
+example.com. 3600 IN DNSKEY 257 3 15 (
+ l02Woi0iS8Aa25FQkUd9RMzZHJpBoRQwAQEX1SxZJA4= )
+
+example.com. 3600 IN DS 3613 15 2 (
+ 3aa5ab37efce57f737fc1627013fee07bdf241bd10f3b1964ab55c78e79
+ a304b )
+
+example.com. 3600 IN MX 10 mail.example.com.
+
+example.com. 3600 IN RRSIG MX 3 3600 (
+ 1440021600 1438207200 3613 example.com. (
+ Edk+IB9KNNWg0HAjm7FazXyrd5m3Rk8zNZbvNpAcM+eysqcUOMIjWoevFkj
+ H5GaMWeG96GUVZu6ECKOQmemHDg== )
+
+
+
+Sury & Edmonds Standards Track [Page 3]
+
+RFC 8080 EdDSA for DNSSEC February 2017
+
+
+Private-key-format: v1.2
+Algorithm: 15 (ED25519)
+PrivateKey: DSSF3o0s0f+ElWzj9E/Osxw8hLpk55chkmx0LYN5WiY=
+
+example.com. 3600 IN DNSKEY 257 3 15 (
+ zPnZ/QwEe7S8C5SPz2OfS5RR40ATk2/rYnE9xHIEijs= )
+
+example.com. 3600 IN DS 35217 15 2 (
+ 401781b934e392de492ec77ae2e15d70f6575a1c0bc59c5275c04ebe80c
+ 6614c )
+
+example.com. 3600 IN MX 10 mail.example.com.
+
+example.com. 3600 IN RRSIG MX 3 3600 (
+ 1440021600 1438207200 35217 example.com. (
+ 5LL2obmzdqjWI+Xto5eP5adXt/T5tMhasWvwcyW4L3SzfcRawOle9bodhC+
+ oip9ayUGjY9T/rL4rN3bOuESGDA== )
+
+6.2. Ed448 Examples
+
+Private-key-format: v1.2
+Algorithm: 16 (ED448)
+PrivateKey: xZ+5Cgm463xugtkY5B0Jx6erFTXp13rYegst0qRtNsOYnaVpMx0Z/c5EiA9x
+ 8wWbDDct/U3FhYWA
+
+example.com. 3600 IN DNSKEY 257 3 16 (
+ 3kgROaDjrh0H2iuixWBrc8g2EpBBLCdGzHmn+G2MpTPhpj/OiBVHHSfPodx
+ 1FYYUcJKm1MDpJtIA )
+
+example.com. 3600 IN DS 9713 16 2 (
+ 6ccf18d5bc5d7fc2fceb1d59d17321402f2aa8d368048db93dd811f5cb2
+ b19c7 )
+
+example.com. 3600 IN MX 10 mail.example.com.
+
+example.com. 3600 IN RRSIG MX 3 3600 (
+ 1440021600 1438207200 9713 example.com. (
+ Nmc0rgGKpr3GKYXcB1JmqqS4NYwhmechvJTqVzt3jR+Qy/lSLFoIk1L+9e3
+ 9GPL+5tVzDPN3f9kAwiu8KCuPPjtl227ayaCZtRKZuJax7n9NuYlZJIusX0
+ SOIOKBGzG+yWYtz1/jjbzl5GGkWvREUCUA )
+
+
+
+
+
+
+
+
+
+
+
+Sury & Edmonds Standards Track [Page 4]
+
+RFC 8080 EdDSA for DNSSEC February 2017
+
+
+Private-key-format: v1.2
+Algorithm: 16 (ED448)
+PrivateKey: WEykD3ht3MHkU8iH4uVOLz8JLwtRBSqiBoM6fF72+Mrp/u5gjxuB1DV6NnPO
+ 2BlZdz4hdSTkOdOA
+
+example.com. 3600 IN DNSKEY 257 3 16 (
+ kkreGWoccSDmUBGAe7+zsbG6ZAFQp+syPmYUurBRQc3tDjeMCJcVMRDmgcN
+ Lp5HlHAMy12VoISsA )
+
+example.com. 3600 IN DS 38353 16 2 (
+ 645ff078b3568f5852b70cb60e8e696cc77b75bfaaffc118cf79cbda1ba
+ 28af4 )
+
+example.com. 3600 IN MX 10 mail.example.com.
+
+example.com. 3600 IN RRSIG MX 3 3600 (
+ 1440021600 1438207200 38353 example.com. (
+ +JjANio/LIzp7osmMYE5XD3H/YES8kXs5Vb9H8MjPS8OAGZMD37+LsCIcjg
+ 5ivt0d4Om/UaqETEAsJjaYe56CEQP5lhRWuD2ivBqE0zfwJTyp4WqvpULbp
+ vaukswvv/WNEFxzEYQEIm9+xDlXj4pMAMA )
+
+7. IANA Considerations
+
+ This document updates the IANA registry "Domain Name System Security
+ (DNSSEC) Algorithm Numbers". The following entries have been added
+ to the registry:
+
+ +--------------+----------+----------+
+ | Number | 15 | 16 |
+ | Description | Ed25519 | Ed448 |
+ | Mnemonic | ED25519 | ED448 |
+ | Zone Signing | Y | Y |
+ | Trans. Sec. | * | * |
+ | Reference | RFC 8080 | RFC 8080 |
+ +--------------+----------+----------+
+
+ * There has been no determination of standardization of the use of
+ this algorithm with Transaction Security.
+
+8. Security Considerations
+
+ The security considerations of [RFC8032] and [RFC7748] are inherited
+ in the usage of Ed25519 and Ed448 in DNSSEC.
+
+ Ed25519 is intended to operate at around the 128-bit security level
+ and Ed448 at around the 224-bit security level. A sufficiently large
+ quantum computer would be able to break both. Reasonable projections
+ of the abilities of classical computers conclude that Ed25519 is
+
+
+
+Sury & Edmonds Standards Track [Page 5]
+
+RFC 8080 EdDSA for DNSSEC February 2017
+
+
+ perfectly safe. Ed448 is provided for those applications with
+ relaxed performance requirements and where there is a desire to hedge
+ against analytical attacks on elliptic curves.
+
+ These assessments could, of course, change in the future if new
+ attacks that work better than the ones known today are found.
+
+ A private key used for a DNSSEC zone MUST NOT be used for any other
+ purpose than for that zone. Otherwise, cross-protocol or cross-
+ application attacks are possible.
+
+9. References
+
+9.1. Normative References
+
+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119,
+ DOI 10.17487/RFC2119, March 1997,
+ .
+
+ [RFC4033] Arends, R., Austein, R., Larson, M., Massey, D., and S.
+ Rose, "DNS Security Introduction and Requirements",
+ RFC 4033, DOI 10.17487/RFC4033, March 2005,
+ .
+
+ [RFC4034] Arends, R., Austein, R., Larson, M., Massey, D., and S.
+ Rose, "Resource Records for the DNS Security Extensions",
+ RFC 4034, DOI 10.17487/RFC4034, March 2005,
+ .
+
+ [RFC4035] Arends, R., Austein, R., Larson, M., Massey, D., and S.
+ Rose, "Protocol Modifications for the DNS Security
+ Extensions", RFC 4035, DOI 10.17487/RFC4035, March 2005,
+ .
+
+ [RFC7748] Langley, A., Hamburg, M., and S. Turner, "Elliptic Curves
+ for Security", RFC 7748, DOI 10.17487/RFC7748, January
+ 2016, .
+
+ [RFC8032] Josefsson, S. and I. Liusvaara, "Edwards-Curve Digital
+ Signature Algorithm (EdDSA)", RFC 8032,
+ DOI 10.17487/RFC8032, January 2017,
+ .
+
+
+
+
+
+
+
+
+Sury & Edmonds Standards Track [Page 6]
+
+RFC 8080 EdDSA for DNSSEC February 2017
+
+
+9.2. Informative References
+
+ [RFC5933] Dolmatov, V., Ed., Chuprina, A., and I. Ustinov, "Use of
+ GOST Signature Algorithms in DNSKEY and RRSIG Resource
+ Records for DNSSEC", RFC 5933, DOI 10.17487/RFC5933, July
+ 2010, .
+
+ [RFC6605] Hoffman, P. and W. Wijngaards, "Elliptic Curve Digital
+ Signature Algorithm (DSA) for DNSSEC", RFC 6605,
+ DOI 10.17487/RFC6605, April 2012,
+ .
+
+Acknowledgements
+
+ Some of the material in this document is copied liberally from
+ [RFC6605].
+
+ The authors of this document wish to thank Jan Vcelak, Pieter Lexis,
+ Kees Monshouwer, Simon Josefsson, Paul Hoffman, and others for a
+ review of this document.
+
+Authors' Addresses
+
+ Ondrej Sury
+ CZ.NIC
+ Milesovska 1136/5
+ Praha 130 00
+ Czech Republic
+
+ Email: ondrej.sury@nic.cz
+
+
+ Robert Edmonds
+ Fastly
+ Atlanta, Georgia
+ United States of America
+
+ Email: edmonds@mycre.ws
+
+
+
+
+
+
+
+
+
+
+
+
+
+Sury & Edmonds Standards Track [Page 7]
+
diff --git a/lib/dns/Makefile.in b/lib/dns/Makefile.in
index d243e3997c..b29936f601 100644
--- a/lib/dns/Makefile.in
+++ b/lib/dns/Makefile.in
@@ -39,12 +39,14 @@ LIBS = @LIBS@
# Alphabetically
OPENSSLGOSTLINKOBJS = opensslgost_link.@O@
+OPENSSLEDDSALINKOBJS = openssleddsa_link.@O@
OPENSSLLINKOBJS = openssl_link.@O@ openssldh_link.@O@ openssldsa_link.@O@ \
- opensslecdsa_link.@O@ @OPENSSLGOSTLINKOBJS@ \
- opensslrsa_link.@O@
+ opensslecdsa_link.@O@ @OPENSSLEDDSALINKOBJS@ \
+ @OPENSSLGOSTLINKOBJS@ opensslrsa_link.@O@
PKCS11LINKOBJS = pkcs11dh_link.@O@ pkcs11dsa_link.@O@ pkcs11rsa_link.@O@ \
- pkcs11ecdsa_link.@O@ pkcs11gost_link.@O@ pkcs11.@O@
+ pkcs11ecdsa_link.@O@ pkcs11eddsa_link.@O@ \
+ pkcs11gost_link.@O@ pkcs11.@O@
DSTOBJS = @DST_EXTRA_OBJS@ @OPENSSLLINKOBJS@ @PKCS11LINKOBJS@ \
dst_api.@O@ dst_lib.@O@ dst_parse.@O@ dst_result.@O@ \
@@ -80,11 +82,14 @@ OBJS= @DNSTAPOBJS@ ${DNSOBJS} ${OTHEROBJS} ${DSTOBJS} \
# Alphabetically
OPENSSLGOSTLINKSRCS = opensslgost_link.c
+OPENSSLEDDDSALINKSRCS = openssleddsa_link.c
OPENSSLLINKSRCS = openssl_link.c openssldh_link.c openssldsa_link.c \
- opensslecdsa_link.c @OPENSSLGOSTLINKSRCS@ opensslrsa_link.c
+ opensslecdsa_link.c @OPENSSLEDDDSALINKSRCS@ \
+ @OPENSSLGOSTLINKSRCS@ opensslrsa_link.c
PKCS11LINKSRCS = pkcs11dh_link.c pkcs11dsa_link.c pkcs11rsa_link.c \
- pkcs11ecdsa_link.c pkcs11gost_link.c pkcs11.c
+ pkcs11ecdsa_link.c pkcs11eddsa_link.c \
+ pkcs11gost_link.c pkcs11.c
DSTSRCS = @DST_EXTRA_SRCS@ @OPENSSLLINKSRCS@ @PKCS11LINKSRCS@ \
dst_api.c dst_lib.c dst_parse.c \
diff --git a/lib/dns/dst_api.c b/lib/dns/dst_api.c
index 307aee1e5f..86c44fe706 100644
--- a/lib/dns/dst_api.c
+++ b/lib/dns/dst_api.c
@@ -227,6 +227,12 @@ dst_lib_init2(isc_mem_t *mctx, isc_entropy_t *ectx,
RETERR(dst__opensslecdsa_init(&dst_t_func[DST_ALG_ECDSA256]));
RETERR(dst__opensslecdsa_init(&dst_t_func[DST_ALG_ECDSA384]));
#endif
+#ifdef HAVE_OPENSSL_ED25519
+ RETERR(dst__openssleddsa_init(&dst_t_func[DST_ALG_ED25519]));
+#endif
+#ifdef HAVE_OPENSSL_ED448
+ RETERR(dst__openssleddsa_init(&dst_t_func[DST_ALG_ED448]));
+#endif
#elif PKCS11CRYPTO
RETERR(dst__pkcs11_init(mctx, engine));
#ifndef PK11_MD5_DISABLE
@@ -247,6 +253,12 @@ dst_lib_init2(isc_mem_t *mctx, isc_entropy_t *ectx,
RETERR(dst__pkcs11ecdsa_init(&dst_t_func[DST_ALG_ECDSA256]));
RETERR(dst__pkcs11ecdsa_init(&dst_t_func[DST_ALG_ECDSA384]));
#endif
+#ifdef HAVE_PKCS11_ED25519
+ RETERR(dst__pkcs11eddsa_init(&dst_t_func[DST_ALG_ED25519]));
+#endif
+#ifdef HAVE_PKCS11_ED448
+ RETERR(dst__pkcs11eddsa_init(&dst_t_func[DST_ALG_ED448]));
+#endif
#ifdef HAVE_PKCS11_GOST
RETERR(dst__pkcs11gost_init(&dst_t_func[DST_ALG_ECCGOST]));
#endif
@@ -1289,6 +1301,12 @@ dst_key_sigsize(const dst_key_t *key, unsigned int *n) {
case DST_ALG_ECDSA384:
*n = DNS_SIG_ECDSA384SIZE;
break;
+ case DST_ALG_ED25519:
+ *n = DNS_SIG_ED25519SIZE;
+ break;
+ case DST_ALG_ED448:
+ *n = DNS_SIG_ED448SIZE;
+ break;
#ifndef PK11_MD5_DISABLE
case DST_ALG_HMACMD5:
*n = 16;
@@ -1631,6 +1649,8 @@ issymmetric(const dst_key_t *key) {
case DST_ALG_ECCGOST:
case DST_ALG_ECDSA256:
case DST_ALG_ECDSA384:
+ case DST_ALG_ED25519:
+ case DST_ALG_ED448:
return (ISC_FALSE);
#ifndef PK11_MD5_DISABLE
case DST_ALG_HMACMD5:
@@ -1919,7 +1939,8 @@ algorithm_status(unsigned int alg) {
alg == DST_ALG_NSEC3RSASHA1 ||
alg == DST_ALG_RSASHA256 || alg == DST_ALG_RSASHA512 ||
alg == DST_ALG_ECCGOST ||
- alg == DST_ALG_ECDSA256 || alg == DST_ALG_ECDSA384)
+ alg == DST_ALG_ECDSA256 || alg == DST_ALG_ECDSA384 ||
+ alg == DST_ALG_ED25519 || alg == DST_ALG_ED448)
return (DST_R_NOCRYPTO);
#endif
return (DST_R_UNSUPPORTEDALG);
diff --git a/lib/dns/dst_internal.h b/lib/dns/dst_internal.h
index d115d1a926..6890f186a9 100644
--- a/lib/dns/dst_internal.h
+++ b/lib/dns/dst_internal.h
@@ -256,9 +256,15 @@ isc_result_t dst__gssapi_init(struct dst_func **funcp);
#ifdef HAVE_OPENSSL_ECDSA
isc_result_t dst__opensslecdsa_init(struct dst_func **funcp);
#endif
+#if defined(HAVE_OPENSSL_ED25519) || defined(HAVE_OPENSSL_ED448)
+isc_result_t dst__openssleddsa_init(struct dst_func **funcp);
+#endif
#ifdef HAVE_PKCS11_ECDSA
isc_result_t dst__pkcs11ecdsa_init(struct dst_func **funcp);
#endif
+#if defined(HAVE_PKCS11_ED25519) || defined(HAVE_PKCS11_ED448)
+isc_result_t dst__pkcs11eddsa_init(struct dst_func **funcp);
+#endif
#ifdef HAVE_OPENSSL_GOST
isc_result_t dst__opensslgost_init(struct dst_func **funcp);
#endif
diff --git a/lib/dns/dst_parse.c b/lib/dns/dst_parse.c
index 893451d5c6..c984c4ca57 100644
--- a/lib/dns/dst_parse.c
+++ b/lib/dns/dst_parse.c
@@ -112,6 +112,10 @@ static struct parse_map map[] = {
{TAG_ECDSA_ENGINE, "Engine:" },
{TAG_ECDSA_LABEL, "Label:" },
+ {TAG_EDDSA_PRIVATEKEY, "PrivateKey:"},
+ {TAG_EDDSA_ENGINE, "Engine:" },
+ {TAG_EDDSA_LABEL, "Label:" },
+
#ifndef PK11_MD5_DISABLE
{TAG_HMACMD5_KEY, "Key:"},
{TAG_HMACMD5_BITS, "Bits:"},
@@ -308,6 +312,38 @@ check_ecdsa(const dst_private_t *priv, isc_boolean_t external) {
return (ok ? 0 : -1 );
}
+static int
+check_eddsa(const dst_private_t *priv, isc_boolean_t external) {
+ int i, j;
+ isc_boolean_t have[EDDSA_NTAGS];
+ isc_boolean_t ok;
+ unsigned int mask;
+
+ if (external)
+ return ((priv->nelements == 0) ? 0 : -1);
+
+ for (i = 0; i < EDDSA_NTAGS; i++)
+ have[i] = ISC_FALSE;
+ for (j = 0; j < priv->nelements; j++) {
+ for (i = 0; i < EDDSA_NTAGS; i++)
+ if (priv->elements[j].tag == TAG(DST_ALG_ED25519, i))
+ break;
+ if (i == EDDSA_NTAGS)
+ return (-1);
+ have[i] = ISC_TRUE;
+ }
+
+ mask = ~0;
+ mask <<= sizeof(mask) * 8 - TAG_SHIFT;
+ mask >>= sizeof(mask) * 8 - TAG_SHIFT;
+
+ if (have[TAG_EDDSA_ENGINE & mask])
+ ok = have[TAG_EDDSA_LABEL & mask];
+ else
+ ok = have[TAG_EDDSA_PRIVATEKEY & mask];
+ return (ok ? 0 : -1 );
+}
+
#ifndef PK11_MD5_DISABLE
static int
check_hmac_md5(const dst_private_t *priv, isc_boolean_t old) {
@@ -385,6 +421,9 @@ check_data(const dst_private_t *priv, const unsigned int alg,
case DST_ALG_ECDSA256:
case DST_ALG_ECDSA384:
return (check_ecdsa(priv, external));
+ case DST_ALG_ED25519:
+ case DST_ALG_ED448:
+ return (check_eddsa(priv, external));
#ifndef PK11_MD5_DISABLE
case DST_ALG_HMACMD5:
return (check_hmac_md5(priv, old));
@@ -736,6 +775,12 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv,
case DST_ALG_ECDSA384:
fprintf(fp, "(ECDSAP384SHA384)\n");
break;
+ case DST_ALG_ED25519:
+ fprintf(fp, "(ED25519)\n");
+ break;
+ case DST_ALG_ED448:
+ fprintf(fp, "(ED448)\n");
+ break;
case DST_ALG_HMACMD5:
fprintf(fp, "(HMAC_MD5)\n");
break;
diff --git a/lib/dns/dst_parse.h b/lib/dns/dst_parse.h
index 1384ac6812..6da8df73b1 100644
--- a/lib/dns/dst_parse.h
+++ b/lib/dns/dst_parse.h
@@ -77,6 +77,11 @@
#define TAG_ECDSA_ENGINE ((DST_ALG_ECDSA256 << TAG_SHIFT) + 1)
#define TAG_ECDSA_LABEL ((DST_ALG_ECDSA256 << TAG_SHIFT) + 2)
+#define EDDSA_NTAGS 4
+#define TAG_EDDSA_PRIVATEKEY ((DST_ALG_ED25519 << TAG_SHIFT) + 0)
+#define TAG_EDDSA_ENGINE ((DST_ALG_ED25519 << TAG_SHIFT) + 1)
+#define TAG_EDDSA_LABEL ((DST_ALG_ED25519 << TAG_SHIFT) + 2)
+
#define OLD_HMACMD5_NTAGS 1
#define HMACMD5_NTAGS 2
#define TAG_HMACMD5_KEY ((DST_ALG_HMACMD5 << TAG_SHIFT) + 0)
diff --git a/lib/dns/include/dns/keyvalues.h b/lib/dns/include/dns/keyvalues.h
index af833955fb..0e7e52bff0 100644
--- a/lib/dns/include/dns/keyvalues.h
+++ b/lib/dns/include/dns/keyvalues.h
@@ -64,6 +64,8 @@
#define DNS_KEYALG_ECCGOST 12
#define DNS_KEYALG_ECDSA256 13
#define DNS_KEYALG_ECDSA384 14
+#define DNS_KEYALG_ED25519 15
+#define DNS_KEYALG_ED448 16
#define DNS_KEYALG_INDIRECT 252
#define DNS_KEYALG_PRIVATEDNS 253
#define DNS_KEYALG_PRIVATEOID 254 /*%< Key begins with OID giving alg */
@@ -100,4 +102,10 @@
#define DNS_KEY_ECDSA256SIZE 64
#define DNS_KEY_ECDSA384SIZE 96
+#define DNS_SIG_ED25519SIZE 64
+#define DNS_SIG_ED448SIZE 114
+
+#define DNS_KEY_ED25519SIZE 32
+#define DNS_KEY_ED448SIZE 57
+
#endif /* DNS_KEYVALUES_H */
diff --git a/lib/dns/include/dst/dst.h b/lib/dns/include/dst/dst.h
index c1191512f6..d37c5c19d1 100644
--- a/lib/dns/include/dst/dst.h
+++ b/lib/dns/include/dst/dst.h
@@ -53,6 +53,8 @@ typedef struct dst_context dst_context_t;
#define DST_ALG_ECCGOST 12
#define DST_ALG_ECDSA256 13
#define DST_ALG_ECDSA384 14
+#define DST_ALG_ED25519 15
+#define DST_ALG_ED448 16
#define DST_ALG_HMACMD5 157
#define DST_ALG_GSSAPI 160
#define DST_ALG_HMACSHA1 161 /* XXXMPA */
diff --git a/lib/dns/openssleddsa_link.c b/lib/dns/openssleddsa_link.c
new file mode 100644
index 0000000000..58f9293748
--- /dev/null
+++ b/lib/dns/openssleddsa_link.c
@@ -0,0 +1,670 @@
+/*
+ * Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include
+
+#if defined(OPENSSL) && \
+ (defined(HAVE_OPENSSL_ED25519) || defined(HAVE_OPENSSL_ED448))
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "dst_internal.h"
+#include "dst_openssl.h"
+#include "dst_parse.h"
+
+#include
+#include
+#include
+#include
+
+#ifndef NID_ED25519
+#error "Ed25519 group is not known (NID_ED25519)"
+#endif
+#ifndef NID_ED448
+#error "Ed448 group is not known (NID_ED448)"
+#endif
+
+#define DST_RET(a) {ret = a; goto err;}
+
+/* OpenSSL doesn't provide direct access to key values */
+
+#define PUBPREFIXLEN 12
+
+static const unsigned char ed25519_pub_prefix[] = {
+ 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65,
+ 0x70, 0x03, 0x21, 0x00
+};
+
+static EVP_PKEY *pub_ed25519_to_ossl(const unsigned char *key)
+{
+ unsigned char buf[PUBPREFIXLEN + DNS_KEY_ED25519SIZE];
+ const unsigned char *p;
+
+ memmove(buf, ed25519_pub_prefix, PUBPREFIXLEN);
+ memmove(buf + PUBPREFIXLEN, key, DNS_KEY_ED25519SIZE);
+ p = buf;
+ return (d2i_PUBKEY(NULL, &p, PUBPREFIXLEN + DNS_KEY_ED25519SIZE));
+}
+
+static isc_result_t pub_ed25519_from_ossl(EVP_PKEY *pkey,
+ unsigned char *key)
+{
+ unsigned char buf[PUBPREFIXLEN + DNS_KEY_ED25519SIZE];
+ unsigned char *p;
+ int len;
+
+ len = i2d_PUBKEY(pkey, NULL);
+ if ((len <= DNS_KEY_ED25519SIZE) ||
+ (len > PUBPREFIXLEN + DNS_KEY_ED25519SIZE))
+ return (DST_R_OPENSSLFAILURE);
+ p = buf;
+ len = i2d_PUBKEY(pkey, &p);
+ if ((len <= DNS_KEY_ED25519SIZE) ||
+ (len > PUBPREFIXLEN + DNS_KEY_ED25519SIZE))
+ return (DST_R_OPENSSLFAILURE);
+ memmove(key, buf + len - DNS_KEY_ED25519SIZE, DNS_KEY_ED25519SIZE);
+ return (ISC_R_SUCCESS);
+}
+
+static const unsigned char ed448_pub_prefix[] = {
+ 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65,
+ 0x71, 0x03, 0x21, 0x00
+};
+
+static EVP_PKEY *pub_ed448_to_ossl(const unsigned char *key)
+{
+ unsigned char buf[PUBPREFIXLEN + DNS_KEY_ED448SIZE];
+ const unsigned char *p;
+
+ memmove(buf, ed448_pub_prefix, PUBPREFIXLEN);
+ memmove(buf + PUBPREFIXLEN, key, DNS_KEY_ED448SIZE);
+ p = buf;
+ return (d2i_PUBKEY(NULL, &p, PUBPREFIXLEN + DNS_KEY_ED448SIZE));
+}
+
+static isc_result_t pub_ed448_from_ossl(EVP_PKEY *pkey,
+ unsigned char *key)
+{
+ unsigned char buf[PUBPREFIXLEN + DNS_KEY_ED448SIZE];
+ unsigned char *p;
+ int len;
+
+ len = i2d_PUBKEY(pkey, NULL);
+ if ((len <= DNS_KEY_ED448SIZE) ||
+ (len > PUBPREFIXLEN + DNS_KEY_ED448SIZE))
+ return (DST_R_OPENSSLFAILURE);
+ p = buf;
+ len = i2d_PUBKEY(pkey, &p);
+ if ((len <= DNS_KEY_ED448SIZE) ||
+ (len > PUBPREFIXLEN + DNS_KEY_ED448SIZE))
+ return (DST_R_OPENSSLFAILURE);
+ memmove(key, buf + len - DNS_KEY_ED448SIZE, DNS_KEY_ED448SIZE);
+ return (ISC_R_SUCCESS);
+}
+
+#define PRIVPREFIXLEN 16
+
+static const unsigned char ed25519_priv_prefix[] = {
+ 0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06,
+ 0x03, 0x2b, 0x65, 0x70, 0x04, 0x22, 0x04, 0x20
+};
+
+static EVP_PKEY *priv_ed25519_to_ossl(const unsigned char *key)
+{
+ unsigned char buf[PRIVPREFIXLEN + DNS_KEY_ED25519SIZE];
+ const unsigned char *p;
+
+ memmove(buf, ed25519_priv_prefix, PRIVPREFIXLEN);
+ memmove(buf + PRIVPREFIXLEN, key, DNS_KEY_ED25519SIZE);
+ p = buf;
+ return (d2i_PrivateKey(NID_ED25519, NULL, &p,
+ PRIVPREFIXLEN + DNS_KEY_ED25519SIZE));
+}
+
+static isc_result_t priv_ed25519_from_ossl(EVP_PKEY *pkey,
+ unsigned char *key)
+{
+ unsigned char buf[PRIVPREFIXLEN + DNS_KEY_ED25519SIZE];
+ unsigned char *p;
+ int len;
+
+ len = i2d_PrivateKey(pkey, NULL);
+ if ((len <= DNS_KEY_ED25519SIZE) ||
+ (len > PRIVPREFIXLEN + DNS_KEY_ED25519SIZE))
+ return (DST_R_OPENSSLFAILURE);
+ p = buf;
+ len = i2d_PrivateKey(pkey, &p);
+ if ((len <= DNS_KEY_ED25519SIZE) ||
+ (len > PRIVPREFIXLEN + DNS_KEY_ED25519SIZE))
+ return (DST_R_OPENSSLFAILURE);
+ memmove(key, buf + len - DNS_KEY_ED25519SIZE, DNS_KEY_ED25519SIZE);
+ return (ISC_R_SUCCESS);
+}
+
+static const unsigned char ed448_priv_prefix[] = {
+ 0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06,
+ 0x03, 0x2b, 0x65, 0x71, 0x04, 0x22, 0x04, 0x20
+};
+
+static EVP_PKEY *priv_ed448_to_ossl(const unsigned char *key)
+{
+ unsigned char buf[PRIVPREFIXLEN + DNS_KEY_ED448SIZE];
+ const unsigned char *p;
+
+ memmove(buf, ed448_priv_prefix, PRIVPREFIXLEN);
+ memmove(buf + PRIVPREFIXLEN, key, DNS_KEY_ED448SIZE);
+ p = buf;
+ return (d2i_PrivateKey(NID_ED448, NULL, &p,
+ PRIVPREFIXLEN + DNS_KEY_ED448SIZE));
+}
+
+static isc_result_t priv_ed448_from_ossl(EVP_PKEY *pkey,
+ unsigned char *key)
+{
+ unsigned char buf[PRIVPREFIXLEN + DNS_KEY_ED448SIZE];
+ unsigned char *p;
+ int len;
+
+ len = i2d_PrivateKey(pkey, NULL);
+ if ((len <= DNS_KEY_ED448SIZE) ||
+ (len > PRIVPREFIXLEN + DNS_KEY_ED448SIZE))
+ return (DST_R_OPENSSLFAILURE);
+ p = buf;
+ len = i2d_PrivateKey(pkey, &p);
+ if ((len <= DNS_KEY_ED448SIZE) ||
+ (len > PRIVPREFIXLEN + DNS_KEY_ED448SIZE))
+ return (DST_R_OPENSSLFAILURE);
+ memmove(key, buf + len - DNS_KEY_ED448SIZE, DNS_KEY_ED448SIZE);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t openssleddsa_todns(const dst_key_t *key,
+ isc_buffer_t *data);
+
+static isc_result_t
+openssleddsa_createctx(dst_key_t *key, dst_context_t *dctx) {
+ isc_buffer_t *buf = NULL;
+ isc_result_t result;
+
+ UNUSED(key);
+ REQUIRE(dctx->key->key_alg == DST_ALG_ED25519 ||
+ dctx->key->key_alg == DST_ALG_ED448);
+
+ result = isc_buffer_allocate(dctx->mctx, &buf, 64);
+ dctx->ctxdata.generic = buf;
+
+ return (result);
+}
+
+static void
+openssleddsa_destroyctx(dst_context_t *dctx) {
+ isc_buffer_t *buf = (isc_buffer_t *) dctx->ctxdata.generic;
+
+ REQUIRE(dctx->key->key_alg == DST_ALG_ED25519 ||
+ dctx->key->key_alg == DST_ALG_ED448);
+ if (buf != NULL)
+ isc_buffer_free(&buf);
+ dctx->ctxdata.generic = NULL;
+}
+
+static isc_result_t
+openssleddsa_adddata(dst_context_t *dctx, const isc_region_t *data) {
+ isc_buffer_t *buf = (isc_buffer_t *) dctx->ctxdata.generic;
+ isc_buffer_t *nbuf = NULL;
+ isc_region_t r;
+ unsigned int length;
+ isc_result_t result;
+
+ REQUIRE(dctx->key->key_alg == DST_ALG_ED25519 ||
+ dctx->key->key_alg == DST_ALG_ED448);
+
+ result = isc_buffer_copyregion(buf, data);
+ if (result == ISC_R_SUCCESS)
+ return (ISC_R_SUCCESS);
+
+ length = isc_buffer_length(buf) + data->length + 64;
+ result = isc_buffer_allocate(dctx->mctx, &nbuf, length);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ isc_buffer_usedregion(buf, &r);
+ (void) isc_buffer_copyregion(nbuf, &r);
+ (void) isc_buffer_copyregion(nbuf, data);
+ isc_buffer_free(&buf);
+ dctx->ctxdata.generic = nbuf;
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+openssleddsa_sign(dst_context_t *dctx, isc_buffer_t *sig) {
+ isc_result_t ret;
+ dst_key_t *key = dctx->key;
+ isc_region_t tbsreg;
+ isc_region_t sigreg;
+ EVP_PKEY *pkey = key->keydata.pkey;
+ EVP_MD_CTX* ctx = EVP_MD_CTX_new();
+ isc_buffer_t *buf = (isc_buffer_t *) dctx->ctxdata.generic;
+ size_t siglen;
+
+ REQUIRE(key->key_alg == DST_ALG_ED25519 ||
+ key->key_alg == DST_ALG_ED448);
+
+ if (ctx == NULL)
+ return (ISC_R_NOMEMORY);
+
+ if (key->key_alg == DST_ALG_ED25519)
+ siglen = DNS_SIG_ED25519SIZE;
+ else
+ siglen = DNS_SIG_ED448SIZE;
+
+ isc_buffer_availableregion(sig, &sigreg);
+ if (sigreg.length < (unsigned int) siglen)
+ DST_RET(ISC_R_NOSPACE);
+
+ isc_buffer_usedregion(buf, &tbsreg);
+
+ if (!EVP_DigestSignInit(ctx, NULL, NULL, NULL, pkey))
+ DST_RET(dst__openssl_toresult3(dctx->category,
+ "EVP_DigestSignInit",
+ ISC_R_FAILURE));
+ if (!EVP_DigestSign(ctx, sigreg.base, &siglen,
+ tbsreg.base, tbsreg.length))
+ DST_RET(dst__openssl_toresult3(dctx->category,
+ "EVP_DigestSign",
+ DST_R_SIGNFAILURE));
+ isc_buffer_add(sig, (unsigned int) siglen);
+ ret = ISC_R_SUCCESS;
+
+ err:
+ if (ctx != NULL)
+ EVP_MD_CTX_free(ctx);
+ isc_buffer_free(&buf);
+ dctx->ctxdata.generic = NULL;
+
+ return (ret);
+}
+
+static isc_result_t
+openssleddsa_verify(dst_context_t *dctx, const isc_region_t *sig) {
+ isc_result_t ret;
+ dst_key_t *key = dctx->key;
+ int status;
+ isc_region_t tbsreg;
+ EVP_PKEY *pkey = key->keydata.pkey;
+ EVP_MD_CTX* ctx = EVP_MD_CTX_new();
+ isc_buffer_t *buf = (isc_buffer_t *) dctx->ctxdata.generic;
+ unsigned int siglen;
+
+ REQUIRE(key->key_alg == DST_ALG_ED25519 ||
+ key->key_alg == DST_ALG_ED448);
+
+ if (ctx == NULL)
+ return (ISC_R_NOMEMORY);
+
+ if (key->key_alg == DST_ALG_ED25519)
+ siglen = DNS_SIG_ED25519SIZE;
+ else
+ siglen = DNS_SIG_ED448SIZE;
+
+ if (sig->length != siglen)
+ return (DST_R_VERIFYFAILURE);
+
+ isc_buffer_usedregion(buf, &tbsreg);
+
+ if (!EVP_DigestVerifyInit(ctx, NULL, NULL, NULL, pkey))
+ DST_RET(dst__openssl_toresult3(dctx->category,
+ "EVP_DigestVerifyInit",
+ ISC_R_FAILURE));
+
+ status = EVP_DigestVerify(ctx, sig->base, siglen,
+ tbsreg.base, tbsreg.length);
+
+ switch (status) {
+ case 1:
+ ret = ISC_R_SUCCESS;
+ break;
+ case 0:
+ ret = dst__openssl_toresult(DST_R_VERIFYFAILURE);
+ break;
+ default:
+ ret = dst__openssl_toresult3(dctx->category,
+ "EVP_DigestVerify",
+ DST_R_VERIFYFAILURE);
+ break;
+ }
+
+ err:
+ if (ctx != NULL)
+ EVP_MD_CTX_free(ctx);
+ isc_buffer_free(&buf);
+ dctx->ctxdata.generic = NULL;
+
+ return (ret);
+}
+
+static isc_boolean_t
+openssleddsa_compare(const dst_key_t *key1, const dst_key_t *key2) {
+ int status;
+ EVP_PKEY *pkey1 = key1->keydata.pkey;
+ EVP_PKEY *pkey2 = key2->keydata.pkey;
+
+ if (pkey1 == NULL && pkey2 == NULL)
+ return (ISC_TRUE);
+ else if (pkey1 == NULL || pkey2 == NULL)
+ return (ISC_FALSE);
+
+ status = EVP_PKEY_cmp(pkey1, pkey2);
+ if (status == 1)
+ return (ISC_TRUE);
+ return (ISC_FALSE);
+}
+
+static isc_result_t
+openssleddsa_generate(dst_key_t *key, int unused, void (*callback)(int)) {
+ isc_result_t ret;
+ EVP_PKEY *pkey = NULL;
+ EVP_PKEY_CTX *ctx = NULL;
+ int nid, status;
+
+ REQUIRE(key->key_alg == DST_ALG_ED25519 ||
+ key->key_alg == DST_ALG_ED448);
+ UNUSED(unused);
+ UNUSED(callback);
+
+ if (key->key_alg == DST_ALG_ED25519) {
+ nid = NID_ED25519;
+ key->key_size = DNS_KEY_ED25519SIZE;
+ } else {
+ nid = NID_ED448;
+ key->key_size = DNS_KEY_ED448SIZE;
+ }
+
+ ctx = EVP_PKEY_CTX_new_id(nid, NULL);
+ if (ctx == NULL)
+ return (dst__openssl_toresult2("EVP_PKEY_CTX_new_id",
+ DST_R_OPENSSLFAILURE));
+
+ status = EVP_PKEY_keygen_init(ctx);
+ if (status != 1)
+ DST_RET (dst__openssl_toresult2("EVP_PKEY_keygen_init",
+ DST_R_OPENSSLFAILURE));
+
+ status = EVP_PKEY_keygen(ctx, &pkey);
+ if (status != 1)
+ DST_RET (dst__openssl_toresult2("EVP_PKEY_keygen",
+ DST_R_OPENSSLFAILURE));
+
+ key->keydata.pkey = pkey;
+ ret = ISC_R_SUCCESS;
+
+ err:
+ if (ctx != NULL)
+ EVP_PKEY_CTX_free(ctx);
+ return (ret);
+}
+
+static isc_boolean_t
+openssleddsa_isprivate(const dst_key_t *key) {
+ EVP_PKEY *pkey = key->keydata.pkey;
+ int len;
+ unsigned long err;
+
+ if (pkey == NULL)
+ return (ISC_FALSE);
+
+ len = i2d_PrivateKey(pkey, NULL);
+ if (len > 0)
+ return (ISC_TRUE);
+ /* can check if first error is EC_R_INVALID_PRIVATE_KEY */
+ while ((err = ERR_get_error()) != 0)
+ /**/;
+
+ return (ISC_FALSE);
+}
+
+static void
+openssleddsa_destroy(dst_key_t *key) {
+ EVP_PKEY *pkey = key->keydata.pkey;
+
+ EVP_PKEY_free(pkey);
+ key->keydata.pkey = NULL;
+}
+
+static isc_result_t
+openssleddsa_todns(const dst_key_t *key, isc_buffer_t *data) {
+ EVP_PKEY *pkey = key->keydata.pkey;
+ isc_region_t r;
+ isc_result_t result;
+
+ REQUIRE(pkey != NULL);
+
+ pkey = key->keydata.pkey;
+ switch (key->key_alg) {
+ case DST_ALG_ED25519:
+ isc_buffer_availableregion(data, &r);
+ if (r.length < DNS_KEY_ED25519SIZE)
+ return (ISC_R_NOSPACE);
+ result = pub_ed25519_from_ossl(pkey, r.base);
+ if (result == ISC_R_SUCCESS)
+ isc_buffer_add(data, DNS_KEY_ED25519SIZE);
+ return (result);
+ case DST_ALG_ED448:
+ isc_buffer_availableregion(data, &r);
+ if (r.length < DNS_KEY_ED448SIZE)
+ return (ISC_R_NOSPACE);
+ result = pub_ed448_from_ossl(pkey, r.base);
+ if (result == ISC_R_SUCCESS)
+ isc_buffer_add(data, DNS_KEY_ED448SIZE);
+ return (result);
+ default:
+ INSIST(0);
+ }
+}
+
+static isc_result_t
+openssleddsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
+ EVP_PKEY *pkey;
+ isc_region_t r;
+ unsigned int len;
+
+ REQUIRE(key->key_alg == DST_ALG_ED25519 ||
+ key->key_alg == DST_ALG_ED448);
+
+ isc_buffer_remainingregion(data, &r);
+ if (r.length == 0)
+ return (ISC_R_SUCCESS);
+ if (key->key_alg == DST_ALG_ED25519) {
+ len = DNS_KEY_ED25519SIZE;
+ if (r.length < len)
+ return (DST_R_INVALIDPUBLICKEY);
+ pkey = pub_ed25519_to_ossl(r.base);
+ } else {
+ len = DNS_KEY_ED448SIZE;
+ if (r.length < len)
+ return (DST_R_INVALIDPUBLICKEY);
+ pkey = pub_ed448_to_ossl(r.base);
+ }
+ if (pkey == NULL)
+ return (dst__openssl_toresult(ISC_R_FAILURE));
+ isc_buffer_forward(data, len);
+ key->keydata.pkey = pkey;
+ key->key_size = len;
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+openssleddsa_tofile(const dst_key_t *key, const char *directory) {
+ isc_result_t ret;
+ EVP_PKEY *pkey;
+ dst_private_t priv;
+ unsigned char *buf = NULL;
+ unsigned int len;
+
+ REQUIRE(key->key_alg == DST_ALG_ED25519 ||
+ key->key_alg == DST_ALG_ED448);
+
+ if (key->keydata.pkey == NULL)
+ return (DST_R_NULLKEY);
+
+ if (key->external) {
+ priv.nelements = 0;
+ return (dst__privstruct_writefile(key, &priv, directory));
+ }
+
+ pkey = key->keydata.pkey;
+ if (key->key_alg == DST_ALG_ED25519) {
+ len = DNS_KEY_ED25519SIZE;
+ buf = isc_mem_get(key->mctx, len);
+ if (buf == NULL)
+ return (ISC_R_NOMEMORY);
+ priv.elements[0].tag = TAG_EDDSA_PRIVATEKEY;
+ priv.elements[0].length = len;
+ ret = priv_ed25519_from_ossl(pkey, buf);
+ if (ret != ISC_R_SUCCESS)
+ DST_RET (dst__openssl_toresult(ret));
+ priv.elements[0].data = buf;
+ priv.nelements = 1;
+ ret = dst__privstruct_writefile(key, &priv, directory);
+ } else {
+ len = DNS_KEY_ED448SIZE;
+ buf = isc_mem_get(key->mctx, len);
+ if (buf == NULL)
+ return (ISC_R_NOMEMORY);
+ priv.elements[0].tag = TAG_EDDSA_PRIVATEKEY;
+ priv.elements[0].length = len;
+ ret = priv_ed448_from_ossl(pkey, buf);
+ if (ret != ISC_R_SUCCESS)
+ DST_RET (dst__openssl_toresult(ret));
+ priv.elements[0].data = buf;
+ priv.nelements = 1;
+ ret = dst__privstruct_writefile(key, &priv, directory);
+ }
+
+ err:
+ if (buf != NULL)
+ isc_mem_put(key->mctx, buf, len);
+ return (ret);
+}
+
+static isc_result_t
+eddsa_check(EVP_PKEY *privkey, dst_key_t *pub)
+{
+ EVP_PKEY *pkey;
+
+ if (pub == NULL)
+ return (ISC_R_SUCCESS);
+ pkey = pub->keydata.pkey;
+ if (pkey == NULL)
+ return (ISC_R_SUCCESS);
+ if (EVP_PKEY_cmp(privkey, pkey) == 1)
+ return (ISC_R_SUCCESS);
+ return (ISC_R_FAILURE);
+}
+
+static isc_result_t
+openssleddsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
+ dst_private_t priv;
+ isc_result_t ret;
+ EVP_PKEY *pkey = NULL;
+ unsigned int len;
+ isc_mem_t *mctx = key->mctx;
+
+ REQUIRE(key->key_alg == DST_ALG_ED25519 ||
+ key->key_alg == DST_ALG_ED448);
+
+ /* read private key file */
+ ret = dst__privstruct_parse(key, DST_ALG_ED25519, lexer, mctx, &priv);
+ if (ret != ISC_R_SUCCESS)
+ goto err;
+
+ if (key->external) {
+ if (priv.nelements != 0)
+ DST_RET(DST_R_INVALIDPRIVATEKEY);
+ if (pub == NULL)
+ DST_RET(DST_R_INVALIDPRIVATEKEY);
+ key->keydata.pkey = pub->keydata.pkey;
+ pub->keydata.pkey = NULL;
+ dst__privstruct_free(&priv, mctx);
+ memset(&priv, 0, sizeof(priv));
+ return (ISC_R_SUCCESS);
+ }
+
+ if (key->key_alg == DST_ALG_ED25519) {
+ len = DNS_KEY_ED25519SIZE;
+ if (priv.elements[0].length < len)
+ DST_RET(DST_R_INVALIDPRIVATEKEY);
+ pkey = priv_ed25519_to_ossl(priv.elements[0].data);
+ } else {
+ len = DNS_KEY_ED448SIZE;
+ if (priv.elements[0].length < len)
+ DST_RET(DST_R_INVALIDPRIVATEKEY);
+ pkey = priv_ed448_to_ossl(priv.elements[0].data);
+ }
+ if (pkey == NULL)
+ DST_RET (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
+ if (eddsa_check(pkey, pub) != ISC_R_SUCCESS) {
+ EVP_PKEY_free(pkey);
+ DST_RET(DST_R_INVALIDPRIVATEKEY);
+ }
+ key->keydata.pkey = pkey;
+ key->key_size = len;
+ ret = ISC_R_SUCCESS;
+
+ err:
+ dst__privstruct_free(&priv, mctx);
+ memset(&priv, 0, sizeof(priv));
+ return (ret);
+}
+
+static dst_func_t openssleddsa_functions = {
+ openssleddsa_createctx,
+ NULL, /*%< createctx2 */
+ openssleddsa_destroyctx,
+ openssleddsa_adddata,
+ openssleddsa_sign,
+ openssleddsa_verify,
+ NULL, /*%< verify2 */
+ NULL, /*%< computesecret */
+ openssleddsa_compare,
+ NULL, /*%< paramcompare */
+ openssleddsa_generate,
+ openssleddsa_isprivate,
+ openssleddsa_destroy,
+ openssleddsa_todns,
+ openssleddsa_fromdns,
+ openssleddsa_tofile,
+ openssleddsa_parse,
+ NULL, /*%< cleanup */
+ NULL, /*%< fromlabel */
+ NULL, /*%< dump */
+ NULL, /*%< restore */
+};
+
+isc_result_t
+dst__openssleddsa_init(dst_func_t **funcp) {
+ REQUIRE(funcp != NULL);
+ if (*funcp == NULL)
+ *funcp = &openssleddsa_functions;
+ return (ISC_R_SUCCESS);
+}
+
+#else /* HAVE_OPENSSL_EDxxx */
+
+#include
+
+EMPTY_TRANSLATION_UNIT
+
+#endif /* HAVE_OPENSSL_EDxxx */
+/*! \file */
diff --git a/lib/dns/pkcs11eddsa_link.c b/lib/dns/pkcs11eddsa_link.c
new file mode 100644
index 0000000000..095bfe1a2d
--- /dev/null
+++ b/lib/dns/pkcs11eddsa_link.c
@@ -0,0 +1,1180 @@
+/*
+ * Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include
+
+#if defined(PKCS11CRYPTO) && \
+ defined(HAVE_PKCS11_ED25519) || defined(HAVE_PKCS11_ED448)
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "dst_internal.h"
+#include "dst_parse.h"
+#include "dst_pkcs11.h"
+
+#include
+#include
+#define WANT_ECC_CURVES
+#include
+
+#include
+#include
+
+/*
+ * FIPS 186-3 EDDSA keys:
+ * mechanisms:
+ * CKM_EDDSA,
+ * CKM_EDDSA_KEY_PAIR_GEN
+ * domain parameters:
+ * CKA_EC_PARAMS (choice with OID namedCurve)
+ * public keys:
+ * object class CKO_PUBLIC_KEY
+ * key type CKK_EDDSA
+ * attribute CKA_EC_PARAMS (choice with OID namedCurve)
+ * attribute CKA_EC_POINT (big int A, CKA_VALUE on the token)
+ * private keys:
+ * object class CKO_PRIVATE_KEY
+ * key type CKK_EDDSA
+ * attribute CKA_EC_PARAMS (choice with OID namedCurve)
+ * attribute CKA_VALUE (big int k)
+ */
+
+#define DST_RET(a) {ret = a; goto err;}
+
+static CK_BBOOL truevalue = TRUE;
+static CK_BBOOL falsevalue = FALSE;
+
+static isc_result_t pkcs11eddsa_todns(const dst_key_t *key,
+ isc_buffer_t *data);
+static void pkcs11eddsa_destroy(dst_key_t *key);
+static isc_result_t pkcs11eddsa_fetch(dst_key_t *key, const char *engine,
+ const char *label, dst_key_t *pub);
+
+static isc_result_t
+pkcs11eddsa_createctx(dst_key_t *key, dst_context_t *dctx) {
+ isc_buffer_t *buf = NULL;
+ isc_result_t result;
+
+ UNUSED(key);
+ REQUIRE(dctx->key->key_alg == DST_ALG_ED25519 ||
+ dctx->key->key_alg == DST_ALG_ED448);
+
+ result = isc_buffer_allocate(dctx->mctx, &buf, 16);
+ isc_buffer_setautorealloc(buf, ISC_TRUE);
+ dctx->ctxdata.generic = buf;
+
+ return (result);
+}
+
+static void
+pkcs11eddsa_destroyctx(dst_context_t *dctx) {
+ isc_buffer_t *buf = (isc_buffer_t *) dctx->ctxdata.generic;
+
+ REQUIRE(dctx->key->key_alg == DST_ALG_ED25519 ||
+ dctx->key->key_alg == DST_ALG_ED448);
+ if (buf != NULL)
+ isc_buffer_free(&buf);
+ dctx->ctxdata.generic = NULL;
+}
+
+static isc_result_t
+pkcs11eddsa_adddata(dst_context_t *dctx, const isc_region_t *data) {
+ isc_buffer_t *buf = (isc_buffer_t *) dctx->ctxdata.generic;
+ isc_buffer_t *nbuf = NULL;
+ isc_region_t r;
+ unsigned int length;
+ isc_result_t result;
+
+ REQUIRE(dctx->key->key_alg == DST_ALG_ED25519 ||
+ dctx->key->key_alg == DST_ALG_ED448);
+
+ result = isc_buffer_copyregion(buf, data);
+ if (result == ISC_R_SUCCESS)
+ return (ISC_R_SUCCESS);
+
+ length = isc_buffer_length(buf) + data->length + 64;
+ result = isc_buffer_allocate(dctx->mctx, &nbuf, length);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ isc_buffer_usedregion(buf, &r);
+ (void) isc_buffer_copyregion(nbuf, &r);
+ (void) isc_buffer_copyregion(nbuf, data);
+ isc_buffer_free(&buf);
+ dctx->ctxdata.generic = nbuf;
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+pkcs11eddsa_sign(dst_context_t *dctx, isc_buffer_t *sig) {
+ isc_buffer_t *buf = (isc_buffer_t *) dctx->ctxdata.generic;
+ CK_RV rv;
+ CK_MECHANISM mech = { CKM_EDDSA, NULL, 0 };
+ CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE;
+ CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY;
+ CK_KEY_TYPE keyType = CKK_EDDSA;
+ CK_ATTRIBUTE keyTemplate[] =
+ {
+ { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
+ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
+ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
+ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
+ { CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
+ { CKA_EC_PARAMS, NULL, 0 },
+ { CKA_VALUE, NULL, 0 }
+ };
+ CK_ATTRIBUTE *attr;
+ CK_ULONG siglen;
+ CK_SLOT_ID slotid;
+ pk11_context_t *pk11_ctx;
+ dst_key_t *key = dctx->key;
+ pk11_object_t *ec = key->keydata.pkey;
+ isc_region_t t;
+ isc_region_t r;
+ isc_result_t ret = ISC_R_SUCCESS;
+ unsigned int i;
+
+ REQUIRE(key->key_alg == DST_ALG_ED25519 ||
+ key->key_alg == DST_ALG_ED448);
+ REQUIRE(ec != NULL);
+
+ if (key->key_alg == DST_ALG_ED25519)
+ siglen = DNS_SIG_ED25519SIZE;
+ else
+ siglen = DNS_SIG_ED448SIZE;
+
+ pk11_ctx = (pk11_context_t *) isc_mem_get(dctx->mctx,
+ sizeof(*pk11_ctx));
+ if (pk11_ctx == NULL)
+ return (ISC_R_NOMEMORY);
+ memset(pk11_ctx, 0, sizeof(*pk11_ctx));
+ if (ec->ontoken && (dctx->use == DO_SIGN))
+ slotid = ec->slot;
+ else
+ slotid = pk11_get_best_token(OP_EC);
+ ret = pk11_get_session(pk11_ctx, OP_EC, ISC_TRUE, ISC_FALSE,
+ ec->reqlogon, NULL, slotid);
+ if (ret != ISC_R_SUCCESS)
+ goto err;
+
+ isc_buffer_availableregion(sig, &r);
+ if (r.length < siglen)
+ DST_RET(ISC_R_NOSPACE);
+
+ if (ec->ontoken && (ec->object != CK_INVALID_HANDLE)) {
+ pk11_ctx->ontoken = ec->ontoken;
+ pk11_ctx->object = ec->object;
+ goto token_key;
+ }
+
+ for (attr = pk11_attribute_first(ec);
+ attr != NULL;
+ attr = pk11_attribute_next(ec, attr))
+ switch (attr->type) {
+ case CKA_EC_PARAMS:
+ INSIST(keyTemplate[5].type == attr->type);
+ keyTemplate[5].pValue = isc_mem_get(dctx->mctx,
+ attr->ulValueLen);
+ if (keyTemplate[5].pValue == NULL)
+ DST_RET(ISC_R_NOMEMORY);
+ memmove(keyTemplate[5].pValue, attr->pValue,
+ attr->ulValueLen);
+ keyTemplate[5].ulValueLen = attr->ulValueLen;
+ break;
+ case CKA_VALUE:
+ INSIST(keyTemplate[6].type == attr->type);
+ keyTemplate[6].pValue = isc_mem_get(dctx->mctx,
+ attr->ulValueLen);
+ if (keyTemplate[6].pValue == NULL)
+ DST_RET(ISC_R_NOMEMORY);
+ memmove(keyTemplate[6].pValue, attr->pValue,
+ attr->ulValueLen);
+ keyTemplate[6].ulValueLen = attr->ulValueLen;
+ break;
+ }
+ pk11_ctx->object = CK_INVALID_HANDLE;
+ pk11_ctx->ontoken = ISC_FALSE;
+ PK11_RET(pkcs_C_CreateObject,
+ (pk11_ctx->session,
+ keyTemplate, (CK_ULONG) 7,
+ &hKey),
+ ISC_R_FAILURE);
+
+ token_key:
+
+ PK11_RET(pkcs_C_SignInit,
+ (pk11_ctx->session, &mech,
+ pk11_ctx->ontoken ? pk11_ctx->object : hKey),
+ ISC_R_FAILURE);
+
+ isc_buffer_usedregion(buf, &t);
+
+ PK11_RET(pkcs_C_Sign,
+ (pk11_ctx->session,
+ (CK_BYTE_PTR) t.base, (CK_ULONG) t.length,
+ (CK_BYTE_PTR) r.base, &siglen),
+ DST_R_SIGNFAILURE);
+
+ isc_buffer_add(sig, (unsigned int) siglen);
+
+ err:
+
+ if (hKey != CK_INVALID_HANDLE)
+ (void) pkcs_C_DestroyObject(pk11_ctx->session, hKey);
+ for (i = 5; i <= 6; i++)
+ if (keyTemplate[i].pValue != NULL) {
+ memset(keyTemplate[i].pValue, 0,
+ keyTemplate[i].ulValueLen);
+ isc_mem_put(dctx->mctx,
+ keyTemplate[i].pValue,
+ keyTemplate[i].ulValueLen);
+ }
+ pk11_return_session(pk11_ctx);
+ memset(pk11_ctx, 0, sizeof(*pk11_ctx));
+ isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx));
+ isc_buffer_free(&buf);
+ dctx->ctxdata.generic = NULL;
+
+ return (ret);
+}
+
+static isc_result_t
+pkcs11eddsa_verify(dst_context_t *dctx, const isc_region_t *sig) {
+ isc_buffer_t *buf = (isc_buffer_t *) dctx->ctxdata.generic;
+ CK_RV rv;
+ CK_MECHANISM mech = { CKM_EDDSA, NULL, 0 };
+ CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE;
+ CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY;
+ CK_KEY_TYPE keyType = CKK_EDDSA;
+ CK_ATTRIBUTE keyTemplate[] =
+ {
+ { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
+ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
+ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
+ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
+ { CKA_VERIFY, &truevalue, (CK_ULONG) sizeof(truevalue) },
+ { CKA_EC_PARAMS, NULL, 0 },
+ { CKA_VALUE, NULL, 0 }
+ };
+ CK_ATTRIBUTE *attr;
+ CK_SLOT_ID slotid;
+ pk11_context_t *pk11_ctx;
+ dst_key_t *key = dctx->key;
+ pk11_object_t *ec = key->keydata.pkey;
+ isc_region_t t;
+ isc_result_t ret = ISC_R_SUCCESS;
+ unsigned int i;
+
+ REQUIRE(key->key_alg == DST_ALG_ED25519 ||
+ key->key_alg == DST_ALG_ED448);
+ REQUIRE(ec != NULL);
+
+ pk11_ctx = (pk11_context_t *) isc_mem_get(dctx->mctx,
+ sizeof(*pk11_ctx));
+ if (pk11_ctx == NULL)
+ return (ISC_R_NOMEMORY);
+ memset(pk11_ctx, 0, sizeof(*pk11_ctx));
+ if (ec->ontoken && (dctx->use == DO_SIGN))
+ slotid = ec->slot;
+ else
+ slotid = pk11_get_best_token(OP_EC);
+ ret = pk11_get_session(pk11_ctx, OP_EC, ISC_TRUE, ISC_FALSE,
+ ec->reqlogon, NULL, slotid);
+ if (ret != ISC_R_SUCCESS)
+ goto err;
+
+ for (attr = pk11_attribute_first(ec);
+ attr != NULL;
+ attr = pk11_attribute_next(ec, attr))
+ switch (attr->type) {
+ case CKA_EC_PARAMS:
+ INSIST(keyTemplate[5].type == attr->type);
+ keyTemplate[5].pValue = isc_mem_get(dctx->mctx,
+ attr->ulValueLen);
+ if (keyTemplate[5].pValue == NULL)
+ DST_RET(ISC_R_NOMEMORY);
+ memmove(keyTemplate[5].pValue, attr->pValue,
+ attr->ulValueLen);
+ keyTemplate[5].ulValueLen = attr->ulValueLen;
+ break;
+ case CKA_EC_POINT:
+ /* keyTemplate[6].type is CKA_VALUE */
+ keyTemplate[6].pValue = isc_mem_get(dctx->mctx,
+ attr->ulValueLen);
+ if (keyTemplate[6].pValue == NULL)
+ DST_RET(ISC_R_NOMEMORY);
+ memmove(keyTemplate[6].pValue, attr->pValue,
+ attr->ulValueLen);
+ keyTemplate[6].ulValueLen = attr->ulValueLen;
+ break;
+ }
+ pk11_ctx->object = CK_INVALID_HANDLE;
+ pk11_ctx->ontoken = ISC_FALSE;
+ PK11_RET(pkcs_C_CreateObject,
+ (pk11_ctx->session,
+ keyTemplate, (CK_ULONG) 7,
+ &hKey),
+ ISC_R_FAILURE);
+
+ PK11_RET(pkcs_C_VerifyInit,
+ (pk11_ctx->session, &mech, hKey),
+ ISC_R_FAILURE);
+
+ isc_buffer_usedregion(buf, &t);
+
+ PK11_RET(pkcs_C_Verify,
+ (pk11_ctx->session,
+ (CK_BYTE_PTR) t.base, (CK_ULONG) t.length,
+ (CK_BYTE_PTR) sig->base, (CK_ULONG) sig->length),
+ DST_R_VERIFYFAILURE);
+
+ err:
+
+ if (hKey != CK_INVALID_HANDLE)
+ (void) pkcs_C_DestroyObject(pk11_ctx->session, hKey);
+ for (i = 5; i <= 6; i++)
+ if (keyTemplate[i].pValue != NULL) {
+ memset(keyTemplate[i].pValue, 0,
+ keyTemplate[i].ulValueLen);
+ isc_mem_put(dctx->mctx,
+ keyTemplate[i].pValue,
+ keyTemplate[i].ulValueLen);
+ }
+ pk11_return_session(pk11_ctx);
+ memset(pk11_ctx, 0, sizeof(*pk11_ctx));
+ isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx));
+ isc_buffer_free(&buf);
+ dctx->ctxdata.generic = NULL;
+
+ return (ret);
+}
+
+static isc_boolean_t
+pkcs11eddsa_compare(const dst_key_t *key1, const dst_key_t *key2) {
+ pk11_object_t *ec1, *ec2;
+ CK_ATTRIBUTE *attr1, *attr2;
+
+ ec1 = key1->keydata.pkey;
+ ec2 = key2->keydata.pkey;
+
+ if ((ec1 == NULL) && (ec2 == NULL))
+ return (ISC_TRUE);
+ else if ((ec1 == NULL) || (ec2 == NULL))
+ return (ISC_FALSE);
+
+ attr1 = pk11_attribute_bytype(ec1, CKA_EC_PARAMS);
+ attr2 = pk11_attribute_bytype(ec2, CKA_EC_PARAMS);
+ if ((attr1 == NULL) && (attr2 == NULL))
+ return (ISC_TRUE);
+ else if ((attr1 == NULL) || (attr2 == NULL) ||
+ (attr1->ulValueLen != attr2->ulValueLen) ||
+ !isc_safe_memequal(attr1->pValue, attr2->pValue,
+ attr1->ulValueLen))
+ return (ISC_FALSE);
+
+ attr1 = pk11_attribute_bytype(ec1, CKA_EC_POINT);
+ attr2 = pk11_attribute_bytype(ec2, CKA_EC_POINT);
+ if ((attr1 == NULL) && (attr2 == NULL))
+ return (ISC_TRUE);
+ else if ((attr1 == NULL) || (attr2 == NULL) ||
+ (attr1->ulValueLen != attr2->ulValueLen) ||
+ !isc_safe_memequal(attr1->pValue, attr2->pValue,
+ attr1->ulValueLen))
+ return (ISC_FALSE);
+
+ attr1 = pk11_attribute_bytype(ec1, CKA_VALUE);
+ attr2 = pk11_attribute_bytype(ec2, CKA_VALUE);
+ if (((attr1 != NULL) || (attr2 != NULL)) &&
+ ((attr1 == NULL) || (attr2 == NULL) ||
+ (attr1->ulValueLen != attr2->ulValueLen) ||
+ !isc_safe_memequal(attr1->pValue, attr2->pValue,
+ attr1->ulValueLen)))
+ return (ISC_FALSE);
+
+ if (!ec1->ontoken && !ec2->ontoken)
+ return (ISC_TRUE);
+ else if (ec1->ontoken || ec2->ontoken ||
+ (ec1->object != ec2->object))
+ return (ISC_FALSE);
+
+ return (ISC_TRUE);
+}
+
+#define SETCURVE() \
+ if (key->key_alg == DST_ALG_ED25519) { \
+ attr->pValue = isc_mem_get(key->mctx, \
+ sizeof(pk11_ecc_ed25519)); \
+ if (attr->pValue == NULL) \
+ DST_RET(ISC_R_NOMEMORY); \
+ memmove(attr->pValue, \
+ pk11_ecc_ed25519, sizeof(pk11_ecc_ed25519)); \
+ attr->ulValueLen = sizeof(pk11_ecc_ed25519); \
+ } else { \
+ attr->pValue = isc_mem_get(key->mctx, \
+ sizeof(pk11_ecc_ed448)); \
+ if (attr->pValue == NULL) \
+ DST_RET(ISC_R_NOMEMORY); \
+ memmove(attr->pValue, \
+ pk11_ecc_ed448, sizeof(pk11_ecc_ed448)); \
+ attr->ulValueLen = sizeof(pk11_ecc_ed448); \
+ }
+
+#define FREECURVE() \
+ if (attr->pValue != NULL) { \
+ memset(attr->pValue, 0, attr->ulValueLen); \
+ isc_mem_put(key->mctx, attr->pValue, attr->ulValueLen); \
+ attr->pValue = NULL; \
+ }
+
+static isc_result_t
+pkcs11eddsa_generate(dst_key_t *key, int unused, void (*callback)(int)) {
+ CK_RV rv;
+ CK_MECHANISM mech = { CKM_EDDSA_KEY_PAIR_GEN, NULL, 0 };
+ CK_OBJECT_HANDLE pub = CK_INVALID_HANDLE;
+ CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY;
+ CK_KEY_TYPE keyType = CKK_EDDSA;
+ CK_ATTRIBUTE pubTemplate[] =
+ {
+ { CKA_CLASS, &pubClass, (CK_ULONG) sizeof(pubClass) },
+ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
+ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
+ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
+ { CKA_VERIFY, &truevalue, (CK_ULONG) sizeof(truevalue) },
+ { CKA_EC_PARAMS, NULL, 0 }
+ };
+ CK_OBJECT_HANDLE priv = CK_INVALID_HANDLE;
+ CK_OBJECT_HANDLE privClass = CKO_PRIVATE_KEY;
+ CK_ATTRIBUTE privTemplate[] =
+ {
+ { CKA_CLASS, &privClass, (CK_ULONG) sizeof(privClass) },
+ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
+ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
+ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
+ { CKA_SENSITIVE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
+ { CKA_EXTRACTABLE, &truevalue, (CK_ULONG) sizeof(truevalue) },
+ { CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) }
+ };
+ CK_ATTRIBUTE *attr;
+ pk11_object_t *ec;
+ pk11_context_t *pk11_ctx;
+ isc_result_t ret;
+
+ REQUIRE(key->key_alg == DST_ALG_ED25519 ||
+ key->key_alg == DST_ALG_ED448);
+ UNUSED(unused);
+ UNUSED(callback);
+
+ pk11_ctx = (pk11_context_t *) isc_mem_get(key->mctx,
+ sizeof(*pk11_ctx));
+ if (pk11_ctx == NULL)
+ return (ISC_R_NOMEMORY);
+ ret = pk11_get_session(pk11_ctx, OP_EC, ISC_TRUE, ISC_FALSE,
+ ISC_FALSE, NULL, pk11_get_best_token(OP_EC));
+ if (ret != ISC_R_SUCCESS)
+ goto err;
+
+ ec = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*ec));
+ if (ec == NULL)
+ DST_RET(ISC_R_NOMEMORY);
+ memset(ec, 0, sizeof(*ec));
+ key->keydata.pkey = ec;
+ ec->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 3);
+ if (ec->repr == NULL)
+ DST_RET(ISC_R_NOMEMORY);
+ memset(ec->repr, 0, sizeof(*attr) * 3);
+ ec->attrcnt = 3;
+
+ attr = ec->repr;
+ attr[0].type = CKA_EC_PARAMS;
+ attr[1].type = CKA_VALUE;
+ attr[2].type = CKA_VALUE;
+
+ attr = &pubTemplate[5];
+ SETCURVE();
+
+ PK11_RET(pkcs_C_GenerateKeyPair,
+ (pk11_ctx->session, &mech,
+ pubTemplate, (CK_ULONG) 6,
+ privTemplate, (CK_ULONG) 7,
+ &pub, &priv),
+ DST_R_CRYPTOFAILURE);
+
+ attr = &pubTemplate[5];
+ FREECURVE();
+
+ attr = ec->repr;
+ SETCURVE();
+
+ attr++;
+ PK11_RET(pkcs_C_GetAttributeValue,
+ (pk11_ctx->session, pub, attr, 1),
+ DST_R_CRYPTOFAILURE);
+ attr->pValue = isc_mem_get(key->mctx, attr->ulValueLen);
+ if (attr->pValue == NULL)
+ DST_RET(ISC_R_NOMEMORY);
+ memset(attr->pValue, 0, attr->ulValueLen);
+ PK11_RET(pkcs_C_GetAttributeValue,
+ (pk11_ctx->session, pub, attr, 1),
+ DST_R_CRYPTOFAILURE);
+ attr->type = CKA_EC_POINT;
+
+ attr++;
+ PK11_RET(pkcs_C_GetAttributeValue,
+ (pk11_ctx->session, priv, attr, 1),
+ DST_R_CRYPTOFAILURE);
+ attr->pValue = isc_mem_get(key->mctx, attr->ulValueLen);
+ if (attr->pValue == NULL)
+ DST_RET(ISC_R_NOMEMORY);
+ memset(attr->pValue, 0, attr->ulValueLen);
+ PK11_RET(pkcs_C_GetAttributeValue,
+ (pk11_ctx->session, priv, attr, 1),
+ DST_R_CRYPTOFAILURE);
+
+ (void) pkcs_C_DestroyObject(pk11_ctx->session, priv);
+ (void) pkcs_C_DestroyObject(pk11_ctx->session, pub);
+ pk11_return_session(pk11_ctx);
+ memset(pk11_ctx, 0, sizeof(*pk11_ctx));
+ isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx));
+
+ if (key->key_alg == DST_ALG_ED25519)
+ key->key_size = DNS_KEY_ED25519SIZE;
+ else
+ key->key_size = DNS_KEY_ED448SIZE;
+
+ return (ISC_R_SUCCESS);
+
+ err:
+ pkcs11eddsa_destroy(key);
+ if (priv != CK_INVALID_HANDLE)
+ (void) pkcs_C_DestroyObject(pk11_ctx->session, priv);
+ if (pub != CK_INVALID_HANDLE)
+ (void) pkcs_C_DestroyObject(pk11_ctx->session, pub);
+ pk11_return_session(pk11_ctx);
+ memset(pk11_ctx, 0, sizeof(*pk11_ctx));
+ isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx));
+
+ return (ret);
+}
+
+static isc_boolean_t
+pkcs11eddsa_isprivate(const dst_key_t *key) {
+ pk11_object_t *ec = key->keydata.pkey;
+ CK_ATTRIBUTE *attr;
+
+ if (ec == NULL)
+ return (ISC_FALSE);
+ attr = pk11_attribute_bytype(ec, CKA_VALUE);
+ return (ISC_TF((attr != NULL) || ec->ontoken));
+}
+
+static void
+pkcs11eddsa_destroy(dst_key_t *key) {
+ pk11_object_t *ec = key->keydata.pkey;
+ CK_ATTRIBUTE *attr;
+
+ if (ec == NULL)
+ return;
+
+ INSIST((ec->object == CK_INVALID_HANDLE) || ec->ontoken);
+
+ for (attr = pk11_attribute_first(ec);
+ attr != NULL;
+ attr = pk11_attribute_next(ec, attr))
+ switch (attr->type) {
+ case CKA_LABEL:
+ case CKA_ID:
+ case CKA_EC_PARAMS:
+ case CKA_EC_POINT:
+ case CKA_VALUE:
+ FREECURVE();
+ break;
+ }
+ if (ec->repr != NULL) {
+ memset(ec->repr, 0, ec->attrcnt * sizeof(*attr));
+ isc_mem_put(key->mctx,
+ ec->repr,
+ ec->attrcnt * sizeof(*attr));
+ }
+ memset(ec, 0, sizeof(*ec));
+ isc_mem_put(key->mctx, ec, sizeof(*ec));
+ key->keydata.pkey = NULL;
+}
+
+static isc_result_t
+pkcs11eddsa_todns(const dst_key_t *key, isc_buffer_t *data) {
+ pk11_object_t *ec;
+ isc_region_t r;
+ unsigned int len;
+ CK_ATTRIBUTE *attr;
+
+ REQUIRE(key->keydata.pkey != NULL);
+
+ if (key->key_alg == DST_ALG_ED25519)
+ len = DNS_KEY_ED25519SIZE;
+ else
+ len = DNS_KEY_ED448SIZE;
+
+ ec = key->keydata.pkey;
+ attr = pk11_attribute_bytype(ec, CKA_EC_POINT);
+ if ((attr == NULL) || (attr->ulValueLen != len))
+ return (ISC_R_FAILURE);
+
+ isc_buffer_availableregion(data, &r);
+ if (r.length < len)
+ return (ISC_R_NOSPACE);
+ memmove(r.base, (CK_BYTE_PTR) attr->pValue, len);
+ isc_buffer_add(data, len);
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+pkcs11eddsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
+ pk11_object_t *ec;
+ isc_region_t r;
+ unsigned int len;
+ CK_ATTRIBUTE *attr;
+
+ REQUIRE(key->key_alg == DST_ALG_ED25519 ||
+ key->key_alg == DST_ALG_ED448);
+
+ if (key->key_alg == DST_ALG_ED25519)
+ len = DNS_KEY_ED25519SIZE;
+ else
+ len = DNS_KEY_ED448SIZE;
+
+ isc_buffer_remainingregion(data, &r);
+ if (r.length == 0)
+ return (ISC_R_SUCCESS);
+ if (r.length != len)
+ return (DST_R_INVALIDPUBLICKEY);
+
+ ec = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*ec));
+ if (ec == NULL)
+ return (ISC_R_NOMEMORY);
+ memset(ec, 0, sizeof(*ec));
+ ec->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 2);
+ if (ec->repr == NULL)
+ goto nomemory;
+ ec->attrcnt = 2;
+
+ attr = ec->repr;
+ attr->type = CKA_EC_PARAMS;
+ if (key->key_alg == DST_ALG_ED25519) {
+ attr->pValue =
+ isc_mem_get(key->mctx, sizeof(pk11_ecc_ed25519));
+ if (attr->pValue == NULL)
+ goto nomemory;
+ memmove(attr->pValue,
+ pk11_ecc_ed25519, sizeof(pk11_ecc_ed25519));
+ attr->ulValueLen = sizeof(pk11_ecc_ed25519);
+ } else {
+ attr->pValue =
+ isc_mem_get(key->mctx, sizeof(pk11_ecc_ed448));
+ if (attr->pValue == NULL)
+ goto nomemory;
+ memmove(attr->pValue,
+ pk11_ecc_ed448, sizeof(pk11_ecc_ed448));
+ attr->ulValueLen = sizeof(pk11_ecc_ed448);
+ }
+
+ attr++;
+ attr->type = CKA_EC_POINT;
+ attr->pValue = isc_mem_get(key->mctx, len);
+ if (attr->pValue == NULL)
+ goto nomemory;
+ memmove((CK_BYTE_PTR) attr->pValue, r.base, len);
+ attr->ulValueLen = len;
+
+ isc_buffer_forward(data, len);
+ key->keydata.pkey = ec;
+ key->key_size = len;
+ return (ISC_R_SUCCESS);
+
+ nomemory:
+ for (attr = pk11_attribute_first(ec);
+ attr != NULL;
+ attr = pk11_attribute_next(ec, attr))
+ switch (attr->type) {
+ case CKA_EC_PARAMS:
+ case CKA_EC_POINT:
+ FREECURVE();
+ break;
+ }
+ if (ec->repr != NULL) {
+ memset(ec->repr, 0, ec->attrcnt * sizeof(*attr));
+ isc_mem_put(key->mctx,
+ ec->repr,
+ ec->attrcnt * sizeof(*attr));
+ }
+ memset(ec, 0, sizeof(*ec));
+ isc_mem_put(key->mctx, ec, sizeof(*ec));
+ return (ISC_R_NOMEMORY);
+}
+
+static isc_result_t
+pkcs11eddsa_tofile(const dst_key_t *key, const char *directory) {
+ isc_result_t ret;
+ pk11_object_t *ec;
+ dst_private_t priv;
+ unsigned char *buf = NULL;
+ unsigned int i = 0;
+ CK_ATTRIBUTE *attr;
+
+ if (key->keydata.pkey == NULL)
+ return (DST_R_NULLKEY);
+
+ if (key->external) {
+ priv.nelements = 0;
+ return (dst__privstruct_writefile(key, &priv, directory));
+ }
+
+ ec = key->keydata.pkey;
+ attr = pk11_attribute_bytype(ec, CKA_VALUE);
+ if (attr != NULL) {
+ buf = isc_mem_get(key->mctx, attr->ulValueLen);
+ if (buf == NULL)
+ return (ISC_R_NOMEMORY);
+ priv.elements[i].tag = TAG_EDDSA_PRIVATEKEY;
+ priv.elements[i].length = (unsigned short) attr->ulValueLen;
+ memmove(buf, attr->pValue, attr->ulValueLen);
+ priv.elements[i].data = buf;
+ i++;
+ }
+
+ if (key->engine != NULL) {
+ priv.elements[i].tag = TAG_EDDSA_ENGINE;
+ priv.elements[i].length = strlen(key->engine) + 1;
+ priv.elements[i].data = (unsigned char *)key->engine;
+ i++;
+ }
+
+ if (key->label != NULL) {
+ priv.elements[i].tag = TAG_EDDSA_LABEL;
+ priv.elements[i].length = strlen(key->label) + 1;
+ priv.elements[i].data = (unsigned char *)key->label;
+ i++;
+ }
+
+ priv.nelements = i;
+ ret = dst__privstruct_writefile(key, &priv, directory);
+
+ if (buf != NULL) {
+ memset(buf, 0, attr->ulValueLen);
+ isc_mem_put(key->mctx, buf, attr->ulValueLen);
+ }
+ return (ret);
+}
+
+static isc_result_t
+pkcs11eddsa_fetch(dst_key_t *key, const char *engine, const char *label,
+ dst_key_t *pub)
+{
+ CK_RV rv;
+ CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY;
+ CK_KEY_TYPE keyType = CKK_EDDSA;
+ CK_ATTRIBUTE searchTemplate[] =
+ {
+ { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
+ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
+ { CKA_TOKEN, &truevalue, (CK_ULONG) sizeof(truevalue) },
+ { CKA_LABEL, NULL, 0 }
+ };
+ CK_ULONG cnt;
+ CK_ATTRIBUTE *attr;
+ CK_ATTRIBUTE *pubattr;
+ pk11_object_t *ec;
+ pk11_object_t *pubec;
+ pk11_context_t *pk11_ctx = NULL;
+ isc_result_t ret;
+
+ if (label == NULL)
+ return (DST_R_NOENGINE);
+
+ ec = key->keydata.pkey;
+ pubec = pub->keydata.pkey;
+
+ ec->object = CK_INVALID_HANDLE;
+ ec->ontoken = ISC_TRUE;
+ ec->reqlogon = ISC_TRUE;
+ ec->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 2);
+ if (ec->repr == NULL)
+ return (ISC_R_NOMEMORY);
+ memset(ec->repr, 0, sizeof(*attr) * 2);
+ ec->attrcnt = 2;
+ attr = ec->repr;
+
+ attr->type = CKA_EC_PARAMS;
+ pubattr = pk11_attribute_bytype(pubec, CKA_EC_PARAMS);
+ attr->pValue = isc_mem_get(key->mctx, pubattr->ulValueLen);
+ if (attr->pValue == NULL)
+ DST_RET(ISC_R_NOMEMORY);
+ memmove(attr->pValue, pubattr->pValue, pubattr->ulValueLen);
+ attr->ulValueLen = pubattr->ulValueLen;
+ attr++;
+
+ attr->type = CKA_EC_POINT;
+ pubattr = pk11_attribute_bytype(pubec, CKA_EC_POINT);
+ attr->pValue = isc_mem_get(key->mctx, pubattr->ulValueLen);
+ if (attr->pValue == NULL)
+ DST_RET(ISC_R_NOMEMORY);
+ memmove(attr->pValue, pubattr->pValue, pubattr->ulValueLen);
+ attr->ulValueLen = pubattr->ulValueLen;
+
+ ret = pk11_parse_uri(ec, label, key->mctx, OP_EC);
+ if (ret != ISC_R_SUCCESS)
+ goto err;
+
+ pk11_ctx = (pk11_context_t *) isc_mem_get(key->mctx,
+ sizeof(*pk11_ctx));
+ if (pk11_ctx == NULL)
+ DST_RET(ISC_R_NOMEMORY);
+ ret = pk11_get_session(pk11_ctx, OP_EC, ISC_TRUE, ISC_FALSE,
+ ec->reqlogon, NULL, ec->slot);
+ if (ret != ISC_R_SUCCESS)
+ goto err;
+
+ attr = pk11_attribute_bytype(ec, CKA_LABEL);
+ if (attr == NULL) {
+ attr = pk11_attribute_bytype(ec, CKA_ID);
+ INSIST(attr != NULL);
+ searchTemplate[3].type = CKA_ID;
+ }
+ searchTemplate[3].pValue = attr->pValue;
+ searchTemplate[3].ulValueLen = attr->ulValueLen;
+
+ PK11_RET(pkcs_C_FindObjectsInit,
+ (pk11_ctx->session, searchTemplate, (CK_ULONG) 4),
+ DST_R_CRYPTOFAILURE);
+ PK11_RET(pkcs_C_FindObjects,
+ (pk11_ctx->session, &ec->object, (CK_ULONG) 1, &cnt),
+ DST_R_CRYPTOFAILURE);
+ (void) pkcs_C_FindObjectsFinal(pk11_ctx->session);
+ if (cnt == 0)
+ DST_RET(ISC_R_NOTFOUND);
+ if (cnt > 1)
+ DST_RET(ISC_R_EXISTS);
+
+ if (engine != NULL) {
+ key->engine = isc_mem_strdup(key->mctx, engine);
+ if (key->engine == NULL)
+ DST_RET(ISC_R_NOMEMORY);
+ }
+
+ key->label = isc_mem_strdup(key->mctx, label);
+ if (key->label == NULL)
+ DST_RET(ISC_R_NOMEMORY);
+
+ pk11_return_session(pk11_ctx);
+ memset(pk11_ctx, 0, sizeof(*pk11_ctx));
+ isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx));
+ return (ISC_R_SUCCESS);
+
+ err:
+ if (pk11_ctx != NULL) {
+ pk11_return_session(pk11_ctx);
+ memset(pk11_ctx, 0, sizeof(*pk11_ctx));
+ isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx));
+ }
+ return (ret);
+}
+
+static isc_result_t
+pkcs11eddsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
+ dst_private_t priv;
+ isc_result_t ret;
+ pk11_object_t *ec = NULL;
+ CK_ATTRIBUTE *attr, *pattr;
+ isc_mem_t *mctx = key->mctx;
+ unsigned int i;
+ const char *engine = NULL, *label = NULL;
+
+ REQUIRE(key->key_alg == DST_ALG_ED25519 ||
+ key->key_alg == DST_ALG_ED448);
+
+ if ((pub == NULL) || (pub->keydata.pkey == NULL))
+ DST_RET(DST_R_INVALIDPRIVATEKEY);
+
+ /* read private key file */
+ ret = dst__privstruct_parse(key, DST_ALG_ED25519, lexer, mctx, &priv);
+ if (ret != ISC_R_SUCCESS)
+ return (ret);
+
+ if (key->external) {
+ if (priv.nelements != 0)
+ DST_RET(DST_R_INVALIDPRIVATEKEY);
+
+ key->keydata.pkey = pub->keydata.pkey;
+ pub->keydata.pkey = NULL;
+ key->key_size = pub->key_size;
+
+ dst__privstruct_free(&priv, mctx);
+ memset(&priv, 0, sizeof(priv));
+
+ return (ISC_R_SUCCESS);
+ }
+
+ for (i = 0; i < priv.nelements; i++) {
+ switch (priv.elements[i].tag) {
+ case TAG_EDDSA_ENGINE:
+ engine = (char *)priv.elements[i].data;
+ break;
+ case TAG_EDDSA_LABEL:
+ label = (char *)priv.elements[i].data;
+ break;
+ default:
+ break;
+ }
+ }
+ ec = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*ec));
+ if (ec == NULL)
+ DST_RET(ISC_R_NOMEMORY);
+ memset(ec, 0, sizeof(*ec));
+ key->keydata.pkey = ec;
+
+ /* Is this key is stored in a HSM? See if we can fetch it. */
+ if ((label != NULL) || (engine != NULL)) {
+ ret = pkcs11eddsa_fetch(key, engine, label, pub);
+ if (ret != ISC_R_SUCCESS)
+ goto err;
+ dst__privstruct_free(&priv, mctx);
+ memset(&priv, 0, sizeof(priv));
+ return (ret);
+ }
+
+ ec->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 3);
+ if (ec->repr == NULL)
+ DST_RET(ISC_R_NOMEMORY);
+ memset(ec->repr, 0, sizeof(*attr) * 3);
+ ec->attrcnt = 3;
+
+ attr = ec->repr;
+ attr->type = CKA_EC_PARAMS;
+ pattr = pk11_attribute_bytype(pub->keydata.pkey, CKA_EC_PARAMS);
+ INSIST(pattr != NULL);
+ attr->pValue = isc_mem_get(key->mctx, pattr->ulValueLen);
+ if (attr->pValue == NULL)
+ DST_RET(ISC_R_NOMEMORY);
+ memmove(attr->pValue, pattr->pValue, pattr->ulValueLen);
+ attr->ulValueLen = pattr->ulValueLen;
+
+ attr++;
+ attr->type = CKA_EC_POINT;
+ pattr = pk11_attribute_bytype(pub->keydata.pkey, CKA_EC_POINT);
+ INSIST(pattr != NULL);
+ attr->pValue = isc_mem_get(key->mctx, pattr->ulValueLen);
+ if (attr->pValue == NULL)
+ DST_RET(ISC_R_NOMEMORY);
+ memmove(attr->pValue, pattr->pValue, pattr->ulValueLen);
+ attr->ulValueLen = pattr->ulValueLen;
+
+ attr++;
+ attr->type = CKA_VALUE;
+ attr->pValue = isc_mem_get(key->mctx, priv.elements[0].length);
+ if (attr->pValue == NULL)
+ DST_RET(ISC_R_NOMEMORY);
+ memmove(attr->pValue, priv.elements[0].data, priv.elements[0].length);
+ attr->ulValueLen = priv.elements[0].length;
+
+ dst__privstruct_free(&priv, mctx);
+ memset(&priv, 0, sizeof(priv));
+ if (key->key_alg == DST_ALG_ED25519)
+ key->key_size = DNS_KEY_ED25519SIZE;
+ else
+ key->key_size = DNS_KEY_ED448SIZE;
+
+ return (ISC_R_SUCCESS);
+
+ err:
+ pkcs11eddsa_destroy(key);
+ dst__privstruct_free(&priv, mctx);
+ memset(&priv, 0, sizeof(priv));
+ return (ret);
+}
+
+static isc_result_t
+pkcs11eddsa_fromlabel(dst_key_t *key, const char *engine, const char *label,
+ const char *pin)
+{
+ CK_RV rv;
+ CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE;
+ CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY;
+ CK_KEY_TYPE keyType = CKK_EDDSA;
+ CK_ATTRIBUTE searchTemplate[] =
+ {
+ { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
+ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
+ { CKA_TOKEN, &truevalue, (CK_ULONG) sizeof(truevalue) },
+ { CKA_LABEL, NULL, 0 }
+ };
+ CK_ULONG cnt;
+ CK_ATTRIBUTE *attr;
+ pk11_object_t *ec;
+ pk11_context_t *pk11_ctx = NULL;
+ isc_result_t ret;
+ unsigned int i;
+
+ UNUSED(pin);
+
+ ec = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*ec));
+ if (ec == NULL)
+ return (ISC_R_NOMEMORY);
+ memset(ec, 0, sizeof(*ec));
+ ec->object = CK_INVALID_HANDLE;
+ ec->ontoken = ISC_TRUE;
+ ec->reqlogon = ISC_TRUE;
+ key->keydata.pkey = ec;
+
+ ec->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 2);
+ if (ec->repr == NULL)
+ DST_RET(ISC_R_NOMEMORY);
+ memset(ec->repr, 0, sizeof(*attr) * 2);
+ ec->attrcnt = 2;
+ attr = ec->repr;
+ attr[0].type = CKA_EC_PARAMS;
+ attr[1].type = CKA_VALUE;
+
+ ret = pk11_parse_uri(ec, label, key->mctx, OP_EC);
+ if (ret != ISC_R_SUCCESS)
+ goto err;
+
+ pk11_ctx = (pk11_context_t *) isc_mem_get(key->mctx,
+ sizeof(*pk11_ctx));
+ if (pk11_ctx == NULL)
+ DST_RET(ISC_R_NOMEMORY);
+ ret = pk11_get_session(pk11_ctx, OP_EC, ISC_TRUE, ISC_FALSE,
+ ec->reqlogon, NULL, ec->slot);
+ if (ret != ISC_R_SUCCESS)
+ goto err;
+
+ attr = pk11_attribute_bytype(ec, CKA_LABEL);
+ if (attr == NULL) {
+ attr = pk11_attribute_bytype(ec, CKA_ID);
+ INSIST(attr != NULL);
+ searchTemplate[3].type = CKA_ID;
+ }
+ searchTemplate[3].pValue = attr->pValue;
+ searchTemplate[3].ulValueLen = attr->ulValueLen;
+
+ PK11_RET(pkcs_C_FindObjectsInit,
+ (pk11_ctx->session, searchTemplate, (CK_ULONG) 4),
+ DST_R_CRYPTOFAILURE);
+ PK11_RET(pkcs_C_FindObjects,
+ (pk11_ctx->session, &hKey, (CK_ULONG) 1, &cnt),
+ DST_R_CRYPTOFAILURE);
+ (void) pkcs_C_FindObjectsFinal(pk11_ctx->session);
+ if (cnt == 0)
+ DST_RET(ISC_R_NOTFOUND);
+ if (cnt > 1)
+ DST_RET(ISC_R_EXISTS);
+
+ attr = ec->repr;
+ PK11_RET(pkcs_C_GetAttributeValue,
+ (pk11_ctx->session, hKey, attr, 2),
+ DST_R_CRYPTOFAILURE);
+ for (i = 0; i <= 1; i++) {
+ attr[i].pValue = isc_mem_get(key->mctx, attr[i].ulValueLen);
+ if (attr[i].pValue == NULL)
+ DST_RET(ISC_R_NOMEMORY);
+ memset(attr[i].pValue, 0, attr[i].ulValueLen);
+ }
+ PK11_RET(pkcs_C_GetAttributeValue,
+ (pk11_ctx->session, hKey, attr, 2),
+ DST_R_CRYPTOFAILURE);
+ attr[1].type = CKA_EC_POINT;
+
+ keyClass = CKO_PRIVATE_KEY;
+ PK11_RET(pkcs_C_FindObjectsInit,
+ (pk11_ctx->session, searchTemplate, (CK_ULONG) 4),
+ DST_R_CRYPTOFAILURE);
+ PK11_RET(pkcs_C_FindObjects,
+ (pk11_ctx->session, &ec->object, (CK_ULONG) 1, &cnt),
+ DST_R_CRYPTOFAILURE);
+ (void) pkcs_C_FindObjectsFinal(pk11_ctx->session);
+ if (cnt == 0)
+ DST_RET(ISC_R_NOTFOUND);
+ if (cnt > 1)
+ DST_RET(ISC_R_EXISTS);
+
+ if (engine != NULL) {
+ key->engine = isc_mem_strdup(key->mctx, engine);
+ if (key->engine == NULL)
+ DST_RET(ISC_R_NOMEMORY);
+ }
+
+ key->label = isc_mem_strdup(key->mctx, label);
+ if (key->label == NULL)
+ DST_RET(ISC_R_NOMEMORY);
+ if (key->key_alg == DST_ALG_ED25519)
+ key->key_size = DNS_KEY_ED25519SIZE;
+ else
+ key->key_size = DNS_KEY_ED448SIZE;
+
+ pk11_return_session(pk11_ctx);
+ memset(pk11_ctx, 0, sizeof(*pk11_ctx));
+ isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx));
+ return (ISC_R_SUCCESS);
+
+ err:
+ pkcs11eddsa_destroy(key);
+ if (pk11_ctx != NULL) {
+ pk11_return_session(pk11_ctx);
+ memset(pk11_ctx, 0, sizeof(*pk11_ctx));
+ isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx));
+ }
+ return (ret);
+}
+
+static dst_func_t pkcs11eddsa_functions = {
+ pkcs11eddsa_createctx,
+ NULL, /*%< createctx2 */
+ pkcs11eddsa_destroyctx,
+ pkcs11eddsa_adddata,
+ pkcs11eddsa_sign,
+ pkcs11eddsa_verify,
+ NULL, /*%< verify2 */
+ NULL, /*%< computesecret */
+ pkcs11eddsa_compare,
+ NULL, /*%< paramcompare */
+ pkcs11eddsa_generate,
+ pkcs11eddsa_isprivate,
+ pkcs11eddsa_destroy,
+ pkcs11eddsa_todns,
+ pkcs11eddsa_fromdns,
+ pkcs11eddsa_tofile,
+ pkcs11eddsa_parse,
+ NULL, /*%< cleanup */
+ pkcs11eddsa_fromlabel,
+ NULL, /*%< dump */
+ NULL, /*%< restore */
+};
+
+isc_result_t
+dst__pkcs11eddsa_init(dst_func_t **funcp) {
+ REQUIRE(funcp != NULL);
+ if (*funcp == NULL)
+ *funcp = &pkcs11eddsa_functions;
+ return (ISC_R_SUCCESS);
+}
+
+#else /* PKCS11CRYPTO && HAVE_PKCS11_EDxxx */
+
+#include
+
+EMPTY_TRANSLATION_UNIT
+
+#endif /* PKCS11CRYPTO && HAVE_PKCS11_EDxxx */
+/*! \file */
diff --git a/lib/dns/rcode.c b/lib/dns/rcode.c
index 534f16a3c2..46ab9f4045 100644
--- a/lib/dns/rcode.c
+++ b/lib/dns/rcode.c
@@ -132,6 +132,8 @@
{ DNS_KEYALG_ECCGOST, "ECCGOST", 0 }, \
{ DNS_KEYALG_ECDSA256, "ECDSAP256SHA256", 0 }, \
{ DNS_KEYALG_ECDSA384, "ECDSAP384SHA384", 0 }, \
+ { DNS_KEYALG_ED25519, "ED25519", 0 }, \
+ { DNS_KEYALG_ED448, "ED448", 0 }, \
{ DNS_KEYALG_INDIRECT, "INDIRECT", 0 }, \
{ DNS_KEYALG_PRIVATEDNS, "PRIVATEDNS", 0 }, \
{ DNS_KEYALG_PRIVATEOID, "PRIVATEOID", 0 }, \
diff --git a/lib/dns/win32/libdns.dsp.in b/lib/dns/win32/libdns.dsp.in
index 186a045f02..51657bcbf8 100644
--- a/lib/dns/win32/libdns.dsp.in
+++ b/lib/dns/win32/libdns.dsp.in
@@ -887,6 +887,10 @@ SOURCE=..\opensslecdsa_link.c
# End Source File
# Begin Source File
+SOURCE=..\openssleddsa_link.c
+# End Source File
+# Begin Source File
+
SOURCE=..\opensslgost_link.c
# End Source File
# Begin Source File
@@ -913,6 +917,10 @@ SOURCE=..\pkcs11ecdsa_link.c
# End Source File
# Begin Source File
+SOURCE=..\pkcs11eddsa_link.c
+# End Source File
+# Begin Source File
+
SOURCE=..\pkcs11gost_link.c
# End Source File
# Begin Source File
diff --git a/lib/dns/win32/libdns.mak.in b/lib/dns/win32/libdns.mak.in
index d0d1744987..760689e613 100644
--- a/lib/dns/win32/libdns.mak.in
+++ b/lib/dns/win32/libdns.mak.in
@@ -175,6 +175,7 @@ CLEAN :
-@erase "$(INTDIR)\openssldh_link.obj"
-@erase "$(INTDIR)\openssldsa_link.obj"
-@erase "$(INTDIR)\opensslecdsa_link.obj"
+ -@erase "$(INTDIR)\openssleddsa_link.obj"
-@erase "$(INTDIR)\opensslgost_link.obj"
-@erase "$(INTDIR)\opensslrsa_link.obj"
@END OPENSSL
@@ -185,6 +186,7 @@ CLEAN :
-@erase "$(INTDIR)\pkcs11dh_link.obj"
-@erase "$(INTDIR)\pkcs11dsa_link.obj"
-@erase "$(INTDIR)\pkcs11ecdsa_link.obj"
+ -@erase "$(INTDIR)\pkcs11eddsa_link.obj"
-@erase "$(INTDIR)\pkcs11gost_link.obj"
-@erase "$(INTDIR)\pkcs11rsa_link.obj"
@END PKCS11
@@ -378,6 +380,7 @@ LINK32_OBJS= \
"$(INTDIR)\openssldh_link.obj" \
"$(INTDIR)\openssldsa_link.obj" \
"$(INTDIR)\opensslecdsa_link.obj" \
+ "$(INTDIR)\openssleddsa_link.obj" \
"$(INTDIR)\opensslgost_link.obj" \
"$(INTDIR)\opensslrsa_link.obj" \
@END OPENSSL
@@ -386,6 +389,7 @@ LINK32_OBJS= \
"$(INTDIR)\pkcs11dh_link.obj" \
"$(INTDIR)\pkcs11dsa_link.obj" \
"$(INTDIR)\pkcs11ecdsa_link.obj" \
+ "$(INTDIR)\pkcs11eddsa_link.obj" \
"$(INTDIR)\pkcs11gost_link.obj" \
"$(INTDIR)\pkcs11rsa_link.obj" \
@END PKCS11
@@ -529,6 +533,8 @@ CLEAN :
-@erase "$(INTDIR)\openssldsa_link.sbr"
-@erase "$(INTDIR)\opensslecdsa_link.obj"
-@erase "$(INTDIR)\opensslecdsa_link.sbr"
+ -@erase "$(INTDIR)\openssleddsa_link.obj"
+ -@erase "$(INTDIR)\openssleddsa_link.sbr"
-@erase "$(INTDIR)\opensslgost_link.obj"
-@erase "$(INTDIR)\opensslgost_link.sbr"
-@erase "$(INTDIR)\opensslrsa_link.obj"
@@ -547,6 +553,8 @@ CLEAN :
-@erase "$(INTDIR)\pkcs11dsa_link.sbr"
-@erase "$(INTDIR)\pkcs11ecdsa_link.obj"
-@erase "$(INTDIR)\pkcs11ecdsa_link.sbr"
+ -@erase "$(INTDIR)\pkcs11eddsa_link.obj"
+ -@erase "$(INTDIR)\pkcs11eddsa_link.sbr"
-@erase "$(INTDIR)\pkcs11gost_link.obj"
-@erase "$(INTDIR)\pkcs11gost_link.sbr"
-@erase "$(INTDIR)\pkcs11rsa_link.obj"
@@ -780,6 +788,7 @@ BSC32_SBRS= \
"$(INTDIR)\openssldh_link.sbr" \
"$(INTDIR)\openssldsa_link.sbr" \
"$(INTDIR)\opensslecdsa_link.sbr" \
+ "$(INTDIR)\openssleddsa_link.sbr" \
"$(INTDIR)\opensslgost_link.sbr" \
"$(INTDIR)\opensslrsa_link.sbr" \
@END OPENSSL
@@ -788,6 +797,7 @@ BSC32_SBRS= \
"$(INTDIR)\pkcs11dh_link.sbr" \
"$(INTDIR)\pkcs11dsa_link.sbr" \
"$(INTDIR)\pkcs11ecdsa_link.sbr" \
+ "$(INTDIR)\pkcs11eddsa_link.sbr" \
"$(INTDIR)\pkcs11gost_link.sbr" \
"$(INTDIR)\pkcs11rsa_link.sbr"
@END PKCS11
@@ -899,6 +909,7 @@ LINK32_OBJS= \
"$(INTDIR)\openssldh_link.obj" \
"$(INTDIR)\openssldsa_link.obj" \
"$(INTDIR)\opensslecdsa_link.obj" \
+ "$(INTDIR)\openssleddsa_link.obj" \
"$(INTDIR)\opensslgost_link.obj" \
"$(INTDIR)\opensslrsa_link.obj" \
@END OPENSSL
@@ -907,6 +918,7 @@ LINK32_OBJS= \
"$(INTDIR)\pkcs11dh_link.obj" \
"$(INTDIR)\pkcs11dsa_link.obj" \
"$(INTDIR)\pkcs11ecdsa_link.obj" \
+ "$(INTDIR)\pkcs11eddsa_link.obj" \
"$(INTDIR)\pkcs11gost_link.obj" \
"$(INTDIR)\pkcs11rsa_link.obj" \
@END PKCS11
@@ -2644,6 +2656,24 @@ SOURCE=..\opensslecdsa_link.c
$(CPP) $(CPP_PROJ) $(SOURCE)
+!ENDIF
+
+SOURCE=..\openssleddsa_link.c
+
+!IF "$(CFG)" == "libdns - @PLATFORM@ Release"
+
+
+"$(INTDIR)\openssleddsa_link.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libdns - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\openssleddsa_link.obj" "$(INTDIR)\openssleddsa_link.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
!ENDIF
SOURCE=..\opensslgost_link.c
@@ -2754,6 +2784,24 @@ SOURCE=..\pkcs11ecdsa_link.c
$(CPP) $(CPP_PROJ) $(SOURCE)
+!ENDIF
+
+SOURCE=..\pkcs11eddsa_link.c
+
+!IF "$(CFG)" == "libdns - @PLATFORM@ Release"
+
+
+"$(INTDIR)\pkcs11eddsa_link.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libdns - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\pkcs11eddsa_link.obj" "$(INTDIR)\pkcs11eddsa_link.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
!ENDIF
SOURCE=..\pkcs11gost_link.c
diff --git a/lib/dns/win32/libdns.vcxproj.filters.in b/lib/dns/win32/libdns.vcxproj.filters.in
index e2244c56dd..674f2514c3 100644
--- a/lib/dns/win32/libdns.vcxproj.filters.in
+++ b/lib/dns/win32/libdns.vcxproj.filters.in
@@ -309,6 +309,9 @@
Dst Source Files
+
+ Dst Source Files
+
Dst Source Files
@@ -329,6 +332,9 @@
Dst Source Files
+
+ Dst Source Files
+
Dst Source Files
diff --git a/lib/dns/win32/libdns.vcxproj.in b/lib/dns/win32/libdns.vcxproj.in
index 1308f58f6f..502a58d7ec 100644
--- a/lib/dns/win32/libdns.vcxproj.in
+++ b/lib/dns/win32/libdns.vcxproj.in
@@ -163,6 +163,7 @@
+
@@ -174,6 +175,7 @@
+
@END PKCS11
diff --git a/lib/isc/hmacmd5.c b/lib/isc/hmacmd5.c
index 1b812933a6..3002ce56fb 100644
--- a/lib/isc/hmacmd5.c
+++ b/lib/isc/hmacmd5.c
@@ -95,8 +95,19 @@ isc_hmacmd5_init(isc_hmacmd5_t *ctx, const unsigned char *key,
{ CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
{ CKA_VALUE, NULL, (CK_ULONG) len }
};
+#ifdef PK11_PAD_HMAC_KEYS
+ CK_BYTE keypad[ISC_MD5_DIGESTLENGTH];
+ if (len < ISC_MD5_DIGESTLENGTH) {
+ memset(keypad, 0, ISC_MD5_DIGESTLENGTH);
+ memmove(keypad, key, len);
+ keyTemplate[5].pValue = keypad;
+ keyTemplate[5].ulValueLen = ISC_MD5_DIGESTLENGTH;
+ } else
+ DE_CONST(key, keyTemplate[5].pValue);
+#else
DE_CONST(key, keyTemplate[5].pValue);
+#endif
RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, ISC_TRUE, ISC_FALSE,
ISC_FALSE, NULL, 0) == ISC_R_SUCCESS);
ctx->object = CK_INVALID_HANDLE;
diff --git a/lib/isc/hmacsha.c b/lib/isc/hmacsha.c
index c132aa2fdf..5cf8ec0a42 100644
--- a/lib/isc/hmacsha.c
+++ b/lib/isc/hmacsha.c
@@ -265,8 +265,19 @@ isc_hmacsha1_init(isc_hmacsha1_t *ctx, const unsigned char *key,
{ CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
{ CKA_VALUE, NULL, (CK_ULONG) len }
};
+#ifdef PK11_PAD_HMAC_KEYS
+ CK_BYTE keypad[ISC_SHA1_DIGESTLENGTH];
+ if (len < ISC_SHA1_DIGESTLENGTH) {
+ memset(keypad, 0, ISC_SHA1_DIGESTLENGTH);
+ memmove(keypad, key, len);
+ keyTemplate[5].pValue = keypad;
+ keyTemplate[5].ulValueLen = ISC_SHA1_DIGESTLENGTH;
+ } else
+ DE_CONST(key, keyTemplate[5].pValue);
+#else
DE_CONST(key, keyTemplate[5].pValue);
+#endif
RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, ISC_TRUE, ISC_FALSE,
ISC_FALSE, NULL, 0) == ISC_R_SUCCESS);
ctx->object = CK_INVALID_HANDLE;
@@ -424,8 +435,19 @@ isc_hmacsha224_init(isc_hmacsha224_t *ctx, const unsigned char *key,
{ CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
{ CKA_VALUE, NULL, (CK_ULONG) len }
};
+#ifdef PK11_PAD_HMAC_KEYS
+ CK_BYTE keypad[ISC_SHA224_DIGESTLENGTH];
+ if (len < ISC_SHA224_DIGESTLENGTH) {
+ memset(keypad, 0, ISC_SHA224_DIGESTLENGTH);
+ memmove(keypad, key, len);
+ keyTemplate[5].pValue = keypad;
+ keyTemplate[5].ulValueLen = ISC_SHA224_DIGESTLENGTH;
+ } else
+ DE_CONST(key, keyTemplate[5].pValue);
+#else
DE_CONST(key, keyTemplate[5].pValue);
+#endif
RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, ISC_TRUE, ISC_FALSE,
ISC_FALSE, NULL, 0) == ISC_R_SUCCESS);
ctx->object = CK_INVALID_HANDLE;
@@ -583,8 +605,19 @@ isc_hmacsha256_init(isc_hmacsha256_t *ctx, const unsigned char *key,
{ CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
{ CKA_VALUE, NULL, (CK_ULONG) len }
};
+#ifdef PK11_PAD_HMAC_KEYS
+ CK_BYTE keypad[ISC_SHA256_DIGESTLENGTH];
+ if (len < ISC_SHA256_DIGESTLENGTH) {
+ memset(keypad, 0, ISC_SHA256_DIGESTLENGTH);
+ memmove(keypad, key, len);
+ keyTemplate[5].pValue = keypad;
+ keyTemplate[5].ulValueLen = ISC_SHA256_DIGESTLENGTH;
+ } else
+ DE_CONST(key, keyTemplate[5].pValue);
+#else
DE_CONST(key, keyTemplate[5].pValue);
+#endif
RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, ISC_TRUE, ISC_FALSE,
ISC_FALSE, NULL, 0) == ISC_R_SUCCESS);
ctx->object = CK_INVALID_HANDLE;
@@ -742,8 +775,19 @@ isc_hmacsha384_init(isc_hmacsha384_t *ctx, const unsigned char *key,
{ CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
{ CKA_VALUE, NULL, (CK_ULONG) len }
};
+#ifdef PK11_PAD_HMAC_KEYS
+ CK_BYTE keypad[ISC_SHA384_DIGESTLENGTH];
+ if (len < ISC_SHA384_DIGESTLENGTH) {
+ memset(keypad, 0, ISC_SHA384_DIGESTLENGTH);
+ memmove(keypad, key, len);
+ keyTemplate[5].pValue = keypad;
+ keyTemplate[5].ulValueLen = ISC_SHA384_DIGESTLENGTH;
+ } else
+ DE_CONST(key, keyTemplate[5].pValue);
+#else
DE_CONST(key, keyTemplate[5].pValue);
+#endif
RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, ISC_TRUE, ISC_FALSE,
ISC_FALSE, NULL, 0) == ISC_R_SUCCESS);
ctx->object = CK_INVALID_HANDLE;
@@ -901,8 +945,19 @@ isc_hmacsha512_init(isc_hmacsha512_t *ctx, const unsigned char *key,
{ CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
{ CKA_VALUE, NULL, (CK_ULONG) len }
};
+#ifdef PK11_PAD_HMAC_KEYS
+ CK_BYTE keypad[ISC_SHA512_DIGESTLENGTH];
+ if (len < ISC_SHA512_DIGESTLENGTH) {
+ memset(keypad, 0, ISC_SHA512_DIGESTLENGTH);
+ memmove(keypad, key, len);
+ keyTemplate[5].pValue = keypad;
+ keyTemplate[5].ulValueLen = ISC_SHA512_DIGESTLENGTH;
+ } else
+ DE_CONST(key, keyTemplate[5].pValue);
+#else
DE_CONST(key, keyTemplate[5].pValue);
+#endif
RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, ISC_TRUE, ISC_FALSE,
ISC_FALSE, NULL, 0) == ISC_R_SUCCESS);
ctx->object = CK_INVALID_HANDLE;
diff --git a/lib/isc/include/pk11/constants.h b/lib/isc/include/pk11/constants.h
index dbd1ba0b20..deb327a789 100644
--- a/lib/isc/include/pk11/constants.h
+++ b/lib/isc/include/pk11/constants.h
@@ -23,6 +23,12 @@ static CK_BYTE pk11_ecc_prime256v1[] = {
static CK_BYTE pk11_ecc_secp384r1[] = {
0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22
};
+static CK_BYTE pk11_ecc_ed25519[] = {
+ 0x06, 0x03, 0x2b, 0x65, 0x70
+};
+static CK_BYTE pk11_ecc_ed448[] = {
+ 0x06, 0x03, 0x2b, 0x65, 0x71
+};
#endif
#ifdef WANT_DH_PRIMES
diff --git a/lib/isc/include/pk11/site.h b/lib/isc/include/pk11/site.h
index 727af2e52c..b037383926 100644
--- a/lib/isc/include/pk11/site.h
+++ b/lib/isc/include/pk11/site.h
@@ -23,6 +23,9 @@
*
*\li PK11__DISABLE:
* Same as SKIP, and disable support for the algorithm.
+ *
+ *\li PK11_PAD_HMAC_KEYS:
+ * Extend HMAC keys shorter than digest length.
*/
/* current implemented flags are:
@@ -38,6 +41,7 @@ PK11_SHA512_HMAC_REPLACE
PK11_MD5_DISABLE
PK11_DSA_DISABLE
PK11_DH_DISABLE
+PK11_PAD_HMAC_KEYS
*/
/*
@@ -66,8 +70,11 @@ PK11_DH_DISABLE
#endif
#if PK11_FLAVOR == PK11_SOFTHSMV1_FLAVOR
-#define PK11_DH_DISABLE
-#define PK11_DSA_DISABLE
+#define PK11_PAD_HMAC_KEYS
+#endif
+
+#if PK11_FLAVOR == PK11_SOFTHSMV2_FLAVOR
+/* SoftHSMv2 was updated to enforce minimal key sizes... argh! */
#define PK11_MD5_HMAC_REPLACE
#define PK11_SHA_1_HMAC_REPLACE
#define PK11_SHA224_HMAC_REPLACE
@@ -76,9 +83,6 @@ PK11_DH_DISABLE
#define PK11_SHA512_HMAC_REPLACE
#endif
-#if PK11_FLAVOR == PK11_SOFTHSMV2_FLAVOR
-#endif
-
#if PK11_FLAVOR == PK11_CRYPTECH_FLAVOR
#define PK11_DH_DISABLE
#define PK11_DSA_DISABLE
diff --git a/lib/isc/include/pkcs11/Makefile.in b/lib/isc/include/pkcs11/Makefile.in
index e5f17d3c58..0bf5060a27 100644
--- a/lib/isc/include/pkcs11/Makefile.in
+++ b/lib/isc/include/pkcs11/Makefile.in
@@ -17,7 +17,7 @@ VERSION=@BIND9_VERSION@
# machine generated. The latter are handled specially in the
# install target below.
#
-HEADERS = pkcs11f.h pkcs11.h pkcs11t.h
+HEADERS = pkcs11f.h pkcs11.h pkcs11t.h eddsa.h
SUBDIRS =
TARGETS =
diff --git a/lib/isc/include/pkcs11/eddsa.h b/lib/isc/include/pkcs11/eddsa.h
new file mode 100644
index 0000000000..e43b3d5c13
--- /dev/null
+++ b/lib/isc/include/pkcs11/eddsa.h
@@ -0,0 +1,22 @@
+#ifndef _EDDSA_H_
+#define _EDDSA_H_ 1
+
+#ifndef CKK_EDDSA
+#ifdef PK11_SOFTHSMV2_FLAVOR
+#define CKK_EDDSA 0x00008003UL
+#endif
+#endif
+
+#ifndef CKM_EDDSA_KEY_PAIR_GEN
+#ifdef PK11_SOFTHSMV2_FLAVOR
+#define CKM_EDDSA_KEY_PAIR_GEN 0x00009040UL
+#endif
+#endif
+
+#ifndef CKM_EDDSA
+#ifdef PK11_SOFTHSMV2_FLAVOR
+#define CKM_EDDSA 0x00009041UL
+#endif
+#endif
+
+#endif /* _EDDSA_H_ */
diff --git a/lib/isc/pk11.c b/lib/isc/pk11.c
index 31c9a390a3..a7347d1d2d 100644
--- a/lib/isc/pk11.c
+++ b/lib/isc/pk11.c
@@ -30,6 +30,7 @@
#include
#include
+#include
/* was 32 octets, Petr Spacek suggested 1024, SoftHSMv2 uses 256... */
#ifndef PINLEN
@@ -871,12 +872,33 @@ scan_slots(void) {
PK11_TRACEM(CKM_GOSTR3410_WITH_GOSTR3411);
}
if (bad)
- goto try_aes;
+ goto try_eddsa;
token->operations |= 1 << OP_GOST;
if (best_gost_token == NULL)
best_gost_token = token;
+ try_eddsa:
+#if defined(CKM_EDDSA_KEY_PAIR_GEN) && defined(CKM_EDDSA) && defined(CKK_EDDSA)
+ bad = ISC_FALSE;
+ rv = pkcs_C_GetMechanismInfo(slot, CKM_EDDSA_KEY_PAIR_GEN,
+ &mechInfo);
+ if ((rv != CKR_OK) ||
+ ((mechInfo.flags & CKF_GENERATE_KEY_PAIR) == 0)) {
+ bad = ISC_TRUE;
+ PK11_TRACEM(CKM_EDDSA_KEY_PAIR_GEN);
+ }
+ rv = pkcs_C_GetMechanismInfo(slot, CKM_EDDSA, &mechInfo);
+ if ((rv != CKR_OK) ||
+ ((mechInfo.flags & CKF_SIGN) == 0) ||
+ ((mechInfo.flags & CKF_VERIFY) == 0)) {
+ bad = ISC_TRUE;
+ PK11_TRACEM(CKM_EDDSA);
+ }
+ if (bad)
+ goto try_aes;
+
try_aes:
+#endif
bad = ISC_FALSE;
rv = pkcs_C_GetMechanismInfo(slot, CKM_AES_ECB, &mechInfo);
if ((rv != CKR_OK) || ((mechInfo.flags & CKF_ENCRYPT) == 0)) {
diff --git a/win32utils/Configure b/win32utils/Configure
index 442b675907..b6b0ff5f43 100644
--- a/win32utils/Configure
+++ b/win32utils/Configure
@@ -406,9 +406,13 @@ my @substdefh = ("AES_CC",
"HAVE_OPENSSL_AES",
"HAVE_OPENSSL_DSA",
"HAVE_OPENSSL_ECDSA",
+ "HAVE_OPENSSL_ED25519",
+ "HAVE_OPENSSL_ED448",
"HAVE_OPENSSL_EVP_AES",
"HAVE_OPENSSL_GOST",
"HAVE_PKCS11_ECDSA",
+ "HAVE_PKCS11_ED25519",
+ "HAVE_PKCS11_ED448",
"HAVE_PKCS11_GOST",
"HAVE_READLINE",
"HAVE_ZLIB",
@@ -569,6 +573,7 @@ my @withlist = ("aes",
"cc-alg",
"cross-compile",
"ecdsa",
+ "eddsa",
"extra-tests",
"gssapi",
"geoip",
@@ -629,6 +634,7 @@ my @help = (
" with-openssl[=PATH] build with OpenSSL yes|no|path\n",
" with-pkcs11[=PATH] build with PKCS#11 support yes|no|provider-path\n",
" with-ecdsa crypto ECDSA\n",
+" with-eddsa crypto EDDSA yes|all|no\n",
" with-gost[=ENC] crypto GOST yes|no|raw|ans1\n",
" with-aes crypto AES\n",
" with-cc-alg choose the algorithm for cookies aes|sha1|sha256\n",
@@ -673,6 +679,8 @@ my $openssl_path = "..\\..\\";
my $use_pkcs11 = "no";
my $pkcs11_path = "unknown";
my $use_ecdsa = "auto";
+my $use_eddsa = "auto";
+my $use_ed448 = "auto";
my $use_gost = "auto";
my $gost_encoding = "raw";
my $use_aes = "auto";
@@ -753,19 +761,19 @@ if ($legacy_only && ($want_x64 ne "yes")) {
}
if ($want_checkfiles eq "yes") {
- foreach (@filelist) {
- next if -r $_ . ".in";
- s/\\/\//g;
- next if -r $_ . ".in";
- print "missing $_.in from filelist\n";
- }
- foreach (@projectlist) {
- next if -r $_ . ".in";
- s/\\/\//g;
- next if -r $_ . ".in";
- print "missing $_.in from projectlist\n";
- }
- exit(0);
+ foreach (@filelist) {
+ next if -r $_ . ".in";
+ s/\\/\//g;
+ next if -r $_ . ".in";
+ print "missing $_.in from filelist\n";
+ }
+ foreach (@projectlist) {
+ next if -r $_ . ".in";
+ s/\\/\//g;
+ next if -r $_ . ".in";
+ print "missing $_.in from projectlist\n";
+ }
+ exit(0);
}
# configure the platform
@@ -966,10 +974,19 @@ sub mywith {
} elsif ($val =~ /^yes$/i) {
$use_ecdsa = "yes";
}
+ } elsif ($key =~ /^eddsa$/i) {
+ if ($val =~ /^no$/i) {
+ $use_eddsa = "no";
+ } elsif ($val !~ /^no$/i) {
+ $use_eddsa = "yes";
+ if ($val =~ /^all$/i) {
+ $use_ed448 = "yes";
+ }
+ }
} elsif ($key =~ /^gost$/i) {
if ($val =~ /^no$/i) {
$use_gost = "no";
- } elsif ($val =~ /^yes$/i) {
+ } elsif ($val !~ /^no$/i) {
$use_gost = "yes";
$gost_encoding = $val;
}
@@ -1204,6 +1221,16 @@ if ($verbose) {
} else {
print "ecdsa: enabled\n";
}
+ if ($use_eddsa eq "no") {
+ print "eddsa: disabled\n";
+ } else {
+ print "ed25519: enabled\n";
+ if ($use_ed448 eq "no") {
+ print "ed448: disabled\n";
+ } else {
+ print "ed448: enabled\n";
+ }
+ }
if ($use_gost eq "no") {
print "gost: disabled\n";
} else {
@@ -1497,6 +1524,26 @@ if ($enable_native_pkcs11 eq "yes") {
}
$configdefh{"HAVE_PKCS11_ECDSA"} = 1;
}
+ if ($use_eddsa eq "no") {
+ if ($verbose) {
+ print "no EDDSA support in native PKCS#11\n";
+ }
+ } else {
+ if ($verbose) {
+ print "enabled Ed25519 support in native PKCS#11\n";
+ }
+ $configdefh{"HAVE_PKCS11_ED25519"} = 1;
+ if ($use_ed448 eq "no") {
+ if ($verbose) {
+ print "no Ed448 support in native PKCS#11\n";
+ }
+ } else {
+ if ($verbose) {
+ print "enabled Ed448 support in native PKCS#11\n";
+ }
+ $configdefh{"HAVE_PKCS11_ED448"} = 1;
+ }
+ }
if ($use_gost eq "no") {
if ($verbose) {
print "no GOST support in native PKCS#11\n";
@@ -1831,6 +1878,7 @@ EOF
if ($verbose) {
print "EVP_sha512 test failed: disabling EVP_sha512\n";
}
+ $use_eddsa = "no";
} else {
$configdefh{"HAVE_EVP_SHA512"} = 1;
}
@@ -1839,6 +1887,7 @@ EOF
print "can't compile EVP_sha512 test: $compret\n";
print "disabling EVP_sha512\n";
}
+ $use_eddsa = "no";
}
}
@@ -1893,6 +1942,104 @@ if ($use_ecdsa ne "no") {
$configdefh{"HAVE_OPENSSL_ECDSA"} = 1;
}
+# with-eddsa
+if ($use_openssl eq "no") {
+ $use_eddsa = "no";
+}
+if ($use_eddsa eq "auto") {
+ if ($verbose) {
+ print "checking for OpenSSL ED25519 support\n";
+ }
+ open F, ">tested25519.c" || die $!;
+ print F << 'EOF';
+#include
+#include
+
+int
+main(void)
+{
+ EVP_PKEY_CTX *ctx;
+
+ ctx = EVP_PKEY_CTX_new_id(NID_ED25519, NULL);
+ if (ctx == NULL)
+ return (2);
+ return (0);
+}
+EOF
+ close F;
+ my $include = $configinc{"OPENSSL_INC"};
+ my $library = $configlib{"OPENSSL_LIB"};
+ $compret = `cl /nologo /MD /I "$include" tested25519.c "$library"`;
+ if (grep { -f and -x } ".\\tested25519.exe") {
+ `.\\tested25519.exe`;
+ if ($? != 0) {
+ if ($verbose) {
+ print "EDDSA test failed: disabling EDDSA\n";
+ }
+ $use_eddsa = "no";
+ }
+ } else {
+ if ($verbose) {
+ print "can't compile EDDSA test: $compret\n";
+ print "disabling EDDSA\n";
+ }
+ $use_eddsa = "no";
+ }
+}
+
+if ($use_eddsa ne "no") {
+ $use_eddsa = "yes";
+ $configdefh{"HAVE_OPENSSL_ED25519"} = 1;
+} else {
+ $use_ed448 = "no";
+}
+
+if ($use_ed448 eq "auto") {
+ if ($verbose) {
+ print "checking for OpenSSL ED448 support\n";
+ }
+ open F, ">tested448.c" || die $!;
+ print F << 'EOF';
+#include
+#include
+
+int
+main(void)
+{
+ EVP_PKEY_CTX *ctx;
+
+ ctx = EVP_PKEY_CTX_new_id(NID_ED448, NULL);
+ if (ctx == NULL)
+ return (2);
+ return (0);
+}
+EOF
+ close F;
+ my $include = $configinc{"OPENSSL_INC"};
+ my $library = $configlib{"OPENSSL_LIB"};
+ $compret = `cl /nologo /MD /I "$include" tested448.c "$library"`;
+ if (grep { -f and -x } ".\\tested448.exe") {
+ `.\\tested448.exe`;
+ if ($? != 0) {
+ if ($verbose) {
+ print "ED448 test failed: disabling ED448\n";
+ }
+ $use_ed448 = "no";
+ }
+ } else {
+ if ($verbose) {
+ print "can't compile ED448 test: $compret\n";
+ print "disabling ED448\n";
+ }
+ $use_ed448 = "no";
+ }
+}
+
+if ($use_ed448 ne "no") {
+ $use_ed448 = "yes";
+ $configdefh{"HAVE_OPENSSL_ED448"} = 1;
+}
+
# with-gost
if ($use_openssl eq "no") {
$use_gost = "no";
@@ -3425,6 +3572,7 @@ exit 0;
# --with-openssl supported
# --with-pkcs11 supported
# --with-ecdsa supported
+# --with-eddsa supported
# --with-gost supported
# --with-aes supported
# --with-cc-alg supported