From: W.C.A. Wijngaards Date: Tue, 22 Mar 2016 14:10:01 +0000 (+0100) Subject: * Prepare for ED25519, ED448 support: todo convert* routines in X-Git-Tag: release-1.7.0-rc1~77 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cb04d6e54c06462f6ac406b1f5387d79d5534687;p=thirdparty%2Fldns.git * 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. --- diff --git a/Changelog b/Changelog index ae2d8ff8..451d88eb 100644 --- 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 diff --git a/configure.ac b/configure.ac index b85504d1..1d1f0e3a 100644 --- a/configure.ac +++ b/configure.ac @@ -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 @@ -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 + ]) + 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) diff --git a/dnssec.c b/dnssec.c index 2f1db653..36119f7e 100644 --- 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>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 */ diff --git a/dnssec_sign.c b/dnssec_sign.c index ca5425a5..87c033e7 100644 --- a/dnssec_sign.c +++ b/dnssec_sign.c @@ -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; diff --git a/dnssec_verify.c b/dnssec_verify.c index 85f8e9ba..ee080e27 100644 --- a/dnssec_verify.c +++ b/dnssec_verify.c @@ -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: diff --git a/examples/ldns-key2ds.c b/examples/ldns-key2ds.c index 9426f685..be1f8c65 100644 --- a/examples/ldns-key2ds.c +++ b/examples/ldns-key2ds.c @@ -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; } diff --git a/examples/ldns-keygen.c b/examples/ldns-keygen.c index b5f576ed..292fc21e 100644 --- a/examples/ldns-keygen.c +++ b/examples/ldns-keygen.c @@ -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: diff --git a/host2str.c b/host2str.c index 3445254a..00de4cd2 100644 --- a/host2str.c +++ b/host2str.c @@ -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 fcf29883..7ec01ad2 100644 --- 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 + * 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_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: diff --git a/ldns/dnssec.h b/ldns/dnssec.h index 0e1037e9..41691b63 100644 --- a/ldns/dnssec.h +++ b/ldns/dnssec.h @@ -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 diff --git a/ldns/keys.h b/ldns/keys.h index 78332f08..db2c485f 100644 --- a/ldns/keys.h +++ b/ldns/keys.h @@ -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 */ diff --git a/rr_functions.c b/rr_functions.c index b03751b0..20a0bfaa 100644 --- a/rr_functions.c +++ b/rr_functions.c @@ -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;