Home | History | Annotate | Download | only in bio
      1 /* Copyright (c) 2014, 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 #if !defined(_POSIX_C_SOURCE)
     16 #define _POSIX_C_SOURCE 201410L
     17 #endif
     18 
     19 #include <openssl/base.h>
     20 
     21 #if !defined(OPENSSL_WINDOWS)
     22 #include <arpa/inet.h>
     23 #include <fcntl.h>
     24 #include <netinet/in.h>
     25 #include <string.h>
     26 #include <sys/socket.h>
     27 #include <unistd.h>
     28 #else
     29 #include <io.h>
     30 #pragma warning(push, 3)
     31 #include <winsock2.h>
     32 #include <ws2tcpip.h>
     33 #pragma warning(pop)
     34 #endif
     35 
     36 #include <openssl/bio.h>
     37 #include <openssl/crypto.h>
     38 #include <openssl/err.h>
     39 #include <openssl/mem.h>
     40 
     41 #include <algorithm>
     42 
     43 #include "../test/scoped_types.h"
     44 
     45 
     46 #if !defined(OPENSSL_WINDOWS)
     47 static int closesocket(int sock) {
     48   return close(sock);
     49 }
     50 
     51 static void PrintSocketError(const char *func) {
     52   perror(func);
     53 }
     54 #else
     55 static void PrintSocketError(const char *func) {
     56   fprintf(stderr, "%s: %d\n", func, WSAGetLastError());
     57 }
     58 #endif
     59 
     60 class ScopedSocket {
     61  public:
     62   ScopedSocket(int sock) : sock_(sock) {}
     63   ~ScopedSocket() {
     64     closesocket(sock_);
     65   }
     66 
     67  private:
     68   const int sock_;
     69 };
     70 
     71 static bool TestSocketConnect() {
     72   static const char kTestMessage[] = "test";
     73 
     74   int listening_sock = socket(AF_INET, SOCK_STREAM, 0);
     75   if (listening_sock == -1) {
     76     PrintSocketError("socket");
     77     return false;
     78   }
     79   ScopedSocket listening_sock_closer(listening_sock);
     80 
     81   struct sockaddr_in sin;
     82   memset(&sin, 0, sizeof(sin));
     83   sin.sin_family = AF_INET;
     84   if (!inet_pton(AF_INET, "127.0.0.1", &sin.sin_addr)) {
     85     PrintSocketError("inet_pton");
     86     return false;
     87   }
     88   if (bind(listening_sock, (struct sockaddr *)&sin, sizeof(sin)) != 0) {
     89     PrintSocketError("bind");
     90     return false;
     91   }
     92   if (listen(listening_sock, 1)) {
     93     PrintSocketError("listen");
     94     return false;
     95   }
     96   socklen_t sockaddr_len = sizeof(sin);
     97   if (getsockname(listening_sock, (struct sockaddr *)&sin, &sockaddr_len) ||
     98       sockaddr_len != sizeof(sin)) {
     99     PrintSocketError("getsockname");
    100     return false;
    101   }
    102 
    103   char hostname[80];
    104   BIO_snprintf(hostname, sizeof(hostname), "%s:%d", "127.0.0.1",
    105                ntohs(sin.sin_port));
    106   ScopedBIO bio(BIO_new_connect(hostname));
    107   if (!bio) {
    108     fprintf(stderr, "BIO_new_connect failed.\n");
    109     return false;
    110   }
    111 
    112   if (BIO_write(bio.get(), kTestMessage, sizeof(kTestMessage)) !=
    113       sizeof(kTestMessage)) {
    114     fprintf(stderr, "BIO_write failed.\n");
    115     ERR_print_errors_fp(stderr);
    116     return false;
    117   }
    118 
    119   int sock = accept(listening_sock, (struct sockaddr *) &sin, &sockaddr_len);
    120   if (sock == -1) {
    121     PrintSocketError("accept");
    122     return false;
    123   }
    124   ScopedSocket sock_closer(sock);
    125 
    126   char buf[5];
    127   if (recv(sock, buf, sizeof(buf), 0) != sizeof(kTestMessage)) {
    128     PrintSocketError("read");
    129     return false;
    130   }
    131   if (memcmp(buf, kTestMessage, sizeof(kTestMessage))) {
    132     return false;
    133   }
    134 
    135   return true;
    136 }
    137 
    138 
    139 // BioReadZeroCopyWrapper is a wrapper around the zero-copy APIs to make
    140 // testing easier.
    141 static size_t BioReadZeroCopyWrapper(BIO *bio, uint8_t *data, size_t len) {
    142   uint8_t *read_buf;
    143   size_t read_buf_offset;
    144   size_t available_bytes;
    145   size_t len_read = 0;
    146 
    147   do {
    148     if (!BIO_zero_copy_get_read_buf(bio, &read_buf, &read_buf_offset,
    149                                     &available_bytes)) {
    150       return 0;
    151     }
    152 
    153     available_bytes = std::min(available_bytes, len - len_read);
    154     memmove(data + len_read, read_buf + read_buf_offset, available_bytes);
    155 
    156     BIO_zero_copy_get_read_buf_done(bio, available_bytes);
    157 
    158     len_read += available_bytes;
    159   } while (len - len_read > 0 && available_bytes > 0);
    160 
    161   return len_read;
    162 }
    163 
    164 // BioWriteZeroCopyWrapper is a wrapper around the zero-copy APIs to make
    165 // testing easier.
    166 static size_t BioWriteZeroCopyWrapper(BIO *bio, const uint8_t *data,
    167                                       size_t len) {
    168   uint8_t *write_buf;
    169   size_t write_buf_offset;
    170   size_t available_bytes;
    171   size_t len_written = 0;
    172 
    173   do {
    174     if (!BIO_zero_copy_get_write_buf(bio, &write_buf, &write_buf_offset,
    175                                      &available_bytes)) {
    176       return 0;
    177     }
    178 
    179     available_bytes = std::min(available_bytes, len - len_written);
    180     memmove(write_buf + write_buf_offset, data + len_written, available_bytes);
    181 
    182     BIO_zero_copy_get_write_buf_done(bio, available_bytes);
    183 
    184     len_written += available_bytes;
    185   } while (len - len_written > 0 && available_bytes > 0);
    186 
    187   return len_written;
    188 }
    189 
    190 static bool TestZeroCopyBioPairs() {
    191   // Test read and write, especially triggering the ring buffer wrap-around.
    192   uint8_t bio1_application_send_buffer[1024];
    193   uint8_t bio2_application_recv_buffer[1024];
    194 
    195   const size_t kLengths[] = {254, 255, 256, 257, 510, 511, 512, 513};
    196 
    197   // These trigger ring buffer wrap around.
    198   const size_t kPartialLengths[] = {0, 1, 2, 3, 128, 255, 256, 257, 511, 512};
    199 
    200   static const size_t kBufferSize = 512;
    201 
    202   srand(1);
    203   for (size_t i = 0; i < sizeof(bio1_application_send_buffer); i++) {
    204     bio1_application_send_buffer[i] = rand() & 255;
    205   }
    206 
    207   // Transfer bytes from bio1_application_send_buffer to
    208   // bio2_application_recv_buffer in various ways.
    209   for (size_t i = 0; i < sizeof(kLengths) / sizeof(kLengths[0]); i++) {
    210     for (size_t j = 0; j < sizeof(kPartialLengths) / sizeof(kPartialLengths[0]);
    211          j++) {
    212       size_t total_write = 0;
    213       size_t total_read = 0;
    214 
    215       BIO *bio1, *bio2;
    216       if (!BIO_new_bio_pair(&bio1, kBufferSize, &bio2, kBufferSize)) {
    217         return false;
    218       }
    219       ScopedBIO bio1_scoper(bio1);
    220       ScopedBIO bio2_scoper(bio2);
    221 
    222       total_write += BioWriteZeroCopyWrapper(
    223           bio1, bio1_application_send_buffer, kLengths[i]);
    224 
    225       // This tests interleaved read/write calls. Do a read between zero copy
    226       // write calls.
    227       uint8_t *write_buf;
    228       size_t write_buf_offset;
    229       size_t available_bytes;
    230       if (!BIO_zero_copy_get_write_buf(bio1, &write_buf, &write_buf_offset,
    231                                        &available_bytes)) {
    232         return false;
    233       }
    234 
    235       // Free kPartialLengths[j] bytes in the beginning of bio1 write buffer.
    236       // This enables ring buffer wrap around for the next write.
    237       total_read += BIO_read(bio2, bio2_application_recv_buffer + total_read,
    238                              kPartialLengths[j]);
    239 
    240       size_t interleaved_write_len = std::min(kPartialLengths[j],
    241                                               available_bytes);
    242 
    243       // Write the data for the interleaved write call. If the buffer becomes
    244       // empty after a read, the write offset is normally set to 0. Check that
    245       // this does not happen for interleaved read/write and that
    246       // |write_buf_offset| is still valid.
    247       memcpy(write_buf + write_buf_offset,
    248              bio1_application_send_buffer + total_write, interleaved_write_len);
    249       if (BIO_zero_copy_get_write_buf_done(bio1, interleaved_write_len)) {
    250         total_write += interleaved_write_len;
    251       }
    252 
    253       // Do another write in case |write_buf_offset| was wrapped.
    254       total_write += BioWriteZeroCopyWrapper(
    255           bio1, bio1_application_send_buffer + total_write,
    256           kPartialLengths[j] - interleaved_write_len);
    257 
    258       // Drain the rest.
    259       size_t bytes_left = BIO_pending(bio2);
    260       total_read += BioReadZeroCopyWrapper(
    261           bio2, bio2_application_recv_buffer + total_read, bytes_left);
    262 
    263       if (total_read != total_write) {
    264         fprintf(stderr, "Lengths not equal in round (%u, %u)\n", (unsigned)i,
    265                 (unsigned)j);
    266         return false;
    267       }
    268       if (total_read > kLengths[i] + kPartialLengths[j]) {
    269         fprintf(stderr, "Bad lengths in round (%u, %u)\n", (unsigned)i,
    270                 (unsigned)j);
    271         return false;
    272       }
    273       if (memcmp(bio1_application_send_buffer, bio2_application_recv_buffer,
    274                  total_read) != 0) {
    275         fprintf(stderr, "Buffers not equal in round (%u, %u)\n", (unsigned)i,
    276                 (unsigned)j);
    277         return false;
    278       }
    279     }
    280   }
    281 
    282   return true;
    283 }
    284 
    285 static bool TestPrintf() {
    286   // Test a short output, a very long one, and various sizes around
    287   // 256 (the size of the buffer) to ensure edge cases are correct.
    288   static const size_t kLengths[] = { 5, 250, 251, 252, 253, 254, 1023 };
    289 
    290   ScopedBIO bio(BIO_new(BIO_s_mem()));
    291   if (!bio) {
    292     fprintf(stderr, "BIO_new failed\n");
    293     return false;
    294   }
    295 
    296   for (size_t i = 0; i < sizeof(kLengths) / sizeof(kLengths[0]); i++) {
    297     char string[1024];
    298     if (kLengths[i] >= sizeof(string)) {
    299       fprintf(stderr, "Bad test string length\n");
    300       return false;
    301     }
    302     memset(string, 'a', sizeof(string));
    303     string[kLengths[i]] = '\0';
    304 
    305     int ret = BIO_printf(bio.get(), "test %s", string);
    306     if (ret < 0 || static_cast<size_t>(ret) != 5 + kLengths[i]) {
    307       fprintf(stderr, "BIO_printf failed: %d\n", ret);
    308       return false;
    309     }
    310     const uint8_t *contents;
    311     size_t len;
    312     if (!BIO_mem_contents(bio.get(), &contents, &len)) {
    313       fprintf(stderr, "BIO_mem_contents failed\n");
    314       return false;
    315     }
    316     if (len != 5 + kLengths[i] ||
    317         strncmp((const char *)contents, "test ", 5) != 0 ||
    318         strncmp((const char *)contents + 5, string, kLengths[i]) != 0) {
    319       fprintf(stderr, "Contents did not match: %.*s\n", (int)len, contents);
    320       return false;
    321     }
    322 
    323     if (!BIO_reset(bio.get())) {
    324       fprintf(stderr, "BIO_reset failed\n");
    325       return false;
    326     }
    327   }
    328 
    329   return true;
    330 }
    331 
    332 static bool ReadASN1(bool should_succeed, const uint8_t *data, size_t data_len,
    333                      size_t expected_len, size_t max_len) {
    334   ScopedBIO bio(BIO_new_mem_buf(const_cast<uint8_t*>(data), data_len));
    335 
    336   uint8_t *out;
    337   size_t out_len;
    338   int ok = BIO_read_asn1(bio.get(), &out, &out_len, max_len);
    339   if (!ok) {
    340     out = nullptr;
    341   }
    342   ScopedOpenSSLBytes out_storage(out);
    343 
    344   if (should_succeed != (ok == 1)) {
    345     return false;
    346   }
    347 
    348   if (should_succeed &&
    349       (out_len != expected_len || memcmp(data, out, expected_len) != 0)) {
    350     return false;
    351   }
    352 
    353   return true;
    354 }
    355 
    356 static bool TestASN1() {
    357   static const uint8_t kData1[] = {0x30, 2, 1, 2, 0, 0};
    358   static const uint8_t kData2[] = {0x30, 3, 1, 2};  /* truncated */
    359   static const uint8_t kData3[] = {0x30, 0x81, 1, 1};  /* should be short len */
    360   static const uint8_t kData4[] = {0x30, 0x82, 0, 1, 1};  /* zero padded. */
    361 
    362   if (!ReadASN1(true, kData1, sizeof(kData1), 4, 100) ||
    363       !ReadASN1(false, kData2, sizeof(kData2), 0, 100) ||
    364       !ReadASN1(false, kData3, sizeof(kData3), 0, 100) ||
    365       !ReadASN1(false, kData4, sizeof(kData4), 0, 100)) {
    366     return false;
    367   }
    368 
    369   static const size_t kLargePayloadLen = 8000;
    370   static const uint8_t kLargePrefix[] = {0x30, 0x82, kLargePayloadLen >> 8,
    371                                          kLargePayloadLen & 0xff};
    372   ScopedOpenSSLBytes large(reinterpret_cast<uint8_t *>(
    373       OPENSSL_malloc(sizeof(kLargePrefix) + kLargePayloadLen)));
    374   if (!large) {
    375     return false;
    376   }
    377   memset(large.get() + sizeof(kLargePrefix), 0, kLargePayloadLen);
    378   memcpy(large.get(), kLargePrefix, sizeof(kLargePrefix));
    379 
    380   if (!ReadASN1(true, large.get(), sizeof(kLargePrefix) + kLargePayloadLen,
    381                 sizeof(kLargePrefix) + kLargePayloadLen,
    382                 kLargePayloadLen * 2)) {
    383     fprintf(stderr, "Large payload test failed.\n");
    384     return false;
    385   }
    386 
    387   if (!ReadASN1(false, large.get(), sizeof(kLargePrefix) + kLargePayloadLen,
    388                 sizeof(kLargePrefix) + kLargePayloadLen,
    389                 kLargePayloadLen - 1)) {
    390     fprintf(stderr, "max_len test failed.\n");
    391     return false;
    392   }
    393 
    394   static const uint8_t kIndefPrefix[] = {0x30, 0x80};
    395   memcpy(large.get(), kIndefPrefix, sizeof(kIndefPrefix));
    396   if (!ReadASN1(true, large.get(), sizeof(kLargePrefix) + kLargePayloadLen,
    397                 sizeof(kLargePrefix) + kLargePayloadLen,
    398                 kLargePayloadLen*2)) {
    399     fprintf(stderr, "indefinite length test failed.\n");
    400     return false;
    401   }
    402 
    403   if (!ReadASN1(false, large.get(), sizeof(kLargePrefix) + kLargePayloadLen,
    404                 sizeof(kLargePrefix) + kLargePayloadLen,
    405                 kLargePayloadLen-1)) {
    406     fprintf(stderr, "indefinite length, max_len test failed.\n");
    407     return false;
    408   }
    409 
    410   return true;
    411 }
    412 
    413 int main(void) {
    414   CRYPTO_library_init();
    415   ERR_load_crypto_strings();
    416 
    417 #if defined(OPENSSL_WINDOWS)
    418   // Initialize Winsock.
    419   WORD wsa_version = MAKEWORD(2, 2);
    420   WSADATA wsa_data;
    421   int wsa_err = WSAStartup(wsa_version, &wsa_data);
    422   if (wsa_err != 0) {
    423     fprintf(stderr, "WSAStartup failed: %d\n", wsa_err);
    424     return 1;
    425   }
    426   if (wsa_data.wVersion != wsa_version) {
    427     fprintf(stderr, "Didn't get expected version: %x\n", wsa_data.wVersion);
    428     return 1;
    429   }
    430 #endif
    431 
    432   if (!TestSocketConnect() ||
    433       !TestPrintf() ||
    434       !TestZeroCopyBioPairs() ||
    435       !TestASN1()) {
    436     return 1;
    437   }
    438 
    439   printf("PASS\n");
    440   return 0;
    441 }
    442