Release 2.14.6

- [BUGFIX] Fix amplification mitigation in 0-RTT case.
- [BUGFIX] IETF mini connection should not tickable if cannot send
  a packet due to amplification.
- [BUGFIX] Fail if active_connection_id_limit TP is smaller than 2.
- [BUGFIX] Qlog server certificates for IETF QUIC connections.
- [BUGFIX] Uninitialized struct padding usage in tokgen (benign).
- [BUGFIX] Incorrect argument to shi_lookup() (benign).
This commit is contained in:
Dmitri Tikhonov 2020-05-06 09:35:33 -04:00
parent 72585dc942
commit b55a5117d9
18 changed files with 248 additions and 20 deletions

View File

@ -1,3 +1,13 @@
2020-05-06
- 2.14.6
- [BUGFIX] Fix amplification mitigation in 0-RTT case.
- [BUGFIX] IETF mini connection should not tickable if cannot send
a packet due to amplification.
- [BUGFIX] Fail if active_connection_id_limit TP is smaller than 2.
- [BUGFIX] Qlog server certificates for IETF QUIC connections.
- [BUGFIX] Uninitialized struct padding usage in tokgen (benign).
- [BUGFIX] Incorrect argument to shi_lookup() (benign).
2020-04-29
- 2.14.5
- [BUGFIX] In coalesced datagram, ignore packets whose CID does not match.

View File

@ -26,7 +26,7 @@ author = u'LiteSpeed Technologies'
# The short X.Y version
version = u'2.14'
# The full version, including alpha/beta/rc tags
release = u'2.14.5'
release = u'2.14.6'
# -- General configuration ---------------------------------------------------

View File

@ -25,7 +25,7 @@ extern "C" {
#define LSQUIC_MAJOR_VERSION 2
#define LSQUIC_MINOR_VERSION 14
#define LSQUIC_PATCH_VERSION 5
#define LSQUIC_PATCH_VERSION 6
/**
* Engine flags:

View File

@ -57,6 +57,11 @@ struct lsquic_conn_public {
#if LSQUIC_EXTRA_CHECKS
unsigned long stream_frame_bytes;
#endif
/* "unsigned" is wide enough: these values are only used for amplification
* limit before initial path is validated.
*/
unsigned bytes_in; /* successfully processed */
unsigned bytes_out;
};
#endif

View File

@ -1019,9 +1019,15 @@ verify_server_cert_callback (SSL *ssl, uint8_t *out_alert)
return ssl_verify_invalid;
}
s = enc_sess->esi_enpub->enp_verify_cert(
enc_sess->esi_enpub->enp_verify_ctx, chain);
return s == 0 ? ssl_verify_ok : ssl_verify_invalid;
EV_LOG_CERT_CHAIN(LSQUIC_LOG_CONN_ID, chain);
if (enc_sess->esi_enpub->enp_verify_cert)
{
s = enc_sess->esi_enpub->enp_verify_cert(
enc_sess->esi_enpub->enp_verify_ctx, chain);
return s == 0 ? ssl_verify_ok : ssl_verify_invalid;
}
else
return ssl_verify_ok;
}
@ -1302,7 +1308,9 @@ init_client (struct enc_sess_iquic *const enc_sess)
SSL_CTX_sess_set_new_cb(ssl_ctx, iquic_new_session_cb);
if (enc_sess->esi_enpub->enp_kli)
SSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback);
if (enc_sess->esi_enpub->enp_verify_cert)
if (enc_sess->esi_enpub->enp_verify_cert
|| LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)
|| LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_QLOG))
SSL_CTX_set_custom_verify(ssl_ctx, SSL_VERIFY_PEER,
verify_server_cert_callback);
SSL_CTX_set_early_data_enabled(ssl_ctx, 1);

View File

@ -10,6 +10,8 @@
#include <string.h>
#include <sys/queue.h>
#include <openssl/x509.h>
#include "lsquic.h"
#include "lsquic_types.h"
#include "lsquic_int_types.h"
@ -566,6 +568,24 @@ lsquic_ev_log_check_certs (const lsquic_cid_t *cid, const lsquic_str_t **certs,
}
void
lsquic_ev_log_cert_chain (const lsquic_cid_t *cid, struct stack_st_X509 *chain)
{
X509_NAME *name;
X509 *cert;
unsigned i;
char buf[0x100];
for (i = 0; i < sk_X509_num(chain); ++i)
{
cert = sk_X509_value(chain, i);
name = X509_get_subject_name(cert);
LCID("cert #%u: name: %s", i,
X509_NAME_oneline(name, buf, sizeof(buf)));
}
}
void
lsquic_ev_log_version_negotiation (const lsquic_cid_t *cid,
const char *action, const char *ver)

