diff --git a/lib/dns/dst_api.c b/lib/dns/dst_api.c index 896ee76251..4cd63395c2 100644 --- a/lib/dns/dst_api.c +++ b/lib/dns/dst_api.c @@ -219,10 +219,12 @@ dst_lib_init(isc_mem_t *mctx, const char *engine) { RETERR(dst__opensslecdsa_init(&dst_t_func[DST_ALG_ECDSA256])); RETERR(dst__opensslecdsa_init(&dst_t_func[DST_ALG_ECDSA384])); #ifdef HAVE_OPENSSL_ED25519 - RETERR(dst__openssleddsa_init(&dst_t_func[DST_ALG_ED25519])); + RETERR(dst__openssleddsa_init(&dst_t_func[DST_ALG_ED25519], + DST_ALG_ED25519)); #endif /* ifdef HAVE_OPENSSL_ED25519 */ #ifdef HAVE_OPENSSL_ED448 - RETERR(dst__openssleddsa_init(&dst_t_func[DST_ALG_ED448])); + RETERR(dst__openssleddsa_init(&dst_t_func[DST_ALG_ED448], + DST_ALG_ED448)); #endif /* ifdef HAVE_OPENSSL_ED448 */ #if HAVE_GSSAPI diff --git a/lib/dns/dst_internal.h b/lib/dns/dst_internal.h index 40b54dd029..ad9e097fd9 100644 --- a/lib/dns/dst_internal.h +++ b/lib/dns/dst_internal.h @@ -215,7 +215,7 @@ isc_result_t dst__opensslecdsa_init(struct dst_func **funcp); #if HAVE_OPENSSL_ED25519 || HAVE_OPENSSL_ED448 isc_result_t -dst__openssleddsa_init(struct dst_func **funcp); +dst__openssleddsa_init(struct dst_func **funcp, unsigned char algorithm); #endif /* HAVE_OPENSSL_ED25519 || HAVE_OPENSSL_ED448 */ #if HAVE_GSSAPI isc_result_t diff --git a/lib/dns/openssleddsa_link.c b/lib/dns/openssleddsa_link.c index a2c6f6f4a6..a547ac37d4 100644 --- a/lib/dns/openssleddsa_link.c +++ b/lib/dns/openssleddsa_link.c @@ -339,7 +339,7 @@ openssleddsa_fromdns(dst_key_t *key, isc_buffer_t *data) { isc_result_t ret; isc_region_t r; size_t len; - EVP_PKEY *pkey; + EVP_PKEY *pkey = NULL; REQUIRE(alginfo != NULL); @@ -565,11 +565,108 @@ static dst_func_t openssleddsa_functions = { NULL, /*%< restore */ }; +/* + * The test vectors below where generated by util/gen-eddsa-vectors.c + */ +#if HAVE_OPENSSL_ED448 +static unsigned char ed448_pub[] = + "\x0a\x19\x36\xf0\x4c\x2d\xc1\xfe\xbe\xdc\xfa\xf6\xeb\xd2\x8f\x3b\x04" + "\x14\x2e\x88\xc6\xb5\xdc\xe8\x2a\xc6\xb9\x7c\xa8\x22\xe8\x36\xfb\x06" + "\x55\xa3\x3c\xdb\x9d\x68\x59\x7e\xa9\x5f\x93\x96\x87\x83\x28\xce\xdd" + "\x12\xc9\xb8\x78\x02\x80"; +static unsigned char ed448_sig[] = + "\x7e\xec\x4e\x11\xd9\x79\x89\xd2\xe2\x85\x7a\x1c\xd7\x36\xe8\x24\x1f" + "\x90\xa0\x9c\x84\xfb\x51\xcd\xdc\xfd\x05\xcd\x8c\x08\x51\x05\x18\xc8" + "\x85\xb2\x28\x00\xea\xfe\x10\x46\xad\x52\xe6\xe9\x62\x35\x3b\x2a\x14" + "\x8b\xe7\xf0\x66\x5f\x00\x66\x3c\xa1\x4d\x03\x95\xcc\x73\xfc\xf2\x40" + "\x4b\x67\x85\x5b\x9f\xa9\x87\xb6\xbb\xa3\x9d\x73\x9f\xcb\x4e\x2c\xd2" + "\x46\xc7\x84\xd3\x7d\x94\x32\x30\x27\xb0\xa7\xf6\x6d\xf4\x77\xe8\xf5" + "\xb4\xee\x3f\x0e\x2b\x35\xdd\x5a\x35\xfe\x35\x00"; +#endif + +#if HAVE_OPENSSL_ED25519 +static unsigned char ed25519_pub[] = + "\x66\x5c\x21\x59\xe3\xa0\x6e\xa3\x7d\x82\x7c\xf1\xe7\xa3\xdd\xaf\xd1" + "\x6d\x92\x81\xfb\x09\x0c\x7c\xfe\x6d\xf8\x87\x24\x7e\x6e\x25"; +static unsigned char ed25519_sig[] = + "\x26\x70\x5c\xc1\x85\xb6\x5e\x65\xe5\xa7\xd5\x85\x63\xc9\x1d\x45\x56" + "\x38\xa3\x9c\xa3\x42\x4d\xc8\x89\xff\x84\xea\x2c\xa8\x8b\xfa\x2f\xab" + "\x75\x7c\x68\x95\xfd\xdf\x62\x60\x4e\x4d\x10\xf8\x3c\xae\xcf\x18\x93" + "\x90\x05\xa4\x54\x38\x45\x2f\x81\x71\x1e\x0f\x46\x04"; +#endif + +static isc_result_t +check_algorithm(unsigned char algorithm) { + EVP_MD_CTX *evp_md_ctx = EVP_MD_CTX_create(); + EVP_PKEY *pkey = NULL; + const eddsa_alginfo_t *alginfo = NULL; + const unsigned char *key = NULL; + const unsigned char *sig = NULL; + const unsigned char test[] = "test"; + isc_result_t ret = ISC_R_SUCCESS; + size_t key_len, sig_len; + + if (evp_md_ctx == NULL) { + DST_RET(ISC_R_NOMEMORY); + } + + switch (algorithm) { +#if HAVE_OPENSSL_ED448 + case DST_ALG_ED448: + sig = ed448_sig; + sig_len = sizeof(ed448_sig) - 1; + key = ed448_pub; + key_len = sizeof(ed448_pub) - 1; + alginfo = openssleddsa_alg_info(algorithm); + break; +#endif +#if HAVE_OPENSSL_ED25519 + case DST_ALG_ED25519: + sig = ed25519_sig; + sig_len = sizeof(ed25519_sig) - 1; + key = ed25519_pub; + key_len = sizeof(ed25519_pub) - 1; + alginfo = openssleddsa_alg_info(algorithm); + break; +#endif + default: + DST_RET(ISC_R_NOTIMPLEMENTED); + } + + ret = raw_key_to_ossl(alginfo, 0, key, &key_len, &pkey); + if (ret != ISC_R_SUCCESS) { + goto err; + } + + /* + * Check that we can verify the signature. + */ + if (EVP_DigestVerifyInit(evp_md_ctx, NULL, NULL, NULL, pkey) != 1 || + EVP_DigestVerify(evp_md_ctx, sig, sig_len, test, + sizeof(test) - 1) != 1) + { + DST_RET(ISC_R_NOTIMPLEMENTED); + } + +err: + if (pkey != NULL) { + EVP_PKEY_free(pkey); + } + if (evp_md_ctx != NULL) { + EVP_MD_CTX_destroy(evp_md_ctx); + } + ERR_clear_error(); + return (ret); +} + isc_result_t -dst__openssleddsa_init(dst_func_t **funcp) { +dst__openssleddsa_init(dst_func_t **funcp, unsigned char algorithm) { REQUIRE(funcp != NULL); + if (*funcp == NULL) { - *funcp = &openssleddsa_functions; + if (check_algorithm(algorithm) == ISC_R_SUCCESS) { + *funcp = &openssleddsa_functions; + } } return (ISC_R_SUCCESS); } diff --git a/util/gen-eddsa-vectors.c b/util/gen-eddsa-vectors.c new file mode 100644 index 0000000000..12faa36008 --- /dev/null +++ b/util/gen-eddsa-vectors.c @@ -0,0 +1,118 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * 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 https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include + +#include +#include +#include +#include +#include +#include + +/* + * The test vectors were generated using OpenSSL 3.0 and + * util/gen-eddsa-vectors.c. Rerunning will generate a new set of + * test vectors as the private key is not preserved. + * + * e.g. + * cc util/gen-eddsa-vectors.c -I /opt/local/include \ + * -L /opt/local/lib -lcrypto + */ + +int +main() { + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(NID_ED25519, NULL); + EVP_PKEY *pkey = NULL; + unsigned char buf[512]; + size_t bytes; + EVP_MD_CTX *evp_md_ctx = EVP_MD_CTX_create(); + + if (ctx == NULL || evp_md_ctx == NULL) { + return (1); + } + + if (EVP_PKEY_keygen_init(ctx) != 1 || + EVP_PKEY_keygen(ctx, &pkey) != 1 || pkey == NULL) + { + return (1); + } + + bytes = sizeof(buf); + if (EVP_PKEY_get_raw_public_key(pkey, buf, &bytes) != 1) { + return (1); + } + + printf("unsigned char ed25519_pub[] = \""); + for (size_t i = 0; i < bytes; i++) { + printf("\\x%02x", buf[i]); + } + printf("\";\n"); + + bytes = sizeof(buf); + if (EVP_DigestSignInit(evp_md_ctx, NULL, NULL, NULL, pkey) != 1 || + EVP_DigestSign(evp_md_ctx, buf, &bytes, + (const unsigned char *)"test", 4) != 1) + { + return (1); + } + + printf("unsigned char ed25519_sig[] = \""); + for (size_t i = 0; i < bytes; i++) { + printf("\\x%02x", buf[i]); + } + printf("\";\n\n"); + + EVP_MD_CTX_free(evp_md_ctx); + EVP_PKEY_free(pkey); + pkey = NULL; + + ctx = EVP_PKEY_CTX_new_id(NID_ED448, NULL); + evp_md_ctx = EVP_MD_CTX_create(); + if (ctx == NULL || evp_md_ctx == NULL) { + return (1); + } + + if (EVP_PKEY_keygen_init(ctx) != 1 || + EVP_PKEY_keygen(ctx, &pkey) != 1 || pkey == NULL) + { + return (1); + } + + bytes = sizeof(buf); + if (EVP_PKEY_get_raw_public_key(pkey, buf, &bytes) != 1) { + return (1); + } + + printf("unsigned char ed448_pub[] = \""); + for (size_t i = 0; i < bytes; i++) { + printf("\\x%02x", buf[i]); + } + printf("\";\n"); + + bytes = sizeof(buf); + if (EVP_DigestSignInit(evp_md_ctx, NULL, NULL, NULL, pkey) != 1 || + EVP_DigestSign(evp_md_ctx, buf, &bytes, + (const unsigned char *)"test", 4) != 1) + { + return (1); + } + + printf("unsigned char ed448_sig[] = \""); + for (size_t i = 0; i < bytes; i++) { + printf("\\x%02x", buf[i]); + } + printf("\";\n\n"); + + return (0); +}