From cb9eeb062c323391fcd98da0c30e844fa5162e90 Mon Sep 17 00:00:00 2001 From: ott Date: Tue, 12 Dec 2017 16:30:12 +0100 Subject: [PATCH] resolve: add support for RFC 8080 (#7600) RFC 8080 describes how to use EdDSA keys and signatures in DNSSEC. It uses the curves Ed25519 and Ed448. Libgcrypt 1.8.1 does not support Ed448, so only the Ed25519 is supported at the moment. Once Libgcrypt supports Ed448, support for it can be trivially added to resolve. --- src/resolve/RFCs | 1 + src/resolve/resolved-dns-dnssec.c | 225 +++++++++++++++++++++++++----- src/resolve/resolved-dns-rr.c | 2 + src/resolve/resolved-dns-rr.h | 2 + src/resolve/test-dnssec.c | 186 ++++++++++++++++++++++++ 5 files changed, 378 insertions(+), 38 deletions(-) diff --git a/src/resolve/RFCs b/src/resolve/RFCs index 09c85f95182..7190c16faaa 100644 --- a/src/resolve/RFCs +++ b/src/resolve/RFCs @@ -53,6 +53,7 @@ Y https://tools.ietf.org/html/rfc6975 → Signaling Cryptographic Algorithm Unde Y https://tools.ietf.org/html/rfc7129 → Authenticated Denial of Existence in the DNS Y https://tools.ietf.org/html/rfc7646 → Definition and Use of DNSSEC Negative Trust Anchors ~ https://tools.ietf.org/html/rfc7719 → DNS Terminology +Y https://tools.ietf.org/html/rfc8080 → Edwards-Curve Digital Security Algorithm (EdDSA) for DNSSEC Also relevant: diff --git a/src/resolve/resolved-dns-dnssec.c b/src/resolve/resolved-dns-dnssec.c index f04b246a3d6..e3eca7e62cc 100644 --- a/src/resolve/resolved-dns-dnssec.c +++ b/src/resolve/resolved-dns-dnssec.c @@ -18,12 +18,16 @@ along with systemd; If not, see . ***/ +#include + #if HAVE_GCRYPT #include #endif #include "alloc-util.h" #include "dns-domain.h" +#include "fd-util.h" +#include "fileio.h" #include "gcrypt-util.h" #include "hexdecoct.h" #include "resolved-dns-dnssec.h" @@ -436,6 +440,99 @@ static int dnssec_ecdsa_verify( q, key_size*2+1); } +#if GCRYPT_VERSION_NUMBER >= 0x010600 +static int dnssec_eddsa_verify_raw( + const char *curve, + const void *signature_r, size_t signature_r_size, + const void *signature_s, size_t signature_s_size, + const void *data, size_t data_size, + const void *key, size_t key_size) { + + gcry_sexp_t public_key_sexp = NULL, data_sexp = NULL, signature_sexp = NULL; + gcry_error_t ge; + int k; + + ge = gcry_sexp_build(&signature_sexp, + NULL, + "(sig-val (eddsa (r %b) (s %b)))", + (int) signature_r_size, + signature_r, + (int) signature_s_size, + signature_s); + if (ge != 0) { + k = -EIO; + goto finish; + } + + ge = gcry_sexp_build(&data_sexp, + NULL, + "(data (flags eddsa) (hash-algo sha512) (value %b))", + (int) data_size, + data); + if (ge != 0) { + k = -EIO; + goto finish; + } + + ge = gcry_sexp_build(&public_key_sexp, + NULL, + "(public-key (ecc (curve %s) (flags eddsa) (q %b)))", + curve, + (int) key_size, + key); + if (ge != 0) { + k = -EIO; + goto finish; + } + + ge = gcry_pk_verify(signature_sexp, data_sexp, public_key_sexp); + if (gpg_err_code(ge) == GPG_ERR_BAD_SIGNATURE) + k = 0; + else if (ge != 0) { + log_debug("EdDSA signature check failed: %s", gpg_strerror(ge)); + k = -EIO; + } else + k = 1; +finish: + if (public_key_sexp) + gcry_sexp_release(public_key_sexp); + if (signature_sexp) + gcry_sexp_release(signature_sexp); + if (data_sexp) + gcry_sexp_release(data_sexp); + + return k; +} + +static int dnssec_eddsa_verify( + int algorithm, + const void *data, size_t data_size, + DnsResourceRecord *rrsig, + DnsResourceRecord *dnskey) { + const char *curve; + size_t key_size; + + if (algorithm == DNSSEC_ALGORITHM_ED25519) { + curve = "Ed25519"; + key_size = 32; + } else + return -EOPNOTSUPP; + + if (dnskey->dnskey.key_size != key_size) + return -EINVAL; + + if (rrsig->rrsig.signature_size != key_size * 2) + return -EINVAL; + + return dnssec_eddsa_verify_raw( + curve, + rrsig->rrsig.signature, key_size, + (uint8_t*) rrsig->rrsig.signature + key_size, key_size, + data, data_size, + dnskey->dnskey.key, key_size); +} +#endif + static void md_add_uint8(gcry_md_hd_t md, uint8_t v) { gcry_md_write(md, &v, sizeof(v)); } @@ -445,9 +542,18 @@ static void md_add_uint16(gcry_md_hd_t md, uint16_t v) { gcry_md_write(md, &v, sizeof(v)); } -static void md_add_uint32(gcry_md_hd_t md, uint32_t v) { +static void fwrite_uint8(FILE *fp, uint8_t v) { + fwrite(&v, sizeof(v), 1, fp); +} + +static void fwrite_uint16(FILE *fp, uint16_t v) { + v = htobe16(v); + fwrite(&v, sizeof(v), 1, fp); +} + +static void fwrite_uint32(FILE *fp, uint32_t v) { v = htobe32(v); - gcry_md_write(md, &v, sizeof(v)); + fwrite(&v, sizeof(v), 1, fp); } static int dnssec_rrsig_prepare(DnsResourceRecord *rrsig) { @@ -613,6 +719,9 @@ int dnssec_verify_rrset( gcry_md_hd_t md = NULL; int r, md_algorithm; size_t k, n = 0; + size_t sig_size = 0; + _cleanup_free_ char *sig_data = NULL; + _cleanup_fclose_ FILE *f = NULL; size_t hash_size; void *hash; bool wildcard; @@ -628,14 +737,6 @@ int dnssec_verify_rrset( * using the signature "rrsig" and the key "dnskey". It's * assumed that RRSIG and DNSKEY match. */ - md_algorithm = algorithm_to_gcrypt_md(rrsig->rrsig.algorithm); - if (md_algorithm == -EOPNOTSUPP) { - *result = DNSSEC_UNSUPPORTED_ALGORITHM; - return 0; - } - if (md_algorithm < 0) - return md_algorithm; - r = dnssec_rrsig_prepare(rrsig); if (r == -EINVAL) { *result = DNSSEC_INVALID; @@ -725,28 +826,23 @@ int dnssec_verify_rrset( /* Bring the RRs into canonical order */ qsort_safe(list, n, sizeof(DnsResourceRecord*), rr_compare); - /* OK, the RRs are now in canonical order. Let's calculate the digest */ - initialize_libgcrypt(false); - - hash_size = gcry_md_get_algo_dlen(md_algorithm); - assert(hash_size > 0); - - gcry_md_open(&md, md_algorithm, 0); - if (!md) - return -EIO; + f = open_memstream(&sig_data, &sig_size); + if (!f) + return -ENOMEM; + __fsetlocking(f, FSETLOCKING_BYCALLER); - md_add_uint16(md, rrsig->rrsig.type_covered); - md_add_uint8(md, rrsig->rrsig.algorithm); - md_add_uint8(md, rrsig->rrsig.labels); - md_add_uint32(md, rrsig->rrsig.original_ttl); - md_add_uint32(md, rrsig->rrsig.expiration); - md_add_uint32(md, rrsig->rrsig.inception); - md_add_uint16(md, rrsig->rrsig.key_tag); + fwrite_uint16(f, rrsig->rrsig.type_covered); + fwrite_uint8(f, rrsig->rrsig.algorithm); + fwrite_uint8(f, rrsig->rrsig.labels); + fwrite_uint32(f, rrsig->rrsig.original_ttl); + fwrite_uint32(f, rrsig->rrsig.expiration); + fwrite_uint32(f, rrsig->rrsig.inception); + fwrite_uint16(f, rrsig->rrsig.key_tag); r = dns_name_to_wire_format(rrsig->rrsig.signer, wire_format_name, sizeof(wire_format_name), true); if (r < 0) goto finish; - gcry_md_write(md, wire_format_name, r); + fwrite(wire_format_name, 1, r, f); /* Convert the source of synthesis into wire format */ r = dns_name_to_wire_format(source, wire_format_name, sizeof(wire_format_name), true); @@ -760,24 +856,66 @@ int dnssec_verify_rrset( /* Hash the source of synthesis. If this is a wildcard, then prefix it with the *. label */ if (wildcard) - gcry_md_write(md, (uint8_t[]) { 1, '*'}, 2); - gcry_md_write(md, wire_format_name, r); + fwrite((uint8_t[]) { 1, '*'}, sizeof(uint8_t), 2, f); + fwrite(wire_format_name, 1, r, f); - md_add_uint16(md, rr->key->type); - md_add_uint16(md, rr->key->class); - md_add_uint32(md, rrsig->rrsig.original_ttl); + fwrite_uint16(f, rr->key->type); + fwrite_uint16(f, rr->key->class); + fwrite_uint32(f, rrsig->rrsig.original_ttl); l = DNS_RESOURCE_RECORD_RDATA_SIZE(rr); assert(l <= 0xFFFF); - md_add_uint16(md, (uint16_t) l); - gcry_md_write(md, DNS_RESOURCE_RECORD_RDATA(rr), l); + fwrite_uint16(f, (uint16_t) l); + fwrite(DNS_RESOURCE_RECORD_RDATA(rr), 1, l, f); } - hash = gcry_md_read(md, 0); - if (!hash) { - r = -EIO; + r = fflush_and_check(f); + if (r < 0) + return r; + + initialize_libgcrypt(false); + + switch (rrsig->rrsig.algorithm) { +#if GCRYPT_VERSION_NUMBER >= 0x010600 + case DNSSEC_ALGORITHM_ED25519: + break; +#else + case DNSSEC_ALGORITHM_ED25519: +#endif + case DNSSEC_ALGORITHM_ED448: + *result = DNSSEC_UNSUPPORTED_ALGORITHM; + r = 0; goto finish; + default: + /* OK, the RRs are now in canonical order. Let's calculate the digest */ + md_algorithm = algorithm_to_gcrypt_md(rrsig->rrsig.algorithm); + if (md_algorithm == -EOPNOTSUPP) { + *result = DNSSEC_UNSUPPORTED_ALGORITHM; + r = 0; + goto finish; + } + if (md_algorithm < 0) { + r = md_algorithm; + goto finish; + } + + gcry_md_open(&md, md_algorithm, 0); + if (!md) { + r = -EIO; + goto finish; + } + + hash_size = gcry_md_get_algo_dlen(md_algorithm); + assert(hash_size > 0); + + gcry_md_write(md, sig_data, sig_size); + + hash = gcry_md_read(md, 0); + if (!hash) { + r = -EIO; + goto finish; + } } switch (rrsig->rrsig.algorithm) { @@ -802,6 +940,15 @@ int dnssec_verify_rrset( rrsig, dnskey); break; +#if GCRYPT_VERSION_NUMBER >= 0x010600 + case DNSSEC_ALGORITHM_ED25519: + r = dnssec_eddsa_verify( + rrsig->rrsig.algorithm, + sig_data, sig_size, + rrsig, + dnskey); + break; +#endif } if (r < 0) @@ -821,7 +968,9 @@ int dnssec_verify_rrset( r = 0; finish: - gcry_md_close(md); + if (md) + gcry_md_close(md); + return r; } diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c index 4a0c1d6a354..26d2cbcc200 100644 --- a/src/resolve/resolved-dns-rr.c +++ b/src/resolve/resolved-dns-rr.c @@ -1849,6 +1849,8 @@ static const char* const dnssec_algorithm_table[_DNSSEC_ALGORITHM_MAX_DEFINED] = [DNSSEC_ALGORITHM_ECC_GOST] = "ECC-GOST", [DNSSEC_ALGORITHM_ECDSAP256SHA256] = "ECDSAP256SHA256", [DNSSEC_ALGORITHM_ECDSAP384SHA384] = "ECDSAP384SHA384", + [DNSSEC_ALGORITHM_ED25519] = "ED25519", + [DNSSEC_ALGORITHM_ED448] = "ED448", [DNSSEC_ALGORITHM_INDIRECT] = "INDIRECT", [DNSSEC_ALGORITHM_PRIVATEDNS] = "PRIVATEDNS", [DNSSEC_ALGORITHM_PRIVATEOID] = "PRIVATEOID", diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h index 3f3d46e6b3e..8e1a6bb2dc4 100644 --- a/src/resolve/resolved-dns-rr.h +++ b/src/resolve/resolved-dns-rr.h @@ -57,6 +57,8 @@ enum { DNSSEC_ALGORITHM_ECC_GOST = 12, /* RFC 5933 */ DNSSEC_ALGORITHM_ECDSAP256SHA256 = 13, /* RFC 6605 */ DNSSEC_ALGORITHM_ECDSAP384SHA384 = 14, /* RFC 6605 */ + DNSSEC_ALGORITHM_ED25519 = 15, /* RFC 8080 */ + DNSSEC_ALGORITHM_ED448 = 16, /* RFC 8080 */ DNSSEC_ALGORITHM_INDIRECT = 252, DNSSEC_ALGORITHM_PRIVATEDNS, DNSSEC_ALGORITHM_PRIVATEOID, diff --git a/src/resolve/test-dnssec.c b/src/resolve/test-dnssec.c index aea7fff1d6d..2d2b5e31bf8 100644 --- a/src/resolve/test-dnssec.c +++ b/src/resolve/test-dnssec.c @@ -19,6 +19,7 @@ ***/ #include +#include #include #include @@ -124,6 +125,189 @@ static void test_dnssec_verify_dns_key(void) { assert_se(dnssec_verify_dnskey_by_ds(dnskey, ds2, false) > 0); } +static void test_dnssec_verify_rfc8080_ed25519_example1(void) { + static const uint8_t dnskey_blob[] = { + 0x97, 0x4d, 0x96, 0xa2, 0x2d, 0x22, 0x4b, 0xc0, 0x1a, 0xdb, 0x91, 0x50, 0x91, 0x47, 0x7d, + 0x44, 0xcc, 0xd9, 0x1c, 0x9a, 0x41, 0xa1, 0x14, 0x30, 0x01, 0x01, 0x17, 0xd5, 0x2c, 0x59, + 0x24, 0xe + }; + static const uint8_t ds_fprint[] = { + 0xdd, 0xa6, 0xb9, 0x69, 0xbd, 0xfb, 0x79, 0xf7, 0x1e, 0xe7, 0xb7, 0xfb, 0xdf, 0xb7, 0xdc, + 0xd7, 0xad, 0xbb, 0xd3, 0x5d, 0xdf, 0x79, 0xed, 0x3b, 0x6d, 0xd7, 0xf6, 0xe3, 0x56, 0xdd, + 0xd7, 0x47, 0xf7, 0x6f, 0x5f, 0x7a, 0xe1, 0xa6, 0xf9, 0xe5, 0xce, 0xfc, 0x7b, 0xbf, 0x5a, + 0xdf, 0x4e, 0x1b + }; + static const uint8_t signature_blob[] = { + 0xa0, 0xbf, 0x64, 0xac, 0x9b, 0xa7, 0xef, 0x17, 0xc1, 0x38, 0x85, 0x9c, 0x18, 0x78, 0xbb, + 0x99, 0xa8, 0x39, 0xfe, 0x17, 0x59, 0xac, 0xa5, 0xb0, 0xd7, 0x98, 0xcf, 0x1a, 0xb1, 0xe9, + 0x8d, 0x07, 0x91, 0x02, 0xf4, 0xdd, 0xb3, 0x36, 0x8f, 0x0f, 0xe4, 0x0b, 0xb3, 0x77, 0xf1, + 0xf0, 0x0e, 0x0c, 0xdd, 0xed, 0xb7, 0x99, 0x16, 0x7d, 0x56, 0xb6, 0xe9, 0x32, 0x78, 0x30, + 0x72, 0xba, 0x8d, 0x02 + }; + + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *dnskey = NULL, *ds = NULL, *mx = NULL, + *rrsig = NULL; + _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; + DnssecResult result; + + dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "example.com."); + assert_se(dnskey); + + dnskey->dnskey.flags = 257; + dnskey->dnskey.protocol = 3; + dnskey->dnskey.algorithm = DNSSEC_ALGORITHM_ED25519; + dnskey->dnskey.key_size = sizeof(dnskey_blob); + dnskey->dnskey.key = memdup(dnskey_blob, sizeof(dnskey_blob)); + assert_se(dnskey->dnskey.key); + + log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey))); + + ds = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "example.com."); + assert_se(ds); + + ds->ds.key_tag = 3613; + ds->ds.algorithm = DNSSEC_ALGORITHM_ED25519; + ds->ds.digest_type = DNSSEC_DIGEST_SHA256; + ds->ds.digest_size = sizeof(ds_fprint); + ds->ds.digest = memdup(ds_fprint, ds->ds.digest_size); + assert_se(ds->ds.digest); + + log_info("DS: %s", strna(dns_resource_record_to_string(ds))); + + mx = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_MX, "example.com."); + assert_se(mx); + + mx->mx.priority = 10; + mx->mx.exchange = strdup("mail.example.com."); + assert_se(mx->mx.exchange); + + log_info("MX: %s", strna(dns_resource_record_to_string(mx))); + + rrsig = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_RRSIG, "example.com."); + assert_se(rrsig); + + rrsig->rrsig.type_covered = DNS_TYPE_MX; + rrsig->rrsig.algorithm = DNSSEC_ALGORITHM_ED25519; + rrsig->rrsig.labels = 2; + rrsig->rrsig.original_ttl = 3600; + rrsig->rrsig.expiration = 1440021600; + rrsig->rrsig.inception = 1438207200; + rrsig->rrsig.key_tag = 3613; + rrsig->rrsig.signer = strdup("example.com."); + assert_se(rrsig->rrsig.signer); + rrsig->rrsig.signature_size = sizeof(signature_blob); + rrsig->rrsig.signature = memdup(signature_blob, rrsig->rrsig.signature_size); + assert_se(rrsig->rrsig.signature); + + log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig))); + + assert_se(dnssec_key_match_rrsig(mx->key, rrsig) > 0); + assert_se(dnssec_rrsig_match_dnskey(rrsig, dnskey, false) > 0); + + answer = dns_answer_new(1); + assert_se(answer); + assert_se(dns_answer_add(answer, mx, 0, DNS_ANSWER_AUTHENTICATED) >= 0); + + assert_se(dnssec_verify_rrset(answer, mx->key, rrsig, dnskey, + rrsig->rrsig.inception * USEC_PER_SEC, &result) >= 0); +#if GCRYPT_VERSION_NUMBER >= 0x010600 + assert_se(result == DNSSEC_VALIDATED); +#else + assert_se(result == DNSSEC_UNSUPPORTED_ALGORITHM); +#endif +} + +static void test_dnssec_verify_rfc8080_ed25519_example2(void) { + static const uint8_t dnskey_blob[] = { + 0xcc, 0xf9, 0xd9, 0xfd, 0x0c, 0x04, 0x7b, 0xb4, 0xbc, 0x0b, 0x94, 0x8f, 0xcf, 0x63, 0x9f, + 0x4b, 0x94, 0x51, 0xe3, 0x40, 0x13, 0x93, 0x6f, 0xeb, 0x62, 0x71, 0x3d, 0xc4, 0x72, 0x4, + 0x8a, 0x3b + }; + static const uint8_t ds_fprint[] = { + 0xe3, 0x4d, 0x7b, 0xf3, 0x56, 0xfd, 0xdf, 0x87, 0xb7, 0xf7, 0x67, 0x5e, 0xe3, 0xdd, 0x9e, + 0x73, 0xbe, 0xda, 0x7b, 0x67, 0xb5, 0xe5, 0xde, 0xf4, 0x7f, 0xae, 0x7b, 0xe5, 0xad, 0x5c, + 0xd1, 0xb7, 0x39, 0xf5, 0xce, 0x76, 0xef, 0x97, 0x34, 0xe1, 0xe6, 0xde, 0xf3, 0x47, 0x3a, + 0xeb, 0x5e, 0x1c + }; + static const uint8_t signature_blob[] = { + 0xcd, 0x74, 0x34, 0x6e, 0x46, 0x20, 0x41, 0x31, 0x05, 0xc9, 0xf2, 0xf2, 0x8b, 0xd4, 0x28, + 0x89, 0x8e, 0x83, 0xf1, 0x97, 0x58, 0xa3, 0x8c, 0x32, 0x52, 0x15, 0x62, 0xa1, 0x86, 0x57, + 0x15, 0xd4, 0xf8, 0xd7, 0x44, 0x0f, 0x44, 0x84, 0xd0, 0x4a, 0xa2, 0x52, 0x9f, 0x34, 0x28, + 0x4a, 0x6e, 0x69, 0xa0, 0x9e, 0xe0, 0x0f, 0xb0, 0x10, 0x47, 0x43, 0xbb, 0x2a, 0xe2, 0x39, + 0x93, 0x6a, 0x5c, 0x06 + }; + + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *dnskey = NULL, *ds = NULL, *mx = NULL, + *rrsig = NULL; + _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; + DnssecResult result; + + dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "example.com."); + assert_se(dnskey); + + dnskey->dnskey.flags = 257; + dnskey->dnskey.protocol = 3; + dnskey->dnskey.algorithm = DNSSEC_ALGORITHM_ED25519; + dnskey->dnskey.key_size = sizeof(dnskey_blob); + dnskey->dnskey.key = memdup(dnskey_blob, sizeof(dnskey_blob)); + assert_se(dnskey->dnskey.key); + + log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey))); + + ds = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "example.com."); + assert_se(ds); + + ds->ds.key_tag = 35217; + ds->ds.algorithm = DNSSEC_ALGORITHM_ED25519; + ds->ds.digest_type = DNSSEC_DIGEST_SHA256; + ds->ds.digest_size = sizeof(ds_fprint); + ds->ds.digest = memdup(ds_fprint, ds->ds.digest_size); + assert_se(ds->ds.digest); + + log_info("DS: %s", strna(dns_resource_record_to_string(ds))); + + mx = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_MX, "example.com."); + assert_se(mx); + + mx->mx.priority = 10; + mx->mx.exchange = strdup("mail.example.com."); + assert_se(mx->mx.exchange); + + log_info("MX: %s", strna(dns_resource_record_to_string(mx))); + + rrsig = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_RRSIG, "example.com."); + assert_se(rrsig); + + rrsig->rrsig.type_covered = DNS_TYPE_MX; + rrsig->rrsig.algorithm = DNSSEC_ALGORITHM_ED25519; + rrsig->rrsig.labels = 2; + rrsig->rrsig.original_ttl = 3600; + rrsig->rrsig.expiration = 1440021600; + rrsig->rrsig.inception = 1438207200; + rrsig->rrsig.key_tag = 35217; + rrsig->rrsig.signer = strdup("example.com."); + assert_se(rrsig->rrsig.signer); + rrsig->rrsig.signature_size = sizeof(signature_blob); + rrsig->rrsig.signature = memdup(signature_blob, rrsig->rrsig.signature_size); + assert_se(rrsig->rrsig.signature); + + log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig))); + + assert_se(dnssec_key_match_rrsig(mx->key, rrsig) > 0); + assert_se(dnssec_rrsig_match_dnskey(rrsig, dnskey, false) > 0); + + answer = dns_answer_new(1); + assert_se(answer); + assert_se(dns_answer_add(answer, mx, 0, DNS_ANSWER_AUTHENTICATED) >= 0); + + assert_se(dnssec_verify_rrset(answer, mx->key, rrsig, dnskey, + rrsig->rrsig.inception * USEC_PER_SEC, &result) >= 0); +#if GCRYPT_VERSION_NUMBER >= 0x010600 + assert_se(result == DNSSEC_VALIDATED); +#else + assert_se(result == DNSSEC_UNSUPPORTED_ALGORITHM); +#endif +} static void test_dnssec_verify_rrset(void) { static const uint8_t signature_blob[] = { @@ -335,6 +519,8 @@ int main(int argc, char*argv[]) { #if HAVE_GCRYPT test_dnssec_verify_dns_key(); + test_dnssec_verify_rfc8080_ed25519_example1(); + test_dnssec_verify_rfc8080_ed25519_example2(); test_dnssec_verify_rrset(); test_dnssec_verify_rrset2(); test_dnssec_nsec3_hash(); -- 2.39.2