This page hosts a formal specification of tls_client_hello using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.
All parsing code for C++98/STL generated by Kaitai Struct depends on the C++/STL runtime library. You have to install it before you can parse data.
For C++, the easiest way is to clone the runtime library sources and build them along with your project.
Using Kaitai Struct in C++/STL usually consists of 3 steps.
std::istream
). One can open local file for that, or use existing std::string
or char*
buffer.
#include <fstream>
std::ifstream is("path/to/local/file.bin", std::ifstream::binary);
#include <sstream>
std::istringstream is(str);
#include <sstream>
const char buf[] = { ... };
std::string str(buf, sizeof buf);
std::istringstream is(str);
#include "kaitai/kaitaistream.h"
kaitai::kstream ks(&is);
tls_client_hello_t data(&ks);
After that, one can get various attributes from the structure by invoking getter methods like:
data.version() // => get version
#ifndef TLS_CLIENT_HELLO_H_
#define TLS_CLIENT_HELLO_H_
// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
#include "kaitai/kaitaistruct.h"
#include <stdint.h>
#include <vector>
#if KAITAI_STRUCT_VERSION < 9000L
#error "Incompatible Kaitai Struct C++/STL API: version 0.9 or later is required"
#endif
class tls_client_hello_t : public kaitai::kstruct {
public:
class server_name_t;
class random_t;
class session_id_t;
class sni_t;
class cipher_suites_t;
class compression_methods_t;
class alpn_t;
class extensions_t;
class version_t;
class protocol_t;
class extension_t;
tls_client_hello_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = 0, tls_client_hello_t* p__root = 0);
private:
void _read();
void _clean_up();
public:
~tls_client_hello_t();
class server_name_t : public kaitai::kstruct {
public:
server_name_t(kaitai::kstream* p__io, tls_client_hello_t::sni_t* p__parent = 0, tls_client_hello_t* p__root = 0);
private:
void _read();
void _clean_up();
public:
~server_name_t();
private:
uint8_t m_name_type;
uint16_t m_length;
std::string m_host_name;
tls_client_hello_t* m__root;
tls_client_hello_t::sni_t* m__parent;
public:
uint8_t name_type() const { return m_name_type; }
uint16_t length() const { return m_length; }
std::string host_name() const { return m_host_name; }
tls_client_hello_t* _root() const { return m__root; }
tls_client_hello_t::sni_t* _parent() const { return m__parent; }
};
class random_t : public kaitai::kstruct {
public:
random_t(kaitai::kstream* p__io, tls_client_hello_t* p__parent = 0, tls_client_hello_t* p__root = 0);
private:
void _read();
void _clean_up();
public:
~random_t();
private:
uint32_t m_gmt_unix_time;
std::string m_random;
tls_client_hello_t* m__root;
tls_client_hello_t* m__parent;
public:
uint32_t gmt_unix_time() const { return m_gmt_unix_time; }
std::string random() const { return m_random; }
tls_client_hello_t* _root() const { return m__root; }
tls_client_hello_t* _parent() const { return m__parent; }
};
class session_id_t : public kaitai::kstruct {
public:
session_id_t(kaitai::kstream* p__io, tls_client_hello_t* p__parent = 0, tls_client_hello_t* p__root = 0);
private:
void _read();
void _clean_up();
public:
~session_id_t();
private:
uint8_t m_len;
std::string m_sid;
tls_client_hello_t* m__root;
tls_client_hello_t* m__parent;
public:
uint8_t len() const { return m_len; }
std::string sid() const { return m_sid; }
tls_client_hello_t* _root() const { return m__root; }
tls_client_hello_t* _parent() const { return m__parent; }
};
class sni_t : public kaitai::kstruct {
public:
sni_t(kaitai::kstream* p__io, tls_client_hello_t::extension_t* p__parent = 0, tls_client_hello_t* p__root = 0);
private:
void _read();
void _clean_up();
public:
~sni_t();
private:
uint16_t m_list_length;
std::vector<server_name_t*>* m_server_names;
tls_client_hello_t* m__root;
tls_client_hello_t::extension_t* m__parent;
public:
uint16_t list_length() const { return m_list_length; }
std::vector<server_name_t*>* server_names() const { return m_server_names; }
tls_client_hello_t* _root() const { return m__root; }
tls_client_hello_t::extension_t* _parent() const { return m__parent; }
};
class cipher_suites_t : public kaitai::kstruct {
public:
cipher_suites_t(kaitai::kstream* p__io, tls_client_hello_t* p__parent = 0, tls_client_hello_t* p__root = 0);
private:
void _read();
void _clean_up();
public:
~cipher_suites_t();
private:
uint16_t m_len;
std::vector<uint16_t>* m_cipher_suites;
tls_client_hello_t* m__root;
tls_client_hello_t* m__parent;
public:
uint16_t len() const { return m_len; }
std::vector<uint16_t>* cipher_suites() const { return m_cipher_suites; }
tls_client_hello_t* _root() const { return m__root; }
tls_client_hello_t* _parent() const { return m__parent; }
};
class compression_methods_t : public kaitai::kstruct {
public:
compression_methods_t(kaitai::kstream* p__io, tls_client_hello_t* p__parent = 0, tls_client_hello_t* p__root = 0);
private:
void _read();
void _clean_up();
public:
~compression_methods_t();
private:
uint8_t m_len;
std::string m_compression_methods;
tls_client_hello_t* m__root;
tls_client_hello_t* m__parent;
public:
uint8_t len() const { return m_len; }
std::string compression_methods() const { return m_compression_methods; }
tls_client_hello_t* _root() const { return m__root; }
tls_client_hello_t* _parent() const { return m__parent; }
};
class alpn_t : public kaitai::kstruct {
public:
alpn_t(kaitai::kstream* p__io, tls_client_hello_t::extension_t* p__parent = 0, tls_client_hello_t* p__root = 0);
private:
void _read();
void _clean_up();
public:
~alpn_t();
private:
uint16_t m_ext_len;
std::vector<protocol_t*>* m_alpn_protocols;
tls_client_hello_t* m__root;
tls_client_hello_t::extension_t* m__parent;
public:
uint16_t ext_len() const { return m_ext_len; }
std::vector<protocol_t*>* alpn_protocols() const { return m_alpn_protocols; }
tls_client_hello_t* _root() const { return m__root; }
tls_client_hello_t::extension_t* _parent() const { return m__parent; }
};
class extensions_t : public kaitai::kstruct {
public:
extensions_t(kaitai::kstream* p__io, tls_client_hello_t* p__parent = 0, tls_client_hello_t* p__root = 0);
private:
void _read();
void _clean_up();
public:
~extensions_t();
private:
uint16_t m_len;
std::vector<extension_t*>* m_extensions;
tls_client_hello_t* m__root;
tls_client_hello_t* m__parent;
public:
uint16_t len() const { return m_len; }
std::vector<extension_t*>* extensions() const { return m_extensions; }
tls_client_hello_t* _root() const { return m__root; }
tls_client_hello_t* _parent() const { return m__parent; }
};
class version_t : public kaitai::kstruct {
public:
version_t(kaitai::kstream* p__io, tls_client_hello_t* p__parent = 0, tls_client_hello_t* p__root = 0);
private:
void _read();
void _clean_up();
public:
~version_t();
private:
uint8_t m_major;
uint8_t m_minor;
tls_client_hello_t* m__root;
tls_client_hello_t* m__parent;
public:
uint8_t major() const { return m_major; }
uint8_t minor() const { return m_minor; }
tls_client_hello_t* _root() const { return m__root; }
tls_client_hello_t* _parent() const { return m__parent; }
};
class protocol_t : public kaitai::kstruct {
public:
protocol_t(kaitai::kstream* p__io, tls_client_hello_t::alpn_t* p__parent = 0, tls_client_hello_t* p__root = 0);
private:
void _read();
void _clean_up();
public:
~protocol_t();
private:
uint8_t m_strlen;
std::string m_name;
tls_client_hello_t* m__root;
tls_client_hello_t::alpn_t* m__parent;
public:
uint8_t strlen() const { return m_strlen; }
std::string name() const { return m_name; }
tls_client_hello_t* _root() const { return m__root; }
tls_client_hello_t::alpn_t* _parent() const { return m__parent; }
};
class extension_t : public kaitai::kstruct {
public:
extension_t(kaitai::kstream* p__io, tls_client_hello_t::extensions_t* p__parent = 0, tls_client_hello_t* p__root = 0);
private:
void _read();
void _clean_up();
public:
~extension_t();
private:
uint16_t m_type;
uint16_t m_len;
kaitai::kstruct* m_body;
bool n_body;
public:
bool _is_null_body() { body(); return n_body; };
private:
tls_client_hello_t* m__root;
tls_client_hello_t::extensions_t* m__parent;
std::string m__raw_body;
kaitai::kstream* m__io__raw_body;
public:
uint16_t type() const { return m_type; }
uint16_t len() const { return m_len; }
kaitai::kstruct* body() const { return m_body; }
tls_client_hello_t* _root() const { return m__root; }
tls_client_hello_t::extensions_t* _parent() const { return m__parent; }
std::string _raw_body() const { return m__raw_body; }
kaitai::kstream* _io__raw_body() const { return m__io__raw_body; }
};
private:
version_t* m_version;
random_t* m_random;
session_id_t* m_session_id;
cipher_suites_t* m_cipher_suites;
compression_methods_t* m_compression_methods;
extensions_t* m_extensions;
bool n_extensions;
public:
bool _is_null_extensions() { extensions(); return n_extensions; };
private:
tls_client_hello_t* m__root;
kaitai::kstruct* m__parent;
public:
version_t* version() const { return m_version; }
random_t* random() const { return m_random; }
session_id_t* session_id() const { return m_session_id; }
cipher_suites_t* cipher_suites() const { return m_cipher_suites; }
compression_methods_t* compression_methods() const { return m_compression_methods; }
extensions_t* extensions() const { return m_extensions; }
tls_client_hello_t* _root() const { return m__root; }
kaitai::kstruct* _parent() const { return m__parent; }
};
#endif // TLS_CLIENT_HELLO_H_
// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
#include "tls_client_hello.h"
tls_client_hello_t::tls_client_hello_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, tls_client_hello_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = this;
m_version = 0;
m_random = 0;
m_session_id = 0;
m_cipher_suites = 0;
m_compression_methods = 0;
m_extensions = 0;
try {
_read();
} catch(...) {
_clean_up();
throw;
}
}
void tls_client_hello_t::_read() {
m_version = new version_t(m__io, this, m__root);
m_random = new random_t(m__io, this, m__root);
m_session_id = new session_id_t(m__io, this, m__root);
m_cipher_suites = new cipher_suites_t(m__io, this, m__root);
m_compression_methods = new compression_methods_t(m__io, this, m__root);
n_extensions = true;
if (_io()->is_eof() == false) {
n_extensions = false;
m_extensions = new extensions_t(m__io, this, m__root);
}
}
tls_client_hello_t::~tls_client_hello_t() {
_clean_up();
}
void tls_client_hello_t::_clean_up() {
if (m_version) {
delete m_version; m_version = 0;
}
if (m_random) {
delete m_random; m_random = 0;
}
if (m_session_id) {
delete m_session_id; m_session_id = 0;
}
if (m_cipher_suites) {
delete m_cipher_suites; m_cipher_suites = 0;
}
if (m_compression_methods) {
delete m_compression_methods; m_compression_methods = 0;
}
if (!n_extensions) {
if (m_extensions) {
delete m_extensions; m_extensions = 0;
}
}
}
tls_client_hello_t::server_name_t::server_name_t(kaitai::kstream* p__io, tls_client_hello_t::sni_t* p__parent, tls_client_hello_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
try {
_read();
} catch(...) {
_clean_up();
throw;
}
}
void tls_client_hello_t::server_name_t::_read() {
m_name_type = m__io->read_u1();
m_length = m__io->read_u2be();
m_host_name = m__io->read_bytes(length());
}
tls_client_hello_t::server_name_t::~server_name_t() {
_clean_up();
}
void tls_client_hello_t::server_name_t::_clean_up() {
}
tls_client_hello_t::random_t::random_t(kaitai::kstream* p__io, tls_client_hello_t* p__parent, tls_client_hello_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
try {
_read();
} catch(...) {
_clean_up();
throw;
}
}
void tls_client_hello_t::random_t::_read() {
m_gmt_unix_time = m__io->read_u4be();
m_random = m__io->read_bytes(28);
}
tls_client_hello_t::random_t::~random_t() {
_clean_up();
}
void tls_client_hello_t::random_t::_clean_up() {
}
tls_client_hello_t::session_id_t::session_id_t(kaitai::kstream* p__io, tls_client_hello_t* p__parent, tls_client_hello_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
try {
_read();
} catch(...) {
_clean_up();
throw;
}
}
void tls_client_hello_t::session_id_t::_read() {
m_len = m__io->read_u1();
m_sid = m__io->read_bytes(len());
}
tls_client_hello_t::session_id_t::~session_id_t() {
_clean_up();
}
void tls_client_hello_t::session_id_t::_clean_up() {
}
tls_client_hello_t::sni_t::sni_t(kaitai::kstream* p__io, tls_client_hello_t::extension_t* p__parent, tls_client_hello_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
m_server_names = 0;
try {
_read();
} catch(...) {
_clean_up();
throw;
}
}
void tls_client_hello_t::sni_t::_read() {
m_list_length = m__io->read_u2be();
m_server_names = new std::vector<server_name_t*>();
{
int i = 0;
while (!m__io->is_eof()) {
m_server_names->push_back(new server_name_t(m__io, this, m__root));
i++;
}
}
}
tls_client_hello_t::sni_t::~sni_t() {
_clean_up();
}
void tls_client_hello_t::sni_t::_clean_up() {
if (m_server_names) {
for (std::vector<server_name_t*>::iterator it = m_server_names->begin(); it != m_server_names->end(); ++it) {
delete *it;
}
delete m_server_names; m_server_names = 0;
}
}
tls_client_hello_t::cipher_suites_t::cipher_suites_t(kaitai::kstream* p__io, tls_client_hello_t* p__parent, tls_client_hello_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
m_cipher_suites = 0;
try {
_read();
} catch(...) {
_clean_up();
throw;
}
}
void tls_client_hello_t::cipher_suites_t::_read() {
m_len = m__io->read_u2be();
m_cipher_suites = new std::vector<uint16_t>();
const int l_cipher_suites = (len() / 2);
for (int i = 0; i < l_cipher_suites; i++) {
m_cipher_suites->push_back(m__io->read_u2be());
}
}
tls_client_hello_t::cipher_suites_t::~cipher_suites_t() {
_clean_up();
}
void tls_client_hello_t::cipher_suites_t::_clean_up() {
if (m_cipher_suites) {
delete m_cipher_suites; m_cipher_suites = 0;
}
}
tls_client_hello_t::compression_methods_t::compression_methods_t(kaitai::kstream* p__io, tls_client_hello_t* p__parent, tls_client_hello_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
try {
_read();
} catch(...) {
_clean_up();
throw;
}
}
void tls_client_hello_t::compression_methods_t::_read() {
m_len = m__io->read_u1();
m_compression_methods = m__io->read_bytes(len());
}
tls_client_hello_t::compression_methods_t::~compression_methods_t() {
_clean_up();
}
void tls_client_hello_t::compression_methods_t::_clean_up() {
}
tls_client_hello_t::alpn_t::alpn_t(kaitai::kstream* p__io, tls_client_hello_t::extension_t* p__parent, tls_client_hello_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
m_alpn_protocols = 0;
try {
_read();
} catch(...) {
_clean_up();
throw;
}
}
void tls_client_hello_t::alpn_t::_read() {
m_ext_len = m__io->read_u2be();
m_alpn_protocols = new std::vector<protocol_t*>();
{
int i = 0;
while (!m__io->is_eof()) {
m_alpn_protocols->push_back(new protocol_t(m__io, this, m__root));
i++;
}
}
}
tls_client_hello_t::alpn_t::~alpn_t() {
_clean_up();
}
void tls_client_hello_t::alpn_t::_clean_up() {
if (m_alpn_protocols) {
for (std::vector<protocol_t*>::iterator it = m_alpn_protocols->begin(); it != m_alpn_protocols->end(); ++it) {
delete *it;
}
delete m_alpn_protocols; m_alpn_protocols = 0;
}
}
tls_client_hello_t::extensions_t::extensions_t(kaitai::kstream* p__io, tls_client_hello_t* p__parent, tls_client_hello_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
m_extensions = 0;
try {
_read();
} catch(...) {
_clean_up();
throw;
}
}
void tls_client_hello_t::extensions_t::_read() {
m_len = m__io->read_u2be();
m_extensions = new std::vector<extension_t*>();
{
int i = 0;
while (!m__io->is_eof()) {
m_extensions->push_back(new extension_t(m__io, this, m__root));
i++;
}
}
}
tls_client_hello_t::extensions_t::~extensions_t() {
_clean_up();
}
void tls_client_hello_t::extensions_t::_clean_up() {
if (m_extensions) {
for (std::vector<extension_t*>::iterator it = m_extensions->begin(); it != m_extensions->end(); ++it) {
delete *it;
}
delete m_extensions; m_extensions = 0;
}
}
tls_client_hello_t::version_t::version_t(kaitai::kstream* p__io, tls_client_hello_t* p__parent, tls_client_hello_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
try {
_read();
} catch(...) {
_clean_up();
throw;
}
}
void tls_client_hello_t::version_t::_read() {
m_major = m__io->read_u1();
m_minor = m__io->read_u1();
}
tls_client_hello_t::version_t::~version_t() {
_clean_up();
}
void tls_client_hello_t::version_t::_clean_up() {
}
tls_client_hello_t::protocol_t::protocol_t(kaitai::kstream* p__io, tls_client_hello_t::alpn_t* p__parent, tls_client_hello_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
try {
_read();
} catch(...) {
_clean_up();
throw;
}
}
void tls_client_hello_t::protocol_t::_read() {
m_strlen = m__io->read_u1();
m_name = m__io->read_bytes(strlen());
}
tls_client_hello_t::protocol_t::~protocol_t() {
_clean_up();
}
void tls_client_hello_t::protocol_t::_clean_up() {
}
tls_client_hello_t::extension_t::extension_t(kaitai::kstream* p__io, tls_client_hello_t::extensions_t* p__parent, tls_client_hello_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
m__io__raw_body = 0;
try {
_read();
} catch(...) {
_clean_up();
throw;
}
}
void tls_client_hello_t::extension_t::_read() {
m_type = m__io->read_u2be();
m_len = m__io->read_u2be();
n_body = true;
switch (type()) {
case 0: {
n_body = false;
m__raw_body = m__io->read_bytes(len());
m__io__raw_body = new kaitai::kstream(m__raw_body);
m_body = new sni_t(m__io__raw_body, this, m__root);
break;
}
case 16: {
n_body = false;
m__raw_body = m__io->read_bytes(len());
m__io__raw_body = new kaitai::kstream(m__raw_body);
m_body = new alpn_t(m__io__raw_body, this, m__root);
break;
}
default: {
m__raw_body = m__io->read_bytes(len());
break;
}
}
}
tls_client_hello_t::extension_t::~extension_t() {
_clean_up();
}
void tls_client_hello_t::extension_t::_clean_up() {
if (!n_body) {
if (m__io__raw_body) {
delete m__io__raw_body; m__io__raw_body = 0;
}
if (m_body) {
delete m_body; m_body = 0;
}
}
}