diff options
Diffstat (limited to 'contrib/bind9/lib/dns')
35 files changed, 5871 insertions, 152 deletions
diff --git a/contrib/bind9/lib/dns/Makefile.in b/contrib/bind9/lib/dns/Makefile.in index e88d2b4ddb46..fbbec2eba8e7 100644 --- a/contrib/bind9/lib/dns/Makefile.in +++ b/contrib/bind9/lib/dns/Makefile.in @@ -13,7 +13,7 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: Makefile.in,v 1.126.2.3.2.15 2004/07/20 07:01:57 marka Exp $ +# $Id: Makefile.in,v 1.126.2.3.2.17 2004/12/09 04:07:15 marka Exp $ srcdir = @srcdir@ VPATH = @srcdir@ @@ -29,9 +29,10 @@ top_srcdir = @top_srcdir@ @BIND9_MAKE_INCLUDES@ -CINCLUDES = -I. ${DNS_INCLUDES} ${ISC_INCLUDES} +CINCLUDES = -I. -Iinclude ${DNS_INCLUDES} \ + ${ISC_INCLUDES} @DST_OPENSSL_INC@ @DST_GSSAPI_INC@ -CDEFINES = +CDEFINES = -DUSE_MD5 @USE_OPENSSL@ @USE_GSSAPI@ CWARNINGS = ISCLIBS = ../../lib/isc/libisc.@A@ @@ -42,13 +43,10 @@ LIBS = @LIBS@ # Alphabetically -DSTOBJS = sec/dst/dst_api.@O@ \ - sec/dst/dst_lib.@O@ sec/dst/dst_parse.@O@ \ - sec/dst/dst_result.@O@ sec/dst/gssapi_link.@O@ \ - sec/dst/gssapictx.@O@ sec/dst/hmac_link.@O@ \ - sec/dst/key.@O@ sec/dst/openssl_link.@O@ \ - sec/dst/openssldh_link.@O@ sec/dst/openssldsa_link.@O@ \ - sec/dst/opensslrsa_link.@O@ +DSTOBJS = dst_api.@O@ dst_lib.@O@ dst_parse.@O@ dst_result.@O@ \ + gssapi_link.@O@ gssapictx.@O@ hmac_link.@O@ key.@O@ \ + openssl_link.@O@ openssldh_link.@O@ openssldsa_link.@O@ \ + opensslrsa_link.@O@ # Alphabetically DNSOBJS = acl.@O@ adb.@O@ byaddr.@O@ \ @@ -69,6 +67,12 @@ DNSOBJS = acl.@O@ adb.@O@ byaddr.@O@ \ OBJS= ${DNSOBJS} ${OTHEROBJS} ${DSTOBJS} # Alphabetically +DSTSRCS = dst_api.c dst_lib.c dst_parse.c \ + dst_result.c gssapi_link.c gssapictx.c \ + hmac_link.c key.c \ + openssl_link.c openssldh_link.c \ + openssldsa_link.c opensslrsa_link.c + SRCS = acl.c adb.c byaddr.c \ cache.c callbacks.c compress.c \ db.c dbiterator.c dbtable.c diff.c dispatch.c \ @@ -83,8 +87,9 @@ SRCS = acl.c adb.c byaddr.c \ stats.c tcpmsg.c time.c timer.c tkey.c \ tsig.c ttl.c validator.c \ version.c view.c xfrin.c zone.c zonekey.c zt.c ${OTHERSRCS} +SRCS = ${DSTSRCS} ${DNSSRCS} -SUBDIRS = include sec +SUBDIRS = include TARGETS = include/dns/enumtype.h include/dns/enumclass.h \ include/dns/rdatastruct.h timestamp @@ -159,6 +164,5 @@ depend: include/dns/enumtype.h include/dns/enumclass.h \ include/dns/rdatastruct.h code.h subdirs: include/dns/enumtype.h include/dns/enumclass.h \ include/dns/rdatastruct.h code.h -${DNSOBJS}: include/dns/enumtype.h include/dns/enumclass.h \ +${OBJS}: include/dns/enumtype.h include/dns/enumclass.h \ include/dns/rdatastruct.h -rdata.${0}: code.h diff --git a/contrib/bind9/lib/dns/adb.c b/contrib/bind9/lib/dns/adb.c index 43b66692a287..9c8d4d5b4ac5 100644 --- a/contrib/bind9/lib/dns/adb.c +++ b/contrib/bind9/lib/dns/adb.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: adb.c,v 1.181.2.11.2.19 2004/09/01 05:19:57 marka Exp $ */ +/* $Id: adb.c,v 1.181.2.11.2.20 2004/11/10 22:32:40 marka Exp $ */ /* * Implementation notes @@ -278,7 +278,7 @@ static inline dns_adbname_t *find_name_and_lock(dns_adb_t *, dns_name_t *, unsigned int, int *); static inline dns_adbentry_t *find_entry_and_lock(dns_adb_t *, isc_sockaddr_t *, int *); -static void dump_adb(dns_adb_t *, FILE *, isc_boolean_t debug); +static void dump_adb(dns_adb_t *, FILE *, isc_boolean_t debug, isc_stdtime_t); static void print_dns_name(FILE *, dns_name_t *); static void print_namehook_list(FILE *, const char *legend, dns_adbnamehooklist_t *list, @@ -315,7 +315,8 @@ static inline isc_boolean_t unlink_name(dns_adb_t *, dns_adbname_t *); static inline void link_entry(dns_adb_t *, int, dns_adbentry_t *); static inline isc_boolean_t unlink_entry(dns_adb_t *, dns_adbentry_t *); static isc_boolean_t kill_name(dns_adbname_t **, isc_eventtype_t); -static void water(void *arg, int mark); +static void water(void *, int); +static void dump_entry(FILE *, dns_adbentry_t *, isc_boolean_t, isc_stdtime_t); /* * MUST NOT overlap DNS_ADBFIND_* flags! @@ -1937,7 +1938,7 @@ timer_cleanup(isc_task_t *task, isc_event_t *ev) { if (adb->next_cleanbucket >= NBUCKETS) { adb->next_cleanbucket = 0; #ifdef DUMP_ADB_AFTER_CLEANING - dump_adb(adb, stdout, ISC_TRUE); + dump_adb(adb, stdout, ISC_TRUE, now); #endif } } @@ -2707,6 +2708,9 @@ dns_adb_cancelfind(dns_adbfind_t *find) { void dns_adb_dump(dns_adb_t *adb, FILE *f) { + int i; + isc_stdtime_t now; + REQUIRE(DNS_ADB_VALID(adb)); REQUIRE(f != NULL); @@ -2718,7 +2722,14 @@ dns_adb_dump(dns_adb_t *adb, FILE *f) { */ LOCK(&adb->lock); - dump_adb(adb, f, ISC_FALSE); + isc_stdtime_get(&now); + + for (i = 0; i < NBUCKETS; i++) + RUNTIME_CHECK(cleanup_names(adb, i, now) == ISC_FALSE); + for (i = 0; i < NBUCKETS; i++) + RUNTIME_CHECK(cleanup_entries(adb, i, now) == ISC_FALSE); + + dump_adb(adb, f, ISC_FALSE, now); UNLOCK(&adb->lock); } @@ -2730,12 +2741,10 @@ dump_ttl(FILE *f, const char *legend, isc_stdtime_t value, isc_stdtime_t now) { } static void -dump_adb(dns_adb_t *adb, FILE *f, isc_boolean_t debug) { +dump_adb(dns_adb_t *adb, FILE *f, isc_boolean_t debug, isc_stdtime_t now) { int i; dns_adbname_t *name; - isc_stdtime_t now; - - isc_stdtime_get(&now); + dns_adbentry_t *entry; fprintf(f, ";\n; Address database dump\n;\n"); if (debug) @@ -2793,6 +2802,17 @@ dump_adb(dns_adb_t *adb, FILE *f, isc_boolean_t debug) { } } + fprintf(f, ";\n; Unassociated entries\n;\n"); + + for (i = 0; i < NBUCKETS; i++) { + entry = ISC_LIST_HEAD(adb->entries[i]); + while (entry != NULL) { + if (entry->refcnt == 0) + dump_entry(f, entry, debug, now); + entry = ISC_LIST_NEXT(entry, plink); + } + } + /* * Unlock everything */ @@ -2818,6 +2838,8 @@ dump_entry(FILE *f, dns_adbentry_t *entry, isc_boolean_t debug, fprintf(f, ";\t%s [srtt %u] [flags %08x]", addrbuf, entry->srtt, entry->flags); + if (entry->expires != 0) + fprintf(f, " [ttl %d]", entry->expires - now); fprintf(f, "\n"); for (zi = ISC_LIST_HEAD(entry->zoneinfo); zi != NULL; @@ -3495,16 +3517,16 @@ dns_adb_flush(dns_adb_t *adb) { LOCK(&adb->lock); - for (i = 0; i < NBUCKETS; i++) { - /* - * Call our cleanup routines. - */ + /* + * Call our cleanup routines. + */ + for (i = 0; i < NBUCKETS; i++) RUNTIME_CHECK(cleanup_names(adb, i, INT_MAX) == ISC_FALSE); + for (i = 0; i < NBUCKETS; i++) RUNTIME_CHECK(cleanup_entries(adb, i, INT_MAX) == ISC_FALSE); - } #ifdef DUMP_ADB_AFTER_CLEANING - dump_adb(adb, stdout, ISC_TRUE); + dump_adb(adb, stdout, ISC_TRUE, INT_MAX); #endif UNLOCK(&adb->lock); diff --git a/contrib/bind9/lib/dns/api b/contrib/bind9/lib/dns/api index 444e0c5cd0c5..c06a62ec803a 100644 --- a/contrib/bind9/lib/dns/api +++ b/contrib/bind9/lib/dns/api @@ -1,3 +1,3 @@ LIBINTERFACE = 20 -LIBREVISION = 0 +LIBREVISION = 2 LIBAGE = 0 diff --git a/contrib/bind9/lib/dns/dst_api.c b/contrib/bind9/lib/dns/dst_api.c new file mode 100644 index 000000000000..19f60a27e805 --- /dev/null +++ b/contrib/bind9/lib/dns/dst_api.c @@ -0,0 +1,1185 @@ +/* + * Portions Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 1999-2003 Internet Software Consortium. + * Portions Copyright (C) 1995-2000 by Network Associates, Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE + * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Principal Author: Brian Wellington + * $Id: dst_api.c,v 1.1.4.1 2004/12/09 04:07:16 marka Exp $ + */ + +#include <config.h> + +#include <stdlib.h> + +#include <isc/buffer.h> +#include <isc/dir.h> +#include <isc/entropy.h> +#include <isc/fsaccess.h> +#include <isc/lex.h> +#include <isc/mem.h> +#include <isc/once.h> +#include <isc/print.h> +#include <isc/random.h> +#include <isc/string.h> +#include <isc/time.h> +#include <isc/util.h> + +#include <dns/fixedname.h> +#include <dns/keyvalues.h> +#include <dns/name.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> +#include <dns/ttl.h> +#include <dns/types.h> + +#include <dst/result.h> + +#include "dst_internal.h" + +#define DST_AS_STR(t) ((t).value.as_textregion.base) + +static dst_func_t *dst_t_func[DST_MAX_ALGS]; +static isc_entropy_t *dst_entropy_pool = NULL; +static unsigned int dst_entropy_flags = 0; +static isc_boolean_t dst_initialized = ISC_FALSE; + +isc_mem_t *dst__memory_pool = NULL; + +/* + * Static functions. + */ +static dst_key_t * get_key_struct(dns_name_t *name, + unsigned int alg, + unsigned int flags, + unsigned int protocol, + unsigned int bits, + dns_rdataclass_t rdclass, + isc_mem_t *mctx); +static isc_result_t read_public_key(const char *filename, + int type, + isc_mem_t *mctx, + dst_key_t **keyp); +static isc_result_t write_public_key(const dst_key_t *key, int type, + const char *directory); +static isc_result_t buildfilename(dns_name_t *name, + dns_keytag_t id, + unsigned int alg, + unsigned int type, + const char *directory, + isc_buffer_t *out); +static isc_result_t computeid(dst_key_t *key); +static isc_result_t frombuffer(dns_name_t *name, + unsigned int alg, + unsigned int flags, + unsigned int protocol, + dns_rdataclass_t rdclass, + isc_buffer_t *source, + isc_mem_t *mctx, + dst_key_t **keyp); + +static isc_result_t algorithm_status(unsigned int alg); + +static isc_result_t addsuffix(char *filename, unsigned int len, + const char *ofilename, const char *suffix); + +#define RETERR(x) \ + do { \ + result = (x); \ + if (result != ISC_R_SUCCESS) \ + goto out; \ + } while (0) + +#define CHECKALG(alg) \ + do { \ + isc_result_t _r; \ + _r = algorithm_status(alg); \ + if (_r != ISC_R_SUCCESS) \ + return (_r); \ + } while (0); \ + +isc_result_t +dst_lib_init(isc_mem_t *mctx, isc_entropy_t *ectx, unsigned int eflags) { + isc_result_t result; + + REQUIRE(mctx != NULL && ectx != NULL); + REQUIRE(dst_initialized == ISC_FALSE); + + dst__memory_pool = NULL; + +#ifdef OPENSSL + UNUSED(mctx); + /* + * When using --with-openssl, there seems to be no good way of not + * leaking memory due to the openssl error handling mechanism. + * Avoid assertions by using a local memory context and not checking + * for leaks on exit. + */ + result = isc_mem_create(0, 0, &dst__memory_pool); + if (result != ISC_R_SUCCESS) + return (result); + isc_mem_setdestroycheck(dst__memory_pool, ISC_FALSE); +#else + isc_mem_attach(mctx, &dst__memory_pool); +#endif + isc_entropy_attach(ectx, &dst_entropy_pool); + dst_entropy_flags = eflags; + + dst_result_register(); + + memset(dst_t_func, 0, sizeof(dst_t_func)); + RETERR(dst__hmacmd5_init(&dst_t_func[DST_ALG_HMACMD5])); +#ifdef OPENSSL + RETERR(dst__openssl_init()); + RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSAMD5])); + RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA1])); +#ifdef HAVE_OPENSSL_DSA + RETERR(dst__openssldsa_init(&dst_t_func[DST_ALG_DSA])); +#endif + RETERR(dst__openssldh_init(&dst_t_func[DST_ALG_DH])); +#endif /* OPENSSL */ +#ifdef GSSAPI + RETERR(dst__gssapi_init(&dst_t_func[DST_ALG_GSSAPI])); +#endif + dst_initialized = ISC_TRUE; + return (ISC_R_SUCCESS); + + out: + dst_lib_destroy(); + return (result); +} + +void +dst_lib_destroy(void) { + int i; + RUNTIME_CHECK(dst_initialized == ISC_TRUE); + dst_initialized = ISC_FALSE; + + for (i = 0; i < DST_MAX_ALGS; i++) + if (dst_t_func[i] != NULL && dst_t_func[i]->cleanup != NULL) + dst_t_func[i]->cleanup(); +#ifdef OPENSSL + dst__openssl_destroy(); +#endif + if (dst__memory_pool != NULL) + isc_mem_detach(&dst__memory_pool); + if (dst_entropy_pool != NULL) + isc_entropy_detach(&dst_entropy_pool); + +} + +isc_boolean_t +dst_algorithm_supported(unsigned int alg) { + REQUIRE(dst_initialized == ISC_TRUE); + + if (alg >= DST_MAX_ALGS || dst_t_func[alg] == NULL) + return (ISC_FALSE); + return (ISC_TRUE); +} + +isc_result_t +dst_context_create(dst_key_t *key, isc_mem_t *mctx, dst_context_t **dctxp) { + dst_context_t *dctx; + isc_result_t result; + + REQUIRE(dst_initialized == ISC_TRUE); + REQUIRE(VALID_KEY(key)); + REQUIRE(mctx != NULL); + REQUIRE(dctxp != NULL && *dctxp == NULL); + + if (key->func->createctx == NULL) + return (DST_R_UNSUPPORTEDALG); + if (key->opaque == NULL) + return (DST_R_NULLKEY); + + dctx = isc_mem_get(mctx, sizeof(dst_context_t)); + if (dctx == NULL) + return (ISC_R_NOMEMORY); + dctx->key = key; + dctx->mctx = mctx; + result = key->func->createctx(key, dctx); + if (result != ISC_R_SUCCESS) { + isc_mem_put(mctx, dctx, sizeof(dst_context_t)); + return (result); + } + dctx->magic = CTX_MAGIC; + *dctxp = dctx; + return (ISC_R_SUCCESS); +} + +void +dst_context_destroy(dst_context_t **dctxp) { + dst_context_t *dctx; + + REQUIRE(dctxp != NULL && VALID_CTX(*dctxp)); + + dctx = *dctxp; + INSIST(dctx->key->func->destroyctx != NULL); + dctx->key->func->destroyctx(dctx); + dctx->magic = 0; + isc_mem_put(dctx->mctx, dctx, sizeof(dst_context_t)); + *dctxp = NULL; +} + +isc_result_t +dst_context_adddata(dst_context_t *dctx, const isc_region_t *data) { + REQUIRE(VALID_CTX(dctx)); + REQUIRE(data != NULL); + INSIST(dctx->key->func->adddata != NULL); + + return (dctx->key->func->adddata(dctx, data)); +} + +isc_result_t +dst_context_sign(dst_context_t *dctx, isc_buffer_t *sig) { + dst_key_t *key; + + REQUIRE(VALID_CTX(dctx)); + REQUIRE(sig != NULL); + + key = dctx->key; + CHECKALG(key->key_alg); + if (key->opaque == NULL) + return (DST_R_NULLKEY); + if (key->func->sign == NULL) + return (DST_R_NOTPRIVATEKEY); + if (key->func->isprivate == NULL || + key->func->isprivate(key) == ISC_FALSE) + return (DST_R_NOTPRIVATEKEY); + + return (key->func->sign(dctx, sig)); +} + +isc_result_t +dst_context_verify(dst_context_t *dctx, isc_region_t *sig) { + REQUIRE(VALID_CTX(dctx)); + REQUIRE(sig != NULL); + + CHECKALG(dctx->key->key_alg); + if (dctx->key->opaque == NULL) + return (DST_R_NULLKEY); + if (dctx->key->func->verify == NULL) + return (DST_R_NOTPUBLICKEY); + + return (dctx->key->func->verify(dctx, sig)); +} + +isc_result_t +dst_key_computesecret(const dst_key_t *pub, const dst_key_t *priv, + isc_buffer_t *secret) +{ + REQUIRE(dst_initialized == ISC_TRUE); + REQUIRE(VALID_KEY(pub) && VALID_KEY(priv)); + REQUIRE(secret != NULL); + + CHECKALG(pub->key_alg); + CHECKALG(priv->key_alg); + + if (pub->opaque == NULL || priv->opaque == NULL) + return (DST_R_NULLKEY); + + if (pub->key_alg != priv->key_alg || + pub->func->computesecret == NULL || + priv->func->computesecret == NULL) + return (DST_R_KEYCANNOTCOMPUTESECRET); + + if (dst_key_isprivate(priv) == ISC_FALSE) + return (DST_R_NOTPRIVATEKEY); + + return (pub->func->computesecret(pub, priv, secret)); +} + +isc_result_t +dst_key_tofile(const dst_key_t *key, int type, const char *directory) { + isc_result_t ret = ISC_R_SUCCESS; + + REQUIRE(dst_initialized == ISC_TRUE); + REQUIRE(VALID_KEY(key)); + REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0); + + CHECKALG(key->key_alg); + + if (key->func->tofile == NULL) + return (DST_R_UNSUPPORTEDALG); + + if (type & DST_TYPE_PUBLIC) { + ret = write_public_key(key, type, directory); + if (ret != ISC_R_SUCCESS) + return (ret); + } + + if ((type & DST_TYPE_PRIVATE) && + (key->key_flags & DNS_KEYFLAG_TYPEMASK) != DNS_KEYTYPE_NOKEY) + return (key->func->tofile(key, directory)); + else + return (ISC_R_SUCCESS); +} + +isc_result_t +dst_key_fromfile(dns_name_t *name, dns_keytag_t id, + unsigned int alg, int type, const char *directory, + isc_mem_t *mctx, dst_key_t **keyp) +{ + char filename[ISC_DIR_NAMEMAX]; + isc_buffer_t b; + dst_key_t *key; + isc_result_t result; + + REQUIRE(dst_initialized == ISC_TRUE); + REQUIRE(dns_name_isabsolute(name)); + REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0); + REQUIRE(mctx != NULL); + REQUIRE(keyp != NULL && *keyp == NULL); + + CHECKALG(alg); + + isc_buffer_init(&b, filename, sizeof(filename)); + result = buildfilename(name, id, alg, type, directory, &b); + if (result != ISC_R_SUCCESS) + return (result); + + key = NULL; + result = dst_key_fromnamedfile(filename, type, mctx, &key); + if (result != ISC_R_SUCCESS) + return (result); + + result = computeid(key); + if (result != ISC_R_SUCCESS) { + dst_key_free(&key); + return (result); + } + + if (!dns_name_equal(name, key->key_name) || + id != key->key_id || + alg != key->key_alg) + { + dst_key_free(&key); + return (DST_R_INVALIDPRIVATEKEY); + } + key->key_id = id; + + *keyp = key; + return (ISC_R_SUCCESS); +} + +isc_result_t +dst_key_fromnamedfile(const char *filename, int type, isc_mem_t *mctx, + dst_key_t **keyp) +{ + isc_result_t result; + dst_key_t *pubkey = NULL, *key = NULL; + dns_keytag_t id; + char *newfilename = NULL; + int newfilenamelen = 0; + isc_lex_t *lex = NULL; + + REQUIRE(dst_initialized == ISC_TRUE); + REQUIRE(filename != NULL); + REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0); + REQUIRE(mctx != NULL); + REQUIRE(keyp != NULL && *keyp == NULL); + + result = read_public_key(filename, type, mctx, &pubkey); + if (result != ISC_R_SUCCESS) + return (result); + + if ((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) == DST_TYPE_PUBLIC || + (pubkey->key_flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY) + { + result = computeid(pubkey); + if (result != ISC_R_SUCCESS) { + dst_key_free(&pubkey); + return (result); + } + + *keyp = pubkey; + return (ISC_R_SUCCESS); + } + + result = algorithm_status(pubkey->key_alg); + if (result != ISC_R_SUCCESS) { + dst_key_free(&pubkey); + return (result); + } + + key = get_key_struct(pubkey->key_name, pubkey->key_alg, + pubkey->key_flags, pubkey->key_proto, 0, + pubkey->key_class, mctx); + id = pubkey->key_id; + dst_key_free(&pubkey); + + if (key == NULL) + return (ISC_R_NOMEMORY); + + if (key->func->parse == NULL) + RETERR(DST_R_UNSUPPORTEDALG); + + newfilenamelen = strlen(filename) + 9; + newfilename = isc_mem_get(mctx, newfilenamelen); + if (newfilename == NULL) + RETERR(ISC_R_NOMEMORY); + result = addsuffix(newfilename, newfilenamelen, filename, ".private"); + INSIST(result == ISC_R_SUCCESS); + + RETERR(isc_lex_create(mctx, 1500, &lex)); + RETERR(isc_lex_openfile(lex, newfilename)); + isc_mem_put(mctx, newfilename, newfilenamelen); + + RETERR(key->func->parse(key, lex)); + isc_lex_destroy(&lex); + + RETERR(computeid(key)); + + if (id != key->key_id) + RETERR(DST_R_INVALIDPRIVATEKEY); + + *keyp = key; + return (ISC_R_SUCCESS); + out: + if (newfilename != NULL) + isc_mem_put(mctx, newfilename, newfilenamelen); + if (lex != NULL) + isc_lex_destroy(&lex); + dst_key_free(&key); + return (result); +} + +isc_result_t +dst_key_todns(const dst_key_t *key, isc_buffer_t *target) { + REQUIRE(dst_initialized == ISC_TRUE); + REQUIRE(VALID_KEY(key)); + REQUIRE(target != NULL); + + CHECKALG(key->key_alg); + + if (key->func->todns == NULL) + return (DST_R_UNSUPPORTEDALG); + + if (isc_buffer_availablelength(target) < 4) + return (ISC_R_NOSPACE); + isc_buffer_putuint16(target, (isc_uint16_t)(key->key_flags & 0xffff)); + isc_buffer_putuint8(target, (isc_uint8_t)key->key_proto); + isc_buffer_putuint8(target, (isc_uint8_t)key->key_alg); + + if (key->key_flags & DNS_KEYFLAG_EXTENDED) { + if (isc_buffer_availablelength(target) < 2) + return (ISC_R_NOSPACE); + isc_buffer_putuint16(target, + (isc_uint16_t)((key->key_flags >> 16) + & 0xffff)); + } + + if (key->opaque == NULL) /* NULL KEY */ + return (ISC_R_SUCCESS); + + return (key->func->todns(key, target)); +} + +isc_result_t +dst_key_fromdns(dns_name_t *name, dns_rdataclass_t rdclass, + isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) +{ + isc_uint8_t alg, proto; + isc_uint32_t flags, extflags; + dst_key_t *key = NULL; + dns_keytag_t id; + isc_region_t r; + isc_result_t result; + + REQUIRE(dst_initialized); + + isc_buffer_remainingregion(source, &r); + + if (isc_buffer_remaininglength(source) < 4) + return (DST_R_INVALIDPUBLICKEY); + flags = isc_buffer_getuint16(source); + proto = isc_buffer_getuint8(source); + alg = isc_buffer_getuint8(source); + + id = dst_region_computeid(&r, alg); + + if (flags & DNS_KEYFLAG_EXTENDED) { + if (isc_buffer_remaininglength(source) < 2) + return (DST_R_INVALIDPUBLICKEY); + extflags = isc_buffer_getuint16(source); + flags |= (extflags << 16); + } + + result = frombuffer(name, alg, flags, proto, rdclass, source, + mctx, &key); + if (result != ISC_R_SUCCESS) + return (result); + key->key_id = id; + + *keyp = key; + return (ISC_R_SUCCESS); +} + +isc_result_t +dst_key_frombuffer(dns_name_t *name, unsigned int alg, + unsigned int flags, unsigned int protocol, + dns_rdataclass_t rdclass, + isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) +{ + dst_key_t *key = NULL; + isc_result_t result; + + REQUIRE(dst_initialized); + + result = frombuffer(name, alg, flags, protocol, rdclass, source, + mctx, &key); + if (result != ISC_R_SUCCESS) + return (result); + + result = computeid(key); + if (result != ISC_R_SUCCESS) { + dst_key_free(&key); + return (result); + } + + *keyp = key; + return (ISC_R_SUCCESS); +} + +isc_result_t +dst_key_tobuffer(const dst_key_t *key, isc_buffer_t *target) { + REQUIRE(dst_initialized == ISC_TRUE); + REQUIRE(VALID_KEY(key)); + REQUIRE(target != NULL); + + CHECKALG(key->key_alg); + + if (key->func->todns == NULL) + return (DST_R_UNSUPPORTEDALG); + + return (key->func->todns(key, target)); +} + +isc_result_t +dst_key_privatefrombuffer(dst_key_t *key, isc_buffer_t *buffer) { + isc_lex_t *lex = NULL; + isc_result_t result = ISC_R_SUCCESS; + + REQUIRE(dst_initialized == ISC_TRUE); + REQUIRE(VALID_KEY(key)); + REQUIRE(!dst_key_isprivate(key)); + REQUIRE(buffer != NULL); + + if (key->func->parse == NULL) + RETERR(DST_R_UNSUPPORTEDALG); + + RETERR(isc_lex_create(key->mctx, 1500, &lex)); + RETERR(isc_lex_openbuffer(lex, buffer)); + RETERR(key->func->parse(key, lex)); + out: + if (lex != NULL) + isc_lex_destroy(&lex); + return (result); +} + +isc_result_t +dst_key_fromgssapi(dns_name_t *name, void *opaque, isc_mem_t *mctx, + dst_key_t **keyp) +{ + dst_key_t *key; + + REQUIRE(opaque != NULL); + REQUIRE(keyp != NULL && *keyp == NULL); + + key = get_key_struct(name, DST_ALG_GSSAPI, 0, DNS_KEYPROTO_DNSSEC, + 0, dns_rdataclass_in, mctx); + if (key == NULL) + return (ISC_R_NOMEMORY); + key->opaque = opaque; + *keyp = key; + return (ISC_R_SUCCESS); +} + +isc_result_t +dst_key_generate(dns_name_t *name, unsigned int alg, + unsigned int bits, unsigned int param, + unsigned int flags, unsigned int protocol, + dns_rdataclass_t rdclass, + isc_mem_t *mctx, dst_key_t **keyp) +{ + dst_key_t *key; + isc_result_t ret; + + REQUIRE(dst_initialized == ISC_TRUE); + REQUIRE(dns_name_isabsolute(name)); + REQUIRE(mctx != NULL); + REQUIRE(keyp != NULL && *keyp == NULL); + + CHECKALG(alg); + + key = get_key_struct(name, alg, flags, protocol, bits, rdclass, mctx); + if (key == NULL) + return (ISC_R_NOMEMORY); + + if (bits == 0) { /* NULL KEY */ + key->key_flags |= DNS_KEYTYPE_NOKEY; + *keyp = key; + return (ISC_R_SUCCESS); + } + + if (key->func->generate == NULL) { + dst_key_free(&key); + return (DST_R_UNSUPPORTEDALG); + } + + ret = key->func->generate(key, param); + if (ret != ISC_R_SUCCESS) { + dst_key_free(&key); + return (ret); + } + + ret = computeid(key); + if (ret != ISC_R_SUCCESS) { + dst_key_free(&key); + return (ret); + } + + *keyp = key; + return (ISC_R_SUCCESS); +} + +isc_boolean_t +dst_key_compare(const dst_key_t *key1, const dst_key_t *key2) { + REQUIRE(dst_initialized == ISC_TRUE); + REQUIRE(VALID_KEY(key1)); + REQUIRE(VALID_KEY(key2)); + + if (key1 == key2) + return (ISC_TRUE); + if (key1 == NULL || key2 == NULL) + return (ISC_FALSE); + if (key1->key_alg == key2->key_alg && + key1->key_id == key2->key_id && + key1->func->compare != NULL && + key1->func->compare(key1, key2) == ISC_TRUE) + return (ISC_TRUE); + else + return (ISC_FALSE); +} + +isc_boolean_t +dst_key_paramcompare(const dst_key_t *key1, const dst_key_t *key2) { + REQUIRE(dst_initialized == ISC_TRUE); + REQUIRE(VALID_KEY(key1)); + REQUIRE(VALID_KEY(key2)); + + if (key1 == key2) + return (ISC_TRUE); + if (key1 == NULL || key2 == NULL) + return (ISC_FALSE); + if (key1->key_alg == key2->key_alg && + key1->func->paramcompare != NULL && + key1->func->paramcompare(key1, key2) == ISC_TRUE) + return (ISC_TRUE); + else + return (ISC_FALSE); +} + +void +dst_key_free(dst_key_t **keyp) { + isc_mem_t *mctx; + dst_key_t *key; + + REQUIRE(dst_initialized == ISC_TRUE); + REQUIRE(keyp != NULL && VALID_KEY(*keyp)); + + key = *keyp; + mctx = key->mctx; + + if (key->opaque != NULL) { + INSIST(key->func->destroy != NULL); + key->func->destroy(key); + } + + dns_name_free(key->key_name, mctx); + isc_mem_put(mctx, key->key_name, sizeof(dns_name_t)); + memset(key, 0, sizeof(dst_key_t)); + isc_mem_put(mctx, key, sizeof(dst_key_t)); + *keyp = NULL; +} + +isc_boolean_t +dst_key_isprivate(const dst_key_t *key) { + REQUIRE(VALID_KEY(key)); + INSIST(key->func->isprivate != NULL); + return (key->func->isprivate(key)); +} + +isc_result_t +dst_key_buildfilename(const dst_key_t *key, int type, + const char *directory, isc_buffer_t *out) { + + REQUIRE(VALID_KEY(key)); + REQUIRE(type == DST_TYPE_PRIVATE || type == DST_TYPE_PUBLIC || + type == 0); + + return (buildfilename(key->key_name, key->key_id, key->key_alg, + type, directory, out)); +} + +isc_result_t +dst_key_sigsize(const dst_key_t *key, unsigned int *n) { + REQUIRE(dst_initialized == ISC_TRUE); + REQUIRE(VALID_KEY(key)); + REQUIRE(n != NULL); + + /* XXXVIX this switch statement is too sparse to gen a jump table. */ + switch (key->key_alg) { + case DST_ALG_RSAMD5: + case DST_ALG_RSASHA1: + *n = (key->key_size + 7) / 8; + break; + case DST_ALG_DSA: + *n = DNS_SIG_DSASIGSIZE; + break; + case DST_ALG_HMACMD5: + *n = 16; + break; + case DST_ALG_GSSAPI: + *n = 128; /* XXX */ + break; + case DST_ALG_DH: + default: + return (DST_R_UNSUPPORTEDALG); + } + return (ISC_R_SUCCESS); +} + +isc_result_t +dst_key_secretsize(const dst_key_t *key, unsigned int *n) { + REQUIRE(dst_initialized == ISC_TRUE); + REQUIRE(VALID_KEY(key)); + REQUIRE(n != NULL); + + if (key->key_alg == DST_ALG_DH) + *n = (key->key_size + 7) / 8; + else + return (DST_R_UNSUPPORTEDALG); + return (ISC_R_SUCCESS); +} + +/*** + *** Static methods + ***/ + +/* + * Allocates a key structure and fills in some of the fields. + */ +static dst_key_t * +get_key_struct(dns_name_t *name, unsigned int alg, + unsigned int flags, unsigned int protocol, + unsigned int bits, dns_rdataclass_t rdclass, + isc_mem_t *mctx) +{ + dst_key_t *key; + isc_result_t result; + + key = (dst_key_t *) isc_mem_get(mctx, sizeof(dst_key_t)); + if (key == NULL) + return (NULL); + + memset(key, 0, sizeof(dst_key_t)); + key->magic = KEY_MAGIC; + + key->key_name = isc_mem_get(mctx, sizeof(dns_name_t)); + if (key->key_name == NULL) { + isc_mem_put(mctx, key, sizeof(dst_key_t)); + return (NULL); + } + dns_name_init(key->key_name, NULL); + result = dns_name_dup(name, mctx, key->key_name); + if (result != ISC_R_SUCCESS) { + isc_mem_put(mctx, key->key_name, sizeof(dns_name_t)); + isc_mem_put(mctx, key, sizeof(dst_key_t)); + return (NULL); + } + key->key_alg = alg; + key->key_flags = flags; + key->key_proto = protocol; + key->mctx = mctx; + key->opaque = NULL; + key->key_size = bits; + key->key_class = rdclass; + key->func = dst_t_func[alg]; + return (key); +} + +/* + * Reads a public key from disk + */ +static isc_result_t +read_public_key(const char *filename, int type, + isc_mem_t *mctx, dst_key_t **keyp) +{ + u_char rdatabuf[DST_KEY_MAXSIZE]; + isc_buffer_t b; + dns_fixedname_t name; + isc_lex_t *lex = NULL; + isc_token_t token; + isc_result_t ret; + dns_rdata_t rdata = DNS_RDATA_INIT; + unsigned int opt = ISC_LEXOPT_DNSMULTILINE; + char *newfilename; + unsigned int newfilenamelen; + dns_rdataclass_t rdclass = dns_rdataclass_in; + isc_lexspecials_t specials; + isc_uint32_t ttl; + isc_result_t result; + dns_rdatatype_t keytype; + + newfilenamelen = strlen(filename) + 5; + newfilename = isc_mem_get(mctx, newfilenamelen); + if (newfilename == NULL) + return (ISC_R_NOMEMORY); + ret = addsuffix(newfilename, newfilenamelen, filename, ".key"); + INSIST(ret == ISC_R_SUCCESS); + + /* + * Open the file and read its formatted contents + * File format: + * domain.name [ttl] [class] KEY <flags> <protocol> <algorithm> <key> + */ + + /* 1500 should be large enough for any key */ + ret = isc_lex_create(mctx, 1500, &lex); + if (ret != ISC_R_SUCCESS) + goto cleanup; + + memset(specials, 0, sizeof(specials)); + specials['('] = 1; + specials[')'] = 1; + specials['"'] = 1; + isc_lex_setspecials(lex, specials); + isc_lex_setcomments(lex, ISC_LEXCOMMENT_DNSMASTERFILE); + + ret = isc_lex_openfile(lex, newfilename); + if (ret != ISC_R_SUCCESS) + goto cleanup; + +#define NEXTTOKEN(lex, opt, token) { \ + ret = isc_lex_gettoken(lex, opt, token); \ + if (ret != ISC_R_SUCCESS) \ + goto cleanup; \ + } + +#define BADTOKEN() { \ + ret = ISC_R_UNEXPECTEDTOKEN; \ + goto cleanup; \ + } + + /* Read the domain name */ + NEXTTOKEN(lex, opt, &token); + if (token.type != isc_tokentype_string) + BADTOKEN(); + dns_fixedname_init(&name); + isc_buffer_init(&b, DST_AS_STR(token), strlen(DST_AS_STR(token))); + isc_buffer_add(&b, strlen(DST_AS_STR(token))); + ret = dns_name_fromtext(dns_fixedname_name(&name), &b, dns_rootname, + ISC_FALSE, NULL); + if (ret != ISC_R_SUCCESS) + goto cleanup; + + /* Read the next word: either TTL, class, or 'KEY' */ + NEXTTOKEN(lex, opt, &token); + + /* If it's a TTL, read the next one */ + result = dns_ttl_fromtext(&token.value.as_textregion, &ttl); + if (result == ISC_R_SUCCESS) + NEXTTOKEN(lex, opt, &token); + + if (token.type != isc_tokentype_string) + BADTOKEN(); + + ret = dns_rdataclass_fromtext(&rdclass, &token.value.as_textregion); + if (ret == ISC_R_SUCCESS) + NEXTTOKEN(lex, opt, &token); + + if (token.type != isc_tokentype_string) + BADTOKEN(); + + if (strcasecmp(DST_AS_STR(token), "DNSKEY") == 0) + keytype = dns_rdatatype_dnskey; + else if (strcasecmp(DST_AS_STR(token), "KEY") == 0) + keytype = dns_rdatatype_key; /* SIG(0), TKEY */ + else + BADTOKEN(); + + if (((type & DST_TYPE_KEY) != 0 && keytype != dns_rdatatype_key) || + ((type & DST_TYPE_KEY) == 0 && keytype != dns_rdatatype_dnskey)) { + ret = DST_R_BADKEYTYPE; + goto cleanup; + } + + isc_buffer_init(&b, rdatabuf, sizeof(rdatabuf)); + ret = dns_rdata_fromtext(&rdata, rdclass, keytype, lex, NULL, + ISC_FALSE, mctx, &b, NULL); + if (ret != ISC_R_SUCCESS) + goto cleanup; + + ret = dst_key_fromdns(dns_fixedname_name(&name), rdclass, &b, mctx, + keyp); + if (ret != ISC_R_SUCCESS) + goto cleanup; + + cleanup: + if (lex != NULL) + isc_lex_destroy(&lex); + isc_mem_put(mctx, newfilename, newfilenamelen); + + return (ret); +} + +static isc_boolean_t +issymmetric(const dst_key_t *key) { + REQUIRE(dst_initialized == ISC_TRUE); + REQUIRE(VALID_KEY(key)); + + /* XXXVIX this switch statement is too sparse to gen a jump table. */ + switch (key->key_alg) { + case DST_ALG_RSAMD5: + case DST_ALG_RSASHA1: + case DST_ALG_DSA: + case DST_ALG_DH: + return (ISC_FALSE); + case DST_ALG_HMACMD5: + case DST_ALG_GSSAPI: + return (ISC_TRUE); + default: + return (ISC_FALSE); + } +} + +/* + * Writes a public key to disk in DNS format. + */ +static isc_result_t +write_public_key(const dst_key_t *key, int type, const char *directory) { + FILE *fp; + isc_buffer_t keyb, textb, fileb, classb; + isc_region_t r; + char filename[ISC_DIR_NAMEMAX]; + unsigned char key_array[DST_KEY_MAXSIZE]; + char text_array[DST_KEY_MAXTEXTSIZE]; + char class_array[10]; + isc_result_t ret; + dns_rdata_t rdata = DNS_RDATA_INIT; + isc_fsaccess_t access; + + REQUIRE(VALID_KEY(key)); + + isc_buffer_init(&keyb, key_array, sizeof(key_array)); + isc_buffer_init(&textb, text_array, sizeof(text_array)); + isc_buffer_init(&classb, class_array, sizeof(class_array)); + + ret = dst_key_todns(key, &keyb); + if (ret != ISC_R_SUCCESS) + return (ret); + + isc_buffer_usedregion(&keyb, &r); + dns_rdata_fromregion(&rdata, key->key_class, dns_rdatatype_dnskey, &r); + + ret = dns_rdata_totext(&rdata, (dns_name_t *) NULL, &textb); + if (ret != ISC_R_SUCCESS) + return (DST_R_INVALIDPUBLICKEY); + + ret = dns_rdataclass_totext(key->key_class, &classb); + if (ret != ISC_R_SUCCESS) + return (DST_R_INVALIDPUBLICKEY); + + /* + * Make the filename. + */ + isc_buffer_init(&fileb, filename, sizeof(filename)); + ret = dst_key_buildfilename(key, DST_TYPE_PUBLIC, directory, &fileb); + if (ret != ISC_R_SUCCESS) + return (ret); + + /* + * Create public key file. + */ + if ((fp = fopen(filename, "w")) == NULL) + return (DST_R_WRITEERROR); + + if (issymmetric(key)) { + access = 0; + isc_fsaccess_add(ISC_FSACCESS_OWNER, + ISC_FSACCESS_READ | ISC_FSACCESS_WRITE, + &access); + (void)isc_fsaccess_set(filename, access); + } + + ret = dns_name_print(key->key_name, fp); + if (ret != ISC_R_SUCCESS) + return (ret); + + fprintf(fp, " "); + + isc_buffer_usedregion(&classb, &r); + fwrite(r.base, 1, r.length, fp); + + if ((type & DST_TYPE_KEY) != 0) + fprintf(fp, " KEY "); + else + fprintf(fp, " DNSKEY "); + + isc_buffer_usedregion(&textb, &r); + fwrite(r.base, 1, r.length, fp); + + fputc('\n', fp); + fclose(fp); + + return (ISC_R_SUCCESS); +} + +static isc_result_t +buildfilename(dns_name_t *name, dns_keytag_t id, + unsigned int alg, unsigned int type, + const char *directory, isc_buffer_t *out) +{ + const char *suffix = ""; + unsigned int len; + isc_result_t result; + + REQUIRE(out != NULL); + if ((type & DST_TYPE_PRIVATE) != 0) + suffix = ".private"; + else if (type == DST_TYPE_PUBLIC) + suffix = ".key"; + if (directory != NULL) { + if (isc_buffer_availablelength(out) < strlen(directory)) + return (ISC_R_NOSPACE); + isc_buffer_putstr(out, directory); + if (strlen(directory) > 0U && + directory[strlen(directory) - 1] != '/') + isc_buffer_putstr(out, "/"); + } + if (isc_buffer_availablelength(out) < 1) + return (ISC_R_NOSPACE); + isc_buffer_putstr(out, "K"); + result = dns_name_tofilenametext(name, ISC_FALSE, out); + if (result != ISC_R_SUCCESS) + return (result); + len = 1 + 3 + 1 + 5 + strlen(suffix) + 1; + if (isc_buffer_availablelength(out) < len) + return (ISC_R_NOSPACE); + sprintf((char *) isc_buffer_used(out), "+%03d+%05d%s", alg, id, suffix); + isc_buffer_add(out, len); + return (ISC_R_SUCCESS); +} + +static isc_result_t +computeid(dst_key_t *key) { + isc_buffer_t dnsbuf; + unsigned char dns_array[DST_KEY_MAXSIZE]; + isc_region_t r; + isc_result_t ret; + + isc_buffer_init(&dnsbuf, dns_array, sizeof(dns_array)); + ret = dst_key_todns(key, &dnsbuf); + if (ret != ISC_R_SUCCESS) + return (ret); + + isc_buffer_usedregion(&dnsbuf, &r); + key->key_id = dst_region_computeid(&r, key->key_alg); + return (ISC_R_SUCCESS); +} + +static isc_result_t +frombuffer(dns_name_t *name, unsigned int alg, unsigned int flags, + unsigned int protocol, dns_rdataclass_t rdclass, + isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) +{ + dst_key_t *key; + isc_result_t ret; + + REQUIRE(dns_name_isabsolute(name)); + REQUIRE(source != NULL); + REQUIRE(mctx != NULL); + REQUIRE(keyp != NULL && *keyp == NULL); + + key = get_key_struct(name, alg, flags, protocol, 0, rdclass, mctx); + if (key == NULL) + return (ISC_R_NOMEMORY); + + if (isc_buffer_remaininglength(source) > 0) { + ret = algorithm_status(alg); + if (ret != ISC_R_SUCCESS) { + dst_key_free(&key); + return (ret); + } + if (key->func->fromdns == NULL) { + dst_key_free(&key); + return (DST_R_UNSUPPORTEDALG); + } + + ret = key->func->fromdns(key, source); + if (ret != ISC_R_SUCCESS) { + dst_key_free(&key); + return (ret); + } + } + + *keyp = key; + return (ISC_R_SUCCESS); +} + +static isc_result_t +algorithm_status(unsigned int alg) { + REQUIRE(dst_initialized == ISC_TRUE); + + if (dst_algorithm_supported(alg)) + return (ISC_R_SUCCESS); +#ifndef OPENSSL + if (alg == DST_ALG_RSAMD5 || alg == DST_ALG_RSASHA1 || + alg == DST_ALG_DSA || alg == DST_ALG_DH || + alg == DST_ALG_HMACMD5) + return (DST_R_NOCRYPTO); +#endif + return (DST_R_UNSUPPORTEDALG); +} + +static isc_result_t +addsuffix(char *filename, unsigned int len, const char *ofilename, + const char *suffix) +{ + int olen = strlen(ofilename); + int n; + + if (olen > 1 && ofilename[olen - 1] == '.') + olen -= 1; + else if (olen > 8 && strcmp(ofilename + olen - 8, ".private") == 0) + olen -= 8; + else if (olen > 4 && strcmp(ofilename + olen - 4, ".key") == 0) + olen -= 4; + + n = snprintf(filename, len, "%.*s%s", olen, ofilename, suffix); + if (n < 0) + return (ISC_R_NOSPACE); + return (ISC_R_SUCCESS); +} + +isc_result_t +dst__entropy_getdata(void *buf, unsigned int len, isc_boolean_t pseudo) { + unsigned int flags = dst_entropy_flags; + if (pseudo) + flags &= ~ISC_ENTROPY_GOODONLY; + return (isc_entropy_getdata(dst_entropy_pool, buf, len, NULL, flags)); +} diff --git a/contrib/bind9/lib/dns/dst_internal.h b/contrib/bind9/lib/dns/dst_internal.h new file mode 100644 index 000000000000..982eb6d22958 --- /dev/null +++ b/contrib/bind9/lib/dns/dst_internal.h @@ -0,0 +1,134 @@ +/* + * Portions Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 2000-2002 Internet Software Consortium. + * Portions Copyright (C) 1995-2000 by Network Associates, Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE + * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* $Id: dst_internal.h,v 1.1.4.1 2004/12/09 04:07:16 marka Exp $ */ + +#ifndef DST_DST_INTERNAL_H +#define DST_DST_INTERNAL_H 1 + +#include <isc/lang.h> +#include <isc/buffer.h> +#include <isc/int.h> +#include <isc/magic.h> +#include <isc/region.h> +#include <isc/types.h> + +#include <dst/dst.h> + +ISC_LANG_BEGINDECLS + +#define KEY_MAGIC ISC_MAGIC('D','S','T','K') +#define CTX_MAGIC ISC_MAGIC('D','S','T','C') + +#define VALID_KEY(x) ISC_MAGIC_VALID(x, KEY_MAGIC) +#define VALID_CTX(x) ISC_MAGIC_VALID(x, CTX_MAGIC) + +extern isc_mem_t *dst__memory_pool; + +/*** + *** Types + ***/ + +typedef struct dst_func dst_func_t; + +struct dst_key { + unsigned int magic; + dns_name_t * key_name; /* name of the key */ + unsigned int key_size; /* size of the key in bits */ + unsigned int key_proto; /* protocols this key is used for */ + unsigned int key_alg; /* algorithm of the key */ + isc_uint32_t key_flags; /* flags of the public key */ + isc_uint16_t key_id; /* identifier of the key */ + dns_rdataclass_t key_class; /* class of the key record */ + isc_mem_t *mctx; /* memory context */ + void * opaque; /* pointer to key in crypto pkg fmt */ + dst_func_t * func; /* crypto package specific functions */ +}; + +struct dst_context { + unsigned int magic; + dst_key_t *key; + isc_mem_t *mctx; + void *opaque; +}; + +struct dst_func { + /* + * Context functions + */ + isc_result_t (*createctx)(dst_key_t *key, dst_context_t *dctx); + void (*destroyctx)(dst_context_t *dctx); + isc_result_t (*adddata)(dst_context_t *dctx, const isc_region_t *data); + + /* + * Key operations + */ + isc_result_t (*sign)(dst_context_t *dctx, isc_buffer_t *sig); + isc_result_t (*verify)(dst_context_t *dctx, const isc_region_t *sig); + isc_result_t (*computesecret)(const dst_key_t *pub, + const dst_key_t *priv, + isc_buffer_t *secret); + isc_boolean_t (*compare)(const dst_key_t *key1, const dst_key_t *key2); + isc_boolean_t (*paramcompare)(const dst_key_t *key1, + const dst_key_t *key2); + isc_result_t (*generate)(dst_key_t *key, int parms); + isc_boolean_t (*isprivate)(const dst_key_t *key); + void (*destroy)(dst_key_t *key); + + /* conversion functions */ + isc_result_t (*todns)(const dst_key_t *key, isc_buffer_t *data); + isc_result_t (*fromdns)(dst_key_t *key, isc_buffer_t *data); + isc_result_t (*tofile)(const dst_key_t *key, const char *directory); + isc_result_t (*parse)(dst_key_t *key, isc_lex_t *lexer); + + /* cleanup */ + void (*cleanup)(void); +}; + +/* + * Initializers + */ +isc_result_t dst__openssl_init(void); + +isc_result_t dst__hmacmd5_init(struct dst_func **funcp); +isc_result_t dst__opensslrsa_init(struct dst_func **funcp); +isc_result_t dst__openssldsa_init(struct dst_func **funcp); +isc_result_t dst__openssldh_init(struct dst_func **funcp); +isc_result_t dst__gssapi_init(struct dst_func **funcp); + +/* + * Destructors + */ +void dst__openssl_destroy(void); + +/* + * Memory allocators using the DST memory pool. + */ +void * dst__mem_alloc(size_t size); +void dst__mem_free(void *ptr); +void * dst__mem_realloc(void *ptr, size_t size); + +/* + * Entropy retriever using the DST entropy pool. + */ +isc_result_t dst__entropy_getdata(void *buf, unsigned int len, + isc_boolean_t pseudo); + +ISC_LANG_ENDDECLS + +#endif /* DST_DST_INTERNAL_H */ diff --git a/contrib/bind9/lib/dns/dst_lib.c b/contrib/bind9/lib/dns/dst_lib.c new file mode 100644 index 000000000000..804611043524 --- /dev/null +++ b/contrib/bind9/lib/dns/dst_lib.c @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Principal Author: Brian Wellington + * $Id: dst_lib.c,v 1.1.4.1 2004/12/09 04:07:16 marka Exp $ + */ + +#include <config.h> + +#include <stddef.h> + +#include <isc/once.h> +#include <isc/msgcat.h> +#include <isc/util.h> + +#include <dst/lib.h> + +/*** + *** Globals + ***/ + +LIBDNS_EXTERNAL_DATA isc_msgcat_t * dst_msgcat = NULL; + + +/*** + *** Private + ***/ + +static isc_once_t msgcat_once = ISC_ONCE_INIT; + + +/*** + *** Functions + ***/ + +static void +open_msgcat(void) { + isc_msgcat_open("libdst.cat", &dst_msgcat); +} + +void +dst_lib_initmsgcat(void) { + + /* + * Initialize the DST library's message catalog, dst_msgcat, if it + * has not already been initialized. + */ + + RUNTIME_CHECK(isc_once_do(&msgcat_once, open_msgcat) == ISC_R_SUCCESS); +} diff --git a/contrib/bind9/lib/dns/dst_openssl.h b/contrib/bind9/lib/dns/dst_openssl.h new file mode 100644 index 000000000000..8dbc35073b52 --- /dev/null +++ b/contrib/bind9/lib/dns/dst_openssl.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* $Id: dst_openssl.h,v 1.1.2.1 2004/12/09 04:07:17 marka Exp $ */ + +#ifndef DST_OPENSSL_H +#define DST_OPENSSL_H 1 + +#include <isc/lang.h> +#include <isc/result.h> + +ISC_LANG_BEGINDECLS + +isc_result_t +dst__openssl_toresult(isc_result_t fallback); + +ISC_LANG_ENDDECLS + +#endif /* DST_OPENSSL_H */ diff --git a/contrib/bind9/lib/dns/dst_parse.c b/contrib/bind9/lib/dns/dst_parse.c new file mode 100644 index 000000000000..d34aeca9b516 --- /dev/null +++ b/contrib/bind9/lib/dns/dst_parse.c @@ -0,0 +1,412 @@ +/* + * Portions Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 1999-2002 Internet Software Consortium. + * Portions Copyright (C) 1995-2000 by Network Associates, Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE + * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Principal Author: Brian Wellington + * $Id: dst_parse.c,v 1.1.4.1 2004/12/09 04:07:17 marka Exp $ + */ + +#include <config.h> + +#include <isc/base64.h> +#include <isc/dir.h> +#include <isc/fsaccess.h> +#include <isc/lex.h> +#include <isc/mem.h> +#include <isc/string.h> +#include <isc/util.h> + +#include "dst_internal.h" +#include "dst_parse.h" +#include "dst/result.h" + +#define DST_AS_STR(t) ((t).value.as_textregion.base) + +#define PRIVATE_KEY_STR "Private-key-format:" +#define ALGORITHM_STR "Algorithm:" + +struct parse_map { + const int value; + const char *tag; +}; + +static struct parse_map map[] = { + {TAG_RSA_MODULUS, "Modulus:"}, + {TAG_RSA_PUBLICEXPONENT, "PublicExponent:"}, + {TAG_RSA_PRIVATEEXPONENT, "PrivateExponent:"}, + {TAG_RSA_PRIME1, "Prime1:"}, + {TAG_RSA_PRIME2, "Prime2:"}, + {TAG_RSA_EXPONENT1, "Exponent1:"}, + {TAG_RSA_EXPONENT2, "Exponent2:"}, + {TAG_RSA_COEFFICIENT, "Coefficient:"}, + + {TAG_DH_PRIME, "Prime(p):"}, + {TAG_DH_GENERATOR, "Generator(g):"}, + {TAG_DH_PRIVATE, "Private_value(x):"}, + {TAG_DH_PUBLIC, "Public_value(y):"}, + + {TAG_DSA_PRIME, "Prime(p):"}, + {TAG_DSA_SUBPRIME, "Subprime(q):"}, + {TAG_DSA_BASE, "Base(g):"}, + {TAG_DSA_PRIVATE, "Private_value(x):"}, + {TAG_DSA_PUBLIC, "Public_value(y):"}, + + {TAG_HMACMD5_KEY, "Key:"}, + {0, NULL} +}; + +static int +find_value(const char *s, const unsigned int alg) { + int i; + + for (i = 0; ; i++) { + if (map[i].tag == NULL) + return (-1); + else if (strcasecmp(s, map[i].tag) == 0 && + TAG_ALG(map[i].value) == alg) + return (map[i].value); + } +} + +static const char * +find_tag(const int value) { + int i; + + for (i = 0; ; i++) { + if (map[i].tag == NULL) + return (NULL); + else if (value == map[i].value) + return (map[i].tag); + } +} + +static int +check_rsa(const dst_private_t *priv) { + int i, j; + if (priv->nelements != RSA_NTAGS) + return (-1); + for (i = 0; i < RSA_NTAGS; i++) { + for (j = 0; j < priv->nelements; j++) + if (priv->elements[j].tag == TAG(DST_ALG_RSAMD5, i)) + break; + if (j == priv->nelements) + return (-1); + } + return (0); +} + +static int +check_dh(const dst_private_t *priv) { + int i, j; + if (priv->nelements != DH_NTAGS) + return (-1); + for (i = 0; i < DH_NTAGS; i++) { + for (j = 0; j < priv->nelements; j++) + if (priv->elements[j].tag == TAG(DST_ALG_DH, i)) + break; + if (j == priv->nelements) + return (-1); + } + return (0); +} + +static int +check_dsa(const dst_private_t *priv) { + int i, j; + if (priv->nelements != DSA_NTAGS) + return (-1); + for (i = 0; i < DSA_NTAGS; i++) { + for (j = 0; j < priv->nelements; j++) + if (priv->elements[j].tag == TAG(DST_ALG_DSA, i)) + break; + if (j == priv->nelements) + return (-1); + } + return (0); +} + +static int +check_hmac_md5(const dst_private_t *priv) { + if (priv->nelements != HMACMD5_NTAGS) + return (-1); + if (priv->elements[0].tag != TAG_HMACMD5_KEY) + return (-1); + return (0); +} + +static int +check_data(const dst_private_t *priv, const unsigned int alg) { + /* XXXVIX this switch statement is too sparse to gen a jump table. */ + switch (alg) { + case DST_ALG_RSAMD5: + case DST_ALG_RSASHA1: + return (check_rsa(priv)); + case DST_ALG_DH: + return (check_dh(priv)); + case DST_ALG_DSA: + return (check_dsa(priv)); + case DST_ALG_HMACMD5: + return (check_hmac_md5(priv)); + default: + return (DST_R_UNSUPPORTEDALG); + } +} + +void +dst__privstruct_free(dst_private_t *priv, isc_mem_t *mctx) { + int i; + + if (priv == NULL) + return; + for (i = 0; i < priv->nelements; i++) { + if (priv->elements[i].data == NULL) + continue; + memset(priv->elements[i].data, 0, MAXFIELDSIZE); + isc_mem_put(mctx, priv->elements[i].data, MAXFIELDSIZE); + } + priv->nelements = 0; +} + +int +dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex, + isc_mem_t *mctx, dst_private_t *priv) +{ + int n = 0, major, minor; + isc_buffer_t b; + isc_token_t token; + unsigned char *data = NULL; + unsigned int opt = ISC_LEXOPT_EOL; + isc_result_t ret; + + REQUIRE(priv != NULL); + + priv->nelements = 0; + +#define NEXTTOKEN(lex, opt, token) \ + do { \ + ret = isc_lex_gettoken(lex, opt, token); \ + if (ret != ISC_R_SUCCESS) \ + goto fail; \ + } while (0) + +#define READLINE(lex, opt, token) \ + do { \ + ret = isc_lex_gettoken(lex, opt, token); \ + if (ret == ISC_R_EOF) \ + break; \ + else if (ret != ISC_R_SUCCESS) \ + goto fail; \ + } while ((*token).type != isc_tokentype_eol) + + /* + * Read the description line. + */ + NEXTTOKEN(lex, opt, &token); + if (token.type != isc_tokentype_string || + strcmp(DST_AS_STR(token), PRIVATE_KEY_STR) != 0) + { + ret = DST_R_INVALIDPRIVATEKEY; + goto fail; + } + + NEXTTOKEN(lex, opt, &token); + if (token.type != isc_tokentype_string || + (DST_AS_STR(token))[0] != 'v') + { + ret = DST_R_INVALIDPRIVATEKEY; + goto fail; + } + if (sscanf(DST_AS_STR(token), "v%d.%d", &major, &minor) != 2) + { + ret = DST_R_INVALIDPRIVATEKEY; + goto fail; + } + + if (major > MAJOR_VERSION || + (major == MAJOR_VERSION && minor > MINOR_VERSION)) + { + ret = DST_R_INVALIDPRIVATEKEY; + goto fail; + } + + READLINE(lex, opt, &token); + + /* + * Read the algorithm line. + */ + NEXTTOKEN(lex, opt, &token); + if (token.type != isc_tokentype_string || + strcmp(DST_AS_STR(token), ALGORITHM_STR) != 0) + { + ret = DST_R_INVALIDPRIVATEKEY; + goto fail; + } + + NEXTTOKEN(lex, opt | ISC_LEXOPT_NUMBER, &token); + if (token.type != isc_tokentype_number || + token.value.as_ulong != (unsigned long) dst_key_alg(key)) + { + ret = DST_R_INVALIDPRIVATEKEY; + goto fail; + } + + READLINE(lex, opt, &token); + + /* + * Read the key data. + */ + for (n = 0; n < MAXFIELDS; n++) { + int tag; + isc_region_t r; + + do { + ret = isc_lex_gettoken(lex, opt, &token); + if (ret == ISC_R_EOF) + goto done; + if (ret != ISC_R_SUCCESS) + goto fail; + } while (token.type == isc_tokentype_eol); + + if (token.type != isc_tokentype_string) { + ret = DST_R_INVALIDPRIVATEKEY; + goto fail; + } + + memset(&priv->elements[n], 0, sizeof(dst_private_element_t)); + tag = find_value(DST_AS_STR(token), alg); + if (tag < 0 || TAG_ALG(tag) != alg) { + ret = DST_R_INVALIDPRIVATEKEY; + goto fail; + } + priv->elements[n].tag = tag; + + data = (unsigned char *) isc_mem_get(mctx, MAXFIELDSIZE); + if (data == NULL) + goto fail; + + isc_buffer_init(&b, data, MAXFIELDSIZE); + ret = isc_base64_tobuffer(lex, &b, -1); + if (ret != ISC_R_SUCCESS) + goto fail; + isc_buffer_usedregion(&b, &r); + priv->elements[n].length = r.length; + priv->elements[n].data = r.base; + + READLINE(lex, opt, &token); + data = NULL; + } + done: + priv->nelements = n; + + if (check_data(priv, alg) < 0) + goto fail; + + return (ISC_R_SUCCESS); + +fail: + priv->nelements = n; + dst__privstruct_free(priv, mctx); + if (data != NULL) + isc_mem_put(mctx, data, MAXFIELDSIZE); + + return (ret); +} + +int +dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv, + const char *directory) +{ + FILE *fp; + int ret, i; + isc_result_t iret; + char filename[ISC_DIR_NAMEMAX]; + char buffer[MAXFIELDSIZE * 2]; + isc_buffer_t b; + isc_fsaccess_t access; + + REQUIRE(priv != NULL); + + if (check_data(priv, dst_key_alg(key)) < 0) + return (DST_R_INVALIDPRIVATEKEY); + + isc_buffer_init(&b, filename, sizeof(filename)); + ret = dst_key_buildfilename(key, DST_TYPE_PRIVATE, directory, &b); + if (ret != ISC_R_SUCCESS) + return (ret); + + if ((fp = fopen(filename, "w")) == NULL) + return (DST_R_WRITEERROR); + + access = 0; + isc_fsaccess_add(ISC_FSACCESS_OWNER, + ISC_FSACCESS_READ | ISC_FSACCESS_WRITE, + &access); + (void)isc_fsaccess_set(filename, access); + + /* XXXDCL return value should be checked for full filesystem */ + fprintf(fp, "%s v%d.%d\n", PRIVATE_KEY_STR, MAJOR_VERSION, + MINOR_VERSION); + + fprintf(fp, "%s %d ", ALGORITHM_STR, dst_key_alg(key)); + /* XXXVIX this switch statement is too sparse to gen a jump table. */ + switch (dst_key_alg(key)) { + case DST_ALG_RSAMD5: + fprintf(fp, "(RSA)\n"); + break; + case DST_ALG_DH: + fprintf(fp, "(DH)\n"); + break; + case DST_ALG_DSA: + fprintf(fp, "(DSA)\n"); + break; + case DST_ALG_RSASHA1: + fprintf(fp, "(RSASHA1)\n"); + break; + case DST_ALG_HMACMD5: + fprintf(fp, "(HMAC_MD5)\n"); + break; + default: + fprintf(fp, "(?)\n"); + break; + } + + for (i = 0; i < priv->nelements; i++) { + isc_buffer_t b; + isc_region_t r; + const char *s; + + s = find_tag(priv->elements[i].tag); + + r.base = priv->elements[i].data; + r.length = priv->elements[i].length; + isc_buffer_init(&b, buffer, sizeof(buffer)); + iret = isc_base64_totext(&r, sizeof(buffer), "", &b); + if (iret != ISC_R_SUCCESS) { + fclose(fp); + return (DST_R_INVALIDPRIVATEKEY); + } + isc_buffer_usedregion(&b, &r); + + fprintf(fp, "%s ", s); + fwrite(r.base, 1, r.length, fp); + fprintf(fp, "\n"); + } + + fclose(fp); + return (ISC_R_SUCCESS); +} diff --git a/contrib/bind9/lib/dns/dst_parse.h b/contrib/bind9/lib/dns/dst_parse.h new file mode 100644 index 000000000000..9ecef4f7b646 --- /dev/null +++ b/contrib/bind9/lib/dns/dst_parse.h @@ -0,0 +1,95 @@ +/* + * Portions Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 2000-2002 Internet Software Consortium. + * Portions Copyright (C) 1995-2000 by Network Associates, Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE + * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* $Id: dst_parse.h,v 1.1.4.1 2004/12/09 04:07:17 marka Exp $ */ + +#ifndef DST_DST_PARSE_H +#define DST_DST_PARSE_H 1 + +#include <isc/lang.h> + +#include <dst/dst.h> + +#define MAJOR_VERSION 1 +#define MINOR_VERSION 2 + +#define MAXFIELDSIZE 512 +#define MAXFIELDS 12 + +#define TAG_SHIFT 4 +#define TAG_ALG(tag) ((unsigned int)(tag) >> TAG_SHIFT) +#define TAG(alg, off) (((alg) << TAG_SHIFT) + (off)) + +/* These are used by both RSA-MD5 and RSA-SHA1 */ +#define RSA_NTAGS 8 +#define TAG_RSA_MODULUS ((DST_ALG_RSAMD5 << TAG_SHIFT) + 0) +#define TAG_RSA_PUBLICEXPONENT ((DST_ALG_RSAMD5 << TAG_SHIFT) + 1) +#define TAG_RSA_PRIVATEEXPONENT ((DST_ALG_RSAMD5 << TAG_SHIFT) + 2) +#define TAG_RSA_PRIME1 ((DST_ALG_RSAMD5 << TAG_SHIFT) + 3) +#define TAG_RSA_PRIME2 ((DST_ALG_RSAMD5 << TAG_SHIFT) + 4) +#define TAG_RSA_EXPONENT1 ((DST_ALG_RSAMD5 << TAG_SHIFT) + 5) +#define TAG_RSA_EXPONENT2 ((DST_ALG_RSAMD5 << TAG_SHIFT) + 6) +#define TAG_RSA_COEFFICIENT ((DST_ALG_RSAMD5 << TAG_SHIFT) + 7) + +#define DH_NTAGS 4 +#define TAG_DH_PRIME ((DST_ALG_DH << TAG_SHIFT) + 0) +#define TAG_DH_GENERATOR ((DST_ALG_DH << TAG_SHIFT) + 1) +#define TAG_DH_PRIVATE ((DST_ALG_DH << TAG_SHIFT) + 2) +#define TAG_DH_PUBLIC ((DST_ALG_DH << TAG_SHIFT) + 3) + +#define DSA_NTAGS 5 +#define TAG_DSA_PRIME ((DST_ALG_DSA << TAG_SHIFT) + 0) +#define TAG_DSA_SUBPRIME ((DST_ALG_DSA << TAG_SHIFT) + 1) +#define TAG_DSA_BASE ((DST_ALG_DSA << TAG_SHIFT) + 2) +#define TAG_DSA_PRIVATE ((DST_ALG_DSA << TAG_SHIFT) + 3) +#define TAG_DSA_PUBLIC ((DST_ALG_DSA << TAG_SHIFT) + 4) + +#define HMACMD5_NTAGS 1 +#define TAG_HMACMD5_KEY ((DST_ALG_HMACMD5 << TAG_SHIFT) + 0) + +struct dst_private_element { + unsigned short tag; + unsigned short length; + unsigned char *data; +}; + +typedef struct dst_private_element dst_private_element_t; + +struct dst_private { + unsigned short nelements; + dst_private_element_t elements[MAXFIELDS]; +}; + +typedef struct dst_private dst_private_t; + +ISC_LANG_BEGINDECLS + +void +dst__privstruct_free(dst_private_t *priv, isc_mem_t *mctx); + +int +dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex, + isc_mem_t *mctx, dst_private_t *priv); + +int +dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv, + const char *directory); + +ISC_LANG_ENDDECLS + +#endif /* DST_DST_PARSE_H */ diff --git a/contrib/bind9/lib/dns/dst_result.c b/contrib/bind9/lib/dns/dst_result.c new file mode 100644 index 000000000000..9b1536c3cc4e --- /dev/null +++ b/contrib/bind9/lib/dns/dst_result.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Principal Author: Brian Wellington + * $Id: dst_result.c,v 1.1.4.1 2004/12/09 04:07:17 marka Exp $ + */ + +#include <config.h> + +#include <isc/once.h> +#include <isc/util.h> + +#include <dst/result.h> +#include <dst/lib.h> + +static const char *text[DST_R_NRESULTS] = { + "algorithm is unsupported", /* 0 */ + "openssl failure", /* 1 */ + "built with no crypto support", /* 2 */ + "illegal operation for a null key", /* 3 */ + "public key is invalid", /* 4 */ + "private key is invalid", /* 5 */ + "UNUSED6", /* 6 */ + "error occurred writing key to disk", /* 7 */ + "invalid algorithm specific parameter", /* 8 */ + "UNUSED9", /* 9 */ + "UNUSED10", /* 10 */ + "sign failure", /* 11 */ + "UNUSED12", /* 12 */ + "UNUSED13", /* 13 */ + "verify failure", /* 14 */ + "not a public key", /* 15 */ + "not a private key", /* 16 */ + "not a key that can compute a secret", /* 17 */ + "failure computing a shared secret", /* 18 */ + "no randomness available", /* 19 */ + "bad key type" /* 20 */ +}; + +#define DST_RESULT_RESULTSET 2 + +static isc_once_t once = ISC_ONCE_INIT; + +static void +initialize_action(void) { + isc_result_t result; + + result = isc_result_register(ISC_RESULTCLASS_DST, DST_R_NRESULTS, + text, dst_msgcat, DST_RESULT_RESULTSET); + if (result != ISC_R_SUCCESS) + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_result_register() failed: %u", result); +} + +static void +initialize(void) { + dst_lib_initmsgcat(); + RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); +} + +const char * +dst_result_totext(isc_result_t result) { + initialize(); + + return (isc_result_totext(result)); +} + +void +dst_result_register(void) { + initialize(); +} diff --git a/contrib/bind9/lib/dns/gssapi_link.c b/contrib/bind9/lib/dns/gssapi_link.c new file mode 100644 index 000000000000..0a2e848a5894 --- /dev/null +++ b/contrib/bind9/lib/dns/gssapi_link.c @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000-2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * $Id: gssapi_link.c,v 1.1.4.1 2004/12/09 04:07:17 marka Exp $ + */ + +#ifdef GSSAPI + +#include <config.h> + +#include <isc/buffer.h> +#include <isc/mem.h> +#include <isc/string.h> +#include <isc/util.h> + +#include <dst/result.h> + +#include "dst_internal.h" +#include "dst_parse.h" + +#include <gssapi/gssapi.h> + +#define INITIAL_BUFFER_SIZE 1024 +#define BUFFER_EXTRA 1024 + +#define REGION_TO_GBUFFER(r, gb) \ + do { \ + (gb).length = (r).length; \ + (gb).value = (r).base; \ + } while (0) + +typedef struct gssapi_ctx { + isc_buffer_t *buffer; + gss_ctx_id_t *context_id; +} gssapi_ctx_t; + + +static isc_result_t +gssapi_createctx(dst_key_t *key, dst_context_t *dctx) { + gssapi_ctx_t *ctx; + isc_result_t result; + + UNUSED(key); + + ctx = isc_mem_get(dctx->mctx, sizeof(gssapi_ctx_t)); + if (ctx == NULL) + return (ISC_R_NOMEMORY); + ctx->buffer = NULL; + result = isc_buffer_allocate(dctx->mctx, &ctx->buffer, + INITIAL_BUFFER_SIZE); + if (result != ISC_R_SUCCESS) { + isc_mem_put(dctx->mctx, ctx, sizeof(gssapi_ctx_t)); + return (result); + } + ctx->context_id = key->opaque; + dctx->opaque = ctx; + return (ISC_R_SUCCESS); +} + +static void +gssapi_destroyctx(dst_context_t *dctx) { + gssapi_ctx_t *ctx = dctx->opaque; + + if (ctx != NULL) { + if (ctx->buffer != NULL) + isc_buffer_free(&ctx->buffer); + isc_mem_put(dctx->mctx, ctx, sizeof(gssapi_ctx_t)); + dctx->opaque = NULL; + } +} + +static isc_result_t +gssapi_adddata(dst_context_t *dctx, const isc_region_t *data) { + gssapi_ctx_t *ctx = dctx->opaque; + isc_buffer_t *newbuffer = NULL; + isc_region_t r; + unsigned int length; + isc_result_t result; + + result = isc_buffer_copyregion(ctx->buffer, data); + if (result == ISC_R_SUCCESS) + return (ISC_R_SUCCESS); + + length = isc_buffer_length(ctx->buffer) + data->length + BUFFER_EXTRA; + + result = isc_buffer_allocate(dctx->mctx, &newbuffer, length); + if (result != ISC_R_SUCCESS) + return (result); + + isc_buffer_usedregion(ctx->buffer, &r); + (void) isc_buffer_copyregion(newbuffer, &r); + (void) isc_buffer_copyregion(newbuffer, data); + + isc_buffer_free(&ctx->buffer); + ctx->buffer = newbuffer; + + return (ISC_R_SUCCESS); +} + +static isc_result_t +gssapi_sign(dst_context_t *dctx, isc_buffer_t *sig) { + gssapi_ctx_t *ctx = dctx->opaque; + isc_region_t message; + gss_buffer_desc gmessage, gsig; + OM_uint32 minor, gret; + + isc_buffer_usedregion(ctx->buffer, &message); + REGION_TO_GBUFFER(message, gmessage); + + gret = gss_get_mic(&minor, ctx->context_id, + GSS_C_QOP_DEFAULT, &gmessage, &gsig); + if (gret != 0) + return (ISC_R_FAILURE); + + if (gsig.length > isc_buffer_availablelength(sig)) { + gss_release_buffer(&minor, &gsig); + return (ISC_R_NOSPACE); + } + + isc_buffer_putmem(sig, gsig.value, gsig.length); + + gss_release_buffer(&minor, &gsig); + + return (ISC_R_SUCCESS); +} + +static isc_result_t +gssapi_verify(dst_context_t *dctx, const isc_region_t *sig) { + gssapi_ctx_t *ctx = dctx->opaque; + isc_region_t message; + gss_buffer_desc gmessage, gsig; + OM_uint32 minor, gret; + + isc_buffer_usedregion(ctx->buffer, &message); + REGION_TO_GBUFFER(message, gmessage); + + REGION_TO_GBUFFER(*sig, gsig); + + gret = gss_verify_mic(&minor, ctx->context_id, &gmessage, &gsig, NULL); + if (gret != 0) + return (ISC_R_FAILURE); + + return (ISC_R_SUCCESS); +} + +static isc_boolean_t +gssapi_compare(const dst_key_t *key1, const dst_key_t *key2) { + gss_ctx_id_t gsskey1 = key1->opaque; + gss_ctx_id_t gsskey2 = key2->opaque; + + /* No idea */ + return (ISC_TF(gsskey1 == gsskey2)); +} + +static isc_result_t +gssapi_generate(dst_key_t *key, int unused) { + UNUSED(key); + UNUSED(unused); + + /* No idea */ + return (ISC_R_FAILURE); +} + +static isc_boolean_t +gssapi_isprivate(const dst_key_t *key) { + UNUSED(key); + return (ISC_TRUE); +} + +static void +gssapi_destroy(dst_key_t *key) { + UNUSED(key); + /* No idea */ +} + +static dst_func_t gssapi_functions = { + gssapi_createctx, + gssapi_destroyctx, + gssapi_adddata, + gssapi_sign, + gssapi_verify, + NULL, /* computesecret */ + gssapi_compare, + NULL, /* paramcompare */ + gssapi_generate, + gssapi_isprivate, + gssapi_destroy, + NULL, /* todns */ + NULL, /* fromdns */ + NULL, /* tofile */ + NULL, /* parse */ + NULL, /* cleanup */ +}; + +isc_result_t +dst__gssapi_init(dst_func_t **funcp) { + REQUIRE(funcp != NULL); + if (*funcp == NULL) + *funcp = &gssapi_functions; + return (ISC_R_SUCCESS); +} + +#else +int gssapi_link_unneeded = 1; +#endif diff --git a/contrib/bind9/lib/dns/gssapictx.c b/contrib/bind9/lib/dns/gssapictx.c new file mode 100644 index 000000000000..2605a7a051ad --- /dev/null +++ b/contrib/bind9/lib/dns/gssapictx.c @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* $Id: gssapictx.c,v 1.1.4.1 2004/12/09 04:07:17 marka Exp $ */ + +#include <config.h> + +#include <stdlib.h> + +#include <isc/buffer.h> +#include <isc/dir.h> +#include <isc/entropy.h> +#include <isc/lex.h> +#include <isc/mem.h> +#include <isc/once.h> +#include <isc/random.h> +#include <isc/string.h> +#include <isc/time.h> +#include <isc/util.h> + +#include <dns/fixedname.h> +#include <dns/name.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> +#include <dns/result.h> +#include <dns/types.h> +#include <dns/keyvalues.h> + +#include <dst/gssapi.h> +#include <dst/result.h> + +#include "dst_internal.h" + +#ifdef GSSAPI + +#include <gssapi/gssapi.h> + +#define RETERR(x) do { \ + result = (x); \ + if (result != ISC_R_SUCCESS) \ + goto out; \ + } while (0) + +#define REGION_TO_GBUFFER(r, gb) \ + do { \ + (gb).length = (r).length; \ + (gb).value = (r).base; \ + } while (0) + +#define GBUFFER_TO_REGION(gb, r) \ + do { \ + (r).length = (gb).length; \ + (r).base = (gb).value; \ + } while (0) + +static inline void +name_to_gbuffer(dns_name_t *name, isc_buffer_t *buffer, + gss_buffer_desc *gbuffer) +{ + dns_name_t tname, *namep; + isc_region_t r; + isc_result_t result; + + if (!dns_name_isabsolute(name)) + namep = name; + else { + unsigned int labels; + dns_name_init(&tname, NULL); + labels = dns_name_countlabels(name); + dns_name_getlabelsequence(name, 0, labels - 1, &tname); + namep = &tname; + } + + result = dns_name_totext(namep, ISC_FALSE, buffer); + isc_buffer_putuint8(buffer, 0); + isc_buffer_usedregion(buffer, &r); + REGION_TO_GBUFFER(r, *gbuffer); +} + +isc_result_t +dst_gssapi_acquirecred(dns_name_t *name, isc_boolean_t initiate, void **cred) { + isc_buffer_t namebuf; + gss_name_t gname; + gss_buffer_desc gnamebuf; + unsigned char array[DNS_NAME_MAXTEXT + 1]; + OM_uint32 gret, minor; + gss_OID_set mechs; + OM_uint32 lifetime; + gss_cred_usage_t usage; + + REQUIRE(cred != NULL && *cred == NULL); + + if (name != NULL) { + isc_buffer_init(&namebuf, array, sizeof(array)); + name_to_gbuffer(name, &namebuf, &gnamebuf); + gret = gss_import_name(&minor, &gnamebuf, GSS_C_NO_OID, + &gname); + if (gret != GSS_S_COMPLETE) + return (ISC_R_FAILURE); + } else + gname = NULL; + + if (initiate) + usage = GSS_C_INITIATE; + else + usage = GSS_C_ACCEPT; + + gret = gss_acquire_cred(&minor, gname, GSS_C_INDEFINITE, + GSS_C_NO_OID_SET, usage, + cred, &mechs, &lifetime); + if (gret != GSS_S_COMPLETE) + return (ISC_R_FAILURE); + return (ISC_R_SUCCESS); +} + +isc_result_t +dst_gssapi_initctx(dns_name_t *name, void *cred, + isc_region_t *intoken, isc_buffer_t *outtoken, + void **context) +{ + isc_region_t r; + isc_buffer_t namebuf; + gss_buffer_desc gnamebuf, gintoken, *gintokenp, gouttoken; + OM_uint32 gret, minor, flags, ret_flags; + gss_OID mech_type, ret_mech_type; + OM_uint32 lifetime; + gss_name_t gname; + isc_result_t result; + unsigned char array[DNS_NAME_MAXTEXT + 1]; + + isc_buffer_init(&namebuf, array, sizeof(array)); + name_to_gbuffer(name, &namebuf, &gnamebuf); + gret = gss_import_name(&minor, &gnamebuf, GSS_C_NO_OID, &gname); + if (gret != GSS_S_COMPLETE) + return (ISC_R_FAILURE); + + if (intoken != NULL) { + REGION_TO_GBUFFER(*intoken, gintoken); + gintokenp = &gintoken; + } else + gintokenp = NULL; + + if (*context == NULL) + *context = GSS_C_NO_CONTEXT; + flags = GSS_C_REPLAY_FLAG | GSS_C_MUTUAL_FLAG | GSS_C_DELEG_FLAG | + GSS_C_SEQUENCE_FLAG | GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG; + mech_type = GSS_C_NO_OID; + + gret = gss_init_sec_context(&minor, cred, context, gname, + mech_type, flags, 0, + GSS_C_NO_CHANNEL_BINDINGS, gintokenp, + &ret_mech_type, &gouttoken, &ret_flags, + &lifetime); + if (gret != GSS_S_COMPLETE && gret != GSS_S_CONTINUE_NEEDED) + return (ISC_R_FAILURE); + + GBUFFER_TO_REGION(gouttoken, r); + RETERR(isc_buffer_copyregion(outtoken, &r)); + + if (gret == GSS_S_COMPLETE) + return (ISC_R_SUCCESS); + else + return (DNS_R_CONTINUE); + + out: + return (result); +} + +isc_result_t +dst_gssapi_acceptctx(dns_name_t *name, void *cred, + isc_region_t *intoken, isc_buffer_t *outtoken, + void **context) +{ + isc_region_t r; + isc_buffer_t namebuf; + gss_buffer_desc gnamebuf, gintoken, gouttoken; + OM_uint32 gret, minor, flags; + gss_OID mech_type; + OM_uint32 lifetime; + gss_cred_id_t delegated_cred; + gss_name_t gname; + isc_result_t result; + unsigned char array[DNS_NAME_MAXTEXT + 1]; + + isc_buffer_init(&namebuf, array, sizeof(array)); + name_to_gbuffer(name, &namebuf, &gnamebuf); + gret = gss_import_name(&minor, &gnamebuf, GSS_C_NO_OID, &gname); + if (gret != GSS_S_COMPLETE) + return (ISC_R_FAILURE); + + REGION_TO_GBUFFER(*intoken, gintoken); + + if (*context == NULL) + *context = GSS_C_NO_CONTEXT; + + gret = gss_accept_sec_context(&minor, context, cred, &gintoken, + GSS_C_NO_CHANNEL_BINDINGS, gname, + &mech_type, &gouttoken, &flags, + &lifetime, &delegated_cred); + if (gret != GSS_S_COMPLETE) + return (ISC_R_FAILURE); + + GBUFFER_TO_REGION(gouttoken, r); + RETERR(isc_buffer_copyregion(outtoken, &r)); + + return (ISC_R_SUCCESS); + + out: + return (result); +} + +#else + +isc_result_t +dst_gssapi_acquirecred(dns_name_t *name, isc_boolean_t initiate, void **cred) { + UNUSED(name); + UNUSED(initiate); + UNUSED(cred); + return (ISC_R_NOTIMPLEMENTED); +} + +isc_result_t +dst_gssapi_initctx(dns_name_t *name, void *cred, + isc_region_t *intoken, isc_buffer_t *outtoken, + void **context) +{ + UNUSED(name); + UNUSED(cred); + UNUSED(intoken); + UNUSED(outtoken); + UNUSED(context); + return (ISC_R_NOTIMPLEMENTED); +} + +isc_result_t +dst_gssapi_acceptctx(dns_name_t *name, void *cred, + isc_region_t *intoken, isc_buffer_t *outtoken, + void **context) +{ + UNUSED(name); + UNUSED(cred); + UNUSED(intoken); + UNUSED(outtoken); + UNUSED(context); + return (ISC_R_NOTIMPLEMENTED); +} + +#endif diff --git a/contrib/bind9/lib/dns/hmac_link.c b/contrib/bind9/lib/dns/hmac_link.c new file mode 100644 index 000000000000..762fceecb42f --- /dev/null +++ b/contrib/bind9/lib/dns/hmac_link.c @@ -0,0 +1,282 @@ +/* + * Portions Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 1999-2002 Internet Software Consortium. + * Portions Copyright (C) 1995-2000 by Network Associates, Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE + * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Principal Author: Brian Wellington + * $Id: hmac_link.c,v 1.1.4.1 2004/12/09 04:07:17 marka Exp $ + */ + +#include <config.h> + +#include <isc/buffer.h> +#include <isc/hmacmd5.h> +#include <isc/md5.h> +#include <isc/mem.h> +#include <isc/string.h> +#include <isc/util.h> + +#include <dst/result.h> + +#include "dst_internal.h" +#include "dst_parse.h" + +#define HMAC_LEN 64 +#define HMAC_IPAD 0x36 +#define HMAC_OPAD 0x5c + +static isc_result_t hmacmd5_fromdns(dst_key_t *key, isc_buffer_t *data); + +typedef struct hmackey { + unsigned char key[HMAC_LEN]; +} HMAC_Key; + +static isc_result_t +hmacmd5_createctx(dst_key_t *key, dst_context_t *dctx) { + isc_hmacmd5_t *hmacmd5ctx; + HMAC_Key *hkey = key->opaque; + + hmacmd5ctx = isc_mem_get(dctx->mctx, sizeof(isc_hmacmd5_t)); + if (hmacmd5ctx == NULL) + return (ISC_R_NOMEMORY); + isc_hmacmd5_init(hmacmd5ctx, hkey->key, HMAC_LEN); + dctx->opaque = hmacmd5ctx; + return (ISC_R_SUCCESS); +} + +static void +hmacmd5_destroyctx(dst_context_t *dctx) { + isc_hmacmd5_t *hmacmd5ctx = dctx->opaque; + + if (hmacmd5ctx != NULL) { + isc_hmacmd5_invalidate(hmacmd5ctx); + isc_mem_put(dctx->mctx, hmacmd5ctx, sizeof(isc_hmacmd5_t)); + dctx->opaque = NULL; + } +} + +static isc_result_t +hmacmd5_adddata(dst_context_t *dctx, const isc_region_t *data) { + isc_hmacmd5_t *hmacmd5ctx = dctx->opaque; + + isc_hmacmd5_update(hmacmd5ctx, data->base, data->length); + return (ISC_R_SUCCESS); +} + +static isc_result_t +hmacmd5_sign(dst_context_t *dctx, isc_buffer_t *sig) { + isc_hmacmd5_t *hmacmd5ctx = dctx->opaque; + unsigned char *digest; + + if (isc_buffer_availablelength(sig) < ISC_MD5_DIGESTLENGTH) + return (ISC_R_NOSPACE); + digest = isc_buffer_used(sig); + isc_hmacmd5_sign(hmacmd5ctx, digest); + isc_buffer_add(sig, ISC_MD5_DIGESTLENGTH); + + return (ISC_R_SUCCESS); +} + +static isc_result_t +hmacmd5_verify(dst_context_t *dctx, const isc_region_t *sig) { + isc_hmacmd5_t *hmacmd5ctx = dctx->opaque; + + if (sig->length < ISC_MD5_DIGESTLENGTH) + return (DST_R_VERIFYFAILURE); + + if (isc_hmacmd5_verify(hmacmd5ctx, sig->base)) + return (ISC_R_SUCCESS); + else + return (DST_R_VERIFYFAILURE); +} + +static isc_boolean_t +hmacmd5_compare(const dst_key_t *key1, const dst_key_t *key2) { + HMAC_Key *hkey1, *hkey2; + + hkey1 = (HMAC_Key *)key1->opaque; + hkey2 = (HMAC_Key *)key2->opaque; + + if (hkey1 == NULL && hkey2 == NULL) + return (ISC_TRUE); + else if (hkey1 == NULL || hkey2 == NULL) + return (ISC_FALSE); + + if (memcmp(hkey1->key, hkey2->key, HMAC_LEN) == 0) + return (ISC_TRUE); + else + return (ISC_FALSE); +} + +static isc_result_t +hmacmd5_generate(dst_key_t *key, int pseudorandom_ok) { + isc_buffer_t b; + isc_result_t ret; + int bytes; + unsigned char data[HMAC_LEN]; + + bytes = (key->key_size + 7) / 8; + if (bytes > 64) { + bytes = 64; + key->key_size = 512; + } + + memset(data, 0, HMAC_LEN); + ret = dst__entropy_getdata(data, bytes, ISC_TF(pseudorandom_ok != 0)); + + if (ret != ISC_R_SUCCESS) + return (ret); + + isc_buffer_init(&b, data, bytes); + isc_buffer_add(&b, bytes); + ret = hmacmd5_fromdns(key, &b); + memset(data, 0, HMAC_LEN); + + return (ret); +} + +static isc_boolean_t +hmacmd5_isprivate(const dst_key_t *key) { + UNUSED(key); + return (ISC_TRUE); +} + +static void +hmacmd5_destroy(dst_key_t *key) { + HMAC_Key *hkey = key->opaque; + memset(hkey, 0, sizeof(HMAC_Key)); + isc_mem_put(key->mctx, hkey, sizeof(HMAC_Key)); + key->opaque = NULL; +} + +static isc_result_t +hmacmd5_todns(const dst_key_t *key, isc_buffer_t *data) { + HMAC_Key *hkey; + unsigned int bytes; + + REQUIRE(key->opaque != NULL); + + hkey = (HMAC_Key *) key->opaque; + + bytes = (key->key_size + 7) / 8; + if (isc_buffer_availablelength(data) < bytes) + return (ISC_R_NOSPACE); + isc_buffer_putmem(data, hkey->key, bytes); + + return (ISC_R_SUCCESS); +} + +static isc_result_t +hmacmd5_fromdns(dst_key_t *key, isc_buffer_t *data) { + HMAC_Key *hkey; + int keylen; + isc_region_t r; + isc_md5_t md5ctx; + + isc_buffer_remainingregion(data, &r); + if (r.length == 0) + return (ISC_R_SUCCESS); + + hkey = (HMAC_Key *) isc_mem_get(key->mctx, sizeof(HMAC_Key)); + if (hkey == NULL) + return (ISC_R_NOMEMORY); + + memset(hkey->key, 0, sizeof(hkey->key)); + + if (r.length > HMAC_LEN) { + isc_md5_init(&md5ctx); + isc_md5_update(&md5ctx, r.base, r.length); + isc_md5_final(&md5ctx, hkey->key); + keylen = ISC_MD5_DIGESTLENGTH; + } + else { + memcpy(hkey->key, r.base, r.length); + keylen = r.length; + } + + key->key_size = keylen * 8; + key->opaque = hkey; + + return (ISC_R_SUCCESS); +} + +static isc_result_t +hmacmd5_tofile(const dst_key_t *key, const char *directory) { + int cnt = 0; + HMAC_Key *hkey; + dst_private_t priv; + int bytes = (key->key_size + 7) / 8; + + if (key->opaque == NULL) + return (DST_R_NULLKEY); + + hkey = (HMAC_Key *) key->opaque; + + priv.elements[cnt].tag = TAG_HMACMD5_KEY; + priv.elements[cnt].length = bytes; + priv.elements[cnt++].data = hkey->key; + + priv.nelements = cnt; + return (dst__privstruct_writefile(key, &priv, directory)); +} + +static isc_result_t +hmacmd5_parse(dst_key_t *key, isc_lex_t *lexer) { + dst_private_t priv; + isc_result_t ret; + isc_buffer_t b; + isc_mem_t *mctx = key->mctx; + + /* read private key file */ + ret = dst__privstruct_parse(key, DST_ALG_HMACMD5, lexer, mctx, &priv); + if (ret != ISC_R_SUCCESS) + return (ret); + + isc_buffer_init(&b, priv.elements[0].data, priv.elements[0].length); + isc_buffer_add(&b, priv.elements[0].length); + ret = hmacmd5_fromdns(key, &b); + dst__privstruct_free(&priv, mctx); + memset(&priv, 0, sizeof(priv)); + return (ret); +} + +static dst_func_t hmacmd5_functions = { + hmacmd5_createctx, + hmacmd5_destroyctx, + hmacmd5_adddata, + hmacmd5_sign, + hmacmd5_verify, + NULL, /* computesecret */ + hmacmd5_compare, + NULL, /* paramcompare */ + hmacmd5_generate, + hmacmd5_isprivate, + hmacmd5_destroy, + hmacmd5_todns, + hmacmd5_fromdns, + hmacmd5_tofile, + hmacmd5_parse, + NULL, /* cleanup */ +}; + +isc_result_t +dst__hmacmd5_init(dst_func_t **funcp) { + REQUIRE(funcp != NULL); + if (*funcp == NULL) + *funcp = &hmacmd5_functions; + return (ISC_R_SUCCESS); +} diff --git a/contrib/bind9/lib/dns/include/Makefile.in b/contrib/bind9/lib/dns/include/Makefile.in index 0e411dae1948..92dfb3b816dd 100644 --- a/contrib/bind9/lib/dns/include/Makefile.in +++ b/contrib/bind9/lib/dns/include/Makefile.in @@ -13,13 +13,13 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: Makefile.in,v 1.11.206.1 2004/03/06 08:13:50 marka Exp $ +# $Id: Makefile.in,v 1.11.206.2 2004/12/09 04:07:19 marka Exp $ srcdir = @srcdir@ VPATH = @srcdir@ top_srcdir = @top_srcdir@ -SUBDIRS = dns +SUBDIRS = dns dst TARGETS = @BIND9_MAKE_RULES@ diff --git a/contrib/bind9/lib/dns/include/dns/name.h b/contrib/bind9/lib/dns/include/dns/name.h index dd6a1239d745..5f6a3db9c191 100644 --- a/contrib/bind9/lib/dns/include/dns/name.h +++ b/contrib/bind9/lib/dns/include/dns/name.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: name.h,v 1.95.2.3.2.11 2004/09/01 05:19:59 marka Exp $ */ +/* $Id: name.h,v 1.95.2.3.2.12 2004/09/08 00:29:34 marka Exp $ */ #ifndef DNS_NAME_H #define DNS_NAME_H 1 @@ -560,7 +560,7 @@ dns_name_getlabel(const dns_name_t *name, unsigned int n, dns_label_t *label); * be changed while 'label' is still in use. * * Requires: - * n < dns_label_countlabels(name) + * n < dns_name_countlabels(name) */ void @@ -582,9 +582,9 @@ dns_name_getlabelsequence(const dns_name_t *source, unsigned int first, * Requires: * 'source' and 'target' are valid names. * - * first < dns_label_countlabels(name) + * first < dns_name_countlabels(name) * - * first + n <= dns_label_countlabels(name) + * first + n <= dns_name_countlabels(name) */ @@ -601,7 +601,7 @@ dns_name_clone(dns_name_t *source, dns_name_t *target); * This call is functionally equivalent to: * * dns_name_getlabelsequence(source, 0, - * dns_label_countlabels(source), + * dns_name_countlabels(source), * target); * * but is more efficient. Also, dns_name_clone() works even if 'source' diff --git a/contrib/bind9/lib/dns/include/dns/rbt.h b/contrib/bind9/lib/dns/include/dns/rbt.h index de2d30964407..6f99a7dfb069 100644 --- a/contrib/bind9/lib/dns/include/dns/rbt.h +++ b/contrib/bind9/lib/dns/include/dns/rbt.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rbt.h,v 1.55.12.5 2004/03/08 09:04:38 marka Exp $ */ +/* $Id: rbt.h,v 1.55.12.6 2004/10/11 05:55:51 marka Exp $ */ #ifndef DNS_RBT_H #define DNS_RBT_H 1 @@ -603,15 +603,18 @@ dns_rbt_destroy(dns_rbt_t **rbtp); isc_result_t dns_rbt_destroy2(dns_rbt_t **rbtp, unsigned int quantum); /* - * Stop working with a red-black tree of trees. Once dns_rbt_destroy2() - * has been called on a 'rbt' only dns_rbt_destroy() or dns_rbt_destroy2() - * may be used on the tree. If 'quantum' is zero then the entire tree will - * be destroyed. - * + * Stop working with a red-black tree of trees. + * If 'quantum' is zero then the entire tree will be destroyed. + * If 'quantum' is non zero then up to 'quantum' nodes will be destroyed + * allowing the rbt to be incrementally destroyed by repeated calls to + * dns_rbt_destroy2(). Once dns_rbt_destroy2() has been called no other + * operations than dns_rbt_destroy()/dns_rbt_destroy2() should be + * performed on the tree of trees. + * * Requires: * *rbt is a valid rbt manager. * - * Ensures: + * Ensures on ISC_R_SUCCESS: * All space allocated by the RBT library has been returned. * * *rbt is invalidated as an rbt manager. diff --git a/contrib/bind9/lib/dns/include/dns/zone.h b/contrib/bind9/lib/dns/include/dns/zone.h index ebd8d8ce6ecc..b7680fa27741 100644 --- a/contrib/bind9/lib/dns/include/dns/zone.h +++ b/contrib/bind9/lib/dns/include/dns/zone.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zone.h,v 1.106.2.7.4.14 2004/03/06 08:14:01 marka Exp $ */ +/* $Id: zone.h,v 1.106.2.7.4.15 2004/10/26 02:08:43 marka Exp $ */ #ifndef DNS_ZONE_H #define DNS_ZONE_H 1 @@ -971,6 +971,13 @@ dns_zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump); * * Requires: * 'zone' to be a valid zone. + * + * Returns: + * DNS_R_SUCCESS + * DNS_R_BADZONE zone failed basic consistancy checks: + * * a single SOA must exist + * * some NS records must exist. + * Others */ isc_uint32_t diff --git a/contrib/bind9/lib/dns/include/dst/Makefile.in b/contrib/bind9/lib/dns/include/dst/Makefile.in new file mode 100644 index 000000000000..efebfaa59bf0 --- /dev/null +++ b/contrib/bind9/lib/dns/include/dst/Makefile.in @@ -0,0 +1,37 @@ +# Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") +# Copyright (C) 1998-2001 Internet Software Consortium. +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +# PERFORMANCE OF THIS SOFTWARE. + +# $Id: Makefile.in,v 1.1.4.1 2004/12/09 04:07:19 marka Exp $ + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +@BIND9_VERSION@ + +HEADERS = dst.h lib.h result.h + +SUBDIRS = +TARGETS = + +@BIND9_MAKE_RULES@ + +installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/dst + +install:: installdirs + for i in ${HEADERS}; do \ + ${INSTALL_DATA} ${srcdir}/$$i ${DESTDIR}${includedir}/dst ; \ + done diff --git a/contrib/bind9/lib/dns/include/dst/dst.h b/contrib/bind9/lib/dns/include/dst/dst.h new file mode 100644 index 000000000000..1629da592a75 --- /dev/null +++ b/contrib/bind9/lib/dns/include/dst/dst.h @@ -0,0 +1,570 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000-2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* $Id: dst.h,v 1.1.4.1 2004/12/09 04:07:19 marka Exp $ */ + +#ifndef DST_DST_H +#define DST_DST_H 1 + +#include <isc/lang.h> + +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +/*** + *** Types + ***/ + +/* + * The dst_key structure is opaque. Applications should use the accessor + * functions provided to retrieve key attributes. If an application needs + * to set attributes, new accessor functions will be written. + */ + +typedef struct dst_key dst_key_t; +typedef struct dst_context dst_context_t; + +/* DST algorithm codes */ +#define DST_ALG_UNKNOWN 0 +#define DST_ALG_RSAMD5 1 +#define DST_ALG_RSA DST_ALG_RSAMD5 /* backwards compatibility */ +#define DST_ALG_DH 2 +#define DST_ALG_DSA 3 +#define DST_ALG_ECC 4 +#define DST_ALG_RSASHA1 5 +#define DST_ALG_HMACMD5 157 +#define DST_ALG_GSSAPI 160 +#define DST_ALG_PRIVATE 254 +#define DST_ALG_EXPAND 255 +#define DST_MAX_ALGS 255 + +/* A buffer of this size is large enough to hold any key */ +#define DST_KEY_MAXSIZE 1280 + +/* + * A buffer of this size is large enough to hold the textual representation + * of any key + */ +#define DST_KEY_MAXTEXTSIZE 2048 + +/* 'Type' for dst_read_key() */ +#define DST_TYPE_KEY 0x1000000 /* KEY key */ +#define DST_TYPE_PRIVATE 0x2000000 +#define DST_TYPE_PUBLIC 0x4000000 + +/*** + *** Functions + ***/ + +isc_result_t +dst_lib_init(isc_mem_t *mctx, isc_entropy_t *ectx, unsigned int eflags); +/* + * Initializes the DST subsystem. + * + * Requires: + * "mctx" is a valid memory context + * "ectx" is a valid entropy context + * + * Returns: + * ISC_R_SUCCESS + * ISC_R_NOMEMORY + * + * Ensures: + * DST is properly initialized. + */ + +void +dst_lib_destroy(void); +/* + * Releases all resources allocated by DST. + */ + +isc_boolean_t +dst_algorithm_supported(unsigned int alg); +/* + * Checks that a given algorithm is supported by DST. + * + * Returns: + * ISC_TRUE + * ISC_FALSE + */ + +isc_result_t +dst_context_create(dst_key_t *key, isc_mem_t *mctx, dst_context_t **dctxp); +/* + * Creates a context to be used for a sign or verify operation. + * + * Requires: + * "key" is a valid key. + * "mctx" is a valid memory context. + * dctxp != NULL && *dctxp == NULL + * + * Returns: + * ISC_R_SUCCESS + * ISC_R_NOMEMORY + * + * Ensures: + * *dctxp will contain a usable context. + */ + +void +dst_context_destroy(dst_context_t **dctxp); +/* + * Destroys all memory associated with a context. + * + * Requires: + * *dctxp != NULL && *dctxp == NULL + * + * Ensures: + * *dctxp == NULL + */ + +isc_result_t +dst_context_adddata(dst_context_t *dctx, const isc_region_t *data); +/* + * Incrementally adds data to the context to be used in a sign or verify + * operation. + * + * Requires: + * "dctx" is a valid context + * "data" is a valid region + * + * Returns: + * ISC_R_SUCCESS + * DST_R_SIGNFAILURE + * all other errors indicate failure + */ + +isc_result_t +dst_context_sign(dst_context_t *dctx, isc_buffer_t *sig); +/* + * Computes a signature using the data and key stored in the context. + * + * Requires: + * "dctx" is a valid context. + * "sig" is a valid buffer. + * + * Returns: + * ISC_R_SUCCESS + * DST_R_VERIFYFAILURE + * all other errors indicate failure + * + * Ensures: + * "sig" will contain the signature + */ + +isc_result_t +dst_context_verify(dst_context_t *dctx, isc_region_t *sig); +/* + * Verifies the signature using the data and key stored in the context. + * + * Requires: + * "dctx" is a valid context. + * "sig" is a valid region. + * + * Returns: + * ISC_R_SUCCESS + * all other errors indicate failure + * + * Ensures: + * "sig" will contain the signature + */ + +isc_result_t +dst_key_computesecret(const dst_key_t *pub, const dst_key_t *priv, + isc_buffer_t *secret); +/* + * Computes a shared secret from two (Diffie-Hellman) keys. + * + * Requires: + * "pub" is a valid key that can be used to derive a shared secret + * "priv" is a valid private key that can be used to derive a shared secret + * "secret" is a valid buffer + * + * Returns: + * ISC_R_SUCCESS + * any other result indicates failure + * + * Ensures: + * If successful, secret will contain the derived shared secret. + */ + +isc_result_t +dst_key_fromfile(dns_name_t *name, dns_keytag_t id, unsigned int alg, int type, + const char *directory, isc_mem_t *mctx, dst_key_t **keyp); +/* + * Reads a key from permanent storage. The key can either be a public or + * private key, and is specified by name, algorithm, and id. If a private key + * is specified, the public key must also be present. If directory is NULL, + * the current directory is assumed. + * + * Requires: + * "name" is a valid absolute dns name. + * "id" is a valid key tag identifier. + * "alg" is a supported key algorithm. + * "type" is DST_TYPE_PUBLIC, DST_TYPE_PRIVATE, or the bitwise union. + * DST_TYPE_KEY look for a KEY record otherwise DNSKEY + * "mctx" is a valid memory context. + * "keyp" is not NULL and "*keyp" is NULL. + * + * Returns: + * ISC_R_SUCCESS + * any other result indicates failure + * + * Ensures: + * If successful, *keyp will contain a valid key. + */ + +isc_result_t +dst_key_fromnamedfile(const char *filename, int type, isc_mem_t *mctx, + dst_key_t **keyp); +/* + * Reads a key from permanent storage. The key can either be a public or + * key, and is specified by filename. If a private key is specified, the + * public key must also be present. + * + * Requires: + * "filename" is not NULL + * "type" is DST_TYPE_PUBLIC, DST_TYPE_PRIVATE, or the bitwise union + * DST_TYPE_KEY look for a KEY record otherwise DNSKEY + * "mctx" is a valid memory context + * "keyp" is not NULL and "*keyp" is NULL. + * + * Returns: + * ISC_R_SUCCESS + * any other result indicates failure + * + * Ensures: + * If successful, *keyp will contain a valid key. + */ + +isc_result_t +dst_key_tofile(const dst_key_t *key, int type, const char *directory); +/* + * Writes a key to permanent storage. The key can either be a public or + * private key. Public keys are written in DNS format and private keys + * are written as a set of base64 encoded values. If directory is NULL, + * the current directory is assumed. + * + * Requires: + * "key" is a valid key. + * "type" is DST_TYPE_PUBLIC, DST_TYPE_PRIVATE, or the bitwise union + * + * Returns: + * ISC_R_SUCCESS + * any other result indicates failure + */ + +isc_result_t +dst_key_fromdns(dns_name_t *name, dns_rdataclass_t rdclass, + isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp); +/* + * Converts a DNS KEY record into a DST key. + * + * Requires: + * "name" is a valid absolute dns name. + * "source" is a valid buffer. There must be at least 4 bytes available. + * "mctx" is a valid memory context. + * "keyp" is not NULL and "*keyp" is NULL. + * + * Returns: + * ISC_R_SUCCESS + * any other result indicates failure + * + * Ensures: + * If successful, *keyp will contain a valid key, and the consumed + * pointer in data will be advanced. + */ + +isc_result_t +dst_key_todns(const dst_key_t *key, isc_buffer_t *target); +/* + * Converts a DST key into a DNS KEY record. + * + * Requires: + * "key" is a valid key. + * "target" is a valid buffer. There must be at least 4 bytes unused. + * + * Returns: + * ISC_R_SUCCESS + * any other result indicates failure + * + * Ensures: + * If successful, the used pointer in 'target' is advanced by at least 4. + */ + +isc_result_t +dst_key_frombuffer(dns_name_t *name, unsigned int alg, + unsigned int flags, unsigned int protocol, + dns_rdataclass_t rdclass, + isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp); +/* + * Converts a buffer containing DNS KEY RDATA into a DST key. + * + * Requires: + * "name" is a valid absolute dns name. + * "alg" is a supported key algorithm. + * "source" is a valid buffer. + * "mctx" is a valid memory context. + * "keyp" is not NULL and "*keyp" is NULL. + * + * Returns: + * ISC_R_SUCCESS + * any other result indicates failure + * + * Ensures: + * If successful, *keyp will contain a valid key, and the consumed + * pointer in source will be advanced. + */ + +isc_result_t +dst_key_tobuffer(const dst_key_t *key, isc_buffer_t *target); +/* + * Converts a DST key into DNS KEY RDATA format. + * + * Requires: + * "key" is a valid key. + * "target" is a valid buffer. + * + * Returns: + * ISC_R_SUCCESS + * any other result indicates failure + * + * Ensures: + * If successful, the used pointer in 'target' is advanced. + */ + +isc_result_t +dst_key_privatefrombuffer(dst_key_t *key, isc_buffer_t *buffer); +/* + * Converts a public key into a private key, reading the private key + * information from the buffer. The buffer should contain the same data + * as the .private key file would. + * + * Requires: + * "key" is a valid public key. + * "buffer" is not NULL. + * + * Returns: + * ISC_R_SUCCESS + * any other result indicates failure + * + * Ensures: + * If successful, key will contain a valid private key. + */ + + +isc_result_t +dst_key_fromgssapi(dns_name_t *name, void *opaque, isc_mem_t *mctx, + dst_key_t **keyp); +/* + * Converts a GSSAPI opaque context id into a DST key. + * + * Requires: + * "name" is a valid absolute dns name. + * "opaque" is a GSSAPI context id. + * "mctx" is a valid memory context. + * "keyp" is not NULL and "*keyp" is NULL. + * + * Returns: + * ISC_R_SUCCESS + * any other result indicates failure + * + * Ensures: + * If successful, *keyp will contain a valid key and be responsible for + * the context id. + */ + +isc_result_t +dst_key_generate(dns_name_t *name, unsigned int alg, + unsigned int bits, unsigned int param, + unsigned int flags, unsigned int protocol, + dns_rdataclass_t rdclass, + isc_mem_t *mctx, dst_key_t **keyp); +/* + * Generate a DST key (or keypair) with the supplied parameters. The + * interpretation of the "param" field depends on the algorithm: + * RSA: exponent + * 0 use exponent 3 + * !0 use Fermat4 (2^16 + 1) + * DH: generator + * 0 default - use well known prime if bits == 768 or 1024, + * otherwise use 2 as the generator. + * !0 use this value as the generator. + * DSA: unused + * HMACMD5: entropy + * 0 default - require good entropy + * !0 lack of good entropy is ok + * + * Requires: + * "name" is a valid absolute dns name. + * "keyp" is not NULL and "*keyp" is NULL. + * + * Returns: + * ISC_R_SUCCESS + * any other result indicates failure + * + * Ensures: + * If successful, *keyp will contain a valid key. + */ + +isc_boolean_t +dst_key_compare(const dst_key_t *key1, const dst_key_t *key2); +/* + * Compares two DST keys. + * + * Requires: + * "key1" is a valid key. + * "key2" is a valid key. + * + * Returns: + * ISC_TRUE + * ISC_FALSE + */ + +isc_boolean_t +dst_key_paramcompare(const dst_key_t *key1, const dst_key_t *key2); +/* + * Compares the parameters of two DST keys. This is used to determine if + * two (Diffie-Hellman) keys can be used to derive a shared secret. + * + * Requires: + * "key1" is a valid key. + * "key2" is a valid key. + * + * Returns: + * ISC_TRUE + * ISC_FALSE + */ + +void +dst_key_free(dst_key_t **keyp); +/* + * Release all memory associated with the key. + * + * Requires: + * "keyp" is not NULL and "*keyp" is a valid key. + * + * Ensures: + * All memory associated with "*keyp" will be freed. + * *keyp == NULL + */ + +/* + * Accessor functions to obtain key fields. + * + * Require: + * "key" is a valid key. + */ +dns_name_t * +dst_key_name(const dst_key_t *key); + +unsigned int +dst_key_size(const dst_key_t *key); + +unsigned int +dst_key_proto(const dst_key_t *key); + +unsigned int +dst_key_alg(const dst_key_t *key); + +isc_uint32_t +dst_key_flags(const dst_key_t *key); + +dns_keytag_t +dst_key_id(const dst_key_t *key); + +dns_rdataclass_t +dst_key_class(const dst_key_t *key); + +isc_boolean_t +dst_key_isprivate(const dst_key_t *key); + +isc_boolean_t +dst_key_iszonekey(const dst_key_t *key); + +isc_boolean_t +dst_key_isnullkey(const dst_key_t *key); + +isc_result_t +dst_key_buildfilename(const dst_key_t *key, int type, + const char *directory, isc_buffer_t *out); +/* + * Generates the filename used by dst to store the specified key. + * If directory is NULL, the current directory is assumed. + * + * Requires: + * "key" is a valid key + * "type" is either DST_TYPE_PUBLIC, DST_TYPE_PRIVATE, or 0 for no suffix. + * "out" is a valid buffer + * + * Ensures: + * the file name will be written to "out", and the used pointer will + * be advanced. + */ + +isc_result_t +dst_key_sigsize(const dst_key_t *key, unsigned int *n); +/* + * Computes the size of a signature generated by the given key. + * + * Requires: + * "key" is a valid key. + * "n" is not NULL + * + * Returns: + * ISC_R_SUCCESS + * DST_R_UNSUPPORTEDALG + * + * Ensures: + * "n" stores the size of a generated signature + */ + +isc_result_t +dst_key_secretsize(const dst_key_t *key, unsigned int *n); +/* + * Computes the size of a shared secret generated by the given key. + * + * Requires: + * "key" is a valid key. + * "n" is not NULL + * + * Returns: + * ISC_R_SUCCESS + * DST_R_UNSUPPORTEDALG + * + * Ensures: + * "n" stores the size of a generated shared secret + */ + +isc_uint16_t +dst_region_computeid(const isc_region_t *source, unsigned int alg); +/* + * Computes the key id of the key stored in the provided region with the + * given algorithm. + * + * Requires: + * "source" contains a valid, non-NULL region. + * + * Returns: + * the key id + */ + +ISC_LANG_ENDDECLS + +#endif /* DST_DST_H */ diff --git a/contrib/bind9/lib/dns/include/dst/gssapi.h b/contrib/bind9/lib/dns/include/dst/gssapi.h new file mode 100644 index 000000000000..1d746568d638 --- /dev/null +++ b/contrib/bind9/lib/dns/include/dst/gssapi.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* $Id: gssapi.h,v 1.1.4.1 2004/12/09 04:07:20 marka Exp $ */ + +#ifndef DST_GSSAPI_H +#define DST_GSSAPI_H 1 + +#include <isc/lang.h> + +#include <isc/types.h> + +ISC_LANG_BEGINDECLS + +/*** + *** Types + ***/ + +/*** + *** Functions + ***/ + +isc_result_t +dst_gssapi_acquirecred(dns_name_t *name, isc_boolean_t initiate, void **cred); + +isc_result_t +dst_gssapi_initctx(dns_name_t *name, void *cred, + isc_region_t *intoken, isc_buffer_t *outtoken, + void **context); + +isc_result_t +dst_gssapi_acceptctx(dns_name_t *name, void *cred, + isc_region_t *intoken, isc_buffer_t *outtoken, + void **context); + +/* + * XXX + */ + +ISC_LANG_ENDDECLS + +#endif /* DST_GSSAPI_H */ diff --git a/contrib/bind9/lib/dns/include/dst/lib.h b/contrib/bind9/lib/dns/include/dst/lib.h new file mode 100644 index 000000000000..7a8e73e4dc55 --- /dev/null +++ b/contrib/bind9/lib/dns/include/dst/lib.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* $Id: lib.h,v 1.1.4.1 2004/12/09 04:07:20 marka Exp $ */ + +#ifndef DST_LIB_H +#define DST_LIB_H 1 + +#include <isc/types.h> +#include <isc/lang.h> + +ISC_LANG_BEGINDECLS + +LIBDNS_EXTERNAL_DATA extern isc_msgcat_t *dst_msgcat; + +void +dst_lib_initmsgcat(void); +/* + * Initialize the DST library's message catalog, dst_msgcat, if it + * has not already been initialized. + */ + +ISC_LANG_ENDDECLS + +#endif /* DST_LIB_H */ diff --git a/contrib/bind9/lib/dns/include/dst/result.h b/contrib/bind9/lib/dns/include/dst/result.h new file mode 100644 index 000000000000..015e0863c4d8 --- /dev/null +++ b/contrib/bind9/lib/dns/include/dst/result.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* $Id: result.h,v 1.1.4.1 2004/12/09 04:07:20 marka Exp $ */ + +#ifndef DST_RESULT_H +#define DST_RESULT_H 1 + +#include <isc/lang.h> +#include <isc/resultclass.h> + +/* + * Nothing in this file truly depends on <isc/result.h>, but the + * DST result codes are considered to be publicly derived from + * the ISC result codes, so including this file buys you the ISC_R_ + * namespace too. + */ +#include <isc/result.h> /* Contractual promise. */ + +#define DST_R_UNSUPPORTEDALG (ISC_RESULTCLASS_DST + 0) +#define DST_R_OPENSSLFAILURE (ISC_RESULTCLASS_DST + 1) +#define DST_R_NOCRYPTO (ISC_RESULTCLASS_DST + 2) +#define DST_R_NULLKEY (ISC_RESULTCLASS_DST + 3) +#define DST_R_INVALIDPUBLICKEY (ISC_RESULTCLASS_DST + 4) +#define DST_R_INVALIDPRIVATEKEY (ISC_RESULTCLASS_DST + 5) +/* 6 is unused */ +#define DST_R_WRITEERROR (ISC_RESULTCLASS_DST + 7) +#define DST_R_INVALIDPARAM (ISC_RESULTCLASS_DST + 8) +/* 9 is unused */ +/* 10 is unused */ +#define DST_R_SIGNFAILURE (ISC_RESULTCLASS_DST + 11) +/* 12 is unused */ +/* 13 is unused */ +#define DST_R_VERIFYFAILURE (ISC_RESULTCLASS_DST + 14) +#define DST_R_NOTPUBLICKEY (ISC_RESULTCLASS_DST + 15) +#define DST_R_NOTPRIVATEKEY (ISC_RESULTCLASS_DST + 16) +#define DST_R_KEYCANNOTCOMPUTESECRET (ISC_RESULTCLASS_DST + 17) +#define DST_R_COMPUTESECRETFAILURE (ISC_RESULTCLASS_DST + 18) +#define DST_R_NORANDOMNESS (ISC_RESULTCLASS_DST + 19) +#define DST_R_BADKEYTYPE (ISC_RESULTCLASS_DST + 20) + +#define DST_R_NRESULTS 21 /* Number of results */ + +ISC_LANG_BEGINDECLS + +const char * +dst_result_totext(isc_result_t); + +void +dst_result_register(void); + +ISC_LANG_ENDDECLS + +#endif /* DST_RESULT_H */ diff --git a/contrib/bind9/lib/dns/journal.c b/contrib/bind9/lib/dns/journal.c index 28fd3547de5e..13fbdeef70fe 100644 --- a/contrib/bind9/lib/dns/journal.c +++ b/contrib/bind9/lib/dns/journal.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: journal.c,v 1.77.2.1.10.8 2004/05/14 05:27:47 marka Exp $ */ +/* $Id: journal.c,v 1.77.2.1.10.9 2004/09/16 04:57:02 marka Exp $ */ #include <config.h> @@ -1035,8 +1035,8 @@ dns_journal_commit(dns_journal_t *j) { */ if (j->x.n_soa != 2) { isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR, - "malformed transaction: %d SOAs", - j->x.n_soa); + "%s: malformed transaction: %d SOAs", + j->filename, j->x.n_soa); return (ISC_R_UNEXPECTED); } if (! (DNS_SERIAL_GT(j->x.pos[1].serial, j->x.pos[0].serial) || @@ -1044,8 +1044,8 @@ dns_journal_commit(dns_journal_t *j) { j->x.pos[1].serial == j->x.pos[0].serial))) { isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR, - "malformed transaction: serial number " - "would decrease"); + "%s: malformed transaction: serial number " + "would decrease", j->filename); return (ISC_R_UNEXPECTED); } if (! JOURNAL_EMPTY(&j->header)) { @@ -1266,8 +1266,8 @@ roll_forward(dns_journal_t *j, dns_db_t *db) { if (++n_put > 100) { isc_log_write(JOURNAL_DEBUG_LOGARGS(3), - "applying diff to database (%u)", - db_serial); + "%s: applying diff to database (%u)", + j->filename, db_serial); (void)dns_diff_print(&diff, NULL); CHECK(dns_diff_apply(&diff, db, ver)); dns_diff_clear(&diff); @@ -1280,8 +1280,8 @@ roll_forward(dns_journal_t *j, dns_db_t *db) { if (n_put != 0) { isc_log_write(JOURNAL_DEBUG_LOGARGS(3), - "applying final diff to database (%u)", - db_serial); + "%s: applying final diff to database (%u)", + j->filename, db_serial); (void)dns_diff_print(&diff, NULL); CHECK(dns_diff_apply(&diff, db, ver)); dns_diff_clear(&diff); @@ -1352,7 +1352,8 @@ dns_journal_print(isc_mem_t *mctx, const char *filename, FILE *file) { if (result != ISC_R_SUCCESS) { isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR, - "journal open failure"); + "journal open failure: %s: %s", + isc_result_totext(result), j->filename); return (result); } @@ -1545,7 +1546,8 @@ read_one_rr(dns_journal_t *j) { CHECK(journal_read_xhdr(j, &xhdr)); if (xhdr.size == 0) { isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR, - "journal corrupt: empty transaction"); + "%s: journal corrupt: empty transaction", + j->filename); FAIL(ISC_R_UNEXPECTED); } if (xhdr.serial0 != j->it.current_serial) { diff --git a/contrib/bind9/lib/dns/key.c b/contrib/bind9/lib/dns/key.c new file mode 100644 index 000000000000..7abb2d7f6e97 --- /dev/null +++ b/contrib/bind9/lib/dns/key.c @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* $Id: key.c,v 1.1.4.1 2004/12/09 04:07:18 marka Exp $ */ + +#include <config.h> + +#include <stdlib.h> + +#include <isc/region.h> +#include <isc/util.h> + +#include <dns/keyvalues.h> + +#include <dst/dst.h> + +#include "dst_internal.h" + +isc_uint16_t +dst_region_computeid(const isc_region_t *source, unsigned int alg) { + isc_uint32_t ac; + const unsigned char *p; + int size; + + REQUIRE(source != NULL); + REQUIRE(source->length >= 4); + + p = source->base; + size = source->length; + + if (alg == DST_ALG_RSAMD5) + return ((p[size - 3] << 8) + p[size - 2]); + + for (ac = 0; size > 1; size -= 2, p += 2) + ac += ((*p) << 8) + *(p + 1); + + if (size > 0) + ac += ((*p) << 8); + ac += (ac >> 16) & 0xffff; + + return ((isc_uint16_t)(ac & 0xffff)); +} + +dns_name_t * +dst_key_name(const dst_key_t *key) { + REQUIRE(VALID_KEY(key)); + return (key->key_name); +} + +unsigned int +dst_key_size(const dst_key_t *key) { + REQUIRE(VALID_KEY(key)); + return (key->key_size); +} + +unsigned int +dst_key_proto(const dst_key_t *key) { + REQUIRE(VALID_KEY(key)); + return (key->key_proto); +} + +unsigned int +dst_key_alg(const dst_key_t *key) { + REQUIRE(VALID_KEY(key)); + return (key->key_alg); +} + +isc_uint32_t +dst_key_flags(const dst_key_t *key) { + REQUIRE(VALID_KEY(key)); + return (key->key_flags); +} + +dns_keytag_t +dst_key_id(const dst_key_t *key) { + REQUIRE(VALID_KEY(key)); + return (key->key_id); +} + +dns_rdataclass_t +dst_key_class(const dst_key_t *key) { + REQUIRE(VALID_KEY(key)); + return (key->key_class); +} + +isc_boolean_t +dst_key_iszonekey(const dst_key_t *key) { + REQUIRE(VALID_KEY(key)); + + if ((key->key_flags & DNS_KEYTYPE_NOAUTH) != 0) + return (ISC_FALSE); + if ((key->key_flags & DNS_KEYFLAG_OWNERMASK) != DNS_KEYOWNER_ZONE) + return (ISC_FALSE); + if (key->key_proto != DNS_KEYPROTO_DNSSEC && + key->key_proto != DNS_KEYPROTO_ANY) + return (ISC_FALSE); + return (ISC_TRUE); +} + +isc_boolean_t +dst_key_isnullkey(const dst_key_t *key) { + REQUIRE(VALID_KEY(key)); + + if ((key->key_flags & DNS_KEYFLAG_TYPEMASK) != DNS_KEYTYPE_NOKEY) + return (ISC_FALSE); + if ((key->key_flags & DNS_KEYFLAG_OWNERMASK) != DNS_KEYOWNER_ZONE) + return (ISC_FALSE); + if (key->key_proto != DNS_KEYPROTO_DNSSEC && + key->key_proto != DNS_KEYPROTO_ANY) + return (ISC_FALSE); + return (ISC_TRUE); +} diff --git a/contrib/bind9/lib/dns/openssl_link.c b/contrib/bind9/lib/dns/openssl_link.c new file mode 100644 index 000000000000..62eac05f30a0 --- /dev/null +++ b/contrib/bind9/lib/dns/openssl_link.c @@ -0,0 +1,219 @@ +/* + * Portions Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 1999-2003 Internet Software Consortium. + * Portions Copyright (C) 1995-2000 by Network Associates, Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE + * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Principal Author: Brian Wellington + * $Id: openssl_link.c,v 1.1.4.1 2004/12/09 04:07:18 marka Exp $ + */ +#ifdef OPENSSL + +#include <config.h> + +#include <isc/entropy.h> +#include <isc/mem.h> +#include <isc/mutex.h> +#include <isc/mutexblock.h> +#include <isc/string.h> +#include <isc/thread.h> +#include <isc/util.h> + +#include "dst_internal.h" +#include "dst_openssl.h" + +#include <openssl/err.h> +#include <openssl/rand.h> +#include <openssl/crypto.h> + +#if defined(CRYPTO_LOCK_ENGINE) && (OPENSSL_VERSION_NUMBER < 0x00907000L) +#define USE_ENGINE 1 +#endif + +#ifdef USE_ENGINE +#include <openssl/engine.h> +#endif + +static RAND_METHOD *rm = NULL; +static isc_mutex_t *locks = NULL; +static int nlocks; + +#ifdef USE_ENGINE +static ENGINE *e; +#endif + + +static int +entropy_get(unsigned char *buf, int num) { + isc_result_t result; + if (num < 0) + return (-1); + result = dst__entropy_getdata(buf, (unsigned int) num, ISC_FALSE); + return (result == ISC_R_SUCCESS ? num : -1); +} + +static int +entropy_getpseudo(unsigned char *buf, int num) { + isc_result_t result; + if (num < 0) + return (-1); + result = dst__entropy_getdata(buf, (unsigned int) num, ISC_TRUE); + return (result == ISC_R_SUCCESS ? num : -1); +} + +static void +entropy_add(const void *buf, int num, double entropy) { + /* + * Do nothing. The only call to this provides no useful data anyway. + */ + UNUSED(buf); + UNUSED(num); + UNUSED(entropy); +} + +static void +lock_callback(int mode, int type, const char *file, int line) { + UNUSED(file); + UNUSED(line); + if ((mode & CRYPTO_LOCK) != 0) + LOCK(&locks[type]); + else + UNLOCK(&locks[type]); +} + +static unsigned long +id_callback(void) { + return ((unsigned long)isc_thread_self()); +} + +static void * +mem_alloc(size_t size) { + INSIST(dst__memory_pool != NULL); + return (isc_mem_allocate(dst__memory_pool, size)); +} + +static void +mem_free(void *ptr) { + INSIST(dst__memory_pool != NULL); + if (ptr != NULL) + isc_mem_free(dst__memory_pool, ptr); +} + +static void * +mem_realloc(void *ptr, size_t size) { + void *p; + + INSIST(dst__memory_pool != NULL); + p = NULL; + if (size > 0U) { + p = mem_alloc(size); + if (p != NULL && ptr != NULL) + memcpy(p, ptr, size); + } + if (ptr != NULL) + mem_free(ptr); + return (p); +} + +isc_result_t +dst__openssl_init() { + isc_result_t result; + + CRYPTO_set_mem_functions(mem_alloc, mem_realloc, mem_free); + nlocks = CRYPTO_num_locks(); + locks = mem_alloc(sizeof(isc_mutex_t) * nlocks); + if (locks == NULL) + return (ISC_R_NOMEMORY); + result = isc_mutexblock_init(locks, nlocks); + if (result != ISC_R_SUCCESS) + goto cleanup_mutexalloc; + CRYPTO_set_locking_callback(lock_callback); + CRYPTO_set_id_callback(id_callback); + rm = mem_alloc(sizeof(RAND_METHOD)); + if (rm == NULL) { + result = ISC_R_NOMEMORY; + goto cleanup_mutexinit; + } + rm->seed = NULL; + rm->bytes = entropy_get; + rm->cleanup = NULL; + rm->add = entropy_add; + rm->pseudorand = entropy_getpseudo; + rm->status = NULL; +#ifdef USE_ENGINE + e = ENGINE_new(); + if (e == NULL) { + result = ISC_R_NOMEMORY; + goto cleanup_rm; + } + ENGINE_set_RAND(e, rm); + RAND_set_rand_method(e); +#else + RAND_set_rand_method(rm); +#endif + return (ISC_R_SUCCESS); + +#ifdef USE_ENGINE + cleanup_rm: + mem_free(rm); +#endif + cleanup_mutexinit: + DESTROYMUTEXBLOCK(locks, nlocks); + cleanup_mutexalloc: + mem_free(locks); + return (result); +} + +void +dst__openssl_destroy() { + ERR_clear_error(); +#ifdef USE_ENGINE + if (e != NULL) { + ENGINE_free(e); + e = NULL; + } +#endif + if (locks != NULL) { + DESTROYMUTEXBLOCK(locks, nlocks); + mem_free(locks); + } + if (rm != NULL) + mem_free(rm); +} + +isc_result_t +dst__openssl_toresult(isc_result_t fallback) { + isc_result_t result = fallback; + int err = ERR_get_error(); + + switch (ERR_GET_REASON(err)) { + case ERR_R_MALLOC_FAILURE: + result = ISC_R_NOMEMORY; + break; + default: + break; + } + ERR_clear_error(); + return (result); +} + +#else /* OPENSSL */ + +#include <isc/util.h> + +EMPTY_TRANSLATION_UNIT + +#endif /* OPENSSL */ diff --git a/contrib/bind9/lib/dns/openssldh_link.c b/contrib/bind9/lib/dns/openssldh_link.c new file mode 100644 index 000000000000..24255834d780 --- /dev/null +++ b/contrib/bind9/lib/dns/openssldh_link.c @@ -0,0 +1,608 @@ +/* + * Portions Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 1999-2002 Internet Software Consortium. + * Portions Copyright (C) 1995-2000 by Network Associates, Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE + * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Principal Author: Brian Wellington + * $Id: openssldh_link.c,v 1.1.4.1 2004/12/09 04:07:18 marka Exp $ + */ + +#ifdef OPENSSL + +#include <config.h> + +#include <ctype.h> + +#include <isc/mem.h> +#include <isc/string.h> +#include <isc/util.h> + +#include <dst/result.h> + +#include "dst_internal.h" +#include "dst_openssl.h" +#include "dst_parse.h" + +#include <openssl/dh.h> + +#define PRIME768 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088" \ + "A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25" \ + "F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF" + +#define PRIME1024 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" \ + "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF2" \ + "5F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406" \ + "B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF" + +#define PRIME1536 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \ + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \ + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \ + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \ + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \ + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" \ + "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF" + + +static isc_result_t openssldh_todns(const dst_key_t *key, isc_buffer_t *data); + +static BIGNUM bn2, bn768, bn1024, bn1536; + +static isc_result_t +openssldh_computesecret(const dst_key_t *pub, const dst_key_t *priv, + isc_buffer_t *secret) +{ + DH *dhpub, *dhpriv; + int ret; + isc_region_t r; + unsigned int len; + + REQUIRE(pub->opaque != NULL); + REQUIRE(priv->opaque != NULL); + + dhpub = (DH *) pub->opaque; + dhpriv = (DH *) priv->opaque; + + len = DH_size(dhpriv); + isc_buffer_availableregion(secret, &r); + if (r.length < len) + return (ISC_R_NOSPACE); + ret = DH_compute_key(r.base, dhpub->pub_key, dhpriv); + if (ret == 0) + return (dst__openssl_toresult(DST_R_COMPUTESECRETFAILURE)); + isc_buffer_add(secret, len); + return (ISC_R_SUCCESS); +} + +static isc_boolean_t +openssldh_compare(const dst_key_t *key1, const dst_key_t *key2) { + int status; + DH *dh1, *dh2; + + dh1 = (DH *) key1->opaque; + dh2 = (DH *) key2->opaque; + + if (dh1 == NULL && dh2 == NULL) + return (ISC_TRUE); + else if (dh1 == NULL || dh2 == NULL) + return (ISC_FALSE); + + status = BN_cmp(dh1->p, dh2->p) || + BN_cmp(dh1->g, dh2->g) || + BN_cmp(dh1->pub_key, dh2->pub_key); + + if (status != 0) + return (ISC_FALSE); + + if (dh1->priv_key != NULL || dh2->priv_key != NULL) { + if (dh1->priv_key == NULL || dh2->priv_key == NULL) + return (ISC_FALSE); + if (BN_cmp(dh1->priv_key, dh2->priv_key) != 0) + return (ISC_FALSE); + } + return (ISC_TRUE); +} + +static isc_boolean_t +openssldh_paramcompare(const dst_key_t *key1, const dst_key_t *key2) { + int status; + DH *dh1, *dh2; + + dh1 = (DH *) key1->opaque; + dh2 = (DH *) key2->opaque; + + if (dh1 == NULL && dh2 == NULL) + return (ISC_TRUE); + else if (dh1 == NULL || dh2 == NULL) + return (ISC_FALSE); + + status = BN_cmp(dh1->p, dh2->p) || + BN_cmp(dh1->g, dh2->g); + + if (status != 0) + return (ISC_FALSE); + return (ISC_TRUE); +} + +static isc_result_t +openssldh_generate(dst_key_t *key, int generator) { + DH *dh = NULL; + + if (generator == 0) { + if (key->key_size == 768 || + key->key_size == 1024 || + key->key_size == 1536) + { + dh = DH_new(); + if (dh == NULL) + return (ISC_R_NOMEMORY); + if (key->key_size == 768) + dh->p = &bn768; + else if (key->key_size == 1024) + dh->p = &bn1024; + else + dh->p = &bn1536; + dh->g = &bn2; + } + else + generator = 2; + } + + if (generator != 0) + dh = DH_generate_parameters(key->key_size, generator, + NULL, NULL); + + if (dh == NULL) + return (dst__openssl_toresult(DST_R_OPENSSLFAILURE)); + + if (DH_generate_key(dh) == 0) { + DH_free(dh); + return (dst__openssl_toresult(DST_R_OPENSSLFAILURE)); + } + dh->flags &= ~DH_FLAG_CACHE_MONT_P; + + key->opaque = dh; + + return (ISC_R_SUCCESS); +} + +static isc_boolean_t +openssldh_isprivate(const dst_key_t *key) { + DH *dh = (DH *) key->opaque; + return (ISC_TF(dh != NULL && dh->priv_key != NULL)); +} + +static void +openssldh_destroy(dst_key_t *key) { + DH *dh = key->opaque; + + if (dh == NULL) + return; + + if (dh->p == &bn768 || dh->p == &bn1024 || dh->p == &bn1536) + dh->p = NULL; + if (dh->g == &bn2) + dh->g = NULL; + DH_free(dh); + key->opaque = NULL; +} + +static void +uint16_toregion(isc_uint16_t val, isc_region_t *region) { + *region->base++ = (val & 0xff00) >> 8; + *region->base++ = (val & 0x00ff); +} + +static isc_uint16_t +uint16_fromregion(isc_region_t *region) { + isc_uint16_t val; + unsigned char *cp = region->base; + + val = ((unsigned int)(cp[0])) << 8; + val |= ((unsigned int)(cp[1])); + + region->base += 2; + return (val); +} + +static isc_result_t +openssldh_todns(const dst_key_t *key, isc_buffer_t *data) { + DH *dh; + isc_region_t r; + isc_uint16_t dnslen, plen, glen, publen; + + REQUIRE(key->opaque != NULL); + + dh = (DH *) key->opaque; + + isc_buffer_availableregion(data, &r); + + if (dh->g == &bn2 && + (dh->p == &bn768 || dh->p == &bn1024 || dh->p == &bn1536)) { + plen = 1; + glen = 0; + } + else { + plen = BN_num_bytes(dh->p); + glen = BN_num_bytes(dh->g); + } + publen = BN_num_bytes(dh->pub_key); + dnslen = plen + glen + publen + 6; + if (r.length < (unsigned int) dnslen) + return (ISC_R_NOSPACE); + + uint16_toregion(plen, &r); + if (plen == 1) { + if (dh->p == &bn768) + *r.base = 1; + else if (dh->p == &bn1024) + *r.base = 2; + else + *r.base = 3; + } + else + BN_bn2bin(dh->p, r.base); + r.base += plen; + + uint16_toregion(glen, &r); + if (glen > 0) + BN_bn2bin(dh->g, r.base); + r.base += glen; + + uint16_toregion(publen, &r); + BN_bn2bin(dh->pub_key, r.base); + r.base += publen; + + isc_buffer_add(data, dnslen); + + return (ISC_R_SUCCESS); +} + +static isc_result_t +openssldh_fromdns(dst_key_t *key, isc_buffer_t *data) { + DH *dh; + isc_region_t r; + isc_uint16_t plen, glen, publen; + int special = 0; + + isc_buffer_remainingregion(data, &r); + if (r.length == 0) + return (ISC_R_SUCCESS); + + dh = DH_new(); + if (dh == NULL) + return (ISC_R_NOMEMORY); + dh->flags &= ~DH_FLAG_CACHE_MONT_P; + + /* + * Read the prime length. 1 & 2 are table entries, > 16 means a + * prime follows, otherwise an error. + */ + if (r.length < 2) { + DH_free(dh); + return (DST_R_INVALIDPUBLICKEY); + } + plen = uint16_fromregion(&r); + if (plen < 16 && plen != 1 && plen != 2) { + DH_free(dh); + return (DST_R_INVALIDPUBLICKEY); + } + if (r.length < plen) { + DH_free(dh); + return (DST_R_INVALIDPUBLICKEY); + } + if (plen == 1 || plen == 2) { + if (plen == 1) + special = *r.base++; + else + special = uint16_fromregion(&r); + switch (special) { + case 1: + dh->p = &bn768; + break; + case 2: + dh->p = &bn1024; + break; + case 3: + dh->p = &bn1536; + break; + default: + DH_free(dh); + return (DST_R_INVALIDPUBLICKEY); + } + } + else { + dh->p = BN_bin2bn(r.base, plen, NULL); + r.base += plen; + } + + /* + * Read the generator length. This should be 0 if the prime was + * special, but it might not be. If it's 0 and the prime is not + * special, we have a problem. + */ + if (r.length < 2) { + DH_free(dh); + return (DST_R_INVALIDPUBLICKEY); + } + glen = uint16_fromregion(&r); + if (r.length < glen) { + DH_free(dh); + return (DST_R_INVALIDPUBLICKEY); + } + if (special != 0) { + if (glen == 0) + dh->g = &bn2; + else { + dh->g = BN_bin2bn(r.base, glen, NULL); + if (BN_cmp(dh->g, &bn2) == 0) { + BN_free(dh->g); + dh->g = &bn2; + } + else { + DH_free(dh); + return (DST_R_INVALIDPUBLICKEY); + } + } + } + else { + if (glen == 0) { + DH_free(dh); + return (DST_R_INVALIDPUBLICKEY); + } + dh->g = BN_bin2bn(r.base, glen, NULL); + } + r.base += glen; + + if (r.length < 2) { + DH_free(dh); + return (DST_R_INVALIDPUBLICKEY); + } + publen = uint16_fromregion(&r); + if (r.length < publen) { + DH_free(dh); + return (DST_R_INVALIDPUBLICKEY); + } + dh->pub_key = BN_bin2bn(r.base, publen, NULL); + r.base += publen; + + key->key_size = BN_num_bits(dh->p); + + isc_buffer_forward(data, plen + glen + publen + 6); + + key->opaque = (void *) dh; + + return (ISC_R_SUCCESS); +} + +static isc_result_t +openssldh_tofile(const dst_key_t *key, const char *directory) { + int i; + DH *dh; + dst_private_t priv; + unsigned char *bufs[4]; + isc_result_t result; + + if (key->opaque == NULL) + return (DST_R_NULLKEY); + + dh = (DH *) key->opaque; + + for (i = 0; i < 4; i++) { + bufs[i] = isc_mem_get(key->mctx, BN_num_bytes(dh->p)); + if (bufs[i] == NULL) { + result = ISC_R_NOMEMORY; + goto fail; + } + } + + i = 0; + + priv.elements[i].tag = TAG_DH_PRIME; + priv.elements[i].length = BN_num_bytes(dh->p); + BN_bn2bin(dh->p, bufs[i]); + priv.elements[i].data = bufs[i]; + i++; + + priv.elements[i].tag = TAG_DH_GENERATOR; + priv.elements[i].length = BN_num_bytes(dh->g); + BN_bn2bin(dh->g, bufs[i]); + priv.elements[i].data = bufs[i]; + i++; + + priv.elements[i].tag = TAG_DH_PRIVATE; + priv.elements[i].length = BN_num_bytes(dh->priv_key); + BN_bn2bin(dh->priv_key, bufs[i]); + priv.elements[i].data = bufs[i]; + i++; + + priv.elements[i].tag = TAG_DH_PUBLIC; + priv.elements[i].length = BN_num_bytes(dh->pub_key); + BN_bn2bin(dh->pub_key, bufs[i]); + priv.elements[i].data = bufs[i]; + i++; + + priv.nelements = i; + result = dst__privstruct_writefile(key, &priv, directory); + fail: + for (i = 0; i < 4; i++) { + if (bufs[i] == NULL) + break; + isc_mem_put(key->mctx, bufs[i], BN_num_bytes(dh->p)); + } + return (result); +} + +static isc_result_t +openssldh_parse(dst_key_t *key, isc_lex_t *lexer) { + dst_private_t priv; + isc_result_t ret; + int i; + DH *dh = NULL; + isc_mem_t *mctx; +#define DST_RET(a) {ret = a; goto err;} + + mctx = key->mctx; + + /* read private key file */ + ret = dst__privstruct_parse(key, DST_ALG_DH, lexer, mctx, &priv); + if (ret != ISC_R_SUCCESS) + return (ret); + + dh = DH_new(); + if (dh == NULL) + DST_RET(ISC_R_NOMEMORY); + dh->flags &= ~DH_FLAG_CACHE_MONT_P; + key->opaque = dh; + + for (i = 0; i < priv.nelements; i++) { + BIGNUM *bn; + bn = BN_bin2bn(priv.elements[i].data, + priv.elements[i].length, NULL); + if (bn == NULL) + DST_RET(ISC_R_NOMEMORY); + + switch (priv.elements[i].tag) { + case TAG_DH_PRIME: + dh->p = bn; + break; + case TAG_DH_GENERATOR: + dh->g = bn; + break; + case TAG_DH_PRIVATE: + dh->priv_key = bn; + break; + case TAG_DH_PUBLIC: + dh->pub_key = bn; + break; + } + } + dst__privstruct_free(&priv, mctx); + + key->key_size = BN_num_bits(dh->p); + + if ((key->key_size == 768 || + key->key_size == 1024 || + key->key_size == 1536) && + BN_cmp(dh->g, &bn2) == 0) + { + if (key->key_size == 768 && BN_cmp(dh->p, &bn768) == 0) { + BN_free(dh->p); + BN_free(dh->g); + dh->p = &bn768; + dh->g = &bn2; + } else if (key->key_size == 1024 && + BN_cmp(dh->p, &bn1024) == 0) { + BN_free(dh->p); + BN_free(dh->g); + dh->p = &bn1024; + dh->g = &bn2; + } else if (key->key_size == 1536 && + BN_cmp(dh->p, &bn1536) == 0) { + BN_free(dh->p); + BN_free(dh->g); + dh->p = &bn1536; + dh->g = &bn2; + } + } + + return (ISC_R_SUCCESS); + + err: + openssldh_destroy(key); + dst__privstruct_free(&priv, mctx); + memset(&priv, 0, sizeof(priv)); + return (ret); +} + +static void +BN_fromhex(BIGNUM *b, const char *str) { + static const char hexdigits[] = "0123456789abcdef"; + unsigned char data[512]; + unsigned int i; + BIGNUM *out; + + RUNTIME_CHECK(strlen(str) < 1024U && strlen(str) % 2 == 0U); + for (i = 0; i < strlen(str); i += 2) { + char *s; + unsigned int high, low; + + s = strchr(hexdigits, tolower((unsigned char)str[i])); + RUNTIME_CHECK(s != NULL); + high = s - hexdigits; + + s = strchr(hexdigits, tolower((unsigned char)str[i + 1])); + RUNTIME_CHECK(s != NULL); + low = s - hexdigits; + + data[i/2] = (unsigned char)((high << 4) + low); + } + out = BN_bin2bn(data, strlen(str)/2, b); + RUNTIME_CHECK(out != NULL); +} + +static void +openssldh_cleanup(void) { + BN_free(&bn2); + BN_free(&bn768); + BN_free(&bn1024); + BN_free(&bn1536); +} + +static dst_func_t openssldh_functions = { + NULL, /* createctx */ + NULL, /* destroyctx */ + NULL, /* adddata */ + NULL, /* openssldh_sign */ + NULL, /* openssldh_verify */ + openssldh_computesecret, + openssldh_compare, + openssldh_paramcompare, + openssldh_generate, + openssldh_isprivate, + openssldh_destroy, + openssldh_todns, + openssldh_fromdns, + openssldh_tofile, + openssldh_parse, + openssldh_cleanup, +}; + +isc_result_t +dst__openssldh_init(dst_func_t **funcp) { + REQUIRE(funcp != NULL); + if (*funcp == NULL) { + BN_init(&bn2); + BN_init(&bn768); + BN_init(&bn1024); + BN_init(&bn1536); + BN_set_word(&bn2, 2); + BN_fromhex(&bn768, PRIME768); + BN_fromhex(&bn1024, PRIME1024); + BN_fromhex(&bn1536, PRIME1536); + *funcp = &openssldh_functions; + } + return (ISC_R_SUCCESS); +} + +#else /* OPENSSL */ + +#include <isc/util.h> + +EMPTY_TRANSLATION_UNIT + +#endif /* OPENSSL */ diff --git a/contrib/bind9/lib/dns/openssldsa_link.c b/contrib/bind9/lib/dns/openssldsa_link.c new file mode 100644 index 000000000000..ac84a6565be4 --- /dev/null +++ b/contrib/bind9/lib/dns/openssldsa_link.c @@ -0,0 +1,443 @@ +/* + * Portions Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 1999-2002 Internet Software Consortium. + * Portions Copyright (C) 1995-2000 by Network Associates, Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE + * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* $Id: openssldsa_link.c,v 1.1.4.1 2004/12/09 04:07:18 marka Exp $ */ + +#ifdef OPENSSL + +#include <config.h> + +#include <string.h> + +#include <isc/entropy.h> +#include <isc/mem.h> +#include <isc/sha1.h> +#include <isc/util.h> + +#include <dst/result.h> + +#include "dst_internal.h" +#include "dst_openssl.h" +#include "dst_parse.h" + +#include <openssl/dsa.h> + +static isc_result_t openssldsa_todns(const dst_key_t *key, isc_buffer_t *data); + +static isc_result_t +openssldsa_createctx(dst_key_t *key, dst_context_t *dctx) { + isc_sha1_t *sha1ctx; + + UNUSED(key); + + sha1ctx = isc_mem_get(dctx->mctx, sizeof(isc_sha1_t)); + isc_sha1_init(sha1ctx); + dctx->opaque = sha1ctx; + return (ISC_R_SUCCESS); +} + +static void +openssldsa_destroyctx(dst_context_t *dctx) { + isc_sha1_t *sha1ctx = dctx->opaque; + + if (sha1ctx != NULL) { + isc_sha1_invalidate(sha1ctx); + isc_mem_put(dctx->mctx, sha1ctx, sizeof(isc_sha1_t)); + dctx->opaque = NULL; + } +} + +static isc_result_t +openssldsa_adddata(dst_context_t *dctx, const isc_region_t *data) { + isc_sha1_t *sha1ctx = dctx->opaque; + + isc_sha1_update(sha1ctx, data->base, data->length); + return (ISC_R_SUCCESS); +} + +static int +BN_bn2bin_fixed(BIGNUM *bn, unsigned char *buf, int size) { + int bytes = size - BN_num_bytes(bn); + while (bytes-- > 0) + *buf++ = 0; + BN_bn2bin(bn, buf); + return (size); +} + +static isc_result_t +openssldsa_sign(dst_context_t *dctx, isc_buffer_t *sig) { + isc_sha1_t *sha1ctx = dctx->opaque; + dst_key_t *key = dctx->key; + DSA *dsa = key->opaque; + DSA_SIG *dsasig; + isc_region_t r; + unsigned char digest[ISC_SHA1_DIGESTLENGTH]; + + isc_buffer_availableregion(sig, &r); + if (r.length < ISC_SHA1_DIGESTLENGTH * 2 + 1) + return (ISC_R_NOSPACE); + + isc_sha1_final(sha1ctx, digest); + + dsasig = DSA_do_sign(digest, ISC_SHA1_DIGESTLENGTH, dsa); + if (dsasig == NULL) + return (dst__openssl_toresult(DST_R_SIGNFAILURE)); + + *r.base++ = (key->key_size - 512)/64; + BN_bn2bin_fixed(dsasig->r, r.base, ISC_SHA1_DIGESTLENGTH); + r.base += ISC_SHA1_DIGESTLENGTH; + BN_bn2bin_fixed(dsasig->s, r.base, ISC_SHA1_DIGESTLENGTH); + r.base += ISC_SHA1_DIGESTLENGTH; + DSA_SIG_free(dsasig); + isc_buffer_add(sig, ISC_SHA1_DIGESTLENGTH * 2 + 1); + + return (ISC_R_SUCCESS); +} + +static isc_result_t +openssldsa_verify(dst_context_t *dctx, const isc_region_t *sig) { + isc_sha1_t *sha1ctx = dctx->opaque; + dst_key_t *key = dctx->key; + DSA *dsa = key->opaque; + DSA_SIG *dsasig; + int status = 0; + unsigned char digest[ISC_SHA1_DIGESTLENGTH]; + unsigned char *cp = sig->base; + + isc_sha1_final(sha1ctx, digest); + + if (sig->length < 2 * ISC_SHA1_DIGESTLENGTH + 1) + return (DST_R_VERIFYFAILURE); + + cp++; /* Skip T */ + dsasig = DSA_SIG_new(); + dsasig->r = BN_bin2bn(cp, ISC_SHA1_DIGESTLENGTH, NULL); + cp += ISC_SHA1_DIGESTLENGTH; + dsasig->s = BN_bin2bn(cp, ISC_SHA1_DIGESTLENGTH, NULL); + cp += ISC_SHA1_DIGESTLENGTH; + + status = DSA_do_verify(digest, ISC_SHA1_DIGESTLENGTH, dsasig, dsa); + DSA_SIG_free(dsasig); + if (status == 0) + return (dst__openssl_toresult(DST_R_VERIFYFAILURE)); + + return (ISC_R_SUCCESS); +} + +static isc_boolean_t +openssldsa_compare(const dst_key_t *key1, const dst_key_t *key2) { + int status; + DSA *dsa1, *dsa2; + + dsa1 = (DSA *) key1->opaque; + dsa2 = (DSA *) key2->opaque; + + if (dsa1 == NULL && dsa2 == NULL) + return (ISC_TRUE); + else if (dsa1 == NULL || dsa2 == NULL) + return (ISC_FALSE); + + status = BN_cmp(dsa1->p, dsa2->p) || + BN_cmp(dsa1->q, dsa2->q) || + BN_cmp(dsa1->g, dsa2->g) || + BN_cmp(dsa1->pub_key, dsa2->pub_key); + + if (status != 0) + return (ISC_FALSE); + + if (dsa1->priv_key != NULL || dsa2->priv_key != NULL) { + if (dsa1->priv_key == NULL || dsa2->priv_key == NULL) + return (ISC_FALSE); + if (BN_cmp(dsa1->priv_key, dsa2->priv_key)) + return (ISC_FALSE); + } + return (ISC_TRUE); +} + +static isc_result_t +openssldsa_generate(dst_key_t *key, int unused) { + DSA *dsa; + unsigned char rand_array[ISC_SHA1_DIGESTLENGTH]; + isc_result_t result; + + UNUSED(unused); + + result = dst__entropy_getdata(rand_array, sizeof(rand_array), + ISC_FALSE); + if (result != ISC_R_SUCCESS) + return (result); + + dsa = DSA_generate_parameters(key->key_size, rand_array, + ISC_SHA1_DIGESTLENGTH, NULL, NULL, + NULL, NULL); + + if (dsa == NULL) + return (dst__openssl_toresult(DST_R_OPENSSLFAILURE)); + + if (DSA_generate_key(dsa) == 0) { + DSA_free(dsa); + return (dst__openssl_toresult(DST_R_OPENSSLFAILURE)); + } + dsa->flags &= ~DSA_FLAG_CACHE_MONT_P; + + key->opaque = dsa; + + return (ISC_R_SUCCESS); +} + +static isc_boolean_t +openssldsa_isprivate(const dst_key_t *key) { + DSA *dsa = (DSA *) key->opaque; + return (ISC_TF(dsa != NULL && dsa->priv_key != NULL)); +} + +static void +openssldsa_destroy(dst_key_t *key) { + DSA *dsa = key->opaque; + DSA_free(dsa); + key->opaque = NULL; +} + + +static isc_result_t +openssldsa_todns(const dst_key_t *key, isc_buffer_t *data) { + DSA *dsa; + isc_region_t r; + int dnslen; + unsigned int t, p_bytes; + + REQUIRE(key->opaque != NULL); + + dsa = (DSA *) key->opaque; + + isc_buffer_availableregion(data, &r); + + t = (BN_num_bytes(dsa->p) - 64) / 8; + if (t > 8) + return (DST_R_INVALIDPUBLICKEY); + p_bytes = 64 + 8 * t; + + dnslen = 1 + (key->key_size * 3)/8 + ISC_SHA1_DIGESTLENGTH; + if (r.length < (unsigned int) dnslen) + return (ISC_R_NOSPACE); + + *r.base++ = t; + BN_bn2bin_fixed(dsa->q, r.base, ISC_SHA1_DIGESTLENGTH); + r.base += ISC_SHA1_DIGESTLENGTH; + BN_bn2bin_fixed(dsa->p, r.base, key->key_size/8); + r.base += p_bytes; + BN_bn2bin_fixed(dsa->g, r.base, key->key_size/8); + r.base += p_bytes; + BN_bn2bin_fixed(dsa->pub_key, r.base, key->key_size/8); + r.base += p_bytes; + + isc_buffer_add(data, dnslen); + + return (ISC_R_SUCCESS); +} + +static isc_result_t +openssldsa_fromdns(dst_key_t *key, isc_buffer_t *data) { + DSA *dsa; + isc_region_t r; + unsigned int t, p_bytes; + isc_mem_t *mctx = key->mctx; + + UNUSED(mctx); + + isc_buffer_remainingregion(data, &r); + if (r.length == 0) + return (ISC_R_SUCCESS); + + dsa = DSA_new(); + if (dsa == NULL) + return (ISC_R_NOMEMORY); + dsa->flags &= ~DSA_FLAG_CACHE_MONT_P; + + t = (unsigned int) *r.base++; + if (t > 8) { + DSA_free(dsa); + return (DST_R_INVALIDPUBLICKEY); + } + p_bytes = 64 + 8 * t; + + if (r.length < 1 + ISC_SHA1_DIGESTLENGTH + 3 * p_bytes) { + DSA_free(dsa); + return (DST_R_INVALIDPUBLICKEY); + } + + dsa->q = BN_bin2bn(r.base, ISC_SHA1_DIGESTLENGTH, NULL); + r.base += ISC_SHA1_DIGESTLENGTH; + + dsa->p = BN_bin2bn(r.base, p_bytes, NULL); + r.base += p_bytes; + + dsa->g = BN_bin2bn(r.base, p_bytes, NULL); + r.base += p_bytes; + + dsa->pub_key = BN_bin2bn(r.base, p_bytes, NULL); + r.base += p_bytes; + + key->key_size = p_bytes * 8; + + isc_buffer_forward(data, 1 + ISC_SHA1_DIGESTLENGTH + 3 * p_bytes); + + key->opaque = (void *) dsa; + + return (ISC_R_SUCCESS); +} + + +static isc_result_t +openssldsa_tofile(const dst_key_t *key, const char *directory) { + int cnt = 0; + DSA *dsa; + dst_private_t priv; + unsigned char bufs[5][128]; + + if (key->opaque == NULL) + return (DST_R_NULLKEY); + + dsa = (DSA *) key->opaque; + + priv.elements[cnt].tag = TAG_DSA_PRIME; + priv.elements[cnt].length = BN_num_bytes(dsa->p); + BN_bn2bin(dsa->p, bufs[cnt]); + priv.elements[cnt].data = bufs[cnt]; + cnt++; + + priv.elements[cnt].tag = TAG_DSA_SUBPRIME; + priv.elements[cnt].length = BN_num_bytes(dsa->q); + BN_bn2bin(dsa->q, bufs[cnt]); + priv.elements[cnt].data = bufs[cnt]; + cnt++; + + priv.elements[cnt].tag = TAG_DSA_BASE; + priv.elements[cnt].length = BN_num_bytes(dsa->g); + BN_bn2bin(dsa->g, bufs[cnt]); + priv.elements[cnt].data = bufs[cnt]; + cnt++; + + priv.elements[cnt].tag = TAG_DSA_PRIVATE; + priv.elements[cnt].length = BN_num_bytes(dsa->priv_key); + BN_bn2bin(dsa->priv_key, bufs[cnt]); + priv.elements[cnt].data = bufs[cnt]; + cnt++; + + priv.elements[cnt].tag = TAG_DSA_PUBLIC; + priv.elements[cnt].length = BN_num_bytes(dsa->pub_key); + BN_bn2bin(dsa->pub_key, bufs[cnt]); + priv.elements[cnt].data = bufs[cnt]; + cnt++; + + priv.nelements = cnt; + return (dst__privstruct_writefile(key, &priv, directory)); +} + +static isc_result_t +openssldsa_parse(dst_key_t *key, isc_lex_t *lexer) { + dst_private_t priv; + isc_result_t ret; + int i; + DSA *dsa = NULL; + isc_mem_t *mctx = key->mctx; +#define DST_RET(a) {ret = a; goto err;} + + /* read private key file */ + ret = dst__privstruct_parse(key, DST_ALG_DSA, lexer, mctx, &priv); + if (ret != ISC_R_SUCCESS) + return (ret); + + dsa = DSA_new(); + if (dsa == NULL) + DST_RET(ISC_R_NOMEMORY); + dsa->flags &= ~DSA_FLAG_CACHE_MONT_P; + key->opaque = dsa; + + for (i=0; i < priv.nelements; i++) { + BIGNUM *bn; + bn = BN_bin2bn(priv.elements[i].data, + priv.elements[i].length, NULL); + if (bn == NULL) + DST_RET(ISC_R_NOMEMORY); + + switch (priv.elements[i].tag) { + case TAG_DSA_PRIME: + dsa->p = bn; + break; + case TAG_DSA_SUBPRIME: + dsa->q = bn; + break; + case TAG_DSA_BASE: + dsa->g = bn; + break; + case TAG_DSA_PRIVATE: + dsa->priv_key = bn; + break; + case TAG_DSA_PUBLIC: + dsa->pub_key = bn; + break; + } + } + dst__privstruct_free(&priv, mctx); + + key->key_size = BN_num_bits(dsa->p); + + return (ISC_R_SUCCESS); + + err: + openssldsa_destroy(key); + dst__privstruct_free(&priv, mctx); + memset(&priv, 0, sizeof(priv)); + return (ret); +} + +static dst_func_t openssldsa_functions = { + openssldsa_createctx, + openssldsa_destroyctx, + openssldsa_adddata, + openssldsa_sign, + openssldsa_verify, + NULL, /* computesecret */ + openssldsa_compare, + NULL, /* paramcompare */ + openssldsa_generate, + openssldsa_isprivate, + openssldsa_destroy, + openssldsa_todns, + openssldsa_fromdns, + openssldsa_tofile, + openssldsa_parse, + NULL, /* cleanup */ +}; + +isc_result_t +dst__openssldsa_init(dst_func_t **funcp) { + REQUIRE(funcp != NULL); + if (*funcp == NULL) + *funcp = &openssldsa_functions; + return (ISC_R_SUCCESS); +} + +#else /* OPENSSL */ + +#include <isc/util.h> + +EMPTY_TRANSLATION_UNIT + +#endif /* OPENSSL */ diff --git a/contrib/bind9/lib/dns/opensslrsa_link.c b/contrib/bind9/lib/dns/opensslrsa_link.c new file mode 100644 index 000000000000..0d4426bfabef --- /dev/null +++ b/contrib/bind9/lib/dns/opensslrsa_link.c @@ -0,0 +1,567 @@ +/* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000-2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Principal Author: Brian Wellington + * $Id: opensslrsa_link.c,v 1.1.4.1 2004/12/09 04:07:18 marka Exp $ + */ +#ifdef OPENSSL + +#include <config.h> + +#include <isc/entropy.h> +#include <isc/md5.h> +#include <isc/sha1.h> +#include <isc/mem.h> +#include <isc/string.h> +#include <isc/util.h> + +#include <dst/result.h> + +#include "dst_internal.h" +#include "dst_openssl.h" +#include "dst_parse.h" + +#include <openssl/err.h> +#include <openssl/objects.h> +#include <openssl/rsa.h> + + /* + * XXXMPA Temporarially disable RSA_BLINDING as it requires + * good quality random data that cannot currently be guarenteed. + * XXXMPA Find which versions of openssl use pseudo random data + * and set RSA_FLAG_BLINDING for those. + */ + +#if 0 +#if OPENSSL_VERSION_NUMBER < 0x0090601fL +#define SET_FLAGS(rsa) \ + do { \ + (rsa)->flags &= ~(RSA_FLAG_CACHE_PUBLIC | RSA_FLAG_CACHE_PRIVATE); \ + (rsa)->flags |= RSA_FLAG_BLINDING; \ + } while (0) +#else +#define SET_FLAGS(rsa) \ + do { \ + (rsa)->flags |= RSA_FLAG_BLINDING; \ + } while (0) +#endif +#endif + +#if OPENSSL_VERSION_NUMBER < 0x0090601fL +#define SET_FLAGS(rsa) \ + do { \ + (rsa)->flags &= ~(RSA_FLAG_CACHE_PUBLIC | RSA_FLAG_CACHE_PRIVATE); \ + (rsa)->flags &= ~RSA_FLAG_BLINDING; \ + } while (0) +#else +#define SET_FLAGS(rsa) \ + do { \ + (rsa)->flags &= ~RSA_FLAG_BLINDING; \ + } while (0) +#endif + +static isc_result_t opensslrsa_todns(const dst_key_t *key, isc_buffer_t *data); + +static isc_result_t +opensslrsa_createctx(dst_key_t *key, dst_context_t *dctx) { + UNUSED(key); + REQUIRE(dctx->key->key_alg == DST_ALG_RSAMD5 || + dctx->key->key_alg == DST_ALG_RSASHA1); + + if (dctx->key->key_alg == DST_ALG_RSAMD5) { + isc_md5_t *md5ctx; + + md5ctx = isc_mem_get(dctx->mctx, sizeof(isc_md5_t)); + isc_md5_init(md5ctx); + dctx->opaque = md5ctx; + } else { + isc_sha1_t *sha1ctx; + + sha1ctx = isc_mem_get(dctx->mctx, sizeof(isc_sha1_t)); + isc_sha1_init(sha1ctx); + dctx->opaque = sha1ctx; + } + + return (ISC_R_SUCCESS); +} + +static void +opensslrsa_destroyctx(dst_context_t *dctx) { + REQUIRE(dctx->key->key_alg == DST_ALG_RSAMD5 || + dctx->key->key_alg == DST_ALG_RSASHA1); + + if (dctx->key->key_alg == DST_ALG_RSAMD5) { + isc_md5_t *md5ctx = dctx->opaque; + + if (md5ctx != NULL) { + isc_md5_invalidate(md5ctx); + isc_mem_put(dctx->mctx, md5ctx, sizeof(isc_md5_t)); + } + } else { + isc_sha1_t *sha1ctx = dctx->opaque; + + if (sha1ctx != NULL) { + isc_sha1_invalidate(sha1ctx); + isc_mem_put(dctx->mctx, sha1ctx, sizeof(isc_sha1_t)); + } + } + dctx->opaque = NULL; +} + +static isc_result_t +opensslrsa_adddata(dst_context_t *dctx, const isc_region_t *data) { + REQUIRE(dctx->key->key_alg == DST_ALG_RSAMD5 || + dctx->key->key_alg == DST_ALG_RSASHA1); + + if (dctx->key->key_alg == DST_ALG_RSAMD5) { + isc_md5_t *md5ctx = dctx->opaque; + isc_md5_update(md5ctx, data->base, data->length); + } else { + isc_sha1_t *sha1ctx = dctx->opaque; + isc_sha1_update(sha1ctx, data->base, data->length); + } + return (ISC_R_SUCCESS); +} + +static isc_result_t +opensslrsa_sign(dst_context_t *dctx, isc_buffer_t *sig) { + dst_key_t *key = dctx->key; + RSA *rsa = key->opaque; + isc_region_t r; + /* note: ISC_SHA1_DIGESTLENGTH > ISC_MD5_DIGESTLENGTH */ + unsigned char digest[ISC_SHA1_DIGESTLENGTH]; + unsigned int siglen = 0; + int status; + int type; + unsigned int digestlen; + char *message; + unsigned long err; + const char* file; + int line; + + REQUIRE(dctx->key->key_alg == DST_ALG_RSAMD5 || + dctx->key->key_alg == DST_ALG_RSASHA1); + + isc_buffer_availableregion(sig, &r); + + if (r.length < (unsigned int) RSA_size(rsa)) + return (ISC_R_NOSPACE); + + if (dctx->key->key_alg == DST_ALG_RSAMD5) { + isc_md5_t *md5ctx = dctx->opaque; + isc_md5_final(md5ctx, digest); + type = NID_md5; + digestlen = ISC_MD5_DIGESTLENGTH; + } else { + isc_sha1_t *sha1ctx = dctx->opaque; + isc_sha1_final(sha1ctx, digest); + type = NID_sha1; + digestlen = ISC_SHA1_DIGESTLENGTH; + } + + status = RSA_sign(type, digest, digestlen, r.base, &siglen, rsa); + if (status == 0) { + err = ERR_peek_error_line(&file, &line); + if (err != 0U) { + message = ERR_error_string(err, NULL); + fprintf(stderr, "%s:%s:%d\n", message, + file ? file : "", line); + } + return (dst__openssl_toresult(DST_R_OPENSSLFAILURE)); + } + + isc_buffer_add(sig, siglen); + + return (ISC_R_SUCCESS); +} + +static isc_result_t +opensslrsa_verify(dst_context_t *dctx, const isc_region_t *sig) { + dst_key_t *key = dctx->key; + RSA *rsa = key->opaque; + /* note: ISC_SHA1_DIGESTLENGTH > ISC_MD5_DIGESTLENGTH */ + unsigned char digest[ISC_SHA1_DIGESTLENGTH]; + int status = 0; + int type; + unsigned int digestlen; + + REQUIRE(dctx->key->key_alg == DST_ALG_RSAMD5 || + dctx->key->key_alg == DST_ALG_RSASHA1); + + if (dctx->key->key_alg == DST_ALG_RSAMD5) { + isc_md5_t *md5ctx = dctx->opaque; + isc_md5_final(md5ctx, digest); + type = NID_md5; + digestlen = ISC_MD5_DIGESTLENGTH; + } else { + isc_sha1_t *sha1ctx = dctx->opaque; + isc_sha1_final(sha1ctx, digest); + type = NID_sha1; + digestlen = ISC_SHA1_DIGESTLENGTH; + } + + if (sig->length < (unsigned int) RSA_size(rsa)) + return (DST_R_VERIFYFAILURE); + + status = RSA_verify(type, digest, digestlen, sig->base, + RSA_size(rsa), rsa); + if (status == 0) + return (dst__openssl_toresult(DST_R_VERIFYFAILURE)); + + return (ISC_R_SUCCESS); +} + +static isc_boolean_t +opensslrsa_compare(const dst_key_t *key1, const dst_key_t *key2) { + int status; + RSA *rsa1, *rsa2; + + rsa1 = (RSA *) key1->opaque; + rsa2 = (RSA *) key2->opaque; + + if (rsa1 == NULL && rsa2 == NULL) + return (ISC_TRUE); + else if (rsa1 == NULL || rsa2 == NULL) + return (ISC_FALSE); + + status = BN_cmp(rsa1->n, rsa2->n) || + BN_cmp(rsa1->e, rsa2->e); + + if (status != 0) + return (ISC_FALSE); + + if (rsa1->d != NULL || rsa2->d != NULL) { + if (rsa1->d == NULL || rsa2->d == NULL) + return (ISC_FALSE); + status = BN_cmp(rsa1->d, rsa2->d) || + BN_cmp(rsa1->p, rsa2->p) || + BN_cmp(rsa1->q, rsa2->q); + + if (status != 0) + return (ISC_FALSE); + } + return (ISC_TRUE); +} + +static isc_result_t +opensslrsa_generate(dst_key_t *key, int exp) { + RSA *rsa; + unsigned long e; + + if (exp == 0) + e = RSA_3; + else + e = RSA_F4; + rsa = RSA_generate_key(key->key_size, e, NULL, NULL); + if (rsa == NULL) + return (dst__openssl_toresult(DST_R_OPENSSLFAILURE)); + SET_FLAGS(rsa); + key->opaque = rsa; + + return (ISC_R_SUCCESS); +} + +static isc_boolean_t +opensslrsa_isprivate(const dst_key_t *key) { + RSA *rsa = (RSA *) key->opaque; + return (ISC_TF(rsa != NULL && rsa->d != NULL)); +} + +static void +opensslrsa_destroy(dst_key_t *key) { + RSA *rsa = key->opaque; + RSA_free(rsa); + key->opaque = NULL; +} + + +static isc_result_t +opensslrsa_todns(const dst_key_t *key, isc_buffer_t *data) { + RSA *rsa; + isc_region_t r; + unsigned int e_bytes; + unsigned int mod_bytes; + + REQUIRE(key->opaque != NULL); + + rsa = (RSA *) key->opaque; + + isc_buffer_availableregion(data, &r); + + e_bytes = BN_num_bytes(rsa->e); + mod_bytes = BN_num_bytes(rsa->n); + + if (e_bytes < 256) { /* key exponent is <= 2040 bits */ + if (r.length < 1) + return (ISC_R_NOSPACE); + isc_buffer_putuint8(data, (isc_uint8_t) e_bytes); + } else { + if (r.length < 3) + return (ISC_R_NOSPACE); + isc_buffer_putuint8(data, 0); + isc_buffer_putuint16(data, (isc_uint16_t) e_bytes); + } + + if (r.length < e_bytes + mod_bytes) + return (ISC_R_NOSPACE); + isc_buffer_availableregion(data, &r); + + BN_bn2bin(rsa->e, r.base); + r.base += e_bytes; + BN_bn2bin(rsa->n, r.base); + + isc_buffer_add(data, e_bytes + mod_bytes); + + return (ISC_R_SUCCESS); +} + +static isc_result_t +opensslrsa_fromdns(dst_key_t *key, isc_buffer_t *data) { + RSA *rsa; + isc_region_t r; + unsigned int e_bytes; + + isc_buffer_remainingregion(data, &r); + if (r.length == 0) + return (ISC_R_SUCCESS); + + rsa = RSA_new(); + if (rsa == NULL) + return (ISC_R_NOMEMORY); + SET_FLAGS(rsa); + + if (r.length < 1) { + RSA_free(rsa); + return (DST_R_INVALIDPUBLICKEY); + } + e_bytes = *r.base++; + r.length--; + + if (e_bytes == 0) { + if (r.length < 2) { + RSA_free(rsa); + return (DST_R_INVALIDPUBLICKEY); + } + e_bytes = ((*r.base++) << 8); + e_bytes += *r.base++; + r.length -= 2; + } + + if (r.length < e_bytes) { + RSA_free(rsa); + return (DST_R_INVALIDPUBLICKEY); + } + rsa->e = BN_bin2bn(r.base, e_bytes, NULL); + r.base += e_bytes; + r.length -= e_bytes; + + rsa->n = BN_bin2bn(r.base, r.length, NULL); + + key->key_size = BN_num_bits(rsa->n); + + isc_buffer_forward(data, r.length); + + key->opaque = (void *) rsa; + + return (ISC_R_SUCCESS); +} + + +static isc_result_t +opensslrsa_tofile(const dst_key_t *key, const char *directory) { + int i; + RSA *rsa; + dst_private_t priv; + unsigned char *bufs[8]; + isc_result_t result; + + if (key->opaque == NULL) + return (DST_R_NULLKEY); + + rsa = (RSA *) key->opaque; + + for (i = 0; i < 8; i++) { + bufs[i] = isc_mem_get(key->mctx, BN_num_bytes(rsa->n)); + if (bufs[i] == NULL) { + result = ISC_R_NOMEMORY; + goto fail; + } + } + + i = 0; + + priv.elements[i].tag = TAG_RSA_MODULUS; + priv.elements[i].length = BN_num_bytes(rsa->n); + BN_bn2bin(rsa->n, bufs[i]); + priv.elements[i].data = bufs[i]; + i++; + + priv.elements[i].tag = TAG_RSA_PUBLICEXPONENT; + priv.elements[i].length = BN_num_bytes(rsa->e); + BN_bn2bin(rsa->e, bufs[i]); + priv.elements[i].data = bufs[i]; + i++; + + priv.elements[i].tag = TAG_RSA_PRIVATEEXPONENT; + priv.elements[i].length = BN_num_bytes(rsa->d); + BN_bn2bin(rsa->d, bufs[i]); + priv.elements[i].data = bufs[i]; + i++; + + priv.elements[i].tag = TAG_RSA_PRIME1; + priv.elements[i].length = BN_num_bytes(rsa->p); + BN_bn2bin(rsa->p, bufs[i]); + priv.elements[i].data = bufs[i]; + i++; + + priv.elements[i].tag = TAG_RSA_PRIME2; + priv.elements[i].length = BN_num_bytes(rsa->q); + BN_bn2bin(rsa->q, bufs[i]); + priv.elements[i].data = bufs[i]; + i++; + + priv.elements[i].tag = TAG_RSA_EXPONENT1; + priv.elements[i].length = BN_num_bytes(rsa->dmp1); + BN_bn2bin(rsa->dmp1, bufs[i]); + priv.elements[i].data = bufs[i]; + i++; + + priv.elements[i].tag = TAG_RSA_EXPONENT2; + priv.elements[i].length = BN_num_bytes(rsa->dmq1); + BN_bn2bin(rsa->dmq1, bufs[i]); + priv.elements[i].data = bufs[i]; + i++; + + priv.elements[i].tag = TAG_RSA_COEFFICIENT; + priv.elements[i].length = BN_num_bytes(rsa->iqmp); + BN_bn2bin(rsa->iqmp, bufs[i]); + priv.elements[i].data = bufs[i]; + i++; + + priv.nelements = i; + result = dst__privstruct_writefile(key, &priv, directory); + fail: + for (i = 0; i < 8; i++) { + if (bufs[i] == NULL) + break; + isc_mem_put(key->mctx, bufs[i], BN_num_bytes(rsa->n)); + } + return (result); +} + +static isc_result_t +opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer) { + dst_private_t priv; + isc_result_t ret; + int i; + RSA *rsa = NULL; + isc_mem_t *mctx = key->mctx; +#define DST_RET(a) {ret = a; goto err;} + + /* read private key file */ + ret = dst__privstruct_parse(key, DST_ALG_RSA, lexer, mctx, &priv); + if (ret != ISC_R_SUCCESS) + return (ret); + + rsa = RSA_new(); + if (rsa == NULL) + DST_RET(ISC_R_NOMEMORY); + SET_FLAGS(rsa); + key->opaque = rsa; + + for (i = 0; i < priv.nelements; i++) { + BIGNUM *bn; + bn = BN_bin2bn(priv.elements[i].data, + priv.elements[i].length, NULL); + if (bn == NULL) + DST_RET(ISC_R_NOMEMORY); + + switch (priv.elements[i].tag) { + case TAG_RSA_MODULUS: + rsa->n = bn; + break; + case TAG_RSA_PUBLICEXPONENT: + rsa->e = bn; + break; + case TAG_RSA_PRIVATEEXPONENT: + rsa->d = bn; + break; + case TAG_RSA_PRIME1: + rsa->p = bn; + break; + case TAG_RSA_PRIME2: + rsa->q = bn; + break; + case TAG_RSA_EXPONENT1: + rsa->dmp1 = bn; + break; + case TAG_RSA_EXPONENT2: + rsa->dmq1 = bn; + break; + case TAG_RSA_COEFFICIENT: + rsa->iqmp = bn; + break; + } + } + dst__privstruct_free(&priv, mctx); + + key->key_size = BN_num_bits(rsa->n); + + return (ISC_R_SUCCESS); + + err: + opensslrsa_destroy(key); + dst__privstruct_free(&priv, mctx); + memset(&priv, 0, sizeof(priv)); + return (ret); +} + +static dst_func_t opensslrsa_functions = { + opensslrsa_createctx, + opensslrsa_destroyctx, + opensslrsa_adddata, + opensslrsa_sign, + opensslrsa_verify, + NULL, /* computesecret */ + opensslrsa_compare, + NULL, /* paramcompare */ + opensslrsa_generate, + opensslrsa_isprivate, + opensslrsa_destroy, + opensslrsa_todns, + opensslrsa_fromdns, + opensslrsa_tofile, + opensslrsa_parse, + NULL, /* cleanup */ +}; + +isc_result_t +dst__opensslrsa_init(dst_func_t **funcp) { + REQUIRE(funcp != NULL); + if (*funcp == NULL) + *funcp = &opensslrsa_functions; + return (ISC_R_SUCCESS); +} + +#else /* OPENSSL */ + +#include <isc/util.h> + +EMPTY_TRANSLATION_UNIT + +#endif /* OPENSSL */ diff --git a/contrib/bind9/lib/dns/rbt.c b/contrib/bind9/lib/dns/rbt.c index a3608f73c0bf..cb43858069f5 100644 --- a/contrib/bind9/lib/dns/rbt.c +++ b/contrib/bind9/lib/dns/rbt.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rbt.c,v 1.115.2.2.2.9 2004/03/08 21:06:27 marka Exp $ */ +/* $Id: rbt.c,v 1.115.2.2.2.11 2004/10/25 01:36:07 marka Exp $ */ /* Principal Authors: DCL */ @@ -64,7 +64,6 @@ struct dns_rbt { unsigned int nodecount; unsigned int hashsize; dns_rbtnode_t ** hashtable; - unsigned int quantum; }; #define RED 0 @@ -180,25 +179,6 @@ find_up(dns_rbtnode_t *node) { return (PARENT(root)); } -#ifdef DNS_RBT_USEHASH -static inline void -compute_node_hash(dns_rbtnode_t *node) { - unsigned int hash; - dns_name_t name; - dns_rbtnode_t *up_node; - - dns_name_init(&name, NULL); - NODENAME(node, &name); - hash = dns_name_hashbylabel(&name, ISC_FALSE); - - up_node = find_up(node); - if (up_node != NULL) - hash += HASHVAL(up_node); - - HASHVAL(node) = hash; -} -#endif - /* * Forward declarations. */ @@ -207,11 +187,11 @@ create_node(isc_mem_t *mctx, dns_name_t *name, dns_rbtnode_t **nodep); #ifdef DNS_RBT_USEHASH static inline void -hash_node(dns_rbt_t *rbt, dns_rbtnode_t *node); +hash_node(dns_rbt_t *rbt, dns_rbtnode_t *node, dns_name_t *name); static inline void unhash_node(dns_rbt_t *rbt, dns_rbtnode_t *node); #else -#define hash_node(rbt, node) (ISC_R_SUCCESS) +#define hash_node(rbt, node, name) (ISC_R_SUCCESS) #define unhash_node(rbt, node) #endif @@ -231,7 +211,8 @@ static isc_result_t dns_rbt_deletetree(dns_rbt_t *rbt, dns_rbtnode_t *node); static void -dns_rbt_deletetreeflat(dns_rbt_t *rbt, dns_rbtnode_t **nodep); +dns_rbt_deletetreeflat(dns_rbt_t *rbt, unsigned int quantum, + dns_rbtnode_t **nodep); /* * Initialize a red/black tree of trees. @@ -268,7 +249,6 @@ dns_rbt_create(isc_mem_t *mctx, void (*deleter)(void *, void *), return (result); } #endif - rbt->quantum = 0; rbt->magic = RBT_MAGIC; *rbtp = rbt; @@ -292,9 +272,7 @@ dns_rbt_destroy2(dns_rbt_t **rbtp, unsigned int quantum) { rbt = *rbtp; - rbt->quantum = quantum; - - dns_rbt_deletetreeflat(rbt, &rbt->root); + dns_rbt_deletetreeflat(rbt, quantum, &rbt->root); if (rbt->root != NULL) return (ISC_R_QUOTA); @@ -377,13 +355,14 @@ dns_rbt_addnode(dns_rbt_t *rbt, dns_name_t *name, dns_rbtnode_t **nodep) { * Does this thing have too many variables or what? */ dns_rbtnode_t **root, *parent, *child, *current, *new_current; - dns_name_t *add_name, current_name, *prefix, *suffix; - dns_fixedname_t fixedcopy, fixedprefix, fixedsuffix; + dns_name_t *add_name, *new_name, current_name, *prefix, *suffix; + dns_fixedname_t fixedcopy, fixedprefix, fixedsuffix, fnewname; dns_offsets_t current_offsets; dns_namereln_t compared; isc_result_t result = ISC_R_SUCCESS; dns_rbtnodechain_t chain; unsigned int common_labels; + unsigned int nlabels, hlabels; int order; REQUIRE(VALID_RBT(rbt)); @@ -405,7 +384,7 @@ dns_rbt_addnode(dns_rbt_t *rbt, dns_name_t *name, dns_rbtnode_t **nodep) { new_current->is_root = 1; rbt->root = new_current; *nodep = new_current; - hash_node(rbt, new_current); + hash_node(rbt, new_current, name); } return (result); } @@ -423,6 +402,10 @@ dns_rbt_addnode(dns_rbt_t *rbt, dns_name_t *name, dns_rbtnode_t **nodep) { current = NULL; child = *root; dns_name_init(¤t_name, current_offsets); + dns_fixedname_init(&fnewname); + new_name = dns_fixedname_name(&fnewname); + nlabels = dns_name_countlabels(name); + hlabels = 0; do { current = child; @@ -462,6 +445,7 @@ dns_rbt_addnode(dns_rbt_t *rbt, dns_name_t *name, dns_rbtnode_t **nodep) { * the non-common parts of these two names should * start a new tree. */ + hlabels += common_labels; if (compared == dns_namereln_subdomain) { /* * All of the existing labels are in common, @@ -588,7 +572,10 @@ dns_rbt_addnode(dns_rbt_t *rbt, dns_name_t *name, dns_rbtnode_t **nodep) { ATTRS(current) &= ~DNS_NAMEATTR_ABSOLUTE; rbt->nodecount++; - hash_node(rbt, new_current); + dns_name_getlabelsequence(name, + nlabels - hlabels, + hlabels, new_name); + hash_node(rbt, new_current, new_name); if (common_labels == dns_name_countlabels(add_name)) { @@ -635,7 +622,7 @@ dns_rbt_addnode(dns_rbt_t *rbt, dns_name_t *name, dns_rbtnode_t **nodep) { dns_rbt_addonlevel(new_current, current, order, root); rbt->nodecount++; *nodep = new_current; - hash_node(rbt, new_current); + hash_node(rbt, new_current, name); } return (result); @@ -687,6 +674,7 @@ dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_name_t *foundname, dns_namereln_t compared; isc_result_t result, saved_result; unsigned int common_labels; + unsigned int hlabels = 0; int order; REQUIRE(VALID_RBT(rbt)); @@ -782,11 +770,17 @@ dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_name_t *foundname, dns_name_init(&hash_name, NULL); hashagain: + /* + * Hash includes tail. + */ + dns_name_getlabelsequence(name, + nlabels - tlabels, + hlabels + tlabels, + &hash_name); + hash = dns_name_fullhash(&hash_name, ISC_FALSE); dns_name_getlabelsequence(search_name, nlabels - tlabels, tlabels, &hash_name); - hash = HASHVAL(up_current) + - dns_name_hashbylabel(&hash_name, ISC_FALSE); for (hnode = rbt->hashtable[hash % rbt->hashsize]; hnode != NULL; @@ -863,6 +857,7 @@ dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_name_t *foundname, */ dns_name_split(search_name, common_labels, search_name, NULL); + hlabels += common_labels; /* * This might be the closest enclosing name. */ @@ -1475,10 +1470,10 @@ create_node(isc_mem_t *mctx, dns_name_t *name, dns_rbtnode_t **nodep) { #ifdef DNS_RBT_USEHASH static inline void -hash_add_node(dns_rbt_t *rbt, dns_rbtnode_t *node) { +hash_add_node(dns_rbt_t *rbt, dns_rbtnode_t *node, dns_name_t *name) { unsigned int hash; - compute_node_hash(node); + HASHVAL(node) = dns_name_fullhash(name, ISC_FALSE); hash = HASHVAL(node) % rbt->hashsize; HASHNEXT(node) = rbt->hashtable[hash]; @@ -1539,14 +1534,14 @@ rehash(dns_rbt_t *rbt) { } static inline void -hash_node(dns_rbt_t *rbt, dns_rbtnode_t *node) { +hash_node(dns_rbt_t *rbt, dns_rbtnode_t *node, dns_name_t *name) { REQUIRE(DNS_RBTNODE_VALID(node)); if (rbt->nodecount >= (rbt->hashsize *3)) rehash(rbt); - hash_add_node(rbt, node); + hash_add_node(rbt, node, name); } static inline void @@ -2021,8 +2016,6 @@ dns_rbt_deletetree(dns_rbt_t *rbt, dns_rbtnode_t *node) { done: if (result != ISC_R_SUCCESS) return (result); - if (rbt->quantum != 0 && --rbt->quantum == 0) - return (ISC_R_QUOTA); if (DATA(node) != NULL && rbt->data_deleter != NULL) rbt->data_deleter(DATA(node), rbt->deleter_arg); @@ -2037,7 +2030,9 @@ dns_rbt_deletetree(dns_rbt_t *rbt, dns_rbtnode_t *node) { } static void -dns_rbt_deletetreeflat(dns_rbt_t *rbt, dns_rbtnode_t **nodep) { +dns_rbt_deletetreeflat(dns_rbt_t *rbt, unsigned int quantum, + dns_rbtnode_t **nodep) +{ dns_rbtnode_t *parent; dns_rbtnode_t *node = *nodep; REQUIRE(VALID_RBT(rbt)); @@ -2081,7 +2076,7 @@ dns_rbt_deletetreeflat(dns_rbt_t *rbt, dns_rbtnode_t **nodep) { isc_mem_put(rbt->mctx, node, NODE_SIZE(node)); rbt->nodecount--; node = parent; - if (rbt->quantum != 0 && --rbt->quantum == 0) { + if (quantum != 0 && --quantum == 0) { *nodep = node; return; } diff --git a/contrib/bind9/lib/dns/rdata.c b/contrib/bind9/lib/dns/rdata.c index 6bf2b66dc1ac..6d4c098698ab 100644 --- a/contrib/bind9/lib/dns/rdata.c +++ b/contrib/bind9/lib/dns/rdata.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rdata.c,v 1.147.2.11.2.15 2004/03/12 10:31:25 marka Exp $ */ +/* $Id: rdata.c,v 1.147.2.11.2.16 2004/10/06 05:37:40 marka Exp $ */ #include <config.h> #include <ctype.h> @@ -1588,7 +1588,7 @@ warn_badname(dns_name_t *name, isc_lex_t *lexer, file = isc_lex_getsourcename(lexer); line = isc_lex_getsourceline(lexer); dns_name_format(name, namebuf, sizeof(namebuf)); - (*callbacks->warn)(callbacks, "%s:%u: %s: %s", + (*callbacks->warn)(callbacks, "%s:%u: warning: %s: %s", file, line, namebuf, dns_result_totext(DNS_R_BADNAME)); } diff --git a/contrib/bind9/lib/dns/rdata/in_1/wks_11.c b/contrib/bind9/lib/dns/rdata/in_1/wks_11.c index 91b30e4a9e9d..c27868602de6 100644 --- a/contrib/bind9/lib/dns/rdata/in_1/wks_11.c +++ b/contrib/bind9/lib/dns/rdata/in_1/wks_11.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: wks_11.c,v 1.44.12.7 2004/03/08 09:04:44 marka Exp $ */ +/* $Id: wks_11.c,v 1.44.12.8 2004/09/16 01:00:58 marka Exp $ */ /* Reviewed: Fri Mar 17 15:01:49 PST 2000 by explorer */ @@ -107,7 +107,7 @@ fromtext_in_wks(ARGS_FROMTEXT) { service[sizeof(service)-1] = '\0'; for (i = strlen(service) - 1; i >= 0; i--) if (isupper(service[i]&0xff)) - service[i] = tolower(service[i]); + service[i] = tolower(service[i]&0xff); port = strtol(DNS_AS_STR(token), &e, 10); if (*e == 0) diff --git a/contrib/bind9/lib/dns/resolver.c b/contrib/bind9/lib/dns/resolver.c index c76631a2bbf1..90af5b020e7b 100644 --- a/contrib/bind9/lib/dns/resolver.c +++ b/contrib/bind9/lib/dns/resolver.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: resolver.c,v 1.218.2.18.4.43 2004/08/28 06:25:19 marka Exp $ */ +/* $Id: resolver.c,v 1.218.2.18.4.51 2005/02/08 23:59:44 marka Exp $ */ #include <config.h> @@ -524,7 +524,7 @@ fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp, */ INSIST(no_response); rtt = query->addrinfo->srtt + - (100000 * fctx->restarts); + (200000 * fctx->restarts); if (rtt > 10000000) rtt = 10000000; /* @@ -762,6 +762,9 @@ static void resquery_senddone(isc_task_t *task, isc_event_t *event) { isc_socketevent_t *sevent = (isc_socketevent_t *)event; resquery_t *query = event->ev_arg; + isc_boolean_t retry = ISC_FALSE; + isc_result_t result; + fetchctx_t *fctx; REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE); @@ -780,6 +783,7 @@ resquery_senddone(isc_task_t *task, isc_event_t *event) { INSIST(RESQUERY_SENDING(query)); query->sends--; + fctx = query->fctx; if (RESQUERY_CANCELED(query)) { if (query->sends == 0) { @@ -791,10 +795,43 @@ resquery_senddone(isc_task_t *task, isc_event_t *event) { isc_socket_detach(&query->tcpsocket); resquery_destroy(&query); } - } else if (sevent->result != ISC_R_SUCCESS) - fctx_cancelquery(&query, NULL, NULL, ISC_FALSE); + } else + switch (sevent->result) { + case ISC_R_SUCCESS: + break; + + case ISC_R_HOSTUNREACH: + case ISC_R_NETUNREACH: + case ISC_R_NOPERM: + case ISC_R_ADDRNOTAVAIL: + case ISC_R_CONNREFUSED: + + /* + * No route to remote. + */ + fctx_cancelquery(&query, NULL, NULL, ISC_TRUE); + retry = ISC_TRUE; + break; + + default: + fctx_cancelquery(&query, NULL, NULL, ISC_FALSE); + break; + } isc_event_free(&event); + + if (retry) { + /* + * Behave as if the idle timer has expired. For TCP + * this may not actually reflect the latest timer. + */ + fctx->attributes &= ~FCTX_ATTR_ADDRWAIT; + result = fctx_stopidletimer(fctx); + if (result != ISC_R_SUCCESS) + fctx_done(fctx, result); + else + fctx_try(fctx); + } } static inline isc_result_t @@ -1311,7 +1348,10 @@ static void resquery_connected(isc_task_t *task, isc_event_t *event) { isc_socketevent_t *sevent = (isc_socketevent_t *)event; resquery_t *query = event->ev_arg; + isc_boolean_t retry = ISC_FALSE; isc_result_t result; + unsigned int attrs; + fetchctx_t *fctx; REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT); REQUIRE(VALID_QUERY(query)); @@ -1329,6 +1369,7 @@ resquery_connected(isc_task_t *task, isc_event_t *event) { */ query->connects--; + fctx = query->fctx; if (RESQUERY_CANCELED(query)) { /* @@ -1338,9 +1379,8 @@ resquery_connected(isc_task_t *task, isc_event_t *event) { isc_socket_detach(&query->tcpsocket); resquery_destroy(&query); } else { - if (sevent->result == ISC_R_SUCCESS) { - unsigned int attrs; - + switch (sevent->result) { + case ISC_R_SUCCESS: /* * We are connected. Create a dispatcher and * send the query. @@ -1373,22 +1413,48 @@ resquery_connected(isc_task_t *task, isc_event_t *event) { result = resquery_send(query); if (result != ISC_R_SUCCESS) { - fetchctx_t *fctx = query->fctx; fctx_cancelquery(&query, NULL, NULL, ISC_FALSE); fctx_done(fctx, result); } - } else { + break; + + case ISC_R_NETUNREACH: + case ISC_R_HOSTUNREACH: + case ISC_R_CONNREFUSED: + case ISC_R_NOPERM: + case ISC_R_ADDRNOTAVAIL: + /* + * No route to remote. + */ + isc_socket_detach(&query->tcpsocket); + fctx_cancelquery(&query, NULL, NULL, ISC_TRUE); + retry = ISC_TRUE; + break; + + default: isc_socket_detach(&query->tcpsocket); fctx_cancelquery(&query, NULL, NULL, ISC_FALSE); + break; } } isc_event_free(&event); + + if (retry) { + /* + * Behave as if the idle timer has expired. For TCP + * connections this may not actually reflect the latest timer. + */ + fctx->attributes &= ~FCTX_ATTR_ADDRWAIT; + result = fctx_stopidletimer(fctx); + if (result != ISC_R_SUCCESS) + fctx_done(fctx, result); + else + fctx_try(fctx); + } } - - static void fctx_finddone(isc_task_t *task, isc_event_t *event) { fetchctx_t *fctx; @@ -3519,6 +3585,14 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, isc_stdtime_t now) { fctx->validators, validator, link); } + } else if (CHAINING(rdataset)) { + if (rdataset->type == dns_rdatatype_cname) + eresult = DNS_R_CNAME; + else { + INSIST(rdataset->type == + dns_rdatatype_dname); + eresult = DNS_R_DNAME; + } } } else if (!EXTERNAL(rdataset)) { /* @@ -4127,7 +4201,7 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname, dns_message_currentname(message, section, &name); if (dns_name_issubdomain(name, &fctx->domain)) { /* - * Look for NS RRset first. + * Look for NS/SOA RRsets first. */ for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; @@ -4141,7 +4215,7 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname, return (DNS_R_FORMERR); if (type == dns_rdatatype_ns) { /* - * NS or SIG NS. + * NS or RRSIG NS. * * Only one set of NS RRs is allowed. */ @@ -4159,17 +4233,9 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname, DNS_RDATASETATTR_CACHE; rdataset->trust = dns_trust_glue; } - } - for (rdataset = ISC_LIST_HEAD(name->list); - rdataset != NULL; - rdataset = ISC_LIST_NEXT(rdataset, link)) { - type = rdataset->type; - if (type == dns_rdatatype_rrsig) - type = rdataset->covers; - if (type == dns_rdatatype_soa || - type == dns_rdatatype_nsec) { + if (type == dns_rdatatype_soa) { /* - * SOA, RRSIG SOA, NSEC, or RRSIG NSEC. + * SOA, or RRSIG SOA. * * Only one SOA is allowed. */ @@ -4180,8 +4246,38 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname, return (DNS_R_FORMERR); soa_name = name; } - if (ns_name == NULL) { - negative_response = ISC_TRUE; + name->attributes |= + DNS_NAMEATTR_NCACHE; + rdataset->attributes |= + DNS_RDATASETATTR_NCACHE; + if (aa) + rdataset->trust = + dns_trust_authauthority; + else + rdataset->trust = + dns_trust_additional; + } + } + /* + * A negative response has a SOA record (Type 2) + * and a optional NS RRset (Type 1) or it has neither + * a SOA or a NS RRset (Type 3, handled above) or + * rcode is NXDOMAIN (handled above) in which case + * the NS RRset is allowed (Type 4). + */ + if (soa_name != NULL) + negative_response = ISC_TRUE; + for (rdataset = ISC_LIST_HEAD(name->list); + rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) { + type = rdataset->type; + if (type == dns_rdatatype_rrsig) + type = rdataset->covers; + if (type == dns_rdatatype_nsec) { + /* + * NSEC or RRSIG NSEC. + */ + if (negative_response) { name->attributes |= DNS_NAMEATTR_NCACHE; rdataset->attributes |= @@ -4210,7 +4306,7 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname, * this is a referral, and there * should only be one DS. */ - if (negative_response) + if (ns_name == NULL) return (DNS_R_FORMERR); if (rdataset->type == dns_rdatatype_ds) { @@ -5229,10 +5325,15 @@ resquery_response(isc_task_t *task, isc_event_t *event) { domainbuf, namebuf, typebuf, classbuf, addrbuf); } - if ((fctx->res->options | DNS_RESOLVER_CHECKNAMES) != 0) + if ((fctx->res->options & DNS_RESOLVER_CHECKNAMES) != 0) checknames(message); /* + * Clear cache bits. + */ + fctx->attributes &= ~(FCTX_ATTR_WANTNCACHE | FCTX_ATTR_WANTCACHE); + + /* * Did we get any answers? */ if (message->counts[DNS_SECTION_ANSWER] > 0 && @@ -5380,13 +5481,16 @@ resquery_response(isc_task_t *task, isc_event_t *event) { return; } findoptions = 0; + if (dns_rdatatype_atparent(fctx->type)) + findoptions |= DNS_DBFIND_NOEXACT; if ((options & DNS_FETCHOPT_UNSHARED) == 0) name = &fctx->name; else name = &fctx->domain; result = dns_view_findzonecut(fctx->res->view, name, fname, - now, 0, ISC_TRUE, + now, findoptions, + ISC_TRUE, &fctx->nameservers, NULL); if (result != ISC_R_SUCCESS) { diff --git a/contrib/bind9/lib/dns/validator.c b/contrib/bind9/lib/dns/validator.c index c55c893911fb..069b9c228f92 100644 --- a/contrib/bind9/lib/dns/validator.c +++ b/contrib/bind9/lib/dns/validator.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000-2003 Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: validator.c,v 1.91.2.5.8.12 2004/06/11 01:17:36 marka Exp $ */ +/* $Id: validator.c,v 1.91.2.5.8.15 2005/02/09 05:13:02 marka Exp $ */ #include <config.h> @@ -497,6 +497,8 @@ nsecnoexistnodata(dns_validator_t *val, dns_name_t* name, dns_name_t *nsecname, REQUIRE(exists != NULL); REQUIRE(data != NULL); + REQUIRE(nsecset != NULL && + nsecset->type == dns_rdatatype_nsec); result = dns_rdataset_first(nsecset); if (result != ISC_R_SUCCESS) { @@ -661,7 +663,7 @@ authvalidated(isc_task_t *task, isc_event_t *event) { if (rdataset->trust == dns_trust_secure) val->seensig = ISC_TRUE; - if (val->nsecset != NULL && + if (rdataset->type == dns_rdatatype_nsec && rdataset->trust == dns_trust_secure && ((val->attributes & VALATTR_NEEDNODATA) != 0 || (val->attributes & VALATTR_NEEDNOQNAME) != 0) && @@ -2354,8 +2356,18 @@ proveunsecure(dns_validator_t *val, isc_boolean_t resume) { } if (result == ISC_R_NOTFOUND) { - if (!val->havedlvsep) + if (!val->havedlvsep) { + validator_log(val, ISC_LOG_DEBUG(3), + "not beneath secure root / DLV"); + if (val->mustbesecure) { + validator_log(val, ISC_LOG_WARNING, + "must be secure failure"); + result = DNS_R_MUSTBESECURE; + goto out; + } + val->event->rdataset->trust = dns_trust_answer; return (ISC_R_SUCCESS); + } dns_name_copy(dns_fixedname_name(&val->dlvsep), dns_fixedname_name(&secroot), NULL); } else if (result != ISC_R_SUCCESS) diff --git a/contrib/bind9/lib/dns/xfrin.c b/contrib/bind9/lib/dns/xfrin.c index c9f1d74a0413..aa4d054ca331 100644 --- a/contrib/bind9/lib/dns/xfrin.c +++ b/contrib/bind9/lib/dns/xfrin.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: xfrin.c,v 1.124.2.4.2.7 2004/03/08 09:04:33 marka Exp $ */ +/* $Id: xfrin.c,v 1.124.2.4.2.9 2004/10/13 22:28:42 marka Exp $ */ #include <config.h> @@ -500,8 +500,8 @@ xfr_rr(dns_xfrin_ctx_t *xfr, dns_name_t *name, isc_uint32_t ttl, case XFRST_IXFR_ADD: if (rdata->type == dns_rdatatype_soa) { isc_uint32_t soa_serial = dns_soa_getserial(rdata); - CHECK(ixfr_commit(xfr)); if (soa_serial == xfr->end_serial) { + CHECK(ixfr_commit(xfr)); xfr->state = XFRST_END; break; } else if (soa_serial != xfr->ixfr.current_serial) { @@ -511,6 +511,7 @@ xfr_rr(dns_xfrin_ctx_t *xfr, dns_name_t *name, isc_uint32_t ttl, xfr->ixfr.current_serial, soa_serial); FAIL(DNS_R_FORMERR); } else { + CHECK(ixfr_commit(xfr)); xfr->state = XFRST_IXFR_DELSOA; goto redo; } @@ -922,9 +923,10 @@ tuple2msgname(dns_difftuple_t *tuple, dns_message_t *msg, dns_name_t **target) failure: - if (rds != NULL) + if (rds != NULL) { dns_rdataset_disassociate(rds); dns_message_puttemprdataset(msg, &rds); + } if (rdl != NULL) { ISC_LIST_UNLINK(rdl->rdata, rdata, link); dns_message_puttemprdatalist(msg, &rdl); diff --git a/contrib/bind9/lib/dns/zone.c b/contrib/bind9/lib/dns/zone.c index b5cbc6e798ea..29f99cb1d68a 100644 --- a/contrib/bind9/lib/dns/zone.c +++ b/contrib/bind9/lib/dns/zone.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zone.c,v 1.333.2.23.2.50 2004/08/28 05:53:37 marka Exp $ */ +/* $Id: zone.c,v 1.333.2.23.2.55 2005/02/03 23:50:45 marka Exp $ */ #include <config.h> @@ -1488,7 +1488,7 @@ zone_count_ns_rr(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, result = ISC_R_SUCCESS; goto invalidate_rdataset; } - else if (result != ISC_R_SUCCESS) + if (result != ISC_R_SUCCESS) goto invalidate_rdataset; count = 0; @@ -1524,6 +1524,22 @@ zone_load_soa_rr(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, dns_rdataset_init(&rdataset); result = dns_db_findrdataset(db, node, version, dns_rdatatype_soa, dns_rdatatype_none, 0, &rdataset, NULL); + if (result == ISC_R_NOTFOUND) { + if (soacount != NULL) + *soacount = 0; + if (serial != NULL) + *serial = 0; + if (refresh != NULL) + *refresh = 0; + if (retry != NULL) + *retry = 0; + if (expire != NULL) + *expire = 0; + if (minimum != NULL) + *minimum = 0; + result = ISC_R_SUCCESS; + goto invalidate_rdataset; + } if (result != ISC_R_SUCCESS) goto invalidate_rdataset; @@ -2199,7 +2215,6 @@ zone_expire(dns_zone_t *zone) { zone->refresh = DNS_ZONE_DEFAULTREFRESH; zone->retry = DNS_ZONE_DEFAULTRETRY; DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_HAVETIMERS); - DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDDUMP); zone_unload(zone); } @@ -2554,6 +2569,7 @@ zone_unload(dns_zone_t *zone) { dns_db_detach(&zone->db); DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_LOADED); + DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDDUMP); } void @@ -2907,6 +2923,7 @@ zone_notify(dns_zone_t *zone) { dns_notifytype_t notifytype; unsigned int flags = 0; isc_boolean_t loggednotify = ISC_FALSE; + dns_db_t *db = NULL; REQUIRE(DNS_ZONE_VALID(zone)); @@ -2921,6 +2938,13 @@ zone_notify(dns_zone_t *zone) { if (notifytype == dns_notifytype_no) return; + LOCK_ZONE(zone); + if (zone->db != NULL) + dns_db_attach(zone->db, &db); + UNLOCK_ZONE(zone); + if (db == NULL) + return; + origin = &zone->origin; /* @@ -2933,14 +2957,13 @@ zone_notify(dns_zone_t *zone) { /* * Get SOA RRset. */ - dns_db_currentversion(zone->db, &version); - result = dns_db_findnode(zone->db, origin, ISC_FALSE, &node); + dns_db_currentversion(db, &version); + result = dns_db_findnode(db, origin, ISC_FALSE, &node); if (result != ISC_R_SUCCESS) goto cleanup1; dns_rdataset_init(&soardset); - result = dns_db_findrdataset(zone->db, node, version, - dns_rdatatype_soa, + result = dns_db_findrdataset(db, node, version, dns_rdatatype_soa, dns_rdatatype_none, 0, &soardset, NULL); if (result != ISC_R_SUCCESS) goto cleanup2; @@ -2997,8 +3020,7 @@ zone_notify(dns_zone_t *zone) { */ dns_rdataset_init(&nsrdset); - result = dns_db_findrdataset(zone->db, node, version, - dns_rdatatype_ns, + result = dns_db_findrdataset(db, node, version, dns_rdatatype_ns, dns_rdatatype_none, 0, &nsrdset, NULL); if (result != ISC_R_SUCCESS) goto cleanup3; @@ -3055,9 +3077,10 @@ zone_notify(dns_zone_t *zone) { if (dns_name_dynamic(&master)) dns_name_free(&master, zone->mctx); cleanup2: - dns_db_detachnode(zone->db, &node); + dns_db_detachnode(db, &node); cleanup1: - dns_db_closeversion(zone->db, &version, ISC_FALSE); + dns_db_closeversion(db, &version, ISC_FALSE); + dns_db_detach(&db); } /*** @@ -3623,7 +3646,12 @@ refresh_callback(isc_task_t *task, isc_event_t *event) { result = ISC_R_FAILURE; if (zone->journal != NULL) result = isc_file_settime(zone->journal, &now); - if (result != ISC_R_SUCCESS) + if (result == ISC_R_SUCCESS && + !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP) && + !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DUMPING)) { + result = isc_file_settime(zone->masterfile, + &now); + } else if (result != ISC_R_SUCCESS) result = isc_file_settime(zone->masterfile, &now); /* Someone removed the file from underneath us! */ @@ -5208,6 +5236,8 @@ static isc_result_t zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) { dns_dbversion_t *ver; isc_result_t result; + unsigned int soacount = 0; + unsigned int nscount = 0; /* * 'zone' locked by caller. @@ -5215,6 +5245,27 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) { REQUIRE(DNS_ZONE_VALID(zone)); REQUIRE(LOCKED_ZONE(zone)); + result = zone_get_from_db(db, &zone->origin, &nscount, &soacount, + NULL, NULL, NULL, NULL, NULL); + if (result == ISC_R_SUCCESS) { + if (soacount != 1) { + dns_zone_log(zone, ISC_LOG_ERROR, + "has %d SOA records", soacount); + result = DNS_R_BADZONE; + } + if (nscount == 0) { + dns_zone_log(zone, ISC_LOG_ERROR, "has no NS records"); + result = DNS_R_BADZONE; + } + if (result != ISC_R_SUCCESS) + return (result); + } else { + dns_zone_log(zone, ISC_LOG_ERROR, + "retrieving SOA and NS records failed: %s", + dns_result_totext(result)); + return (result); + } + ver = NULL; dns_db_currentversion(db, &ver); @@ -5364,10 +5415,19 @@ zone_xfrdone(dns_zone_t *zone, isc_result_t result) { "transferred zone " "has %d SOA record%s", soacount, (soacount != 0) ? "s" : ""); - if (nscount == 0) + if (nscount == 0) { dns_zone_log(zone, ISC_LOG_ERROR, "transferred zone " "has no NS records"); + if (DNS_ZONE_FLAG(zone, + DNS_ZONEFLG_HAVETIMERS)) { + zone->refresh = DNS_ZONE_DEFAULTREFRESH; + zone->retry = DNS_ZONE_DEFAULTRETRY; + } + DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_HAVETIMERS); + zone_unload(zone); + goto next_master; + } zone->serial = serial; zone->refresh = RANGE(refresh, zone->minrefresh, zone->maxrefresh); @@ -5442,6 +5502,7 @@ zone_xfrdone(dns_zone_t *zone, isc_result_t result) { goto same_master; default: + next_master: zone->curmaster++; same_master: if (zone->curmaster >= zone->masterscnt) { |