diff options
Diffstat (limited to '')
-rw-r--r-- | tests/tls13/ext-parse.h | 229 |
1 files changed, 229 insertions, 0 deletions
diff --git a/tests/tls13/ext-parse.h b/tests/tls13/ext-parse.h new file mode 100644 index 0000000..9a22de5 --- /dev/null +++ b/tests/tls13/ext-parse.h @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2017 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuTLS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ + +#include "utils.h" + +#define TLS_EXT_SUPPORTED_VERSIONS 43 +#define TLS_EXT_POST_HANDSHAKE 49 + +#define SKIP16(pos, _total) { \ + uint16_t _s; \ + if ((size_t)pos+2 > (size_t)_total) fail("error0: at %d total: %d\n", pos+2, _total); \ + _s = (msg->data[pos] << 8) | msg->data[pos+1]; \ + if ((size_t)(pos+2+_s) > (size_t)_total) fail("error1: at %d field: %d, total: %d\n", pos+2, (int)_s, _total); \ + pos += 2+_s; \ + } + +#define SKIP8(pos, _total) { \ + uint8_t _s; \ + if ((size_t)pos+1 > (size_t)_total) fail("error\n"); \ + _s = msg->data[pos]; \ + if ((size_t)(pos+1+_s) > (size_t)_total) fail("error\n"); \ + pos += 1+_s; \ + } + +typedef void (*ext_parse_func)(void *priv, gnutls_datum_t *extdata); + +#define HANDSHAKE_SESSION_ID_POS 34 + +#if defined __clang__ || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-function" +#endif + +/* Returns 0 if the extension was not found, 1 otherwise. + */ +static unsigned find_client_extension(const gnutls_datum_t *msg, unsigned extnr, void *priv, ext_parse_func cb) +{ + unsigned pos; + + if (msg->size < HANDSHAKE_SESSION_ID_POS) + fail("invalid client hello\n"); + + /* we expect the legacy version to be present */ + /* ProtocolVersion legacy_version = 0x0303 */ + if (msg->data[0] != 0x03) { + fail("ProtocolVersion contains %d.%d\n", (int)msg->data[0], (int)msg->data[1]); + } + + pos = HANDSHAKE_SESSION_ID_POS; + /* legacy_session_id */ + SKIP8(pos, msg->size); + + /* CipherSuites */ + SKIP16(pos, msg->size); + + /* legacy_compression_methods */ + SKIP8(pos, msg->size); + + pos += 2; + + while (pos < msg->size) { + uint16_t type; + + if (pos+4 > msg->size) + fail("invalid client hello\n"); + + type = (msg->data[pos] << 8) | msg->data[pos+1]; + pos+=2; + + if (debug) + success("Found client extension %d\n", (int)type); + + if (type != extnr) { + SKIP16(pos, msg->size); + } else { /* found */ + ssize_t size = (msg->data[pos] << 8) | msg->data[pos+1]; + gnutls_datum_t data; + + pos+=2; + if (pos + size > msg->size) { + fail("error in extension length (pos: %d, ext: %d, total: %d)\n", pos, (int)size, msg->size); + } + data.data = &msg->data[pos]; + data.size = size; + if (cb) + cb(priv, &data); + return 1; + } + } + return 0; +} + +static unsigned is_client_extension_last(const gnutls_datum_t *msg, unsigned extnr) +{ + unsigned pos, found = 0; + + if (msg->size < HANDSHAKE_SESSION_ID_POS) + fail("invalid client hello\n"); + + /* we expect the legacy version to be present */ + /* ProtocolVersion legacy_version = 0x0303 */ + if (msg->data[0] != 0x03) { + fail("ProtocolVersion contains %d.%d\n", (int)msg->data[0], (int)msg->data[1]); + } + + pos = HANDSHAKE_SESSION_ID_POS; + /* legacy_session_id */ + SKIP8(pos, msg->size); + + /* CipherSuites */ + SKIP16(pos, msg->size); + + /* legacy_compression_methods */ + SKIP8(pos, msg->size); + + pos += 2; + + while (pos < msg->size) { + uint16_t type; + + if (pos+4 > msg->size) + fail("invalid client hello\n"); + + type = (msg->data[pos] << 8) | msg->data[pos+1]; + pos+=2; + + if (debug) + success("Found client extension %d\n", (int)type); + + if (type != extnr) { + if (found) { + success("found extension %d after %d\n", type, extnr); + return 0; + } + SKIP16(pos, msg->size); + } else { /* found */ + found = 1; + SKIP16(pos, msg->size); + } + } + + if (found) + return 1; + return 0; +} + +#define TLS_RANDOM_SIZE 32 + +static unsigned find_server_extension(const gnutls_datum_t *msg, unsigned extnr, void *priv, ext_parse_func cb) +{ + unsigned pos = 0; + + success("server hello of %d bytes\n", msg->size); + /* we expect the legacy version to be present */ + /* ProtocolVersion legacy_version = 0x0303 */ + if (msg->data[0] != 0x03 || msg->data[1] != 0x03) { + fail("ProtocolVersion contains %d.%d\n", (int)msg->data[0], (int)msg->data[1]); + } + + if (msg->data[1] >= 0x04) { + success("assuming TLS 1.3 or better hello format (seen %d.%d)\n", (int)msg->data[0], (int)msg->data[1]); + } + + pos += 2+TLS_RANDOM_SIZE; + + /* legacy_session_id */ + SKIP8(pos, msg->size); + + /* CipherSuite */ + pos += 2; + + /* legacy_compression_methods */ + SKIP8(pos, msg->size); + + pos += 2; + + while (pos < msg->size) { + uint16_t type; + + if (pos+4 > msg->size) + fail("invalid server hello\n"); + + type = (msg->data[pos] << 8) | msg->data[pos+1]; + pos+=2; + + success("Found server extension %d\n", (int)type); + + if (type != extnr) { + SKIP16(pos, msg->size); + } else { /* found */ + ssize_t size = (msg->data[pos] << 8) | msg->data[pos+1]; + gnutls_datum_t data; + + pos+=2; + if (pos + size < msg->size) { + fail("error in server extension length (pos: %d, total: %d)\n", pos, msg->size); + } + data.data = &msg->data[pos]; + data.size = size; + if (cb) + cb(priv, &data); + return 1; + } + } + + return 0; +} + +#if defined __clang__ || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) +# pragma GCC diagnostic pop +#endif |