-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Task/Issue URL:https://app.asana.com/0/488551667048375/1205675418279581/f ### Description Improve TLS parsing ### Steps to test this PR #### Unit tests * cd `netguard/src/test` * `make` * `./test_tls` should pass #### Smoke Tests - [x] from this branch, publish the library to maven local ie. `./gradlew clean assemble publishToMavenLocal` - [x] In the DDG android app apply the following path ```diff Subject: [PATCH] Maven local use --- Index: build.gradle IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== diff --git a/build.gradle b/build.gradle --- a/build.gradle (revision d11f7491d7ab4b27223fd352f83c26be403e79ed) +++ b/build.gradle (revision 3b1fe446b5d33e4d8a7f400137134ea0b5a797d7) @@ -40,6 +40,7 @@ repositories { google() mavenCentral() + mavenLocal() } configurations.all { resolutionStrategy.force 'org.objenesis:objenesis:2.6' Index: versions.properties IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>ISO-8859-1 =================================================================== diff --git a/versions.properties b/versions.properties --- a/versions.properties (revision d11f7491d7ab4b27223fd352f83c26be403e79ed) +++ b/versions.properties (revision 3b1fe446b5d33e4d8a7f400137134ea0b5a797d7) @@ -55,7 +55,7 @@ version.com.android.installreferrer..installreferrer=2.2 -version.com.duckduckgo.netguard..netguard-android=1.6.0 +version.com.duckduckgo.netguard..netguard-android=1.7.0-SNAPSHOT version.com.duckduckgo.synccrypto..sync-crypto-android=0.3.0 ``` - [x] build DDG app - [x] AppTP smoke tests
- Loading branch information
Showing
8 changed files
with
729 additions
and
127 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
/cmake-build-debug/ | ||
**/cmake-build-debug/ | ||
.idea | ||
/CMakeFiles/ | ||
CMakeCache.txt | ||
src/.vscode/ | ||
*.o |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,212 @@ | ||
|
||
#include <stdio.h> | ||
#include <stdint.h> | ||
#include <string.h> /* strncpy() */ | ||
#include <sys/socket.h> | ||
#include <sys/types.h> | ||
#include <netinet/in.h> | ||
//#include <netinet/in6.h> | ||
#include <netinet/ip.h> | ||
#include <netinet/ip6.h> | ||
#include "platform.h" | ||
#include "tls.h" | ||
|
||
static int parse_tls_server_name(const uint8_t *data, size_t data_len, char *server_name); | ||
static int parse_extensions(const uint8_t*, size_t, char *); | ||
static int parse_server_name_extension(const uint8_t*, size_t, char *); | ||
|
||
#define TLS_HEADER_LEN 5 // size of the TLS Record Header | ||
#ifndef MIN | ||
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) | ||
#endif | ||
|
||
|
||
/** | ||
* Parse a TLS packet for the Server Name Indication extension in the client hello handshake. | ||
* Returns the first server name found | ||
* | ||
* @param data the TLS packet | ||
* @param data_len the TLS packet length | ||
* @param server_name pointer to the server name static array. This method does not allocate memory for it | ||
* | ||
* @returns | ||
* >=0 length of the server name found | ||
* -1 incomplete TLS request | ||
* -2 no SNI header found | ||
* -3 invalid TLS client hello | ||
* -4 invalid TLs packet | ||
*/ | ||
static int parse_tls_server_name(const uint8_t *data, size_t data_len, char *server_name) { | ||
*server_name = 0; | ||
|
||
if (data_len < TLS_HEADER_LEN) { | ||
return -1; | ||
} | ||
|
||
/* | ||
* Check for SSL 2.0 compatible Client Hello | ||
* | ||
* High bit of first byte (length) and content type is Client Hello | ||
* | ||
* See RFC5246 Appendix E.2 | ||
*/ | ||
if ((data[0] & 0x80) && (data[2] == 1)) { | ||
log_print(PLATFORM_LOG_PRIORITY_DEBUG, "Received SSL 2.0 Client Hello which can not support SNI."); | ||
return -2; | ||
} | ||
|
||
uint8_t content_type = (uint8_t) *data; | ||
if (content_type != 0x16) { | ||
log_print(PLATFORM_LOG_PRIORITY_DEBUG, "Request did not begin with TLS handshake."); | ||
return -3; | ||
} | ||
|
||
uint8_t tls_version_major = data[1]; | ||
uint8_t tls_version_minor = data[2]; | ||
if (tls_version_major < 3) { | ||
// receive handshake that can't support SNI | ||
return -2; | ||
} | ||
|
||
/* TLS record length */ | ||
size_t len = ((size_t)data[3] << 8) + (size_t)data[4] + TLS_HEADER_LEN; | ||
data_len = MIN(len, data_len); | ||
if (data_len < len) { | ||
// purposely don't return as we have checks later on | ||
log_print(PLATFORM_LOG_PRIORITY_WARN, "TLS data length smaller than expected, proceed anyways"); | ||
} | ||
|
||
/* handshake */ | ||
size_t pos = TLS_HEADER_LEN; | ||
if (pos + 1 > data_len) { | ||
return -4; | ||
} | ||
|
||
if (data[pos] != 0x1) { | ||
// not a client hello | ||
return -4; | ||
} | ||
|
||
/* Skip past fixed length records: | ||
1 Handshake Type | ||
3 Length | ||
2 Version (again) | ||
32 Random | ||
to Session ID Length | ||
*/ | ||
pos += 38; | ||
|
||
// Session ID | ||
if (pos + 1 > data_len) return -4; | ||
len = (size_t)data[pos]; | ||
pos += 1 + len; | ||
|
||
/* Cipher Suites */ | ||
if (pos + 2 > data_len) return -4; | ||
len = ((size_t)data[pos] << 8) + (size_t)data[pos + 1]; | ||
pos += 2 + len; | ||
|
||
/* Compression Methods */ | ||
if (pos + 1 > data_len) return -4; | ||
len = (size_t)data[pos]; | ||
pos += 1 + len; | ||
|
||
if (pos == data_len && tls_version_major == 3 && tls_version_minor == 0) { | ||
// "Received SSL 3.0 handshake without extensions" | ||
return -2; | ||
} | ||
|
||
/* Extensions */ | ||
if (pos + 2 > data_len) { | ||
return -4; | ||
} | ||
len = ((size_t)data[pos] << 8) + (size_t)data[pos + 1]; | ||
pos += 2; | ||
|
||
if (pos + len > data_len) { | ||
return -4; | ||
} | ||
return parse_extensions(data + pos, len, server_name); | ||
} | ||
|
||
static int parse_extensions(const uint8_t *data, size_t data_len, char *hostname) { | ||
size_t pos = 0; | ||
size_t len; | ||
|
||
/* Parse each 4 bytes for the extension header */ | ||
while (pos + 4 <= data_len) { | ||
/* Extension Length */ | ||
len = ((size_t)data[pos + 2] << 8) + | ||
(size_t)data[pos + 3]; | ||
|
||
/* Check if it's a server name extension */ | ||
if (data[pos] == 0x00 && data[pos + 1] == 0x00) { | ||
/* There can be only one extension of each type, so we break | ||
our state and move p to beinnging of the extension here */ | ||
if (pos + 4 + len > data_len) | ||
return -5; | ||
return parse_server_name_extension(data + pos + 4, len, hostname); | ||
} | ||
pos += 4 + len; /* Advance to the next extension header */ | ||
} | ||
/* Check we ended where we expected to */ | ||
if (pos != data_len) | ||
return -5; | ||
|
||
return -2; | ||
} | ||
|
||
static int parse_server_name_extension(const uint8_t *data, size_t data_len, char *hostname) { | ||
size_t pos = 2; /* skip server name list length */ | ||
size_t len; | ||
|
||
while (pos + 3 < data_len) { | ||
len = ((size_t)data[pos + 1] << 8) + | ||
(size_t)data[pos + 2]; | ||
|
||
if (pos + 3 + len > data_len) { | ||
return -4; | ||
} | ||
|
||
switch (data[pos]) { /* name type */ | ||
case 0x00: /* host_name */ | ||
strncpy(hostname, (const char *)(data + pos + 3), len); | ||
(hostname)[len] = '\0'; | ||
return len; | ||
default: | ||
log_print(PLATFORM_LOG_PRIORITY_DEBUG, "Unknown server name extension name type: %d", data[pos]); | ||
} | ||
pos += 3 + len; | ||
} | ||
/* Check we ended where we expected to */ | ||
if (pos != data_len) { | ||
return -4; | ||
} | ||
|
||
return -2; | ||
} | ||
|
||
int get_server_name( | ||
const uint8_t *pkt, | ||
size_t length, | ||
const uint8_t *tls, | ||
char *server_name | ||
) { | ||
size_t data_len = length - (tls - pkt); | ||
int error_code = parse_tls_server_name(tls, data_len, server_name); | ||
if (error_code >= 0) { | ||
log_print(PLATFORM_LOG_PRIORITY_DEBUG, "Found server name %s", server_name); | ||
} else if (error_code == -1) { | ||
log_print(PLATFORM_LOG_PRIORITY_DEBUG, "Incomplete TLs request"); | ||
} else if (error_code == -2) { | ||
log_print(PLATFORM_LOG_PRIORITY_DEBUG, "No SNI header found"); | ||
} else if (error_code == -3) { | ||
log_print(PLATFORM_LOG_PRIORITY_DEBUG, "invalid TLS client hello"); | ||
} else if (error_code == -4) { | ||
log_print(PLATFORM_LOG_PRIORITY_DEBUG, "invalid TLS packet"); | ||
} else { | ||
log_print(PLATFORM_LOG_PRIORITY_DEBUG, "Unknown error"); | ||
} | ||
|
||
return error_code; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
CC = gcc | ||
CFLAGS = -Wall -Wimplicit-function-declaration -I../netguard/include | ||
|
||
SRC = test_tls.c ../netguard/tls_parser.c | ||
OBJ = $(SRC:.c=.o) | ||
EXECUTABLE = test_tls | ||
|
||
all: $(EXECUTABLE) | ||
|
||
$(EXECUTABLE): $(OBJ) | ||
$(CC) $(CFLAGS) $(OBJ) -o $@ $(LDFLAGS) | ||
|
||
%.o: %.c | ||
$(CC) $(CFLAGS) -c $< -o $@ | ||
|
||
clean: | ||
rm -f $(OBJ) $(EXECUTABLE) | ||
|
Oops, something went wrong.