]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/test-dnssec.c
Merge pull request #7606 from yuwata/run-timer
[thirdparty/systemd.git] / src / resolve / test-dnssec.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2015 Lennart Poettering
6
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.
11
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.
16
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/>.
19 ***/
20
21 #include <arpa/inet.h>
22 #include <gcrypt.h>
23 #include <netinet/in.h>
24 #include <sys/socket.h>
25
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"
31
32 static void test_dnssec_canonicalize_one(const char *original, const char *canonical, int r) {
33 char canonicalized[DNSSEC_CANONICAL_HOSTNAME_MAX];
34
35 assert_se(dnssec_canonicalize(original, canonicalized, sizeof(canonicalized)) == r);
36 if (r < 0)
37 return;
38
39 assert_se(streq(canonicalized, canonical));
40 }
41
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);
50 }
51
52 #if HAVE_GCRYPT
53
54 static void test_dnssec_verify_dns_key(void) {
55
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,
59 };
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,
63 };
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,
82 };
83
84 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *dnskey = NULL, *ds1 = NULL, *ds2 = NULL;
85
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");
88 assert_se(ds1);
89
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);
96
97 log_info("DS1: %s", strna(dns_resource_record_to_string(ds1)));
98
99 ds2 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "NASA.GOV");
100 assert_se(ds2);
101
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);
108
109 log_info("DS2: %s", strna(dns_resource_record_to_string(ds2)));
110
111 dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nasa.GOV");
112 assert_se(dnskey);
113
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);
120
121 log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey)));
122 log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey, false));
123
124 assert_se(dnssec_verify_dnskey_by_ds(dnskey, ds1, false) > 0);
125 assert_se(dnssec_verify_dnskey_by_ds(dnskey, ds2, false) > 0);
126 }
127
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,
132 0x24, 0xe
133 };
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,
138 0xdf, 0x4e, 0x1b
139 };
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
146 };
147
148 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *dnskey = NULL, *ds = NULL, *mx = NULL,
149 *rrsig = NULL;
150 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
151 DnssecResult result;
152
153 dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "example.com.");
154 assert_se(dnskey);
155
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);
162
163 log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey)));
164
165 ds = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "example.com.");
166 assert_se(ds);
167
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);
174
175 log_info("DS: %s", strna(dns_resource_record_to_string(ds)));
176
177 mx = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_MX, "example.com.");
178 assert_se(mx);
179
180 mx->mx.priority = 10;
181 mx->mx.exchange = strdup("mail.example.com.");
182 assert_se(mx->mx.exchange);
183
184 log_info("MX: %s", strna(dns_resource_record_to_string(mx)));
185
186 rrsig = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_RRSIG, "example.com.");
187 assert_se(rrsig);
188
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);
201
202 log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig)));
203
204 assert_se(dnssec_key_match_rrsig(mx->key, rrsig) > 0);
205 assert_se(dnssec_rrsig_match_dnskey(rrsig, dnskey, false) > 0);
206
207 answer = dns_answer_new(1);
208 assert_se(answer);
209 assert_se(dns_answer_add(answer, mx, 0, DNS_ANSWER_AUTHENTICATED) >= 0);
210
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);
215 #else
216 assert_se(result == DNSSEC_UNSUPPORTED_ALGORITHM);
217 #endif
218 }
219
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,
224 0x8a, 0x3b
225 };
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,
230 0xeb, 0x5e, 0x1c
231 };
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
238 };
239
240 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *dnskey = NULL, *ds = NULL, *mx = NULL,
241 *rrsig = NULL;
242 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
243 DnssecResult result;
244
245 dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "example.com.");
246 assert_se(dnskey);
247
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);
254
255 log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey)));
256
257 ds = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "example.com.");
258 assert_se(ds);
259
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);
266
267 log_info("DS: %s", strna(dns_resource_record_to_string(ds)));
268
269 mx = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_MX, "example.com.");
270 assert_se(mx);
271
272 mx->mx.priority = 10;
273 mx->mx.exchange = strdup("mail.example.com.");
274 assert_se(mx->mx.exchange);
275
276 log_info("MX: %s", strna(dns_resource_record_to_string(mx)));
277
278 rrsig = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_RRSIG, "example.com.");
279 assert_se(rrsig);
280
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);
293
294 log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig)));
295
296 assert_se(dnssec_key_match_rrsig(mx->key, rrsig) > 0);
297 assert_se(dnssec_rrsig_match_dnskey(rrsig, dnskey, false) > 0);
298
299 answer = dns_answer_new(1);
300 assert_se(answer);
301 assert_se(dns_answer_add(answer, mx, 0, DNS_ANSWER_AUTHENTICATED) >= 0);
302
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);
307 #else
308 assert_se(result == DNSSEC_UNSUPPORTED_ALGORITHM);
309 #endif
310 }
311 static void test_dnssec_verify_rrset(void) {
312
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,
322 };
323
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,
334 };
335
336 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *a = NULL, *rrsig = NULL, *dnskey = NULL;
337 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
338 DnssecResult result;
339
340 a = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, "nAsA.gov");
341 assert_se(a);
342
343 a->a.in_addr.s_addr = inet_addr("52.0.14.116");
344
345 log_info("A: %s", strna(dns_resource_record_to_string(a)));
346
347 rrsig = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_RRSIG, "NaSa.GOV.");
348 assert_se(rrsig);
349
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);
362
363 log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig)));
364
365 dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nASA.gOV");
366 assert_se(dnskey);
367
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);
374
375 log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey)));
376 log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey, false));
377
378 assert_se(dnssec_key_match_rrsig(a->key, rrsig) > 0);
379 assert_se(dnssec_rrsig_match_dnskey(rrsig, dnskey, false) > 0);
380
381 answer = dns_answer_new(1);
382 assert_se(answer);
383 assert_se(dns_answer_add(answer, a, 0, DNS_ANSWER_AUTHENTICATED) >= 0);
384
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);
388 }
389
390 static void test_dnssec_verify_rrset2(void) {
391
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,
401 };
402
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,
413 };
414
415 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *nsec = NULL, *rrsig = NULL, *dnskey = NULL;
416 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
417 DnssecResult result;
418
419 nsec = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_NSEC, "nasa.gov");
420 assert_se(nsec);
421
422 nsec->nsec.next_domain_name = strdup("3D-Printing.nasa.gov");
423 assert_se(nsec->nsec.next_domain_name);
424
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);
436
437 log_info("NSEC: %s", strna(dns_resource_record_to_string(nsec)));
438
439 rrsig = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_RRSIG, "NaSa.GOV.");
440 assert_se(rrsig);
441
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);
454
455 log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig)));
456
457 dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nASA.gOV");
458 assert_se(dnskey);
459
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);
466
467 log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey)));
468 log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey, false));
469
470 assert_se(dnssec_key_match_rrsig(nsec->key, rrsig) > 0);
471 assert_se(dnssec_rrsig_match_dnskey(rrsig, dnskey, false) > 0);
472
473 answer = dns_answer_new(1);
474 assert_se(answer);
475 assert_se(dns_answer_add(answer, nsec, 0, DNS_ANSWER_AUTHENTICATED) >= 0);
476
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);
480 }
481
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;
488 int k;
489
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.");
492 assert_se(rr);
493
494 rr->nsec3.algorithm = DNSSEC_DIGEST_SHA1;
495 rr->nsec3.flags = 1;
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);
503
504 log_info("NSEC3: %s", strna(dns_resource_record_to_string(rr)));
505
506 k = dnssec_nsec3_hash(rr, "eurid.eu", &h);
507 assert_se(k >= 0);
508
509 b = base32hexmem(h, k, false);
510 assert_se(b);
511 assert_se(strcasecmp(b, "PJ8S08RR45VIQDAQGE7EN3VHKNROTBMM") == 0);
512 }
513
514 #endif
515
516 int main(int argc, char*argv[]) {
517
518 test_dnssec_canonicalize();
519
520 #if HAVE_GCRYPT
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();
527 #endif
528
529 return 0;
530 }