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)
closesocket(int sock)47 static int closesocket(int sock) {
48   return close(sock);
49 }
50 
PrintSocketError(const char * func)51 static void PrintSocketError(const char *func) {
52   perror(func);
53 }
54 #else
PrintSocketError(const char * func)55 static void PrintSocketError(const char *func) {
56   fprintf(stderr, "%s: %d\n", func, WSAGetLastError());
57 }
58 #endif
59 
60 class ScopedSocket {
61  public:
ScopedSocket(int sock)62   ScopedSocket(int sock) : sock_(sock) {}
~ScopedSocket()63   ~ScopedSocket() {
64     closesocket(sock_);
65   }
66 
67  private:
68   const int sock_;
69 };
70 
TestSocketConnect()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.
BioReadZeroCopyWrapper(BIO * bio,uint8_t * data,size_t len)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.
BioWriteZeroCopyWrapper(BIO * bio,const uint8_t * data,size_t len)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 
TestZeroCopyBioPairs()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 
TestPrintf()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 
ReadASN1(bool should_succeed,const uint8_t * data,size_t data_len,size_t expected_len,size_t max_len)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 
TestASN1()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 
main(void)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