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>
25 #include <netinet/in.h>
26 #include <sys/socket.h>
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"
34 static void test_dnssec_canonicalize_one(const char *original
, const char *canonical
, int r
) {
35 char canonicalized
[DNSSEC_CANONICAL_HOSTNAME_MAX
];
37 assert_se(dnssec_canonicalize(original
, canonicalized
, sizeof(canonicalized
)) == r
);
41 assert_se(streq(canonicalized
, canonical
));
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
);
56 static void test_dnssec_verify_dns_key(void) {
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,
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,
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,
86 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*dnskey
= NULL
, *ds1
= NULL
, *ds2
= NULL
;
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");
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
);
99 log_info("DS1: %s", strna(dns_resource_record_to_string(ds1
)));
101 ds2
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_DS
, "NASA.GOV");
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
);
111 log_info("DS2: %s", strna(dns_resource_record_to_string(ds2
)));
113 dnskey
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_DNSKEY
, "nasa.GOV");
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
);
123 log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey
)));
124 log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey
, false));
126 assert_se(dnssec_verify_dnskey_by_ds(dnskey
, ds1
, false) > 0);
127 assert_se(dnssec_verify_dnskey_by_ds(dnskey
, ds2
, false) > 0);
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,
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,
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
150 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*dnskey
= NULL
, *ds
= NULL
, *mx
= NULL
,
152 _cleanup_(dns_answer_unrefp
) DnsAnswer
*answer
= NULL
;
155 dnskey
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_DNSKEY
, "example.com.");
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
);
165 log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey
)));
167 ds
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_DS
, "example.com.");
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
);
177 log_info("DS: %s", strna(dns_resource_record_to_string(ds
)));
179 mx
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_MX
, "example.com.");
182 mx
->mx
.priority
= 10;
183 mx
->mx
.exchange
= strdup("mail.example.com.");
184 assert_se(mx
->mx
.exchange
);
186 log_info("MX: %s", strna(dns_resource_record_to_string(mx
)));
188 rrsig
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_RRSIG
, "example.com.");
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
);
204 log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig
)));
206 assert_se(dnssec_key_match_rrsig(mx
->key
, rrsig
) > 0);
207 assert_se(dnssec_rrsig_match_dnskey(rrsig
, dnskey
, false) > 0);
209 answer
= dns_answer_new(1);
211 assert_se(dns_answer_add(answer
, mx
, 0, DNS_ANSWER_AUTHENTICATED
) >= 0);
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
);
218 assert_se(result
== DNSSEC_UNSUPPORTED_ALGORITHM
);
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,
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,
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
242 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*dnskey
= NULL
, *ds
= NULL
, *mx
= NULL
,
244 _cleanup_(dns_answer_unrefp
) DnsAnswer
*answer
= NULL
;
247 dnskey
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_DNSKEY
, "example.com.");
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
);
257 log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey
)));
259 ds
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_DS
, "example.com.");
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
);
269 log_info("DS: %s", strna(dns_resource_record_to_string(ds
)));
271 mx
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_MX
, "example.com.");
274 mx
->mx
.priority
= 10;
275 mx
->mx
.exchange
= strdup("mail.example.com.");
276 assert_se(mx
->mx
.exchange
);
278 log_info("MX: %s", strna(dns_resource_record_to_string(mx
)));
280 rrsig
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_RRSIG
, "example.com.");
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
);
296 log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig
)));
298 assert_se(dnssec_key_match_rrsig(mx
->key
, rrsig
) > 0);
299 assert_se(dnssec_rrsig_match_dnskey(rrsig
, dnskey
, false) > 0);
301 answer
= dns_answer_new(1);
303 assert_se(dns_answer_add(answer
, mx
, 0, DNS_ANSWER_AUTHENTICATED
) >= 0);
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
);
310 assert_se(result
== DNSSEC_UNSUPPORTED_ALGORITHM
);
313 static void test_dnssec_verify_rrset(void) {
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,
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,
338 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*a
= NULL
, *rrsig
= NULL
, *dnskey
= NULL
;
339 _cleanup_(dns_answer_unrefp
) DnsAnswer
*answer
= NULL
;
342 a
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_A
, "nAsA.gov");
345 a
->a
.in_addr
.s_addr
= inet_addr("52.0.14.116");
347 log_info("A: %s", strna(dns_resource_record_to_string(a
)));
349 rrsig
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_RRSIG
, "NaSa.GOV.");
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
);
365 log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig
)));
367 dnskey
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_DNSKEY
, "nASA.gOV");
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
);
377 log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey
)));
378 log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey
, false));
380 assert_se(dnssec_key_match_rrsig(a
->key
, rrsig
) > 0);
381 assert_se(dnssec_rrsig_match_dnskey(rrsig
, dnskey
, false) > 0);
383 answer
= dns_answer_new(1);
385 assert_se(dns_answer_add(answer
, a
, 0, DNS_ANSWER_AUTHENTICATED
) >= 0);
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
);
392 static void test_dnssec_verify_rrset2(void) {
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,
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,
417 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*nsec
= NULL
, *rrsig
= NULL
, *dnskey
= NULL
;
418 _cleanup_(dns_answer_unrefp
) DnsAnswer
*answer
= NULL
;
421 nsec
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_NSEC
, "nasa.gov");
424 nsec
->nsec
.next_domain_name
= strdup("3D-Printing.nasa.gov");
425 assert_se(nsec
->nsec
.next_domain_name
);
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);
439 log_info("NSEC: %s", strna(dns_resource_record_to_string(nsec
)));
441 rrsig
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_RRSIG
, "NaSa.GOV.");
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
);
457 log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig
)));
459 dnskey
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_DNSKEY
, "nASA.gOV");
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
);
469 log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey
)));
470 log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey
, false));
472 assert_se(dnssec_key_match_rrsig(nsec
->key
, rrsig
) > 0);
473 assert_se(dnssec_rrsig_match_dnskey(rrsig
, dnskey
, false) > 0);
475 answer
= dns_answer_new(1);
477 assert_se(dns_answer_add(answer
, nsec
, 0, DNS_ANSWER_AUTHENTICATED
) >= 0);
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
);
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
;
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.");
496 rr
->nsec3
.algorithm
= DNSSEC_DIGEST_SHA1
;
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
);
506 log_info("NSEC3: %s", strna(dns_resource_record_to_string(rr
)));
508 k
= dnssec_nsec3_hash(rr
, "eurid.eu", &h
);
511 b
= base32hexmem(h
, k
, false);
513 assert_se(strcasecmp(b
, "PJ8S08RR45VIQDAQGE7EN3VHKNROTBMM") == 0);
518 int main(int argc
, char*argv
[]) {
520 test_dnssec_canonicalize();
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();