]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/test-dnssec.c
ebabfba96d1ac6fdae86daeb6b1750be82fc99ea
[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 #if HAVE_GCRYPT
23 #include <gcrypt.h>
24 #endif
25 #include <netinet/in.h>
26 #include <sys/socket.h>
27
28 #include "alloc-util.h"
29 #include "resolved-dns-dnssec.h"
30 #include "resolved-dns-rr.h"
31 #include "string-util.h"
32 #include "hexdecoct.h"
33
34 static void test_dnssec_canonicalize_one(const char *original, const char *canonical, int r) {
35 char canonicalized[DNSSEC_CANONICAL_HOSTNAME_MAX];
36
37 assert_se(dnssec_canonicalize(original, canonicalized, sizeof(canonicalized)) == r);
38 if (r < 0)
39 return;
40
41 assert_se(streq(canonicalized, canonical));
42 }
43
44 static void test_dnssec_canonicalize(void) {
45 test_dnssec_canonicalize_one("", ".", 1);
46 test_dnssec_canonicalize_one(".", ".", 1);
47 test_dnssec_canonicalize_one("foo", "foo.", 4);
48 test_dnssec_canonicalize_one("foo.", "foo.", 4);
49 test_dnssec_canonicalize_one("FOO.", "foo.", 4);
50 test_dnssec_canonicalize_one("FOO.bar.", "foo.bar.", 8);
51 test_dnssec_canonicalize_one("FOO..bar.", NULL, -EINVAL);
52 }
53
54 #if HAVE_GCRYPT
55
56 static void test_dnssec_verify_dns_key(void) {
57
58 static const uint8_t ds1_fprint[] = {
59 0x46, 0x8B, 0xC8, 0xDD, 0xC7, 0xE8, 0x27, 0x03, 0x40, 0xBB, 0x8A, 0x1F, 0x3B, 0x2E, 0x45, 0x9D,
60 0x80, 0x67, 0x14, 0x01,
61 };
62 static const uint8_t ds2_fprint[] = {
63 0x8A, 0xEE, 0x80, 0x47, 0x05, 0x5F, 0x83, 0xD1, 0x48, 0xBA, 0x8F, 0xF6, 0xDD, 0xA7, 0x60, 0xCE,
64 0x94, 0xF7, 0xC7, 0x5E, 0x52, 0x4C, 0xF2, 0xE9, 0x50, 0xB9, 0x2E, 0xCB, 0xEF, 0x96, 0xB9, 0x98,
65 };
66 static const uint8_t dnskey_blob[] = {
67 0x03, 0x01, 0x00, 0x01, 0xa8, 0x12, 0xda, 0x4f, 0xd2, 0x7d, 0x54, 0x14, 0x0e, 0xcc, 0x5b, 0x5e,
68 0x45, 0x9c, 0x96, 0x98, 0xc0, 0xc0, 0x85, 0x81, 0xb1, 0x47, 0x8c, 0x7d, 0xe8, 0x39, 0x50, 0xcc,
69 0xc5, 0xd0, 0xf2, 0x00, 0x81, 0x67, 0x79, 0xf6, 0xcc, 0x9d, 0xad, 0x6c, 0xbb, 0x7b, 0x6f, 0x48,
70 0x97, 0x15, 0x1c, 0xfd, 0x0b, 0xfe, 0xd3, 0xd7, 0x7d, 0x9f, 0x81, 0x26, 0xd3, 0xc5, 0x65, 0x49,
71 0xcf, 0x46, 0x62, 0xb0, 0x55, 0x6e, 0x47, 0xc7, 0x30, 0xef, 0x51, 0xfb, 0x3e, 0xc6, 0xef, 0xde,
72 0x27, 0x3f, 0xfa, 0x57, 0x2d, 0xa7, 0x1d, 0x80, 0x46, 0x9a, 0x5f, 0x14, 0xb3, 0xb0, 0x2c, 0xbe,
73 0x72, 0xca, 0xdf, 0xb2, 0xff, 0x36, 0x5b, 0x4f, 0xec, 0x58, 0x8e, 0x8d, 0x01, 0xe9, 0xa9, 0xdf,
74 0xb5, 0x60, 0xad, 0x52, 0x4d, 0xfc, 0xa9, 0x3e, 0x8d, 0x35, 0x95, 0xb3, 0x4e, 0x0f, 0xca, 0x45,
75 0x1b, 0xf7, 0xef, 0x3a, 0x88, 0x25, 0x08, 0xc7, 0x4e, 0x06, 0xc1, 0x62, 0x1a, 0xce, 0xd8, 0x77,
76 0xbd, 0x02, 0x65, 0xf8, 0x49, 0xfb, 0xce, 0xf6, 0xa8, 0x09, 0xfc, 0xde, 0xb2, 0x09, 0x9d, 0x39,
77 0xf8, 0x63, 0x9c, 0x32, 0x42, 0x7c, 0xa0, 0x30, 0x86, 0x72, 0x7a, 0x4a, 0xc6, 0xd4, 0xb3, 0x2d,
78 0x24, 0xef, 0x96, 0x3f, 0xc2, 0xda, 0xd3, 0xf2, 0x15, 0x6f, 0xda, 0x65, 0x4b, 0x81, 0x28, 0x68,
79 0xf4, 0xfe, 0x3e, 0x71, 0x4f, 0x50, 0x96, 0x72, 0x58, 0xa1, 0x89, 0xdd, 0x01, 0x61, 0x39, 0x39,
80 0xc6, 0x76, 0xa4, 0xda, 0x02, 0x70, 0x3d, 0xc0, 0xdc, 0x8d, 0x70, 0x72, 0x04, 0x90, 0x79, 0xd4,
81 0xec, 0x65, 0xcf, 0x49, 0x35, 0x25, 0x3a, 0x14, 0x1a, 0x45, 0x20, 0xeb, 0x31, 0xaf, 0x92, 0xba,
82 0x20, 0xd3, 0xcd, 0xa7, 0x13, 0x44, 0xdc, 0xcf, 0xf0, 0x27, 0x34, 0xb9, 0xe7, 0x24, 0x6f, 0x73,
83 0xe7, 0xea, 0x77, 0x03,
84 };
85
86 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *dnskey = NULL, *ds1 = NULL, *ds2 = NULL;
87
88 /* The two DS RRs in effect for nasa.gov on 2015-12-01. */
89 ds1 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "nasa.gov");
90 assert_se(ds1);
91
92 ds1->ds.key_tag = 47857;
93 ds1->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256;
94 ds1->ds.digest_type = DNSSEC_DIGEST_SHA1;
95 ds1->ds.digest_size = sizeof(ds1_fprint);
96 ds1->ds.digest = memdup(ds1_fprint, ds1->ds.digest_size);
97 assert_se(ds1->ds.digest);
98
99 log_info("DS1: %s", strna(dns_resource_record_to_string(ds1)));
100
101 ds2 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "NASA.GOV");
102 assert_se(ds2);
103
104 ds2->ds.key_tag = 47857;
105 ds2->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256;
106 ds2->ds.digest_type = DNSSEC_DIGEST_SHA256;
107 ds2->ds.digest_size = sizeof(ds2_fprint);
108 ds2->ds.digest = memdup(ds2_fprint, ds2->ds.digest_size);
109 assert_se(ds2->ds.digest);
110
111 log_info("DS2: %s", strna(dns_resource_record_to_string(ds2)));
112
113 dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nasa.GOV");
114 assert_se(dnskey);
115
116 dnskey->dnskey.flags = 257;
117 dnskey->dnskey.protocol = 3;
118 dnskey->dnskey.algorithm = DNSSEC_ALGORITHM_RSASHA256;
119 dnskey->dnskey.key_size = sizeof(dnskey_blob);
120 dnskey->dnskey.key = memdup(dnskey_blob, sizeof(dnskey_blob));
121 assert_se(dnskey->dnskey.key);
122
123 log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey)));
124 log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey, false));
125
126 assert_se(dnssec_verify_dnskey_by_ds(dnskey, ds1, false) > 0);
127 assert_se(dnssec_verify_dnskey_by_ds(dnskey, ds2, false) > 0);
128 }
129
130 static void test_dnssec_verify_rfc8080_ed25519_example1(void) {
131 static const uint8_t dnskey_blob[] = {
132 0x97, 0x4d, 0x96, 0xa2, 0x2d, 0x22, 0x4b, 0xc0, 0x1a, 0xdb, 0x91, 0x50, 0x91, 0x47, 0x7d,
133 0x44, 0xcc, 0xd9, 0x1c, 0x9a, 0x41, 0xa1, 0x14, 0x30, 0x01, 0x01, 0x17, 0xd5, 0x2c, 0x59,
134 0x24, 0xe
135 };
136 static const uint8_t ds_fprint[] = {
137 0xdd, 0xa6, 0xb9, 0x69, 0xbd, 0xfb, 0x79, 0xf7, 0x1e, 0xe7, 0xb7, 0xfb, 0xdf, 0xb7, 0xdc,
138 0xd7, 0xad, 0xbb, 0xd3, 0x5d, 0xdf, 0x79, 0xed, 0x3b, 0x6d, 0xd7, 0xf6, 0xe3, 0x56, 0xdd,
139 0xd7, 0x47, 0xf7, 0x6f, 0x5f, 0x7a, 0xe1, 0xa6, 0xf9, 0xe5, 0xce, 0xfc, 0x7b, 0xbf, 0x5a,
140 0xdf, 0x4e, 0x1b
141 };
142 static const uint8_t signature_blob[] = {
143 0xa0, 0xbf, 0x64, 0xac, 0x9b, 0xa7, 0xef, 0x17, 0xc1, 0x38, 0x85, 0x9c, 0x18, 0x78, 0xbb,
144 0x99, 0xa8, 0x39, 0xfe, 0x17, 0x59, 0xac, 0xa5, 0xb0, 0xd7, 0x98, 0xcf, 0x1a, 0xb1, 0xe9,
145 0x8d, 0x07, 0x91, 0x02, 0xf4, 0xdd, 0xb3, 0x36, 0x8f, 0x0f, 0xe4, 0x0b, 0xb3, 0x77, 0xf1,
146 0xf0, 0x0e, 0x0c, 0xdd, 0xed, 0xb7, 0x99, 0x16, 0x7d, 0x56, 0xb6, 0xe9, 0x32, 0x78, 0x30,
147 0x72, 0xba, 0x8d, 0x02
148 };
149
150 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *dnskey = NULL, *ds = NULL, *mx = NULL,
151 *rrsig = NULL;
152 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
153 DnssecResult result;
154
155 dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "example.com.");
156 assert_se(dnskey);
157
158 dnskey->dnskey.flags = 257;
159 dnskey->dnskey.protocol = 3;
160 dnskey->dnskey.algorithm = DNSSEC_ALGORITHM_ED25519;
161 dnskey->dnskey.key_size = sizeof(dnskey_blob);
162 dnskey->dnskey.key = memdup(dnskey_blob, sizeof(dnskey_blob));
163 assert_se(dnskey->dnskey.key);
164
165 log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey)));
166
167 ds = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "example.com.");
168 assert_se(ds);
169
170 ds->ds.key_tag = 3613;
171 ds->ds.algorithm = DNSSEC_ALGORITHM_ED25519;
172 ds->ds.digest_type = DNSSEC_DIGEST_SHA256;
173 ds->ds.digest_size = sizeof(ds_fprint);
174 ds->ds.digest = memdup(ds_fprint, ds->ds.digest_size);
175 assert_se(ds->ds.digest);
176
177 log_info("DS: %s", strna(dns_resource_record_to_string(ds)));
178
179 mx = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_MX, "example.com.");
180 assert_se(mx);
181
182 mx->mx.priority = 10;
183 mx->mx.exchange = strdup("mail.example.com.");
184 assert_se(mx->mx.exchange);
185
186 log_info("MX: %s", strna(dns_resource_record_to_string(mx)));
187
188 rrsig = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_RRSIG, "example.com.");
189 assert_se(rrsig);
190
191 rrsig->rrsig.type_covered = DNS_TYPE_MX;
192 rrsig->rrsig.algorithm = DNSSEC_ALGORITHM_ED25519;
193 rrsig->rrsig.labels = 2;
194 rrsig->rrsig.original_ttl = 3600;
195 rrsig->rrsig.expiration = 1440021600;
196 rrsig->rrsig.inception = 1438207200;
197 rrsig->rrsig.key_tag = 3613;
198 rrsig->rrsig.signer = strdup("example.com.");
199 assert_se(rrsig->rrsig.signer);
200 rrsig->rrsig.signature_size = sizeof(signature_blob);
201 rrsig->rrsig.signature = memdup(signature_blob, rrsig->rrsig.signature_size);
202 assert_se(rrsig->rrsig.signature);
203
204 log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig)));
205
206 assert_se(dnssec_key_match_rrsig(mx->key, rrsig) > 0);
207 assert_se(dnssec_rrsig_match_dnskey(rrsig, dnskey, false) > 0);
208
209 answer = dns_answer_new(1);
210 assert_se(answer);
211 assert_se(dns_answer_add(answer, mx, 0, DNS_ANSWER_AUTHENTICATED) >= 0);
212
213 assert_se(dnssec_verify_rrset(answer, mx->key, rrsig, dnskey,
214 rrsig->rrsig.inception * USEC_PER_SEC, &result) >= 0);
215 #if GCRYPT_VERSION_NUMBER >= 0x010600
216 assert_se(result == DNSSEC_VALIDATED);
217 #else
218 assert_se(result == DNSSEC_UNSUPPORTED_ALGORITHM);
219 #endif
220 }
221
222 static void test_dnssec_verify_rfc8080_ed25519_example2(void) {
223 static const uint8_t dnskey_blob[] = {
224 0xcc, 0xf9, 0xd9, 0xfd, 0x0c, 0x04, 0x7b, 0xb4, 0xbc, 0x0b, 0x94, 0x8f, 0xcf, 0x63, 0x9f,
225 0x4b, 0x94, 0x51, 0xe3, 0x40, 0x13, 0x93, 0x6f, 0xeb, 0x62, 0x71, 0x3d, 0xc4, 0x72, 0x4,
226 0x8a, 0x3b
227 };
228 static const uint8_t ds_fprint[] = {
229 0xe3, 0x4d, 0x7b, 0xf3, 0x56, 0xfd, 0xdf, 0x87, 0xb7, 0xf7, 0x67, 0x5e, 0xe3, 0xdd, 0x9e,
230 0x73, 0xbe, 0xda, 0x7b, 0x67, 0xb5, 0xe5, 0xde, 0xf4, 0x7f, 0xae, 0x7b, 0xe5, 0xad, 0x5c,
231 0xd1, 0xb7, 0x39, 0xf5, 0xce, 0x76, 0xef, 0x97, 0x34, 0xe1, 0xe6, 0xde, 0xf3, 0x47, 0x3a,
232 0xeb, 0x5e, 0x1c
233 };
234 static const uint8_t signature_blob[] = {
235 0xcd, 0x74, 0x34, 0x6e, 0x46, 0x20, 0x41, 0x31, 0x05, 0xc9, 0xf2, 0xf2, 0x8b, 0xd4, 0x28,
236 0x89, 0x8e, 0x83, 0xf1, 0x97, 0x58, 0xa3, 0x8c, 0x32, 0x52, 0x15, 0x62, 0xa1, 0x86, 0x57,
237 0x15, 0xd4, 0xf8, 0xd7, 0x44, 0x0f, 0x44, 0x84, 0xd0, 0x4a, 0xa2, 0x52, 0x9f, 0x34, 0x28,
238 0x4a, 0x6e, 0x69, 0xa0, 0x9e, 0xe0, 0x0f, 0xb0, 0x10, 0x47, 0x43, 0xbb, 0x2a, 0xe2, 0x39,
239 0x93, 0x6a, 0x5c, 0x06
240 };
241
242 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *dnskey = NULL, *ds = NULL, *mx = NULL,
243 *rrsig = NULL;
244 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
245 DnssecResult result;
246
247 dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "example.com.");
248 assert_se(dnskey);
249
250 dnskey->dnskey.flags = 257;
251 dnskey->dnskey.protocol = 3;
252 dnskey->dnskey.algorithm = DNSSEC_ALGORITHM_ED25519;
253 dnskey->dnskey.key_size = sizeof(dnskey_blob);
254 dnskey->dnskey.key = memdup(dnskey_blob, sizeof(dnskey_blob));
255 assert_se(dnskey->dnskey.key);
256
257 log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey)));
258
259 ds = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "example.com.");
260 assert_se(ds);
261
262 ds->ds.key_tag = 35217;
263 ds->ds.algorithm = DNSSEC_ALGORITHM_ED25519;
264 ds->ds.digest_type = DNSSEC_DIGEST_SHA256;
265 ds->ds.digest_size = sizeof(ds_fprint);
266 ds->ds.digest = memdup(ds_fprint, ds->ds.digest_size);
267 assert_se(ds->ds.digest);
268
269 log_info("DS: %s", strna(dns_resource_record_to_string(ds)));
270
271 mx = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_MX, "example.com.");
272 assert_se(mx);
273
274 mx->mx.priority = 10;
275 mx->mx.exchange = strdup("mail.example.com.");
276 assert_se(mx->mx.exchange);
277
278 log_info("MX: %s", strna(dns_resource_record_to_string(mx)));
279
280 rrsig = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_RRSIG, "example.com.");
281 assert_se(rrsig);
282
283 rrsig->rrsig.type_covered = DNS_TYPE_MX;
284 rrsig->rrsig.algorithm = DNSSEC_ALGORITHM_ED25519;
285 rrsig->rrsig.labels = 2;
286 rrsig->rrsig.original_ttl = 3600;
287 rrsig->rrsig.expiration = 1440021600;
288 rrsig->rrsig.inception = 1438207200;
289 rrsig->rrsig.key_tag = 35217;
290 rrsig->rrsig.signer = strdup("example.com.");
291 assert_se(rrsig->rrsig.signer);
292 rrsig->rrsig.signature_size = sizeof(signature_blob);
293 rrsig->rrsig.signature = memdup(signature_blob, rrsig->rrsig.signature_size);
294 assert_se(rrsig->rrsig.signature);
295
296 log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig)));
297
298 assert_se(dnssec_key_match_rrsig(mx->key, rrsig) > 0);
299 assert_se(dnssec_rrsig_match_dnskey(rrsig, dnskey, false) > 0);
300
301 answer = dns_answer_new(1);
302 assert_se(answer);
303 assert_se(dns_answer_add(answer, mx, 0, DNS_ANSWER_AUTHENTICATED) >= 0);
304
305 assert_se(dnssec_verify_rrset(answer, mx->key, rrsig, dnskey,
306 rrsig->rrsig.inception * USEC_PER_SEC, &result) >= 0);
307 #if GCRYPT_VERSION_NUMBER >= 0x010600
308 assert_se(result == DNSSEC_VALIDATED);
309 #else
310 assert_se(result == DNSSEC_UNSUPPORTED_ALGORITHM);
311 #endif
312 }
313 static void test_dnssec_verify_rrset(void) {
314
315 static const uint8_t signature_blob[] = {
316 0x7f, 0x79, 0xdd, 0x5e, 0x89, 0x79, 0x18, 0xd0, 0x34, 0x86, 0x8c, 0x72, 0x77, 0x75, 0x48, 0x4d,
317 0xc3, 0x7d, 0x38, 0x04, 0xab, 0xcd, 0x9e, 0x4c, 0x82, 0xb0, 0x92, 0xca, 0xe9, 0x66, 0xe9, 0x6e,
318 0x47, 0xc7, 0x68, 0x8c, 0x94, 0xf6, 0x69, 0xcb, 0x75, 0x94, 0xe6, 0x30, 0xa6, 0xfb, 0x68, 0x64,
319 0x96, 0x1a, 0x84, 0xe1, 0xdc, 0x16, 0x4c, 0x83, 0x6c, 0x44, 0xf2, 0x74, 0x4d, 0x74, 0x79, 0x8f,
320 0xf3, 0xf4, 0x63, 0x0d, 0xef, 0x5a, 0xe7, 0xe2, 0xfd, 0xf2, 0x2b, 0x38, 0x7c, 0x28, 0x96, 0x9d,
321 0xb6, 0xcd, 0x5c, 0x3b, 0x57, 0xe2, 0x24, 0x78, 0x65, 0xd0, 0x9e, 0x77, 0x83, 0x09, 0x6c, 0xff,
322 0x3d, 0x52, 0x3f, 0x6e, 0xd1, 0xed, 0x2e, 0xf9, 0xee, 0x8e, 0xa6, 0xbe, 0x9a, 0xa8, 0x87, 0x76,
323 0xd8, 0x77, 0xcc, 0x96, 0xa0, 0x98, 0xa1, 0xd1, 0x68, 0x09, 0x43, 0xcf, 0x56, 0xd9, 0xd1, 0x66,
324 };
325
326 static const uint8_t dnskey_blob[] = {
327 0x03, 0x01, 0x00, 0x01, 0x9b, 0x49, 0x9b, 0xc1, 0xf9, 0x9a, 0xe0, 0x4e, 0xcf, 0xcb, 0x14, 0x45,
328 0x2e, 0xc9, 0xf9, 0x74, 0xa7, 0x18, 0xb5, 0xf3, 0xde, 0x39, 0x49, 0xdf, 0x63, 0x33, 0x97, 0x52,
329 0xe0, 0x8e, 0xac, 0x50, 0x30, 0x8e, 0x09, 0xd5, 0x24, 0x3d, 0x26, 0xa4, 0x49, 0x37, 0x2b, 0xb0,
330 0x6b, 0x1b, 0xdf, 0xde, 0x85, 0x83, 0xcb, 0x22, 0x4e, 0x60, 0x0a, 0x91, 0x1a, 0x1f, 0xc5, 0x40,
331 0xb1, 0xc3, 0x15, 0xc1, 0x54, 0x77, 0x86, 0x65, 0x53, 0xec, 0x10, 0x90, 0x0c, 0x91, 0x00, 0x5e,
332 0x15, 0xdc, 0x08, 0x02, 0x4c, 0x8c, 0x0d, 0xc0, 0xac, 0x6e, 0xc4, 0x3e, 0x1b, 0x80, 0x19, 0xe4,
333 0xf7, 0x5f, 0x77, 0x51, 0x06, 0x87, 0x61, 0xde, 0xa2, 0x18, 0x0f, 0x40, 0x8b, 0x79, 0x72, 0xfa,
334 0x8d, 0x1a, 0x44, 0x47, 0x0d, 0x8e, 0x3a, 0x2d, 0xc7, 0x39, 0xbf, 0x56, 0x28, 0x97, 0xd9, 0x20,
335 0x4f, 0x00, 0x51, 0x3b,
336 };
337
338 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *a = NULL, *rrsig = NULL, *dnskey = NULL;
339 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
340 DnssecResult result;
341
342 a = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, "nAsA.gov");
343 assert_se(a);
344
345 a->a.in_addr.s_addr = inet_addr("52.0.14.116");
346
347 log_info("A: %s", strna(dns_resource_record_to_string(a)));
348
349 rrsig = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_RRSIG, "NaSa.GOV.");
350 assert_se(rrsig);
351
352 rrsig->rrsig.type_covered = DNS_TYPE_A;
353 rrsig->rrsig.algorithm = DNSSEC_ALGORITHM_RSASHA256;
354 rrsig->rrsig.labels = 2;
355 rrsig->rrsig.original_ttl = 600;
356 rrsig->rrsig.expiration = 0x5683135c;
357 rrsig->rrsig.inception = 0x565b7da8;
358 rrsig->rrsig.key_tag = 63876;
359 rrsig->rrsig.signer = strdup("Nasa.Gov.");
360 assert_se(rrsig->rrsig.signer);
361 rrsig->rrsig.signature_size = sizeof(signature_blob);
362 rrsig->rrsig.signature = memdup(signature_blob, rrsig->rrsig.signature_size);
363 assert_se(rrsig->rrsig.signature);
364
365 log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig)));
366
367 dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nASA.gOV");
368 assert_se(dnskey);
369
370 dnskey->dnskey.flags = 256;
371 dnskey->dnskey.protocol = 3;
372 dnskey->dnskey.algorithm = DNSSEC_ALGORITHM_RSASHA256;
373 dnskey->dnskey.key_size = sizeof(dnskey_blob);
374 dnskey->dnskey.key = memdup(dnskey_blob, sizeof(dnskey_blob));
375 assert_se(dnskey->dnskey.key);
376
377 log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey)));
378 log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey, false));
379
380 assert_se(dnssec_key_match_rrsig(a->key, rrsig) > 0);
381 assert_se(dnssec_rrsig_match_dnskey(rrsig, dnskey, false) > 0);
382
383 answer = dns_answer_new(1);
384 assert_se(answer);
385 assert_se(dns_answer_add(answer, a, 0, DNS_ANSWER_AUTHENTICATED) >= 0);
386
387 /* Validate the RR as it if was 2015-12-2 today */
388 assert_se(dnssec_verify_rrset(answer, a->key, rrsig, dnskey, 1449092754*USEC_PER_SEC, &result) >= 0);
389 assert_se(result == DNSSEC_VALIDATED);
390 }
391
392 static void test_dnssec_verify_rrset2(void) {
393
394 static const uint8_t signature_blob[] = {
395 0x48, 0x45, 0xc8, 0x8b, 0xc0, 0x14, 0x92, 0xf5, 0x15, 0xc6, 0x84, 0x9d, 0x2f, 0xe3, 0x32, 0x11,
396 0x7d, 0xf1, 0xe6, 0x87, 0xb9, 0x42, 0xd3, 0x8b, 0x9e, 0xaf, 0x92, 0x31, 0x0a, 0x53, 0xad, 0x8b,
397 0xa7, 0x5c, 0x83, 0x39, 0x8c, 0x28, 0xac, 0xce, 0x6e, 0x9c, 0x18, 0xe3, 0x31, 0x16, 0x6e, 0xca,
398 0x38, 0x31, 0xaf, 0xd9, 0x94, 0xf1, 0x84, 0xb1, 0xdf, 0x5a, 0xc2, 0x73, 0x22, 0xf6, 0xcb, 0xa2,
399 0xe7, 0x8c, 0x77, 0x0c, 0x74, 0x2f, 0xc2, 0x13, 0xb0, 0x93, 0x51, 0xa9, 0x4f, 0xae, 0x0a, 0xda,
400 0x45, 0xcc, 0xfd, 0x43, 0x99, 0x36, 0x9a, 0x0d, 0x21, 0xe0, 0xeb, 0x30, 0x65, 0xd4, 0xa0, 0x27,
401 0x37, 0x3b, 0xe4, 0xc1, 0xc5, 0xa1, 0x2a, 0xd1, 0x76, 0xc4, 0x7e, 0x64, 0x0e, 0x5a, 0xa6, 0x50,
402 0x24, 0xd5, 0x2c, 0xcc, 0x6d, 0xe5, 0x37, 0xea, 0xbd, 0x09, 0x34, 0xed, 0x24, 0x06, 0xa1, 0x22,
403 };
404
405 static const uint8_t dnskey_blob[] = {
406 0x03, 0x01, 0x00, 0x01, 0xc3, 0x7f, 0x1d, 0xd1, 0x1c, 0x97, 0xb1, 0x13, 0x34, 0x3a, 0x9a, 0xea,
407 0xee, 0xd9, 0x5a, 0x11, 0x1b, 0x17, 0xc7, 0xe3, 0xd4, 0xda, 0x20, 0xbc, 0x5d, 0xba, 0x74, 0xe3,
408 0x37, 0x99, 0xec, 0x25, 0xce, 0x93, 0x7f, 0xbd, 0x22, 0x73, 0x7e, 0x14, 0x71, 0xe0, 0x60, 0x07,
409 0xd4, 0x39, 0x8b, 0x5e, 0xe9, 0xba, 0x25, 0xe8, 0x49, 0xe9, 0x34, 0xef, 0xfe, 0x04, 0x5c, 0xa5,
410 0x27, 0xcd, 0xa9, 0xda, 0x70, 0x05, 0x21, 0xab, 0x15, 0x82, 0x24, 0xc3, 0x94, 0xf5, 0xd7, 0xb7,
411 0xc4, 0x66, 0xcb, 0x32, 0x6e, 0x60, 0x2b, 0x55, 0x59, 0x28, 0x89, 0x8a, 0x72, 0xde, 0x88, 0x56,
412 0x27, 0x95, 0xd9, 0xac, 0x88, 0x4f, 0x65, 0x2b, 0x68, 0xfc, 0xe6, 0x41, 0xc1, 0x1b, 0xef, 0x4e,
413 0xd6, 0xc2, 0x0f, 0x64, 0x88, 0x95, 0x5e, 0xdd, 0x3a, 0x02, 0x07, 0x50, 0xa9, 0xda, 0xa4, 0x49,
414 0x74, 0x62, 0xfe, 0xd7,
415 };
416
417 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *nsec = NULL, *rrsig = NULL, *dnskey = NULL;
418 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
419 DnssecResult result;
420
421 nsec = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_NSEC, "nasa.gov");
422 assert_se(nsec);
423
424 nsec->nsec.next_domain_name = strdup("3D-Printing.nasa.gov");
425 assert_se(nsec->nsec.next_domain_name);
426
427 nsec->nsec.types = bitmap_new();
428 assert_se(nsec->nsec.types);
429 assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_A) >= 0);
430 assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_NS) >= 0);
431 assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_SOA) >= 0);
432 assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_MX) >= 0);
433 assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_TXT) >= 0);
434 assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_RRSIG) >= 0);
435 assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_NSEC) >= 0);
436 assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_DNSKEY) >= 0);
437 assert_se(bitmap_set(nsec->nsec.types, 65534) >= 0);
438
439 log_info("NSEC: %s", strna(dns_resource_record_to_string(nsec)));
440
441 rrsig = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_RRSIG, "NaSa.GOV.");
442 assert_se(rrsig);
443
444 rrsig->rrsig.type_covered = DNS_TYPE_NSEC;
445 rrsig->rrsig.algorithm = DNSSEC_ALGORITHM_RSASHA256;
446 rrsig->rrsig.labels = 2;
447 rrsig->rrsig.original_ttl = 300;
448 rrsig->rrsig.expiration = 0x5689002f;
449 rrsig->rrsig.inception = 0x56617230;
450 rrsig->rrsig.key_tag = 30390;
451 rrsig->rrsig.signer = strdup("Nasa.Gov.");
452 assert_se(rrsig->rrsig.signer);
453 rrsig->rrsig.signature_size = sizeof(signature_blob);
454 rrsig->rrsig.signature = memdup(signature_blob, rrsig->rrsig.signature_size);
455 assert_se(rrsig->rrsig.signature);
456
457 log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig)));
458
459 dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nASA.gOV");
460 assert_se(dnskey);
461
462 dnskey->dnskey.flags = 256;
463 dnskey->dnskey.protocol = 3;
464 dnskey->dnskey.algorithm = DNSSEC_ALGORITHM_RSASHA256;
465 dnskey->dnskey.key_size = sizeof(dnskey_blob);
466 dnskey->dnskey.key = memdup(dnskey_blob, sizeof(dnskey_blob));
467 assert_se(dnskey->dnskey.key);
468
469 log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey)));
470 log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey, false));
471
472 assert_se(dnssec_key_match_rrsig(nsec->key, rrsig) > 0);
473 assert_se(dnssec_rrsig_match_dnskey(rrsig, dnskey, false) > 0);
474
475 answer = dns_answer_new(1);
476 assert_se(answer);
477 assert_se(dns_answer_add(answer, nsec, 0, DNS_ANSWER_AUTHENTICATED) >= 0);
478
479 /* Validate the RR as it if was 2015-12-11 today */
480 assert_se(dnssec_verify_rrset(answer, nsec->key, rrsig, dnskey, 1449849318*USEC_PER_SEC, &result) >= 0);
481 assert_se(result == DNSSEC_VALIDATED);
482 }
483
484 static void test_dnssec_nsec3_hash(void) {
485 static const uint8_t salt[] = { 0xB0, 0x1D, 0xFA, 0xCE };
486 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 };
487 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
488 uint8_t h[DNSSEC_HASH_SIZE_MAX];
489 _cleanup_free_ char *b = NULL;
490 int k;
491
492 /* The NSEC3 RR for eurid.eu on 2015-12-14. */
493 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_NSEC3, "PJ8S08RR45VIQDAQGE7EN3VHKNROTBMM.eurid.eu.");
494 assert_se(rr);
495
496 rr->nsec3.algorithm = DNSSEC_DIGEST_SHA1;
497 rr->nsec3.flags = 1;
498 rr->nsec3.iterations = 1;
499 rr->nsec3.salt = memdup(salt, sizeof(salt));
500 assert_se(rr->nsec3.salt);
501 rr->nsec3.salt_size = sizeof(salt);
502 rr->nsec3.next_hashed_name = memdup(next_hashed_name, sizeof(next_hashed_name));
503 assert_se(rr->nsec3.next_hashed_name);
504 rr->nsec3.next_hashed_name_size = sizeof(next_hashed_name);
505
506 log_info("NSEC3: %s", strna(dns_resource_record_to_string(rr)));
507
508 k = dnssec_nsec3_hash(rr, "eurid.eu", &h);
509 assert_se(k >= 0);
510
511 b = base32hexmem(h, k, false);
512 assert_se(b);
513 assert_se(strcasecmp(b, "PJ8S08RR45VIQDAQGE7EN3VHKNROTBMM") == 0);
514 }
515
516 #endif
517
518 int main(int argc, char*argv[]) {
519
520 test_dnssec_canonicalize();
521
522 #if HAVE_GCRYPT
523 test_dnssec_verify_dns_key();
524 test_dnssec_verify_rfc8080_ed25519_example1();
525 test_dnssec_verify_rfc8080_ed25519_example2();
526 test_dnssec_verify_rrset();
527 test_dnssec_verify_rrset2();
528 test_dnssec_nsec3_hash();
529 #endif
530
531 return 0;
532 }