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