+3819. [bug] NSEC3 hashes need to be able to be entered and
+ displayed without padding. This is not a issue for
+ currently defined algorithms but may be for future
+ hash algorithms. [RT #27925]
+
3818. [bug] Stop lying to the optimizer that 'void *arg' is a
constant in isc_event_allocate.
--- /dev/null
+; Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+;
+; Permission to use, copy, modify, and/or 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.
+
+$TTL 600
+@ SOA ns hostmaster 2011012708 3600 1200 604800 1200
+ NS ns
+ns A 192.0.2.1
+
+; The following NSEC3 RR is invalid as the Next Hashed Owner Name field
+; is padded. See RFC 5155.
+0p9mhaveqvm6t7vbl5lop2u3t2rp3tom NSEC3 1 1 12 aabbccdd (
+ CPNMU=== MX DNSKEY NS
+ SOA NSEC3PARAM RRSIG )
--- /dev/null
+; Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+;
+; Permission to use, copy, modify, and/or 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.
+
+$TTL 600
+@ SOA ns hostmaster 2011012708 3600 1200 604800 1200
+ NS ns
+ns A 192.0.2.1
+
+; The following NSEC3 RR owner is invalid as the owner name is padded.
+CPNMU=== NSEC3 2 1 12 aabbccdd ( CPNMU MX DNSKEY NS
+ SOA NSEC3PARAM RRSIG )
--- /dev/null
+; Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+;
+; Permission to use, copy, modify, and/or 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.
+
+$TTL 600
+@ SOA ns hostmaster 2011012708 3600 1200 604800 1200
+ NS ns
+ns A 192.0.2.1
+
+; a hash that isn't a multiple of 8 characters
+CPNMU NSEC3 2 1 12 aabbccdd ( CPNMU MX DNSKEY NS
+ SOA NSEC3PARAM RRSIG )
region.base = hash;
region.length = length;
isc_buffer_init(&buffer, text, sizeof(text));
- isc_base32hex_totext(®ion, 1, "", &buffer);
+ isc_base32hexnp_totext(®ion, 1, "", &buffer);
fprintf(stdout, "%.*s (salt=%s, hash=%u, iterations=%u)\n",
(int)isc_buffer_usedlength(&buffer), text, argv[1], hash_alg, iterations);
return(0);
#define DNS_MASTER_LHS 2048
#define DNS_MASTER_RHS MINTSIZ
+#define CHECKNAMESFAIL(x) (((x) & DNS_MASTER_CHECKNAMESFAIL) != 0)
+
typedef ISC_LIST(dns_rdatalist_t) rdatalist_head_t;
typedef struct dns_incctx dns_incctx_t;
dns_name_format(name, namebuf, sizeof(namebuf));
result = DNS_R_BADOWNERNAME;
desc = dns_result_totext(result);
- if ((lctx->options & DNS_MASTER_CHECKNAMESFAIL) != 0) {
+ if (CHECKNAMESFAIL(lctx->options) ||
+ type == dns_rdatatype_nsec3) {
(*callbacks->error)(callbacks,
"%s:%lu: %s: %s",
source, line,
} else
covers = 0;
+ /*
+ * Check the ownername of NSEC3 records
+ */
+ if (rdtype == dns_rdatatype_nsec3 &&
+ !dns_rdata_checkowner(name, msg->rdclass, rdtype,
+ ISC_FALSE)) {
+ result = DNS_R_BADOWNERNAME;
+ goto cleanup;
+ }
+
/*
* If we are doing a dynamic update or this is a meta-type,
* don't bother searching for a name, just append this one
if (hash_length != NULL)
*hash_length = len;
- /* convert the hash to base32hex */
+ /* convert the hash to base32hex non-padded */
region.base = rethash;
region.length = (unsigned int)len;
isc_buffer_init(&namebuffer, nametext, sizeof nametext);
- isc_base32hex_totext(®ion, 1, "", &namebuffer);
+ isc_base32hexnp_totext(®ion, 1, "", &namebuffer);
/* convert the hex to a domain name */
dns_fixedname_init(result);
dns_nsec3_hashlength(dns_hash_t hash) {
switch (hash) {
- case dns_hash_sha1: return(ISC_SHA1_DIGESTLENGTH);
+ case dns_hash_sha1:
+ return(ISC_SHA1_DIGESTLENGTH);
}
return (0);
}
isc_boolean_t
dns_nsec3_supportedhash(dns_hash_t hash) {
switch (hash) {
- case dns_hash_sha1: return (ISC_TRUE);
+ case dns_hash_sha1:
+ return (ISC_TRUE);
}
return (ISC_FALSE);
}
RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
ISC_FALSE));
isc_buffer_init(&b, bm, sizeof(bm));
- RETTOK(isc_base32hex_decodestring(DNS_AS_STR(token), &b));
+ RETTOK(isc_base32hexnp_decodestring(DNS_AS_STR(token), &b));
if (isc_buffer_usedlength(&b) > 0xffU)
RETTOK(ISC_R_RANGE);
RETERR(uint8_tobuffer(isc_buffer_usedlength(&b), target));
i = sr.length;
sr.length = j;
- RETERR(isc_base32hex_totext(&sr, 1, "", target));
+ RETERR(isc_base32hexnp_totext(&sr, 1, "", target));
sr.length = i - j;
if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) == 0)
static inline isc_boolean_t
checkowner_nsec3(ARGS_CHECKOWNER) {
+ unsigned char owner[NSEC3_MAX_HASH_LENGTH];
+ isc_buffer_t buffer;
+ dns_label_t label;
- REQUIRE(type == 50);
+ REQUIRE(type == 50);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
- UNUSED(name);
- UNUSED(type);
- UNUSED(rdclass);
- UNUSED(wildcard);
+ /*
+ * First label is a base32hex string without padding.
+ */
+ dns_name_getlabel(name, 0, &label);
+ isc_region_consume(&label, 1);
+ isc_buffer_init(&buffer, owner, sizeof(owner));
+ if (isc_base32hexnp_decoderegion(&label, &buffer) == ISC_R_SUCCESS)
+ return (ISC_TRUE);
- return (ISC_TRUE);
+ return (ISC_FALSE);
}
static inline isc_boolean_t
dns_name_getlabel(&nsec3name, 0, &hashlabel);
isc_region_consume(&hashlabel, 1);
isc_buffer_init(&buffer, owner, sizeof(owner));
- result = isc_base32hex_decoderegion(&hashlabel, &buffer);
+ result = isc_base32hexnp_decoderegion(&hashlabel, &buffer);
if (result != ISC_R_SUCCESS) {
dns_rdataset_disassociate(&set);
continue;
REQUIRE(DNS_ZONE_VALID(zone));
- if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMES))
+ if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMES) &&
+ rdata->type != dns_rdatatype_nsec3)
return (ISC_R_SUCCESS);
- if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMESFAIL)) {
+ if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMESFAIL) ||
+ rdata->type == dns_rdatatype_nsec3) {
level = ISC_LOG_ERROR;
fail = ISC_TRUE;
}
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: base32.c,v 1.6 2009/10/21 01:22:29 each Exp $ */
+/* $Id: base32.c,v 1.6.698.1 2012/02/15 05:00:16 marka Exp $ */
/*! \file */
static isc_result_t
base32_totext(isc_region_t *source, int wordlength, const char *wordbreak,
- isc_buffer_t *target, const char base[])
+ isc_buffer_t *target, const char base[], char pad)
{
char buf[9];
unsigned int loops = 0;
buf[0] = base[((source->base[0]>>3)&0x1f)]; /* 5 + */
if (source->length == 1) {
buf[1] = base[(source->base[0]<<2)&0x1c];
- buf[2] = buf[3] = buf[4] = '=';
- buf[5] = buf[6] = buf[7] = '=';
+ buf[2] = buf[3] = buf[4] = pad;
+ buf[5] = buf[6] = buf[7] = pad;
RETERR(str_totext(buf, target));
break;
}
buf[2] = base[((source->base[1]>>1)&0x1f)]; /* 5 + */
if (source->length == 2) {
buf[3] = base[(source->base[1]<<4)&0x10];
- buf[4] = buf[5] = buf[6] = buf[7] = '=';
+ buf[4] = buf[5] = buf[6] = buf[7] = pad;
RETERR(str_totext(buf, target));
break;
}
((source->base[2]>>4)&0x0f)]; /* 4 + */
if (source->length == 3) {
buf[4] = base[(source->base[2]<<1)&0x1e];
- buf[5] = buf[6] = buf[7] = '=';
+ buf[5] = buf[6] = buf[7] = pad;
RETERR(str_totext(buf, target));
break;
}
buf[5] = base[((source->base[3]>>2)&0x1f)]; /* 5 + */
if (source->length == 4) {
buf[6] = base[(source->base[3]<<3)&0x18];
- buf[7] = '=';
+ buf[7] = pad;
RETERR(str_totext(buf, target));
break;
}
isc_base32_totext(isc_region_t *source, int wordlength,
const char *wordbreak, isc_buffer_t *target)
{
- return (base32_totext(source, wordlength, wordbreak, target, base32));
+ return (base32_totext(source, wordlength, wordbreak, target,
+ base32, '='));
}
isc_result_t
const char *wordbreak, isc_buffer_t *target)
{
return (base32_totext(source, wordlength, wordbreak, target,
- base32hex));
+ base32hex, '='));
+}
+
+isc_result_t
+isc_base32hexnp_totext(isc_region_t *source, int wordlength,
+ const char *wordbreak, isc_buffer_t *target)
+{
+ return (base32_totext(source, wordlength, wordbreak, target,
+ base32hex, 0));
}
/*%
int val[8];
const char *base; /*%< Which encoding we are using */
int seen_32; /*%< Number of significant bytes if non zero */
+ isc_boolean_t pad; /*%< Expect padding */
} base32_decode_ctx_t;
static inline void
-base32_decode_init(base32_decode_ctx_t *ctx, int length,
- const char base[], isc_buffer_t *target)
+base32_decode_init(base32_decode_ctx_t *ctx, int length, const char base[],
+ isc_boolean_t pad, isc_buffer_t *target)
{
ctx->digits = 0;
ctx->seen_end = ISC_FALSE;
ctx->length = length;
ctx->target = target;
ctx->base = base;
+ ctx->pad = pad;
}
static inline isc_result_t
if ((s = strchr(ctx->base, c)) == NULL)
return (ISC_R_BADBASE32);
last = (unsigned int)(s - ctx->base);
+
/*
* Handle lower case.
*/
if (last > 32)
last -= 33;
+
/*
* Check that padding is contiguous.
*/
if (last != 32 && ctx->seen_32 != 0)
return (ISC_R_BADBASE32);
+
+ /*
+ * If padding is not permitted flag padding as a error.
+ */
+ if (last == 32 && !ctx->pad)
+ return (ISC_R_BADBASE32);
+
/*
* Check that padding starts at the right place and that
* bits that should be zero are.
ctx->seen_32 = 4;
break;
}
+
/*
* Zero fill pad values.
*/
static inline isc_result_t
base32_decode_finish(base32_decode_ctx_t *ctx) {
+
if (ctx->length > 0)
return (ISC_R_UNEXPECTEDEND);
+ /*
+ * Add missing padding if required.
+ */
+ if (!ctx->pad && ctx->digits != 0) {
+ ctx->pad = ISC_TRUE;
+ do {
+ RETERR(base32_decode_char(ctx, '='));
+ } while (ctx->digits != 0);
+ }
if (ctx->digits != 0)
return (ISC_R_BADBASE32);
return (ISC_R_SUCCESS);
}
static isc_result_t
-base32_tobuffer(isc_lex_t *lexer, const char base[], isc_buffer_t *target,
- int length)
+base32_tobuffer(isc_lex_t *lexer, const char base[], isc_boolean_t pad,
+ isc_buffer_t *target, int length)
{
base32_decode_ctx_t ctx;
isc_textregion_t *tr;
isc_token_t token;
isc_boolean_t eol;
- base32_decode_init(&ctx, length, base, target);
+ base32_decode_init(&ctx, length, base, pad, target);
while (!ctx.seen_end && (ctx.length != 0)) {
unsigned int i;
isc_result_t
isc_base32_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
- return (base32_tobuffer(lexer, base32, target, length));
+ return (base32_tobuffer(lexer, base32, ISC_TRUE, target, length));
}
isc_result_t
isc_base32hex_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
- return (base32_tobuffer(lexer, base32hex, target, length));
+ return (base32_tobuffer(lexer, base32hex, ISC_TRUE, target, length));
+}
+
+isc_result_t
+isc_base32hexnp_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
+ return (base32_tobuffer(lexer, base32hex, ISC_FALSE, target, length));
}
static isc_result_t
-base32_decodestring(const char *cstr, const char base[], isc_buffer_t *target) {
+base32_decodestring(const char *cstr, const char base[], isc_boolean_t pad,
+ isc_buffer_t *target)
+{
base32_decode_ctx_t ctx;
- base32_decode_init(&ctx, -1, base, target);
+ base32_decode_init(&ctx, -1, base, pad, target);
for (;;) {
int c = *cstr++;
if (c == '\0')
isc_result_t
isc_base32_decodestring(const char *cstr, isc_buffer_t *target) {
- return (base32_decodestring(cstr, base32, target));
+ return (base32_decodestring(cstr, base32, ISC_TRUE, target));
}
isc_result_t
isc_base32hex_decodestring(const char *cstr, isc_buffer_t *target) {
- return (base32_decodestring(cstr, base32hex, target));
+ return (base32_decodestring(cstr, base32hex, ISC_TRUE, target));
+}
+
+isc_result_t
+isc_base32hexnp_decodestring(const char *cstr, isc_buffer_t *target) {
+ return (base32_decodestring(cstr, base32hex, ISC_FALSE, target));
}
static isc_result_t
-base32_decoderegion(isc_region_t *source, const char base[], isc_buffer_t *target) {
+base32_decoderegion(isc_region_t *source, const char base[],
+ isc_boolean_t pad, isc_buffer_t *target)
+{
base32_decode_ctx_t ctx;
- base32_decode_init(&ctx, -1, base, target);
+ base32_decode_init(&ctx, -1, base, pad, target);
while (source->length != 0) {
int c = *source->base;
RETERR(base32_decode_char(&ctx, c));
isc_result_t
isc_base32_decoderegion(isc_region_t *source, isc_buffer_t *target) {
- return (base32_decoderegion(source, base32, target));
+ return (base32_decoderegion(source, base32, ISC_TRUE, target));
}
isc_result_t
isc_base32hex_decoderegion(isc_region_t *source, isc_buffer_t *target) {
- return (base32_decoderegion(source, base32hex, target));
+ return (base32_decoderegion(source, base32hex, ISC_TRUE, target));
+}
+
+isc_result_t
+isc_base32hexnp_decoderegion(isc_region_t *source, isc_buffer_t *target) {
+ return (base32_decoderegion(source, base32hex, ISC_FALSE, target));
}
static isc_result_t
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: base32.h,v 1.3 2008/09/25 04:02:39 tbox Exp $ */
-
#ifndef ISC_BASE32_H
#define ISC_BASE32_H 1
*
* Base 32 hex preserves the sort order of data when it is encoded /
* decoded.
+ *
+ * Base 32 hex "np" is base 32 hex but no padding is produced or accepted.
*/
#include <isc/lang.h>
isc_result_t
isc_base32hex_totext(isc_region_t *source, int wordlength,
const char *wordbreak, isc_buffer_t *target);
+isc_result_t
+isc_base32hexnp_totext(isc_region_t *source, int wordlength,
+ const char *wordbreak, isc_buffer_t *target);
/*!<
* \brief Convert data into base32 encoded text.
*
isc_base32_decodestring(const char *cstr, isc_buffer_t *target);
isc_result_t
isc_base32hex_decodestring(const char *cstr, isc_buffer_t *target);
+isc_result_t
+isc_base32hexnp_decodestring(const char *cstr, isc_buffer_t *target);
/*!<
- * \brief Decode a null-terminated base32 string.
+ * \brief Decode a null-terminated string in base32, base32hex, or
+ * base32hex non-padded.
*
* Requires:
*\li 'cstr' is non-null.
isc_base32_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length);
isc_result_t
isc_base32hex_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length);
+isc_result_t
+isc_base32hexnp_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length);
/*!<
- * \brief Convert base32 encoded text from a lexer context into data.
+ * \brief Convert text encoded in base32, base32hex, or base32hex
+ * non-padded from a lexer context into data.
*
* Requires:
*\li 'lex' is a valid lexer context
isc_base32_decoderegion(isc_region_t *source, isc_buffer_t *target);
isc_result_t
isc_base32hex_decoderegion(isc_region_t *source, isc_buffer_t *target);
+isc_result_t
+isc_base32hexnp_decoderegion(isc_region_t *source, isc_buffer_t *target);
/*!<
- * \brief Decode a packed (no white space permitted) base32 region.
+ * \brief Decode a packed (no white space permitted) region in
+ * base32, base32hex or base32hex non-padded.
*
* Requires:
*\li 'source' is a valid region.