diff --git a/gennghttpxfun.py b/gennghttpxfun.py index 7e391d21..f7e202fc 100755 --- a/gennghttpxfun.py +++ b/gennghttpxfun.py @@ -168,6 +168,7 @@ OPTIONS = [ "no-strip-incoming-x-forwarded-proto", "ocsp-startup", "no-verify-ocsp", + "verify-client-tolerate-expired", ] LOGVARS = [ diff --git a/src/shrpx.cc b/src/shrpx.cc index 95e1dda2..9dbdedb0 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -2137,6 +2137,11 @@ SSL/TLS: Path to file that contains CA certificates to verify client certificate. The file must be in PEM format. It can contain multiple certificates. + --verify-client-tolerate-expired + Accept expired client certificate. Operator should + handle the expired client certificate by some means + (e.g., mruby script). Otherwise, this option might + cause a security risk. --client-private-key-file= Path to file that contains client private key used in backend client authentication. @@ -3406,6 +3411,8 @@ int main(int argc, char **argv) { {SHRPX_OPT_NO_STRIP_INCOMING_X_FORWARDED_PROTO.c_str(), no_argument, &flag, 158}, {SHRPX_OPT_SINGLE_PROCESS.c_str(), no_argument, &flag, 159}, + {SHRPX_OPT_VERIFY_CLIENT_TOLERATE_EXPIRED.c_str(), no_argument, &flag, + 160}, {nullptr, 0, nullptr, 0}}; int option_index = 0; @@ -4167,6 +4174,11 @@ int main(int argc, char **argv) { cmdcfgs.emplace_back(SHRPX_OPT_SINGLE_PROCESS, StringRef::from_lit("yes")); break; + case 160: + // --verify-client-tolerate-expired + cmdcfgs.emplace_back(SHRPX_OPT_VERIFY_CLIENT_TOLERATE_EXPIRED, + StringRef::from_lit("yes")); + break; default: break; } diff --git a/src/shrpx_config.cc b/src/shrpx_config.cc index 21a7e09d..e7efed2b 100644 --- a/src/shrpx_config.cc +++ b/src/shrpx_config.cc @@ -2173,6 +2173,11 @@ int option_lookup_token(const char *name, size_t namelen) { break; case 30: switch (name[29]) { + case 'd': + if (util::strieq_l("verify-client-tolerate-expire", name, 29)) { + return SHRPX_OPTID_VERIFY_CLIENT_TOLERATE_EXPIRED; + } + break; case 'r': if (util::strieq_l("strip-incoming-x-forwarded-fo", name, 29)) { return SHRPX_OPTID_STRIP_INCOMING_X_FORWARDED_FOR; @@ -3554,6 +3559,10 @@ int parse_config(Config *config, int optid, const StringRef &opt, case SHRPX_OPTID_NO_VERIFY_OCSP: config->tls.ocsp.no_verify = util::strieq_l("yes", optarg); + return 0; + case SHRPX_OPTID_VERIFY_CLIENT_TOLERATE_EXPIRED: + config->tls.client_verify.tolerate_expired = util::strieq_l("yes", optarg); + return 0; case SHRPX_OPTID_CONF: LOG(WARN) << "conf: ignored"; diff --git a/src/shrpx_config.h b/src/shrpx_config.h index 96bf8c8e..d631a566 100644 --- a/src/shrpx_config.h +++ b/src/shrpx_config.h @@ -343,6 +343,8 @@ constexpr auto SHRPX_OPT_NO_STRIP_INCOMING_X_FORWARDED_PROTO = StringRef::from_lit("no-strip-incoming-x-forwarded-proto"); constexpr auto SHRPX_OPT_OCSP_STARTUP = StringRef::from_lit("ocsp-startup"); constexpr auto SHRPX_OPT_NO_VERIFY_OCSP = StringRef::from_lit("no-verify-ocsp"); +constexpr auto SHRPX_OPT_VERIFY_CLIENT_TOLERATE_EXPIRED = + StringRef::from_lit("verify-client-tolerate-expired"); constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8; @@ -602,6 +604,8 @@ struct TLSConfig { // certificate validation StringRef cacert; bool enabled; + // true if we accept an expired client certificate. + bool tolerate_expired; } client_verify; // Client (backend connection) TLS configuration. @@ -1125,6 +1129,7 @@ enum { SHRPX_OPTID_USER, SHRPX_OPTID_VERIFY_CLIENT, SHRPX_OPTID_VERIFY_CLIENT_CACERT, + SHRPX_OPTID_VERIFY_CLIENT_TOLERATE_EXPIRED, SHRPX_OPTID_WORKER_FRONTEND_CONNECTIONS, SHRPX_OPTID_WORKER_READ_BURST, SHRPX_OPTID_WORKER_READ_RATE, diff --git a/src/shrpx_tls.cc b/src/shrpx_tls.cc index d0bf6085..32818278 100644 --- a/src/shrpx_tls.cc +++ b/src/shrpx_tls.cc @@ -94,6 +94,12 @@ int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) { if (!preverify_ok) { int err = X509_STORE_CTX_get_error(ctx); int depth = X509_STORE_CTX_get_error_depth(ctx); + if (err == X509_V_ERR_CERT_HAS_EXPIRED && depth == 0 && + get_config()->tls.client_verify.tolerate_expired) { + LOG(INFO) << "The client certificate has expired, but is accepted by " + "configuration"; + return 1; + } LOG(ERROR) << "client certificate verify error:num=" << err << ":" << X509_verify_cert_error_string(err) << ":depth=" << depth; }