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
#define IS_OFF(semaphore, light) \
((semaphore)[(light) / 8] ^ (byte) (0x01 << ((light) % 8)))
#define TURN_ON(semaphore, light) \
((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;
if (list == NULL) /* won't check type since this function is static */
return BAD_FUNC_ARG;
if ((extension = XMALLOC(sizeof(TLSX), 0, DYNAMIC_TYPE_TLSX)) == NULL)
extension = (TLSX*)XMALLOC(sizeof(TLSX), 0, DYNAMIC_TYPE_TLSX);
if (extension == NULL)
return MEMORY_E;
extension->type = type;
extension->data = NULL;
extension->data = data;
extension->resp = 0;
extension->next = *list;
*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;
}
#ifndef NO_CYASSL_SERVER
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);
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;
} else {
XFREE(sni, 0, DYNAMIC_TYPE_TLSX);
@ -823,7 +841,7 @@ static word16 TLSX_SNI_GetSize(SNI* list)
switch (sni->type) {
case CYASSL_SNI_HOST_NAME:
length += XSTRLEN((char*) sni->data.host_name);
length += XSTRLEN((char*)sni->data.host_name);
break;
}
}
@ -844,7 +862,7 @@ static word16 TLSX_SNI_Write(SNI* list, byte* output)
switch (sni->type) {
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 */
offset += OPAQUE16_LEN;
@ -941,7 +959,7 @@ static int TLSX_SNI_Parse(CYASSL* ssl, byte* input, word16 length,
if (offset + size > length)
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 */
}
@ -949,7 +967,7 @@ static int TLSX_SNI_Parse(CYASSL* ssl, byte* input, word16 length,
case CYASSL_SNI_HOST_NAME: {
byte matched = (XSTRLEN(sni->data.host_name) == size)
&& (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) {
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)
{
TLSX* extension = NULL;
TLSX* extension = TLSX_Find(*extensions, SERVER_NAME_INDICATION);
SNI* sni = NULL;
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)
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 ((ret = TLSX_Append(extensions, SERVER_NAME_INDICATION)) != 0) {
if ((ret = TLSX_Push(extensions, SERVER_NAME_INDICATION, (void*)sni))
!= 0) {
TLSX_SNI_Free(sni);
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. */
sni->next = (SNI*) extension->data;
extension->data = (void*) sni;
/* look for another server name of the same type to remove */
do {
if (sni->next && sni->next->type == type) {
SNI *next = sni->next;
/* look for another server name of the same type to remove (replacement) */
do {
if (sni->next && sni->next->type == type) {
SNI *next = sni->next;
sni->next = next->next;
TLSX_SNI_Free(next);
sni->next = next->next;
TLSX_SNI_Free(next);
break;
}
} while ((sni = sni->next));
break;
}
} while ((sni = sni->next));
}
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)
{
TLSX* extension = NULL;
byte* data = NULL;
int ret = 0;
byte* data = NULL;
int ret = 0;
if (extensions == NULL)
return BAD_FUNC_ARG;
@ -1253,29 +1263,11 @@ int TLSX_UseMaxFragment(TLSX** extensions, byte mfl)
data[0] = mfl;
/* 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);
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;
}
@ -1304,7 +1296,7 @@ int TLSX_UseTruncatedHMAC(TLSX** extensions)
return BAD_FUNC_ARG;
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 SSL_SUCCESS;
@ -1556,7 +1548,7 @@ int TLSX_ValidateEllipticCurves(CYASSL* ssl, byte first, byte second) {
int TLSX_UseSupportedCurve(TLSX** extensions, word16 name)
{
TLSX* extension = NULL;
TLSX* extension = TLSX_Find(*extensions, ELLIPTIC_CURVES);
EllipticCurve* curve = NULL;
int ret = 0;
@ -1566,37 +1558,29 @@ int TLSX_UseSupportedCurve(TLSX** extensions, word16 name)
if ((ret = TLSX_EllipticCurve_Append(&curve, name)) != 0)
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 ((ret = TLSX_Append(extensions, ELLIPTIC_CURVES)) != 0) {
if ((ret = TLSX_Push(extensions, ELLIPTIC_CURVES, curve)) != 0) {
XFREE(curve, 0, DYNAMIC_TYPE_TLSX);
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. */
curve->next = (EllipticCurve*) extension->data;
extension->data = (void*) curve;
/* look for another curve of the same name to remove (replacement) */
do {
if (curve->next && curve->next->name == name) {
EllipticCurve *next = curve->next;
/* look for another curve of the same name to remove (replacement) */
do {
if (curve->next && curve->next->name == name) {
EllipticCurve *next = curve->next;
curve->next = next->next;
XFREE(next, 0, DYNAMIC_TYPE_TLSX);
curve->next = next->next;
XFREE(next, 0, DYNAMIC_TYPE_TLSX);
break;
}
} while ((curve = curve->next));
break;
}
} while ((curve = curve->next));
}
return SSL_SUCCESS;
}
@ -1627,6 +1611,113 @@ int TLSX_UseSupportedCurve(TLSX** extensions, word16 name)
#define EC_VALIDATE_REQUEST(a, b)
#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)
{
@ -1647,7 +1738,7 @@ void TLSX_FreeAll(TLSX* list)
switch (extension->type) {
case SERVER_NAME_INDICATION:
SNI_FREE_ALL((SNI *) extension->data);
SNI_FREE_ALL((SNI*)extension->data);
break;
case MAX_FRAGMENT_LENGTH:
@ -1661,6 +1752,10 @@ void TLSX_FreeAll(TLSX* list)
case ELLIPTIC_CURVES:
EC_FREE_ALL(extension->data);
break;
case SECURE_RENEGOTIATION:
SCR_FREE_ALL(extension->data);
break;
}
XFREE(extension, 0, DYNAMIC_TYPE_TLSX);
@ -1682,30 +1777,35 @@ static word16 TLSX_GetSize(TLSX* list, byte* semaphore, byte isRequest)
if (!isRequest && !extension->resp)
continue; /* skip! */
if (IS_OFF(semaphore, extension->type)) {
/* type + data length */
length += HELLO_EXT_TYPE_SZ + OPAQUE16_LEN;
if (!IS_OFF(semaphore, extension->type))
continue; /* skip! */
switch (extension->type) {
case SERVER_NAME_INDICATION:
if (isRequest)
length += SNI_GET_SIZE((SNI *) extension->data);
break;
case MAX_FRAGMENT_LENGTH:
length += MFL_GET_SIZE(extension->data);
break;
/* type + data length */
length += HELLO_EXT_TYPE_SZ + OPAQUE16_LEN;
case TRUNCATED_HMAC:
/* empty extension. */
break;
switch (extension->type) {
case SERVER_NAME_INDICATION:
if (isRequest)
length += SNI_GET_SIZE(extension->data);
break;
case MAX_FRAGMENT_LENGTH:
length += MFL_GET_SIZE(extension->data);
break;
case ELLIPTIC_CURVES:
length += EC_GET_SIZE((EllipticCurve *) extension->data);
break;
}
case TRUNCATED_HMAC:
/* empty extension. */
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;
@ -1724,41 +1824,44 @@ static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore,
if (!isRequest && !extension->resp)
continue; /* skip! */
if (IS_OFF(semaphore, extension->type)) {
/* extension type */
c16toa(extension->type, output + offset);
offset += HELLO_EXT_TYPE_SZ + OPAQUE16_LEN;
length_offset = offset;
if (!IS_OFF(semaphore, extension->type))
continue; /* skip! */
/* extension data should be written internally */
switch (extension->type) {
case SERVER_NAME_INDICATION:
if (isRequest)
offset += SNI_WRITE((SNI *) extension->data,
output + offset);
break;
/* extension type */
c16toa(extension->type, output + offset);
offset += HELLO_EXT_TYPE_SZ + OPAQUE16_LEN;
length_offset = offset;
case MAX_FRAGMENT_LENGTH:
offset += MFL_WRITE((byte *) extension->data,
output + offset);
break;
/* extension data should be written internally */
switch (extension->type) {
case SERVER_NAME_INDICATION:
if (isRequest)
offset += SNI_WRITE((SNI*)extension->data, output + offset);
break;
case TRUNCATED_HMAC:
/* empty extension. */
break;
case MAX_FRAGMENT_LENGTH:
offset += MFL_WRITE((byte*)extension->data, output + offset);
break;
case TRUNCATED_HMAC:
/* empty extension. */
break;
case ELLIPTIC_CURVES:
offset += EC_WRITE((EllipticCurve *) extension->data,
offset += EC_WRITE((EllipticCurve*)extension->data,
output + offset);
break;
}
/* writing extension data length */
c16toa(offset - length_offset,
output + length_offset - OPAQUE16_LEN);
TURN_ON(semaphore, extension->type);
case SECURE_RENEGOTIATION:
offset += SCR_WRITE((SecureRenegotiation*)extension->data,
output + offset, isRequest);
break;
}
/* writing extension data length */
c16toa(offset - length_offset, output + length_offset - OPAQUE16_LEN);
TURN_ON(semaphore, extension->type);
}
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);
break;
case SECURE_RENEGOTIATION:
CYASSL_MSG("Secure Renegotiation extension received");
ret = SCR_PARSE(ssl, input + offset, size, isRequest);
break;
case HELLO_EXT_SIG_ALGO:
if (isRequest) {
/* do not mess with offset inside the switch! */