ALPN and SNI Extension parsing improvements

SNI will not have more than one type, only one entry in the list per
type and therefore no need to loop.
ALPN error checks improved.
This commit is contained in:
Sean Parkinson
2019-06-28 15:52:51 +10:00
parent f51a8fffde
commit 1592d6f856

112
src/tls.c
View File

@ -1530,6 +1530,9 @@ static int TLSX_ALPN_ParseAndSet(WOLFSSL *ssl, byte *input, word16 length,
ato16(input, &size); ato16(input, &size);
offset += OPAQUE16_LEN; offset += OPAQUE16_LEN;
if (size == 0)
return BUFFER_ERROR;
extension = TLSX_Find(ssl->extensions, TLSX_APPLICATION_LAYER_PROTOCOL); extension = TLSX_Find(ssl->extensions, TLSX_APPLICATION_LAYER_PROTOCOL);
if (extension == NULL) if (extension == NULL)
extension = TLSX_Find(ssl->ctx->extensions, extension = TLSX_Find(ssl->ctx->extensions,
@ -1579,7 +1582,7 @@ static int TLSX_ALPN_ParseAndSet(WOLFSSL *ssl, byte *input, word16 length,
for (size = 0; offset < length; offset += size) { for (size = 0; offset < length; offset += size) {
size = input[offset++]; size = input[offset++];
if (offset + size > length) if (offset + size > length || size == 0)
return BUFFER_ERROR; return BUFFER_ERROR;
if (isRequest) { if (isRequest) {
@ -1898,6 +1901,10 @@ static int TLSX_SNI_Parse(WOLFSSL* ssl, byte* input, word16 length,
word16 size = 0; word16 size = 0;
word16 offset = 0; word16 offset = 0;
int cacheOnly = 0; int cacheOnly = 0;
SNI *sni = NULL;
byte type;
int matchStat;
byte matched;
#endif #endif
TLSX *extension = TLSX_Find(ssl->extensions, TLSX_SERVER_NAME); TLSX *extension = TLSX_Find(ssl->extensions, TLSX_SERVER_NAME);
@ -1951,73 +1958,64 @@ static int TLSX_SNI_Parse(WOLFSSL* ssl, byte* input, word16 length,
offset += OPAQUE16_LEN; offset += OPAQUE16_LEN;
/* validating sni list length */ /* validating sni list length */
if (length != OPAQUE16_LEN + size) if (length != OPAQUE16_LEN + size || size == 0)
return BUFFER_ERROR; return BUFFER_ERROR;
for (size = 0; offset < length; offset += size) { /* SNI was badly specified and only one type is now recognized and allowed.
SNI *sni = NULL; * Only one SNI value per type (RFC6066), so, no loop. */
byte type = input[offset++]; type = input[offset++];
if (type != WOLFSSL_SNI_HOST_NAME)
return BUFFER_ERROR;
if (offset + OPAQUE16_LEN > length) if (offset + OPAQUE16_LEN > length)
return BUFFER_ERROR; return BUFFER_ERROR;
ato16(input + offset, &size);
offset += OPAQUE16_LEN;
ato16(input + offset, &size); if (offset + size != length || size == 0)
offset += OPAQUE16_LEN; return BUFFER_ERROR;
if (offset + size > length) if (!cacheOnly && !(sni = TLSX_SNI_Find((SNI*)extension->data, type)))
return BUFFER_ERROR; return 0; /* not using this type of SNI. */
if (!cacheOnly && !(sni = TLSX_SNI_Find((SNI*)extension->data, type)))
continue; /* not using this type of SNI. */
switch(type) {
case WOLFSSL_SNI_HOST_NAME: {
int matchStat;
byte matched;
#ifdef WOLFSSL_TLS13 #ifdef WOLFSSL_TLS13
/* Don't process the second ClientHello SNI extension if there /* Don't process the second ClientHello SNI extension if there
* was problems with the first. * was problems with the first.
*/ */
if (!cacheOnly && sni->status != 0) if (!cacheOnly && sni->status != 0)
break; return 0;
#endif #endif
matched = cacheOnly || matched = cacheOnly || (XSTRLEN(sni->data.host_name) == size &&
((XSTRLEN(sni->data.host_name) == size) && XSTRNCMP(sni->data.host_name, (const char*)input + offset, size) == 0);
(XSTRNCMP(sni->data.host_name,
(const char*)input + offset, size) == 0));
if (matched || sni->options & WOLFSSL_SNI_ANSWER_ON_MISMATCH) { if (matched || sni->options & WOLFSSL_SNI_ANSWER_ON_MISMATCH) {
int r = TLSX_UseSNI(&ssl->extensions, int r = TLSX_UseSNI(&ssl->extensions, type, input + offset, size,
type, input + offset, size, ssl->heap); ssl->heap);
if (r != WOLFSSL_SUCCESS)
return r; /* throws error. */
if (r != WOLFSSL_SUCCESS) if (cacheOnly) {
return r; /* throws error. */ WOLFSSL_MSG("Forcing storage of SNI, Fake match");
matchStat = WOLFSSL_SNI_FORCE_KEEP;
if(cacheOnly) {
WOLFSSL_MSG("Forcing storage of SNI, Fake match");
matchStat = WOLFSSL_SNI_FORCE_KEEP;
} else if(matched) {
WOLFSSL_MSG("SNI did match!");
matchStat = WOLFSSL_SNI_REAL_MATCH;
} else {
WOLFSSL_MSG("fake SNI match from ANSWER_ON_MISMATCH");
matchStat = WOLFSSL_SNI_FAKE_MATCH;
}
TLSX_SNI_SetStatus(ssl->extensions, type, (byte)matchStat);
if(!cacheOnly)
TLSX_SetResponse(ssl, TLSX_SERVER_NAME);
} else if (!(sni->options & WOLFSSL_SNI_CONTINUE_ON_MISMATCH)) {
SendAlert(ssl, alert_fatal, unrecognized_name);
return UNKNOWN_SNI_HOST_NAME_E;
}
break;
}
} }
else if (matched) {
WOLFSSL_MSG("SNI did match!");
matchStat = WOLFSSL_SNI_REAL_MATCH;
}
else {
WOLFSSL_MSG("fake SNI match from ANSWER_ON_MISMATCH");
matchStat = WOLFSSL_SNI_FAKE_MATCH;
}
TLSX_SNI_SetStatus(ssl->extensions, type, (byte)matchStat);
if(!cacheOnly)
TLSX_SetResponse(ssl, TLSX_SERVER_NAME);
}
else if (!(sni->options & WOLFSSL_SNI_CONTINUE_ON_MISMATCH)) {
SendAlert(ssl, alert_fatal, unrecognized_name);
return UNKNOWN_SNI_HOST_NAME_E;
} }
#else #else
(void)input; (void)input;