Annotation of embedaddon/dnsmasq/src/crypto.c, revision 1.1
1.1 ! misho 1: /* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
! 2:
! 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/ecdsa.h>
! 23: #include <nettle/ecc-curve.h>
! 24: #include <nettle/eddsa.h>
! 25: #if NETTLE_VERSION_MAJOR == 3 && NETTLE_VERSION_MINOR >= 6
! 26: # include <nettle/gostdsa.h>
! 27: #endif
! 28: #endif
! 29:
! 30: #if defined(HAVE_DNSSEC) || defined(HAVE_CRYPTOHASH)
! 31: #include <nettle/nettle-meta.h>
! 32: #include <nettle/bignum.h>
! 33:
! 34: /* 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:
! 40: struct null_hash_digest
! 41: {
! 42: uint8_t *buff;
! 43: size_t len;
! 44: };
! 45:
! 46: struct null_hash_ctx
! 47: {
! 48: size_t len;
! 49: };
! 50:
! 51: static size_t null_hash_buff_sz = 0;
! 52: static uint8_t *null_hash_buff = NULL;
! 53: #define BUFF_INCR 128
! 54:
! 55: static void null_hash_init(void *ctx)
! 56: {
! 57: ((struct null_hash_ctx *)ctx)->len = 0;
! 58: }
! 59:
! 60: static 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:
! 88: static 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:
! 96: static 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 */
! 107: const struct nettle_hash *hash_find(char *name)
! 108: {
! 109: if (!name)
! 110: return NULL;
! 111:
! 112: /* 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
! 118: versions. It also #defines nettle_hashes, so use that to tell
! 119: if we have the new facilities. */
! 120:
! 121: #ifdef nettle_hashes
! 122: return nettle_lookup_hash(name);
! 123: #else
! 124: {
! 125: int i;
! 126:
! 127: for (i = 0; nettle_hashes[i]; i++)
! 128: if (strcmp(nettle_hashes[i]->name, name) == 0)
! 129: return nettle_hashes[i];
! 130: }
! 131:
! 132: return NULL;
! 133: #endif
! 134: }
! 135:
! 136: /* expand ctx and digest memory allocations if necessary and init hash function */
! 137: int 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: }
! 173:
! 174: #endif
! 175:
! 176: #ifdef HAVE_DNSSEC
! 177:
! 178: static 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: {
! 219: 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:
! 230: static 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;
! 241: #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
! 245:
! 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:
! 264: nettle_ecc_point_init(key_256, nettle_get_secp_256r1());
! 265: }
! 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:
! 277: nettle_ecc_point_init(key_384, nettle_get_secp_384r1());
! 278: }
! 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:
! 304: #if NETTLE_VERSION_MAJOR == 3 && NETTLE_VERSION_MINOR >= 6
! 305: static 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:
! 345: static 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:
! 351: if (digest_len != sizeof(struct null_hash_digest) ||
! 352: !(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:
! 362: if (key_len != ED25519_KEY_SIZE ||
! 363: sig_len != ED25519_SIGNATURE_SIZE)
! 364: return 0;
! 365:
! 366: return ed25519_sha512_verify(p,
! 367: ((struct null_hash_digest *)digest)->len,
! 368: ((struct null_hash_digest *)digest)->buff,
! 369: sig);
! 370:
! 371: #if NETTLE_VERSION_MAJOR == 3 && NETTLE_VERSION_MINOR >= 6
! 372: case 16:
! 373: 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:
! 383: }
! 384:
! 385: return 0;
! 386: }
! 387:
! 388: static int (*verify_func(int algo))(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
! 389: unsigned char *digest, size_t digest_len, int algo)
! 390: {
! 391:
! 392: /* Ensure at runtime that we have support for this digest */
! 393: 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: {
! 399: case 5: case 7: case 8: case 10:
! 400: return dnsmasq_rsa_verify;
! 401:
! 402: #if NETTLE_VERSION_MAJOR == 3 && NETTLE_VERSION_MINOR >= 6
! 403: case 12:
! 404: return dnsmasq_gostdsa_verify;
! 405: #endif
! 406:
! 407: case 13: case 14:
! 408: return dnsmasq_ecdsa_verify;
! 409:
! 410: case 15: case 16:
! 411: return dnsmasq_eddsa_verify;
! 412: }
! 413:
! 414: return NULL;
! 415: }
! 416:
! 417: int 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:
! 432: /* Note the ds_digest_name(), algo_digest_name() and nsec3_digest_name()
! 433: define which algo numbers we support. If algo_digest_name() returns
! 434: non-NULL for an algorithm number, we assume that algorithm is
! 435: supported by verify(). */
! 436:
! 437: /* http://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */
! 438: char *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 */
! 451: char *algo_digest_name(int algo)
! 452: {
! 453: switch (algo)
! 454: {
! 455: case 1: return NULL; /* RSA/MD5 - Must Not Implement. RFC 6944 para 2.3. */
! 456: case 2: return NULL; /* Diffie-Hellman */
! 457: case 3: return NULL; ; /* DSA/SHA1 - Must Not Implement. RFC 8624 section 3.1 */
! 458: case 5: return "sha1"; /* RSA/SHA1 */
! 459: case 6: return NULL; /* DSA-NSEC3-SHA1 - Must Not Implement. RFC 8624 section 3.1 */
! 460: case 7: return "sha1"; /* RSASHA1-NSEC3-SHA1 */
! 461: case 8: return "sha256"; /* RSA/SHA-256 */
! 462: case 10: return "sha512"; /* RSA/SHA-512 */
! 463: case 12: return "gosthash94"; /* ECC-GOST */
! 464: case 13: return "sha256"; /* ECDSAP256SHA256 */
! 465: case 14: return "sha384"; /* ECDSAP384SHA384 */
! 466: case 15: return "null_hash"; /* ED25519 */
! 467: case 16: return "null_hash"; /* ED448 */
! 468: default: return NULL;
! 469: }
! 470: }
! 471:
! 472: /* http://www.iana.org/assignments/dnssec-nsec3-parameters/dnssec-nsec3-parameters.xhtml */
! 473: char *nsec3_digest_name(int digest)
! 474: {
! 475: switch (digest)
! 476: {
! 477: case 1: return "sha1";
! 478: default: return NULL;
! 479: }
! 480: }
! 481:
! 482: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>