diff --git a/lib/dns/include/dns/message.h b/lib/dns/include/dns/message.h index 5995ce92bd..844b8c1213 100644 --- a/lib/dns/include/dns/message.h +++ b/lib/dns/include/dns/message.h @@ -190,6 +190,7 @@ struct dns_message { ISC_LIST(dns_rdata_t) freerdata; ISC_LIST(dns_rdatalist_t) freerdatalist; + dns_tsig_keyring_t *ring; dns_rcode_t tsigstatus; dns_rcode_t querytsigstatus; dns_rdata_any_tsig_t *tsig; @@ -272,9 +273,7 @@ dns_message_parse(dns_message_t *msg, isc_buffer_t *source, * DNS message. * * OPT records are detected and stored in the pseudo-section "opt". - * TSIGs are detected and stored in the pseudo-section "tsig". At detection - * time, the TSIG is verified (XXX) and the message fails if the TSIG fails - * to verify. + * TSIGs are detected and stored in the pseudo-section "tsig". * * If 'preserve_order' is true, or if the opcode of the message is UPDATE, * a separate dns_name_t object will be created for each RR in the message. @@ -887,6 +886,26 @@ dns_message_signer(dns_message_t *msg, dns_name_t *signer); * the signature has not been verified yet */ +isc_result_t +dns_message_checksig(dns_message_t *msg, dns_view_t *view); +/* + * If this message was signed, verify the signature. + * + * Requires: + * + * msg is a valid parsed message. + * view is a valid view + * + * Returns: + * + * ISC_R_SUCCESS - the message was unsigned, or the message + * was signed correctly. + * + * DNS_R_EXPECTEDTSIG - A TSIG was expected, but not seen + * DNS_R_UNEXPECTEDTSIG - A TSIG was seen but not expected + * DNS_R_TSIGVERIFYFAILURE - The TSIG failed to verify + */ + ISC_LANG_ENDDECLS #endif /* DNS_MESSAGE_H */ diff --git a/lib/dns/include/dns/tkey.h b/lib/dns/include/dns/tkey.h index de19359b28..cb38652027 100644 --- a/lib/dns/include/dns/tkey.h +++ b/lib/dns/include/dns/tkey.h @@ -36,15 +36,22 @@ ISC_LANG_BEGINDECLS #define DNS_TKEYMODE_RESOLVERASSIGNED 4 #define DNS_TKEYMODE_DELETE 5 +struct dns_tkey_ctx { + dst_key_t *dhkey; + dns_name_t *domain; + isc_mem_t *mctx; +}; + isc_result_t -dns_tkey_init(isc_log_t *lctx, dns_c_ctx_t *cfg, isc_mem_t *mctx); +dns_tkey_init(dns_c_ctx_t *cfg, isc_mem_t *mctx, dns_tkey_ctx_t **tctx); /* * Obtains TKEY configuration information, including default DH key * and default domain from the configuration, if it's not NULL. * * Requires: - * 'lctx' is not NULL * 'mctx' is not NULL + * 'tctx' is not NULL + * '*tctx' is NULL * * Returns * ISC_R_SUCCESS @@ -53,19 +60,26 @@ dns_tkey_init(isc_log_t *lctx, dns_c_ctx_t *cfg, isc_mem_t *mctx); */ void -dns_tkey_destroy(void); +dns_tkey_destroy(dns_tkey_ctx_t **tctx); /* - * Frees all data associated with the TKEY subsystem + * Frees all data associated with the TKEY context + * + * Requires: + * 'tctx' is not NULL + * '*tctx' is not NULL */ isc_result_t -dns_tkey_processquery(dns_message_t *msg); +dns_tkey_processquery(dns_message_t *msg, dns_tkey_ctx_t *tctx, + dns_tsig_keyring_t *ring); /* * Processes a query containing a TKEY record, adding or deleting TSIG * keys if necessary, and modifies the message to contain the response. * * Requires: * 'msg' is a valid message + * 'tctx' is a valid TKEY context + * 'ring' is a valid TSIG keyring * * Returns * ISC_R_SUCCESS msg was updated (the TKEY operation succeeded, @@ -117,7 +131,8 @@ dns_tkey_builddeletequery(dns_message_t *msg, dns_tsigkey_t *key); isc_result_t dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg, - dst_key_t *key, dns_tsigkey_t **outkey); + dst_key_t *key, isc_buffer_t *nonce, + dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring); /* * Processes a response to a query containing a TKEY that was * designed to generate a shared secret using a Diffie-Hellman key @@ -129,6 +144,7 @@ dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg, * 'rmsg' is a valid message (the response) * 'key' is a valid Diffie Hellman dst key * 'outkey' is either NULL or a pointer to NULL + * 'ring' is not NULL * * Returns: * ISC_R_SUCCESS the shared key was successfully added @@ -137,7 +153,8 @@ dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg, */ isc_result_t -dns_tkey_processdeleteresponse(dns_message_t *qmsg, dns_message_t *rmsg); +dns_tkey_processdeleteresponse(dns_message_t *qmsg, dns_message_t *rmsg, + dns_tsig_keyring_t *ring); /* * Processes a response to a query containing a TKEY that was * designed to delete a shared secret. If the query was successful, @@ -146,6 +163,7 @@ dns_tkey_processdeleteresponse(dns_message_t *qmsg, dns_message_t *rmsg); * Requires: * 'qmsg' is a valid message (the query) * 'rmsg' is a valid message (the response) + * 'ring' is not NULL * * Returns: * ISC_R_SUCCESS the shared key was successfully deleted diff --git a/lib/dns/include/dns/tsig.h b/lib/dns/include/dns/tsig.h index ce1b8ddf83..2e5c27fc86 100644 --- a/lib/dns/include/dns/tsig.h +++ b/lib/dns/include/dns/tsig.h @@ -20,7 +20,7 @@ #include #include -#include +#include #include #include @@ -38,6 +38,12 @@ extern dns_name_t *dns_tsig_hmacmd5_name; /* Default fudge value. */ #define DNS_TSIG_FUDGE 300 +struct dns_tsig_keyring { + ISC_LIST(dns_tsigkey_t) keys; + isc_rwlock_t lock; + isc_mem_t *mctx; +}; + struct dns_tsigkey { /* Unlocked */ unsigned int magic; /* Magic number. */ @@ -62,10 +68,11 @@ struct dns_tsigkey { isc_result_t dns_tsigkey_create(dns_name_t *name, dns_name_t *algorithm, unsigned char *secret, int length, isc_boolean_t generated, - dns_name_t *creator, isc_mem_t *mctx, dns_tsigkey_t **key); + dns_name_t *creator, isc_mem_t *mctx, + dns_tsig_keyring_t *ring, dns_tsigkey_t **key); /* - * Creates and saves a tsig key structure. If key is not NULL, *key - * will contain a copy of the key. + * Creates a tsig key structure and saves it in the keyring. If key is + * not NULL, *key * will contain a copy of the key. * * Requires: * 'name' is a valid dns_name_t @@ -74,6 +81,7 @@ dns_tsigkey_create(dns_name_t *name, dns_name_t *algorithm, * 'length' is an integer greater than 0 * 'creator' points to a valid dns_name_t or is NULL * 'mctx' is a valid memory context + * 'ring' is a valid TSIG keyring * 'key' or '*key' must be NULL * * Returns: @@ -84,12 +92,13 @@ dns_tsigkey_create(dns_name_t *name, dns_name_t *algorithm, */ void -dns_tsigkey_free(dns_tsigkey_t **key); +dns_tsigkey_free(dns_tsigkey_t **key, dns_tsig_keyring_t *ring); /* * Frees the tsig key structure pointed to by 'key'. * * Requires: * 'key' is a valid TSIG key + * 'ring' is a valid TSIG keyring containing the key */ void @@ -119,7 +128,8 @@ dns_tsig_sign(dns_message_t *msg); */ isc_result_t -dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg); +dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg, + dns_tsig_keyring_t *sring, dns_tsig_keyring_t *dring); /* * Verifies the TSIG record in this message * @@ -129,6 +139,8 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg); * 'msg->tsigkey' is a valid TSIG key if this is a response * 'msg->tsig' is NULL * 'msg->querytsig' is not NULL if this is a response + * 'sring' is a valid keyring or NULL + * 'dring' is a valid keyring or NULL * * Returns: * DNS_R_SUCCESS @@ -140,28 +152,9 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg); * DNS_R_TSIGVERIFYFAILURE - the TSIG failed to verify */ -isc_result_t -dns_tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg); -/* - * Verifies the TSIG record in this continuation of a TCP response, - * if there is one. - * - * Requires: - * 'source' is a valid buffer containing the unparsed message - * 'msg' is a valid message - * 'msg->tsigkey' is a valid TSIG key - * 'msg->tsig' is NULL - * 'msg->querytsig' is not NULL - * - * Returns: - * DNS_R_SUCCESS - * ISC_R_NOMEMORY - * DNS_R_TSIGVERIFYFAILURE - the TSIG failed to verify - */ - isc_result_t dns_tsigkey_find(dns_tsigkey_t **tsigkey, dns_name_t *name, - dns_name_t *algorithm); + dns_name_t *algorithm, dns_tsig_keyring_t *ring); /* * Returns the TSIG key corresponding to this name and (possibly) * algorithm. Also increments the key's reference counter. @@ -171,6 +164,7 @@ dns_tsigkey_find(dns_tsigkey_t **tsigkey, dns_name_t *name, * '*tsigkey' is NULL * 'name' is a valid dns_name_t * 'algorithm' is a valid dns_name_t or NULL + * 'ring' is a valid keyring * * Returns: * ISC_R_SUCCESS @@ -179,15 +173,15 @@ dns_tsigkey_find(dns_tsigkey_t **tsigkey, dns_name_t *name, isc_result_t -dns_tsig_init(isc_log_t *lctx, dns_c_ctx_t *confctx, isc_mem_t *mctx); +dns_tsig_init(dns_c_ctx_t *confctx, isc_mem_t *mctx, dns_tsig_keyring_t **ring); /* * Initializes the TSIG subsystem. If confctx is not NULL, any * specified keys are loaded. * * Requires: - * 'lctx' is not NULL * 'mctx' is not NULL - + * 'ring' is not NULL, and '*ring' is NULL + * * Returns: * ISC_R_SUCCESS * ISC_R_NOMEMORY @@ -195,9 +189,12 @@ dns_tsig_init(isc_log_t *lctx, dns_c_ctx_t *confctx, isc_mem_t *mctx); void -dns_tsig_destroy(void); +dns_tsig_destroy(dns_tsig_keyring_t **ring); /* * Frees all data associated with the TSIG subsystem + * + * Requires: + * 'ring' is not NULL */ ISC_LANG_ENDDECLS diff --git a/lib/dns/include/dns/types.h b/lib/dns/include/dns/types.h index 9380b6e907..dc1a657056 100644 --- a/lib/dns/include/dns/types.h +++ b/lib/dns/include/dns/types.h @@ -78,6 +78,8 @@ typedef struct dns_dispatch dns_dispatch_t; typedef struct dns_dispentry dns_dispentry_t; typedef struct dns_dispatchevent dns_dispatchevent_t; typedef struct dns_tsigkey dns_tsigkey_t; +typedef struct dns_tsig_keyring dns_tsig_keyring_t; +typedef struct dns_tkey_ctx dns_tkey_ctx_t; typedef struct dns_view dns_view_t; typedef ISC_LIST(dns_view_t) dns_viewlist_t; typedef struct dns_zone dns_zone_t; diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index ea7a05fd4b..140b22a405 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -88,6 +88,8 @@ struct dns_view { isc_task_t * task; isc_event_t resevent; isc_event_t adbevent; + dns_tsig_keyring_t * statickeys; + dns_tsig_keyring_t * dynamickeys; /* Locked by lock. */ unsigned int references; unsigned int attributes; @@ -226,6 +228,26 @@ dns_view_sethints(dns_view_t *view, dns_db_t *hints); * The hints database of 'view' is 'hints'. */ +void +dns_view_setkeyring(dns_view_t *view, dns_tsig_keyring_t *ring); +/* + * Set the view's static TSIG keys + * + * Requires: + * + * 'view' is a valid, unfrozen view, whose static TSIG keyring has not + * been set. + * + * 'ring' is a valid TSIG keyring + * + * Ensures: + * + * The static TSIG keyring of 'view' is 'ring'. + */ + + + + isc_result_t dns_view_addzone(dns_view_t *view, dns_zone_t *zone); /* @@ -421,6 +443,21 @@ dns_view_load(dns_view_t *view); * 'view' is a valid. */ +isc_result_t +dns_view_checksig(dns_view_t *view, isc_buffer_t *source, dns_message_t *msg); +/* + * Verifies the signature of a message. + * + * Requires: + * + * 'view' is a valid view. + * 'source' is a valid buffer containing the message + * 'msg' is a valid message + * + * Returns: + * see dns_tsig_verify() + */ + ISC_LANG_ENDDECLS #endif /* DNS_VIEW_H */ diff --git a/lib/dns/message.c b/lib/dns/message.c index 4c2f23c015..b1f9954243 100644 --- a/lib/dns/message.c +++ b/lib/dns/message.c @@ -38,6 +38,7 @@ #include #include #include +#include #define DNS_MESSAGE_OPCODE_MASK 0x7800U #define DNS_MESSAGE_OPCODE_SHIFT 11 @@ -287,6 +288,7 @@ msginitprivate(dns_message_t *m) static inline void msginittsig(dns_message_t *m) { + m->ring = NULL; m->tsigstatus = m->querytsigstatus = dns_rcode_noerror; m->tsig = m->querytsig = NULL; m->tsigkey = NULL; @@ -455,7 +457,7 @@ msgreset(dns_message_t *msg, isc_boolean_t everything) } if (msg->tsigkey != NULL) { - dns_tsigkey_free(&msg->tsigkey); + dns_tsigkey_free(&msg->tsigkey, msg->ring); msg->tsigkey = NULL; } @@ -1317,17 +1319,9 @@ dns_message_parse(dns_message_t *msg, isc_buffer_t *source, if (r.length != 0) return (DNS_R_FORMERR); - if (msg->tsigkey != NULL || - !ISC_LIST_EMPTY(msg->sections[DNS_SECTION_TSIG])) + if (!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_TSIG]) || + !ISC_LIST_EMPTY(msg->sections[DNS_SECTION_SIG0])) { - if (!msg->tcp_continuation) - ret = dns_tsig_verify(source, msg); - else - ret = dns_tsig_verify_tcp(source, msg); - if (ret != DNS_R_SUCCESS) - return ret; - } - else if (!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_SIG0])) { msg->saved = isc_mem_get(msg->mctx, sizeof(isc_region_t)); if (msg->saved == NULL) return (ISC_R_NOMEMORY); @@ -2148,3 +2142,21 @@ dns_message_signer(dns_message_t *msg, dns_name_t *signer) { return (result); } + +isc_result_t +dns_message_checksig(dns_message_t *msg, dns_view_t *view) { + isc_buffer_t b; + + REQUIRE(DNS_MESSAGE_VALID(msg)); + REQUIRE(view != NULL); + + if (msg->tsigkey == NULL && + ISC_LIST_EMPTY(msg->sections[DNS_SECTION_TSIG])) + return (ISC_R_SUCCESS); + if (msg->saved == NULL) + return (DNS_R_EXPECTEDTSIG); + isc_buffer_init(&b, msg->saved->base, msg->saved->length, + ISC_BUFFERTYPE_BINARY); + isc_buffer_add(&b, msg->saved->length); + return dns_view_checksig(view, &b, msg); +} diff --git a/lib/dns/tkey.c b/lib/dns/tkey.c index 7388344f71..1c083cf794 100644 --- a/lib/dns/tkey.c +++ b/lib/dns/tkey.c @@ -16,7 +16,7 @@ */ /* - * $Id: tkey.c,v 1.15 1999/12/06 12:40:30 brister Exp $ + * $Id: tkey.c,v 1.16 2000/01/21 20:18:36 bwelling Exp $ * Principal Author: Brian Wellington */ @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -63,12 +64,8 @@ } while (0) -static dst_key_t *tkey_dhkey = NULL; -static dns_name_t *tkey_domain = NULL; -static isc_mem_t *tkey_mctx = NULL; - isc_result_t -dns_tkey_init(isc_log_t *lctx, dns_c_ctx_t *cfg, isc_mem_t *mctx) { +dns_tkey_init(dns_c_ctx_t *cfg, isc_mem_t *mctx, dns_tkey_ctx_t **tctx) { isc_result_t result; char *s; int n; @@ -76,11 +73,16 @@ dns_tkey_init(isc_log_t *lctx, dns_c_ctx_t *cfg, isc_mem_t *mctx) { unsigned char data[1024]; dns_name_t domain; - RUNTIME_CHECK(tkey_domain == NULL); - RUNTIME_CHECK(tkey_dhkey == NULL); - - REQUIRE(lctx != NULL); /* XXX lctx is now unused. */ REQUIRE(mctx != NULL); + REQUIRE(tctx != NULL); + REQUIRE(*tctx == NULL); + + *tctx = isc_mem_get(mctx, sizeof(dns_tkey_ctx_t)); + if (*tctx == NULL) + return (ISC_R_NOMEMORY); + (*tctx)->mctx = mctx; + (*tctx)->dhkey = NULL; + (*tctx)->domain = NULL; if (cfg == NULL) return (ISC_R_SUCCESS); @@ -91,47 +93,50 @@ dns_tkey_init(isc_log_t *lctx, dns_c_ctx_t *cfg, isc_mem_t *mctx) { return (ISC_R_SUCCESS); RETERR(dst_key_fromfile(s, n, DNS_KEYALG_DH, DST_TYPE_PUBLIC|DST_TYPE_PRIVATE, - mctx, &tkey_dhkey)); + mctx, &(*tctx)->dhkey)); s = NULL; RETERR(dns_c_ctx_gettkeydomain(cfg, &s)); dns_name_init(&domain, NULL); - tkey_domain = (dns_name_t *) isc_mem_get(mctx, sizeof(dns_name_t)); - if (tkey_domain == NULL) + (*tctx)->domain = (dns_name_t *) isc_mem_get(mctx, sizeof(dns_name_t)); + if ((*tctx)->domain == NULL) return (ISC_R_NOMEMORY); - dns_name_init(tkey_domain, NULL); + dns_name_init((*tctx)->domain, NULL); isc_buffer_init(&b, s, strlen(s), ISC_BUFFERTYPE_TEXT); isc_buffer_add(&b, strlen(s)); isc_buffer_init(&namebuf, data, sizeof(data), ISC_BUFFERTYPE_BINARY); RETERR(dns_name_fromtext(&domain, &b, dns_rootname, ISC_FALSE, &namebuf)); - RETERR(dns_name_dup(&domain, mctx, tkey_domain)); - - tkey_mctx = mctx; + RETERR(dns_name_dup(&domain, mctx, (*tctx)->domain)); return (ISC_R_SUCCESS); failure: - if (tkey_dhkey != NULL) { - dst_key_free(tkey_dhkey); - tkey_dhkey = NULL; + if ((*tctx)->dhkey != NULL) { + dst_key_free((*tctx)->dhkey); + (*tctx)->dhkey = NULL; } - if (tkey_domain != NULL) { - dns_name_free(tkey_domain, mctx); - isc_mem_put(mctx, tkey_domain, sizeof(dns_name_t)); - tkey_domain = NULL; + if ((*tctx)->domain != NULL) { + dns_name_free((*tctx)->domain, mctx); + isc_mem_put(mctx, (*tctx)->domain, sizeof(dns_name_t)); + (*tctx)->domain = NULL; } return (result); } void -dns_tkey_destroy(void) { - if (tkey_mctx == NULL) - return; - if (tkey_dhkey != NULL) - dst_key_free(tkey_dhkey); - if (tkey_domain != NULL) - isc_mem_put(tkey_mctx, tkey_domain, sizeof(dns_name_t)); - tkey_mctx = NULL; +dns_tkey_destroy(dns_tkey_ctx_t **tctx) { + isc_mem_t *mctx; + + REQUIRE(tctx != NULL); + REQUIRE(*tctx != NULL); + + if ((*tctx)->dhkey != NULL) + dst_key_free((*tctx)->dhkey); + if ((*tctx)->domain != NULL) + isc_mem_put((*tctx)->mctx, (*tctx)->domain, sizeof(dns_name_t)); + + mctx = (*tctx)->mctx; + isc_mem_put(mctx, *tctx, sizeof(dns_tkey_ctx_t)); } static isc_result_t @@ -169,6 +174,7 @@ add_rdata_to_list(dns_message_t *msg, dns_name_t *name, dns_rdata_t *rdata, RETERR(dns_message_gettemprdatalist(msg, &newlist)); newlist->rdclass = newrdata->rdclass; newlist->type = newrdata->type; + newlist->covers = 0; newlist->ttl = ttl; ISC_LIST_INIT(newlist->rdata); ISC_LIST_APPEND(newlist->rdata, newrdata, link); @@ -191,27 +197,59 @@ add_rdata_to_list(dns_message_t *msg, dns_name_t *name, dns_rdata_t *rdata, dns_message_puttempname(msg, &newname); if (newlist != NULL) dns_message_puttemprdatalist(msg, &newlist); - if (newset != NULL) + if (newset != NULL) { + dns_rdataset_disassociate(newset); dns_message_puttemprdataset(msg, &newset); + } return (result); } static isc_result_t -compute_secret(isc_buffer_t *shared, isc_region_t *randomness, - isc_buffer_t *secret) +compute_secret(isc_buffer_t *shared, isc_region_t *queryrandomness, + isc_region_t *serverrandomness, isc_buffer_t *secret) { dst_context_t ctx; isc_result_t result; - isc_region_t r; + isc_region_t r, r2; + char digests[32]; + isc_buffer_t b; + unsigned int i; + isc_buffer_init(&b, digests, sizeof(digests), ISC_BUFFERTYPE_BINARY); isc_buffer_used(shared, &r); + + /* MD5 ( query data | DH value ) */ RETERR(dst_digest(DST_SIGMODE_INIT, DST_DIGEST_MD5, &ctx, NULL, NULL)); + RETERR(dst_digest(DST_SIGMODE_UPDATE, DST_DIGEST_MD5, &ctx, + queryrandomness, NULL)); RETERR(dst_digest(DST_SIGMODE_UPDATE, DST_DIGEST_MD5, &ctx, &r, NULL)); - if (randomness->length != 0) - RETERR(dst_digest(DST_SIGMODE_UPDATE, DST_DIGEST_MD5, - &ctx, randomness, secret)); - RETERR(dst_digest(DST_SIGMODE_FINAL, DST_DIGEST_MD5, &ctx, NULL, - secret)); + RETERR(dst_digest(DST_SIGMODE_FINAL, DST_DIGEST_MD5, &ctx, NULL, &b)); + + /* MD5 ( server data | DH value ) */ + RETERR(dst_digest(DST_SIGMODE_INIT, DST_DIGEST_MD5, &ctx, NULL, NULL)); + RETERR(dst_digest(DST_SIGMODE_UPDATE, DST_DIGEST_MD5, &ctx, + serverrandomness, NULL)); + RETERR(dst_digest(DST_SIGMODE_UPDATE, DST_DIGEST_MD5, &ctx, &r, NULL)); + RETERR(dst_digest(DST_SIGMODE_FINAL, DST_DIGEST_MD5, &ctx, NULL, &b)); + + /* XOR ( DH value, MD5-1 | MD5-2) */ + isc_buffer_available(secret, &r); + isc_buffer_used(shared, &r2); + if (r.length < sizeof(digests) || r.length < r2.length) + return (ISC_R_NOSPACE); + if (r2.length > sizeof(digests)) { + memcpy(r.base, r2.base, r2.length); + for (i = 0; i < sizeof(digests); i++) + r.base[i] ^= digests[i]; + isc_buffer_add(secret, r2.length); + } + else { + memcpy(r.base, digests, sizeof(digests)); + for (i = 0; i < r2.length; i++) + r.base[i] ^= r2.base[i]; + isc_buffer_add(secret, sizeof(digests)); + } + failure: return result; @@ -219,8 +257,9 @@ compute_secret(isc_buffer_t *shared, isc_region_t *randomness, static isc_result_t process_dhtkey(dns_message_t *msg, dns_name_t *name, - dns_rdata_generic_tkey_t *tkeyin, - dns_rdata_generic_tkey_t *tkeyout, dns_namelist_t *namelist) + dns_rdata_generic_tkey_t *tkeyin, dns_tkey_ctx_t *tctx, + dns_rdata_generic_tkey_t *tkeyout, + dns_tsig_keyring_t *ring, dns_namelist_t *namelist) { isc_result_t result = ISC_R_SUCCESS; dns_name_t *keyname, ourname, signer, *creator; @@ -229,14 +268,14 @@ process_dhtkey(dns_message_t *msg, dns_name_t *name, isc_boolean_t found_key = ISC_FALSE, found_incompatible = ISC_FALSE; dst_key_t *pubkey = NULL; isc_buffer_t ourkeybuf, ournamein, ournameout, *shared = NULL; - isc_region_t r, ourkeyr; + isc_region_t r, r2, ourkeyr; isc_uint32_t ourttl; unsigned char keydata[DST_KEY_MAXSIZE]; unsigned char namedata[1024]; dns_tsigkey_t *tsigkey; unsigned int sharedsize; isc_buffer_t randombuf, secret; - unsigned char *randomdata = NULL, secretdata[TKEY_RANDOM_AMOUNT]; + unsigned char *randomdata = NULL, secretdata[256]; /* Look for a DH KEY record that will work with ours */ result = dns_message_firstname(msg, DNS_SECTION_ADDITIONAL); @@ -261,7 +300,7 @@ process_dhtkey(dns_message_t *msg, dns_name_t *name, } if (dst_key_alg(pubkey) == DNS_KEYALG_DH) { if (dst_key_paramcompare(pubkey, - tkey_dhkey)) + tctx->dhkey)) { found_key = ISC_TRUE; goto got_key; @@ -290,13 +329,13 @@ process_dhtkey(dns_message_t *msg, dns_name_t *name, isc_buffer_init(&ourkeybuf, keydata, sizeof(keydata), ISC_BUFFERTYPE_BINARY); - RETERR(dst_key_todns(tkey_dhkey, &ourkeybuf)); + RETERR(dst_key_todns(tctx->dhkey, &ourkeybuf)); isc_buffer_used(&ourkeybuf, &ourkeyr); dns_rdata_fromregion(&ourkeyrdata, dns_rdataclass_in, dns_rdatatype_key, &ourkeyr); - isc_buffer_init(&ournamein, dst_key_name(tkey_dhkey), - strlen(dst_key_name(tkey_dhkey)), ISC_BUFFERTYPE_TEXT); - isc_buffer_add(&ournamein, strlen(dst_key_name(tkey_dhkey))); + isc_buffer_init(&ournamein, dst_key_name(tctx->dhkey), + strlen(dst_key_name(tctx->dhkey)), ISC_BUFFERTYPE_TEXT); + isc_buffer_add(&ournamein, strlen(dst_key_name(tctx->dhkey))); isc_buffer_init(&ournameout, namedata, sizeof(namedata), ISC_BUFFERTYPE_BINARY); dns_name_init(&ourname, NULL); @@ -326,11 +365,11 @@ process_dhtkey(dns_message_t *msg, dns_name_t *name, RETERR(add_rdata_to_list(msg, &ourname, &ourkeyrdata, ourttl, namelist)); - RETERR(dst_secret_size(tkey_dhkey, &sharedsize)); + RETERR(dst_secret_size(tctx->dhkey, &sharedsize)); RETERR(isc_buffer_allocate(msg->mctx, &shared, sharedsize, ISC_BUFFERTYPE_BINARY)); - RETERR(dst_computesecret(pubkey, tkey_dhkey, shared)); + RETERR(dst_computesecret(pubkey, tctx->dhkey, shared)); isc_buffer_init(&secret, secretdata, sizeof(secretdata), ISC_BUFFERTYPE_BINARY); @@ -345,7 +384,9 @@ process_dhtkey(dns_message_t *msg, dns_name_t *name, RETERR(dst_random_get(TKEY_RANDOM_AMOUNT, &randombuf)); isc_buffer_used(&randombuf, &r); - RETERR(compute_secret(shared, &r, &secret)); + r2.base = tkeyin->key; + r2.length = tkeyin->keylen; + RETERR(compute_secret(shared, &r2, &r, &secret)); dns_name_init(&signer, NULL); result = dns_message_signer(msg, &signer); @@ -359,7 +400,8 @@ process_dhtkey(dns_message_t *msg, dns_name_t *name, isc_buffer_used(&secret, &r); tsigkey = NULL; result = dns_tsigkey_create(name, &tkeyin->algorithm, r.base, r.length, - ISC_TRUE, creator, msg->mctx, &tsigkey); + ISC_TRUE, creator, msg->mctx, ring, + &tsigkey); isc_buffer_free(&shared); shared = NULL; if (result == ISC_R_NOTFOUND) { @@ -387,6 +429,7 @@ process_dhtkey(dns_message_t *msg, dns_name_t *name, ISC_LIST_UNLINK(*namelist, tname, link); tset = ISC_LIST_HEAD(tname->list); + dns_rdataset_disassociate(tset); dns_message_puttemprdataset(msg, &tset); dns_message_puttempname(msg, &tname); tname = next; @@ -401,6 +444,7 @@ static isc_result_t process_deletetkey(dns_message_t *msg, dns_name_t *name, dns_rdata_generic_tkey_t *tkeyin, dns_rdata_generic_tkey_t *tkeyout, + dns_tsig_keyring_t *ring, dns_namelist_t *namelist) { isc_result_t result; @@ -412,7 +456,7 @@ process_deletetkey(dns_message_t *msg, dns_name_t *name, tkeyout = tkeyout; namelist = namelist; - result = dns_tsigkey_find(&tsigkey, name, &tkeyin->algorithm); + result = dns_tsigkey_find(&tsigkey, name, &tkeyin->algorithm, ring); if (result != ISC_R_SUCCESS) tkeyout->error = dns_tsigerror_badname; @@ -448,13 +492,15 @@ process_deletetkey(dns_message_t *msg, dns_name_t *name, */ dns_tsigkey_setdeleted(tsigkey); /* Release the reference */ - dns_tsigkey_free(&tsigkey); + dns_tsigkey_free(&tsigkey, ring); return (ISC_R_SUCCESS); } isc_result_t -dns_tkey_processquery(dns_message_t *msg) { +dns_tkey_processquery(dns_message_t *msg, dns_tkey_ctx_t *tctx, + dns_tsig_keyring_t *ring) +{ isc_result_t result = ISC_R_SUCCESS; dns_rdata_generic_tkey_t tkeyin, tkeyout; dns_name_t *qname, *name, *keyname; @@ -463,6 +509,10 @@ dns_tkey_processquery(dns_message_t *msg) { isc_buffer_t *dynbuf = NULL; dns_namelist_t namelist; + REQUIRE(msg != NULL); + REQUIRE(tctx != NULL); + REQUIRE(ring != NULL); + /* Need to do this to determine if this should be freed later */ memset(&tkeyin, 0, sizeof(dns_rdata_generic_tkey_t)); @@ -570,16 +620,16 @@ dns_tkey_processquery(dns_message_t *msg) { goto failure; } } - result = dns_name_concatenate(&prefix, tkey_domain, + result = dns_name_concatenate(&prefix, tctx->domain, keyname, buf); dns_message_takebuffer(msg, &buf); if (result != ISC_R_SUCCESS) goto failure; - result = dns_tsigkey_find(&tsigkey, keyname, NULL); + result = dns_tsigkey_find(&tsigkey, keyname, NULL, ring); if (result == ISC_R_SUCCESS) { tkeyout.error = dns_tsigerror_badname; - dns_tsigkey_free(&tsigkey); + dns_tsigkey_free(&tsigkey, ring); goto failure_with_tkey; } else if (result != ISC_R_NOTFOUND) @@ -595,13 +645,13 @@ dns_tkey_processquery(dns_message_t *msg) { switch (tkeyin.mode) { case DNS_TKEYMODE_DIFFIEHELLMAN: - RETERR(process_dhtkey(msg, keyname, &tkeyin, - &tkeyout, &namelist)); + RETERR(process_dhtkey(msg, keyname, &tkeyin, tctx, + &tkeyout, ring, &namelist)); tkeyout.error = dns_rcode_noerror; break; case DNS_TKEYMODE_DELETE: RETERR(process_deletetkey(msg, keyname, &tkeyin, - &tkeyout, &namelist)); + &tkeyout, ring, &namelist)); tkeyout.error = dns_rcode_noerror; break; case DNS_TKEYMODE_SERVERASSIGNED: @@ -712,8 +762,10 @@ buildquery(dns_message_t *msg, dns_name_t *name, dns_message_puttempname(msg, &qname); if (aname != NULL) dns_message_puttempname(msg, &aname); - if (question != NULL) + if (question != NULL) { + dns_rdataset_disassociate(question); dns_message_puttemprdataset(msg, &question); + } if (dynbuf != NULL) isc_buffer_free(&dynbuf); return (result); @@ -738,8 +790,6 @@ dns_tkey_builddhquery(dns_message_t *msg, dst_key_t *key, dns_name_t *name, REQUIRE(name != NULL); REQUIRE(algorithm != NULL); - nonce = nonce; /* until the new spec is done */ - tkey.common.rdclass = dns_rdataclass_in /**/; tkey.common.rdtype = dns_rdatatype_tkey; ISC_LINK_INIT(&tkey.common, link); @@ -748,9 +798,12 @@ dns_tkey_builddhquery(dns_message_t *msg, dst_key_t *key, dns_name_t *name, dns_name_clone(algorithm, &tkey.algorithm); tkey.inception = tkey.expire = 0; tkey.mode = DNS_TKEYMODE_DIFFIEHELLMAN; + isc_buffer_region(nonce, &r); tkey.error = 0; - tkey.keylen = tkey.otherlen = 0; - tkey.key = tkey.other = NULL; + tkey.key = r.base; + tkey.keylen = r.length; + tkey.other = NULL; + tkey.otherlen = 0; RETERR(buildquery(msg, name, &tkey)); @@ -836,7 +889,8 @@ find_tkey(dns_message_t *msg, dns_name_t **name, dns_rdata_t *rdata) { isc_result_t dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg, - dst_key_t *key, dns_tsigkey_t **outkey) + dst_key_t *key, isc_buffer_t *nonce, + dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring) { dns_rdata_t qtkeyrdata, rtkeyrdata; dns_name_t keyname, *tkeyname, *theirkeyname, *ourkeyname, *tempname; @@ -845,10 +899,10 @@ dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg, dst_key_t *theirkey; dns_tsigkey_t *tsigkey; dns_rdata_generic_tkey_t qtkey, rtkey; - unsigned char keydata[1024], secretdata[16]; + unsigned char keydata[1024], secretdata[256]; unsigned int sharedsize; isc_buffer_t keysrc, keybuf, *shared = NULL, secret; - isc_region_t r; + isc_region_t r, r2; isc_result_t result; REQUIRE(qmsg != NULL); @@ -858,6 +912,7 @@ dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg, REQUIRE(dst_key_isprivate(key)); if (outkey != NULL) REQUIRE(*outkey == NULL); + REQUIRE(ring != NULL); RETERR(find_tkey(rmsg, &tkeyname, &rtkeyrdata)); RETERR(dns_rdata_tostruct(&rtkeyrdata, &rtkey, rmsg->mctx)); @@ -930,13 +985,14 @@ dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg, r.base = rtkey.key; r.length = rtkey.keylen; - RETERR(compute_secret(shared, &r, &secret)); + isc_buffer_region(nonce, &r2); + RETERR(compute_secret(shared, &r2, &r, &secret)); isc_buffer_used(&secret, &r); tsigkey = NULL; result = dns_tsigkey_create(tkeyname, &rtkey.algorithm, r.base, r.length, ISC_TRUE, - NULL, rmsg->mctx, outkey); + NULL, rmsg->mctx, ring, outkey); isc_buffer_free(&shared); return (result); @@ -948,7 +1004,9 @@ dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg, } isc_result_t -dns_tkey_processdeleteresponse(dns_message_t *qmsg, dns_message_t *rmsg) { +dns_tkey_processdeleteresponse(dns_message_t *qmsg, dns_message_t *rmsg, + dns_tsig_keyring_t *ring) +{ dns_rdata_t qtkeyrdata, rtkeyrdata; dns_name_t *tkeyname, *tempname; dns_rdata_generic_tkey_t qtkey, rtkey; @@ -975,12 +1033,12 @@ dns_tkey_processdeleteresponse(dns_message_t *qmsg, dns_message_t *rmsg) { goto failure; } - RETERR(dns_tsigkey_find(&tsigkey, tkeyname, &rtkey.algorithm)); + RETERR(dns_tsigkey_find(&tsigkey, tkeyname, &rtkey.algorithm,ring)); /* Mark the key as deleted */ dns_tsigkey_setdeleted(tsigkey); /* Release the reference */ - dns_tsigkey_free(&tsigkey); + dns_tsigkey_free(&tsigkey, ring); failure: return (result); diff --git a/lib/dns/tsig.c b/lib/dns/tsig.c index 2dab2445bf..6853c452d2 100644 --- a/lib/dns/tsig.c +++ b/lib/dns/tsig.c @@ -16,7 +16,7 @@ */ /* - * $Id: tsig.c,v 1.36 1999/12/17 21:09:34 bwelling Exp $ + * $Id: tsig.c,v 1.37 2000/01/21 20:18:37 bwelling Exp $ * Principal Author: Brian Wellington */ @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -54,19 +55,20 @@ #define TSIG_MAGIC 0x54534947 /* TSIG */ #define VALID_TSIG_KEY(x) ((x) != NULL && (x)->magic == TSIG_MAGIC) -/* XXXBEW If an unsorted list isn't good enough, this can be updated */ -static ISC_LIST(dns_tsigkey_t) tsigkeys; -static isc_rwlock_t tsiglock; -static isc_mem_t *tsig_mctx = NULL; +#define is_response(msg) (msg->flags & DNS_MESSAGEFLAG_QR) +static isc_once_t once = ISC_ONCE_INIT; +static dns_name_t hmacmd5_name; dns_name_t *dns_tsig_hmacmd5_name = NULL; -#define is_response(msg) (msg->flags & DNS_MESSAGEFLAG_QR) +static isc_result_t +dns_tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg); isc_result_t dns_tsigkey_create(dns_name_t *name, dns_name_t *algorithm, unsigned char *secret, int length, isc_boolean_t generated, - dns_name_t *creator, isc_mem_t *mctx, dns_tsigkey_t **key) + dns_name_t *creator, isc_mem_t *mctx, + dns_tsig_keyring_t *ring, dns_tsigkey_t **key) { isc_buffer_t b, nameb; char namestr[1025]; @@ -144,19 +146,19 @@ dns_tsigkey_create(dns_name_t *name, dns_name_t *algorithm, goto cleanup_algorithm; ISC_LINK_INIT(tkey, link); - isc_rwlock_lock(&tsiglock, isc_rwlocktype_write); - tmp = ISC_LIST_HEAD(tsigkeys); + isc_rwlock_lock(&ring->lock, isc_rwlocktype_write); + tmp = ISC_LIST_HEAD(ring->keys); while (tmp != NULL) { if (dns_name_equal(&tkey->name, &tmp->name)) { ret = ISC_R_EXISTS; - isc_rwlock_unlock(&tsiglock, + isc_rwlock_unlock(&ring->lock, isc_rwlocktype_write); goto cleanup_algorithm; } tmp = ISC_LIST_NEXT(tmp, link); } - ISC_LIST_APPEND(tsigkeys, tkey, link); - isc_rwlock_unlock(&tsiglock, isc_rwlocktype_write); + ISC_LIST_APPEND(ring->keys, tkey, link); + isc_rwlock_unlock(&ring->lock, isc_rwlocktype_write); } else tkey->key = NULL; @@ -189,7 +191,7 @@ cleanup_key: } static void -tsigkey_free(dns_tsigkey_t **key) { +tsigkey_free(dns_tsigkey_t **key, dns_tsig_keyring_t *ring) { dns_tsigkey_t *tkey; REQUIRE(key != NULL); @@ -199,9 +201,9 @@ tsigkey_free(dns_tsigkey_t **key) { tkey->magic = 0; if (tkey->key != NULL) { - isc_rwlock_lock(&tsiglock, isc_rwlocktype_write); - ISC_LIST_UNLINK(tsigkeys, tkey, link); - isc_rwlock_unlock(&tsiglock, isc_rwlocktype_write); + isc_rwlock_lock(&ring->lock, isc_rwlocktype_write); + ISC_LIST_UNLINK(ring->keys, tkey, link); + isc_rwlock_unlock(&ring->lock, isc_rwlocktype_write); } dns_name_free(&tkey->name, tkey->mctx); dns_name_free(&tkey->algorithm, tkey->mctx); @@ -215,7 +217,7 @@ tsigkey_free(dns_tsigkey_t **key) { } void -dns_tsigkey_free(dns_tsigkey_t **key) { +dns_tsigkey_free(dns_tsigkey_t **key, dns_tsig_keyring_t *ring) { dns_tsigkey_t *tkey; REQUIRE(key != NULL); @@ -230,7 +232,7 @@ dns_tsigkey_free(dns_tsigkey_t **key) { return; } isc_mutex_unlock(&tkey->lock); - tsigkey_free(key); + tsigkey_free(key, ring); } void @@ -526,7 +528,9 @@ cleanup_struct: } isc_result_t -dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg) { +dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg, + dns_tsig_keyring_t *sring, dns_tsig_keyring_t *dring) +{ dns_rdata_any_tsig_t *tsig; isc_region_t r, source_r, header_r, sig_r; isc_buffer_t databuf; @@ -549,6 +553,9 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg) { if (msg->tsigkey != NULL) REQUIRE(VALID_TSIG_KEY(msg->tsigkey)); + if (msg->tcp_continuation) + return(dns_tsig_verify_tcp(source, msg)); + /* There should be a TSIG record... */ if (ISC_LIST_EMPTY(msg->sections[DNS_SECTION_TSIG])) return (DNS_R_EXPECTEDTSIG); @@ -598,13 +605,23 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg) { /* Find dns_tsigkey_t based on keyname */ if (msg->tsigkey == NULL) { - ret = dns_tsigkey_find(&tsigkey, keyname, &tsig->algorithm); + ret = ISC_R_NOTFOUND; + if (sring != NULL) + ret = dns_tsigkey_find(&tsigkey, keyname, + &tsig->algorithm, sring); + if (ret == ISC_R_NOTFOUND && dring != NULL) + ret = dns_tsigkey_find(&tsigkey, keyname, + &tsig->algorithm, dring); if (ret != ISC_R_SUCCESS) { + if (dring == NULL) { + ret = DNS_R_TSIGVERIFYFAILURE; + goto cleanup_struct; + } msg->tsigstatus = dns_tsigerror_badkey; msg->tsigkey = NULL; ret = dns_tsigkey_create(keyname, &tsig->algorithm, NULL, 0, ISC_FALSE, NULL, - mctx, &msg->tsigkey); + mctx, dring, &msg->tsigkey); if (ret != ISC_R_SUCCESS) goto cleanup_struct; return (DNS_R_TSIGVERIFYFAILURE); @@ -751,7 +768,7 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg) { cleanup_key: if (dns_tsigkey_empty(msg->tsigkey)) { - dns_tsigkey_free(&msg->tsigkey); + dns_tsigkey_free(&msg->tsigkey, dring); msg->tsigkey = NULL; } cleanup_struct: @@ -762,7 +779,7 @@ cleanup_emptystruct: return (ret); } -isc_result_t +static isc_result_t dns_tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) { dns_rdata_any_tsig_t *tsig = NULL; isc_region_t r, source_r, header_r, sig_r; @@ -928,16 +945,17 @@ cleanup_emptystruct: isc_result_t dns_tsigkey_find(dns_tsigkey_t **tsigkey, dns_name_t *name, - dns_name_t *algorithm) + dns_name_t *algorithm, dns_tsig_keyring_t *ring) { dns_tsigkey_t *key; REQUIRE(tsigkey != NULL); REQUIRE(*tsigkey == NULL); REQUIRE(name != NULL); + REQUIRE(ring != NULL); - isc_rwlock_lock(&tsiglock, isc_rwlocktype_read); - key = ISC_LIST_HEAD(tsigkeys); + isc_rwlock_lock(&ring->lock, isc_rwlocktype_read); + key = ISC_LIST_HEAD(ring->keys); while (key != NULL) { if (dns_name_equal(&key->name, name) && (algorithm == NULL || @@ -948,21 +966,24 @@ dns_tsigkey_find(dns_tsigkey_t **tsigkey, dns_name_t *name, key->refs++; isc_mutex_unlock(&key->lock); *tsigkey = key; - isc_rwlock_unlock(&tsiglock, isc_rwlocktype_read); + isc_rwlock_unlock(&ring->lock, isc_rwlocktype_read); return (ISC_R_SUCCESS); } key = ISC_LIST_NEXT(key, link); } - isc_rwlock_unlock(&tsiglock, isc_rwlocktype_read); + isc_rwlock_unlock(&ring->lock, isc_rwlocktype_read); *tsigkey = NULL; return (ISC_R_NOTFOUND); } static isc_result_t -add_initial_keys(dns_c_kdeflist_t *list, isc_mem_t *mctx) { +add_initial_keys(dns_c_kdeflist_t *list, dns_tsig_keyring_t *ring, + isc_mem_t *mctx) +{ isc_lex_t *lex = NULL; dns_c_kdef_t *key; unsigned char *secret = NULL; + int secretalloc = 0; int secretlen = 0; isc_result_t ret; @@ -1008,7 +1029,7 @@ add_initial_keys(dns_c_kdeflist_t *list, isc_mem_t *mctx) { ret = ISC_R_BADBASE64; goto failure; } - secretlen = strlen(key->secret) * 3 / 4; + secretalloc = secretlen = strlen(key->secret) * 3 / 4; secret = isc_mem_get(mctx, secretlen); if (secret == NULL) { ret = ISC_R_NOMEMORY; @@ -1028,12 +1049,13 @@ add_initial_keys(dns_c_kdeflist_t *list, isc_mem_t *mctx) { ret = isc_base64_tobuffer(lex, &secretbuf, -1); if (ret != ISC_R_SUCCESS) goto failure; + secretlen = ISC_BUFFER_USEDCOUNT(&secretbuf); isc_lex_close(lex); isc_lex_destroy(&lex); ret = dns_tsigkey_create(&keyname, &alg, secret, secretlen, - ISC_FALSE, NULL, mctx, NULL); - isc_mem_put(mctx, secret, secretlen); + ISC_FALSE, NULL, mctx, ring, NULL); + isc_mem_put(mctx, secret, secretalloc); secret = NULL; if (ret != ISC_R_SUCCESS) goto failure; @@ -1050,18 +1072,33 @@ add_initial_keys(dns_c_kdeflist_t *list, isc_mem_t *mctx) { } +static void +dns_tsig_inithmac() { + isc_region_t r; + char *str = "\010HMAC-MD5\007SIG-ALG\003REG\003INT"; + dns_name_init(&hmacmd5_name, NULL); + r.base = str; + r.length = strlen(str) + 1; + dns_name_fromregion(&hmacmd5_name, &r); + dns_tsig_hmacmd5_name = &hmacmd5_name; +} + isc_result_t -dns_tsig_init(isc_log_t *lctx, dns_c_ctx_t *confctx, isc_mem_t *mctx) { - isc_buffer_t hmacsrc, namebuf; +dns_tsig_init(dns_c_ctx_t *confctx, isc_mem_t *mctx, dns_tsig_keyring_t **ring) +{ isc_result_t ret; - dns_name_t hmac_name; - unsigned char data[32]; dns_c_kdeflist_t *keylist = NULL; - REQUIRE(lctx != NULL); /* XXX lctx is now unused. */ REQUIRE(mctx != NULL); + REQUIRE(ring != NULL); + REQUIRE(*ring == NULL); - ret = isc_rwlock_init(&tsiglock, 0, 0); + RUNTIME_CHECK(isc_once_do(&once, dns_tsig_inithmac) == ISC_R_SUCCESS); + *ring = isc_mem_get(mctx, sizeof(dns_tsig_keyring_t)); + if (ring == NULL) + return (ISC_R_NOMEMORY); + + ret = isc_rwlock_init(&(*ring)->lock, 0, 0); if (ret != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_rwlock_init() failed: %s", @@ -1069,34 +1106,17 @@ dns_tsig_init(isc_log_t *lctx, dns_c_ctx_t *confctx, isc_mem_t *mctx) { return (DNS_R_UNEXPECTED); } - ISC_LIST_INIT(tsigkeys); - isc_buffer_init(&hmacsrc, DNS_TSIG_HMACMD5, - strlen(DNS_TSIG_HMACMD5), ISC_BUFFERTYPE_TEXT); - isc_buffer_add(&hmacsrc, strlen(DNS_TSIG_HMACMD5)); - isc_buffer_init(&namebuf, data, sizeof(data), ISC_BUFFERTYPE_BINARY); - - dns_name_init(&hmac_name, NULL); - ret = dns_name_fromtext(&hmac_name, &hmacsrc, NULL, ISC_TRUE, &namebuf); - if (ret != ISC_R_SUCCESS) - return (ret); - - dns_tsig_hmacmd5_name = isc_mem_get(mctx, sizeof(dns_name_t)); - if (dns_tsig_hmacmd5_name == NULL) - return (ISC_R_NOMEMORY); - dns_name_init(dns_tsig_hmacmd5_name, NULL); - ret = dns_name_dup(&hmac_name, mctx, dns_tsig_hmacmd5_name); - if (ret != ISC_R_SUCCESS) - goto failure; + ISC_LIST_INIT((*ring)->keys); if (confctx != NULL) { ret = dns_c_ctx_getkdeflist(confctx, &keylist); if (ret == ISC_R_SUCCESS) - ret = add_initial_keys(keylist, mctx); + ret = add_initial_keys(keylist, *ring, mctx); else if (ret != ISC_R_NOTFOUND) goto failure; } - tsig_mctx = mctx; + (*ring)->mctx = mctx; return (ISC_R_SUCCESS); @@ -1106,15 +1126,16 @@ dns_tsig_init(isc_log_t *lctx, dns_c_ctx_t *confctx, isc_mem_t *mctx) { } void -dns_tsig_destroy() { - if (tsig_mctx == NULL) - return; - while (!ISC_LIST_EMPTY(tsigkeys)) { - dns_tsigkey_t *key = ISC_LIST_HEAD(tsigkeys); +dns_tsig_destroy(dns_tsig_keyring_t **ring) { + REQUIRE(ring != NULL); + REQUIRE(*ring != NULL); + + while (!ISC_LIST_EMPTY((*ring)->keys)) { + dns_tsigkey_t *key = ISC_LIST_HEAD((*ring)->keys); key->refs = 0; key->deleted = ISC_TRUE; - tsigkey_free(&key); + tsigkey_free(&key, *ring); } - dns_name_free(dns_tsig_hmacmd5_name, tsig_mctx); - isc_mem_put(tsig_mctx, dns_tsig_hmacmd5_name, sizeof(dns_name_t)); + + *ring = NULL; } diff --git a/lib/dns/view.c b/lib/dns/view.c index 2a9d527c31..6ad52e64b9 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -33,9 +33,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -106,6 +108,9 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, view->task = NULL; view->references = 1; view->attributes = (DNS_VIEWATTR_RESSHUTDOWN|DNS_VIEWATTR_ADBSHUTDOWN); + view->statickeys = NULL; + view->dynamickeys = NULL; + result = dns_tsig_init(NULL, view->mctx, &view->dynamickeys); ISC_LINK_INIT(view, link); ISC_EVENT_INIT(&view->resevent, sizeof view->resevent, 0, NULL, DNS_EVENT_VIEWRESSHUTDOWN, resolver_shutdown, @@ -348,6 +353,20 @@ dns_view_sethints(dns_view_t *view, dns_db_t *hints) { dns_db_attach(hints, &view->hints); } +void +dns_view_setkeyring(dns_view_t *view, dns_tsig_keyring_t *ring) { + + /* + * Set the view's static TSIG keyring + */ + + REQUIRE(DNS_VIEW_VALID(view)); + REQUIRE(view->statickeys == NULL); + REQUIRE(ring != NULL); + + view->statickeys = ring; +} + isc_result_t dns_view_addzone(dns_view_t *view, dns_zone_t *zone) { isc_result_t result; @@ -783,3 +802,14 @@ dns_view_load(dns_view_t *view) { dns_zt_load(view->zonetable); } + +isc_result_t +dns_view_checksig(dns_view_t *view, isc_buffer_t *source, dns_message_t *msg) { + REQUIRE(DNS_VIEW_VALID(view)); + REQUIRE(source != NULL); + REQUIRE(DNS_MESSAGE_VALID(msg)); + + return dns_tsig_verify(source, msg, view->statickeys, + view->dynamickeys); +} +