mirror of
https://github.com/openssl/openssl.git
synced 2024-11-21 01:15:20 +08:00
PR: 2658
Submitted by: Robin Seggelmann <seggelmann@fh-muenster.de> Reviewed by: steve Support for TLS/DTLS heartbeats.
This commit is contained in:
parent
84b6e277d4
commit
4817504d06
3
CHANGES
3
CHANGES
@ -255,6 +255,9 @@
|
||||
|
||||
Changes between 1.0.0f and 1.0.1 [xx XXX xxxx]
|
||||
|
||||
*) Add support for TLS/DTLS heartbeats.
|
||||
[Robin Seggelmann <seggelmann@fh-muenster.de>]
|
||||
|
||||
*) Improved PRNG seeding for VOS.
|
||||
[Paul Green <Paul.Green@stratus.com>]
|
||||
|
||||
|
20
apps/s_cb.c
20
apps/s_cb.c
@ -603,6 +603,26 @@ void MS_CALLBACK msg_cb(int write_p, int version, int content_type, const void *
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_HEARTBEATS
|
||||
if (content_type == 24) /* Heartbeat */
|
||||
{
|
||||
str_details1 = ", Heartbeat";
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
switch (((const unsigned char*)buf)[0])
|
||||
{
|
||||
case 1:
|
||||
str_details1 = ", HeartbeatRequest";
|
||||
break;
|
||||
case 2:
|
||||
str_details1 = ", HeartbeatResponse";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
BIO_printf(bio, "%s %s%s [length %04lx]%s%s\n", str_write_p, str_version, str_content_type, (unsigned long)len, str_details1, str_details2);
|
||||
|
@ -1862,6 +1862,14 @@ printf("read=%d pending=%d peek=%d\n",k,SSL_pending(con),SSL_peek(con,zbuf,10240
|
||||
SSL_renegotiate(con);
|
||||
cbuf_len=0;
|
||||
}
|
||||
#ifndef OPENSSL_NO_HEARTBEATS
|
||||
else if ((!c_ign_eof) && (cbuf[0] == 'B'))
|
||||
{
|
||||
BIO_printf(bio_err,"HEARTBEATING\n");
|
||||
SSL_heartbeat(con);
|
||||
cbuf_len=0;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
cbuf_len=i;
|
||||
|
@ -2222,6 +2222,16 @@ static int sv_body(char *hostname, int s, unsigned char *context)
|
||||
goto err;
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_HEARTBEATS
|
||||
if ((buf[0] == 'B') &&
|
||||
((buf[1] == '\n') || (buf[1] == '\r')))
|
||||
{
|
||||
BIO_printf(bio_err,"HEARTBEATING\n");
|
||||
SSL_heartbeat(con);
|
||||
i=0;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
if ((buf[0] == 'r') &&
|
||||
((buf[1] == '\n') || (buf[1] == '\r')))
|
||||
{
|
||||
|
152
ssl/d1_both.c
152
ssl/d1_both.c
@ -1084,7 +1084,11 @@ int dtls1_read_failed(SSL *s, int code)
|
||||
return code;
|
||||
}
|
||||
|
||||
if ( ! SSL_in_init(s)) /* done, no need to send a retransmit */
|
||||
#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;
|
||||
@ -1438,3 +1442,149 @@ int dtls1_shutdown(SSL *s)
|
||||
#endif
|
||||
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 */
|
||||
|
||||
/* Read type and payload length first */
|
||||
hbtype = *p++;
|
||||
n2s(p, payload);
|
||||
pl = p;
|
||||
|
||||
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);
|
||||
|
||||
if (hbtype == TLS1_HB_REQUEST)
|
||||
{
|
||||
unsigned char *buffer, *bp;
|
||||
int r;
|
||||
|
||||
/* Allocate memory for the response, size is 1 byte
|
||||
* 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);
|
||||
/* Random padding */
|
||||
RAND_pseudo_bytes(p, padding);
|
||||
|
||||
r = dtls1_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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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) || s->in_handshake)
|
||||
{
|
||||
SSLerr(SSL_F_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.
|
||||
*/
|
||||
OPENSSL_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
|
||||
|
@ -177,6 +177,19 @@ int dtls1_connect(SSL *s)
|
||||
BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE, s->in_handshake, NULL);
|
||||
#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)
|
||||
{
|
||||
dtls1_stop_timer(s);
|
||||
s->tlsext_hb_pending = 0;
|
||||
s->tlsext_hb_seq++;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (;;)
|
||||
{
|
||||
state=s->state;
|
||||
|
@ -424,6 +424,14 @@ int dtls1_handle_timeout(SSL *s)
|
||||
state->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);
|
||||
}
|
||||
|
13
ssl/d1_pkt.c
13
ssl/d1_pkt.c
@ -937,6 +937,19 @@ 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)
|
||||
{
|
||||
|
@ -186,6 +186,19 @@ 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;
|
||||
|
@ -236,7 +236,7 @@ typedef struct dtls1_state_st
|
||||
|
||||
struct dtls1_timeout_st timeout;
|
||||
|
||||
/* Indicates when the last handshake msg sent will timeout */
|
||||
/* Indicates when the last handshake msg or heartbeat sent will timeout */
|
||||
struct timeval next_timeout;
|
||||
|
||||
/* Timeout duration */
|
||||
|
@ -204,6 +204,18 @@ 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
|
||||
|
||||
for (;;)
|
||||
{
|
||||
state=s->state;
|
||||
|
21
ssl/s3_lib.c
21
ssl/s3_lib.c
@ -3328,6 +3328,27 @@ 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_version(s) == DTLS1_VERSION || SSL_version(s) == DTLS1_BAD_VER)
|
||||
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 */
|
||||
default:
|
||||
break;
|
||||
|
13
ssl/s3_pkt.c
13
ssl/s3_pkt.c
@ -1070,6 +1070,19 @@ 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)
|
||||
{
|
||||
|
@ -238,6 +238,18 @@ 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;
|
||||
|
26
ssl/ssl.h
26
ssl/ssl.h
@ -676,6 +676,11 @@ struct ssl_session_st
|
||||
#define SSL_get_secure_renegotiation_support(ssl) \
|
||||
SSL_ctrl((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
|
||||
|
||||
void SSL_CTX_set_msg_callback(SSL_CTX *ctx, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg));
|
||||
void SSL_set_msg_callback(SSL *ssl, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg));
|
||||
#define SSL_CTX_set_msg_callback_arg(ctx, arg) SSL_CTX_ctrl((ctx), SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, (arg))
|
||||
@ -1339,8 +1344,16 @@ struct ssl_st
|
||||
|
||||
#define session_ctx initial_ctx
|
||||
|
||||
STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles; /* What we'll do */
|
||||
SRTP_PROTECTION_PROFILE *srtp_profile; /* What's been chosen */
|
||||
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 */
|
||||
#else
|
||||
#define session_ctx ctx
|
||||
#endif /* OPENSSL_NO_TLSEXT */
|
||||
@ -1583,6 +1596,11 @@ 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
|
||||
#endif
|
||||
|
||||
#define DTLS_CTRL_GET_TIMEOUT 73
|
||||
@ -2065,6 +2083,7 @@ void ERR_load_SSL_strings(void);
|
||||
#define SSL_F_DTLS1_GET_MESSAGE_FRAGMENT 253
|
||||
#define SSL_F_DTLS1_GET_RECORD 254
|
||||
#define SSL_F_DTLS1_HANDLE_TIMEOUT 297
|
||||
#define SSL_F_DTLS1_HEARTBEAT 314
|
||||
#define SSL_F_DTLS1_OUTPUT_CERT_CHAIN 255
|
||||
#define SSL_F_DTLS1_PREPROCESS_FRAGMENT 288
|
||||
#define SSL_F_DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE 256
|
||||
@ -2255,6 +2274,7 @@ void ERR_load_SSL_strings(void);
|
||||
#define SSL_F_TLS1_CHECK_SERVERHELLO_TLSEXT 274
|
||||
#define SSL_F_TLS1_ENC 210
|
||||
#define SSL_F_TLS1_EXPORT_KEYING_MATERIAL 312
|
||||
#define SSL_F_TLS1_HEARTBEAT 313
|
||||
#define SSL_F_TLS1_PREPARE_CLIENTHELLO_TLSEXT 275
|
||||
#define SSL_F_TLS1_PREPARE_SERVERHELLO_TLSEXT 276
|
||||
#define SSL_F_TLS1_PRF 284
|
||||
@ -2509,6 +2529,8 @@ void ERR_load_SSL_strings(void);
|
||||
#define SSL_R_TLSV1_UNRECOGNIZED_NAME 1112
|
||||
#define SSL_R_TLSV1_UNSUPPORTED_EXTENSION 1110
|
||||
#define SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER 232
|
||||
#define SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT 368
|
||||
#define SSL_R_TLS_HEARTBEAT_PENDING 369
|
||||
#define SSL_R_TLS_ILLEGAL_EXPORTER_LABEL 367
|
||||
#define SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST 157
|
||||
#define SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST 233
|
||||
|
@ -322,6 +322,7 @@ extern "C" {
|
||||
#define SSL3_RT_ALERT 21
|
||||
#define SSL3_RT_HANDSHAKE 22
|
||||
#define SSL3_RT_APPLICATION_DATA 23
|
||||
#define TLS1_RT_HEARTBEAT 24
|
||||
|
||||
#define SSL3_AL_WARNING 1
|
||||
#define SSL3_AL_FATAL 2
|
||||
@ -339,6 +340,9 @@ extern "C" {
|
||||
#define SSL3_AD_CERTIFICATE_UNKNOWN 46
|
||||
#define SSL3_AD_ILLEGAL_PARAMETER 47 /* fatal */
|
||||
|
||||
#define TLS1_HB_REQUEST 1
|
||||
#define TLS1_HB_RESPONSE 2
|
||||
|
||||
#ifndef OPENSSL_NO_SSL_INTERN
|
||||
|
||||
typedef struct ssl3_record_st
|
||||
|
@ -88,6 +88,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
|
||||
{ERR_FUNC(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT), "DTLS1_GET_MESSAGE_FRAGMENT"},
|
||||
{ERR_FUNC(SSL_F_DTLS1_GET_RECORD), "DTLS1_GET_RECORD"},
|
||||
{ERR_FUNC(SSL_F_DTLS1_HANDLE_TIMEOUT), "DTLS1_HANDLE_TIMEOUT"},
|
||||
{ERR_FUNC(SSL_F_DTLS1_HEARTBEAT), "DTLS1_HEARTBEAT"},
|
||||
{ERR_FUNC(SSL_F_DTLS1_OUTPUT_CERT_CHAIN), "DTLS1_OUTPUT_CERT_CHAIN"},
|
||||
{ERR_FUNC(SSL_F_DTLS1_PREPROCESS_FRAGMENT), "DTLS1_PREPROCESS_FRAGMENT"},
|
||||
{ERR_FUNC(SSL_F_DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE), "DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE"},
|
||||
@ -278,6 +279,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
|
||||
{ERR_FUNC(SSL_F_TLS1_CHECK_SERVERHELLO_TLSEXT), "TLS1_CHECK_SERVERHELLO_TLSEXT"},
|
||||
{ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"},
|
||||
{ERR_FUNC(SSL_F_TLS1_EXPORT_KEYING_MATERIAL), "TLS1_EXPORT_KEYING_MATERIAL"},
|
||||
{ERR_FUNC(SSL_F_TLS1_HEARTBEAT), "SSL_F_TLS1_HEARTBEAT"},
|
||||
{ERR_FUNC(SSL_F_TLS1_PREPARE_CLIENTHELLO_TLSEXT), "TLS1_PREPARE_CLIENTHELLO_TLSEXT"},
|
||||
{ERR_FUNC(SSL_F_TLS1_PREPARE_SERVERHELLO_TLSEXT), "TLS1_PREPARE_SERVERHELLO_TLSEXT"},
|
||||
{ERR_FUNC(SSL_F_TLS1_PRF), "tls1_prf"},
|
||||
@ -535,6 +537,8 @@ static ERR_STRING_DATA SSL_str_reasons[]=
|
||||
{ERR_REASON(SSL_R_TLSV1_UNRECOGNIZED_NAME),"tlsv1 unrecognized name"},
|
||||
{ERR_REASON(SSL_R_TLSV1_UNSUPPORTED_EXTENSION),"tlsv1 unsupported extension"},
|
||||
{ERR_REASON(SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER),"tls client cert req with anon cipher"},
|
||||
{ERR_REASON(SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT),"peer does not accept heartbearts"},
|
||||
{ERR_REASON(SSL_R_TLS_HEARTBEAT_PENDING) ,"heartbeat request already pending"},
|
||||
{ERR_REASON(SSL_R_TLS_ILLEGAL_EXPORTER_LABEL),"tls illegal exporter label"},
|
||||
{ERR_REASON(SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST),"tls invalid ecpointformat list"},
|
||||
{ERR_REASON(SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST),"tls peer did not respond with certificate list"},
|
||||
|
@ -1088,6 +1088,13 @@ int ssl_prepare_serverhello_tlsext(SSL *s);
|
||||
int ssl_check_clienthello_tlsext(SSL *s);
|
||||
int ssl_check_serverhello_tlsext(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
|
||||
|
211
ssl/t1_lib.c
211
ssl/t1_lib.c
@ -114,6 +114,7 @@
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/ocsp.h>
|
||||
#include <openssl/rand.h>
|
||||
#include "ssl_locl.h"
|
||||
|
||||
const char tls1_version_str[]="TLSv1" OPENSSL_VERSION_PTEXT;
|
||||
@ -618,6 +619,20 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
|
||||
i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, &ret);
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_HEARTBEATS
|
||||
/* Add Heartbeat extension */
|
||||
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)
|
||||
{
|
||||
@ -796,6 +811,20 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
|
||||
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_HEARTBEATS
|
||||
/* Add Heartbeat extension */
|
||||
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;
|
||||
@ -840,6 +869,11 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
|
||||
s->s3->next_proto_neg_seen = 0;
|
||||
#endif
|
||||
|
||||
#ifndef OPENSSL_NO_HEARTBEATS
|
||||
s->tlsext_heartbeat &= ~(SSL_TLSEXT_HB_ENABLED |
|
||||
SSL_TLSEXT_HB_DONT_SEND_REQUESTS);
|
||||
#endif
|
||||
|
||||
if (data >= (d+n-2))
|
||||
goto ri_check;
|
||||
n2s(data,len);
|
||||
@ -1227,6 +1261,21 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
|
||||
else
|
||||
s->tlsext_status_type = -1;
|
||||
}
|
||||
#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;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
else if (type == TLSEXT_TYPE_next_proto_neg &&
|
||||
s->s3->tmp.finish_md_len == 0)
|
||||
@ -1312,6 +1361,11 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
|
||||
s->s3->next_proto_neg_seen = 0;
|
||||
#endif
|
||||
|
||||
#ifndef OPENSSL_NO_HEARTBEATS
|
||||
s->tlsext_heartbeat &= ~(SSL_TLSEXT_HB_ENABLED |
|
||||
SSL_TLSEXT_HB_DONT_SEND_REQUESTS);
|
||||
#endif
|
||||
|
||||
if (data >= (d+n-2))
|
||||
goto ri_check;
|
||||
|
||||
@ -1478,6 +1532,21 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
|
||||
return 0;
|
||||
renegotiate_seen = 1;
|
||||
}
|
||||
#ifndef OPENSSL_NO_HEARTBEATS
|
||||
else if (type == TLSEXT_TYPE_heartbeat)
|
||||
{
|
||||
switch(data[0])
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else if (type == TLSEXT_TYPE_use_srtp)
|
||||
{
|
||||
if(ssl_parse_serverhello_use_srtp_ext(s, data, size,
|
||||
@ -2330,3 +2399,145 @@ int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize)
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#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 */
|
||||
|
||||
/* Read type and payload length first */
|
||||
hbtype = *p++;
|
||||
n2s(p, payload);
|
||||
pl = p;
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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)
|
||||
{
|
||||
SSLerr(SSL_F_TLS1_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_TLS1_HEARTBEAT,SSL_R_TLS_HEARTBEAT_PENDING);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ...and no handshake in progress. */
|
||||
if (SSL_in_init(s) || s->in_handshake)
|
||||
{
|
||||
SSLerr(SSL_F_TLS1_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.
|
||||
*/
|
||||
OPENSSL_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
|
||||
|
13
ssl/tls1.h
13
ssl/tls1.h
@ -256,6 +256,9 @@ extern "C" {
|
||||
/* ExtensionType value from RFC5764 */
|
||||
#define TLSEXT_TYPE_use_srtp 14
|
||||
|
||||
/* Heartbeat extension */
|
||||
#define TLSEXT_TYPE_heartbeat 15
|
||||
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
|
||||
#define TLSEXT_MAXLEN_host_name 255
|
||||
@ -327,6 +330,16 @@ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB_ARG, 0, arg)
|
||||
#define SSL_CTX_set_tlsext_ticket_key_cb(ssl, cb) \
|
||||
SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB,(void (*)(void))cb)
|
||||
|
||||
#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
|
||||
|
||||
/* PSK ciphersuites from 4279 */
|
||||
|
Loading…
Reference in New Issue
Block a user