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)
47static int closesocket(int sock) {
48  return close(sock);
49}
50
51static void PrintSocketError(const char *func) {
52  perror(func);
53}
54#else
55static void PrintSocketError(const char *func) {
56  fprintf(stderr, "%s: %d\n", func, WSAGetLastError());
57}
58#endif
59
60class ScopedSocket {
61 public:
62  ScopedSocket(int sock) : sock_(sock) {}
63  ~ScopedSocket() {
64    closesocket(sock_);
65  }
66
67 private:
68  const int sock_;
69};
70
71static 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.
141static 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.
166static 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
190static 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
285static 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
332static 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
356static 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
413int 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