blob: fbfacf89db22b1362a2cc1932ccb7ddc21e5e627 [file] [log] [blame]
David Benjamin3db1ded2015-03-26 01:38:04 -04001/* 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>
David Benjamina353cdb2016-06-09 16:48:33 -040030OPENSSL_MSVC_PRAGMA(warning(push, 3))
David Benjamin3db1ded2015-03-26 01:38:04 -040031#include <winsock2.h>
32#include <ws2tcpip.h>
David Benjamina353cdb2016-06-09 16:48:33 -040033OPENSSL_MSVC_PRAGMA(warning(pop))
David Benjamin3db1ded2015-03-26 01:38:04 -040034#endif
35
36#include <openssl/bio.h>
37#include <openssl/crypto.h>
38#include <openssl/err.h>
Brian Smith054e6822015-03-27 21:12:01 -100039#include <openssl/mem.h>
David Benjamin3db1ded2015-03-26 01:38:04 -040040
41#include <algorithm>
42
Steven Valdezcb966542016-08-17 16:56:14 -040043#include "../internal.h"
Adam Langleyd2b5af52016-07-12 08:03:59 -070044
David Benjamin3db1ded2015-03-26 01:38:04 -040045
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:
David Benjamin1e5ac5d2016-11-01 16:37:09 -040062 explicit ScopedSocket(int sock) : sock_(sock) {}
David Benjamin3db1ded2015-03-26 01:38:04 -040063 ~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;
David Benjamin17cf2cb2016-12-13 01:07:13 -050082 OPENSSL_memset(&sin, 0, sizeof(sin));
David Benjamin3db1ded2015-03-26 01:38:04 -040083 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));
Matt Braithwaited17d74d2016-08-17 20:10:28 -0700106 bssl::UniquePtr<BIO> bio(BIO_new_connect(hostname));
David Benjamin3db1ded2015-03-26 01:38:04 -0400107 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");
Brian Smith83a82982015-04-09 16:21:10 -1000115 ERR_print_errors_fp(stderr);
David Benjamin3db1ded2015-03-26 01:38:04 -0400116 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 }
David Benjamin17cf2cb2016-12-13 01:07:13 -0500131 if (OPENSSL_memcmp(buf, kTestMessage, sizeof(kTestMessage))) {
David Benjamin3db1ded2015-03-26 01:38:04 -0400132 return false;
133 }
134
135 return true;
136}
137
David Benjamin3db1ded2015-03-26 01:38:04 -0400138static bool TestPrintf() {
139 // Test a short output, a very long one, and various sizes around
140 // 256 (the size of the buffer) to ensure edge cases are correct.
141 static const size_t kLengths[] = { 5, 250, 251, 252, 253, 254, 1023 };
142
Matt Braithwaited17d74d2016-08-17 20:10:28 -0700143 bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
David Benjamin3db1ded2015-03-26 01:38:04 -0400144 if (!bio) {
145 fprintf(stderr, "BIO_new failed\n");
146 return false;
147 }
148
Steven Valdezcb966542016-08-17 16:56:14 -0400149 for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kLengths); i++) {
David Benjamin3db1ded2015-03-26 01:38:04 -0400150 char string[1024];
151 if (kLengths[i] >= sizeof(string)) {
152 fprintf(stderr, "Bad test string length\n");
153 return false;
154 }
David Benjamin17cf2cb2016-12-13 01:07:13 -0500155 OPENSSL_memset(string, 'a', sizeof(string));
David Benjamin3db1ded2015-03-26 01:38:04 -0400156 string[kLengths[i]] = '\0';
157
158 int ret = BIO_printf(bio.get(), "test %s", string);
159 if (ret < 0 || static_cast<size_t>(ret) != 5 + kLengths[i]) {
160 fprintf(stderr, "BIO_printf failed: %d\n", ret);
161 return false;
162 }
163 const uint8_t *contents;
164 size_t len;
165 if (!BIO_mem_contents(bio.get(), &contents, &len)) {
166 fprintf(stderr, "BIO_mem_contents failed\n");
167 return false;
168 }
169 if (len != 5 + kLengths[i] ||
170 strncmp((const char *)contents, "test ", 5) != 0 ||
171 strncmp((const char *)contents + 5, string, kLengths[i]) != 0) {
172 fprintf(stderr, "Contents did not match: %.*s\n", (int)len, contents);
173 return false;
174 }
175
176 if (!BIO_reset(bio.get())) {
177 fprintf(stderr, "BIO_reset failed\n");
178 return false;
179 }
180 }
181
182 return true;
183}
184
Adam Langley71106ad2015-05-18 17:25:20 -0700185static bool ReadASN1(bool should_succeed, const uint8_t *data, size_t data_len,
186 size_t expected_len, size_t max_len) {
Matt Braithwaited17d74d2016-08-17 20:10:28 -0700187 bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(data, data_len));
Adam Langley71106ad2015-05-18 17:25:20 -0700188
189 uint8_t *out;
190 size_t out_len;
191 int ok = BIO_read_asn1(bio.get(), &out, &out_len, max_len);
192 if (!ok) {
193 out = nullptr;
194 }
Matt Braithwaited17d74d2016-08-17 20:10:28 -0700195 bssl::UniquePtr<uint8_t> out_storage(out);
Adam Langley71106ad2015-05-18 17:25:20 -0700196
197 if (should_succeed != (ok == 1)) {
198 return false;
199 }
200
David Benjamin17cf2cb2016-12-13 01:07:13 -0500201 if (should_succeed && (out_len != expected_len ||
202 OPENSSL_memcmp(data, out, expected_len) != 0)) {
Adam Langley71106ad2015-05-18 17:25:20 -0700203 return false;
204 }
205
206 return true;
207}
208
209static bool TestASN1() {
210 static const uint8_t kData1[] = {0x30, 2, 1, 2, 0, 0};
211 static const uint8_t kData2[] = {0x30, 3, 1, 2}; /* truncated */
212 static const uint8_t kData3[] = {0x30, 0x81, 1, 1}; /* should be short len */
213 static const uint8_t kData4[] = {0x30, 0x82, 0, 1, 1}; /* zero padded. */
214
215 if (!ReadASN1(true, kData1, sizeof(kData1), 4, 100) ||
216 !ReadASN1(false, kData2, sizeof(kData2), 0, 100) ||
217 !ReadASN1(false, kData3, sizeof(kData3), 0, 100) ||
218 !ReadASN1(false, kData4, sizeof(kData4), 0, 100)) {
219 return false;
220 }
221
222 static const size_t kLargePayloadLen = 8000;
223 static const uint8_t kLargePrefix[] = {0x30, 0x82, kLargePayloadLen >> 8,
224 kLargePayloadLen & 0xff};
Matt Braithwaited17d74d2016-08-17 20:10:28 -0700225 bssl::UniquePtr<uint8_t> large(reinterpret_cast<uint8_t *>(
Adam Langley71106ad2015-05-18 17:25:20 -0700226 OPENSSL_malloc(sizeof(kLargePrefix) + kLargePayloadLen)));
227 if (!large) {
228 return false;
229 }
David Benjamin17cf2cb2016-12-13 01:07:13 -0500230 OPENSSL_memset(large.get() + sizeof(kLargePrefix), 0, kLargePayloadLen);
231 OPENSSL_memcpy(large.get(), kLargePrefix, sizeof(kLargePrefix));
Adam Langley71106ad2015-05-18 17:25:20 -0700232
233 if (!ReadASN1(true, large.get(), sizeof(kLargePrefix) + kLargePayloadLen,
234 sizeof(kLargePrefix) + kLargePayloadLen,
235 kLargePayloadLen * 2)) {
236 fprintf(stderr, "Large payload test failed.\n");
237 return false;
238 }
239
240 if (!ReadASN1(false, large.get(), sizeof(kLargePrefix) + kLargePayloadLen,
241 sizeof(kLargePrefix) + kLargePayloadLen,
242 kLargePayloadLen - 1)) {
243 fprintf(stderr, "max_len test failed.\n");
244 return false;
245 }
246
247 static const uint8_t kIndefPrefix[] = {0x30, 0x80};
David Benjamin17cf2cb2016-12-13 01:07:13 -0500248 OPENSSL_memcpy(large.get(), kIndefPrefix, sizeof(kIndefPrefix));
Adam Langley71106ad2015-05-18 17:25:20 -0700249 if (!ReadASN1(true, large.get(), sizeof(kLargePrefix) + kLargePayloadLen,
250 sizeof(kLargePrefix) + kLargePayloadLen,
251 kLargePayloadLen*2)) {
252 fprintf(stderr, "indefinite length test failed.\n");
253 return false;
254 }
255
256 if (!ReadASN1(false, large.get(), sizeof(kLargePrefix) + kLargePayloadLen,
257 sizeof(kLargePrefix) + kLargePayloadLen,
258 kLargePayloadLen-1)) {
259 fprintf(stderr, "indefinite length, max_len test failed.\n");
260 return false;
261 }
262
263 return true;
264}
265
David Benjamin82bbe552016-12-06 23:17:40 -0500266static bool TestPair() {
267 // Run through the tests twice, swapping |bio1| and |bio2|, for symmetry.
268 for (int i = 0; i < 2; i++) {
269 BIO *bio1, *bio2;
270 if (!BIO_new_bio_pair(&bio1, 10, &bio2, 10)) {
271 return false;
272 }
273 bssl::UniquePtr<BIO> free_bio1(bio1), free_bio2(bio2);
274
275 if (i == 1) {
276 std::swap(bio1, bio2);
277 }
278
279 // Check initial states.
280 if (BIO_ctrl_get_write_guarantee(bio1) != 10 ||
281 BIO_ctrl_get_read_request(bio1) != 0) {
282 return false;
283 }
284
285 // Data written in one end may be read out the other.
286 char buf[20];
287 if (BIO_write(bio1, "12345", 5) != 5 ||
288 BIO_ctrl_get_write_guarantee(bio1) != 5 ||
289 BIO_read(bio2, buf, sizeof(buf)) != 5 ||
David Benjamin17cf2cb2016-12-13 01:07:13 -0500290 OPENSSL_memcmp(buf, "12345", 5) != 0 ||
David Benjamin82bbe552016-12-06 23:17:40 -0500291 BIO_ctrl_get_write_guarantee(bio1) != 10) {
292 return false;
293 }
294
295 // Attempting to write more than 10 bytes will write partially.
296 if (BIO_write(bio1, "1234567890___", 13) != 10 ||
297 BIO_ctrl_get_write_guarantee(bio1) != 0 ||
298 BIO_write(bio1, "z", 1) != -1 ||
299 !BIO_should_write(bio1) ||
300 BIO_read(bio2, buf, sizeof(buf)) != 10 ||
David Benjamin17cf2cb2016-12-13 01:07:13 -0500301 OPENSSL_memcmp(buf, "1234567890", 10) != 0 ||
David Benjamin82bbe552016-12-06 23:17:40 -0500302 BIO_ctrl_get_write_guarantee(bio1) != 10) {
303 return false;
304 }
305
306 // Unsuccessful reads update the read request.
307 if (BIO_read(bio2, buf, 5) != -1 ||
308 !BIO_should_read(bio2) ||
309 BIO_ctrl_get_read_request(bio1) != 5) {
310 return false;
311 }
312
313 // The read request is clamped to the size of the buffer.
314 if (BIO_read(bio2, buf, 20) != -1 ||
315 !BIO_should_read(bio2) ||
316 BIO_ctrl_get_read_request(bio1) != 10) {
317 return false;
318 }
319
320 // Data may be written and read in chunks.
321 if (BIO_write(bio1, "12345", 5) != 5 ||
322 BIO_ctrl_get_write_guarantee(bio1) != 5 ||
323 BIO_write(bio1, "67890___", 8) != 5 ||
324 BIO_ctrl_get_write_guarantee(bio1) != 0 ||
325 BIO_read(bio2, buf, 3) != 3 ||
David Benjamin17cf2cb2016-12-13 01:07:13 -0500326 OPENSSL_memcmp(buf, "123", 3) != 0 ||
David Benjamin82bbe552016-12-06 23:17:40 -0500327 BIO_ctrl_get_write_guarantee(bio1) != 3 ||
328 BIO_read(bio2, buf, sizeof(buf)) != 7 ||
David Benjamin17cf2cb2016-12-13 01:07:13 -0500329 OPENSSL_memcmp(buf, "4567890", 7) != 0 ||
David Benjamin82bbe552016-12-06 23:17:40 -0500330 BIO_ctrl_get_write_guarantee(bio1) != 10) {
331 return false;
332 }
333
334 // Successful reads reset the read request.
335 if (BIO_ctrl_get_read_request(bio1) != 0) {
336 return false;
337 }
338
339 // Test writes and reads starting in the middle of the ring buffer and
340 // wrapping to front.
341 if (BIO_write(bio1, "abcdefgh", 8) != 8 ||
342 BIO_ctrl_get_write_guarantee(bio1) != 2 ||
343 BIO_read(bio2, buf, 3) != 3 ||
David Benjamin17cf2cb2016-12-13 01:07:13 -0500344 OPENSSL_memcmp(buf, "abc", 3) != 0 ||
David Benjamin82bbe552016-12-06 23:17:40 -0500345 BIO_ctrl_get_write_guarantee(bio1) != 5 ||
346 BIO_write(bio1, "ijklm___", 8) != 5 ||
347 BIO_ctrl_get_write_guarantee(bio1) != 0 ||
348 BIO_read(bio2, buf, sizeof(buf)) != 10 ||
David Benjamin17cf2cb2016-12-13 01:07:13 -0500349 OPENSSL_memcmp(buf, "defghijklm", 10) != 0 ||
David Benjamin82bbe552016-12-06 23:17:40 -0500350 BIO_ctrl_get_write_guarantee(bio1) != 10) {
351 return false;
352 }
353
354 // Data may flow from both ends in parallel.
355 if (BIO_write(bio1, "12345", 5) != 5 ||
356 BIO_write(bio2, "67890", 5) != 5 ||
357 BIO_read(bio2, buf, sizeof(buf)) != 5 ||
David Benjamin17cf2cb2016-12-13 01:07:13 -0500358 OPENSSL_memcmp(buf, "12345", 5) != 0 ||
David Benjamin82bbe552016-12-06 23:17:40 -0500359 BIO_read(bio1, buf, sizeof(buf)) != 5 ||
David Benjamin17cf2cb2016-12-13 01:07:13 -0500360 OPENSSL_memcmp(buf, "67890", 5) != 0) {
David Benjamin82bbe552016-12-06 23:17:40 -0500361 return false;
362 }
363
364 // Closing the write end causes an EOF on the read half, after draining.
365 if (BIO_write(bio1, "12345", 5) != 5 ||
366 !BIO_shutdown_wr(bio1) ||
367 BIO_read(bio2, buf, sizeof(buf)) != 5 ||
David Benjamin17cf2cb2016-12-13 01:07:13 -0500368 OPENSSL_memcmp(buf, "12345", 5) != 0 ||
David Benjamin82bbe552016-12-06 23:17:40 -0500369 BIO_read(bio2, buf, sizeof(buf)) != 0) {
370 return false;
371 }
372
373 // A closed write end may not be written to.
374 if (BIO_ctrl_get_write_guarantee(bio1) != 0 ||
375 BIO_write(bio1, "_____", 5) != -1) {
376 return false;
377 }
378
379 uint32_t err = ERR_get_error();
380 if (ERR_GET_LIB(err) != ERR_LIB_BIO ||
381 ERR_GET_REASON(err) != BIO_R_BROKEN_PIPE) {
382 return false;
383 }
384
385 // The other end is still functional.
386 if (BIO_write(bio2, "12345", 5) != 5 ||
387 BIO_read(bio1, buf, sizeof(buf)) != 5 ||
David Benjamin17cf2cb2016-12-13 01:07:13 -0500388 OPENSSL_memcmp(buf, "12345", 5) != 0) {
David Benjamin82bbe552016-12-06 23:17:40 -0500389 return false;
390 }
391 }
392
393 return true;
394}
395
David Benjaminaac1e2d2016-12-06 22:35:41 -0500396int main() {
David Benjamin3db1ded2015-03-26 01:38:04 -0400397 CRYPTO_library_init();
David Benjamin3db1ded2015-03-26 01:38:04 -0400398
399#if defined(OPENSSL_WINDOWS)
400 // Initialize Winsock.
401 WORD wsa_version = MAKEWORD(2, 2);
402 WSADATA wsa_data;
403 int wsa_err = WSAStartup(wsa_version, &wsa_data);
404 if (wsa_err != 0) {
405 fprintf(stderr, "WSAStartup failed: %d\n", wsa_err);
406 return 1;
407 }
408 if (wsa_data.wVersion != wsa_version) {
409 fprintf(stderr, "Didn't get expected version: %x\n", wsa_data.wVersion);
410 return 1;
411 }
412#endif
413
Adam Langley10f97f32016-07-12 08:09:33 -0700414 if (!TestSocketConnect() ||
415 !TestPrintf() ||
David Benjamin82bbe552016-12-06 23:17:40 -0500416 !TestASN1() ||
417 !TestPair()) {
David Benjamin3db1ded2015-03-26 01:38:04 -0400418 return 1;
419 }
420
421 printf("PASS\n");
422 return 0;
423}