From ad9c6f06c5ceebbeda3796e1649d1226e86eb769 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Fri, 27 Oct 2017 22:13:49 +0100 Subject: [PATCH] Add support for Ed25519 DNSSEC signature algorithm. --- Makefile | 2 +- bld/Android.mk | 2 +- src/blockdata.c | 3 +- src/crypto.c | 456 ++++++++++++++++++++++++++++++++++++++++++++++++ src/dnsmasq.h | 15 ++ src/dnssec.c | 321 ---------------------------------- 6 files changed, 475 insertions(+), 324 deletions(-) create mode 100644 src/crypto.c diff --git a/Makefile b/Makefile index 73ea23e..98ec760 100644 --- a/Makefile +++ b/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 diff --git a/bld/Android.mk b/bld/Android.mk index eafef35..80ec842 100644 --- a/bld/Android.mk +++ b/bld/Android.mk @@ -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 diff --git a/src/blockdata.c b/src/blockdata.c index 8683b9b..a4e1f81 100644 --- a/src/blockdata.c +++ b/src/blockdata.c @@ -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; diff --git a/src/crypto.c b/src/crypto.c new file mode 100644 index 0000000..83372c7 --- /dev/null +++ b/src/crypto.c @@ -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 . +*/ + +#include "dnsmasq.h" + +#ifdef HAVE_DNSSEC + +#include +#include +#ifndef NO_NETTLE_ECC +# include +# include +# include +#endif +#include +#include + +/* 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 +#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 diff --git a/src/dnsmasq.h b/src/dnsmasq.h index e0184a9..b4d836a 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -142,6 +142,10 @@ extern int capget(cap_user_header_t header, cap_user_data_t data); #include #endif +#ifdef HAVE_DNSSEC +# include +#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); diff --git a/src/dnssec.c b/src/dnssec.c index 3819eda..cc79a23 100644 --- a/src/dnssec.c +++ b/src/dnssec.c @@ -19,332 +19,11 @@ #ifdef HAVE_DNSSEC -#include -#include -#ifndef NO_NETTLE_ECC -# include -# include -#endif -#include -#include - -/* 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 -#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