]> git.ipfire.org Git - thirdparty/ldns.git/commitdiff
* Prepare for ED25519, ED448 support: todo convert* routines in
authorW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Tue, 22 Mar 2016 14:10:01 +0000 (15:10 +0100)
committerW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Tue, 22 Mar 2016 14:10:01 +0000 (15:10 +0100)
  dnssec.h, once openssl has support for signing with these algorithms.
  The dns algorithm number is not yet allocated. These features are
  not fully implemented yet.

12 files changed:
Changelog
configure.ac
dnssec.c
dnssec_sign.c
dnssec_verify.c
examples/ldns-key2ds.c
examples/ldns-keygen.c
host2str.c
keys.c
ldns/dnssec.h
ldns/keys.h
rr_functions.c

index ae2d8ff8605c7f99171f08e6c3c1e337dd65c094..451d88eb5460b9272ae2119a98909f818557c659 100644 (file)
--- a/Changelog
+++ b/Changelog
@@ -63,6 +63,10 @@ TBD
        * bugfix #726: 2 typos in drill manpage.
          Thanks Hugo Lombard
        * Add type CSYNC support, RFC 7477.
+       * Prepare for ED25519, ED448 support: todo convert* routines in
+         dnssec.h, once openssl has support for signing with these algorithms.
+         The dns algorithm number is not yet allocated. These features are
+         not fully implemented yet.
 
 1.6.17 2014-01-10
        * Fix ldns_dnssec_zone_new_frm_fp_l to allow the last parsed line of a
index b85504d1de3a9dcdca588ff09ac5059295c8655d..1d1f0e3a70ee8bb9e739cb068436d06b81101632 100644 (file)
@@ -301,7 +301,7 @@ tmp_LIBS=$LIBS
 
 ACX_WITH_SSL_OPTIONAL
 
-AC_CHECK_FUNCS([EVP_sha256 ENGINE_load_cryptodev EVP_PKEY_keygen ECDSA_SIG_get0 EVP_MD_CTX_new])
+AC_CHECK_FUNCS([EVP_sha256 ENGINE_load_cryptodev EVP_PKEY_keygen ECDSA_SIG_get0 EVP_MD_CTX_new EVP_PKEY_base_id])
 
 # for macosx, see if glibtool exists and use that
 # BSD's need to know the version...
@@ -370,11 +370,11 @@ case "$enable_dsa" in
       ;;
 esac
 
-AC_ARG_ENABLE(ed25519, AC_HELP_STRING([--enable-ed25519], [Enable ed25519 support (experimental)]))
+AC_ARG_ENABLE(ed25519, AC_HELP_STRING([--enable-ed25519], [Enable ED25519 support (experimental)]))
 case "$enable_ed25519" in
     yes)
       if test "x$HAVE_SSL" != "xyes"; then
-        AC_MSG_ERROR([DSA enabled, but no SSL support])
+        AC_MSG_ERROR([ED25519 enabled, but no SSL support])
       fi
       AC_CHECK_DECLS([NID_X25519], [], [AC_MSG_ERROR([OpenSSL does not support the EDDSA curve: please upgrade OpenSSL or rerun with --disable-ed25519])], [AC_INCLUDES_DEFAULT
 #include <openssl/evp.h>
@@ -385,6 +385,21 @@ case "$enable_ed25519" in
       ;;
 esac
 
+AC_ARG_ENABLE(ed448, AC_HELP_STRING([--enable-ed448], [Enable ED448 support (experimental)]))
+case "$enable_ed448" in
+    yes)
+      if test "x$HAVE_SSL" != "xyes"; then
+        AC_MSG_ERROR([ED448 enabled, but no SSL support])
+      fi
+      AC_CHECK_DECLS([NID_X448], [], [AC_MSG_ERROR([OpenSSL does not support the EDDSA curve: please upgrade OpenSSL or rerun with --disable-ed448])], [AC_INCLUDES_DEFAULT
+#include <openssl/evp.h>
+      ])
+      AC_DEFINE_UNQUOTED([USE_ED448], [1], [Define this to enable ED448 support.])
+      ;;
+    *|no) dnl default
+      ;;
+esac
+
 AC_ARG_ENABLE(dane, AC_HELP_STRING([--disable-dane], [Disable DANE support]))
 case "$enable_dane" in
     no)
