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