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