1 #include "dnscrypt.h"
2 
3 typedef struct Cached_ {
4     uint8_t pk[crypto_box_PUBLICKEYBYTES];
5     uint8_t server_pk[crypto_box_PUBLICKEYBYTES];
6     uint8_t shared[crypto_box_BEFORENMBYTES];
7 } Cached;
8 
9 static Cached cache[4096];
10 
11 static inline size_t
h12(const uint8_t pk[crypto_box_PUBLICKEYBYTES],const uint8_t server_pk[crypto_box_PUBLICKEYBYTES],bool use_xchacha20)12 h12(const uint8_t pk[crypto_box_PUBLICKEYBYTES],
13     const uint8_t server_pk[crypto_box_PUBLICKEYBYTES], bool use_xchacha20)
14 {
15     uint64_t a, b, c, d, e;
16     uint32_t h;
17 
18     memcpy(&a, &pk[0], 8);  memcpy(&b, &pk[8], 8);
19     memcpy(&c, &pk[16], 8); memcpy(&d, &pk[24], 8);
20     e = a ^ b ^ c ^ d;
21     memcpy(&a, &server_pk[0], 8);  memcpy(&b, &server_pk[8], 8);
22     memcpy(&c, &server_pk[16], 8); memcpy(&d, &server_pk[24], 8);
23     e ^= a ^ b ^ c ^ d;
24     h = ((uint32_t) e) ^ ((uint32_t) (e >> 32));
25     return (size_t) (((h >> 20) ^ (h >> 8) ^ (h << 4) ^ use_xchacha20) & 0xfff);
26 }
27 
28 static int
cache_get(Cached ** const cached_p,const uint8_t pk[crypto_box_PUBLICKEYBYTES],const uint8_t server_pk[crypto_box_PUBLICKEYBYTES],const bool use_xchacha20)29 cache_get(Cached ** const cached_p,
30           const uint8_t pk[crypto_box_PUBLICKEYBYTES],
31           const uint8_t server_pk[crypto_box_PUBLICKEYBYTES], const bool use_xchacha20)
32 {
33     Cached *cached = &cache[h12(pk, server_pk, use_xchacha20)];
34 
35     *cached_p = cached;
36     if (memcmp(cached->pk, pk, crypto_box_PUBLICKEYBYTES - 1) == 0 &&
37         (cached->pk[crypto_box_PUBLICKEYBYTES - 1] ^ use_xchacha20) == pk[crypto_box_PUBLICKEYBYTES - 1] &&
38         memcmp(cached->server_pk, server_pk, crypto_box_PUBLICKEYBYTES - 1) == 0) {
39         return 1;
40     }
41     return 0;
42 }
43 
44 static void
cache_set(const uint8_t shared[crypto_box_BEFORENMBYTES],const uint8_t pk[crypto_box_PUBLICKEYBYTES],const uint8_t server_pk[crypto_box_PUBLICKEYBYTES],const bool use_xchacha20)45 cache_set(const uint8_t shared[crypto_box_BEFORENMBYTES],
46           const uint8_t pk[crypto_box_PUBLICKEYBYTES],
47           const uint8_t server_pk[crypto_box_PUBLICKEYBYTES], const bool use_xchacha20)
48 {
49     Cached *cached;
50 
51     cache_get(&cached, pk, server_pk, use_xchacha20);
52     memcpy(cached->pk, pk, crypto_box_PUBLICKEYBYTES);
53     cached->pk[crypto_box_PUBLICKEYBYTES - 1] ^= use_xchacha20;
54     memcpy(cached->server_pk, server_pk, crypto_box_PUBLICKEYBYTES);
55     memcpy(cached->shared, shared, crypto_box_BEFORENMBYTES);
56 }
57 
58 const dnsccert *
find_cert(const struct context * c,const unsigned char magic_query[DNSCRYPT_MAGIC_HEADER_LEN],const size_t dns_query_len)59 find_cert(const struct context *c,
60           const unsigned char magic_query[DNSCRYPT_MAGIC_HEADER_LEN],
61           const size_t dns_query_len)
62 {
63     const dnsccert *certs = c->certs;
64     size_t i;
65 
66     if (dns_query_len <= DNSCRYPT_QUERY_HEADER_SIZE) {
67         return NULL;
68     }
69     for (i = 0U; i < c->certs_count; i++) {
70         if (memcmp(certs[i].magic_query, magic_query, DNSCRYPT_MAGIC_HEADER_LEN) == 0) {
71             return &certs[i];
72         }
73     }
74     if (memcmp(magic_query, CERT_OLD_MAGIC_HEADER, DNSCRYPT_MAGIC_HEADER_LEN) == 0) {
75         return &certs[0];
76     }
77     return NULL;
78 }
79 
80 int
dnscrypt_cmp_client_nonce(const uint8_t client_nonce[crypto_box_HALF_NONCEBYTES],const uint8_t * const buf,const size_t len)81 dnscrypt_cmp_client_nonce(const uint8_t
82                           client_nonce[crypto_box_HALF_NONCEBYTES],
83                           const uint8_t *const buf, const size_t len)
84 {
85     const size_t client_nonce_offset = sizeof(DNSCRYPT_MAGIC_RESPONSE) - 1;
86 
87     if (len < client_nonce_offset + crypto_box_HALF_NONCEBYTES
88         || memcmp(client_nonce, buf + client_nonce_offset,
89                   crypto_box_HALF_NONCEBYTES) != 0) {
90         return -1;
91     }
92 
93     return 0;
94 }
95 
96 uint64_t
dnscrypt_hrtime(void)97 dnscrypt_hrtime(void)
98 {
99     struct timeval tv;
100     uint64_t ts = (uint64_t)0U;
101     int ret;
102 
103     ret = evutil_gettimeofday(&tv, NULL);
104     assert(ret == 0);
105     if (ret == 0) {
106         ts = (uint64_t)tv.tv_sec * 1000000U + (uint64_t)tv.tv_usec;
107     }
108     return ts;
109 }
110 
111 void
dnscrypt_key_to_fingerprint(char fingerprint[80U],const uint8_t * const key)112 dnscrypt_key_to_fingerprint(char fingerprint[80U], const uint8_t *const key)
113 {
114     const size_t fingerprint_size = 80U;
115     size_t fingerprint_pos = (size_t) 0U;
116     size_t key_pos = (size_t) 0U;
117 
118     COMPILER_ASSERT(crypto_box_PUBLICKEYBYTES == 32U);
119     COMPILER_ASSERT(crypto_box_SECRETKEYBYTES == 32U);
120     for (;;) {
121         assert(fingerprint_size > fingerprint_pos);
122         evutil_snprintf(&fingerprint[fingerprint_pos],
123                         fingerprint_size - fingerprint_pos, "%02X%02X",
124                         key[key_pos], key[key_pos + 1U]);
125         key_pos += 2U;
126         if (key_pos >= crypto_box_PUBLICKEYBYTES) {
127             break;
128         }
129         fingerprint[fingerprint_pos + 4U] = ':';
130         fingerprint_pos += 5U;
131     }
132 }
133 
134 static int
_dnscrypt_parse_char(uint8_t key[crypto_box_PUBLICKEYBYTES],size_t * const key_pos_p,int * const state_p,const int c,uint8_t * const val_p)135 _dnscrypt_parse_char(uint8_t key[crypto_box_PUBLICKEYBYTES],
136                      size_t * const key_pos_p, int *const state_p,
137                      const int c, uint8_t *const val_p)
138 {
139     uint8_t c_val;
140 
141     switch (*state_p) {
142     case 0:
143     case 1:
144         if (isspace(c) || (c == ':' && *state_p == 0)) {
145             break;
146         }
147         if (c == '#') {
148             *state_p = 2;
149             break;
150         }
151         if (!isxdigit(c)) {
152             return -1;
153         }
154         c_val = (uint8_t)((c >= '0' && c <= '9') ? c - '0' : c - 'a' + 10);
155         assert(c_val < 16U);
156         if (*state_p == 0) {
157             *val_p = c_val * 16U;
158             *state_p = 1;
159         } else {
160             *val_p |= c_val;
161             key[(*key_pos_p)++] = *val_p;
162             if (*key_pos_p >= crypto_box_PUBLICKEYBYTES) {
163                 return 0;
164             }
165             *state_p = 0;
166         }
167         break;
168     case 2:
169         if (c == '\n') {
170             *state_p = 0;
171         }
172     }
173     return 1;
174 }
175 
176 int
dnscrypt_fingerprint_to_key(const char * const fingerprint,uint8_t key[crypto_box_PUBLICKEYBYTES])177 dnscrypt_fingerprint_to_key(const char *const fingerprint,
178                             uint8_t key[crypto_box_PUBLICKEYBYTES])
179 {
180     const char *p = fingerprint;
181     size_t key_pos = (size_t) 0U;
182     int c;
183     int ret;
184     int state = 0;
185     uint8_t val = 0U;
186 
187     if (fingerprint == NULL) {
188         return -1;
189     }
190     while ((c = tolower((int)(unsigned char)*p)) != 0) {
191         ret = _dnscrypt_parse_char(key, &key_pos, &state, c, &val);
192         if (ret <= 0) {
193             return ret;
194         }
195         p++;
196     }
197     return -1;
198 }
199 
200 /**
201  * Add random padding to a buffer, according to a client nonce.
202  * The length has to depend on the query in order to avoid reply attacks.
203  *
204  * @param buf a buffer
205  * @param len the initial size of the buffer
206  * @param max_len the maximum size
207  * @param nonce a nonce, made of the client nonce repeated twice
208  * @param secretkey
209  * @return the new size, after padding
210  */
211 size_t
dnscrypt_pad(uint8_t * buf,const size_t len,const size_t max_len,const uint8_t * nonce,const uint8_t * secretkey)212 dnscrypt_pad(uint8_t *buf, const size_t len, const size_t max_len,
213              const uint8_t *nonce, const uint8_t *secretkey)
214 {
215     uint8_t *buf_padding_area = buf + len;
216     size_t padded_len;
217     uint32_t rnd;
218 
219     // no padding
220     if (max_len < len + DNSCRYPT_MIN_PAD_LEN)
221         return len;
222 
223     assert(nonce[crypto_box_HALF_NONCEBYTES] == nonce[0]);
224 
225     crypto_stream((unsigned char *)&rnd, (unsigned long long)sizeof(rnd), nonce,
226                   secretkey);
227     padded_len =
228         len + DNSCRYPT_MIN_PAD_LEN + rnd % (max_len - len -
229                                             DNSCRYPT_MIN_PAD_LEN + 1);
230     padded_len += DNSCRYPT_BLOCK_SIZE - padded_len % DNSCRYPT_BLOCK_SIZE;
231     if (padded_len > max_len)
232         padded_len = max_len;
233 
234     memset(buf_padding_area, 0, padded_len - len);
235     *buf_padding_area = 0x80;
236 
237     return padded_len;
238 }
239 
240 //  8 bytes: magic_query
241 // 32 bytes: the client's DNSCurve public key (crypto_box_PUBLICKEYBYTES)
242 // 12 bytes: a client-selected nonce (crypto_box_HALF_NONCEBYTES)
243 // 16 bytes: Poly1305 MAC (crypto_box_MACBYTES)
244 
245 #define DNSCRYPT_QUERY_BOX_OFFSET \
246     (DNSCRYPT_MAGIC_HEADER_LEN + crypto_box_PUBLICKEYBYTES + crypto_box_HALF_NONCEBYTES)
247 
248 int
dnscrypt_server_uncurve(struct context * c,const dnsccert * cert,uint8_t client_nonce[crypto_box_HALF_NONCEBYTES],uint8_t nmkey[crypto_box_BEFORENMBYTES],uint8_t * const buf,size_t * const lenp)249 dnscrypt_server_uncurve(struct context *c, const dnsccert *cert,
250                         uint8_t client_nonce[crypto_box_HALF_NONCEBYTES],
251                         uint8_t nmkey[crypto_box_BEFORENMBYTES],
252                         uint8_t *const buf, size_t * const lenp)
253 {
254     size_t len = *lenp;
255 
256     if (len <= DNSCRYPT_QUERY_HEADER_SIZE) {
257         return -1;
258     }
259 
260     struct dnscrypt_query_header *query_header =
261         (struct dnscrypt_query_header *)buf;
262     Cached *cached;
263 
264     if (cache_get(&cached, query_header->publickey, cert->keypair->crypt_publickey, XCHACHA20_CERT(cert))) {
265         memcpy(nmkey, cached->shared, crypto_box_BEFORENMBYTES);
266     } else {
267         memcpy(nmkey, query_header->publickey, crypto_box_PUBLICKEYBYTES);
268         if (XCHACHA20_CERT(cert)) {
269 #ifdef HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_OPEN_EASY
270             if (crypto_box_curve25519xchacha20poly1305_beforenm(nmkey, nmkey,
271                     cert->keypair->crypt_secretkey) != 0) {
272                 return -1;
273             }
274 #endif
275         } else {
276             if (crypto_box_beforenm(nmkey, nmkey,
277                     cert->keypair->crypt_secretkey) != 0) {
278                 return -1;
279             }
280         }
281         cache_set(nmkey, query_header->publickey, cert->keypair->crypt_publickey, XCHACHA20_CERT(cert));
282     }
283 
284     uint8_t nonce[crypto_box_NONCEBYTES];
285     memcpy(nonce, query_header->nonce, crypto_box_HALF_NONCEBYTES);
286     memset(nonce + crypto_box_HALF_NONCEBYTES, 0, crypto_box_HALF_NONCEBYTES);
287 
288     if (XCHACHA20_CERT(cert)) {
289 #ifdef HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_OPEN_EASY
290         if (crypto_box_curve25519xchacha20poly1305_open_easy_afternm
291             (buf, buf + DNSCRYPT_QUERY_BOX_OFFSET,
292              len - DNSCRYPT_QUERY_BOX_OFFSET, nonce, nmkey) != 0) {
293             return -1;
294         }
295 #endif
296     } else {
297         if (crypto_box_open_easy_afternm
298             (buf, buf + DNSCRYPT_QUERY_BOX_OFFSET,
299              len - DNSCRYPT_QUERY_BOX_OFFSET, nonce, nmkey) != 0) {
300             return -1;
301         }
302     }
303 
304     len -= DNSCRYPT_QUERY_HEADER_SIZE;
305     while (len > 0 && buf[--len] == 0);
306     if (buf[len] != 0x80) {
307         return -1;
308     }
309 
310     memcpy(client_nonce, nonce, crypto_box_HALF_NONCEBYTES);
311     *lenp = len;
312 
313     return 0;
314 }
315 
316 void
add_server_nonce(struct context * c,uint8_t * nonce)317 add_server_nonce(struct context *c, uint8_t *nonce)
318 {
319     uint64_t ts;
320     uint64_t tsn;
321     uint32_t suffix;
322     ts = dnscrypt_hrtime();
323     if (ts <= c->nonce_ts_last) {
324         ts = c->nonce_ts_last + 1;
325     }
326     c->nonce_ts_last = ts;
327     tsn = (ts << 10) | (randombytes_random() & 0x3ff);
328 #if (BYTE_ORDER == LITTLE_ENDIAN)
329     tsn =
330         (((uint64_t)htonl((uint32_t)tsn)) << 32) | htonl((uint32_t)(tsn >> 32));
331 #endif
332     memcpy(nonce + crypto_box_HALF_NONCEBYTES, &tsn, 8);
333     suffix = randombytes_random();
334     memcpy(nonce + crypto_box_HALF_NONCEBYTES + 8, &suffix, 4);
335 }
336 
337 //  8 bytes: magic header (CERT_MAGIC_HEADER)
338 // 12 bytes: the client's nonce
339 // 12 bytes: server nonce extension
340 // 16 bytes: Poly1305 MAC (crypto_box_MACBYTES)
341 
342 #define DNSCRYPT_REPLY_BOX_OFFSET \
343     (DNSCRYPT_MAGIC_HEADER_LEN + crypto_box_HALF_NONCEBYTES + crypto_box_HALF_NONCEBYTES)
344 
345 int
dnscrypt_server_curve(struct context * c,const dnsccert * cert,uint8_t client_nonce[crypto_box_HALF_NONCEBYTES],uint8_t nmkey[crypto_box_BEFORENMBYTES],uint8_t * const buf,size_t * const lenp,const size_t max_len)346 dnscrypt_server_curve(struct context *c, const dnsccert *cert,
347                       uint8_t client_nonce[crypto_box_HALF_NONCEBYTES],
348                       uint8_t nmkey[crypto_box_BEFORENMBYTES],
349                       uint8_t *const buf, size_t * const lenp,
350                       const size_t max_len)
351 {
352     uint8_t nonce[crypto_box_NONCEBYTES];
353     uint8_t *boxed;
354     size_t len = *lenp;
355 
356     memcpy(nonce, client_nonce, crypto_box_HALF_NONCEBYTES);
357     memcpy(nonce + crypto_box_HALF_NONCEBYTES, client_nonce,
358            crypto_box_HALF_NONCEBYTES);
359 
360     boxed = buf + DNSCRYPT_REPLY_BOX_OFFSET;
361     memmove(boxed + crypto_box_MACBYTES, buf, len);
362     len =
363         dnscrypt_pad(boxed + crypto_box_MACBYTES, len,
364                      max_len - DNSCRYPT_REPLY_HEADER_SIZE, nonce,
365                      c->keypairs[0].crypt_secretkey);
366     // add server nonce extension
367     add_server_nonce(c, nonce);
368 
369     if (XCHACHA20_CERT(cert)) {
370 #ifdef HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_OPEN_EASY
371         if (crypto_box_curve25519xchacha20poly1305_easy_afternm
372             (boxed, boxed + crypto_box_MACBYTES, len, nonce, nmkey) != 0) {
373             return -1;
374         }
375 #endif
376     } else {
377         if (crypto_box_easy_afternm(boxed, boxed + crypto_box_MACBYTES,
378                                     len, nonce, nmkey) != 0) {
379             return -1;
380         }
381     }
382 
383     memcpy(buf, DNSCRYPT_MAGIC_RESPONSE, DNSCRYPT_MAGIC_HEADER_LEN);
384     memcpy(buf + DNSCRYPT_MAGIC_HEADER_LEN, nonce, crypto_box_NONCEBYTES);
385     *lenp = len + DNSCRYPT_REPLY_HEADER_SIZE;
386     return 0;
387 }
388 
389 /**
390  * Return 0 if served.
391  */
392 int
dnscrypt_self_serve_cert_file(struct context * c,struct dns_header * header,size_t * dns_query_len,size_t max_len)393 dnscrypt_self_serve_cert_file(struct context *c, struct dns_header *header,
394                               size_t *dns_query_len, size_t max_len)
395 {
396     unsigned char *p;
397     unsigned char *ansp;
398     int qtype;
399     unsigned int nameoffset;
400     p = (unsigned char *)(header + 1);
401     int anscount = 0;
402 
403     if (ntohs(header->qdcount) != 1) {
404         return -1;
405     }
406     /* determine end of questions section (we put answers there) */
407     if (!(ansp = skip_questions(header, *dns_query_len))) {
408         return -2;
409     }
410 
411     /* save pointer to name for copying into answers */
412     nameoffset = p - (unsigned char *)header;
413 
414     if (!extract_name(header, *dns_query_len, &p, c->namebuff, 1, 4)) {
415         return -3;
416     }
417     GETSHORT(qtype, p);
418     logger(LOG_DEBUG, "qtype: %d, c->provider_name: %s, c->namebuff: %s", qtype, c->provider_name, c->namebuff);
419     if (qtype == T_TXT && strcasecmp(c->provider_name, c->namebuff) == 0) {
420         // reply with signed certificate
421         const size_t size = 1 + sizeof(struct SignedCert);
422         static uint8_t **txt;
423 
424         // Allocate static buffers containing the certificates.
425         // This is only called once the first time a TXT request is made.
426         if(!txt) {
427             txt = calloc(c->signed_certs_count, sizeof(uint8_t *));
428             if (!txt) {
429                 return -4;
430             }
431             for (int i=0; i < c->signed_certs_count; i++) {
432                 *(txt + i) = malloc(size);
433                 if (!*(txt + i))
434                     return -5;
435                 **(txt + i) = sizeof(struct SignedCert);
436                 memcpy(*(txt + i) + 1, c->signed_certs + i, sizeof(struct SignedCert));
437             }
438         }
439 
440         for (int i=0; i < c->signed_certs_count; i++) {
441             if (add_resource_record
442                 (header, nameoffset, max_len, &ansp, 0, NULL, T_TXT, C_IN, "t", size,
443                     *(txt + i))) {
444                 anscount++;
445             } else {
446                 return -6;
447             }
448         }
449         /* done all questions, set up header and return length of result */
450         /* clear authoritative and truncated flags, set QR flag */
451         header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
452         /* set RA flag */
453         header->hb4 |= HB4_RA;
454 
455         SET_RCODE(header, NOERROR);
456         header->ancount = htons(anscount);
457         header->nscount = htons(0);
458         header->arcount = htons(0);
459         *dns_query_len = ansp - (unsigned char *)header;
460 
461         return 0;
462     }
463 
464     return -7;
465 }
466 
467