Skip to content

Commit

Permalink
tls-supported-groups SvcParam support (#236)
Browse files Browse the repository at this point in the history
* tls-supported-groups SvcParam support

From https://datatracker.ietf.org/doc/draft-ietf-tls-key-share-prediction/01/
Also:
- draft-ietf-ohai-svcb-config became RFC 9540 for the ohttp SvcParam
- added tests for ohttp
  • Loading branch information
wtoorop authored Nov 12, 2024
1 parent 7c5aa09 commit 0411158
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 5 deletions.
4 changes: 3 additions & 1 deletion include/zone.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,8 +221,10 @@ extern "C" {
#define ZONE_SVC_PARAM_KEY_IPV6HINT (6u)
/** URI template in relative form @rfc{9461} */
#define ZONE_SVC_PARAM_KEY_DOHPATH (7u)
/** Target is an Oblivious HTTP service @draft{ohai,svcb-config} */
/** Target is an Oblivious HTTP service @rfc{9540} */
#define ZONE_SVC_PARAM_KEY_OHTTP (8u)
/** Supported groups in TLS @draft{ietf, tls-key-share-prediction} */
#define ZONE_SVC_PARAM_KEY_TLS_SUPPORTED_GROUPS (9u)
/** Reserved ("invalid key") @rfc{9460} */
#define ZONE_SVC_PARAM_KEY_INVALID_KEY (65535u)
/** @} */
Expand Down
10 changes: 8 additions & 2 deletions src/generic/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ struct string {
typedef struct mnemonic mnemonic_t;
struct mnemonic {
struct {
char data[16];
char data[16]; /* MUST be 16 because of usage with SIMD cmpeq */
size_t length;
} key;
uint32_t value;
Expand Down Expand Up @@ -78,7 +78,13 @@ typedef int32_t (*parse_svc_param_t)(
const token_t *);

struct svc_param_info {
mnemonic_t name;
struct {
struct {
char data[24];
size_t length;
} key;
uint32_t value;
} name;
uint32_t has_value;
parse_svc_param_t parse, parse_lax;
};
Expand Down
59 changes: 58 additions & 1 deletion src/generic/svcb.h
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,55 @@ static int32_t parse_unknown(
return 0;
}

nonnull_all
static int32_t parse_tls_supported_groups(
parser_t *parser,
const type_info_t *type,
const rdata_info_t *field,
uint16_t key,
const svc_param_info_t *param,
rdata_t *rdata,
const token_t *token)
{
const char *t = token->data, *te = token->data + token->length;
const uint8_t *rdata_start = rdata->octets;

(void)field;
(void)key;
(void)param;

while (t < te && rdata->octets+2 <= rdata->limit) {
uint64_t number = 0;
for (;; t++) {
const uint64_t digit = (uint8_t)*t - '0';
if (digit > 9)
break;
number = number * 10 + digit;
}

uint16_t group = (uint16_t)number;
group = htobe16(group);
memcpy(rdata->octets, &group, 2);
rdata->octets += 2;
if (number > 65535)
SYNTAX_ERROR(parser, "Invalid tls-supported-group in %s", NAME(type));

const uint8_t *g;
for (g = rdata_start; g < rdata->octets - 2; g += 2) {
if (memcmp(g, &group, 2) == 0)
SEMANTIC_ERROR(parser, "Duplicate group in tls-supported-groups in %s", NAME(type));
}
if (*t != ',')
break;
else
t++;
}

if (t != te || rdata->octets > rdata->limit)
SYNTAX_ERROR(parser, "Invalid tls-supported-groups in %s", NAME(type));
return 0;
}

nonnull_all
static int32_t parse_mandatory_lax(
parser_t *parser,
Expand Down Expand Up @@ -421,7 +470,13 @@ static const svc_param_info_t svc_params[] = {
// If the "alpn" SvcParam indicates support for HTTP, "dohpath" MUST be
// present.
SVC_PARAM("dohpath", 7u, MANDATORY_VALUE, parse_dohpath, parse_dohpath),
SVC_PARAM("ohttp", 8u, 0u, 0, 0),
// RFC9540 section 4.
// Both the presentation and wire-format values for the "ohttp" parameter
// MUST be empty.
SVC_PARAM("ohttp", 8u, NO_VALUE, parse_unknown, parse_unknown),
// draft-ietf-tls-key-share-prediction-01 section 3.1
SVC_PARAM("tls-supported-groups", 9u, MANDATORY_VALUE,
parse_tls_supported_groups, parse_tls_supported_groups),
};

static const svc_param_info_t unknown_svc_param =
Expand Down Expand Up @@ -485,6 +540,8 @@ static really_inline size_t scan_svc_param(
return (void)(*param = &svc_params[(*key = ZONE_SVC_PARAM_KEY_DOHPATH)]), 7;
else if (memcmp(data, "ohttp", 5) == 0)
return (void)(*param = &svc_params[(*key = ZONE_SVC_PARAM_KEY_OHTTP)]), 5;
else if (memcmp(data, "tls-supported-groups", 20) == 0)
return (void)(*param = &svc_params[(*key = ZONE_SVC_PARAM_KEY_TLS_SUPPORTED_GROUPS)]), 20;
else if (memcmp(data, "key", 3) == 0)
return scan_unknown_svc_param_key(data, key, param);
else
Expand Down
83 changes: 82 additions & 1 deletion tests/svcb.c
Original file line number Diff line number Diff line change
Expand Up @@ -690,6 +690,80 @@ static const rdata_t nsd_s09_rdata =
0x00, 0x01, 0x00, 0x03, 2, 'h', '2',
0x00, 0x07, 0x00, 0x12, '/', 'd', 'n', 's', '-', 'q', 'u', 'e', 'r', 'y', '{', 0xc3, 0xa9, '?', 'd', 'n', 's', '}');

// From RFC9540 Section 4.1
static const char ohttp_s1_text[] =
PAD("ohttp-s1 HTTPS 1 . ( alpn=h2 ohttp )");
static const rdata_t ohttp_s1_rdata =
RDATA(
0x00, 0x01, // priority
0x00, // target
0x00, 0x01, 0x00, 0x03, 2, 'h', '2', // alpn=h2
0x00, 0x08, 0x00, 0x00 // ohttp
);

static const char ohttp_s2_text[] =
PAD("ohttp-s2 HTTPS 1 . ( mandatory=ohttp ohttp )");
static const rdata_t ohttp_s2_rdata =
RDATA(
0x00, 0x01, // priority
0x00, // target
0x00, 0x00, 0x00, 0x02, 0x00, 0x08, // mandatory=ohttp
0x00, 0x08, 0x00, 0x00 // ohttp
);

// From RFC9540 Section 4.2.1
static const char ohttp_s3_text[] =
PAD("ohttp-s3 SVCB 1 doh.example.net. ( alpn=h2 dohpath=/dns-query{?dns} ohttp )");
static const rdata_t ohttp_s3_rdata =
RDATA(
0x00, 0x01, // priority
3, 'd', 'o', 'h', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'n', 'e', 't', 0, // target
0x00, 0x01, 0x00, 0x03, 2, 'h', '2', // alpn=h2
0x00, 0x07, 0x00, 0x10, '/', 'd', 'n', 's', '-', 'q', 'u', 'e', 'r', 'y', '{', '?', 'd', 'n', 's', '}',
0x00, 0x08, 0x00, 0x00 // ohttp
);

// From RFC9540 Section 4:
// Both the presentation and wire-format values for the "ohttp" parameter
// MUST be empty.
static const char ohttp_f1_text[] =
PAD("ohttp-f1 HTTPS 1 . ( alpn=h2 ohttp=hopsa )");

#if 0
// wire-format non-empty value for the "ohttp" parameter does not fail yet
static const char ohttp_f2_generic_text[] =
PAD("ohttp-f2 SVCB \\# 19 (\n"
"00 01 ; priority\n"
"00 ; target\n"
"00 01 00 03 02 68 32 ; alpn=h2\n"
"00 08 00 05 68 6f 70 73 61 ; ohttp=hopsa\n"
")");
#endif

// From draft-ietf-tls-key-share-prediction-01 Section 3.1
static const char tsg_s1_text[] =
PAD("tsg-s1 7200 IN SVCB 3 server.example.net. (\n"
"port=\"8004\" tls-supported-groups=29,23 )");
static const rdata_t tsg_s1_rdata =
RDATA(
0x00, 0x03, // priority
6, 's', 'e', 'r', 'v', 'e', 'r', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'n', 'e', 't', 0, // target
0x00, 0x03, 0x00, 0x02, 0x1f, 0x44, // port="8004"
0x00, 0x09, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x17 // tls-supported-groups=29,23
);

// From draft-ietf-tls-key-share-prediction-01 Section 3.1:
// An empty list of values is invalid
static const char tsg_f1_text[] =
PAD("tsg-f1 7200 IN SVCB 3 server.example.net. (\n"
"port=\"8004\" tls-supported-groups )");

// From draft-ietf-tls-key-share-prediction-01 Section 3.1:
// An list containing duplicates is invalid
static const char tsg_f2_text[] =
PAD("tsg-f2 7200 IN SVCB 3 server.example.net. (\n"
"port=\"8004\" tls-supported-groups=29,23,29 )");

// FIXME: make a test that verifies correct behavior for no-default-alpn="some value"

typedef struct test test_t;
Expand Down Expand Up @@ -777,7 +851,14 @@ static const test_t tests[] = {
{ true, ZONE_TYPE_HTTPS, 0, nsd_s05_https_text, &nsd_s05_https_secondary_rdata },
{ false, ZONE_TYPE_HTTPS, 0, nsd_s06_text, &nsd_s06_rdata },
{ false, ZONE_TYPE_HTTPS, 0, nsd_s08_text, &nsd_s08_rdata },
{ false, ZONE_TYPE_HTTPS, 0, nsd_s09_text, &nsd_s09_rdata }
{ false, ZONE_TYPE_HTTPS, 0, nsd_s09_text, &nsd_s09_rdata },
{ false, ZONE_TYPE_HTTPS, 0, ohttp_s1_text, &ohttp_s1_rdata },
{ false, ZONE_TYPE_HTTPS, 0, ohttp_s2_text, &ohttp_s2_rdata },
{ false, ZONE_TYPE_SVCB, 0, ohttp_s3_text, &ohttp_s3_rdata },
{ false, ZONE_TYPE_HTTPS, ZONE_SEMANTIC_ERROR, ohttp_f1_text, NULL },
{ false, ZONE_TYPE_SVCB, 0, tsg_s1_text, &tsg_s1_rdata },
{ false, ZONE_TYPE_SVCB, ZONE_SEMANTIC_ERROR, tsg_f1_text, NULL },
{ false, ZONE_TYPE_SVCB, ZONE_SEMANTIC_ERROR, tsg_f2_text, NULL }
};

static int32_t add_rr(
Expand Down

0 comments on commit 0411158

Please sign in to comment.