mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 02:08:24 +00:00
Add support for Ed25519 DNSSEC signature algorithm.
This commit is contained in:
2
Makefile
2
Makefile
@@ -76,7 +76,7 @@ objs = cache.o rfc1035.o util.o option.o forward.o network.o \
|
||||
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
|
||||
dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \
|
||||
domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \
|
||||
poll.o rrfilter.o edns0.o arp.o
|
||||
poll.o rrfilter.o edns0.o arp.o crypto.o
|
||||
|
||||
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
|
||||
dns-protocol.h radv-protocol.h ip6addr.h
|
||||
|
||||
@@ -10,7 +10,7 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
|
||||
dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
|
||||
radv.c slaac.c auth.c ipset.c domain.c \
|
||||
dnssec.c dnssec-openssl.c blockdata.c tables.c \
|
||||
loop.c inotify.c poll.c rrfilter.c edns0.c arp.c
|
||||
loop.c inotify.c poll.c rrfilter.c edns0.c arp.c crypto.c
|
||||
|
||||
LOCAL_MODULE := dnsmasq
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ static void blockdata_expand(int n)
|
||||
{
|
||||
struct blockdata *new = whine_malloc(n * sizeof(struct blockdata));
|
||||
|
||||
if (n > 0 && new)
|
||||
if (new)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -100,6 +100,7 @@ struct blockdata *blockdata_alloc(char *data, size_t len)
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void blockdata_free(struct blockdata *blocks)
|
||||
{
|
||||
struct blockdata *tmp;
|
||||
|
||||
456
src/crypto.c
Normal file
456
src/crypto.c
Normal file
@@ -0,0 +1,456 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
|
||||
#include <nettle/rsa.h>
|
||||
#include <nettle/dsa.h>
|
||||
#ifndef NO_NETTLE_ECC
|
||||
# include <nettle/ecdsa.h>
|
||||
# include <nettle/ecc-curve.h>
|
||||
# include <nettle/eddsa.h>
|
||||
#endif
|
||||
#include <nettle/nettle-meta.h>
|
||||
#include <nettle/bignum.h>
|
||||
|
||||
/* Nettle-3.0 moved to a new API for DSA. We use a name that's defined in the new API
|
||||
to detect Nettle-3, and invoke the backwards compatibility mode. */
|
||||
#ifdef dsa_params_init
|
||||
#include <nettle/dsa-compat.h>
|
||||
#endif
|
||||
|
||||
/* Implement a "hash-function" to the nettle API, which simply returns
|
||||
the input data, concatenated into a single, statically maintained, buffer.
|
||||
|
||||
Used for the EdDSA sigs, which operate on the whole message, rather
|
||||
than a digest. */
|
||||
|
||||
struct null_hash_digest
|
||||
{
|
||||
uint8_t *buff;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
struct null_hash_ctx
|
||||
{
|
||||
size_t len;
|
||||
};
|
||||
|
||||
static size_t null_hash_buff_sz = 0;
|
||||
static uint8_t *null_hash_buff = NULL;
|
||||
#define BUFF_INCR 128
|
||||
|
||||
static void null_hash_init(void *ctx)
|
||||
{
|
||||
((struct null_hash_ctx *)ctx)->len = 0;
|
||||
}
|
||||
|
||||
static void null_hash_update(void *ctxv, size_t length, const uint8_t *src)
|
||||
{
|
||||
struct null_hash_ctx *ctx = ctxv;
|
||||
size_t new_len = ctx->len + length;
|
||||
|
||||
if (new_len > null_hash_buff_sz)
|
||||
{
|
||||
uint8_t *new;
|
||||
|
||||
if (!(new = whine_malloc(new_len + BUFF_INCR)))
|
||||
return;
|
||||
|
||||
if (null_hash_buff)
|
||||
{
|
||||
if (ctx->len != 0)
|
||||
memcpy(new, null_hash_buff, ctx->len);
|
||||
free(null_hash_buff);
|
||||
}
|
||||
|
||||
null_hash_buff_sz = new_len + BUFF_INCR;
|
||||
null_hash_buff = new;
|
||||
}
|
||||
|
||||
memcpy(null_hash_buff + ctx->len, src, length);
|
||||
ctx->len += length;
|
||||
}
|
||||
|
||||
|
||||
static void null_hash_digest(void *ctx, size_t length, uint8_t *dst)
|
||||
{
|
||||
(void)length;
|
||||
|
||||
((struct null_hash_digest *)dst)->buff = null_hash_buff;
|
||||
((struct null_hash_digest *)dst)->len = ((struct null_hash_ctx *)ctx)->len;
|
||||
}
|
||||
|
||||
static struct nettle_hash null_hash = {
|
||||
"null_hash",
|
||||
sizeof(struct null_hash_ctx),
|
||||
sizeof(struct null_hash_digest),
|
||||
0,
|
||||
(nettle_hash_init_func *) null_hash_init,
|
||||
(nettle_hash_update_func *) null_hash_update,
|
||||
(nettle_hash_digest_func *) null_hash_digest
|
||||
};
|
||||
|
||||
/* Find pointer to correct hash function in nettle library */
|
||||
const struct nettle_hash *hash_find(char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; nettle_hashes[i]; i++)
|
||||
{
|
||||
if (strcmp(nettle_hashes[i]->name, name) == 0)
|
||||
return nettle_hashes[i];
|
||||
}
|
||||
|
||||
/* We provide a "null" hash which returns the input data as digest. */
|
||||
if (strcmp(null_hash.name, name) == 0)
|
||||
return &null_hash;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* expand ctx and digest memory allocations if necessary and init hash function */
|
||||
int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **digestp)
|
||||
{
|
||||
static void *ctx = NULL;
|
||||
static unsigned char *digest = NULL;
|
||||
static unsigned int ctx_sz = 0;
|
||||
static unsigned int digest_sz = 0;
|
||||
|
||||
void *new;
|
||||
|
||||
if (ctx_sz < hash->context_size)
|
||||
{
|
||||
if (!(new = whine_malloc(hash->context_size)))
|
||||
return 0;
|
||||
if (ctx)
|
||||
free(ctx);
|
||||
ctx = new;
|
||||
ctx_sz = hash->context_size;
|
||||
}
|
||||
|
||||
if (digest_sz < hash->digest_size)
|
||||
{
|
||||
if (!(new = whine_malloc(hash->digest_size)))
|
||||
return 0;
|
||||
if (digest)
|
||||
free(digest);
|
||||
digest = new;
|
||||
digest_sz = hash->digest_size;
|
||||
}
|
||||
|
||||
*ctxp = ctx;
|
||||
*digestp = digest;
|
||||
|
||||
hash->init(ctx);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dnsmasq_rsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
unsigned char *p;
|
||||
size_t exp_len;
|
||||
|
||||
static struct rsa_public_key *key = NULL;
|
||||
static mpz_t sig_mpz;
|
||||
|
||||
(void)digest_len;
|
||||
|
||||
if (key == NULL)
|
||||
{
|
||||
if (!(key = whine_malloc(sizeof(struct rsa_public_key))))
|
||||
return 0;
|
||||
|
||||
nettle_rsa_public_key_init(key);
|
||||
mpz_init(sig_mpz);
|
||||
}
|
||||
|
||||
if ((key_len < 3) || !(p = blockdata_retrieve(key_data, key_len, NULL)))
|
||||
return 0;
|
||||
|
||||
key_len--;
|
||||
if ((exp_len = *p++) == 0)
|
||||
{
|
||||
GETSHORT(exp_len, p);
|
||||
key_len -= 2;
|
||||
}
|
||||
|
||||
if (exp_len >= key_len)
|
||||
return 0;
|
||||
|
||||
key->size = key_len - exp_len;
|
||||
mpz_import(key->e, exp_len, 1, 1, 0, 0, p);
|
||||
mpz_import(key->n, key->size, 1, 1, 0, 0, p + exp_len);
|
||||
|
||||
mpz_import(sig_mpz, sig_len, 1, 1, 0, 0, sig);
|
||||
|
||||
switch (algo)
|
||||
{
|
||||
case 1:
|
||||
return nettle_rsa_md5_verify_digest(key, digest, sig_mpz);
|
||||
case 5: case 7:
|
||||
return nettle_rsa_sha1_verify_digest(key, digest, sig_mpz);
|
||||
case 8:
|
||||
return nettle_rsa_sha256_verify_digest(key, digest, sig_mpz);
|
||||
case 10:
|
||||
return nettle_rsa_sha512_verify_digest(key, digest, sig_mpz);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dnsmasq_dsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
unsigned char *p;
|
||||
unsigned int t;
|
||||
|
||||
static struct dsa_public_key *key = NULL;
|
||||
static struct dsa_signature *sig_struct;
|
||||
|
||||
(void)digest_len;
|
||||
|
||||
if (key == NULL)
|
||||
{
|
||||
if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))) ||
|
||||
!(key = whine_malloc(sizeof(struct dsa_public_key))))
|
||||
return 0;
|
||||
|
||||
nettle_dsa_public_key_init(key);
|
||||
nettle_dsa_signature_init(sig_struct);
|
||||
}
|
||||
|
||||
if ((sig_len < 41) || !(p = blockdata_retrieve(key_data, key_len, NULL)))
|
||||
return 0;
|
||||
|
||||
t = *p++;
|
||||
|
||||
if (key_len < (213 + (t * 24)))
|
||||
return 0;
|
||||
|
||||
mpz_import(key->q, 20, 1, 1, 0, 0, p); p += 20;
|
||||
mpz_import(key->p, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
|
||||
mpz_import(key->g, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
|
||||
mpz_import(key->y, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
|
||||
|
||||
mpz_import(sig_struct->r, 20, 1, 1, 0, 0, sig+1);
|
||||
mpz_import(sig_struct->s, 20, 1, 1, 0, 0, sig+21);
|
||||
|
||||
(void)algo;
|
||||
|
||||
return nettle_dsa_sha1_verify_digest(key, digest, sig_struct);
|
||||
}
|
||||
|
||||
#ifndef NO_NETTLE_ECC
|
||||
static int dnsmasq_ecdsa_verify(struct blockdata *key_data, unsigned int key_len,
|
||||
unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
unsigned char *p;
|
||||
unsigned int t;
|
||||
struct ecc_point *key;
|
||||
|
||||
static struct ecc_point *key_256 = NULL, *key_384 = NULL;
|
||||
static mpz_t x, y;
|
||||
static struct dsa_signature *sig_struct;
|
||||
|
||||
if (!sig_struct)
|
||||
{
|
||||
if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))))
|
||||
return 0;
|
||||
|
||||
nettle_dsa_signature_init(sig_struct);
|
||||
mpz_init(x);
|
||||
mpz_init(y);
|
||||
}
|
||||
|
||||
switch (algo)
|
||||
{
|
||||
case 13:
|
||||
if (!key_256)
|
||||
{
|
||||
if (!(key_256 = whine_malloc(sizeof(struct ecc_point))))
|
||||
return 0;
|
||||
|
||||
nettle_ecc_point_init(key_256, &nettle_secp_256r1);
|
||||
}
|
||||
|
||||
key = key_256;
|
||||
t = 32;
|
||||
break;
|
||||
|
||||
case 14:
|
||||
if (!key_384)
|
||||
{
|
||||
if (!(key_384 = whine_malloc(sizeof(struct ecc_point))))
|
||||
return 0;
|
||||
|
||||
nettle_ecc_point_init(key_384, &nettle_secp_384r1);
|
||||
}
|
||||
|
||||
key = key_384;
|
||||
t = 48;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sig_len != 2*t || key_len != 2*t ||
|
||||
!(p = blockdata_retrieve(key_data, key_len, NULL)))
|
||||
return 0;
|
||||
|
||||
mpz_import(x, t , 1, 1, 0, 0, p);
|
||||
mpz_import(y, t , 1, 1, 0, 0, p + t);
|
||||
|
||||
if (!ecc_point_set(key, x, y))
|
||||
return 0;
|
||||
|
||||
mpz_import(sig_struct->r, t, 1, 1, 0, 0, sig);
|
||||
mpz_import(sig_struct->s, t, 1, 1, 0, 0, sig + t);
|
||||
|
||||
return nettle_ecdsa_verify(key, digest_len, digest, sig_struct);
|
||||
}
|
||||
|
||||
static int dnsmasq_eddsa_verify(struct blockdata *key_data, unsigned int key_len,
|
||||
unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
unsigned char *p;
|
||||
|
||||
if (key_len != ED25519_KEY_SIZE ||
|
||||
sig_len != ED25519_SIGNATURE_SIZE ||
|
||||
digest_len != sizeof(struct null_hash_digest) ||
|
||||
!(p = blockdata_retrieve(key_data, key_len, NULL)))
|
||||
return 0;
|
||||
|
||||
/* The "digest" returned by the null_hash function is simply a struct null_hash_digest
|
||||
which has a pointer to the actual data and a length, because the buffer
|
||||
may need to be extended during "hashing". */
|
||||
|
||||
switch (algo)
|
||||
{
|
||||
case 15:
|
||||
return ed25519_sha512_verify(p,
|
||||
((struct null_hash_digest *)digest)->len,
|
||||
((struct null_hash_digest *)digest)->buff,
|
||||
sig);
|
||||
case 16:
|
||||
/* Ed448 when available */
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int (*verify_func(int algo))(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
|
||||
/* Enure at runtime that we have support for this digest */
|
||||
if (!hash_find(algo_digest_name(algo)))
|
||||
return NULL;
|
||||
|
||||
/* This switch defines which sig algorithms we support, can't introspect Nettle for that. */
|
||||
switch (algo)
|
||||
{
|
||||
case 1: case 5: case 7: case 8: case 10:
|
||||
return dnsmasq_rsa_verify;
|
||||
|
||||
case 3: case 6:
|
||||
return dnsmasq_dsa_verify;
|
||||
|
||||
#ifndef NO_NETTLE_ECC
|
||||
case 13: case 14:
|
||||
return dnsmasq_ecdsa_verify;
|
||||
|
||||
case 15: case 16:
|
||||
return dnsmasq_eddsa_verify;
|
||||
#endif
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
|
||||
int (*func)(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo);
|
||||
|
||||
func = verify_func(algo);
|
||||
|
||||
if (!func)
|
||||
return 0;
|
||||
|
||||
return (*func)(key_data, key_len, sig, sig_len, digest, digest_len, algo);
|
||||
}
|
||||
|
||||
/* http://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */
|
||||
char *ds_digest_name(int digest)
|
||||
{
|
||||
switch (digest)
|
||||
{
|
||||
case 1: return "sha1";
|
||||
case 2: return "sha256";
|
||||
case 3: return "gosthash94";
|
||||
case 4: return "sha384";
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* http://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */
|
||||
char *algo_digest_name(int algo)
|
||||
{
|
||||
switch (algo)
|
||||
{
|
||||
case 1: return "md5";
|
||||
case 3: return "sha1";
|
||||
case 5: return "sha1";
|
||||
case 6: return "sha1";
|
||||
case 7: return "sha1";
|
||||
case 8: return "sha256";
|
||||
case 10: return "sha512";
|
||||
case 12: return "gosthash94";
|
||||
case 13: return "sha256";
|
||||
case 14: return "sha384";
|
||||
case 15: return "null_hash"; /* Ed25519 */
|
||||
case 16: return NULL; /* Ed448 */
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* http://www.iana.org/assignments/dnssec-nsec3-parameters/dnssec-nsec3-parameters.xhtml */
|
||||
char *nsec3_digest_name(int digest)
|
||||
{
|
||||
switch (digest)
|
||||
{
|
||||
case 1: return "sha1";
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -142,6 +142,10 @@ extern int capget(cap_user_header_t header, cap_user_data_t data);
|
||||
#include <priv.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
# include <nettle/nettle-meta.h>
|
||||
#endif
|
||||
|
||||
/* daemon is function in the C library.... */
|
||||
#define daemon dnsmasq_daemon
|
||||
|
||||
@@ -1179,6 +1183,17 @@ size_t filter_rrsigs(struct dns_header *header, size_t plen);
|
||||
unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name);
|
||||
int setup_timestamp(void);
|
||||
|
||||
/* crypto.c */
|
||||
const struct nettle_hash *hash_find(char *name);
|
||||
int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **digestp);
|
||||
int (*verify_func(int algo))(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo);
|
||||
int verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo);
|
||||
char *ds_digest_name(int digest);
|
||||
char *algo_digest_name(int algo);
|
||||
char *nsec3_digest_name(int digest);
|
||||
|
||||
/* util.c */
|
||||
void rand_init(void);
|
||||
unsigned short rand16(void);
|
||||
|
||||
321
src/dnssec.c
321
src/dnssec.c
@@ -19,332 +19,11 @@
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
|
||||
#include <nettle/rsa.h>
|
||||
#include <nettle/dsa.h>
|
||||
#ifndef NO_NETTLE_ECC
|
||||
# include <nettle/ecdsa.h>
|
||||
# include <nettle/ecc-curve.h>
|
||||
#endif
|
||||
#include <nettle/nettle-meta.h>
|
||||
#include <nettle/bignum.h>
|
||||
|
||||
/* Nettle-3.0 moved to a new API for DSA. We use a name that's defined in the new API
|
||||
to detect Nettle-3, and invoke the backwards compatibility mode. */
|
||||
#ifdef dsa_params_init
|
||||
#include <nettle/dsa-compat.h>
|
||||
#endif
|
||||
|
||||
#define SERIAL_UNDEF -100
|
||||
#define SERIAL_EQ 0
|
||||
#define SERIAL_LT -1
|
||||
#define SERIAL_GT 1
|
||||
|
||||
/* http://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */
|
||||
static char *ds_digest_name(int digest)
|
||||
{
|
||||
switch (digest)
|
||||
{
|
||||
case 1: return "sha1";
|
||||
case 2: return "sha256";
|
||||
case 3: return "gosthash94";
|
||||
case 4: return "sha384";
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* http://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */
|
||||
static char *algo_digest_name(int algo)
|
||||
{
|
||||
switch (algo)
|
||||
{
|
||||
case 1: return "md5";
|
||||
case 3: return "sha1";
|
||||
case 5: return "sha1";
|
||||
case 6: return "sha1";
|
||||
case 7: return "sha1";
|
||||
case 8: return "sha256";
|
||||
case 10: return "sha512";
|
||||
case 12: return "gosthash94";
|
||||
case 13: return "sha256";
|
||||
case 14: return "sha384";
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* http://www.iana.org/assignments/dnssec-nsec3-parameters/dnssec-nsec3-parameters.xhtml */
|
||||
static char *nsec3_digest_name(int digest)
|
||||
{
|
||||
switch (digest)
|
||||
{
|
||||
case 1: return "sha1";
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Find pointer to correct hash function in nettle library */
|
||||
static const struct nettle_hash *hash_find(char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; nettle_hashes[i]; i++)
|
||||
{
|
||||
if (strcmp(nettle_hashes[i]->name, name) == 0)
|
||||
return nettle_hashes[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* expand ctx and digest memory allocations if necessary and init hash function */
|
||||
static int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **digestp)
|
||||
{
|
||||
static void *ctx = NULL;
|
||||
static unsigned char *digest = NULL;
|
||||
static unsigned int ctx_sz = 0;
|
||||
static unsigned int digest_sz = 0;
|
||||
|
||||
void *new;
|
||||
|
||||
if (ctx_sz < hash->context_size)
|
||||
{
|
||||
if (!(new = whine_malloc(hash->context_size)))
|
||||
return 0;
|
||||
if (ctx)
|
||||
free(ctx);
|
||||
ctx = new;
|
||||
ctx_sz = hash->context_size;
|
||||
}
|
||||
|
||||
if (digest_sz < hash->digest_size)
|
||||
{
|
||||
if (!(new = whine_malloc(hash->digest_size)))
|
||||
return 0;
|
||||
if (digest)
|
||||
free(digest);
|
||||
digest = new;
|
||||
digest_sz = hash->digest_size;
|
||||
}
|
||||
|
||||
*ctxp = ctx;
|
||||
*digestp = digest;
|
||||
|
||||
hash->init(ctx);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dnsmasq_rsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
unsigned char *p;
|
||||
size_t exp_len;
|
||||
|
||||
static struct rsa_public_key *key = NULL;
|
||||
static mpz_t sig_mpz;
|
||||
|
||||
(void)digest_len;
|
||||
|
||||
if (key == NULL)
|
||||
{
|
||||
if (!(key = whine_malloc(sizeof(struct rsa_public_key))))
|
||||
return 0;
|
||||
|
||||
nettle_rsa_public_key_init(key);
|
||||
mpz_init(sig_mpz);
|
||||
}
|
||||
|
||||
if ((key_len < 3) || !(p = blockdata_retrieve(key_data, key_len, NULL)))
|
||||
return 0;
|
||||
|
||||
key_len--;
|
||||
if ((exp_len = *p++) == 0)
|
||||
{
|
||||
GETSHORT(exp_len, p);
|
||||
key_len -= 2;
|
||||
}
|
||||
|
||||
if (exp_len >= key_len)
|
||||
return 0;
|
||||
|
||||
key->size = key_len - exp_len;
|
||||
mpz_import(key->e, exp_len, 1, 1, 0, 0, p);
|
||||
mpz_import(key->n, key->size, 1, 1, 0, 0, p + exp_len);
|
||||
|
||||
mpz_import(sig_mpz, sig_len, 1, 1, 0, 0, sig);
|
||||
|
||||
switch (algo)
|
||||
{
|
||||
case 1:
|
||||
return nettle_rsa_md5_verify_digest(key, digest, sig_mpz);
|
||||
case 5: case 7:
|
||||
return nettle_rsa_sha1_verify_digest(key, digest, sig_mpz);
|
||||
case 8:
|
||||
return nettle_rsa_sha256_verify_digest(key, digest, sig_mpz);
|
||||
case 10:
|
||||
return nettle_rsa_sha512_verify_digest(key, digest, sig_mpz);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dnsmasq_dsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
unsigned char *p;
|
||||
unsigned int t;
|
||||
|
||||
static struct dsa_public_key *key = NULL;
|
||||
static struct dsa_signature *sig_struct;
|
||||
|
||||
(void)digest_len;
|
||||
|
||||
if (key == NULL)
|
||||
{
|
||||
if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))) ||
|
||||
!(key = whine_malloc(sizeof(struct dsa_public_key))))
|
||||
return 0;
|
||||
|
||||
nettle_dsa_public_key_init(key);
|
||||
nettle_dsa_signature_init(sig_struct);
|
||||
}
|
||||
|
||||
if ((sig_len < 41) || !(p = blockdata_retrieve(key_data, key_len, NULL)))
|
||||
return 0;
|
||||
|
||||
t = *p++;
|
||||
|
||||
if (key_len < (213 + (t * 24)))
|
||||
return 0;
|
||||
|
||||
mpz_import(key->q, 20, 1, 1, 0, 0, p); p += 20;
|
||||
mpz_import(key->p, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
|
||||
mpz_import(key->g, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
|
||||
mpz_import(key->y, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
|
||||
|
||||
mpz_import(sig_struct->r, 20, 1, 1, 0, 0, sig+1);
|
||||
mpz_import(sig_struct->s, 20, 1, 1, 0, 0, sig+21);
|
||||
|
||||
(void)algo;
|
||||
|
||||
return nettle_dsa_sha1_verify_digest(key, digest, sig_struct);
|
||||
}
|
||||
|
||||
#ifndef NO_NETTLE_ECC
|
||||
static int dnsmasq_ecdsa_verify(struct blockdata *key_data, unsigned int key_len,
|
||||
unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
unsigned char *p;
|
||||
unsigned int t;
|
||||
struct ecc_point *key;
|
||||
|
||||
static struct ecc_point *key_256 = NULL, *key_384 = NULL;
|
||||
static mpz_t x, y;
|
||||
static struct dsa_signature *sig_struct;
|
||||
|
||||
if (!sig_struct)
|
||||
{
|
||||
if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))))
|
||||
return 0;
|
||||
|
||||
nettle_dsa_signature_init(sig_struct);
|
||||
mpz_init(x);
|
||||
mpz_init(y);
|
||||
}
|
||||
|
||||
switch (algo)
|
||||
{
|
||||
case 13:
|
||||
if (!key_256)
|
||||
{
|
||||
if (!(key_256 = whine_malloc(sizeof(struct ecc_point))))
|
||||
return 0;
|
||||
|
||||
nettle_ecc_point_init(key_256, &nettle_secp_256r1);
|
||||
}
|
||||
|
||||
key = key_256;
|
||||
t = 32;
|
||||
break;
|
||||
|
||||
case 14:
|
||||
if (!key_384)
|
||||
{
|
||||
if (!(key_384 = whine_malloc(sizeof(struct ecc_point))))
|
||||
return 0;
|
||||
|
||||
nettle_ecc_point_init(key_384, &nettle_secp_384r1);
|
||||
}
|
||||
|
||||
key = key_384;
|
||||
t = 48;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sig_len != 2*t || key_len != 2*t ||
|
||||
!(p = blockdata_retrieve(key_data, key_len, NULL)))
|
||||
return 0;
|
||||
|
||||
mpz_import(x, t , 1, 1, 0, 0, p);
|
||||
mpz_import(y, t , 1, 1, 0, 0, p + t);
|
||||
|
||||
if (!ecc_point_set(key, x, y))
|
||||
return 0;
|
||||
|
||||
mpz_import(sig_struct->r, t, 1, 1, 0, 0, sig);
|
||||
mpz_import(sig_struct->s, t, 1, 1, 0, 0, sig + t);
|
||||
|
||||
return nettle_ecdsa_verify(key, digest_len, digest, sig_struct);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int (*verify_func(int algo))(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
|
||||
/* Enure at runtime that we have support for this digest */
|
||||
if (!hash_find(algo_digest_name(algo)))
|
||||
return NULL;
|
||||
|
||||
/* This switch defines which sig algorithms we support, can't introspect Nettle for that. */
|
||||
switch (algo)
|
||||
{
|
||||
case 1: case 5: case 7: case 8: case 10:
|
||||
return dnsmasq_rsa_verify;
|
||||
|
||||
case 3: case 6:
|
||||
return dnsmasq_dsa_verify;
|
||||
|
||||
#ifndef NO_NETTLE_ECC
|
||||
case 13: case 14:
|
||||
return dnsmasq_ecdsa_verify;
|
||||
#endif
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
|
||||
int (*func)(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo);
|
||||
|
||||
func = verify_func(algo);
|
||||
|
||||
if (!func)
|
||||
return 0;
|
||||
|
||||
return (*func)(key_data, key_len, sig, sig_len, digest, digest_len, algo);
|
||||
}
|
||||
|
||||
/* Convert from presentation format to wire format, in place.
|
||||
Also map UC -> LC.
|
||||
Note that using extract_name to get presentation format
|
||||
|
||||
Reference in New Issue
Block a user