blob: fecc64a2cb3698933e457b1f54f69ebc39f32deb [file] [log] [blame]
Simon Kelleyd1ced3a2018-01-01 22:18:03 +00001/* dnsmasq is Copyright (c) 2000-2018 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>
22#include <nettle/dsa.h>
Simon Kelley94b68782018-03-17 18:39:23 +000023#include <nettle/ecdsa.h>
24#include <nettle/ecc-curve.h>
25#include <nettle/eddsa.h>
Simon Kelleyad9c6f02017-10-27 22:13:49 +010026#include <nettle/nettle-meta.h>
27#include <nettle/bignum.h>
28
Simon Kelleyad9c6f02017-10-27 22:13:49 +010029/* Implement a "hash-function" to the nettle API, which simply returns
30 the input data, concatenated into a single, statically maintained, buffer.
31
32 Used for the EdDSA sigs, which operate on the whole message, rather
33 than a digest. */
34
35struct null_hash_digest
36{
37 uint8_t *buff;
38 size_t len;
39};
40
41struct null_hash_ctx
42{
43 size_t len;
44};
45
46static size_t null_hash_buff_sz = 0;
47static uint8_t *null_hash_buff = NULL;
48#define BUFF_INCR 128
49
50static void null_hash_init(void *ctx)
51{
52 ((struct null_hash_ctx *)ctx)->len = 0;
53}
54
55static void null_hash_update(void *ctxv, size_t length, const uint8_t *src)
56{
57 struct null_hash_ctx *ctx = ctxv;
58 size_t new_len = ctx->len + length;
59
60 if (new_len > null_hash_buff_sz)
61 {
62 uint8_t *new;
63
64 if (!(new = whine_malloc(new_len + BUFF_INCR)))
65 return;
66
67 if (null_hash_buff)
68 {
69 if (ctx->len != 0)
70 memcpy(new, null_hash_buff, ctx->len);
71 free(null_hash_buff);
72 }
73
74 null_hash_buff_sz = new_len + BUFF_INCR;
75 null_hash_buff = new;
76 }
77
78 memcpy(null_hash_buff + ctx->len, src, length);
79 ctx->len += length;
80}
81
82
83static void null_hash_digest(void *ctx, size_t length, uint8_t *dst)
84{
85 (void)length;
86
87 ((struct null_hash_digest *)dst)->buff = null_hash_buff;
88 ((struct null_hash_digest *)dst)->len = ((struct null_hash_ctx *)ctx)->len;
89}
90
91static struct nettle_hash null_hash = {
92 "null_hash",
93 sizeof(struct null_hash_ctx),
94 sizeof(struct null_hash_digest),
95 0,
96 (nettle_hash_init_func *) null_hash_init,
97 (nettle_hash_update_func *) null_hash_update,
98 (nettle_hash_digest_func *) null_hash_digest
99};
100
101/* Find pointer to correct hash function in nettle library */
102const struct nettle_hash *hash_find(char *name)
103{
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100104 if (!name)
105 return NULL;
106
Simon Kelleyf3223fb2018-03-06 22:55:36 +0000107 /* We provide a "null" hash which returns the input data as digest. */
108 if (strcmp(null_hash.name, name) == 0)
109 return &null_hash;
110
111 /* libnettle >= 3.4 provides nettle_lookup_hash() which avoids nasty ABI
112 incompatibilities if sizeof(nettle_hashes) changes between library
Simon Kelley94b68782018-03-17 18:39:23 +0000113 versions. It also #defines nettle_hashes, so use that to tell
114 if we have the new facilities. */
Simon Kelleyf3223fb2018-03-06 22:55:36 +0000115
Simon Kelley94b68782018-03-17 18:39:23 +0000116#ifdef nettle_hashes
Simon Kelleyf3223fb2018-03-06 22:55:36 +0000117 return nettle_lookup_hash(name);
118#else
Simon Kelley8b965522018-03-10 20:44:17 +0000119 {
120 int i;
121
122 for (i = 0; nettle_hashes[i]; i++)
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100123 if (strcmp(nettle_hashes[i]->name, name) == 0)
124 return nettle_hashes[i];
Simon Kelley8b965522018-03-10 20:44:17 +0000125 }
126
127 return NULL;
Simon Kelleyf3223fb2018-03-06 22:55:36 +0000128#endif
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100129}
130
131/* expand ctx and digest memory allocations if necessary and init hash function */
132int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **digestp)
133{
134 static void *ctx = NULL;
135 static unsigned char *digest = NULL;
136 static unsigned int ctx_sz = 0;
137 static unsigned int digest_sz = 0;
138
139 void *new;
140
141 if (ctx_sz < hash->context_size)
142 {
143 if (!(new = whine_malloc(hash->context_size)))
144 return 0;
145 if (ctx)
146 free(ctx);
147 ctx = new;
148 ctx_sz = hash->context_size;
149 }
150
151 if (digest_sz < hash->digest_size)
152 {
153 if (!(new = whine_malloc(hash->digest_size)))
154 return 0;
155 if (digest)
156 free(digest);
157 digest = new;
158 digest_sz = hash->digest_size;
159 }
160
161 *ctxp = ctx;
162 *digestp = digest;
163
164 hash->init(ctx);
165
166 return 1;
167}
168
169static int dnsmasq_rsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
170 unsigned char *digest, size_t digest_len, int algo)
171{
172 unsigned char *p;
173 size_t exp_len;
174
175 static struct rsa_public_key *key = NULL;
176 static mpz_t sig_mpz;
177
178 (void)digest_len;
179
180 if (key == NULL)
181 {
182 if (!(key = whine_malloc(sizeof(struct rsa_public_key))))
183 return 0;
184
185 nettle_rsa_public_key_init(key);
186 mpz_init(sig_mpz);
187 }
188
189 if ((key_len < 3) || !(p = blockdata_retrieve(key_data, key_len, NULL)))
190 return 0;
191
192 key_len--;
193 if ((exp_len = *p++) == 0)
194 {
195 GETSHORT(exp_len, p);
196 key_len -= 2;
197 }
198
199 if (exp_len >= key_len)
200 return 0;
201
202 key->size = key_len - exp_len;
203 mpz_import(key->e, exp_len, 1, 1, 0, 0, p);
204 mpz_import(key->n, key->size, 1, 1, 0, 0, p + exp_len);
205
206 mpz_import(sig_mpz, sig_len, 1, 1, 0, 0, sig);
207
208 switch (algo)
209 {
210 case 1:
211 return nettle_rsa_md5_verify_digest(key, digest, sig_mpz);
212 case 5: case 7:
213 return nettle_rsa_sha1_verify_digest(key, digest, sig_mpz);
214 case 8:
215 return nettle_rsa_sha256_verify_digest(key, digest, sig_mpz);
216 case 10:
217 return nettle_rsa_sha512_verify_digest(key, digest, sig_mpz);
218 }
219
220 return 0;
221}
222
223static int dnsmasq_dsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
224 unsigned char *digest, size_t digest_len, int algo)
225{
226 unsigned char *p;
227 unsigned int t;
Simon Kelley94b68782018-03-17 18:39:23 +0000228
229 static mpz_t y;
230 static struct dsa_params *params = NULL;
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100231 static struct dsa_signature *sig_struct;
232
233 (void)digest_len;
234
Simon Kelley94b68782018-03-17 18:39:23 +0000235 if (params == NULL)
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100236 {
237 if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))) ||
Simon Kelley94b68782018-03-17 18:39:23 +0000238 !(params = whine_malloc(sizeof(struct dsa_params))))
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100239 return 0;
240
Simon Kelley94b68782018-03-17 18:39:23 +0000241 mpz_init(y);
242 nettle_dsa_params_init(params);
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100243 nettle_dsa_signature_init(sig_struct);
244 }
245
246 if ((sig_len < 41) || !(p = blockdata_retrieve(key_data, key_len, NULL)))
247 return 0;
248
249 t = *p++;
250
251 if (key_len < (213 + (t * 24)))
252 return 0;
253
Simon Kelley94b68782018-03-17 18:39:23 +0000254 mpz_import(params->q, 20, 1, 1, 0, 0, p); p += 20;
255 mpz_import(params->p, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
256 mpz_import(params->g, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
257 mpz_import(y, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100258
259 mpz_import(sig_struct->r, 20, 1, 1, 0, 0, sig+1);
260 mpz_import(sig_struct->s, 20, 1, 1, 0, 0, sig+21);
261
262 (void)algo;
263
Simon Kelley94b68782018-03-17 18:39:23 +0000264 return nettle_dsa_verify(params, y, digest_len, digest, sig_struct);
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100265}
266
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100267static int dnsmasq_ecdsa_verify(struct blockdata *key_data, unsigned int key_len,
268 unsigned char *sig, size_t sig_len,
269 unsigned char *digest, size_t digest_len, int algo)
270{
271 unsigned char *p;
272 unsigned int t;
273 struct ecc_point *key;
274
275 static struct ecc_point *key_256 = NULL, *key_384 = NULL;
276 static mpz_t x, y;
277 static struct dsa_signature *sig_struct;
Vladislav Grishenkoab73a742019-06-26 20:27:11 +0500278#if NETTLE_VERSION_MAJOR == 3 && NETTLE_VERSION_MINOR < 4
279#define nettle_get_secp_256r1() (&nettle_secp_256r1)
280#define nettle_get_secp_384r1() (&nettle_secp_384r1)
281#endif
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100282
283 if (!sig_struct)
284 {
285 if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))))
286 return 0;
287
288 nettle_dsa_signature_init(sig_struct);
289 mpz_init(x);
290 mpz_init(y);
291 }
292
293 switch (algo)
294 {
295 case 13:
296 if (!key_256)
297 {
298 if (!(key_256 = whine_malloc(sizeof(struct ecc_point))))
299 return 0;
300
Vladislav Grishenkoab73a742019-06-26 20:27:11 +0500301 nettle_ecc_point_init(key_256, nettle_get_secp_256r1());
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100302 }
303
304 key = key_256;
305 t = 32;
306 break;
307
308 case 14:
309 if (!key_384)
310 {
311 if (!(key_384 = whine_malloc(sizeof(struct ecc_point))))
312 return 0;
313
Vladislav Grishenkoab73a742019-06-26 20:27:11 +0500314 nettle_ecc_point_init(key_384, nettle_get_secp_384r1());
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100315 }
316
317 key = key_384;
318 t = 48;
319 break;
320
321 default:
322 return 0;
323 }
324
325 if (sig_len != 2*t || key_len != 2*t ||
326 !(p = blockdata_retrieve(key_data, key_len, NULL)))
327 return 0;
328
329 mpz_import(x, t , 1, 1, 0, 0, p);
330 mpz_import(y, t , 1, 1, 0, 0, p + t);
331
332 if (!ecc_point_set(key, x, y))
333 return 0;
334
335 mpz_import(sig_struct->r, t, 1, 1, 0, 0, sig);
336 mpz_import(sig_struct->s, t, 1, 1, 0, 0, sig + t);
337
338 return nettle_ecdsa_verify(key, digest_len, digest, sig_struct);
339}
340
341static int dnsmasq_eddsa_verify(struct blockdata *key_data, unsigned int key_len,
342 unsigned char *sig, size_t sig_len,
343 unsigned char *digest, size_t digest_len, int algo)
344{
345 unsigned char *p;
346
347 if (key_len != ED25519_KEY_SIZE ||
348 sig_len != ED25519_SIGNATURE_SIZE ||
349 digest_len != sizeof(struct null_hash_digest) ||
350 !(p = blockdata_retrieve(key_data, key_len, NULL)))
351 return 0;
352
353 /* The "digest" returned by the null_hash function is simply a struct null_hash_digest
354 which has a pointer to the actual data and a length, because the buffer
355 may need to be extended during "hashing". */
356
357 switch (algo)
358 {
359 case 15:
360 return ed25519_sha512_verify(p,
361 ((struct null_hash_digest *)digest)->len,
362 ((struct null_hash_digest *)digest)->buff,
363 sig);
364 case 16:
365 /* Ed448 when available */
366 return 0;
367 }
368
369 return 0;
370}
371
Simon Kelleyb77efc12017-10-27 23:23:53 +0100372static 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 +0100373 unsigned char *digest, size_t digest_len, int algo)
374{
375
376 /* Enure at runtime that we have support for this digest */
377 if (!hash_find(algo_digest_name(algo)))
378 return NULL;
379
380 /* This switch defines which sig algorithms we support, can't introspect Nettle for that. */
381 switch (algo)
382 {
383 case 1: case 5: case 7: case 8: case 10:
384 return dnsmasq_rsa_verify;
385
386 case 3: case 6:
387 return dnsmasq_dsa_verify;
Simon Kelley94b68782018-03-17 18:39:23 +0000388
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100389 case 13: case 14:
390 return dnsmasq_ecdsa_verify;
391
392 case 15: case 16:
393 return dnsmasq_eddsa_verify;
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100394 }
395
396 return NULL;
397}
398
399int verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
400 unsigned char *digest, size_t digest_len, int algo)
401{
402
403 int (*func)(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
404 unsigned char *digest, size_t digest_len, int algo);
405
406 func = verify_func(algo);
407
408 if (!func)
409 return 0;
410
411 return (*func)(key_data, key_len, sig, sig_len, digest, digest_len, algo);
412}
413
Simon Kelleyb77efc12017-10-27 23:23:53 +0100414/* Note the ds_digest_name(), algo_digest_name() and nsec3_digest_name()
415 define which algo numbers we support. If algo_digest_name() returns
Simon Kelley0954a972017-10-27 23:26:51 +0100416 non-NULL for an algorithm number, we assume that algorithm is
Simon Kelleyb77efc12017-10-27 23:23:53 +0100417 supported by verify(). */
418
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100419/* http://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */
420char *ds_digest_name(int digest)
421{
422 switch (digest)
423 {
424 case 1: return "sha1";
425 case 2: return "sha256";
426 case 3: return "gosthash94";
427 case 4: return "sha384";
428 default: return NULL;
429 }
430}
431
432/* http://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */
433char *algo_digest_name(int algo)
434{
435 switch (algo)
436 {
Simon Kelley0954a972017-10-27 23:26:51 +0100437 case 1: return NULL; /* RSA/MD5 - Must Not Implement. RFC 6944 para 2.3. */
Simon Kelleyb77efc12017-10-27 23:23:53 +0100438 case 2: return NULL; /* Diffie-Hellman */
439 case 3: return "sha1"; /* DSA/SHA1 */
440 case 5: return "sha1"; /* RSA/SHA1 */
441 case 6: return "sha1"; /* DSA-NSEC3-SHA1 */
442 case 7: return "sha1"; /* RSASHA1-NSEC3-SHA1 */
443 case 8: return "sha256"; /* RSA/SHA-256 */
444 case 10: return "sha512"; /* RSA/SHA-512 */
445 case 12: return NULL; /* ECC-GOST */
446 case 13: return "sha256"; /* ECDSAP256SHA256 */
447 case 14: return "sha384"; /* ECDSAP384SHA384 */
448 case 15: return "null_hash"; /* ED25519 */
449 case 16: return NULL; /* ED448 */
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100450 default: return NULL;
451 }
452}
453
454/* http://www.iana.org/assignments/dnssec-nsec3-parameters/dnssec-nsec3-parameters.xhtml */
455char *nsec3_digest_name(int digest)
456{
457 switch (digest)
458 {
459 case 1: return "sha1";
460 default: return NULL;
461 }
462}
463
464#endif