From e402b6b0b9a843db695ea001badf2c83687a0f2a Mon Sep 17 00:00:00 2001 From: Jeroen Koekkoek Date: Mon, 30 Oct 2023 16:20:59 +0100 Subject: [PATCH] Add support for HIP RR --- CMakeLists.txt | 3 +- src/fallback/base16.h | 35 +++++++- src/fallback/base64.h | 200 ++++++++++++++++++++++++++++++++++++++++++ src/fallback/parser.c | 2 +- src/generic/base64.c | 46 ---------- src/generic/base64.h | 98 --------------------- src/haswell/parser.c | 2 +- src/types.h | 99 +++++++++++++++++---- src/westmere/parser.c | 2 +- tests/types.c | 37 ++++++++ 10 files changed, 356 insertions(+), 168 deletions(-) create mode 100644 src/fallback/base64.h delete mode 100644 src/generic/base64.c delete mode 100644 src/generic/base64.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 899488f..9067663 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -136,8 +136,7 @@ target_include_directories( target_sources(zone PRIVATE src/zone.c src/log.c - src/fallback/parser.c - src/generic/base64.c) + src/fallback/parser.c) add_executable(zone-bench src/bench.c src/fallback/bench.c) target_include_directories( diff --git a/src/fallback/base16.h b/src/fallback/base16.h index bc7e15c..6238c26 100644 --- a/src/fallback/base16.h +++ b/src/fallback/base16.h @@ -64,7 +64,7 @@ static const uint8_t b16rmap[256] = { // digits are impractical, but supported (BIND supports uneven // sequences) zone_nonnull_all -static zone_really_inline int32_t parse_base16( +static zone_really_inline int32_t parse_base16_sequence( zone_parser_t *parser, const zone_type_info_t *type, const zone_field_info_t *field, @@ -115,6 +115,39 @@ static zone_really_inline int32_t parse_base16( return ZONE_BLOB; } +zone_nonnull_all +static zone_really_inline int32_t parse_base16( + zone_parser_t *parser, + const zone_type_info_t *type, + const zone_field_info_t *field, + const token_t *token) +{ + int32_t r; + + if ((r = have_contiguous(parser, type, field, token)) < 0) + return r; + + const char *p = token->data; + uint8_t x0 = 0x80, x1 = 0x80; + uint8_t *ws = &parser->rdata->octets[parser->rdata->length], *w = ws; + const uint8_t *we = &parser->rdata->octets[ZONE_RDATA_SIZE]; + + while (w < we) { + x0 = b16rmap[ (uint8_t)(p[0]) ]; + x1 = b16rmap[ (uint8_t)(p[1]) ]; + if ((x0 | x1) & 0x80) + break; + w[0] = (uint8_t)((x0 << 4) | x1); + w += 1; p += 2; + } + + if (w - ws == 1 || w >= we || x0 != 0x80) + SYNTAX_ERROR(parser, "Invalid %s in %s record", NAME(field), TNAME(type)); + + parser->rdata->length += (size_t)(w - ws); + return 0; +} + zone_nonnull_all static zone_really_inline int32_t parse_salt( zone_parser_t *parser, diff --git a/src/fallback/base64.h b/src/fallback/base64.h new file mode 100644 index 0000000..075d0d7 --- /dev/null +++ b/src/fallback/base64.h @@ -0,0 +1,200 @@ +/* + * base64.h -- naive base64 parser + * + * Copyright (c) 2022, NLnet Labs. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ +#ifndef BASE64_H +#define BASE64_H + +static uint8_t b64rmap[256] = { + 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0 - 7 */ + 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, /* 8 - 15 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 16 - 23 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 24 - 31 */ + 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 32 - 39 */ + 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, /* 40 - 47 */ + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, /* 48 - 55 */ + 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, /* 56 - 63 */ + 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* 64 - 71 */ + 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, /* 72 - 79 */ + 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, /* 80 - 87 */ + 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, /* 88 - 95 */ + 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, /* 96 - 103 */ + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, /* 104 - 111 */ + 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, /* 112 - 119 */ + 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, /* 120 - 127 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 128 - 135 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 136 - 143 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 144 - 151 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 152 - 159 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 160 - 167 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 168 - 175 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 176 - 183 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 184 - 191 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 192 - 199 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 200 - 207 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 208 - 215 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 216 - 223 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 224 - 231 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 232 - 239 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 240 - 247 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 248 - 255 */ +}; + +static const uint8_t b64rmap_special = 0xf0; + +zone_nonnull_all +static zone_really_inline int32_t parse_base64_sequence( + zone_parser_t *parser, + const zone_type_info_t *type, + const zone_field_info_t *field, + token_t *token) +{ + int32_t r; + uint32_t state = 0; + + if ((r = have_contiguous(parser, type, field, token)) < 0) + return r; + + do { + const char *p = token->data; + + for (;; p++) { + const uint8_t ofs = b64rmap[(uint8_t)*p]; + + if (ofs >= b64rmap_special) + break; + + switch (state) { + case 0: + parser->rdata->octets[parser->rdata->length ] = (uint8_t)(ofs << 2); + state = 1; + break; + case 1: + parser->rdata->octets[parser->rdata->length++] |= (uint8_t)(ofs >> 4); + parser->rdata->octets[parser->rdata->length ] = (uint8_t)((ofs & 0x0f) << 4); + state = 2; + break; + case 2: + parser->rdata->octets[parser->rdata->length++] |= (uint8_t)(ofs >> 2); + parser->rdata->octets[parser->rdata->length ] = (uint8_t)((ofs & 0x03) << 6); + state = 3; + break; + case 3: + parser->rdata->octets[parser->rdata->length++] |= ofs; + parser->rdata->octets[parser->rdata->length ] = 0; + state = 0; + break; + default: + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); + } + } + + if (*p == '=') { + switch (state) { + case 0: // invalid, pad character in first position + case 1: // invalid, pad character in second position + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); + case 2: // valid, one byte of info + state = 4; + if (*p++ != '=') + break; + // fall through + case 3: // valid, two bytes of info + case 4: + state = 5; + p++; + break; + default: + break; + } + } + + if (is_contiguous((uint8_t)*p)) + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); + lex(parser, token); + } while (token->code == CONTIGUOUS); + + if ((r = have_delimiter(parser, type, token)) < 0) + return r; + if (state != 0 && state != 5) + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); + + return ZONE_BLOB; +} + +zone_nonnull_all +static zone_really_inline int32_t parse_base64( + zone_parser_t *parser, + const zone_type_info_t *type, + const zone_field_info_t *field, + const token_t *token) +{ + int32_t r; + uint32_t state = 0; + + if ((r = have_contiguous(parser, type, field, token)) < 0) + return r; + + const char *p = token->data; + for (;; p++) { + const uint8_t ofs = b64rmap[(uint8_t)*p]; + + if (ofs >= b64rmap_special) + break; + + switch (state) { + case 0: + parser->rdata->octets[parser->rdata->length ] = (uint8_t)(ofs << 2); + state = 1; + break; + case 1: + parser->rdata->octets[parser->rdata->length++] |= (uint8_t)(ofs >> 4); + parser->rdata->octets[parser->rdata->length ] = (uint8_t)((ofs & 0x0f) << 4); + state = 2; + break; + case 2: + parser->rdata->octets[parser->rdata->length++] |= (uint8_t)(ofs >> 2); + parser->rdata->octets[parser->rdata->length ] = (uint8_t)((ofs & 0x03) << 6); + state = 3; + break; + case 3: + parser->rdata->octets[parser->rdata->length++] |= ofs; + parser->rdata->octets[parser->rdata->length ] = 0; + state = 0; + break; + default: + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); + } + } + + if (*p == '=') { + switch (state) { + case 0: // invalid, pad character in first position + case 1: // invalid, pad character in second position + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); + case 2: // valid, one byte of info + state = 4; + if (*p++ != '=') + break; + // fall through + case 3: // valid, two bytes of info + case 4: + state = 5; + p++; + break; + default: + break; + } + } + + if (is_contiguous((uint8_t)*p)) + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); + + return 0; +} + +#endif // BASE64_H diff --git a/src/fallback/parser.c b/src/fallback/parser.c index 9ef1543..18e25c6 100644 --- a/src/fallback/parser.c +++ b/src/fallback/parser.c @@ -22,7 +22,7 @@ #include "generic/ip6.h" #include "fallback/base16.h" #include "fallback/base32.h" -#include "generic/base64.h" +#include "fallback/base64.h" #include "generic/nsec.h" #include "generic/nxt.h" #include "generic/caa.h" diff --git a/src/generic/base64.c b/src/generic/base64.c deleted file mode 100644 index 2e82a81..0000000 --- a/src/generic/base64.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * base64.c -- some useful comment - * - * Copyright (c) 2022-2023, NLnet Labs. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - */ -#include - -static uint8_t b64rmap[256] = { - 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0 - 7 */ - 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, /* 8 - 15 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 16 - 23 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 24 - 31 */ - 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 32 - 39 */ - 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, /* 40 - 47 */ - 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, /* 48 - 55 */ - 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, /* 56 - 63 */ - 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* 64 - 71 */ - 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, /* 72 - 79 */ - 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, /* 80 - 87 */ - 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, /* 88 - 95 */ - 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, /* 96 - 103 */ - 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, /* 104 - 111 */ - 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, /* 112 - 119 */ - 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, /* 120 - 127 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 128 - 135 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 136 - 143 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 144 - 151 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 152 - 159 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 160 - 167 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 168 - 175 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 176 - 183 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 184 - 191 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 192 - 199 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 200 - 207 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 208 - 215 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 216 - 223 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 224 - 231 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 232 - 239 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 240 - 247 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 248 - 255 */ -}; - -const uint8_t *zone_b64rmap = b64rmap; diff --git a/src/generic/base64.h b/src/generic/base64.h deleted file mode 100644 index 587dc78..0000000 --- a/src/generic/base64.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * base64.h -- parser for base64 rdata in (DNS) zone files - * - * Copyright (c) 2022, NLnet Labs. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - */ -#ifndef BASE64_H -#define BASE64_H - -extern const uint8_t *zone_b64rmap; - -static const uint8_t b64rmap_special = 0xf0; -static const uint8_t b64rmap_end = 0xfd; -static const uint8_t b64rmap_space = 0xfe; - -zone_nonnull_all -static zone_really_inline int32_t parse_base64( - zone_parser_t *parser, - const zone_type_info_t *type, - const zone_field_info_t *field, - token_t *token) -{ - int32_t r; - uint32_t state = 0; - - if ((r = have_contiguous(parser, type, field, token)) < 0) - return r; - - do { - const char *p = token->data; - - for (;; p++) { - const uint8_t ofs = zone_b64rmap[(uint8_t)*p]; - - if (ofs >= b64rmap_special) - break; - - switch (state) { - case 0: - parser->rdata->octets[parser->rdata->length ] = (uint8_t)(ofs << 2); - state = 1; - break; - case 1: - parser->rdata->octets[parser->rdata->length++] |= (uint8_t)(ofs >> 4); - parser->rdata->octets[parser->rdata->length ] = (uint8_t)((ofs & 0x0f) << 4); - state = 2; - break; - case 2: - parser->rdata->octets[parser->rdata->length++] |= (uint8_t)(ofs >> 2); - parser->rdata->octets[parser->rdata->length ] = (uint8_t)((ofs & 0x03) << 6); - state = 3; - break; - case 3: - parser->rdata->octets[parser->rdata->length++] |= ofs; - parser->rdata->octets[parser->rdata->length ] = 0; - state = 0; - break; - default: - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); - } - } - - if (*p == '=') { - switch (state) { - case 0: // invalid, pad character in first position - case 1: // invalid, pad character in second position - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); - case 2: // valid, one byte of info - state = 4; - if (*p++ != '=') - break; - // fall through - case 3: // valid, two bytes of info - case 4: - state = 5; - p++; - break; - default: - break; - } - } - - if (is_contiguous((uint8_t)*p)) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); - lex(parser, token); - } while (token->code == CONTIGUOUS); - - if ((r = have_delimiter(parser, type, token)) < 0) - return r; - if (state != 0 && state != 5) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); - - return ZONE_BLOB; -} - -#endif // BASE64_H diff --git a/src/haswell/parser.c b/src/haswell/parser.c index d9eef32..5d100e5 100644 --- a/src/haswell/parser.c +++ b/src/haswell/parser.c @@ -23,7 +23,7 @@ #include "generic/name.h" #include "fallback/base16.h" #include "haswell/base32.h" -#include "generic/base64.h" +#include "fallback/base64.h" #include "generic/nsec.h" #include "generic/nxt.h" #include "generic/caa.h" diff --git a/src/types.h b/src/types.h index 99af88d..e7a2e12 100644 --- a/src/types.h +++ b/src/types.h @@ -832,10 +832,7 @@ static int32_t parse_key_rdata( if ((r = parse_int8(parser, type, &type->rdata.fields[2], token)) < 0) return r; lex(parser, token); - if ((r = parse_base64(parser, type, &type->rdata.fields[3], token)) < 0) - return r; - lex(parser, token); - if ((r = have_delimiter(parser, type, token)) < 0) + if ((r = parse_base64_sequence(parser, type, &type->rdata.fields[3], token)) < 0) return r; return check_key_rr(parser, type); @@ -1216,7 +1213,7 @@ static int32_t parse_cert_rdata( if ((r = parse_symbol8(parser, type, &type->rdata.fields[2], token)) < 0) return r; lex(parser, token); - if ((r = parse_base64(parser, type, &type->rdata.fields[3], token)) < 0) + if ((r = parse_base64_sequence(parser, type, &type->rdata.fields[3], token)) < 0) return r; return accept_rr(parser, type); @@ -1295,7 +1292,7 @@ static int32_t parse_ds_rdata( if ((r = parse_symbol8(parser, type, &type->rdata.fields[2], token)) < 0) return r; lex(parser, token); - if ((r = parse_base16(parser, type, &type->rdata.fields[3], token)) < 0) + if ((r = parse_base16_sequence(parser, type, &type->rdata.fields[3], token)) < 0) return r; return accept_rr(parser, type); @@ -1341,7 +1338,7 @@ static int32_t parse_sshfp_rdata( if ((r = parse_int8(parser, type, &type->rdata.fields[1], token)) < 0) return r; lex(parser, token); - if ((r = parse_base16(parser, type, &type->rdata.fields[2], token)) < 0) + if ((r = parse_base16_sequence(parser, type, &type->rdata.fields[2], token)) < 0) return r; return check_sshfp_rr(parser, type); @@ -1485,7 +1482,7 @@ static int32_t parse_ipseckey_rdata( return r; break; default: - if ((r = parse_base64(parser, t, &t->rdata.fields[4], token)) < 0) + if ((r = parse_base64_sequence(parser, t, &t->rdata.fields[4], token)) < 0) return r; break; } @@ -1548,7 +1545,7 @@ static int32_t parse_rrsig_rdata( if ((r = parse_name(parser, type, &type->rdata.fields[7], token)) < 0) return r; lex(parser, token); - if ((r = parse_base64(parser, type, &type->rdata.fields[8], token)) < 0) + if ((r = parse_base64_sequence(parser, type, &type->rdata.fields[8], token)) < 0) return r; return accept_rr(parser, type); @@ -1623,7 +1620,7 @@ static int32_t parse_dnskey_rdata( if ((r = parse_symbol8(parser, type, &type->rdata.fields[2], token)) < 0) return r; lex(parser, token); - if ((r = parse_base64(parser, type, &type->rdata.fields[3], token)) < 0) + if ((r = parse_base64_sequence(parser, type, &type->rdata.fields[3], token)) < 0) return r; return accept_rr(parser, type); @@ -1647,7 +1644,7 @@ static int32_t parse_dhcid_rdata( { int32_t r; - if ((r = parse_base64(parser, type, &type->rdata.fields[0], token)) < 0) + if ((r = parse_base64_sequence(parser, type, &type->rdata.fields[0], token)) < 0) return r; return check_dhcid_rr(parser, type); @@ -1783,11 +1780,65 @@ static int32_t parse_tlsa_rdata( if ((r = parse_int8(parser, type, &type->rdata.fields[2], token)) < 0) return r; lex(parser, token); - if ((r = parse_base16(parser, type, &type->rdata.fields[3], token)) < 0) + if ((r = parse_base16_sequence(parser, type, &type->rdata.fields[3], token)) < 0) return r; + + return accept_rr(parser, type); +} + +zone_nonnull_all +static int32_t check_hip_rr( + zone_parser_t *parser, const zone_type_info_t *type) +{ + // FIXME: verify field lengths etc + return accept_rr(parser, type); +} + +zone_nonnull_all +static int32_t parse_hip_rdata( + zone_parser_t *parser, const zone_type_info_t *type, token_t *token) +{ + int32_t result; + + // reserve octet for HIT length + parser->rdata->length = 1; + + // PK algorithm + if ((result = parse_int8(parser, type, &type->rdata.fields[1], token)) < 0) + return result; + + // reserve octets for PK length + parser->rdata->length += 2; + + // HIT lex(parser, token); - if ((r = have_delimiter(parser, type, token)) < 0) - return r; + if ((result = parse_base16(parser, type, &type->rdata.fields[3], token)) < 0) + return result; + + if (parser->rdata->length > 255 + 4) + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&type->rdata.fields[3]), TNAME(type)); + uint8_t hit_length = (uint8_t)(parser->rdata->length - 4); + parser->rdata->octets[0] = hit_length; + + // Public Key + lex(parser, token); + if ((result = parse_base64(parser, type, &type->rdata.fields[4], token)) < 0) + return result; + + if (parser->rdata->length > 65535u + 4u + hit_length) + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&type->rdata.fields[4]), TNAME(type)); + uint16_t pk_length = htons((uint16_t)((parser->rdata->length - hit_length) - 4)); + memcpy(&parser->rdata->octets[2], &pk_length, sizeof(pk_length)); + + lex(parser, token); + while (token->code & (CONTIGUOUS | QUOTED)) { + if ((result = parse_name(parser, type, &type->rdata.fields[5], token)) < 0) + return result; + lex(parser, token); + } + + if ((result = have_delimiter(parser, type, token)) < 0) + return result; return accept_rr(parser, type); } @@ -1809,7 +1860,7 @@ static int32_t parse_openpgpkey_rdata( { int32_t r; - if ((r = parse_base64(parser, type, &type->rdata.fields[0], token)) < 0) + if ((r = parse_base64_sequence(parser, type, &type->rdata.fields[0], token)) < 0) return r; return accept_rr(parser, type); @@ -1880,7 +1931,7 @@ static int32_t parse_zonemd_rdata( if ((r = parse_int8(parser, type, &type->rdata.fields[2], token)) < 0) return r; lex(parser, token); - if ((r = parse_base16(parser, type, &type->rdata.fields[3], token)) < 0) + if ((r = parse_base16_sequence(parser, type, &type->rdata.fields[3], token)) < 0) return r; return accept_rr(parser, type); @@ -2159,7 +2210,7 @@ static int32_t parse_generic_rdata( lex(parser, token); if (n) - r = parse_base16(parser, type, &fields[1], token); + r = parse_base16_sequence(parser, type, &fields[1], token); else r = have_delimiter(parser, type, token); if (r < 0) @@ -2521,6 +2572,15 @@ static const zone_field_info_t cdnskey_rdata_fields[] = { FIELD("publickey", ZONE_BLOB, ZONE_BASE64) }; +static const zone_field_info_t hip_rdata_fields[] = { + FIELD("HIT length", ZONE_INT8, 0), + FIELD("PK algorithm", ZONE_INT8, 0), + FIELD("PK length", ZONE_INT16, 0), + FIELD("HIT", ZONE_STRING, 0), // FIXME: not really a string + FIELD("Public Key", ZONE_STRING, 0), // FIXME: not really a string + FIELD("Rendezvous Servers", ZONE_NAME, ZONE_SEQUENCE) +}; + static const zone_field_info_t openpgpkey_rdata_fields[] = { FIELD("key", ZONE_BLOB, ZONE_BASE64) }; @@ -2711,7 +2771,10 @@ static const type_descriptor_t types[] = { check_tlsa_rr, parse_tlsa_rdata), UNKNOWN_TYPE(54), - UNKNOWN_TYPE(55), // HIP + + TYPE("HIP", ZONE_HIP, ZONE_ANY, FIELDS(hip_rdata_fields), + check_hip_rr, parse_hip_rdata), + UNKNOWN_TYPE(56), UNKNOWN_TYPE(57), UNKNOWN_TYPE(58), diff --git a/src/westmere/parser.c b/src/westmere/parser.c index 0816fee..c4015de 100644 --- a/src/westmere/parser.c +++ b/src/westmere/parser.c @@ -23,7 +23,7 @@ #include "generic/name.h" #include "fallback/base16.h" #include "westmere/base32.h" -#include "generic/base64.h" +#include "fallback/base64.h" #include "generic/nsec.h" #include "generic/nxt.h" #include "generic/caa.h" diff --git a/tests/types.c b/tests/types.c index 17898c8..a681ad1 100644 --- a/tests/types.c +++ b/tests/types.c @@ -530,6 +530,42 @@ static const rdata_t smimea_rdata = 0x79, 0x83, 0xa1, 0xd1, 0x6e, 0x8a, 0x41, 0x0e, 0x45, 0x61, 0xcb, 0x10, 0x66, 0x18, 0xe9, 0x71); +static const char hip_text[] = + PAD("www.example.com. IN HIP ( 2 200100107B1A74DF365639CC39F1D578\n" + " AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cI" + "vM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ry" + "ra+bSRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXd" + "XF5D\n" + " rvs1.example.com.\n" + " rvs2.example.com. )"); +static const rdata_t hip_rdata = + RDATA(// HIT length + 0x10, + // PK algorithm + 2, + // Public Key length + 0x00, 0x84, + // HIT + 0x20, 0x01, 0x00, 0x10, 0x7b, 0x1a, 0x74, 0xdf, 0x36, 0x56, 0x39, 0xcc, + 0x39, 0xf1, 0xd5, 0x78, + // Public Key + 0x03, 0x01, 0x00, 0x01, 0xb7, 0x71, 0xca, 0x13, 0x6e, 0x4a, 0xeb, 0x5c, + 0xe4, 0x43, 0x33, 0xc5, 0x3b, 0x3d, 0x2c, 0x13, 0xc2, 0x22, 0x43, 0x85, + 0x1f, 0xc7, 0x08, 0xbc, 0xce, 0x29, 0xf7, 0xe2, 0xeb, 0x57, 0x87, 0xb5, + 0xf5, 0x6c, 0xca, 0xd3, 0x4f, 0x82, 0x23, 0xac, 0xc1, 0x09, 0x04, 0xdd, + 0xb5, 0x6b, 0x2e, 0xc4, 0xa6, 0xd6, 0x23, 0x2f, 0x3b, 0x50, 0xea, 0x09, + 0x4f, 0x09, 0x14, 0xb3, 0xb9, 0x41, 0xbb, 0xe5, 0x29, 0xaf, 0x58, 0x2c, + 0x36, 0xbb, 0xad, 0xef, 0xda, 0xf2, 0xad, 0xaf, 0x9b, 0x49, 0x11, 0x90, + 0x6f, 0x5b, 0x25, 0x22, 0x60, 0x3c, 0x61, 0x52, 0x72, 0xb8, 0x80, 0xec, + 0x8f, 0xb9, 0x30, 0xcc, 0x6e, 0xe3, 0x9c, 0x44, 0x4d, 0xaa, 0x75, 0xb1, + 0x67, 0x8f, 0x00, 0x5a, 0x4b, 0x24, 0x99, 0xd1, 0xda, 0x54, 0x33, 0xf8, + 0x05, 0xc7, 0xa5, 0xad, 0x32, 0x37, 0xac, 0xc5, 0xdd, 0x5c, 0x5e, 0x43, + // rvs1.example.com + 4, 'r', 'v', 's', '1', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'c', 'o', 'm', 0, + // rvs2.example.com + 4, 'r', 'v', 's', '2', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'c', 'o', 'm', 0, + ); + static const char cds_text[] = PAD(" CDS 58470 5 1 ( 3079F1593EBAD6DC121E202A8B766A6A4837206C )"); static const char cds_generic_text[] = @@ -884,6 +920,7 @@ static const test_t tests[] = { { ZONE_TLSA, tlsa_generic_text, &tlsa_rdata }, { ZONE_SMIMEA, smimea_text, &smimea_rdata }, { ZONE_SMIMEA, smimea_generic_text, &smimea_rdata }, + { ZONE_HIP, hip_text, &hip_rdata }, { ZONE_CDS, cds_text, &cds_rdata }, { ZONE_CDS, cds_generic_text, &cds_rdata }, { ZONE_CDNSKEY, cdnskey_text, &cdnskey_rdata },