]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/test-dnssec.c
resolve: add support for RFC 8080 (#7600)
[thirdparty/systemd.git] / src / resolve / test-dnssec.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
2b442ac8
LP
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>
cb9eeb06 22#include <gcrypt.h>
2b442ac8
LP
23#include <netinet/in.h>
24#include <sys/socket.h>
25
26#include "alloc-util.h"
27#include "resolved-dns-dnssec.h"
2b442ac8
LP
28#include "resolved-dns-rr.h"
29#include "string-util.h"
72667f08 30#include "hexdecoct.h"
2b442ac8 31
1691cfd8
ZJS
32static void test_dnssec_canonicalize_one(const char *original, const char *canonical, int r) {
33 char canonicalized[DNSSEC_CANONICAL_HOSTNAME_MAX];
a3db237b 34
1691cfd8
ZJS
35 assert_se(dnssec_canonicalize(original, canonicalized, sizeof(canonicalized)) == r);
36 if (r < 0)
37 return;
a3db237b 38
1691cfd8
ZJS
39 assert_se(streq(canonicalized, canonical));
40}
41
42static 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
349cc4a5 52#if HAVE_GCRYPT
1691cfd8
ZJS
53
54static 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 };
a3db237b 64 static const uint8_t dnskey_blob[] = {
1691cfd8
ZJS
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,
a3db237b
LP
82 };
83
1691cfd8 84 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *dnskey = NULL, *ds1 = NULL, *ds2 = NULL;
a3db237b 85
1691cfd8
ZJS
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);
a3db237b 89
1691cfd8
ZJS
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);
a3db237b 96
1691cfd8 97 log_info("DS1: %s", strna(dns_resource_record_to_string(ds1)));
a3db237b 98
1691cfd8
ZJS
99 ds2 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "NASA.GOV");
100 assert_se(ds2);
a3db237b 101
1691cfd8
ZJS
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);
a3db237b 108
1691cfd8 109 log_info("DS2: %s", strna(dns_resource_record_to_string(ds2)));
a3db237b 110
1691cfd8 111 dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nasa.GOV");
a3db237b
LP
112 assert_se(dnskey);
113
1691cfd8 114 dnskey->dnskey.flags = 257;
a3db237b
LP
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
7b50eb2e 121 log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey)));
0c857028 122 log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey, false));
a3db237b 123
1691cfd8
ZJS
124 assert_se(dnssec_verify_dnskey_by_ds(dnskey, ds1, false) > 0);
125 assert_se(dnssec_verify_dnskey_by_ds(dnskey, ds2, false) > 0);
a3db237b
LP
126}
127
cb9eeb06
MCO
128static 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
220static 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}
2b442ac8
LP
311static 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;
547973de 338 DnssecResult result;
2b442ac8
LP
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
7b50eb2e 345 log_info("A: %s", strna(dns_resource_record_to_string(a)));
2b442ac8
LP
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
7b50eb2e 363 log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig)));
2b442ac8
LP
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
7b50eb2e 375 log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey)));
0c857028 376 log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey, false));
2b442ac8
LP
377
378 assert_se(dnssec_key_match_rrsig(a->key, rrsig) > 0);
0c857028 379 assert_se(dnssec_rrsig_match_dnskey(rrsig, dnskey, false) > 0);
2b442ac8
LP
380
381 answer = dns_answer_new(1);
382 assert_se(answer);
105e1512 383 assert_se(dns_answer_add(answer, a, 0, DNS_ANSWER_AUTHENTICATED) >= 0);
2b442ac8 384
2a326321 385 /* Validate the RR as it if was 2015-12-2 today */
547973de
LP
386 assert_se(dnssec_verify_rrset(answer, a->key, rrsig, dnskey, 1449092754*USEC_PER_SEC, &result) >= 0);
387 assert_se(result == DNSSEC_VALIDATED);
2b442ac8
LP
388}
389
1691cfd8 390static void test_dnssec_verify_rrset2(void) {
2b442ac8 391
1691cfd8
ZJS
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,
2b442ac8 401 };
1691cfd8 402
2b442ac8 403 static const uint8_t dnskey_blob[] = {
1691cfd8
ZJS
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,
2b442ac8
LP
413 };
414
1691cfd8
ZJS
415 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *nsec = NULL, *rrsig = NULL, *dnskey = NULL;
416 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
417 DnssecResult result;
2b442ac8 418
1691cfd8
ZJS
419 nsec = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_NSEC, "nasa.gov");
420 assert_se(nsec);
2b442ac8 421
1691cfd8
ZJS
422 nsec->nsec.next_domain_name = strdup("3D-Printing.nasa.gov");
423 assert_se(nsec->nsec.next_domain_name);
2b442ac8 424
1691cfd8
ZJS
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);
2b442ac8 436
1691cfd8 437 log_info("NSEC: %s", strna(dns_resource_record_to_string(nsec)));
2b442ac8 438
1691cfd8
ZJS
439 rrsig = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_RRSIG, "NaSa.GOV.");
440 assert_se(rrsig);
2b442ac8 441
1691cfd8
ZJS
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);
2b442ac8 454
1691cfd8
ZJS
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");
2b442ac8
LP
458 assert_se(dnskey);
459
1691cfd8 460 dnskey->dnskey.flags = 256;
2b442ac8
LP
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
7b50eb2e 467 log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey)));
0c857028 468 log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey, false));
2b442ac8 469
1691cfd8
ZJS
470 assert_se(dnssec_key_match_rrsig(nsec->key, rrsig) > 0);
471 assert_se(dnssec_rrsig_match_dnskey(rrsig, dnskey, false) > 0);
2b442ac8 472
1691cfd8
ZJS
473 answer = dns_answer_new(1);
474 assert_se(answer);
475 assert_se(dns_answer_add(answer, nsec, 0, DNS_ANSWER_AUTHENTICATED) >= 0);
2b442ac8 476
1691cfd8
ZJS
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);
2b442ac8
LP
480}
481
72667f08
LP
482static 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;
72667f08 486 uint8_t h[DNSSEC_HASH_SIZE_MAX];
7b50eb2e 487 _cleanup_free_ char *b = NULL;
72667f08
LP
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
7b50eb2e 504 log_info("NSEC3: %s", strna(dns_resource_record_to_string(rr)));
72667f08
LP
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
1691cfd8
ZJS
514#endif
515
2b442ac8
LP
516int main(int argc, char*argv[]) {
517
518 test_dnssec_canonicalize();
1691cfd8 519
349cc4a5 520#if HAVE_GCRYPT
2b442ac8 521 test_dnssec_verify_dns_key();
cb9eeb06
MCO
522 test_dnssec_verify_rfc8080_ed25519_example1();
523 test_dnssec_verify_rfc8080_ed25519_example2();
2b442ac8 524 test_dnssec_verify_rrset();
a3db237b 525 test_dnssec_verify_rrset2();
72667f08 526 test_dnssec_nsec3_hash();
a915abf3 527#endif
2b442ac8
LP
528
529 return 0;
530}