Latest changes

- Hide handshake implementation behind a set of function pointers
- Use monotonically increasing clock
- Make sure that retx delay is not larger than the max of 60 seconds
This commit is contained in:
Dmitri Tikhonov 2017-10-09 07:52:09 -04:00
parent 0fb9ea94ae
commit 83287402d5
13 changed files with 343 additions and 247 deletions

View File

@ -1,3 +1,9 @@
2017-10-09
- Hide handshake implementation behind a set of function pointers
- Use monotonically increasing clock
- Make sure that retx delay is not larger than the max of 60 seconds
2017-09-29
- A few fixes to code and README

View File

@ -15,6 +15,7 @@
#include "lsquic_int_types.h"
#include "lsquic.h"
#include "lsquic_str.h"
#include "lsquic_handshake.h"
#include "lsquic_chsk_stream.h"
#include "lsquic_ver_neg.h"
@ -78,9 +79,9 @@ hsk_client_on_read (lsquic_stream_t *stream, struct lsquic_stream_ctx *sh)
}
c_hsk->buf_off += nread;
s = handle_chlo_reply(c_hsk->lconn->cn_enc_session,
s = c_hsk->lconn->cn_esf->esf_handle_chlo_reply(c_hsk->lconn->cn_enc_session,
c_hsk->buf_in, c_hsk->buf_off);
LSQ_DEBUG("handle_chlo_reply returned %d", s);
LSQ_DEBUG("lsquic_enc_session_handle_chlo_reply returned %d", s);
switch (s)
{
case DATA_NOT_ENOUGH:
@ -101,7 +102,7 @@ hsk_client_on_read (lsquic_stream_t *stream, struct lsquic_stream_ctx *sh)
lsquic_mm_put_16k(c_hsk->mm, c_hsk->buf_in);
c_hsk->buf_in = NULL;
lsquic_stream_wantread(stream, 0);
if (is_hs_done(c_hsk->lconn->cn_enc_session))
if (c_hsk->lconn->cn_esf->esf_is_hsk_done(c_hsk->lconn->cn_enc_session))
{
LSQ_DEBUG("handshake is complete, inform connection");
c_hsk->lconn->cn_if->ci_handshake_done(c_hsk->lconn);
@ -114,9 +115,9 @@ hsk_client_on_read (lsquic_stream_t *stream, struct lsquic_stream_ctx *sh)
}
break;
default:
LSQ_WARN("handle_chlo_reply returned unknown value %d", s);
LSQ_WARN("lsquic_enc_session_handle_chlo_reply returned unknown value %d", s);
case DATA_FORMAT_ERROR:
LSQ_INFO("handle_chlo_reply returned an error");
LSQ_INFO("lsquic_enc_session_handle_chlo_reply returned an error");
break;
}
}
@ -144,8 +145,8 @@ hsk_client_on_write (lsquic_stream_t *stream, struct lsquic_stream_ctx *sh)
}
len = 4 * 1024;
if (0 != gen_chlo(c_hsk->lconn->cn_enc_session, c_hsk->ver_neg->vn_ver,
buf, &len))
if (0 != c_hsk->lconn->cn_esf->esf_gen_chlo(c_hsk->lconn->cn_enc_session,
c_hsk->ver_neg->vn_ver, buf, &len))
{
LSQ_WARN("cannot create CHLO message");
lsquic_mm_put_4k(c_hsk->mm, buf);

View File

@ -8,6 +8,7 @@
#include "lsquic_conn.h"
#include "lsquic_packet_common.h"
#include "lsquic_packet_in.h"
#include "lsquic_str.h"
#include "lsquic_handshake.h"
#include "lsquic_mm.h"
#include "lsquic_engine_public.h"
@ -119,7 +120,8 @@ lsquic_conn_decrypt_packet (lsquic_conn_t *lconn,
header_len = packet_in->pi_header_sz;
data_len = packet_in->pi_data_sz - packet_in->pi_header_sz;
if (0 == lsquic_dec(lconn->cn_enc_session, lconn->cn_version, 0,
if (0 == lconn->cn_esf->esf_decrypt(lconn->cn_enc_session,
lconn->cn_version, 0,
packet_in->pi_packno, packet_in->pi_data,
&header_len, data_len,
lsquic_packet_in_nonce(packet_in),

View File

@ -88,6 +88,8 @@ struct lsquic_conn
{
void *cn_peer_ctx;
struct lsquic_enc_session *cn_enc_session;
const struct enc_session_funcs
*cn_esf;
lsquic_cid_t cn_cid;
STAILQ_ENTRY(lsquic_conn) cn_next_closed_conn;
TAILQ_ENTRY(lsquic_conn) cn_next_all,

View File

@ -41,6 +41,7 @@
#include "lsquic_full_conn.h"
#include "lsquic_util.h"
#include "lsquic_qtags.h"
#include "lsquic_str.h"
#include "lsquic_handshake.h"
#include "lsquic_mm.h"
#include "lsquic_conn_hash.h"
@ -1072,7 +1073,7 @@ really_encrypt_packet (const lsquic_conn_t *conn,
return -1;
is_hello_packet = !!(packet_out->po_flags & PO_HELLO);
enc = lsquic_enc(conn->cn_enc_session, conn->cn_version, 0,
enc = conn->cn_esf->esf_encrypt(conn->cn_enc_session, conn->cn_version, 0,
packet_out->po_packno, header_buf, header_sz,
packet_out->po_data, packet_out->po_data_sz,
buf, bufsz, &packet_sz, is_hello_packet);

View File

@ -34,6 +34,8 @@
#include "lsquic_set.h"
#include "lsquic_malo.h"
#include "lsquic_chsk_stream.h"
#include "lsquic_str.h"
#include "lsquic_qtags.h"
#include "lsquic_handshake.h"
#include "lsquic_headers_stream.h"
#include "lsquic_frame_common.h"
@ -325,7 +327,8 @@ send_smhl (const struct full_conn *conn)
uint32_t smhl;
return conn->fc_conn.cn_enc_session
&& (conn->fc_conn.cn_flags & LSCONN_HANDSHAKE_DONE)
&& 0 == get_peer_setting(conn->fc_conn.cn_enc_session, QTAG_SMHL, &smhl)
&& 0 == conn->fc_conn.cn_esf->esf_get_peer_setting(
conn->fc_conn.cn_enc_session, QTAG_SMHL, &smhl)
&& 1 == smhl;
}
@ -387,8 +390,8 @@ apply_peer_settings (struct full_conn *conn)
#endif
for (n = 0; n < sizeof(tags) / sizeof(tags[0]); ++n)
if (0 != get_peer_setting(conn->fc_conn.cn_enc_session,
tags[n].tag, tags[n].val))
if (0 != conn->fc_conn.cn_esf->esf_get_peer_setting(
conn->fc_conn.cn_enc_session, tags[n].tag, tags[n].val))
{
LSQ_INFO("peer did not supply value for %s", tags[n].tag_str);
return -1;
@ -521,15 +524,20 @@ full_conn_client_new (struct lsquic_engine_public *enpub,
const char *hostname, unsigned short max_packet_size)
{
struct full_conn *conn;
enum lsquic_version version;
lsquic_cid_t cid;
const struct enc_session_funcs *esf;
cid = generate_cid();
version = highest_bit_set(enpub->enp_settings.es_versions);
esf = select_esf_by_ver(version);
cid = esf->esf_generate_cid();
conn = new_conn_common(cid, enpub, stream_if, stream_if_ctx, flags,
max_packet_size);
if (!conn)
return NULL;
conn->fc_conn.cn_enc_session = new_enc_session_c(hostname, cid,
conn->fc_enpub);
conn->fc_conn.cn_esf = esf;
conn->fc_conn.cn_enc_session =
conn->fc_conn.cn_esf->esf_create_client(hostname, cid, conn->fc_enpub);
if (!conn->fc_conn.cn_enc_session)
{
LSQ_WARN("could not create enc session: %s", strerror(errno));
@ -547,7 +555,6 @@ full_conn_client_new (struct lsquic_engine_public *enpub,
conn->fc_stream_ifs[STREAM_IF_HSK]
.stream_if = &lsquic_client_hsk_stream_if;
conn->fc_stream_ifs[STREAM_IF_HSK].stream_if_ctx = &conn->fc_hsk_ctx.client;
/* TODO the client does not know how to perform version negotiation */
init_ver_neg(conn, conn->fc_settings->es_versions);
conn->fc_conn.cn_pf = select_pf_by_ver(conn->fc_ver_neg.vn_ver);
if (conn->fc_settings->es_handshake_to)
@ -628,7 +635,7 @@ full_conn_ci_destroy (lsquic_conn_t *lconn)
lsquic_send_ctl_cleanup(&conn->fc_send_ctl);
lsquic_rechist_cleanup(&conn->fc_rechist);
if (conn->fc_conn.cn_enc_session)
free_enc_session(conn->fc_conn.cn_enc_session);
conn->fc_conn.cn_esf->esf_destroy(conn->fc_conn.cn_enc_session);
lsquic_malo_destroy(conn->fc_pub.packet_out_malo);
#if FULL_CONN_STATS
LSQ_NOTICE("received %u packets, of which %u were not decryptable, %u were "

View File

@ -3,20 +3,24 @@
* Global state
*/
#include "lsquic_int_types.h"
#include "lsquic_types.h"
#include "lsquic.h"
#include "lsquic_str.h"
#include "lsquic_handshake.h"
#include "lsquic_util.h"
int
lsquic_global_init (int flags)
{
return handshake_init(flags);
lsquic_init_timers();
return lsquic_enc_session_gquic_1.esf_global_init(flags);
}
void
lsquic_global_cleanup (void)
{
handshake_cleanup();
lsquic_enc_session_gquic_1.esf_global_cleanup();
}

View File

@ -18,6 +18,7 @@
#include "lsquic.h"
#include "lsquic_types.h"
#include "lsquic_crypto.h"
#include "lsquic_str.h"
#include "lsquic_handshake.h"
#include "lsquic_parse.h"
#include "lsquic_crt_compress.h"
@ -25,9 +26,9 @@
#include "lsquic_version.h"
#include "lsquic_mm.h"
#include "lsquic_engine_public.h"
#include "lsquic_str.h"
#include "lsquic_hash.h"
#include "lsquic_buf.h"
#include "lsquic_qtags.h"
#include "fiu-local.h"
@ -38,6 +39,114 @@
#define LSQUIC_LOGGER_MODULE LSQLM_HANDSHAKE
#include "lsquic_logger.h"
enum handshake_state
{
HSK_CHLO_REJ = 0,
HSK_SHLO,
HSK_COMPLETED,
N_HSK_STATES
};
#if LSQUIC_KEEP_ENC_SESS_HISTORY
typedef unsigned char eshist_idx_t;
enum enc_sess_history_event
{
ESHE_EMPTY = '\0',
ESHE_SET_SNI = 'I',
ESHE_SET_SNO = 'O',
ESHE_SET_STK = 'K',
ESHE_SET_SCID = 'D',
ESHE_SET_PROF = 'P',
};
#endif
typedef struct hs_ctx_st
{
enum {
HSET_TCID = (1 << 0), /* tcid is set */
HSET_SMHL = (1 << 1), /* smhl is set */
HSET_SCID = (1 << 2),
} set;
enum {
HOPT_NSTP = (1 << 0), /* NSTP option present in COPT */
HOPT_SREJ = (1 << 1), /* SREJ option present in COPT */
} opts;
uint32_t pdmd;
uint32_t aead;
uint32_t kexs;
uint32_t mids;
uint32_t scls;
uint32_t cfcw;
uint32_t sfcw;
uint32_t srbf;
uint32_t icsl;
uint32_t irtt;
uint64_t rcid;
uint32_t tcid;
uint32_t smhl;
uint64_t ctim; /* any usage? */
uint64_t sttl;
unsigned char scid[SCID_LENGTH];
//unsigned char chlo_hash[32]; //SHA256 HASH of CHLO
unsigned char nonc[DNONC_LENGTH]; /* 4 tm, 8 orbit ---> REJ, 20 rand */
unsigned char pubs[32];
uint32_t rrej;
struct lsquic_str ccs;
struct lsquic_str sni; /* 0 rtt */
struct lsquic_str ccrt;
struct lsquic_str stk;
struct lsquic_str sno;
struct lsquic_str prof;
struct lsquic_str csct;
struct lsquic_str crt; /* compressed certs buffer */
} hs_ctx_t;
struct lsquic_enc_session
{
enum handshake_state hsk_state;
uint8_t have_key; /* 0, no 1, I, 2, D, 3, F */
uint8_t peer_have_final_key;
uint8_t server_start_use_final_key;
lsquic_cid_t cid;
unsigned char priv_key[32];
EVP_AEAD_CTX *enc_ctx_i;
EVP_AEAD_CTX *dec_ctx_i;
/* Have to save the initial key for diversification need */
unsigned char enc_key_i[aes128_key_len];
unsigned char dec_key_i[aes128_key_len];
unsigned char enc_key_nonce_i[aes128_iv_len];
unsigned char dec_key_nonce_i[aes128_iv_len];
EVP_AEAD_CTX *enc_ctx_f;
EVP_AEAD_CTX *dec_ctx_f;
unsigned char enc_key_nonce_f[aes128_iv_len];
unsigned char dec_key_nonce_f[aes128_iv_len];
hs_ctx_t hs_ctx;
lsquic_session_cache_info_t *info;
SSL_CTX * ssl_ctx;
const struct lsquic_engine_public *enpub;
struct lsquic_str * cert_ptr; /* pointer to the leaf cert of the server, not real copy */
struct lsquic_str chlo; /* real copy of CHLO message */
struct lsquic_str sstk;
struct lsquic_str ssno;
#if LSQUIC_KEEP_ENC_SESS_HISTORY
eshist_idx_t es_hist_idx;
unsigned char es_hist_buf[1 << ESHIST_BITS];
#endif
};
/***
* client side, it will store the domain/certs as cache cert
@ -49,6 +158,15 @@ static struct lsquic_hash *s_cached_client_certs;
*/
static struct lsquic_hash *s_cached_client_session_infos;
/* save to hash table */
static lsquic_session_cache_info_t *retrieve_session_info_entry(const char *key);
static void remove_expire_session_info_entry();
static void remove_session_info_entry(struct lsquic_str *key);
static void free_info (lsquic_session_cache_info_t *);
static void c_free_cert_hash_item (cert_hash_item_t *item);
static void c_free_cert_hash_item(cert_hash_item_t *item);
static int get_tag_val_u32 (unsigned char *v, int len, uint32_t *val);
@ -74,8 +192,8 @@ eshist_append (lsquic_enc_session_t *enc_session,
# define ESHIST_APPEND(sess, event) do { } while (0)
#endif
int
handshake_init(int flags)
static int
lsquic_handshake_init(int flags)
{
crypto_init();
return init_hs_hash_tables(flags);
@ -114,8 +232,8 @@ cleanup_hs_hash_tables (void)
}
void
handshake_cleanup (void)
static void
lsquic_handshake_cleanup (void)
{
cleanup_hs_hash_tables();
lsquic_crt_cleanup();
@ -141,7 +259,8 @@ static int init_hs_hash_tables(int flags)
/* client */
cert_hash_item_t* c_find_certs(lsquic_str_t *domain)
cert_hash_item_t *
c_find_certs (const lsquic_str_t *domain)
{
struct lsquic_hash_elem *el;
@ -159,7 +278,8 @@ cert_hash_item_t* c_find_certs(lsquic_str_t *domain)
/* client */
/* certs is an array of lsquic_str_t * */
cert_hash_item_t *make_cert_hash_item(lsquic_str_t *domain, lsquic_str_t **certs, int count)
static cert_hash_item_t *
make_cert_hash_item (lsquic_str_t *domain, lsquic_str_t **certs, int count)
{
int i;
uint64_t hash;
@ -180,7 +300,8 @@ cert_hash_item_t *make_cert_hash_item(lsquic_str_t *domain, lsquic_str_t **certs
/* client */
void c_free_cert_hash_item(cert_hash_item_t *item)
void
c_free_cert_hash_item (cert_hash_item_t *item)
{
int i;
if (item)
@ -196,7 +317,8 @@ void c_free_cert_hash_item(cert_hash_item_t *item)
/* client */
int c_insert_certs(cert_hash_item_t *item)
static int
c_insert_certs (cert_hash_item_t *item)
{
if (lsquic_hash_insert(s_cached_client_certs,
lsquic_str_cstr(item->domain),
@ -223,7 +345,8 @@ static int save_session_info_entry(lsquic_str_t *key, lsquic_session_cache_info_
/* If entry updated and need to remove cached entry */
void remove_session_info_entry(lsquic_str_t *key)
static void
remove_session_info_entry (lsquic_str_t *key)
{
lsquic_session_cache_info_t *entry;
struct lsquic_hash_elem *el;
@ -239,7 +362,7 @@ void remove_session_info_entry(lsquic_str_t *key)
/* client */
lsquic_session_cache_info_t *
static lsquic_session_cache_info_t *
retrieve_session_info_entry (const char *key)
{
lsquic_session_cache_info_t *entry;
@ -262,7 +385,11 @@ retrieve_session_info_entry (const char *key)
/* call it in timer() */
void remove_expire_session_info_entry()
#if __GNUC__
__attribute__((unused))
#endif
static void
remove_expire_session_info_entry (void)
{
time_t tm = time(NULL);
struct lsquic_hash_elem *el;
@ -280,8 +407,9 @@ void remove_expire_session_info_entry()
}
lsquic_enc_session_t *new_enc_session_c(const char *domain, lsquic_cid_t cid,
const struct lsquic_engine_public *enpub)
static lsquic_enc_session_t *
lsquic_enc_session_create_client (const char *domain, lsquic_cid_t cid,
const struct lsquic_engine_public *enpub)
{
lsquic_session_cache_info_t *info;
lsquic_enc_session_t *enc_session;
@ -318,7 +446,8 @@ lsquic_enc_session_t *new_enc_session_c(const char *domain, lsquic_cid_t cid,
}
void free_enc_session(lsquic_enc_session_t *enc_session)
static void
lsquic_enc_session_destroy (lsquic_enc_session_t *enc_session)
{
if (!enc_session)
return ;
@ -360,7 +489,8 @@ void free_enc_session(lsquic_enc_session_t *enc_session)
}
void free_info(lsquic_session_cache_info_t *info)
static void
free_info (lsquic_session_cache_info_t *info)
{
lsquic_str_d(&info->sstk);
lsquic_str_d(&info->scfg);
@ -376,7 +506,8 @@ static int get_hs_state(lsquic_enc_session_t *enc_session)
/* make sure have more room for encrypt */
int is_hs_done(lsquic_enc_session_t *enc_session)
static int
lsquic_enc_session_is_hsk_done (lsquic_enc_session_t *enc_session)
{
return (get_hs_state(enc_session) == HSK_COMPLETED);
}
@ -672,7 +803,8 @@ generate_cid_buf (void *buf, size_t bufsz)
}
lsquic_cid_t generate_cid(void)
static lsquic_cid_t
lsquic_generate_cid (void)
{
lsquic_cid_t cid;
generate_cid_buf(&cid, sizeof(cid));
@ -783,9 +915,9 @@ struct message_writer
#define MSG_LEN_VAL(len) (+(len))
int
gen_chlo (lsquic_enc_session_t *enc_session, enum lsquic_version version,
uint8_t *buf, size_t *len)
static int
lsquic_enc_session_gen_chlo (lsquic_enc_session_t *enc_session,
enum lsquic_version version, uint8_t *buf, size_t *len)
{
int ret, include_pad;
const lsquic_str_t *const ccs = get_common_certs_hash();
@ -944,7 +1076,7 @@ gen_chlo (lsquic_enc_session_t *enc_session, enum lsquic_version version,
else
ret = 0;
LSQ_DEBUG("gen_chlo called, return %d, buf_len %zd.", ret, *len);
LSQ_DEBUG("lsquic_enc_session_gen_chlo called, return %d, buf_len %zd.", ret, *len);
return ret;
}
@ -1000,7 +1132,8 @@ void setup_aead_ctx(EVP_AEAD_CTX **ctx, unsigned char key[], int key_len,
}
int determine_diversification_key(lsquic_enc_session_t *enc_session,
static int
determine_diversification_key (lsquic_enc_session_t *enc_session,
uint8_t *diversification_nonce
)
{
@ -1177,8 +1310,9 @@ he2str (enum handshake_error he)
* DATA_NOT_ENOUGH(-2) for not enough data,
* DATA_FORMAT_ERROR(-1) all other errors
*/
int handle_chlo_reply(lsquic_enc_session_t *enc_session, const uint8_t *data,
int len)
static int
lsquic_enc_session_handle_chlo_reply (lsquic_enc_session_t *enc_session,
const uint8_t *data, int len)
{
uint32_t head_tag;
int ret;
@ -1278,7 +1412,7 @@ int handle_chlo_reply(lsquic_enc_session_t *enc_session, const uint8_t *data,
}
end:
LSQ_DEBUG("handle_chlo_reply called, buf in %d, return %d.", len, ret);
LSQ_DEBUG("lsquic_enc_session_handle_chlo_reply called, buf in %d, return %d.", len, ret);
EV_LOG_CONN_EVENT(enc_session->cid, "%s returning %s", __func__,
he2str(ret));
return ret;
@ -1413,28 +1547,20 @@ decrypt_packet (lsquic_enc_session_t *enc_session, uint8_t path_id,
}
#ifndef NDEBUG
/* In debug builds, we need to be able to override this function for testing */
__attribute__((weak))
int
static int
lsquic_enc_session_have_key_gt_one (const lsquic_enc_session_t *enc_session)
{
return enc_session && enc_session->have_key > 1;
}
#endif
#ifndef NDEBUG
/* Use weak linkage so that tests can override this function */
__attribute__((weak))
#endif
/* The size of `buf' is *header_len plus data_len. The two parts of the
* buffer correspond to the header and the payload of incoming QUIC packet.
*/
/* 0 for OK, otherwise nonezero */
int lsquic_dec(lsquic_enc_session_t *enc_session, enum lsquic_version version,
static int
lsquic_enc_session_decrypt (lsquic_enc_session_t *enc_session,
enum lsquic_version version,
uint8_t path_id, uint64_t pack_num,
unsigned char *buf, size_t *header_len, size_t data_len,
unsigned char *diversification_nonce,
@ -1456,7 +1582,9 @@ int lsquic_dec(lsquic_enc_session_t *enc_session, enum lsquic_version version,
}
int lsquic_enc(lsquic_enc_session_t *enc_session, enum lsquic_version version,
static int
lsquic_enc_session_encrypt (lsquic_enc_session_t *enc_session,
enum lsquic_version version,
uint8_t path_id, uint64_t pack_num,
const unsigned char *header, size_t header_len,
const unsigned char *data, size_t data_len,
@ -1507,7 +1635,7 @@ int lsquic_enc(lsquic_enc_session_t *enc_session, enum lsquic_version version,
((IS_SERVER(enc_session)) &&
enc_session->server_start_use_final_key == 0))
{
LSQ_DEBUG("lsquic_enc using 'I' key...");
LSQ_DEBUG("lsquic_enc_session_encrypt using 'I' key...");
key = enc_session->enc_ctx_i;
memcpy(nonce, enc_session->enc_key_nonce_i, 4);
if (is_shlo && enc_session->have_key == 3)
@ -1517,7 +1645,7 @@ int lsquic_enc(lsquic_enc_session_t *enc_session, enum lsquic_version version,
}
else
{
LSQ_DEBUG("lsquic_enc using 'F' key...");
LSQ_DEBUG("lsquic_enc_session_encrypt using 'F' key...");
key = enc_session->enc_ctx_f;
memcpy(nonce, enc_session->enc_key_nonce_f, 4);
}
@ -1536,8 +1664,9 @@ int lsquic_enc(lsquic_enc_session_t *enc_session, enum lsquic_version version,
}
int
get_peer_option (const lsquic_enc_session_t *enc_session, uint32_t tag)
static int
lsquic_enc_session_get_peer_option (const lsquic_enc_session_t *enc_session,
uint32_t tag)
{
switch (tag)
{
@ -1555,9 +1684,9 @@ get_peer_option (const lsquic_enc_session_t *enc_session, uint32_t tag)
/* Query a several parameters sent by the peer that are required by
* connection.
*/
int
get_peer_setting (const lsquic_enc_session_t *enc_session, uint32_t tag,
uint32_t *val)
static int
lsquic_enc_session_get_peer_setting (const lsquic_enc_session_t *enc_session,
uint32_t tag, uint32_t *val)
{
switch (tag)
{
@ -1616,7 +1745,7 @@ get_peer_setting (const lsquic_enc_session_t *enc_session, uint32_t tag,
#if LSQUIC_KEEP_ENC_SESS_HISTORY
void
static void
lsquic_get_enc_hist (const lsquic_enc_session_t *enc_session,
char buf[(1 << ESHIST_BITS) + 1])
{
@ -1635,3 +1764,25 @@ lsquic_get_enc_hist (const lsquic_enc_session_t *enc_session,
#endif
#ifdef NDEBUG
const
#endif
struct enc_session_funcs lsquic_enc_session_gquic_1 =
{
.esf_global_init = lsquic_handshake_init,
.esf_global_cleanup = lsquic_handshake_cleanup,
#if LSQUIC_KEEP_ENC_SESS_HISTORY
.esf_get_hist = lsquic_get_enc_hist,
#endif
.esf_destroy = lsquic_enc_session_destroy,
.esf_is_hsk_done = lsquic_enc_session_is_hsk_done,
.esf_encrypt = lsquic_enc_session_encrypt,
.esf_decrypt = lsquic_enc_session_decrypt,
.esf_get_peer_setting = lsquic_enc_session_get_peer_setting,
.esf_get_peer_option = lsquic_enc_session_get_peer_option,
.esf_create_client = lsquic_enc_session_create_client,
.esf_generate_cid = lsquic_generate_cid,
.esf_gen_chlo = lsquic_enc_session_gen_chlo,
.esf_handle_chlo_reply = lsquic_enc_session_handle_chlo_reply,
};

View File

@ -1,18 +1,11 @@
/* Copyright (c) 2017 LiteSpeed Technologies Inc. See LICENSE. */
#ifndef LSQUIC_HANDSHAKE_H
#define LSQUIC_HANDSHAKE_H
#include <stdint.h>
#include <openssl/base.h>
#include <openssl/aead.h>
#include <time.h>
#include "lsquic_str.h"
#ifndef LSQUIC_HANDSHAKE_SERVER_H
#define LSQUIC_HANDSHAKE_SERVER_H
struct lsquic_engine_public;
struct sockaddr;
struct lsquic_enc_session;
#include "lsquic_qtags.h"
typedef struct lsquic_enc_session lsquic_enc_session_t;
#define STK_LENGTH 60
#define SNO_LENGTH 56
@ -21,16 +14,6 @@ struct sockaddr;
#define aes128_key_len 16
#define aes128_iv_len 4
/* client side, certs and hashs
*/
typedef struct cert_hash_item_st
{
struct lsquic_str* domain; /*with port, such as "xyz.com:8088" as the key */
struct lsquic_str* crts;
struct lsquic_str* hashs;
int count;
} cert_hash_item_t;
enum handshake_error /* TODO: rename this enum */
{
DATA_NOT_ENOUGH = -2,
@ -42,66 +25,6 @@ enum handshake_error /* TODO: rename this enum */
HS_2RTT = 2,
};
enum handshake_state
{
HSK_CHLO_REJ = 0,
HSK_SHLO,
HSK_COMPLETED,
N_HSK_STATES
};
typedef struct tag_value_st
{
uint32_t tag;
const char * value;
int len;
} tag_value_t;
typedef struct hs_ctx_st
{
enum {
HSET_TCID = (1 << 0), /* tcid is set */
HSET_SMHL = (1 << 1), /* smhl is set */
HSET_SCID = (1 << 2),
} set;
enum {
HOPT_NSTP = (1 << 0), /* NSTP option present in COPT */
HOPT_SREJ = (1 << 1), /* SREJ option present in COPT */
} opts;
uint32_t pdmd;
uint32_t aead;
uint32_t kexs;
uint32_t mids;
uint32_t scls;
uint32_t cfcw;
uint32_t sfcw;
uint32_t srbf;
uint32_t icsl;
uint32_t irtt;
uint64_t rcid;
uint32_t tcid;
uint32_t smhl;
uint64_t ctim; /* any usage? */
uint64_t sttl;
unsigned char scid[SCID_LENGTH];
//unsigned char chlo_hash[32]; //SHA256 HASH of CHLO
unsigned char nonc[DNONC_LENGTH]; /* 4 tm, 8 orbit ---> REJ, 20 rand */
unsigned char pubs[32];
uint32_t rrej;
struct lsquic_str ccs;
struct lsquic_str sni; /* 0 rtt */
struct lsquic_str ccrt;
struct lsquic_str stk;
struct lsquic_str sno;
struct lsquic_str prof;
struct lsquic_str csct;
struct lsquic_str crt; /* compressed certs buffer */
} hs_ctx_t;
/* client side need to store 0rtt info per STK */
typedef struct lsquic_session_cache_info_st
{
@ -129,126 +52,89 @@ typedef struct lsquic_session_cache_info_st
#endif
#if LSQUIC_KEEP_ENC_SESS_HISTORY
#define ESHIST_BITS 7
#define ESHIST_MASK ((1 << ESHIST_BITS) - 1)
#define ESHIST_STR_SIZE ((1 << ESHIST_BITS) + 1)
typedef unsigned char eshist_idx_t;
enum enc_sess_history_event
{
ESHE_EMPTY = '\0',
ESHE_SET_SNI = 'I',
ESHE_SET_SNO = 'O',
ESHE_SET_STK = 'K',
ESHE_SET_SCID = 'D',
ESHE_SET_PROF = 'P',
};
#endif
typedef struct lsquic_enc_session
struct enc_session_funcs
{
enum handshake_state hsk_state;
uint8_t have_key; /* 0, no 1, I, 2, D, 3, F */
uint8_t peer_have_final_key;
uint8_t server_start_use_final_key;
/* Global initialization: call once per implementation */
int (*esf_global_init)(int flags);
lsquic_cid_t cid;
unsigned char priv_key[32];
EVP_AEAD_CTX *enc_ctx_i;
EVP_AEAD_CTX *dec_ctx_i;
/* Have to save the initial key for diversification need */
unsigned char enc_key_i[aes128_key_len];
unsigned char dec_key_i[aes128_key_len];
unsigned char enc_key_nonce_i[aes128_iv_len];
unsigned char dec_key_nonce_i[aes128_iv_len];
EVP_AEAD_CTX *enc_ctx_f;
EVP_AEAD_CTX *dec_ctx_f;
unsigned char enc_key_nonce_f[aes128_iv_len];
unsigned char dec_key_nonce_f[aes128_iv_len];
hs_ctx_t hs_ctx;
lsquic_session_cache_info_t *info;
SSL_CTX * ssl_ctx;
const struct lsquic_engine_public *enpub;
struct lsquic_str * cert_ptr; /* pointer to the leaf cert of the server, not real copy */
struct lsquic_str chlo; /* real copy of CHLO message */
struct lsquic_str sstk;
struct lsquic_str ssno;
/* Global cleanup: call once per implementation */
void (*esf_global_cleanup) (void);
#if LSQUIC_KEEP_ENC_SESS_HISTORY
eshist_idx_t es_hist_idx;
unsigned char es_hist_buf[1 << ESHIST_BITS];
#endif
} lsquic_enc_session_t;
#if LSQUIC_KEEP_ENC_SESS_HISTORY
void
lsquic_get_enc_hist (const lsquic_enc_session_t *, char buf[ESHIST_STR_SIZE]);
/* Grab encryption session history */
void (*esf_get_hist) (const lsquic_enc_session_t *,
char buf[ESHIST_STR_SIZE]);
#endif
int handshake_init(int flags);
void handshake_cleanup();
/* Destroy enc session */
void (*esf_destroy)(lsquic_enc_session_t *enc_session);
lsquic_enc_session_t *
new_enc_session_c(const char *domain, lsquic_cid_t cid,
const struct lsquic_engine_public *);
/* Return true if handshake has been completed */
int (*esf_is_hsk_done)(lsquic_enc_session_t *enc_session);
void free_enc_session(lsquic_enc_session_t *enc_session);
void free_info(lsquic_session_cache_info_t *info);
lsquic_cid_t generate_cid(void);
/* save to hash table */
lsquic_session_cache_info_t *retrieve_session_info_entry(const char *key);
void remove_expire_session_info_entry();
void remove_session_info_entry(struct lsquic_str *key);
cert_hash_item_t *make_cert_hash_item(struct lsquic_str *domain, struct lsquic_str **certs, int count);
void c_free_cert_hash_item(cert_hash_item_t *item);
cert_hash_item_t* c_find_certs(struct lsquic_str *domain);
int c_insert_certs(cert_hash_item_t *item);
/* -1 error, 0, OK, response in `buf' */
int gen_chlo(lsquic_enc_session_t *enc_session, enum lsquic_version,
uint8_t *buf, size_t *len);
int handle_chlo_reply(lsquic_enc_session_t *enc_session, const uint8_t *data,
int len);
int is_hs_done(lsquic_enc_session_t *enc_session);
/**
* The belows are global functions
*/
int lsquic_enc(lsquic_enc_session_t *enc_session, enum lsquic_version,
/* Encrypt buffer */
int (*esf_encrypt)(lsquic_enc_session_t *enc_session, enum lsquic_version,
uint8_t path_id, uint64_t pack_num,
const unsigned char *header, size_t header_len,
const unsigned char *data, size_t data_len,
unsigned char *buf_out, size_t max_out_len, size_t *out_len,
int is_hello);
int lsquic_dec(lsquic_enc_session_t *enc_session, enum lsquic_version,
uint8_t path_id, uint64_t pack_num,
unsigned char *buf, size_t *header_len, size_t data_len,
unsigned char *diversification_nonce,
unsigned char *buf_out, size_t max_out_len, size_t *out_len);
/* Decrypt buffer */
int (*esf_decrypt)(lsquic_enc_session_t *enc_session, enum lsquic_version,
uint8_t path_id, uint64_t pack_num,
unsigned char *buf, size_t *header_len, size_t data_len,
unsigned char *diversification_nonce,
unsigned char *buf_out, size_t max_out_len, size_t *out_len);
int
get_peer_setting (const lsquic_enc_session_t *, uint32_t tag, uint32_t *val);
/* Get value of setting specified by `tag' */
int (*esf_get_peer_setting) (const lsquic_enc_session_t *, uint32_t tag,
uint32_t *val);
int
get_peer_option (const lsquic_enc_session_t *enc_session, uint32_t tag);
/* Get value of peer option (that from COPT array) */
int (*esf_get_peer_option) (const lsquic_enc_session_t *enc_session,
uint32_t tag);
/* Create client session */
lsquic_enc_session_t *
(*esf_create_client) (const char *domain, lsquic_cid_t cid,
const struct lsquic_engine_public *);
/* Generate connection ID */
lsquic_cid_t (*esf_generate_cid) (void);
/* -1 error, 0, OK, response in `buf' */
int
(*esf_gen_chlo) (lsquic_enc_session_t *, enum lsquic_version,
uint8_t *buf, size_t *len);
int
(*esf_handle_chlo_reply) (lsquic_enc_session_t *,
const uint8_t *data, int len);
};
extern
#ifdef NDEBUG
#define lsquic_enc_session_have_key_gt_one(e) ((e) && (e)->have_key > 1)
#else
int
lsquic_enc_session_have_key_gt_one (const lsquic_enc_session_t *enc_session);
const
#endif
struct enc_session_funcs lsquic_enc_session_gquic_1;
#define select_esf_by_ver(ver) \
(ver ? &lsquic_enc_session_gquic_1 : &lsquic_enc_session_gquic_1)
/* client side, certs and hashs
*/
typedef struct cert_hash_item_st
{
struct lsquic_str* domain; /*with port, such as "xyz.com:8088" as the key */
struct lsquic_str* crts;
struct lsquic_str* hashs;
int count;
} cert_hash_item_t;
#endif

View File

@ -8,7 +8,7 @@
#include <stdint.h>
typedef uint64_t lsquic_time_t; /* Microseconds since the epoch */
typedef uint64_t lsquic_time_t; /* Microseconds since some time */
typedef uint64_t lsquic_packno_t;
typedef uint32_t lsquic_ver_tag_t; /* Opaque 4-byte value */

View File

@ -235,8 +235,6 @@ calculate_packet_rto (lsquic_send_ctl_t *ctl)
exp = MAX_RTO_BACKOFFS;
delay = delay * (1 << exp);
if (delay > MAX_RTO_DELAY)
delay = MAX_RTO_DELAY;
return delay;
}
@ -306,6 +304,9 @@ set_retx_alarm (lsquic_send_ctl_t *ctl)
break;
}
if (delay > MAX_RTO_DELAY)
delay = MAX_RTO_DELAY;
LSQ_DEBUG("set retx alarm to %"PRIu64", which is %"PRIu64
" usec from now, mode %s", now + delay, delay, retx2str[rm]);
lsquic_alarmset_set(ctl->sc_alset, AL_RETX, now + delay);

View File

@ -8,17 +8,49 @@
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#if !(defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0) && defined(__APPLE__)
#include <mach/mach_time.h>
#endif
#include "lsquic_int_types.h"
#include "lsquic_util.h"
#if defined(__APPLE__)
static mach_timebase_info_data_t timebase;
#endif
void
lsquic_init_timers (void)
{
#if defined(__APPLE__)
mach_timebase_info(&timebase);
#endif
}
lsquic_time_t
lsquic_time_now (void)
{
#if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0
struct timespec ts;
(void) clock_gettime(CLOCK_MONOTONIC, &ts);
return (lsquic_time_t) ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
#elif defined(__APPLE__)
lsquic_time_t t = mach_absolute_time();
t *= timebase.numer;
t /= timebase.denom;
t /= 1000;
return t;
#else
# warn Monotonically increasing clock is not available on this platform
struct timeval tv;
(void) gettimeofday(&tv, NULL);
return (lsquic_time_t) tv.tv_sec * 1000000 + tv.tv_usec;
#endif
}

View File

@ -13,6 +13,9 @@ extern "C" {
lsquic_time_t
lsquic_time_now (void);
void
lsquic_init_timers (void);
/* Returns 1 if `buf' contains only zero bytes, 0 otherwise.
*/
int