Merge branch 'master' into ssh

This commit is contained in:
toddouska
2015-07-01 16:37:33 -07:00
5 changed files with 419 additions and 273 deletions

View File

@@ -8030,6 +8030,9 @@ const char* wolfSSL_ERR_reason_error_string(unsigned long e)
case DH_KEY_SIZE_E: case DH_KEY_SIZE_E:
return "DH key too small Error"; return "DH key too small Error";
case SNI_ABSENT_ERROR:
return "No Server Name Indication extension Error";
default : default :
return "unknown error number"; return "unknown error number";
} }

314
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 #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 #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) static INLINE word16 TLSX_ToSemaphore(word16 type)
{ {
switch (type) { switch (type) {
case SECURE_RENEGOTIATION:
case SECURE_RENEGOTIATION: /* 0xFF01 */
return 63; return 63;
default: default:
@@ -739,30 +762,45 @@ static INLINE word16 TLSX_ToSemaphore(word16 type)
return type; return type;
} }
/** Checks if a specific light (tls extension) is not set in the semaphore. */
#define IS_OFF(semaphore, light) \ #define IS_OFF(semaphore, light) \
((semaphore)[(light) / 8] ^ (byte) (0x01 << ((light) % 8))) ((semaphore)[(light) / 8] ^ (byte) (0x01 << ((light) % 8)))
/** Turn on a specific light (tls extension) in the semaphore. */
#define TURN_ON(semaphore, light) \ #define TURN_ON(semaphore, light) \
((semaphore)[(light) / 8] |= (byte) (0x01 << ((light) % 8))) ((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) 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) if (extension == NULL)
return MEMORY_E; return MEMORY_E;
extension->type = type; /* pushes the new extension on the list. */
extension->data = data;
extension->resp = 0;
extension->next = *list; extension->next = *list;
*list = extension; *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 { do {
if (extension->next && extension->next->type == type) { if (extension->next && extension->next->type == type) {
TLSX *next = extension->next; TLSX *next = extension->next;
@@ -781,9 +819,9 @@ static int TLSX_Push(TLSX** list, TLSX_Type type, void* data)
return 0; return 0;
} }
#ifndef NO_WOLFSSL_SERVER #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);
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 #endif
/* SNI - Server Name Indication */ /* Server Name Indication */
#ifdef HAVE_SNI #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) static void TLSX_SNI_Free(SNI* sni)
{ {
if (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) static void TLSX_SNI_FreeAll(SNI* list)
{ {
SNI* sni; 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) /** Tells the buffered size of the SNI objects in a list. */
{
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;
}
static word16 TLSX_SNI_GetSize(SNI* list) static word16 TLSX_SNI_GetSize(SNI* list)
{ {
SNI* sni; SNI* sni;
@@ -885,6 +919,7 @@ static word16 TLSX_SNI_GetSize(SNI* list)
return length; return length;
} }
/** Writes the SNI objects of a list in a buffer. */
static word16 TLSX_SNI_Write(SNI* list, byte* output) static word16 TLSX_SNI_Write(SNI* list, byte* output)
{ {
SNI* sni; SNI* sni;
@@ -915,6 +950,7 @@ static word16 TLSX_SNI_Write(SNI* list, byte* output)
return offset; return offset;
} }
/** Finds a SNI object in the provided list. */
static SNI* TLSX_SNI_Find(SNI *list, byte type) static SNI* TLSX_SNI_Find(SNI *list, byte type)
{ {
SNI *sni = list; SNI *sni = list;
@@ -926,17 +962,18 @@ static SNI* TLSX_SNI_Find(SNI *list, byte type)
} }
#ifndef NO_WOLFSSL_SERVER #ifndef NO_WOLFSSL_SERVER
/** Sets the status of a SNI object. */
static void TLSX_SNI_SetStatus(TLSX* extensions, byte type, byte status) static void TLSX_SNI_SetStatus(TLSX* extensions, byte type, byte status)
{ {
TLSX* extension = TLSX_Find(extensions, SERVER_NAME_INDICATION); TLSX* extension = TLSX_Find(extensions, SERVER_NAME_INDICATION);
SNI* sni = TLSX_SNI_Find(extension ? extension->data : NULL, type); SNI* sni = TLSX_SNI_Find(extension ? extension->data : NULL, type);
if (sni) { if (sni)
sni->status = status; sni->status = status;
WOLFSSL_MSG("SNI did match!");
}
} }
/** Gets the status of a SNI object. */
byte TLSX_SNI_Status(TLSX* extensions, byte type) byte TLSX_SNI_Status(TLSX* extensions, byte type)
{ {
TLSX* extension = TLSX_Find(extensions, SERVER_NAME_INDICATION); TLSX* extension = TLSX_Find(extensions, SERVER_NAME_INDICATION);
@@ -947,8 +984,10 @@ byte TLSX_SNI_Status(TLSX* extensions, byte type)
return 0; return 0;
} }
#endif
#endif /* NO_WOLFSSL_SERVER */
/** Parses a buffer of SNI extensions. */
static int TLSX_SNI_Parse(WOLFSSL* ssl, byte* input, word16 length, static int TLSX_SNI_Parse(WOLFSSL* ssl, byte* input, word16 length,
byte isRequest) 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); extension = TLSX_Find(ssl->ctx->extensions, SERVER_NAME_INDICATION);
if (!extension || !extension->data) if (!extension || !extension->data)
return isRequest ? 0 : BUFFER_ERROR; /* not using SNI OR unexpected return isRequest ? 0 /* not using SNI. */
SNI response from server. */ : BUFFER_ERROR; /* unexpected SNI response. */
if (!isRequest) if (!isRequest)
return length ? BUFFER_ERROR : 0; /* SNI response must be empty! return length ? BUFFER_ERROR /* SNI response MUST be empty. */
Nothing else to do. */ : 0; /* nothing else to do. */
#ifndef NO_WOLFSSL_SERVER #ifndef NO_WOLFSSL_SERVER
@@ -995,9 +1034,8 @@ static int TLSX_SNI_Parse(WOLFSSL* ssl, byte* input, word16 length,
if (offset + size > length) if (offset + size > length)
return BUFFER_ERROR; return BUFFER_ERROR;
if (!(sni = TLSX_SNI_Find((SNI*)extension->data, type))) { if (!(sni = TLSX_SNI_Find((SNI*)extension->data, type)))
continue; /* not using this SNI type */ continue; /* not using this type of SNI. */
}
switch(type) { switch(type) {
case WOLFSSL_SNI_HOST_NAME: { 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, int r = TLSX_UseSNI(&ssl->extensions,
type, input + offset, size); 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, 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)) { } else if (!(sni->options & WOLFSSL_SNI_CONTINUE_ON_MISMATCH)) {
SendAlert(ssl, alert_fatal, unrecognized_name); SendAlert(ssl, alert_fatal, unrecognized_name);
@@ -1022,8 +1065,6 @@ static int TLSX_SNI_Parse(WOLFSSL* ssl, byte* input, word16 length,
break; break;
} }
} }
TLSX_SetResponse(ssl, SERVER_NAME_INDICATION);
} }
#endif #endif
@@ -1031,21 +1072,63 @@ static int TLSX_SNI_Parse(WOLFSSL* ssl, byte* input, word16 length,
return 0; 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) int TLSX_UseSNI(TLSX** extensions, byte type, const void* data, word16 size)
{ {
TLSX* extension = TLSX_Find(*extensions, SERVER_NAME_INDICATION); TLSX* extension = TLSX_Find(*extensions, SERVER_NAME_INDICATION);
SNI* sni = NULL; SNI* sni = NULL;
int ret = 0;
if (extensions == NULL || data == NULL) if (extensions == NULL || data == NULL)
return BAD_FUNC_ARG; return BAD_FUNC_ARG;
if ((ret = TLSX_SNI_Append(&sni, type, data, size)) != 0) if ((sni = TLSX_SNI_New(type, data, size)) == NULL)
return ret; return MEMORY_E;
if (!extension) { if (!extension) {
if ((ret = TLSX_Push(extensions, SERVER_NAME_INDICATION, (void*)sni)) int ret = TLSX_Push(extensions, SERVER_NAME_INDICATION, (void*)sni);
!= 0) { if (ret != 0) {
TLSX_SNI_Free(sni); TLSX_SNI_Free(sni);
return ret; return ret;
} }
@@ -1055,7 +1138,7 @@ int TLSX_UseSNI(TLSX** extensions, byte type, const void* data, word16 size)
sni->next = (SNI*)extension->data; sni->next = (SNI*)extension->data;
extension->data = (void*)sni; 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 { do {
if (sni->next && sni->next->type == type) { if (sni->next && sni->next->type == type) {
SNI *next = sni->next; SNI *next = sni->next;
@@ -1063,6 +1146,8 @@ int TLSX_UseSNI(TLSX** extensions, byte type, const void* data, word16 size)
sni->next = next->next; sni->next = next->next;
TLSX_SNI_Free(next); TLSX_SNI_Free(next);
/* there is no way to occur more than */
/* two SNIs of the same type. */
break; break;
} }
} while ((sni = sni->next)); } while ((sni = sni->next));
@@ -1072,6 +1157,8 @@ int TLSX_UseSNI(TLSX** extensions, byte type, const void* data, word16 size)
} }
#ifndef NO_WOLFSSL_SERVER #ifndef NO_WOLFSSL_SERVER
/** Tells the SNI requested by the client. */
word16 TLSX_SNI_GetRequest(TLSX* extensions, byte type, void** data) word16 TLSX_SNI_GetRequest(TLSX* extensions, byte type, void** data)
{ {
TLSX* extension = TLSX_Find(extensions, SERVER_NAME_INDICATION); TLSX* extension = TLSX_Find(extensions, SERVER_NAME_INDICATION);
@@ -1088,6 +1175,7 @@ word16 TLSX_SNI_GetRequest(TLSX* extensions, byte type, void** data)
return 0; return 0;
} }
/** Sets the options for a SNI object. */
void TLSX_SNI_SetOptions(TLSX* extensions, byte type, byte options) void TLSX_SNI_SetOptions(TLSX* extensions, byte type, byte options)
{ {
TLSX* extension = TLSX_Find(extensions, SERVER_NAME_INDICATION); TLSX* extension = TLSX_Find(extensions, SERVER_NAME_INDICATION);
@@ -1097,6 +1185,7 @@ void TLSX_SNI_SetOptions(TLSX* extensions, byte type, byte options)
sni->options = options; sni->options = options;
} }
/** Retrieves a SNI request from a client hello buffer. */
int TLSX_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz, int TLSX_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz,
byte type, byte* sni, word32* inOutSz) byte type, byte* sni, word32* inOutSz)
{ {
@@ -1114,19 +1203,19 @@ int TLSX_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz,
/* http://tools.ietf.org/html/rfc4346#appendix-E.1 */ /* http://tools.ietf.org/html/rfc4346#appendix-E.1 */
if ((enum HandShakeType) clientHello[++offset] == client_hello) { if ((enum HandShakeType) clientHello[++offset] == client_hello) {
offset += ENUM_LEN + VERSION_SZ; /* skip version */ offset += ENUM_LEN + VERSION_SZ; /* skip version */
ato16(clientHello + offset, &len16); ato16(clientHello + offset, &len16);
offset += OPAQUE16_LEN; offset += OPAQUE16_LEN;
if (len16 % 3) /* cipher_spec_length must be multiple of 3 */ if (len16 % 3) /* cipher_spec_length must be multiple of 3 */
return BUFFER_ERROR; return BUFFER_ERROR;
ato16(clientHello + offset, &len16); ato16(clientHello + offset, &len16);
offset += OPAQUE16_LEN; offset += OPAQUE16_LEN;
if (len16 != 0) /* session_id_length must be 0 */ if (len16 != 0) /* session_id_length must be 0 */
return BUFFER_ERROR; return BUFFER_ERROR;
return SNI_UNSUPPORTED; return SNI_UNSUPPORTED;
} }
@@ -1249,17 +1338,19 @@ int TLSX_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz,
#endif #endif
#define SNI_FREE_ALL TLSX_SNI_FreeAll #define SNI_FREE_ALL TLSX_SNI_FreeAll
#define SNI_GET_SIZE TLSX_SNI_GetSize #define SNI_GET_SIZE TLSX_SNI_GetSize
#define SNI_WRITE TLSX_SNI_Write #define SNI_WRITE TLSX_SNI_Write
#define SNI_PARSE TLSX_SNI_Parse #define SNI_PARSE TLSX_SNI_Parse
#define SNI_VERIFY_PARSE TLSX_SNI_VerifyParse
#else #else
#define SNI_FREE_ALL(list) #define SNI_FREE_ALL(list)
#define SNI_GET_SIZE(list) 0 #define SNI_GET_SIZE(list) 0
#define SNI_WRITE(a, b) 0 #define SNI_WRITE(a, b) 0
#define SNI_PARSE(a, b, c, d) 0 #define SNI_PARSE(a, b, c, d) 0
#define SNI_VERIFY_PARSE(a, b) 0
#endif /* HAVE_SNI */ #endif /* HAVE_SNI */
@@ -1433,7 +1524,7 @@ static void TLSX_EllipticCurve_ValidateRequest(WOLFSSL* ssl, byte* semaphore)
if (ssl->suites->suites[i] == ECC_BYTE) if (ssl->suites->suites[i] == ECC_BYTE)
return; return;
/* No elliptic curve suite found */ /* turns semaphore on to avoid sending this extension. */
TURN_ON(semaphore, TLSX_ToSemaphore(ELLIPTIC_CURVES)); TURN_ON(semaphore, TLSX_ToSemaphore(ELLIPTIC_CURVES));
} }
@@ -1956,7 +2047,7 @@ int TLSX_UseSessionTicket(TLSX** extensions, SessionTicket* ticket)
#endif /* HAVE_SESSION_TICKET */ #endif /* HAVE_SESSION_TICKET */
/** Finds an extension in the provided list. */
TLSX* TLSX_Find(TLSX* list, TLSX_Type type) TLSX* TLSX_Find(TLSX* list, TLSX_Type type)
{ {
TLSX* extension = list; TLSX* extension = list;
@@ -1967,6 +2058,7 @@ TLSX* TLSX_Find(TLSX* list, TLSX_Type type)
return extension; return extension;
} }
/** Releases all extensions in the provided list. */
void TLSX_FreeAll(TLSX* list) void TLSX_FreeAll(TLSX* list)
{ {
TLSX* extension; TLSX* extension;
@@ -1975,6 +2067,7 @@ void TLSX_FreeAll(TLSX* list)
list = extension->next; list = extension->next;
switch (extension->type) { switch (extension->type) {
case SERVER_NAME_INDICATION: case SERVER_NAME_INDICATION:
SNI_FREE_ALL((SNI*)extension->data); SNI_FREE_ALL((SNI*)extension->data);
break; break;
@@ -2004,10 +2097,12 @@ void TLSX_FreeAll(TLSX* list)
} }
} }
/** Checks if the tls extensions are supported based on the protocol version. */
int TLSX_SupportExtensions(WOLFSSL* ssl) { int TLSX_SupportExtensions(WOLFSSL* ssl) {
return ssl && (IsTLS(ssl) || ssl->version.major == DTLS_MAJOR); 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) static word16 TLSX_GetSize(TLSX* list, byte* semaphore, byte isRequest)
{ {
TLSX* extension; TLSX* extension;
@@ -2016,26 +2111,31 @@ static word16 TLSX_GetSize(TLSX* list, byte* semaphore, byte isRequest)
while ((extension = list)) { while ((extension = list)) {
list = extension->next; list = extension->next;
/* only extensions marked as response are sent back to the client. */
if (!isRequest && !extension->resp) if (!isRequest && !extension->resp)
continue; /* skip! */ continue; /* skip! */
/* ssl level extensions are expected to override ctx level ones. */
if (!IS_OFF(semaphore, TLSX_ToSemaphore(extension->type))) if (!IS_OFF(semaphore, TLSX_ToSemaphore(extension->type)))
continue; /* skip! */ continue; /* skip! */
/* type + data length */ /* extension type + extension data length. */
length += HELLO_EXT_TYPE_SZ + OPAQUE16_LEN; length += HELLO_EXT_TYPE_SZ + OPAQUE16_LEN;
switch (extension->type) { switch (extension->type) {
case SERVER_NAME_INDICATION: case SERVER_NAME_INDICATION:
/* SNI only sends the name on the request. */
if (isRequest) if (isRequest)
length += SNI_GET_SIZE(extension->data); length += SNI_GET_SIZE(extension->data);
break; break;
case MAX_FRAGMENT_LENGTH: case MAX_FRAGMENT_LENGTH:
length += MFL_GET_SIZE(extension->data); length += MFL_GET_SIZE(extension->data);
break; break;
case TRUNCATED_HMAC: case TRUNCATED_HMAC:
/* empty extension. */ /* always empty. */
break; break;
case ELLIPTIC_CURVES: case ELLIPTIC_CURVES:
@@ -2051,12 +2151,15 @@ static word16 TLSX_GetSize(TLSX* list, byte* semaphore, byte isRequest)
break; break;
} }
/* marks the extension as processed so ctx level */
/* extensions don't overlap with ssl level ones. */
TURN_ON(semaphore, TLSX_ToSemaphore(extension->type)); TURN_ON(semaphore, TLSX_ToSemaphore(extension->type));
} }
return length; return length;
} }
/** Writes the extensions of a list in a buffer. */
static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore, static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore,
byte isRequest) byte isRequest)
{ {
@@ -2067,18 +2170,20 @@ static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore,
while ((extension = list)) { while ((extension = list)) {
list = extension->next; list = extension->next;
/* only extensions marked as response are written in a response. */
if (!isRequest && !extension->resp) if (!isRequest && !extension->resp)
continue; /* skip! */ continue; /* skip! */
/* ssl level extensions are expected to override ctx level ones. */
if (!IS_OFF(semaphore, TLSX_ToSemaphore(extension->type))) if (!IS_OFF(semaphore, TLSX_ToSemaphore(extension->type)))
continue; /* skip! */ continue; /* skip! */
/* extension type */ /* writes extension type. */
c16toa(extension->type, output + offset); c16toa(extension->type, output + offset);
offset += HELLO_EXT_TYPE_SZ + OPAQUE16_LEN; offset += HELLO_EXT_TYPE_SZ + OPAQUE16_LEN;
length_offset = offset; length_offset = offset;
/* extension data should be written internally */ /* extension data should be written internally. */
switch (extension->type) { switch (extension->type) {
case SERVER_NAME_INDICATION: case SERVER_NAME_INDICATION:
if (isRequest) if (isRequest)
@@ -2090,7 +2195,7 @@ static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore,
break; break;
case TRUNCATED_HMAC: case TRUNCATED_HMAC:
/* empty extension. */ /* always empty. */
break; break;
case ELLIPTIC_CURVES: case ELLIPTIC_CURVES:
@@ -2108,9 +2213,11 @@ static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore,
break; break;
} }
/* writing extension data length */ /* writes extension data length. */
c16toa(offset - length_offset, output + length_offset - OPAQUE16_LEN); 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)); TURN_ON(semaphore, TLSX_ToSemaphore(extension->type));
} }
@@ -2119,6 +2226,7 @@ static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore,
#ifndef NO_WOLFSSL_CLIENT #ifndef NO_WOLFSSL_CLIENT
/** Tells the buffered size of extensions to be sent into the client hello. */
word16 TLSX_GetRequestSize(WOLFSSL* ssl) word16 TLSX_GetRequestSize(WOLFSSL* ssl)
{ {
word16 length = 0; word16 length = 0;
@@ -2140,11 +2248,12 @@ word16 TLSX_GetRequestSize(WOLFSSL* ssl)
} }
if (length) if (length)
length += OPAQUE16_LEN; /* for total length storage */ length += OPAQUE16_LEN; /* for total length storage. */
return length; return length;
} }
/** Writes the extensions to be sent into the client hello. */
word16 TLSX_WriteRequest(WOLFSSL* ssl, byte* output) word16 TLSX_WriteRequest(WOLFSSL* ssl, byte* output)
{ {
word16 offset = 0; word16 offset = 0;
@@ -2155,6 +2264,7 @@ word16 TLSX_WriteRequest(WOLFSSL* ssl, byte* output)
offset += OPAQUE16_LEN; /* extensions length */ offset += OPAQUE16_LEN; /* extensions length */
EC_VALIDATE_REQUEST(ssl, semaphore); EC_VALIDATE_REQUEST(ssl, semaphore);
STK_VALIDATE_REQUEST(ssl);
if (ssl->extensions) if (ssl->extensions)
offset += TLSX_Write(ssl->extensions, output + offset, offset += TLSX_Write(ssl->extensions, output + offset,
@@ -2195,6 +2305,7 @@ word16 TLSX_WriteRequest(WOLFSSL* ssl, byte* output)
#ifndef NO_WOLFSSL_SERVER #ifndef NO_WOLFSSL_SERVER
/** Tells the buffered size of extensions to be sent into the server hello. */
word16 TLSX_GetResponseSize(WOLFSSL* ssl) word16 TLSX_GetResponseSize(WOLFSSL* ssl)
{ {
word16 length = 0; word16 length = 0;
@@ -2211,6 +2322,7 @@ word16 TLSX_GetResponseSize(WOLFSSL* ssl)
return length; return length;
} }
/** Writes the server hello extensions into a buffer. */
word16 TLSX_WriteResponse(WOLFSSL *ssl, byte* output) word16 TLSX_WriteResponse(WOLFSSL *ssl, byte* output)
{ {
word16 offset = 0; word16 offset = 0;
@@ -2231,6 +2343,7 @@ word16 TLSX_WriteResponse(WOLFSSL *ssl, byte* output)
#endif /* NO_WOLFSSL_SERVER */ #endif /* NO_WOLFSSL_SERVER */
/** Parses a buffer of TLS extensions. */
int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest, int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest,
Suites *suites) Suites *suites)
{ {
@@ -2318,6 +2431,9 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest,
offset += size; offset += size;
} }
if (ret == 0)
ret = SNI_VERIFY_PARSE(ssl, isRequest);
return ret; return ret;
} }
@@ -2326,8 +2442,7 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest,
#undef TURN_ON #undef TURN_ON
#undef SEMAPHORE_SIZE #undef SEMAPHORE_SIZE
#endif #endif /* HAVE_TLS_EXTENSIONS */
#ifndef NO_WOLFSSL_CLIENT #ifndef NO_WOLFSSL_CLIENT
@@ -2465,4 +2580,3 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest,
#endif /* NO_WOLFSSL_SERVER */ #endif /* NO_WOLFSSL_SERVER */
#endif /* NO_TLS */ #endif /* NO_TLS */

View File

@@ -134,9 +134,9 @@ static void test_wolfSSL_Method_Allocators(void)
static void test_wolfSSL_CTX_new(WOLFSSL_METHOD *method) static void test_wolfSSL_CTX_new(WOLFSSL_METHOD *method)
{ {
WOLFSSL_CTX *ctx; WOLFSSL_CTX *ctx;
AssertNull(ctx = wolfSSL_CTX_new(NULL)); AssertNull(ctx = wolfSSL_CTX_new(NULL));
AssertNotNull(method); AssertNotNull(method);
AssertNotNull(ctx = wolfSSL_CTX_new(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())); AssertNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));
/* invalid context */ /* invalid context */
AssertFalse(wolfSSL_CTX_use_certificate_file(NULL, svrCert, AssertFalse(wolfSSL_CTX_use_certificate_file(NULL, svrCert,
SSL_FILETYPE_PEM)); SSL_FILETYPE_PEM));
/* invalid cert file */ /* invalid cert file */
AssertFalse(wolfSSL_CTX_use_certificate_file(ctx, bogusFile, AssertFalse(wolfSSL_CTX_use_certificate_file(ctx, bogusFile,
SSL_FILETYPE_PEM)); SSL_FILETYPE_PEM));
/* invalid cert type */ /* invalid cert type */
AssertFalse(wolfSSL_CTX_use_certificate_file(ctx, svrCert, 9999)); 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())); AssertNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));
/* invalid context */ /* invalid context */
AssertFalse(wolfSSL_CTX_use_PrivateKey_file(NULL, svrKey, AssertFalse(wolfSSL_CTX_use_PrivateKey_file(NULL, svrKey,
SSL_FILETYPE_PEM)); SSL_FILETYPE_PEM));
/* invalid key file */ /* invalid key file */
AssertFalse(wolfSSL_CTX_use_PrivateKey_file(ctx, bogusFile, AssertFalse(wolfSSL_CTX_use_PrivateKey_file(ctx, bogusFile,
SSL_FILETYPE_PEM)); SSL_FILETYPE_PEM));
/* invalid key type */ /* invalid key type */
AssertFalse(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKey, 9999)); 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; WOLFSSL_CTX *ctx;
AssertNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); AssertNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
/* invalid context */ /* invalid context */
AssertFalse(wolfSSL_CTX_load_verify_locations(NULL, caCert, 0)); 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())); AssertNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
AssertTrue(wolfSSL_CTX_load_verify_locations(ctx, caCert, 0)); AssertTrue(wolfSSL_CTX_load_verify_locations(ctx, caCert, 0));
/* invalid context */ /* invalid context */
AssertNull(ssl = wolfSSL_new(NULL)); AssertNull(ssl = wolfSSL_new(NULL));
/* success */ /* success */
AssertNotNull(ssl = wolfSSL_new(ctx_nocert)); AssertNotNull(ssl = wolfSSL_new(ctx_nocert));
wolfSSL_free(ssl); wolfSSL_free(ssl);
/* success */ /* success */
AssertNotNull(ssl = wolfSSL_new(ctx)); AssertNotNull(ssl = wolfSSL_new(ctx));
wolfSSL_free(ssl); wolfSSL_free(ssl);
wolfSSL_CTX_free(ctx); wolfSSL_CTX_free(ctx);
wolfSSL_CTX_free(ctx_nocert); wolfSSL_CTX_free(ctx_nocert);
#endif #endif
@@ -353,7 +353,7 @@ static THREAD_RETURN WOLFSSL_THREAD test_server_nofail(void* args)
"Please run from wolfSSL home dir");*/ "Please run from wolfSSL home dir");*/
goto done; goto done;
} }
ssl = wolfSSL_new(ctx); ssl = wolfSSL_new(ctx);
tcp_accept(&sockfd, &clientfd, (func_args*)args, port, 0, 0, 0); tcp_accept(&sockfd, &clientfd, (func_args*)args, port, 0, 0, 0);
CloseSocket(sockfd); CloseSocket(sockfd);
@@ -382,7 +382,7 @@ static THREAD_RETURN WOLFSSL_THREAD test_server_nofail(void* args)
input[idx] = 0; input[idx] = 0;
printf("Client message: %s\n", input); printf("Client message: %s\n", input);
} }
if (wolfSSL_write(ssl, msg, sizeof(msg)) != sizeof(msg)) if (wolfSSL_write(ssl, msg, sizeof(msg)) != sizeof(msg))
{ {
/*err_sys("SSL_write failed");*/ /*err_sys("SSL_write failed");*/
@@ -401,7 +401,7 @@ done:
wolfSSL_shutdown(ssl); wolfSSL_shutdown(ssl);
wolfSSL_free(ssl); wolfSSL_free(ssl);
wolfSSL_CTX_free(ctx); wolfSSL_CTX_free(ctx);
CloseSocket(clientfd); CloseSocket(clientfd);
((func_args*)args)->return_code = TEST_SUCCESS; ((func_args*)args)->return_code = TEST_SUCCESS;
@@ -494,7 +494,7 @@ static void test_client_nofail(void* args)
done2: done2:
wolfSSL_free(ssl); wolfSSL_free(ssl);
wolfSSL_CTX_free(ctx); wolfSSL_CTX_free(ctx);
CloseSocket(sockfd); CloseSocket(sockfd);
((func_args*)args)->return_code = TEST_SUCCESS; ((func_args*)args)->return_code = TEST_SUCCESS;
@@ -720,10 +720,10 @@ static void test_wolfSSL_read_write(void)
StartTCP(); StartTCP();
InitTcpReady(&ready); InitTcpReady(&ready);
server_args.signal = &ready; server_args.signal = &ready;
client_args.signal = &ready; client_args.signal = &ready;
start_thread(test_server_nofail, &server_args, &serverThread); start_thread(test_server_nofail, &server_args, &serverThread);
wait_tcp_ready(&server_args); wait_tcp_ready(&server_args);
test_client_nofail(&client_args); test_client_nofail(&client_args);
@@ -746,68 +746,106 @@ static void test_wolfSSL_read_write(void)
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#ifdef HAVE_SNI #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) static void use_SNI_at_ctx(WOLFSSL_CTX* ctx)
{ {
byte type = WOLFSSL_SNI_HOST_NAME;
char name[] = "www.yassl.com";
AssertIntEQ(SSL_SUCCESS, 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) static void use_SNI_at_ssl(WOLFSSL* ssl)
{ {
byte type = WOLFSSL_SNI_HOST_NAME;
char name[] = "www.yassl.com";
AssertIntEQ(SSL_SUCCESS, 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) static void different_SNI_at_ssl(WOLFSSL* ssl)
{ {
byte type = WOLFSSL_SNI_HOST_NAME;
char name[] = "ww2.yassl.com";
AssertIntEQ(SSL_SUCCESS, 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) static void use_SNI_WITH_CONTINUE_at_ssl(WOLFSSL* ssl)
{ {
byte type = WOLFSSL_SNI_HOST_NAME;
use_SNI_at_ssl(ssl); use_SNI_at_ssl(ssl);
wolfSSL_SNI_SetOptions(ssl, WOLFSSL_SNI_HOST_NAME,
wolfSSL_SNI_SetOptions(ssl, type, WOLFSSL_SNI_CONTINUE_ON_MISMATCH); WOLFSSL_SNI_CONTINUE_ON_MISMATCH);
} }
static void use_SNI_WITH_FAKE_ANSWER_at_ssl(WOLFSSL* ssl) static void use_SNI_WITH_FAKE_ANSWER_at_ssl(WOLFSSL* ssl)
{ {
byte type = WOLFSSL_SNI_HOST_NAME;
use_SNI_at_ssl(ssl); use_SNI_at_ssl(ssl);
wolfSSL_SNI_SetOptions(ssl, WOLFSSL_SNI_HOST_NAME,
wolfSSL_SNI_SetOptions(ssl, type, WOLFSSL_SNI_ANSWER_ON_MISMATCH); 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)); 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)); 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) 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 */ char* request = (char*) &type; /* to be overwriten */
AssertIntEQ(WOLFSSL_SNI_NO_MATCH, wolfSSL_SNI_Status(ssl, type)); AssertIntEQ(WOLFSSL_SNI_NO_MATCH, wolfSSL_SNI_Status(ssl, type));
AssertNotNull(request); AssertNotNull(request);
AssertIntEQ(0, wolfSSL_SNI_GetRequest(ssl, type, (void**) &request)); AssertIntEQ(0, wolfSSL_SNI_GetRequest(ssl, type, (void**) &request));
AssertNull(request); AssertNull(request);
@@ -815,30 +853,118 @@ static void verify_SNI_no_matching(WOLFSSL* ssl)
static void verify_SNI_real_matching(WOLFSSL* ssl) static void verify_SNI_real_matching(WOLFSSL* ssl)
{ {
byte type = WOLFSSL_SNI_HOST_NAME; byte type = WOLFSSL_SNI_HOST_NAME;
char* request = NULL; char* request = NULL;
char name[] = "www.yassl.com";
word16 length = XSTRLEN(name);
AssertIntEQ(WOLFSSL_SNI_REAL_MATCH, wolfSSL_SNI_Status(ssl, type)); AssertIntEQ(WOLFSSL_SNI_REAL_MATCH, wolfSSL_SNI_Status(ssl, type));
AssertIntEQ(15, wolfSSL_SNI_GetRequest(ssl, type, (void**) &request));
AssertIntEQ(length, wolfSSL_SNI_GetRequest(ssl, type, (void**) &request));
AssertNotNull(request); AssertNotNull(request);
AssertStrEQ(name, request); AssertStrEQ("www.wolfssl.com", request);
} }
static void verify_SNI_fake_matching(WOLFSSL* ssl) static void verify_SNI_fake_matching(WOLFSSL* ssl)
{ {
byte type = WOLFSSL_SNI_HOST_NAME; byte type = WOLFSSL_SNI_HOST_NAME;
char* request = NULL; char* request = NULL;
char name[] = "ww2.yassl.com";
word16 length = XSTRLEN(name);
AssertIntEQ(WOLFSSL_SNI_FAKE_MATCH, wolfSSL_SNI_Status(ssl, type)); AssertIntEQ(WOLFSSL_SNI_FAKE_MATCH, wolfSSL_SNI_Status(ssl, type));
AssertIntEQ(15, wolfSSL_SNI_GetRequest(ssl, type, (void**) &request));
AssertIntEQ(length, wolfSSL_SNI_GetRequest(ssl, type, (void**) &request));
AssertNotNull(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) 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, 0x01, 0x04, 0x03, 0x05, 0x03, 0x02, 0x03, 0x04, 0x02, 0x02, 0x02, 0x00,
0x12, 0x00, 0x00 0x12, 0x00, 0x00
}; };
byte buffer5[] = { /* SSL v2.0 client hello */ byte buffer5[] = { /* SSL v2.0 client hello */
0x00, 0x2b, 0x01, 0x03, 0x01, 0x00, 0x09, 0x00, 0x00, 0x00, 0x2b, 0x01, 0x03, 0x01, 0x00, 0x09, 0x00, 0x00,
/* dummy bytes bellow, just to pass size check */ /* dummy bytes bellow, just to pass size check */
@@ -933,7 +1059,7 @@ static void test_wolfSSL_SNI_GetFromBuffer(void)
0, result, &length)); 0, result, &length));
buffer[1] = 0x03; buffer[1] = 0x03;
AssertIntEQ(SNI_UNSUPPORTED, wolfSSL_SNI_GetFromBuffer(buffer, AssertIntEQ(SNI_UNSUPPORTED, wolfSSL_SNI_GetFromBuffer(buffer,
sizeof(buffer), 0, result, &length)); sizeof(buffer), 0, result, &length));
buffer[2] = 0x03; buffer[2] = 0x03;
@@ -964,121 +1090,19 @@ static void test_wolfSSL_SNI_GetFromBuffer(void)
buffer5[2] = 0x01; buffer5[6] = 0x08; buffer5[2] = 0x01; buffer5[6] = 0x08;
AssertIntEQ(BUFFER_ERROR, wolfSSL_SNI_GetFromBuffer(buffer5, AssertIntEQ(BUFFER_ERROR, wolfSSL_SNI_GetFromBuffer(buffer5,
sizeof(buffer5), 0, result, &length)); sizeof(buffer5), 0, result, &length));
buffer5[6] = 0x09; buffer5[8] = 0x01; buffer5[6] = 0x09; buffer5[8] = 0x01;
AssertIntEQ(BUFFER_ERROR, wolfSSL_SNI_GetFromBuffer(buffer5, AssertIntEQ(BUFFER_ERROR, wolfSSL_SNI_GetFromBuffer(buffer5,
sizeof(buffer5), 0, result, &length)); 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 */ #endif /* HAVE_SNI */
static void test_wolfSSL_UseSNI(void) static void test_wolfSSL_UseSNI(void)
{ {
#ifdef HAVE_SNI #ifdef HAVE_SNI
callback_functions client_callbacks = {wolfSSLv23_client_method, 0, 0, 0}; test_wolfSSL_UseSNI_params();
callback_functions server_callbacks = {wolfSSLv23_server_method, 0, 0, 0}; test_wolfSSL_UseSNI_connection();
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_SNI_GetFromBuffer(); test_wolfSSL_SNI_GetFromBuffer();
#endif #endif

View File

@@ -134,6 +134,7 @@ enum wolfSSL_ErrorCodes {
BAD_TICKET_ENCRYPT = -400, /* Bad user ticket encrypt */ BAD_TICKET_ENCRYPT = -400, /* Bad user ticket encrypt */
DH_KEY_SIZE_E = -401, /* DH Key too small */ DH_KEY_SIZE_E = -401, /* DH Key too small */
SNI_ABSENT_ERROR = -402, /* No SNI request. */
/* add strings to SetErrorString !!!!! */ /* add strings to SetErrorString !!!!! */
@@ -165,5 +166,3 @@ void SetErrorString(int err, char* buff);
#endif /* wolfSSL_ERROR_H */ #endif /* wolfSSL_ERROR_H */

View File

@@ -1273,8 +1273,8 @@ enum {
WOLFSSL_SNI_HOST_NAME = 0 WOLFSSL_SNI_HOST_NAME = 0
}; };
WOLFSSL_API int wolfSSL_UseSNI(WOLFSSL* ssl, unsigned char type, const void* data, WOLFSSL_API int wolfSSL_UseSNI(WOLFSSL* ssl, unsigned char type,
unsigned short size); const void* data, unsigned short size);
WOLFSSL_API int wolfSSL_CTX_UseSNI(WOLFSSL_CTX* ctx, unsigned char type, WOLFSSL_API int wolfSSL_CTX_UseSNI(WOLFSSL_CTX* ctx, unsigned char type,
const void* data, unsigned short size); const void* data, unsigned short size);
@@ -1282,26 +1282,33 @@ WOLFSSL_API int wolfSSL_CTX_UseSNI(WOLFSSL_CTX* ctx, unsigned char type,
/* SNI options */ /* SNI options */
enum { enum {
WOLFSSL_SNI_CONTINUE_ON_MISMATCH = 0x01, /* do not abort on mismatch flag */ /* Do not abort the handshake if the requested SNI didn't match. */
WOLFSSL_SNI_ANSWER_ON_MISMATCH = 0x02 /* fake match on mismatch flag */ 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,
/* 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, WOLFSSL_API void wolfSSL_SNI_SetOptions(WOLFSSL* ssl, unsigned char type,
unsigned char options); unsigned char options);
WOLFSSL_API void wolfSSL_CTX_SNI_SetOptions(WOLFSSL_CTX* ctx, unsigned char type, WOLFSSL_API void wolfSSL_CTX_SNI_SetOptions(WOLFSSL_CTX* ctx,
unsigned char options); unsigned char type, unsigned char options);
/* SNI status */ /* SNI status */
enum { enum {
WOLFSSL_SNI_NO_MATCH = 0, 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_SNI_REAL_MATCH = 2
}; };
WOLFSSL_API unsigned char wolfSSL_SNI_Status(WOLFSSL* ssl, unsigned char type); WOLFSSL_API unsigned char wolfSSL_SNI_Status(WOLFSSL* ssl, unsigned char type);
WOLFSSL_API unsigned short wolfSSL_SNI_GetRequest(WOLFSSL *ssl, unsigned char type, WOLFSSL_API unsigned short wolfSSL_SNI_GetRequest(WOLFSSL *ssl,
void** data); unsigned char type, void** data);
WOLFSSL_API int wolfSSL_SNI_GetFromBuffer( WOLFSSL_API int wolfSSL_SNI_GetFromBuffer(
const unsigned char* clientHello, unsigned int helloSz, const unsigned char* clientHello, unsigned int helloSz,
unsigned char type, unsigned char* sni, unsigned int* inOutSz); unsigned char type, unsigned char* sni, unsigned int* inOutSz);
@@ -1467,4 +1474,3 @@ WOLFSSL_API int wolfSSL_accept_ex(WOLFSSL*, HandShakeCallBack, TimeoutCallBack,
#endif /* WOLFSSL_SSL_H */ #endif /* WOLFSSL_SSL_H */