]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Added Ed25519 support (#44696)
authorFrancis Dupont <fdupont@isc.org>
Mon, 31 Jul 2017 13:26:00 +0000 (15:26 +0200)
committerFrancis Dupont <fdupont@isc.org>
Mon, 31 Jul 2017 13:26:00 +0000 (15:26 +0200)
57 files changed:
CHANGES
bin/dnssec/dnssec-keyfromlabel.c
bin/dnssec/dnssec-keyfromlabel.docbook
bin/dnssec/dnssec-keygen.c
bin/dnssec/dnssec-keygen.docbook
bin/pkcs11/pkcs11-keygen.c
bin/pkcs11/pkcs11-keygen.docbook
bin/python/isc/dnskey.py.in
bin/python/isc/policy.py.in
bin/tests/system/conf.sh.in
bin/tests/system/conf.sh.win32
bin/tests/system/eddsa/clean.sh [new file with mode: 0644]
bin/tests/system/eddsa/ns1/named.conf [new file with mode: 0644]
bin/tests/system/eddsa/ns1/root.db.in [new file with mode: 0644]
bin/tests/system/eddsa/ns1/sign.sh [new file with mode: 0644]
bin/tests/system/eddsa/ns2/Xexample.com.+015+03613.key [new file with mode: 0644]
bin/tests/system/eddsa/ns2/Xexample.com.+015+03613.private [new file with mode: 0644]
bin/tests/system/eddsa/ns2/Xexample.com.+015+35217.key [new file with mode: 0644]
bin/tests/system/eddsa/ns2/Xexample.com.+015+35217.private [new file with mode: 0644]
bin/tests/system/eddsa/ns2/example.com.db [new file with mode: 0644]
bin/tests/system/eddsa/ns2/named.conf [new file with mode: 0644]
bin/tests/system/eddsa/ns2/sign.sh [new file with mode: 0644]
bin/tests/system/eddsa/prereq.sh [new file with mode: 0644]
bin/tests/system/eddsa/setup.sh [new file with mode: 0644]
bin/tests/system/eddsa/tests.sh [new file with mode: 0644]
bin/tests/system/pkcs11/ns1/named.conf
bin/tests/system/pkcs11/prereq.sh
bin/tests/system/pkcs11/setup.sh
bin/tests/system/pkcs11/tests.sh
bin/tests/system/testcrypto.sh
config.h.in
config.h.win32
configure
configure.in
doc/rfc/rfc8080.txt [new file with mode: 0644]
lib/dns/Makefile.in
lib/dns/dst_api.c
lib/dns/dst_internal.h
lib/dns/dst_parse.c
lib/dns/dst_parse.h
lib/dns/include/dns/keyvalues.h
lib/dns/include/dst/dst.h
lib/dns/openssleddsa_link.c [new file with mode: 0644]
lib/dns/pkcs11eddsa_link.c [new file with mode: 0644]
lib/dns/rcode.c
lib/dns/win32/libdns.dsp.in
lib/dns/win32/libdns.mak.in
lib/dns/win32/libdns.vcxproj.filters.in
lib/dns/win32/libdns.vcxproj.in
lib/isc/hmacmd5.c
lib/isc/hmacsha.c
lib/isc/include/pk11/constants.h
lib/isc/include/pk11/site.h
lib/isc/include/pkcs11/Makefile.in
lib/isc/include/pkcs11/eddsa.h [new file with mode: 0644]
lib/isc/pk11.c
win32utils/Configure

diff --git a/CHANGES b/CHANGES
index dac5c45ff2fa8f65adc8e46ebd1350fd45dfd143..f3ed2409ebb55989225e3dffaeac1f87a04e6293 100644 (file)
--- 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
index 891f31fac550bfda8f670e16ff7de7480fa34c5b..53834005e0e5d352b9eb83cf6a38fe01ee93181e 100644 (file)
@@ -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);
                }
index aeaca1add29d361f57fb16a7cf008d3cec7be550..2ea188b22326bff1e4d1f031c0909805edf34339 100644 (file)
            Selects the cryptographic algorithm.  The value of
            <option>algorithm</option> 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.
          </para>
          <para>
index ac4ab8768453561bf283298411b6cdc273651cd5..1beefa987f1af915b691e1e48b826a10621a287e 100644 (file)
@@ -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 */
 
index e398de62ee9c4a3793ebac9ebeb3e50d2b184322..6c79e7f016ea9f0a3d7e7cbd5d0cf26a6a6158e6 100644 (file)
            Selects the cryptographic algorithm.  For DNSSEC keys, the value
            of <option>algorithm</option> 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
            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.
          </para>
        </listitem>
       </varlistentry>
