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