From 03c48633b0c80b70899dcfc24b1aa138b4cb9599 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B4=94=E4=B8=80=E9=B8=A3?= Date: Thu, 13 Sep 2018 15:52:00 +0800 Subject: [PATCH 1/5] refactor ssl_client_hello_parse --- platform/src/ssl_utils.cc | 901 ++++++++++++++++++++------------------ 1 file changed, 471 insertions(+), 430 deletions(-) diff --git a/platform/src/ssl_utils.cc b/platform/src/ssl_utils.cc index ed129d1..5549eb0 100644 --- a/platform/src/ssl_utils.cc +++ b/platform/src/ssl_utils.cc @@ -1644,444 +1644,485 @@ int ssl_is_ocspreq(const unsigned char * buf, size_t sz) return 1; } -/* - * Ugly hack to manually parse a clientHello message from a memory buffer. - * This is needed in order to be able to support SNI and STARTTLS. - * - * The OpenSSL SNI API only allows to read the indicated server name at the - * time when we have to provide the server cert. OpenSSL does not - * allow to asynchroniously read the indicated server name, wait for some - * unrelated event to happen, and then later to provide the server cert - * to use and continue the handshake. Therefore we resort to parsing the - * server name from the ClientHello manually before OpenSSL gets to work on it. - * - * For STARTTLS support in autossl mode, we need to peek into the buffer of - * received octets and decide whether we have something that resembles a - * (possibly incomplete) ClientHello message, so we can upgrade the connection - * to SSL automatically. - * - * This function takes a buffer containing (part of) a ClientHello message as - * seen on the network as input. - * - * Returns: - * 1 if buf does not contain a complete ClientHello message; - * *clienthello may point to the start of a truncated ClientHello message, - * indicating that the caller should retry later with more bytes available - * 0 if buf contains a complete ClientHello message; - * *clienthello will point to the start of the complete ClientHello message - * - * If a servername pointer was supplied by the caller, and a server name - * extension was found and parsed, the server name is returned in *servername - * as a newly allocated string that must be freed by the caller. This may - * only occur for a return value of 0. - * - * If search is non-zero, then the buffer will be searched for a ClientHello - * message beginning at offsets >= 0, whereas if search is zero, only - * ClientHello messages starting at offset 0 will be considered. - * - * This code currently supports SSL 2.0, SSL 3.0 and TLS 1.0-1.2. - * - * References: - * draft-hickman-netscape-ssl-00: The SSL Protocol - * RFC 6101: The Secure Sockets Layer (SSL) Protocol Version 3.0 - * RFC 2246: The TLS Protocol Version 1.0 - * RFC 3546: Transport Layer Security (TLS) Extensions - * RFC 4346: The Transport Layer Security (TLS) Protocol Version 1.1 - * RFC 4366: Transport Layer Security (TLS) Extensions - * RFC 5246: The Transport Layer Security (TLS) Protocol Version 1.2 - * RFC 6066: Transport Layer Security (TLS) Extensions: Extension Definitions - */ -int -ssl_tls_clienthello_parse( - const unsigned char * buf, ssize_t sz, int search, - const unsigned char ** clienthello, char ** servername) + +struct cipher_suite { -#ifdef DEBUG_CLIENTHELLO_PARSER -#define DBG_printf(...) log_dbg_printf("ClientHello parser: " __VA_ARGS__) -#else /* !DEBUG_CLIENTHELLO_PARSER */ -#define DBG_printf(...) -#endif /* !DEBUG_CLIENTHELLO_PARSER */ - const unsigned char * p = buf; - ssize_t n = sz; - char * sn = NULL; + int value; + char* name; +}; - ssize_t tlsextslen; - ssize_t sidlen; - ssize_t suiteslen; - ssize_t compslen; - ssize_t msglen; - ssize_t recordlen; +struct cipher_suite cipher_suite_list[] = +{ + {0xC030, "ECDHE-RSA-AES256-GCM-SHA384"}, + {0xC02C, "ECDHE-ECDSA-AES256-GCM-SHA384"}, + {0xC028, "ECDHE-RSA-AES256-SHA384"}, + {0xC024, "ECDHE-ECDSA-AES256-SHA384"}, + {0xC014, "ECDHE-RSA-AES256-SHA"}, + {0xC00A, "ECDHE-ECDSA-AES256-SHA"}, + {0x00A5, "DH-DSS-AES256-GCM-SHA384"}, + {0x00A3, "DHE-DSS-AES256-GCM-SHA384"}, + {0x00A1, "DH-RSA-AES256-GCM-SHA384"}, + {0x009F, "DHE-RSA-AES256-GCM-SHA384"}, + {0x006B, "DHE-RSA-AES256-SHA256"}, + {0x006A, "DHE-DSS-AES256-SHA256"}, + {0x0069, "DH-RSA-AES256-SHA256"}, + {0x0068, "DH-DSS-AES256-SHA256"}, + {0x0039, "DHE-RSA-AES256-SHA"}, + {0x0038, "DHE-DSS-AES256-SHA"}, + {0x0037, "DH-RSA-AES256-SHA"}, + {0x0036, "DH-DSS-AES256-SHA"}, + {0x0088, "DHE-RSA-CAMELLIA256-SHA"}, + {0x0087, "DHE-DSS-CAMELLIA256-SHA"}, + {0x0086, "DH-RSA-CAMELLIA256-SHA"}, + {0x0085, "DH-DSS-CAMELLIA256-SHA"}, + {0xC019, "AECDH-AES256-SHA"}, + {0x00A7, "ADH-AES256-GCM-SHA384"}, + {0x006D, "ADH-AES256-SHA256"}, + {0x003A, "ADH-AES256-SHA"}, + {0x0089, "ADH-CAMELLIA256-SHA"}, + {0xC032, "ECDH-RSA-AES256-GCM-SHA384"}, + {0xC02E, "ECDH-ECDSA-AES256-GCM-SHA384"}, + {0xC02A, "ECDH-RSA-AES256-SHA384"}, + {0xC026, "ECDH-ECDSA-AES256-SHA384"}, + {0xC00F, "ECDH-RSA-AES256-SHA"}, + {0xC005, "ECDH-ECDSA-AES256-SHA"}, + {0x009D, "AES256-GCM-SHA384"}, + {0x003D, "AES256-SHA256"}, + {0x0035, "AES256-SHA"}, + {0x0084, "CAMELLIA256-SHA"}, + {0x008D, "PSK-AES256-CBC-SHA"}, + {0xC02F, "ECDHE-RSA-AES128-GCM-SHA256"}, + {0xC02B, "ECDHE-ECDSA-AES128-GCM-SHA256"}, + {0xC027, "ECDHE-RSA-AES128-SHA256"}, + {0xC023, "ECDHE-ECDSA-AES128-SHA256"}, + {0xC013, "ECDHE-RSA-AES128-SHA"}, + {0xC009, "ECDHE-ECDSA-AES128-SHA"}, + {0x00A4, "DH-DSS-AES128-GCM-SHA256"}, + {0x00A2, "DHE-DSS-AES128-GCM-SHA256"}, + {0x00A0, "DH-RSA-AES128-GCM-SHA256"}, + {0x009E, "DHE-RSA-AES128-GCM-SHA256"}, + {0x0067, "DHE-RSA-AES128-SHA256"}, + {0x0040, "DHE-DSS-AES128-SHA256"}, + {0x003F, "DH-RSA-AES128-SHA256"}, + {0x003E, "DH-DSS-AES128-SHA256"}, + {0x0033, "DHE-RSA-AES128-SHA"}, + {0x0032, "DHE-DSS-AES128-SHA"}, + {0x0031, "DH-RSA-AES128-SHA"}, + {0x0030, "DH-DSS-AES128-SHA"}, + {0x009A, "DHE-RSA-SEED-SHA"}, + {0x0099, "DHE-DSS-SEED-SHA"}, + {0x0098, "DH-RSA-SEED-SHA"}, + {0x0097, "DH-DSS-SEED-SHA"}, + {0x0045, "DHE-RSA-CAMELLIA128-SHA"}, + {0x0044, "DHE-DSS-CAMELLIA128-SHA"}, + {0x0043, "DH-RSA-CAMELLIA128-SHA"}, + {0x0042, "DH-DSS-CAMELLIA128-SHA"}, + {0xC018, "AECDH-AES128-SHA"}, + {0x00A6, "ADH-AES128-GCM-SHA256"}, + {0x006C, "ADH-AES128-SHA256"}, + {0x0034, "ADH-AES128-SHA"}, + {0x009B, "ADH-SEED-SHA"}, + {0x0046, "ADH-CAMELLIA128-SHA"}, + {0xC031, "ECDH-RSA-AES128-GCM-SHA256"}, + {0xC02D, "ECDH-ECDSA-AES128-GCM-SHA256"}, + {0xC029, "ECDH-RSA-AES128-SHA256"}, + {0xC025, "ECDH-ECDSA-AES128-SHA256"}, + {0xC00E, "ECDH-RSA-AES128-SHA"}, + {0xC004, "ECDH-ECDSA-AES128-SHA"}, + {0x009C, "AES128-GCM-SHA256"}, + {0x003C, "AES128-SHA256"}, + {0x002F, "AES128-SHA"}, + {0x0096, "SEED-SHA"}, + {0x0041, "CAMELLIA128-SHA"}, + {0x008C, "PSK-AES128-CBC-SHA"}, + {0xC012, "ECDHE-RSA-DES-CBC3-SHA"}, + {0xC008, "ECDHE-ECDSA-DES-CBC3-SHA"}, + {0x0016, "EDH-RSA-DES-CBC3-SHA"}, + {0x0013, "EDH-DSS-DES-CBC3-SHA"}, + {0x0010, "DH-RSA-DES-CBC3-SHA"}, + {0x000D, "DH-DSS-DES-CBC3-SHA"}, + {0xC017, "AECDH-DES-CBC3-SHA"}, + {0x001B, "ADH-DES-CBC3-SHA"}, + {0xC00D, "ECDH-RSA-DES-CBC3-SHA"}, + {0xC003, "ECDH-ECDSA-DES-CBC3-SHA"}, + {0x000A, "DES-CBC3-SHA"}, + {0x0007, "IDEA-CBC-SHA"}, + {0x008B, "PSK-3DES-EDE-CBC-SHA"}, + {0x0021, "KRB5-IDEA-CBC-SHA"}, + {0x001F, "KRB5-DES-CBC3-SHA"}, + {0x0025, "KRB5-IDEA-CBC-MD5"}, + {0x0023, "KRB5-DES-CBC3-MD5"}, + {0xC011, "ECDHE-RSA-RC4-SHA"}, + {0xC007, "ECDHE-ECDSA-RC4-SHA"}, + {0xC016, "AECDH-RC4-SHA"}, + {0x0018, "ADH-RC4-MD5"}, + {0xC00C, "ECDH-RSA-RC4-SHA"}, + {0xC002, "ECDH-ECDSA-RC4-SHA"}, + {0x0005, "RC4-SHA"}, + {0x0004, "RC4-MD5"}, + {0x008A, "PSK-RC4-SHA"}, + {0x0020, "KRB5-RC4-SHA"}, + {0x0024, "KRB5-RC4-MD5"}, + {0xC010, "ECDHE-RSA-NULL-SHA"}, + {0xC006, "ECDHE-ECDSA-NULL-SHA"}, + {0xC015, "AECDH-NULL-SHA"}, + {0xC00B, "ECDH-RSA-NULL-SHA"}, + {0xC001, "ECDH-ECDSA-NULL-SHA"}, + {0x003B, "NULL-SHA256"}, + {0x0002, "NULL-SHA"}, + {0x0001, "NULL-MD5"} +}; - //===== +struct cipher_suite cipher_suite_list_tls13[] = +{ + {0x1301, "TLS_AES_128_GCM_SHA256"}, + {0x1302, "TLS_AES_256_GCM_SHA384"}, + {0x1303, "TLS_CHACHA20_POLY1305_SHA256"}, + {0x1304, "TLS_AES_128_CCM_SHA256"}, + {0x1305, "TLS_AES_128_CCM_8_SHA256"} +}; - *clienthello = NULL; +enum parse_chello_result +{ + PARSE_CHELLO_INVALID_FORMAT = 0, + PARSE_CHELLO_NOT_ENOUGH_BUFF, + PARSE_CHELLO_SUCCESS +}; - DBG_printf("parsing buffer of sz %zd\n", sz); - do - { - if (*clienthello) - { - /* - * Rewind after skipping an invalid ClientHello by - * restarting the search one byte after the beginning - * of the last candidate - */ - p = (*clienthello) + 1; - n = sz - (p - buf); - if (sn) - { - free(sn); - sn = NULL; - } - } +struct ssl_version +{ + int major; + int minor; +}; - if (search) - { - /* Search for a potential ClientHello */ - while ((n > 0) && (*p != 0x16) && (*p != 0x80)) - { - p++; - n--; - } - if (n <= 0) - { - /* Search completed without a match; reset - * clienthello to NULL to indicate to the - * caller that this buffer does not need to be - * retried */ - DBG_printf("===> No match:" - " rv 1, *clienthello NULL\n"); - *clienthello = NULL; - return 1; - } - } - *clienthello = p; - DBG_printf("candidate at offset %td\n", p - buf); +struct ssl_chello +{ + struct ssl_version record_layer_version; + struct ssl_version chello_version; + char* sni; + char* alpn; + char* cipher_suites; + char* cipher_suites_tls13; +}; - DBG_printf("byte 0: %02x\n", *p); - /* +0 0x80 +2 0x01 SSLv2 short header, clientHello; - * +0 0x16 +1 0x03 SSLv3/TLSv1.x handshake, clientHello */ - if (*p == 0x80) - { - /* SSLv2 handled here */ - p++; - n--; - if (n < 10) - { /* length + 9 */ - DBG_printf("===> [SSLv2] Truncated:" - " rv 1, *clienthello set\n"); - return 1; - } - - DBG_printf("length: %02x\n", p[0]); - if (n - 1 < p[0]) - { - DBG_printf("===> [SSLv2] Truncated:" - " rv 1, *clienthello set\n"); - return 1; - } - p++; - n--; - - DBG_printf("msgtype: %02x\n", p[0]); - if (*p != 0x01) - continue; - p++; - n--; - - DBG_printf("version: %02x %02x\n", p[0], p[1]); - /* byte order is actually swapped for SSLv2 */ - if (!( -#ifdef HAVE_SSLV2 - (p[0] == 0x00 && p[1] == 0x02) || -#endif /* HAVE_SSLV2 */ - (p[0] == 0x03 && p[1] <= 0x03))) - continue; - p += 2; - n -= 2; - - DBG_printf("cipher-spec-len: %02x %02x\n", p[0], p[1]); - ssize_t cipherspec_len = p[0] << 8 | p[1]; - p += 2; - n -= 2; - - DBG_printf("session-id-len: %02x %02x\n", p[0], p[1]); - ssize_t sessionid_len = p[0] << 8 | p[1]; - p += 2; - n -= 2; - - DBG_printf("challenge-len: %02x %02x\n", p[0], p[1]); - ssize_t challenge_len = p[0] << 8 | p[1]; - p += 2; - n -= 2; - if (challenge_len < 16 || challenge_len > 32) - continue; - - if (n < cipherspec_len - + sessionid_len - + challenge_len) - { - DBG_printf("===> [SSLv2] Truncated:" - " rv 1, *clienthello set\n"); - return 1; - } - - p += cipherspec_len + sessionid_len + challenge_len; - n -= cipherspec_len + sessionid_len + challenge_len; - goto done_parsing; - } - else if (*p != 0x16) - { - /* this can only happen if search is 0 */ - DBG_printf("===> No match: rv 1, *clienthello NULL\n"); - *clienthello = NULL; - return 1; - } - p++; - n--; - - if (n < 2) - { - DBG_printf("===> Truncated: rv 1, *clienthello set\n"); - return 1; - } - DBG_printf("version: %02x %02x\n", p[0], p[1]); - /* This supports up to TLS 1.2 (0x03 0x03) and will need to be - * updated for TLS 1.3 once that is standardized and still - * compatible with this parser; remember to also update the - * inner version check below */ - if (p[0] != 0x03 || p[1] > 0x03) - continue; - p += 2; - n -= 2; - - if (n < 2) - { - DBG_printf("===> Truncated: rv 1, *clienthello set\n"); - return 1; - } - DBG_printf("length: %02x %02x\n", p[0], p[1]); - - recordlen = p[1] + (p[0] << 8); - DBG_printf("recordlen=%zd\n", recordlen); - p += 2; - n -= 2; - if (recordlen < 36) /* arbitrary size too small for a c-h */ - continue; - if (n < recordlen) - { - DBG_printf("n < recordlen: n=%zd\n", n); - DBG_printf("===> Truncated: rv 1, *clienthello set\n"); - return 1; - } - - /* from here we give up on a candidate if there is not enough - * data available in the buffer, because we already checked the - * availability of the whole record. */ - - if (n < 1) - continue; - DBG_printf("message type: %i\n", *p); - if (*p != 0x01) /* message type: ClientHello */ - continue; - p++; - n--; - - if (n < 3) - continue; - DBG_printf("message len: %02x %02x %02x\n", p[0], p[1], p[2]); - msglen = p[2] + (p[1] << 8) + (p[0] << 16); - DBG_printf("msglen=%zd\n", msglen); - p += 3; - n -= 3; - if (msglen < 32) /* arbitrary size too small for a c-h */ - continue; - if (msglen != recordlen - 4) - { - DBG_printf("msglen != recordlen - 4\n"); - continue; - } - if (n < msglen) - continue; - n = msglen; /* only parse first message */ - - if (n < 2) - continue; - DBG_printf("clienthello version %02x %02x\n", p[0], p[1]); - /* inner version check, see outer one above */ - if (p[0] != 0x03 || p[1] > 0x03) - continue; - p += 2; - n -= 2; - - if (n < 32) - continue; - DBG_printf("clienthello random %02x %02x %02x %02x ...\n", - p[0], p[1], p[2], p[3]); - DBG_printf("compare localtime: %08x\n", - (unsigned int) time(NULL)); - p += 32; - n -= 32; - - if (n < 1) - continue; - DBG_printf("clienthello sidlen %02x\n", *p); - sidlen = *p; /* session id length, 0..32 */ - p += 1; - n -= 1; - if (n < sidlen) - continue; - p += sidlen; - n -= sidlen; - - if (n < 2) - continue; - DBG_printf("clienthello cipher suites length %02x %02x\n", - p[0], p[1]); - - suiteslen = p[1] + (p[0] << 8); - p += 2; - n -= 2; - if (n < suiteslen) - continue; - p += suiteslen; - n -= suiteslen; - - if (n < 1) - continue; - DBG_printf("clienthello compress methods length %02x\n", *p); - - compslen = *p; - p++; - n--; - if (n < compslen) - continue; - p += compslen; - n -= compslen; - - /* begin of extensions */ - - if (n == 0) - { - /* valid ClientHello without extensions */ - DBG_printf("===> Match: rv 0, *clienthello set\n"); - if (servername) - *servername = NULL; - return 0; - } - if (n < 2) - continue; - DBG_printf("tlsexts length %02x %02x\n", p[0], p[1]); - tlsextslen = p[1] + (p[0] << 8); - DBG_printf("tlsextslen %zd\n", tlsextslen); - p += 2; - n -= 2; - if (n < tlsextslen) - continue; - n = tlsextslen; /* only parse exts, ignore trailing bits */ - - while (n > 0) - { - if (n < 4) - goto continue_search; - DBG_printf("tlsext type %02x %02x len %02x %02x\n", - p[0], p[1], p[2], p[3]); - unsigned short exttype = p[1] + (p[0] << 8); - ssize_t extlen = p[3] + (p[2] << 8); - p += 4; - n -= 4; - if (n < extlen) - goto continue_search; - switch (exttype) - { - case 0: - { - ssize_t extn = extlen; - const unsigned char * extp = p; - - if (extn < 2) - goto continue_search; - DBG_printf("list length %02x %02x\n", - extp[0], extp[1]); - ssize_t namelistlen = extp[1] + (extp[0] << 8); - DBG_printf("namelistlen = %zd\n", namelistlen); - extp += 2; - extn -= 2; - - if (namelistlen != extn) - goto continue_search; - - while (extn > 0) - { - if (extn < 3) - goto continue_search; - DBG_printf("ServerName type %02x" - " len %02x %02x\n", - extp[0], extp[1], extp[2]); - unsigned char sntype = extp[0]; - ssize_t snlen = extp[2] + (extp[1] << 8); - extp += 3; - extn -= 3; - if (snlen > extn) - goto continue_search; - if (snlen > TLSEXT_MAXLEN_host_name) - goto continue_search; - /* - * We copy the first name only. - * RFC 6066: "The ServerNameList MUST - * NOT contain more than one name of - * the same name_type." - */ - if (servername && - sntype == 0 && sn == NULL) - { - sn = (char *)malloc(snlen + 1); - memcpy(sn, extp, snlen); - sn[snlen] = '\0'; - /* deliberately not checking - * for malformed hostnames - * containing invalid chars */ - } - extp += snlen; - extn -= snlen; - } - break; - } - default: DBG_printf("skipped\n"); - break; - } - p += extlen; - n -= extlen; - } /* while have more extensions */ - -done_parsing:; -#ifdef DEBUG_CLIENTHELLO_PARSER - if (n > 0) { - DBG_printf("unparsed next bytes %02x %02x %02x %02x\n", - p[0], p[1], p[2], p[3]); - } -#endif /* DEBUG_CLIENTHELLO_PARSER */ - DBG_printf("%zd bytes unparsed\n", n); - - /* Valid ClientHello with or without server name */ - DBG_printf("===> Match: rv 0, *clienthello set\n"); - if (servername) - *servername = sn; - return 0; -continue_search:; - } while (search && n > 0); - - /* No valid ClientHello messages found, not even a truncated one */ - DBG_printf("===> No match: rv 1, *clienthello NULL\n"); - *clienthello = NULL; - if (sn) - { - free(sn); - sn = NULL; - } - return 1; +void ssl_chello_free(struct ssl_chello* chello) +{ + free(chello->sni); + chello->sni = NULL; + free(chello->alpn); + chello->alpn = NULL; + free(chello->cipher_suites); + chello->cipher_suites = NULL; + free(chello->cipher_suites_tls13); + chello->cipher_suites_tls13 = NULL; + free(chello); } -/* vim: set noet ft=c: */ +struct chello* ssl_chello_parse(const char* buff, size_t buff_len, enum parse_chello_result* result) +{ + if(buff == NULL) + { + result = PARSE_CHELLO_INVALID_FORMAT; + return NULL; + } + if(buff_len < 1) + { + result = PARSE_CHELLO_NOT_ENOUGH_BUFF; + return NULL; + } + if(buff[0] != 0x80 && buff[0] != 0x16) + { + result = PARSE_CHELLO_INVALID_FORMAT; + return NULL; + } + /* SSL 2.0 compatible Client Hello + * High bit of first byte (length) and content type is Client Hello + * See RFC5246 Appendix E.2 + * if it is SSL 2.0, only parse version + */ + if(buff[0] == 0x80) + { + struct chello* _chello = (struct chello*)ALLOC(struct chello, 1); + _chello->record_layer_version.major = 0x02; + if(buff_len < 2) + { + *result = PARSE_CHELLO_NOT_ENOUGH_BUFF; + return _chello; + } + size_t len = (size_t)buff[1]; + if (buff_len < len + 2) + { + *result = PARSE_CHELLO_NOT_ENOUGH_BUFF; + return _chello; + } + buff_len = len + 2; + size_t pos = 2; + /* Handshark Message Type: Client Hello */ + if (pos + 1 > buff_len) + { + *result = PARSE_CHELLO_INVALID_FORMAT; + return _chello; + } + if (buff[pos] != 0x01) + { + *result = PARSE_CHELLO_INVALID_FORMAT; + return _chello; + } + pos += 1; + /* Version */ + if(pos + 2 > buff_len) + { + *result = PARSE_CHELLO_INVALID_FORMAT; + return _chello; + } + _chello->chello_version.major = buff[pos]; + _chello->chello_version.minor = buff[pos + 1]; + *result = PARSE_CHELLO_SUCCESS; + return _chello; + } + else + { + if (buff_len < 5) + { + *result = PARSE_CHELLO_NOT_ENOUGH_BUFF; + return NULL; + } + if(buff[1] != 3 || buff[2] > 4 || buff[2] < 0) + { + *result = PARSE_CHELLO_INVALID_FORMAT; + return NULL; + } + struct chello* _chello = (struct chello*)ALLOC(struct chello, 1); + _chello->record_layer_version.major = buff[1]; + _chello->record_layer_version.minor = buff[2]; + _chello->chello_version.major = -1; + _chello->chello_version.minor = -1; + _chello->sni = NULL; + _chello->alpn = NULL; + _chello->cipher_suites = NULL; + _chello->cipher_suites_tls13 = NULL; + /* TLS record length */ + size_t len = ((size_t)buf[3] << 8) + (size_t)buf[4] + 5; + if (buff_len < len) + { + *result = PARSE_CHELLO_NOT_ENOUGH_BUFF; + return _chello; + } + buff_len = len; + size_t pos = 5; + if (pos + 1 > buff_len) + { + *result = PARSE_CHELLO_INVALID_FORMAT; + return _chello; + } + if (buff[pos] != 0x01) + { + *result = PARSE_CHELLO_INVALID_FORMAT; + return _chello; + } + pos += 4; + if(pos + 2 > buff_len) + { + *result = PARSE_CHELLO_INVALID_FORMAT; + return _chello; + } + _chello->chello_version.major = buff[pos]; + _chello->chello_version.minor = buff[pos+1]; + pos += 34; + /* Session ID */ + if (pos + 1 > buff_len) + { + *result = PARSE_CHELLO_INVALID_FORMAT; + return _chello; + } + len = (size_t)buff[pos]; + pos += 1 + len; + /* Cipher Suites */ + if (pos + 2 > buff_len) + { + *result = PARSE_CHELLO_INVALID_FORMAT; + return _chello; + } + len = ((size_t)buff[pos] << 8) + (size_t)buff[pos + 1]; + pos += 2; + if(pos + len > buff_len) + { + *result = PARSE_CHELLO_INVALID_FORMAT; + return _chello; + } + int n = sizeof(cipher_suite_list) / sizeof(struct cipher_suite); + _chello->cipher_suites = parse_cipher_suites(cipher_suite_list, n, buff + pos, len, result); + if(*result != PARSE_CHELLO_SUCCESS) + { + return _chello; + } + n = sizeof(cipher_suite_list_tls13) / sizeof(struct cipher_suite); + _chello->cipher_suites_tls13 = parse_cipher_suites_tls13(cipher_suite_list_tls13, n, buff + pos, len, result); + if(*result != PARSE_CHELLO_SUCCESS) + { + return _chello; + } + pos += len; + /* Compression Methods */ + if (pos >= buff_len) + { + *result = PARSE_CHELLO_INVALID_FORMAT; + return _chello; + } + len = (size_t)buff[pos]; + pos += 1 + len; + /* ssl 3.0, no extensions */ + if(_chello->record_layer_version.major == 3 && _chello->record_layer_version.minor == 0) + { + if(pos == buff_len) + { + *result = PARSE_CHELLO_SUCCESS; + return _chello; + } + else + { + *result = PARSE_CHELLO_INVALID_FORMAT; + return _chello; + } + } + /* Extensions */ + if (pos + 2 > buff_len) + { + *result = PARSE_CHELLO_INVALID_FORMAT; + return _chello; + } + len = ((size_t)buff[pos] << 8) + (size_t)buff[pos + 1]; + pos += 2; + if (pos + len > buff_len) + { + *result = PARSE_CHELLO_INVALID_FORMAT; + return _chello; + } + enum parse_chello_result rtn = parse_extensions(buff + pos, len, _chello); + *result = rtn; + return _chello; + } +} + +static enum parse_chello_result parse_extensions(const char* buff, size_t buff_len, struct chello* chello) { + size_t pos = 0; + /* Parse each 4 bytes for the extension header */ + while (pos + 4 <= buff_len) + { + size_t len = ((size_t)buff[pos + 2] << 8) + (size_t)buff[pos + 3]; + /* Check if it's a server name extension */ + if (buff[pos] == 0x00 && buff[pos + 1] == 0x00) + { + if (pos + 4 + len > buff_len) + { + return PARSE_CHELLO_INVALID_FORMAT; + } + pos + = 4; + enum parse_chello_result result = PARSE_CHELLO_SUCCESS; + chello->sni = parse_server_name_extension(data + pos, len, &result); + if(result != PARSE_CHELLO_SUCCESS) + { + return result; + } + } + /* Check if it's a alpn extension */ + if (buff[pos] == 0x00 && buff[pos + 1] == 0x10) + { + if (pos + 4 + len > buff_len) + { + return PARSE_CHELLO_INVALID_FORMAT; + } + pos + = 4; + enum parse_chello_result result = PARSE_CHELLO_SUCCESS; + chello->alpn = parse_alpn_extension(data + pos, len, &result); + if(result != PARSE_CHELLO_SUCCESS) + { + return result; + } + } + pos += len; + } + /* Check we ended where we expected to */ + if (pos != data_len) + { + return PARSE_CHELLO_INVALID_FORMAT; + } + return PARSE_CHELLO_SUCCESS; +} + +static const char* parse_cipher_suites(struct cipher_suite* _cipher_suite_list, int n, const char* buff, size_t buff_len, enum parse_chello_result* result) +{ + char* cipher_suites_str = malloc(TFE_STRING_MAX); + cipher_suites_str[0] = "\0"; + size_t pos = 0; + while(pos < buff_len) + { + int i = 0; + for(i = 0;i < n; i++) + { + int val = buff[pos] << 8 + buff[pos + 1]; + if(_cipher_suite_list[i].value == val) + { + strncat(cipher_suites_str, _cipher_suite_list[i].name, TFE_STRING_MAX); + } + } + pos += 2; + } + if(pos != buff_len) + { + *result = PARSE_CHELLO_INVALID_FORMAT; + return NULL; + } + *result = PARSE_CHELLO_SUCCESS; + return cipher_suites_str; +} + + +static const char* parse_alpn_extension(const char* buff, size_t buff_len, enum parse_chello_result* result) +{ + size_t len = ((size_t)buff[pos] << 8) + (size_t)buff[pos + 1]; + if(2 + len != buff_len) + { + *result = PARSE_CHELLO_INVALID_FORMAT; + return NULL; + } + char* alpn = malloc(len + 1); + strncpy(alpn, buff + 2, len); + alpn[len] = '\0'; + *result = PARSE_CHELLO_SUCCESS; + return alpn; +} + +static const char* parse_server_name_extension(const char* buff, size_t buff_len, enum parse_chello_result* result) +{ + size_t pos = 2; /* skip server name list length */ + size_t len; + const char* sni = NULL; + while (pos + 3 < buff_len) + { + len = ((size_t)buff[pos + 1] << 8) + (size_t)buff[pos + 2]; + if (pos + 3 + len > buff_len) + { + *result = PARSE_CHELLO_INVALID_FORMAT; + return NULL; + } + switch (buff[pos]) + { + case 0x00: /* host_name */ + sni = malloc(len + 1); + strncpy(sni, (const char *)(buff + pos + 3), len); + sni[len] = '\0'; + *result = PARSE_CHELLO_SUCCESS; + default: + sni = NULL; + } + pos += 3 + len; + } + if (pos != buff_len) + { + *result = PARSE_CHELLO_INVALID_FORMAT; + } + return sni; +} From 1fa1af6ce334c931a808d0ff5ae5ff344822cc29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B4=94=E4=B8=80=E9=B8=A3?= Date: Thu, 13 Sep 2018 20:10:21 +0800 Subject: [PATCH 2/5] fix bugs --- platform/CMakeLists.txt | 21 ++ platform/include/internal/ssl_utils.h | 27 +++ platform/src/ssl_utils.cc | 283 ++++++++++++-------------- platform/test/test_chello_parse.cpp | 154 ++++++++++++++ 4 files changed, 331 insertions(+), 154 deletions(-) create mode 100644 platform/test/test_chello_parse.cpp diff --git a/platform/CMakeLists.txt b/platform/CMakeLists.txt index bd9c376..dd8bbc8 100644 --- a/platform/CMakeLists.txt +++ b/platform/CMakeLists.txt @@ -60,3 +60,24 @@ target_link_libraries(test_tfe_rpc pthread dl MESA_field_stat) install(TARGETS test_tfe_rpc RUNTIME DESTINATION ./) + + +### test_chello_parse +add_executable(test_chello_parse test/test_chello_parse.cpp src/ssl_utils.cc) + +target_include_directories(test_chello_parse PRIVATE ${CMAKE_CURRENT_LIST_DIR}/include/internal) + +target_link_libraries(test_chello_parse common) +target_link_libraries(test_chello_parse pthread dl + openssl-ssl-static + openssl-crypto-static + pthread libevent-static + libevent-static-openssl + libevent-static-pthreads + MESA_handle_logger + MESA_prof_load + MESA_htable wiredcfg + cjson + MESA_field_stat) + +install(TARGETS test_chello_parse RUNTIME DESTINATION ./) diff --git a/platform/include/internal/ssl_utils.h b/platform/include/internal/ssl_utils.h index c1e50ae..4bd1377 100644 --- a/platform/include/internal/ssl_utils.h +++ b/platform/include/internal/ssl_utils.h @@ -178,4 +178,31 @@ int ssl_tls_clienthello_parse(const unsigned char *, ssize_t, int, int ssl_dnsname_match(const char *, size_t, const char *, size_t); char * ssl_wildcardify(const char *); + +enum parse_chello_result +{ + PARSE_CHELLO_INVALID_FORMAT = 0, + PARSE_CHELLO_NOT_ENOUGH_BUFF, + PARSE_CHELLO_SUCCESS +}; + +struct ssl_version +{ + uint8_t major; + uint8_t minor; +}; + +struct ssl_chello +{ + struct ssl_version record_layer_version; + struct ssl_version chello_version; + char* sni; + char* alpn; + char* cipher_suites; + char* cipher_suites_tls13; +}; +struct ssl_chello* ssl_chello_parse(const unsigned char* buff, size_t buff_len, enum parse_chello_result* result); + +void ssl_chello_free(struct ssl_chello* chello); + #endif /* !SSL_H */ diff --git a/platform/src/ssl_utils.cc b/platform/src/ssl_utils.cc index 5549eb0..17bf877 100644 --- a/platform/src/ssl_utils.cc +++ b/platform/src/ssl_utils.cc @@ -1648,7 +1648,7 @@ int ssl_is_ocspreq(const unsigned char * buf, size_t sz) struct cipher_suite { int value; - char* name; + const char* name; }; struct cipher_suite cipher_suite_list[] = @@ -1782,30 +1782,6 @@ struct cipher_suite cipher_suite_list_tls13[] = {0x1305, "TLS_AES_128_CCM_8_SHA256"} }; -enum parse_chello_result -{ - PARSE_CHELLO_INVALID_FORMAT = 0, - PARSE_CHELLO_NOT_ENOUGH_BUFF, - PARSE_CHELLO_SUCCESS -}; - - -struct ssl_version -{ - int major; - int minor; -}; - -struct ssl_chello -{ - struct ssl_version record_layer_version; - struct ssl_version chello_version; - char* sni; - char* alpn; - char* cipher_suites; - char* cipher_suites_tls13; -}; - void ssl_chello_free(struct ssl_chello* chello) { @@ -1820,21 +1796,141 @@ void ssl_chello_free(struct ssl_chello* chello) free(chello); } -struct chello* ssl_chello_parse(const char* buff, size_t buff_len, enum parse_chello_result* result) +static char* parse_alpn_extension(const unsigned char* buff, size_t buff_len, enum parse_chello_result* result) +{ + size_t pos = 0; + size_t len = ((size_t)buff[pos] << 8) + (size_t)buff[pos + 1]; + if(2 + len != buff_len) + { + *result = PARSE_CHELLO_INVALID_FORMAT; + return NULL; + } + char* alpn = (char*)malloc(len + 1); + strncpy(alpn, (const char*)buff + 2, len); + alpn[len] = '\0'; + *result = PARSE_CHELLO_SUCCESS; + return alpn; +} + +static char* parse_server_name_extension(const unsigned char* buff, size_t buff_len, enum parse_chello_result* result) +{ + size_t pos = 2; /* skip server name list length */ + size_t len; + char* sni = NULL; + while (pos + 3 < buff_len) + { + len = ((size_t)buff[pos + 1] << 8) + (size_t)buff[pos + 2]; + if (pos + 3 + len > buff_len) + { + *result = PARSE_CHELLO_INVALID_FORMAT; + return NULL; + } + switch (buff[pos]) + { + case 0x00: /* host_name */ + sni = (char*)malloc(len + 1); + strncpy(sni, (const char*)buff + pos + 3, len); + sni[len] = '\0'; + *result = PARSE_CHELLO_SUCCESS; + } + pos += 3 + len; + } + if (pos != buff_len) + { + *result = PARSE_CHELLO_INVALID_FORMAT; + } + return sni; +} + +static enum parse_chello_result parse_extensions(const unsigned char* buff, size_t buff_len, struct ssl_chello* chello) { + size_t pos = 0; + /* Parse each 4 bytes for the extension header */ + while (pos + 4 <= buff_len) + { + size_t len = ((size_t)buff[pos + 2] << 8) + (size_t)buff[pos + 3]; + /* Check if it's a server name extension */ + if (buff[pos] == 0x00 && buff[pos + 1] == 0x00) + { + if (pos + 4 + len > buff_len) + { + return PARSE_CHELLO_INVALID_FORMAT; + } + enum parse_chello_result result = PARSE_CHELLO_SUCCESS; + chello->sni = parse_server_name_extension(buff + pos + 4, len, &result); + if(result != PARSE_CHELLO_SUCCESS) + { + return result; + } + } + /* Check if it's a alpn extension */ + if (buff[pos] == 0x00 && buff[pos + 1] == 0x10) + { + if (pos + 4 + len > buff_len) + { + return PARSE_CHELLO_INVALID_FORMAT; + } + enum parse_chello_result result = PARSE_CHELLO_SUCCESS; + chello->alpn = parse_alpn_extension(buff + pos + 4, len, &result); + if(result != PARSE_CHELLO_SUCCESS) + { + return result; + } + } + pos += (4 + len); + } + /* Check we ended where we expected to */ + if (pos != buff_len) + { + return PARSE_CHELLO_INVALID_FORMAT; + } + return PARSE_CHELLO_SUCCESS; +} + +static char* parse_cipher_suites(struct cipher_suite* _cipher_suite_list, int n, const unsigned char* buff, size_t buff_len, enum parse_chello_result* result) +{ + char* cipher_suites_str = (char* )malloc(TFE_STRING_MAX); + cipher_suites_str[0] = '\0'; + size_t pos = 0; + while(pos < buff_len) + { + int i = 0; + for(i = 0;i < n; i++) + { + int val = (buff[pos] << 8) + buff[pos + 1]; + if(_cipher_suite_list[i].value == val) + { + strncat(cipher_suites_str, _cipher_suite_list[i].name, TFE_STRING_MAX); + strncat(cipher_suites_str, ":", TFE_STRING_MAX); + } + } + pos += 2; + } + int len = strnlen(cipher_suites_str, TFE_STRING_MAX); + cipher_suites_str[len-1] = '\0'; + if(pos != buff_len) + { + *result = PARSE_CHELLO_INVALID_FORMAT; + return NULL; + } + *result = PARSE_CHELLO_SUCCESS; + return cipher_suites_str; +} + +struct ssl_chello* ssl_chello_parse(const unsigned char* buff, size_t buff_len, enum parse_chello_result* result) { if(buff == NULL) { - result = PARSE_CHELLO_INVALID_FORMAT; + *result = PARSE_CHELLO_INVALID_FORMAT; return NULL; } if(buff_len < 1) { - result = PARSE_CHELLO_NOT_ENOUGH_BUFF; + *result = PARSE_CHELLO_NOT_ENOUGH_BUFF; return NULL; } if(buff[0] != 0x80 && buff[0] != 0x16) { - result = PARSE_CHELLO_INVALID_FORMAT; + *result = PARSE_CHELLO_INVALID_FORMAT; return NULL; } /* SSL 2.0 compatible Client Hello @@ -1844,7 +1940,7 @@ struct chello* ssl_chello_parse(const char* buff, size_t buff_len, enum parse_ch */ if(buff[0] == 0x80) { - struct chello* _chello = (struct chello*)ALLOC(struct chello, 1); + struct ssl_chello* _chello = (struct ssl_chello*)ALLOC(struct ssl_chello, 1); _chello->record_layer_version.major = 0x02; if(buff_len < 2) { @@ -1894,7 +1990,7 @@ struct chello* ssl_chello_parse(const char* buff, size_t buff_len, enum parse_ch *result = PARSE_CHELLO_INVALID_FORMAT; return NULL; } - struct chello* _chello = (struct chello*)ALLOC(struct chello, 1); + struct ssl_chello* _chello = (struct ssl_chello*)ALLOC(struct ssl_chello, 1); _chello->record_layer_version.major = buff[1]; _chello->record_layer_version.minor = buff[2]; _chello->chello_version.major = -1; @@ -1904,7 +2000,7 @@ struct chello* ssl_chello_parse(const char* buff, size_t buff_len, enum parse_ch _chello->cipher_suites = NULL; _chello->cipher_suites_tls13 = NULL; /* TLS record length */ - size_t len = ((size_t)buf[3] << 8) + (size_t)buf[4] + 5; + size_t len = ((size_t)buff[3] << 8) + (size_t)buff[4] + 5; if (buff_len < len) { *result = PARSE_CHELLO_NOT_ENOUGH_BUFF; @@ -1959,7 +2055,7 @@ struct chello* ssl_chello_parse(const char* buff, size_t buff_len, enum parse_ch return _chello; } n = sizeof(cipher_suite_list_tls13) / sizeof(struct cipher_suite); - _chello->cipher_suites_tls13 = parse_cipher_suites_tls13(cipher_suite_list_tls13, n, buff + pos, len, result); + _chello->cipher_suites_tls13 = parse_cipher_suites(cipher_suite_list_tls13, n, buff + pos, len, result); if(*result != PARSE_CHELLO_SUCCESS) { return _chello; @@ -2005,124 +2101,3 @@ struct chello* ssl_chello_parse(const char* buff, size_t buff_len, enum parse_ch return _chello; } } - -static enum parse_chello_result parse_extensions(const char* buff, size_t buff_len, struct chello* chello) { - size_t pos = 0; - /* Parse each 4 bytes for the extension header */ - while (pos + 4 <= buff_len) - { - size_t len = ((size_t)buff[pos + 2] << 8) + (size_t)buff[pos + 3]; - /* Check if it's a server name extension */ - if (buff[pos] == 0x00 && buff[pos + 1] == 0x00) - { - if (pos + 4 + len > buff_len) - { - return PARSE_CHELLO_INVALID_FORMAT; - } - pos + = 4; - enum parse_chello_result result = PARSE_CHELLO_SUCCESS; - chello->sni = parse_server_name_extension(data + pos, len, &result); - if(result != PARSE_CHELLO_SUCCESS) - { - return result; - } - } - /* Check if it's a alpn extension */ - if (buff[pos] == 0x00 && buff[pos + 1] == 0x10) - { - if (pos + 4 + len > buff_len) - { - return PARSE_CHELLO_INVALID_FORMAT; - } - pos + = 4; - enum parse_chello_result result = PARSE_CHELLO_SUCCESS; - chello->alpn = parse_alpn_extension(data + pos, len, &result); - if(result != PARSE_CHELLO_SUCCESS) - { - return result; - } - } - pos += len; - } - /* Check we ended where we expected to */ - if (pos != data_len) - { - return PARSE_CHELLO_INVALID_FORMAT; - } - return PARSE_CHELLO_SUCCESS; -} - -static const char* parse_cipher_suites(struct cipher_suite* _cipher_suite_list, int n, const char* buff, size_t buff_len, enum parse_chello_result* result) -{ - char* cipher_suites_str = malloc(TFE_STRING_MAX); - cipher_suites_str[0] = "\0"; - size_t pos = 0; - while(pos < buff_len) - { - int i = 0; - for(i = 0;i < n; i++) - { - int val = buff[pos] << 8 + buff[pos + 1]; - if(_cipher_suite_list[i].value == val) - { - strncat(cipher_suites_str, _cipher_suite_list[i].name, TFE_STRING_MAX); - } - } - pos += 2; - } - if(pos != buff_len) - { - *result = PARSE_CHELLO_INVALID_FORMAT; - return NULL; - } - *result = PARSE_CHELLO_SUCCESS; - return cipher_suites_str; -} - - -static const char* parse_alpn_extension(const char* buff, size_t buff_len, enum parse_chello_result* result) -{ - size_t len = ((size_t)buff[pos] << 8) + (size_t)buff[pos + 1]; - if(2 + len != buff_len) - { - *result = PARSE_CHELLO_INVALID_FORMAT; - return NULL; - } - char* alpn = malloc(len + 1); - strncpy(alpn, buff + 2, len); - alpn[len] = '\0'; - *result = PARSE_CHELLO_SUCCESS; - return alpn; -} - -static const char* parse_server_name_extension(const char* buff, size_t buff_len, enum parse_chello_result* result) -{ - size_t pos = 2; /* skip server name list length */ - size_t len; - const char* sni = NULL; - while (pos + 3 < buff_len) - { - len = ((size_t)buff[pos + 1] << 8) + (size_t)buff[pos + 2]; - if (pos + 3 + len > buff_len) - { - *result = PARSE_CHELLO_INVALID_FORMAT; - return NULL; - } - switch (buff[pos]) - { - case 0x00: /* host_name */ - sni = malloc(len + 1); - strncpy(sni, (const char *)(buff + pos + 3), len); - sni[len] = '\0'; - *result = PARSE_CHELLO_SUCCESS; - default: - sni = NULL; - } - pos += 3 + len; - } - if (pos != buff_len) - { - *result = PARSE_CHELLO_INVALID_FORMAT; - } - return sni; -} diff --git a/platform/test/test_chello_parse.cpp b/platform/test/test_chello_parse.cpp new file mode 100644 index 0000000..ab793a6 --- /dev/null +++ b/platform/test/test_chello_parse.cpp @@ -0,0 +1,154 @@ + +#include "ssl_utils.h" +#include "tfe_utils.h" +#include +#include +#include + +char* parse_alpn(const char* alpn) +{ + int size = strlen(alpn); + char* result = (char*)malloc(100); + result[0] = '\0'; + int i = 0; + for(i = 0;i < size; ) + { + int size1 = alpn[i]; + strncat(result, alpn + i + 1, size1); + strncat(result, ", ", 2); + i += (1 + size1); + } + int size2 = strlen(result); + result[size2] = '\0'; + return result; +} +int main() +{ + + //ssl2.0 + unsigned char buff[] = + { + 0x80, 0x77, 0x01, 0x03, 0x01, 0x00, 0x4e, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x39, 0x00, 0x00, 0x38, 0x00, 0x00, 0x35, + 0x00, 0x00, 0x16, 0x00, 0x00, 0x13, 0x00, 0x00, 0x0a, 0x07, + 0x00, 0xc0, 0x00, 0x00, 0x33, 0x00, 0x00, 0x32, 0x00, 0x00, + 0x2f, 0x03, 0x00, 0x80, 0x00, 0x00, 0x05, 0x00, 0x00, 0x04, + 0x01, 0x00, 0x80, 0x00, 0x00, 0x15, 0x00, 0x00, 0x12, 0x00, + 0x00, 0x09, 0x06, 0x00, 0x40, 0x00, 0x00, 0x14, 0x00, 0x00, + 0x11, 0x00, 0x00, 0x08, 0x00, 0x00, 0x06, 0x04, 0x00, 0x80, + 0x00, 0x00, 0x03, 0x02, 0x00, 0x80, 0x00, 0x00, 0xff, 0xe2, + 0xd8, 0x90, 0x3f, 0xbd, 0x26, 0x76, 0xb2, 0xf3, 0x8b, 0x1b, + 0x36, 0xed, 0x29, 0x04, 0x8d, 0x72, 0x1a, 0xe7, 0xc4, 0xd5, + 0xbc, 0x56, 0xb1, 0x63, 0x8e, 0x8d, 0x9e, 0x08, 0x74, 0xb9, + 0x69 + }; + size_t buff_len = sizeof(buff) / sizeof(char); + enum parse_chello_result result; + struct ssl_chello* chello = ssl_chello_parse(buff, buff_len, &result); + printf("-----------------------------ssl2.0 only parse version --------------------------------\n"); + printf("record layer version is %d, %d\n", chello->record_layer_version.major, chello->record_layer_version.minor); + printf("\n\n"); + ssl_chello_free(chello); + chello = NULL; + + //ssl3.0, no extensions + unsigned char buff1[] = + { + 0x16, 0x03, 0x00, 0x00, 0x51, 0x01, 0x00, 0x00, 0x4d, 0x03, + 0x00, 0x50, 0x42, 0xb2, 0x29, 0x1f, 0xcf, 0x52, 0xa0, 0x94, + 0x87, 0x05, 0xe7, 0x0b, 0x63, 0x08, 0x12, 0xa2, 0x6c, 0x59, + 0xf7, 0xf5, 0x72, 0x2b, 0x57, 0x14, 0xa7, 0x07, 0x95, 0xcb, + 0xce, 0xe5, 0xe4, 0x00, 0x00, 0x26, 0x00, 0x04, 0x00, 0x05, + 0x00, 0x2f, 0x00, 0x33, 0x00, 0x32, 0x00, 0x0a, 0xfe, 0xff, + 0x00, 0x16, 0x00, 0x13, 0x00, 0x66, 0x00, 0x09, 0xfe, 0xfe, + 0x00, 0x15, 0x00, 0x12, 0x00, 0x03, 0x00, 0x08, 0x00, 0x06, + 0x00, 0x14, 0x00, 0x11, 0x01, 0x00 + }; + size_t buff1_len = sizeof(buff1) / sizeof(char); + enum parse_chello_result result1; + struct ssl_chello* chello1 = ssl_chello_parse(buff1, buff1_len, &result1); + printf("--------------------------------ssl3.0, no extensions --------------------------------\n"); + printf("record layer version is %d, %d\n", chello1->record_layer_version.major, chello1->record_layer_version.minor); + printf("client hello version: %d, %d\n", chello1->chello_version.major, chello1->chello_version.minor); + printf("cipher suites is %s\n", chello1->cipher_suites); + if(chello1->cipher_suites_tls13) + { + printf("cipher suites for tls1.3 is %s\n", chello1->cipher_suites_tls13); + } + printf("\n\n"); + ssl_chello_free(chello1); + chello1 = NULL; + + //tls1.2 + unsigned char buff2[] = + { + 0x16, 0x03, 0x01, 0x02, 0x00, 0x01, 0x00, 0x01, 0xfc, 0x03, + 0x03, 0x30, 0x6d, 0x1d, 0xd5, 0x0d, 0xa6, 0x1e, 0x0b, 0xe6, + 0xf7, 0xf0, 0xd3, 0xfa, 0x14, 0xdc, 0x80, 0x24, 0xe5, 0x34, + 0x2d, 0x9c, 0x68, 0x6b, 0x0a, 0x40, 0x59, 0xc6, 0x2c, 0xbb, + 0xf1, 0x04, 0xee, 0x20, 0xc4, 0x33, 0x03, 0x91, 0xa9, 0x0d, + 0xfa, 0xae, 0x93, 0x9b, 0xbe, 0x22, 0x7c, 0x99, 0x5f, 0xaf, + 0xdc, 0xe1, 0x14, 0xab, 0xbc, 0x57, 0x1f, 0x7f, 0xe0, 0x5c, + 0x59, 0xe3, 0x8b, 0xaa, 0x70, 0xf8, 0x00, 0x22, 0x5a, 0x5a, + 0x13, 0x01, 0x13, 0x02, 0x13, 0x03, 0xc0, 0x2b, 0xc0, 0x2f, + 0xc0, 0x2c, 0xc0, 0x30, 0xcc, 0xa9, 0xcc, 0xa8, 0xc0, 0x13, + 0xc0, 0x14, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x2f, 0x00, 0x35, + 0x00, 0x0a, 0x01, 0x00, 0x01, 0x91, 0xea, 0xea, 0x00, 0x00, + 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, + 0x10, 0x00, 0x00, 0x0d, 0x77, 0x77, 0x77, 0x2e, 0x62, 0x61, + 0x69, 0x64, 0x75, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x17, 0x00, + 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x14, 0x00, + 0x12, 0x04, 0x03, 0x08, 0x04, 0x04, 0x01, 0x05, 0x03, 0x08, + 0x05, 0x05, 0x01, 0x08, 0x06, 0x06, 0x01, 0x02, 0x01, 0x00, + 0x05, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x0e, 0x00, 0x0c, 0x02, 0x68, + 0x32, 0x08, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31, + 0x75, 0x50, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, + 0x00, 0x33, 0x00, 0x2b, 0x00, 0x29, 0xea, 0xea, 0x00, 0x01, + 0x00, 0x00, 0x1d, 0x00, 0x20, 0x1b, 0xae, 0xc9, 0x4f, 0x17, + 0x30, 0xf2, 0xec, 0x4c, 0xc1, 0xdb, 0xf7, 0xe4, 0x72, 0xad, + 0x22, 0xa8, 0xe9, 0x2c, 0x67, 0x4d, 0x8a, 0x87, 0x22, 0xd1, + 0x65, 0x2f, 0x08, 0xef, 0x01, 0xd9, 0x73, 0x00, 0x2d, 0x00, + 0x02, 0x01, 0x01, 0x00, 0x2b, 0x00, 0x0b, 0x0a, 0x1a, 0x1a, + 0x7f, 0x17, 0x03, 0x03, 0x03, 0x02, 0x03, 0x01, 0x00, 0x0a, + 0x00, 0x0a, 0x00, 0x08, 0xea, 0xea, 0x00, 0x1d, 0x00, 0x17, + 0x00, 0x18, 0x00, 0x1b, 0x00, 0x03, 0x02, 0x00, 0x02, 0xaa, + 0xaa, 0x00, 0x01, 0x00, 0x00, 0x15, 0x00, 0xc7, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + size_t buff2_len = sizeof(buff2) / sizeof(char); + enum parse_chello_result result2; + struct ssl_chello* chello2 = ssl_chello_parse(buff2, buff2_len, &result2); + printf("---------------------------tls1.2 --------------------------------\n"); + printf("record layer version: %d, %d\n", chello2->record_layer_version.major, chello2->record_layer_version.minor); + printf("client hello version: %d, %d\n", chello2->chello_version.major, chello2->chello_version.minor); + printf("cipher suites: %s\n", chello2->cipher_suites); + printf("cipher suites for tls1.3: %s\n", chello2->cipher_suites_tls13); + printf("sni: %s\n", chello2->sni); + char* alpn = parse_alpn(chello2->alpn); + printf("alpn: %s\n", alpn); + free(alpn); + alpn = NULL; + printf("\n\n"); + ssl_chello_free(chello2); + chello2 = NULL; +} From 58a525215b1d4caceeb34f8df5429ab2d4851d30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B4=94=E4=B8=80=E9=B8=A3?= Date: Thu, 13 Sep 2018 20:25:12 +0800 Subject: [PATCH 3/5] change int to size_t --- common/include/tfe_rpc.h | 2 +- common/src/tfe_rpc.cpp | 2 +- platform/src/key_keeper.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common/include/tfe_rpc.h b/common/include/tfe_rpc.h index 1c7de0d..3d3a5b2 100644 --- a/common/include/tfe_rpc.h +++ b/common/include/tfe_rpc.h @@ -6,7 +6,7 @@ struct tfe_rpc_response_result{ int status_code; const char* status_msg; char* data; - int len; + size_t len; }; enum TFE_RPC_FLAG diff --git a/common/src/tfe_rpc.cpp b/common/src/tfe_rpc.cpp index d49da9a..e511ace 100644 --- a/common/src/tfe_rpc.cpp +++ b/common/src/tfe_rpc.cpp @@ -93,7 +93,7 @@ void read_chunk_cb(struct evhttp_request* response, void* arg) { return; } - int evbuf_len = evbuffer_get_length(evbuf); + size_t evbuf_len = evbuffer_get_length(evbuf); char* data = (char*)evbuffer_pullup(evbuf, evbuf_len); //printf("data is %s\n", data==NULL ? "NULL":"NOT NULL"); struct tfe_rpc_response_result* result = ALLOC(struct tfe_rpc_response_result, 1); diff --git a/platform/src/key_keeper.cpp b/platform/src/key_keeper.cpp index aa163fd..1124c1d 100644 --- a/platform/src/key_keeper.cpp +++ b/platform/src/key_keeper.cpp @@ -352,7 +352,7 @@ static void certstore_rpc_on_succ(void* result, void* user) int status_code = response->status_code; const char* status_msg = response->status_msg; char* data = response->data; - int len = response->len; + size_t len = response->len; if(status_code == HTTP_OK) { *(data+len) = '\0'; From a8fce0770f74a3e12061598417aa74a7e112df6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B4=94=E4=B8=80=E9=B8=A3?= Date: Fri, 14 Sep 2018 14:09:37 +0800 Subject: [PATCH 4/5] fix bugs --- platform/include/internal/ssl_utils.h | 10 +++++----- platform/src/ssl_utils.cc | 20 ++++++++++---------- platform/test/test_chello_parse.cpp | 13 ++++++++----- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/platform/include/internal/ssl_utils.h b/platform/include/internal/ssl_utils.h index 4bd1377..6f4aea9 100644 --- a/platform/include/internal/ssl_utils.h +++ b/platform/include/internal/ssl_utils.h @@ -181,9 +181,9 @@ char * ssl_wildcardify(const char *); enum parse_chello_result { - PARSE_CHELLO_INVALID_FORMAT = 0, - PARSE_CHELLO_NOT_ENOUGH_BUFF, - PARSE_CHELLO_SUCCESS + PARSE_CHELLO_SUCCESS = 0, + PARSE_CHELLO_INVALID_FORMAT = -1, + PARSE_CHELLO_NOT_ENOUGH_BUFF = -2 }; struct ssl_version @@ -194,8 +194,8 @@ struct ssl_version struct ssl_chello { - struct ssl_version record_layer_version; - struct ssl_version chello_version; + struct ssl_version min_version; + struct ssl_version max_version; char* sni; char* alpn; char* cipher_suites; diff --git a/platform/src/ssl_utils.cc b/platform/src/ssl_utils.cc index 17bf877..b3a4358 100644 --- a/platform/src/ssl_utils.cc +++ b/platform/src/ssl_utils.cc @@ -1941,7 +1941,7 @@ struct ssl_chello* ssl_chello_parse(const unsigned char* buff, size_t buff_len, if(buff[0] == 0x80) { struct ssl_chello* _chello = (struct ssl_chello*)ALLOC(struct ssl_chello, 1); - _chello->record_layer_version.major = 0x02; + _chello->min_version.major = 0x02; if(buff_len < 2) { *result = PARSE_CHELLO_NOT_ENOUGH_BUFF; @@ -1973,8 +1973,8 @@ struct ssl_chello* ssl_chello_parse(const unsigned char* buff, size_t buff_len, *result = PARSE_CHELLO_INVALID_FORMAT; return _chello; } - _chello->chello_version.major = buff[pos]; - _chello->chello_version.minor = buff[pos + 1]; + _chello->max_version.major = buff[pos]; + _chello->max_version.minor = buff[pos + 1]; *result = PARSE_CHELLO_SUCCESS; return _chello; } @@ -1991,10 +1991,10 @@ struct ssl_chello* ssl_chello_parse(const unsigned char* buff, size_t buff_len, return NULL; } struct ssl_chello* _chello = (struct ssl_chello*)ALLOC(struct ssl_chello, 1); - _chello->record_layer_version.major = buff[1]; - _chello->record_layer_version.minor = buff[2]; - _chello->chello_version.major = -1; - _chello->chello_version.minor = -1; + _chello->min_version.major = buff[1]; + _chello->min_version.minor = buff[2]; + _chello->max_version.major = -1; + _chello->max_version.minor = -1; _chello->sni = NULL; _chello->alpn = NULL; _chello->cipher_suites = NULL; @@ -2024,8 +2024,8 @@ struct ssl_chello* ssl_chello_parse(const unsigned char* buff, size_t buff_len, *result = PARSE_CHELLO_INVALID_FORMAT; return _chello; } - _chello->chello_version.major = buff[pos]; - _chello->chello_version.minor = buff[pos+1]; + _chello->max_version.major = buff[pos]; + _chello->max_version.minor = buff[pos+1]; pos += 34; /* Session ID */ if (pos + 1 > buff_len) @@ -2070,7 +2070,7 @@ struct ssl_chello* ssl_chello_parse(const unsigned char* buff, size_t buff_len, len = (size_t)buff[pos]; pos += 1 + len; /* ssl 3.0, no extensions */ - if(_chello->record_layer_version.major == 3 && _chello->record_layer_version.minor == 0) + if(_chello->min_version.major == 3 && _chello->min_version.minor == 0) { if(pos == buff_len) { diff --git a/platform/test/test_chello_parse.cpp b/platform/test/test_chello_parse.cpp index ab793a6..cff41db 100644 --- a/platform/test/test_chello_parse.cpp +++ b/platform/test/test_chello_parse.cpp @@ -46,7 +46,8 @@ int main() enum parse_chello_result result; struct ssl_chello* chello = ssl_chello_parse(buff, buff_len, &result); printf("-----------------------------ssl2.0 only parse version --------------------------------\n"); - printf("record layer version is %d, %d\n", chello->record_layer_version.major, chello->record_layer_version.minor); + printf("result is %d\n", result); + printf("min version is %d, %d\n", chello->min_version.major, chello->min_version.minor); printf("\n\n"); ssl_chello_free(chello); chello = NULL; @@ -68,8 +69,9 @@ int main() enum parse_chello_result result1; struct ssl_chello* chello1 = ssl_chello_parse(buff1, buff1_len, &result1); printf("--------------------------------ssl3.0, no extensions --------------------------------\n"); - printf("record layer version is %d, %d\n", chello1->record_layer_version.major, chello1->record_layer_version.minor); - printf("client hello version: %d, %d\n", chello1->chello_version.major, chello1->chello_version.minor); + printf("result is %d\n", result1); + printf("min version is %d, %d\n", chello1->min_version.major, chello1->min_version.minor); + printf("max version: %d, %d\n", chello1->max_version.major, chello1->max_version.minor); printf("cipher suites is %s\n", chello1->cipher_suites); if(chello1->cipher_suites_tls13) { @@ -139,8 +141,9 @@ int main() enum parse_chello_result result2; struct ssl_chello* chello2 = ssl_chello_parse(buff2, buff2_len, &result2); printf("---------------------------tls1.2 --------------------------------\n"); - printf("record layer version: %d, %d\n", chello2->record_layer_version.major, chello2->record_layer_version.minor); - printf("client hello version: %d, %d\n", chello2->chello_version.major, chello2->chello_version.minor); + printf("result is %d\n", result2); + printf("min version: %d, %d\n", chello2->min_version.major, chello2->min_version.minor); + printf("max version: %d, %d\n", chello2->max_version.major, chello2->max_version.minor); printf("cipher suites: %s\n", chello2->cipher_suites); printf("cipher suites for tls1.3: %s\n", chello2->cipher_suites_tls13); printf("sni: %s\n", chello2->sni); From 23fdab53a7d9e304ca2bdecb417e9440b4067b31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B4=94=E4=B8=80=E9=B8=A3?= Date: Fri, 14 Sep 2018 16:58:19 +0800 Subject: [PATCH 5/5] fix bugs --- platform/src/key_keeper.cpp | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/platform/src/key_keeper.cpp b/platform/src/key_keeper.cpp index 1124c1d..a8612ac 100644 --- a/platform/src/key_keeper.cpp +++ b/platform/src/key_keeper.cpp @@ -234,7 +234,7 @@ static void err_out(X509* cert, EVP_PKEY* key, STACK_OF(X509)* chain) return; } -static struct keyring* get_keyring_from_response(const char* data) +static struct keyring_private* get_keyring_from_response(const char* data) { X509* cert = NULL; EVP_PKEY* key = NULL; @@ -300,7 +300,7 @@ static struct keyring* get_keyring_from_response(const char* data) X509_free(cert); EVP_PKEY_free(key); sk_X509_pop_free(chain, X509_free); - return &(_kyr->head); + return _kyr; } static long keyring_local_cache_query_cb(void * data, const uchar * key, uint size, void * user_arg) @@ -356,13 +356,15 @@ static void certstore_rpc_on_succ(void* result, void* user) if(status_code == HTTP_OK) { *(data+len) = '\0'; - struct keyring* kyr= get_keyring_from_response(data); - promise_success(p, (void*)kyr); + struct keyring_private* kyr= get_keyring_from_response(data); + keyring_ref_inc(kyr); int ret = MESA_htable_add(htable, key, key_len, (void*)kyr); if(ret<0) { key_keeper_free_keyring((struct keyring*)kyr); } + promise_success(p, (void*)kyr); + key_keeper_free_keyring((struct keyring*)kyr); } else { @@ -516,15 +518,17 @@ void key_keeper_async_ask(struct future * f, struct key_keeper * keeper, const c { filename = keeper->untrusted_ca_path; } - struct keyring_private* ring = generate_x509_keyring(origin_cert, keyring_id, filename); - if(ring) + struct keyring_private* kyr = generate_x509_keyring(origin_cert, keyring_id, filename); + if(kyr) { - promise_success(p, (void*)ring); - int ret = MESA_htable_add(ctx->htable, ctx->key, ctx->key_len, (void*)ring); - if(ret<0) + keyring_ref_inc(kyr); + int ret = MESA_htable_add(ctx->htable, ctx->key, ctx->key_len, (void*)kyr); + if(ret < 0) { - key_keeper_free_keyring((struct keyring*)ring); + key_keeper_free_keyring((struct keyring*)kyr); } + promise_success(p, (void*)kyr); + key_keeper_free_keyring((struct keyring*)kyr); } else {