Home | History | Annotate | Download | only in test
      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