blob: a5254b2186287e024243ea64055b423f7d961751 [file] [log] [blame]
Adam Langleyaacec172014-06-20 12:00:00 -07001/* Copyright (c) 2014, Google Inc.
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14
15#include <openssl/base.h>
16
David Benjamind28f59c2015-11-17 22:32:50 -050017#include <stdio.h>
18
Steven Valdez87c0bb22016-12-07 10:31:16 -050019#if !defined(OPENSSL_WINDOWS)
20#include <sys/select.h>
21#else
David Benjamin7c7ab212017-01-10 15:20:19 -050022OPENSSL_MSVC_PRAGMA(warning(push, 3))
Steven Valdez87c0bb22016-12-07 10:31:16 -050023#include <winsock2.h>
David Benjamin7c7ab212017-01-10 15:20:19 -050024OPENSSL_MSVC_PRAGMA(warning(pop))
Steven Valdez87c0bb22016-12-07 10:31:16 -050025#endif
26
Adam Langleyaacec172014-06-20 12:00:00 -070027#include <openssl/err.h>
David Benjamin05709232015-03-23 19:01:33 -040028#include <openssl/pem.h>
Adam Langleyaacec172014-06-20 12:00:00 -070029#include <openssl/ssl.h>
30
David Benjamin17cf2cb2016-12-13 01:07:13 -050031#include "../crypto/internal.h"
Adam Langleyaacec172014-06-20 12:00:00 -070032#include "internal.h"
Dave Tapuskab8a824d2014-12-10 19:09:52 -050033#include "transport_common.h"
Adam Langleyaacec172014-06-20 12:00:00 -070034
35
36static const struct argument kArguments[] = {
37 {
David Benjamin712f3722017-04-05 14:52:09 -040038 "-connect", kRequiredArgument,
39 "The hostname and port of the server to connect to, e.g. foo.com:443",
Adam Langleyaacec172014-06-20 12:00:00 -070040 },
41 {
David Benjamin712f3722017-04-05 14:52:09 -040042 "-cipher", kOptionalArgument,
43 "An OpenSSL-style cipher suite string that configures the offered "
44 "ciphers",
Adam Langley5f51c252014-10-28 15:45:39 -070045 },
46 {
Piotr Sikorad0757062017-04-14 02:59:34 -070047 "-curves", kOptionalArgument,
48 "An OpenSSL-style ECDH curves list that configures the offered curves",
49 },
50 {
David Benjamin712f3722017-04-05 14:52:09 -040051 "-max-version", kOptionalArgument,
52 "The maximum acceptable protocol version",
David Benjamin05709232015-03-23 19:01:33 -040053 },
54 {
David Benjamin712f3722017-04-05 14:52:09 -040055 "-min-version", kOptionalArgument,
56 "The minimum acceptable protocol version",
David Benjamin05709232015-03-23 19:01:33 -040057 },
58 {
David Benjamin712f3722017-04-05 14:52:09 -040059 "-server-name", kOptionalArgument, "The server name to advertise",
David Benjamin05709232015-03-23 19:01:33 -040060 },
61 {
David Benjamin712f3722017-04-05 14:52:09 -040062 "-select-next-proto", kOptionalArgument,
63 "An NPN protocol to select if the server supports NPN",
David Benjamin05709232015-03-23 19:01:33 -040064 },
65 {
David Benjamin712f3722017-04-05 14:52:09 -040066 "-alpn-protos", kOptionalArgument,
67 "A comma-separated list of ALPN protocols to advertise",
David Benjamin05709232015-03-23 19:01:33 -040068 },
69 {
David Benjamin712f3722017-04-05 14:52:09 -040070 "-fallback-scsv", kBooleanArgument, "Enable FALLBACK_SCSV",
David Benjamin05709232015-03-23 19:01:33 -040071 },
72 {
David Benjamin712f3722017-04-05 14:52:09 -040073 "-ocsp-stapling", kBooleanArgument,
74 "Advertise support for OCSP stabling",
David Benjamin05709232015-03-23 19:01:33 -040075 },
76 {
David Benjamin712f3722017-04-05 14:52:09 -040077 "-signed-certificate-timestamps", kBooleanArgument,
78 "Advertise support for signed certificate timestamps",
David Benjamin05709232015-03-23 19:01:33 -040079 },
80 {
David Benjamin712f3722017-04-05 14:52:09 -040081 "-channel-id-key", kOptionalArgument,
82 "The key to use for signing a channel ID",
David Benjamin05709232015-03-23 19:01:33 -040083 },
84 {
David Benjamin712f3722017-04-05 14:52:09 -040085 "-false-start", kBooleanArgument, "Enable False Start",
David Benjamin621f95a2015-08-28 15:08:34 -040086 },
David Benjamin1043ac02015-06-04 15:26:04 -040087 {
David Benjamin712f3722017-04-05 14:52:09 -040088 "-session-in", kOptionalArgument,
89 "A file containing a session to resume.",
David Benjamin86e412d2015-12-02 19:34:58 -050090 },
91 {
David Benjamin712f3722017-04-05 14:52:09 -040092 "-session-out", kOptionalArgument,
93 "A file to write the negotiated session to.",
Adam Langley403c52a2016-07-07 14:52:02 -070094 },
95 {
David Benjamin712f3722017-04-05 14:52:09 -040096 "-key", kOptionalArgument,
David Benjamincb3af3e2017-04-09 09:52:47 -040097 "PEM-encoded file containing the private key.",
98 },
99 {
100 "-cert", kOptionalArgument,
101 "PEM-encoded file containing the leaf certificate and optional "
102 "certificate chain. This is taken from the -key argument if this "
103 "argument is not provided.",
David Benjamin65ac9972016-09-02 21:35:25 -0400104 },
105 {
David Benjamin712f3722017-04-05 14:52:09 -0400106 "-starttls", kOptionalArgument,
107 "A STARTTLS mini-protocol to run before the TLS handshake. Supported"
108 " values: 'smtp'",
Steven Valdez87c0bb22016-12-07 10:31:16 -0500109 },
110 {
David Benjamin712f3722017-04-05 14:52:09 -0400111 "-grease", kBooleanArgument, "Enable GREASE",
112 },
113 {
114 "-test-resumption", kBooleanArgument,
115 "Connect to the server twice. The first connection is closed once a "
116 "session is established. The second connection offers it.",
117 },
118 {
119 "-root-certs", kOptionalArgument,
120 "A filename containing one of more PEM root certificates. Implies that "
121 "verification is required.",
Adam Langleye5dfb522017-02-03 10:31:00 -0800122 },
123 {
Steven Valdeze831a812017-03-09 14:56:07 -0500124 "-early-data", kOptionalArgument, "Allow early data",
Steven Valdez2d850622017-01-11 11:34:52 -0500125 },
126 {
Steven Valdezdbe01582017-07-14 10:39:28 -0400127 "-tls13-variant", kOptionalArgument,
128 "Enable the specified experimental TLS 1.3 variant",
Steven Valdez520e1222017-06-13 12:45:25 -0400129 },
130 {
David Benjamin69522112017-03-28 15:38:29 -0500131 "-ed25519", kBooleanArgument, "Advertise Ed25519 support",
132 },
133 {
David Benjaminee7aa022017-07-07 16:47:59 -0400134 "-http-tunnel", kOptionalArgument,
135 "An HTTP proxy server to tunnel the TCP connection through",
136 },
137 {
David Benjamin6df76672017-08-16 13:02:24 -0400138 "-renegotiate-freely", kBooleanArgument,
139 "Allow renegotiations from the peer.",
140 },
141 {
David Benjaminf60bcfb2017-08-18 15:23:44 -0400142 "-debug", kBooleanArgument,
143 "Print debug information about the handshake",
144 },
145 {
David Benjamin712f3722017-04-05 14:52:09 -0400146 "", kOptionalArgument, "",
Adam Langleyaacec172014-06-20 12:00:00 -0700147 },
148};
149
Matt Braithwaited17d74d2016-08-17 20:10:28 -0700150static bssl::UniquePtr<EVP_PKEY> LoadPrivateKey(const std::string &file) {
151 bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_file()));
David Benjamin05709232015-03-23 19:01:33 -0400152 if (!bio || !BIO_read_filename(bio.get(), file.c_str())) {
153 return nullptr;
154 }
Matt Braithwaited17d74d2016-08-17 20:10:28 -0700155 bssl::UniquePtr<EVP_PKEY> pkey(PEM_read_bio_PrivateKey(bio.get(), nullptr,
156 nullptr, nullptr));
David Benjamin05709232015-03-23 19:01:33 -0400157 return pkey;
158}
159
David Benjamin05709232015-03-23 19:01:33 -0400160static int NextProtoSelectCallback(SSL* ssl, uint8_t** out, uint8_t* outlen,
161 const uint8_t* in, unsigned inlen, void* arg) {
162 *out = reinterpret_cast<uint8_t *>(arg);
163 *outlen = strlen(reinterpret_cast<const char *>(arg));
164 return SSL_TLSEXT_ERR_OK;
165}
166
David Benjamind28f59c2015-11-17 22:32:50 -0500167static FILE *g_keylog_file = nullptr;
168
169static void KeyLogCallback(const SSL *ssl, const char *line) {
170 fprintf(g_keylog_file, "%s\n", line);
171 fflush(g_keylog_file);
172}
173
Matt Braithwaited17d74d2016-08-17 20:10:28 -0700174static bssl::UniquePtr<BIO> session_out;
Steven Valdez87c0bb22016-12-07 10:31:16 -0500175static bssl::UniquePtr<SSL_SESSION> resume_session;
Steven Valdez7b689f62016-08-02 15:59:26 -0400176
177static int NewSessionCallback(SSL *ssl, SSL_SESSION *session) {
178 if (session_out) {
179 if (!PEM_write_bio_SSL_SESSION(session_out.get(), session) ||
180 BIO_flush(session_out.get()) <= 0) {
181 fprintf(stderr, "Error while saving session:\n");
182 ERR_print_errors_cb(PrintErrorCallback, stderr);
183 return 0;
184 }
185 }
Steven Valdez87c0bb22016-12-07 10:31:16 -0500186 resume_session = bssl::UniquePtr<SSL_SESSION>(session);
187 return 1;
188}
Steven Valdez7b689f62016-08-02 15:59:26 -0400189
Steven Valdez87c0bb22016-12-07 10:31:16 -0500190static bool WaitForSession(SSL *ssl, int sock) {
191 fd_set read_fds;
192 FD_ZERO(&read_fds);
193
194 if (!SocketSetNonBlocking(sock, true)) {
195 return false;
196 }
197
198 while (!resume_session) {
199 FD_SET(sock, &read_fds);
200 int ret = select(sock + 1, &read_fds, NULL, NULL, NULL);
201 if (ret <= 0) {
202 perror("select");
203 return false;
204 }
205
206 uint8_t buffer[512];
207 int ssl_ret = SSL_read(ssl, buffer, sizeof(buffer));
208
209 if (ssl_ret <= 0) {
210 int ssl_err = SSL_get_error(ssl, ssl_ret);
211 if (ssl_err == SSL_ERROR_WANT_READ) {
212 continue;
213 }
214 fprintf(stderr, "Error while reading: %d\n", ssl_err);
215 ERR_print_errors_cb(PrintErrorCallback, stderr);
216 return false;
217 }
218 }
219
220 return true;
221}
222
223static bool DoConnection(SSL_CTX *ctx,
224 std::map<std::string, std::string> args_map,
225 bool (*cb)(SSL *ssl, int sock)) {
226 int sock = -1;
David Benjaminee7aa022017-07-07 16:47:59 -0400227 if (args_map.count("-http-tunnel") != 0) {
228 if (!Connect(&sock, args_map["-http-tunnel"]) ||
229 !DoHTTPTunnel(sock, args_map["-connect"])) {
230 return false;
231 }
232 } else if (!Connect(&sock, args_map["-connect"])) {
Steven Valdez87c0bb22016-12-07 10:31:16 -0500233 return false;
234 }
235
236 if (args_map.count("-starttls") != 0) {
237 const std::string& starttls = args_map["-starttls"];
238 if (starttls == "smtp") {
239 if (!DoSMTPStartTLS(sock)) {
240 return false;
241 }
242 } else {
243 fprintf(stderr, "Unknown value for -starttls: %s\n", starttls.c_str());
244 return false;
245 }
246 }
247
248 bssl::UniquePtr<BIO> bio(BIO_new_socket(sock, BIO_CLOSE));
249 bssl::UniquePtr<SSL> ssl(SSL_new(ctx));
250
251 if (args_map.count("-server-name") != 0) {
252 SSL_set_tlsext_host_name(ssl.get(), args_map["-server-name"].c_str());
253 }
254
255 if (args_map.count("-session-in") != 0) {
256 bssl::UniquePtr<BIO> in(BIO_new_file(args_map["-session-in"].c_str(),
257 "rb"));
258 if (!in) {
259 fprintf(stderr, "Error reading session\n");
260 ERR_print_errors_cb(PrintErrorCallback, stderr);
261 return false;
262 }
263 bssl::UniquePtr<SSL_SESSION> session(PEM_read_bio_SSL_SESSION(in.get(),
264 nullptr, nullptr, nullptr));
265 if (!session) {
266 fprintf(stderr, "Error reading session\n");
267 ERR_print_errors_cb(PrintErrorCallback, stderr);
268 return false;
269 }
270 SSL_set_session(ssl.get(), session.get());
David Benjamin712f3722017-04-05 14:52:09 -0400271 }
272
David Benjamin6df76672017-08-16 13:02:24 -0400273 if (args_map.count("-renegotiate-freely") != 0) {
274 SSL_set_renegotiate_mode(ssl.get(), ssl_renegotiate_freely);
275 }
276
David Benjamin712f3722017-04-05 14:52:09 -0400277 if (resume_session) {
Steven Valdez87c0bb22016-12-07 10:31:16 -0500278 SSL_set_session(ssl.get(), resume_session.get());
279 }
280
281 SSL_set_bio(ssl.get(), bio.get(), bio.get());
282 bio.release();
283
284 int ret = SSL_connect(ssl.get());
285 if (ret != 1) {
286 int ssl_err = SSL_get_error(ssl.get(), ret);
287 fprintf(stderr, "Error while connecting: %d\n", ssl_err);
288 ERR_print_errors_cb(PrintErrorCallback, stderr);
289 return false;
290 }
291
Steven Valdeze831a812017-03-09 14:56:07 -0500292 if (args_map.count("-early-data") != 0 && SSL_in_early_data(ssl.get())) {
293 int ed_size = args_map["-early-data"].size();
294 int ssl_ret = SSL_write(ssl.get(), args_map["-early-data"].data(), ed_size);
295 if (ssl_ret <= 0) {
296 int ssl_err = SSL_get_error(ssl.get(), ssl_ret);
297 fprintf(stderr, "Error while writing: %d\n", ssl_err);
298 ERR_print_errors_cb(PrintErrorCallback, stderr);
299 return false;
300 } else if (ssl_ret != ed_size) {
301 fprintf(stderr, "Short write from SSL_write.\n");
302 return false;
303 }
304 }
305
Steven Valdez87c0bb22016-12-07 10:31:16 -0500306 fprintf(stderr, "Connected.\n");
307 PrintConnectionInfo(ssl.get());
308
309 return cb(ssl.get(), sock);
Steven Valdez7b689f62016-08-02 15:59:26 -0400310}
311
David Benjamin590b6772017-08-08 20:09:17 -0400312static bool GetTLS13Variant(tls13_variant_t *out, const std::string &in) {
313 if (in == "draft") {
314 *out = tls13_default;
315 return true;
316 }
317 if (in == "experiment") {
318 *out = tls13_experiment;
319 return true;
320 }
321 if (in == "record-type") {
322 *out = tls13_record_type_experiment;
323 return true;
324 }
325 if (in == "no-session-id") {
326 *out = tls13_no_session_id_experiment;
327 return true;
328 }
329 return false;
330}
331
David Benjaminf60bcfb2017-08-18 15:23:44 -0400332static void InfoCallback(const SSL *ssl, int type, int value) {
333 switch (type) {
334 case SSL_CB_HANDSHAKE_START:
335 fprintf(stderr, "Handshake started.\n");
336 break;
337 case SSL_CB_HANDSHAKE_DONE:
338 fprintf(stderr, "Handshake done.\n");
339 break;
340 case SSL_CB_CONNECT_LOOP:
341 fprintf(stderr, "Handshake progress: %s\n", SSL_state_string_long(ssl));
342 break;
343 }
344}
345
Adam Langleyaacec172014-06-20 12:00:00 -0700346bool Client(const std::vector<std::string> &args) {
Brian Smith33970e62015-01-27 22:32:08 -0800347 if (!InitSocketLibrary()) {
348 return false;
349 }
350
Adam Langleyaacec172014-06-20 12:00:00 -0700351 std::map<std::string, std::string> args_map;
352
353 if (!ParseKeyValueArguments(&args_map, args, kArguments)) {
354 PrintUsage(kArguments);
355 return false;
356 }
357
David Benjamin65b87ce2017-08-17 13:11:23 -0400358 bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
Adam Langleyaacec172014-06-20 12:00:00 -0700359
David Benjamin859ec3c2014-09-02 16:29:36 -0400360 const char *keylog_file = getenv("SSLKEYLOGFILE");
361 if (keylog_file) {
David Benjamind28f59c2015-11-17 22:32:50 -0500362 g_keylog_file = fopen(keylog_file, "a");
363 if (g_keylog_file == nullptr) {
364 perror("fopen");
David Benjamin859ec3c2014-09-02 16:29:36 -0400365 return false;
366 }
David Benjamind28f59c2015-11-17 22:32:50 -0500367 SSL_CTX_set_keylog_callback(ctx.get(), KeyLogCallback);
David Benjamin859ec3c2014-09-02 16:29:36 -0400368 }
369
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500370 if (args_map.count("-cipher") != 0 &&
Matthew Braithwaitea57dcfb2017-02-17 22:08:23 -0800371 !SSL_CTX_set_strict_cipher_list(ctx.get(), args_map["-cipher"].c_str())) {
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500372 fprintf(stderr, "Failed setting cipher list\n");
373 return false;
Adam Langley5f51c252014-10-28 15:45:39 -0700374 }
375
Piotr Sikorad0757062017-04-14 02:59:34 -0700376 if (args_map.count("-curves") != 0 &&
377 !SSL_CTX_set1_curves_list(ctx.get(), args_map["-curves"].c_str())) {
378 fprintf(stderr, "Failed setting curves list\n");
379 return false;
380 }
381
Adam Langley040bc492017-02-09 15:30:52 -0800382 uint16_t max_version = TLS1_3_VERSION;
383 if (args_map.count("-max-version") != 0 &&
384 !VersionFromString(&max_version, args_map["-max-version"])) {
385 fprintf(stderr, "Unknown protocol version: '%s'\n",
386 args_map["-max-version"].c_str());
387 return false;
388 }
389
390 if (!SSL_CTX_set_max_proto_version(ctx.get(), max_version)) {
391 return false;
David Benjamin05709232015-03-23 19:01:33 -0400392 }
393
394 if (args_map.count("-min-version") != 0) {
395 uint16_t version;
396 if (!VersionFromString(&version, args_map["-min-version"])) {
397 fprintf(stderr, "Unknown protocol version: '%s'\n",
398 args_map["-min-version"].c_str());
399 return false;
400 }
David Benjamine4706902016-09-20 15:12:23 -0400401 if (!SSL_CTX_set_min_proto_version(ctx.get(), version)) {
David Benjamin2dc02042016-09-19 19:57:37 -0400402 return false;
403 }
David Benjamin05709232015-03-23 19:01:33 -0400404 }
405
406 if (args_map.count("-select-next-proto") != 0) {
407 const std::string &proto = args_map["-select-next-proto"];
408 if (proto.size() > 255) {
409 fprintf(stderr, "Bad NPN protocol: '%s'\n", proto.c_str());
410 return false;
411 }
412 // |SSL_CTX_set_next_proto_select_cb| is not const-correct.
413 SSL_CTX_set_next_proto_select_cb(ctx.get(), NextProtoSelectCallback,
414 const_cast<char *>(proto.c_str()));
415 }
416
417 if (args_map.count("-alpn-protos") != 0) {
418 const std::string &alpn_protos = args_map["-alpn-protos"];
419 std::vector<uint8_t> wire;
420 size_t i = 0;
421 while (i <= alpn_protos.size()) {
422 size_t j = alpn_protos.find(',', i);
423 if (j == std::string::npos) {
424 j = alpn_protos.size();
425 }
426 size_t len = j - i;
427 if (len > 255) {
428 fprintf(stderr, "Invalid ALPN protocols: '%s'\n", alpn_protos.c_str());
429 return false;
430 }
431 wire.push_back(static_cast<uint8_t>(len));
432 wire.resize(wire.size() + len);
David Benjamin17cf2cb2016-12-13 01:07:13 -0500433 OPENSSL_memcpy(wire.data() + wire.size() - len, alpn_protos.data() + i,
434 len);
David Benjamin05709232015-03-23 19:01:33 -0400435 i = j + 1;
436 }
437 if (SSL_CTX_set_alpn_protos(ctx.get(), wire.data(), wire.size()) != 0) {
438 return false;
439 }
440 }
441
442 if (args_map.count("-fallback-scsv") != 0) {
443 SSL_CTX_set_mode(ctx.get(), SSL_MODE_SEND_FALLBACK_SCSV);
444 }
445
446 if (args_map.count("-ocsp-stapling") != 0) {
447 SSL_CTX_enable_ocsp_stapling(ctx.get());
448 }
449
450 if (args_map.count("-signed-certificate-timestamps") != 0) {
451 SSL_CTX_enable_signed_cert_timestamps(ctx.get());
452 }
453
454 if (args_map.count("-channel-id-key") != 0) {
Matt Braithwaited17d74d2016-08-17 20:10:28 -0700455 bssl::UniquePtr<EVP_PKEY> pkey =
456 LoadPrivateKey(args_map["-channel-id-key"]);
David Benjamin05709232015-03-23 19:01:33 -0400457 if (!pkey || !SSL_CTX_set1_tls_channel_id(ctx.get(), pkey.get())) {
458 return false;
459 }
David Benjamin05709232015-03-23 19:01:33 -0400460 }
461
David Benjamin1043ac02015-06-04 15:26:04 -0400462 if (args_map.count("-false-start") != 0) {
463 SSL_CTX_set_mode(ctx.get(), SSL_MODE_ENABLE_FALSE_START);
464 }
465
David Benjamin86e412d2015-12-02 19:34:58 -0500466 if (args_map.count("-key") != 0) {
467 const std::string &key = args_map["-key"];
David Benjamincb3af3e2017-04-09 09:52:47 -0400468 if (!SSL_CTX_use_PrivateKey_file(ctx.get(), key.c_str(),
469 SSL_FILETYPE_PEM)) {
David Benjamin86e412d2015-12-02 19:34:58 -0500470 fprintf(stderr, "Failed to load private key: %s\n", key.c_str());
471 return false;
472 }
David Benjamincb3af3e2017-04-09 09:52:47 -0400473 const std::string &cert =
474 args_map.count("-cert") != 0 ? args_map["-cert"] : key;
475 if (!SSL_CTX_use_certificate_chain_file(ctx.get(), cert.c_str())) {
476 fprintf(stderr, "Failed to load cert chain: %s\n", cert.c_str());
David Benjamin86e412d2015-12-02 19:34:58 -0500477 return false;
478 }
479 }
480
Steven Valdez87c0bb22016-12-07 10:31:16 -0500481 SSL_CTX_set_session_cache_mode(ctx.get(), SSL_SESS_CACHE_CLIENT);
482 SSL_CTX_sess_set_new_cb(ctx.get(), NewSessionCallback);
483
Steven Valdez7b689f62016-08-02 15:59:26 -0400484 if (args_map.count("-session-out") != 0) {
485 session_out.reset(BIO_new_file(args_map["-session-out"].c_str(), "wb"));
486 if (!session_out) {
David Benjamin70728842016-09-06 18:18:52 -0400487 fprintf(stderr, "Error while opening %s:\n",
488 args_map["-session-out"].c_str());
Steven Valdez7b689f62016-08-02 15:59:26 -0400489 ERR_print_errors_cb(PrintErrorCallback, stderr);
490 return false;
491 }
Steven Valdez7b689f62016-08-02 15:59:26 -0400492 }
493
David Benjamin65ac9972016-09-02 21:35:25 -0400494 if (args_map.count("-grease") != 0) {
495 SSL_CTX_set_grease_enabled(ctx.get(), 1);
496 }
497
Adam Langleye5dfb522017-02-03 10:31:00 -0800498 if (args_map.count("-root-certs") != 0) {
499 if (!SSL_CTX_load_verify_locations(
500 ctx.get(), args_map["-root-certs"].c_str(), nullptr)) {
501 fprintf(stderr, "Failed to load root certificates.\n");
502 ERR_print_errors_cb(PrintErrorCallback, stderr);
503 return false;
504 }
505 SSL_CTX_set_verify(ctx.get(), SSL_VERIFY_PEER, nullptr);
506 }
507
Steven Valdez2d850622017-01-11 11:34:52 -0500508 if (args_map.count("-early-data") != 0) {
509 SSL_CTX_set_early_data_enabled(ctx.get(), 1);
510 }
511
Steven Valdez520e1222017-06-13 12:45:25 -0400512 if (args_map.count("-tls13-variant") != 0) {
David Benjamin590b6772017-08-08 20:09:17 -0400513 tls13_variant_t variant;
514 if (!GetTLS13Variant(&variant, args_map["-tls13-variant"])) {
515 fprintf(stderr, "Unknown TLS 1.3 variant: %s\n",
516 args_map["-tls13-variant"].c_str());
517 return false;
518 }
519 SSL_CTX_set_tls13_variant(ctx.get(), variant);
Steven Valdez520e1222017-06-13 12:45:25 -0400520 }
521
David Benjamin69522112017-03-28 15:38:29 -0500522 if (args_map.count("-ed25519") != 0) {
523 SSL_CTX_set_ed25519_enabled(ctx.get(), 1);
524 }
525
David Benjaminf60bcfb2017-08-18 15:23:44 -0400526 if (args_map.count("-debug") != 0) {
527 SSL_CTX_set_info_callback(ctx.get(), InfoCallback);
528 }
529
David Benjamin712f3722017-04-05 14:52:09 -0400530 if (args_map.count("-test-resumption") != 0) {
531 if (args_map.count("-session-in") != 0) {
532 fprintf(stderr,
533 "Flags -session-in and -test-resumption are incompatible.\n");
534 return false;
535 }
536
537 if (!DoConnection(ctx.get(), args_map, &WaitForSession)) {
538 return false;
539 }
Adam Langleyaacec172014-06-20 12:00:00 -0700540 }
541
Steven Valdez87c0bb22016-12-07 10:31:16 -0500542 return DoConnection(ctx.get(), args_map, &TransferData);
Adam Langleyaacec172014-06-20 12:00:00 -0700543}