|
|
|
#ifndef SRC_NODE_CRYPTO_CLIENTHELLO_H_
|
|
|
|
#define SRC_NODE_CRYPTO_CLIENTHELLO_H_
|
|
|
|
|
|
|
|
#include "node.h"
|
|
|
|
|
|
|
|
#include <stddef.h> // size_t
|
|
|
|
#include <stdlib.h> // nullptr
|
|
|
|
|
|
|
|
namespace node {
|
|
|
|
|
|
|
|
class ClientHelloParser {
|
|
|
|
public:
|
|
|
|
ClientHelloParser() : state_(kEnded),
|
|
|
|
onhello_cb_(nullptr),
|
|
|
|
onend_cb_(nullptr),
|
|
|
|
cb_arg_(nullptr),
|
|
|
|
session_size_(0),
|
|
|
|
session_id_(nullptr),
|
|
|
|
servername_size_(0),
|
|
|
|
servername_(nullptr),
|
|
|
|
ocsp_request_(0),
|
|
|
|
tls_ticket_size_(0),
|
|
|
|
tls_ticket_(nullptr) {
|
|
|
|
Reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
class ClientHello {
|
|
|
|
public:
|
|
|
|
inline uint8_t session_size() const { return session_size_; }
|
|
|
|
inline const uint8_t* session_id() const { return session_id_; }
|
|
|
|
inline bool has_ticket() const { return has_ticket_; }
|
|
|
|
inline uint8_t servername_size() const { return servername_size_; }
|
|
|
|
inline const uint8_t* servername() const { return servername_; }
|
|
|
|
inline int ocsp_request() const { return ocsp_request_; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
uint8_t session_size_;
|
|
|
|
const uint8_t* session_id_;
|
|
|
|
bool has_ticket_;
|
|
|
|
uint8_t servername_size_;
|
|
|
|
const uint8_t* servername_;
|
|
|
|
int ocsp_request_;
|
|
|
|
|
|
|
|
friend class ClientHelloParser;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef void (*OnHelloCb)(void* arg, const ClientHello& hello);
|
|
|
|
typedef void (*OnEndCb)(void* arg);
|
|
|
|
|
|
|
|
void Parse(const uint8_t* data, size_t avail);
|
|
|
|
|
|
|
|
inline void Reset();
|
|
|
|
inline void Start(OnHelloCb onhello_cb, OnEndCb onend_cb, void* onend_arg);
|
|
|
|
inline void End();
|
|
|
|
inline bool IsPaused() const;
|
|
|
|
inline bool IsEnded() const;
|
|
|
|
|
|
|
|
private:
|
|
|
|
static const size_t kMaxTLSFrameLen = 16 * 1024 + 5;
|
|
|
|
static const size_t kMaxSSLExFrameLen = 32 * 1024;
|
|
|
|
static const uint8_t kServernameHostname = 0;
|
|
|
|
static const uint8_t kStatusRequestOCSP = 1;
|
|
|
|
static const size_t kMinStatusRequestSize = 5;
|
|
|
|
|
|
|
|
enum ParseState {
|
|
|
|
kWaiting,
|
|
|
|
kTLSHeader,
|
|
|
|
kPaused,
|
|
|
|
kEnded
|
|
|
|
};
|
|
|
|
|
|
|
|
enum FrameType {
|
|
|
|
kChangeCipherSpec = 20,
|
|
|
|
kAlert = 21,
|
|
|
|
kHandshake = 22,
|
|
|
|
kApplicationData = 23,
|
|
|
|
kOther = 255
|
|
|
|
};
|
|
|
|
|
|
|
|
enum HandshakeType {
|
|
|
|
kClientHello = 1
|
|
|
|
};
|
|
|
|
|
|
|
|
enum ExtensionType {
|
|
|
|
kServerName = 0,
|
|
|
|
kStatusRequest = 5,
|
|
|
|
kTLSSessionTicket = 35
|
|
|
|
};
|
|
|
|
|
|
|
|
bool ParseRecordHeader(const uint8_t* data, size_t avail);
|
|
|
|
void ParseHeader(const uint8_t* data, size_t avail);
|
|
|
|
void ParseExtension(ExtensionType type,
|
|
|
|
const uint8_t* data,
|
|
|
|
size_t len);
|
|
|
|
bool ParseTLSClientHello(const uint8_t* data, size_t avail);
|
|
|
|
|
|
|
|
ParseState state_;
|
|
|
|
OnHelloCb onhello_cb_;
|
|
|
|
OnEndCb onend_cb_;
|
|
|
|
void* cb_arg_;
|
|
|
|
size_t frame_len_;
|
|
|
|
size_t body_offset_;
|
|
|
|
size_t extension_offset_;
|
|
|
|
uint8_t session_size_;
|
|
|
|
const uint8_t* session_id_;
|
|
|
|
uint16_t servername_size_;
|
|
|
|
const uint8_t* servername_;
|
|
|
|
uint8_t ocsp_request_;
|
|
|
|
uint16_t tls_ticket_size_;
|
|
|
|
const uint8_t* tls_ticket_;
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace node
|
|
|
|
|
|
|
|
#endif // SRC_NODE_CRYPTO_CLIENTHELLO_H_
|