lazy-allocation of buffer to store unknown extensions
diff --git a/lib/picotls.c b/lib/picotls.c
index 51a5ac7..7dd98c1 100644
--- a/lib/picotls.c
+++ b/lib/picotls.c
@@ -2385,21 +2385,24 @@
return ret;
}
-static int handle_unknown_extension(ptls_t *tls, ptls_handshake_properties_t *properties, uint16_t type, const uint8_t *src,
- const uint8_t *const end, ptls_raw_extension_t *slots)
+static int should_collect_unknown_extension(ptls_t *tls, ptls_handshake_properties_t *properties, uint16_t type)
{
- if (properties != NULL && properties->collect_extension != NULL && properties->collect_extension(tls, properties, type)) {
- size_t i;
- for (i = 0; slots[i].type != UINT16_MAX; ++i) {
- assert(i < MAX_UNKNOWN_EXTENSIONS);
- if (slots[i].type == type)
- return PTLS_ALERT_ILLEGAL_PARAMETER;
- }
- if (i < MAX_UNKNOWN_EXTENSIONS) {
- slots[i].type = type;
- slots[i].data = ptls_iovec_init(src, end - src);
- slots[i + 1].type = UINT16_MAX;
- }
+ return properties != NULL && properties->collect_extension != NULL && properties->collect_extension(tls, properties, type);
+}
+
+static int collect_unknown_extension(ptls_t *tls, uint16_t type, const uint8_t *src, const uint8_t *const end,
+ ptls_raw_extension_t *slots)
+{
+ size_t i;
+ for (i = 0; slots[i].type != UINT16_MAX; ++i) {
+ assert(i < MAX_UNKNOWN_EXTENSIONS);
+ if (slots[i].type == type)
+ return PTLS_ALERT_ILLEGAL_PARAMETER;
+ }
+ if (i < MAX_UNKNOWN_EXTENSIONS) {
+ slots[i].type = type;
+ slots[i].data = ptls_iovec_init(src, end - src);
+ slots[i + 1].type = UINT16_MAX;
}
return 0;
}
@@ -2418,11 +2421,10 @@
{
const uint8_t *src = message.base + PTLS_HANDSHAKE_HEADER_SIZE, *const end = message.base + message.len, *esni_nonce = NULL;
uint16_t type;
- ptls_raw_extension_t unknown_extensions[MAX_UNKNOWN_EXTENSIONS + 1];
+ static const ptls_raw_extension_t no_unknown_extensions = {UINT16_MAX};
+ ptls_raw_extension_t *unknown_extensions = (ptls_raw_extension_t *)&no_unknown_extensions;
int ret, skip_early_data = 1;
- unknown_extensions[0].type = UINT16_MAX;
-
decode_extensions(src, end, PTLS_HANDSHAKE_TYPE_ENCRYPTED_EXTENSIONS, &type, {
if (tls->ctx->on_extension != NULL &&
(ret = tls->ctx->on_extension->cb(tls->ctx->on_extension, tls, PTLS_HANDSHAKE_TYPE_ENCRYPTED_EXTENSIONS, type,
@@ -2477,7 +2479,14 @@
skip_early_data = 0;
break;
default:
- handle_unknown_extension(tls, properties, type, src, end, unknown_extensions);
+ if (should_collect_unknown_extension(tls, properties, type)) {
+ if (unknown_extensions == &no_unknown_extensions) {
+ unknown_extensions = malloc(sizeof(*unknown_extensions) * (MAX_UNKNOWN_EXTENSIONS + 1));
+ unknown_extensions[0].type = UINT16_MAX;
+ }
+ if ((ret = collect_unknown_extension(tls, type, src, end, unknown_extensions)) != 0)
+ goto Exit;
+ }
break;
}
src = end;
@@ -2511,6 +2520,8 @@
ret = PTLS_ERROR_IN_PROGRESS;
Exit:
+ if (unknown_extensions != &no_unknown_extensions)
+ free(unknown_extensions);
return ret;
}
@@ -3401,7 +3412,10 @@
ch->status_request = 1;
break;
default:
- handle_unknown_extension(tls, properties, exttype, src, end, ch->unknown_extensions);
+ if (should_collect_unknown_extension(tls, properties, exttype)) {
+ if ((ret = collect_unknown_extension(tls, exttype, src, end, ch->unknown_extensions)) != 0)
+ goto Exit;
+ }
break;
}
src = end;