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