blob: ebb871e67039798d7a25772258f820359a130616 [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;
278
279 if (!sig_struct)
280 {
281 if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))))
282 return 0;
283
284 nettle_dsa_signature_init(sig_struct);
285 mpz_init(x);
286 mpz_init(y);
287 }
288
289 switch (algo)
290 {
291 case 13:
292 if (!key_256)
293 {
294 if (!(key_256 = whine_malloc(sizeof(struct ecc_point))))
295 return 0;
296
297 nettle_ecc_point_init(key_256, &nettle_secp_256r1);
298 }
299
300 key = key_256;
301 t = 32;
302 break;
303
304 case 14:
305 if (!key_384)
306 {
307 if (!(key_384 = whine_malloc(sizeof(struct ecc_point))))
308 return 0;
309
310 nettle_ecc_point_init(key_384, &nettle_secp_384r1);
311 }
312
313 key = key_384;
314 t = 48;
315 break;
316
317 default:
318 return 0;
319 }
320
321 if (sig_len != 2*t || key_len != 2*t ||
322 !(p = blockdata_retrieve(key_data, key_len, NULL)))
323 return 0;
324
325 mpz_import(x, t , 1, 1, 0, 0, p);
326 mpz_import(y, t , 1, 1, 0, 0, p + t);
327
328 if (!ecc_point_set(key, x, y))
329 return 0;
330
331 mpz_import(sig_struct->r, t, 1, 1, 0, 0, sig);
332 mpz_import(sig_struct->s, t, 1, 1, 0, 0, sig + t);
333
334 return nettle_ecdsa_verify(key, digest_len, digest, sig_struct);
335}
336
337static int dnsmasq_eddsa_verify(struct blockdata *key_data, unsigned int key_len,
338 unsigned char *sig, size_t sig_len,
339 unsigned char *digest, size_t digest_len, int algo)
340{
341 unsigned char *p;
342
343 if (key_len != ED25519_KEY_SIZE ||
344 sig_len != ED25519_SIGNATURE_SIZE ||
345 digest_len != sizeof(struct null_hash_digest) ||
346 !(p = blockdata_retrieve(key_data, key_len, NULL)))
347 return 0;
348
349 /* The "digest" returned by the null_hash function is simply a struct null_hash_digest
350 which has a pointer to the actual data and a length, because the buffer
351 may need to be extended during "hashing". */
352
353 switch (algo)
354 {
355 case 15:
356 return ed25519_sha512_verify(p,
357 ((struct null_hash_digest *)digest)->len,
358 ((struct null_hash_digest *)digest)->buff,
359 sig);
360 case 16:
361 /* Ed448 when available */
362 return 0;
363 }
364
365 return 0;
366}
367
Simon Kelleyb77efc12017-10-27 23:23:53 +0100368static 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 +0100369 unsigned char *digest, size_t digest_len, int algo)
370{
371
372 /* Enure at runtime that we have support for this digest */
373 if (!hash_find(algo_digest_name(algo)))
374 return NULL;
375
376 /* This switch defines which sig algorithms we support, can't introspect Nettle for that. */
377 switch (algo)
378 {
379 case 1: case 5: case 7: case 8: case 10:
380 return dnsmasq_rsa_verify;
381
382 case 3: case 6:
383 return dnsmasq_dsa_verify;
Simon Kelley94b68782018-03-17 18:39:23 +0000384
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100385 case 13: case 14:
386 return dnsmasq_ecdsa_verify;
387
388 case 15: case 16:
389 return dnsmasq_eddsa_verify;
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100390 }
391
392 return NULL;
393}
394
395int verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
396 unsigned char *digest, size_t digest_len, int algo)
397{
398
399 int (*func)(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 func = verify_func(algo);
403
404 if (!func)
405 return 0;
406
407 return (*func)(key_data, key_len, sig, sig_len, digest, digest_len, algo);
408}
409
Simon Kelleyb77efc12017-10-27 23:23:53 +0100410/* Note the ds_digest_name(), algo_digest_name() and nsec3_digest_name()
411 define which algo numbers we support. If algo_digest_name() returns
Simon Kelley0954a972017-10-27 23:26:51 +0100412 non-NULL for an algorithm number, we assume that algorithm is
Simon Kelleyb77efc12017-10-27 23:23:53 +0100413 supported by verify(). */
414
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100415/* http://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */
416char *ds_digest_name(int digest)
417{
418 switch (digest)
419 {
420 case 1: return "sha1";
421 case 2: return "sha256";
422 case 3: return "gosthash94";
423 case 4: return "sha384";
424 default: return NULL;
425 }
426}
427
428/* http://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */
429char *algo_digest_name(int algo)
430{
431 switch (algo)
432 {
Simon Kelley0954a972017-10-27 23:26:51 +0100433 case 1: return NULL; /* RSA/MD5 - Must Not Implement. RFC 6944 para 2.3. */
Simon Kelleyb77efc12017-10-27 23:23:53 +0100434 case 2: return NULL; /* Diffie-Hellman */
435 case 3: return "sha1"; /* DSA/SHA1 */
436 case 5: return "sha1"; /* RSA/SHA1 */
437 case 6: return "sha1"; /* DSA-NSEC3-SHA1 */
438 case 7: return "sha1"; /* RSASHA1-NSEC3-SHA1 */
439 case 8: return "sha256"; /* RSA/SHA-256 */
440 case 10: return "sha512"; /* RSA/SHA-512 */
441 case 12: return NULL; /* ECC-GOST */
442 case 13: return "sha256"; /* ECDSAP256SHA256 */
443 case 14: return "sha384"; /* ECDSAP384SHA384 */
444 case 15: return "null_hash"; /* ED25519 */
445 case 16: return NULL; /* ED448 */
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100446 default: return NULL;
447 }
448}
449
450/* http://www.iana.org/assignments/dnssec-nsec3-parameters/dnssec-nsec3-parameters.xhtml */
451char *nsec3_digest_name(int digest)
452{
453 switch (digest)
454 {
455 case 1: return "sha1";
456 default: return NULL;
457 }
458}
459
460#endif