index 75baa040522d41796611fb0bac52371da4cc25fd..fe314ab409242f5f8b778e03cbfbdc7f9b0de787 100644 (file)
@@ -73,6 +73,7 @@
 #define WANT_DH_PRIMES
 #define WANT_ECC_CURVES
 #include <pk11/constants.h>
+#include <pkcs11/eddsa.h>
 
 #if !(defined(HAVE_GETPASSPHRASE) || (defined (__SVR4) && defined (__sun)))
 #define getpassphrase(x)       getpass(x)
 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;
 
        /*
index f4ff1316e24c08b14a069be9280de8403fc9fbcb..e17c2a17fe780a33d7a61f2376a67de7bcb1deaa 100644 (file)
         <listitem>
           <para>
             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
             <option>algorithm</option> 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".
           </para>
         </listitem>
       </varlistentry>
@@ -86,7 +86,8 @@
           <para>
             Create the key pair with <option>keysize</option> 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.
           </para>
         </listitem>
       </varlistentry>
index 081ca062be44373abc11ab3ea4488184d302b69d..357fab8bdb365651f4294e7e0450722fa72dd911 100644 (file)
@@ -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
index 015fd4f098aa30f3c7a822606240e14514a7fc66..9ae3e55427e5c948506d04742e23ca341aa20bed 100644 (file)
@@ -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)
 
index 9b1d314dfeb4def635bceeba3118357581579496..5e09f5d12252aec741c5273d3a9f72087f3aa9a2 100644 (file)
@@ -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
index eea45ab36405a34042600b95323864aaf185a37f..f85723ddc5a8f8bcc056bdf2149f7532552f02df 100644 (file)
@@ -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 (file)
index 0000000..1c0eac7
--- /dev/null
@@ -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 (file)
index 0000000..80c4ea3
--- /dev/null
@@ -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 (file)
index 0000000..994113c
--- /dev/null
@@ -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 (file)
index 0000000..9d48efc
--- /dev/null
@@ -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 <<EOF
+trusted-keys {
+    "$dn" $flags $proto $alg "$key";
+};
+EOF
+' > 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 (file)
index 0000000..ff6d5bf
--- /dev/null
@@ -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 (file)
index 0000000..788b2d7
--- /dev/null
@@ -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 (file)
index 0000000..71e4620
--- /dev/null
@@ -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 (file)
index 0000000..78ec36d
--- /dev/null
@@ -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 (file)
index 0000000..e9d5303
--- /dev/null
@@ -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 (file)
index 0000000..b4e911e
--- /dev/null
@@ -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 (file)
index 0000000..19e861a
--- /dev/null
@@ -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 (file)
index 0000000..c67a067
--- /dev/null
@@ -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 (file)
index 0000000..74e3e7a
--- /dev/null
@@ -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 (file)
index 0000000..fefbff3
--- /dev/null
@@ -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
index c0df9d59bcd9b5f7894f739024e3725b53ad0b8d..e5e06b04f02bbc3bcfc4972e3d48b0302d2b07cc 100644 (file)
@@ -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; };
+};
index e365f78bf3e598ce3f9db8ab28a8ffd29e02b3c1..2b5900a27561a1dacbc2689da843e31c8459a43e 100644 (file)
@@ -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
index 850034c0c794aa641faa43afce6dc44b7cc4eb62..d81b5f97500bd054b8c98f0c1a0d6a3477eb41a8 100644 (file)
@@ -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
index a5d4a8bd1cd6575736329bca3c9e3abf4e5ac62b..fdf1663ef4248cc5033f9ef114a8c57b63e457b1 100644 (file)
@@ -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
index 2f8e59cd286a054224906bc7398d0dcb6f45b97a..8aad3e04d8680a0c3d898f822dbbc8944e6ae900 100644 (file)
@@ -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
index b7befbb5b81f8a030b221b176b0f2c514ab31897..89fdb143fa584fbc0193435034a865c1097872c4 100644 (file)
@@ -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
 
index 6f3f72484a021a25c3b1e49bb94f4e1e53786270..9d45f7ba5117a7038a24b9bbf5ea497cbf564579 100644 (file)
@@ -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@
 
index e75b6bb3250e33791e76b39fae7ca1dc0499b0bc..640d9aa6c310824dc64f8efb6b83f745a52bc2dc 100755 (executable)
--- 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 <openssl/evp.h>
+#include <openssl/objects.h>
+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 <openssl/evp.h>
+#include <openssl/objects.h>
+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)"
index 69f8bdcd749377d4fcdc715765dd28f3b006f090..50dbd40231b75926d9d11d7de54d0d42eb7b24f7 100644 (file)
@@ -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 <openssl/evp.h>
+#include <openssl/objects.h>
+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 <openssl/evp.h>
+#include <openssl/objects.h>
+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 (file)
index 0000000..631f9c1
--- /dev/null
@@ -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]
+\f
+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]
+\f
+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]
+\f
+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]
+\f
+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]
+\f
+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,
+              <http://www.rfc-editor.org/info/rfc2119>.
+
+   [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,
+              <http://www.rfc-editor.org/info/rfc4033>.
+
+   [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,
+              <http://www.rfc-editor.org/info/rfc4034>.
+
+   [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,
+              <http://www.rfc-editor.org/info/rfc4035>.
+
+   [RFC7748]  Langley, A., Hamburg, M., and S. Turner, "Elliptic Curves
+              for Security", RFC 7748, DOI 10.17487/RFC7748, January
+              2016, <http://www.rfc-editor.org/info/rfc7748>.
+
+   [RFC8032]  Josefsson, S. and I. Liusvaara, "Edwards-Curve Digital
+              Signature Algorithm (EdDSA)", RFC 8032,
+              DOI 10.17487/RFC8032, January 2017,
+              <http://www.rfc-editor.org/info/rfc8032>.
+
+
+
+
+
+
+
+
+Sury & Edmonds               Standards Track                    [Page 6]
+\f
+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, <http://www.rfc-editor.org/info/rfc5933>.
+
+   [RFC6605]  Hoffman, P. and W. Wijngaards, "Elliptic Curve Digital
+              Signature Algorithm (DSA) for DNSSEC", RFC 6605,
+              DOI 10.17487/RFC6605, April 2012,
+              <http://www.rfc-editor.org/info/rfc6605>.
+
+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]
+\f
index d243e3997c941aca0a40f74e19bc9bd3ce612e26..b29936f601ff0d5ea181c0fb03a3aa3c3e9547b7 100644 (file)
@@ -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 \
index 307aee1e5fd7effab755b1feb55cd9f5fbdc49ab..86c44fe7065ec19259f90791ba7cdb0bbcd68c66 100644 (file)
@@ -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);
index d115d1a926f553678f79e578a67ab29859d3e783..6890f186a9499c180662b289227dfef4f5e38ff8 100644 (file)
@@ -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
index 893451d5c6b18e55bac88388f0133add9506677f..c984c4ca578a0f79d1906540209cc8183c0ae4fc 100644 (file)
@@ -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;
index 1384ac681209a4b4931d134d1ed93f6106527ffa..6da8df73b18cc610457d7f572db3418f4d962d84 100644 (file)
 #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)
index af833955fbafe6134ff6017e8fceb10424dbe642..0e7e52bff0b4716f22f2a449945fe7a79723c564 100644 (file)
@@ -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 */
 #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 */
