From f1d1898ddf995ccf9339fe38383cc38a00f489f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mois=C3=A9s=20Guimar=C3=A3es?= Date: Mon, 3 Jun 2013 17:55:06 -0300 Subject: [PATCH] Added new option to SNI: CYASSL_SNI_ANSWER_ON_MISMATCH Added new function to SNI API: CyaSSL_SNI_Matched() --- cyassl/internal.h | 2 ++ cyassl/ssl.h | 5 +++- src/ssl.c | 5 ++++ src/tls.c | 66 +++++++++++++++++++++++++++++++++-------------- 4 files changed, 58 insertions(+), 20 deletions(-) diff --git a/cyassl/internal.h b/cyassl/internal.h index f53733d83..39947748a 100644 --- a/cyassl/internal.h +++ b/cyassl/internal.h @@ -1157,6 +1157,7 @@ typedef struct SNI { struct SNI* next; /* List Behavior */ #ifndef NO_CYASSL_SERVER byte options; /* Behaviour options */ + byte matched; /* Matching result */ #endif } SNI; @@ -1164,6 +1165,7 @@ CYASSL_LOCAL int TLSX_UseSNI(TLSX** extensions, byte type, const void* data, word16 size); #ifndef NO_CYASSL_SERVER +CYASSL_LOCAL byte TLSX_SNI_Matched(TLSX* extensions, byte type); CYASSL_LOCAL void TLSX_SNI_SetOptions(TLSX* extensions, byte type, byte options); #endif diff --git a/cyassl/ssl.h b/cyassl/ssl.h index 0af93fdfe..3ed5bc457 100644 --- a/cyassl/ssl.h +++ b/cyassl/ssl.h @@ -944,9 +944,12 @@ CYASSL_API int CyaSSL_CTX_UseSNI(CYASSL_CTX* ctx, unsigned char type, #ifndef NO_CYASSL_SERVER /* SNI options */ enum { - CYASSL_SNI_CONTINUE_ON_MISMATCH = 0x01 + CYASSL_SNI_CONTINUE_ON_MISMATCH = 0x01, /* do not abort on mismatch flag */ + CYASSL_SNI_ANSWER_ON_MISMATCH = 0x02 /* fake match on mismatch flag */ }; +CYASSL_API unsigned char CyaSSL_SNI_Matched(CYASSL* ssl, unsigned char type); + CYASSL_API void CyaSSL_SNI_SetOptions(CYASSL* ssl, unsigned char type, unsigned char options); CYASSL_API void CyaSSL_CTX_SNI_SetOptions(CYASSL_CTX* ctx, unsigned char type, diff --git a/src/ssl.c b/src/ssl.c index cd86c938a..60caf99d6 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -528,6 +528,11 @@ int CyaSSL_CTX_UseSNI(CYASSL_CTX* ctx, byte type, const void* data, word16 size) } #ifndef NO_CYASSL_SERVER +byte CyaSSL_SNI_Matched(CYASSL* ssl, byte type) +{ + return TLSX_SNI_Matched(ssl ? ssl->extensions : NULL, type); +} + void CyaSSL_SNI_SetOptions(CYASSL* ssl, byte type, byte options) { if (ssl && ssl->extensions) diff --git a/src/tls.c b/src/tls.c index b902738ef..6e5965595 100644 --- a/src/tls.c +++ b/src/tls.c @@ -582,7 +582,12 @@ static int TLSX_SNI_Append(SNI** list, byte type, const void* data, word16 size) sni->type = type; sni->next = *list; + +#ifndef NO_CYASSL_SERVER sni->options = 0; + sni->matched = 0; +#endif + *list = sni; return 0; @@ -648,6 +653,30 @@ static SNI* TLSX_SNI_Find(SNI *list, byte type) return sni; } +#ifndef NO_CYASSL_SERVER +static void TLSX_SNI_SetMatched(TLSX* extensions, byte type) +{ + TLSX* extension = TLSX_Find(extensions, SERVER_NAME_INDICATION); + SNI* sni = TLSX_SNI_Find(extension ? extension->data : NULL, type); + + if (sni) { + sni->matched = 1; + CYASSL_MSG("SNI did match!"); + } +} + +byte TLSX_SNI_Matched(TLSX* extensions, byte type) +{ + TLSX* extension = TLSX_Find(extensions, SERVER_NAME_INDICATION); + SNI* sni = TLSX_SNI_Find(extension ? extension->data : NULL, type); + + if (sni) + return sni->matched; + + return 0; +} +#endif + static int TLSX_SNI_Parse(CYASSL* ssl, byte* input, word16 length, byte isRequest) { @@ -707,27 +736,24 @@ static int TLSX_SNI_Parse(CYASSL* ssl, byte* input, word16 length, } switch(type) { - case CYASSL_SNI_HOST_NAME: - if (XSTRLEN(sni->data.host_name) != size - || XSTRNCMP(sni->data.host_name, - (const char *) input + offset, size)) { - if (sni->options & CYASSL_SNI_CONTINUE_ON_MISMATCH) - break; - /** - * Better client thinks the server is not using SNI, - * instead of thinking that the host_name matched. - * No empty SNI response in this case. - */ + case CYASSL_SNI_HOST_NAME: { + byte matched = (XSTRLEN(sni->data.host_name) == size) + && (XSTRNCMP(sni->data.host_name, + (const char *) input + offset, size) == 0); - SendAlert(ssl, alert_fatal, unrecognized_name); - - return UNKNOWN_SNI_HOST_NAME_E; - } else { + if (matched || sni->options & CYASSL_SNI_ANSWER_ON_MISMATCH) { int r = TLSX_UseSNI(&ssl->extensions, type, (byte *) "", 0); if (r) return r; /* throw error */ + + if (matched) TLSX_SNI_SetMatched(ssl->extensions, type); + } else if (!(sni->options & CYASSL_SNI_CONTINUE_ON_MISMATCH)) { + SendAlert(ssl, alert_fatal, unrecognized_name); + + return UNKNOWN_SNI_HOST_NAME_E; } break; + } } TLSX_SetResponse(ssl, SERVER_NAME_INDICATION); @@ -788,11 +814,11 @@ int TLSX_UseSNI(TLSX** extensions, byte type, const void* data, word16 size) #ifndef NO_CYASSL_SERVER void TLSX_SNI_SetOptions(TLSX* extensions, byte type, byte options) { - TLSX* extension = TLSX_Find(extensions, SERVER_NAME_INDICATION); - SNI* sni = TLSX_SNI_Find(extension ? extension->data : NULL, type); + TLSX* extension = TLSX_Find(extensions, SERVER_NAME_INDICATION); + SNI* sni = TLSX_SNI_Find(extension ? extension->data : NULL, type); - if (sni) - sni->options = options; + if (sni) + sni->options = options; } #endif @@ -1047,6 +1073,8 @@ int TLSX_Parse(CYASSL* ssl, byte* input, word16 length, byte isRequest, switch (type) { case SERVER_NAME_INDICATION: + CYASSL_MSG("SNI extension received"); + ret = SNI_PARSE(ssl, input + offset, size, isRequest); break;