1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2015 Lennart Poettering
12 #include <netinet/in.h>
13 #include <sys/socket.h>
15 #include "alloc-util.h"
16 #include "resolved-dns-dnssec.h"
17 #include "resolved-dns-rr.h"
18 #include "string-util.h"
19 #include "hexdecoct.h"
21 static void test_dnssec_canonicalize_one(const char *original
, const char *canonical
, int r
) {
22 char canonicalized
[DNSSEC_CANONICAL_HOSTNAME_MAX
];
24 assert_se(dnssec_canonicalize(original
, canonicalized
, sizeof(canonicalized
)) == r
);
28 assert_se(streq(canonicalized
, canonical
));
31 static void test_dnssec_canonicalize(void) {
32 test_dnssec_canonicalize_one("", ".", 1);
33 test_dnssec_canonicalize_one(".", ".", 1);
34 test_dnssec_canonicalize_one("foo", "foo.", 4);
35 test_dnssec_canonicalize_one("foo.", "foo.", 4);
36 test_dnssec_canonicalize_one("FOO.", "foo.", 4);
37 test_dnssec_canonicalize_one("FOO.bar.", "foo.bar.", 8);
38 test_dnssec_canonicalize_one("FOO..bar.", NULL
, -EINVAL
);
43 static void test_dnssec_verify_dns_key(void) {
45 static const uint8_t ds1_fprint
[] = {
46 0x46, 0x8B, 0xC8, 0xDD, 0xC7, 0xE8, 0x27, 0x03, 0x40, 0xBB, 0x8A, 0x1F, 0x3B, 0x2E, 0x45, 0x9D,
47 0x80, 0x67, 0x14, 0x01,
49 static const uint8_t ds2_fprint
[] = {
50 0x8A, 0xEE, 0x80, 0x47, 0x05, 0x5F, 0x83, 0xD1, 0x48, 0xBA, 0x8F, 0xF6, 0xDD, 0xA7, 0x60, 0xCE,
51 0x94, 0xF7, 0xC7, 0x5E, 0x52, 0x4C, 0xF2, 0xE9, 0x50, 0xB9, 0x2E, 0xCB, 0xEF, 0x96, 0xB9, 0x98,
53 static const uint8_t dnskey_blob
[] = {
54 0x03, 0x01, 0x00, 0x01, 0xa8, 0x12, 0xda, 0x4f, 0xd2, 0x7d, 0x54, 0x14, 0x0e, 0xcc, 0x5b, 0x5e,
55 0x45, 0x9c, 0x96, 0x98, 0xc0, 0xc0, 0x85, 0x81, 0xb1, 0x47, 0x8c, 0x7d, 0xe8, 0x39, 0x50, 0xcc,
56 0xc5, 0xd0, 0xf2, 0x00, 0x81, 0x67, 0x79, 0xf6, 0xcc, 0x9d, 0xad, 0x6c, 0xbb, 0x7b, 0x6f, 0x48,
57 0x97, 0x15, 0x1c, 0xfd, 0x0b, 0xfe, 0xd3, 0xd7, 0x7d, 0x9f, 0x81, 0x26, 0xd3, 0xc5, 0x65, 0x49,
58 0xcf, 0x46, 0x62, 0xb0, 0x55, 0x6e, 0x47, 0xc7, 0x30, 0xef, 0x51, 0xfb, 0x3e, 0xc6, 0xef, 0xde,
59 0x27, 0x3f, 0xfa, 0x57, 0x2d, 0xa7, 0x1d, 0x80, 0x46, 0x9a, 0x5f, 0x14, 0xb3, 0xb0, 0x2c, 0xbe,
60 0x72, 0xca, 0xdf, 0xb2, 0xff, 0x36, 0x5b, 0x4f, 0xec, 0x58, 0x8e, 0x8d, 0x01, 0xe9, 0xa9, 0xdf,
61 0xb5, 0x60, 0xad, 0x52, 0x4d, 0xfc, 0xa9, 0x3e, 0x8d, 0x35, 0x95, 0xb3, 0x4e, 0x0f, 0xca, 0x45,
62 0x1b, 0xf7, 0xef, 0x3a, 0x88, 0x25, 0x08, 0xc7, 0x4e, 0x06, 0xc1, 0x62, 0x1a, 0xce, 0xd8, 0x77,
63 0xbd, 0x02, 0x65, 0xf8, 0x49, 0xfb, 0xce, 0xf6, 0xa8, 0x09, 0xfc, 0xde, 0xb2, 0x09, 0x9d, 0x39,
64 0xf8, 0x63, 0x9c, 0x32, 0x42, 0x7c, 0xa0, 0x30, 0x86, 0x72, 0x7a, 0x4a, 0xc6, 0xd4, 0xb3, 0x2d,
65 0x24, 0xef, 0x96, 0x3f, 0xc2, 0xda, 0xd3, 0xf2, 0x15, 0x6f, 0xda, 0x65, 0x4b, 0x81, 0x28, 0x68,
66 0xf4, 0xfe, 0x3e, 0x71, 0x4f, 0x50, 0x96, 0x72, 0x58, 0xa1, 0x89, 0xdd, 0x01, 0x61, 0x39, 0x39,
67 0xc6, 0x76, 0xa4, 0xda, 0x02, 0x70, 0x3d, 0xc0, 0xdc, 0x8d, 0x70, 0x72, 0x04, 0x90, 0x79, 0xd4,
68 0xec, 0x65, 0xcf, 0x49, 0x35, 0x25, 0x3a, 0x14, 0x1a, 0x45, 0x20, 0xeb, 0x31, 0xaf, 0x92, 0xba,
69 0x20, 0xd3, 0xcd, 0xa7, 0x13, 0x44, 0xdc, 0xcf, 0xf0, 0x27, 0x34, 0xb9, 0xe7, 0x24, 0x6f, 0x73,
70 0xe7, 0xea, 0x77, 0x03,
73 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*dnskey
= NULL
, *ds1
= NULL
, *ds2
= NULL
;
75 /* The two DS RRs in effect for nasa.gov on 2015-12-01. */
76 ds1
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_DS
, "nasa.gov");
79 ds1
->ds
.key_tag
= 47857;
80 ds1
->ds
.algorithm
= DNSSEC_ALGORITHM_RSASHA256
;
81 ds1
->ds
.digest_type
= DNSSEC_DIGEST_SHA1
;
82 ds1
->ds
.digest_size
= sizeof(ds1_fprint
);
83 ds1
->ds
.digest
= memdup(ds1_fprint
, ds1
->ds
.digest_size
);
84 assert_se(ds1
->ds
.digest
);
86 log_info("DS1: %s", strna(dns_resource_record_to_string(ds1
)));
88 ds2
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_DS
, "NASA.GOV");
91 ds2
->ds
.key_tag
= 47857;
92 ds2
->ds
.algorithm
= DNSSEC_ALGORITHM_RSASHA256
;
93 ds2
->ds
.digest_type
= DNSSEC_DIGEST_SHA256
;
94 ds2
->ds
.digest_size
= sizeof(ds2_fprint
);
95 ds2
->ds
.digest
= memdup(ds2_fprint
, ds2
->ds
.digest_size
);
96 assert_se(ds2
->ds
.digest
);
98 log_info("DS2: %s", strna(dns_resource_record_to_string(ds2
)));
100 dnskey
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_DNSKEY
, "nasa.GOV");
103 dnskey
->dnskey
.flags
= 257;
104 dnskey
->dnskey
.protocol
= 3;
105 dnskey
->dnskey
.algorithm
= DNSSEC_ALGORITHM_RSASHA256
;
106 dnskey
->dnskey
.key_size
= sizeof(dnskey_blob
);
107 dnskey
->dnskey
.key
= memdup(dnskey_blob
, sizeof(dnskey_blob
));
108 assert_se(dnskey
->dnskey
.key
);
110 log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey
)));
111 log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey
, false));
113 assert_se(dnssec_verify_dnskey_by_ds(dnskey
, ds1
, false) > 0);
114 assert_se(dnssec_verify_dnskey_by_ds(dnskey
, ds2
, false) > 0);
117 static void test_dnssec_verify_rfc8080_ed25519_example1(void) {
118 static const uint8_t dnskey_blob
[] = {
119 0x97, 0x4d, 0x96, 0xa2, 0x2d, 0x22, 0x4b, 0xc0, 0x1a, 0xdb, 0x91, 0x50, 0x91, 0x47, 0x7d,
120 0x44, 0xcc, 0xd9, 0x1c, 0x9a, 0x41, 0xa1, 0x14, 0x30, 0x01, 0x01, 0x17, 0xd5, 0x2c, 0x59,
123 static const uint8_t ds_fprint
[] = {
124 0xdd, 0xa6, 0xb9, 0x69, 0xbd, 0xfb, 0x79, 0xf7, 0x1e, 0xe7, 0xb7, 0xfb, 0xdf, 0xb7, 0xdc,
125 0xd7, 0xad, 0xbb, 0xd3, 0x5d, 0xdf, 0x79, 0xed, 0x3b, 0x6d, 0xd7, 0xf6, 0xe3, 0x56, 0xdd,
126 0xd7, 0x47, 0xf7, 0x6f, 0x5f, 0x7a, 0xe1, 0xa6, 0xf9, 0xe5, 0xce, 0xfc, 0x7b, 0xbf, 0x5a,
129 static const uint8_t signature_blob
[] = {
130 0xa0, 0xbf, 0x64, 0xac, 0x9b, 0xa7, 0xef, 0x17, 0xc1, 0x38, 0x85, 0x9c, 0x18, 0x78, 0xbb,
131 0x99, 0xa8, 0x39, 0xfe, 0x17, 0x59, 0xac, 0xa5, 0xb0, 0xd7, 0x98, 0xcf, 0x1a, 0xb1, 0xe9,
132 0x8d, 0x07, 0x91, 0x02, 0xf4, 0xdd, 0xb3, 0x36, 0x8f, 0x0f, 0xe4, 0x0b, 0xb3, 0x77, 0xf1,
133 0xf0, 0x0e, 0x0c, 0xdd, 0xed, 0xb7, 0x99, 0x16, 0x7d, 0x56, 0xb6, 0xe9, 0x32, 0x78, 0x30,
134 0x72, 0xba, 0x8d, 0x02
137 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*dnskey
= NULL
, *ds
= NULL
, *mx
= NULL
,
139 _cleanup_(dns_answer_unrefp
) DnsAnswer
*answer
= NULL
;
142 dnskey
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_DNSKEY
, "example.com.");
145 dnskey
->dnskey
.flags
= 257;
146 dnskey
->dnskey
.protocol
= 3;
147 dnskey
->dnskey
.algorithm
= DNSSEC_ALGORITHM_ED25519
;
148 dnskey
->dnskey
.key_size
= sizeof(dnskey_blob
);
149 dnskey
->dnskey
.key
= memdup(dnskey_blob
, sizeof(dnskey_blob
));
150 assert_se(dnskey
->dnskey
.key
);
152 log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey
)));
154 ds
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_DS
, "example.com.");
157 ds
->ds
.key_tag
= 3613;
158 ds
->ds
.algorithm
= DNSSEC_ALGORITHM_ED25519
;
159 ds
->ds
.digest_type
= DNSSEC_DIGEST_SHA256
;
160 ds
->ds
.digest_size
= sizeof(ds_fprint
);
161 ds
->ds
.digest
= memdup(ds_fprint
, ds
->ds
.digest_size
);
162 assert_se(ds
->ds
.digest
);
164 log_info("DS: %s", strna(dns_resource_record_to_string(ds
)));
166 mx
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_MX
, "example.com.");
169 mx
->mx
.priority
= 10;
170 mx
->mx
.exchange
= strdup("mail.example.com.");
171 assert_se(mx
->mx
.exchange
);
173 log_info("MX: %s", strna(dns_resource_record_to_string(mx
)));
175 rrsig
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_RRSIG
, "example.com.");
178 rrsig
->rrsig
.type_covered
= DNS_TYPE_MX
;
179 rrsig
->rrsig
.algorithm
= DNSSEC_ALGORITHM_ED25519
;
180 rrsig
->rrsig
.labels
= 2;
181 rrsig
->rrsig
.original_ttl
= 3600;
182 rrsig
->rrsig
.expiration
= 1440021600;
183 rrsig
->rrsig
.inception
= 1438207200;
184 rrsig
->rrsig
.key_tag
= 3613;
185 rrsig
->rrsig
.signer
= strdup("example.com.");
186 assert_se(rrsig
->rrsig
.signer
);
187 rrsig
->rrsig
.signature_size
= sizeof(signature_blob
);
188 rrsig
->rrsig
.signature
= memdup(signature_blob
, rrsig
->rrsig
.signature_size
);
189 assert_se(rrsig
->rrsig
.signature
);
191 log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig
)));
193 assert_se(dnssec_key_match_rrsig(mx
->key
, rrsig
) > 0);
194 assert_se(dnssec_rrsig_match_dnskey(rrsig
, dnskey
, false) > 0);
196 answer
= dns_answer_new(1);
198 assert_se(dns_answer_add(answer
, mx
, 0, DNS_ANSWER_AUTHENTICATED
) >= 0);
200 assert_se(dnssec_verify_rrset(answer
, mx
->key
, rrsig
, dnskey
,
201 rrsig
->rrsig
.inception
* USEC_PER_SEC
, &result
) >= 0);
202 #if GCRYPT_VERSION_NUMBER >= 0x010600
203 assert_se(result
== DNSSEC_VALIDATED
);
205 assert_se(result
== DNSSEC_UNSUPPORTED_ALGORITHM
);
209 static void test_dnssec_verify_rfc8080_ed25519_example2(void) {
210 static const uint8_t dnskey_blob
[] = {
211 0xcc, 0xf9, 0xd9, 0xfd, 0x0c, 0x04, 0x7b, 0xb4, 0xbc, 0x0b, 0x94, 0x8f, 0xcf, 0x63, 0x9f,
212 0x4b, 0x94, 0x51, 0xe3, 0x40, 0x13, 0x93, 0x6f, 0xeb, 0x62, 0x71, 0x3d, 0xc4, 0x72, 0x4,
215 static const uint8_t ds_fprint
[] = {
216 0xe3, 0x4d, 0x7b, 0xf3, 0x56, 0xfd, 0xdf, 0x87, 0xb7, 0xf7, 0x67, 0x5e, 0xe3, 0xdd, 0x9e,
217 0x73, 0xbe, 0xda, 0x7b, 0x67, 0xb5, 0xe5, 0xde, 0xf4, 0x7f, 0xae, 0x7b, 0xe5, 0xad, 0x5c,
218 0xd1, 0xb7, 0x39, 0xf5, 0xce, 0x76, 0xef, 0x97, 0x34, 0xe1, 0xe6, 0xde, 0xf3, 0x47, 0x3a,
221 static const uint8_t signature_blob
[] = {
222 0xcd, 0x74, 0x34, 0x6e, 0x46, 0x20, 0x41, 0x31, 0x05, 0xc9, 0xf2, 0xf2, 0x8b, 0xd4, 0x28,
223 0x89, 0x8e, 0x83, 0xf1, 0x97, 0x58, 0xa3, 0x8c, 0x32, 0x52, 0x15, 0x62, 0xa1, 0x86, 0x57,
224 0x15, 0xd4, 0xf8, 0xd7, 0x44, 0x0f, 0x44, 0x84, 0xd0, 0x4a, 0xa2, 0x52, 0x9f, 0x34, 0x28,
225 0x4a, 0x6e, 0x69, 0xa0, 0x9e, 0xe0, 0x0f, 0xb0, 0x10, 0x47, 0x43, 0xbb, 0x2a, 0xe2, 0x39,
226 0x93, 0x6a, 0x5c, 0x06
229 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*dnskey
= NULL
, *ds
= NULL
, *mx
= NULL
,
231 _cleanup_(dns_answer_unrefp
) DnsAnswer
*answer
= NULL
;
234 dnskey
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_DNSKEY
, "example.com.");
237 dnskey
->dnskey
.flags
= 257;
238 dnskey
->dnskey
.protocol
= 3;
239 dnskey
->dnskey
.algorithm
= DNSSEC_ALGORITHM_ED25519
;
240 dnskey
->dnskey
.key_size
= sizeof(dnskey_blob
);
241 dnskey
->dnskey
.key
= memdup(dnskey_blob
, sizeof(dnskey_blob
));
242 assert_se(dnskey
->dnskey
.key
);
244 log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey
)));
246 ds
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_DS
, "example.com.");
249 ds
->ds
.key_tag
= 35217;
250 ds
->ds
.algorithm
= DNSSEC_ALGORITHM_ED25519
;
251 ds
->ds
.digest_type
= DNSSEC_DIGEST_SHA256
;
252 ds
->ds
.digest_size
= sizeof(ds_fprint
);
253 ds
->ds
.digest
= memdup(ds_fprint
, ds
->ds
.digest_size
);
254 assert_se(ds
->ds
.digest
);
256 log_info("DS: %s", strna(dns_resource_record_to_string(ds
)));
258 mx
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_MX
, "example.com.");
261 mx
->mx
.priority
= 10;
262 mx
->mx
.exchange
= strdup("mail.example.com.");
263 assert_se(mx
->mx
.exchange
);
265 log_info("MX: %s", strna(dns_resource_record_to_string(mx
)));
267 rrsig
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_RRSIG
, "example.com.");
270 rrsig
->rrsig
.type_covered
= DNS_TYPE_MX
;
271 rrsig
->rrsig
.algorithm
= DNSSEC_ALGORITHM_ED25519
;
272 rrsig
->rrsig
.labels
= 2;
273 rrsig
->rrsig
.original_ttl
= 3600;
274 rrsig
->rrsig
.expiration
= 1440021600;
275 rrsig
->rrsig
.inception
= 1438207200;
276 rrsig
->rrsig
.key_tag
= 35217;
277 rrsig
->rrsig
.signer
= strdup("example.com.");
278 assert_se(rrsig
->rrsig
.signer
);
279 rrsig
->rrsig
.signature_size
= sizeof(signature_blob
);
280 rrsig
->rrsig
.signature
= memdup(signature_blob
, rrsig
->rrsig
.signature_size
);
281 assert_se(rrsig
->rrsig
.signature
);
283 log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig
)));
285 assert_se(dnssec_key_match_rrsig(mx
->key
, rrsig
) > 0);
286 assert_se(dnssec_rrsig_match_dnskey(rrsig
, dnskey
, false) > 0);
288 answer
= dns_answer_new(1);
290 assert_se(dns_answer_add(answer
, mx
, 0, DNS_ANSWER_AUTHENTICATED
) >= 0);
292 assert_se(dnssec_verify_rrset(answer
, mx
->key
, rrsig
, dnskey
,
293 rrsig
->rrsig
.inception
* USEC_PER_SEC
, &result
) >= 0);
294 #if GCRYPT_VERSION_NUMBER >= 0x010600
295 assert_se(result
== DNSSEC_VALIDATED
);
297 assert_se(result
== DNSSEC_UNSUPPORTED_ALGORITHM
);
300 static void test_dnssec_verify_rrset(void) {
302 static const uint8_t signature_blob
[] = {
303 0x7f, 0x79, 0xdd, 0x5e, 0x89, 0x79, 0x18, 0xd0, 0x34, 0x86, 0x8c, 0x72, 0x77, 0x75, 0x48, 0x4d,
304 0xc3, 0x7d, 0x38, 0x04, 0xab, 0xcd, 0x9e, 0x4c, 0x82, 0xb0, 0x92, 0xca, 0xe9, 0x66, 0xe9, 0x6e,
305 0x47, 0xc7, 0x68, 0x8c, 0x94, 0xf6, 0x69, 0xcb, 0x75, 0x94, 0xe6, 0x30, 0xa6, 0xfb, 0x68, 0x64,
306 0x96, 0x1a, 0x84, 0xe1, 0xdc, 0x16, 0x4c, 0x83, 0x6c, 0x44, 0xf2, 0x74, 0x4d, 0x74, 0x79, 0x8f,
307 0xf3, 0xf4, 0x63, 0x0d, 0xef, 0x5a, 0xe7, 0xe2, 0xfd, 0xf2, 0x2b, 0x38, 0x7c, 0x28, 0x96, 0x9d,
308 0xb6, 0xcd, 0x5c, 0x3b, 0x57, 0xe2, 0x24, 0x78, 0x65, 0xd0, 0x9e, 0x77, 0x83, 0x09, 0x6c, 0xff,
309 0x3d, 0x52, 0x3f, 0x6e, 0xd1, 0xed, 0x2e, 0xf9, 0xee, 0x8e, 0xa6, 0xbe, 0x9a, 0xa8, 0x87, 0x76,
310 0xd8, 0x77, 0xcc, 0x96, 0xa0, 0x98, 0xa1, 0xd1, 0x68, 0x09, 0x43, 0xcf, 0x56, 0xd9, 0xd1, 0x66,
313 static const uint8_t dnskey_blob
[] = {
314 0x03, 0x01, 0x00, 0x01, 0x9b, 0x49, 0x9b, 0xc1, 0xf9, 0x9a, 0xe0, 0x4e, 0xcf, 0xcb, 0x14, 0x45,
315 0x2e, 0xc9, 0xf9, 0x74, 0xa7, 0x18, 0xb5, 0xf3, 0xde, 0x39, 0x49, 0xdf, 0x63, 0x33, 0x97, 0x52,
316 0xe0, 0x8e, 0xac, 0x50, 0x30, 0x8e, 0x09, 0xd5, 0x24, 0x3d, 0x26, 0xa4, 0x49, 0x37, 0x2b, 0xb0,
317 0x6b, 0x1b, 0xdf, 0xde, 0x85, 0x83, 0xcb, 0x22, 0x4e, 0x60, 0x0a, 0x91, 0x1a, 0x1f, 0xc5, 0x40,
318 0xb1, 0xc3, 0x15, 0xc1, 0x54, 0x77, 0x86, 0x65, 0x53, 0xec, 0x10, 0x90, 0x0c, 0x91, 0x00, 0x5e,
319 0x15, 0xdc, 0x08, 0x02, 0x4c, 0x8c, 0x0d, 0xc0, 0xac, 0x6e, 0xc4, 0x3e, 0x1b, 0x80, 0x19, 0xe4,
320 0xf7, 0x5f, 0x77, 0x51, 0x06, 0x87, 0x61, 0xde, 0xa2, 0x18, 0x0f, 0x40, 0x8b, 0x79, 0x72, 0xfa,
321 0x8d, 0x1a, 0x44, 0x47, 0x0d, 0x8e, 0x3a, 0x2d, 0xc7, 0x39, 0xbf, 0x56, 0x28, 0x97, 0xd9, 0x20,
322 0x4f, 0x00, 0x51, 0x3b,
325 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*a
= NULL
, *rrsig
= NULL
, *dnskey
= NULL
;
326 _cleanup_(dns_answer_unrefp
) DnsAnswer
*answer
= NULL
;
329 a
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_A
, "nAsA.gov");
332 a
->a
.in_addr
.s_addr
= inet_addr("52.0.14.116");
334 log_info("A: %s", strna(dns_resource_record_to_string(a
)));
336 rrsig
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_RRSIG
, "NaSa.GOV.");
339 rrsig
->rrsig
.type_covered
= DNS_TYPE_A
;
340 rrsig
->rrsig
.algorithm
= DNSSEC_ALGORITHM_RSASHA256
;
341 rrsig
->rrsig
.labels
= 2;
342 rrsig
->rrsig
.original_ttl
= 600;
343 rrsig
->rrsig
.expiration
= 0x5683135c;
344 rrsig
->rrsig
.inception
= 0x565b7da8;
345 rrsig
->rrsig
.key_tag
= 63876;
346 rrsig
->rrsig
.signer
= strdup("Nasa.Gov.");
347 assert_se(rrsig
->rrsig
.signer
);
348 rrsig
->rrsig
.signature_size
= sizeof(signature_blob
);
349 rrsig
->rrsig
.signature
= memdup(signature_blob
, rrsig
->rrsig
.signature_size
);
350 assert_se(rrsig
->rrsig
.signature
);
352 log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig
)));
354 dnskey
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_DNSKEY
, "nASA.gOV");
357 dnskey
->dnskey
.flags
= 256;
358 dnskey
->dnskey
.protocol
= 3;
359 dnskey
->dnskey
.algorithm
= DNSSEC_ALGORITHM_RSASHA256
;
360 dnskey
->dnskey
.key_size
= sizeof(dnskey_blob
);
361 dnskey
->dnskey
.key
= memdup(dnskey_blob
, sizeof(dnskey_blob
));
362 assert_se(dnskey
->dnskey
.key
);
364 log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey
)));
365 log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey
, false));
367 assert_se(dnssec_key_match_rrsig(a
->key
, rrsig
) > 0);
368 assert_se(dnssec_rrsig_match_dnskey(rrsig
, dnskey
, false) > 0);
370 answer
= dns_answer_new(1);
372 assert_se(dns_answer_add(answer
, a
, 0, DNS_ANSWER_AUTHENTICATED
) >= 0);
374 /* Validate the RR as it if was 2015-12-2 today */
375 assert_se(dnssec_verify_rrset(answer
, a
->key
, rrsig
, dnskey
, 1449092754*USEC_PER_SEC
, &result
) >= 0);
376 assert_se(result
== DNSSEC_VALIDATED
);
379 static void test_dnssec_verify_rrset2(void) {
381 static const uint8_t signature_blob
[] = {
382 0x48, 0x45, 0xc8, 0x8b, 0xc0, 0x14, 0x92, 0xf5, 0x15, 0xc6, 0x84, 0x9d, 0x2f, 0xe3, 0x32, 0x11,
383 0x7d, 0xf1, 0xe6, 0x87, 0xb9, 0x42, 0xd3, 0x8b, 0x9e, 0xaf, 0x92, 0x31, 0x0a, 0x53, 0xad, 0x8b,
384 0xa7, 0x5c, 0x83, 0x39, 0x8c, 0x28, 0xac, 0xce, 0x6e, 0x9c, 0x18, 0xe3, 0x31, 0x16, 0x6e, 0xca,
385 0x38, 0x31, 0xaf, 0xd9, 0x94, 0xf1, 0x84, 0xb1, 0xdf, 0x5a, 0xc2, 0x73, 0x22, 0xf6, 0xcb, 0xa2,
386 0xe7, 0x8c, 0x77, 0x0c, 0x74, 0x2f, 0xc2, 0x13, 0xb0, 0x93, 0x51, 0xa9, 0x4f, 0xae, 0x0a, 0xda,
387 0x45, 0xcc, 0xfd, 0x43, 0x99, 0x36, 0x9a, 0x0d, 0x21, 0xe0, 0xeb, 0x30, 0x65, 0xd4, 0xa0, 0x27,
388 0x37, 0x3b, 0xe4, 0xc1, 0xc5, 0xa1, 0x2a, 0xd1, 0x76, 0xc4, 0x7e, 0x64, 0x0e, 0x5a, 0xa6, 0x50,
389 0x24, 0xd5, 0x2c, 0xcc, 0x6d, 0xe5, 0x37, 0xea, 0xbd, 0x09, 0x34, 0xed, 0x24, 0x06, 0xa1, 0x22,
392 static const uint8_t dnskey_blob
[] = {
393 0x03, 0x01, 0x00, 0x01, 0xc3, 0x7f, 0x1d, 0xd1, 0x1c, 0x97, 0xb1, 0x13, 0x34, 0x3a, 0x9a, 0xea,
394 0xee, 0xd9, 0x5a, 0x11, 0x1b, 0x17, 0xc7, 0xe3, 0xd4, 0xda, 0x20, 0xbc, 0x5d, 0xba, 0x74, 0xe3,
395 0x37, 0x99, 0xec, 0x25, 0xce, 0x93, 0x7f, 0xbd, 0x22, 0x73, 0x7e, 0x14, 0x71, 0xe0, 0x60, 0x07,
396 0xd4, 0x39, 0x8b, 0x5e, 0xe9, 0xba, 0x25, 0xe8, 0x49, 0xe9, 0x34, 0xef, 0xfe, 0x04, 0x5c, 0xa5,
397 0x27, 0xcd, 0xa9, 0xda, 0x70, 0x05, 0x21, 0xab, 0x15, 0x82, 0x24, 0xc3, 0x94, 0xf5, 0xd7, 0xb7,
398 0xc4, 0x66, 0xcb, 0x32, 0x6e, 0x60, 0x2b, 0x55, 0x59, 0x28, 0x89, 0x8a, 0x72, 0xde, 0x88, 0x56,
399 0x27, 0x95, 0xd9, 0xac, 0x88, 0x4f, 0x65, 0x2b, 0x68, 0xfc, 0xe6, 0x41, 0xc1, 0x1b, 0xef, 0x4e,
400 0xd6, 0xc2, 0x0f, 0x64, 0x88, 0x95, 0x5e, 0xdd, 0x3a, 0x02, 0x07, 0x50, 0xa9, 0xda, 0xa4, 0x49,
401 0x74, 0x62, 0xfe, 0xd7,
404 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*nsec
= NULL
, *rrsig
= NULL
, *dnskey
= NULL
;
405 _cleanup_(dns_answer_unrefp
) DnsAnswer
*answer
= NULL
;
408 nsec
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_NSEC
, "nasa.gov");
411 nsec
->nsec
.next_domain_name
= strdup("3D-Printing.nasa.gov");
412 assert_se(nsec
->nsec
.next_domain_name
);
414 nsec
->nsec
.types
= bitmap_new();
415 assert_se(nsec
->nsec
.types
);
416 assert_se(bitmap_set(nsec
->nsec
.types
, DNS_TYPE_A
) >= 0);
417 assert_se(bitmap_set(nsec
->nsec
.types
, DNS_TYPE_NS
) >= 0);
418 assert_se(bitmap_set(nsec
->nsec
.types
, DNS_TYPE_SOA
) >= 0);
419 assert_se(bitmap_set(nsec
->nsec
.types
, DNS_TYPE_MX
) >= 0);
420 assert_se(bitmap_set(nsec
->nsec
.types
, DNS_TYPE_TXT
) >= 0);
421 assert_se(bitmap_set(nsec
->nsec
.types
, DNS_TYPE_RRSIG
) >= 0);
422 assert_se(bitmap_set(nsec
->nsec
.types
, DNS_TYPE_NSEC
) >= 0);
423 assert_se(bitmap_set(nsec
->nsec
.types
, DNS_TYPE_DNSKEY
) >= 0);
424 assert_se(bitmap_set(nsec
->nsec
.types
, 65534) >= 0);
426 log_info("NSEC: %s", strna(dns_resource_record_to_string(nsec
)));
428 rrsig
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_RRSIG
, "NaSa.GOV.");
431 rrsig
->rrsig
.type_covered
= DNS_TYPE_NSEC
;
432 rrsig
->rrsig
.algorithm
= DNSSEC_ALGORITHM_RSASHA256
;
433 rrsig
->rrsig
.labels
= 2;
434 rrsig
->rrsig
.original_ttl
= 300;
435 rrsig
->rrsig
.expiration
= 0x5689002f;
436 rrsig
->rrsig
.inception
= 0x56617230;
437 rrsig
->rrsig
.key_tag
= 30390;
438 rrsig
->rrsig
.signer
= strdup("Nasa.Gov.");
439 assert_se(rrsig
->rrsig
.signer
);
440 rrsig
->rrsig
.signature_size
= sizeof(signature_blob
);
441 rrsig
->rrsig
.signature
= memdup(signature_blob
, rrsig
->rrsig
.signature_size
);
442 assert_se(rrsig
->rrsig
.signature
);
444 log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig
)));
446 dnskey
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_DNSKEY
, "nASA.gOV");
449 dnskey
->dnskey
.flags
= 256;
450 dnskey
->dnskey
.protocol
= 3;
451 dnskey
->dnskey
.algorithm
= DNSSEC_ALGORITHM_RSASHA256
;
452 dnskey
->dnskey
.key_size
= sizeof(dnskey_blob
);
453 dnskey
->dnskey
.key
= memdup(dnskey_blob
, sizeof(dnskey_blob
));
454 assert_se(dnskey
->dnskey
.key
);
456 log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey
)));
457 log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey
, false));
459 assert_se(dnssec_key_match_rrsig(nsec
->key
, rrsig
) > 0);
460 assert_se(dnssec_rrsig_match_dnskey(rrsig
, dnskey
, false) > 0);
462 answer
= dns_answer_new(1);
464 assert_se(dns_answer_add(answer
, nsec
, 0, DNS_ANSWER_AUTHENTICATED
) >= 0);
466 /* Validate the RR as it if was 2015-12-11 today */
467 assert_se(dnssec_verify_rrset(answer
, nsec
->key
, rrsig
, dnskey
, 1449849318*USEC_PER_SEC
, &result
) >= 0);
468 assert_se(result
== DNSSEC_VALIDATED
);
471 static void test_dnssec_nsec3_hash(void) {
472 static const uint8_t salt
[] = { 0xB0, 0x1D, 0xFA, 0xCE };
473 static const uint8_t next_hashed_name
[] = { 0x84, 0x10, 0x26, 0x53, 0xc9, 0xfa, 0x4d, 0x85, 0x6c, 0x97, 0x82, 0xe2, 0x8f, 0xdf, 0x2d, 0x5e, 0x87, 0x69, 0xc4, 0x52 };
474 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
475 uint8_t h
[DNSSEC_HASH_SIZE_MAX
];
476 _cleanup_free_
char *b
= NULL
;
479 /* The NSEC3 RR for eurid.eu on 2015-12-14. */
480 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_NSEC3
, "PJ8S08RR45VIQDAQGE7EN3VHKNROTBMM.eurid.eu.");
483 rr
->nsec3
.algorithm
= DNSSEC_DIGEST_SHA1
;
485 rr
->nsec3
.iterations
= 1;
486 rr
->nsec3
.salt
= memdup(salt
, sizeof(salt
));
487 assert_se(rr
->nsec3
.salt
);
488 rr
->nsec3
.salt_size
= sizeof(salt
);
489 rr
->nsec3
.next_hashed_name
= memdup(next_hashed_name
, sizeof(next_hashed_name
));
490 assert_se(rr
->nsec3
.next_hashed_name
);
491 rr
->nsec3
.next_hashed_name_size
= sizeof(next_hashed_name
);
493 log_info("NSEC3: %s", strna(dns_resource_record_to_string(rr
)));
495 k
= dnssec_nsec3_hash(rr
, "eurid.eu", &h
);
498 b
= base32hexmem(h
, k
, false);
500 assert_se(strcasecmp(b
, "PJ8S08RR45VIQDAQGE7EN3VHKNROTBMM") == 0);
505 int main(int argc
, char*argv
[]) {
507 test_dnssec_canonicalize();
510 test_dnssec_verify_dns_key();
511 test_dnssec_verify_rfc8080_ed25519_example1();
512 test_dnssec_verify_rfc8080_ed25519_example2();
513 test_dnssec_verify_rrset();
514 test_dnssec_verify_rrset2();
515 test_dnssec_nsec3_hash();