Index: Configure
===================================================================
RCS file: /v/openssl/cvs/openssl/Configure,v
retrieving revision 1.621.2.37.2.25
diff -u -r1.621.2.37.2.25 Configure
--- Configure	19 Dec 2011 17:02:33 -0000	1.621.2.37.2.25
+++ Configure	23 Dec 2011 07:59:47 -0000
@@ -1022,6 +1022,11 @@
 	$disabled{"srp"} = "forced";
 	}
 
+if (defined($disabled{"tlsext"}))
+	{
+	$disabled{"heartbeats"} = "forced";
+	}
+
 if ($target eq "TABLE") {
 	foreach $target (sort keys %table) {
 		print_table_entry($target);
Index: apps/s_cb.c
===================================================================
RCS file: /v/openssl/cvs/openssl/apps/s_cb.c,v
retrieving revision 1.27.2.8.2.2
diff -u -r1.27.2.8.2.2 s_cb.c
--- apps/s_cb.c	13 Nov 2011 13:13:13 -0000	1.27.2.8.2.2
+++ apps/s_cb.c	23 Dec 2011 07:59:47 -0000
@@ -600,6 +600,26 @@
 					}
 				}
 			}
+
+#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);
Index: apps/s_client.c
===================================================================
RCS file: /v/openssl/cvs/openssl/apps/s_client.c,v
retrieving revision 1.123.2.6.2.10
diff -u -r1.123.2.6.2.10 s_client.c
--- apps/s_client.c	14 Dec 2011 22:18:02 -0000	1.123.2.6.2.10
+++ apps/s_client.c	23 Dec 2011 07:59:47 -0000
@@ -1862,6 +1862,14 @@
 				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;
Index: apps/s_server.c
===================================================================
RCS file: /v/openssl/cvs/openssl/apps/s_server.c,v
retrieving revision 1.136.2.15.2.12
diff -u -r1.136.2.15.2.12 s_server.c
--- apps/s_server.c	15 Nov 2011 23:51:21 -0000	1.136.2.15.2.12
+++ apps/s_server.c	23 Dec 2011 07:59:47 -0000
@@ -2176,6 +2176,16 @@
 					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')))
 					{
Index: ssl/d1_both.c
===================================================================
RCS file: /v/openssl/cvs/openssl/ssl/d1_both.c,v
retrieving revision 1.14.2.21.2.5
diff -u -r1.14.2.21.2.5 d1_both.c
--- ssl/d1_both.c	27 Oct 2011 13:06:43 -0000	1.14.2.21.2.5
+++ ssl/d1_both.c	23 Dec 2011 07:59:48 -0000
@@ -1084,7 +1084,11 @@
 		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;
@@ -1417,3 +1421,148 @@
 
 	ccs_hdr->type = *(data++);
 	}
