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]

(cherry picked from commit 36e5ac0033)
This commit is contained in:
Mark Andrews 2014-04-24 18:58:03 +10:00
parent 336c54e9ac
commit c10c7ddb6e
13 changed files with 209 additions and 46 deletions

View file

@ -1,3 +1,8 @@
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.

View file

@ -0,0 +1,24 @@
; 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 )

View file

@ -0,0 +1,22 @@
; 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 )

View file

@ -0,0 +1,22 @@
; 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 )

View file

@ -116,7 +116,7 @@ main(int argc, char **argv) {
region.base = hash;
region.length = length;
isc_buffer_init(&buffer, text, sizeof(text));
isc_base32hex_totext(&region, 1, "", &buffer);
isc_base32hexnp_totext(&region, 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);

View file

@ -91,6 +91,8 @@
#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;
@ -1760,7 +1762,8 @@ load_text(dns_loadctx_t *lctx) {
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,

View file

@ -1376,6 +1376,16 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
} 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

View file

@ -253,11 +253,11 @@ dns_nsec3_hashname(dns_fixedname_t *result,
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(&region, 1, "", &namebuffer);
isc_base32hexnp_totext(&region, 1, "", &namebuffer);
/* convert the hex to a domain name */
dns_fixedname_init(result);
@ -269,7 +269,8 @@ unsigned int
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);
}
@ -277,7 +278,8 @@ dns_nsec3_hashlength(dns_hash_t hash) {
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);
}

View file

@ -100,7 +100,7 @@ fromtext_nsec3(ARGS_FROMTEXT) {
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));
@ -191,7 +191,7 @@ totext_nsec3(ARGS_TOTEXT) {
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)
@ -474,15 +474,26 @@ digest_nsec3(ARGS_DIGEST) {
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(name);
UNUSED(type);
UNUSED(rdclass);
UNUSED(wildcard);
UNUSED(type);
UNUSED(rdclass);
UNUSED(wildcard);
return (ISC_TRUE);
/*
* 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_FALSE);
}
static inline isc_boolean_t

View file

@ -343,7 +343,7 @@ isdelegation(dns_name_t *name, dns_rdataset_t *rdataset,
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;

View file

@ -15731,10 +15731,12 @@ dns_zone_checknames(dns_zone_t *zone, dns_name_t *name, dns_rdata_t *rdata) {
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;
}

View file

@ -14,7 +14,7 @@
* 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 */
@ -54,7 +54,7 @@ static const char base32hex[] =
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;
@ -67,8 +67,8 @@ base32_totext(isc_region_t *source, int wordlength, const char *wordbreak,
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;
}
@ -77,7 +77,7 @@ base32_totext(isc_region_t *source, int wordlength, const char *wordbreak,
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;
}
@ -85,7 +85,7 @@ base32_totext(isc_region_t *source, int wordlength, const char *wordbreak,
((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;
}
@ -94,7 +94,7 @@ base32_totext(isc_region_t *source, int wordlength, const char *wordbreak,
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;
}
@ -121,7 +121,8 @@ isc_result_t
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
@ -129,7 +130,15 @@ isc_base32hex_totext(isc_region_t *source, int wordlength,
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));
}
/*%
@ -143,11 +152,12 @@ typedef struct {
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;
@ -155,6 +165,7 @@ base32_decode_init(base32_decode_ctx_t *ctx, int length,
ctx->length = length;
ctx->target = target;
ctx->base = base;
ctx->pad = pad;
}
static inline isc_result_t
@ -167,16 +178,25 @@ base32_decode_char(base32_decode_ctx_t *ctx, int c) {
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.
@ -212,6 +232,7 @@ base32_decode_char(base32_decode_ctx_t *ctx, int c) {
ctx->seen_32 = 4;
break;
}
/*
* Zero fill pad values.
*/
@ -244,23 +265,33 @@ base32_decode_char(base32_decode_ctx_t *ctx, int c) {
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;
@ -285,19 +316,26 @@ base32_tobuffer(isc_lex_t *lexer, const char base[], isc_buffer_t *target,
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')
@ -312,19 +350,26 @@ base32_decodestring(const char *cstr, const char base[], isc_buffer_t *target) {
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));
@ -336,12 +381,17 @@ base32_decoderegion(isc_region_t *source, const char base[], isc_buffer_t *targe
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

View file

@ -14,8 +14,6 @@
* 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
@ -27,6 +25,8 @@
*
* 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>
@ -44,6 +44,9 @@ isc_base32_totext(isc_region_t *source, int wordlength,
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.
*
@ -69,8 +72,11 @@ isc_result_t
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.
@ -91,8 +97,11 @@ isc_result_t
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
@ -110,8 +119,11 @@ isc_result_t
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.