View File

@ -17,6 +17,7 @@ struct lsquic_packet_out;
struct parse_funcs;
struct stream_frame;
struct uncompressed_headers;
struct stack_st_X509;
/* Log a generic event not tied to any particular connection */
@ -329,6 +330,16 @@ lsquic_ev_log_check_certs (const lsquic_cid_t *, const lsquic_str_t **, size_t);
lsquic_qlog_check_certs(__VA_ARGS__); \
} while (0)
void
lsquic_ev_log_cert_chain (const lsquic_cid_t *, struct stack_st_X509 *);
#define EV_LOG_CERT_CHAIN(...) do { \
if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)) \
lsquic_ev_log_cert_chain(__VA_ARGS__); \
if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_QLOG)) \
lsquic_qlog_cert_chain(__VA_ARGS__); \
} while (0)
void
lsquic_ev_log_version_negotiation (const lsquic_cid_t *, const char *, const char *);

View File

@ -138,6 +138,12 @@ enum ifull_conn_flags
};
enum more_flags
{
MF_VALIDATE_PATH = 1 << 0,
};
#define N_PATHS 2
enum send
@ -315,6 +321,7 @@ struct ietf_full_conn
unsigned ifc_max_streams_in[N_SDS];
uint64_t ifc_max_stream_data_uni;
enum ifull_conn_flags ifc_flags;
enum more_flags ifc_mflags;
enum send_flags ifc_send_flags;
enum send_flags ifc_delayed_send;
struct {
@ -1318,6 +1325,12 @@ lsquic_ietf_full_conn_server_new (struct lsquic_engine_public *enpub,
conn->ifc_paths[0].cop_path = imc->imc_path;
conn->ifc_paths[0].cop_flags = COP_VALIDATED;
conn->ifc_used_paths = 1 << 0;
if (imc->imc_flags & IMC_ADDR_VALIDATED)
lsquic_send_ctl_path_validated(&conn->ifc_send_ctl);
else
conn->ifc_mflags |= MF_VALIDATE_PATH;
conn->ifc_pub.bytes_out = imc->imc_bytes_out;
conn->ifc_pub.bytes_in = imc->imc_bytes_in;
if (imc->imc_flags & IMC_PATH_CHANGED)
{
LSQ_DEBUG("path changed during mini conn: schedule PATH_CHALLENGE");
@ -6284,6 +6297,14 @@ process_regular_packet (struct ietf_full_conn *conn,
else
conn->ifc_spin_bit = !lsquic_packet_in_spin_bit(packet_in);
}
conn->ifc_pub.bytes_in += packet_in->pi_data_sz;
if ((conn->ifc_mflags & MF_VALIDATE_PATH) &&
(packet_in->pi_header_type == HETY_NOT_SET
|| packet_in->pi_header_type == HETY_HANDSHAKE))
{
conn->ifc_mflags &= ~MF_VALIDATE_PATH;
lsquic_send_ctl_path_validated(&conn->ifc_send_ctl);
}
return 0;
case REC_ST_DUP:
LSQ_INFO("packet %"PRIu64" is a duplicate", packet_in->pi_packno);
@ -6482,6 +6503,8 @@ ietf_full_conn_ci_packet_sent (struct lsquic_conn *lconn,
lsquic_alarmset_set(&conn->ifc_alset, AL_BLOCKED_KA,
packet_out->po_sent + (1 + (7 & lsquic_crand_get_nybble(
conn->ifc_enpub->enp_crand))) * 1000000);
conn->ifc_pub.bytes_out += lsquic_packet_out_sent_sz(&conn->ifc_conn,
packet_out);
}

View File

@ -46,6 +46,9 @@ static const struct conn_iface mini_conn_ietf_iface;
static unsigned highest_bit_set (unsigned long long);
static int
imico_can_send (const struct ietf_mini_conn *, size_t);
static const enum header_type el2hety[] =
{
@ -625,11 +628,15 @@ ietf_mini_conn_ci_is_tickable (struct lsquic_conn *lconn)
{
struct ietf_mini_conn *const conn = (struct ietf_mini_conn *) lconn;
const struct lsquic_packet_out *packet_out;
size_t packet_size;
if (conn->imc_enpub->enp_flags & ENPUB_CAN_SEND)
TAILQ_FOREACH(packet_out, &conn->imc_packets_out, po_next)
if (!(packet_out->po_flags & PO_SENT))
return 1;
{
packet_size = lsquic_packet_out_total_sz(lconn, packet_out);
return imico_can_send(conn, packet_size + IQUIC_TAG_LEN);
}
return 0;
}

View File

@ -214,7 +214,7 @@ typedef struct lsquic_packet_out
lconn->cn_pf->pf_packout_max_header_size(lconn, po_flags, dcid_len))
#define lsquic_packet_out_total_sz(lconn, p) (\
lconn->cn_pf->pf_packout_size(lconn, p))
(lconn)->cn_pf->pf_packout_size(lconn, p))
#if __GNUC__
#if LSQUIC_EXTRA_CHECKS

View File

@ -14,6 +14,9 @@
#include <arpa/inet.h>
#endif
#include <openssl/ssl.h>
#include <openssl/x509.h>
#include "lsquic.h"
#include "lsquic_types.h"
#include "lsquic_int_types.h"
@ -203,6 +206,46 @@ lsquic_qlog_check_certs (const lsquic_cid_t* cid, const lsquic_str_t **certs,
}
void
lsquic_qlog_cert_chain (const lsquic_cid_t* cid, struct stack_st_X509 *chain)
{
X509 *cert;
unsigned i;
unsigned char *buf;
char *hexbuf, *newbuf;
size_t hexbuf_sz;
int len;
lsquic_time_t now;
now = lsquic_time_now();
hexbuf = NULL;
hexbuf_sz = 0;
for (i = 0; i < sk_X509_num(chain); ++i)
{
cert = sk_X509_value(chain, i);
buf = NULL;
len = i2d_X509(cert, &buf);
if (len <= 0)
break;
if ((size_t) len * 2 + 1 > hexbuf_sz)
{
hexbuf_sz = len * 2 + 1;
newbuf = realloc(hexbuf, hexbuf_sz);
if (!newbuf)
break;
hexbuf = newbuf;
}
lsquic_hexstr(buf, (size_t) len, hexbuf, hexbuf_sz);
LCID("[%" PRIu64 ",\"SECURITY\",\"CHECK_CERT\",\"CERTLOG\","
"{\"certificate\":\"%s\"}]", now, hexbuf);
OPENSSL_free(buf);
}
if (hexbuf)
free(hexbuf);
}
void
lsquic_qlog_version_negotiation (const lsquic_cid_t* cid,
const char *action, const char *ver)

View File

@ -10,6 +10,8 @@
#include "lsquic_packet_common.h"
#include "lsquic_str.h"
struct stack_st_X509;
/*
EventCategory
CONNECTIVITY
@ -83,6 +85,9 @@ lsquic_qlog_zero_rtt (const lsquic_cid_t *);
void
lsquic_qlog_check_certs (const lsquic_cid_t *, const lsquic_str_t **, size_t);
void
lsquic_qlog_cert_chain (const lsquic_cid_t *, struct stack_st_X509 *);
void
lsquic_qlog_version_negotiation (const lsquic_cid_t *, const char *, const char *);

View File

@ -119,6 +119,12 @@ send_ctl_all_bytes_out (const struct lsquic_send_ctl *ctl);
static void
send_ctl_reschedule_poison (struct lsquic_send_ctl *ctl);
static int
send_ctl_can_send_pre_hsk (struct lsquic_send_ctl *ctl);
static int
send_ctl_can_send (struct lsquic_send_ctl *ctl);
#ifdef NDEBUG
static
#elif __GNUC__
@ -363,6 +369,11 @@ lsquic_send_ctl_init (lsquic_send_ctl_t *ctl, struct lsquic_alarmset *alset,
ctl->sc_flags |= SC_SANITY_CHECK;
#endif
ctl->sc_gap = UINT64_MAX - 1 /* Can't have +1 == 0 */;
if ((ctl->sc_conn_pub->lconn->cn_flags & (LSCONN_IETF|LSCONN_SERVER))
== (LSCONN_IETF|LSCONN_SERVER))
ctl->sc_can_send = send_ctl_can_send_pre_hsk;
else
ctl->sc_can_send = send_ctl_can_send;
}
@ -1101,8 +1112,6 @@ lsquic_send_ctl_got_ack (lsquic_send_ctl_t *ctl,
packet_out->po_packno);
#if LSQUIC_CONN_STATS
++ctl->sc_conn_pub->conn_stats->out.acked_via_loss;
LSQ_DEBUG("acking via loss record %"PRIu64,
packet_out->po_packno);
#endif
}
else
@ -1367,13 +1376,8 @@ lsquic_send_ctl_pacer_blocked (struct lsquic_send_ctl *ctl)
}
#ifndef NDEBUG
#if __GNUC__
__attribute__((weak))
#endif
#endif
int
lsquic_send_ctl_can_send (lsquic_send_ctl_t *ctl)
static int
send_ctl_can_send (struct lsquic_send_ctl *ctl)
{
const unsigned n_out = send_ctl_all_bytes_out(ctl);
LSQ_DEBUG("%s: n_out: %u (unacked_all: %u); cwnd: %"PRIu64, __func__,
@ -1400,6 +1404,37 @@ lsquic_send_ctl_can_send (lsquic_send_ctl_t *ctl)
}
static int
send_ctl_can_send_pre_hsk (struct lsquic_send_ctl *ctl)
{
unsigned bytes_in, bytes_out;
bytes_in = ctl->sc_conn_pub->bytes_in;
bytes_out = ctl->sc_conn_pub->bytes_out + ctl->sc_bytes_scheduled;
if (bytes_out >= bytes_in * 2 + bytes_in / 2 /* This should work out
to around 3 on average */)
{
LSQ_DEBUG("%s: amplification block: %u bytes in, %u bytes out",
__func__, bytes_in, bytes_out);
return 0;
}
else
return send_ctl_can_send(ctl);
}
#ifndef NDEBUG
#if __GNUC__
__attribute__((weak))
#endif
#endif
int
lsquic_send_ctl_can_send (struct lsquic_send_ctl *ctl)
{
return ctl->sc_can_send(ctl);
}
/* Like lsquic_send_ctl_can_send(), but no mods */
static int
send_ctl_could_send (const struct lsquic_send_ctl *ctl)
@ -2986,3 +3021,11 @@ lsquic_send_ctl_begin_optack_detection (struct lsquic_send_ctl *ctl)
rand = lsquic_crand_get_byte(ctl->sc_enpub->enp_crand);
ctl->sc_gap = ctl->sc_cur_packno + 1 + rand;
}
void
lsquic_send_ctl_path_validated (struct lsquic_send_ctl *ctl)
{
LSQ_DEBUG("path validated: switch to regular can_send");
ctl->sc_can_send = send_ctl_can_send;
}

