]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/test-dnssec.c
resolved: apparently not all names are used in canonical form for DNSSEC validation
[thirdparty/systemd.git] / src / resolve / test-dnssec.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2015 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <arpa/inet.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
31 static void test_dnssec_verify_rrset2(void) {
32
33 static const uint8_t signature_blob[] = {
34 0x48, 0x45, 0xc8, 0x8b, 0xc0, 0x14, 0x92, 0xf5, 0x15, 0xc6, 0x84, 0x9d, 0x2f, 0xe3, 0x32, 0x11,
35 0x7d, 0xf1, 0xe6, 0x87, 0xb9, 0x42, 0xd3, 0x8b, 0x9e, 0xaf, 0x92, 0x31, 0x0a, 0x53, 0xad, 0x8b,
36 0xa7, 0x5c, 0x83, 0x39, 0x8c, 0x28, 0xac, 0xce, 0x6e, 0x9c, 0x18, 0xe3, 0x31, 0x16, 0x6e, 0xca,
37 0x38, 0x31, 0xaf, 0xd9, 0x94, 0xf1, 0x84, 0xb1, 0xdf, 0x5a, 0xc2, 0x73, 0x22, 0xf6, 0xcb, 0xa2,
38 0xe7, 0x8c, 0x77, 0x0c, 0x74, 0x2f, 0xc2, 0x13, 0xb0, 0x93, 0x51, 0xa9, 0x4f, 0xae, 0x0a, 0xda,
39 0x45, 0xcc, 0xfd, 0x43, 0x99, 0x36, 0x9a, 0x0d, 0x21, 0xe0, 0xeb, 0x30, 0x65, 0xd4, 0xa0, 0x27,
40 0x37, 0x3b, 0xe4, 0xc1, 0xc5, 0xa1, 0x2a, 0xd1, 0x76, 0xc4, 0x7e, 0x64, 0x0e, 0x5a, 0xa6, 0x50,
41 0x24, 0xd5, 0x2c, 0xcc, 0x6d, 0xe5, 0x37, 0xea, 0xbd, 0x09, 0x34, 0xed, 0x24, 0x06, 0xa1, 0x22,
42 };
43
44 static const uint8_t dnskey_blob[] = {
45 0x03, 0x01, 0x00, 0x01, 0xc3, 0x7f, 0x1d, 0xd1, 0x1c, 0x97, 0xb1, 0x13, 0x34, 0x3a, 0x9a, 0xea,
46 0xee, 0xd9, 0x5a, 0x11, 0x1b, 0x17, 0xc7, 0xe3, 0xd4, 0xda, 0x20, 0xbc, 0x5d, 0xba, 0x74, 0xe3,
47 0x37, 0x99, 0xec, 0x25, 0xce, 0x93, 0x7f, 0xbd, 0x22, 0x73, 0x7e, 0x14, 0x71, 0xe0, 0x60, 0x07,
48 0xd4, 0x39, 0x8b, 0x5e, 0xe9, 0xba, 0x25, 0xe8, 0x49, 0xe9, 0x34, 0xef, 0xfe, 0x04, 0x5c, 0xa5,
49 0x27, 0xcd, 0xa9, 0xda, 0x70, 0x05, 0x21, 0xab, 0x15, 0x82, 0x24, 0xc3, 0x94, 0xf5, 0xd7, 0xb7,
50 0xc4, 0x66, 0xcb, 0x32, 0x6e, 0x60, 0x2b, 0x55, 0x59, 0x28, 0x89, 0x8a, 0x72, 0xde, 0x88, 0x56,
51 0x27, 0x95, 0xd9, 0xac, 0x88, 0x4f, 0x65, 0x2b, 0x68, 0xfc, 0xe6, 0x41, 0xc1, 0x1b, 0xef, 0x4e,
52 0xd6, 0xc2, 0x0f, 0x64, 0x88, 0x95, 0x5e, 0xdd, 0x3a, 0x02, 0x07, 0x50, 0xa9, 0xda, 0xa4, 0x49,
53 0x74, 0x62, 0xfe, 0xd7,
54 };
55
56 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *nsec = NULL, *rrsig = NULL, *dnskey = NULL;
57 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
58 _cleanup_free_ char *x = NULL, *y = NULL, *z = NULL;
59 DnssecResult result;
60
61 nsec = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_NSEC, "nasa.gov");
62 assert_se(nsec);
63
64 nsec->nsec.next_domain_name = strdup("3D-Printing.nasa.gov");
65 assert_se(nsec->nsec.next_domain_name);
66
67 nsec->nsec.types = bitmap_new();
68 assert_se(nsec->nsec.types);
69 assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_A) >= 0);
70 assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_NS) >= 0);
71 assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_SOA) >= 0);
72 assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_MX) >= 0);
73 assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_TXT) >= 0);
74 assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_RRSIG) >= 0);
75 assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_NSEC) >= 0);
76 assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_DNSKEY) >= 0);
77 assert_se(bitmap_set(nsec->nsec.types, 65534) >= 0);
78
79 assert_se(dns_resource_record_to_string(nsec, &x) >= 0);
80 log_info("NSEC: %s", x);
81
82 rrsig = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_RRSIG, "NaSa.GOV.");
83 assert_se(rrsig);
84
85 rrsig->rrsig.type_covered = DNS_TYPE_NSEC;
86 rrsig->rrsig.algorithm = DNSSEC_ALGORITHM_RSASHA256;
87 rrsig->rrsig.labels = 2;
88 rrsig->rrsig.original_ttl = 300;
89 rrsig->rrsig.expiration = 0x5689002f;
90 rrsig->rrsig.inception = 0x56617230;
91 rrsig->rrsig.key_tag = 30390;
92 rrsig->rrsig.signer = strdup("Nasa.Gov.");
93 assert_se(rrsig->rrsig.signer);
94 rrsig->rrsig.signature_size = sizeof(signature_blob);
95 rrsig->rrsig.signature = memdup(signature_blob, rrsig->rrsig.signature_size);
96 assert_se(rrsig->rrsig.signature);
97
98 assert_se(dns_resource_record_to_string(rrsig, &y) >= 0);
99 log_info("RRSIG: %s", y);
100
101 dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nASA.gOV");
102 assert_se(dnskey);
103
104 dnskey->dnskey.flags = 256;
105 dnskey->dnskey.protocol = 3;
106 dnskey->dnskey.algorithm = DNSSEC_ALGORITHM_RSASHA256;
107 dnskey->dnskey.key_size = sizeof(dnskey_blob);
108 dnskey->dnskey.key = memdup(dnskey_blob, sizeof(dnskey_blob));
109 assert_se(dnskey->dnskey.key);
110
111 assert_se(dns_resource_record_to_string(dnskey, &z) >= 0);
112 log_info("DNSKEY: %s", z);
113 log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey));
114
115 assert_se(dnssec_key_match_rrsig(nsec->key, rrsig) > 0);
116 assert_se(dnssec_rrsig_match_dnskey(rrsig, dnskey) > 0);
117
118 answer = dns_answer_new(1);
119 assert_se(answer);
120 assert_se(dns_answer_add(answer, nsec, 0) >= 0);
121
122 /* Validate the RR as it if was 2015-12-11 today */
123 assert_se(dnssec_verify_rrset(answer, nsec->key, rrsig, dnskey, 1449849318*USEC_PER_SEC, &result) >= 0);
124 assert_se(result == DNSSEC_VALIDATED);
125 }
126
127 static void test_dnssec_verify_rrset(void) {
128
129 static const uint8_t signature_blob[] = {
130 0x7f, 0x79, 0xdd, 0x5e, 0x89, 0x79, 0x18, 0xd0, 0x34, 0x86, 0x8c, 0x72, 0x77, 0x75, 0x48, 0x4d,
131 0xc3, 0x7d, 0x38, 0x04, 0xab, 0xcd, 0x9e, 0x4c, 0x82, 0xb0, 0x92, 0xca, 0xe9, 0x66, 0xe9, 0x6e,
132 0x47, 0xc7, 0x68, 0x8c, 0x94, 0xf6, 0x69, 0xcb, 0x75, 0x94, 0xe6, 0x30, 0xa6, 0xfb, 0x68, 0x64,
133 0x96, 0x1a, 0x84, 0xe1, 0xdc, 0x16, 0x4c, 0x83, 0x6c, 0x44, 0xf2, 0x74, 0x4d, 0x74, 0x79, 0x8f,
134 0xf3, 0xf4, 0x63, 0x0d, 0xef, 0x5a, 0xe7, 0xe2, 0xfd, 0xf2, 0x2b, 0x38, 0x7c, 0x28, 0x96, 0x9d,
135 0xb6, 0xcd, 0x5c, 0x3b, 0x57, 0xe2, 0x24, 0x78, 0x65, 0xd0, 0x9e, 0x77, 0x83, 0x09, 0x6c, 0xff,
136 0x3d, 0x52, 0x3f, 0x6e, 0xd1, 0xed, 0x2e, 0xf9, 0xee, 0x8e, 0xa6, 0xbe, 0x9a, 0xa8, 0x87, 0x76,
137 0xd8, 0x77, 0xcc, 0x96, 0xa0, 0x98, 0xa1, 0xd1, 0x68, 0x09, 0x43, 0xcf, 0x56, 0xd9, 0xd1, 0x66,
138 };
139
140 static const uint8_t dnskey_blob[] = {
141 0x03, 0x01, 0x00, 0x01, 0x9b, 0x49, 0x9b, 0xc1, 0xf9, 0x9a, 0xe0, 0x4e, 0xcf, 0xcb, 0x14, 0x45,
142 0x2e, 0xc9, 0xf9, 0x74, 0xa7, 0x18, 0xb5, 0xf3, 0xde, 0x39, 0x49, 0xdf, 0x63, 0x33, 0x97, 0x52,
143 0xe0, 0x8e, 0xac, 0x50, 0x30, 0x8e, 0x09, 0xd5, 0x24, 0x3d, 0x26, 0xa4, 0x49, 0x37, 0x2b, 0xb0,
144 0x6b, 0x1b, 0xdf, 0xde, 0x85, 0x83, 0xcb, 0x22, 0x4e, 0x60, 0x0a, 0x91, 0x1a, 0x1f, 0xc5, 0x40,
145 0xb1, 0xc3, 0x15, 0xc1, 0x54, 0x77, 0x86, 0x65, 0x53, 0xec, 0x10, 0x90, 0x0c, 0x91, 0x00, 0x5e,
146 0x15, 0xdc, 0x08, 0x02, 0x4c, 0x8c, 0x0d, 0xc0, 0xac, 0x6e, 0xc4, 0x3e, 0x1b, 0x80, 0x19, 0xe4,
147 0xf7, 0x5f, 0x77, 0x51, 0x06, 0x87, 0x61, 0xde, 0xa2, 0x18, 0x0f, 0x40, 0x8b, 0x79, 0x72, 0xfa,
148 0x8d, 0x1a, 0x44, 0x47, 0x0d, 0x8e, 0x3a, 0x2d, 0xc7, 0x39, 0xbf, 0x56, 0x28, 0x97, 0xd9, 0x20,
149 0x4f, 0x00, 0x51, 0x3b,
150 };
151
152 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *a = NULL, *rrsig = NULL, *dnskey = NULL;
153 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
154 _cleanup_free_ char *x = NULL, *y = NULL, *z = NULL;
155 DnssecResult result;
156
157 a = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, "nAsA.gov");
158 assert_se(a);
159
160 a->a.in_addr.s_addr = inet_addr("52.0.14.116");
161
162 assert_se(dns_resource_record_to_string(a, &x) >= 0);
163 log_info("A: %s", x);
164
165 rrsig = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_RRSIG, "NaSa.GOV.");
166 assert_se(rrsig);
167
168 rrsig->rrsig.type_covered = DNS_TYPE_A;
169 rrsig->rrsig.algorithm = DNSSEC_ALGORITHM_RSASHA256;
170 rrsig->rrsig.labels = 2;
171 rrsig->rrsig.original_ttl = 600;
172 rrsig->rrsig.expiration = 0x5683135c;
173 rrsig->rrsig.inception = 0x565b7da8;
174 rrsig->rrsig.key_tag = 63876;
175 rrsig->rrsig.signer = strdup("Nasa.Gov.");
176 assert_se(rrsig->rrsig.signer);
177 rrsig->rrsig.signature_size = sizeof(signature_blob);
178 rrsig->rrsig.signature = memdup(signature_blob, rrsig->rrsig.signature_size);
179 assert_se(rrsig->rrsig.signature);
180
181 assert_se(dns_resource_record_to_string(rrsig, &y) >= 0);
182 log_info("RRSIG: %s", y);
183
184 dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nASA.gOV");
185 assert_se(dnskey);
186
187 dnskey->dnskey.flags = 256;
188 dnskey->dnskey.protocol = 3;
189 dnskey->dnskey.algorithm = DNSSEC_ALGORITHM_RSASHA256;
190 dnskey->dnskey.key_size = sizeof(dnskey_blob);
191 dnskey->dnskey.key = memdup(dnskey_blob, sizeof(dnskey_blob));
192 assert_se(dnskey->dnskey.key);
193
194 assert_se(dns_resource_record_to_string(dnskey, &z) >= 0);
195 log_info("DNSKEY: %s", z);
196 log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey));
197
198 assert_se(dnssec_key_match_rrsig(a->key, rrsig) > 0);
199 assert_se(dnssec_rrsig_match_dnskey(rrsig, dnskey) > 0);
200
201 answer = dns_answer_new(1);
202 assert_se(answer);
203 assert_se(dns_answer_add(answer, a, 0) >= 0);
204
205 /* Validate the RR as it if was 2015-12-2 today */
206 assert_se(dnssec_verify_rrset(answer, a->key, rrsig, dnskey, 1449092754*USEC_PER_SEC, &result) >= 0);
207 assert_se(result == DNSSEC_VALIDATED);
208 }
209
210 static void test_dnssec_verify_dns_key(void) {
211
212 static const uint8_t ds1_fprint[] = {
213 0x46, 0x8B, 0xC8, 0xDD, 0xC7, 0xE8, 0x27, 0x03, 0x40, 0xBB, 0x8A, 0x1F, 0x3B, 0x2E, 0x45, 0x9D,
214 0x80, 0x67, 0x14, 0x01,
215 };
216 static const uint8_t ds2_fprint[] = {
217 0x8A, 0xEE, 0x80, 0x47, 0x05, 0x5F, 0x83, 0xD1, 0x48, 0xBA, 0x8F, 0xF6, 0xDD, 0xA7, 0x60, 0xCE,
218 0x94, 0xF7, 0xC7, 0x5E, 0x52, 0x4C, 0xF2, 0xE9, 0x50, 0xB9, 0x2E, 0xCB, 0xEF, 0x96, 0xB9, 0x98,
219 };
220 static const uint8_t dnskey_blob[] = {
221 0x03, 0x01, 0x00, 0x01, 0xa8, 0x12, 0xda, 0x4f, 0xd2, 0x7d, 0x54, 0x14, 0x0e, 0xcc, 0x5b, 0x5e,
222 0x45, 0x9c, 0x96, 0x98, 0xc0, 0xc0, 0x85, 0x81, 0xb1, 0x47, 0x8c, 0x7d, 0xe8, 0x39, 0x50, 0xcc,
223 0xc5, 0xd0, 0xf2, 0x00, 0x81, 0x67, 0x79, 0xf6, 0xcc, 0x9d, 0xad, 0x6c, 0xbb, 0x7b, 0x6f, 0x48,
224 0x97, 0x15, 0x1c, 0xfd, 0x0b, 0xfe, 0xd3, 0xd7, 0x7d, 0x9f, 0x81, 0x26, 0xd3, 0xc5, 0x65, 0x49,
225 0xcf, 0x46, 0x62, 0xb0, 0x55, 0x6e, 0x47, 0xc7, 0x30, 0xef, 0x51, 0xfb, 0x3e, 0xc6, 0xef, 0xde,
226 0x27, 0x3f, 0xfa, 0x57, 0x2d, 0xa7, 0x1d, 0x80, 0x46, 0x9a, 0x5f, 0x14, 0xb3, 0xb0, 0x2c, 0xbe,
227 0x72, 0xca, 0xdf, 0xb2, 0xff, 0x36, 0x5b, 0x4f, 0xec, 0x58, 0x8e, 0x8d, 0x01, 0xe9, 0xa9, 0xdf,
228 0xb5, 0x60, 0xad, 0x52, 0x4d, 0xfc, 0xa9, 0x3e, 0x8d, 0x35, 0x95, 0xb3, 0x4e, 0x0f, 0xca, 0x45,
229 0x1b, 0xf7, 0xef, 0x3a, 0x88, 0x25, 0x08, 0xc7, 0x4e, 0x06, 0xc1, 0x62, 0x1a, 0xce, 0xd8, 0x77,
230 0xbd, 0x02, 0x65, 0xf8, 0x49, 0xfb, 0xce, 0xf6, 0xa8, 0x09, 0xfc, 0xde, 0xb2, 0x09, 0x9d, 0x39,
231 0xf8, 0x63, 0x9c, 0x32, 0x42, 0x7c, 0xa0, 0x30, 0x86, 0x72, 0x7a, 0x4a, 0xc6, 0xd4, 0xb3, 0x2d,
232 0x24, 0xef, 0x96, 0x3f, 0xc2, 0xda, 0xd3, 0xf2, 0x15, 0x6f, 0xda, 0x65, 0x4b, 0x81, 0x28, 0x68,
233 0xf4, 0xfe, 0x3e, 0x71, 0x4f, 0x50, 0x96, 0x72, 0x58, 0xa1, 0x89, 0xdd, 0x01, 0x61, 0x39, 0x39,
234 0xc6, 0x76, 0xa4, 0xda, 0x02, 0x70, 0x3d, 0xc0, 0xdc, 0x8d, 0x70, 0x72, 0x04, 0x90, 0x79, 0xd4,
235 0xec, 0x65, 0xcf, 0x49, 0x35, 0x25, 0x3a, 0x14, 0x1a, 0x45, 0x20, 0xeb, 0x31, 0xaf, 0x92, 0xba,
236 0x20, 0xd3, 0xcd, 0xa7, 0x13, 0x44, 0xdc, 0xcf, 0xf0, 0x27, 0x34, 0xb9, 0xe7, 0x24, 0x6f, 0x73,
237 0xe7, 0xea, 0x77, 0x03,
238 };
239
240 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *dnskey = NULL, *ds1 = NULL, *ds2 = NULL;
241 _cleanup_free_ char *a = NULL, *b = NULL, *c = NULL;
242
243 /* The two DS RRs in effect for nasa.gov on 2015-12-01. */
244 ds1 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "nasa.gov");
245 assert_se(ds1);
246
247 ds1->ds.key_tag = 47857;
248 ds1->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256;
249 ds1->ds.digest_type = DNSSEC_DIGEST_SHA1;
250 ds1->ds.digest_size = sizeof(ds1_fprint);
251 ds1->ds.digest = memdup(ds1_fprint, ds1->ds.digest_size);
252 assert_se(ds1->ds.digest);
253
254 assert_se(dns_resource_record_to_string(ds1, &a) >= 0);
255 log_info("DS1: %s", a);
256
257 ds2 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "NASA.GOV");
258 assert_se(ds2);
259
260 ds2->ds.key_tag = 47857;
261 ds2->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256;
262 ds2->ds.digest_type = DNSSEC_DIGEST_SHA256;
263 ds2->ds.digest_size = sizeof(ds2_fprint);
264 ds2->ds.digest = memdup(ds2_fprint, ds2->ds.digest_size);
265 assert_se(ds2->ds.digest);
266
267 assert_se(dns_resource_record_to_string(ds2, &b) >= 0);
268 log_info("DS2: %s", b);
269
270 dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nasa.GOV");
271 assert_se(dnskey);
272
273 dnskey->dnskey.flags = 257;
274 dnskey->dnskey.protocol = 3;
275 dnskey->dnskey.algorithm = DNSSEC_ALGORITHM_RSASHA256;
276 dnskey->dnskey.key_size = sizeof(dnskey_blob);
277 dnskey->dnskey.key = memdup(dnskey_blob, sizeof(dnskey_blob));
278 assert_se(dnskey->dnskey.key);
279
280 assert_se(dns_resource_record_to_string(dnskey, &c) >= 0);
281 log_info("DNSKEY: %s", c);
282 log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey));
283
284 assert_se(dnssec_verify_dnskey(dnskey, ds1) > 0);
285 assert_se(dnssec_verify_dnskey(dnskey, ds2) > 0);
286 }
287
288 static void test_dnssec_canonicalize_one(const char *original, const char *canonical, int r) {
289 char canonicalized[DNSSEC_CANONICAL_HOSTNAME_MAX];
290
291 assert_se(dnssec_canonicalize(original, canonicalized, sizeof(canonicalized)) == r);
292 if (r < 0)
293 return;
294
295 assert_se(streq(canonicalized, canonical));
296 }
297
298 static void test_dnssec_canonicalize(void) {
299 test_dnssec_canonicalize_one("", ".", 1);
300 test_dnssec_canonicalize_one(".", ".", 1);
301 test_dnssec_canonicalize_one("foo", "foo.", 4);
302 test_dnssec_canonicalize_one("foo.", "foo.", 4);
303 test_dnssec_canonicalize_one("FOO.", "foo.", 4);
304 test_dnssec_canonicalize_one("FOO.bar.", "foo.bar.", 8);
305 test_dnssec_canonicalize_one("FOO..bar.", NULL, -EINVAL);
306 }
307
308 int main(int argc, char*argv[]) {
309
310 test_dnssec_canonicalize();
311 test_dnssec_verify_dns_key();
312 test_dnssec_verify_rrset();
313 test_dnssec_verify_rrset2();
314
315 return 0;
316 }