2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
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.
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.
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.
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.
22 #define BOOST_TEST_DYN_LINK
23 #define BOOST_TEST_NO_MAIN
25 #include <boost/test/unit_test.hpp>
27 #include "dnscrypt.hh"
29 #include "dnsparser.hh"
30 #include "dnswriter.hh"
37 BOOST_AUTO_TEST_SUITE(dnscrypt_cc
)
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
);
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();
58 std::shared_ptr
<DnsCryptQuery
> query
= std::make_shared
<DnsCryptQuery
>();
59 uint16_t decryptedLen
= 0;
61 ctx
.parsePacket((char*) plainQuery
.data(), len
, query
, false, &decryptedLen
);
63 BOOST_CHECK_EQUAL(query
->valid
, true);
64 BOOST_CHECK_EQUAL(query
->encrypted
, false);
66 std::vector
<uint8_t> response
;
68 ctx
.getCertificateResponse(query
, response
);
70 MOADNSParser
mdp(false, (char*) response
.data(), response
.size());
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);
77 BOOST_CHECK_EQUAL(mdp
.d_qname
.toString(), "2.name.");
78 BOOST_CHECK(mdp
.d_qclass
== QClass::IN
);
79 BOOST_CHECK(mdp
.d_qtype
== QType::TXT
);
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
);
93 DNSName
name("2.name.");
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();
100 std::shared_ptr
<DnsCryptQuery
> query
= std::make_shared
<DnsCryptQuery
>();
101 uint16_t decryptedLen
= 0;
103 ctx
.parsePacket((char*) plainQuery
.data(), len
, query
, false, &decryptedLen
);
105 BOOST_CHECK_EQUAL(query
->valid
, false);
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
);
119 DNSName
name("2.WRONG.name.");
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();
126 std::shared_ptr
<DnsCryptQuery
> query
= std::make_shared
<DnsCryptQuery
>();
127 uint16_t decryptedLen
= 0;
129 ctx
.parsePacket((char*) plainQuery
.data(), len
, query
, false, &decryptedLen
);
131 BOOST_CHECK_EQUAL(query
->valid
, false);
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
);
145 DnsCryptPrivateKey clientPrivateKey
;
146 unsigned char clientPublicKey
[DNSCRYPT_PUBLIC_KEY_SIZE
];
148 DnsCryptContext::generateResolverKeyPair(clientPrivateKey
, clientPublicKey
);
150 unsigned char clientNonce
[DNSCRYPT_NONCE_SIZE
/ 2] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, 0x09, 0x0A, 0x0B };
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
;
161 plainQuery
.reserve(requiredSize
);
162 uint16_t len
= plainQuery
.size();
163 uint16_t encryptedResponseLen
= 0;
165 int res
= ctx
.encryptQuery((char*) plainQuery
.data(), len
, plainQuery
.capacity(), clientPublicKey
, clientPrivateKey
, clientNonce
, false, &encryptedResponseLen
);
167 BOOST_CHECK_EQUAL(res
, 0);
168 BOOST_CHECK(encryptedResponseLen
> len
);
170 std::shared_ptr
<DnsCryptQuery
> query
= std::make_shared
<DnsCryptQuery
>();
171 uint16_t decryptedLen
= 0;
173 ctx
.parsePacket((char*) plainQuery
.data(), encryptedResponseLen
, query
, false, &decryptedLen
);
175 BOOST_CHECK_EQUAL(query
->valid
, true);
176 BOOST_CHECK_EQUAL(query
->encrypted
, true);
178 MOADNSParser
mdp(true, (char*) plainQuery
.data(), decryptedLen
);
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);
185 BOOST_CHECK_EQUAL(mdp
.d_qname
, name
);
186 BOOST_CHECK(mdp
.d_qclass
== QClass::IN
);
187 BOOST_CHECK(mdp
.d_qtype
== QType::AAAA
);
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
);
201 DnsCryptPrivateKey clientPrivateKey
;
202 unsigned char clientPublicKey
[DNSCRYPT_PUBLIC_KEY_SIZE
];
204 DnsCryptContext::generateResolverKeyPair(clientPrivateKey
, clientPublicKey
);
206 unsigned char clientNonce
[DNSCRYPT_NONCE_SIZE
/ 2] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, 0x09, 0x0A, 0x0B };
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;
213 uint16_t len
= plainQuery
.size();
214 uint16_t encryptedResponseLen
= 0;
216 int res
= ctx
.encryptQuery((char*) plainQuery
.data(), len
, plainQuery
.capacity(), clientPublicKey
, clientPrivateKey
, clientNonce
, false, &encryptedResponseLen
);
218 BOOST_CHECK_EQUAL(res
, ENOBUFS
);
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
);
232 DnsCryptPrivateKey clientPrivateKey
;
233 unsigned char clientPublicKey
[DNSCRYPT_PUBLIC_KEY_SIZE
];
235 DnsCryptContext::generateResolverKeyPair(clientPrivateKey
, clientPublicKey
);
237 unsigned char clientNonce
[DNSCRYPT_NONCE_SIZE
/ 2] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, 0x09, 0x0A, 0x0B };
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;
244 size_t requiredSize
= plainQuery
.size() + sizeof(DnsCryptQueryHeader
) + DNSCRYPT_MAC_SIZE
;
245 if (requiredSize
< DnsCryptQuery::minUDPLength
) {
246 requiredSize
= DnsCryptQuery::minUDPLength
;
249 plainQuery
.reserve(requiredSize
);
251 uint16_t len
= plainQuery
.size();
252 uint16_t encryptedResponseLen
= 0;
254 int res
= ctx
.encryptQuery((char*) plainQuery
.data(), len
, plainQuery
.capacity(), clientPublicKey
, clientPrivateKey
, clientNonce
, false, &encryptedResponseLen
);
256 BOOST_CHECK_EQUAL(res
, 0);
257 BOOST_CHECK(encryptedResponseLen
> len
);
259 DnsCryptContext::generateCertificate(1, now
, now
+ (24 * 60 * 3600), providerPrivateKey
, resolverPrivateKey
, resolverCert
);
260 ctx
.setNewCertificate(resolverCert
, resolverPrivateKey
);
262 std::shared_ptr
<DnsCryptQuery
> query
= std::make_shared
<DnsCryptQuery
>();
263 uint16_t decryptedLen
= 0;
265 ctx
.parsePacket((char*) plainQuery
.data(), encryptedResponseLen
, query
, false, &decryptedLen
);
267 BOOST_CHECK_EQUAL(query
->valid
, true);
268 BOOST_CHECK_EQUAL(query
->encrypted
, true);
270 MOADNSParser
mdp(true, (char*) plainQuery
.data(), decryptedLen
);
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);
277 BOOST_CHECK_EQUAL(mdp
.d_qname
, name
);
278 BOOST_CHECK(mdp
.d_qclass
== QClass::IN
);
279 BOOST_CHECK(mdp
.d_qtype
== QType::AAAA
);
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
);
293 DnsCryptPrivateKey clientPrivateKey
;
294 unsigned char clientPublicKey
[DNSCRYPT_PUBLIC_KEY_SIZE
];
296 DnsCryptContext::generateResolverKeyPair(clientPrivateKey
, clientPublicKey
);
298 unsigned char clientNonce
[DNSCRYPT_NONCE_SIZE
/ 2] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, 0x09, 0x0A, 0x0B };
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;
305 size_t requiredSize
= plainQuery
.size() + sizeof(DnsCryptQueryHeader
) + DNSCRYPT_MAC_SIZE
;
306 if (requiredSize
< DnsCryptQuery::minUDPLength
) {
307 requiredSize
= DnsCryptQuery::minUDPLength
;
310 plainQuery
.reserve(requiredSize
);
312 uint16_t len
= plainQuery
.size();
313 uint16_t encryptedResponseLen
= 0;
315 int res
= ctx
.encryptQuery((char*) plainQuery
.data(), len
, plainQuery
.capacity(), clientPublicKey
, clientPrivateKey
, clientNonce
, false, &encryptedResponseLen
);
317 BOOST_CHECK_EQUAL(res
, 0);
318 BOOST_CHECK(encryptedResponseLen
> len
);
320 DnsCryptContext::generateCertificate(1, now
, now
+ (24 * 60 * 3600), providerPrivateKey
, resolverPrivateKey
, resolverCert
);
321 ctx
.setNewCertificate(resolverCert
, resolverPrivateKey
);
323 DnsCryptContext::generateCertificate(1, now
, now
+ (24 * 60 * 3600), providerPrivateKey
, resolverPrivateKey
, resolverCert
);
324 ctx
.setNewCertificate(resolverCert
, resolverPrivateKey
);
326 /* we have changed the key two times, we don't have the one used to encrypt this query */
328 std::shared_ptr
<DnsCryptQuery
> query
= std::make_shared
<DnsCryptQuery
>();
329 uint16_t decryptedLen
= 0;
331 ctx
.parsePacket((char*) plainQuery
.data(), encryptedResponseLen
, query
, false, &decryptedLen
);
333 BOOST_CHECK_EQUAL(query
->valid
, false);
338 BOOST_AUTO_TEST_SUITE_END();