]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/test-dnscrypt_cc.cc
rec: ensure correct service user on debian
[thirdparty/pdns.git] / pdns / test-dnscrypt_cc.cc
1 /*
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 */
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_syslog{true};
35
36 BOOST_AUTO_TEST_SUITE(test_dnscrypt_cc)
37
38 #ifdef HAVE_DNSCRYPT
39
40 // plaintext query for cert
41 BOOST_AUTO_TEST_CASE(DNSCryptPlaintextQuery) {
42 DNSCryptPrivateKey resolverPrivateKey;
43 DNSCryptCert resolverCert;
44 unsigned char providerPublicKey[DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE];
45 unsigned char providerPrivateKey[DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE];
46 time_t now = time(nullptr);
47 DNSCryptContext::generateProviderKeys(providerPublicKey, providerPrivateKey);
48 DNSCryptContext::generateCertificate(1, now, now + (24 * 60 * 3600), DNSCryptExchangeVersion::VERSION1, providerPrivateKey, resolverPrivateKey, resolverCert);
49 auto ctx = std::make_shared<DNSCryptContext>("2.name", resolverCert, resolverPrivateKey);
50
51 DNSName name("2.name.");
52 vector<uint8_t> plainQuery;
53 DNSPacketWriter pw(plainQuery, name, QType::TXT, QClass::IN, 0);
54 pw.getHeader()->rd = 0;
55 uint16_t len = plainQuery.size();
56
57 std::shared_ptr<DNSCryptQuery> query = std::make_shared<DNSCryptQuery>(ctx);
58 uint16_t decryptedLen = 0;
59
60 query->parsePacket((char*) plainQuery.data(), len, false, &decryptedLen, now);
61
62 BOOST_CHECK_EQUAL(query->isValid(), true);
63 BOOST_CHECK_EQUAL(query->isEncrypted(), false);
64
65 std::vector<uint8_t> response;
66
67 query->getCertificateResponse(now, response);
68
69 MOADNSParser mdp(false, (char*) response.data(), response.size());
70
71 BOOST_CHECK_EQUAL(mdp.d_header.qdcount, 1);
72 BOOST_CHECK_EQUAL(mdp.d_header.ancount, 1);
73 BOOST_CHECK_EQUAL(mdp.d_header.nscount, 0);
74 BOOST_CHECK_EQUAL(mdp.d_header.arcount, 0);
75
76 BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "2.name.");
77 BOOST_CHECK(mdp.d_qclass == QClass::IN);
78 BOOST_CHECK(mdp.d_qtype == QType::TXT);
79 }
80
81 // invalid plaintext query (A)
82 BOOST_AUTO_TEST_CASE(DNSCryptPlaintextQueryInvalidA) {
83 DNSCryptPrivateKey resolverPrivateKey;
84 DNSCryptCert resolverCert;
85 unsigned char providerPublicKey[DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE];
86 unsigned char providerPrivateKey[DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE];
87 time_t now = time(nullptr);
88 DNSCryptContext::generateProviderKeys(providerPublicKey, providerPrivateKey);
89 DNSCryptContext::generateCertificate(1, now, now + (24 * 60 * 3600), DNSCryptExchangeVersion::VERSION1, providerPrivateKey, resolverPrivateKey, resolverCert);
90 auto ctx = std::make_shared<DNSCryptContext>("2.name", resolverCert, resolverPrivateKey);
91
92 DNSName name("2.name.");
93
94 vector<uint8_t> plainQuery;
95 DNSPacketWriter pw(plainQuery, name, QType::A, QClass::IN, 0);
96 pw.getHeader()->rd = 0;
97 uint16_t len = plainQuery.size();
98
99 std::shared_ptr<DNSCryptQuery> query = std::make_shared<DNSCryptQuery>(ctx);
100 uint16_t decryptedLen = 0;
101
102 query->parsePacket((char*) plainQuery.data(), len, false, &decryptedLen, now);
103
104 BOOST_CHECK_EQUAL(query->isValid(), false);
105 }
106
107 // invalid plaintext query (wrong provider name)
108 BOOST_AUTO_TEST_CASE(DNSCryptPlaintextQueryInvalidProviderName) {
109 DNSCryptPrivateKey resolverPrivateKey;
110 DNSCryptCert resolverCert;
111 unsigned char providerPublicKey[DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE];
112 unsigned char providerPrivateKey[DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE];
113 time_t now = time(nullptr);
114 DNSCryptContext::generateProviderKeys(providerPublicKey, providerPrivateKey);
115 DNSCryptContext::generateCertificate(1, now, now + (24 * 60 * 3600), DNSCryptExchangeVersion::VERSION1, providerPrivateKey, resolverPrivateKey, resolverCert);
116 auto ctx = std::make_shared<DNSCryptContext>("2.name", resolverCert, resolverPrivateKey);
117
118 DNSName name("2.WRONG.name.");
119
120 vector<uint8_t> plainQuery;
121 DNSPacketWriter pw(plainQuery, name, QType::TXT, QClass::IN, 0);
122 pw.getHeader()->rd = 0;
123 uint16_t len = plainQuery.size();
124
125 std::shared_ptr<DNSCryptQuery> query = std::make_shared<DNSCryptQuery>(ctx);
126 uint16_t decryptedLen = 0;
127
128 query->parsePacket((char*) plainQuery.data(), len, false, &decryptedLen, now);
129
130 BOOST_CHECK_EQUAL(query->isValid(), false);
131 }
132
133 // valid encrypted query
134 BOOST_AUTO_TEST_CASE(DNSCryptEncryptedQueryValid) {
135 DNSCryptPrivateKey resolverPrivateKey;
136 DNSCryptCert resolverCert;
137 unsigned char providerPublicKey[DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE];
138 unsigned char providerPrivateKey[DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE];
139 time_t now = time(nullptr);
140 DNSCryptContext::generateProviderKeys(providerPublicKey, providerPrivateKey);
141 DNSCryptContext::generateCertificate(1, now, now + (24 * 60 * 3600), DNSCryptExchangeVersion::VERSION1, providerPrivateKey, resolverPrivateKey, resolverCert);
142 auto ctx = std::make_shared<DNSCryptContext>("2.name", resolverCert, resolverPrivateKey);
143
144 DNSCryptPrivateKey clientPrivateKey;
145 unsigned char clientPublicKey[DNSCRYPT_PUBLIC_KEY_SIZE];
146
147 DNSCryptContext::generateResolverKeyPair(clientPrivateKey, clientPublicKey);
148
149 unsigned char clientNonce[DNSCRYPT_NONCE_SIZE / 2] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, 0x09, 0x0A, 0x0B };
150
151 DNSName name("www.powerdns.com.");
152 vector<uint8_t> plainQuery;
153 DNSPacketWriter pw(plainQuery, name, QType::AAAA, QClass::IN, 0);
154 pw.getHeader()->rd = 1;
155 size_t requiredSize = plainQuery.size() + sizeof(DNSCryptQueryHeader) + DNSCRYPT_MAC_SIZE;
156 if (requiredSize < DNSCryptQuery::s_minUDPLength) {
157 requiredSize = DNSCryptQuery::s_minUDPLength;
158 }
159
160 plainQuery.reserve(requiredSize);
161 uint16_t len = plainQuery.size();
162 uint16_t encryptedResponseLen = 0;
163
164 int res = ctx->encryptQuery((char*) plainQuery.data(), len, plainQuery.capacity(), clientPublicKey, clientPrivateKey, clientNonce, false, &encryptedResponseLen, std::make_shared<DNSCryptCert>(resolverCert));
165
166 BOOST_CHECK_EQUAL(res, 0);
167 BOOST_CHECK(encryptedResponseLen > len);
168
169 std::shared_ptr<DNSCryptQuery> query = std::make_shared<DNSCryptQuery>(ctx);
170 uint16_t decryptedLen = 0;
171
172 query->parsePacket((char*) plainQuery.data(), encryptedResponseLen, false, &decryptedLen, now);
173
174 BOOST_CHECK_EQUAL(query->isValid(), true);
175 BOOST_CHECK_EQUAL(query->isEncrypted(), true);
176
177 MOADNSParser mdp(true, (char*) plainQuery.data(), decryptedLen);
178
179 BOOST_CHECK_EQUAL(mdp.d_header.qdcount, 1);
180 BOOST_CHECK_EQUAL(mdp.d_header.ancount, 0);
181 BOOST_CHECK_EQUAL(mdp.d_header.nscount, 0);
182 BOOST_CHECK_EQUAL(mdp.d_header.arcount, 0);
183
184 BOOST_CHECK_EQUAL(mdp.d_qname, name);
185 BOOST_CHECK(mdp.d_qclass == QClass::IN);
186 BOOST_CHECK(mdp.d_qtype == QType::AAAA);
187 }
188
189 // valid encrypted query with not enough room
190 BOOST_AUTO_TEST_CASE(DNSCryptEncryptedQueryValidButShort) {
191 DNSCryptPrivateKey resolverPrivateKey;
192 DNSCryptCert resolverCert;
193 unsigned char providerPublicKey[DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE];
194 unsigned char providerPrivateKey[DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE];
195 time_t now = time(nullptr);
196 DNSCryptContext::generateProviderKeys(providerPublicKey, providerPrivateKey);
197 DNSCryptContext::generateCertificate(1, now, now + (24 * 60 * 3600), DNSCryptExchangeVersion::VERSION1, providerPrivateKey, resolverPrivateKey, resolverCert);
198 auto ctx = std::make_shared<DNSCryptContext>("2.name", resolverCert, resolverPrivateKey);
199
200 DNSCryptPrivateKey clientPrivateKey;
201 unsigned char clientPublicKey[DNSCRYPT_PUBLIC_KEY_SIZE];
202
203 DNSCryptContext::generateResolverKeyPair(clientPrivateKey, clientPublicKey);
204
205 unsigned char clientNonce[DNSCRYPT_NONCE_SIZE / 2] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, 0x09, 0x0A, 0x0B };
206
207 DNSName name("www.powerdns.com.");
208 vector<uint8_t> plainQuery;
209 DNSPacketWriter pw(plainQuery, name, QType::AAAA, QClass::IN, 0);
210 pw.getHeader()->rd = 1;
211
212 uint16_t len = plainQuery.size();
213 uint16_t encryptedResponseLen = 0;
214
215 int res = ctx->encryptQuery((char*) plainQuery.data(), len, plainQuery.capacity(), clientPublicKey, clientPrivateKey, clientNonce, false, &encryptedResponseLen, std::make_shared<DNSCryptCert>(resolverCert));
216
217 BOOST_CHECK_EQUAL(res, ENOBUFS);
218 }
219
220 // valid encrypted query with old key
221 BOOST_AUTO_TEST_CASE(DNSCryptEncryptedQueryValidWithOldKey) {
222 DNSCryptPrivateKey resolverPrivateKey;
223 DNSCryptCert resolverCert;
224 unsigned char providerPublicKey[DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE];
225 unsigned char providerPrivateKey[DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE];
226 time_t now = time(nullptr);
227 DNSCryptContext::generateProviderKeys(providerPublicKey, providerPrivateKey);
228 DNSCryptContext::generateCertificate(1, now, now + (24 * 60 * 3600), DNSCryptExchangeVersion::VERSION1, providerPrivateKey, resolverPrivateKey, resolverCert);
229 auto ctx = std::make_shared<DNSCryptContext>("2.name", resolverCert, resolverPrivateKey);
230
231 DNSCryptPrivateKey clientPrivateKey;
232 unsigned char clientPublicKey[DNSCRYPT_PUBLIC_KEY_SIZE];
233
234 DNSCryptContext::generateResolverKeyPair(clientPrivateKey, clientPublicKey);
235
236 unsigned char clientNonce[DNSCRYPT_NONCE_SIZE / 2] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, 0x09, 0x0A, 0x0B };
237
238 DNSName name("www.powerdns.com.");
239 vector<uint8_t> plainQuery;
240 DNSPacketWriter pw(plainQuery, name, QType::AAAA, QClass::IN, 0);
241 pw.getHeader()->rd = 1;
242
243 size_t requiredSize = plainQuery.size() + sizeof(DNSCryptQueryHeader) + DNSCRYPT_MAC_SIZE;
244 if (requiredSize < DNSCryptQuery::s_minUDPLength) {
245 requiredSize = DNSCryptQuery::s_minUDPLength;
246 }
247
248 plainQuery.reserve(requiredSize);
249
250 uint16_t len = plainQuery.size();
251 uint16_t encryptedResponseLen = 0;
252
253 int res = ctx->encryptQuery((char*) plainQuery.data(), len, plainQuery.capacity(), clientPublicKey, clientPrivateKey, clientNonce, false, &encryptedResponseLen, std::make_shared<DNSCryptCert>(resolverCert));
254
255 BOOST_CHECK_EQUAL(res, 0);
256 BOOST_CHECK(encryptedResponseLen > len);
257
258 DNSCryptCert newResolverCert;
259 DNSCryptContext::generateCertificate(2, now, now + (24 * 60 * 3600), DNSCryptExchangeVersion::VERSION1, providerPrivateKey, resolverPrivateKey, newResolverCert);
260 ctx->addNewCertificate(newResolverCert, resolverPrivateKey);
261 ctx->markInactive(resolverCert.getSerial());
262
263 std::shared_ptr<DNSCryptQuery> query = std::make_shared<DNSCryptQuery>(ctx);
264 uint16_t decryptedLen = 0;
265
266 query->parsePacket((char*) plainQuery.data(), encryptedResponseLen, false, &decryptedLen, now);
267
268 BOOST_CHECK_EQUAL(query->isValid(), true);
269 BOOST_CHECK_EQUAL(query->isEncrypted(), true);
270
271 MOADNSParser mdp(true, (char*) plainQuery.data(), decryptedLen);
272
273 BOOST_CHECK_EQUAL(mdp.d_header.qdcount, 1);
274 BOOST_CHECK_EQUAL(mdp.d_header.ancount, 0);
275 BOOST_CHECK_EQUAL(mdp.d_header.nscount, 0);
276 BOOST_CHECK_EQUAL(mdp.d_header.arcount, 0);
277
278 BOOST_CHECK_EQUAL(mdp.d_qname, name);
279 BOOST_CHECK(mdp.d_qclass == QClass::IN);
280 BOOST_CHECK(mdp.d_qtype == QType::AAAA);
281 }
282
283 // valid encrypted query with wrong key
284 BOOST_AUTO_TEST_CASE(DNSCryptEncryptedQueryInvalidWithWrongKey) {
285 DNSCryptPrivateKey resolverPrivateKey;
286 DNSCryptCert resolverCert;
287 unsigned char providerPublicKey[DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE];
288 unsigned char providerPrivateKey[DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE];
289 time_t now = time(nullptr);
290 DNSCryptContext::generateProviderKeys(providerPublicKey, providerPrivateKey);
291 DNSCryptContext::generateCertificate(1, now, now + (24 * 60 * 3600), DNSCryptExchangeVersion::VERSION1, providerPrivateKey, resolverPrivateKey, resolverCert);
292 auto ctx = std::make_shared<DNSCryptContext>("2.name", resolverCert, resolverPrivateKey);
293
294 DNSCryptPrivateKey clientPrivateKey;
295 unsigned char clientPublicKey[DNSCRYPT_PUBLIC_KEY_SIZE];
296
297 DNSCryptContext::generateResolverKeyPair(clientPrivateKey, clientPublicKey);
298
299 unsigned char clientNonce[DNSCRYPT_NONCE_SIZE / 2] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, 0x09, 0x0A, 0x0B };
300
301 DNSName name("www.powerdns.com.");
302 vector<uint8_t> plainQuery;
303 DNSPacketWriter pw(plainQuery, name, QType::AAAA, QClass::IN, 0);
304 pw.getHeader()->rd = 1;
305
306 size_t requiredSize = plainQuery.size() + sizeof(DNSCryptQueryHeader) + DNSCRYPT_MAC_SIZE;
307 if (requiredSize < DNSCryptQuery::s_minUDPLength) {
308 requiredSize = DNSCryptQuery::s_minUDPLength;
309 }
310
311 plainQuery.reserve(requiredSize);
312
313 uint16_t len = plainQuery.size();
314 uint16_t encryptedResponseLen = 0;
315
316 int res = ctx->encryptQuery((char*) plainQuery.data(), len, plainQuery.capacity(), clientPublicKey, clientPrivateKey, clientNonce, false, &encryptedResponseLen, std::make_shared<DNSCryptCert>(resolverCert));
317
318 BOOST_CHECK_EQUAL(res, 0);
319 BOOST_CHECK(encryptedResponseLen > len);
320
321 DNSCryptCert newResolverCert;
322 DNSCryptContext::generateCertificate(2, now, now + (24 * 60 * 3600), DNSCryptExchangeVersion::VERSION1, providerPrivateKey, resolverPrivateKey, newResolverCert);
323 ctx->addNewCertificate(newResolverCert, resolverPrivateKey);
324 ctx->markInactive(resolverCert.getSerial());
325 ctx->removeInactiveCertificate(resolverCert.getSerial());
326
327 /* we have removed the old certificate, we can't decrypt this query */
328
329 std::shared_ptr<DNSCryptQuery> query = std::make_shared<DNSCryptQuery>(ctx);
330 uint16_t decryptedLen = 0;
331
332 query->parsePacket((char*) plainQuery.data(), encryptedResponseLen, false, &decryptedLen, now);
333
334 BOOST_CHECK_EQUAL(query->isValid(), false);
335 }
336
337 #endif
338
339 BOOST_AUTO_TEST_SUITE_END();