index 2f1db653a622560e7787a8fe5d22daebd59be1aa..36119f7e25854cfdef4bf34bdad348466eed07c7 100644 (file)
--- a/dnssec.c
+++ b/dnssec.c
@@ -1883,7 +1883,8 @@ ldns_convert_ecdsa_rrsig_rdf2asn1(ldns_buffer *target_buffer,
 
         r_high = ((d[0+r_rem]&0x80)?1:0);
         s_high = ((d[bnsize+s_rem]&0x80)?1:0);
-        raw_sig_len = pre_len + r_high + bnsize - r_rem + mid_len + s_high + bnsize - s_rem;
+        raw_sig_len = pre_len + r_high + bnsize - r_rem + mid_len +
+               s_high + bnsize - s_rem;
         if(ldns_buffer_reserve(target_buffer, (size_t) raw_sig_len)) {
                 ldns_buffer_write_u8(target_buffer, pre[0]);
                 ldns_buffer_write_u8(target_buffer, raw_sig_len-2);
@@ -1903,4 +1904,69 @@ ldns_convert_ecdsa_rrsig_rdf2asn1(ldns_buffer *target_buffer,
 
 #endif /* S_SPLINT_S */
 #endif /* USE_ECDSA */
+
+#if defined(USE_ED25519) || defined(USE_ED448)
+/* debug printout routine */
+static void print_hex(const char* str, uint8_t* d, int len)
+{
+       const char hex[] = "0123456789abcdef";
+       int i;
+       printf("%s [len=%d]: ", str, len);
+       for(i=0; i<len; i++) {
+               int x = (d[i]&0xf0)>>4;
+               int y = (d[i]&0x0f);
+               printf("%c%c", hex[x], hex[y]);
+       }
+       printf("\n");
+}
+#endif
+
+#ifdef USE_ED25519
+ldns_rdf *
+ldns_convert_ed25519_rrsig_asn12rdf(const ldns_buffer *sig, long sig_len)
+{
+       unsigned char *data = (unsigned char*)ldns_buffer_begin(sig);
+        ldns_rdf* rdf = NULL;
+
+       /* TODO when Openssl supports signing and you can test this */
+       print_hex("sig in ASN", data, sig_len);
+
+        return rdf;
+}
+
+ldns_status
+ldns_convert_ed25519_rrsig_rdf2asn1(ldns_buffer *target_buffer,
+        const ldns_rdf *sig_rdf)
+{
+       /* TODO when Openssl supports signing and you can test this. */
+       /* convert sig_buf into ASN1 into the target_buffer */
+       print_hex("sig raw", ldns_rdf_data(sig_rdf), ldns_rdf_size(sig_rdf));
+        return ldns_buffer_status(target_buffer);
+}
+#endif /* USE_ED25519 */
+
+#ifdef USE_ED448
+ldns_rdf *
+ldns_convert_ed448_rrsig_asn12rdf(const ldns_buffer *sig, long sig_len)
+{
+       unsigned char *data = (unsigned char*)ldns_buffer_begin(sig);
+        ldns_rdf* rdf = NULL;
+
+       /* TODO when Openssl supports signing and you can test this */
+       print_hex("sig in ASN", data, sig_len);
+
+       return rdf;
+}
+
+ldns_status
+ldns_convert_ed448_rrsig_rdf2asn1(ldns_buffer *target_buffer,
+        const ldns_rdf *sig_rdf)
+{
+       /* TODO when Openssl supports signing and you can test this. */
+       /* convert sig_buf into ASN1 into the target_buffer */
+       print_hex("sig raw", ldns_rdf_data(sig_rdf), ldns_rdf_size(sig_rdf));
+        return ldns_buffer_status(target_buffer);
+}
+#endif /* USE_ED448 */
+
 #endif /* HAVE_SSL */
index ca5425a5ec4691b39597b51b5d1d0fd8dc169c6e..87c033e7a57dbacb45ddd9b59e2bbec465e2f52b 100644 (file)
@@ -173,6 +173,22 @@ ldns_sign_public_buffer(ldns_buffer *sign_buf, ldns_key *current_key)
                                   ldns_key_evp_key(current_key),
                                   EVP_sha384());
                 break;
+#endif
+#ifdef USE_ED25519
+        case LDNS_SIGN_ED25519:
+               b64rdf = ldns_sign_public_evp(
+                                  sign_buf,
+                                  ldns_key_evp_key(current_key),
+                                  EVP_sha512());
+                break;
+#endif
+#ifdef USE_ED448
+        case LDNS_SIGN_ED448:
+               b64rdf = ldns_sign_public_evp(
+                                  sign_buf,
+                                  ldns_key_evp_key(current_key),
+                                  EVP_sha512());
+                break;
 #endif
        case LDNS_SIGN_RSAMD5:
                b64rdf = ldns_sign_public_evp(
@@ -409,7 +425,7 @@ ldns_sign_public_evp(ldns_buffer *to_sign,
                                 const EVP_MD *digest_type)
 {
        unsigned int siglen;
-       ldns_rdf *sigdata_rdf;
+       ldns_rdf *sigdata_rdf = NULL;
        ldns_buffer *b64sig;
        EVP_MD_CTX *ctx;
        const EVP_MD *md_type;
@@ -464,29 +480,51 @@ ldns_sign_public_evp(ldns_buffer *to_sign,
                return NULL;
        }
 
-       /* unfortunately, OpenSSL output is differenct from DNS DSA format */
-#ifndef S_SPLINT_S
+       /* OpenSSL output is different, convert it */
+       r = 0;
 #ifdef USE_DSA
+       /* unfortunately, OpenSSL output is different from DNS DSA format */
        if (EVP_PKEY_type(key->type) == EVP_PKEY_DSA) {
+               r = 1;
                sigdata_rdf = ldns_convert_dsa_rrsig_asn12rdf(b64sig, siglen);
        }
 #endif
-#if defined(USE_DSA) && defined(USE_ECDSA)
-       else
-#endif
-#ifdef USE_ECDSA
-        if(EVP_PKEY_base_id(key) == EVP_PKEY_EC &&
-                ldns_pkey_is_ecdsa(key)) {
-                sigdata_rdf = ldns_convert_ecdsa_rrsig_asn1len2rdf(
-                       b64sig, siglen, ldns_pkey_is_ecdsa(key));
+#if defined(USE_ECDSA) || defined(USE_ED25519) || defined(USE_ED448)
+       if(
+#  ifdef HAVE_EVP_PKEY_BASE_ID
+               EVP_PKEY_base_id(key)
+#  else
+               EVP_PKEY_type(key->type)
+#  endif
+               == EVP_PKEY_EC) {
+#  ifdef USE_ECDSA
+                if(ldns_pkey_is_ecdsa(key)) {
+                       r = 1;
+                       sigdata_rdf = ldns_convert_ecdsa_rrsig_asn1len2rdf(
+                               b64sig, siglen, ldns_pkey_is_ecdsa(key));
+               }
+#  endif /* USE_ECDSA */
+#  ifdef USE_ED25519
+               if(EVP_PKEY_id(key) == NID_X25519) {
+                       r = 1;
+                       sigdata_rdf = ldns_convert_ed25519_rrsig_asn12rdf(
+                               b64sig, siglen);
+               }
+#  endif /* USE_ED25519 */
+#  ifdef USE_ED448
+               if(EVP_PKEY_id(key) == NID_X448) {
+                       r = 1;
+                       sigdata_rdf = ldns_convert_ed448_rrsig_asn12rdf(
+                               b64sig, siglen);
+               }
+#  endif /* USE_ED448 */
        }
-#endif
-       else {
+#endif /* PKEY_EC */
+       if(r == 0) {
                /* ok output for other types is the same */
                sigdata_rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, siglen,
                                                                         ldns_buffer_begin(b64sig));
        }
-#endif /* splint */
        ldns_buffer_free(b64sig);
        EVP_MD_CTX_destroy(ctx);
        return sigdata_rdf;
index 85f8e9baa3121467405e95ae01278e12456b2ac2..ee080e276e1ea34127bacf65d8c807c6a23d3ea9 100644 (file)
@@ -1854,6 +1854,100 @@ ldns_verify_rrsig_gost_raw(const unsigned char* sig, size_t siglen,
 }
 #endif
 
+#ifdef USE_ED25519
+EVP_PKEY*
+ldns_ed255192pkey_raw(const unsigned char* key, size_t keylen)
+{
+        const unsigned char* pp = key; /* pp gets modified by o2i() */
+        EVP_PKEY *evp_key;
+        EC_KEY *ec;
+       if(keylen != 32)
+               return NULL; /* wrong length */
+        ec = EC_KEY_new_by_curve_name(NID_X25519);
+       if(!ec) return NULL;
+        if(!o2i_ECPublicKey(&ec, &pp, (int)keylen)) {
+                EC_KEY_free(ec);
+                return NULL;
+       }
+        evp_key = EVP_PKEY_new();
+        if(!evp_key) {
+                EC_KEY_free(ec);
+                return NULL;
+        }
+        if (!EVP_PKEY_assign_EC_KEY(evp_key, ec)) {
+               EVP_PKEY_free(evp_key);
+               EC_KEY_free(ec);
+               return NULL;
+       }
+        return evp_key;
+}
+
+static ldns_status
+ldns_verify_rrsig_ed25519_raw(unsigned char* sig, size_t siglen,
+       ldns_buffer* rrset, unsigned char* key, size_t keylen)
+{
+        EVP_PKEY *evp_key;
+        ldns_status result;
+
+        evp_key = ldns_ed255192pkey_raw(key, keylen);
+        if(!evp_key) {
+               /* could not convert key */
+               return LDNS_STATUS_CRYPTO_BOGUS;
+        }
+       result = ldns_verify_rrsig_evp_raw(sig, siglen, rrset, evp_key,
+               EVP_sha512());
+       EVP_PKEY_free(evp_key);
+       return result;
+}
+#endif /* USE_ED25519 */
+
+#ifdef USE_ED448
+EVP_PKEY*
+ldns_ed4482pkey_raw(const unsigned char* key, size_t keylen)
+{
+        const unsigned char* pp = key; /* pp gets modified by o2i() */
+        EVP_PKEY *evp_key;
+        EC_KEY *ec;
+       if(keylen != 57)
+               return NULL; /* wrong length */
+        ec = EC_KEY_new_by_curve_name(NID_X448);
+       if(!ec) return NULL;
+        if(!o2i_ECPublicKey(&ec, &pp, (int)keylen)) {
+                EC_KEY_free(ec);
+                return NULL;
+       }
+        evp_key = EVP_PKEY_new();
+        if(!evp_key) {
+                EC_KEY_free(ec);
+                return NULL;
+        }
+        if (!EVP_PKEY_assign_EC_KEY(evp_key, ec)) {
+               EVP_PKEY_free(evp_key);
+               EC_KEY_free(ec);
+               return NULL;
+       }
+        return evp_key;
+}
+
+static ldns_status
+ldns_verify_rrsig_ed448_raw(unsigned char* sig, size_t siglen,
+       ldns_buffer* rrset, unsigned char* key, size_t keylen)
+{
+        EVP_PKEY *evp_key;
+        ldns_status result;
+
+        evp_key = ldns_ed4482pkey_raw(key, keylen);
+        if(!evp_key) {
+               /* could not convert key */
+               return LDNS_STATUS_CRYPTO_BOGUS;
+        }
+       result = ldns_verify_rrsig_evp_raw(sig, siglen, rrset, evp_key,
+               EVP_sha512());
+       EVP_PKEY_free(evp_key);
+       return result;
+}
+#endif /* USE_ED448 */
+
 #ifdef USE_ECDSA
 EVP_PKEY*
 ldns_ecdsa2pkey_raw(const unsigned char* key, size_t keylen, uint8_t algo)
@@ -1981,6 +2075,18 @@ ldns_verify_rrsig_buffers_raw(unsigned char* sig, size_t siglen,
                return ldns_verify_rrsig_ecdsa_raw(sig, siglen, verify_buf,
                        key, keylen, algo);
                break;
+#endif
+#ifdef USE_ED25519
+       case LDNS_ED25519:
+               return ldns_verify_rrsig_ed25519_raw(sig, siglen, verify_buf,
+                       key, keylen);
+               break;
+#endif
+#ifdef USE_ED448
+       case LDNS_ED448:
+               return ldns_verify_rrsig_ed448_raw(sig, siglen, verify_buf,
+                       key, keylen);
+               break;
 #endif
        case LDNS_RSAMD5:
                return ldns_verify_rrsig_rsamd5_raw(sig,
@@ -2122,6 +2228,32 @@ ldns_rrsig2rawsig_buffer(ldns_buffer* rawsig_buf, const ldns_rr* rrsig)
                        return LDNS_STATUS_MEM_ERR;
                 }
                 break;
+#endif
+#ifdef USE_ED25519
+       case LDNS_ED25519:
+                /* EVP produces an ASN prefix on the signature, which is
+                 * not used in the DNS */
+               if (ldns_rr_rdf(rrsig, 8) == NULL) {
+                       return LDNS_STATUS_MISSING_RDATA_FIELDS_RRSIG;
+               }
+               if (ldns_convert_ed25519_rrsig_rdf2asn1(
+                       rawsig_buf, ldns_rr_rdf(rrsig, 8)) != LDNS_STATUS_OK) {
+                       return LDNS_STATUS_MEM_ERR;
+                }
+               break;
+#endif
+#ifdef USE_ED448
+       case LDNS_ED448:
+                /* EVP produces an ASN prefix on the signature, which is
+                 * not used in the DNS */
+               if (ldns_rr_rdf(rrsig, 8) == NULL) {
+                       return LDNS_STATUS_MISSING_RDATA_FIELDS_RRSIG;
+               }
+               if (ldns_convert_ed448_rrsig_rdf2asn1(
+                       rawsig_buf, ldns_rr_rdf(rrsig, 8)) != LDNS_STATUS_OK) {
+                       return LDNS_STATUS_MEM_ERR;
+                }
+               break;
 #endif
        case LDNS_DH:
        case LDNS_ECC:
index 9426f685929b6fbb2368e031c713ae2172ca3633..be1f8c654ac1df08ec90a04071e16caa46651a34 100644 (file)
@@ -62,6 +62,14 @@ suitable_hash(ldns_signing_algorithm algorithm)
                return LDNS_SHA256;
        case LDNS_SIGN_ECDSAP384SHA384:
                return LDNS_SHA384;
+#endif
+#ifdef USE_ED25519
+       case LDNS_SIGN_ED25519:
+               return LDNS_SHA256;
+#endif
+#ifdef USE_ED448
+       case LDNS_SIGN_ED448:
+               return LDNS_SHA256;
 #endif
        default: break;
        }
index b5f576ed05ad3202b5199ac588f1a02712ddddc8..292fc21efb6f924a1c08c86626a0b3c68d691f65 100644 (file)
@@ -217,6 +217,12 @@ main(int argc, char *argv[])
                ds = ldns_key_rr2ds(pubkey, LDNS_SHA384);
                break;
        case LDNS_SIGN_ECDSAP256SHA256:
+#endif
+#ifdef USE_ED25519
+       case LDNS_SIGN_ED25519:
+#endif
+#ifdef USE_ED448
+       case LDNS_SIGN_ED448:
 #endif
        case LDNS_SIGN_RSASHA256:
        case LDNS_SIGN_RSASHA512:
index 3445254a2e6486fe48c85ec6ef5ef5650f4298c7..00de4cd286c24344fdbab383e7a50b495868b007 100644 (file)
@@ -56,6 +56,12 @@ ldns_lookup_table ldns_algorithms[] = {
 #ifdef USE_ECDSA
         { LDNS_ECDSAP256SHA256, "ECDSAP256SHA256"},
         { LDNS_ECDSAP384SHA384, "ECDSAP384SHA384"},
+#endif
+#ifdef USE_ED25519
+       { LDNS_ED25519, "ED25519"},
+#endif
+#ifdef USE_ED448
+       { LDNS_ED448, "ED448"},
 #endif
         { LDNS_INDIRECT, "INDIRECT" },
         { LDNS_PRIVATEDNS, "PRIVATEDNS" },
@@ -2284,6 +2290,60 @@ ldns_key2buffer_str(ldns_buffer *output, const ldns_key *k)
                                goto error;
 #endif /* ECDSA */
                                 break;
+#ifdef USE_ED25519
+                       case LDNS_SIGN_ED25519:
+                                ldns_buffer_printf(output, "Private-key-format: v1.2\n");
+                               ldns_buffer_printf(output, "Algorithm: %d (", ldns_key_algorithm(k));
+                                status=ldns_algorithm2buffer_str(output, (ldns_algorithm)ldns_key_algorithm(k));
+                               ldns_buffer_printf(output, ")\n");
+                                ldns_buffer_printf(output, "PrivateKey: ");
+                               if(k->_key.key) {
+                                        EC_KEY* ec = EVP_PKEY_get1_EC_KEY(k->_key.key);
+                                        const BIGNUM* b = EC_KEY_get0_private_key(ec);
+                                        i = (uint16_t)BN_bn2bin(b, bignum);
+                                        if (i > LDNS_MAX_KEYLEN) {
+                                                goto error;
+                                        }
+                                        b64_bignum =  ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, i, bignum);
+                                        if (ldns_rdf2buffer_str(output, b64_bignum) != LDNS_STATUS_OK) {
+                                               ldns_rdf_deep_free(b64_bignum);
+                                                goto error;
+                                        }
+                                        ldns_rdf_deep_free(b64_bignum);
+                                        /* down reference count in EC_KEY
+                                         * its still assigned to the PKEY */
+                                        EC_KEY_free(ec);
+                               }
+                               ldns_buffer_printf(output, "\n");
+                               break;
+#endif /* USE_ED25519 */
+#ifdef USE_ED448
+                       case LDNS_SIGN_ED448:
+                                ldns_buffer_printf(output, "Private-key-format: v1.2\n");
+                               ldns_buffer_printf(output, "Algorithm: %d (", ldns_key_algorithm(k));
+                                status=ldns_algorithm2buffer_str(output, (ldns_algorithm)ldns_key_algorithm(k));
+                               ldns_buffer_printf(output, ")\n");
+                                ldns_buffer_printf(output, "PrivateKey: ");
+                               if(k->_key.key) {
+                                        EC_KEY* ec = EVP_PKEY_get1_EC_KEY(k->_key.key);
+                                        const BIGNUM* b = EC_KEY_get0_private_key(ec);
+                                        i = (uint16_t)BN_bn2bin(b, bignum);
+                                        if (i > LDNS_MAX_KEYLEN) {
+                                                goto error;
+                                        }
+                                        b64_bignum =  ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, i, bignum);
+                                        if (ldns_rdf2buffer_str(output, b64_bignum) != LDNS_STATUS_OK) {
+                                               ldns_rdf_deep_free(b64_bignum);
+                                                goto error;
+                                        }
+                                        ldns_rdf_deep_free(b64_bignum);
+                                        /* down reference count in EC_KEY
+                                         * its still assigned to the PKEY */
+                                        EC_KEY_free(ec);
+                               }
+                               ldns_buffer_printf(output, "\n");
+                               break;
+#endif /* USE_ED448 */
                        case LDNS_SIGN_HMACMD5:
                                /* there's not much of a format defined for TSIG */
                                /* It's just a binary blob, Same for all algorithms */
diff --git a/keys.c b/keys.c
index fcf29883f281b6eaec3c6ba3dfec5cdb59b6a71a..7ec01ad2d383468dc37c410c984fdf1d9de7cbcf 100644 (file)
--- a/keys.c
+++ b/keys.c
@@ -35,6 +35,12 @@ ldns_lookup_table ldns_signing_algorithms[] = {
         { LDNS_SIGN_ECDSAP256SHA256, "ECDSAP256SHA256" },
         { LDNS_SIGN_ECDSAP384SHA384, "ECDSAP384SHA384" },
 #endif
+#ifdef USE_ED25519
+       { LDNS_SIGN_ED25519, "ED25519" },
+#endif
+#ifdef USE_ED448
+       { LDNS_SIGN_ED448, "ED448" },
+#endif
 #ifdef USE_DSA
         { LDNS_SIGN_DSA, "DSA" },
         { LDNS_SIGN_DSA_NSEC3, "DSA-NSEC3-SHA1" },
@@ -246,7 +252,7 @@ ldns_key_new_frm_fp_ecdsa_l(FILE* fp, ldns_algorithm alg, int* line_nr)
         BIGNUM* bn;
         EVP_PKEY* evp_key;
         EC_KEY* ec;
-       if (ldns_fget_keyword_data_l(fp, "PrivateKey", ": ", token, "\n", 
+       if (ldns_fget_keyword_data_l(fp, "PrivateKey", ": ", token, "\n",
                sizeof(token), line_nr) == -1)
                return NULL;
        if(ldns_str2rdf_b64(&b64rdf, token) != LDNS_STATUS_OK)
@@ -288,7 +294,159 @@ ldns_key_new_frm_fp_ecdsa_l(FILE* fp, ldns_algorithm alg, int* line_nr)
         return evp_key;
 }
 #endif
-       
+
+#ifdef USE_ED25519
+/** turn private key buffer into EC_KEY structure */
+static EC_KEY*
+ldns_ed25519_priv_raw(uint8_t* pkey, int plen)
+{
+       const unsigned char* pp;
+       uint8_t buf[256];
+       int buflen = 0;
+       uint8_t pre[] = {0x30, 0x32, 0x02, 0x01, 0x01, 0x04, 0x20};
+       int pre_len = 7;
+       uint8_t post[] = {0xa0, 0x0b, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04,
+               0x01, 0xda, 0x47, 0x0f, 0x01};
+       int post_len = 13;
+       int i;
+       /* ASN looks like this for ED25519
+        * 30320201010420 <32byteskey>
+        * andparameters a00b06092b06010401da470f01
+        * (noparameters, preamble is 30250201010420).
+        * the key is reversed (little endian).
+        */
+       buflen = pre_len + plen + post_len;
+       if((size_t)buflen > sizeof(buf))
+               return NULL;
+       memmove(buf, pre, pre_len);
+       /* reverse the pkey into the buf */
+       for(i=0; i<plen; i++)
+               buf[pre_len+i] = pkey[plen-1-i];
+       memmove(buf+pre_len+plen, post, post_len);
+       pp = buf;
+       return d2i_ECPrivateKey(NULL, &pp, buflen);
+}
+
+/** read ED25519 private key */
+static EVP_PKEY*
+ldns_key_new_frm_fp_ed25519_l(FILE* fp, int* line_nr)
+{
+       char token[16384];
+        ldns_rdf* b64rdf = NULL;
+        EVP_PKEY* evp_key;
+        EC_KEY* ec;
+       if (ldns_fget_keyword_data_l(fp, "PrivateKey", ": ", token, "\n",
+               sizeof(token), line_nr) == -1)
+               return NULL;
+       if(ldns_str2rdf_b64(&b64rdf, token) != LDNS_STATUS_OK)
+               return NULL;
+
+       /* we use d2i_ECPrivateKey because it calculates the public key
+        * from the private part, which others, EC_KEY_set_private_key,
+        * and o2i methods, do not do */
+       /* for that the private key has to be encoded in ASN1 notation
+        * with a X25519 prefix on it */
+
+       ec = ldns_ed25519_priv_raw(ldns_rdf_data(b64rdf),
+               (int)ldns_rdf_size(b64rdf));
+       ldns_rdf_deep_free(b64rdf);
+       if(!ec) return NULL;
+       if(EC_GROUP_get_curve_name(EC_KEY_get0_group(ec)) != NID_X25519) {
+               /* wrong group, bad asn conversion */
+                EC_KEY_free(ec);
+               return NULL;
+       }
+
+        evp_key = EVP_PKEY_new();
+        if(!evp_key) {
+                EC_KEY_free(ec);
+                return NULL;
+        }
+        if (!EVP_PKEY_assign_EC_KEY(evp_key, ec)) {
+               EVP_PKEY_free(evp_key);
+                EC_KEY_free(ec);
+                return NULL;
+       }
+        return evp_key;
+}
+#endif
+
+#ifdef USE_ED448
+/** turn private key buffer into EC_KEY structure */
+static EC_KEY*
+ldns_ed448_priv_raw(uint8_t* pkey, int plen)
+{
+       const unsigned char* pp;
+       uint8_t buf[256];
+       int buflen = 0;
+       uint8_t pre[] = {0x30, 0x4b, 0x02, 0x01, 0x01, 0x04, 0x39};
+       int pre_len = 7;
+       uint8_t post[] = {0xa0, 0x0b, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04,
+               0x01, 0xda, 0x47, 0x0f, 0x02};
+       int post_len = 13;
+       int i;
+       /* ASN looks like this for ED25519
+        * And for ED448, the parameters are ...02 instead of ...01
+        * For ED25519 it was:
+        * 30320201010420 <32byteskey>
+        * andparameters a00b06092b06010401da470f01
+        * (noparameters, preamble is 30250201010420).
+        * the key is reversed (little endian).
+        *
+        * For ED448 the key is 57 bytes, and that changes lengths.
+        * 304b0201010439 <57bytekey> a00b06092b06010401da470f02
+        */
+       buflen = pre_len + plen + post_len;
+       if((size_t)buflen > sizeof(buf))
+               return NULL;
+       memmove(buf, pre, pre_len);
+       /* reverse the pkey into the buf */
+       for(i=0; i<plen; i++)
+               buf[pre_len+i] = pkey[plen-1-i];
+       memmove(buf+pre_len+plen, post, post_len);
+       pp = buf;
+       return d2i_ECPrivateKey(NULL, &pp, buflen);
+}
+
+/** read ED448 private key */
+static EVP_PKEY*
+ldns_key_new_frm_fp_ed448_l(FILE* fp, int* line_nr)
+{
+       char token[16384];
+        ldns_rdf* b64rdf = NULL;
+        EVP_PKEY* evp_key;
+        EC_KEY* ec;
+       if (ldns_fget_keyword_data_l(fp, "PrivateKey", ": ", token, "\n", 
+               sizeof(token), line_nr) == -1)
+               return NULL;
+       if(ldns_str2rdf_b64(&b64rdf, token) != LDNS_STATUS_OK)
+               return NULL;
+
+       /* convert private key into ASN notation and then convert that */
+       ec = ldns_ed448_priv_raw(ldns_rdf_data(b64rdf),
+               (int)ldns_rdf_size(b64rdf));
+       ldns_rdf_deep_free(b64rdf);
+       if(!ec) return NULL;
+       if(EC_GROUP_get_curve_name(EC_KEY_get0_group(ec)) != NID_X448) {
+               /* wrong group, bad asn conversion */
+                EC_KEY_free(ec);
+               return NULL;
+       }
+
+        evp_key = EVP_PKEY_new();
+        if(!evp_key) {
+                EC_KEY_free(ec);
+                return NULL;
+        }
+        if (!EVP_PKEY_assign_EC_KEY(evp_key, ec)) {
+               EVP_PKEY_free(evp_key);
+                EC_KEY_free(ec);
+                return NULL;
+       }
+       return evp_key;
+}
+#endif
+
 ldns_status
 ldns_key_new_frm_fp_l(ldns_key **key, FILE *fp, int *line_nr)
 {
@@ -430,6 +588,26 @@ ldns_key_new_frm_fp_l(ldns_key **key, FILE *fp, int *line_nr)
                fprintf(stderr, "Warning: ECDSA not compiled into this ");
                fprintf(stderr, "version of ldns, use --enable-ecdsa\n");
 # endif
+#endif
+        }
+       if (strncmp(d, "15 ED25519", 3) == 0) {
+#ifdef USE_ED25519
+                alg = LDNS_SIGN_ED25519;
+#else
+# ifdef STDERR_MSGS
+               fprintf(stderr, "Warning: ED25519 not compiled into this ");
+               fprintf(stderr, "version of ldns, use --enable-ed25519\n");
+# endif
+#endif
+        }
+       if (strncmp(d, "16 ED448", 3) == 0) {
+#ifdef USE_ED448
+                alg = LDNS_SIGN_ED448;
+#else
+# ifdef STDERR_MSGS
+               fprintf(stderr, "Warning: ED448 not compiled into this ");
+               fprintf(stderr, "version of ldns, use --enable-ed448\n");
+# endif
 #endif
         }
        if (strncmp(d, "157 HMAC-MD5", 4) == 0) {
@@ -520,6 +698,32 @@ ldns_key_new_frm_fp_l(ldns_key **key, FILE *fp, int *line_nr)
                        }
 #endif /* splint */
                        break;
+#endif
+#ifdef USE_ED25519
+               case LDNS_SIGN_ED25519:
+                        ldns_key_set_algorithm(k, alg);
+                        ldns_key_set_evp_key(k,
+                                ldns_key_new_frm_fp_ed25519_l(fp, line_nr));
+#ifndef S_SPLINT_S
+                       if(!k->_key.key) {
+                               ldns_key_free(k);
+                               return LDNS_STATUS_ERR;
+                       }
+#endif /* splint */
+                       break;
+#endif
+#ifdef USE_ED448
+               case LDNS_SIGN_ED448:
+                        ldns_key_set_algorithm(k, alg);
+                        ldns_key_set_evp_key(k,
+                                ldns_key_new_frm_fp_ed448_l(fp, line_nr));
+#ifndef S_SPLINT_S
+                       if(!k->_key.key) {
+                               ldns_key_free(k);
+                               return LDNS_STATUS_ERR;
+                       }
+#endif /* splint */
+                       break;
 #endif
                default:
                        ldns_key_free(k);
@@ -1008,6 +1212,62 @@ ldns_key_new_frm_algorithm(ldns_signing_algorithm alg, uint16_t size)
                        return NULL;
 #endif /* ECDSA */
                        break;
+#ifdef USE_ED25519
+               case LDNS_SIGN_ED25519:
+#ifdef HAVE_EVP_PKEY_KEYGEN
+                       ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
+                       if(!ctx) {
+                               ldns_key_free(k);
+                               return NULL;
+                       }
+                       if(EVP_PKEY_keygen_init(ctx) <= 0) {
+                               ldns_key_free(k);
+                               EVP_PKEY_CTX_free(ctx);
+                               return NULL;
+                       }
+                       if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx,
+                               NID_X25519) <= 0) {
+                               ldns_key_free(k);
+                               EVP_PKEY_CTX_free(ctx);
+                               return NULL;
+                       }
+                       if (EVP_PKEY_keygen(ctx, &k->_key.key) <= 0) {
+                               ldns_key_free(k);
+                               EVP_PKEY_CTX_free(ctx);
+                               return NULL;
+                       }
+                       EVP_PKEY_CTX_free(ctx);
+#endif
+                       break;
+#endif /* ED25519 */
+#ifdef USE_ED448
+               case LDNS_SIGN_ED448:
+#ifdef HAVE_EVP_PKEY_KEYGEN
+                       ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
+                       if(!ctx) {
+                               ldns_key_free(k);
+                               return NULL;
+                       }
+                       if(EVP_PKEY_keygen_init(ctx) <= 0) {
+                               ldns_key_free(k);
+                               EVP_PKEY_CTX_free(ctx);
+                               return NULL;
+                       }
+                       if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx,
+                               NID_X448) <= 0) {
+                               ldns_key_free(k);
+                               EVP_PKEY_CTX_free(ctx);
+                               return NULL;
+                       }
+                       if (EVP_PKEY_keygen(ctx, &k->_key.key) <= 0) {
+                               ldns_key_free(k);
+                               EVP_PKEY_CTX_free(ctx);
+                               return NULL;
+                       }
+                       EVP_PKEY_CTX_free(ctx);
+#endif
+                       break;
+#endif /* ED448 */
        }
        ldns_key_set_algorithm(k, alg);
        return k;
@@ -1613,6 +1873,44 @@ ldns_key2rr(const ldns_key *k)
                        return NULL;
 #endif /* ECDSA */
                         break;
+#ifdef USE_ED25519
+                case LDNS_SIGN_ED25519:
+                       ldns_rr_push_rdf(pubkey, ldns_native2rdf_int8(
+                               LDNS_RDF_TYPE_ALG, ldns_key_algorithm(k)));
+                        bin = NULL;
+                        ec = EVP_PKEY_get1_EC_KEY(k->_key.key);
+                        EC_KEY_set_conv_form(ec, POINT_CONVERSION_UNCOMPRESSED);
+                        size = (uint16_t)i2o_ECPublicKey(ec, NULL);
+                        if(!i2o_ECPublicKey(ec, &bin)) {
+                                EC_KEY_free(ec);
+                                ldns_rr_free(pubkey);
+                                return NULL;
+                        }
+                        /* down the reference count for ec, its still assigned
+                         * to the pkey */
+                        EC_KEY_free(ec);
+                       internal_data = 1;
+                       break;
+#endif
+#ifdef USE_ED448
+                case LDNS_SIGN_ED448:
+                       ldns_rr_push_rdf(pubkey, ldns_native2rdf_int8(
+                               LDNS_RDF_TYPE_ALG, ldns_key_algorithm(k)));
+                        bin = NULL;
+                        ec = EVP_PKEY_get1_EC_KEY(k->_key.key);
+                        EC_KEY_set_conv_form(ec, POINT_CONVERSION_UNCOMPRESSED);
+                        size = (uint16_t)i2o_ECPublicKey(ec, NULL);
+                        if(!i2o_ECPublicKey(ec, &bin)) {
+                                EC_KEY_free(ec);
+                                ldns_rr_free(pubkey);
+                                return NULL;
+                        }
+                        /* down the reference count for ec, its still assigned
+                         * to the pkey */
+                        EC_KEY_free(ec);
+                       internal_data = 1;
+                       break;
+#endif
                case LDNS_SIGN_HMACMD5:
                case LDNS_SIGN_HMACSHA1:
                case LDNS_SIGN_HMACSHA256:
index 0e1037e9402d023ffdb394a3baa5c89a2ea27d11..41691b63e73213390416a8dc7571c4b2615dec1a 100644 (file)
@@ -173,6 +173,24 @@ EVP_PKEY* ldns_gost2pkey_raw(const unsigned char* key, size_t keylen);
  */
 EVP_PKEY* ldns_ecdsa2pkey_raw(const unsigned char* key, size_t keylen, uint8_t algo);
 
+/**
+ * Converts a holding buffer with key material to EVP PKEY in openssl.
+ * Only available if ldns was compiled with ED25519.
+ * \param[in] key data to convert
+ * \param[in] keylen length of the key data
+ * \return the key or NULL on error.
+ */
+EVP_PKEY* ldns_ed255192pkey_raw(const unsigned char* key, size_t keylen);
+
+/**
+ * Converts a holding buffer with key material to EVP PKEY in openssl.
+ * Only available if ldns was compiled with ED448.
+ * \param[in] key data to convert
+ * \param[in] keylen length of the key data
+ * \return the key or NULL on error.
+ */
+EVP_PKEY* ldns_ed4482pkey_raw(const unsigned char* key, size_t keylen);
+
 #endif /* LDNS_BUILD_CONFIG_HAVE_SSL */
 
 #if LDNS_BUILD_CONFIG_HAVE_SSL
@@ -538,6 +556,56 @@ ldns_status
 ldns_convert_ecdsa_rrsig_rdf2asn1(ldns_buffer *target_buffer,
         const ldns_rdf *sig_rdf);
 
+/**
+ * Converts the ECDSA signature from ASN1 representation (as
+ * used by OpenSSL) to raw signature data as used in DNS
+ * This routine is only present if ldns is compiled with ED25519 support.
+ *
+ * \param[in] sig The signature in ASN1 format
+ * \param[in] sig_len The length of the signature
+ * \return a new rdf with the signature
+ */
+ldns_rdf *
+ldns_convert_ed25519_rrsig_asn12rdf(const ldns_buffer *sig, long sig_len);
+
+/**
+ * Converts the RRSIG signature RDF (from DNS) to a buffer with the
+ * signature in ASN1 format as openssl uses it.
+ * This routine is only present if ldns is compiled with ED25519 support.
+ *
+ * \param[out] target_buffer buffer to place the signature data in ASN1.
+ * \param[in] sig_rdf The signature rdf to convert
+ * \return LDNS_STATUS_OK on success, error code otherwise
+ */
+ldns_status
+ldns_convert_ed25519_rrsig_rdf2asn1(ldns_buffer *target_buffer,
+        const ldns_rdf *sig_rdf);
+
+/**
+ * Converts the ECDSA signature from ASN1 representation (as
+ * used by OpenSSL) to raw signature data as used in DNS
+ * This routine is only present if ldns is compiled with ED448 support.
+ *
+ * \param[in] sig The signature in ASN1 format
+ * \param[in] sig_len The length of the signature
+ * \return a new rdf with the signature
+ */
+ldns_rdf *
+ldns_convert_ed448_rrsig_asn12rdf(const ldns_buffer *sig, long sig_len);
+
+/**
+ * Converts the RRSIG signature RDF (from DNS) to a buffer with the
+ * signature in ASN1 format as openssl uses it.
+ * This routine is only present if ldns is compiled with ED448 support.
+ *
+ * \param[out] target_buffer buffer to place the signature data in ASN1.
+ * \param[in] sig_rdf The signature rdf to convert
+ * \return LDNS_STATUS_OK on success, error code otherwise
+ */
+ldns_status
+ldns_convert_ed448_rrsig_rdf2asn1(ldns_buffer *target_buffer,
+        const ldns_rdf *sig_rdf);
+
 #endif /* LDNS_BUILD_CONFIG_HAVE_SSL */
 
 #ifdef __cplusplus
index 78332f080c425fc83f5dc9a52c9aedf2ac8e1c09..db2c485ff1700766916c0f39882bfc5ded9b7e42 100644 (file)
@@ -55,6 +55,16 @@ enum ldns_enum_algorithm
         LDNS_ECC_GOST           = 12,  /* RFC 5933 */
         LDNS_ECDSAP256SHA256    = 13,  /* RFC 6605 */
         LDNS_ECDSAP384SHA384    = 14,  /* RFC 6605 */
+#ifdef USE_ED25519
+       /* this ifdef is internal to ldns, because we do not want to export
+        * the symbol.  Users can define it if they want access,
+        * the feature is not fully implemented at this time and openssl
+        * does not support it fully either (also for ED448). */
+       LDNS_ED25519            = 15,  /* draft-ietf-curdle-dnskey-ed25519 */
+#endif
+#ifdef USE_ED448
+       LDNS_ED448              = 16,  /* draft-ietf-curdle-dnskey-ed448 */
+#endif
         LDNS_INDIRECT           = 252,
         LDNS_PRIVATEDNS         = 253,
         LDNS_PRIVATEOID         = 254
@@ -88,6 +98,12 @@ enum ldns_enum_signing_algorithm
        LDNS_SIGN_ECC_GOST       = LDNS_ECC_GOST,
         LDNS_SIGN_ECDSAP256SHA256 = LDNS_ECDSAP256SHA256,
         LDNS_SIGN_ECDSAP384SHA384 = LDNS_ECDSAP384SHA384,
+#ifdef USE_ED25519
+       LDNS_SIGN_ED25519        = LDNS_ED25519,
+#endif
+#ifdef USE_ED448
+       LDNS_SIGN_ED448          = LDNS_ED448,
+#endif
        LDNS_SIGN_HMACMD5        = 157, /* not official! This type is for TSIG, not DNSSEC */
        LDNS_SIGN_HMACSHA1       = 158, /* not official! This type is for TSIG, not DNSSEC */
        LDNS_SIGN_HMACSHA256 = 159  /* ditto */
index b03751b01ec2332c0f251bcd024cb62b062d2723..20a0bfaa1aa3b5ef6a5201fbf36ccfe514939ed9 100644 (file)
@@ -320,6 +320,14 @@ ldns_rr_dnskey_key_size_raw(const unsigned char* keydata,
                 return 256;
         case LDNS_SIGN_ECDSAP384SHA384:
                 return 384;
+#endif
+#ifdef USE_ED25519
+       case LDNS_SIGN_ED25519:
+               return 256;
+#endif
+#ifdef USE_ED448
+       case LDNS_SIGN_ED448:
+               return 456;
 #endif
        case LDNS_SIGN_HMACMD5:
                return len;