nghttpx: Add an option to postpone early data processing

This commit is contained in:
Tatsuhiro Tsujikawa 2017-11-26 17:47:19 +09:00
parent 770e44de4d
commit 47f6012407
5 changed files with 33 additions and 2 deletions

View File

@ -170,6 +170,7 @@ OPTIONS = [
"no-verify-ocsp", "no-verify-ocsp",
"verify-client-tolerate-expired", "verify-client-tolerate-expired",
"ignore-per-pattern-mruby-error", "ignore-per-pattern-mruby-error",
"tls-postpone-early-data",
] ]
LOGVARS = [ LOGVARS = [

View File

@ -2370,6 +2370,12 @@ SSL/TLS:
HTTP/2. To use those cipher suites with HTTP/2, HTTP/2. To use those cipher suites with HTTP/2,
consider to use --client-no-http2-cipher-black-list consider to use --client-no-http2-cipher-black-list
option. But be aware its implications. option. But be aware its implications.
--tls-postpone-early-data
Postpone forwarding HTTP requests sent in early data,
including those sent in partially in it, until TLS
handshake finishes. This option must be used to
mitigate possible replay attack unless all backend
servers recognize "Early-Data" header field.
HTTP/2: HTTP/2:
-c, --frontend-http2-max-concurrent-streams=<N> -c, --frontend-http2-max-concurrent-streams=<N>
@ -3436,6 +3442,7 @@ int main(int argc, char **argv) {
160}, 160},
{SHRPX_OPT_IGNORE_PER_PATTERN_MRUBY_ERROR.c_str(), no_argument, &flag, {SHRPX_OPT_IGNORE_PER_PATTERN_MRUBY_ERROR.c_str(), no_argument, &flag,
161}, 161},
{SHRPX_OPT_TLS_POSTPONE_EARLY_DATA.c_str(), no_argument, &flag, 162},
{nullptr, 0, nullptr, 0}}; {nullptr, 0, nullptr, 0}};
int option_index = 0; int option_index = 0;
@ -4207,6 +4214,11 @@ int main(int argc, char **argv) {
cmdcfgs.emplace_back(SHRPX_OPT_IGNORE_PER_PATTERN_MRUBY_ERROR, cmdcfgs.emplace_back(SHRPX_OPT_IGNORE_PER_PATTERN_MRUBY_ERROR,
StringRef::from_lit("yes")); StringRef::from_lit("yes"));
break; break;
case 162:
// --tls-postpone-early-data
cmdcfgs.emplace_back(SHRPX_OPT_TLS_POSTPONE_EARLY_DATA,
StringRef::from_lit("yes"));
break;
default: default:
break; break;
} }

View File