index c1191512f6612459354d9955191595bd863b6f86..d37c5c19d1f3c8761fc174d8bde8af46c49df52d 100644 (file)
@@ -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 (file)
index 0000000..58f9293
--- /dev/null
@@ -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 <config.h>
+
+#if defined(OPENSSL) && \
+    (defined(HAVE_OPENSSL_ED25519) || defined(HAVE_OPENSSL_ED448))
+
+#include <isc/entropy.h>
+#include <isc/mem.h>
+#include <isc/sha2.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <dns/keyvalues.h>
+#include <dst/result.h>
+
+#include "dst_internal.h"
+#include "dst_openssl.h"
+#include "dst_parse.h"
+
+#include <openssl/err.h>
+#include <openssl/objects.h>
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+
+#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 <isc/util.h>
+
+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 (file)
index 0000000..095bfe1
--- /dev/null
@@ -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 <config.h>
+
+#if defined(PKCS11CRYPTO) && \
+    defined(HAVE_PKCS11_ED25519) || defined(HAVE_PKCS11_ED448)
+
+#include <isc/entropy.h>
+#include <isc/mem.h>
+#include <isc/safe.h>
+#include <isc/sha2.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <dns/keyvalues.h>
+#include <dst/result.h>
+
+#include "dst_internal.h"
+#include "dst_parse.h"
+#include "dst_pkcs11.h"
+
+#include <pk11/pk11.h>
+#include <pk11/internal.h>
+#define WANT_ECC_CURVES
+#include <pk11/constants.h>
+
+#include <pkcs11/pkcs11.h>
+#include <pkcs11/eddsa.h>
+
+/*
+ * 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 <isc/util.h>
+
+EMPTY_TRANSLATION_UNIT
+
+#endif /* PKCS11CRYPTO && HAVE_PKCS11_EDxxx */
+/*! \file */
index 534f16a3c20a756b471550f1fdd418171e210214..46ab9f4045488a277b996d9d239421e88e816e76 100644 (file)
        { 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 }, \
