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 33 bool HandbackReady(SSL *ssl, int ret) { 34 return ret < 0 && SSL_get_error(ssl, ret) == SSL_ERROR_HANDBACK; 35 } 36 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 (!config->async || !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 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 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 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