diff --git a/examples/SpdyServer.cc b/examples/SpdyServer.cc index 269e64c..846ed86 100644 --- a/examples/SpdyServer.cc +++ b/examples/SpdyServer.cc @@ -57,7 +57,7 @@ const std::string SPDYD_SERVER = "spdyd spdylay/"SPDYLAY_VERSION; } // namespace Config::Config(): verbose(false), daemon(false), port(0), data_ptr(0), - spdy3_only(false) + spdy3_only(false), verify_client(false) {} Request::Request(int32_t stream_id) @@ -874,6 +874,15 @@ int next_proto_cb(SSL *s, const unsigned char **data, unsigned int *len, } } // namespace +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; +} +} // namespace + int SpdyServer::run() { SSL_CTX *ssl_ctx; @@ -900,7 +909,12 @@ int SpdyServer::run() std::cerr << "SSL_CTX_check_private_key failed." << std::endl; return -1; } - + if(config_->verify_client) { + SSL_CTX_set_verify(ssl_ctx, + SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE | + SSL_VERIFY_FAIL_IF_NO_PEER_CERT, + verify_callback); + } // We speaks "spdy/2" and "spdy/3". std::pair next_proto; unsigned char proto_list[14]; diff --git a/examples/SpdyServer.h b/examples/SpdyServer.h index 4aefde4..aaf262d 100644 --- a/examples/SpdyServer.h +++ b/examples/SpdyServer.h @@ -51,6 +51,7 @@ struct Config { spdylay_on_request_recv_callback on_request_recv_callback; void *data_ptr; bool spdy3_only; + bool verify_client; Config(); }; diff --git a/examples/spdycat.cc b/examples/spdycat.cc index 7319c73..7e1e446 100644 --- a/examples/spdycat.cc +++ b/examples/spdycat.cc @@ -63,6 +63,8 @@ struct Config { bool verbose; bool spdy3_only; int timeout; + std::string certfile; + std::string keyfile; Config():null_out(false), remote_name(false), verbose(false), spdy3_only(false), timeout(-1) {} }; @@ -152,6 +154,20 @@ int communicate(const std::string& host, uint16_t port, next_proto = "spdy/3"; } setup_ssl_ctx(ssl_ctx, &next_proto); + if(!config.keyfile.empty()) { + if(SSL_CTX_use_PrivateKey_file(ssl_ctx, config.keyfile.c_str(), + SSL_FILETYPE_PEM) != 1) { + std::cerr << ERR_error_string(ERR_get_error(), 0) << std::endl; + return -1; + } + } + if(!config.certfile.empty()) { + if(SSL_CTX_use_certificate_chain_file(ssl_ctx, + config.certfile.c_str()) != 1) { + std::cerr << ERR_error_string(ERR_get_error(), 0) << std::endl; + return -1; + } + } SSL *ssl = SSL_new(ssl_ctx); if(!ssl) { std::cerr << ERR_error_string(ERR_get_error(), 0) << std::endl; @@ -282,7 +298,7 @@ int run(char **uris, int n) void print_usage(std::ostream& out) { - out << "Usage: spdycat [-Onv3] [--timeout=seconds] [URI...]" << std::endl; + out << "Usage: spdycat [-Onv3] [-t=seconds] [--cert=CERT] [--key=KEY] [URI...]" << std::endl; } void print_help(std::ostream& out) @@ -299,19 +315,25 @@ void print_help(std::ostream& out) << " filename. Not implemented yet.\n" << " -3, --spdy3 Only use SPDY/3.\n" << " -t, --timeout=N Timeout each request after N seconds.\n" - << "\n" + << " --cert=CERT Use the specified client certificate file.\n" + << " The file must be in PEM format.\n" + << " --key=KEY Use the client private key file. The file\n" + << " must be in PEM format.\n" << std::endl; } int main(int argc, char **argv) { while(1) { + int flag; static option long_options[] = { {"verbose", no_argument, 0, 'v' }, {"null-out", no_argument, 0, 'n' }, {"remote-name", no_argument, 0, 'O' }, {"spdy3", no_argument, 0, '3' }, {"timeout", required_argument, 0, 't' }, + {"cert", required_argument, &flag, 1 }, + {"key", required_argument, &flag, 2 }, {"help", no_argument, 0, 'h' }, {0, 0, 0, 0 } }; @@ -341,6 +363,18 @@ int main(int argc, char **argv) break; case '?': exit(EXIT_FAILURE); + case 0: + switch(flag) { + case 1: + // cert option + config.certfile = optarg; + break; + case 2: + // key option + config.keyfile = optarg; + break; + } + break; default: break; } diff --git a/examples/spdyd.cc b/examples/spdyd.cc index f66a4a3..7f23506 100644 --- a/examples/spdyd.cc +++ b/examples/spdyd.cc @@ -61,6 +61,12 @@ void print_help(std::ostream& out) << " current working directory is changed to '/'.\n" << " Therefore if this option is used, -d option\n" << " must be specified.\n" + << " -V, --verify-client\n" + << " The server sends a client certificate\n" + << " request. If the client did not return a\n" + << " certificate, the handshake is terminated.\n" + << " Currently, this option just requests a\n" + << " client certificate and does not verify it.\n" << "\n" << " -d, --htdocs=PATH Specify document root. If this option is not\n" << " specified, the document root is the current\n" @@ -86,10 +92,11 @@ int main(int argc, char **argv) {"help", no_argument, 0, 'h' }, {"verbose", no_argument, 0, 'v' }, {"spdy3", no_argument, 0, '3' }, + {"verify-client", no_argument, 0, 'V' }, {0, 0, 0, 0 } }; int option_index = 0; - int c = getopt_long(argc, argv, "Dd:hv3", long_options, &option_index); + int c = getopt_long(argc, argv, "DVd:hv3", long_options, &option_index); if(c == -1) { break; } @@ -97,6 +104,9 @@ int main(int argc, char **argv) case 'D': config.daemon = true; break; + case 'V': + config.verify_client = true; + break; case 'd': config.htdocs = optarg; break;