blob: dcb8e0d358a1bdab38f5b4a30e22cd2f6fcd1014 [file] [log] [blame]
Dave Tapuskab8a824d2014-12-10 19:09:52 -05001/* 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
Dave Tapuskab8a824d2014-12-10 19:09:52 -050017#include <string>
18#include <vector>
19
20#include <errno.h>
Adam Langley403c52a2016-07-07 14:52:02 -070021#include <limits.h>
Brian Smith054e6822015-03-27 21:12:01 -100022#include <stddef.h>
David Benjaminf0df86a2015-04-20 11:32:12 -040023#include <stdlib.h>
Adam Langley2b2d66d2015-01-30 17:08:37 -080024#include <string.h>
Dave Tapuskab8a824d2014-12-10 19:09:52 -050025#include <sys/types.h>
Dave Tapuskab8a824d2014-12-10 19:09:52 -050026
27#if !defined(OPENSSL_WINDOWS)
28#include <arpa/inet.h>
29#include <fcntl.h>
30#include <netdb.h>
31#include <netinet/in.h>
32#include <sys/select.h>
Brian Smith33970e62015-01-27 22:32:08 -080033#include <sys/socket.h>
Dave Tapuskab8a824d2014-12-10 19:09:52 -050034#include <unistd.h>
35#else
Brian Smith33970e62015-01-27 22:32:08 -080036#include <io.h>
David Benjamina353cdb2016-06-09 16:48:33 -040037OPENSSL_MSVC_PRAGMA(warning(push, 3))
Adam Langley3e719312015-03-20 16:32:23 -070038#include <winsock2.h>
39#include <ws2tcpip.h>
David Benjamina353cdb2016-06-09 16:48:33 -040040OPENSSL_MSVC_PRAGMA(warning(pop))
Brian Smithefed2212015-01-28 16:20:02 -080041
Brian Smith33970e62015-01-27 22:32:08 -080042typedef int ssize_t;
David Benjamin4fec04b2016-10-10 14:56:47 -040043OPENSSL_MSVC_PRAGMA(comment(lib, "Ws2_32.lib"))
Dave Tapuskab8a824d2014-12-10 19:09:52 -050044#endif
45
46#include <openssl/err.h>
47#include <openssl/ssl.h>
Gabriel Rednerdcb33832016-04-06 15:47:28 -040048#include <openssl/x509.h>
Dave Tapuskab8a824d2014-12-10 19:09:52 -050049
David Benjamin17cf2cb2016-12-13 01:07:13 -050050#include "../crypto/internal.h"
Dave Tapuskab8a824d2014-12-10 19:09:52 -050051#include "internal.h"
Piotr Sikorac6d30292016-03-18 17:28:36 -070052#include "transport_common.h"
Dave Tapuskab8a824d2014-12-10 19:09:52 -050053
54
Brian Smith33970e62015-01-27 22:32:08 -080055#if !defined(OPENSSL_WINDOWS)
56static int closesocket(int sock) {
57 return close(sock);
58}
59#endif
60
61bool InitSocketLibrary() {
62#if defined(OPENSSL_WINDOWS)
63 WSADATA wsaData;
64 int err = WSAStartup(MAKEWORD(2, 2), &wsaData);
65 if (err != 0) {
66 fprintf(stderr, "WSAStartup failed with error %d\n", err);
67 return false;
68 }
69#endif
70 return true;
71}
72
David Benjaminee7aa022017-07-07 16:47:59 -040073static void SplitHostPort(std::string *out_hostname, std::string *out_port,
74 const std::string &hostname_and_port) {
David Benjamin72acbec2016-06-22 13:01:24 -040075 size_t colon_offset = hostname_and_port.find_last_of(':');
76 const size_t bracket_offset = hostname_and_port.find_last_of(']');
Dave Tapuskab8a824d2014-12-10 19:09:52 -050077 std::string hostname, port;
78
David Benjamin72acbec2016-06-22 13:01:24 -040079 // An IPv6 literal may have colons internally, guarded by square brackets.
80 if (bracket_offset != std::string::npos &&
81 colon_offset != std::string::npos && bracket_offset > colon_offset) {
82 colon_offset = std::string::npos;
83 }
84
Dave Tapuskab8a824d2014-12-10 19:09:52 -050085 if (colon_offset == std::string::npos) {
David Benjaminee7aa022017-07-07 16:47:59 -040086 *out_hostname = hostname_and_port;
87 *out_port = "443";
Dave Tapuskab8a824d2014-12-10 19:09:52 -050088 } else {
David Benjaminee7aa022017-07-07 16:47:59 -040089 *out_hostname = hostname_and_port.substr(0, colon_offset);
90 *out_port = hostname_and_port.substr(colon_offset + 1);
Dave Tapuskab8a824d2014-12-10 19:09:52 -050091 }
David Benjaminee7aa022017-07-07 16:47:59 -040092}
93
David Benjamin3c37d0a2018-05-05 00:42:23 -040094static std::string GetLastSocketErrorString() {
95#if defined(OPENSSL_WINDOWS)
96 int error = WSAGetLastError();
97 char *buffer;
98 DWORD len = FormatMessageA(
99 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, 0, error, 0,
100 reinterpret_cast<char *>(&buffer), 0, nullptr);
101 if (len == 0) {
102 char buf[256];
103 snprintf(buf, sizeof(buf), "unknown error (0x%x)", error);
104 return buf;
105 }
106 std::string ret(buffer, len);
107 LocalFree(buffer);
108 return ret;
109#else
110 return strerror(errno);
111#endif
112}
113
114static void PrintSocketError(const char *function) {
115 // On Windows, |perror| and |errno| are part of the C runtime, while sockets
116 // are separate, so we must print errors manually.
117 std::string error = GetLastSocketErrorString();
118 fprintf(stderr, "%s: %s\n", function, error.c_str());
119}
120
David Benjaminee7aa022017-07-07 16:47:59 -0400121// Connect sets |*out_sock| to be a socket connected to the destination given
122// in |hostname_and_port|, which should be of the form "www.example.com:123".
123// It returns true on success and false otherwise.
124bool Connect(int *out_sock, const std::string &hostname_and_port) {
125 std::string hostname, port;
126 SplitHostPort(&hostname, &port, hostname_and_port);
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500127
David Benjamin72acbec2016-06-22 13:01:24 -0400128 // Handle IPv6 literals.
129 if (hostname.size() >= 2 && hostname[0] == '[' &&
130 hostname[hostname.size() - 1] == ']') {
131 hostname = hostname.substr(1, hostname.size() - 2);
132 }
133
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500134 struct addrinfo hint, *result;
David Benjamin17cf2cb2016-12-13 01:07:13 -0500135 OPENSSL_memset(&hint, 0, sizeof(hint));
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500136 hint.ai_family = AF_UNSPEC;
137 hint.ai_socktype = SOCK_STREAM;
138
139 int ret = getaddrinfo(hostname.c_str(), port.c_str(), &hint, &result);
140 if (ret != 0) {
141 fprintf(stderr, "getaddrinfo returned: %s\n", gai_strerror(ret));
142 return false;
143 }
144
145 bool ok = false;
146 char buf[256];
147
148 *out_sock =
149 socket(result->ai_family, result->ai_socktype, result->ai_protocol);
150 if (*out_sock < 0) {
David Benjamin3c37d0a2018-05-05 00:42:23 -0400151 PrintSocketError("socket");
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500152 goto out;
153 }
154
155 switch (result->ai_family) {
156 case AF_INET: {
157 struct sockaddr_in *sin =
158 reinterpret_cast<struct sockaddr_in *>(result->ai_addr);
159 fprintf(stderr, "Connecting to %s:%d\n",
160 inet_ntop(result->ai_family, &sin->sin_addr, buf, sizeof(buf)),
161 ntohs(sin->sin_port));
162 break;
163 }
164 case AF_INET6: {
165 struct sockaddr_in6 *sin6 =
166 reinterpret_cast<struct sockaddr_in6 *>(result->ai_addr);
167 fprintf(stderr, "Connecting to [%s]:%d\n",
168 inet_ntop(result->ai_family, &sin6->sin6_addr, buf, sizeof(buf)),
169 ntohs(sin6->sin6_port));
170 break;
171 }
172 }
173
174 if (connect(*out_sock, result->ai_addr, result->ai_addrlen) != 0) {
David Benjamin3c37d0a2018-05-05 00:42:23 -0400175 PrintSocketError("connect");
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500176 goto out;
177 }
178 ok = true;
179
180out:
181 freeaddrinfo(result);
182 return ok;
183}
184
David Benjamin2b0444e2017-06-27 17:29:27 -0400185Listener::~Listener() {
186 if (server_sock_ >= 0) {
187 closesocket(server_sock_);
188 }
189}
190
191bool Listener::Init(const std::string &port) {
192 if (server_sock_ >= 0) {
193 return false;
194 }
195
196 struct sockaddr_in6 addr;
David Benjamin17cf2cb2016-12-13 01:07:13 -0500197 OPENSSL_memset(&addr, 0, sizeof(addr));
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500198
Matt Braithwaite29d8adb2015-09-28 19:45:54 -0700199 addr.sin6_family = AF_INET6;
David Benjamin02afbd32017-10-05 15:04:08 -0400200 // Windows' IN6ADDR_ANY_INIT does not have enough curly braces for clang-cl
201 // (https://crbug.com/772108), while other platforms like NaCl are missing
202 // in6addr_any, so use a mix of both.
203#if defined(OPENSSL_WINDOWS)
204 addr.sin6_addr = in6addr_any;
205#else
Matthew Braithwaiteb3488972016-10-19 15:05:29 -0700206 addr.sin6_addr = IN6ADDR_ANY_INIT;
David Benjamin02afbd32017-10-05 15:04:08 -0400207#endif
Matt Braithwaite29d8adb2015-09-28 19:45:54 -0700208 addr.sin6_port = htons(atoi(port.c_str()));
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500209
David Benjamin6add9f12017-01-06 16:02:39 -0500210#if defined(OPENSSL_WINDOWS)
211 const BOOL enable = TRUE;
212#else
213 const int enable = 1;
214#endif
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500215
David Benjamin2b0444e2017-06-27 17:29:27 -0400216 server_sock_ = socket(addr.sin6_family, SOCK_STREAM, 0);
217 if (server_sock_ < 0) {
David Benjamin3c37d0a2018-05-05 00:42:23 -0400218 PrintSocketError("socket");
David Benjamin2b0444e2017-06-27 17:29:27 -0400219 return false;
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500220 }
221
David Benjamin2b0444e2017-06-27 17:29:27 -0400222 if (setsockopt(server_sock_, SOL_SOCKET, SO_REUSEADDR, (const char *)&enable,
Steven Valdezbf5bda32016-12-28 10:51:01 -0500223 sizeof(enable)) < 0) {
David Benjamin3c37d0a2018-05-05 00:42:23 -0400224 PrintSocketError("setsockopt");
David Benjamin2b0444e2017-06-27 17:29:27 -0400225 return false;
Steven Valdezbf5bda32016-12-28 10:51:01 -0500226 }
227
David Benjamin2b0444e2017-06-27 17:29:27 -0400228 if (bind(server_sock_, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
David Benjamin3c37d0a2018-05-05 00:42:23 -0400229 PrintSocketError("connect");
David Benjamin2b0444e2017-06-27 17:29:27 -0400230 return false;
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500231 }
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500232
David Benjamin2b0444e2017-06-27 17:29:27 -0400233 listen(server_sock_, SOMAXCONN);
234 return true;
235}
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500236
David Benjamin2b0444e2017-06-27 17:29:27 -0400237bool Listener::Accept(int *out_sock) {
238 struct sockaddr_in6 addr;
239 socklen_t addr_len = sizeof(addr);
240 *out_sock = accept(server_sock_, (struct sockaddr *)&addr, &addr_len);
241 return *out_sock >= 0;
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500242}
243
David Benjamin225e5ad2016-07-16 14:51:58 +0200244bool VersionFromString(uint16_t *out_version, const std::string &version) {
245 if (version == "ssl3") {
246 *out_version = SSL3_VERSION;
247 return true;
248 } else if (version == "tls1" || version == "tls1.0") {
249 *out_version = TLS1_VERSION;
250 return true;
251 } else if (version == "tls1.1") {
252 *out_version = TLS1_1_VERSION;
253 return true;
254 } else if (version == "tls1.2") {
255 *out_version = TLS1_2_VERSION;
256 return true;
257 } else if (version == "tls1.3") {
258 *out_version = TLS1_3_VERSION;
259 return true;
260 }
261 return false;
262}
263
Peter Wu5663b632017-09-15 15:09:03 +0100264void PrintConnectionInfo(BIO *bio, const SSL *ssl) {
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500265 const SSL_CIPHER *cipher = SSL_get_current_cipher(ssl);
266
Peter Wu5663b632017-09-15 15:09:03 +0100267 BIO_printf(bio, " Version: %s\n", SSL_get_version(ssl));
268 BIO_printf(bio, " Resumed session: %s\n",
269 SSL_session_reused(ssl) ? "yes" : "no");
270 BIO_printf(bio, " Cipher: %s\n", SSL_CIPHER_standard_name(cipher));
David Benjamin49864a52016-07-13 15:50:26 -0400271 uint16_t curve = SSL_get_curve_id(ssl);
272 if (curve != 0) {
Peter Wu5663b632017-09-15 15:09:03 +0100273 BIO_printf(bio, " ECDHE curve: %s\n", SSL_get_curve_name(curve));
David Benjamin49864a52016-07-13 15:50:26 -0400274 }
David Benjamin31168c92016-09-09 16:49:02 -0400275 uint16_t sigalg = SSL_get_peer_signature_algorithm(ssl);
276 if (sigalg != 0) {
Peter Wu5663b632017-09-15 15:09:03 +0100277 BIO_printf(bio, " Signature algorithm: %s\n",
David Benjamin6cc352e2017-11-02 17:21:39 -0400278 SSL_get_signature_algorithm_name(
279 sigalg, SSL_version(ssl) != TLS1_2_VERSION));
David Benjamin31168c92016-09-09 16:49:02 -0400280 }
Peter Wu5663b632017-09-15 15:09:03 +0100281 BIO_printf(bio, " Secure renegotiation: %s\n",
282 SSL_get_secure_renegotiation_support(ssl) ? "yes" : "no");
283 BIO_printf(bio, " Extended master secret: %s\n",
284 SSL_get_extms_support(ssl) ? "yes" : "no");
David Benjamin05709232015-03-23 19:01:33 -0400285
286 const uint8_t *next_proto;
287 unsigned next_proto_len;
288 SSL_get0_next_proto_negotiated(ssl, &next_proto, &next_proto_len);
Peter Wu5663b632017-09-15 15:09:03 +0100289 BIO_printf(bio, " Next protocol negotiated: %.*s\n", next_proto_len,
290 next_proto);
David Benjamin05709232015-03-23 19:01:33 -0400291
292 const uint8_t *alpn;
293 unsigned alpn_len;
294 SSL_get0_alpn_selected(ssl, &alpn, &alpn_len);
Peter Wu5663b632017-09-15 15:09:03 +0100295 BIO_printf(bio, " ALPN protocol: %.*s\n", alpn_len, alpn);
Gabriel Rednerdcb33832016-04-06 15:47:28 -0400296
Alessandro Ghedini8d3f1302016-11-14 21:24:18 +0000297 const char *host_name = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
298 if (host_name != nullptr && SSL_is_server(ssl)) {
Peter Wu5663b632017-09-15 15:09:03 +0100299 BIO_printf(bio, " Client sent SNI: %s\n", host_name);
Alessandro Ghedini8d3f1302016-11-14 21:24:18 +0000300 }
301
Alessandro Ghedini1149ee12016-12-12 14:48:55 +0000302 if (!SSL_is_server(ssl)) {
303 const uint8_t *ocsp_staple;
304 size_t ocsp_staple_len;
305 SSL_get0_ocsp_response(ssl, &ocsp_staple, &ocsp_staple_len);
Peter Wu5663b632017-09-15 15:09:03 +0100306 BIO_printf(bio, " OCSP staple: %s\n", ocsp_staple_len > 0 ? "yes" : "no");
Alessandro Ghedinif6d64ef2017-02-16 00:57:35 +0000307
308 const uint8_t *sct_list;
309 size_t sct_list_len;
310 SSL_get0_signed_cert_timestamp_list(ssl, &sct_list, &sct_list_len);
Peter Wu5663b632017-09-15 15:09:03 +0100311 BIO_printf(bio, " SCT list: %s\n", sct_list_len > 0 ? "yes" : "no");
Alessandro Ghedini1149ee12016-12-12 14:48:55 +0000312 }
313
David Benjamin4ddbc7b2017-11-11 14:21:50 +0800314 BIO_printf(
315 bio, " Early data: %s\n",
316 (SSL_early_data_accepted(ssl) || SSL_in_early_data(ssl)) ? "yes" : "no");
Alessandro Ghedinica307ab2017-03-26 12:19:40 -0500317
Gabriel Rednerdcb33832016-04-06 15:47:28 -0400318 // Print the server cert subject and issuer names.
David Benjamin0cce8632016-10-20 15:13:26 -0400319 bssl::UniquePtr<X509> peer(SSL_get_peer_certificate(ssl));
320 if (peer != nullptr) {
Peter Wu5663b632017-09-15 15:09:03 +0100321 BIO_printf(bio, " Cert subject: ");
322 X509_NAME_print_ex(bio, X509_get_subject_name(peer.get()), 0,
323 XN_FLAG_ONELINE);
324 BIO_printf(bio, "\n Cert issuer: ");
325 X509_NAME_print_ex(bio, X509_get_issuer_name(peer.get()), 0,
326 XN_FLAG_ONELINE);
327 BIO_printf(bio, "\n");
Gabriel Rednerdcb33832016-04-06 15:47:28 -0400328 }
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500329}
330
331bool SocketSetNonBlocking(int sock, bool is_non_blocking) {
332 bool ok;
333
334#if defined(OPENSSL_WINDOWS)
335 u_long arg = is_non_blocking;
Brian Smith33970e62015-01-27 22:32:08 -0800336 ok = 0 == ioctlsocket(sock, FIONBIO, &arg);
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500337#else
338 int flags = fcntl(sock, F_GETFL, 0);
339 if (flags < 0) {
340 return false;
341 }
342 if (is_non_blocking) {
343 flags |= O_NONBLOCK;
344 } else {
345 flags &= ~O_NONBLOCK;
346 }
347 ok = 0 == fcntl(sock, F_SETFL, flags);
348#endif
349 if (!ok) {
350 fprintf(stderr, "Failed to set socket non-blocking.\n");
351 }
352 return ok;
353}
354
Steven Valdez56851c82017-07-24 10:19:57 -0400355static bool SocketSelect(int sock, bool stdin_open, bool *socket_ready,
356 bool *stdin_ready) {
357#if !defined(OPENSSL_WINDOWS)
358 fd_set read_fds;
359 FD_ZERO(&read_fds);
360 if (stdin_open) {
361 FD_SET(0, &read_fds);
362 }
363 FD_SET(sock, &read_fds);
364 if (select(sock + 1, &read_fds, NULL, NULL, NULL) <= 0) {
365 perror("select");
366 return false;
367 }
368
369 if (FD_ISSET(0, &read_fds)) {
370 *stdin_ready = true;
371 }
372 if (FD_ISSET(sock, &read_fds)) {
373 *socket_ready = true;
374 }
375
376 return true;
377#else
378 WSAEVENT socket_handle = WSACreateEvent();
379 if (socket_handle == WSA_INVALID_EVENT ||
David Benjamin3c37d0a2018-05-05 00:42:23 -0400380 WSAEventSelect(sock, socket_handle, FD_READ | FD_CLOSE) != 0) {
Steven Valdez56851c82017-07-24 10:19:57 -0400381 WSACloseEvent(socket_handle);
382 return false;
383 }
384
385 HANDLE read_fds[2];
386 read_fds[0] = socket_handle;
387 read_fds[1] = GetStdHandle(STD_INPUT_HANDLE);
388
389 switch (
390 WaitForMultipleObjects(stdin_open ? 2 : 1, read_fds, FALSE, INFINITE)) {
391 case WAIT_OBJECT_0 + 0:
392 *socket_ready = true;
393 break;
394 case WAIT_OBJECT_0 + 1:
395 *stdin_ready = true;
396 break;
397 case WAIT_TIMEOUT:
398 break;
399 default:
400 WSACloseEvent(socket_handle);
401 return false;
402 }
403
404 WSACloseEvent(socket_handle);
405 return true;
406#endif
407}
408
David Benjamin3c37d0a2018-05-05 00:42:23 -0400409void PrintSSLError(FILE *file, const char *msg, int ssl_err, int ret) {
410 switch (ssl_err) {
411 case SSL_ERROR_SSL:
412 fprintf(file, "%s: %s\n", msg, ERR_reason_error_string(ERR_peek_error()));
413 break;
414 case SSL_ERROR_SYSCALL:
415 if (ret == 0) {
416 fprintf(file, "%s: peer closed connection\n", msg);
417 } else {
418 std::string error = GetLastSocketErrorString();
419 fprintf(file, "%s: %s\n", msg, error.c_str());
420 }
421 break;
422 case SSL_ERROR_ZERO_RETURN:
423 fprintf(file, "%s: received close_notify\n", msg);
424 break;
425 default:
426 fprintf(file, "%s: unknown error type (%d)\n", msg, ssl_err);
427 }
428 ERR_print_errors_fp(file);
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500429}
430
431bool TransferData(SSL *ssl, int sock) {
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500432 if (!SocketSetNonBlocking(sock, true)) {
433 return false;
434 }
435
Steven Valdez56851c82017-07-24 10:19:57 -0400436 bool stdin_open = true;
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500437 for (;;) {
Steven Valdez56851c82017-07-24 10:19:57 -0400438 bool socket_ready = false;
439 bool stdin_ready = false;
440 if (!SocketSelect(sock, stdin_open, &socket_ready, &stdin_ready)) {
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500441 return false;
442 }
443
Steven Valdez56851c82017-07-24 10:19:57 -0400444 if (stdin_ready) {
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500445 uint8_t buffer[512];
446 ssize_t n;
447
448 do {
nmittlerf0322b22016-05-19 08:49:59 -0700449 n = BORINGSSL_READ(0, buffer, sizeof(buffer));
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500450 } while (n == -1 && errno == EINTR);
451
452 if (n == 0) {
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500453 stdin_open = false;
Brian Smith33970e62015-01-27 22:32:08 -0800454#if !defined(OPENSSL_WINDOWS)
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500455 shutdown(sock, SHUT_WR);
Brian Smith33970e62015-01-27 22:32:08 -0800456#else
457 shutdown(sock, SD_SEND);
458#endif
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500459 continue;
460 } else if (n < 0) {
461 perror("read from stdin");
462 return false;
463 }
464
Steven Valdez56851c82017-07-24 10:19:57 -0400465 // On Windows, SocketSelect ends up setting sock to non-blocking.
466#if !defined(OPENSSL_WINDOWS)
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500467 if (!SocketSetNonBlocking(sock, false)) {
468 return false;
469 }
Steven Valdez56851c82017-07-24 10:19:57 -0400470#endif
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500471 int ssl_ret = SSL_write(ssl, buffer, n);
Steven Valdez0cdbc872018-05-07 12:42:11 -0400472 if (ssl_ret <= 0) {
473 int ssl_err = SSL_get_error(ssl, ssl_ret);
David Benjamin3c37d0a2018-05-05 00:42:23 -0400474 PrintSSLError(stderr, "Error while writing", ssl_err, ssl_ret);
Steven Valdez0cdbc872018-05-07 12:42:11 -0400475 return false;
476 } else if (ssl_ret != n) {
477 fprintf(stderr, "Short write from SSL_write.\n");
David Benjamine7ca8a52018-05-05 00:42:23 -0400478 return false;
479 }
David Benjamin3c37d0a2018-05-05 00:42:23 -0400480
481 // Note we handle errors before restoring the non-blocking state. On
482 // Windows, |SocketSetNonBlocking| internally clears the last error.
483 if (!SocketSetNonBlocking(sock, true)) {
484 return false;
485 }
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500486 }
487
Steven Valdez56851c82017-07-24 10:19:57 -0400488 if (socket_ready) {
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500489 uint8_t buffer[512];
490 int ssl_ret = SSL_read(ssl, buffer, sizeof(buffer));
491
492 if (ssl_ret < 0) {
493 int ssl_err = SSL_get_error(ssl, ssl_ret);
494 if (ssl_err == SSL_ERROR_WANT_READ) {
495 continue;
496 }
David Benjamin3c37d0a2018-05-05 00:42:23 -0400497 PrintSSLError(stderr, "Error while reading", ssl_err, ssl_ret);
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500498 return false;
499 } else if (ssl_ret == 0) {
500 return true;
501 }
502
503 ssize_t n;
504 do {
nmittlerf0322b22016-05-19 08:49:59 -0700505 n = BORINGSSL_WRITE(1, buffer, ssl_ret);
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500506 } while (n == -1 && errno == EINTR);
507
508 if (n != ssl_ret) {
509 fprintf(stderr, "Short write to stderr.\n");
510 return false;
511 }
512 }
513 }
514}
Adam Langley403c52a2016-07-07 14:52:02 -0700515
516// SocketLineReader wraps a small buffer around a socket for line-orientated
517// protocols.
518class SocketLineReader {
519 public:
520 explicit SocketLineReader(int sock) : sock_(sock) {}
521
522 // Next reads a '\n'- or '\r\n'-terminated line from the socket and, on
523 // success, sets |*out_line| to it and returns true. Otherwise it returns
524 // false.
525 bool Next(std::string *out_line) {
526 for (;;) {
527 for (size_t i = 0; i < buf_len_; i++) {
528 if (buf_[i] != '\n') {
529 continue;
530 }
531
532 size_t length = i;
533 if (i > 0 && buf_[i - 1] == '\r') {
534 length--;
535 }
536
537 out_line->assign(buf_, length);
538 buf_len_ -= i + 1;
David Benjamin17cf2cb2016-12-13 01:07:13 -0500539 OPENSSL_memmove(buf_, &buf_[i + 1], buf_len_);
Adam Langley403c52a2016-07-07 14:52:02 -0700540
541 return true;
542 }
543
544 if (buf_len_ == sizeof(buf_)) {
545 fprintf(stderr, "Received line too long!\n");
546 return false;
547 }
548
549 ssize_t n;
550 do {
551 n = recv(sock_, &buf_[buf_len_], sizeof(buf_) - buf_len_, 0);
552 } while (n == -1 && errno == EINTR);
553
554 if (n < 0) {
555 fprintf(stderr, "Read error from socket\n");
556 return false;
557 }
558
559 buf_len_ += n;
560 }
561 }
562
563 // ReadSMTPReply reads one or more lines that make up an SMTP reply. On
564 // success, it sets |*out_code| to the reply's code (e.g. 250) and
565 // |*out_content| to the body of the reply (e.g. "OK") and returns true.
566 // Otherwise it returns false.
567 //
568 // See https://tools.ietf.org/html/rfc821#page-48
569 bool ReadSMTPReply(unsigned *out_code, std::string *out_content) {
570 out_content->clear();
571
572 // kMaxLines is the maximum number of lines that we'll accept in an SMTP
573 // reply.
574 static const unsigned kMaxLines = 512;
575 for (unsigned i = 0; i < kMaxLines; i++) {
576 std::string line;
577 if (!Next(&line)) {
578 return false;
579 }
580
581 if (line.size() < 4) {
582 fprintf(stderr, "Short line from SMTP server: %s\n", line.c_str());
583 return false;
584 }
585
586 const std::string code_str = line.substr(0, 3);
587 char *endptr;
588 const unsigned long code = strtoul(code_str.c_str(), &endptr, 10);
589 if (*endptr || code > UINT_MAX) {
590 fprintf(stderr, "Failed to parse code from line: %s\n", line.c_str());
591 return false;
592 }
593
594 if (i == 0) {
595 *out_code = code;
596 } else if (code != *out_code) {
597 fprintf(stderr,
598 "Reply code varied within a single reply: was %u, now %u\n",
599 *out_code, static_cast<unsigned>(code));
600 return false;
601 }
602
603 if (line[3] == ' ') {
604 // End of reply.
605 *out_content += line.substr(4, std::string::npos);
606 return true;
607 } else if (line[3] == '-') {
608 // Another line of reply will follow this one.
609 *out_content += line.substr(4, std::string::npos);
610 out_content->push_back('\n');
611 } else {
612 fprintf(stderr, "Bad character after code in SMTP reply: %s\n",
613 line.c_str());
614 return false;
615 }
616 }
617
618 fprintf(stderr, "Rejected SMTP reply of more then %u lines\n", kMaxLines);
619 return false;
620 }
621
622 private:
623 const int sock_;
624 char buf_[512];
625 size_t buf_len_ = 0;
626};
627
628// SendAll writes |data_len| bytes from |data| to |sock|. It returns true on
629// success and false otherwise.
630static bool SendAll(int sock, const char *data, size_t data_len) {
631 size_t done = 0;
632
633 while (done < data_len) {
634 ssize_t n;
635 do {
636 n = send(sock, &data[done], data_len - done, 0);
637 } while (n == -1 && errno == EINTR);
638
639 if (n < 0) {
640 fprintf(stderr, "Error while writing to socket\n");
641 return false;
642 }
643
644 done += n;
645 }
646
647 return true;
648}
649
650bool DoSMTPStartTLS(int sock) {
651 SocketLineReader line_reader(sock);
652
Adam Langley61367ee2016-07-11 12:24:55 -0700653 unsigned code_220 = 0;
Adam Langley403c52a2016-07-07 14:52:02 -0700654 std::string reply_220;
655 if (!line_reader.ReadSMTPReply(&code_220, &reply_220)) {
656 return false;
657 }
658
659 if (code_220 != 220) {
660 fprintf(stderr, "Expected 220 line from SMTP server but got code %u\n",
661 code_220);
662 return false;
663 }
664
665 static const char kHelloLine[] = "EHLO BoringSSL\r\n";
666 if (!SendAll(sock, kHelloLine, sizeof(kHelloLine) - 1)) {
667 return false;
668 }
669
Adam Langley61367ee2016-07-11 12:24:55 -0700670 unsigned code_250 = 0;
Adam Langley403c52a2016-07-07 14:52:02 -0700671 std::string reply_250;
672 if (!line_reader.ReadSMTPReply(&code_250, &reply_250)) {
673 return false;
674 }
675
676 if (code_250 != 250) {
677 fprintf(stderr, "Expected 250 line after EHLO but got code %u\n", code_250);
678 return false;
679 }
680
681 // https://tools.ietf.org/html/rfc1869#section-4.3
Adam Langley505cf392016-08-09 21:16:45 -0700682 if (("\n" + reply_250 + "\n").find("\nSTARTTLS\n") == std::string::npos) {
Adam Langley403c52a2016-07-07 14:52:02 -0700683 fprintf(stderr, "Server does not support STARTTLS\n");
684 return false;
685 }
686
687 static const char kSTARTTLSLine[] = "STARTTLS\r\n";
688 if (!SendAll(sock, kSTARTTLSLine, sizeof(kSTARTTLSLine) - 1)) {
689 return false;
690 }
691
692 if (!line_reader.ReadSMTPReply(&code_220, &reply_220)) {
693 return false;
694 }
695
696 if (code_220 != 220) {
697 fprintf(
698 stderr,
699 "Expected 220 line from SMTP server after STARTTLS, but got code %u\n",
700 code_220);
701 return false;
702 }
703
704 return true;
705}
David Benjaminee7aa022017-07-07 16:47:59 -0400706
707bool DoHTTPTunnel(int sock, const std::string &hostname_and_port) {
708 std::string hostname, port;
709 SplitHostPort(&hostname, &port, hostname_and_port);
710
711 fprintf(stderr, "Establishing HTTP tunnel to %s:%s.\n", hostname.c_str(),
712 port.c_str());
713 char buf[1024];
714 snprintf(buf, sizeof(buf), "CONNECT %s:%s HTTP/1.0\r\n\r\n", hostname.c_str(),
715 port.c_str());
716 if (!SendAll(sock, buf, strlen(buf))) {
717 return false;
718 }
719
720 SocketLineReader line_reader(sock);
721
722 // Read until an empty line, signaling the end of the HTTP response.
723 std::string line;
724 for (;;) {
725 if (!line_reader.Next(&line)) {
726 return false;
727 }
728 if (line.empty()) {
729 return true;
730 }
731 fprintf(stderr, "%s\n", line.c_str());
732 }
733}