1 /* Copyright (c) 2018, 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 <errno.h>
16 #include <fcntl.h>
17 #include <signal.h>
18 #include <unistd.h>
19
20 #include <openssl/bytestring.h>
21 #include <openssl/rand.h>
22 #include <openssl/ssl.h>
23
24 #include "../internal.h"
25 #include "handshake_util.h"
26 #include "test_config.h"
27 #include "test_state.h"
28
29 using namespace bssl;
30
31 namespace {
32
HandbackReady(SSL * ssl,int ret)33 bool HandbackReady(SSL *ssl, int ret) {
34 return ret < 0 && SSL_get_error(ssl, ret) == SSL_ERROR_HANDBACK;
35 }
36
Handshaker(const TestConfig * config,int rfd,int wfd,Span<const uint8_t> input,int control)37 bool Handshaker(const TestConfig *config, int rfd, int wfd,
38 Span<const uint8_t> input, int control) {
39 UniquePtr<SSL_CTX> ctx = config->SetupCtx(/*old_ctx=*/nullptr);
40 if (!ctx) {
41 return false;
42 }
43 UniquePtr<SSL> ssl = config->NewSSL(ctx.get(), nullptr, false, nullptr);
44
45 // Set |O_NONBLOCK| in order to break out of the loop when we hit
46 // |SSL_ERROR_WANT_READ|, so that we can send |kControlMsgWantRead| to the
47 // proxy.
48 if (fcntl(rfd, F_SETFL, O_NONBLOCK) != 0) {
49 perror("fcntl");
50 return false;
51 }
52 SSL_set_rfd(ssl.get(), rfd);
53 SSL_set_wfd(ssl.get(), wfd);
54
55 CBS cbs, handoff;
56 CBS_init(&cbs, input.data(), input.size());
57 if (!CBS_get_asn1_element(&cbs, &handoff, CBS_ASN1_SEQUENCE) ||
58 !DeserializeContextState(&cbs, ctx.get()) ||
59 !SetTestState(ssl.get(), TestState::Deserialize(&cbs, ctx.get())) ||
60 !GetTestState(ssl.get()) ||
61 !SSL_apply_handoff(ssl.get(), handoff)) {
62 fprintf(stderr, "Handoff application failed.\n");
63 return false;
64 }
65
66 int ret = 0;
67 for (;;) {
68 ret = CheckIdempotentError(
69 "SSL_do_handshake", ssl.get(),
70 [&]() -> int { return SSL_do_handshake(ssl.get()); });
71 if (SSL_get_error(ssl.get(), ret) == SSL_ERROR_WANT_READ) {
72 // Synchronize with the proxy, i.e. don't let the handshake continue until
73 // the proxy has sent more data.
74 char msg = kControlMsgWantRead;
75 if (write(control, &msg, 1) != 1 ||
76 read(control, &msg, 1) != 1 ||
77 msg != kControlMsgWriteCompleted) {
78 fprintf(stderr, "read via proxy failed\n");
79 return false;
80 }
81 continue;
82 }
83 if (!RetryAsync(ssl.get(), ret)) {
84 break;
85 }
86 }
87 if (!HandbackReady(ssl.get(), ret)) {
88 ERR_print_errors_fp(stderr);
89 return false;
90 }
91
92 ScopedCBB output;
93 CBB handback;
94 Array<uint8_t> bytes;
95 if (!CBB_init(output.get(), 1024) ||
96 !CBB_add_u24_length_prefixed(output.get(), &handback) ||
97 !SSL_serialize_handback(ssl.get(), &handback) ||
98 !SerializeContextState(ssl->ctx.get(), output.get()) ||
99 !GetTestState(ssl.get())->Serialize(output.get()) ||
100 !CBBFinishArray(output.get(), &bytes)) {
101 fprintf(stderr, "Handback serialisation failed.\n");
102 return false;
103 }
104
105 char msg = kControlMsgHandback;
106 if (write(control, &msg, 1) == -1 ||
107 write(control, bytes.data(), bytes.size()) == -1) {
108 perror("write");
109 return false;
110 }
111 return true;
112 }
113
read_eintr(int fd,void * out,size_t len)114 ssize_t read_eintr(int fd, void *out, size_t len) {
115 ssize_t ret;
116 do {
117 ret = read(fd, out, len);
118 } while (ret < 0 && errno == EINTR);
119 return ret;
120 }
121
write_eintr(int fd,const void * in,size_t len)122 ssize_t write_eintr(int fd, const void *in, size_t len) {
123 ssize_t ret;
124 do {
125 ret = write(fd, in, len);
126 } while (ret < 0 && errno == EINTR);
127 return ret;
128 }
129
SignalError()130 int SignalError() {
131 const char msg = kControlMsgError;
132 if (write_eintr(kFdControl, &msg, 1) != 1) {
133 return 2;
134 }
135 return 1;
136 }
137
138 } // namespace
139
main(int argc,char ** argv)140 int main(int argc, char **argv) {
141 TestConfig initial_config, resume_config, retry_config;
142 if (!ParseConfig(argc - 1, argv + 1, &initial_config, &resume_config,
143 &retry_config)) {
144 return SignalError();
145 }
146 const TestConfig *config = initial_config.handshaker_resume
147 ? &resume_config : &initial_config;
148 #if defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE)
149 if (initial_config.handshaker_resume) {
150 // If the PRNG returns exactly the same values when trying to resume then a
151 // "random" session ID will happen to exactly match the session ID
152 // "randomly" generated on the initial connection. The client will thus
153 // incorrectly believe that the server is resuming.
154 uint8_t byte;
155 RAND_bytes(&byte, 1);
156 }
157 #endif // BORINGSSL_UNSAFE_DETERMINISTIC_MODE
158
159 // read() will return the entire message in one go, because it's a datagram
160 // socket.
161 constexpr size_t kBufSize = 1024 * 1024;
162 bssl::UniquePtr<uint8_t> buf((uint8_t *) OPENSSL_malloc(kBufSize));
163 ssize_t len = read_eintr(kFdControl, buf.get(), kBufSize);
164 if (len == -1) {
165 perror("read");
166 return 2;
167 }
168 Span<uint8_t> handoff(buf.get(), len);
169 if (!Handshaker(config, kFdProxyToHandshaker, kFdHandshakerToProxy, handoff,
170 kFdControl)) {
171 return SignalError();
172 }
173 return 0;
174 }
175