mirror of
https://github.com/openssl/openssl.git
synced 2025-03-19 19:50:42 +08:00
Remove heartbeat support
Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Tim Hudson <tjh@openssl.org> (Merged from https://github.com/openssl/openssl/pull/1669)
This commit is contained in:
parent
349d1cfddc
commit
e72040c1dc
3
CHANGES
3
CHANGES
@ -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
|
||||
|
3
INSTALL
3
INSTALL
@ -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.
|
||||
|
||||
|
168
ssl/d1_lib.c
168
ssl/d1_lib.c
@ -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) {
|
||||
/*
|
||||
|
15
ssl/s3_lib.c
15
ssl/s3_lib.c
@ -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
|
||||
|
100
ssl/t1_lib.c
100
ssl/t1_lib.c
@ -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
|
||||
|
@ -1,376 +0,0 @@
|
||||
/*
|
||||
* 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 */
|
@ -1,12 +0,0 @@
|
||||
#! /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
|
||||
|
Loading…
x
Reference in New Issue
Block a user