提交 e72040c1 编写于 作者: R Richard Levitte 提交者: Rich Salz

Remove heartbeat support

Reviewed-by: NRich Salz <rsalz@openssl.org>
Reviewed-by: NTim Hudson <tjh@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/1669)
上级 349d1cfd
......@@ -15,6 +15,9 @@
https://www.akkadia.org/drepper/SHA-crypt.txt
[Richard Levitte]
*) Heartbeat support has been removed; the ABI is changed for now.
[Richard Levitte, Rich Salz]
Changes between 1.1.0b and 1.1.0c [xx XXX xxxx]
*) ChaCha20/Poly1305 heap-buffer-overflow
......
......@@ -333,9 +333,6 @@
available if the GOST algorithms are also available through
loading an externally supplied engine.
enable-heartbeats
Build support for DTLS heartbeats.
no-hw-padlock
Don't build the padlock engine.
......
......@@ -378,12 +378,6 @@ int dtls1_handle_timeout(SSL *s)
if (s->d1->timeout.read_timeouts > DTLS1_TMO_READ_COUNT) {
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);
......@@ -859,168 +853,6 @@ static int dtls1_handshake_write(SSL *s)
return dtls1_do_write(s, SSL3_RT_HANDSHAKE);
}
#ifndef OPENSSL_NO_HEARTBEATS
# define HEARTBEAT_SIZE(payload, padding) ( \
1 /* heartbeat type */ + \
2 /* heartbeat length */ + \
(payload) + (padding))
# define HEARTBEAT_SIZE_STD(payload) HEARTBEAT_SIZE(payload, 16)
int dtls1_process_heartbeat(SSL *s, unsigned char *p, size_t length)
{
unsigned char *pl;
unsigned short hbtype;
unsigned int payload;
unsigned int padding = 16; /* Use minimum padding */
size_t written;
if (s->msg_callback)
s->msg_callback(0, s->version, DTLS1_RT_HEARTBEAT,
p, length, s, s->msg_callback_arg);
/* Read type and payload length */
if (HEARTBEAT_SIZE_STD(0) > length)
return 0; /* silently discard */
if (length > SSL3_RT_MAX_PLAIN_LENGTH)
return 0; /* silently discard per RFC 6520 sec. 4 */
hbtype = *p++;
n2s(p, payload);
if (HEARTBEAT_SIZE_STD(payload) > length)
return 0; /* silently discard per RFC 6520 sec. 4 */
pl = p;
if (hbtype == TLS1_HB_REQUEST) {
unsigned char *buffer, *bp;
size_t write_length = HEARTBEAT_SIZE(payload, padding);
int r;
if (write_length > SSL3_RT_MAX_PLAIN_LENGTH)
return 0;
/* Allocate memory for the response. */
buffer = OPENSSL_malloc(write_length);
if (buffer == NULL)
return -1;
bp = buffer;
/* Enter response type, length and copy payload */
*bp++ = TLS1_HB_RESPONSE;
s2n(payload, bp);
memcpy(bp, pl, payload);
bp += payload;
/* Random padding */
if (RAND_bytes(bp, padding) <= 0) {
OPENSSL_free(buffer);
return -1;
}
r = dtls1_write_bytes(s, DTLS1_RT_HEARTBEAT, buffer, write_length,
&written);
if (r > 0 && s->msg_callback)
s->msg_callback(1, s->version, DTLS1_RT_HEARTBEAT,
buffer, write_length, s, s->msg_callback_arg);
OPENSSL_free(buffer);
if (r <= 0)
return -1;
} 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 = -1;
size_t payload = 18; /* Sequence number + random bytes */
size_t padding = 16; /* Use minimum padding */
size_t size, written;
/* Only send if peer supports and accepts HB requests... */
if (!(s->tlsext_heartbeat & SSL_DTLSEXT_HB_ENABLED) ||
s->tlsext_heartbeat & SSL_DTLSEXT_HB_DONT_SEND_REQUESTS) {
SSLerr(SSL_F_DTLS1_HEARTBEAT, SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT);
return -1;
}
/* ...and there is none in flight yet... */
if (s->tlsext_hb_pending) {
SSLerr(SSL_F_DTLS1_HEARTBEAT, SSL_R_TLS_HEARTBEAT_PENDING);
return -1;
}
/* ...and no handshake in progress. */
if (SSL_in_init(s) || ossl_statem_get_in_handshake(s)) {
SSLerr(SSL_F_DTLS1_HEARTBEAT, SSL_R_UNEXPECTED_MESSAGE);
return -1;
}
/*-
* Create HeartBeat message, we just use a sequence number
* as payload to distinguish different messages and add
* some random stuff.
*/
size = HEARTBEAT_SIZE(payload, padding);
buf = OPENSSL_malloc(size);
if (buf == NULL) {
SSLerr(SSL_F_DTLS1_HEARTBEAT, ERR_R_MALLOC_FAILURE);
return -1;
}
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 */
if (RAND_bytes(p, 16) <= 0) {
SSLerr(SSL_F_DTLS1_HEARTBEAT, ERR_R_INTERNAL_ERROR);
goto err;
}
p += 16;
/* Random padding */
if (RAND_bytes(p, padding) <= 0) {
SSLerr(SSL_F_DTLS1_HEARTBEAT, ERR_R_INTERNAL_ERROR);
goto err;
}
ret = dtls1_write_bytes(s, DTLS1_RT_HEARTBEAT, buf, size, &written);
if (ret > 0) {
if (s->msg_callback)
s->msg_callback(1, s->version, DTLS1_RT_HEARTBEAT,
buf, size, s, s->msg_callback_arg);
dtls1_start_timer(s);
s->tlsext_hb_pending = 1;
}
err:
OPENSSL_free(buf);
return ret;
}
#endif
int dtls1_shutdown(SSL *s)
{
int ret;
......
......@@ -575,21 +575,6 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
dest = s->rlayer.d->alert_fragment;
dest_len = &s->rlayer.d->alert_fragment_len;
}
#ifndef OPENSSL_NO_HEARTBEATS
else if (SSL3_RECORD_get_type(rr) == DTLS1_RT_HEARTBEAT) {
/* We allow a 0 return */
if (dtls1_process_heartbeat(s, SSL3_RECORD_get_data(rr),
SSL3_RECORD_get_length(rr)) < 0) {
return -1;
}
/* Exit and notify application to read again */
SSL3_RECORD_set_length(rr, 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 (SSL3_RECORD_get_type(rr) != SSL3_RT_CHANGE_CIPHER_SPEC) {
/*
......
......@@ -3049,23 +3049,8 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
#ifndef OPENSSL_NO_HEARTBEATS
case SSL_CTRL_DTLS_EXT_SEND_HEARTBEAT:
if (SSL_IS_DTLS(s))
ret = dtls1_heartbeat(s);
break;
case SSL_CTRL_GET_DTLS_EXT_HEARTBEAT_PENDING:
if (SSL_IS_DTLS(s))
ret = s->tlsext_hb_pending;
break;
case SSL_CTRL_SET_DTLS_EXT_HEARTBEAT_NO_REQUESTS:
if (SSL_IS_DTLS(s)) {
if (larg)
s->tlsext_heartbeat |= SSL_DTLSEXT_HB_DONT_RECV_REQUESTS;
else
s->tlsext_heartbeat &= ~SSL_DTLSEXT_HB_DONT_RECV_REQUESTS;
ret = 1;
}
break;
#endif
......
......@@ -1107,17 +1107,6 @@ struct ssl_st {
STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles;
/* What's been chosen */
SRTP_PROTECTION_PROFILE *srtp_profile;
/*-
* Is use of the Heartbeat extension negotiated?
* 0: disabled
* 1: enabled
* 2: enabled, but not allowed to send Requests
*/
unsigned int tlsext_heartbeat;
/* Indicates if a HeartbeatRequest is in flight */
unsigned int tlsext_hb_pending;
/* HeartbeatRequest sequence number */
unsigned int tlsext_hb_seq;
/*
* For a client, this contains the list of supported protocols in wire
* format.
......@@ -1404,7 +1393,7 @@ typedef struct dtls1_state_st {
struct hm_header_st r_msg_hdr;
struct dtls1_timeout_st timeout;
/*
* Indicates when the last handshake msg or heartbeat sent will timeout
* Indicates when the last handshake msg sent will timeout
*/
struct timeval next_timeout;
/* Timeout duration */
......@@ -1813,10 +1802,6 @@ const SSL_METHOD *func_name(void) \
struct openssl_ssl_test_functions {
int (*p_ssl_init_wbio_buffer) (SSL *s);
int (*p_ssl3_setup_buffers) (SSL *s);
# ifndef OPENSSL_NO_HEARTBEATS
int (*p_dtls1_process_heartbeat) (SSL *s,
unsigned char *p, unsigned int length);
# endif
};
const char *ssl_protocol_to_string(int version);
......@@ -2074,13 +2059,6 @@ __owur int ssl_check_clienthello_tlsext_late(SSL *s, int *al);
__owur int ssl_parse_serverhello_tlsext(SSL *s, PACKET *pkt);
__owur int ssl_prepare_clienthello_tlsext(SSL *s);
__owur int ssl_prepare_serverhello_tlsext(SSL *s);
# ifndef OPENSSL_NO_HEARTBEATS
__owur int dtls1_heartbeat(SSL *s);
__owur int dtls1_process_heartbeat(SSL *s, unsigned char *p,
size_t length);
# endif
__owur RAW_EXTENSION *tls_get_extension_by_type(RAW_EXTENSION *exts,
size_t numexts,
unsigned int type);
......@@ -2178,7 +2156,6 @@ void ssl_comp_free_compression_methods_int(void);
# define ssl_init_wbio_buffer SSL_test_functions()->p_ssl_init_wbio_buffer
# define ssl3_setup_buffers SSL_test_functions()->p_ssl3_setup_buffers
# define dtls1_process_heartbeat SSL_test_functions()->p_dtls1_process_heartbeat
# endif
#endif
......@@ -14,10 +14,6 @@
static const struct openssl_ssl_test_functions ssl_test_functions = {
ssl_init_wbio_buffer,
ssl3_setup_buffers,
# ifndef OPENSSL_NO_HEARTBEATS
# undef dtls1_process_heartbeat
dtls1_process_heartbeat
# endif
};
const struct openssl_ssl_test_functions *SSL_test_functions(void)
......
......@@ -251,20 +251,6 @@ static int state_machine(SSL *s, int server)
}
#endif
#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) {
if (SSL_IS_DTLS(s))
dtls1_stop_timer(s);
s->tlsext_hb_pending = 0;
s->tlsext_hb_seq++;
}
#endif
/* Initialise state machine */
if (st->state == MSG_FLOW_RENEGOTIATE) {
......
......@@ -919,13 +919,8 @@ int dtls1_read_failed(SSL *s, int code)
*/
return code;
}
#ifndef OPENSSL_NO_HEARTBEATS
/* done, no need to send a retransmit */
if (!SSL_in_init(s) && !s->tlsext_hb_pending)
#else
/* done, no need to send a retransmit */
if (!SSL_in_init(s))
#endif
{
BIO_set_flags(SSL_get_rbio(s), BIO_FLAGS_READ);
return code;
......
......@@ -243,7 +243,6 @@ int SSL_extension_supported(unsigned int ext_type)
case TLSEXT_TYPE_application_layer_protocol_negotiation:
case TLSEXT_TYPE_ec_point_formats:
case TLSEXT_TYPE_supported_groups:
case TLSEXT_TYPE_heartbeat:
#ifndef OPENSSL_NO_NEXTPROTONEG
case TLSEXT_TYPE_next_proto_neg:
#endif
......
......@@ -1254,30 +1254,6 @@ int ssl_add_clienthello_tlsext(SSL *s, WPACKET *pkt, int *al)
}
}
#endif
#ifndef OPENSSL_NO_HEARTBEATS
if (SSL_IS_DTLS(s)) {
unsigned int mode;
/*-
* Set mode:
* 1: peer may send requests
* 2: peer not allowed to send requests
*/
if (s->tlsext_heartbeat & SSL_DTLSEXT_HB_DONT_RECV_REQUESTS)
mode = SSL_DTLSEXT_HB_DONT_SEND_REQUESTS;
else
mode = SSL_DTLSEXT_HB_ENABLED;
if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_heartbeat)
/* Sub-packet for Hearbeat extension */
|| !WPACKET_start_sub_packet_u16(pkt)
|| !WPACKET_put_bytes_u8(pkt, mode)
|| !WPACKET_close(pkt)) {
SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
return 0;
}
}
#endif
#ifndef OPENSSL_NO_NEXTPROTONEG
if (s->ctx->next_proto_select_cb && !s->s3->tmp.finish_md_len) {
......@@ -1555,30 +1531,6 @@ int ssl_add_serverhello_tlsext(SSL *s, WPACKET *pkt, int *al)
return 0;
}
}
#ifndef OPENSSL_NO_HEARTBEATS
/* Add Heartbeat extension if we've received one */
if (SSL_IS_DTLS(s) && (s->tlsext_heartbeat & SSL_DTLSEXT_HB_ENABLED)) {
unsigned int mode;
/*-
* Set mode:
* 1: peer may send requests
* 2: peer not allowed to send requests
*/
if (s->tlsext_heartbeat & SSL_DTLSEXT_HB_DONT_RECV_REQUESTS)
mode = SSL_DTLSEXT_HB_DONT_SEND_REQUESTS;
else
mode = SSL_DTLSEXT_HB_ENABLED;
if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_heartbeat)
|| !WPACKET_start_sub_packet_u16(pkt)
|| !WPACKET_put_bytes_u8(pkt, mode)
|| !WPACKET_close(pkt)) {
SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
return 0;
}
}
#endif
#ifndef OPENSSL_NO_NEXTPROTONEG
next_proto_neg_seen = s->s3->next_proto_neg_seen;
......@@ -1821,10 +1773,6 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CLIENTHELLO_MSG *hello, int *al)
OPENSSL_free(s->s3->alpn_proposed);
s->s3->alpn_proposed = NULL;
s->s3->alpn_proposed_len = 0;
#ifndef OPENSSL_NO_HEARTBEATS
s->tlsext_heartbeat &= ~(SSL_DTLSEXT_HB_ENABLED |
SSL_DTLSEXT_HB_DONT_SEND_REQUESTS);
#endif
#ifndef OPENSSL_NO_EC
if (s->options & SSL_OP_SAFARI_ECDHE_ECDSA_BUG)
......@@ -2116,29 +2064,6 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CLIENTHELLO_MSG *hello, int *al)
s->tlsext_status_type = -1;
}
}
#ifndef OPENSSL_NO_HEARTBEATS
else if (SSL_IS_DTLS(s) && currext->type == TLSEXT_TYPE_heartbeat) {
unsigned int hbtype;
if (!PACKET_get_1(&currext->data, &hbtype)
|| PACKET_remaining(&currext->data)) {
*al = SSL_AD_DECODE_ERROR;
return 0;
}
switch (hbtype) {
case 0x01: /* Client allows us to send HB requests */
s->tlsext_heartbeat |= SSL_DTLSEXT_HB_ENABLED;
break;
case 0x02: /* Client doesn't accept HB requests */
s->tlsext_heartbeat |= SSL_DTLSEXT_HB_ENABLED;
s->tlsext_heartbeat |= SSL_DTLSEXT_HB_DONT_SEND_REQUESTS;
break;
default:
*al = SSL_AD_ILLEGAL_PARAMETER;
return 0;
}
}
#endif
#ifndef OPENSSL_NO_NEXTPROTONEG
else if (currext->type == TLSEXT_TYPE_next_proto_neg
&& s->s3->tmp.finish_md_len == 0) {
......@@ -2270,10 +2195,6 @@ static int ssl_scan_serverhello_tlsext(SSL *s, PACKET *pkt, int *al)
OPENSSL_free(s->s3->alpn_selected);
s->s3->alpn_selected = NULL;
#ifndef OPENSSL_NO_HEARTBEATS
s->tlsext_heartbeat &= ~(SSL_DTLSEXT_HB_ENABLED |
SSL_DTLSEXT_HB_DONT_SEND_REQUESTS);
#endif
s->s3->flags &= ~TLS1_FLAGS_ENCRYPT_THEN_MAC;
......@@ -2463,27 +2384,6 @@ static int ssl_scan_serverhello_tlsext(SSL *s, PACKET *pkt, int *al)
}
s->s3->alpn_selected_len = len;
}
#ifndef OPENSSL_NO_HEARTBEATS
else if (SSL_IS_DTLS(s) && type == TLSEXT_TYPE_heartbeat) {
unsigned int hbtype;
if (!PACKET_get_1(&spkt, &hbtype)) {
*al = SSL_AD_DECODE_ERROR;
return 0;
}
switch (hbtype) {
case 0x01: /* Server allows us to send HB requests */
s->tlsext_heartbeat |= SSL_DTLSEXT_HB_ENABLED;
break;
case 0x02: /* Server doesn't accept HB requests */
s->tlsext_heartbeat |= SSL_DTLSEXT_HB_ENABLED;
s->tlsext_heartbeat |= SSL_DTLSEXT_HB_DONT_SEND_REQUESTS;
break;
default:
*al = SSL_AD_ILLEGAL_PARAMETER;
return 0;
}
}
#endif
#ifndef OPENSSL_NO_SRTP
else if (SSL_IS_DTLS(s) && type == TLSEXT_TYPE_use_srtp) {
if (ssl_parse_serverhello_use_srtp_ext(s, &spkt, al))
......
......@@ -74,7 +74,6 @@ static ssl_trace_tbl ssl_content_tbl[] = {
{SSL3_RT_ALERT, "Alert"},
{SSL3_RT_HANDSHAKE, "Handshake"},
{SSL3_RT_APPLICATION_DATA, "ApplicationData"},
{DTLS1_RT_HEARTBEAT, "HeartBeat"}
};
/* Handshake types */
......@@ -453,7 +452,6 @@ static ssl_trace_tbl ssl_exts_tbl[] = {
{TLSEXT_TYPE_srp, "srp"},
{TLSEXT_TYPE_signature_algorithms, "signature_algorithms"},
{TLSEXT_TYPE_use_srtp, "use_srtp"},
{TLSEXT_TYPE_heartbeat, "heartbeat"},
{TLSEXT_TYPE_session_ticket, "session_ticket"},
{TLSEXT_TYPE_supported_versions, "supported_versions"},
{TLSEXT_TYPE_renegotiate, "renegotiate"},
......@@ -534,11 +532,6 @@ static ssl_trace_tbl ssl_hb_tbl[] = {
{2, "peer_not_allowed_to_send"}
};
static ssl_trace_tbl ssl_hb_type_tbl[] = {
{1, "heartbeat_request"},
{2, "heartbeat_response"}
};
static ssl_trace_tbl ssl_ctype_tbl[] = {
{1, "rsa_sign"},
{2, "dss_sign"},
......@@ -718,12 +711,7 @@ static int ssl_print_extension(BIO *bio, int indent, int server, int extype,
break;
case TLSEXT_TYPE_heartbeat:
if (extlen != 1)
return 0;
BIO_indent(bio, indent + 2, 80);
BIO_printf(bio, "HeartbeatMode: %s\n",
ssl_trace_str(ext[0], ssl_hb_tbl));
break;
return 0;
case TLSEXT_TYPE_session_ticket:
if (extlen != 0)
......@@ -1270,22 +1258,6 @@ static int ssl_print_handshake(BIO *bio, SSL *ssl,
return 1;
}
static int ssl_print_heartbeat(BIO *bio, int indent,
const unsigned char *msg, size_t msglen)
{
if (msglen < 3)
return 0;
BIO_indent(bio, indent, 80);
BIO_printf(bio, "HeartBeatMessageType: %s\n",
ssl_trace_str(msg[0], ssl_hb_type_tbl));
msg++;
msglen--;
if (!ssl_print_hexbuf(bio, indent, "payload", 2, &msg, &msglen))
return 0;
ssl_print_hex(bio, indent, "padding", msg, msglen);
return 1;
}
const char *SSL_CIPHER_standard_name(const SSL_CIPHER *c)
{
return ssl_trace_str(c->id & 0xFFFF, ssl_ciphers_tbl);
......@@ -1343,9 +1315,6 @@ void SSL_trace(int write_p, int version, int content_type,
SSL_alert_type_string_long(msg[0] << 8),
msg[0], SSL_alert_desc_string_long(msg[1]), msg[1]);
}
case DTLS1_RT_HEARTBEAT:
ssl_print_heartbeat(bio, 4, msg, msglen);
break;
}
......
......@@ -19,7 +19,7 @@ IF[{- !$disabled{tests} -}]
randtest dhtest enginetest casttest \
bftest ssltest_old dsatest exptest rsa_test \
evp_test evp_extra_test igetest v3nametest v3ext \
danetest heartbeat_test p5_crpt2_test bad_dtls_test \
danetest p5_crpt2_test bad_dtls_test \
constant_time_test verify_extra_test clienthellotest \
packettest asynctest secmemtest srptest memleaktest \
dtlsv1listentest ct_test threadstest afalgtest d2i_test \
......@@ -178,10 +178,6 @@ IF[{- !$disabled{tests} -}]
INCLUDE[danetest]=../include
DEPEND[danetest]=../libcrypto ../libssl
SOURCE[heartbeat_test]=heartbeat_test.c testutil.c
INCLUDE[heartbeat_test]=.. ../include
DEPEND[heartbeat_test]=../libcrypto ../libssl
SOURCE[p5_crpt2_test]=p5_crpt2_test.c
INCLUDE[p5_crpt2_test]=../include
DEPEND[p5_crpt2_test]=../libcrypto
......
/*
* Copyright 2014-2016 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
/*-
* 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
*/
#define OPENSSL_UNIT_TEST
#include "../ssl/ssl_locl.h"
#include "testutil.h"
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if !defined(OPENSSL_NO_HEARTBEATS) && !defined(OPENSSL_NO_UNIT_TEST)
/* 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 *p, unsigned int length);
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)) {
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->rlayer.wbuf.buf, 0, fixture.s->rlayer.wbuf.len);
fail:
if (!setup_ok) {
ERR_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,
DTLS_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 void tear_down(HEARTBEAT_TEST_FIXTURE fixture)
{
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->rlayer.rrec.data = payload;
s->rlayer.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(sent_buf, payload, sizeof(sent_buf));
return_value = fixture.process_heartbeat(s, s->rlayer.rrec.data,
s->rlayer.rrec.length);
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->rlayer.
wbuf.buf[fixture.return_payload_offset + s->rlayer.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 =
OPENSSL_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)\
SETUP_TEST_FIXTURE(HEARTBEAT_TEST_FIXTURE, set_up_##type)
# define EXECUTE_HEARTBEAT_TEST()\
EXECUTE_TEST(execute_heartbeat, tear_down)
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[MAX_PRINTABLE_CHARACTERS + 4] =
" 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 + MAX_PRINTABLE_CHARACTERS];
memset(payload_buf, ' ', MIN_PADDING_SIZE + 3);
payload_buf[MIN_PADDING_SIZE + 3] = '\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[4 + MAX_PRINTABLE_CHARACTERS] =
" 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[MAX_PRINTABLE_CHARACTERS + 4];
memset(payload_buf, ' ', MIN_PADDING_SIZE + 2);
payload_buf[MIN_PADDING_SIZE + 2] = '\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();
}
# undef EXECUTE_HEARTBEAT_TEST
# undef SETUP_HEARTBEAT_TEST_FIXTURE
int main(int argc, char *argv[])
{
int result = 0;
ADD_TEST(test_dtls1_not_bleeding);
ADD_TEST(test_dtls1_not_bleeding_empty_payload);
ADD_TEST(test_dtls1_heartbleed);
ADD_TEST(test_dtls1_heartbleed_empty_payload);
ADD_TEST(test_dtls1_heartbleed_excessive_plaintext_length);
result = run_tests(argv[0]);
return result;
}
#else /* OPENSSL_NO_HEARTBEATS */
int main(int argc, char *argv[])
{
return EXIT_SUCCESS;
}
#endif /* OPENSSL_NO_HEARTBEATS */
#! /usr/bin/env perl
# Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved.
#
# Licensed under the OpenSSL license (the "License"). You may not use
# this file except in compliance with the License. You can obtain a copy
# in the file LICENSE in the source distribution or at
# https://www.openssl.org/source/license.html
use OpenSSL::Test::Simple;
simple_test("test_heartbeat", "heartbeat_test", "heartbeats");
......@@ -283,7 +283,6 @@
-T HASH_CTX
-T HEAPENTRY32
-T HEAPLIST32
-T HEARTBEAT_TEST_FIXTURE
-T HMAC_CTX
-T ICA_KEY_RSA_CRT
-T ICA_KEY_RSA_CRT_REC
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册