View File

@ -64,6 +64,7 @@ typedef struct lsquic_send_ctl {
lsquic_time_t sc_largest_acked_sent_time;
lsquic_time_t sc_last_sent_time;
lsquic_time_t sc_last_rto_time;
int (*sc_can_send)(struct lsquic_send_ctl *);
unsigned sc_bytes_unacked_retx;
unsigned sc_bytes_scheduled;
union {
@ -383,4 +384,7 @@ lsquic_send_ctl_begin_optack_detection (struct lsquic_send_ctl *);
#define lsquic_send_ctl_n_unacked(ctl_) ((ctl_)->sc_n_in_flight_retx)
void
lsquic_send_ctl_path_validated (struct lsquic_send_ctl *);
#endif

View File

@ -92,11 +92,18 @@ get_or_generate_state (struct lsquic_engine_public *enpub, time_t now,
size_t bufsz;
struct {
time_t now;
unsigned char buf[20];
} srst_ikm;
unsigned char buf[24];
}
#if __GNUC__
/* This is more of a documentation note: this struct should already
* have a multiple-of-eight size.
*/
__attribute__((packed))
#endif
srst_ikm;
data = shm_state;
sz = sizeof(shm_state);
sz = sizeof(*shm_state);
s = shi->shi_lookup(ctx, TOKGEN_SHM_KEY, TOKGEN_SHM_KEY_SIZE, &data, &sz);
if (s == 1)

View File

@ -152,6 +152,7 @@ static const uint64_t min_vals[MAX_NUMERIC_TPI + 1] =
/* On the other hand, we do enforce the lower bound. */
[TPI_MAX_PACKET_SIZE] = 1200,
[TPI_MIN_ACK_DELAY] = 1,
[TPI_ACTIVE_CONNECTION_ID_LIMIT] = 2,
};

View File

@ -67,6 +67,7 @@ SET(TESTS
stop_waiting_gquic_be
streamgen
streamparse
tokgen
trapa
varint
ver_nego

View File

@ -0,0 +1,40 @@
/* Copyright (c) 2017 - 2020 LiteSpeed Technologies Inc. See LICENSE. */
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <sys/queue.h>
#include "lsquic.h"
#include "lsquic_types.h"
#include "lsquic_int_types.h"
#include "lsquic_mm.h"
#include "lsquic_tokgen.h"
#include "lsquic_stock_shi.h"
#include "lsquic_engine_public.h"
int
main (int argc, char **argv)
{
struct lsquic_engine_public enpub = {
.enp_shi_ctx = lsquic_stock_shared_hash_new(),
.enp_shi = &stock_shi,
};
struct token_generator *tg;
unsigned char token[16];
unsigned i;
lsquic_cid_t cid;
memset(&cid, 0, sizeof(cid));
cid.len = 8;
tg = lsquic_tg_new(&enpub);
lsquic_tg_generate_sreset(tg, &cid, token);
for (i = 0; i < sizeof(token); ++i)
printf("%02X", token[i]);
printf("\n");
lsquic_tg_destroy(tg);
return 0;
}