From 13ab3e3ce1b2693c5adeef8bb98a4fd66cd51c33 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Thu, 26 Jun 2014 15:50:03 -0400 Subject: [PATCH] Remove heartbeat extension. Change-Id: I0273a31e49c5367b89b9899553e3ebe13ec50687 Reviewed-on: https://boringssl-review.googlesource.com/1050 Reviewed-by: Adam Langley --- ssl/CMakeLists.txt | 8 - ssl/d1_both.c | 161 --------------- ssl/d1_clnt.c | 13 -- ssl/d1_lib.c | 8 - ssl/d1_pkt.c | 13 -- ssl/d1_srvr.c | 13 -- ssl/heartbeat_test.c | 461 ------------------------------------------- ssl/s3_clnt.c | 12 -- ssl/s3_lib.c | 21 -- ssl/s3_pkt.c | 13 -- ssl/s3_srvr.c | 12 -- ssl/ssl.h | 20 -- ssl/ssl3.h | 4 - ssl/ssl_error.c | 2 - ssl/ssl_locl.h | 7 - ssl/t1_lib.c | 237 ---------------------- ssl/tls1.h | 12 +- util/all_tests.sh | 1 - 18 files changed, 1 insertion(+), 1017 deletions(-) delete mode 100644 ssl/heartbeat_test.c diff --git a/ssl/CMakeLists.txt b/ssl/CMakeLists.txt index 4c515285e..3e613b46b 100644 --- a/ssl/CMakeLists.txt +++ b/ssl/CMakeLists.txt @@ -44,11 +44,3 @@ add_library( $ ) - -add_executable( - heartbeat_test - - heartbeat_test.c -) - -target_link_libraries(heartbeat_test ssl crypto) diff --git a/ssl/d1_both.c b/ssl/d1_both.c index 69d77fbfc..4e854a20e 100644 --- a/ssl/d1_both.c +++ b/ssl/d1_both.c @@ -974,11 +974,7 @@ int dtls1_read_failed(SSL *s, int code) return code; } -#ifndef OPENSSL_NO_HEARTBEATS - if (!SSL_in_init(s) && !s->tlsext_hb_pending) /* done, no need to send a retransmit */ -#else if (!SSL_in_init(s)) /* done, no need to send a retransmit */ -#endif { BIO_set_flags(SSL_get_rbio(s), BIO_FLAGS_READ); return code; @@ -1316,160 +1312,3 @@ int dtls1_shutdown(SSL *s) ret = ssl3_shutdown(s); return ret; } - -#ifndef OPENSSL_NO_HEARTBEATS -int -dtls1_process_heartbeat(SSL *s) - { - unsigned char *p = &s->s3->rrec.data[0], *pl; - unsigned short hbtype; - unsigned int payload; - unsigned int padding = 16; /* Use minimum padding */ - - if (s->msg_callback) - s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT, - &s->s3->rrec.data[0], s->s3->rrec.length, - s, s->msg_callback_arg); - - /* Read type and payload length first */ - if (1 + 2 + 16 > s->s3->rrec.length) - return 0; /* silently discard */ - hbtype = *p++; - n2s(p, payload); - if (1 + 2 + payload + 16 > s->s3->rrec.length) - return 0; /* silently discard per RFC 6520 sec. 4 */ - pl = p; - - if (hbtype == TLS1_HB_REQUEST) - { - unsigned char *buffer, *bp; - unsigned int write_length = 1 /* heartbeat type */ + - 2 /* heartbeat length */ + - payload + padding; - int r; - - if (write_length > SSL3_RT_MAX_PLAIN_LENGTH) - return 0; - - /* Allocate memory for the response, size is 1 byte - * message type, plus 2 bytes payload length, plus - * payload, plus padding - */ - buffer = OPENSSL_malloc(write_length); - bp = buffer; - - /* Enter response type, length and copy payload */ - *bp++ = TLS1_HB_RESPONSE; - s2n(payload, bp); - memcpy(bp, pl, payload); - bp += payload; - /* Random padding */ - RAND_pseudo_bytes(bp, padding); - - r = dtls1_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, write_length); - - if (r >= 0 && s->msg_callback) - s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT, - buffer, write_length, - s, s->msg_callback_arg); - - OPENSSL_free(buffer); - - if (r < 0) - return r; - } - else if (hbtype == TLS1_HB_RESPONSE) - { - unsigned int seq; - - /* We only send sequence numbers (2 bytes unsigned int), - * and 16 random bytes, so we just try to read the - * sequence number */ - n2s(pl, seq); - - if (payload == 18 && seq == s->tlsext_hb_seq) - { - dtls1_stop_timer(s); - s->tlsext_hb_seq++; - s->tlsext_hb_pending = 0; - } - } - - return 0; - } - -int -dtls1_heartbeat(SSL *s) - { - unsigned char *buf, *p; - int ret; - unsigned int payload = 18; /* Sequence number + random bytes */ - unsigned int padding = 16; /* Use minimum padding */ - - /* Only send if peer supports and accepts HB requests... */ - if (!(s->tlsext_heartbeat & SSL_TLSEXT_HB_ENABLED) || - s->tlsext_heartbeat & SSL_TLSEXT_HB_DONT_SEND_REQUESTS) - { - OPENSSL_PUT_ERROR(SSL, dtls1_heartbeat, SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT); - return -1; - } - - /* ...and there is none in flight yet... */ - if (s->tlsext_hb_pending) - { - OPENSSL_PUT_ERROR(SSL, dtls1_heartbeat, SSL_R_TLS_HEARTBEAT_PENDING); - return -1; - } - - /* ...and no handshake in progress. */ - if (SSL_in_init(s) || s->in_handshake) - { - OPENSSL_PUT_ERROR(SSL, dtls1_heartbeat, SSL_R_UNEXPECTED_MESSAGE); - return -1; - } - - /* Check if padding is too long, payload and padding - * must not exceed 2^14 - 3 = 16381 bytes in total. - */ - assert(payload + padding <= 16381); - - /* Create HeartBeat message, we just use a sequence number - * as payload to distuingish different messages and add - * some random stuff. - * - Message Type, 1 byte - * - Payload Length, 2 bytes (unsigned int) - * - Payload, the sequence number (2 bytes uint) - * - Payload, random bytes (16 bytes uint) - * - Padding - */ - buf = OPENSSL_malloc(1 + 2 + payload + padding); - p = buf; - /* Message Type */ - *p++ = TLS1_HB_REQUEST; - /* Payload length (18 bytes here) */ - s2n(payload, p); - /* Sequence number */ - s2n(s->tlsext_hb_seq, p); - /* 16 random bytes */ - RAND_pseudo_bytes(p, 16); - p += 16; - /* Random padding */ - RAND_pseudo_bytes(p, padding); - - ret = dtls1_write_bytes(s, TLS1_RT_HEARTBEAT, buf, 3 + payload + padding); - if (ret >= 0) - { - if (s->msg_callback) - s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT, - buf, 3 + payload + padding, - s, s->msg_callback_arg); - - dtls1_start_timer(s); - s->tlsext_hb_pending = 1; - } - - OPENSSL_free(buf); - - return ret; - } -#endif diff --git a/ssl/d1_clnt.c b/ssl/d1_clnt.c index be862a5e5..1fbd70bf0 100644 --- a/ssl/d1_clnt.c +++ b/ssl/d1_clnt.c @@ -177,19 +177,6 @@ int dtls1_connect(SSL *s) s->in_handshake++; if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s); -#ifndef OPENSSL_NO_HEARTBEATS - /* If we're awaiting a HeartbeatResponse, pretend we - * already got and don't await it anymore, because - * Heartbeats don't make sense during handshakes anyway. - */ - if (s->tlsext_hb_pending) - { - dtls1_stop_timer(s); - s->tlsext_hb_pending = 0; - s->tlsext_hb_seq++; - } -#endif - for (;;) { state=s->state; diff --git a/ssl/d1_lib.c b/ssl/d1_lib.c index d039346b4..fbfdca750 100644 --- a/ssl/d1_lib.c +++ b/ssl/d1_lib.c @@ -464,14 +464,6 @@ int dtls1_handle_timeout(SSL *s) s->d1->timeout.read_timeouts = 1; } -#ifndef OPENSSL_NO_HEARTBEATS - if (s->tlsext_hb_pending) - { - s->tlsext_hb_pending = 0; - return dtls1_heartbeat(s); - } -#endif - dtls1_start_timer(s); return dtls1_retransmit_buffered_messages(s); } diff --git a/ssl/d1_pkt.c b/ssl/d1_pkt.c index f987bd7a5..8b44c21a7 100644 --- a/ssl/d1_pkt.c +++ b/ssl/d1_pkt.c @@ -889,19 +889,6 @@ start: dest = s->d1->alert_fragment; dest_len = &s->d1->alert_fragment_len; } -#ifndef OPENSSL_NO_HEARTBEATS - else if (rr->type == TLS1_RT_HEARTBEAT) - { - dtls1_process_heartbeat(s); - - /* Exit and notify application to read again */ - rr->length = 0; - s->rwstate=SSL_READING; - BIO_clear_retry_flags(SSL_get_rbio(s)); - BIO_set_retry_read(SSL_get_rbio(s)); - return(-1); - } -#endif /* else it's a CCS message, or application data or wrong */ else if (rr->type != SSL3_RT_CHANGE_CIPHER_SPEC) { diff --git a/ssl/d1_srvr.c b/ssl/d1_srvr.c index 7e155e951..2eba38dd8 100644 --- a/ssl/d1_srvr.c +++ b/ssl/d1_srvr.c @@ -190,19 +190,6 @@ int dtls1_accept(SSL *s) return(-1); } -#ifndef OPENSSL_NO_HEARTBEATS - /* If we're awaiting a HeartbeatResponse, pretend we - * already got and don't await it anymore, because - * Heartbeats don't make sense during handshakes anyway. - */ - if (s->tlsext_hb_pending) - { - dtls1_stop_timer(s); - s->tlsext_hb_pending = 0; - s->tlsext_hb_seq++; - } -#endif - for (;;) { state=s->state; diff --git a/ssl/heartbeat_test.c b/ssl/heartbeat_test.c deleted file mode 100644 index f3595899b..000000000 --- a/ssl/heartbeat_test.c +++ /dev/null @@ -1,461 +0,0 @@ -/* test/heartbeat_test.c */ -/* - * Unit test for TLS heartbeats. - * - * Acts as a regression test against the Heartbleed bug (CVE-2014-0160). - * - * Author: Mike Bland (mbland@acm.org, http://mike-bland.com/) - * Date: 2014-04-12 - * License: Creative Commons Attribution 4.0 International (CC By 4.0) - * http://creativecommons.org/licenses/by/4.0/deed.en_US - * - * OUTPUT - * ------ - * The program returns zero on success. It will print a message with a count - * of the number of failed tests and return nonzero if any tests fail. - * - * It will print the contents of the request and response buffers for each - * failing test. In a "fixed" version, all the tests should pass and there - * should be no output. - * - * In a "bleeding" version, you'll see: - * - * test_dtls1_heartbleed failed: - * expected payload len: 0 - * received: 1024 - * sent 26 characters - * "HEARTBLEED " - * received 1024 characters - * "HEARTBLEED \xde\xad\xbe\xef..." - * ** test_dtls1_heartbleed failed ** - * - * The contents of the returned buffer in the failing test will depend on the - * contents of memory on your machine. - * - * MORE INFORMATION - * ---------------- - * http://mike-bland.com/2014/04/12/heartbleed.html - * http://mike-bland.com/tags/heartbleed.html - */ - -#include -#include -#include -#include - -#include -#include -#include -#include "../ssl/ssl_locl.h" - -/* As per https://tools.ietf.org/html/rfc6520#section-4 */ -#define MIN_PADDING_SIZE 16 - -/* Maximum number of payload characters to print as test output */ -#define MAX_PRINTABLE_CHARACTERS 1024 - -typedef struct heartbeat_test_fixture - { - SSL_CTX *ctx; - SSL *s; - const char* test_case_name; - int (*process_heartbeat)(SSL* s); - unsigned char* payload; - int sent_payload_len; - int expected_return_value; - int return_payload_offset; - int expected_payload_len; - const char* expected_return_payload; - } HEARTBEAT_TEST_FIXTURE; - -static HEARTBEAT_TEST_FIXTURE set_up(const char* const test_case_name, - const SSL_METHOD* meth) - { - HEARTBEAT_TEST_FIXTURE fixture; - int setup_ok = 1; - memset(&fixture, 0, sizeof(fixture)); - fixture.test_case_name = test_case_name; - - fixture.ctx = SSL_CTX_new(meth); - if (!fixture.ctx) - { - fprintf(stderr, "Failed to allocate SSL_CTX for test: %s\n", - test_case_name); - setup_ok = 0; - goto fail; - } - - fixture.s = SSL_new(fixture.ctx); - if (!fixture.s) - { - fprintf(stderr, "Failed to allocate SSL for test: %s\n", test_case_name); - setup_ok = 0; - goto fail; - } - - if (!ssl_init_wbio_buffer(fixture.s, 1)) - { - fprintf(stderr, "Failed to set up wbio buffer for test: %s\n", - test_case_name); - setup_ok = 0; - goto fail; - } - - if (!ssl3_setup_buffers(fixture.s)) - { - fprintf(stderr, "Failed to setup buffers for test: %s\n", - test_case_name); - setup_ok = 0; - goto fail; - } - - /* Clear the memory for the return buffer, since this isn't automatically - * zeroed in opt mode and will cause spurious test failures that will change - * with each execution. - */ - memset(fixture.s->s3->wbuf.buf, 0, fixture.s->s3->wbuf.len); - - fail: - if (!setup_ok) - { - BIO_print_errors_fp(stderr); - exit(EXIT_FAILURE); - } - return fixture; - } - -static HEARTBEAT_TEST_FIXTURE set_up_dtls(const char* const test_case_name) - { - HEARTBEAT_TEST_FIXTURE fixture = set_up(test_case_name, - DTLSv1_server_method()); - fixture.process_heartbeat = dtls1_process_heartbeat; - - /* As per dtls1_get_record(), skipping the following from the beginning of - * the returned heartbeat message: - * type-1 byte; version-2 bytes; sequence number-8 bytes; length-2 bytes - * - * And then skipping the 1-byte type encoded by process_heartbeat for - * a total of 14 bytes, at which point we can grab the length and the - * payload we seek. - */ - fixture.return_payload_offset = 14; - return fixture; - } - -/* Needed by ssl3_write_bytes() */ -static int dummy_handshake(SSL* s) - { - return 1; - } - -static HEARTBEAT_TEST_FIXTURE set_up_tls(const char* const test_case_name) - { - HEARTBEAT_TEST_FIXTURE fixture = set_up(test_case_name, - TLSv1_server_method()); - fixture.process_heartbeat = tls1_process_heartbeat; - fixture.s->handshake_func = dummy_handshake; - - /* As per do_ssl3_write(), skipping the following from the beginning of - * the returned heartbeat message: - * type-1 byte; version-2 bytes; length-2 bytes - * - * And then skipping the 1-byte type encoded by process_heartbeat for - * a total of 6 bytes, at which point we can grab the length and the payload - * we seek. - */ - fixture.return_payload_offset = 6; - return fixture; - } - -static void tear_down(HEARTBEAT_TEST_FIXTURE fixture) - { - BIO_print_errors_fp(stderr); - SSL_free(fixture.s); - SSL_CTX_free(fixture.ctx); - } - -static void print_payload(const char* const prefix, - const unsigned char *payload, const int n) - { - const int end = n < MAX_PRINTABLE_CHARACTERS ? n - : MAX_PRINTABLE_CHARACTERS; - int i = 0; - - printf("%s %d character%s", prefix, n, n == 1 ? "" : "s"); - if (end != n) printf(" (first %d shown)", end); - printf("\n \""); - - for (; i != end; ++i) - { - const unsigned char c = payload[i]; - if (isprint(c)) fputc(c, stdout); - else printf("\\x%02x", c); - } - printf("\"\n"); - } - -static int execute_heartbeat(HEARTBEAT_TEST_FIXTURE fixture) - { - int result = 0; - SSL* s = fixture.s; - unsigned char *payload = fixture.payload; - unsigned char sent_buf[MAX_PRINTABLE_CHARACTERS + 1]; - int return_value; - unsigned const char *p; - int actual_payload_len; - - s->s3->rrec.data = payload; - s->s3->rrec.length = strlen((const char*)payload); - *payload++ = TLS1_HB_REQUEST; - s2n(fixture.sent_payload_len, payload); - - /* Make a local copy of the request, since it gets overwritten at some - * point */ - memcpy((char *)sent_buf, (const char*)payload, sizeof(sent_buf)); - - return_value = fixture.process_heartbeat(s); - - if (return_value != fixture.expected_return_value) - { - printf("%s failed: expected return value %d, received %d\n", - fixture.test_case_name, fixture.expected_return_value, - return_value); - result = 1; - } - - /* If there is any byte alignment, it will be stored in wbuf.offset. */ - p = &(s->s3->wbuf.buf[ - fixture.return_payload_offset + s->s3->wbuf.offset]); - actual_payload_len = 0; - n2s(p, actual_payload_len); - - if (actual_payload_len != fixture.expected_payload_len) - { - printf("%s failed:\n expected payload len: %d\n received: %d\n", - fixture.test_case_name, fixture.expected_payload_len, - actual_payload_len); - print_payload("sent", sent_buf, strlen((const char*)sent_buf)); - print_payload("received", p, actual_payload_len); - result = 1; - } - else - { - char* actual_payload = BUF_strndup((const char*)p, actual_payload_len); - if (strcmp(actual_payload, fixture.expected_return_payload) != 0) - { - printf("%s failed:\n expected payload: \"%s\"\n received: \"%s\"\n", - fixture.test_case_name, fixture.expected_return_payload, - actual_payload); - result = 1; - } - OPENSSL_free(actual_payload); - } - - if (result != 0) - { - printf("** %s failed **\n--------\n", fixture.test_case_name); - } - return result; - } - -static int honest_payload_size(unsigned char payload_buf[]) - { - /* Omit three-byte pad at the beginning for type and payload length */ - return strlen((const char*)&payload_buf[3]) - MIN_PADDING_SIZE; - } - -#define SETUP_HEARTBEAT_TEST_FIXTURE(type)\ - HEARTBEAT_TEST_FIXTURE fixture = set_up_##type(__func__);\ - int result = 0 - -#define EXECUTE_HEARTBEAT_TEST()\ - if (execute_heartbeat(fixture) != 0) result = 1;\ - tear_down(fixture);\ - return result - -static int test_dtls1_not_bleeding() - { - SETUP_HEARTBEAT_TEST_FIXTURE(dtls); - /* Three-byte pad at the beginning for type and payload length */ - unsigned char payload_buf[] = " Not bleeding, sixteen spaces of padding" - " "; - const int payload_buf_len = honest_payload_size(payload_buf); - - fixture.payload = &payload_buf[0]; - fixture.sent_payload_len = payload_buf_len; - fixture.expected_return_value = 0; - fixture.expected_payload_len = payload_buf_len; - fixture.expected_return_payload = "Not bleeding, sixteen spaces of padding"; - EXECUTE_HEARTBEAT_TEST(); - } - -static int test_dtls1_not_bleeding_empty_payload() - { - int payload_buf_len; - - SETUP_HEARTBEAT_TEST_FIXTURE(dtls); - /* Three-byte pad at the beginning for type and payload length, plus a NUL - * at the end */ - unsigned char payload_buf[4 + MIN_PADDING_SIZE]; - memset(payload_buf, ' ', sizeof(payload_buf)); - payload_buf[sizeof(payload_buf) - 1] = '\0'; - payload_buf_len = honest_payload_size(payload_buf); - - fixture.payload = &payload_buf[0]; - fixture.sent_payload_len = payload_buf_len; - fixture.expected_return_value = 0; - fixture.expected_payload_len = payload_buf_len; - fixture.expected_return_payload = ""; - EXECUTE_HEARTBEAT_TEST(); - } - -static int test_dtls1_heartbleed() - { - SETUP_HEARTBEAT_TEST_FIXTURE(dtls); - /* Three-byte pad at the beginning for type and payload length */ - unsigned char payload_buf[] = " HEARTBLEED "; - - fixture.payload = &payload_buf[0]; - fixture.sent_payload_len = MAX_PRINTABLE_CHARACTERS; - fixture.expected_return_value = 0; - fixture.expected_payload_len = 0; - fixture.expected_return_payload = ""; - EXECUTE_HEARTBEAT_TEST(); - } - -static int test_dtls1_heartbleed_empty_payload() - { - SETUP_HEARTBEAT_TEST_FIXTURE(dtls); - /* Excluding the NUL at the end, one byte short of type + payload length + - * minimum padding */ - unsigned char payload_buf[MIN_PADDING_SIZE + 3]; - memset(payload_buf, ' ', sizeof(payload_buf)); - payload_buf[sizeof(payload_buf) - 1] = '\0'; - - fixture.payload = &payload_buf[0]; - fixture.sent_payload_len = MAX_PRINTABLE_CHARACTERS; - fixture.expected_return_value = 0; - fixture.expected_payload_len = 0; - fixture.expected_return_payload = ""; - EXECUTE_HEARTBEAT_TEST(); - } - -static int test_dtls1_heartbleed_excessive_plaintext_length() - { - SETUP_HEARTBEAT_TEST_FIXTURE(dtls); - /* Excluding the NUL at the end, one byte in excess of maximum allowed - * heartbeat message length */ - unsigned char payload_buf[SSL3_RT_MAX_PLAIN_LENGTH + 2]; - memset(payload_buf, ' ', sizeof(payload_buf)); - payload_buf[sizeof(payload_buf) - 1] = '\0'; - - fixture.payload = &payload_buf[0]; - fixture.sent_payload_len = honest_payload_size(payload_buf); - fixture.expected_return_value = 0; - fixture.expected_payload_len = 0; - fixture.expected_return_payload = ""; - EXECUTE_HEARTBEAT_TEST(); - } - -static int test_tls1_not_bleeding() - { - SETUP_HEARTBEAT_TEST_FIXTURE(tls); - /* Three-byte pad at the beginning for type and payload length */ - unsigned char payload_buf[] = " Not bleeding, sixteen spaces of padding" - " "; - const int payload_buf_len = honest_payload_size(payload_buf); - - fixture.payload = &payload_buf[0]; - fixture.sent_payload_len = payload_buf_len; - fixture.expected_return_value = 0; - fixture.expected_payload_len = payload_buf_len; - fixture.expected_return_payload = "Not bleeding, sixteen spaces of padding"; - EXECUTE_HEARTBEAT_TEST(); - } - -static int test_tls1_not_bleeding_empty_payload() - { - int payload_buf_len; - - SETUP_HEARTBEAT_TEST_FIXTURE(tls); - /* Three-byte pad at the beginning for type and payload length, plus a NUL - * at the end */ - unsigned char payload_buf[4 + MIN_PADDING_SIZE]; - memset(payload_buf, ' ', sizeof(payload_buf)); - payload_buf[sizeof(payload_buf) - 1] = '\0'; - payload_buf_len = honest_payload_size(payload_buf); - - fixture.payload = &payload_buf[0]; - fixture.sent_payload_len = payload_buf_len; - fixture.expected_return_value = 0; - fixture.expected_payload_len = payload_buf_len; - fixture.expected_return_payload = ""; - EXECUTE_HEARTBEAT_TEST(); - } - -static int test_tls1_heartbleed() - { - SETUP_HEARTBEAT_TEST_FIXTURE(tls); - /* Three-byte pad at the beginning for type and payload length */ - unsigned char payload_buf[] = " HEARTBLEED "; - - fixture.payload = &payload_buf[0]; - fixture.sent_payload_len = MAX_PRINTABLE_CHARACTERS; - fixture.expected_return_value = 0; - fixture.expected_payload_len = 0; - fixture.expected_return_payload = ""; - EXECUTE_HEARTBEAT_TEST(); - } - -static int test_tls1_heartbleed_empty_payload() - { - SETUP_HEARTBEAT_TEST_FIXTURE(tls); - /* Excluding the NUL at the end, one byte short of type + payload length + - * minimum padding */ - unsigned char payload_buf[MIN_PADDING_SIZE + 3]; - memset(payload_buf, ' ', sizeof(payload_buf)); - payload_buf[sizeof(payload_buf) - 1] = '\0'; - - fixture.payload = &payload_buf[0]; - fixture.sent_payload_len = MAX_PRINTABLE_CHARACTERS; - fixture.expected_return_value = 0; - fixture.expected_payload_len = 0; - fixture.expected_return_payload = ""; - EXECUTE_HEARTBEAT_TEST(); - } - -#undef EXECUTE_HEARTBEAT_TEST -#undef SETUP_HEARTBEAT_TEST_FIXTURE - -int main(int argc, char *argv[]) - { - int num_failed; - - SSL_library_init(); - SSL_load_error_strings(); - - num_failed = test_dtls1_not_bleeding() + - test_dtls1_not_bleeding_empty_payload() + - test_dtls1_heartbleed() + - test_dtls1_heartbleed_empty_payload() + - /* The following test causes an assertion failure at - * ssl/d1_pkt.c:dtls1_write_bytes() in versions prior to 1.0.1g: */ - (OPENSSL_VERSION_NUMBER >= 0x1000107fL ? - test_dtls1_heartbleed_excessive_plaintext_length() : 0) + - test_tls1_not_bleeding() + - test_tls1_not_bleeding_empty_payload() + - test_tls1_heartbleed() + - test_tls1_heartbleed_empty_payload() + - 0; - - BIO_print_errors_fp(stderr); - - if (num_failed != 0) - { - printf("%d test%s failed\n", num_failed, num_failed != 1 ? "s" : ""); - return EXIT_FAILURE; - } - - printf("PASS\n"); - return EXIT_SUCCESS; - } diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c index b32a6ffe3..3e522104f 100644 --- a/ssl/s3_clnt.c +++ b/ssl/s3_clnt.c @@ -198,18 +198,6 @@ int ssl3_connect(SSL *s) s->in_handshake++; if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s); -#ifndef OPENSSL_NO_HEARTBEATS - /* If we're awaiting a HeartbeatResponse, pretend we - * already got and don't await it anymore, because - * Heartbeats don't make sense during handshakes anyway. - */ - if (s->tlsext_hb_pending) - { - s->tlsext_hb_pending = 0; - s->tlsext_hb_seq++; - } -#endif - if (SSL_get_mode(s) & SSL_MODE_HANDSHAKE_CUTTHROUGH) { /* Send app data along with CCS/Finished */ diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c index 118d542f9..32a37f68c 100644 --- a/ssl/s3_lib.c +++ b/ssl/s3_lib.c @@ -3087,27 +3087,6 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg) ret = 1; break; -#ifndef OPENSSL_NO_HEARTBEATS - case SSL_CTRL_TLS_EXT_SEND_HEARTBEAT: - if (SSL_IS_DTLS(s)) - ret = dtls1_heartbeat(s); - else - ret = tls1_heartbeat(s); - break; - - case SSL_CTRL_GET_TLS_EXT_HEARTBEAT_PENDING: - ret = s->tlsext_hb_pending; - break; - - case SSL_CTRL_SET_TLS_EXT_HEARTBEAT_NO_REQUESTS: - if (larg) - s->tlsext_heartbeat |= SSL_TLSEXT_HB_DONT_RECV_REQUESTS; - else - s->tlsext_heartbeat &= ~SSL_TLSEXT_HB_DONT_RECV_REQUESTS; - ret = 1; - break; -#endif - #endif /* !OPENSSL_NO_TLSEXT */ case SSL_CTRL_CHAIN: diff --git a/ssl/s3_pkt.c b/ssl/s3_pkt.c index e144217fe..97530a3af 100644 --- a/ssl/s3_pkt.c +++ b/ssl/s3_pkt.c @@ -1076,19 +1076,6 @@ start: dest = s->s3->alert_fragment; dest_len = &s->s3->alert_fragment_len; } -#ifndef OPENSSL_NO_HEARTBEATS - else if (rr->type == TLS1_RT_HEARTBEAT) - { - tls1_process_heartbeat(s); - - /* Exit and notify application to read again */ - rr->length = 0; - s->rwstate=SSL_READING; - BIO_clear_retry_flags(SSL_get_rbio(s)); - BIO_set_retry_read(SSL_get_rbio(s)); - return(-1); - } -#endif if (dest_maxlen > 0) { diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c index 27ac813c9..95ed74d33 100644 --- a/ssl/s3_srvr.c +++ b/ssl/s3_srvr.c @@ -212,18 +212,6 @@ int ssl3_accept(SSL *s) return(-1); } -#ifndef OPENSSL_NO_HEARTBEATS - /* If we're awaiting a HeartbeatResponse, pretend we - * already got and don't await it anymore, because - * Heartbeats don't make sense during handshakes anyway. - */ - if (s->tlsext_hb_pending) - { - s->tlsext_hb_pending = 0; - s->tlsext_hb_seq++; - } -#endif - for (;;) { state=s->state; diff --git a/ssl/ssl.h b/ssl/ssl.h index 33c0d6a01..8d6f7f804 100644 --- a/ssl/ssl.h +++ b/ssl/ssl.h @@ -817,11 +817,6 @@ struct ssl_session_st #define SSL_get_secure_renegotiation_support(ssl) \ SSL_ctrl((SSL*) (ssl), SSL_CTRL_GET_RI_SUPPORT, 0, NULL) -#ifndef OPENSSL_NO_HEARTBEATS -#define SSL_heartbeat(ssl) \ - SSL_ctrl((ssl),SSL_CTRL_TLS_EXT_SEND_HEARTBEAT,0,NULL) -#endif - #define SSL_CTX_set_cert_flags(ctx,op) \ SSL_CTX_ctrl((ctx),SSL_CTRL_CERT_FLAGS,(op),NULL) #define SSL_set_cert_flags(s,op) \ @@ -1626,14 +1621,6 @@ struct ssl_st STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles; /* What we'll do */ SRTP_PROTECTION_PROFILE *srtp_profile; /* What's been chosen */ - unsigned int tlsext_heartbeat; /* Is use of the Heartbeat extension negotiated? - 0: disabled - 1: enabled - 2: enabled, but not allowed to send Requests - */ - unsigned int tlsext_hb_pending; /* Indicates if a HeartbeatRequest is in flight */ - unsigned int tlsext_hb_seq; /* HeartbeatRequest sequence number */ - /* Copied from the SSL_CTX. For a server, means that we'll accept * Channel IDs from clients. For a client, means that we'll advertise * support. */ @@ -1907,11 +1894,6 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION) #define SSL_CTRL_SET_TLS_EXT_SRP_USERNAME 79 #define SSL_CTRL_SET_TLS_EXT_SRP_STRENGTH 80 #define SSL_CTRL_SET_TLS_EXT_SRP_PASSWORD 81 -#ifndef OPENSSL_NO_HEARTBEATS -#define SSL_CTRL_TLS_EXT_SEND_HEARTBEAT 85 -#define SSL_CTRL_GET_TLS_EXT_HEARTBEAT_PENDING 86 -#define SSL_CTRL_SET_TLS_EXT_HEARTBEAT_NO_REQUESTS 87 -#endif /* Callback for verifying audit proofs (client only) */ #define SSL_CTRL_SET_TLSEXT_AUTHZ_SERVER_AUDIT_PROOF_CB 95 #define SSL_CTRL_SET_TLSEXT_AUTHZ_SERVER_AUDIT_PROOF_CB_ARG 96 @@ -2972,7 +2954,6 @@ void ERR_load_SSL_strings(void); #define SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER 309 #define SSL_R_RENEGOTIATION_ENCODING_ERR 310 #define SSL_R_NO_PRIVATEKEY 311 -#define SSL_R_TLS_HEARTBEAT_PENDING 312 #define SSL_R_READ_WRONG_PACKET_TYPE 313 #define SSL_R_SSL3_SESSION_ID_TOO_SHORT 314 #define SSL_R_UNABLE_TO_LOAD_SSL2_MD5_ROUTINES 315 @@ -3061,7 +3042,6 @@ void ERR_load_SSL_strings(void); #define SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER 398 #define SSL_R_CONNECTION_ID_IS_DIFFERENT 399 #define SSL_R_SSLV3_ALERT_NO_CERTIFICATE 400 -#define SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT 401 #define SSL_R_MISSING_VERIFY_MESSAGE 402 #define SSL_R_BAD_DSA_SIGNATURE 403 #define SSL_R_UNKNOWN_SSL_VERSION 404 diff --git a/ssl/ssl3.h b/ssl/ssl3.h index 336330806..2267eca18 100644 --- a/ssl/ssl3.h +++ b/ssl/ssl3.h @@ -320,7 +320,6 @@ extern "C" { #define SSL3_RT_ALERT 21 #define SSL3_RT_HANDSHAKE 22 #define SSL3_RT_APPLICATION_DATA 23 -#define TLS1_RT_HEARTBEAT 24 /* Pseudo content types to indicate additional parameters */ #define TLS1_RT_CRYPTO 0x1000 @@ -356,9 +355,6 @@ extern "C" { #define SSL3_AD_ILLEGAL_PARAMETER 47 /* fatal */ #define SSL3_AD_INAPPROPRIATE_FALLBACK 86 /* fatal */ -#define TLS1_HB_REQUEST 1 -#define TLS1_HB_RESPONSE 2 - #ifndef OPENSSL_NO_SSL_INTERN typedef struct ssl3_record_st diff --git a/ssl/ssl_error.c b/ssl/ssl_error.c index 712417213..0018d079d 100644 --- a/ssl/ssl_error.c +++ b/ssl/ssl_error.c @@ -478,8 +478,6 @@ const ERR_STRING_DATA SSL_error_string_data[] = { {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_UNRECOGNIZED_NAME), "TLSV1_UNRECOGNIZED_NAME"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_UNSUPPORTED_EXTENSION), "TLSV1_UNSUPPORTED_EXTENSION"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER), "TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT), "TLS_HEARTBEAT_PEER_DOESNT_ACCEPT"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_HEARTBEAT_PENDING), "TLS_HEARTBEAT_PENDING"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_ILLEGAL_EXPORTER_LABEL), "TLS_ILLEGAL_EXPORTER_LABEL"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST), "TLS_INVALID_ECPOINTFORMAT_LIST"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST), "TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST"}, diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 195e958fd..2dcff7587 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -1298,13 +1298,6 @@ int tls1_send_server_supplemental_data(SSL *s); /* client only */ int tls1_get_server_supplemental_data(SSL *s); -#ifndef OPENSSL_NO_HEARTBEATS -int tls1_heartbeat(SSL *s); -int dtls1_heartbeat(SSL *s); -int tls1_process_heartbeat(SSL *s); -int dtls1_process_heartbeat(SSL *s); -#endif - #ifdef OPENSSL_NO_SHA256 #define tlsext_tick_md EVP_sha1 #else diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index b3cb70b84..5e9992807 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -1460,22 +1460,6 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf, unsigned c } #endif -#ifndef OPENSSL_NO_HEARTBEATS - /* Add Heartbeat extension */ - if ((limit - ret - 4 - 1) < 0) - return NULL; - s2n(TLSEXT_TYPE_heartbeat,ret); - s2n(1,ret); - /* Set mode: - * 1: peer may send requests - * 2: peer not allowed to send requests - */ - if (s->tlsext_heartbeat & SSL_TLSEXT_HB_DONT_RECV_REQUESTS) - *(ret++) = SSL_TLSEXT_HB_DONT_SEND_REQUESTS; - else - *(ret++) = SSL_TLSEXT_HB_ENABLED; -#endif - #ifndef OPENSSL_NO_NEXTPROTONEG if (s->ctx->next_proto_select_cb && !s->s3->tmp.finish_md_len) { @@ -1807,26 +1791,6 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf, unsigned c ret+=el; } -#ifndef OPENSSL_NO_HEARTBEATS - /* Add Heartbeat extension if we've received one */ - if (s->tlsext_heartbeat & SSL_TLSEXT_HB_ENABLED) - { - if ((limit - ret - 4 - 1) < 0) - return NULL; - s2n(TLSEXT_TYPE_heartbeat,ret); - s2n(1,ret); - /* Set mode: - * 1: peer may send requests - * 2: peer not allowed to send requests - */ - if (s->tlsext_heartbeat & SSL_TLSEXT_HB_DONT_RECV_REQUESTS) - *(ret++) = SSL_TLSEXT_HB_DONT_SEND_REQUESTS; - else - *(ret++) = SSL_TLSEXT_HB_ENABLED; - - } -#endif - #ifndef OPENSSL_NO_NEXTPROTONEG next_proto_neg_seen = s->s3->next_proto_neg_seen; s->s3->next_proto_neg_seen = 0; @@ -2180,11 +2144,6 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char s->s3->alpn_selected = NULL; } -#ifndef OPENSSL_NO_HEARTBEATS - s->tlsext_heartbeat &= ~(SSL_TLSEXT_HB_ENABLED | - SSL_TLSEXT_HB_DONT_SEND_REQUESTS); -#endif - #ifndef OPENSSL_NO_EC if (s->options & SSL_OP_SAFARI_ECDHE_ECDSA_BUG) ssl_check_for_safari(s, data, d, n); @@ -2600,23 +2559,6 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char } #endif -#ifndef OPENSSL_NO_HEARTBEATS - else if (type == TLSEXT_TYPE_heartbeat) - { - switch(data[0]) - { - case 0x01: /* Client allows us to send HB requests */ - s->tlsext_heartbeat |= SSL_TLSEXT_HB_ENABLED; - break; - case 0x02: /* Client doesn't accept HB requests */ - s->tlsext_heartbeat |= SSL_TLSEXT_HB_ENABLED; - s->tlsext_heartbeat |= SSL_TLSEXT_HB_DONT_SEND_REQUESTS; - break; - default: *al = SSL_AD_ILLEGAL_PARAMETER; - return 0; - } - } -#endif #ifndef OPENSSL_NO_NEXTPROTONEG else if (type == TLSEXT_TYPE_next_proto_neg && s->s3->tmp.finish_md_len == 0 && @@ -2857,11 +2799,6 @@ static int ssl_scan_serverhello_tlsext(SSL *s, CBS *cbs, int *out_alert) s->s3->alpn_selected = NULL; } -#ifndef OPENSSL_NO_HEARTBEATS - s->tlsext_heartbeat &= ~(SSL_TLSEXT_HB_ENABLED | - SSL_TLSEXT_HB_DONT_SEND_REQUESTS); -#endif - /* There may be no extensions. */ if (CBS_len(cbs) == 0) { @@ -3081,30 +3018,6 @@ static int ssl_scan_serverhello_tlsext(SSL *s, CBS *cbs, int *out_alert) return 0; renegotiate_seen = 1; } -#ifndef OPENSSL_NO_HEARTBEATS - else if (type == TLSEXT_TYPE_heartbeat) - { - uint8_t heartbeat_mode; - if (!CBS_get_u8(&extension, &heartbeat_mode) || - CBS_len(&extension) != 0) - { - *alert = SSL_AD_DECODE_ERROR; - return 0; - } - switch (heartbeat_mode) - { - case 0x01: /* Server allows us to send HB requests */ - s->tlsext_heartbeat |= SSL_TLSEXT_HB_ENABLED; - break; - case 0x02: /* Server doesn't accept HB requests */ - s->tlsext_heartbeat |= SSL_TLSEXT_HB_ENABLED; - s->tlsext_heartbeat |= SSL_TLSEXT_HB_DONT_SEND_REQUESTS; - break; - default: *alert = SSL_AD_ILLEGAL_PARAMETER; - return 0; - } - } -#endif else if (type == TLSEXT_TYPE_use_srtp) { if (!ssl_parse_serverhello_use_srtp_ext(s, &extension, out_alert)) @@ -4132,156 +4045,6 @@ int SSL_get_shared_sigalgs(SSL *s, int idx, return s->cert->shared_sigalgslen; } - -#ifndef OPENSSL_NO_HEARTBEATS -int -tls1_process_heartbeat(SSL *s) - { - unsigned char *p = &s->s3->rrec.data[0], *pl; - unsigned short hbtype; - unsigned int payload; - unsigned int padding = 16; /* Use minimum padding */ - - if (s->msg_callback) - s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT, - &s->s3->rrec.data[0], s->s3->rrec.length, - s, s->msg_callback_arg); - - /* Read type and payload length first */ - if (1 + 2 + 16 > s->s3->rrec.length) - return 0; /* silently discard */ - hbtype = *p++; - n2s(p, payload); - if (1 + 2 + payload + 16 > s->s3->rrec.length) - return 0; /* silently discard per RFC 6520 sec. 4 */ - pl = p; - - if (hbtype == TLS1_HB_REQUEST) - { - unsigned char *buffer, *bp; - int r; - - /* Allocate memory for the response, size is 1 bytes - * message type, plus 2 bytes payload length, plus - * payload, plus padding - */ - buffer = OPENSSL_malloc(1 + 2 + payload + padding); - bp = buffer; - - /* Enter response type, length and copy payload */ - *bp++ = TLS1_HB_RESPONSE; - s2n(payload, bp); - memcpy(bp, pl, payload); - bp += payload; - /* Random padding */ - RAND_pseudo_bytes(bp, padding); - - r = ssl3_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, 3 + payload + padding); - - if (r >= 0 && s->msg_callback) - s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT, - buffer, 3 + payload + padding, - s, s->msg_callback_arg); - - OPENSSL_free(buffer); - - if (r < 0) - return r; - } - else if (hbtype == TLS1_HB_RESPONSE) - { - unsigned int seq; - - /* We only send sequence numbers (2 bytes unsigned int), - * and 16 random bytes, so we just try to read the - * sequence number */ - n2s(pl, seq); - - if (payload == 18 && seq == s->tlsext_hb_seq) - { - s->tlsext_hb_seq++; - s->tlsext_hb_pending = 0; - } - } - - return 0; - } - -int -tls1_heartbeat(SSL *s) - { - unsigned char *buf, *p; - int ret; - unsigned int payload = 18; /* Sequence number + random bytes */ - unsigned int padding = 16; /* Use minimum padding */ - - /* Only send if peer supports and accepts HB requests... */ - if (!(s->tlsext_heartbeat & SSL_TLSEXT_HB_ENABLED) || - s->tlsext_heartbeat & SSL_TLSEXT_HB_DONT_SEND_REQUESTS) - { - OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT); - return -1; - } - - /* ...and there is none in flight yet... */ - if (s->tlsext_hb_pending) - { - OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, SSL_R_TLS_HEARTBEAT_PENDING); - return -1; - } - - /* ...and no handshake in progress. */ - if (SSL_in_init(s) || s->in_handshake) - { - OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, SSL_R_UNEXPECTED_MESSAGE); - return -1; - } - - /* Check if padding is too long, payload and padding - * must not exceed 2^14 - 3 = 16381 bytes in total. - */ - assert(payload + padding <= 16381); - - /* Create HeartBeat message, we just use a sequence number - * as payload to distuingish different messages and add - * some random stuff. - * - Message Type, 1 byte - * - Payload Length, 2 bytes (unsigned int) - * - Payload, the sequence number (2 bytes uint) - * - Payload, random bytes (16 bytes uint) - * - Padding - */ - buf = OPENSSL_malloc(1 + 2 + payload + padding); - p = buf; - /* Message Type */ - *p++ = TLS1_HB_REQUEST; - /* Payload length (18 bytes here) */ - s2n(payload, p); - /* Sequence number */ - s2n(s->tlsext_hb_seq, p); - /* 16 random bytes */ - RAND_pseudo_bytes(p, 16); - p += 16; - /* Random padding */ - RAND_pseudo_bytes(p, padding); - - ret = ssl3_write_bytes(s, TLS1_RT_HEARTBEAT, buf, 3 + payload + padding); - if (ret >= 0) - { - if (s->msg_callback) - s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT, - buf, 3 + payload + padding, - s, s->msg_callback_arg); - - s->tlsext_hb_pending = 1; - } - - OPENSSL_free(buf); - - return ret; - } -#endif - #if !defined(OPENSSL_NO_TLSEXT) /* tls1_channel_id_hash calculates the signed data for a Channel ID on the given * SSL connection and writes it to |md|. */ diff --git a/ssl/tls1.h b/ssl/tls1.h index 4ef50b760..3afe454b0 100644 --- a/ssl/tls1.h +++ b/ssl/tls1.h @@ -408,17 +408,7 @@ SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_TLSEXT_AUTHZ_SERVER_AUDIT_PROOF_CB,(void #define SSL_CTX_set_tlsext_authz_server_audit_proof_cb_arg(ctx, arg) \ SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TLSEXT_AUTHZ_SERVER_AUDIT_PROOF_CB_ARG, 0, arg); -#ifndef OPENSSL_NO_HEARTBEATS -#define SSL_TLSEXT_HB_ENABLED 0x01 -#define SSL_TLSEXT_HB_DONT_SEND_REQUESTS 0x02 -#define SSL_TLSEXT_HB_DONT_RECV_REQUESTS 0x04 - -#define SSL_get_tlsext_heartbeat_pending(ssl) \ - SSL_ctrl((ssl),SSL_CTRL_GET_TLS_EXT_HEARTBEAT_PENDING,0,NULL) -#define SSL_set_tlsext_heartbeat_no_requests(ssl, arg) \ - SSL_ctrl((ssl),SSL_CTRL_SET_TLS_EXT_HEARTBEAT_NO_REQUESTS,arg,NULL) -#endif -#endif +#endif /* OPENSSL_NO_TLSEXT */ /* PSK ciphersuites from 4279 */ #define TLS1_CK_PSK_WITH_RC4_128_SHA 0x0300008A diff --git a/util/all_tests.sh b/util/all_tests.sh index 86ec2353d..1396c8d06 100644 --- a/util/all_tests.sh +++ b/util/all_tests.sh @@ -36,7 +36,6 @@ TESTS=" ./crypto/x509v3/tab_test ./crypto/x509v3/v3name_test ./crypto/bytestring/bytestring_test -./ssl/heartbeat_test " IFS=$'\n'