From e121d01206f271b33298738f3863c69a465cfd2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moise=CC=81s=20Guimara=CC=83es?= Date: Wed, 1 Jul 2015 12:44:42 -0300 Subject: [PATCH 1/2] 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(). --- src/tls.c | 252 +++++++++++++++++++++++++++++++------------------- wolfssl/ssl.h | 23 +++-- 2 files changed, 172 insertions(+), 103 deletions(-) diff --git a/src/tls.c b/src/tls.c index 3e90df8ff..e095f1756 100644 --- a/src/tls.c +++ b/src/tls.c @@ -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 */ - diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 2c10f895e..f281c89e6 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -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 */ - From ca01cebd284f1121106f60f3152b12a4cd24e7e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moise=CC=81s=20Guimara=CC=83es?= Date: Wed, 1 Jul 2015 19:09:46 -0300 Subject: [PATCH 2/2] adds SNI abort option to turn SNI mandatory for WebSocket (RFC6455 page 17). @see WOLFSSL_SNI_ABORT_ON_ABSENCE and the xxxSNI_SetOptions() functions for further details. --- src/internal.c | 3 + src/tls.c | 62 +++++++- tests/api.c | 346 +++++++++++++++++++++++--------------------- wolfssl/error-ssl.h | 3 +- wolfssl/ssl.h | 5 +- 5 files changed, 248 insertions(+), 171 deletions(-) diff --git a/src/internal.c b/src/internal.c index 75d85b130..49621ec85 100644 --- a/src/internal.c +++ b/src/internal.c @@ -8030,6 +8030,9 @@ const char* wolfSSL_ERR_reason_error_string(unsigned long e) case DH_KEY_SIZE_E: return "DH key too small Error"; + case SNI_ABSENT_ERROR: + return "No Server Name Indication extension Error"; + default : return "unknown error number"; } diff --git a/src/tls.c b/src/tls.c index e095f1756..68f63f9cc 100644 --- a/src/tls.c +++ b/src/tls.c @@ -1072,6 +1072,49 @@ static int TLSX_SNI_Parse(WOLFSSL* ssl, byte* input, word16 length, return 0; } +static int TLSX_SNI_VerifyParse(WOLFSSL* ssl, byte isRequest) +{ + if (isRequest) { + #ifndef NO_WOLFSSL_SERVER + TLSX* ctx_ext = TLSX_Find(ssl->ctx->extensions, SERVER_NAME_INDICATION); + TLSX* ssl_ext = TLSX_Find(ssl->extensions, SERVER_NAME_INDICATION); + SNI* ctx_sni = ctx_ext ? ctx_ext->data : NULL; + SNI* ssl_sni = ssl_ext ? ssl_ext->data : NULL; + SNI* sni = NULL; + + for (; ctx_sni; ctx_sni = ctx_sni->next) { + if (ctx_sni->options & WOLFSSL_SNI_ABORT_ON_ABSENCE) { + sni = TLSX_SNI_Find(ssl_sni, ctx_sni->type); + + if (sni) { + if (sni->status != WOLFSSL_SNI_NO_MATCH) + continue; + + /* if ssl level overrides ctx level, it is ok. */ + if ((sni->options & WOLFSSL_SNI_ABORT_ON_ABSENCE) == 0) + continue; + } + + SendAlert(ssl, alert_fatal, handshake_failure); + return SNI_ABSENT_ERROR; + } + } + + for (; ssl_sni; ssl_sni = ssl_sni->next) { + if (ssl_sni->options & WOLFSSL_SNI_ABORT_ON_ABSENCE) { + if (ssl_sni->status != WOLFSSL_SNI_NO_MATCH) + continue; + + SendAlert(ssl, alert_fatal, handshake_failure); + return SNI_ABSENT_ERROR; + } + } + #endif /* NO_WOLFSSL_SERVER */ + } + + return 0; +} + int TLSX_UseSNI(TLSX** extensions, byte type, const void* data, word16 size) { TLSX* extension = TLSX_Find(*extensions, SERVER_NAME_INDICATION); @@ -1295,17 +1338,19 @@ int TLSX_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz, #endif -#define SNI_FREE_ALL TLSX_SNI_FreeAll -#define SNI_GET_SIZE TLSX_SNI_GetSize -#define SNI_WRITE TLSX_SNI_Write -#define SNI_PARSE TLSX_SNI_Parse +#define SNI_FREE_ALL TLSX_SNI_FreeAll +#define SNI_GET_SIZE TLSX_SNI_GetSize +#define SNI_WRITE TLSX_SNI_Write +#define SNI_PARSE TLSX_SNI_Parse +#define SNI_VERIFY_PARSE TLSX_SNI_VerifyParse #else #define SNI_FREE_ALL(list) -#define SNI_GET_SIZE(list) 0 -#define SNI_WRITE(a, b) 0 -#define SNI_PARSE(a, b, c, d) 0 +#define SNI_GET_SIZE(list) 0 +#define SNI_WRITE(a, b) 0 +#define SNI_PARSE(a, b, c, d) 0 +#define SNI_VERIFY_PARSE(a, b) 0 #endif /* HAVE_SNI */ @@ -2386,6 +2431,9 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest, offset += size; } + if (ret == 0) + ret = SNI_VERIFY_PARSE(ssl, isRequest); + return ret; } diff --git a/tests/api.c b/tests/api.c index 08e70d4ae..02d9cd9b6 100644 --- a/tests/api.c +++ b/tests/api.c @@ -134,9 +134,9 @@ static void test_wolfSSL_Method_Allocators(void) static void test_wolfSSL_CTX_new(WOLFSSL_METHOD *method) { WOLFSSL_CTX *ctx; - + AssertNull(ctx = wolfSSL_CTX_new(NULL)); - + AssertNotNull(method); AssertNotNull(ctx = wolfSSL_CTX_new(method)); @@ -152,10 +152,10 @@ static void test_wolfSSL_CTX_use_certificate_file(void) AssertNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); /* invalid context */ - AssertFalse(wolfSSL_CTX_use_certificate_file(NULL, svrCert, + AssertFalse(wolfSSL_CTX_use_certificate_file(NULL, svrCert, SSL_FILETYPE_PEM)); /* invalid cert file */ - AssertFalse(wolfSSL_CTX_use_certificate_file(ctx, bogusFile, + AssertFalse(wolfSSL_CTX_use_certificate_file(ctx, bogusFile, SSL_FILETYPE_PEM)); /* invalid cert type */ AssertFalse(wolfSSL_CTX_use_certificate_file(ctx, svrCert, 9999)); @@ -181,10 +181,10 @@ static void test_wolfSSL_CTX_use_PrivateKey_file(void) AssertNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); /* invalid context */ - AssertFalse(wolfSSL_CTX_use_PrivateKey_file(NULL, svrKey, + AssertFalse(wolfSSL_CTX_use_PrivateKey_file(NULL, svrKey, SSL_FILETYPE_PEM)); /* invalid key file */ - AssertFalse(wolfSSL_CTX_use_PrivateKey_file(ctx, bogusFile, + AssertFalse(wolfSSL_CTX_use_PrivateKey_file(ctx, bogusFile, SSL_FILETYPE_PEM)); /* invalid key type */ AssertFalse(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKey, 9999)); @@ -209,7 +209,7 @@ static void test_wolfSSL_CTX_load_verify_locations(void) WOLFSSL_CTX *ctx; AssertNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); - + /* invalid context */ AssertFalse(wolfSSL_CTX_load_verify_locations(NULL, caCert, 0)); @@ -272,18 +272,18 @@ static void test_client_wolfSSL_new(void) AssertNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); AssertTrue(wolfSSL_CTX_load_verify_locations(ctx, caCert, 0)); - + /* invalid context */ AssertNull(ssl = wolfSSL_new(NULL)); /* success */ AssertNotNull(ssl = wolfSSL_new(ctx_nocert)); wolfSSL_free(ssl); - + /* success */ AssertNotNull(ssl = wolfSSL_new(ctx)); wolfSSL_free(ssl); - + wolfSSL_CTX_free(ctx); wolfSSL_CTX_free(ctx_nocert); #endif @@ -353,7 +353,7 @@ static THREAD_RETURN WOLFSSL_THREAD test_server_nofail(void* args) "Please run from wolfSSL home dir");*/ goto done; } - + ssl = wolfSSL_new(ctx); tcp_accept(&sockfd, &clientfd, (func_args*)args, port, 0, 0, 0); CloseSocket(sockfd); @@ -382,7 +382,7 @@ static THREAD_RETURN WOLFSSL_THREAD test_server_nofail(void* args) input[idx] = 0; printf("Client message: %s\n", input); } - + if (wolfSSL_write(ssl, msg, sizeof(msg)) != sizeof(msg)) { /*err_sys("SSL_write failed");*/ @@ -401,7 +401,7 @@ done: wolfSSL_shutdown(ssl); wolfSSL_free(ssl); wolfSSL_CTX_free(ctx); - + CloseSocket(clientfd); ((func_args*)args)->return_code = TEST_SUCCESS; @@ -494,7 +494,7 @@ static void test_client_nofail(void* args) done2: wolfSSL_free(ssl); wolfSSL_CTX_free(ctx); - + CloseSocket(sockfd); ((func_args*)args)->return_code = TEST_SUCCESS; @@ -720,10 +720,10 @@ static void test_wolfSSL_read_write(void) StartTCP(); InitTcpReady(&ready); - + server_args.signal = &ready; client_args.signal = &ready; - + start_thread(test_server_nofail, &server_args, &serverThread); wait_tcp_ready(&server_args); test_client_nofail(&client_args); @@ -746,68 +746,106 @@ static void test_wolfSSL_read_write(void) *----------------------------------------------------------------------------*/ #ifdef HAVE_SNI +static void test_wolfSSL_UseSNI_params(void) +{ + WOLFSSL_CTX *ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()); + WOLFSSL *ssl = wolfSSL_new(ctx); + + AssertNotNull(ctx); + AssertNotNull(ssl); + + /* invalid [ctx|ssl] */ + AssertIntNE(SSL_SUCCESS, wolfSSL_CTX_UseSNI(NULL, 0, "ctx", 3)); + AssertIntNE(SSL_SUCCESS, wolfSSL_UseSNI( NULL, 0, "ssl", 3)); + /* invalid type */ + AssertIntNE(SSL_SUCCESS, wolfSSL_CTX_UseSNI(ctx, -1, "ctx", 3)); + AssertIntNE(SSL_SUCCESS, wolfSSL_UseSNI( ssl, -1, "ssl", 3)); + /* invalid data */ + AssertIntNE(SSL_SUCCESS, wolfSSL_CTX_UseSNI(ctx, 0, NULL, 3)); + AssertIntNE(SSL_SUCCESS, wolfSSL_UseSNI( ssl, 0, NULL, 3)); + /* success case */ + AssertIntEQ(SSL_SUCCESS, wolfSSL_CTX_UseSNI(ctx, 0, "ctx", 3)); + AssertIntEQ(SSL_SUCCESS, wolfSSL_UseSNI( ssl, 0, "ssl", 3)); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +} + +/* BEGIN of connection tests callbacks */ static void use_SNI_at_ctx(WOLFSSL_CTX* ctx) { - byte type = WOLFSSL_SNI_HOST_NAME; - char name[] = "www.yassl.com"; - AssertIntEQ(SSL_SUCCESS, - wolfSSL_CTX_UseSNI(ctx, type, (void *) name, XSTRLEN(name))); + wolfSSL_CTX_UseSNI(ctx, WOLFSSL_SNI_HOST_NAME, "www.wolfssl.com", 15)); } static void use_SNI_at_ssl(WOLFSSL* ssl) { - byte type = WOLFSSL_SNI_HOST_NAME; - char name[] = "www.yassl.com"; - AssertIntEQ(SSL_SUCCESS, - wolfSSL_UseSNI(ssl, type, (void *) name, XSTRLEN(name))); + wolfSSL_UseSNI(ssl, WOLFSSL_SNI_HOST_NAME, "www.wolfssl.com", 15)); } static void different_SNI_at_ssl(WOLFSSL* ssl) { - byte type = WOLFSSL_SNI_HOST_NAME; - char name[] = "ww2.yassl.com"; - AssertIntEQ(SSL_SUCCESS, - wolfSSL_UseSNI(ssl, type, (void *) name, XSTRLEN(name))); + wolfSSL_UseSNI(ssl, WOLFSSL_SNI_HOST_NAME, "ww2.wolfssl.com", 15)); } static void use_SNI_WITH_CONTINUE_at_ssl(WOLFSSL* ssl) { - byte type = WOLFSSL_SNI_HOST_NAME; - use_SNI_at_ssl(ssl); - - wolfSSL_SNI_SetOptions(ssl, type, WOLFSSL_SNI_CONTINUE_ON_MISMATCH); + wolfSSL_SNI_SetOptions(ssl, WOLFSSL_SNI_HOST_NAME, + WOLFSSL_SNI_CONTINUE_ON_MISMATCH); } static void use_SNI_WITH_FAKE_ANSWER_at_ssl(WOLFSSL* ssl) { - byte type = WOLFSSL_SNI_HOST_NAME; - use_SNI_at_ssl(ssl); - - wolfSSL_SNI_SetOptions(ssl, type, WOLFSSL_SNI_ANSWER_ON_MISMATCH); + wolfSSL_SNI_SetOptions(ssl, WOLFSSL_SNI_HOST_NAME, + WOLFSSL_SNI_ANSWER_ON_MISMATCH); } -static void verify_SNI_abort_on_client(WOLFSSL* ssl) +static void use_MANDATORY_SNI_at_ctx(WOLFSSL_CTX* ctx) +{ + use_SNI_at_ctx(ctx); + wolfSSL_CTX_SNI_SetOptions(ctx, WOLFSSL_SNI_HOST_NAME, + WOLFSSL_SNI_ABORT_ON_ABSENCE); +} + +static void use_MANDATORY_SNI_at_ssl(WOLFSSL* ssl) +{ + use_SNI_at_ssl(ssl); + wolfSSL_SNI_SetOptions(ssl, WOLFSSL_SNI_HOST_NAME, + WOLFSSL_SNI_ABORT_ON_ABSENCE); +} + +static void use_PSEUDO_MANDATORY_SNI_at_ctx(WOLFSSL_CTX* ctx) +{ + use_SNI_at_ctx(ctx); + wolfSSL_CTX_SNI_SetOptions(ctx, WOLFSSL_SNI_HOST_NAME, + WOLFSSL_SNI_ANSWER_ON_MISMATCH | WOLFSSL_SNI_ABORT_ON_ABSENCE); +} + +static void verify_FATAL_ERROR_on_client(WOLFSSL* ssl) { AssertIntEQ(FATAL_ERROR, wolfSSL_get_error(ssl, 0)); } -static void verify_SNI_abort_on_server(WOLFSSL* ssl) +static void verify_UNKNOWN_SNI_on_server(WOLFSSL* ssl) { AssertIntEQ(UNKNOWN_SNI_HOST_NAME_E, wolfSSL_get_error(ssl, 0)); } +static void verify_SNI_ABSENT_on_server(WOLFSSL* ssl) +{ + AssertIntEQ(SNI_ABSENT_ERROR, wolfSSL_get_error(ssl, 0)); +} + static void verify_SNI_no_matching(WOLFSSL* ssl) { - byte type = WOLFSSL_SNI_HOST_NAME; + byte type = WOLFSSL_SNI_HOST_NAME; char* request = (char*) &type; /* to be overwriten */ AssertIntEQ(WOLFSSL_SNI_NO_MATCH, wolfSSL_SNI_Status(ssl, type)); - AssertNotNull(request); AssertIntEQ(0, wolfSSL_SNI_GetRequest(ssl, type, (void**) &request)); AssertNull(request); @@ -815,30 +853,118 @@ static void verify_SNI_no_matching(WOLFSSL* ssl) static void verify_SNI_real_matching(WOLFSSL* ssl) { - byte type = WOLFSSL_SNI_HOST_NAME; - char* request = NULL; - char name[] = "www.yassl.com"; - word16 length = XSTRLEN(name); + byte type = WOLFSSL_SNI_HOST_NAME; + char* request = NULL; AssertIntEQ(WOLFSSL_SNI_REAL_MATCH, wolfSSL_SNI_Status(ssl, type)); - - AssertIntEQ(length, wolfSSL_SNI_GetRequest(ssl, type, (void**) &request)); + AssertIntEQ(15, wolfSSL_SNI_GetRequest(ssl, type, (void**) &request)); AssertNotNull(request); - AssertStrEQ(name, request); + AssertStrEQ("www.wolfssl.com", request); } static void verify_SNI_fake_matching(WOLFSSL* ssl) { - byte type = WOLFSSL_SNI_HOST_NAME; - char* request = NULL; - char name[] = "ww2.yassl.com"; - word16 length = XSTRLEN(name); + byte type = WOLFSSL_SNI_HOST_NAME; + char* request = NULL; AssertIntEQ(WOLFSSL_SNI_FAKE_MATCH, wolfSSL_SNI_Status(ssl, type)); - - AssertIntEQ(length, wolfSSL_SNI_GetRequest(ssl, type, (void**) &request)); + AssertIntEQ(15, wolfSSL_SNI_GetRequest(ssl, type, (void**) &request)); AssertNotNull(request); - AssertStrEQ(name, request); + AssertStrEQ("ww2.wolfssl.com", request); +} +/* END of connection tests callbacks */ + +/* connection test runner */ +static void test_wolfSSL_client_server(callback_functions* client_callbacks, + callback_functions* server_callbacks) +{ +#ifdef HAVE_IO_TESTS_DEPENDENCIES + tcp_ready ready; + func_args client_args; + func_args server_args; + THREAD_TYPE serverThread; + + StartTCP(); + + client_args.callbacks = client_callbacks; + server_args.callbacks = server_callbacks; + +#ifdef WOLFSSL_TIRTOS + fdOpenSession(Task_self()); +#endif + + /* RUN Server side */ + InitTcpReady(&ready); + server_args.signal = &ready; + client_args.signal = &ready; + start_thread(run_wolfssl_server, &server_args, &serverThread); + wait_tcp_ready(&server_args); + + /* RUN Client side */ + run_wolfssl_client(&client_args); + join_thread(serverThread); + + FreeTcpReady(&ready); +#ifdef WOLFSSL_TIRTOS + fdCloseSession(Task_self()); +#endif + +#else + (void)client_callbacks; + (void)server_callbacks; +#endif +} + +static void test_wolfSSL_UseSNI_connection(void) +{ + unsigned long i; + callback_functions callbacks[] = { + /* success case at ctx */ + {0, use_SNI_at_ctx, 0, 0}, + {0, use_SNI_at_ctx, 0, verify_SNI_real_matching}, + + /* success case at ssl */ + {0, 0, use_SNI_at_ssl, 0}, + {0, 0, use_SNI_at_ssl, verify_SNI_real_matching}, + + /* default missmatch behavior */ + {0, 0, different_SNI_at_ssl, verify_FATAL_ERROR_on_client}, + {0, 0, use_SNI_at_ssl, verify_UNKNOWN_SNI_on_server}, + + /* continue on missmatch */ + {0, 0, different_SNI_at_ssl, 0}, + {0, 0, use_SNI_WITH_CONTINUE_at_ssl, verify_SNI_no_matching}, + + /* fake answer on missmatch */ + {0, 0, different_SNI_at_ssl, 0}, + {0, 0, use_SNI_WITH_FAKE_ANSWER_at_ssl, verify_SNI_fake_matching}, + + /* sni abort - success */ + {0, use_SNI_at_ctx, 0, 0}, + {0, use_MANDATORY_SNI_at_ctx, 0, verify_SNI_real_matching}, + + /* sni abort - abort when absent (ctx) */ + {0, 0, 0, verify_FATAL_ERROR_on_client}, + {0, use_MANDATORY_SNI_at_ctx, 0, verify_SNI_ABSENT_on_server}, + + /* sni abort - abort when absent (ssl) */ + {0, 0, 0, verify_FATAL_ERROR_on_client}, + {0, 0, use_MANDATORY_SNI_at_ssl, verify_SNI_ABSENT_on_server}, + + /* sni abort - success when overwriten */ + {0, 0, 0, 0}, + {0, use_MANDATORY_SNI_at_ctx, use_SNI_at_ssl, verify_SNI_no_matching}, + + /* sni abort - success when allowing missmatches */ + {0, 0, different_SNI_at_ssl, 0}, + {0, use_PSEUDO_MANDATORY_SNI_at_ctx, 0, verify_SNI_fake_matching}, + }; + + for (i = 0; i < sizeof(callbacks) / sizeof(callback_functions); i += 2) { + callbacks[i ].method = wolfSSLv23_client_method; + callbacks[i + 1].method = wolfSSLv23_server_method; + test_wolfSSL_client_server(&callbacks[i], &callbacks[i + 1]); + } } static void test_wolfSSL_SNI_GetFromBuffer(void) @@ -904,7 +1030,7 @@ static void test_wolfSSL_SNI_GetFromBuffer(void) 0x01, 0x04, 0x03, 0x05, 0x03, 0x02, 0x03, 0x04, 0x02, 0x02, 0x02, 0x00, 0x12, 0x00, 0x00 }; - + byte buffer5[] = { /* SSL v2.0 client hello */ 0x00, 0x2b, 0x01, 0x03, 0x01, 0x00, 0x09, 0x00, 0x00, /* dummy bytes bellow, just to pass size check */ @@ -933,7 +1059,7 @@ static void test_wolfSSL_SNI_GetFromBuffer(void) 0, result, &length)); buffer[1] = 0x03; - AssertIntEQ(SNI_UNSUPPORTED, wolfSSL_SNI_GetFromBuffer(buffer, + AssertIntEQ(SNI_UNSUPPORTED, wolfSSL_SNI_GetFromBuffer(buffer, sizeof(buffer), 0, result, &length)); buffer[2] = 0x03; @@ -964,121 +1090,19 @@ static void test_wolfSSL_SNI_GetFromBuffer(void) buffer5[2] = 0x01; buffer5[6] = 0x08; AssertIntEQ(BUFFER_ERROR, wolfSSL_SNI_GetFromBuffer(buffer5, sizeof(buffer5), 0, result, &length)); - + buffer5[6] = 0x09; buffer5[8] = 0x01; AssertIntEQ(BUFFER_ERROR, wolfSSL_SNI_GetFromBuffer(buffer5, sizeof(buffer5), 0, result, &length)); } -static void test_wolfSSL_client_server(callback_functions* client_callbacks, - callback_functions* server_callbacks) -{ -#ifdef HAVE_IO_TESTS_DEPENDENCIES - tcp_ready ready; - func_args client_args; - func_args server_args; - THREAD_TYPE serverThread; - - StartTCP(); - - client_args.callbacks = client_callbacks; - server_args.callbacks = server_callbacks; - -#ifdef WOLFSSL_TIRTOS - fdOpenSession(Task_self()); -#endif - - /* RUN Server side */ - InitTcpReady(&ready); - server_args.signal = &ready; - client_args.signal = &ready; - start_thread(run_wolfssl_server, &server_args, &serverThread); - wait_tcp_ready(&server_args); - - /* RUN Client side */ - run_wolfssl_client(&client_args); - join_thread(serverThread); - - FreeTcpReady(&ready); -#ifdef WOLFSSL_TIRTOS - fdCloseSession(Task_self()); -#endif - -#else - (void)client_callbacks; - (void)server_callbacks; -#endif -} - #endif /* HAVE_SNI */ static void test_wolfSSL_UseSNI(void) { #ifdef HAVE_SNI - callback_functions client_callbacks = {wolfSSLv23_client_method, 0, 0, 0}; - callback_functions server_callbacks = {wolfSSLv23_server_method, 0, 0, 0}; - - WOLFSSL_CTX *ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()); - WOLFSSL *ssl = wolfSSL_new(ctx); - - AssertNotNull(ctx); - AssertNotNull(ssl); - - /* error cases */ - AssertIntNE(SSL_SUCCESS, - wolfSSL_CTX_UseSNI(NULL, 0, (void *) "ctx", XSTRLEN("ctx"))); - AssertIntNE(SSL_SUCCESS, - wolfSSL_UseSNI( NULL, 0, (void *) "ssl", XSTRLEN("ssl"))); - AssertIntNE(SSL_SUCCESS, - wolfSSL_CTX_UseSNI(ctx, -1, (void *) "ctx", XSTRLEN("ctx"))); - AssertIntNE(SSL_SUCCESS, - wolfSSL_UseSNI( ssl, -1, (void *) "ssl", XSTRLEN("ssl"))); - AssertIntNE(SSL_SUCCESS, - wolfSSL_CTX_UseSNI(ctx, 0, (void *) NULL, XSTRLEN("ctx"))); - AssertIntNE(SSL_SUCCESS, - wolfSSL_UseSNI( ssl, 0, (void *) NULL, XSTRLEN("ssl"))); - - /* success case */ - AssertIntEQ(SSL_SUCCESS, - wolfSSL_CTX_UseSNI(ctx, 0, (void *) "ctx", XSTRLEN("ctx"))); - AssertIntEQ(SSL_SUCCESS, - wolfSSL_UseSNI( ssl, 0, (void *) "ssl", XSTRLEN("ssl"))); - - wolfSSL_free(ssl); - wolfSSL_CTX_free(ctx); - - /* Testing success case at ctx */ - client_callbacks.ctx_ready = server_callbacks.ctx_ready = use_SNI_at_ctx; - server_callbacks.on_result = verify_SNI_real_matching; - - test_wolfSSL_client_server(&client_callbacks, &server_callbacks); - - /* Testing success case at ssl */ - client_callbacks.ctx_ready = server_callbacks.ctx_ready = NULL; - client_callbacks.ssl_ready = server_callbacks.ssl_ready = use_SNI_at_ssl; - - test_wolfSSL_client_server(&client_callbacks, &server_callbacks); - - /* Testing default mismatch behaviour */ - client_callbacks.ssl_ready = different_SNI_at_ssl; - client_callbacks.on_result = verify_SNI_abort_on_client; - server_callbacks.on_result = verify_SNI_abort_on_server; - - test_wolfSSL_client_server(&client_callbacks, &server_callbacks); - client_callbacks.on_result = NULL; - - /* Testing continue on mismatch */ - client_callbacks.ssl_ready = different_SNI_at_ssl; - server_callbacks.ssl_ready = use_SNI_WITH_CONTINUE_at_ssl; - server_callbacks.on_result = verify_SNI_no_matching; - - test_wolfSSL_client_server(&client_callbacks, &server_callbacks); - - /* Testing fake answer on mismatch */ - server_callbacks.ssl_ready = use_SNI_WITH_FAKE_ANSWER_at_ssl; - server_callbacks.on_result = verify_SNI_fake_matching; - - test_wolfSSL_client_server(&client_callbacks, &server_callbacks); + test_wolfSSL_UseSNI_params(); + test_wolfSSL_UseSNI_connection(); test_wolfSSL_SNI_GetFromBuffer(); #endif diff --git a/wolfssl/error-ssl.h b/wolfssl/error-ssl.h index f151c3fb5..23e5f4d37 100644 --- a/wolfssl/error-ssl.h +++ b/wolfssl/error-ssl.h @@ -134,6 +134,7 @@ enum wolfSSL_ErrorCodes { BAD_TICKET_ENCRYPT = -400, /* Bad user ticket encrypt */ DH_KEY_SIZE_E = -401, /* DH Key too small */ + SNI_ABSENT_ERROR = -402, /* No SNI request. */ /* add strings to SetErrorString !!!!! */ @@ -165,5 +166,3 @@ void SetErrorString(int err, char* buff); #endif /* wolfSSL_ERROR_H */ - - diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index f281c89e6..cbb9f8314 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -1283,7 +1283,10 @@ enum { /* 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_SNI_ANSWER_ON_MISMATCH = 0x02, + + /* Abort the handshake if the client didn't send a SNI request. */ + WOLFSSL_SNI_ABORT_ON_ABSENCE = 0x04, }; WOLFSSL_API void wolfSSL_SNI_SetOptions(WOLFSSL* ssl, unsigned char type,