@ -2040,6 +2040,11 @@ int option_lookup_token(const char *name, size_t namelen) {
break; break;
case 23: case 23:
switch (name[22]) { switch (name[22]) {
case 'a':
if (util::strieq_l("tls-postpone-early-dat", name, 22)) {
return SHRPX_OPTID_TLS_POSTPONE_EARLY_DATA;
}
break;
case 'e': case 'e':
if (util::strieq_l("client-private-key-fil", name, 22)) { if (util::strieq_l("client-private-key-fil", name, 22)) {
return SHRPX_OPTID_CLIENT_PRIVATE_KEY_FILE; return SHRPX_OPTID_CLIENT_PRIVATE_KEY_FILE;
@ -3590,6 +3595,10 @@ int parse_config(Config *config, int optid, const StringRef &opt,
case SHRPX_OPTID_IGNORE_PER_PATTERN_MRUBY_ERROR: case SHRPX_OPTID_IGNORE_PER_PATTERN_MRUBY_ERROR:
config->ignore_per_pattern_mruby_error = util::strieq_l("yes", optarg); config->ignore_per_pattern_mruby_error = util::strieq_l("yes", optarg);
return 0;
case SHRPX_OPTID_TLS_POSTPONE_EARLY_DATA:
config->tls.postpone_early_data = util::strieq_l("yes", optarg);
return 0; return 0;
case SHRPX_OPTID_CONF: case SHRPX_OPTID_CONF:
LOG(WARN) << "conf: ignored"; LOG(WARN) << "conf: ignored";

View File

@ -347,6 +347,8 @@ constexpr auto SHRPX_OPT_VERIFY_CLIENT_TOLERATE_EXPIRED =
StringRef::from_lit("verify-client-tolerate-expired"); StringRef::from_lit("verify-client-tolerate-expired");
constexpr auto SHRPX_OPT_IGNORE_PER_PATTERN_MRUBY_ERROR = constexpr auto SHRPX_OPT_IGNORE_PER_PATTERN_MRUBY_ERROR =
StringRef::from_lit("ignore-per-pattern-mruby-error"); StringRef::from_lit("ignore-per-pattern-mruby-error");
constexpr auto SHRPX_OPT_TLS_POSTPONE_EARLY_DATA =
StringRef::from_lit("tls-postpone-early-data");
constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8; constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8;
@ -656,6 +658,9 @@ struct TLSConfig {
int max_proto_version; int max_proto_version;
bool insecure; bool insecure;
bool no_http2_cipher_black_list; bool no_http2_cipher_black_list;
// true if forwarding requests included in TLS early data should be
// postponed until TLS handshake finishes.
bool postpone_early_data;
}; };
// custom error page // custom error page
@ -1116,6 +1121,7 @@ enum {
SHRPX_OPTID_TLS_DYN_REC_WARMUP_THRESHOLD, SHRPX_OPTID_TLS_DYN_REC_WARMUP_THRESHOLD,
SHRPX_OPTID_TLS_MAX_PROTO_VERSION, SHRPX_OPTID_TLS_MAX_PROTO_VERSION,
SHRPX_OPTID_TLS_MIN_PROTO_VERSION, SHRPX_OPTID_TLS_MIN_PROTO_VERSION,
SHRPX_OPTID_TLS_POSTPONE_EARLY_DATA,
SHRPX_OPTID_TLS_PROTO_LIST, SHRPX_OPTID_TLS_PROTO_LIST,
SHRPX_OPTID_TLS_SCT_DIR, SHRPX_OPTID_TLS_SCT_DIR,
SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED, SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED,

View File

@ -396,6 +396,7 @@ int Connection::tls_handshake() {
if (!tls.server_handshake || tls.early_data_finish) { if (!tls.server_handshake || tls.early_data_finish) {
rv = SSL_do_handshake(tls.ssl); rv = SSL_do_handshake(tls.ssl);
} else { } else {
auto &tlsconf = get_config()->tls;
for (;;) { for (;;) {
size_t nread; size_t nread;
@ -407,7 +408,8 @@ int Connection::tls_handshake() {
// server waits for EndOfEarlyData and Finished message from // server waits for EndOfEarlyData and Finished message from
// client, which voids the purpose of 0-RTT data. The left // client, which voids the purpose of 0-RTT data. The left
// over of handshake is done through write_tls or read_tls. // over of handshake is done through write_tls or read_tls.
if ((tls.handshake_state == TLS_CONN_WRITE_STARTED || if (!tlsconf.postpone_early_data &&
(tls.handshake_state == TLS_CONN_WRITE_STARTED ||
tls.wbuf.rleft()) && tls.wbuf.rleft()) &&
tls.earlybuf.rleft()) { tls.earlybuf.rleft()) {
rv = 1; rv = 1;
@ -429,7 +431,8 @@ int Connection::tls_handshake() {
} }
tls.early_data_finish = true; tls.early_data_finish = true;
// The same reason stated above. // The same reason stated above.
if ((tls.handshake_state == TLS_CONN_WRITE_STARTED || if (!tlsconf.postpone_early_data &&
(tls.handshake_state == TLS_CONN_WRITE_STARTED ||
tls.wbuf.rleft()) && tls.wbuf.rleft()) &&
tls.earlybuf.rleft()) { tls.earlybuf.rleft()) {
rv = 1; rv = 1;