in tool/server.cc [233:432]
bool Server(const std::vector<std::string> &args) {
if (!InitSocketLibrary()) {
return false;
}
std::map<std::string, std::string> args_map;
args_list_t extra_args;
if (!ParseKeyValueArguments(args_map, extra_args, args, kArguments) ||
extra_args.size() > 0) {
PrintUsage(kArguments);
return false;
}
bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
const char *keylog_file = getenv("SSLKEYLOGFILE");
if (keylog_file) {
g_keylog_file = fopen(keylog_file, "a");
if (g_keylog_file == nullptr) {
perror("fopen");
return false;
}
SSL_CTX_set_keylog_callback(ctx.get(), KeyLogCallback);
}
// Server authentication is required.
if (args_map.count("-key") != 0) {
std::string key = args_map["-key"];
if (!SSL_CTX_use_PrivateKey_file(ctx.get(), key.c_str(),
SSL_FILETYPE_PEM)) {
fprintf(stderr, "Failed to load private key: %s\n", key.c_str());
return false;
}
const std::string &cert =
args_map.count("-cert") != 0 ? args_map["-cert"] : key;
if (!SSL_CTX_use_certificate_chain_file(ctx.get(), cert.c_str())) {
fprintf(stderr, "Failed to load cert chain: %s\n", cert.c_str());
return false;
}
} else {
bssl::UniquePtr<EVP_PKEY> evp_pkey = MakeKeyPairForSelfSignedCert();
if (!evp_pkey) {
return false;
}
bssl::UniquePtr<X509> cert =
MakeSelfSignedCert(evp_pkey.get(), 365 /* valid_days */);
if (!cert) {
return false;
}
if (!SSL_CTX_use_PrivateKey(ctx.get(), evp_pkey.get())) {
fprintf(stderr, "Failed to set private key.\n");
return false;
}
if (!SSL_CTX_use_certificate(ctx.get(), cert.get())) {
fprintf(stderr, "Failed to set certificate.\n");
return false;
}
}
if (args_map.count("-ech-key") + args_map.count("-ech-config") == 1) {
fprintf(stderr,
"-ech-config and -ech-key must be specified together.\n");
return false;
}
if (args_map.count("-ech-key") != 0) {
// Load the ECH private key.
std::string ech_key_path = args_map["-ech-key"];
ScopedFILE ech_key_file(fopen(ech_key_path.c_str(), "rb"));
std::vector<uint8_t> ech_key;
if (ech_key_file == nullptr ||
!ReadAll(&ech_key, ech_key_file.get())) {
fprintf(stderr, "Error reading %s\n", ech_key_path.c_str());
return false;
}
// Load the ECHConfig.
std::string ech_config_path = args_map["-ech-config"];
ScopedFILE ech_config_file(fopen(ech_config_path.c_str(), "rb"));
std::vector<uint8_t> ech_config;
if (ech_config_file == nullptr ||
!ReadAll(&ech_config, ech_config_file.get())) {
fprintf(stderr, "Error reading %s\n", ech_config_path.c_str());
return false;
}
bssl::UniquePtr<SSL_ECH_KEYS> keys(SSL_ECH_KEYS_new());
bssl::ScopedEVP_HPKE_KEY key;
if (!keys ||
!EVP_HPKE_KEY_init(key.get(), EVP_hpke_x25519_hkdf_sha256(),
ech_key.data(), ech_key.size()) ||
!SSL_ECH_KEYS_add(keys.get(),
/*is_retry_config=*/1, ech_config.data(),
ech_config.size(), key.get()) ||
!SSL_CTX_set1_ech_keys(ctx.get(), keys.get())) {
fprintf(stderr, "Error setting server's ECHConfig and private key\n");
return false;
}
}
if (args_map.count("-cipher") != 0 &&
!SSL_CTX_set_strict_cipher_list(ctx.get(), args_map["-cipher"].c_str())) {
fprintf(stderr, "Failed setting cipher list\n");
return false;
}
if (args_map.count("-curves") != 0 &&
!SSL_CTX_set1_curves_list(ctx.get(), args_map["-curves"].c_str())) {
fprintf(stderr, "Failed setting curves list\n");
return false;
}
uint16_t max_version = TLS1_3_VERSION;
if (args_map.count("-max-version") != 0 &&
!VersionFromString(&max_version, args_map["-max-version"])) {
fprintf(stderr, "Unknown protocol version: '%s'\n",
args_map["-max-version"].c_str());
return false;
}
if (!SSL_CTX_set_max_proto_version(ctx.get(), max_version)) {
return false;
}
if (args_map.count("-min-version") != 0) {
uint16_t version;
if (!VersionFromString(&version, args_map["-min-version"])) {
fprintf(stderr, "Unknown protocol version: '%s'\n",
args_map["-min-version"].c_str());
return false;
}
if (!SSL_CTX_set_min_proto_version(ctx.get(), version)) {
return false;
}
}
if (args_map.count("-ocsp-response") != 0 &&
!LoadOCSPResponse(ctx.get(), args_map["-ocsp-response"].c_str())) {
fprintf(stderr, "Failed to load OCSP response: %s\n", args_map["-ocsp-response"].c_str());
return false;
}
if (args_map.count("-early-data") != 0) {
SSL_CTX_set_early_data_enabled(ctx.get(), 1);
}
if (args_map.count("-debug") != 0) {
SSL_CTX_set_info_callback(ctx.get(), InfoCallback);
}
if (args_map.count("-require-any-client-cert") != 0) {
SSL_CTX_set_verify(
ctx.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
SSL_CTX_set_cert_verify_callback(
ctx.get(), [](X509_STORE_CTX *store, void *arg) -> int { return 1; },
nullptr);
}
Listener listener;
if (!listener.Init(args_map["-accept"])) {
return false;
}
bool result = true;
do {
int sock = -1;
if (!listener.Accept(&sock)) {
return false;
}
BIO *bio = BIO_new_socket(sock, BIO_CLOSE);
bssl::UniquePtr<SSL> ssl(SSL_new(ctx.get()));
SSL_set_bio(ssl.get(), bio, bio);
if (args_map.count("-jdk11-workaround") != 0) {
SSL_set_jdk11_workaround(ssl.get(), 1);
}
int ret = SSL_accept(ssl.get());
if (ret != 1) {
int ssl_err = SSL_get_error(ssl.get(), ret);
PrintSSLError(stderr, "Error while connecting", ssl_err, ret);
result = false;
continue;
}
fprintf(stderr, "Connected.\n");
bssl::UniquePtr<BIO> bio_stderr(BIO_new_fp(stderr, BIO_NOCLOSE));
PrintConnectionInfo(bio_stderr.get(), ssl.get());
if (args_map.count("-www") != 0) {
result = HandleWWW(ssl.get());
} else {
result = TransferData(ssl.get(), sock);
}
} while (args_map.count("-loop") != 0);
return result;
}