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