+
+#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++ & 0xff;
+	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 & 0xff;
+		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 != 1)
+		{
+		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 & 0xff;
+	/* 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
Index: ssl/d1_clnt.c
===================================================================
RCS file: /v/openssl/cvs/openssl/ssl/d1_clnt.c,v
retrieving revision 1.16.2.15.2.4
diff -u -r1.16.2.15.2.4 d1_clnt.c
--- ssl/d1_clnt.c	25 May 2011 12:24:43 -0000	1.16.2.15.2.4
+++ ssl/d1_clnt.c	23 Dec 2011 07:59:48 -0000
@@ -164,6 +164,19 @@
 	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;
Index: ssl/d1_lib.c
===================================================================
RCS file: /v/openssl/cvs/openssl/ssl/d1_lib.c,v
retrieving revision 1.8.2.13.2.6
diff -u -r1.8.2.13.2.6 d1_lib.c
--- ssl/d1_lib.c	15 Nov 2011 23:51:21 -0000	1.8.2.13.2.6
+++ ssl/d1_lib.c	23 Dec 2011 07:59:48 -0000
@@ -415,6 +415,14 @@
 		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);
 	}
Index: ssl/d1_pkt.c
===================================================================
RCS file: /v/openssl/cvs/openssl/ssl/d1_pkt.c,v
retrieving revision 1.27.2.25.2.5
diff -u -r1.27.2.25.2.5 d1_pkt.c
--- ssl/d1_pkt.c	1 Sep 2011 14:02:14 -0000	1.27.2.25.2.5
+++ ssl/d1_pkt.c	23 Dec 2011 07:59:48 -0000
@@ -877,6 +877,19 @@
 			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)
 			{
Index: ssl/d1_srvr.c
===================================================================
RCS file: /v/openssl/cvs/openssl/ssl/d1_srvr.c,v
retrieving revision 1.20.2.16.2.11
diff -u -r1.20.2.16.2.11 d1_srvr.c
--- ssl/d1_srvr.c	27 Oct 2011 13:01:20 -0000	1.20.2.16.2.11
+++ ssl/d1_srvr.c	23 Dec 2011 07:59:48 -0000
@@ -175,6 +175,19 @@
 		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;
Index: ssl/dtls1.h
===================================================================
RCS file: /v/openssl/cvs/openssl/ssl/dtls1.h,v
retrieving revision 1.12.2.16.2.1
diff -u -r1.12.2.16.2.1 dtls1.h
--- ssl/dtls1.h	11 May 2011 12:56:38 -0000	1.12.2.16.2.1
+++ ssl/dtls1.h	23 Dec 2011 07:59:48 -0000
@@ -229,7 +229,7 @@
 
 	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 */
Index: ssl/s3_clnt.c
===================================================================
RCS file: /v/openssl/cvs/openssl/ssl/s3_clnt.c,v
retrieving revision 1.129.2.15.2.18
diff -u -r1.129.2.15.2.18 s3_clnt.c
--- ssl/s3_clnt.c	25 Nov 2011 00:18:10 -0000	1.129.2.15.2.18
+++ ssl/s3_clnt.c	23 Dec 2011 07:59:48 -0000
@@ -203,6 +203,18 @@
 	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;
Index: ssl/s3_lib.c
===================================================================
RCS file: /v/openssl/cvs/openssl/ssl/s3_lib.c,v
retrieving revision 1.126.2.4.2.15
diff -u -r1.126.2.4.2.15 s3_lib.c
--- ssl/s3_lib.c	22 Dec 2011 15:01:16 -0000	1.126.2.4.2.15
+++ ssl/s3_lib.c	23 Dec 2011 07:59:48 -0000
@@ -3328,6 +3328,19 @@
 		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_TLS_EXT_HEARTBEAT_PENDING:
+		ret = s->tlsext_hb_pending;
+		break;
+#endif
+
 #endif /* !OPENSSL_NO_TLSEXT */
 	default:
 		break;
Index: ssl/s3_pkt.c
===================================================================
RCS file: /v/openssl/cvs/openssl/ssl/s3_pkt.c,v
retrieving revision 1.72.2.7.2.12
diff -u -r1.72.2.7.2.12 s3_pkt.c
--- ssl/s3_pkt.c	20 Dec 2011 15:05:03 -0000	1.72.2.7.2.12
+++ ssl/s3_pkt.c	23 Dec 2011 07:59:48 -0000
@@ -1070,6 +1070,19 @@
 			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)
 			{
Index: ssl/s3_srvr.c
===================================================================
RCS file: /v/openssl/cvs/openssl/ssl/s3_srvr.c,v
retrieving revision 1.171.2.21.2.18
diff -u -r1.171.2.21.2.18 s3_srvr.c
--- ssl/s3_srvr.c	25 Nov 2011 00:18:10 -0000	1.171.2.21.2.18
+++ ssl/s3_srvr.c	23 Dec 2011 07:59:48 -0000
@@ -236,6 +236,18 @@
 		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;
Index: ssl/ssl.h
===================================================================
RCS file: /v/openssl/cvs/openssl/ssl/ssl.h,v
retrieving revision 1.221.2.24.2.23
diff -u -r1.221.2.24.2.23 ssl.h
--- ssl/ssl.h	22 Dec 2011 16:01:23 -0000	1.221.2.24.2.23
+++ ssl/ssl.h	23 Dec 2011 07:59:48 -0000
@@ -621,6 +621,11 @@
  */
 #define SSL_OP_CRYPTOPRO_TLSEXT_BUG			0x80000000L
 
+#ifndef OPENSSL_NO_HEARTBEATS
+/* Don't allow the peer to send Heartbeat requests */
+#define SSL_OP_NO_HB_REQUEST			0x100000000L
+#endif
+
 /* Allow SSL_write(..., n) to return r with 0 < r < n (i.e. report success
  * when just a single record has been written): */
 #define SSL_MODE_ENABLE_PARTIAL_WRITE       0x00000001L
@@ -673,6 +678,13 @@
 #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)
+#define SSL_heartbeat_pending(ssl) \
+        SSL_ctrl((ssl),SSL_CTRL_TLS_EXT_HEARTBEAT_PENDING,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))
@@ -1332,8 +1344,16 @@
 
 #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 */
