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
130 } // namespace
131
main(int argc,char ** argv)132 int main(int argc, char **argv) {
133 TestConfig initial_config, resume_config, retry_config;
134 if (!ParseConfig(argc - 1, argv + 1, &initial_config, &resume_config,
135 &retry_config)) {
136 return 2;
137 }
138 const TestConfig *config = initial_config.handshaker_resume
139 ? &resume_config : &initial_config;
140 #if defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE)
141 if (initial_config.handshaker_resume) {
142 // If the PRNG returns exactly the same values when trying to resume then a
143 // "random" session ID will happen to exactly match the session ID
144 // "randomly" generated on the initial connection. The client will thus
145 // incorrectly believe that the server is resuming.
146 uint8_t byte;
147 RAND_bytes(&byte, 1);
148 }
149 #endif // BORINGSSL_UNSAFE_DETERMINISTIC_MODE
150
151 // read() will return the entire message in one go, because it's a datagram
152 // socket.
153 constexpr size_t kBufSize = 1024 * 1024;
154 bssl::UniquePtr<uint8_t> buf((uint8_t *) OPENSSL_malloc(kBufSize));
155 ssize_t len = read_eintr(kFdControl, buf.get(), kBufSize);
156 if (len == -1) {
157 perror("read");
158 return 2;
159 }
160 Span<uint8_t> handoff(buf.get(), len);
161 if (!Handshaker(config, kFdProxyToHandshaker, kFdHandshakerToProxy, handoff,
162 kFdControl)) {
163 char msg = kControlMsgError;
164 if (write_eintr(kFdControl, &msg, 1) != 1) {
165 return 3;
166 }
167 return 1;
168 }
169 return 0;
170 }
171