blob: eaf9ea9874af1734997a0ad47baf109ab7e3252d [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 Kelley94b68782018-03-17 18:39:23 +0000127 versions. It also #defines nettle_hashes, so use that to tell
128 if we have the new facilities. */
Simon Kelleyf3223fb2018-03-06 22:55:36 +0000129
Simon Kelley94b68782018-03-17 18:39:23 +0000130#ifdef nettle_hashes
Simon Kelleyf3223fb2018-03-06 22:55:36 +0000131 return nettle_lookup_hash(name);
132#else
Simon Kelley8b965522018-03-10 20:44:17 +0000133 {
134 int i;
135
136 for (i = 0; nettle_hashes[i]; i++)
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100137 if (strcmp(nettle_hashes[i]->name, name) == 0)
138 return nettle_hashes[i];
Simon Kelley8b965522018-03-10 20:44:17 +0000139 }
140
141 return NULL;
Simon Kelleyf3223fb2018-03-06 22:55:36 +0000142#endif
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100143}
144
145/* expand ctx and digest memory allocations if necessary and init hash function */
146int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **digestp)
147{
148 static void *ctx = NULL;
149 static unsigned char *digest = NULL;
150 static unsigned int ctx_sz = 0;
151 static unsigned int digest_sz = 0;
152
153 void *new;
154
155 if (ctx_sz < hash->context_size)
156 {
157 if (!(new = whine_malloc(hash->context_size)))
158 return 0;
159 if (ctx)
160 free(ctx);
161 ctx = new;
162 ctx_sz = hash->context_size;
163 }
164
165 if (digest_sz < hash->digest_size)
166 {
167 if (!(new = whine_malloc(hash->digest_size)))
168 return 0;
169 if (digest)
170 free(digest);
171 digest = new;
172 digest_sz = hash->digest_size;
173 }
174
175 *ctxp = ctx;
176 *digestp = digest;
177
178 hash->init(ctx);
179
180 return 1;
181}
Petr Menšík2024f972020-11-25 17:18:55 +0100182
183#endif
184
185#ifdef HAVE_DNSSEC
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100186
187static int dnsmasq_rsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
188 unsigned char *digest, size_t digest_len, int algo)
189{
190 unsigned char *p;
191 size_t exp_len;
192
193 static struct rsa_public_key *key = NULL;
194 static mpz_t sig_mpz;
195
196 (void)digest_len;
197
198 if (key == NULL)
199 {
200 if (!(key = whine_malloc(sizeof(struct rsa_public_key))))
201 return 0;
202
203 nettle_rsa_public_key_init(key);
204 mpz_init(sig_mpz);
205 }
206
207 if ((key_len < 3) || !(p = blockdata_retrieve(key_data, key_len, NULL)))
208 return 0;
209
210 key_len--;
211 if ((exp_len = *p++) == 0)
212 {
213 GETSHORT(exp_len, p);
214 key_len -= 2;
215 }
216
217 if (exp_len >= key_len)
218 return 0;
219
220 key->size = key_len - exp_len;
221 mpz_import(key->e, exp_len, 1, 1, 0, 0, p);
222 mpz_import(key->n, key->size, 1, 1, 0, 0, p + exp_len);
223
224 mpz_import(sig_mpz, sig_len, 1, 1, 0, 0, sig);
225
226 switch (algo)
227 {
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100228 case 5: case 7:
229 return nettle_rsa_sha1_verify_digest(key, digest, sig_mpz);
230 case 8:
231 return nettle_rsa_sha256_verify_digest(key, digest, sig_mpz);
232 case 10:
233 return nettle_rsa_sha512_verify_digest(key, digest, sig_mpz);
234 }
235
236 return 0;
237}
238
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100239static int dnsmasq_ecdsa_verify(struct blockdata *key_data, unsigned int key_len,
240 unsigned char *sig, size_t sig_len,
241 unsigned char *digest, size_t digest_len, int algo)
242{
243 unsigned char *p;
244 unsigned int t;
245 struct ecc_point *key;
246
247 static struct ecc_point *key_256 = NULL, *key_384 = NULL;
248 static mpz_t x, y;
249 static struct dsa_signature *sig_struct;
Petr Menšík0b3ecf72021-03-27 23:26:48 +0000250#if !MIN_VERSION(3, 4)
Vladislav Grishenkoab73a742019-06-26 20:27:11 +0500251#define nettle_get_secp_256r1() (&nettle_secp_256r1)
252#define nettle_get_secp_384r1() (&nettle_secp_384r1)
253#endif
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100254
255 if (!sig_struct)
256 {
257 if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))))
258 return 0;
259
260 nettle_dsa_signature_init(sig_struct);
261 mpz_init(x);
262 mpz_init(y);
263 }
264
265 switch (algo)
266 {
267 case 13:
268 if (!key_256)
269 {
270 if (!(key_256 = whine_malloc(sizeof(struct ecc_point))))
271 return 0;
272
Vladislav Grishenkoab73a742019-06-26 20:27:11 +0500273 nettle_ecc_point_init(key_256, nettle_get_secp_256r1());
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100274 }
275
276 key = key_256;
277 t = 32;
278 break;
279
280 case 14:
281 if (!key_384)
282 {
283 if (!(key_384 = whine_malloc(sizeof(struct ecc_point))))
284 return 0;
285
Vladislav Grishenkoab73a742019-06-26 20:27:11 +0500286 nettle_ecc_point_init(key_384, nettle_get_secp_384r1());
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100287 }
288
289 key = key_384;
290 t = 48;
291 break;
292
293 default:
294 return 0;
295 }
296
297 if (sig_len != 2*t || key_len != 2*t ||
298 !(p = blockdata_retrieve(key_data, key_len, NULL)))
299 return 0;
300
301 mpz_import(x, t , 1, 1, 0, 0, p);
302 mpz_import(y, t , 1, 1, 0, 0, p + t);
303
304 if (!ecc_point_set(key, x, y))
305 return 0;
306
307 mpz_import(sig_struct->r, t, 1, 1, 0, 0, sig);
308 mpz_import(sig_struct->s, t, 1, 1, 0, 0, sig + t);
309
310 return nettle_ecdsa_verify(key, digest_len, digest, sig_struct);
311}
312
Petr Menšík0b3ecf72021-03-27 23:26:48 +0000313#if MIN_VERSION(3, 6)
Simon Kelleya7d19e92020-02-29 16:27:00 +0000314static int dnsmasq_gostdsa_verify(struct blockdata *key_data, unsigned int key_len,
315 unsigned char *sig, size_t sig_len,
316 unsigned char *digest, size_t digest_len, int algo)
317{
318 unsigned char *p;
319
320 static struct ecc_point *gost_key = NULL;
321 static mpz_t x, y;
322 static struct dsa_signature *sig_struct;
323
324 if (algo != 12 ||
325 sig_len != 64 || key_len != 64 ||
326 !(p = blockdata_retrieve(key_data, key_len, NULL)))
327 return 0;
328
329 if (!sig_struct)
330 {
331 if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))) ||
332 !(gost_key = whine_malloc(sizeof(struct ecc_point))))
333 return 0;
334
335 nettle_dsa_signature_init(sig_struct);
336 nettle_ecc_point_init(gost_key, nettle_get_gost_gc256b());
337 mpz_init(x);
338 mpz_init(y);
339 }
340
341 mpz_import(x, 32 , 1, 1, 0, 0, p);
342 mpz_import(y, 32 , 1, 1, 0, 0, p + 32);
343
344 if (!ecc_point_set(gost_key, x, y))
345 return 0;
346
347 mpz_import(sig_struct->r, 32, 1, 1, 0, 0, sig);
348 mpz_import(sig_struct->s, 32, 1, 1, 0, 0, sig + 32);
349
350 return nettle_gostdsa_verify(gost_key, digest_len, digest, sig_struct);
351}
352#endif
353
Petr Menšík0b3ecf72021-03-27 23:26:48 +0000354#if MIN_VERSION(3, 1)
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100355static int dnsmasq_eddsa_verify(struct blockdata *key_data, unsigned int key_len,
356 unsigned char *sig, size_t sig_len,
357 unsigned char *digest, size_t digest_len, int algo)
358{
359 unsigned char *p;
360
Simon Kelleyec1cc452020-02-29 15:02:40 +0000361 if (digest_len != sizeof(struct null_hash_digest) ||
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100362 !(p = blockdata_retrieve(key_data, key_len, NULL)))
363 return 0;
364
365 /* The "digest" returned by the null_hash function is simply a struct null_hash_digest
366 which has a pointer to the actual data and a length, because the buffer
367 may need to be extended during "hashing". */
368
369 switch (algo)
370 {
371 case 15:
Simon Kelleyec1cc452020-02-29 15:02:40 +0000372 if (key_len != ED25519_KEY_SIZE ||
373 sig_len != ED25519_SIGNATURE_SIZE)
374 return 0;
375
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100376 return ed25519_sha512_verify(p,
377 ((struct null_hash_digest *)digest)->len,
378 ((struct null_hash_digest *)digest)->buff,
379 sig);
Simon Kelleyec1cc452020-02-29 15:02:40 +0000380
Petr Menšík0b3ecf72021-03-27 23:26:48 +0000381#if MIN_VERSION(3, 6)
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100382 case 16:
Simon Kelleyec1cc452020-02-29 15:02:40 +0000383 if (key_len != ED448_KEY_SIZE ||
384 sig_len != ED448_SIGNATURE_SIZE)
385 return 0;
386
387 return ed448_shake256_verify(p,
388 ((struct null_hash_digest *)digest)->len,
389 ((struct null_hash_digest *)digest)->buff,
390 sig);
391#endif
392
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100393 }
394
395 return 0;
396}
Petr Menšík0b3ecf72021-03-27 23:26:48 +0000397#endif
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100398
Simon Kelleyb77efc12017-10-27 23:23:53 +0100399static 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 +0100400 unsigned char *digest, size_t digest_len, int algo)
401{
402
Simon Kelleya7d19e92020-02-29 16:27:00 +0000403 /* Ensure at runtime that we have support for this digest */
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100404 if (!hash_find(algo_digest_name(algo)))
405 return NULL;
406
407 /* This switch defines which sig algorithms we support, can't introspect Nettle for that. */
408 switch (algo)
409 {
Simon Kelley425e2402020-02-26 18:28:32 +0000410 case 5: case 7: case 8: case 10:
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100411 return dnsmasq_rsa_verify;
Simon Kelleya7d19e92020-02-29 16:27:00 +0000412
Petr Menšík0b3ecf72021-03-27 23:26:48 +0000413#if MIN_VERSION(3, 6)
Simon Kelleya7d19e92020-02-29 16:27:00 +0000414 case 12:
415 return dnsmasq_gostdsa_verify;
416#endif
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100417
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100418 case 13: case 14:
419 return dnsmasq_ecdsa_verify;
Petr Menšík0b3ecf72021-03-27 23:26:48 +0000420#if MIN_VERSION(3, 1)
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100421 case 15: case 16:
422 return dnsmasq_eddsa_verify;
Petr Menšík0b3ecf72021-03-27 23:26:48 +0000423#endif
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100424 }
425
426 return NULL;
427}
428
429int verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
430 unsigned char *digest, size_t digest_len, int algo)
431{
432
433 int (*func)(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
434 unsigned char *digest, size_t digest_len, int algo);
435
436 func = verify_func(algo);
437
438 if (!func)
439 return 0;
440
441 return (*func)(key_data, key_len, sig, sig_len, digest, digest_len, algo);
442}
443
Simon Kelleyb77efc12017-10-27 23:23:53 +0100444/* Note the ds_digest_name(), algo_digest_name() and nsec3_digest_name()
445 define which algo numbers we support. If algo_digest_name() returns
Simon Kelley0954a972017-10-27 23:26:51 +0100446 non-NULL for an algorithm number, we assume that algorithm is
Simon Kelleyb77efc12017-10-27 23:23:53 +0100447 supported by verify(). */
448
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100449/* http://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */
450char *ds_digest_name(int digest)
451{
452 switch (digest)
453 {
454 case 1: return "sha1";
455 case 2: return "sha256";
456 case 3: return "gosthash94";
457 case 4: return "sha384";
458 default: return NULL;
459 }
460}
461
462/* http://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */
463char *algo_digest_name(int algo)
464{
465 switch (algo)
466 {
Simon Kelley0954a972017-10-27 23:26:51 +0100467 case 1: return NULL; /* RSA/MD5 - Must Not Implement. RFC 6944 para 2.3. */
Simon Kelleyb77efc12017-10-27 23:23:53 +0100468 case 2: return NULL; /* Diffie-Hellman */
Simon Kelley425e2402020-02-26 18:28:32 +0000469 case 3: return NULL; ; /* DSA/SHA1 - Must Not Implement. RFC 8624 section 3.1 */
Simon Kelleyb77efc12017-10-27 23:23:53 +0100470 case 5: return "sha1"; /* RSA/SHA1 */
Simon Kelley425e2402020-02-26 18:28:32 +0000471 case 6: return NULL; /* DSA-NSEC3-SHA1 - Must Not Implement. RFC 8624 section 3.1 */
Simon Kelleyb77efc12017-10-27 23:23:53 +0100472 case 7: return "sha1"; /* RSASHA1-NSEC3-SHA1 */
473 case 8: return "sha256"; /* RSA/SHA-256 */
474 case 10: return "sha512"; /* RSA/SHA-512 */
Simon Kelleya7d19e92020-02-29 16:27:00 +0000475 case 12: return "gosthash94"; /* ECC-GOST */
Simon Kelleyb77efc12017-10-27 23:23:53 +0100476 case 13: return "sha256"; /* ECDSAP256SHA256 */
477 case 14: return "sha384"; /* ECDSAP384SHA384 */
478 case 15: return "null_hash"; /* ED25519 */
Simon Kelleyec1cc452020-02-29 15:02:40 +0000479 case 16: return "null_hash"; /* ED448 */
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100480 default: return NULL;
481 }
482}
483
484/* http://www.iana.org/assignments/dnssec-nsec3-parameters/dnssec-nsec3-parameters.xhtml */
485char *nsec3_digest_name(int digest)
486{
487 switch (digest)
488 {
489 case 1: return "sha1";
490 default: return NULL;
491 }
492}
493
494#endif