Renames TLSX_Append to TLSX_Push, adding data param and making sure the list doesn't holds duplicate extensions.

Adds SecureRenegotiation functions
This commit is contained in:
Moisés Guimarães
2014-09-16 18:35:41 -03:00
parent 32cea012d9
commit 89b972d946

365
src/tls.c
View File

@@ -703,31 +703,49 @@ int TLS_hmac(CYASSL* ssl, byte* digest, const byte* in, word32 sz,
#ifdef HAVE_TLS_EXTENSIONS #ifdef HAVE_TLS_EXTENSIONS
#define IS_OFF(semaphore, light) \ #define IS_OFF(semaphore, light) \
((semaphore)[(light) / 8] ^ (byte) (0x01 << ((light) % 8))) ((semaphore)[(light) / 8] ^ (byte) (0x01 << ((light) % 8)))
#define TURN_ON(semaphore, light) \ #define TURN_ON(semaphore, light) \
((semaphore)[(light) / 8] |= (byte) (0x01 << ((light) % 8))) ((semaphore)[(light) / 8] |= (byte) (0x01 << ((light) % 8)))
static int TLSX_Append(TLSX** list, TLSX_Type type)
static int TLSX_Push(TLSX** list, TLSX_Type type, void* data)
{ {
TLSX* extension; TLSX* extension;
if (list == NULL) /* won't check type since this function is static */ extension = (TLSX*)XMALLOC(sizeof(TLSX), 0, DYNAMIC_TYPE_TLSX);
return BAD_FUNC_ARG; if (extension == NULL)
if ((extension = XMALLOC(sizeof(TLSX), 0, DYNAMIC_TYPE_TLSX)) == NULL)
return MEMORY_E; return MEMORY_E;
extension->type = type; extension->type = type;
extension->data = NULL; extension->data = data;
extension->resp = 0; extension->resp = 0;
extension->next = *list; extension->next = *list;
*list = extension; *list = extension;
/* remove duplicated extensions, there should be only one of each type. */
do {
if (extension->next && extension->next->type == type) {
TLSX *next = extension->next;
extension->next = next->next;
next->next = NULL;
TLSX_FreeAll(next);
/* there is no way to occur more than */
/* two extensions of the same type. */
break;
}
} while ((extension = extension->next));
return 0; return 0;
} }
#ifndef NO_CYASSL_SERVER #ifndef NO_CYASSL_SERVER
void TLSX_SetResponse(CYASSL* ssl, TLSX_Type type); void TLSX_SetResponse(CYASSL* ssl, TLSX_Type type);
@@ -784,7 +802,7 @@ static int TLSX_SNI_Append(SNI** list, byte type, const void* data, word16 size)
sni->data.host_name = XMALLOC(size + 1, 0, DYNAMIC_TYPE_TLSX); sni->data.host_name = XMALLOC(size + 1, 0, DYNAMIC_TYPE_TLSX);
if (sni->data.host_name) { if (sni->data.host_name) {
XSTRNCPY(sni->data.host_name, (const char*) data, size); XSTRNCPY(sni->data.host_name, (const char*)data, size);
sni->data.host_name[size] = 0; sni->data.host_name[size] = 0;
} else { } else {
XFREE(sni, 0, DYNAMIC_TYPE_TLSX); XFREE(sni, 0, DYNAMIC_TYPE_TLSX);
@@ -823,7 +841,7 @@ static word16 TLSX_SNI_GetSize(SNI* list)
switch (sni->type) { switch (sni->type) {
case CYASSL_SNI_HOST_NAME: case CYASSL_SNI_HOST_NAME:
length += XSTRLEN((char*) sni->data.host_name); length += XSTRLEN((char*)sni->data.host_name);
break; break;
} }
} }
@@ -844,7 +862,7 @@ static word16 TLSX_SNI_Write(SNI* list, byte* output)
switch (sni->type) { switch (sni->type) {
case CYASSL_SNI_HOST_NAME: case CYASSL_SNI_HOST_NAME:
length = XSTRLEN((char*) sni->data.host_name); length = XSTRLEN((char*)sni->data.host_name);
c16toa(length, output + offset); /* sni length */ c16toa(length, output + offset); /* sni length */
offset += OPAQUE16_LEN; offset += OPAQUE16_LEN;
@@ -941,7 +959,7 @@ static int TLSX_SNI_Parse(CYASSL* 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 SNI type */
} }
@@ -949,7 +967,7 @@ static int TLSX_SNI_Parse(CYASSL* ssl, byte* input, word16 length,
case CYASSL_SNI_HOST_NAME: { case CYASSL_SNI_HOST_NAME: {
byte matched = (XSTRLEN(sni->data.host_name) == size) byte matched = (XSTRLEN(sni->data.host_name) == size)
&& (XSTRNCMP(sni->data.host_name, && (XSTRNCMP(sni->data.host_name,
(const char *) input + offset, size) == 0); (const char*)input + offset, size) == 0);
if (matched || sni->options & CYASSL_SNI_ANSWER_ON_MISMATCH) { if (matched || sni->options & CYASSL_SNI_ANSWER_ON_MISMATCH) {
int r = TLSX_UseSNI(&ssl->extensions, int r = TLSX_UseSNI(&ssl->extensions,
@@ -979,7 +997,7 @@ static int TLSX_SNI_Parse(CYASSL* ssl, byte* input, word16 length,
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 = NULL; TLSX* extension = TLSX_Find(*extensions, SERVER_NAME_INDICATION);
SNI* sni = NULL; SNI* sni = NULL;
int ret = 0; int ret = 0;
@@ -989,37 +1007,30 @@ int TLSX_UseSNI(TLSX** extensions, byte type, const void* data, word16 size)
if ((ret = TLSX_SNI_Append(&sni, type, data, size)) != 0) if ((ret = TLSX_SNI_Append(&sni, type, data, size)) != 0)
return ret; return ret;
extension = *extensions;
/* find SNI extension if it already exists. */
while (extension && extension->type != SERVER_NAME_INDICATION)
extension = extension->next;
/* push new SNI extension if it doesn't exists. */
if (!extension) { if (!extension) {
if ((ret = TLSX_Append(extensions, SERVER_NAME_INDICATION)) != 0) { if ((ret = TLSX_Push(extensions, SERVER_NAME_INDICATION, (void*)sni))
!= 0) {
TLSX_SNI_Free(sni); TLSX_SNI_Free(sni);
return ret; return ret;
} }
extension = *extensions;
} }
else {
/* push new SNI object to extension data. */
sni->next = (SNI*)extension->data;
extension->data = (void*)sni;
/* push new SNI object to extension data. */ /* look for another server name of the same type to remove */
sni->next = (SNI*) extension->data; do {
extension->data = (void*) sni; if (sni->next && sni->next->type == type) {
SNI *next = sni->next;
/* look for another server name of the same type to remove (replacement) */ sni->next = next->next;
do { TLSX_SNI_Free(next);
if (sni->next && sni->next->type == type) {
SNI *next = sni->next;
sni->next = next->next; break;
TLSX_SNI_Free(next); }
} while ((sni = sni->next));
break; }
}
} while ((sni = sni->next));
return SSL_SUCCESS; return SSL_SUCCESS;
} }
@@ -1237,9 +1248,8 @@ static int TLSX_MFL_Parse(CYASSL* ssl, byte* input, word16 length,
int TLSX_UseMaxFragment(TLSX** extensions, byte mfl) int TLSX_UseMaxFragment(TLSX** extensions, byte mfl)
{ {
TLSX* extension = NULL; byte* data = NULL;
byte* data = NULL; int ret = 0;
int ret = 0;
if (extensions == NULL) if (extensions == NULL)
return BAD_FUNC_ARG; return BAD_FUNC_ARG;
@@ -1253,29 +1263,11 @@ int TLSX_UseMaxFragment(TLSX** extensions, byte mfl)
data[0] = mfl; data[0] = mfl;
/* push new MFL extension. */ /* push new MFL extension. */
if ((ret = TLSX_Append(extensions, MAX_FRAGMENT_LENGTH)) != 0) { if ((ret = TLSX_Push(extensions, MAX_FRAGMENT_LENGTH, data)) != 0) {
XFREE(data, 0, DYNAMIC_TYPE_TLSX); XFREE(data, 0, DYNAMIC_TYPE_TLSX);
return ret; return ret;
} }
/* place new mfl to extension data. */
extension = *extensions;
extension->data = (void*) data;
/* remove duplicated extensions */
do {
if (extension->next && extension->next->type == MAX_FRAGMENT_LENGTH) {
TLSX *next = extension->next;
extension->next = next->next;
next->next = NULL;
TLSX_FreeAll(next);
break;
}
} while ((extension = extension->next));
return SSL_SUCCESS; return SSL_SUCCESS;
} }
@@ -1304,7 +1296,7 @@ int TLSX_UseTruncatedHMAC(TLSX** extensions)
return BAD_FUNC_ARG; return BAD_FUNC_ARG;
if (!TLSX_Find(*extensions, TRUNCATED_HMAC)) if (!TLSX_Find(*extensions, TRUNCATED_HMAC))
if ((ret = TLSX_Append(extensions, TRUNCATED_HMAC)) != 0) if ((ret = TLSX_Push(extensions, TRUNCATED_HMAC, NULL)) != 0)
return ret; return ret;
return SSL_SUCCESS; return SSL_SUCCESS;
@@ -1556,7 +1548,7 @@ int TLSX_ValidateEllipticCurves(CYASSL* ssl, byte first, byte second) {
int TLSX_UseSupportedCurve(TLSX** extensions, word16 name) int TLSX_UseSupportedCurve(TLSX** extensions, word16 name)
{ {
TLSX* extension = NULL; TLSX* extension = TLSX_Find(*extensions, ELLIPTIC_CURVES);
EllipticCurve* curve = NULL; EllipticCurve* curve = NULL;
int ret = 0; int ret = 0;
@@ -1566,37 +1558,29 @@ int TLSX_UseSupportedCurve(TLSX** extensions, word16 name)
if ((ret = TLSX_EllipticCurve_Append(&curve, name)) != 0) if ((ret = TLSX_EllipticCurve_Append(&curve, name)) != 0)
return ret; return ret;
extension = *extensions;
/* find EllipticCurve extension if it already exists. */
while (extension && extension->type != ELLIPTIC_CURVES)
extension = extension->next;
/* push new EllipticCurve extension if it doesn't exists. */
if (!extension) { if (!extension) {
if ((ret = TLSX_Append(extensions, ELLIPTIC_CURVES)) != 0) { if ((ret = TLSX_Push(extensions, ELLIPTIC_CURVES, curve)) != 0) {
XFREE(curve, 0, DYNAMIC_TYPE_TLSX); XFREE(curve, 0, DYNAMIC_TYPE_TLSX);
return ret; return ret;
} }
extension = *extensions;
} }
else {
/* push new EllipticCurve object to extension data. */
curve->next = (EllipticCurve*)extension->data;
extension->data = (void*)curve;
/* push new EllipticCurve object to extension data. */ /* look for another curve of the same name to remove (replacement) */
curve->next = (EllipticCurve*) extension->data; do {
extension->data = (void*) curve; if (curve->next && curve->next->name == name) {
EllipticCurve *next = curve->next;
/* look for another curve of the same name to remove (replacement) */ curve->next = next->next;
do { XFREE(next, 0, DYNAMIC_TYPE_TLSX);
if (curve->next && curve->next->name == name) {
EllipticCurve *next = curve->next;
curve->next = next->next; break;
XFREE(next, 0, DYNAMIC_TYPE_TLSX); }
} while ((curve = curve->next));
break; }
}
} while ((curve = curve->next));
return SSL_SUCCESS; return SSL_SUCCESS;
} }
@@ -1627,6 +1611,113 @@ int TLSX_UseSupportedCurve(TLSX** extensions, word16 name)
#define EC_VALIDATE_REQUEST(a, b) #define EC_VALIDATE_REQUEST(a, b)
#endif /* HAVE_SUPPORTED_CURVES */ #endif /* HAVE_SUPPORTED_CURVES */
#ifdef HAVE_SECURE_RENEGOTIATION
static byte TLSX_SCR_GetSize(SecureRenegotiation* data, int isRequest)
{
byte length = OPAQUE8_LEN; /* RenegotiationInfo length */
if (data->secure_renegotiation) {
/* client sends client_verify_data only */
length += TLS_FINISHED_SZ;
/* server also sends server_verify_data */
if (!isRequest)
length += TLS_FINISHED_SZ;
}
return length;
}
static word16 TLSX_SCR_Write(SecureRenegotiation* data, byte* output,
int isRequest)
{
word16 offset = OPAQUE8_LEN; /* RenegotiationInfo length */
output[0] = TLSX_SCR_GetSize(data, isRequest);
if (data->secure_renegotiation) {
/* client sends client_verify_data only */
XMEMCPY(output + offset, data->client_verify_data, TLS_FINISHED_SZ);
offset += TLS_FINISHED_SZ;
/* server also sends server_verify_data */
if (!isRequest) {
XMEMCPY(output + offset, data->server_verify_data, TLS_FINISHED_SZ);
offset += TLS_FINISHED_SZ;
}
}
return offset;
}
static int TLSX_SCR_Parse(CYASSL* ssl, byte* input, word16 length,
byte isRequest)
{
if (length != ENUM_LEN)
return BUFFER_ERROR;
switch (*input) {
case CYASSL_MFL_2_9 : ssl->max_fragment = 512; break;
case CYASSL_MFL_2_10: ssl->max_fragment = 1024; break;
case CYASSL_MFL_2_11: ssl->max_fragment = 2048; break;
case CYASSL_MFL_2_12: ssl->max_fragment = 4096; break;
case CYASSL_MFL_2_13: ssl->max_fragment = 8192; break;
default:
SendAlert(ssl, alert_fatal, illegal_parameter);
return UNKNOWN_MAX_FRAG_LEN_E;
}
#ifndef NO_CYASSL_SERVER
if (isRequest) {
int r = TLSX_UseMaxFragment(&ssl->extensions, *input);
if (r != SSL_SUCCESS) return r; /* throw error */
TLSX_SetResponse(ssl, MAX_FRAGMENT_LENGTH);
}
#endif
return 0;
}
int TLSX_UseSecureRenegotiation(TLSX** extensions)
{
int ret = 0;
SecureRenegotiation* data = NULL;
data = (SecureRenegotiation*)XMALLOC(sizeof(SecureRenegotiation), NULL,
DYNAMIC_TYPE_TLSX);
if (data == NULL)
return MEMORY_E;
XMEMSET(data, 0, sizeof(SecureRenegotiation));
ret = TLSX_Push(extensions, SECURE_RENEGOTIATION, data);
if (ret != 0) {
XFREE(data, 0, DYNAMIC_TYPE_TLSX);
return ret;
}
return SSL_SUCCESS;
}
#define SCR_FREE_ALL(data) XFREE(data, NULL, DYNAMIC_TYPE_TLSX)
#define SCR_GET_SIZE TLSX_SCR_GetSize
#define SCR_WRITE TLSX_SCR_Write
#define SCR_PARSE TLSX_SCR_Parse
#else
#define SCR_FREE_ALL(a)
#define SCR_GET_SIZE(a, b) 0
#define SCR_WRITE(a, b, c) 0
#define SCR_PARSE(a, b, c, d) 0
#endif /* HAVE_SECURE_RENEGOTIATION */
TLSX* TLSX_Find(TLSX* list, TLSX_Type type) TLSX* TLSX_Find(TLSX* list, TLSX_Type type)
{ {
@@ -1647,7 +1738,7 @@ void TLSX_FreeAll(TLSX* list)
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;
case MAX_FRAGMENT_LENGTH: case MAX_FRAGMENT_LENGTH:
@@ -1661,6 +1752,10 @@ void TLSX_FreeAll(TLSX* list)
case ELLIPTIC_CURVES: case ELLIPTIC_CURVES:
EC_FREE_ALL(extension->data); EC_FREE_ALL(extension->data);
break; break;
case SECURE_RENEGOTIATION:
SCR_FREE_ALL(extension->data);
break;
} }
XFREE(extension, 0, DYNAMIC_TYPE_TLSX); XFREE(extension, 0, DYNAMIC_TYPE_TLSX);
@@ -1682,30 +1777,35 @@ static word16 TLSX_GetSize(TLSX* list, byte* semaphore, byte isRequest)
if (!isRequest && !extension->resp) if (!isRequest && !extension->resp)
continue; /* skip! */ continue; /* skip! */
if (IS_OFF(semaphore, extension->type)) { if (!IS_OFF(semaphore, extension->type))
/* type + data length */ continue; /* skip! */
length += HELLO_EXT_TYPE_SZ + OPAQUE16_LEN;
switch (extension->type) { /* type + data length */
case SERVER_NAME_INDICATION: length += HELLO_EXT_TYPE_SZ + OPAQUE16_LEN;
if (isRequest)
length += SNI_GET_SIZE((SNI *) extension->data);
break;
case MAX_FRAGMENT_LENGTH:
length += MFL_GET_SIZE(extension->data);
break;
case TRUNCATED_HMAC: switch (extension->type) {
/* empty extension. */ case SERVER_NAME_INDICATION:
break; if (isRequest)
length += SNI_GET_SIZE(extension->data);
break;
case MAX_FRAGMENT_LENGTH:
length += MFL_GET_SIZE(extension->data);
break;
case ELLIPTIC_CURVES: case TRUNCATED_HMAC:
length += EC_GET_SIZE((EllipticCurve *) extension->data); /* empty extension. */
break; break;
}
TURN_ON(semaphore, extension->type); case ELLIPTIC_CURVES:
length += EC_GET_SIZE(extension->data);
break;
case SECURE_RENEGOTIATION:
length += SCR_GET_SIZE(extension->data, isRequest);
break;
} }
TURN_ON(semaphore, extension->type);
} }
return length; return length;
@@ -1724,41 +1824,44 @@ static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore,
if (!isRequest && !extension->resp) if (!isRequest && !extension->resp)
continue; /* skip! */ continue; /* skip! */
if (IS_OFF(semaphore, extension->type)) { if (!IS_OFF(semaphore, extension->type))
/* extension type */ continue; /* skip! */
c16toa(extension->type, output + offset);
offset += HELLO_EXT_TYPE_SZ + OPAQUE16_LEN;
length_offset = offset;
/* extension data should be written internally */ /* extension type */
switch (extension->type) { c16toa(extension->type, output + offset);
case SERVER_NAME_INDICATION: offset += HELLO_EXT_TYPE_SZ + OPAQUE16_LEN;
if (isRequest) length_offset = offset;
offset += SNI_WRITE((SNI *) extension->data,
output + offset);
break;
case MAX_FRAGMENT_LENGTH: /* extension data should be written internally */
offset += MFL_WRITE((byte *) extension->data, switch (extension->type) {
output + offset); case SERVER_NAME_INDICATION:
break; if (isRequest)
offset += SNI_WRITE((SNI*)extension->data, output + offset);
break;
case TRUNCATED_HMAC: case MAX_FRAGMENT_LENGTH:
/* empty extension. */ offset += MFL_WRITE((byte*)extension->data, output + offset);
break; break;
case TRUNCATED_HMAC:
/* empty extension. */
break;
case ELLIPTIC_CURVES: case ELLIPTIC_CURVES:
offset += EC_WRITE((EllipticCurve *) extension->data, offset += EC_WRITE((EllipticCurve*)extension->data,
output + offset); output + offset);
break; break;
}
/* writing extension data length */ case SECURE_RENEGOTIATION:
c16toa(offset - length_offset, offset += SCR_WRITE((SecureRenegotiation*)extension->data,
output + length_offset - OPAQUE16_LEN); output + offset, isRequest);
break;
TURN_ON(semaphore, extension->type);
} }
/* writing extension data length */
c16toa(offset - length_offset, output + length_offset - OPAQUE16_LEN);
TURN_ON(semaphore, extension->type);
} }
return offset; return offset;
@@ -1927,6 +2030,12 @@ int TLSX_Parse(CYASSL* ssl, byte* input, word16 length, byte isRequest,
ret = EC_PARSE(ssl, input + offset, size, isRequest); ret = EC_PARSE(ssl, input + offset, size, isRequest);
break; break;
case SECURE_RENEGOTIATION:
CYASSL_MSG("Secure Renegotiation extension received");
ret = SCR_PARSE(ssl, input + offset, size, isRequest);
break;
case HELLO_EXT_SIG_ALGO: case HELLO_EXT_SIG_ALGO:
if (isRequest) { if (isRequest) {
/* do not mess with offset inside the switch! */ /* do not mess with offset inside the switch! */