Hi Thierry,
On Sat, Feb 25, 2017 at 01:01:54PM +0100, [email protected] wrote:
> The patch implementing this idea is in attachment. It returns the
> client-hello cioher list as binary, hexadecimal string, xxh64 and with
> the decoded ciphers.
Is this supposed to be the last version ? I'm asking because it's still
bogus regarding the length calculation :
> +static inline
> +void ssl_sock_parse_clienthello(int write_p, int version, int content_type,
> + const void *buf, size_t len,
> + struct ssl_capture *capture)
> +{
> + unsigned char *msg;
> + unsigned char *end;
> + unsigned int rec_len;
> +
> + /* This function is called for "from client" and "to server"
> + * connections. The combination of write_p == 0 and content_type == 22
> + * is only avalaible during "from client" connection.
> + */
> +
> + /* "write_p" is set to 0 is the bytes are received messages,
> + * otherwise it is set to 1.
> + */
> + if (write_p != 0)
> + return;
> +
> + /* content_type contains the type of message received or sent
> + * according with the SSL/TLS protocol spec. This message is
> + * encoded with one byte. The value 256 (two bytes) is used
> + * for designing the SSL/TLS record layer. According with the
> + * rfc6101, the expected message (other than 256) are:
> + * - change_cipher_spec(20)
> + * - alert(21)
> + * - handshake(22)
> + * - application_data(23)
> + * - (255)
> + * We are interessed by the handshake and specially the client
> + * hello.
> + */
> + if (content_type != 22)
> + return;
> +
> + /* The message length is at least 4 bytes, containing the
> + * message type and the message length.
> + */
> + if (len < 4)
> + return;
> +
> + /* First byte of the handshake message id the type of
> + * message. The konwn types are:
> + * - hello_request(0)
> + * - client_hello(1)
> + * - server_hello(2)
> + * - certificate(11)
> + * - server_key_exchange (12)
> + * - certificate_request(13)
> + * - server_hello_done(14)
> + * We are interested by the client hello.
> + */
> + msg = (unsigned char *)buf;
> + if (msg[0] != 1)
> + return;
> +
> + /* Next three bytes are the length of the message. The total length
> + * must be this decoded length + 4. If the length given as argument
> + * is not the same, we abort the protocol dissector.
> + */
> + rec_len = (msg[1] << 3) + (msg[2] << 2) + msg[3];
Here. The correct statement is :
rec_len = msg[1] * 65536 + msg[2] * 256 + msg[3];
(or << 16, << 8)
> + if (len < rec_len + 4)
> + return;
> + msg += 4;
> + end = msg + rec_len;
> + if (end <= msg)
> + return;
This one looks wrong as it prevents rec_len from being NULL, the
correct overflow test is if (end < msg).
> + /* Expect 2 bytes for protocol version (1 byte for major and 1 byte
> + * for minor, the random, composed by 4 bytes for the unix time and
> + * 28 bytes for unix payload, and them 1 byte for the session id. So
> + * we jump 1 + 1 + 4 + 28 + 1 bytes.
> + */
> + msg += 1 + 1 + 4 + 28 + 1;
> + if (msg >= end)
> + return;
It seems like this one should be "if (msg > end)" given that it accounts for
a length. However given that it's covered by the next one, maybe it can
simply be dropped.
> + /* Next two bytes are the ciphersuite length. */
> + if (msg + 2 > end)
> + return;
> + rec_len = (msg[0] << 2) + msg[1];
Wrong shift again.
> + msg += 2;
> + if (msg + rec_len > end || msg + rec_len < msg)
> + return;
> +
> + /* Compute the xxh64 of the ciphersuite. */
> + capture->xxh64 = XXH64(msg, rec_len, 0);
> +
> + /* Capture the ciphersuite. */
> + capture->ciphersuite_len = rec_len;
> + if (capture->ciphersuite_len > global_ssl.capture_cipherlist)
> + capture->ciphersuite_len = global_ssl.capture_cipherlist;
> + memcpy(capture->ciphersuite, msg, capture->ciphersuite_len);
> +}
> +
The rest looks OK though. Just let me know.
Thanks,
Willy