]>
Commit | Line | Data |
---|---|---|
11e1e08b | 1 | /* |
6edbf68a PL |
2 | * This file is part of PowerDNS or dnsdist. |
3 | * Copyright -- PowerDNS.COM B.V. and its contributors | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of version 2 of the GNU General Public License as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * In addition, for the avoidance of any doubt, permission is granted to | |
10 | * link this program with OpenSSL and to (re)distribute the binaries | |
11 | * produced as the result of such linking. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
21 | */ | |
11e1e08b RG |
22 | #define BOOST_TEST_DYN_LINK |
23 | #define BOOST_TEST_NO_MAIN | |
24 | ||
25 | #include <boost/test/unit_test.hpp> | |
26 | ||
27 | #include "dnscrypt.hh" | |
28 | #include "dnsname.hh" | |
29 | #include "dnsparser.hh" | |
30 | #include "dnswriter.hh" | |
31 | #include <unistd.h> | |
32 | ||
33 | bool g_verbose{true}; | |
34 | bool g_console{true}; | |
bbfaaa6f | 35 | bool g_syslog{true}; |
11e1e08b RG |
36 | |
37 | BOOST_AUTO_TEST_SUITE(dnscrypt_cc) | |
38 | ||
39 | #ifdef HAVE_DNSCRYPT | |
40 | ||
41 | // plaintext query for cert | |
42 | BOOST_AUTO_TEST_CASE(DNSCryptPlaintextQuery) { | |
43 | DnsCryptPrivateKey resolverPrivateKey; | |
44 | DnsCryptCert resolverCert; | |
45 | unsigned char providerPublicKey[DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE]; | |
46 | unsigned char providerPrivateKey[DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE]; | |
47 | time_t now = time(NULL); | |
48 | DnsCryptContext::generateProviderKeys(providerPublicKey, providerPrivateKey); | |
49 | DnsCryptContext::generateCertificate(1, now, now + (24 * 60 * 3600), providerPrivateKey, resolverPrivateKey, resolverCert); | |
50 | DnsCryptContext ctx("2.name", resolverCert, resolverPrivateKey); | |
51 | ||
52 | DNSName name("2.name."); | |
53 | vector<uint8_t> plainQuery; | |
54 | DNSPacketWriter pw(plainQuery, name, QType::TXT, QClass::IN, 0); | |
55 | pw.getHeader()->rd = 0; | |
56 | uint16_t len = plainQuery.size(); | |
57 | ||
58 | std::shared_ptr<DnsCryptQuery> query = std::make_shared<DnsCryptQuery>(); | |
59 | uint16_t decryptedLen = 0; | |
60 | ||
61 | ctx.parsePacket((char*) plainQuery.data(), len, query, false, &decryptedLen); | |
62 | ||
63 | BOOST_CHECK_EQUAL(query->valid, true); | |
64 | BOOST_CHECK_EQUAL(query->encrypted, false); | |
65 | ||
66 | std::vector<uint8_t> response; | |
67 | ||
68 | ctx.getCertificateResponse(query, response); | |
69 | ||
27c0050c | 70 | MOADNSParser mdp(false, (char*) response.data(), response.size()); |
11e1e08b RG |
71 | |
72 | BOOST_CHECK_EQUAL(mdp.d_header.qdcount, 1); | |
73 | BOOST_CHECK_EQUAL(mdp.d_header.ancount, 1); | |
74 | BOOST_CHECK_EQUAL(mdp.d_header.nscount, 0); | |
75 | BOOST_CHECK_EQUAL(mdp.d_header.arcount, 0); | |
76 | ||
77 | BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "2.name."); | |
bd64cc44 RG |
78 | BOOST_CHECK(mdp.d_qclass == QClass::IN); |
79 | BOOST_CHECK(mdp.d_qtype == QType::TXT); | |
11e1e08b RG |
80 | } |
81 | ||
82 | // invalid plaintext query (A) | |
83 | BOOST_AUTO_TEST_CASE(DNSCryptPlaintextQueryInvalidA) { | |
84 | DnsCryptPrivateKey resolverPrivateKey; | |
85 | DnsCryptCert resolverCert; | |
86 | unsigned char providerPublicKey[DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE]; | |
87 | unsigned char providerPrivateKey[DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE]; | |
88 | time_t now = time(NULL); | |
89 | DnsCryptContext::generateProviderKeys(providerPublicKey, providerPrivateKey); | |
90 | DnsCryptContext::generateCertificate(1, now, now + (24 * 60 * 3600), providerPrivateKey, resolverPrivateKey, resolverCert); | |
91 | DnsCryptContext ctx("2.name", resolverCert, resolverPrivateKey); | |
92 | ||
93 | DNSName name("2.name."); | |
94 | ||
95 | vector<uint8_t> plainQuery; | |
96 | DNSPacketWriter pw(plainQuery, name, QType::A, QClass::IN, 0); | |
97 | pw.getHeader()->rd = 0; | |
98 | uint16_t len = plainQuery.size(); | |
99 | ||
100 | std::shared_ptr<DnsCryptQuery> query = std::make_shared<DnsCryptQuery>(); | |
101 | uint16_t decryptedLen = 0; | |
102 | ||
103 | ctx.parsePacket((char*) plainQuery.data(), len, query, false, &decryptedLen); | |
104 | ||
105 | BOOST_CHECK_EQUAL(query->valid, false); | |
106 | } | |
107 | ||
108 | // invalid plaintext query (wrong provider name) | |
109 | BOOST_AUTO_TEST_CASE(DNSCryptPlaintextQueryInvalidProviderName) { | |
110 | DnsCryptPrivateKey resolverPrivateKey; | |
111 | DnsCryptCert resolverCert; | |
112 | unsigned char providerPublicKey[DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE]; | |
113 | unsigned char providerPrivateKey[DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE]; | |
114 | time_t now = time(NULL); | |
115 | DnsCryptContext::generateProviderKeys(providerPublicKey, providerPrivateKey); | |
116 | DnsCryptContext::generateCertificate(1, now, now + (24 * 60 * 3600), providerPrivateKey, resolverPrivateKey, resolverCert); | |
117 | DnsCryptContext ctx("2.name", resolverCert, resolverPrivateKey); | |
118 | ||
119 | DNSName name("2.WRONG.name."); | |
120 | ||
121 | vector<uint8_t> plainQuery; | |
122 | DNSPacketWriter pw(plainQuery, name, QType::TXT, QClass::IN, 0); | |
123 | pw.getHeader()->rd = 0; | |
124 | uint16_t len = plainQuery.size(); | |
125 | ||
126 | std::shared_ptr<DnsCryptQuery> query = std::make_shared<DnsCryptQuery>(); | |
127 | uint16_t decryptedLen = 0; | |
128 | ||
129 | ctx.parsePacket((char*) plainQuery.data(), len, query, false, &decryptedLen); | |
130 | ||
131 | BOOST_CHECK_EQUAL(query->valid, false); | |
132 | } | |
133 | ||
134 | // valid encrypted query | |
135 | BOOST_AUTO_TEST_CASE(DNSCryptEncryptedQueryValid) { | |
136 | DnsCryptPrivateKey resolverPrivateKey; | |
137 | DnsCryptCert resolverCert; | |
138 | unsigned char providerPublicKey[DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE]; | |
139 | unsigned char providerPrivateKey[DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE]; | |
140 | time_t now = time(NULL); | |
141 | DnsCryptContext::generateProviderKeys(providerPublicKey, providerPrivateKey); | |
142 | DnsCryptContext::generateCertificate(1, now, now + (24 * 60 * 3600), providerPrivateKey, resolverPrivateKey, resolverCert); | |
143 | DnsCryptContext ctx("2.name", resolverCert, resolverPrivateKey); | |
144 | ||
145 | DnsCryptPrivateKey clientPrivateKey; | |
146 | unsigned char clientPublicKey[DNSCRYPT_PUBLIC_KEY_SIZE]; | |
147 | ||
148 | DnsCryptContext::generateResolverKeyPair(clientPrivateKey, clientPublicKey); | |
149 | ||
150 | unsigned char clientNonce[DNSCRYPT_NONCE_SIZE / 2] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, 0x09, 0x0A, 0x0B }; | |
151 | ||
152 | DNSName name("www.powerdns.com."); | |
153 | vector<uint8_t> plainQuery; | |
154 | DNSPacketWriter pw(plainQuery, name, QType::AAAA, QClass::IN, 0); | |
155 | pw.getHeader()->rd = 1; | |
156 | size_t requiredSize = plainQuery.size() + sizeof(DnsCryptQueryHeader) + DNSCRYPT_MAC_SIZE; | |
157 | if (requiredSize < DnsCryptQuery::minUDPLength) { | |
158 | requiredSize = DnsCryptQuery::minUDPLength; | |
159 | } | |
160 | ||
161 | plainQuery.reserve(requiredSize); | |
162 | uint16_t len = plainQuery.size(); | |
163 | uint16_t encryptedResponseLen = 0; | |
164 | ||
165 | int res = ctx.encryptQuery((char*) plainQuery.data(), len, plainQuery.capacity(), clientPublicKey, clientPrivateKey, clientNonce, false, &encryptedResponseLen); | |
166 | ||
167 | BOOST_CHECK_EQUAL(res, 0); | |
168 | BOOST_CHECK(encryptedResponseLen > len); | |
169 | ||
170 | std::shared_ptr<DnsCryptQuery> query = std::make_shared<DnsCryptQuery>(); | |
171 | uint16_t decryptedLen = 0; | |
172 | ||
173 | ctx.parsePacket((char*) plainQuery.data(), encryptedResponseLen, query, false, &decryptedLen); | |
174 | ||
175 | BOOST_CHECK_EQUAL(query->valid, true); | |
176 | BOOST_CHECK_EQUAL(query->encrypted, true); | |
177 | ||
27c0050c | 178 | MOADNSParser mdp(true, (char*) plainQuery.data(), decryptedLen); |
11e1e08b RG |
179 | |
180 | BOOST_CHECK_EQUAL(mdp.d_header.qdcount, 1); | |
181 | BOOST_CHECK_EQUAL(mdp.d_header.ancount, 0); | |
182 | BOOST_CHECK_EQUAL(mdp.d_header.nscount, 0); | |
183 | BOOST_CHECK_EQUAL(mdp.d_header.arcount, 0); | |
184 | ||
185 | BOOST_CHECK_EQUAL(mdp.d_qname, name); | |
bd64cc44 RG |
186 | BOOST_CHECK(mdp.d_qclass == QClass::IN); |
187 | BOOST_CHECK(mdp.d_qtype == QType::AAAA); | |
11e1e08b RG |
188 | } |
189 | ||
190 | // valid encrypted query with not enough room | |
191 | BOOST_AUTO_TEST_CASE(DNSCryptEncryptedQueryValidButShort) { | |
192 | DnsCryptPrivateKey resolverPrivateKey; | |
193 | DnsCryptCert resolverCert; | |
194 | unsigned char providerPublicKey[DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE]; | |
195 | unsigned char providerPrivateKey[DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE]; | |
196 | time_t now = time(NULL); | |
197 | DnsCryptContext::generateProviderKeys(providerPublicKey, providerPrivateKey); | |
198 | DnsCryptContext::generateCertificate(1, now, now + (24 * 60 * 3600), providerPrivateKey, resolverPrivateKey, resolverCert); | |
199 | DnsCryptContext ctx("2.name", resolverCert, resolverPrivateKey); | |
200 | ||
201 | DnsCryptPrivateKey clientPrivateKey; | |
202 | unsigned char clientPublicKey[DNSCRYPT_PUBLIC_KEY_SIZE]; | |
203 | ||
204 | DnsCryptContext::generateResolverKeyPair(clientPrivateKey, clientPublicKey); | |
205 | ||
206 | unsigned char clientNonce[DNSCRYPT_NONCE_SIZE / 2] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, 0x09, 0x0A, 0x0B }; | |
207 | ||
208 | DNSName name("www.powerdns.com."); | |
209 | vector<uint8_t> plainQuery; | |
210 | DNSPacketWriter pw(plainQuery, name, QType::AAAA, QClass::IN, 0); | |
211 | pw.getHeader()->rd = 1; | |
212 | ||
213 | uint16_t len = plainQuery.size(); | |
214 | uint16_t encryptedResponseLen = 0; | |
215 | ||
216 | int res = ctx.encryptQuery((char*) plainQuery.data(), len, plainQuery.capacity(), clientPublicKey, clientPrivateKey, clientNonce, false, &encryptedResponseLen); | |
217 | ||
218 | BOOST_CHECK_EQUAL(res, ENOBUFS); | |
219 | } | |
220 | ||
221 | // valid encrypted query with old key | |
222 | BOOST_AUTO_TEST_CASE(DNSCryptEncryptedQueryValidWithOldKey) { | |
223 | DnsCryptPrivateKey resolverPrivateKey; | |
224 | DnsCryptCert resolverCert; | |
225 | unsigned char providerPublicKey[DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE]; | |
226 | unsigned char providerPrivateKey[DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE]; | |
227 | time_t now = time(NULL); | |
228 | DnsCryptContext::generateProviderKeys(providerPublicKey, providerPrivateKey); | |
229 | DnsCryptContext::generateCertificate(1, now, now + (24 * 60 * 3600), providerPrivateKey, resolverPrivateKey, resolverCert); | |
230 | DnsCryptContext ctx("2.name", resolverCert, resolverPrivateKey); | |
231 | ||
232 | DnsCryptPrivateKey clientPrivateKey; | |
233 | unsigned char clientPublicKey[DNSCRYPT_PUBLIC_KEY_SIZE]; | |
234 | ||
235 | DnsCryptContext::generateResolverKeyPair(clientPrivateKey, clientPublicKey); | |
236 | ||
237 | unsigned char clientNonce[DNSCRYPT_NONCE_SIZE / 2] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, 0x09, 0x0A, 0x0B }; | |
238 | ||
239 | DNSName name("www.powerdns.com."); | |
240 | vector<uint8_t> plainQuery; | |
241 | DNSPacketWriter pw(plainQuery, name, QType::AAAA, QClass::IN, 0); | |
242 | pw.getHeader()->rd = 1; | |
243 | ||
244 | size_t requiredSize = plainQuery.size() + sizeof(DnsCryptQueryHeader) + DNSCRYPT_MAC_SIZE; | |
245 | if (requiredSize < DnsCryptQuery::minUDPLength) { | |
246 | requiredSize = DnsCryptQuery::minUDPLength; | |
247 | } | |
248 | ||
249 | plainQuery.reserve(requiredSize); | |
250 | ||
251 | uint16_t len = plainQuery.size(); | |
252 | uint16_t encryptedResponseLen = 0; | |
253 | ||
254 | int res = ctx.encryptQuery((char*) plainQuery.data(), len, plainQuery.capacity(), clientPublicKey, clientPrivateKey, clientNonce, false, &encryptedResponseLen); | |
255 | ||
256 | BOOST_CHECK_EQUAL(res, 0); | |
257 | BOOST_CHECK(encryptedResponseLen > len); | |
258 | ||
259 | DnsCryptContext::generateCertificate(1, now, now + (24 * 60 * 3600), providerPrivateKey, resolverPrivateKey, resolverCert); | |
260 | ctx.setNewCertificate(resolverCert, resolverPrivateKey); | |
261 | ||
262 | std::shared_ptr<DnsCryptQuery> query = std::make_shared<DnsCryptQuery>(); | |
263 | uint16_t decryptedLen = 0; | |
264 | ||
265 | ctx.parsePacket((char*) plainQuery.data(), encryptedResponseLen, query, false, &decryptedLen); | |
266 | ||
267 | BOOST_CHECK_EQUAL(query->valid, true); | |
268 | BOOST_CHECK_EQUAL(query->encrypted, true); | |
269 | ||
27c0050c | 270 | MOADNSParser mdp(true, (char*) plainQuery.data(), decryptedLen); |
11e1e08b RG |
271 | |
272 | BOOST_CHECK_EQUAL(mdp.d_header.qdcount, 1); | |
273 | BOOST_CHECK_EQUAL(mdp.d_header.ancount, 0); | |
274 | BOOST_CHECK_EQUAL(mdp.d_header.nscount, 0); | |
275 | BOOST_CHECK_EQUAL(mdp.d_header.arcount, 0); | |
276 | ||
277 | BOOST_CHECK_EQUAL(mdp.d_qname, name); | |
bd64cc44 RG |
278 | BOOST_CHECK(mdp.d_qclass == QClass::IN); |
279 | BOOST_CHECK(mdp.d_qtype == QType::AAAA); | |
11e1e08b RG |
280 | } |
281 | ||
282 | // valid encrypted query with wrong key | |
283 | BOOST_AUTO_TEST_CASE(DNSCryptEncryptedQueryInvalidWithWrongKey) { | |
284 | DnsCryptPrivateKey resolverPrivateKey; | |
285 | DnsCryptCert resolverCert; | |
286 | unsigned char providerPublicKey[DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE]; | |
287 | unsigned char providerPrivateKey[DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE]; | |
288 | time_t now = time(NULL); | |
289 | DnsCryptContext::generateProviderKeys(providerPublicKey, providerPrivateKey); | |
290 | DnsCryptContext::generateCertificate(1, now, now + (24 * 60 * 3600), providerPrivateKey, resolverPrivateKey, resolverCert); | |
291 | DnsCryptContext ctx("2.name", resolverCert, resolverPrivateKey); | |
292 | ||
293 | DnsCryptPrivateKey clientPrivateKey; | |
294 | unsigned char clientPublicKey[DNSCRYPT_PUBLIC_KEY_SIZE]; | |
295 | ||
296 | DnsCryptContext::generateResolverKeyPair(clientPrivateKey, clientPublicKey); | |
297 | ||
298 | unsigned char clientNonce[DNSCRYPT_NONCE_SIZE / 2] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, 0x09, 0x0A, 0x0B }; | |
299 | ||
300 | DNSName name("www.powerdns.com."); | |
301 | vector<uint8_t> plainQuery; | |
302 | DNSPacketWriter pw(plainQuery, name, QType::AAAA, QClass::IN, 0); | |
303 | pw.getHeader()->rd = 1; | |
304 | ||
305 | size_t requiredSize = plainQuery.size() + sizeof(DnsCryptQueryHeader) + DNSCRYPT_MAC_SIZE; | |
306 | if (requiredSize < DnsCryptQuery::minUDPLength) { | |
307 | requiredSize = DnsCryptQuery::minUDPLength; | |
308 | } | |
309 | ||
310 | plainQuery.reserve(requiredSize); | |
311 | ||
312 | uint16_t len = plainQuery.size(); | |
313 | uint16_t encryptedResponseLen = 0; | |
314 | ||
315 | int res = ctx.encryptQuery((char*) plainQuery.data(), len, plainQuery.capacity(), clientPublicKey, clientPrivateKey, clientNonce, false, &encryptedResponseLen); | |
316 | ||
317 | BOOST_CHECK_EQUAL(res, 0); | |
318 | BOOST_CHECK(encryptedResponseLen > len); | |
319 | ||
320 | DnsCryptContext::generateCertificate(1, now, now + (24 * 60 * 3600), providerPrivateKey, resolverPrivateKey, resolverCert); | |
321 | ctx.setNewCertificate(resolverCert, resolverPrivateKey); | |
322 | ||
323 | DnsCryptContext::generateCertificate(1, now, now + (24 * 60 * 3600), providerPrivateKey, resolverPrivateKey, resolverCert); | |
324 | ctx.setNewCertificate(resolverCert, resolverPrivateKey); | |
325 | ||
326 | /* we have changed the key two times, we don't have the one used to encrypt this query */ | |
327 | ||
328 | std::shared_ptr<DnsCryptQuery> query = std::make_shared<DnsCryptQuery>(); | |
329 | uint16_t decryptedLen = 0; | |
330 | ||
331 | ctx.parsePacket((char*) plainQuery.data(), encryptedResponseLen, query, false, &decryptedLen); | |
332 | ||
333 | BOOST_CHECK_EQUAL(query->valid, false); | |
334 | } | |
335 | ||
336 | #endif | |
337 | ||
338 | BOOST_AUTO_TEST_SUITE_END(); |