@@ -1576,6 +1596,10 @@
 #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_TLS_EXT_HEARTBEAT_PENDING		86
+#endif
 #endif
 
 #define DTLS_CTRL_GET_TIMEOUT		73
@@ -2245,6 +2269,7 @@
 #define SSL_F_TLS1_PREPARE_SERVERHELLO_TLSEXT		 276
 #define SSL_F_TLS1_PRF					 284
 #define SSL_F_TLS1_SETUP_KEY_BLOCK			 211
+#define SSL_F_TLS1_HEARTBEAT			 333
 #define SSL_F_WRITE_PENDING				 212
 
 /* Reason codes. */
@@ -2499,6 +2524,8 @@
 #define SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST		 157
 #define SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST 233
 #define SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG	 234
+#define SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT	1500
+#define SSL_R_TLS_HEARTBEAT_PENDING				1501
 #define SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER		 235
 #define SSL_R_UNABLE_TO_DECODE_DH_CERTS			 236
 #define SSL_R_UNABLE_TO_DECODE_ECDH_CERTS		 313
Index: ssl/ssl3.h
===================================================================
RCS file: /v/openssl/cvs/openssl/ssl/ssl3.h,v
retrieving revision 1.44.2.7.2.6
diff -u -r1.44.2.7.2.6 ssl3.h
--- ssl/ssl3.h	25 Nov 2011 00:18:10 -0000	1.44.2.7.2.6
+++ ssl/ssl3.h	23 Dec 2011 07:59:48 -0000
@@ -322,6 +322,7 @@
 #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 @@
 #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
Index: ssl/ssl_err.c
===================================================================
RCS file: /v/openssl/cvs/openssl/ssl/ssl_err.c,v
retrieving revision 1.78.2.11.2.8
diff -u -r1.78.2.11.2.8 ssl_err.c
--- ssl/ssl_err.c	15 Nov 2011 23:51:21 -0000	1.78.2.11.2.8
+++ ssl/ssl_err.c	23 Dec 2011 07:59:48 -0000
@@ -282,6 +282,7 @@
 {ERR_FUNC(SSL_F_TLS1_PREPARE_SERVERHELLO_TLSEXT),	"TLS1_PREPARE_SERVERHELLO_TLSEXT"},
 {ERR_FUNC(SSL_F_TLS1_PRF),	"tls1_prf"},
 {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK),	"TLS1_SETUP_KEY_BLOCK"},
+{ERR_FUNC(SSL_F_TLS1_HEARTBEAT),	"SSL_F_TLS1_HEARTBEAT"},
 {ERR_FUNC(SSL_F_WRITE_PENDING),	"WRITE_PENDING"},
 {0,NULL}
 	};
@@ -539,6 +540,8 @@
 {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"},
 {ERR_REASON(SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG),"tls rsa encrypted value length is wrong"},
+{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_TRIED_TO_USE_UNSUPPORTED_CIPHER),"tried to use unsupported cipher"},
 {ERR_REASON(SSL_R_UNABLE_TO_DECODE_DH_CERTS),"unable to decode dh certs"},
 {ERR_REASON(SSL_R_UNABLE_TO_DECODE_ECDH_CERTS),"unable to decode ecdh certs"},
