static int parse_extensions(const char *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 = ((unsigned char)data[pos + 2] << 8) + (unsigned char)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; }
/* Parse a TLS packet for the Server Name Indication extension in the client hello * handshake, returning the first servername found (pointer to static array) */ const char * parse_tls_header(const char* data, int data_len) { char tls_content_type; char tls_version_major; char tls_version_minor; int tls_length; const char* p = data; int len; /* Check that our TCP payload is at least large enough for a TLS header */ if (data_len < TLS_HEADER_LEN) return NULL; tls_content_type = p[0]; if (tls_content_type != TLS_HANDSHAKE_CONTENT_TYPE) { syslog(LOG_DEBUG, "Did not receive TLS handshake"); return NULL; } tls_version_major = p[1]; tls_version_minor = p[2]; if (tls_version_major < 3) { syslog(LOG_DEBUG, "Receved pre SSL 3.0 handshake"); return NULL; } if (tls_version_major == 3 && tls_version_minor < 1) { syslog(LOG_DEBUG, "Receved SSL 3.0 handshake"); return NULL; } tls_length = ((unsigned char)p[3] << 8) + (unsigned char)p[4]; if (data_len < tls_length + TLS_HEADER_LEN) { syslog(LOG_DEBUG, "Did not receive complete TLS handshake header: %d", __LINE__); return NULL; } /* Advance to first TLS payload */ p += TLS_HEADER_LEN; if (p - data >= data_len) { syslog(LOG_DEBUG, "Did not receive complete TLS handshake header: %d", __LINE__); return NULL; } if (*p != TLS_HANDSHAKE_TYPE_CLIENT_HELLO) { syslog(LOG_DEBUG, "Not a client hello"); return NULL; } /* Skip past: 1 Handshake Type 3 Length 2 Version (again) 32 Random to Session ID Length */ p += 38; if (p - data >= data_len) { syslog(LOG_DEBUG, "Did not receive complete TLS handshake header: %d", __LINE__); return NULL; } len = (unsigned char)*p; /* Session ID Length */ p += 1 + len; /* Skip session ID block */ if (p - data >= data_len) { syslog(LOG_DEBUG, "Did not receive complete TLS handshake header: %d", __LINE__); return NULL; } len = (unsigned char)*p << 8; /* Cipher Suites length high byte */ p ++; if (p - data >= data_len) { syslog(LOG_DEBUG, "Did not receive complete TLS handshake header: %d", __LINE__); return NULL; } len += (unsigned char)*p; /* Cipher Suites length low byte */ p += 1 + len; if (p - data >= data_len) { syslog(LOG_DEBUG, "Did not receive complete TLS handshake header: %d", __LINE__); return NULL; } len = (unsigned char)*p; /* Compression Methods length */ p += 1 + len; if (p - data >= data_len) { syslog(LOG_DEBUG, "No extensions present in TLS handshake header: %d", __LINE__); return NULL; } len = (unsigned char)*p << 8; /* Extensions length high byte */ p++; if (p - data >= data_len) { syslog(LOG_DEBUG, "Did not receive complete TLS handshake header: %d", __LINE__); return NULL; } len += (unsigned char)*p; /* Extensions length low byte */ p++; while (1) { if (p - data + 4 >= data_len) { /* 4 bytes for the extension header */ syslog(LOG_DEBUG, "No more TLS handshake extensions: %d", __LINE__); return NULL; } /* Parse our extension header */ len = ((unsigned char)p[2] << 8) + (unsigned char)p[3]; /* Extension length */ if (p[0] == 0x00 && p[1] == 0x00) { /* Check if it's a server name extension */ /* There can be only one extension of each type, so we break our state and move p to beinnging of the extension here */ p += 4; if (p - data + len > data_len) { syslog(LOG_DEBUG, "Did not receive complete TLS handshake header: %d", __LINE__); return NULL; } return parse_server_name_extension(p, len); } p += 4 + len; /* Advance to the next extension header */ } return NULL; }