TLSX and SNI code maintenance:

* improves docs;
 * fixes indentation;
 * Extracts TLSX_New() from TLSX_Push();
 * Replaces TLSX_SNI_Append() with TLSX_SNI_New();
 * Adds missing STK_VALIDATE_REQUEST() in TLSX_WriteRequest();
 * Moves TLSX_SetResponse() to the right position inside TLSX_SNI_Parse().
This commit is contained in:
Moisés Guimarães
2015-07-01 12:44:42 -03:00
parent afde172f28
commit e121d01206
2 changed files with 172 additions and 103 deletions

252
src/tls.c
View File

@@ -713,15 +713,38 @@ int TLS_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz,
#ifdef HAVE_TLS_EXTENSIONS
/**
* The TLSX semaphore is used to calculate the size of the extensions to be sent
* from one peer to another.
*/
/** Supports up to 64 flags. Update as needed. */
/** Supports up to 64 flags. Increase as needed. */
#define SEMAPHORE_SIZE 8
/**
* Converts the extension type (id) to an index in the semaphore.
*
* Oficial reference for TLS extension types:
* http://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xml
*
* Motivation:
* Previously, we used the extension type itself as the index of that
* extension in the semaphore as the extension types were declared
* sequentially, but maintain a semaphore as big as the number of available
* extensions is no longer an option since the release of renegotiation_info.
*
* How to update:
* Assign extension types that extrapolate the number of available semaphores
* to the first available index going backwards in the semaphore array.
* When adding a new extension type that don't extrapolate the number of
* available semaphores, check for a possible collision with with a
* 'remapped' extension type.
*/
static INLINE word16 TLSX_ToSemaphore(word16 type)
{
switch (type) {
case SECURE_RENEGOTIATION:
case SECURE_RENEGOTIATION: /* 0xFF01 */
return 63;
default:
@@ -739,30 +762,45 @@ static INLINE word16 TLSX_ToSemaphore(word16 type)
return type;
}
/** Checks if a specific light (tls extension) is not set in the semaphore. */
#define IS_OFF(semaphore, light) \
((semaphore)[(light) / 8] ^ (byte) (0x01 << ((light) % 8)))
/** Turn on a specific light (tls extension) in the semaphore. */
#define TURN_ON(semaphore, light) \
((semaphore)[(light) / 8] |= (byte) (0x01 << ((light) % 8)))
/** Creates a new extension. */
static TLSX* TLSX_New(TLSX_Type type, void* data)
{
TLSX* extension = (TLSX*)XMALLOC(sizeof(TLSX), 0, DYNAMIC_TYPE_TLSX);
if (extension) {
extension->type = type;
extension->data = data;
extension->resp = 0;
extension->next = NULL;
}
return extension;
}
/**
* Creates a new extension and pushes it to the provided list.
* Checks for duplicate extensions, keeps the newest.
*/
static int TLSX_Push(TLSX** list, TLSX_Type type, void* data)
{
TLSX* extension;
TLSX* extension = TLSX_New(type, data);
extension = (TLSX*)XMALLOC(sizeof(TLSX), 0, DYNAMIC_TYPE_TLSX);
if (extension == NULL)
return MEMORY_E;
extension->type = type;
extension->data = data;
extension->resp = 0;
/* pushes the new extension on the list. */
extension->next = *list;
*list = extension;
/* remove duplicated extensions, there should be only one of each type. */
/* remove duplicate extensions, there should be only one of each type. */
do {
if (extension->next && extension->next->type == type) {
TLSX *next = extension->next;
@@ -781,9 +819,9 @@ static int TLSX_Push(TLSX** list, TLSX_Type type, void* data)
return 0;
}
#ifndef NO_WOLFSSL_SERVER
/** Mark an extension to be sent back to the client. */
void TLSX_SetResponse(WOLFSSL* ssl, TLSX_Type type);
void TLSX_SetResponse(WOLFSSL* ssl, TLSX_Type type)
@@ -796,10 +834,46 @@ void TLSX_SetResponse(WOLFSSL* ssl, TLSX_Type type)
#endif
/* SNI - Server Name Indication */
/* Server Name Indication */
#ifdef HAVE_SNI
/** Creates a new SNI object. */
static SNI* TLSX_SNI_New(byte type, const void* data, word16 size)
{
SNI* sni = (SNI*)XMALLOC(sizeof(SNI), 0, DYNAMIC_TYPE_TLSX);
if (sni) {
sni->type = type;
sni->next = NULL;
#ifndef NO_WOLFSSL_SERVER
sni->options = 0;
sni->status = WOLFSSL_SNI_NO_MATCH;
#endif
switch (sni->type) {
case WOLFSSL_SNI_HOST_NAME:
sni->data.host_name = XMALLOC(size + 1, 0, DYNAMIC_TYPE_TLSX);
if (sni->data.host_name) {
XSTRNCPY(sni->data.host_name, (const char*)data, size);
sni->data.host_name[size] = 0;
} else {
XFREE(sni, 0, DYNAMIC_TYPE_TLSX);
sni = NULL;
}
break;
default: /* invalid type */
XFREE(sni, 0, DYNAMIC_TYPE_TLSX);
sni = NULL;
}
}
return sni;
}
/** Releases a SNI object. */
static void TLSX_SNI_Free(SNI* sni)
{
if (sni) {
@@ -813,6 +887,7 @@ static void TLSX_SNI_Free(SNI* sni)
}
}
/** Releases all SNI objects in the provided list. */
static void TLSX_SNI_FreeAll(SNI* list)
{
SNI* sni;
@@ -823,48 +898,7 @@ static void TLSX_SNI_FreeAll(SNI* list)
}
}
static int TLSX_SNI_Append(SNI** list, byte type, const void* data, word16 size)
{
SNI* sni;
if (list == NULL)
return BAD_FUNC_ARG;
if ((sni = XMALLOC(sizeof(SNI), 0, DYNAMIC_TYPE_TLSX)) == NULL)
return MEMORY_E;
switch (type) {
case WOLFSSL_SNI_HOST_NAME: {
sni->data.host_name = XMALLOC(size + 1, 0, DYNAMIC_TYPE_TLSX);
if (sni->data.host_name) {
XSTRNCPY(sni->data.host_name, (const char*)data, size);
sni->data.host_name[size] = 0;
} else {
XFREE(sni, 0, DYNAMIC_TYPE_TLSX);
return MEMORY_E;
}
}
break;
default: /* invalid type */
XFREE(sni, 0, DYNAMIC_TYPE_TLSX);
return BAD_FUNC_ARG;
}
sni->type = type;
sni->next = *list;
#ifndef NO_WOLFSSL_SERVER
sni->options = 0;
sni->status = WOLFSSL_SNI_NO_MATCH;
#endif
*list = sni;
return 0;
}
/** Tells the buffered size of the SNI objects in a list. */
static word16 TLSX_SNI_GetSize(SNI* list)
{
SNI* sni;
@@ -885,6 +919,7 @@ static word16 TLSX_SNI_GetSize(SNI* list)
return length;
}
/** Writes the SNI objects of a list in a buffer. */
static word16 TLSX_SNI_Write(SNI* list, byte* output)
{
SNI* sni;
@@ -915,6 +950,7 @@ static word16 TLSX_SNI_Write(SNI* list, byte* output)
return offset;
}
/** Finds a SNI object in the provided list. */
static SNI* TLSX_SNI_Find(SNI *list, byte type)
{
SNI *sni = list;
@@ -926,17 +962,18 @@ static SNI* TLSX_SNI_Find(SNI *list, byte type)
}
#ifndef NO_WOLFSSL_SERVER
/** Sets the status of a SNI object. */
static void TLSX_SNI_SetStatus(TLSX* extensions, byte type, byte status)
{
TLSX* extension = TLSX_Find(extensions, SERVER_NAME_INDICATION);
SNI* sni = TLSX_SNI_Find(extension ? extension->data : NULL, type);
if (sni) {
if (sni)
sni->status = status;
WOLFSSL_MSG("SNI did match!");
}
}
/** Gets the status of a SNI object. */
byte TLSX_SNI_Status(TLSX* extensions, byte type)
{
TLSX* extension = TLSX_Find(extensions, SERVER_NAME_INDICATION);
@@ -947,8 +984,10 @@ byte TLSX_SNI_Status(TLSX* extensions, byte type)
return 0;
}
#endif
#endif /* NO_WOLFSSL_SERVER */
/** Parses a buffer of SNI extensions. */
static int TLSX_SNI_Parse(WOLFSSL* ssl, byte* input, word16 length,
byte isRequest)
{
@@ -963,12 +1002,12 @@ static int TLSX_SNI_Parse(WOLFSSL* ssl, byte* input, word16 length,
extension = TLSX_Find(ssl->ctx->extensions, SERVER_NAME_INDICATION);
if (!extension || !extension->data)
return isRequest ? 0 : BUFFER_ERROR; /* not using SNI OR unexpected
SNI response from server. */
return isRequest ? 0 /* not using SNI. */
: BUFFER_ERROR; /* unexpected SNI response. */
if (!isRequest)
return length ? BUFFER_ERROR : 0; /* SNI response must be empty!
Nothing else to do. */
return length ? BUFFER_ERROR /* SNI response MUST be empty. */
: 0; /* nothing else to do. */
#ifndef NO_WOLFSSL_SERVER
@@ -995,9 +1034,8 @@ static int TLSX_SNI_Parse(WOLFSSL* ssl, byte* input, word16 length,
if (offset + size > length)
return BUFFER_ERROR;
if (!(sni = TLSX_SNI_Find((SNI*)extension->data, type))) {
continue; /* not using this SNI type */
}
if (!(sni = TLSX_SNI_Find((SNI*)extension->data, type)))
continue; /* not using this type of SNI. */
switch(type) {
case WOLFSSL_SNI_HOST_NAME: {
@@ -1009,10 +1047,15 @@ static int TLSX_SNI_Parse(WOLFSSL* ssl, byte* input, word16 length,
int r = TLSX_UseSNI(&ssl->extensions,
type, input + offset, size);
if (r != SSL_SUCCESS) return r; /* throw error */
if (r != SSL_SUCCESS)
return r; /* throws error. */
TLSX_SNI_SetStatus(ssl->extensions, type,
matched ? WOLFSSL_SNI_REAL_MATCH : WOLFSSL_SNI_FAKE_MATCH);
matched ? WOLFSSL_SNI_REAL_MATCH
: WOLFSSL_SNI_FAKE_MATCH);
TLSX_SetResponse(ssl, SERVER_NAME_INDICATION);
WOLFSSL_MSG("SNI did match!");
} else if (!(sni->options & WOLFSSL_SNI_CONTINUE_ON_MISMATCH)) {
SendAlert(ssl, alert_fatal, unrecognized_name);
@@ -1022,8 +1065,6 @@ static int TLSX_SNI_Parse(WOLFSSL* ssl, byte* input, word16 length,
break;
}
}
TLSX_SetResponse(ssl, SERVER_NAME_INDICATION);
}
#endif
@@ -1035,17 +1076,16 @@ int TLSX_UseSNI(TLSX** extensions, byte type, const void* data, word16 size)
{
TLSX* extension = TLSX_Find(*extensions, SERVER_NAME_INDICATION);
SNI* sni = NULL;
int ret = 0;
if (extensions == NULL || data == NULL)
return BAD_FUNC_ARG;
if ((ret = TLSX_SNI_Append(&sni, type, data, size)) != 0)
return ret;
if ((sni = TLSX_SNI_New(type, data, size)) == NULL)
return MEMORY_E;
if (!extension) {
if ((ret = TLSX_Push(extensions, SERVER_NAME_INDICATION, (void*)sni))
!= 0) {
int ret = TLSX_Push(extensions, SERVER_NAME_INDICATION, (void*)sni);
if (ret != 0) {
TLSX_SNI_Free(sni);
return ret;
}
@@ -1055,7 +1095,7 @@ int TLSX_UseSNI(TLSX** extensions, byte type, const void* data, word16 size)
sni->next = (SNI*)extension->data;
extension->data = (void*)sni;
/* look for another server name of the same type to remove */
/* remove duplicate SNI, there should be only one of each type. */
do {
if (sni->next && sni->next->type == type) {
SNI *next = sni->next;
@@ -1063,6 +1103,8 @@ int TLSX_UseSNI(TLSX** extensions, byte type, const void* data, word16 size)
sni->next = next->next;
TLSX_SNI_Free(next);
/* there is no way to occur more than */
/* two SNIs of the same type. */
break;
}
} while ((sni = sni->next));
@@ -1072,6 +1114,8 @@ int TLSX_UseSNI(TLSX** extensions, byte type, const void* data, word16 size)
}
#ifndef NO_WOLFSSL_SERVER
/** Tells the SNI requested by the client. */
word16 TLSX_SNI_GetRequest(TLSX* extensions, byte type, void** data)
{
TLSX* extension = TLSX_Find(extensions, SERVER_NAME_INDICATION);
@@ -1088,6 +1132,7 @@ word16 TLSX_SNI_GetRequest(TLSX* extensions, byte type, void** data)
return 0;
}
/** Sets the options for a SNI object. */
void TLSX_SNI_SetOptions(TLSX* extensions, byte type, byte options)
{
TLSX* extension = TLSX_Find(extensions, SERVER_NAME_INDICATION);
@@ -1097,6 +1142,7 @@ void TLSX_SNI_SetOptions(TLSX* extensions, byte type, byte options)
sni->options = options;
}
/** Retrieves a SNI request from a client hello buffer. */
int TLSX_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz,
byte type, byte* sni, word32* inOutSz)
{
@@ -1114,19 +1160,19 @@ int TLSX_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz,
/* http://tools.ietf.org/html/rfc4346#appendix-E.1 */
if ((enum HandShakeType) clientHello[++offset] == client_hello) {
offset += ENUM_LEN + VERSION_SZ; /* skip version */
ato16(clientHello + offset, &len16);
offset += OPAQUE16_LEN;
if (len16 % 3) /* cipher_spec_length must be multiple of 3 */
return BUFFER_ERROR;
ato16(clientHello + offset, &len16);
offset += OPAQUE16_LEN;
if (len16 != 0) /* session_id_length must be 0 */
return BUFFER_ERROR;
return SNI_UNSUPPORTED;
}
@@ -1433,7 +1479,7 @@ static void TLSX_EllipticCurve_ValidateRequest(WOLFSSL* ssl, byte* semaphore)
if (ssl->suites->suites[i] == ECC_BYTE)
return;
/* No elliptic curve suite found */
/* turns semaphore on to avoid sending this extension. */
TURN_ON(semaphore, TLSX_ToSemaphore(ELLIPTIC_CURVES));
}
@@ -1956,7 +2002,7 @@ int TLSX_UseSessionTicket(TLSX** extensions, SessionTicket* ticket)
#endif /* HAVE_SESSION_TICKET */
/** Finds an extension in the provided list. */
TLSX* TLSX_Find(TLSX* list, TLSX_Type type)
{
TLSX* extension = list;
@@ -1967,6 +2013,7 @@ TLSX* TLSX_Find(TLSX* list, TLSX_Type type)
return extension;
}
/** Releases all extensions in the provided list. */
void TLSX_FreeAll(TLSX* list)
{
TLSX* extension;
@@ -1975,6 +2022,7 @@ void TLSX_FreeAll(TLSX* list)
list = extension->next;
switch (extension->type) {
case SERVER_NAME_INDICATION:
SNI_FREE_ALL((SNI*)extension->data);
break;
@@ -2004,10 +2052,12 @@ void TLSX_FreeAll(TLSX* list)
}
}
/** Checks if the tls extensions are supported based on the protocol version. */
int TLSX_SupportExtensions(WOLFSSL* ssl) {
return ssl && (IsTLS(ssl) || ssl->version.major == DTLS_MAJOR);
}
/** Tells the buffered size of the extensions in a list. */
static word16 TLSX_GetSize(TLSX* list, byte* semaphore, byte isRequest)
{
TLSX* extension;
@@ -2016,26 +2066,31 @@ static word16 TLSX_GetSize(TLSX* list, byte* semaphore, byte isRequest)
while ((extension = list)) {
list = extension->next;
/* only extensions marked as response are sent back to the client. */
if (!isRequest && !extension->resp)
continue; /* skip! */
/* ssl level extensions are expected to override ctx level ones. */
if (!IS_OFF(semaphore, TLSX_ToSemaphore(extension->type)))
continue; /* skip! */
/* type + data length */
/* extension type + extension data length. */
length += HELLO_EXT_TYPE_SZ + OPAQUE16_LEN;
switch (extension->type) {
case SERVER_NAME_INDICATION:
/* SNI only sends the name on the request. */
if (isRequest)
length += SNI_GET_SIZE(extension->data);
break;
case MAX_FRAGMENT_LENGTH:
length += MFL_GET_SIZE(extension->data);
break;
case TRUNCATED_HMAC:
/* empty extension. */
/* always empty. */
break;
case ELLIPTIC_CURVES:
@@ -2051,12 +2106,15 @@ static word16 TLSX_GetSize(TLSX* list, byte* semaphore, byte isRequest)
break;
}
/* marks the extension as processed so ctx level */
/* extensions don't overlap with ssl level ones. */
TURN_ON(semaphore, TLSX_ToSemaphore(extension->type));
}
return length;
}
/** Writes the extensions of a list in a buffer. */
static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore,
byte isRequest)
{
@@ -2067,18 +2125,20 @@ static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore,
while ((extension = list)) {
list = extension->next;
/* only extensions marked as response are written in a response. */
if (!isRequest && !extension->resp)
continue; /* skip! */
/* ssl level extensions are expected to override ctx level ones. */
if (!IS_OFF(semaphore, TLSX_ToSemaphore(extension->type)))
continue; /* skip! */
/* extension type */
/* writes extension type. */
c16toa(extension->type, output + offset);
offset += HELLO_EXT_TYPE_SZ + OPAQUE16_LEN;
length_offset = offset;
/* extension data should be written internally */
/* extension data should be written internally. */
switch (extension->type) {
case SERVER_NAME_INDICATION:
if (isRequest)
@@ -2090,7 +2150,7 @@ static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore,
break;
case TRUNCATED_HMAC:
/* empty extension. */
/* always empty. */
break;
case ELLIPTIC_CURVES:
@@ -2108,9 +2168,11 @@ static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore,
break;
}
/* writing extension data length */
/* writes extension data length. */
c16toa(offset - length_offset, output + length_offset - OPAQUE16_LEN);
/* marks the extension as processed so ctx level */
/* extensions don't overlap with ssl level ones. */
TURN_ON(semaphore, TLSX_ToSemaphore(extension->type));
}
@@ -2119,6 +2181,7 @@ static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore,
#ifndef NO_WOLFSSL_CLIENT
/** Tells the buffered size of extensions to be sent into the client hello. */
word16 TLSX_GetRequestSize(WOLFSSL* ssl)
{
word16 length = 0;
@@ -2140,11 +2203,12 @@ word16 TLSX_GetRequestSize(WOLFSSL* ssl)
}
if (length)
length += OPAQUE16_LEN; /* for total length storage */
length += OPAQUE16_LEN; /* for total length storage. */
return length;
}
/** Writes the extensions to be sent into the client hello. */
word16 TLSX_WriteRequest(WOLFSSL* ssl, byte* output)
{
word16 offset = 0;
@@ -2155,6 +2219,7 @@ word16 TLSX_WriteRequest(WOLFSSL* ssl, byte* output)
offset += OPAQUE16_LEN; /* extensions length */
EC_VALIDATE_REQUEST(ssl, semaphore);
STK_VALIDATE_REQUEST(ssl);
if (ssl->extensions)
offset += TLSX_Write(ssl->extensions, output + offset,
@@ -2195,6 +2260,7 @@ word16 TLSX_WriteRequest(WOLFSSL* ssl, byte* output)
#ifndef NO_WOLFSSL_SERVER
/** Tells the buffered size of extensions to be sent into the server hello. */
word16 TLSX_GetResponseSize(WOLFSSL* ssl)
{
word16 length = 0;
@@ -2211,6 +2277,7 @@ word16 TLSX_GetResponseSize(WOLFSSL* ssl)
return length;
}
/** Writes the server hello extensions into a buffer. */
word16 TLSX_WriteResponse(WOLFSSL *ssl, byte* output)
{
word16 offset = 0;
@@ -2231,6 +2298,7 @@ word16 TLSX_WriteResponse(WOLFSSL *ssl, byte* output)
#endif /* NO_WOLFSSL_SERVER */
/** Parses a buffer of TLS extensions. */
int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest,
Suites *suites)
{
@@ -2326,8 +2394,7 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest,
#undef TURN_ON
#undef SEMAPHORE_SIZE
#endif
#endif /* HAVE_TLS_EXTENSIONS */
#ifndef NO_WOLFSSL_CLIENT
@@ -2465,4 +2532,3 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest,
#endif /* NO_WOLFSSL_SERVER */
#endif /* NO_TLS */

View File

@@ -1269,8 +1269,8 @@ enum {
WOLFSSL_SNI_HOST_NAME = 0
};
WOLFSSL_API int wolfSSL_UseSNI(WOLFSSL* ssl, unsigned char type, const void* data,
unsigned short size);
WOLFSSL_API int wolfSSL_UseSNI(WOLFSSL* ssl, unsigned char type,
const void* data, unsigned short size);
WOLFSSL_API int wolfSSL_CTX_UseSNI(WOLFSSL_CTX* ctx, unsigned char type,
const void* data, unsigned short size);
@@ -1278,26 +1278,30 @@ WOLFSSL_API int wolfSSL_CTX_UseSNI(WOLFSSL_CTX* ctx, unsigned char type,
/* SNI options */
enum {
WOLFSSL_SNI_CONTINUE_ON_MISMATCH = 0x01, /* do not abort on mismatch flag */
WOLFSSL_SNI_ANSWER_ON_MISMATCH = 0x02 /* fake match on mismatch flag */
/* Do not abort the handshake if the requested SNI didn't match. */
WOLFSSL_SNI_CONTINUE_ON_MISMATCH = 0x01,
/* Behave as if the requested SNI matched in a case of missmatch. */
/* In this case, the status will be set to WOLFSSL_SNI_FAKE_MATCH. */
WOLFSSL_SNI_ANSWER_ON_MISMATCH = 0x02
};
WOLFSSL_API void wolfSSL_SNI_SetOptions(WOLFSSL* ssl, unsigned char type,
unsigned char options);
WOLFSSL_API void wolfSSL_CTX_SNI_SetOptions(WOLFSSL_CTX* ctx, unsigned char type,
unsigned char options);
WOLFSSL_API void wolfSSL_CTX_SNI_SetOptions(WOLFSSL_CTX* ctx,
unsigned char type, unsigned char options);
/* SNI status */
enum {
WOLFSSL_SNI_NO_MATCH = 0,
WOLFSSL_SNI_FAKE_MATCH = 1, /* if WOLFSSL_SNI_ANSWER_ON_MISMATCH is enabled */
WOLFSSL_SNI_FAKE_MATCH = 1, /**< @see WOLFSSL_SNI_ANSWER_ON_MISMATCH */
WOLFSSL_SNI_REAL_MATCH = 2
};
WOLFSSL_API unsigned char wolfSSL_SNI_Status(WOLFSSL* ssl, unsigned char type);
WOLFSSL_API unsigned short wolfSSL_SNI_GetRequest(WOLFSSL *ssl, unsigned char type,
void** data);
WOLFSSL_API unsigned short wolfSSL_SNI_GetRequest(WOLFSSL *ssl,
unsigned char type, void** data);
WOLFSSL_API int wolfSSL_SNI_GetFromBuffer(
const unsigned char* clientHello, unsigned int helloSz,
unsigned char type, unsigned char* sni, unsigned int* inOutSz);
@@ -1463,4 +1467,3 @@ WOLFSSL_API int wolfSSL_accept_ex(WOLFSSL*, HandShakeCallBack, TimeoutCallBack,
#endif /* WOLFSSL_SSL_H */