]> git.ipfire.org Git - thirdparty/openssl.git/blob - test/heartbeat_test.c
Configure,test/recipes: "pin" glob to File::Glob::glob.
[thirdparty/openssl.git] / test / heartbeat_test.c
1 /*
2 * Copyright 2014-2016 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the OpenSSL license (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10 /*-
11 * Unit test for TLS heartbeats.
12 *
13 * Acts as a regression test against the Heartbleed bug (CVE-2014-0160).
14 *
15 * Author: Mike Bland (mbland@acm.org, http://mike-bland.com/)
16 * Date: 2014-04-12
17 * License: Creative Commons Attribution 4.0 International (CC By 4.0)
18 * http://creativecommons.org/licenses/by/4.0/deed.en_US
19 *
20 * OUTPUT
21 * ------
22 * The program returns zero on success. It will print a message with a count
23 * of the number of failed tests and return nonzero if any tests fail.
24 *
25 * It will print the contents of the request and response buffers for each
26 * failing test. In a "fixed" version, all the tests should pass and there
27 * should be no output.
28 *
29 * In a "bleeding" version, you'll see:
30 *
31 * test_dtls1_heartbleed failed:
32 * expected payload len: 0
33 * received: 1024
34 * sent 26 characters
35 * "HEARTBLEED "
36 * received 1024 characters
37 * "HEARTBLEED \xde\xad\xbe\xef..."
38 * ** test_dtls1_heartbleed failed **
39 *
40 * The contents of the returned buffer in the failing test will depend on the
41 * contents of memory on your machine.
42 *
43 * MORE INFORMATION
44 * ----------------
45 * http://mike-bland.com/2014/04/12/heartbleed.html
46 * http://mike-bland.com/tags/heartbleed.html
47 */
48
49 #define OPENSSL_UNIT_TEST
50
51 #include "../ssl/ssl_locl.h"
52
53 #include "testutil.h"
54 #include <ctype.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58
59 #if !defined(OPENSSL_NO_HEARTBEATS) && !defined(OPENSSL_NO_UNIT_TEST)
60
61 /* As per https://tools.ietf.org/html/rfc6520#section-4 */
62 # define MIN_PADDING_SIZE 16
63
64 /* Maximum number of payload characters to print as test output */
65 # define MAX_PRINTABLE_CHARACTERS 1024
66
67 typedef struct heartbeat_test_fixture {
68 SSL_CTX *ctx;
69 SSL *s;
70 const char *test_case_name;
71 int (*process_heartbeat) (SSL *s, unsigned char *p, unsigned int length);
72 unsigned char *payload;
73 int sent_payload_len;
74 int expected_return_value;
75 int return_payload_offset;
76 int expected_payload_len;
77 const char *expected_return_payload;
78 } HEARTBEAT_TEST_FIXTURE;
79
80 static HEARTBEAT_TEST_FIXTURE set_up(const char *const test_case_name,
81 const SSL_METHOD *meth)
82 {
83 HEARTBEAT_TEST_FIXTURE fixture;
84 int setup_ok = 1;
85 memset(&fixture, 0, sizeof(fixture));
86 fixture.test_case_name = test_case_name;
87
88 fixture.ctx = SSL_CTX_new(meth);
89 if (!fixture.ctx) {
90 fprintf(stderr, "Failed to allocate SSL_CTX for test: %s\n",
91 test_case_name);
92 setup_ok = 0;
93 goto fail;
94 }
95
96 fixture.s = SSL_new(fixture.ctx);
97 if (!fixture.s) {
98 fprintf(stderr, "Failed to allocate SSL for test: %s\n",
99 test_case_name);
100 setup_ok = 0;
101 goto fail;
102 }
103
104 if (!ssl_init_wbio_buffer(fixture.s)) {
105 fprintf(stderr, "Failed to set up wbio buffer for test: %s\n",
106 test_case_name);
107 setup_ok = 0;
108 goto fail;
109 }
110
111 if (!ssl3_setup_buffers(fixture.s)) {
112 fprintf(stderr, "Failed to setup buffers for test: %s\n",
113 test_case_name);
114 setup_ok = 0;
115 goto fail;
116 }
117
118 /*
119 * Clear the memory for the return buffer, since this isn't automatically
120 * zeroed in opt mode and will cause spurious test failures that will
121 * change with each execution.
122 */
123 memset(fixture.s->rlayer.wbuf.buf, 0, fixture.s->rlayer.wbuf.len);
124
125 fail:
126 if (!setup_ok) {
127 ERR_print_errors_fp(stderr);
128 exit(EXIT_FAILURE);
129 }
130 return fixture;
131 }
132
133 static HEARTBEAT_TEST_FIXTURE set_up_dtls(const char *const test_case_name)
134 {
135 HEARTBEAT_TEST_FIXTURE fixture = set_up(test_case_name,
136 DTLS_server_method());
137 fixture.process_heartbeat = dtls1_process_heartbeat;
138
139 /*
140 * As per dtls1_get_record(), skipping the following from the beginning
141 * of the returned heartbeat message: type-1 byte; version-2 bytes;
142 * sequence number-8 bytes; length-2 bytes And then skipping the 1-byte
143 * type encoded by process_heartbeat for a total of 14 bytes, at which
144 * point we can grab the length and the payload we seek.
145 */
146 fixture.return_payload_offset = 14;
147 return fixture;
148 }
149
150 /* Needed by ssl3_write_bytes() */
151 static int dummy_handshake(SSL *s)
152 {
153 return 1;
154 }
155
156 static void tear_down(HEARTBEAT_TEST_FIXTURE fixture)
157 {
158 ERR_print_errors_fp(stderr);
159 SSL_free(fixture.s);
160 SSL_CTX_free(fixture.ctx);
161 }
162
163 static void print_payload(const char *const prefix,
164 const unsigned char *payload, const int n)
165 {
166 const int end = n < MAX_PRINTABLE_CHARACTERS ? n
167 : MAX_PRINTABLE_CHARACTERS;
168 int i = 0;
169
170 printf("%s %d character%s", prefix, n, n == 1 ? "" : "s");
171 if (end != n)
172 printf(" (first %d shown)", end);
173 printf("\n \"");
174
175 for (; i != end; ++i) {
176 const unsigned char c = payload[i];
177 if (isprint(c))
178 fputc(c, stdout);
179 else
180 printf("\\x%02x", c);
181 }
182 printf("\"\n");
183 }
184
185 static int execute_heartbeat(HEARTBEAT_TEST_FIXTURE fixture)
186 {
187 int result = 0;
188 SSL *s = fixture.s;
189 unsigned char *payload = fixture.payload;
190 unsigned char sent_buf[MAX_PRINTABLE_CHARACTERS + 1];
191 int return_value;
192 unsigned const char *p;
193 int actual_payload_len;
194
195 s->rlayer.rrec.data = payload;
196 s->rlayer.rrec.length = strlen((const char *)payload);
197 *payload++ = TLS1_HB_REQUEST;
198 s2n(fixture.sent_payload_len, payload);
199
200 /*
201 * Make a local copy of the request, since it gets overwritten at some
202 * point
203 */
204 memcpy(sent_buf, payload, sizeof(sent_buf));
205
206 return_value = fixture.process_heartbeat(s, s->rlayer.rrec.data,
207 s->rlayer.rrec.length);
208
209 if (return_value != fixture.expected_return_value) {
210 printf("%s failed: expected return value %d, received %d\n",
211 fixture.test_case_name, fixture.expected_return_value,
212 return_value);
213 result = 1;
214 }
215
216 /*
217 * If there is any byte alignment, it will be stored in wbuf.offset.
218 */
219 p = &(s->rlayer.
220 wbuf.buf[fixture.return_payload_offset + s->rlayer.wbuf.offset]);
221 actual_payload_len = 0;
222 n2s(p, actual_payload_len);
223
224 if (actual_payload_len != fixture.expected_payload_len) {
225 printf("%s failed:\n expected payload len: %d\n received: %d\n",
226 fixture.test_case_name, fixture.expected_payload_len,
227 actual_payload_len);
228 print_payload("sent", sent_buf, strlen((const char *)sent_buf));
229 print_payload("received", p, actual_payload_len);
230 result = 1;
231 } else {
232 char *actual_payload =
233 OPENSSL_strndup((const char *)p, actual_payload_len);
234 if (strcmp(actual_payload, fixture.expected_return_payload) != 0) {
235 printf
236 ("%s failed:\n expected payload: \"%s\"\n received: \"%s\"\n",
237 fixture.test_case_name, fixture.expected_return_payload,
238 actual_payload);
239 result = 1;
240 }
241 OPENSSL_free(actual_payload);
242 }
243
244 if (result != 0) {
245 printf("** %s failed **\n--------\n", fixture.test_case_name);
246 }
247 return result;
248 }
249
250 static int honest_payload_size(unsigned char payload_buf[])
251 {
252 /* Omit three-byte pad at the beginning for type and payload length */
253 return strlen((const char *)&payload_buf[3]) - MIN_PADDING_SIZE;
254 }
255
256 # define SETUP_HEARTBEAT_TEST_FIXTURE(type)\
257 SETUP_TEST_FIXTURE(HEARTBEAT_TEST_FIXTURE, set_up_##type)
258
259 # define EXECUTE_HEARTBEAT_TEST()\
260 EXECUTE_TEST(execute_heartbeat, tear_down)
261
262 static int test_dtls1_not_bleeding()
263 {
264 SETUP_HEARTBEAT_TEST_FIXTURE(dtls);
265 /* Three-byte pad at the beginning for type and payload length */
266 unsigned char payload_buf[MAX_PRINTABLE_CHARACTERS + 4] =
267 " Not bleeding, sixteen spaces of padding" " ";
268 const int payload_buf_len = honest_payload_size(payload_buf);
269
270 fixture.payload = &payload_buf[0];
271 fixture.sent_payload_len = payload_buf_len;
272 fixture.expected_return_value = 0;
273 fixture.expected_payload_len = payload_buf_len;
274 fixture.expected_return_payload =
275 "Not bleeding, sixteen spaces of padding";
276 EXECUTE_HEARTBEAT_TEST();
277 }
278
279 static int test_dtls1_not_bleeding_empty_payload()
280 {
281 int payload_buf_len;
282
283 SETUP_HEARTBEAT_TEST_FIXTURE(dtls);
284 /*
285 * Three-byte pad at the beginning for type and payload length, plus a
286 * NUL at the end
287 */
288 unsigned char payload_buf[4 + MAX_PRINTABLE_CHARACTERS];
289 memset(payload_buf, ' ', MIN_PADDING_SIZE + 3);
290 payload_buf[MIN_PADDING_SIZE + 3] = '\0';
291 payload_buf_len = honest_payload_size(payload_buf);
292
293 fixture.payload = &payload_buf[0];
294 fixture.sent_payload_len = payload_buf_len;
295 fixture.expected_return_value = 0;
296 fixture.expected_payload_len = payload_buf_len;
297 fixture.expected_return_payload = "";
298 EXECUTE_HEARTBEAT_TEST();
299 }
300
301 static int test_dtls1_heartbleed()
302 {
303 SETUP_HEARTBEAT_TEST_FIXTURE(dtls);
304 /* Three-byte pad at the beginning for type and payload length */
305 unsigned char payload_buf[4 + MAX_PRINTABLE_CHARACTERS] =
306 " HEARTBLEED ";
307
308 fixture.payload = &payload_buf[0];
309 fixture.sent_payload_len = MAX_PRINTABLE_CHARACTERS;
310 fixture.expected_return_value = 0;
311 fixture.expected_payload_len = 0;
312 fixture.expected_return_payload = "";
313 EXECUTE_HEARTBEAT_TEST();
314 }
315
316 static int test_dtls1_heartbleed_empty_payload()
317 {
318 SETUP_HEARTBEAT_TEST_FIXTURE(dtls);
319 /*
320 * Excluding the NUL at the end, one byte short of type + payload length
321 * + minimum padding
322 */
323 unsigned char payload_buf[MAX_PRINTABLE_CHARACTERS + 4];
324 memset(payload_buf, ' ', MIN_PADDING_SIZE + 2);
325 payload_buf[MIN_PADDING_SIZE + 2] = '\0';
326
327 fixture.payload = &payload_buf[0];
328 fixture.sent_payload_len = MAX_PRINTABLE_CHARACTERS;
329 fixture.expected_return_value = 0;
330 fixture.expected_payload_len = 0;
331 fixture.expected_return_payload = "";
332 EXECUTE_HEARTBEAT_TEST();
333 }
334
335 static int test_dtls1_heartbleed_excessive_plaintext_length()
336 {
337 SETUP_HEARTBEAT_TEST_FIXTURE(dtls);
338 /*
339 * Excluding the NUL at the end, one byte in excess of maximum allowed
340 * heartbeat message length
341 */
342 unsigned char payload_buf[SSL3_RT_MAX_PLAIN_LENGTH + 2];
343 memset(payload_buf, ' ', sizeof(payload_buf));
344 payload_buf[sizeof(payload_buf) - 1] = '\0';
345
346 fixture.payload = &payload_buf[0];
347 fixture.sent_payload_len = honest_payload_size(payload_buf);
348 fixture.expected_return_value = 0;
349 fixture.expected_payload_len = 0;
350 fixture.expected_return_payload = "";
351 EXECUTE_HEARTBEAT_TEST();
352 }
353
354 # undef EXECUTE_HEARTBEAT_TEST
355 # undef SETUP_HEARTBEAT_TEST_FIXTURE
356
357 int main(int argc, char *argv[])
358 {
359 int result = 0;
360
361 ADD_TEST(test_dtls1_not_bleeding);
362 ADD_TEST(test_dtls1_not_bleeding_empty_payload);
363 ADD_TEST(test_dtls1_heartbleed);
364 ADD_TEST(test_dtls1_heartbleed_empty_payload);
365 ADD_TEST(test_dtls1_heartbleed_excessive_plaintext_length);
366
367 result = run_tests(argv[0]);
368 ERR_print_errors_fp(stderr);
369 return result;
370 }
371
372 #else /* OPENSSL_NO_HEARTBEATS */
373
374 int main(int argc, char *argv[])
375 {
376 return EXIT_SUCCESS;
377 }
378 #endif /* OPENSSL_NO_HEARTBEATS */