mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-10-24 04:09:07 +03:00
Hold the EC point formats in one allocation
The point formats extension stored its formats as a linked list with one heap node per one byte value, which is the shape the supported groups extension had before. A node costs sixteen bytes to hold one. Replace the list with a block holding a count, a capacity and a flat array, matching what the supported groups extension does now. The block starts with room for four formats, which is more than are defined, and doubles if a caller adds more.
This commit is contained in:
committed by
Tobias Frauenschläger
parent
caafb688c3
commit
296ef4be79
158
src/tls.c
158
src/tls.c
@@ -4947,20 +4947,74 @@ static int TLSX_SupportedCurve_New(SupportedCurve** curve, word16 name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int TLSX_PointFormat_New(PointFormat** point, byte format, void* heap)
|
||||
/* Formats the first allocation holds. */
|
||||
#define POINT_FORMATS_INIT_CNT 4
|
||||
/* Most formats a list can hold. The capacity is a byte. */
|
||||
#define POINT_FORMATS_MAX_CNT 128
|
||||
/* Append() grows with (byte)(count + 1), which must not wrap. */
|
||||
wc_static_assert(POINT_FORMATS_MAX_CNT < 0xFFU);
|
||||
/* Powers of two, so the doubling in Grow() lands on the maximum exactly. */
|
||||
wc_static_assert((POINT_FORMATS_INIT_CNT &
|
||||
(POINT_FORMATS_INIT_CNT - 1)) == 0);
|
||||
wc_static_assert((POINT_FORMATS_MAX_CNT &
|
||||
(POINT_FORMATS_MAX_CNT - 1)) == 0);
|
||||
wc_static_assert(POINT_FORMATS_INIT_CNT <= POINT_FORMATS_MAX_CNT);
|
||||
|
||||
/* Make room for the requested number of point formats.
|
||||
*
|
||||
* formats The list to grow, allocated when NULL. Updated on reallocation.
|
||||
* cnt The number of formats the list has to hold.
|
||||
* heap The heap used for allocation.
|
||||
* returns 0 on success, otherwise failure.
|
||||
*/
|
||||
static int TLSX_PointFormat_Grow(PointFormats** formats, byte cnt, void* heap)
|
||||
{
|
||||
if (point == NULL)
|
||||
PointFormats* list = *formats;
|
||||
PointFormats* newList;
|
||||
word16 cap = POINT_FORMATS_INIT_CNT;
|
||||
|
||||
if ((list != NULL) && (cnt <= list->cap))
|
||||
return 0;
|
||||
if (cnt > POINT_FORMATS_MAX_CNT)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
(void)heap;
|
||||
while (cap < cnt)
|
||||
cap *= 2;
|
||||
|
||||
*point = (PointFormat*)XMALLOC(sizeof(PointFormat), heap,
|
||||
DYNAMIC_TYPE_TLSX);
|
||||
if (*point == NULL)
|
||||
newList = (PointFormats*)XMALLOC(sizeof(PointFormats) + cap, heap,
|
||||
DYNAMIC_TYPE_TLSX);
|
||||
if (newList == NULL)
|
||||
return MEMORY_E;
|
||||
|
||||
(*point)->format = format;
|
||||
(*point)->next = NULL;
|
||||
newList->count = 0;
|
||||
newList->cap = (byte)cap;
|
||||
|
||||
if (list != NULL) {
|
||||
newList->count = list->count;
|
||||
XMEMCPY(newList->format, list->format, list->count);
|
||||
XFREE(list, heap, DYNAMIC_TYPE_TLSX);
|
||||
}
|
||||
|
||||
*formats = newList;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int TLSX_PointFormat_New(PointFormats** formats, byte format,
|
||||
void* heap)
|
||||
{
|
||||
PointFormats* list = NULL;
|
||||
int ret;
|
||||
|
||||
if (formats == NULL)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
ret = TLSX_PointFormat_Grow(&list, 1, heap);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
list->format[list->count++] = format;
|
||||
*formats = list;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -4976,14 +5030,10 @@ static void TLSX_SupportedCurve_FreeAll(SupportedCurve* list, void* heap)
|
||||
(void)heap;
|
||||
}
|
||||
|
||||
static void TLSX_PointFormat_FreeAll(PointFormat* list, void* heap)
|
||||
static void TLSX_PointFormat_FreeAll(PointFormats* list, void* heap)
|
||||
{
|
||||
PointFormat* point;
|
||||
|
||||
while ((point = list)) {
|
||||
list = point->next;
|
||||
XFREE(point, heap, DYNAMIC_TYPE_TLSX);
|
||||
}
|
||||
if (list != NULL)
|
||||
XFREE(list, heap, DYNAMIC_TYPE_TLSX);
|
||||
(void)heap;
|
||||
}
|
||||
|
||||
@@ -5009,25 +5059,30 @@ static int TLSX_SupportedCurve_Append(SupportedCurve* list, word16 name,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int TLSX_PointFormat_Append(PointFormat* list, byte format, void* heap)
|
||||
static int TLSX_PointFormat_Append(PointFormats** formats, byte format,
|
||||
void* heap)
|
||||
{
|
||||
int ret = WC_NO_ERR_TRACE(BAD_FUNC_ARG);
|
||||
PointFormats* list;
|
||||
int ret;
|
||||
byte i;
|
||||
|
||||
while (list) {
|
||||
if (list->format == format) {
|
||||
ret = 0; /* format already in use */
|
||||
break;
|
||||
}
|
||||
if ((formats == NULL) || (*formats == NULL))
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
if (list->next == NULL) {
|
||||
ret = TLSX_PointFormat_New(&list->next, format, heap);
|
||||
break;
|
||||
}
|
||||
|
||||
list = list->next;
|
||||
list = *formats;
|
||||
for (i = 0; i < list->count; i++) {
|
||||
if (list->format[i] == format)
|
||||
return 0; /* format already in use */
|
||||
}
|
||||
|
||||
return ret;
|
||||
ret = TLSX_PointFormat_Grow(formats, (byte)(list->count + 1), heap);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
list = *formats;
|
||||
list->format[list->count++] = format;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(WOLFSSL_TLS13) || !defined(NO_WOLFSSL_CLIENT)
|
||||
@@ -5192,15 +5247,12 @@ static word16 TLSX_SupportedCurve_GetSize(SupportedCurve* list)
|
||||
|
||||
#endif
|
||||
|
||||
static word16 TLSX_PointFormat_GetSize(PointFormat* list)
|
||||
static word16 TLSX_PointFormat_GetSize(PointFormats* list)
|
||||
{
|
||||
PointFormat* point;
|
||||
word16 length = ENUM_LEN; /* list length */
|
||||
|
||||
while ((point = list)) {
|
||||
list = point->next;
|
||||
length += ENUM_LEN; /* format length */
|
||||
}
|
||||
if (list != NULL)
|
||||
length = (word16)(length + list->count * ENUM_LEN);
|
||||
|
||||
return length;
|
||||
}
|
||||
@@ -5224,13 +5276,14 @@ static word16 TLSX_SupportedCurve_Write(SupportedCurve* list, byte* output)
|
||||
|
||||
#endif
|
||||
|
||||
static word16 TLSX_PointFormat_Write(PointFormat* list, byte* output)
|
||||
static word16 TLSX_PointFormat_Write(PointFormats* list, byte* output)
|
||||
{
|
||||
word16 offset = ENUM_LEN;
|
||||
byte i;
|
||||
|
||||
while (list) {
|
||||
output[offset++] = list->format;
|
||||
list = list->next;
|
||||
if (list != NULL) {
|
||||
for (i = 0; i < list->count; i++)
|
||||
output[offset++] = list->format[i];
|
||||
}
|
||||
|
||||
output[0] = (byte)(offset - ENUM_LEN);
|
||||
@@ -6211,10 +6264,19 @@ int TLSX_UseSupportedCurve(TLSX** extensions, word16 name, void* heap, int side)
|
||||
return WOLFSSL_SUCCESS;
|
||||
}
|
||||
|
||||
/* Add a point format to the extension's list, creating the extension when it
|
||||
* does not exist yet. Appending may reallocate extension->data.
|
||||
*
|
||||
* extensions The list of extensions.
|
||||
* format The point format to add.
|
||||
* heap The heap used for allocation.
|
||||
* returns WOLFSSL_SUCCESS on success, BAD_FUNC_ARG at
|
||||
* POINT_FORMATS_MAX_CNT formats, otherwise an allocation failure.
|
||||
*/
|
||||
int TLSX_UsePointFormat(TLSX** extensions, byte format, void* heap)
|
||||
{
|
||||
TLSX* extension = NULL;
|
||||
PointFormat* point = NULL;
|
||||
PointFormats* formats = NULL;
|
||||
int ret = 0;
|
||||
|
||||
if (extensions == NULL)
|
||||
@@ -6223,19 +6285,19 @@ int TLSX_UsePointFormat(TLSX** extensions, byte format, void* heap)
|
||||
extension = TLSX_Find(*extensions, TLSX_EC_POINT_FORMATS);
|
||||
|
||||
if (!extension) {
|
||||
ret = TLSX_PointFormat_New(&point, format, heap);
|
||||
ret = TLSX_PointFormat_New(&formats, format, heap);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
ret = TLSX_Push(extensions, TLSX_EC_POINT_FORMATS, point, heap);
|
||||
ret = TLSX_Push(extensions, TLSX_EC_POINT_FORMATS, formats, heap);
|
||||
if (ret != 0) {
|
||||
XFREE(point, heap, DYNAMIC_TYPE_TLSX);
|
||||
XFREE(formats, heap, DYNAMIC_TYPE_TLSX);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ret = TLSX_PointFormat_Append((PointFormat*)extension->data, format,
|
||||
heap);
|
||||
ret = TLSX_PointFormat_Append((PointFormats**)&extension->data, format,
|
||||
heap);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
@@ -15523,7 +15585,7 @@ void TLSX_FreeAll(TLSX* list, void* heap)
|
||||
|
||||
case TLSX_EC_POINT_FORMATS:
|
||||
WOLFSSL_MSG("Point Formats extension free");
|
||||
PF_FREE_ALL((PointFormat*)extension->data, heap);
|
||||
PF_FREE_ALL((PointFormats*)extension->data, heap);
|
||||
break;
|
||||
|
||||
case TLSX_STATUS_REQUEST:
|
||||
@@ -15765,7 +15827,7 @@ static int TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType,
|
||||
break;
|
||||
|
||||
case TLSX_EC_POINT_FORMATS:
|
||||
length += PF_GET_SIZE((PointFormat*)extension->data);
|
||||
length += PF_GET_SIZE((PointFormats*)extension->data);
|
||||
break;
|
||||
|
||||
case TLSX_STATUS_REQUEST:
|
||||
@@ -16038,7 +16100,7 @@ static int TLSX_Write(TLSX* list, byte* output, byte* semaphore,
|
||||
|
||||
case TLSX_EC_POINT_FORMATS:
|
||||
WOLFSSL_MSG("Point Formats extension to write");
|
||||
offset += PF_WRITE((PointFormat*)extension->data,
|
||||
offset += PF_WRITE((PointFormats*)extension->data,
|
||||
output + offset);
|
||||
break;
|
||||
|
||||
|
||||
@@ -45741,6 +45741,7 @@ TEST_CASE testCases[] = {
|
||||
TEST_DECL(test_TLSX_ALPN_server_response_count),
|
||||
TEST_DECL(test_TLSX_SupportedCurve_empty_or_unsupported),
|
||||
TEST_DECL(test_TLSX_SignatureAlgorithmsCert_parse),
|
||||
TEST_DECL(test_TLSX_PointFormat_list),
|
||||
TEST_DECL(test_TLSX_MaxFragment_value),
|
||||
TEST_DECL(test_TLSX_PointFormat_uncompressed_required),
|
||||
TEST_DECL(test_wolfSSL_CTX_add_client_custom_ext),
|
||||
|
||||
@@ -3264,6 +3264,95 @@ int test_TLSX_SignatureAlgorithmsCert_parse(void)
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/* The formats live in a counted array that doubles when it fills. No in-tree
|
||||
* caller reaches the growth path, so drive TLSX_UsePointFormat() directly. */
|
||||
int test_TLSX_PointFormat_list(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(HAVE_SUPPORTED_CURVES) && defined(HAVE_TLS_EXTENSIONS) && \
|
||||
!defined(NO_TLS) && !defined(NO_WOLFSSL_CLIENT) && \
|
||||
(defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \
|
||||
defined(HAVE_CURVE448))
|
||||
WOLFSSL_CTX* ctx = NULL;
|
||||
WOLFSSL* ssl = NULL;
|
||||
TLSX** exts = NULL;
|
||||
TLSX* extension = NULL;
|
||||
PointFormats* formats = NULL;
|
||||
void* heap = NULL;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
#ifndef WOLFSSL_NO_TLS12
|
||||
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method()));
|
||||
#else
|
||||
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()));
|
||||
#endif
|
||||
ExpectNotNull(ssl = wolfSSL_new(ctx));
|
||||
if (ssl != NULL) {
|
||||
exts = &ssl->extensions;
|
||||
heap = ssl->heap;
|
||||
ExpectNull(TLSX_Find(ssl->extensions, TLSX_EC_POINT_FORMATS));
|
||||
}
|
||||
if (exts == NULL) {
|
||||
/* ssl is NULL too, so there is nothing else to release. */
|
||||
wolfSSL_CTX_free(ctx);
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/* The three formats RFC 8422 defines, then a repeat of the first. */
|
||||
ExpectIntEQ(TLSX_UsePointFormat(exts, WOLFSSL_EC_PF_UNCOMPRESSED, heap),
|
||||
WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(TLSX_UsePointFormat(exts, 1, heap), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(TLSX_UsePointFormat(exts, 2, heap), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(TLSX_UsePointFormat(exts, WOLFSSL_EC_PF_UNCOMPRESSED, heap),
|
||||
WOLFSSL_SUCCESS);
|
||||
ExpectNotNull(extension = TLSX_Find(*exts, TLSX_EC_POINT_FORMATS));
|
||||
if (extension != NULL)
|
||||
formats = (PointFormats*)extension->data;
|
||||
ExpectNotNull(formats);
|
||||
/* The repeat is dropped, and four is still enough. */
|
||||
ExpectIntEQ(formats == NULL ? -1 : (int)formats->count, 3);
|
||||
ExpectIntEQ(formats == NULL ? -1 : (int)formats->cap, 4);
|
||||
if (formats != NULL) {
|
||||
ExpectIntEQ(formats->format[0], WOLFSSL_EC_PF_UNCOMPRESSED);
|
||||
ExpectIntEQ(formats->format[1], 1);
|
||||
ExpectIntEQ(formats->format[2], 2);
|
||||
}
|
||||
|
||||
/* Past the initial capacity the list grows and keeps what it held. */
|
||||
for (i = 3; EXPECT_SUCCESS() && (i < 10); i++) {
|
||||
ExpectIntEQ(TLSX_UsePointFormat(exts, (byte)i, heap),
|
||||
WOLFSSL_SUCCESS);
|
||||
}
|
||||
if (extension != NULL)
|
||||
formats = (PointFormats*)extension->data;
|
||||
ExpectNotNull(formats);
|
||||
ExpectIntEQ(formats == NULL ? -1 : (int)formats->count, 10);
|
||||
ExpectIntGE(formats == NULL ? -1 : (int)formats->cap, 10);
|
||||
if (formats != NULL) {
|
||||
ExpectIntEQ(formats->format[0], WOLFSSL_EC_PF_UNCOMPRESSED);
|
||||
ExpectIntEQ(formats->format[9], 9);
|
||||
}
|
||||
|
||||
/* The bound is internal to src/tls.c, so discover it. 256 values exceed
|
||||
* any bound a byte capacity can hold. */
|
||||
ret = WOLFSSL_SUCCESS;
|
||||
for (i = 10; (ret == WOLFSSL_SUCCESS) && (i < 256); i++)
|
||||
ret = TLSX_UsePointFormat(exts, (byte)i, heap);
|
||||
ExpectIntEQ(ret, WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
if (extension != NULL)
|
||||
formats = (PointFormats*)extension->data;
|
||||
ExpectNotNull(formats);
|
||||
/* The refused insert leaves the list full. */
|
||||
if (formats != NULL)
|
||||
ExpectIntEQ((int)formats->count, (int)formats->cap);
|
||||
|
||||
wolfSSL_free(ssl);
|
||||
wolfSSL_CTX_free(ctx);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/* The requested code is held in the extension and a response must match. */
|
||||
int test_TLSX_MaxFragment_value(void)
|
||||
{
|
||||
|
||||
@@ -68,6 +68,7 @@ int test_TLSX_QUIC_TP_non_quic(void);
|
||||
int test_TLSX_ALPN_server_response_count(void);
|
||||
int test_TLSX_SupportedCurve_empty_or_unsupported(void);
|
||||
int test_TLSX_SignatureAlgorithmsCert_parse(void);
|
||||
int test_TLSX_PointFormat_list(void);
|
||||
int test_TLSX_MaxFragment_value(void);
|
||||
int test_TLSX_PointFormat_uncompressed_required(void);
|
||||
int test_wolfSSL_CTX_add_client_custom_ext(void);
|
||||
|
||||
@@ -3889,10 +3889,16 @@ typedef struct SupportedCurve {
|
||||
struct SupportedCurve* next; /* List Behavior */
|
||||
} SupportedCurve;
|
||||
|
||||
typedef struct PointFormat {
|
||||
byte format; /* PointFormat */
|
||||
struct PointFormat* next; /* List Behavior */
|
||||
} PointFormat;
|
||||
typedef struct PointFormats {
|
||||
byte count; /* Formats in use */
|
||||
byte cap; /* Formats allocated */
|
||||
/* Ignore "nonstandard extension used : zero-sized array in struct/union"
|
||||
* MSVC warning */
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable: 4200)
|
||||
#endif
|
||||
byte format[WC_FLEXIBLE_ARRAY_SIZE]; /* Point formats */
|
||||
} PointFormats;
|
||||
|
||||
WOLFSSL_LOCAL int TLSX_SupportedCurve_Copy(TLSX* src, TLSX** dst, void* heap);
|
||||
WOLFSSL_LOCAL int TLSX_UseSupportedCurve(TLSX** extensions, word16 name,
|
||||
|
||||
Reference in New Issue
Block a user