Index: ssl/ssl_locl.h
===================================================================
RCS file: /v/openssl/cvs/openssl/ssl/ssl_locl.h,v
retrieving revision 1.100.2.10.2.14
diff -u -r1.100.2.10.2.14 ssl_locl.h
--- ssl/ssl_locl.h	13 Dec 2011 14:25:11 -0000	1.100.2.10.2.14
+++ ssl/ssl_locl.h	23 Dec 2011 07:59:48 -0000
@@ -1089,6 +1089,13 @@
 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
Index: ssl/t1_lib.c
===================================================================
RCS file: /v/openssl/cvs/openssl/ssl/t1_lib.c,v
retrieving revision 1.64.2.14.2.23
diff -u -r1.64.2.14.2.23 t1_lib.c
--- ssl/t1_lib.c	7 Dec 2011 12:28:50 -0000	1.64.2.14.2.23
+++ ssl/t1_lib.c	23 Dec 2011 07:59:48 -0000
@@ -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 @@
 			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 (SSL_get_options(s) & SSL_OP_NO_HB_REQUEST)
+		*(ret++) = 0x02 & 0xff;
+	else
+		*(ret++) = 0x01 & 0xff;
+#endif
+
 #ifndef OPENSSL_NO_NEXTPROTONEG
 	if (s->ctx->next_proto_select_cb && !s->s3->tmp.finish_md_len)
 		{
@@ -796,6 +811,20 @@
 
 		}
 
+#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 (SSL_get_options(s) & SSL_OP_NO_HB_REQUEST)
+		*(ret++) = 0x02 & 0xff;
+	else
+		*(ret++) = 0x01 & 0xff;
+#endif
+
 #ifndef OPENSSL_NO_NEXTPROTONEG
 	next_proto_neg_seen = s->s3->next_proto_neg_seen;
 	s->s3->next_proto_neg_seen = 0;
@@ -1227,6 +1256,20 @@
 				else
 					s->tlsext_status_type = -1;
 			}
+#ifndef OPENSSL_NO_HEARTBEATS
+		else if (type == TLSEXT_TYPE_heartbeat)
+			{
+			switch(data[0] & 0xff)
+				{
+				case 0x01:	/* Client allows us to send HB requests */
+							s->tlsext_heartbeat = 1;
+							break;
+				case 0x02:	/* Client doesn't accept HB requests */
+							s->tlsext_heartbeat = 2;
+							break;
+				}
+			}
+#endif
 #ifndef OPENSSL_NO_NEXTPROTONEG
 		else if (type == TLSEXT_TYPE_next_proto_neg &&
 			 s->s3->tmp.finish_md_len == 0)
@@ -1478,6 +1521,20 @@
 				return 0;
 			renegotiate_seen = 1;
 			}
+#ifndef OPENSSL_NO_HEARTBEATS
+		else if (type == TLSEXT_TYPE_heartbeat)
+			{
+			switch(data[0] & 0xff)
+				{
+				case 0x01:	/* Server allows us to send HB requests */
+							s->tlsext_heartbeat = 1;
+							break;
+				case 0x02:	/* Server doesn't accept HB requests */
+							s->tlsext_heartbeat = 2;
+							break;
+				}
+			}
+#endif
 		else if (type == TLSEXT_TYPE_use_srtp)
                         {
                         if(ssl_parse_serverhello_use_srtp_ext(s, data, size,
@@ -2330,3 +2387,144 @@
 	}
 
 #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++ & 0xff;
+	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 & 0xff;
+		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 != 1)
+		{
+		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 & 0xff;
+	/* 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
Index: ssl/tls1.h
===================================================================
RCS file: /v/openssl/cvs/openssl/ssl/tls1.h,v
retrieving revision 1.40.2.3.2.12
diff -u -r1.40.2.3.2.12 tls1.h
--- ssl/tls1.h	13 Dec 2011 14:25:11 -0000	1.40.2.3.2.12
+++ ssl/tls1.h	23 Dec 2011 07:59:48 -0000
@@ -256,6 +256,9 @@
 /* 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
