* information regarding copyright ownership.
*/
-/* draft-wessels-zone-digest-05 */
+/* RFC 8976 */
#ifndef RDATA_GENERIC_ZONEMD_63_C
#define RDATA_GENERIC_ZONEMD_63_C
fromtext_zonemd(ARGS_FROMTEXT) {
isc_token_t token;
int digest_type, length;
+ isc_buffer_t save;
+ isc_result_t result;
UNUSED(type);
UNUSED(rdclass);
UNUSED(callbacks);
/*
- * Serial.
+ * Zone Serial.
*/
RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
false));
RETERR(uint32_tobuffer(token.value.as_ulong, target));
/*
- * Digest type.
+ * Digest Scheme.
*/
RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
false));
- digest_type = token.value.as_ulong;
- RETERR(uint8_tobuffer(digest_type, target));
+ RETERR(uint8_tobuffer(token.value.as_ulong, target));
/*
- * Reserved.
+ * Digest Type.
*/
RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
false));
- RETERR(uint8_tobuffer(token.value.as_ulong, target));
+ digest_type = token.value.as_ulong;
+ RETERR(uint8_tobuffer(digest_type, target));
/*
* Digest.
case DNS_ZONEMD_DIGEST_SHA384:
length = ISC_SHA384_DIGESTLENGTH;
break;
+ case DNS_ZONEMD_DIGEST_SHA512:
+ length = ISC_SHA512_DIGESTLENGTH;
+ break;
default:
length = -2;
break;
}
- return (isc_hex_tobuffer(lexer, target, length));
+ save = *target;
+ result = isc_hex_tobuffer(lexer, target, length);
+ /* Minimum length of digest is 12 octets. */
+ if (isc_buffer_usedlength(target) - isc_buffer_usedlength(&save) < 12) {
+ return (ISC_R_UNEXPECTEDEND);
+ }
+ return (result);
}
static inline isc_result_t
dns_rdata_toregion(rdata, &sr);
/*
- * Serial.
+ * Zone Serial.
*/
num = uint32_fromregion(&sr);
isc_region_consume(&sr, 4);
RETERR(str_totext(" ", target));
/*
- * Digest type.
+ * Digest scheme.
*/
num = uint8_fromregion(&sr);
isc_region_consume(&sr, 1);
RETERR(str_totext(buf, target));
RETERR(str_totext(" ", target));
+
/*
- * Reserved.
+ * Digest type.
*/
num = uint8_fromregion(&sr);
isc_region_consume(&sr, 1);
static inline isc_result_t
fromwire_zonemd(ARGS_FROMWIRE) {
isc_region_t sr;
+ size_t digestlen = 0;
UNUSED(type);
UNUSED(rdclass);
isc_buffer_activeregion(source, &sr);
/*
- * If we do not recognize the digest type, only ensure that the digest
- * is present at all.
+ * If we do not recognize the digest type, ensure that the digest
+ * meets minimum length (12).
*
* If we do recognize the digest type, ensure that the digest is of the
* correct length.
*/
- if (sr.length < 7 || (sr.base[4] == DNS_ZONEMD_DIGEST_SHA384 &&
- sr.length < 6 + ISC_SHA384_DIGESTLENGTH))
- {
+ if (sr.length < 18) {
+ return (ISC_R_UNEXPECTEDEND);
+ }
+
+ switch (sr.base[5]) {
+ case DNS_ZONEMD_DIGEST_SHA384:
+ digestlen = ISC_SHA384_DIGESTLENGTH;
+ break;
+ case DNS_ZONEMD_DIGEST_SHA512:
+ digestlen = ISC_SHA512_DIGESTLENGTH;
+ break;
+ default:
+ break;
+ }
+
+ if (digestlen != 0 && sr.length < 6 + digestlen) {
return (ISC_R_UNEXPECTEDEND);
}
*
* If there is extra data, dns_rdata_fromwire() will detect that.
*/
- if (sr.base[4] == DNS_ZONEMD_DIGEST_SHA384) {
- sr.length = 6 + ISC_SHA384_DIGESTLENGTH;
+ if (digestlen != 0) {
+ sr.length = 6 + digestlen;
}
isc_buffer_forward(source, sr.length);
case DNS_ZONEMD_DIGEST_SHA384:
REQUIRE(zonemd->length == ISC_SHA384_DIGESTLENGTH);
break;
+ case DNS_ZONEMD_DIGEST_SHA512:
+ REQUIRE(zonemd->length == ISC_SHA512_DIGESTLENGTH);
+ break;
}
RETERR(uint32_tobuffer(zonemd->serial, target));
+ RETERR(uint8_tobuffer(zonemd->scheme, target));
RETERR(uint8_tobuffer(zonemd->digest_type, target));
- RETERR(uint8_tobuffer(zonemd->reserved, target));
return (mem_tobuffer(target, zonemd->digest, zonemd->length));
}
zonemd->serial = uint32_fromregion(®ion);
isc_region_consume(®ion, 4);
- zonemd->digest_type = uint8_fromregion(®ion);
+ zonemd->scheme = uint8_fromregion(®ion);
isc_region_consume(®ion, 1);
- zonemd->reserved = uint8_fromregion(®ion);
+ zonemd->digest_type = uint8_fromregion(®ion);
isc_region_consume(®ion, 1);
zonemd->length = region.length;
* Check all entries in the supplied array.
*/
for (i = 0; wire_ok[i].len != 0; i++) {
+ if (debug) {
+ fprintf(stderr, "calling check_wire_ok_single on %zu\n",
+ i);
+ }
check_wire_ok_single(&wire_ok[i], rdclass, type, structsize);
}
/*
* ZONEMD tests.
*
- * Excerpted from draft-wessels-dns-zone-digest:
+ * Excerpted from RFC 8976:
*
* The ZONEMD RDATA wire format is encoded as follows:
*
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Serial |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Digest Type | Reserved | |
+ * | Scheme |Hash Algorithm | |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
* | Digest |
* / /
* / /
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
- * 2.1.1. The Serial Field
+ * 2.2.1. The Serial Field
+ *
+ * The Serial field is a 32-bit unsigned integer in network byte order.
+ * It is the serial number from the zone's SOA record ([RFC1035],
+ * Section 3.3.13) for which the zone digest was generated.
+ *
+ * It is included here to clearly bind the ZONEMD RR to a particular
+ * version of the zone's content. Without the serial number, a stand-
+ * alone ZONEMD digest has no obvious association to any particular
+ * instance of a zone.
+ *
+ * 2.2.2. The Scheme Field
+ *
+ * The Scheme field is an 8-bit unsigned integer that identifies the
+ * methods by which data is collated and presented as input to the
+ * hashing function.
+ *
+ * Herein, SIMPLE, with Scheme value 1, is the only standardized Scheme
+ * defined for ZONEMD records and it MUST be supported by
+ * implementations. The "ZONEMD Schemes" registry is further described
+ * in Section 5.
+ *
+ * Scheme values 240-254 are allocated for Private Use.
*
- * The Serial field is a 32-bit unsigned integer in network order. It
- * is equal to the serial number from the zone's SOA record
+ * 2.2.3. The Hash Algorithm Field
*
- * 2.1.2. The Digest Type Field
+ * The Hash Algorithm field is an 8-bit unsigned integer that identifies
+ * the cryptographic hash algorithm used to construct the digest.
*
- * The Digest Type field is an 8-bit unsigned integer that identifies
- * the algorithm used to construct the digest.
+ * Herein, SHA384 ([RFC6234]), with Hash Algorithm value 1, is the only
+ * standardized Hash Algorithm defined for ZONEMD records that MUST be
+ * supported by implementations. When SHA384 is used, the size of the
+ * Digest field is 48 octets. The result of the SHA384 digest algorithm
+ * MUST NOT be truncated, and the entire 48-octet digest is published in
+ * the ZONEMD record.
*
- * At the time of this writing, SHA384, with value 1, is the only Digest
- * Type defined for ZONEMD records.
+ * SHA512 ([RFC6234]), with Hash Algorithm value 2, is also defined for
+ * ZONEMD records and SHOULD be supported by implementations. When
+ * SHA512 is used, the size of the Digest field is 64 octets. The
+ * result of the SHA512 digest algorithm MUST NOT be truncated, and the
+ * entire 64-octet digest is published in the ZONEMD record.
*
- * 2.1.3. The Reserved Field
+ * Hash Algorithm values 240-254 are allocated for Private Use.
*
- * The Reserved field is an 8-bit unsigned integer, which is always set
- * to zero.
+ * The "ZONEMD Hash Algorithms" registry is further described in
+ * Section 5.
*
- * 2.1.4. The Digest Field
+ * 2.2.4. The Digest Field
*
* The Digest field is a variable-length sequence of octets containing
- * the message digest.
+ * the output of the hash algorithm. The length of the Digest field is
+ * determined by deducting the fixed size of the Serial, Scheme, and
+ * Hash Algorithm fields from the RDATA size in the ZONEMD RR header.
+ *
+ * The Digest field MUST NOT be shorter than 12 octets. Digests for the
+ * SHA384 and SHA512 hash algorithms specified herein are never
+ * truncated. Digests for future hash algorithms MAY be truncated but
+ * MUST NOT be truncated to a length that results in less than 96 bits
+ * (12 octets) of equivalent strength.
+ *
+ * Section 3 describes how to calculate the digest for a zone.
+ * Section 4 describes how to use the digest to verify the contents of a
+ * zone.
+ *
*/
static void
zonemd(void **state) {
- text_ok_t text_ok[] = { TEXT_INVALID(""),
- TEXT_INVALID("0"),
- TEXT_INVALID("0 0"),
- TEXT_INVALID("0 0 0"),
- TEXT_INVALID("99999999 0 0"),
- TEXT_INVALID("2019020700 0 0"),
- TEXT_INVALID("2019020700 1 0 DEADBEEF"),
- TEXT_VALID("2019020700 2 0 DEADBEEF"),
- TEXT_VALID("2019020700 255 0 DEADBEEF"),
- TEXT_INVALID("2019020700 256 0 DEADBEEF"),
- TEXT_VALID("2019020700 2 255 DEADBEEF"),
- TEXT_INVALID("2019020700 2 256 DEADBEEF"),
- TEXT_VALID("2019020700 1 0 "
- "7162D2BB75C047A53DE98767C9192BEB"
- "14DB01E7E2267135DAF0230A 19BA4A31"
- "6AF6BF64AA5C7BAE24B2992850300509"),
- TEXT_SENTINEL() };
+ text_ok_t text_ok[] = {
+ TEXT_INVALID(""),
+ /* No digest scheme or digest type*/
+ TEXT_INVALID("0"),
+ /* No digest type */
+ TEXT_INVALID("0 0"),
+ /* No digest */
+ TEXT_INVALID("0 0 0"),
+ /* No digest */
+ TEXT_INVALID("99999999 0 0"),
+ /* No digest */
+ TEXT_INVALID("2019020700 0 0"),
+ /* Digest too short */
+ TEXT_INVALID("2019020700 1 1 DEADBEEF"),
+ /* Digest too short */
+ TEXT_INVALID("2019020700 1 2 DEADBEEF"),
+ /* Digest too short */
+ TEXT_INVALID("2019020700 1 3 DEADBEEFDEADBEEFDEADBE"),
+ /* Digest type unknown */
+ TEXT_VALID("2019020700 1 3 DEADBEEFDEADBEEFDEADBEEF"),
+ /* Digest type max */
+ TEXT_VALID("2019020700 1 255 DEADBEEFDEADBEEFDEADBEEF"),
+ /* Digest type too big */
+ TEXT_INVALID("2019020700 0 256 DEADBEEFDEADBEEFDEADBEEF"),
+ /* Scheme max */
+ TEXT_VALID("2019020700 255 3 DEADBEEFDEADBEEFDEADBEEF"),
+ /* Scheme too big */
+ TEXT_INVALID("2019020700 256 3 DEADBEEFDEADBEEFDEADBEEF"),
+ /* SHA384 */
+ TEXT_VALID("2019020700 1 1 "
+ "7162D2BB75C047A53DE98767C9192BEB"
+ "14DB01E7E2267135DAF0230A 19BA4A31"
+ "6AF6BF64AA5C7BAE24B2992850300509"),
+ /* SHA512 */
+ TEXT_VALID("2019020700 1 2 "
+ "08CFA1115C7B948C4163A901270395EA"
+ "226A930CD2CBCF2FA9A5E6EB 85F37C8A"
+ "4E114D884E66F176EAB121CB02DB7D65"
+ "2E0CC4827E7A3204 F166B47E5613FD27"),
+ /* SHA384 too short and with private scheme */
+ TEXT_INVALID("2021042801 0 1 "
+ "7162D2BB75C047A53DE98767C9192BEB"
+ "6AF6BF64AA5C7BAE24B2992850300509"),
+ /* SHA512 too short and with private scheme */
+ TEXT_INVALID("2021042802 5 2 "
+ "A897B40072ECAE9E4CA3F1F227DE8F5E"
+ "480CDEBB16DFC64C1C349A7B5F6C71AB"
+ "E8A88B76EF0BA1604EC25752E946BF98"),
+ TEXT_SENTINEL()
+ };
wire_ok_t wire_ok[] = {
/*
* Short.
*/
WIRE_INVALID(0x00, 0x00, 0x00, 0x00, 0x00, 0x00),
/*
- * Minimal, one-octet hash for an undefined digest type.
+ * Short 11-octet digest.
+ */
+ WIRE_INVALID(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00),
+ /*
+ * Minimal, 12-octet hash for an undefined digest type.
*/
- WIRE_VALID(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),
+ WIRE_VALID(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00),
/*
* SHA-384 is defined, so we insist there be a digest of
* the expected length.
*/
- WIRE_INVALID(0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00),
+ WIRE_INVALID(0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00),
/*
* 48-octet digest, valid for SHA-384.
*/
- WIRE_VALID(0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xde, 0xad, 0xbe,
+ WIRE_VALID(0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xde, 0xad, 0xbe,
0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce,
0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe,
0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce,
/*
* 56-octet digest, too long for SHA-384.
*/
- WIRE_INVALID(0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xde, 0xad,
+ WIRE_INVALID(0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0xde, 0xad,
0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce,
0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad,
0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce,
0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad,
0xbe, 0xef, 0xfa, 0xce),
+ /*
+ * 56-octet digest, too short for SHA-512
+ */
+ WIRE_INVALID(0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0xde, 0xad,
+ 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+ 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce,
+ 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad,
+ 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+ 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce,
+ 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad,
+ 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad),
+ /*
+ * 64-octet digest, just right for SHA-512
+ */
+ WIRE_VALID(0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0xde, 0xad, 0xbe,
+ 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce,
+ 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe,
+ 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce,
+ 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe,
+ 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce,
+ 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe,
+ 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef),
+ /*
+ * 72-octet digest, too long for SHA-512
+ */
+ WIRE_INVALID(0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0xde, 0xad,
+ 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+ 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce,
+ 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad,
+ 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+ 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce,
+ 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad,
+ 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+ 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce,
+ 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce),
/*
* 56-octet digest, valid for an undefined digest type.
*/
- WIRE_VALID(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0xad, 0xbe,
+ WIRE_VALID(0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xde, 0xad, 0xbe,
0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce,
0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe,
0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce,