blob: e366778ce4b91f5f093e0c706fc010afa9425089 [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
Petr Menšík0b3ecf72021-03-27 23:26:48 +000021/* Minimal version of nettle */
22#define MIN_VERSION(major, minor) (NETTLE_VERSION_MAJOR == (major) && NETTLE_VERSION_MINOR >= (minor)) || \
23 (NETTLE_VERSION_MAJOR > (major))
24
Simon Kelleyad9c6f02017-10-27 22:13:49 +010025#include <nettle/rsa.h>
Simon Kelley94b68782018-03-17 18:39:23 +000026#include <nettle/ecdsa.h>
27#include <nettle/ecc-curve.h>
Petr Menšík0b3ecf72021-03-27 23:26:48 +000028#if !defined(NETTLE_VERSION_MAJOR)
29#define NETTLE_VERSION_MAJOR 2
30#endif
31#if MIN_VERSION(3, 1)
Simon Kelley94b68782018-03-17 18:39:23 +000032#include <nettle/eddsa.h>
Petr Menšík0b3ecf72021-03-27 23:26:48 +000033#endif
34#if MIN_VERSION(3, 6)
Simon Kelleya7d19e92020-02-29 16:27:00 +000035# include <nettle/gostdsa.h>
36#endif
Petr Menšík2024f972020-11-25 17:18:55 +010037#endif
38
Simon Kelleya69b0172021-01-24 21:53:28 +000039#if defined(HAVE_DNSSEC) || defined(HAVE_CRYPTOHASH)
Simon Kelleyad9c6f02017-10-27 22:13:49 +010040#include <nettle/nettle-meta.h>
41#include <nettle/bignum.h>
42
Simon Kelleyad9c6f02017-10-27 22:13:49 +010043/* Implement a "hash-function" to the nettle API, which simply returns
44 the input data, concatenated into a single, statically maintained, buffer.
45
46 Used for the EdDSA sigs, which operate on the whole message, rather
47 than a digest. */
48
49struct null_hash_digest
50{
51 uint8_t *buff;
52 size_t len;
53};
54
55struct null_hash_ctx
56{
57 size_t len;
58};
59
60static size_t null_hash_buff_sz = 0;
61static uint8_t *null_hash_buff = NULL;
62#define BUFF_INCR 128
63
64static void null_hash_init(void *ctx)
65{
66 ((struct null_hash_ctx *)ctx)->len = 0;
67}
68
69static void null_hash_update(void *ctxv, size_t length, const uint8_t *src)
70{
71 struct null_hash_ctx *ctx = ctxv;
72 size_t new_len = ctx->len + length;
73
74 if (new_len > null_hash_buff_sz)
75 {
76 uint8_t *new;
77
78 if (!(new = whine_malloc(new_len + BUFF_INCR)))
79 return;
80
81 if (null_hash_buff)
82 {
83 if (ctx->len != 0)
84 memcpy(new, null_hash_buff, ctx->len);
85 free(null_hash_buff);
86 }
87
88 null_hash_buff_sz = new_len + BUFF_INCR;
89 null_hash_buff = new;
90 }
91
92 memcpy(null_hash_buff + ctx->len, src, length);
93 ctx->len += length;
94}
95
96
97static void null_hash_digest(void *ctx, size_t length, uint8_t *dst)
98{
99 (void)length;
100
101 ((struct null_hash_digest *)dst)->buff = null_hash_buff;
102 ((struct null_hash_digest *)dst)->len = ((struct null_hash_ctx *)ctx)->len;
103}
104
105static struct nettle_hash null_hash = {
106 "null_hash",
107 sizeof(struct null_hash_ctx),
108 sizeof(struct null_hash_digest),
109 0,
110 (nettle_hash_init_func *) null_hash_init,
111 (nettle_hash_update_func *) null_hash_update,
112 (nettle_hash_digest_func *) null_hash_digest
113};
114
115/* Find pointer to correct hash function in nettle library */
116const struct nettle_hash *hash_find(char *name)
117{
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100118 if (!name)
119 return NULL;
120
Simon Kelleyf3223fb2018-03-06 22:55:36 +0000121 /* We provide a "null" hash which returns the input data as digest. */
122 if (strcmp(null_hash.name, name) == 0)
123 return &null_hash;
124
125 /* libnettle >= 3.4 provides nettle_lookup_hash() which avoids nasty ABI
126 incompatibilities if sizeof(nettle_hashes) changes between library
Simon Kelley26b5c402021-03-27 23:29:36 +0000127 versions. */
128#if MIN_VERSION(3, 4)
Simon Kelleyf3223fb2018-03-06 22:55:36 +0000129 return nettle_lookup_hash(name);
130#else
Simon Kelley8b965522018-03-10 20:44:17 +0000131 {
132 int i;
133
134 for (i = 0; nettle_hashes[i]; i++)
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100135 if (strcmp(nettle_hashes[i]->name, name) == 0)
136 return nettle_hashes[i];
Simon Kelley8b965522018-03-10 20:44:17 +0000137 }
138
139 return NULL;
Simon Kelleyf3223fb2018-03-06 22:55:36 +0000140#endif
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100141}
142
143/* expand ctx and digest memory allocations if necessary and init hash function */
144int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **digestp)
145{
146 static void *ctx = NULL;
147 static unsigned char *digest = NULL;
148 static unsigned int ctx_sz = 0;
149 static unsigned int digest_sz = 0;
150
151 void *new;
152
153 if (ctx_sz < hash->context_size)
154 {
155 if (!(new = whine_malloc(hash->context_size)))
156 return 0;
157 if (ctx)
158 free(ctx);
159 ctx = new;
160 ctx_sz = hash->context_size;
161 }
162
163 if (digest_sz < hash->digest_size)
164 {
165 if (!(new = whine_malloc(hash->digest_size)))
166 return 0;
167 if (digest)
168 free(digest);
169 digest = new;
170 digest_sz = hash->digest_size;
171 }
172
173 *ctxp = ctx;
174 *digestp = digest;
175
176 hash->init(ctx);
177
178 return 1;
179}
Petr Menšík2024f972020-11-25 17:18:55 +0100180
Simon Kelley26b5c402021-03-27 23:29:36 +0000181#endif /* defined(HAVE_DNSSEC) || defined(HAVE_CRYPTOHASH) */
Petr Menšík2024f972020-11-25 17:18:55 +0100182
183#ifdef HAVE_DNSSEC
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100184
185static int dnsmasq_rsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
186 unsigned char *digest, size_t digest_len, int algo)
187{
188 unsigned char *p;
189 size_t exp_len;
190
191 static struct rsa_public_key *key = NULL;
192 static mpz_t sig_mpz;
193
194 (void)digest_len;
195
196 if (key == NULL)
197 {
198 if (!(key = whine_malloc(sizeof(struct rsa_public_key))))
199 return 0;
200
201 nettle_rsa_public_key_init(key);
202 mpz_init(sig_mpz);
203 }
204
205 if ((key_len < 3) || !(p = blockdata_retrieve(key_data, key_len, NULL)))
206 return 0;
207
208 key_len--;
209 if ((exp_len = *p++) == 0)
210 {
211 GETSHORT(exp_len, p);
212 key_len -= 2;
213 }
214
215 if (exp_len >= key_len)
216 return 0;
217
218 key->size = key_len - exp_len;
219 mpz_import(key->e, exp_len, 1, 1, 0, 0, p);
220 mpz_import(key->n, key->size, 1, 1, 0, 0, p + exp_len);
221
222 mpz_import(sig_mpz, sig_len, 1, 1, 0, 0, sig);
223
224 switch (algo)
225 {
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100226 case 5: case 7:
227 return nettle_rsa_sha1_verify_digest(key, digest, sig_mpz);
228 case 8:
229 return nettle_rsa_sha256_verify_digest(key, digest, sig_mpz);
230 case 10:
231 return nettle_rsa_sha512_verify_digest(key, digest, sig_mpz);
232 }
233
234 return 0;
235}
236
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100237static int dnsmasq_ecdsa_verify(struct blockdata *key_data, unsigned int key_len,
238 unsigned char *sig, size_t sig_len,
239 unsigned char *digest, size_t digest_len, int algo)
240{
241 unsigned char *p;
242 unsigned int t;
243 struct ecc_point *key;
244
245 static struct ecc_point *key_256 = NULL, *key_384 = NULL;
246 static mpz_t x, y;
247 static struct dsa_signature *sig_struct;
Petr Menšík0b3ecf72021-03-27 23:26:48 +0000248#if !MIN_VERSION(3, 4)
Vladislav Grishenkoab73a742019-06-26 20:27:11 +0500249#define nettle_get_secp_256r1() (&nettle_secp_256r1)
250#define nettle_get_secp_384r1() (&nettle_secp_384r1)
251#endif
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100252
253 if (!sig_struct)
254 {
255 if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))))
256 return 0;
257
258 nettle_dsa_signature_init(sig_struct);
259 mpz_init(x);
260 mpz_init(y);
261 }
262
263 switch (algo)
264 {
265 case 13:
266 if (!key_256)
267 {
268 if (!(key_256 = whine_malloc(sizeof(struct ecc_point))))
269 return 0;
270
Vladislav Grishenkoab73a742019-06-26 20:27:11 +0500271 nettle_ecc_point_init(key_256, nettle_get_secp_256r1());
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100272 }
273
274 key = key_256;
275 t = 32;
276 break;
277
278 case 14:
279 if (!key_384)
280 {
281 if (!(key_384 = whine_malloc(sizeof(struct ecc_point))))
282 return 0;
283
Vladislav Grishenkoab73a742019-06-26 20:27:11 +0500284 nettle_ecc_point_init(key_384, nettle_get_secp_384r1());
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100285 }
286
287 key = key_384;
288 t = 48;
289 break;
290
291 default:
292 return 0;
293 }
294
295 if (sig_len != 2*t || key_len != 2*t ||
296 !(p = blockdata_retrieve(key_data, key_len, NULL)))
297 return 0;
298
299 mpz_import(x, t , 1, 1, 0, 0, p);
300 mpz_import(y, t , 1, 1, 0, 0, p + t);
301
302 if (!ecc_point_set(key, x, y))
303 return 0;
304
305 mpz_import(sig_struct->r, t, 1, 1, 0, 0, sig);
306 mpz_import(sig_struct->s, t, 1, 1, 0, 0, sig + t);
307
308 return nettle_ecdsa_verify(key, digest_len, digest, sig_struct);
309}
310
Petr Menšík0b3ecf72021-03-27 23:26:48 +0000311#if MIN_VERSION(3, 6)
Simon Kelleya7d19e92020-02-29 16:27:00 +0000312static int dnsmasq_gostdsa_verify(struct blockdata *key_data, unsigned int key_len,
313 unsigned char *sig, size_t sig_len,
314 unsigned char *digest, size_t digest_len, int algo)
315{
316 unsigned char *p;
317
318 static struct ecc_point *gost_key = NULL;
319 static mpz_t x, y;
320 static struct dsa_signature *sig_struct;
321
322 if (algo != 12 ||
323 sig_len != 64 || key_len != 64 ||
324 !(p = blockdata_retrieve(key_data, key_len, NULL)))
325 return 0;
326
327 if (!sig_struct)
328 {
329 if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))) ||
330 !(gost_key = whine_malloc(sizeof(struct ecc_point))))
331 return 0;
332
333 nettle_dsa_signature_init(sig_struct);
334 nettle_ecc_point_init(gost_key, nettle_get_gost_gc256b());
335 mpz_init(x);
336 mpz_init(y);
337 }
338
339 mpz_import(x, 32 , 1, 1, 0, 0, p);
340 mpz_import(y, 32 , 1, 1, 0, 0, p + 32);
341
342 if (!ecc_point_set(gost_key, x, y))
343 return 0;
344
345 mpz_import(sig_struct->r, 32, 1, 1, 0, 0, sig);
346 mpz_import(sig_struct->s, 32, 1, 1, 0, 0, sig + 32);
347
348 return nettle_gostdsa_verify(gost_key, digest_len, digest, sig_struct);
349}
350#endif
351
Petr Menšík0b3ecf72021-03-27 23:26:48 +0000352#if MIN_VERSION(3, 1)
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100353static int dnsmasq_eddsa_verify(struct blockdata *key_data, unsigned int key_len,
354 unsigned char *sig, size_t sig_len,
355 unsigned char *digest, size_t digest_len, int algo)
356{
357 unsigned char *p;
358
Simon Kelleyec1cc452020-02-29 15:02:40 +0000359 if (digest_len != sizeof(struct null_hash_digest) ||
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100360 !(p = blockdata_retrieve(key_data, key_len, NULL)))
361 return 0;
362
363 /* The "digest" returned by the null_hash function is simply a struct null_hash_digest
364 which has a pointer to the actual data and a length, because the buffer
365 may need to be extended during "hashing". */
366
367 switch (algo)
368 {
369 case 15:
Simon Kelleyec1cc452020-02-29 15:02:40 +0000370 if (key_len != ED25519_KEY_SIZE ||
371 sig_len != ED25519_SIGNATURE_SIZE)
372 return 0;
373
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100374 return ed25519_sha512_verify(p,
375 ((struct null_hash_digest *)digest)->len,
376 ((struct null_hash_digest *)digest)->buff,
377 sig);
Simon Kelleyec1cc452020-02-29 15:02:40 +0000378
Petr Menšík0b3ecf72021-03-27 23:26:48 +0000379#if MIN_VERSION(3, 6)
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100380 case 16:
Simon Kelleyec1cc452020-02-29 15:02:40 +0000381 if (key_len != ED448_KEY_SIZE ||
382 sig_len != ED448_SIGNATURE_SIZE)
383 return 0;
384
385 return ed448_shake256_verify(p,
386 ((struct null_hash_digest *)digest)->len,
387 ((struct null_hash_digest *)digest)->buff,
388 sig);
389#endif
390
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100391 }
392
393 return 0;
394}
Petr Menšík0b3ecf72021-03-27 23:26:48 +0000395#endif
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100396
Simon Kelleyb77efc12017-10-27 23:23:53 +0100397static 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 +0100398 unsigned char *digest, size_t digest_len, int algo)
399{
400
Simon Kelleya7d19e92020-02-29 16:27:00 +0000401 /* Ensure at runtime that we have support for this digest */
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100402 if (!hash_find(algo_digest_name(algo)))
403 return NULL;
404
405 /* This switch defines which sig algorithms we support, can't introspect Nettle for that. */
406 switch (algo)
407 {
Simon Kelley425e2402020-02-26 18:28:32 +0000408 case 5: case 7: case 8: case 10:
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100409 return dnsmasq_rsa_verify;
Simon Kelleya7d19e92020-02-29 16:27:00 +0000410
Petr Menšík0b3ecf72021-03-27 23:26:48 +0000411#if MIN_VERSION(3, 6)
Simon Kelleya7d19e92020-02-29 16:27:00 +0000412 case 12:
413 return dnsmasq_gostdsa_verify;
414#endif
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100415
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100416 case 13: case 14:
417 return dnsmasq_ecdsa_verify;
Petr Menšík0b3ecf72021-03-27 23:26:48 +0000418#if MIN_VERSION(3, 1)
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100419 case 15: case 16:
420 return dnsmasq_eddsa_verify;
Petr Menšík0b3ecf72021-03-27 23:26:48 +0000421#endif
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100422 }
423
424 return NULL;
425}
426
427int verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
428 unsigned char *digest, size_t digest_len, int algo)
429{
430
431 int (*func)(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
432 unsigned char *digest, size_t digest_len, int algo);
433
434 func = verify_func(algo);
435
436 if (!func)
437 return 0;
438
439 return (*func)(key_data, key_len, sig, sig_len, digest, digest_len, algo);
440}
441
Simon Kelleyb77efc12017-10-27 23:23:53 +0100442/* Note the ds_digest_name(), algo_digest_name() and nsec3_digest_name()
443 define which algo numbers we support. If algo_digest_name() returns
Simon Kelley0954a972017-10-27 23:26:51 +0100444 non-NULL for an algorithm number, we assume that algorithm is
Simon Kelleyb77efc12017-10-27 23:23:53 +0100445 supported by verify(). */
446
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100447/* http://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */
448char *ds_digest_name(int digest)
449{
450 switch (digest)
451 {
452 case 1: return "sha1";
453 case 2: return "sha256";
454 case 3: return "gosthash94";
455 case 4: return "sha384";
456 default: return NULL;
457 }
458}
459
460/* http://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */
461char *algo_digest_name(int algo)
462{
463 switch (algo)
464 {
Simon Kelley0954a972017-10-27 23:26:51 +0100465 case 1: return NULL; /* RSA/MD5 - Must Not Implement. RFC 6944 para 2.3. */
Simon Kelleyb77efc12017-10-27 23:23:53 +0100466 case 2: return NULL; /* Diffie-Hellman */
Simon Kelley425e2402020-02-26 18:28:32 +0000467 case 3: return NULL; ; /* DSA/SHA1 - Must Not Implement. RFC 8624 section 3.1 */
Simon Kelleyb77efc12017-10-27 23:23:53 +0100468 case 5: return "sha1"; /* RSA/SHA1 */
Simon Kelley425e2402020-02-26 18:28:32 +0000469 case 6: return NULL; /* DSA-NSEC3-SHA1 - Must Not Implement. RFC 8624 section 3.1 */
Simon Kelleyb77efc12017-10-27 23:23:53 +0100470 case 7: return "sha1"; /* RSASHA1-NSEC3-SHA1 */
471 case 8: return "sha256"; /* RSA/SHA-256 */
472 case 10: return "sha512"; /* RSA/SHA-512 */
Simon Kelleya7d19e92020-02-29 16:27:00 +0000473 case 12: return "gosthash94"; /* ECC-GOST */
Simon Kelleyb77efc12017-10-27 23:23:53 +0100474 case 13: return "sha256"; /* ECDSAP256SHA256 */
475 case 14: return "sha384"; /* ECDSAP384SHA384 */
476 case 15: return "null_hash"; /* ED25519 */
Simon Kelleyec1cc452020-02-29 15:02:40 +0000477 case 16: return "null_hash"; /* ED448 */
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100478 default: return NULL;
479 }
480}
481
482/* http://www.iana.org/assignments/dnssec-nsec3-parameters/dnssec-nsec3-parameters.xhtml */
483char *nsec3_digest_name(int digest)
484{
485 switch (digest)
486 {
487 case 1: return "sha1";
488 default: return NULL;
489 }
490}
491
492#endif