blob: 9e83719deb6d5cd2b2167fcbc6af45313d4b0ccd [file] [log] [blame]
Simon Kelleyc8e8f5c2021-01-24 21:59:37 +00001/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
Simon Kelleyad9c6f02017-10-27 22:13:49 +01002
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
15*/
16
17#include "dnsmasq.h"
18
19#ifdef HAVE_DNSSEC
20
21#include <nettle/rsa.h>
Simon Kelley94b68782018-03-17 18:39:23 +000022#include <nettle/ecdsa.h>
23#include <nettle/ecc-curve.h>
24#include <nettle/eddsa.h>
Simon Kelleya7d19e92020-02-29 16:27:00 +000025#if NETTLE_VERSION_MAJOR == 3 && NETTLE_VERSION_MINOR >= 6
26# include <nettle/gostdsa.h>
27#endif
Petr Menšík2024f972020-11-25 17:18:55 +010028#endif
29
Simon Kelleya69b0172021-01-24 21:53:28 +000030#if defined(HAVE_DNSSEC) || defined(HAVE_CRYPTOHASH)
Simon Kelleyad9c6f02017-10-27 22:13:49 +010031#include <nettle/nettle-meta.h>
32#include <nettle/bignum.h>
33
Simon Kelleyad9c6f02017-10-27 22:13:49 +010034/* Implement a "hash-function" to the nettle API, which simply returns
35 the input data, concatenated into a single, statically maintained, buffer.
36
37 Used for the EdDSA sigs, which operate on the whole message, rather
38 than a digest. */
39
40struct null_hash_digest
41{
42 uint8_t *buff;
43 size_t len;
44};
45
46struct null_hash_ctx
47{
48 size_t len;
49};
50
51static size_t null_hash_buff_sz = 0;
52static uint8_t *null_hash_buff = NULL;
53#define BUFF_INCR 128
54
55static void null_hash_init(void *ctx)
56{
57 ((struct null_hash_ctx *)ctx)->len = 0;
58}
59
60static void null_hash_update(void *ctxv, size_t length, const uint8_t *src)
61{
62 struct null_hash_ctx *ctx = ctxv;
63 size_t new_len = ctx->len + length;
64
65 if (new_len > null_hash_buff_sz)
66 {
67 uint8_t *new;
68
69 if (!(new = whine_malloc(new_len + BUFF_INCR)))
70 return;
71
72 if (null_hash_buff)
73 {
74 if (ctx->len != 0)
75 memcpy(new, null_hash_buff, ctx->len);
76 free(null_hash_buff);
77 }
78
79 null_hash_buff_sz = new_len + BUFF_INCR;
80 null_hash_buff = new;
81 }
82
83 memcpy(null_hash_buff + ctx->len, src, length);
84 ctx->len += length;
85}
86
87
88static void null_hash_digest(void *ctx, size_t length, uint8_t *dst)
89{
90 (void)length;
91
92 ((struct null_hash_digest *)dst)->buff = null_hash_buff;
93 ((struct null_hash_digest *)dst)->len = ((struct null_hash_ctx *)ctx)->len;
94}
95
96static struct nettle_hash null_hash = {
97 "null_hash",
98 sizeof(struct null_hash_ctx),
99 sizeof(struct null_hash_digest),
100 0,
101 (nettle_hash_init_func *) null_hash_init,
102 (nettle_hash_update_func *) null_hash_update,
103 (nettle_hash_digest_func *) null_hash_digest
104};
105
106/* Find pointer to correct hash function in nettle library */
107const struct nettle_hash *hash_find(char *name)
108{
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100109 if (!name)
110 return NULL;
111
Simon Kelleyf3223fb2018-03-06 22:55:36 +0000112 /* We provide a "null" hash which returns the input data as digest. */
113 if (strcmp(null_hash.name, name) == 0)
114 return &null_hash;
115
116 /* libnettle >= 3.4 provides nettle_lookup_hash() which avoids nasty ABI
117 incompatibilities if sizeof(nettle_hashes) changes between library
Simon Kelley94b68782018-03-17 18:39:23 +0000118 versions. It also #defines nettle_hashes, so use that to tell
119 if we have the new facilities. */
Simon Kelleyf3223fb2018-03-06 22:55:36 +0000120
Simon Kelley94b68782018-03-17 18:39:23 +0000121#ifdef nettle_hashes
Simon Kelleyf3223fb2018-03-06 22:55:36 +0000122 return nettle_lookup_hash(name);
123#else
Simon Kelley8b965522018-03-10 20:44:17 +0000124 {
125 int i;
126
127 for (i = 0; nettle_hashes[i]; i++)
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100128 if (strcmp(nettle_hashes[i]->name, name) == 0)
129 return nettle_hashes[i];
Simon Kelley8b965522018-03-10 20:44:17 +0000130 }
131
132 return NULL;
Simon Kelleyf3223fb2018-03-06 22:55:36 +0000133#endif
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100134}
135
136/* expand ctx and digest memory allocations if necessary and init hash function */
137int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **digestp)
138{
139 static void *ctx = NULL;
140 static unsigned char *digest = NULL;
141 static unsigned int ctx_sz = 0;
142 static unsigned int digest_sz = 0;
143
144 void *new;
145
146 if (ctx_sz < hash->context_size)
147 {
148 if (!(new = whine_malloc(hash->context_size)))
149 return 0;
150 if (ctx)
151 free(ctx);
152 ctx = new;
153 ctx_sz = hash->context_size;
154 }
155
156 if (digest_sz < hash->digest_size)
157 {
158 if (!(new = whine_malloc(hash->digest_size)))
159 return 0;
160 if (digest)
161 free(digest);
162 digest = new;
163 digest_sz = hash->digest_size;
164 }
165
166 *ctxp = ctx;
167 *digestp = digest;
168
169 hash->init(ctx);
170
171 return 1;
172}
Petr Menšík2024f972020-11-25 17:18:55 +0100173
174#endif
175
176#ifdef HAVE_DNSSEC
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100177
178static int dnsmasq_rsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
179 unsigned char *digest, size_t digest_len, int algo)
180{
181 unsigned char *p;
182 size_t exp_len;
183
184 static struct rsa_public_key *key = NULL;
185 static mpz_t sig_mpz;
186
187 (void)digest_len;
188
189 if (key == NULL)
190 {
191 if (!(key = whine_malloc(sizeof(struct rsa_public_key))))
192 return 0;
193
194 nettle_rsa_public_key_init(key);
195 mpz_init(sig_mpz);
196 }
197
198 if ((key_len < 3) || !(p = blockdata_retrieve(key_data, key_len, NULL)))
199 return 0;
200
201 key_len--;
202 if ((exp_len = *p++) == 0)
203 {
204 GETSHORT(exp_len, p);
205 key_len -= 2;
206 }
207
208 if (exp_len >= key_len)
209 return 0;
210
211 key->size = key_len - exp_len;
212 mpz_import(key->e, exp_len, 1, 1, 0, 0, p);
213 mpz_import(key->n, key->size, 1, 1, 0, 0, p + exp_len);
214
215 mpz_import(sig_mpz, sig_len, 1, 1, 0, 0, sig);
216
217 switch (algo)
218 {
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100219 case 5: case 7:
220 return nettle_rsa_sha1_verify_digest(key, digest, sig_mpz);
221 case 8:
222 return nettle_rsa_sha256_verify_digest(key, digest, sig_mpz);
223 case 10:
224 return nettle_rsa_sha512_verify_digest(key, digest, sig_mpz);
225 }
226
227 return 0;
228}
229
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100230static int dnsmasq_ecdsa_verify(struct blockdata *key_data, unsigned int key_len,
231 unsigned char *sig, size_t sig_len,
232 unsigned char *digest, size_t digest_len, int algo)
233{
234 unsigned char *p;
235 unsigned int t;
236 struct ecc_point *key;
237
238 static struct ecc_point *key_256 = NULL, *key_384 = NULL;
239 static mpz_t x, y;
240 static struct dsa_signature *sig_struct;
Vladislav Grishenkoab73a742019-06-26 20:27:11 +0500241#if NETTLE_VERSION_MAJOR == 3 && NETTLE_VERSION_MINOR < 4
242#define nettle_get_secp_256r1() (&nettle_secp_256r1)
243#define nettle_get_secp_384r1() (&nettle_secp_384r1)
244#endif
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100245
246 if (!sig_struct)
247 {
248 if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))))
249 return 0;
250
251 nettle_dsa_signature_init(sig_struct);
252 mpz_init(x);
253 mpz_init(y);
254 }
255
256 switch (algo)
257 {
258 case 13:
259 if (!key_256)
260 {
261 if (!(key_256 = whine_malloc(sizeof(struct ecc_point))))
262 return 0;
263
Vladislav Grishenkoab73a742019-06-26 20:27:11 +0500264 nettle_ecc_point_init(key_256, nettle_get_secp_256r1());
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100265 }
266
267 key = key_256;
268 t = 32;
269 break;
270
271 case 14:
272 if (!key_384)
273 {
274 if (!(key_384 = whine_malloc(sizeof(struct ecc_point))))
275 return 0;
276
Vladislav Grishenkoab73a742019-06-26 20:27:11 +0500277 nettle_ecc_point_init(key_384, nettle_get_secp_384r1());
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100278 }
279
280 key = key_384;
281 t = 48;
282 break;
283
284 default:
285 return 0;
286 }
287
288 if (sig_len != 2*t || key_len != 2*t ||
289 !(p = blockdata_retrieve(key_data, key_len, NULL)))
290 return 0;
291
292 mpz_import(x, t , 1, 1, 0, 0, p);
293 mpz_import(y, t , 1, 1, 0, 0, p + t);
294
295 if (!ecc_point_set(key, x, y))
296 return 0;
297
298 mpz_import(sig_struct->r, t, 1, 1, 0, 0, sig);
299 mpz_import(sig_struct->s, t, 1, 1, 0, 0, sig + t);
300
301 return nettle_ecdsa_verify(key, digest_len, digest, sig_struct);
302}
303
Simon Kelleya7d19e92020-02-29 16:27:00 +0000304#if NETTLE_VERSION_MAJOR == 3 && NETTLE_VERSION_MINOR >= 6
305static int dnsmasq_gostdsa_verify(struct blockdata *key_data, unsigned int key_len,
306 unsigned char *sig, size_t sig_len,
307 unsigned char *digest, size_t digest_len, int algo)
308{
309 unsigned char *p;
310
311 static struct ecc_point *gost_key = NULL;
312 static mpz_t x, y;
313 static struct dsa_signature *sig_struct;
314
315 if (algo != 12 ||
316 sig_len != 64 || key_len != 64 ||
317 !(p = blockdata_retrieve(key_data, key_len, NULL)))
318 return 0;
319
320 if (!sig_struct)
321 {
322 if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))) ||
323 !(gost_key = whine_malloc(sizeof(struct ecc_point))))
324 return 0;
325
326 nettle_dsa_signature_init(sig_struct);
327 nettle_ecc_point_init(gost_key, nettle_get_gost_gc256b());
328 mpz_init(x);
329 mpz_init(y);
330 }
331
332 mpz_import(x, 32 , 1, 1, 0, 0, p);
333 mpz_import(y, 32 , 1, 1, 0, 0, p + 32);
334
335 if (!ecc_point_set(gost_key, x, y))
336 return 0;
337
338 mpz_import(sig_struct->r, 32, 1, 1, 0, 0, sig);
339 mpz_import(sig_struct->s, 32, 1, 1, 0, 0, sig + 32);
340
341 return nettle_gostdsa_verify(gost_key, digest_len, digest, sig_struct);
342}
343#endif
344
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100345static int dnsmasq_eddsa_verify(struct blockdata *key_data, unsigned int key_len,
346 unsigned char *sig, size_t sig_len,
347 unsigned char *digest, size_t digest_len, int algo)
348{
349 unsigned char *p;
350
Simon Kelleyec1cc452020-02-29 15:02:40 +0000351 if (digest_len != sizeof(struct null_hash_digest) ||
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100352 !(p = blockdata_retrieve(key_data, key_len, NULL)))
353 return 0;
354
355 /* The "digest" returned by the null_hash function is simply a struct null_hash_digest
356 which has a pointer to the actual data and a length, because the buffer
357 may need to be extended during "hashing". */
358
359 switch (algo)
360 {
361 case 15:
Simon Kelleyec1cc452020-02-29 15:02:40 +0000362 if (key_len != ED25519_KEY_SIZE ||
363 sig_len != ED25519_SIGNATURE_SIZE)
364 return 0;
365
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100366 return ed25519_sha512_verify(p,
367 ((struct null_hash_digest *)digest)->len,
368 ((struct null_hash_digest *)digest)->buff,
369 sig);
Simon Kelleyec1cc452020-02-29 15:02:40 +0000370
371#if NETTLE_VERSION_MAJOR == 3 && NETTLE_VERSION_MINOR >= 6
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100372 case 16:
Simon Kelleyec1cc452020-02-29 15:02:40 +0000373 if (key_len != ED448_KEY_SIZE ||
374 sig_len != ED448_SIGNATURE_SIZE)
375 return 0;
376
377 return ed448_shake256_verify(p,
378 ((struct null_hash_digest *)digest)->len,
379 ((struct null_hash_digest *)digest)->buff,
380 sig);
381#endif
382
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100383 }
384
385 return 0;
386}
387
Simon Kelleyb77efc12017-10-27 23:23:53 +0100388static int (*verify_func(int algo))(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100389 unsigned char *digest, size_t digest_len, int algo)
390{
391
Simon Kelleya7d19e92020-02-29 16:27:00 +0000392 /* Ensure at runtime that we have support for this digest */
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100393 if (!hash_find(algo_digest_name(algo)))
394 return NULL;
395
396 /* This switch defines which sig algorithms we support, can't introspect Nettle for that. */
397 switch (algo)
398 {
Simon Kelley425e2402020-02-26 18:28:32 +0000399 case 5: case 7: case 8: case 10:
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100400 return dnsmasq_rsa_verify;
Simon Kelleya7d19e92020-02-29 16:27:00 +0000401
402#if NETTLE_VERSION_MAJOR == 3 && NETTLE_VERSION_MINOR >= 6
403 case 12:
404 return dnsmasq_gostdsa_verify;
405#endif
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100406
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100407 case 13: case 14:
408 return dnsmasq_ecdsa_verify;
409
410 case 15: case 16:
411 return dnsmasq_eddsa_verify;
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100412 }
413
414 return NULL;
415}
416
417int verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
418 unsigned char *digest, size_t digest_len, int algo)
419{
420
421 int (*func)(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
422 unsigned char *digest, size_t digest_len, int algo);
423
424 func = verify_func(algo);
425
426 if (!func)
427 return 0;
428
429 return (*func)(key_data, key_len, sig, sig_len, digest, digest_len, algo);
430}
431
Simon Kelleyb77efc12017-10-27 23:23:53 +0100432/* Note the ds_digest_name(), algo_digest_name() and nsec3_digest_name()
433 define which algo numbers we support. If algo_digest_name() returns
Simon Kelley0954a972017-10-27 23:26:51 +0100434 non-NULL for an algorithm number, we assume that algorithm is
Simon Kelleyb77efc12017-10-27 23:23:53 +0100435 supported by verify(). */
436
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100437/* http://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */
438char *ds_digest_name(int digest)
439{
440 switch (digest)
441 {
442 case 1: return "sha1";
443 case 2: return "sha256";
444 case 3: return "gosthash94";
445 case 4: return "sha384";
446 default: return NULL;
447 }
448}
449
450/* http://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */
451char *algo_digest_name(int algo)
452{
453 switch (algo)
454 {
Simon Kelley0954a972017-10-27 23:26:51 +0100455 case 1: return NULL; /* RSA/MD5 - Must Not Implement. RFC 6944 para 2.3. */
Simon Kelleyb77efc12017-10-27 23:23:53 +0100456 case 2: return NULL; /* Diffie-Hellman */
Simon Kelley425e2402020-02-26 18:28:32 +0000457 case 3: return NULL; ; /* DSA/SHA1 - Must Not Implement. RFC 8624 section 3.1 */
Simon Kelleyb77efc12017-10-27 23:23:53 +0100458 case 5: return "sha1"; /* RSA/SHA1 */
Simon Kelley425e2402020-02-26 18:28:32 +0000459 case 6: return NULL; /* DSA-NSEC3-SHA1 - Must Not Implement. RFC 8624 section 3.1 */
Simon Kelleyb77efc12017-10-27 23:23:53 +0100460 case 7: return "sha1"; /* RSASHA1-NSEC3-SHA1 */
461 case 8: return "sha256"; /* RSA/SHA-256 */
462 case 10: return "sha512"; /* RSA/SHA-512 */
Simon Kelleya7d19e92020-02-29 16:27:00 +0000463 case 12: return "gosthash94"; /* ECC-GOST */
Simon Kelleyb77efc12017-10-27 23:23:53 +0100464 case 13: return "sha256"; /* ECDSAP256SHA256 */
465 case 14: return "sha384"; /* ECDSAP384SHA384 */
466 case 15: return "null_hash"; /* ED25519 */
Simon Kelleyec1cc452020-02-29 15:02:40 +0000467 case 16: return "null_hash"; /* ED448 */
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100468 default: return NULL;
469 }
470}
471
472/* http://www.iana.org/assignments/dnssec-nsec3-parameters/dnssec-nsec3-parameters.xhtml */
473char *nsec3_digest_name(int digest)
474{
475 switch (digest)
476 {
477 case 1: return "sha1";
478 default: return NULL;
479 }
480}
481
482#endif