nghttpx: Add --verify-client option
This option requires client certificate and successful verification. Use --cacert option to add CA certificates as necessary.
This commit is contained in:
parent
1835bda02e
commit
02acfd7d70
21
src/shrpx.cc
21
src/shrpx.cc
|
@ -417,6 +417,7 @@ void fill_default_config()
|
|||
mod_config()->write_rate = 0;
|
||||
mod_config()->write_burst = 0;
|
||||
mod_config()->npn_list = nullptr;
|
||||
mod_config()->verify_client = false;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
@ -593,6 +594,7 @@ void print_help(std::ostream& out)
|
|||
<< " comma only and any white spaces are treated\n"
|
||||
<< " as a part of protocol string.\n"
|
||||
<< " Default: " << DEFAULT_NPN_LIST << "\n"
|
||||
<< " --verify-client Require and verify client certificate.\n"
|
||||
<< "\n"
|
||||
<< " HTTP/2.0 and SPDY:\n"
|
||||
<< " -c, --spdy-max-concurrent-streams=<NUM>\n"
|
||||
|
@ -730,6 +732,7 @@ int main(int argc, char **argv)
|
|||
{"write-rate", required_argument, &flag, 36},
|
||||
{"write-burst", required_argument, &flag, 37},
|
||||
{"npn-list", required_argument, &flag, 38},
|
||||
{"verify-client", no_argument, &flag, 39},
|
||||
{nullptr, 0, nullptr, 0 }
|
||||
};
|
||||
int option_index = 0;
|
||||
|
@ -933,6 +936,10 @@ int main(int argc, char **argv)
|
|||
// --npn-list
|
||||
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_NPN_LIST, optarg));
|
||||
break;
|
||||
case 39:
|
||||
// --verify-client
|
||||
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_VERIFY_CLIENT, "yes"));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -975,6 +982,20 @@ int main(int argc, char **argv)
|
|||
parse_config_npn_list(DEFAULT_NPN_LIST);
|
||||
}
|
||||
|
||||
if(!get_config()->subcerts.empty()) {
|
||||
mod_config()->cert_tree = ssl::cert_lookup_tree_new();
|
||||
}
|
||||
|
||||
for(auto& keycert : get_config()->subcerts) {
|
||||
auto ssl_ctx = ssl::create_ssl_context(keycert.first.c_str(),
|
||||
keycert.second.c_str());
|
||||
if(ssl::cert_lookup_tree_add_cert_from_file
|
||||
(get_config()->cert_tree, ssl_ctx, keycert.second.c_str()) == -1) {
|
||||
LOG(FATAL) << "Failed to add sub certificate.";
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if(get_config()->cert_file && get_config()->private_key_file) {
|
||||
mod_config()->default_ssl_ctx =
|
||||
ssl::create_ssl_context(get_config()->private_key_file,
|
||||
|
|
|
@ -100,6 +100,7 @@ const char SHRPX_OPT_READ_BURST[] = "read-burst";
|
|||
const char SHRPX_OPT_WRITE_RATE[] = "write-rate";
|
||||
const char SHRPX_OPT_WRITE_BURST[] = "write-burst";
|
||||
const char SHRPX_OPT_NPN_LIST[] = "npn-list";
|
||||
const char SHRPX_OPT_VERIFY_CLIENT[] = "verify-client";
|
||||
|
||||
namespace {
|
||||
Config *config = nullptr;
|
||||
|
@ -335,14 +336,7 @@ int parse_config(const char *opt, const char *optarg)
|
|||
if(sp) {
|
||||
std::string keyfile(optarg, sp);
|
||||
// TODO Do we need private key for subcert?
|
||||
auto ssl_ctx = ssl::create_ssl_context(keyfile.c_str(), sp+1);
|
||||
if(!get_config()->cert_tree) {
|
||||
mod_config()->cert_tree = ssl::cert_lookup_tree_new();
|
||||
}
|
||||
if(ssl::cert_lookup_tree_add_cert_from_file(get_config()->cert_tree,
|
||||
ssl_ctx, sp+1) == -1) {
|
||||
return -1;
|
||||
}
|
||||
mod_config()->subcerts.emplace_back(keyfile, sp+1);
|
||||
}
|
||||
} else if(util::strieq(opt, SHRPX_OPT_SYSLOG)) {
|
||||
mod_config()->syslog = util::strieq(optarg, "yes");
|
||||
|
@ -413,6 +407,8 @@ int parse_config(const char *opt, const char *optarg)
|
|||
mod_config()->write_burst = strtoul(optarg, nullptr, 10);
|
||||
} else if(util::strieq(opt, SHRPX_OPT_NPN_LIST)) {
|
||||
parse_config_npn_list(optarg);
|
||||
} else if(util::strieq(opt, SHRPX_OPT_VERIFY_CLIENT)) {
|
||||
mod_config()->verify_client = util::strieq(optarg, "yes");
|
||||
} else if(util::strieq(opt, "conf")) {
|
||||
LOG(WARNING) << "conf is ignored";
|
||||
} else {
|
||||
|
|
|
@ -91,6 +91,7 @@ extern const char SHRPX_OPT_READ_BURST[];
|
|||
extern const char SHRPX_OPT_WRITE_RATE[];
|
||||
extern const char SHRPX_OPT_WRITE_BURST[];
|
||||
extern const char SHRPX_OPT_NPN_LIST[];
|
||||
extern const char SHRPX_OPT_VERIFY_CLIENT[];
|
||||
|
||||
union sockaddr_union {
|
||||
sockaddr sa;
|
||||
|
@ -184,6 +185,8 @@ struct Config {
|
|||
char **npn_list;
|
||||
// The number of elements in npn_list
|
||||
size_t npn_list_len;
|
||||
// The list of (private key file, certificate file) pair
|
||||
std::vector<std::pair<std::string, std::string>> subcerts;
|
||||
};
|
||||
|
||||
const Config* get_config();
|
||||
|
|
|
@ -73,9 +73,14 @@ int next_proto_cb(SSL *s, const unsigned char **data, unsigned int *len,
|
|||
namespace {
|
||||
int verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
|
||||
{
|
||||
// We don't verify the client certificate. Just request it for the
|
||||
// testing purpose.
|
||||
return 1;
|
||||
if(!preverify_ok) {
|
||||
int err = X509_STORE_CTX_get_error(ctx);
|
||||
int depth = X509_STORE_CTX_get_error_depth(ctx);
|
||||
LOG(ERROR) << "client certificate verify error:num=" << err << ":"
|
||||
<< X509_verify_cert_error_string(err)
|
||||
<< ":depth=" << depth;
|
||||
}
|
||||
return preverify_ok;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
@ -213,6 +218,19 @@ SSL_CTX* create_ssl_context(const char *private_key_file,
|
|||
DIE();
|
||||
}
|
||||
if(get_config()->verify_client) {
|
||||
if(SSL_CTX_set_default_verify_paths(ssl_ctx) != 1) {
|
||||
LOG(WARNING) << "Could not load system trusted ca certificates: "
|
||||
<< ERR_error_string(ERR_get_error(), nullptr);
|
||||
}
|
||||
if(get_config()->cacert) {
|
||||
if(SSL_CTX_load_verify_locations(ssl_ctx, get_config()->cacert, nullptr)
|
||||
!= 1) {
|
||||
LOG(FATAL) << "Could not load trusted ca certificates from "
|
||||
<< get_config()->cacert << ": "
|
||||
<< ERR_error_string(ERR_get_error(), nullptr);
|
||||
DIE();
|
||||
}
|
||||
}
|
||||
SSL_CTX_set_verify(ssl_ctx,
|
||||
SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE |
|
||||
SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
|
||||
|
|
Loading…
Reference in New Issue