blob: 3f75c9fe720823f70bf0ec359ea41aba59065762 [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
94// Connect sets |*out_sock| to be a socket connected to the destination given
95// in |hostname_and_port|, which should be of the form "www.example.com:123".
96// It returns true on success and false otherwise.
97bool Connect(int *out_sock, const std::string &hostname_and_port) {
98 std::string hostname, port;
99 SplitHostPort(&hostname, &port, hostname_and_port);
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500100
David Benjamin72acbec2016-06-22 13:01:24 -0400101 // Handle IPv6 literals.
102 if (hostname.size() >= 2 && hostname[0] == '[' &&
103 hostname[hostname.size() - 1] == ']') {
104 hostname = hostname.substr(1, hostname.size() - 2);
105 }
106
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500107 struct addrinfo hint, *result;
David Benjamin17cf2cb2016-12-13 01:07:13 -0500108 OPENSSL_memset(&hint, 0, sizeof(hint));
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500109 hint.ai_family = AF_UNSPEC;
110 hint.ai_socktype = SOCK_STREAM;
111
112 int ret = getaddrinfo(hostname.c_str(), port.c_str(), &hint, &result);
113 if (ret != 0) {
114 fprintf(stderr, "getaddrinfo returned: %s\n", gai_strerror(ret));
115 return false;
116 }
117
118 bool ok = false;
119 char buf[256];
120
121 *out_sock =
122 socket(result->ai_family, result->ai_socktype, result->ai_protocol);
123 if (*out_sock < 0) {
124 perror("socket");
125 goto out;
126 }
127
128 switch (result->ai_family) {
129 case AF_INET: {
130 struct sockaddr_in *sin =
131 reinterpret_cast<struct sockaddr_in *>(result->ai_addr);
132 fprintf(stderr, "Connecting to %s:%d\n",
133 inet_ntop(result->ai_family, &sin->sin_addr, buf, sizeof(buf)),
134 ntohs(sin->sin_port));
135 break;
136 }
137 case AF_INET6: {
138 struct sockaddr_in6 *sin6 =
139 reinterpret_cast<struct sockaddr_in6 *>(result->ai_addr);
140 fprintf(stderr, "Connecting to [%s]:%d\n",
141 inet_ntop(result->ai_family, &sin6->sin6_addr, buf, sizeof(buf)),
142 ntohs(sin6->sin6_port));
143 break;
144 }
145 }
146
147 if (connect(*out_sock, result->ai_addr, result->ai_addrlen) != 0) {
148 perror("connect");
149 goto out;
150 }
151 ok = true;
152
153out:
154 freeaddrinfo(result);
155 return ok;
156}
157
David Benjamin2b0444e2017-06-27 17:29:27 -0400158Listener::~Listener() {
159 if (server_sock_ >= 0) {
160 closesocket(server_sock_);
161 }
162}
163
164bool Listener::Init(const std::string &port) {
165 if (server_sock_ >= 0) {
166 return false;
167 }
168
169 struct sockaddr_in6 addr;
David Benjamin17cf2cb2016-12-13 01:07:13 -0500170 OPENSSL_memset(&addr, 0, sizeof(addr));
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500171
Matt Braithwaite29d8adb2015-09-28 19:45:54 -0700172 addr.sin6_family = AF_INET6;
Matthew Braithwaiteb3488972016-10-19 15:05:29 -0700173 addr.sin6_addr = IN6ADDR_ANY_INIT;
Matt Braithwaite29d8adb2015-09-28 19:45:54 -0700174 addr.sin6_port = htons(atoi(port.c_str()));
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500175
David Benjamin6add9f12017-01-06 16:02:39 -0500176#if defined(OPENSSL_WINDOWS)
177 const BOOL enable = TRUE;
178#else
179 const int enable = 1;
180#endif
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500181
David Benjamin2b0444e2017-06-27 17:29:27 -0400182 server_sock_ = socket(addr.sin6_family, SOCK_STREAM, 0);
183 if (server_sock_ < 0) {
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500184 perror("socket");
David Benjamin2b0444e2017-06-27 17:29:27 -0400185 return false;
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500186 }
187
David Benjamin2b0444e2017-06-27 17:29:27 -0400188 if (setsockopt(server_sock_, SOL_SOCKET, SO_REUSEADDR, (const char *)&enable,
Steven Valdezbf5bda32016-12-28 10:51:01 -0500189 sizeof(enable)) < 0) {
190 perror("setsockopt");
David Benjamin2b0444e2017-06-27 17:29:27 -0400191 return false;
Steven Valdezbf5bda32016-12-28 10:51:01 -0500192 }
193
David Benjamin2b0444e2017-06-27 17:29:27 -0400194 if (bind(server_sock_, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500195 perror("connect");
David Benjamin2b0444e2017-06-27 17:29:27 -0400196 return false;
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500197 }
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500198
David Benjamin2b0444e2017-06-27 17:29:27 -0400199 listen(server_sock_, SOMAXCONN);
200 return true;
201}
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500202
David Benjamin2b0444e2017-06-27 17:29:27 -0400203bool Listener::Accept(int *out_sock) {
204 struct sockaddr_in6 addr;
205 socklen_t addr_len = sizeof(addr);
206 *out_sock = accept(server_sock_, (struct sockaddr *)&addr, &addr_len);
207 return *out_sock >= 0;
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500208}
209
David Benjamin225e5ad2016-07-16 14:51:58 +0200210bool VersionFromString(uint16_t *out_version, const std::string &version) {
211 if (version == "ssl3") {
212 *out_version = SSL3_VERSION;
213 return true;
214 } else if (version == "tls1" || version == "tls1.0") {
215 *out_version = TLS1_VERSION;
216 return true;
217 } else if (version == "tls1.1") {
218 *out_version = TLS1_1_VERSION;
219 return true;
220 } else if (version == "tls1.2") {
221 *out_version = TLS1_2_VERSION;
222 return true;
223 } else if (version == "tls1.3") {
224 *out_version = TLS1_3_VERSION;
225 return true;
226 }
227 return false;
228}
229
David Benjamin31168c92016-09-09 16:49:02 -0400230static const char *SignatureAlgorithmToString(uint16_t version, uint16_t sigalg) {
231 const bool is_tls12 = version == TLS1_2_VERSION || version == DTLS1_2_VERSION;
232 switch (sigalg) {
233 case SSL_SIGN_RSA_PKCS1_SHA1:
234 return "rsa_pkcs1_sha1";
235 case SSL_SIGN_RSA_PKCS1_SHA256:
236 return "rsa_pkcs1_sha256";
237 case SSL_SIGN_RSA_PKCS1_SHA384:
238 return "rsa_pkcs1_sha384";
239 case SSL_SIGN_RSA_PKCS1_SHA512:
240 return "rsa_pkcs1_sha512";
241 case SSL_SIGN_ECDSA_SHA1:
242 return "ecdsa_sha1";
243 case SSL_SIGN_ECDSA_SECP256R1_SHA256:
244 return is_tls12 ? "ecdsa_sha256" : "ecdsa_secp256r1_sha256";
245 case SSL_SIGN_ECDSA_SECP384R1_SHA384:
246 return is_tls12 ? "ecdsa_sha384" : "ecdsa_secp384r1_sha384";
247 case SSL_SIGN_ECDSA_SECP521R1_SHA512:
248 return is_tls12 ? "ecdsa_sha512" : "ecdsa_secp521r1_sha512";
249 case SSL_SIGN_RSA_PSS_SHA256:
250 return "rsa_pss_sha256";
251 case SSL_SIGN_RSA_PSS_SHA384:
252 return "rsa_pss_sha384";
253 case SSL_SIGN_RSA_PSS_SHA512:
254 return "rsa_pss_sha512";
David Benjamin69522112017-03-28 15:38:29 -0500255 case SSL_SIGN_ED25519:
256 return "ed25519";
David Benjamin31168c92016-09-09 16:49:02 -0400257 default:
258 return "(unknown)";
259 }
260}
261
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500262void PrintConnectionInfo(const SSL *ssl) {
263 const SSL_CIPHER *cipher = SSL_get_current_cipher(ssl);
264
265 fprintf(stderr, " Version: %s\n", SSL_get_version(ssl));
David Benjamin621f95a2015-08-28 15:08:34 -0400266 fprintf(stderr, " Resumed session: %s\n",
267 SSL_session_reused(ssl) ? "yes" : "no");
David Benjamin6fff3862017-06-21 21:07:04 -0400268 fprintf(stderr, " Cipher: %s\n", SSL_CIPHER_standard_name(cipher));
David Benjamin49864a52016-07-13 15:50:26 -0400269 uint16_t curve = SSL_get_curve_id(ssl);
270 if (curve != 0) {
271 fprintf(stderr, " ECDHE curve: %s\n", SSL_get_curve_name(curve));
272 }
David Benjamin31168c92016-09-09 16:49:02 -0400273 uint16_t sigalg = SSL_get_peer_signature_algorithm(ssl);
274 if (sigalg != 0) {
275 fprintf(stderr, " Signature algorithm: %s\n",
276 SignatureAlgorithmToString(SSL_version(ssl), sigalg));
277 }
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500278 fprintf(stderr, " Secure renegotiation: %s\n",
279 SSL_get_secure_renegotiation_support(ssl) ? "yes" : "no");
David Benjamin3995a382016-05-31 16:15:04 -0400280 fprintf(stderr, " Extended master secret: %s\n",
281 SSL_get_extms_support(ssl) ? "yes" : "no");
David Benjamin05709232015-03-23 19:01:33 -0400282
283 const uint8_t *next_proto;
284 unsigned next_proto_len;
285 SSL_get0_next_proto_negotiated(ssl, &next_proto, &next_proto_len);
286 fprintf(stderr, " Next protocol negotiated: %.*s\n", next_proto_len,
287 next_proto);
288
289 const uint8_t *alpn;
290 unsigned alpn_len;
291 SSL_get0_alpn_selected(ssl, &alpn, &alpn_len);
292 fprintf(stderr, " ALPN protocol: %.*s\n", alpn_len, alpn);
Gabriel Rednerdcb33832016-04-06 15:47:28 -0400293
Alessandro Ghedini8d3f1302016-11-14 21:24:18 +0000294 const char *host_name = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
295 if (host_name != nullptr && SSL_is_server(ssl)) {
296 fprintf(stderr, " Client sent SNI: %s\n", host_name);
297 }
298
Alessandro Ghedini1149ee12016-12-12 14:48:55 +0000299 if (!SSL_is_server(ssl)) {
300 const uint8_t *ocsp_staple;
301 size_t ocsp_staple_len;
302 SSL_get0_ocsp_response(ssl, &ocsp_staple, &ocsp_staple_len);
303 fprintf(stderr, " OCSP staple: %s\n", ocsp_staple_len > 0 ? "yes" : "no");
Alessandro Ghedinif6d64ef2017-02-16 00:57:35 +0000304
305 const uint8_t *sct_list;
306 size_t sct_list_len;
307 SSL_get0_signed_cert_timestamp_list(ssl, &sct_list, &sct_list_len);
308 fprintf(stderr, " SCT list: %s\n", sct_list_len > 0 ? "yes" : "no");
Alessandro Ghedini1149ee12016-12-12 14:48:55 +0000309 }
310
Alessandro Ghedinica307ab2017-03-26 12:19:40 -0500311 fprintf(stderr, " Early data: %s\n",
312 SSL_early_data_accepted(ssl) ? "yes" : "no");
313
Gabriel Rednerdcb33832016-04-06 15:47:28 -0400314 // Print the server cert subject and issuer names.
David Benjamin0cce8632016-10-20 15:13:26 -0400315 bssl::UniquePtr<X509> peer(SSL_get_peer_certificate(ssl));
316 if (peer != nullptr) {
Gabriel Rednerdcb33832016-04-06 15:47:28 -0400317 fprintf(stderr, " Cert subject: ");
David Benjamin0cce8632016-10-20 15:13:26 -0400318 X509_NAME_print_ex_fp(stderr, X509_get_subject_name(peer.get()), 0,
Gabriel Rednerdcb33832016-04-06 15:47:28 -0400319 XN_FLAG_ONELINE);
320 fprintf(stderr, "\n Cert issuer: ");
David Benjamin0cce8632016-10-20 15:13:26 -0400321 X509_NAME_print_ex_fp(stderr, X509_get_issuer_name(peer.get()), 0,
Gabriel Rednerdcb33832016-04-06 15:47:28 -0400322 XN_FLAG_ONELINE);
323 fprintf(stderr, "\n");
Gabriel Rednerdcb33832016-04-06 15:47:28 -0400324 }
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500325}
326
327bool SocketSetNonBlocking(int sock, bool is_non_blocking) {
328 bool ok;
329
330#if defined(OPENSSL_WINDOWS)
331 u_long arg = is_non_blocking;
Brian Smith33970e62015-01-27 22:32:08 -0800332 ok = 0 == ioctlsocket(sock, FIONBIO, &arg);
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500333#else
334 int flags = fcntl(sock, F_GETFL, 0);
335 if (flags < 0) {
336 return false;
337 }
338 if (is_non_blocking) {
339 flags |= O_NONBLOCK;
340 } else {
341 flags &= ~O_NONBLOCK;
342 }
343 ok = 0 == fcntl(sock, F_SETFL, flags);
344#endif
345 if (!ok) {
346 fprintf(stderr, "Failed to set socket non-blocking.\n");
347 }
348 return ok;
349}
350
Steven Valdez56851c82017-07-24 10:19:57 -0400351static bool SocketSelect(int sock, bool stdin_open, bool *socket_ready,
352 bool *stdin_ready) {
353#if !defined(OPENSSL_WINDOWS)
354 fd_set read_fds;
355 FD_ZERO(&read_fds);
356 if (stdin_open) {
357 FD_SET(0, &read_fds);
358 }
359 FD_SET(sock, &read_fds);
360 if (select(sock + 1, &read_fds, NULL, NULL, NULL) <= 0) {
361 perror("select");
362 return false;
363 }
364
365 if (FD_ISSET(0, &read_fds)) {
366 *stdin_ready = true;
367 }
368 if (FD_ISSET(sock, &read_fds)) {
369 *socket_ready = true;
370 }
371
372 return true;
373#else
374 WSAEVENT socket_handle = WSACreateEvent();
375 if (socket_handle == WSA_INVALID_EVENT ||
376 WSAEventSelect(sock, socket_handle, FD_READ) != 0) {
377 WSACloseEvent(socket_handle);
378 return false;
379 }
380
381 HANDLE read_fds[2];
382 read_fds[0] = socket_handle;
383 read_fds[1] = GetStdHandle(STD_INPUT_HANDLE);
384
385 switch (
386 WaitForMultipleObjects(stdin_open ? 2 : 1, read_fds, FALSE, INFINITE)) {
387 case WAIT_OBJECT_0 + 0:
388 *socket_ready = true;
389 break;
390 case WAIT_OBJECT_0 + 1:
391 *stdin_ready = true;
392 break;
393 case WAIT_TIMEOUT:
394 break;
395 default:
396 WSACloseEvent(socket_handle);
397 return false;
398 }
399
400 WSACloseEvent(socket_handle);
401 return true;
402#endif
403}
404
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500405// PrintErrorCallback is a callback function from OpenSSL's
406// |ERR_print_errors_cb| that writes errors to a given |FILE*|.
407int PrintErrorCallback(const char *str, size_t len, void *ctx) {
408 fwrite(str, len, 1, reinterpret_cast<FILE*>(ctx));
409 return 1;
410}
411
412bool TransferData(SSL *ssl, int sock) {
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500413 if (!SocketSetNonBlocking(sock, true)) {
414 return false;
415 }
416
Steven Valdez56851c82017-07-24 10:19:57 -0400417 bool stdin_open = true;
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500418 for (;;) {
Steven Valdez56851c82017-07-24 10:19:57 -0400419 bool socket_ready = false;
420 bool stdin_ready = false;
421 if (!SocketSelect(sock, stdin_open, &socket_ready, &stdin_ready)) {
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500422 return false;
423 }
424
Steven Valdez56851c82017-07-24 10:19:57 -0400425 if (stdin_ready) {
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500426 uint8_t buffer[512];
427 ssize_t n;
428
429 do {
nmittlerf0322b22016-05-19 08:49:59 -0700430 n = BORINGSSL_READ(0, buffer, sizeof(buffer));
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500431 } while (n == -1 && errno == EINTR);
432
433 if (n == 0) {
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500434 stdin_open = false;
Brian Smith33970e62015-01-27 22:32:08 -0800435#if !defined(OPENSSL_WINDOWS)
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500436 shutdown(sock, SHUT_WR);
Brian Smith33970e62015-01-27 22:32:08 -0800437#else
438 shutdown(sock, SD_SEND);
439#endif
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500440 continue;
441 } else if (n < 0) {
442 perror("read from stdin");
443 return false;
444 }
445
Steven Valdez56851c82017-07-24 10:19:57 -0400446 // On Windows, SocketSelect ends up setting sock to non-blocking.
447#if !defined(OPENSSL_WINDOWS)
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500448 if (!SocketSetNonBlocking(sock, false)) {
449 return false;
450 }
Steven Valdez56851c82017-07-24 10:19:57 -0400451#endif
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500452 int ssl_ret = SSL_write(ssl, buffer, n);
453 if (!SocketSetNonBlocking(sock, true)) {
454 return false;
455 }
456
457 if (ssl_ret <= 0) {
458 int ssl_err = SSL_get_error(ssl, ssl_ret);
459 fprintf(stderr, "Error while writing: %d\n", ssl_err);
460 ERR_print_errors_cb(PrintErrorCallback, stderr);
461 return false;
462 } else if (ssl_ret != n) {
463 fprintf(stderr, "Short write from SSL_write.\n");
464 return false;
465 }
466 }
467
Steven Valdez56851c82017-07-24 10:19:57 -0400468 if (socket_ready) {
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500469 uint8_t buffer[512];
470 int ssl_ret = SSL_read(ssl, buffer, sizeof(buffer));
471
472 if (ssl_ret < 0) {
473 int ssl_err = SSL_get_error(ssl, ssl_ret);
474 if (ssl_err == SSL_ERROR_WANT_READ) {
475 continue;
476 }
477 fprintf(stderr, "Error while reading: %d\n", ssl_err);
478 ERR_print_errors_cb(PrintErrorCallback, stderr);
479 return false;
480 } else if (ssl_ret == 0) {
481 return true;
482 }
483
484 ssize_t n;
485 do {
nmittlerf0322b22016-05-19 08:49:59 -0700486 n = BORINGSSL_WRITE(1, buffer, ssl_ret);
Dave Tapuskab8a824d2014-12-10 19:09:52 -0500487 } while (n == -1 && errno == EINTR);
488
489 if (n != ssl_ret) {
490 fprintf(stderr, "Short write to stderr.\n");
491 return false;
492 }
493 }
494 }
495}
Adam Langley403c52a2016-07-07 14:52:02 -0700496
497// SocketLineReader wraps a small buffer around a socket for line-orientated
498// protocols.
499class SocketLineReader {
500 public:
501 explicit SocketLineReader(int sock) : sock_(sock) {}
502
503 // Next reads a '\n'- or '\r\n'-terminated line from the socket and, on
504 // success, sets |*out_line| to it and returns true. Otherwise it returns
505 // false.
506 bool Next(std::string *out_line) {
507 for (;;) {
508 for (size_t i = 0; i < buf_len_; i++) {
509 if (buf_[i] != '\n') {
510 continue;
511 }
512
513 size_t length = i;
514 if (i > 0 && buf_[i - 1] == '\r') {
515 length--;
516 }
517
518 out_line->assign(buf_, length);
519 buf_len_ -= i + 1;
David Benjamin17cf2cb2016-12-13 01:07:13 -0500520 OPENSSL_memmove(buf_, &buf_[i + 1], buf_len_);
Adam Langley403c52a2016-07-07 14:52:02 -0700521
522 return true;
523 }
524
525 if (buf_len_ == sizeof(buf_)) {
526 fprintf(stderr, "Received line too long!\n");
527 return false;
528 }
529
530 ssize_t n;
531 do {
532 n = recv(sock_, &buf_[buf_len_], sizeof(buf_) - buf_len_, 0);
533 } while (n == -1 && errno == EINTR);
534
535 if (n < 0) {
536 fprintf(stderr, "Read error from socket\n");
537 return false;
538 }
539
540 buf_len_ += n;
541 }
542 }
543
544 // ReadSMTPReply reads one or more lines that make up an SMTP reply. On
545 // success, it sets |*out_code| to the reply's code (e.g. 250) and
546 // |*out_content| to the body of the reply (e.g. "OK") and returns true.
547 // Otherwise it returns false.
548 //
549 // See https://tools.ietf.org/html/rfc821#page-48
550 bool ReadSMTPReply(unsigned *out_code, std::string *out_content) {
551 out_content->clear();
552
553 // kMaxLines is the maximum number of lines that we'll accept in an SMTP
554 // reply.
555 static const unsigned kMaxLines = 512;
556 for (unsigned i = 0; i < kMaxLines; i++) {
557 std::string line;
558 if (!Next(&line)) {
559 return false;
560 }
561
562 if (line.size() < 4) {
563 fprintf(stderr, "Short line from SMTP server: %s\n", line.c_str());
564 return false;
565 }
566
567 const std::string code_str = line.substr(0, 3);
568 char *endptr;
569 const unsigned long code = strtoul(code_str.c_str(), &endptr, 10);
570 if (*endptr || code > UINT_MAX) {
571 fprintf(stderr, "Failed to parse code from line: %s\n", line.c_str());
572 return false;
573 }
574
575 if (i == 0) {
576 *out_code = code;
577 } else if (code != *out_code) {
578 fprintf(stderr,
579 "Reply code varied within a single reply: was %u, now %u\n",
580 *out_code, static_cast<unsigned>(code));
581 return false;
582 }
583
584 if (line[3] == ' ') {
585 // End of reply.
586 *out_content += line.substr(4, std::string::npos);
587 return true;
588 } else if (line[3] == '-') {
589 // Another line of reply will follow this one.
590 *out_content += line.substr(4, std::string::npos);
591 out_content->push_back('\n');
592 } else {
593 fprintf(stderr, "Bad character after code in SMTP reply: %s\n",
594 line.c_str());
595 return false;
596 }
597 }
598
599 fprintf(stderr, "Rejected SMTP reply of more then %u lines\n", kMaxLines);
600 return false;
601 }
602
603 private:
604 const int sock_;
605 char buf_[512];
606 size_t buf_len_ = 0;
607};
608
609// SendAll writes |data_len| bytes from |data| to |sock|. It returns true on
610// success and false otherwise.
611static bool SendAll(int sock, const char *data, size_t data_len) {
612 size_t done = 0;
613
614 while (done < data_len) {
615 ssize_t n;
616 do {
617 n = send(sock, &data[done], data_len - done, 0);
618 } while (n == -1 && errno == EINTR);
619
620 if (n < 0) {
621 fprintf(stderr, "Error while writing to socket\n");
622 return false;
623 }
624
625 done += n;
626 }
627
628 return true;
629}
630
631bool DoSMTPStartTLS(int sock) {
632 SocketLineReader line_reader(sock);
633
Adam Langley61367ee2016-07-11 12:24:55 -0700634 unsigned code_220 = 0;
Adam Langley403c52a2016-07-07 14:52:02 -0700635 std::string reply_220;
636 if (!line_reader.ReadSMTPReply(&code_220, &reply_220)) {
637 return false;
638 }
639
640 if (code_220 != 220) {
641 fprintf(stderr, "Expected 220 line from SMTP server but got code %u\n",
642 code_220);
643 return false;
644 }
645
646 static const char kHelloLine[] = "EHLO BoringSSL\r\n";
647 if (!SendAll(sock, kHelloLine, sizeof(kHelloLine) - 1)) {
648 return false;
649 }
650
Adam Langley61367ee2016-07-11 12:24:55 -0700651 unsigned code_250 = 0;
Adam Langley403c52a2016-07-07 14:52:02 -0700652 std::string reply_250;
653 if (!line_reader.ReadSMTPReply(&code_250, &reply_250)) {
654 return false;
655 }
656
657 if (code_250 != 250) {
658 fprintf(stderr, "Expected 250 line after EHLO but got code %u\n", code_250);
659 return false;
660 }
661
662 // https://tools.ietf.org/html/rfc1869#section-4.3
Adam Langley505cf392016-08-09 21:16:45 -0700663 if (("\n" + reply_250 + "\n").find("\nSTARTTLS\n") == std::string::npos) {
Adam Langley403c52a2016-07-07 14:52:02 -0700664 fprintf(stderr, "Server does not support STARTTLS\n");
665 return false;
666 }
667
668 static const char kSTARTTLSLine[] = "STARTTLS\r\n";
669 if (!SendAll(sock, kSTARTTLSLine, sizeof(kSTARTTLSLine) - 1)) {
670 return false;
671 }
672
673 if (!line_reader.ReadSMTPReply(&code_220, &reply_220)) {
674 return false;
675 }
676
677 if (code_220 != 220) {
678 fprintf(
679 stderr,
680 "Expected 220 line from SMTP server after STARTTLS, but got code %u\n",
681 code_220);
682 return false;
683 }
684
685 return true;
686}
David Benjaminee7aa022017-07-07 16:47:59 -0400687
688bool DoHTTPTunnel(int sock, const std::string &hostname_and_port) {
689 std::string hostname, port;
690 SplitHostPort(&hostname, &port, hostname_and_port);
691
692 fprintf(stderr, "Establishing HTTP tunnel to %s:%s.\n", hostname.c_str(),
693 port.c_str());
694 char buf[1024];
695 snprintf(buf, sizeof(buf), "CONNECT %s:%s HTTP/1.0\r\n\r\n", hostname.c_str(),
696 port.c_str());
697 if (!SendAll(sock, buf, strlen(buf))) {
698 return false;
699 }
700
701 SocketLineReader line_reader(sock);
702
703 // Read until an empty line, signaling the end of the HTTP response.
704 std::string line;
705 for (;;) {
706 if (!line_reader.Next(&line)) {
707 return false;
708 }
709 if (line.empty()) {
710 return true;
711 }
712 fprintf(stderr, "%s\n", line.c_str());
713 }
714}