1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2015 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include <arpa/inet.h>
23 #include <netinet/in.h>
24 #include <sys/socket.h>
26 #include "alloc-util.h"
27 #include "resolved-dns-dnssec.h"
28 #include "resolved-dns-rr.h"
29 #include "string-util.h"
30 #include "hexdecoct.h"
32 static void test_dnssec_canonicalize_one(const char *original
, const char *canonical
, int r
) {
33 char canonicalized
[DNSSEC_CANONICAL_HOSTNAME_MAX
];
35 assert_se(dnssec_canonicalize(original
, canonicalized
, sizeof(canonicalized
)) == r
);
39 assert_se(streq(canonicalized
, canonical
));
42 static void test_dnssec_canonicalize(void) {
43 test_dnssec_canonicalize_one("", ".", 1);
44 test_dnssec_canonicalize_one(".", ".", 1);
45 test_dnssec_canonicalize_one("foo", "foo.", 4);
46 test_dnssec_canonicalize_one("foo.", "foo.", 4);
47 test_dnssec_canonicalize_one("FOO.", "foo.", 4);
48 test_dnssec_canonicalize_one("FOO.bar.", "foo.bar.", 8);
49 test_dnssec_canonicalize_one("FOO..bar.", NULL
, -EINVAL
);
54 static void test_dnssec_verify_dns_key(void) {
56 static const uint8_t ds1_fprint
[] = {
57 0x46, 0x8B, 0xC8, 0xDD, 0xC7, 0xE8, 0x27, 0x03, 0x40, 0xBB, 0x8A, 0x1F, 0x3B, 0x2E, 0x45, 0x9D,
58 0x80, 0x67, 0x14, 0x01,
60 static const uint8_t ds2_fprint
[] = {
61 0x8A, 0xEE, 0x80, 0x47, 0x05, 0x5F, 0x83, 0xD1, 0x48, 0xBA, 0x8F, 0xF6, 0xDD, 0xA7, 0x60, 0xCE,
62 0x94, 0xF7, 0xC7, 0x5E, 0x52, 0x4C, 0xF2, 0xE9, 0x50, 0xB9, 0x2E, 0xCB, 0xEF, 0x96, 0xB9, 0x98,
64 static const uint8_t dnskey_blob
[] = {
65 0x03, 0x01, 0x00, 0x01, 0xa8, 0x12, 0xda, 0x4f, 0xd2, 0x7d, 0x54, 0x14, 0x0e, 0xcc, 0x5b, 0x5e,
66 0x45, 0x9c, 0x96, 0x98, 0xc0, 0xc0, 0x85, 0x81, 0xb1, 0x47, 0x8c, 0x7d, 0xe8, 0x39, 0x50, 0xcc,
67 0xc5, 0xd0, 0xf2, 0x00, 0x81, 0x67, 0x79, 0xf6, 0xcc, 0x9d, 0xad, 0x6c, 0xbb, 0x7b, 0x6f, 0x48,
68 0x97, 0x15, 0x1c, 0xfd, 0x0b, 0xfe, 0xd3, 0xd7, 0x7d, 0x9f, 0x81, 0x26, 0xd3, 0xc5, 0x65, 0x49,
69 0xcf, 0x46, 0x62, 0xb0, 0x55, 0x6e, 0x47, 0xc7, 0x30, 0xef, 0x51, 0xfb, 0x3e, 0xc6, 0xef, 0xde,
70 0x27, 0x3f, 0xfa, 0x57, 0x2d, 0xa7, 0x1d, 0x80, 0x46, 0x9a, 0x5f, 0x14, 0xb3, 0xb0, 0x2c, 0xbe,
71 0x72, 0xca, 0xdf, 0xb2, 0xff, 0x36, 0x5b, 0x4f, 0xec, 0x58, 0x8e, 0x8d, 0x01, 0xe9, 0xa9, 0xdf,
72 0xb5, 0x60, 0xad, 0x52, 0x4d, 0xfc, 0xa9, 0x3e, 0x8d, 0x35, 0x95, 0xb3, 0x4e, 0x0f, 0xca, 0x45,
73 0x1b, 0xf7, 0xef, 0x3a, 0x88, 0x25, 0x08, 0xc7, 0x4e, 0x06, 0xc1, 0x62, 0x1a, 0xce, 0xd8, 0x77,
74 0xbd, 0x02, 0x65, 0xf8, 0x49, 0xfb, 0xce, 0xf6, 0xa8, 0x09, 0xfc, 0xde, 0xb2, 0x09, 0x9d, 0x39,
75 0xf8, 0x63, 0x9c, 0x32, 0x42, 0x7c, 0xa0, 0x30, 0x86, 0x72, 0x7a, 0x4a, 0xc6, 0xd4, 0xb3, 0x2d,
76 0x24, 0xef, 0x96, 0x3f, 0xc2, 0xda, 0xd3, 0xf2, 0x15, 0x6f, 0xda, 0x65, 0x4b, 0x81, 0x28, 0x68,
77 0xf4, 0xfe, 0x3e, 0x71, 0x4f, 0x50, 0x96, 0x72, 0x58, 0xa1, 0x89, 0xdd, 0x01, 0x61, 0x39, 0x39,
78 0xc6, 0x76, 0xa4, 0xda, 0x02, 0x70, 0x3d, 0xc0, 0xdc, 0x8d, 0x70, 0x72, 0x04, 0x90, 0x79, 0xd4,
79 0xec, 0x65, 0xcf, 0x49, 0x35, 0x25, 0x3a, 0x14, 0x1a, 0x45, 0x20, 0xeb, 0x31, 0xaf, 0x92, 0xba,
80 0x20, 0xd3, 0xcd, 0xa7, 0x13, 0x44, 0xdc, 0xcf, 0xf0, 0x27, 0x34, 0xb9, 0xe7, 0x24, 0x6f, 0x73,
81 0xe7, 0xea, 0x77, 0x03,
84 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*dnskey
= NULL
, *ds1
= NULL
, *ds2
= NULL
;
86 /* The two DS RRs in effect for nasa.gov on 2015-12-01. */
87 ds1
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_DS
, "nasa.gov");
90 ds1
->ds
.key_tag
= 47857;
91 ds1
->ds
.algorithm
= DNSSEC_ALGORITHM_RSASHA256
;
92 ds1
->ds
.digest_type
= DNSSEC_DIGEST_SHA1
;
93 ds1
->ds
.digest_size
= sizeof(ds1_fprint
);
94 ds1
->ds
.digest
= memdup(ds1_fprint
, ds1
->ds
.digest_size
);
95 assert_se(ds1
->ds
.digest
);
97 log_info("DS1: %s", strna(dns_resource_record_to_string(ds1
)));
99 ds2
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_DS
, "NASA.GOV");
102 ds2
->ds
.key_tag
= 47857;
103 ds2
->ds
.algorithm
= DNSSEC_ALGORITHM_RSASHA256
;
104 ds2
->ds
.digest_type
= DNSSEC_DIGEST_SHA256
;
105 ds2
->ds
.digest_size
= sizeof(ds2_fprint
);
106 ds2
->ds
.digest
= memdup(ds2_fprint
, ds2
->ds
.digest_size
);
107 assert_se(ds2
->ds
.digest
);
109 log_info("DS2: %s", strna(dns_resource_record_to_string(ds2
)));
111 dnskey
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_DNSKEY
, "nasa.GOV");
114 dnskey
->dnskey
.flags
= 257;
115 dnskey
->dnskey
.protocol
= 3;
116 dnskey
->dnskey
.algorithm
= DNSSEC_ALGORITHM_RSASHA256
;
117 dnskey
->dnskey
.key_size
= sizeof(dnskey_blob
);
118 dnskey
->dnskey
.key
= memdup(dnskey_blob
, sizeof(dnskey_blob
));
119 assert_se(dnskey
->dnskey
.key
);
121 log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey
)));
122 log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey
, false));
124 assert_se(dnssec_verify_dnskey_by_ds(dnskey
, ds1
, false) > 0);
125 assert_se(dnssec_verify_dnskey_by_ds(dnskey
, ds2
, false) > 0);
128 static void test_dnssec_verify_rfc8080_ed25519_example1(void) {
129 static const uint8_t dnskey_blob
[] = {
130 0x97, 0x4d, 0x96, 0xa2, 0x2d, 0x22, 0x4b, 0xc0, 0x1a, 0xdb, 0x91, 0x50, 0x91, 0x47, 0x7d,
131 0x44, 0xcc, 0xd9, 0x1c, 0x9a, 0x41, 0xa1, 0x14, 0x30, 0x01, 0x01, 0x17, 0xd5, 0x2c, 0x59,
134 static const uint8_t ds_fprint
[] = {
135 0xdd, 0xa6, 0xb9, 0x69, 0xbd, 0xfb, 0x79, 0xf7, 0x1e, 0xe7, 0xb7, 0xfb, 0xdf, 0xb7, 0xdc,
136 0xd7, 0xad, 0xbb, 0xd3, 0x5d, 0xdf, 0x79, 0xed, 0x3b, 0x6d, 0xd7, 0xf6, 0xe3, 0x56, 0xdd,
137 0xd7, 0x47, 0xf7, 0x6f, 0x5f, 0x7a, 0xe1, 0xa6, 0xf9, 0xe5, 0xce, 0xfc, 0x7b, 0xbf, 0x5a,
140 static const uint8_t signature_blob
[] = {
141 0xa0, 0xbf, 0x64, 0xac, 0x9b, 0xa7, 0xef, 0x17, 0xc1, 0x38, 0x85, 0x9c, 0x18, 0x78, 0xbb,
142 0x99, 0xa8, 0x39, 0xfe, 0x17, 0x59, 0xac, 0xa5, 0xb0, 0xd7, 0x98, 0xcf, 0x1a, 0xb1, 0xe9,
143 0x8d, 0x07, 0x91, 0x02, 0xf4, 0xdd, 0xb3, 0x36, 0x8f, 0x0f, 0xe4, 0x0b, 0xb3, 0x77, 0xf1,
144 0xf0, 0x0e, 0x0c, 0xdd, 0xed, 0xb7, 0x99, 0x16, 0x7d, 0x56, 0xb6, 0xe9, 0x32, 0x78, 0x30,
145 0x72, 0xba, 0x8d, 0x02
148 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*dnskey
= NULL
, *ds
= NULL
, *mx
= NULL
,
150 _cleanup_(dns_answer_unrefp
) DnsAnswer
*answer
= NULL
;
153 dnskey
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_DNSKEY
, "example.com.");
156 dnskey
->dnskey
.flags
= 257;
157 dnskey
->dnskey
.protocol
= 3;
158 dnskey
->dnskey
.algorithm
= DNSSEC_ALGORITHM_ED25519
;
159 dnskey
->dnskey
.key_size
= sizeof(dnskey_blob
);
160 dnskey
->dnskey
.key
= memdup(dnskey_blob
, sizeof(dnskey_blob
));
161 assert_se(dnskey
->dnskey
.key
);
163 log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey
)));
165 ds
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_DS
, "example.com.");
168 ds
->ds
.key_tag
= 3613;
169 ds
->ds
.algorithm
= DNSSEC_ALGORITHM_ED25519
;
170 ds
->ds
.digest_type
= DNSSEC_DIGEST_SHA256
;
171 ds
->ds
.digest_size
= sizeof(ds_fprint
);
172 ds
->ds
.digest
= memdup(ds_fprint
, ds
->ds
.digest_size
);
173 assert_se(ds
->ds
.digest
);
175 log_info("DS: %s", strna(dns_resource_record_to_string(ds
)));
177 mx
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_MX
, "example.com.");
180 mx
->mx
.priority
= 10;
181 mx
->mx
.exchange
= strdup("mail.example.com.");
182 assert_se(mx
->mx
.exchange
);
184 log_info("MX: %s", strna(dns_resource_record_to_string(mx
)));
186 rrsig
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_RRSIG
, "example.com.");
189 rrsig
->rrsig
.type_covered
= DNS_TYPE_MX
;
190 rrsig
->rrsig
.algorithm
= DNSSEC_ALGORITHM_ED25519
;
191 rrsig
->rrsig
.labels
= 2;
192 rrsig
->rrsig
.original_ttl
= 3600;
193 rrsig
->rrsig
.expiration
= 1440021600;
194 rrsig
->rrsig
.inception
= 1438207200;
195 rrsig
->rrsig
.key_tag
= 3613;
196 rrsig
->rrsig
.signer
= strdup("example.com.");
197 assert_se(rrsig
->rrsig
.signer
);
198 rrsig
->rrsig
.signature_size
= sizeof(signature_blob
);
199 rrsig
->rrsig
.signature
= memdup(signature_blob
, rrsig
->rrsig
.signature_size
);
200 assert_se(rrsig
->rrsig
.signature
);
202 log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig
)));
204 assert_se(dnssec_key_match_rrsig(mx
->key
, rrsig
) > 0);
205 assert_se(dnssec_rrsig_match_dnskey(rrsig
, dnskey
, false) > 0);
207 answer
= dns_answer_new(1);
209 assert_se(dns_answer_add(answer
, mx
, 0, DNS_ANSWER_AUTHENTICATED
) >= 0);
211 assert_se(dnssec_verify_rrset(answer
, mx
->key
, rrsig
, dnskey
,
212 rrsig
->rrsig
.inception
* USEC_PER_SEC
, &result
) >= 0);
213 #if GCRYPT_VERSION_NUMBER >= 0x010600
214 assert_se(result
== DNSSEC_VALIDATED
);
216 assert_se(result
== DNSSEC_UNSUPPORTED_ALGORITHM
);
220 static void test_dnssec_verify_rfc8080_ed25519_example2(void) {
221 static const uint8_t dnskey_blob
[] = {
222 0xcc, 0xf9, 0xd9, 0xfd, 0x0c, 0x04, 0x7b, 0xb4, 0xbc, 0x0b, 0x94, 0x8f, 0xcf, 0x63, 0x9f,
223 0x4b, 0x94, 0x51, 0xe3, 0x40, 0x13, 0x93, 0x6f, 0xeb, 0x62, 0x71, 0x3d, 0xc4, 0x72, 0x4,
226 static const uint8_t ds_fprint
[] = {
227 0xe3, 0x4d, 0x7b, 0xf3, 0x56, 0xfd, 0xdf, 0x87, 0xb7, 0xf7, 0x67, 0x5e, 0xe3, 0xdd, 0x9e,
228 0x73, 0xbe, 0xda, 0x7b, 0x67, 0xb5, 0xe5, 0xde, 0xf4, 0x7f, 0xae, 0x7b, 0xe5, 0xad, 0x5c,
229 0xd1, 0xb7, 0x39, 0xf5, 0xce, 0x76, 0xef, 0x97, 0x34, 0xe1, 0xe6, 0xde, 0xf3, 0x47, 0x3a,
232 static const uint8_t signature_blob
[] = {
233 0xcd, 0x74, 0x34, 0x6e, 0x46, 0x20, 0x41, 0x31, 0x05, 0xc9, 0xf2, 0xf2, 0x8b, 0xd4, 0x28,
234 0x89, 0x8e, 0x83, 0xf1, 0x97, 0x58, 0xa3, 0x8c, 0x32, 0x52, 0x15, 0x62, 0xa1, 0x86, 0x57,
235 0x15, 0xd4, 0xf8, 0xd7, 0x44, 0x0f, 0x44, 0x84, 0xd0, 0x4a, 0xa2, 0x52, 0x9f, 0x34, 0x28,
236 0x4a, 0x6e, 0x69, 0xa0, 0x9e, 0xe0, 0x0f, 0xb0, 0x10, 0x47, 0x43, 0xbb, 0x2a, 0xe2, 0x39,
237 0x93, 0x6a, 0x5c, 0x06
240 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*dnskey
= NULL
, *ds
= NULL
, *mx
= NULL
,
242 _cleanup_(dns_answer_unrefp
) DnsAnswer
*answer
= NULL
;
245 dnskey
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_DNSKEY
, "example.com.");
248 dnskey
->dnskey
.flags
= 257;
249 dnskey
->dnskey
.protocol
= 3;
250 dnskey
->dnskey
.algorithm
= DNSSEC_ALGORITHM_ED25519
;
251 dnskey
->dnskey
.key_size
= sizeof(dnskey_blob
);
252 dnskey
->dnskey
.key
= memdup(dnskey_blob
, sizeof(dnskey_blob
));
253 assert_se(dnskey
->dnskey
.key
);
255 log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey
)));
257 ds
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_DS
, "example.com.");
260 ds
->ds
.key_tag
= 35217;
261 ds
->ds
.algorithm
= DNSSEC_ALGORITHM_ED25519
;
262 ds
->ds
.digest_type
= DNSSEC_DIGEST_SHA256
;
263 ds
->ds
.digest_size
= sizeof(ds_fprint
);
264 ds
->ds
.digest
= memdup(ds_fprint
, ds
->ds
.digest_size
);
265 assert_se(ds
->ds
.digest
);
267 log_info("DS: %s", strna(dns_resource_record_to_string(ds
)));
269 mx
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_MX
, "example.com.");
272 mx
->mx
.priority
= 10;
273 mx
->mx
.exchange
= strdup("mail.example.com.");
274 assert_se(mx
->mx
.exchange
);
276 log_info("MX: %s", strna(dns_resource_record_to_string(mx
)));
278 rrsig
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_RRSIG
, "example.com.");
281 rrsig
->rrsig
.type_covered
= DNS_TYPE_MX
;
282 rrsig
->rrsig
.algorithm
= DNSSEC_ALGORITHM_ED25519
;
283 rrsig
->rrsig
.labels
= 2;
284 rrsig
->rrsig
.original_ttl
= 3600;
285 rrsig
->rrsig
.expiration
= 1440021600;
286 rrsig
->rrsig
.inception
= 1438207200;
287 rrsig
->rrsig
.key_tag
= 35217;
288 rrsig
->rrsig
.signer
= strdup("example.com.");
289 assert_se(rrsig
->rrsig
.signer
);
290 rrsig
->rrsig
.signature_size
= sizeof(signature_blob
);
291 rrsig
->rrsig
.signature
= memdup(signature_blob
, rrsig
->rrsig
.signature_size
);
292 assert_se(rrsig
->rrsig
.signature
);
294 log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig
)));
296 assert_se(dnssec_key_match_rrsig(mx
->key
, rrsig
) > 0);
297 assert_se(dnssec_rrsig_match_dnskey(rrsig
, dnskey
, false) > 0);
299 answer
= dns_answer_new(1);
301 assert_se(dns_answer_add(answer
, mx
, 0, DNS_ANSWER_AUTHENTICATED
) >= 0);
303 assert_se(dnssec_verify_rrset(answer
, mx
->key
, rrsig
, dnskey
,
304 rrsig
->rrsig
.inception
* USEC_PER_SEC
, &result
) >= 0);
305 #if GCRYPT_VERSION_NUMBER >= 0x010600
306 assert_se(result
== DNSSEC_VALIDATED
);
308 assert_se(result
== DNSSEC_UNSUPPORTED_ALGORITHM
);
311 static void test_dnssec_verify_rrset(void) {
313 static const uint8_t signature_blob
[] = {
314 0x7f, 0x79, 0xdd, 0x5e, 0x89, 0x79, 0x18, 0xd0, 0x34, 0x86, 0x8c, 0x72, 0x77, 0x75, 0x48, 0x4d,
315 0xc3, 0x7d, 0x38, 0x04, 0xab, 0xcd, 0x9e, 0x4c, 0x82, 0xb0, 0x92, 0xca, 0xe9, 0x66, 0xe9, 0x6e,
316 0x47, 0xc7, 0x68, 0x8c, 0x94, 0xf6, 0x69, 0xcb, 0x75, 0x94, 0xe6, 0x30, 0xa6, 0xfb, 0x68, 0x64,
317 0x96, 0x1a, 0x84, 0xe1, 0xdc, 0x16, 0x4c, 0x83, 0x6c, 0x44, 0xf2, 0x74, 0x4d, 0x74, 0x79, 0x8f,
318 0xf3, 0xf4, 0x63, 0x0d, 0xef, 0x5a, 0xe7, 0xe2, 0xfd, 0xf2, 0x2b, 0x38, 0x7c, 0x28, 0x96, 0x9d,
319 0xb6, 0xcd, 0x5c, 0x3b, 0x57, 0xe2, 0x24, 0x78, 0x65, 0xd0, 0x9e, 0x77, 0x83, 0x09, 0x6c, 0xff,
320 0x3d, 0x52, 0x3f, 0x6e, 0xd1, 0xed, 0x2e, 0xf9, 0xee, 0x8e, 0xa6, 0xbe, 0x9a, 0xa8, 0x87, 0x76,
321 0xd8, 0x77, 0xcc, 0x96, 0xa0, 0x98, 0xa1, 0xd1, 0x68, 0x09, 0x43, 0xcf, 0x56, 0xd9, 0xd1, 0x66,
324 static const uint8_t dnskey_blob
[] = {
325 0x03, 0x01, 0x00, 0x01, 0x9b, 0x49, 0x9b, 0xc1, 0xf9, 0x9a, 0xe0, 0x4e, 0xcf, 0xcb, 0x14, 0x45,
326 0x2e, 0xc9, 0xf9, 0x74, 0xa7, 0x18, 0xb5, 0xf3, 0xde, 0x39, 0x49, 0xdf, 0x63, 0x33, 0x97, 0x52,
327 0xe0, 0x8e, 0xac, 0x50, 0x30, 0x8e, 0x09, 0xd5, 0x24, 0x3d, 0x26, 0xa4, 0x49, 0x37, 0x2b, 0xb0,
328 0x6b, 0x1b, 0xdf, 0xde, 0x85, 0x83, 0xcb, 0x22, 0x4e, 0x60, 0x0a, 0x91, 0x1a, 0x1f, 0xc5, 0x40,
329 0xb1, 0xc3, 0x15, 0xc1, 0x54, 0x77, 0x86, 0x65, 0x53, 0xec, 0x10, 0x90, 0x0c, 0x91, 0x00, 0x5e,
330 0x15, 0xdc, 0x08, 0x02, 0x4c, 0x8c, 0x0d, 0xc0, 0xac, 0x6e, 0xc4, 0x3e, 0x1b, 0x80, 0x19, 0xe4,
331 0xf7, 0x5f, 0x77, 0x51, 0x06, 0x87, 0x61, 0xde, 0xa2, 0x18, 0x0f, 0x40, 0x8b, 0x79, 0x72, 0xfa,
332 0x8d, 0x1a, 0x44, 0x47, 0x0d, 0x8e, 0x3a, 0x2d, 0xc7, 0x39, 0xbf, 0x56, 0x28, 0x97, 0xd9, 0x20,
333 0x4f, 0x00, 0x51, 0x3b,
336 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*a
= NULL
, *rrsig
= NULL
, *dnskey
= NULL
;
337 _cleanup_(dns_answer_unrefp
) DnsAnswer
*answer
= NULL
;
340 a
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_A
, "nAsA.gov");
343 a
->a
.in_addr
.s_addr
= inet_addr("52.0.14.116");
345 log_info("A: %s", strna(dns_resource_record_to_string(a
)));
347 rrsig
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_RRSIG
, "NaSa.GOV.");
350 rrsig
->rrsig
.type_covered
= DNS_TYPE_A
;
351 rrsig
->rrsig
.algorithm
= DNSSEC_ALGORITHM_RSASHA256
;
352 rrsig
->rrsig
.labels
= 2;
353 rrsig
->rrsig
.original_ttl
= 600;
354 rrsig
->rrsig
.expiration
= 0x5683135c;
355 rrsig
->rrsig
.inception
= 0x565b7da8;
356 rrsig
->rrsig
.key_tag
= 63876;
357 rrsig
->rrsig
.signer
= strdup("Nasa.Gov.");
358 assert_se(rrsig
->rrsig
.signer
);
359 rrsig
->rrsig
.signature_size
= sizeof(signature_blob
);
360 rrsig
->rrsig
.signature
= memdup(signature_blob
, rrsig
->rrsig
.signature_size
);
361 assert_se(rrsig
->rrsig
.signature
);
363 log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig
)));
365 dnskey
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_DNSKEY
, "nASA.gOV");
368 dnskey
->dnskey
.flags
= 256;
369 dnskey
->dnskey
.protocol
= 3;
370 dnskey
->dnskey
.algorithm
= DNSSEC_ALGORITHM_RSASHA256
;
371 dnskey
->dnskey
.key_size
= sizeof(dnskey_blob
);
372 dnskey
->dnskey
.key
= memdup(dnskey_blob
, sizeof(dnskey_blob
));
373 assert_se(dnskey
->dnskey
.key
);
375 log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey
)));
376 log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey
, false));
378 assert_se(dnssec_key_match_rrsig(a
->key
, rrsig
) > 0);
379 assert_se(dnssec_rrsig_match_dnskey(rrsig
, dnskey
, false) > 0);
381 answer
= dns_answer_new(1);
383 assert_se(dns_answer_add(answer
, a
, 0, DNS_ANSWER_AUTHENTICATED
) >= 0);
385 /* Validate the RR as it if was 2015-12-2 today */
386 assert_se(dnssec_verify_rrset(answer
, a
->key
, rrsig
, dnskey
, 1449092754*USEC_PER_SEC
, &result
) >= 0);
387 assert_se(result
== DNSSEC_VALIDATED
);
390 static void test_dnssec_verify_rrset2(void) {
392 static const uint8_t signature_blob
[] = {
393 0x48, 0x45, 0xc8, 0x8b, 0xc0, 0x14, 0x92, 0xf5, 0x15, 0xc6, 0x84, 0x9d, 0x2f, 0xe3, 0x32, 0x11,
394 0x7d, 0xf1, 0xe6, 0x87, 0xb9, 0x42, 0xd3, 0x8b, 0x9e, 0xaf, 0x92, 0x31, 0x0a, 0x53, 0xad, 0x8b,
395 0xa7, 0x5c, 0x83, 0x39, 0x8c, 0x28, 0xac, 0xce, 0x6e, 0x9c, 0x18, 0xe3, 0x31, 0x16, 0x6e, 0xca,
396 0x38, 0x31, 0xaf, 0xd9, 0x94, 0xf1, 0x84, 0xb1, 0xdf, 0x5a, 0xc2, 0x73, 0x22, 0xf6, 0xcb, 0xa2,
397 0xe7, 0x8c, 0x77, 0x0c, 0x74, 0x2f, 0xc2, 0x13, 0xb0, 0x93, 0x51, 0xa9, 0x4f, 0xae, 0x0a, 0xda,
398 0x45, 0xcc, 0xfd, 0x43, 0x99, 0x36, 0x9a, 0x0d, 0x21, 0xe0, 0xeb, 0x30, 0x65, 0xd4, 0xa0, 0x27,
399 0x37, 0x3b, 0xe4, 0xc1, 0xc5, 0xa1, 0x2a, 0xd1, 0x76, 0xc4, 0x7e, 0x64, 0x0e, 0x5a, 0xa6, 0x50,
400 0x24, 0xd5, 0x2c, 0xcc, 0x6d, 0xe5, 0x37, 0xea, 0xbd, 0x09, 0x34, 0xed, 0x24, 0x06, 0xa1, 0x22,
403 static const uint8_t dnskey_blob
[] = {
404 0x03, 0x01, 0x00, 0x01, 0xc3, 0x7f, 0x1d, 0xd1, 0x1c, 0x97, 0xb1, 0x13, 0x34, 0x3a, 0x9a, 0xea,
405 0xee, 0xd9, 0x5a, 0x11, 0x1b, 0x17, 0xc7, 0xe3, 0xd4, 0xda, 0x20, 0xbc, 0x5d, 0xba, 0x74, 0xe3,
406 0x37, 0x99, 0xec, 0x25, 0xce, 0x93, 0x7f, 0xbd, 0x22, 0x73, 0x7e, 0x14, 0x71, 0xe0, 0x60, 0x07,
407 0xd4, 0x39, 0x8b, 0x5e, 0xe9, 0xba, 0x25, 0xe8, 0x49, 0xe9, 0x34, 0xef, 0xfe, 0x04, 0x5c, 0xa5,
408 0x27, 0xcd, 0xa9, 0xda, 0x70, 0x05, 0x21, 0xab, 0x15, 0x82, 0x24, 0xc3, 0x94, 0xf5, 0xd7, 0xb7,
409 0xc4, 0x66, 0xcb, 0x32, 0x6e, 0x60, 0x2b, 0x55, 0x59, 0x28, 0x89, 0x8a, 0x72, 0xde, 0x88, 0x56,
410 0x27, 0x95, 0xd9, 0xac, 0x88, 0x4f, 0x65, 0x2b, 0x68, 0xfc, 0xe6, 0x41, 0xc1, 0x1b, 0xef, 0x4e,
411 0xd6, 0xc2, 0x0f, 0x64, 0x88, 0x95, 0x5e, 0xdd, 0x3a, 0x02, 0x07, 0x50, 0xa9, 0xda, 0xa4, 0x49,
412 0x74, 0x62, 0xfe, 0xd7,
415 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*nsec
= NULL
, *rrsig
= NULL
, *dnskey
= NULL
;
416 _cleanup_(dns_answer_unrefp
) DnsAnswer
*answer
= NULL
;
419 nsec
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_NSEC
, "nasa.gov");
422 nsec
->nsec
.next_domain_name
= strdup("3D-Printing.nasa.gov");
423 assert_se(nsec
->nsec
.next_domain_name
);
425 nsec
->nsec
.types
= bitmap_new();
426 assert_se(nsec
->nsec
.types
);
427 assert_se(bitmap_set(nsec
->nsec
.types
, DNS_TYPE_A
) >= 0);
428 assert_se(bitmap_set(nsec
->nsec
.types
, DNS_TYPE_NS
) >= 0);
429 assert_se(bitmap_set(nsec
->nsec
.types
, DNS_TYPE_SOA
) >= 0);
430 assert_se(bitmap_set(nsec
->nsec
.types
, DNS_TYPE_MX
) >= 0);
431 assert_se(bitmap_set(nsec
->nsec
.types
, DNS_TYPE_TXT
) >= 0);
432 assert_se(bitmap_set(nsec
->nsec
.types
, DNS_TYPE_RRSIG
) >= 0);
433 assert_se(bitmap_set(nsec
->nsec
.types
, DNS_TYPE_NSEC
) >= 0);
434 assert_se(bitmap_set(nsec
->nsec
.types
, DNS_TYPE_DNSKEY
) >= 0);
435 assert_se(bitmap_set(nsec
->nsec
.types
, 65534) >= 0);
437 log_info("NSEC: %s", strna(dns_resource_record_to_string(nsec
)));
439 rrsig
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_RRSIG
, "NaSa.GOV.");
442 rrsig
->rrsig
.type_covered
= DNS_TYPE_NSEC
;
443 rrsig
->rrsig
.algorithm
= DNSSEC_ALGORITHM_RSASHA256
;
444 rrsig
->rrsig
.labels
= 2;
445 rrsig
->rrsig
.original_ttl
= 300;
446 rrsig
->rrsig
.expiration
= 0x5689002f;
447 rrsig
->rrsig
.inception
= 0x56617230;
448 rrsig
->rrsig
.key_tag
= 30390;
449 rrsig
->rrsig
.signer
= strdup("Nasa.Gov.");
450 assert_se(rrsig
->rrsig
.signer
);
451 rrsig
->rrsig
.signature_size
= sizeof(signature_blob
);
452 rrsig
->rrsig
.signature
= memdup(signature_blob
, rrsig
->rrsig
.signature_size
);
453 assert_se(rrsig
->rrsig
.signature
);
455 log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig
)));
457 dnskey
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_DNSKEY
, "nASA.gOV");
460 dnskey
->dnskey
.flags
= 256;
461 dnskey
->dnskey
.protocol
= 3;
462 dnskey
->dnskey
.algorithm
= DNSSEC_ALGORITHM_RSASHA256
;
463 dnskey
->dnskey
.key_size
= sizeof(dnskey_blob
);
464 dnskey
->dnskey
.key
= memdup(dnskey_blob
, sizeof(dnskey_blob
));
465 assert_se(dnskey
->dnskey
.key
);
467 log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey
)));
468 log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey
, false));
470 assert_se(dnssec_key_match_rrsig(nsec
->key
, rrsig
) > 0);
471 assert_se(dnssec_rrsig_match_dnskey(rrsig
, dnskey
, false) > 0);
473 answer
= dns_answer_new(1);
475 assert_se(dns_answer_add(answer
, nsec
, 0, DNS_ANSWER_AUTHENTICATED
) >= 0);
477 /* Validate the RR as it if was 2015-12-11 today */
478 assert_se(dnssec_verify_rrset(answer
, nsec
->key
, rrsig
, dnskey
, 1449849318*USEC_PER_SEC
, &result
) >= 0);
479 assert_se(result
== DNSSEC_VALIDATED
);
482 static void test_dnssec_nsec3_hash(void) {
483 static const uint8_t salt
[] = { 0xB0, 0x1D, 0xFA, 0xCE };
484 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 };
485 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
486 uint8_t h
[DNSSEC_HASH_SIZE_MAX
];
487 _cleanup_free_
char *b
= NULL
;
490 /* The NSEC3 RR for eurid.eu on 2015-12-14. */
491 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_NSEC3
, "PJ8S08RR45VIQDAQGE7EN3VHKNROTBMM.eurid.eu.");
494 rr
->nsec3
.algorithm
= DNSSEC_DIGEST_SHA1
;
496 rr
->nsec3
.iterations
= 1;
497 rr
->nsec3
.salt
= memdup(salt
, sizeof(salt
));
498 assert_se(rr
->nsec3
.salt
);
499 rr
->nsec3
.salt_size
= sizeof(salt
);
500 rr
->nsec3
.next_hashed_name
= memdup(next_hashed_name
, sizeof(next_hashed_name
));
501 assert_se(rr
->nsec3
.next_hashed_name
);
502 rr
->nsec3
.next_hashed_name_size
= sizeof(next_hashed_name
);
504 log_info("NSEC3: %s", strna(dns_resource_record_to_string(rr
)));
506 k
= dnssec_nsec3_hash(rr
, "eurid.eu", &h
);
509 b
= base32hexmem(h
, k
, false);
511 assert_se(strcasecmp(b
, "PJ8S08RR45VIQDAQGE7EN3VHKNROTBMM") == 0);
516 int main(int argc
, char*argv
[]) {
518 test_dnssec_canonicalize();
521 test_dnssec_verify_dns_key();
522 test_dnssec_verify_rfc8080_ed25519_example1();
523 test_dnssec_verify_rfc8080_ed25519_example2();
524 test_dnssec_verify_rrset();
525 test_dnssec_verify_rrset2();
526 test_dnssec_nsec3_hash();