index 186a045f0218dcc06de3ec58f1b06e3b595cbb68..51657bcbf8e3e2621c10f89dc72be618ab4311cc 100644 (file)
@@ -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
index d0d1744987b772fa041f7ffb7110a78c8825c49d..760689e6136ba5f55712b51d0541801f271d6da3 100644 (file)
@@ -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
index e2244c56ddaf1dd7ad12d9583cc7855c3ed337d9..674f2514c3a9054e10b077541760cd763f432e6b 100644 (file)
     <ClCompile Include="..\opensslecdsa_link.c">
       <Filter>Dst Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="..\openssleddsa_link.c">
+      <Filter>Dst Source Files</Filter>
+    </ClCompile>
     <ClCompile Include="..\opensslgost_link.c">
       <Filter>Dst Source Files</Filter>
     </ClCompile>
     <ClCompile Include="..\pkcs11ecdsa_link.c">
       <Filter>Dst Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="..\pkcs11eddsa_link.c">
+      <Filter>Dst Source Files</Filter>
+    </ClCompile>
     <ClCompile Include="..\pkcs11gost_link.c">
       <Filter>Dst Source Files</Filter>
     </ClCompile>
index 1308f58f6ff94a520ee8c3e7d01a19a7ffff0bd2..502a58d7ec28bc94725046b6468d035e84c8cc7b 100644 (file)
     <ClCompile Include="..\openssldh_link.c" />
     <ClCompile Include="..\openssldsa_link.c" />
     <ClCompile Include="..\opensslecdsa_link.c" />
+    <ClCompile Include="..\openssleddsa_link.c" />
     <ClCompile Include="..\opensslgost_link.c" />
     <ClCompile Include="..\opensslrsa_link.c" />
     <ClCompile Include="..\openssl_link.c" />
     <ClCompile Include="..\pkcs11dh_link.c" />
     <ClCompile Include="..\pkcs11dsa_link.c" />
     <ClCompile Include="..\pkcs11ecdsa_link.c" />
+    <ClCompile Include="..\pkcs11eddsa_link.c" />
     <ClCompile Include="..\pkcs11gost_link.c" />
     <ClCompile Include="..\pkcs11rsa_link.c" />
 @END PKCS11
index 1b812933a689b99734ea349602904fb289568f05..3002ce56fb1889cffcb702d02cefc767ea1a0d77 100644 (file)
@@ -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;
index c132aa2fdf49ea9078045bf5efd61cdb7483f6b4..5cf8ec0a4276f6e28a9520806ee27005bb1d8e29 100644 (file)
@@ -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;
index dbd1ba0b20be71842a2c06b6afa76a12a3907ad5..deb327a789d01e20170299e8112b52a19e5bf388 100644 (file)
@@ -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
index 727af2e52c0a85db712e0fc29d1e780c518b7566..b037383926ad8b509aad7742cbe6913005ce4a98 100644 (file)
@@ -23,6 +23,9 @@
  *
  *\li PK11_<algorithm>_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
index e5f17d3c589cacbe04cef5928a1d987c50699022..0bf5060a27f2b3f46f89e9819c1ffe5e8ab7aa89 100644 (file)
@@ -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 (file)
index 0000000..e43b3d5
--- /dev/null
@@ -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_ */
index 31c9a390a3395117a706d97b38b9deba8e9c6e9f..a7347d1d2d0fe72ccba6cca23dcab0144708c3d1 100644 (file)
@@ -30,6 +30,7 @@
 
 #include <pkcs11/cryptoki.h>
 #include <pkcs11/pkcs11.h>
+#include <pkcs11/eddsa.h>
 
 /* 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)) {
index 442b675907deeab0a705aa469e9e8b4435efae66..b6b0ff5f43826d0383cf6787a738b47faf9ad7d4 100644 (file)
@@ -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 <openssl/evp.h>
+#include <openssl/objects.h>
+
+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 <openssl/evp.h>
+#include <openssl/objects.h>
+
+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