gnutls-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[SCM] GNU gnutls branch, master, updated. gnutls_3_1_0-102-g739d28d


From: Nikos Mavrogiannopoulos
Subject: [SCM] GNU gnutls branch, master, updated. gnutls_3_1_0-102-g739d28d
Date: Thu, 20 Sep 2012 21:37:23 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU gnutls".

http://git.savannah.gnu.org/cgit/gnutls.git/commit/?id=739d28d20b5567eb7c1835747f8a639b5329b63e

The branch, master has been updated
       via  739d28d20b5567eb7c1835747f8a639b5329b63e (commit)
       via  2b997db624a800b6d74bdd9ccbf46cc362495d84 (commit)
       via  46e2ec85cfeafa9a85093d3ce35ccf720e8a9195 (commit)
       via  c53d06fd31d37f61b195d4642bf57d2f26d54374 (commit)
       via  e201d2a1934ea1a8d3c2c0da1df6e94d3178b806 (commit)
       via  1b557d301a1482a11184a54172900a280d1f6996 (commit)
      from  77e104b8c5e0040c38d68f604cce59025ce10243 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 739d28d20b5567eb7c1835747f8a639b5329b63e
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Thu Sep 20 23:36:59 2012 +0200

    updated

commit 2b997db624a800b6d74bdd9ccbf46cc362495d84
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Thu Sep 20 23:36:00 2012 +0200

    updates in heartbeat support

commit 46e2ec85cfeafa9a85093d3ce35ccf720e8a9195
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Thu Sep 20 23:06:06 2012 +0200

    updated documentation

commit c53d06fd31d37f61b195d4642bf57d2f26d54374
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Thu Sep 20 23:01:17 2012 +0200

    updated tests for new security levels

commit e201d2a1934ea1a8d3c2c0da1df6e94d3178b806
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Thu Sep 20 22:59:49 2012 +0200

    several updates in the heartbeat handling code.

commit 1b557d301a1482a11184a54172900a280d1f6996
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Thu Sep 20 18:51:54 2012 +0200

    Corrected issues

-----------------------------------------------------------------------

Summary of changes:
 NEWS                                  |   50 ++++++-
 doc/cha-intro-tls.texi                |    7 +-
 lib/ext/heartbeat.c                   |  291 +++++++++++++++-----------------
 lib/ext/heartbeat.h                   |    7 +-
 lib/gnutls_buffers.c                  |   52 +++++--
 lib/gnutls_buffers.h                  |    4 +-
 lib/gnutls_dtls.c                     |    2 +-
 lib/gnutls_errors.c                   |    8 +-
 lib/gnutls_handshake.c                |    9 +-
 lib/gnutls_handshake.h                |   15 ++
 lib/gnutls_int.h                      |   19 ++-
 lib/gnutls_record.c                   |   55 ++----
 lib/gnutls_record.h                   |    2 +-
 lib/gnutls_state.c                    |    6 +-
 lib/includes/gnutls/gnutls.h.in       |   20 ++-
 lib/libgnutls.map                     |    3 +-
 lib/x509/common.c                     |    1 -
 lib/x509/dn.c                         |    6 +
 src/common.c                          |   16 ++-
 src/serv.c                            |    9 +-
 src/socket.c                          |   19 +-
 src/udp-serv.c                        |   10 +-
 tests/cert-tests/ca-no-pathlen.pem    |    2 +-
 tests/cert-tests/no-ca-or-pathlen.pem |    2 +-
 24 files changed, 353 insertions(+), 262 deletions(-)

diff --git a/NEWS b/NEWS
index 9a2cd4a..f937025 100644
--- a/NEWS
+++ b/NEWS
@@ -2,7 +2,47 @@ GnuTLS NEWS -- History of user-visible changes.                
-*- outline -*-
 Copyright (C) 2000-2012 Free Software Foundation, Inc.
 See the end for copying conditions.
 
-* Version 3.1.1 (unreleased)
+* Version 3.1.2 (unreleased)
+
+** libgnutls: Fixed bug in gnutls_x509_trust_list_add_system_trust()
+and gnutls_x509_trust_list_add_trust_mem() that prevented the loading
+of certificates in the windows platform.
+
+** libgnutls: Added X.509 certificate verification flag 
+GNUTLS_VERIFY_ALLOW_UNSORTED_CHAIN. This flag allows the verification
+of unsorted certificate chains and is enabled by default for
+TLS certificate verification (if gnutls_certificate_set_verify_flags() 
+does not override it).
+
+** libgnutls: Prints warning on certificates that contain keys of
+an insecure level. If the %COMPAT priority flag is not specified
+the TLS connection fails.
+
+** libgnutls: Better mingw32 support (patch by LRN).
+
+** libgnutls: The %COMPAT keyword, if specified, will tolerate
+key usage violation errors (they are far too common to ignore).
+
+** libgnutls: Added GNUTLS_STATELESS_COMPRESSION flag to gnutls_init(),
+which provides a tool to counter compression-related attacks where
+parts of the data are controlled by the attacker _and_ placed in
+separate records (use with care - do not use compression if not sure).
+
+** libgnutls: Depends on libtasn1 2.14 or later.
+
+** certtool: Prints the number of bits of the public key algorithm
+parameter in a private key.
+
+** API and ABI modifications:
+gnutls_x509_privkey_get_pk_algorithm2: Added
+gnutls_heartbeat_ping: Added
+gnutls_heartbeat_pong: Added
+gnutls_heartbeat_allowed: Added
+gnutls_heartbeat_enable: Added
+GNUTLS_SEC_PARAM_WEAK: Added
+GNUTLS_SEC_PARAM_INSECURE: Added
+
+* Version 3.1.1 (released 2012-09-02)
 
 ** gnutls-serv: Listens on IPv6. Patch by Bernhard R. Link.
 
@@ -13,6 +53,14 @@ assume the PKCS #8 file format, instead of ignoring the 
password.
 
 ** tpmtool: No longer asks for key password in registered keys.
 
+** libgnutls: Elliptic curve code was optimized by Ilya Tumaykin.
+wmNAF is now used for point multiplication and other optimizations.
+(the major part of the work was done during Google Summer of Code).
+
+** libgnutls: The default pull_timeout_function only uses select
+instead of a combination of select() and recv() to prevent issues
+when used in stream sockets in some systems.
+
 ** libgnutls: Be tolerant in ECDSA signature violations (e.g. using
 SHA256 with a SECP384 curve instead of SHA-384), to interoperate with
 openssl.
diff --git a/doc/cha-intro-tls.texi b/doc/cha-intro-tls.texi
index 21b8533..8279fff 100644
--- a/doc/cha-intro-tls.texi
+++ b/doc/cha-intro-tls.texi
@@ -456,14 +456,13 @@ local policy affecting HeartBeat messages coming from the 
peer - the policy
 could be checked via @funcref{gnutls_heartbeat_allowed}. 
 The requests coming from peer are answered automatically (if policy permits) 
 inside @funcref{gnutls_record_recv}, requests to peer could be send via
address@hidden or
address@hidden Each request triggers timeout
-which could be checked and manipulated with @funcref{gnutls_heartbeat_timeout}.
address@hidden 
 
 Policy-related functions:
 @showfuncB{gnutls_heartbeat_allowed,gnutls_heartbeat_enable}
+
 Operational functions:
address@hidden,gnutls_heartbeat_ping,gnutls_heartbeat_ping_rnd}
address@hidden,gnutls_heartbeat_pong}
 
 @node Safe renegotiation
 @subsection Safe renegotiation
diff --git a/lib/ext/heartbeat.c b/lib/ext/heartbeat.c
index 677a91d..88dd989 100644
--- a/lib/ext/heartbeat.c
+++ b/lib/ext/heartbeat.c
@@ -65,10 +65,10 @@ _gnutls_heartbeat (unsigned policy)
 /**
   * gnutls_heartbeat_allowed:
   * @session: is a #gnutls_session_t structure.
-  * @type: non zero is for sending, and zero for receiving
+  * @type: one of %GNUTLS_HB_LOCAL_ALLOWED_TO_SEND and 
%GNUTLS_HB_PEER_ALLOWED_TO_SEND
   *
   * This function will check whether heartbeats are allowed
-  * in this session.
+  * to be sent or received in this session. 
   *
   * Returns: Non zero if heartbeats are allowed.
   *
@@ -82,7 +82,7 @@ gnutls_heartbeat_allowed (gnutls_session_t session, unsigned 
int type)
       (session, GNUTLS_EXTENSION_HEARTBEAT, &epriv) < 0)
     return 0;                   /* Not enabled */
 
-  if (type != 0)
+  if (type == GNUTLS_HB_LOCAL_ALLOWED_TO_SEND)
     {
       if (epriv.num & LOCAL_ALLOWED_TO_SEND)
         return 1;
@@ -96,21 +96,21 @@ gnutls_heartbeat_allowed (gnutls_session_t session, 
unsigned int type)
 static int
 heartbeat_allow_recv (gnutls_session_t session)
 {
-  return gnutls_heartbeat_allowed(session, 0);
+  return gnutls_heartbeat_allowed(session, GNUTLS_HB_PEER_ALLOWED_TO_SEND);
 }
 
 static int
 heartbeat_allow_send (gnutls_session_t session)
 {
-  return gnutls_heartbeat_allowed(session, 1);
+  return gnutls_heartbeat_allowed(session, GNUTLS_HB_LOCAL_ALLOWED_TO_SEND);
 }
 
-/**
- * _gnutls_heartbeat_send_data:
+/*-
+ * heartbeat_send_data:
  * @session: is a #gnutls_session_t structure.
  * @data: contains the data to send.
  * @data_size: is the length of the data.
- * @request: true if Request message is about to be send.
+ * @start_timer: true if the heartbeat timer is to be started.
  *
  * This function has the similar semantics with gnutls_record_send() The only
  * difference is that it uses GNUTLS_HEARTBEAT content type.
@@ -123,16 +123,14 @@ heartbeat_allow_send (gnutls_session_t session)
  *   number of bytes sent might be less than @data_size.  The maximum
  *   number of bytes this function can send in a single call depends
  *   on the negotiated maximum record size.
- **/
-ssize_t
-_gnutls_heartbeat_send_data (gnutls_session_t session, const void *data,
-                             size_t data_size, int request)
+ -*/
+static int
+heartbeat_send_data (gnutls_session_t session, const void *data,
+                     size_t data_size, uint8_t type)
 {
   int ret;
-  char pr[128];
   gnutls_buffer_st response;
   uint8_t payload[16];
-  uint8_t type = request ? HEARTBEAT_REQUEST : HEARTBEAT_RESPONSE;
   _gnutls_buffer_init (&response);
 
   ret = gnutls_rnd (GNUTLS_RND_RANDOM, payload, 16);
@@ -146,96 +144,137 @@ _gnutls_heartbeat_send_data (gnutls_session_t session, 
const void *data,
   ret = _gnutls_send_int (session, GNUTLS_HEARTBEAT, -1,
                           EPOCH_WRITE_CURRENT, response.data,
                           response.length, MBUFFER_FLUSH);
-  if (request)
-    {
-      if (ret >= 0)
-        {
-          _gnutls_record_log
-              ("REC[%p]: HB %zu bytes sent OK [%d in packet], saved for 
response verification:%s\n",
-               session, data_size, ret, _gnutls_bin2hex ((uint8_t *) data,
-                                                         data_size, pr,
-                                                         sizeof (pr),
-                                                         NULL));
-          session->internals.dtls.heartbeat_timeout = HEARTBEAT_TIMEOUT;
-          gettime (&session->internals.dtls.heartbeat_sent);
-          _gnutls_buffer_reset (&session->internals.heartbeat_payload);
-          BUFFER_APPEND (&session->internals.heartbeat_payload, data,
-                         data_size);
-        }
-    }
+
   _gnutls_record_log ("REC[%p]: HB sent: %d\n", session, ret);
 
   _gnutls_buffer_clear (&response);
-  return gnutls_assert_val (ret);
+  return ret;
 }
 
 /**
  * gnutls_heartbeat_ping:
  * @session: is a #gnutls_session_t structure.
- * @data_size: is the length of the random data.
- * @wait_for_it: wait for pong or timeout instead of returning
- * immediately.
+ * @data_size: is the length of the ping payload.
+ * @max_tries: if flags is %GNUTLS_HEARTBEAT_WAIT then this sets the number of 
retransmissions.
+ * @flags: if %GNUTLS_HEARTBEAT_WAIT then wait for pong or timeout instead of 
returning immediately.
  *
- * This function has the similar semantics with gnutls_record_send().
- * The only difference is that it uses GNUTLS_HEARTBEAT content type
- * and auto-generate data to send.
+ * This function sends a ping to the peer. If the @flags is set
+ * to %GNUTLS_HEARTBEAT_WAIT then it waits for a reply from the peer.
+ * 
+ * Note that it is highly recommended to use this function with the
+ * flag %GNUTLS_HEARTBEAT_WAIT, or you need to handle retransmissions
+ * and timeouts manually.
  *
- * This function send HeartBeat request message with proper padding.
- *
- *
- * Returns: The number of bytes sent, or a negative error code. The
- *   number of bytes sent might be less than @data_size.  The maximum
- *   number of bytes this function can send in a single call depends
- *   on the negotiated maximum record size. GNUTLS_E_HEARTBEAT_FLIGHT
- *   is returned if HB Request is alredy in flight.
+ * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
  **/
-ssize_t
-gnutls_heartbeat_ping (gnutls_session_t session, size_t data_size)
+int
+gnutls_heartbeat_ping (gnutls_session_t session, size_t data_size, 
+                       unsigned int max_tries, unsigned int flags)
 {
-  int ret = GNUTLS_E_HEARTBEAT_FLIGHT;
+  int ret;
+  unsigned int retries = 1;
 
   if (data_size > MAX_HEARTBEAT_LENGTH)
     return gnutls_assert_val (GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
 
   if (!heartbeat_allow_send (session))
-    return GNUTLS_E_INVALID_REQUEST;
+    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
 
-  _gnutls_record_log
-      ("REC[%p]: sending HB_REQUEST with length: %zu to peer\n",
-       session, data_size);
-
-  if (gnutls_heartbeat_timeout (session, 1) == GNUTLS_E_ILLEGAL_PARAMETER)
+  switch(session->internals.hb_state)
     {
-      uint8_t data[data_size];
-      ret = _gnutls_rnd (GNUTLS_RND_NONCE, data, data_size);
-      if (ret >= 0)
-        ret = _gnutls_heartbeat_send_data (session, data, data_size, 1);
+      case SHB_SEND1:
+        _gnutls_record_log
+         ("REC[%p]: sending HB_REQUEST with length: %zu to peer\n", session, 
data_size);
+
+        _gnutls_buffer_reset(&session->internals.hb_local_data);
+
+        ret = _gnutls_buffer_resize (&session->internals.hb_local_data, 
data_size);
+        if (ret < 0)
+          return gnutls_assert_val(ret);
+
+        ret = _gnutls_rnd (GNUTLS_RND_NONCE, 
session->internals.hb_local_data.data, data_size);
+        if (ret < 0)
+          return gnutls_assert_val(ret);
+
+        session->internals.hb_local_data.length = data_size;
+        session->internals.hb_state = SHB_SEND2;
+      case SHB_SEND2:
+        session->internals.hb_timeout = HEARTBEAT_TIMEOUT;
+retry:
+        ret = heartbeat_send_data (session, 
session->internals.hb_local_data.data, 
+                                   session->internals.hb_local_data.length, 
+                                   HEARTBEAT_REQUEST);
+        if (ret < 0)
+          return gnutls_assert_val(ret);
+
+        gettime (&session->internals.hb_ping_sent);
+            
+        if (!(flags & GNUTLS_HEARTBEAT_WAIT))
+          {
+            session->internals.hb_state = SHB_SEND1;
+            break;
+          }
+        
+        session->internals.hb_state = SHB_RECV;
+
+      case SHB_RECV:
+        ret = _gnutls_recv_int(session, GNUTLS_HEARTBEAT, -1, NULL, 0, NULL, 
session->internals.hb_timeout);
+        if (ret == GNUTLS_E_HEARTBEAT_PONG_RECEIVED)
+          {
+            session->internals.hb_state = SHB_SEND1;
+            break;
+          }
+        else if (ret == GNUTLS_E_TIMEDOUT)
+          {
+            retries++;
+            if (retries > max_tries)
+              {
+                session->internals.hb_state = SHB_SEND1;
+                return gnutls_assert_val(ret);
+              }
+
+            session->internals.hb_timeout *= 2;
+            session->internals.hb_timeout %= MAX_DTLS_TIMEOUT;
+            
+            session->internals.hb_state = SHB_SEND2;
+            goto retry;
+          }
+        else if (ret < 0)
+          {
+            session->internals.hb_state = SHB_SEND1;
+            return gnutls_assert_val(ret);
+          }
     }
-  else
-    _gnutls_record_log
-        ("REC[%p]: HB_REQUEST with length %zu already in-flight: %d\n",
-         session, data_size, gnutls_heartbeat_timeout (session, 1));
 
-  return ret;
+  return 0;
 }
 
 /**
- * simple wrapper for ping with random length
+ * gnutls_heartbeat_pong:
+ * @session: is a #gnutls_session_t structure.
+ * @flags: should be zero
+ *
+ * This function replies to a ping by sending a pong to the peer.
+ *
+ * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
  **/
-ssize_t
-gnutls_heartbeat_ping_rnd (gnutls_session_t session)
+int
+gnutls_heartbeat_pong (gnutls_session_t session, unsigned int flags)
 {
-  uint8_t rnd;
-  int ret;
-  
-  ret = gnutls_rnd (GNUTLS_RND_NONCE, &rnd, 1);
-  if (ret < 0)
-    return gnutls_assert_val(ret);
-  
-  return gnutls_heartbeat_ping (session, rnd + 1);
+int ret;
+
+  if (session->internals.hb_remote_data.length == 0)
+    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+  ret = heartbeat_send_data (session, session->internals.hb_remote_data.data, 
+                             session->internals.hb_remote_data.length, 
+                             HEARTBEAT_RESPONSE);
+
+  _gnutls_buffer_reset (&session->internals.hb_remote_data);
+  return ret;
 }
 
-/**
+/*-
  * Process HB message in buffer.
  * @bufel: the (suspected) HeartBeat message (TLV+padding)
  *
@@ -244,11 +283,12 @@ gnutls_heartbeat_ping_rnd (gnutls_session_t session)
  * GNUTLS_E_AGAIN if processed OK
  * GNUTLS_E_HEARTBEAT_PONG_FAILED on response send failure for request message
  * GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER on payload mismatch for response message
- **/
+ -*/
 int
 _gnutls_heartbeat_handle (gnutls_session_t session, mbuffer_st * bufel)
 {
   char pr[128];
+  int ret;
   uint8_t *msg = _mbuffer_get_udata_ptr (bufel);
   size_t hb_len, len = _mbuffer_get_udata_size (bufel);
 
@@ -261,108 +301,49 @@ _gnutls_heartbeat_handle (gnutls_session_t session, 
mbuffer_st * bufel)
   hb_len = _gnutls_read_uint16 (msg + 1);
   if (hb_len > len - 3)
     return gnutls_assert_val (GNUTLS_E_UNEXPECTED_PACKET);
-
+  
   switch (msg[0])
     {
     case HEARTBEAT_REQUEST:
       _gnutls_record_log
-          ("REC[%p]: received HEARTBEAT_REQUEST, responding...\n",
-           session);
-      if (_gnutls_heartbeat_send_data (session, msg + 3, hb_len, 0) >= 0)
-        return GNUTLS_E_AGAIN;  /* HB responded, no APP_DATA so needs to be 
called again */
-      else
-        {                       /* immediate response failed, TBD: save 
received data somewhere and let upper layers handle it, loosing single ping is 
non-critical for HB */
-          return GNUTLS_E_HEARTBEAT_PONG_FAILED;
-        }
-      break;
+          ("REC[%p]: received HEARTBEAT_REQUEST\n", session);
+
+      _gnutls_buffer_reset(&session->internals.hb_remote_data);
+
+      ret = _gnutls_buffer_resize (&session->internals.hb_remote_data, hb_len);
+      if (ret < 0)
+        return gnutls_assert_val(ret);
+      
+      memcpy(session->internals.hb_remote_data.data, msg+3, hb_len);
+      session->internals.hb_remote_data.length = hb_len;
+
+      return gnutls_assert_val(GNUTLS_E_HEARTBEAT_PING_RECEIVED);
 
     case HEARTBEAT_RESPONSE:
 
-      if (session->internals.heartbeat_payload.length != hb_len)
-        return gnutls_assert_val (GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+      if (hb_len != session->internals.hb_local_data.length)
+        return gnutls_assert_val (GNUTLS_E_UNEXPECTED_PACKET);
 
-      if (memcmp (msg + 3, session->internals.heartbeat_payload.data,
+      if (memcmp (msg + 3, session->internals.hb_local_data.data,
                   hb_len) != 0)
         {
           _gnutls_record_log ("REC[%p]: HB: %s - received\n", session,
                               _gnutls_bin2hex (msg + 3, hb_len, pr,
                                                sizeof (pr), NULL));
-          _gnutls_record_log ("REC[%p]: HB: %s - expected\n", session,
-                              _gnutls_bin2hex (session->internals.
-                                               heartbeat_payload.data,
-                                               hb_len, pr, sizeof (pr),
-                                               NULL));
-          return gnutls_assert_val (GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+          return gnutls_assert_val (GNUTLS_E_UNEXPECTED_PACKET);
         }
-      _gnutls_record_log
-          ("REC[%p]: HB: %zu response bytes received OK (%d msec. left before 
timeout)\n",
-           session, hb_len, gnutls_heartbeat_timeout (session, 1));
 
-      session->internals.dtls.heartbeat_timeout = HEARTBEAT_TIMEOUT;
-      _gnutls_buffer_reset (&session->internals.heartbeat_payload);
-      return GNUTLS_E_AGAIN;
+      _gnutls_buffer_reset (&session->internals.hb_local_data);
 
+      return gnutls_assert_val(GNUTLS_E_HEARTBEAT_PONG_RECEIVED);
     default:
       _gnutls_record_log
           ("REC[%p]: HB: received unknown type %u\n",
            session, msg[0]);
       return gnutls_assert_val (GNUTLS_E_UNEXPECTED_PACKET);
     }
-
-  return gnutls_assert_val (GNUTLS_E_INTERNAL_ERROR);
 }
 
-/**
- * Update HB timeouts: should be called on retransmit to set new timeout.
- * @check_only: guarantees lack of side-effects (no variables are written)
- *
- * Returns:
- * number of milliseconds left before timeout expiration OR
- * GNUTLS_E_TIMEDOUT if timeout expired
- * GNUTLS_E_SUCCESS if timeout updated
- * GNUTLS_E_ILLEGAL_PARAMETER if no HB message is in-flight
- **/
-int
-gnutls_heartbeat_timeout (gnutls_session_t session, int check_only)
-{
-  struct timespec now;
-  unsigned int ms;
-  if (session->internals.heartbeat_payload.length)
-    {
-      _gnutls_debug_log
-          ("HB: %zu bytes are in-flight already: %u msec timeout.\n",
-           session->internals.heartbeat_payload.length,
-           (unsigned int) session->internals.dtls.heartbeat_timeout);
-      gettime (&now);
-      ms = _dtls_timespec_sub_ms (&now,
-                                  &session->internals.dtls.heartbeat_sent);
-      if (ms > session->internals.dtls.heartbeat_timeout)
-        {
-          if (check_only)
-            return GNUTLS_E_TIMEDOUT;
-          _gnutls_buffer_reset (&session->internals.heartbeat_payload);
-
-          if (session->internals.dtls.heartbeat_timeout * 2 >
-              MAX_HEARTBEAT_TIMEOUT)
-            {                   /* update impossible */
-              session->internals.dtls.heartbeat_timeout =
-                  HEARTBEAT_TIMEOUT;
-              return GNUTLS_E_TIMEDOUT;
-            }
-          else
-            {
-              session->internals.dtls.heartbeat_timeout *= 2;
-              gettime (&session->internals.dtls.heartbeat_sent);
-              return GNUTLS_E_SUCCESS;
-            }
-        }
-      else
-        {
-          return ms;
-        }
-    }
-  return GNUTLS_E_ILLEGAL_PARAMETER;
-}
 
 static int
 _gnutls_heartbeat_recv_params (gnutls_session_t session,
diff --git a/lib/ext/heartbeat.h b/lib/ext/heartbeat.h
index 7c4b299..085d14c 100644
--- a/lib/ext/heartbeat.h
+++ b/lib/ext/heartbeat.h
@@ -28,7 +28,7 @@
 #define HEARTBEAT_REQUEST 1
 #define HEARTBEAT_RESPONSE 2
 
-#define MAX_HEARTBEAT_LENGTH 16384
+#define MAX_HEARTBEAT_LENGTH DEFAULT_MAX_RECORD_SIZE
 #define HEARTBEAT_TIMEOUT 1000
 #define MAX_HEARTBEAT_TIMEOUT 60000
 
@@ -42,11 +42,6 @@ extern extension_entry_st ext_mod_heartbeat;
 typedef uint8_t heartbeat_policy_t;
 
 int _gnutls_heartbeat_handle (gnutls_session_t session, mbuffer_st * bufel);
-ssize_t _gnutls_heartbeat_send_data (gnutls_session_t session,
-                                     const void *data, size_t data_size,
-                                     int request);
-ssize_t gnutls_heartbeat_ping (gnutls_session_t session, size_t data_size);
-ssize_t gnutls_heartbeat_ping_rnd (gnutls_session_t session);
 int _gnutls_heartbeat_enabled (gnutls_session_t session, int local);
 int gnutls_heartbeat_timeout (gnutls_session_t session, int check_only);
 #endif
diff --git a/lib/gnutls_buffers.c b/lib/gnutls_buffers.c
index 3dc10d2..30db033 100644
--- a/lib/gnutls_buffers.c
+++ b/lib/gnutls_buffers.c
@@ -49,6 +49,7 @@
 #include <gnutls_dtls.h>
 #include <system.h>
 #include <gnutls_constate.h> /* gnutls_epoch_get */
+#include <gnutls_handshake.h> /* remaining_time() */
 #include <errno.h>
 #include <system.h>
 #include "debug.h"
@@ -174,24 +175,27 @@ int errno_to_gerr(int err)
 
 static ssize_t
 _gnutls_dgram_read (gnutls_session_t session, mbuffer_st **bufel,
-                   gnutls_pull_func pull_func, unsigned int ms)
+                   gnutls_pull_func pull_func, unsigned int *ms)
 {
   ssize_t i, ret;
   uint8_t *ptr;
+  struct timespec t1, t2;
   size_t max_size = _gnutls_get_max_decrypted_data(session);
   size_t recv_size = MAX_RECV_SIZE(session);
   gnutls_transport_ptr_t fd = session->internals.transport_recv_ptr;
+  unsigned int diff;
 
   if (recv_size > max_size)
     recv_size = max_size;
 
   session->internals.direction = 0;
 
-  if (ms)
+  if (ms && *ms > 0)
     {
-      ret = _gnutls_io_check_recv(session, ms);
+      ret = _gnutls_io_check_recv(session, *ms);
       if (ret < 0)
         return gnutls_assert_val(ret);
+      gettime(&t1);
     }
 
   *bufel = _mbuffer_alloc (0, max_size);
@@ -228,6 +232,16 @@ _gnutls_dgram_read (gnutls_session_t session, mbuffer_st 
**bufel,
       _mbuffer_set_udata_size (*bufel, i);
     }
 
+  if (ms && *ms > 0)
+    {
+      gettime(&t2);
+      diff = _dtls_timespec_sub_ms(&t2, &t1);
+      if (diff < *ms)
+        *ms -= diff;
+      else
+        return gnutls_assert_val(GNUTLS_E_TIMEDOUT);
+    }
+
   _gnutls_read_log ("READ: read %d bytes from %p\n", (int) i, fd);
   
   return i;
@@ -239,7 +253,7 @@ cleanup:
 
 static ssize_t
 _gnutls_stream_read (gnutls_session_t session, mbuffer_st **bufel,
-                    size_t size, gnutls_pull_func pull_func, unsigned int ms)
+                    size_t size, gnutls_pull_func pull_func, unsigned int *ms)
 {
   size_t left;
   ssize_t i = 0;
@@ -263,9 +277,9 @@ _gnutls_stream_read (gnutls_session_t session, mbuffer_st 
**bufel,
   left = size;
   while (left > 0)
     {
-      if (ms)
+      if (ms && *ms > 0)
         {
-          ret = _gnutls_io_check_recv(session, ms);
+          ret = _gnutls_io_check_recv(session, *ms);
           if (ret < 0)
             return gnutls_assert_val(ret);
             
@@ -314,12 +328,12 @@ _gnutls_stream_read (gnutls_session_t session, mbuffer_st 
**bufel,
       left -= i;
       (*bufel)->msg.size += i;
 
-      if (ms && left)
+      if (ms && *ms > 0)
         {
           gettime(&t2);
           diff = _dtls_timespec_sub_ms(&t2, &t1);
-          if (diff < ms)
-            ms -= diff;
+          if (diff < *ms)
+            *ms -= diff;
           else
             return gnutls_assert_val(GNUTLS_E_TIMEDOUT);
         }
@@ -341,7 +355,7 @@ finish:
  */
 static ssize_t
 _gnutls_read (gnutls_session_t session, mbuffer_st **bufel,
-             size_t size, gnutls_pull_func pull_func, unsigned int ms)
+             size_t size, gnutls_pull_func pull_func, unsigned int *ms)
 {
   if (IS_DTLS (session))
     /* Size is not passed, since a whole datagram will be read. */
@@ -402,7 +416,10 @@ _gnutls_writev (gnutls_session_t session, const giovec_t * 
giovec,
   return i;
 }
 
-/* This function is like recv(with MSG_PEEK). But it does not return -1 on 
error.
+/* 
+ * @ms: a pointer to the number of milliseconds to wait for data. Use zero or 
NULL for indefinite.
+ *
+ * This function is like recv(with MSG_PEEK). But it does not return -1 on 
error.
  * It does return gnutls_errno instead.
  * This function reads data from the socket and keeps them in a buffer, of up 
to
  * MAX_RECV_SIZE. 
@@ -416,7 +433,7 @@ _gnutls_writev (gnutls_session_t session, const giovec_t * 
giovec,
  */
 ssize_t
 _gnutls_io_read_buffered (gnutls_session_t session, size_t total,
-                          content_type_t recv_type, unsigned int ms)
+                          content_type_t recv_type, unsigned int *ms)
 {
   ssize_t ret = 0;
   size_t min;
@@ -1170,6 +1187,7 @@ _gnutls_handshake_io_recv_int (gnutls_session_t session,
                                handshake_buffer_st * hsk, unsigned int 
optional)
 {
   int ret;
+  unsigned int tleft = 0;
 
   ret = get_last_packet(session, htype, hsk, optional);
   if (ret != GNUTLS_E_AGAIN && ret != GNUTLS_E_INTERRUPTED && ret != 
GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
@@ -1195,9 +1213,17 @@ _gnutls_handshake_io_recv_int (gnutls_session_t session,
         return gnutls_assert_val(ret);
     }
 
+  if (htype != (unsigned)-1)
+    {
+      ret = handshake_remaining_time(session);
+      if (ret < 0)
+        return gnutls_assert_val(ret);
+      tleft = ret;
+    }
+
   /* if we don't have a complete message waiting for us, try 
    * receiving more */
-  ret = _gnutls_recv_in_buffers(session, GNUTLS_HANDSHAKE, htype);
+  ret = _gnutls_recv_in_buffers(session, GNUTLS_HANDSHAKE, htype, tleft);
   if (ret < 0)
     return gnutls_assert_val_fatal(ret);
 
diff --git a/lib/gnutls_buffers.h b/lib/gnutls_buffers.h
index 52106ac..193e97f 100644
--- a/lib/gnutls_buffers.h
+++ b/lib/gnutls_buffers.h
@@ -53,7 +53,7 @@ record_check_unprocessed (gnutls_session_t session)
 int _gnutls_record_buffer_get (content_type_t type,
                                gnutls_session_t session, uint8_t * data,
                                size_t length, uint8_t seq[8]);
-ssize_t _gnutls_io_read_buffered (gnutls_session_t, size_t n, content_type_t, 
unsigned int ms);
+ssize_t _gnutls_io_read_buffered (gnutls_session_t, size_t n, content_type_t, 
unsigned int *ms);
 int _gnutls_io_clear_peeked_data (gnutls_session_t session);
 
 ssize_t _gnutls_io_write_buffered (gnutls_session_t session,
@@ -109,7 +109,7 @@ _gnutls_parse_record_buffered_msgs (gnutls_session_t 
session);
 
 ssize_t
 _gnutls_recv_in_buffers (gnutls_session_t session, content_type_t type,
-                         gnutls_handshake_description_t htype);
+                         gnutls_handshake_description_t htype, unsigned int 
ms);
 
 #define _gnutls_handshake_io_buffer_clear( session) \
         _mbuffer_head_clear( &session->internals.handshake_send_buffer); \
diff --git a/lib/gnutls_dtls.c b/lib/gnutls_dtls.c
index ae6faf9..54c5681 100644
--- a/lib/gnutls_dtls.c
+++ b/lib/gnutls_dtls.c
@@ -179,7 +179,7 @@ static int is_next_hpacket_expected(gnutls_session_t 
session)
 int ret;
 
   /* htype is arbitrary */
-  ret = _gnutls_recv_in_buffers(session, GNUTLS_HANDSHAKE, 
GNUTLS_HANDSHAKE_FINISHED);
+  ret = _gnutls_recv_in_buffers(session, GNUTLS_HANDSHAKE, 
GNUTLS_HANDSHAKE_FINISHED, 0);
   if (ret < 0)
     return gnutls_assert_val(ret);
   
diff --git a/lib/gnutls_errors.c b/lib/gnutls_errors.c
index b43771f..2a14f74 100644
--- a/lib/gnutls_errors.c
+++ b/lib/gnutls_errors.c
@@ -93,10 +93,10 @@ static const gnutls_error_entry error_algorithms[] = {
                GNUTLS_E_NO_CERTIFICATE_FOUND, 1),
   ERROR_ENTRY (N_("The given DSA key is incompatible with the selected TLS 
protocol."),
                GNUTLS_E_INCOMPAT_DSA_KEY_WITH_TLS_PROTOCOL, 1),
-  ERROR_ENTRY (N_("HeartBeat Response to Request has failed for some reason: 
pong dropped."),
-               GNUTLS_E_HEARTBEAT_PONG_FAILED, 1),
-  ERROR_ENTRY (N_("HeartBeat message is already in-flight."),
-               GNUTLS_E_HEARTBEAT_FLIGHT, 1),
+  ERROR_ENTRY (N_("A heartbeat pong message was received."),
+               GNUTLS_E_HEARTBEAT_PONG_RECEIVED, 0),
+  ERROR_ENTRY (N_("A heartbeat ping message was received."),
+               GNUTLS_E_HEARTBEAT_PING_RECEIVED, 0),
   ERROR_ENTRY (N_("There is already a crypto algorithm with lower priority."),
                GNUTLS_E_CRYPTO_ALREADY_REGISTERED, 1),
 
diff --git a/lib/gnutls_handshake.c b/lib/gnutls_handshake.c
index edb736b..1eb5d6b 100644
--- a/lib/gnutls_handshake.c
+++ b/lib/gnutls_handshake.c
@@ -2725,6 +2725,12 @@ _gnutls_recv_handshake_final (gnutls_session_t session, 
int init)
   int ret = 0;
   uint8_t ch;
   unsigned int ccs_len = 1;
+  unsigned int tleft;
+  
+  ret = handshake_remaining_time(session);
+  if (ret < 0)
+    return gnutls_assert_val(ret);
+  tleft = ret;
 
   switch (STATE)
     {
@@ -2747,7 +2753,8 @@ _gnutls_recv_handshake_final (gnutls_session_t session, 
int init)
       if (gnutls_protocol_get_version (session) == GNUTLS_DTLS0_9)
         ccs_len = 3;
 
-      ret = _gnutls_recv_int (session, GNUTLS_CHANGE_CIPHER_SPEC, -1, &ch, 
ccs_len, NULL);
+      ret = _gnutls_recv_int (session, GNUTLS_CHANGE_CIPHER_SPEC, -1, &ch, 
ccs_len, NULL, 
+                              tleft);
       if (ret <= 0)
         {
           ERR ("recv ChangeCipherSpec", ret);
diff --git a/lib/gnutls_handshake.h b/lib/gnutls_handshake.h
index 22a55f7..4fa14f3 100644
--- a/lib/gnutls_handshake.h
+++ b/lib/gnutls_handshake.h
@@ -23,6 +23,8 @@
 #ifndef HANDSHAKE_H
 #define HANDSHAKE_H
 
+#include <gnutls_errors.h>
+
 int _gnutls_send_handshake (gnutls_session_t session, mbuffer_st * bufel,
                             gnutls_handshake_description_t type);
 int _gnutls_recv_hello_request (gnutls_session_t session, void *data,
@@ -55,4 +57,17 @@ void _gnutls_handshake_hash_buffers_clear (gnutls_session_t 
session);
 #define AGAIN(target) (STATE==target?1:0)
 #define AGAIN2(state, target) (state==target?1:0)
 
+inline static int handshake_remaining_time(gnutls_session_t session)
+{
+  if (session->internals.handshake_endtime)
+    {
+      time_t now = gnutls_time(0);
+      if (now < session->internals.handshake_endtime)
+        return (session->internals.handshake_endtime - now) * 1000;
+      else 
+        return gnutls_assert_val(GNUTLS_E_TIMEDOUT);
+    }
+  return 0;
+}
+
 #endif
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index d80c2a7..5462789 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -230,6 +230,13 @@ typedef enum handshake_state_t
   STATE60 = 60, STATE61, STATE62, STATE70, STATE71
 } handshake_state_t;
 
+typedef enum heartbeat_state_t
+{  
+  SHB_SEND1 = 0, 
+  SHB_SEND2, 
+  SHB_RECV, 
+} heartbeat_state_t;
+
 #include <gnutls_str.h>
 
 /* This is the maximum number of algorithms (ciphers or macs etc).
@@ -660,9 +667,6 @@ typedef struct
    */
   time_t async_term;
 
-  struct timespec heartbeat_sent; /* timestamp: when last HeartBeat Request 
was sent*/
-  time_t heartbeat_timeout; /* current timeout, in milliseconds*/
-
   /* last retransmission triggered by record layer */
   struct timespec last_retransmit;
   unsigned int packets_dropped;
@@ -890,14 +894,19 @@ typedef struct
   /* if set it means that the master key was set using
    * gnutls_session_set_master() rather than being negotiated. */
   unsigned int premaster_set:1;
-
+  
   unsigned int cb_tls_unique_len;
   unsigned char cb_tls_unique[MAX_VERIFY_DATA_SIZE];
   
   unsigned int handshake_endtime; /* end time in seconds */
   unsigned int handshake_timeout_ms; /* timeout in milliseconds */
 
-  gnutls_buffer_st heartbeat_payload; /* store in-flight payload for heartbeat 
extension*/
+  gnutls_buffer_st hb_local_data;
+  gnutls_buffer_st hb_remote_data;
+  struct timespec hb_ping_sent; /* timestamp: when last HeartBeat ping was 
sent*/
+  unsigned int hb_timeout; /* current timeout, in milliseconds*/
+
+  heartbeat_state_t hb_state; /* for ping */
   
   /* If you add anything here, check _gnutls_handshake_internal_state_clear().
    */
diff --git a/lib/gnutls_record.c b/lib/gnutls_record.c
index 2a61633..79b4904 100644
--- a/lib/gnutls_record.c
+++ b/lib/gnutls_record.c
@@ -220,7 +220,7 @@ gnutls_bye (gnutls_session_t session, 
gnutls_close_request_t how)
         {
           do
             {
-              ret = _gnutls_recv_int (session, GNUTLS_ALERT, -1, NULL, 0, 
NULL);
+              ret = _gnutls_recv_int (session, GNUTLS_ALERT, -1, NULL, 0, 
NULL, 0);
             }
           while (ret == GNUTLS_E_GOT_APPLICATION_DATA);
 
@@ -508,7 +508,6 @@ check_buffers (gnutls_session_t session, content_type_t 
type,
 {
   if ((type == GNUTLS_APPLICATION_DATA ||
        type == GNUTLS_HANDSHAKE ||
-       type == GNUTLS_HEARTBEAT ||
        type == GNUTLS_CHANGE_CIPHER_SPEC)
       && _gnutls_record_buffer_get_size (session) > 0)
     {
@@ -591,7 +590,6 @@ record_add_to_buffers (gnutls_session_t session,
   if ((recv->type == type)
       && (type == GNUTLS_APPLICATION_DATA ||
           type == GNUTLS_CHANGE_CIPHER_SPEC ||
-         type == GNUTLS_HEARTBEAT ||
           type == GNUTLS_HANDSHAKE))
     {
       _gnutls_record_buffer_put (session, type, seq, bufel);
@@ -874,7 +872,7 @@ record_read_headers (gnutls_session_t session,
 static int recv_headers( gnutls_session_t session, content_type_t type, 
                          gnutls_handshake_description_t htype, 
                          struct tls_record_st* record,
-                         unsigned int ms)
+                         unsigned int *ms)
 {
 int ret;
 gnutls_datum_t raw; /* raw headers */
@@ -952,7 +950,9 @@ gnutls_datum_t raw; /* raw headers */
 
 #define MAX_EMPTY_PACKETS_SEQUENCE 4
 
-/* This will receive record layer packets and add them to 
+/* @ms: is the number of milliseconds to wait for data. Use zero for 
indefinite.
+ *
+ * This will receive record layer packets and add them to 
  * application_data_buffer and handshake_data_buffer.
  *
  * If the htype is not -1 then handshake timeouts
@@ -960,7 +960,7 @@ gnutls_datum_t raw; /* raw headers */
  */
 ssize_t
 _gnutls_recv_in_buffers (gnutls_session_t session, content_type_t type,
-                         gnutls_handshake_description_t htype)
+                         gnutls_handshake_description_t htype, unsigned int ms)
 {
   uint64 *packet_sequence;
   uint8_t *ciphertext;
@@ -970,7 +970,6 @@ _gnutls_recv_in_buffers (gnutls_session_t session, 
content_type_t type,
   record_parameters_st *record_params;
   record_state_st *record_state;
   struct tls_record_st record;
-  time_t now, tleft = 0;
 
 begin:
 
@@ -1003,17 +1002,8 @@ begin:
 
   record_state = &record_params->read;
 
-  if (htype != (unsigned)-1 && session->internals.handshake_endtime > 0)
-    {
-      now = gnutls_time(0);
-      if (now < session->internals.handshake_endtime)
-        tleft = (session->internals.handshake_endtime - now) * 1000;
-      else
-        return gnutls_assert_val(GNUTLS_E_TIMEDOUT);
-    }
-
   /* receive headers */
-  ret = recv_headers(session, type, htype, &record, tleft);
+  ret = recv_headers(session, type, htype, &record, &ms);
   if (ret < 0)
     {
       ret = gnutls_assert_val_fatal(ret);
@@ -1025,20 +1015,11 @@ begin:
   else
     packet_sequence = &record_state->sequence_number;
 
-  if (htype != (unsigned)-1 && session->internals.handshake_endtime > 0)
-    {
-      now = gnutls_time(0);
-      if (now < session->internals.handshake_endtime)
-        tleft = (session->internals.handshake_endtime - now) * 1000;
-      else
-        return gnutls_assert_val(GNUTLS_E_TIMEDOUT);
-    }
-
   /* Read the packet data and insert it to record_recv_buffer.
    */
   ret =
        _gnutls_io_read_buffered (session, record.packet_size,
-                                 record.type, tleft);
+                                 record.type, &ms);
   if (ret != record.packet_size)
     {
       gnutls_assert();
@@ -1178,7 +1159,7 @@ cleanup:
   return ret;
 
 recv_error:
-  if (ret < 0 && gnutls_error_is_fatal (ret) == 0)
+  if (ret < 0 && (gnutls_error_is_fatal (ret) == 0 || ret == 
GNUTLS_E_TIMEDOUT))
     return ret;
 
   if (IS_DTLS(session))
@@ -1210,14 +1191,13 @@ recv_error:
 ssize_t
 _gnutls_recv_int (gnutls_session_t session, content_type_t type,
                   gnutls_handshake_description_t htype,
-                  uint8_t * data, size_t data_size, void* seq)
+                  uint8_t * data, size_t data_size, void* seq,
+                  unsigned int ms)
 {
   int ret;
 
-  if (type != GNUTLS_ALERT && (data_size == 0 || data == NULL))
-    {
-      return GNUTLS_E_INVALID_REQUEST;
-    }
+  if ((type != GNUTLS_ALERT && type != GNUTLS_HEARTBEAT) && (data_size == 0 || 
data == NULL))
+    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
 
   if (session->internals.read_eof != 0)
     {
@@ -1241,7 +1221,7 @@ _gnutls_recv_int (gnutls_session_t session, 
content_type_t type,
   if (ret != 0)
     return ret;
 
-  ret = _gnutls_recv_in_buffers(session, type, htype);
+  ret = _gnutls_recv_in_buffers(session, type, htype, ms);
   if (ret < 0 && ret != GNUTLS_E_SESSION_EOF)
     return gnutls_assert_val(ret);
 
@@ -1312,8 +1292,9 @@ gnutls_record_send (gnutls_session_t session, const void 
*data,
  * The number of bytes received might be less than the requested @data_size.
  **/
 ssize_t
-gnutls_record_recv (gnutls_session_t session, void *data, size_t data_size) {
-    return _gnutls_recv_int (session, GNUTLS_APPLICATION_DATA, -1, data, 
data_size, NULL);
+gnutls_record_recv (gnutls_session_t session, void *data, size_t data_size) 
+{
+    return _gnutls_recv_int (session, GNUTLS_APPLICATION_DATA, -1, data, 
data_size, NULL, 0);
 }
 
 /**
@@ -1341,5 +1322,5 @@ gnutls_record_recv_seq (gnutls_session_t session, void 
*data, size_t data_size,
   unsigned char *seq)
 {
   return _gnutls_recv_int (session, GNUTLS_APPLICATION_DATA, -1, data,
-                           data_size, seq);
+                           data_size, seq, 0);
 }
diff --git a/lib/gnutls_record.h b/lib/gnutls_record.h
index 4151673..12cc31a 100644
--- a/lib/gnutls_record.h
+++ b/lib/gnutls_record.h
@@ -32,7 +32,7 @@ ssize_t _gnutls_send_int (gnutls_session_t session, 
content_type_t type,
                           size_t sizeofdata, unsigned int mflags);
 ssize_t _gnutls_recv_int (gnutls_session_t session, content_type_t type,
                           gnutls_handshake_description_t, uint8_t * data,
-                          size_t sizeofdata, void* seq);
+                          size_t sizeofdata, void* seq, unsigned int ms);
 int _gnutls_get_max_decrypted_data(gnutls_session_t session);
 
 #endif
diff --git a/lib/gnutls_state.c b/lib/gnutls_state.c
index a2feb5b..6adfd41 100644
--- a/lib/gnutls_state.c
+++ b/lib/gnutls_state.c
@@ -326,7 +326,8 @@ gnutls_init (gnutls_session_t * session, unsigned int flags)
 
   /* Initialize buffers */
   _gnutls_buffer_init (&(*session)->internals.handshake_hash_buffer);
-  _gnutls_buffer_init (&(*session)->internals.heartbeat_payload);
+  _gnutls_buffer_init (&(*session)->internals.hb_remote_data);
+  _gnutls_buffer_init (&(*session)->internals.hb_local_data);
 
   _mbuffer_head_init (&(*session)->internals.record_buffer);
   _mbuffer_head_init (&(*session)->internals.record_send_buffer);
@@ -441,7 +442,8 @@ gnutls_deinit (gnutls_session_t session)
       }
 
   _gnutls_buffer_clear (&session->internals.handshake_hash_buffer);
-  _gnutls_buffer_clear (&session->internals.heartbeat_payload);
+  _gnutls_buffer_clear (&session->internals.hb_remote_data);
+  _gnutls_buffer_clear (&session->internals.hb_local_data);
 
   _mbuffer_head_clear (&session->internals.record_buffer);
   _mbuffer_head_clear (&session->internals.record_recv_buffer);
diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in
index b1685cd..ce77a8a 100644
--- a/lib/includes/gnutls/gnutls.h.in
+++ b/lib/includes/gnutls/gnutls.h.in
@@ -857,8 +857,11 @@ gnutls_ecc_curve_t gnutls_ecc_curve_get(gnutls_session_t 
session);
 
 /* Record layer functions.
  */
-  ssize_t gnutls_heartbeat_ping (gnutls_session_t session, size_t data_size);
-  ssize_t gnutls_heartbeat_ping_rnd (gnutls_session_t session);
+#define GNUTLS_HEARTBEAT_WAIT 1
+  int gnutls_heartbeat_ping (gnutls_session_t session, size_t data_size, 
+                       unsigned int max_tries, unsigned int flags);
+  int gnutls_heartbeat_pong (gnutls_session_t session, unsigned int flags);
+
   ssize_t gnutls_record_send (gnutls_session_t session, const void *data,
                               size_t data_size);
   ssize_t gnutls_record_recv (gnutls_session_t session, void *data,
@@ -912,10 +915,11 @@ gnutls_ecc_curve_t gnutls_ecc_curve_get(gnutls_session_t 
session);
 #define GNUTLS_HB_PEER_ALLOWED_TO_SEND (1)
 #define GNUTLS_HB_PEER_NOT_ALLOWED_TO_SEND (1<<1)
 
-    /* Heartbeat */
-    void gnutls_heartbeat_enable (gnutls_session_t session, unsigned int type);
-    int gnutls_heartbeat_allowed (gnutls_session_t session, unsigned int type);
-    int gnutls_heartbeat_timeout (gnutls_session_t session, int check_only);
+  /* Heartbeat */
+  void gnutls_heartbeat_enable (gnutls_session_t session, unsigned int type);
+
+#define GNUTLS_HB_LOCAL_ALLOWED_TO_SEND (1<<2)
+  int gnutls_heartbeat_allowed (gnutls_session_t session, unsigned int type);
 
   /* Safe renegotiation */
   int gnutls_safe_renegotiation_status (gnutls_session_t session);
@@ -1977,8 +1981,8 @@ typedef int (*gnutls_pin_callback_t) (void *userdata, int 
attempt,
 #define GNUTLS_E_OPENPGP_PREFERRED_KEY_ERROR -215
 #define GNUTLS_E_INCOMPAT_DSA_KEY_WITH_TLS_PROTOCOL -216
 
-#define GNUTLS_E_HEARTBEAT_FLIGHT -298
-#define GNUTLS_E_HEARTBEAT_PONG_FAILED -299
+#define GNUTLS_E_HEARTBEAT_PONG_RECEIVED -292
+#define GNUTLS_E_HEARTBEAT_PING_RECEIVED -293
 
 /* PKCS11 related */
 #define GNUTLS_E_PKCS11_ERROR -300
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index 032ee64..110209c 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -302,7 +302,7 @@ GNUTLS_1_4
     gnutls_record_send;
     gnutls_record_set_max_size;
     gnutls_heartbeat_ping;
-    gnutls_heartbeat_ping_rnd;
+    gnutls_heartbeat_pong;
     gnutls_rehandshake;
     gnutls_rsa_export_get_modulus_bits;
     gnutls_rsa_export_get_pubkey;
@@ -337,7 +337,6 @@ GNUTLS_1_4
     gnutls_sign_list;
     gnutls_heartbeat_enable;
     gnutls_heartbeat_allowed;
-    gnutls_heartbeat_timeout;
     gnutls_srp_1024_group_generator;
     gnutls_srp_1024_group_prime;
     gnutls_srp_1536_group_generator;
diff --git a/lib/x509/common.c b/lib/x509/common.c
index 9409141..56bc0d6 100644
--- a/lib/x509/common.c
+++ b/lib/x509/common.c
@@ -538,7 +538,6 @@ time2gtime (const char *ttime, int year)
     {
       memcpy (xx, ttime, 2);
       etime.tm_sec = atoi (xx);
-      ttime += 2;
     }
   else
     etime.tm_sec = 0;
diff --git a/lib/x509/dn.c b/lib/x509/dn.c
index 810c015..5152691 100644
--- a/lib/x509/dn.c
+++ b/lib/x509/dn.c
@@ -178,6 +178,12 @@ _gnutls_x509_parse_dn (ASN1_TYPE asn1_struct,
 
           len = 0;
           result = asn1_read_value (asn1_struct, tmpbuffer3, NULL, &len);
+          if (result != ASN1_MEM_ERROR)
+            {
+              gnutls_assert ();
+              result = _gnutls_asn2err (result);
+              goto cleanup;
+            }
 
           value2 = gnutls_malloc (len);
           if (value2 == NULL)
diff --git a/src/common.c b/src/common.c
index 4b21e22..2bccedc 100644
--- a/src/common.c
+++ b/src/common.c
@@ -1042,6 +1042,8 @@ print_list (const char *priorities, int verbose)
 int check_command(gnutls_session_t session, const char* str)
 {
   size_t len = strnlen(str, 128);
+  int ret;
+
   fprintf (stderr, "*** Processing %zu bytes command: %s\n", len, str);
   if (len > 2 && str[0] == str[1] && str[0] == '*')
   {
@@ -1051,7 +1053,19 @@ int check_command(gnutls_session_t session, const char* 
str)
          gnutls_rehandshake (session);
           return 1;
       } else if (strncmp(str, "**HEARTBEAT**", sizeof ("**HEARTBEAT**") - 1) 
== 0) {
-         gnutls_heartbeat_ping_rnd (session);
+         ret = gnutls_heartbeat_ping (session, 300, 5, GNUTLS_HEARTBEAT_WAIT);
+         if (ret < 0)
+           {
+             if (ret == GNUTLS_E_INVALID_REQUEST)
+               {
+                 fprintf(stderr, "No heartbeat in this session\n");
+               }
+              else
+                {
+                 fprintf(stderr, "ping: %s\n", gnutls_strerror(ret));
+                 exit(1);
+                }
+           }
          return 2;
       }
   }
diff --git a/src/serv.c b/src/serv.c
index b1e5a49..d3dc350 100644
--- a/src/serv.c
+++ b/src/serv.c
@@ -1342,6 +1342,10 @@ tcp_server (const char *name, int port)
               {
                 r = gnutls_record_recv (j->tls_session, buf,
                                         MIN (1024, SMALL_READ_TEST));
+                if (r == GNUTLS_E_HEARTBEAT_PING_RECEIVED)
+                  {
+                    gnutls_heartbeat_pong(j->tls_session, 0);
+                  }
                 if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN)
                   {
                     /* do nothing */
@@ -1376,10 +1380,7 @@ tcp_server (const char *name, int port)
                       {
                         if (r < 0)
                           {
-                            if (GNUTLS_E_HEARTBEAT_PONG_FAILED == r)
-                              fprintf (stderr,
-                                       "HeartBeat pong failed, ping 
dropped\n");
-                            else if (r != GNUTLS_E_UNEXPECTED_PACKET_LENGTH)
+                            if (r != GNUTLS_E_UNEXPECTED_PACKET_LENGTH)
                               {
                                 j->http_state = HTTP_STATE_CLOSING;
                                 check_alert (j->tls_session, r);
diff --git a/src/socket.c b/src/socket.c
index b33f6bc..c504885 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -50,15 +50,16 @@ socket_recv (const socket_st * socket, void *buffer, int 
buffer_size)
   int ret;
 
   if (socket->secure)
-    do
-      {
-        ret = gnutls_record_recv (socket->session, buffer, buffer_size);
-       if (GNUTLS_E_HEARTBEAT_PONG_FAILED == ret) {
-           fprintf (stderr, "HeartBeat pong failed, ping dropped\n");
-           ret = GNUTLS_E_AGAIN;
-       }
-      }
-    while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
+    {
+      do
+        {
+          ret = gnutls_record_recv (socket->session, buffer, buffer_size);
+          if (ret == GNUTLS_E_HEARTBEAT_PING_RECEIVED)
+            gnutls_heartbeat_pong(socket->session, 0);
+        }
+      while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN || ret == 
GNUTLS_E_HEARTBEAT_PING_RECEIVED);
+
+    }
   else
     do
       {
diff --git a/src/udp-serv.c b/src/udp-serv.c
index 478435f..08d2677 100644
--- a/src/udp-serv.c
+++ b/src/udp-serv.c
@@ -144,9 +144,13 @@ void udp_server(const char* name, int port, int mtu)
 
         for(;;)
           {
-            do {
-              ret = gnutls_record_recv_seq(session, buffer, MAX_BUFFER, 
sequence);
-            } while(ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
+            do 
+              {
+                ret = gnutls_record_recv_seq(session, buffer, MAX_BUFFER, 
sequence);
+                if (ret == GNUTLS_E_HEARTBEAT_PING_RECEIVED)
+                  gnutls_heartbeat_pong(session, 0);
+              }
+            while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN || ret 
== GNUTLS_E_HEARTBEAT_PING_RECEIVED);
 
             if (ret == GNUTLS_E_REHANDSHAKE)
               {
diff --git a/tests/cert-tests/ca-no-pathlen.pem 
b/tests/cert-tests/ca-no-pathlen.pem
index b2f6448..070be43 100644
--- a/tests/cert-tests/ca-no-pathlen.pem
+++ b/tests/cert-tests/ca-no-pathlen.pem
@@ -7,7 +7,7 @@ X.509 Certificate Information:
                Not After: Sat Jan 27 10:00:06 UTC 2007
        Subject: O=GnuTLS test certificate
        Subject Public Key Algorithm: RSA
-       Certificate Security Level: Low (512 bits)
+       Certificate Security Level: Insecure (512 bits)
                Modulus (bits 512):
                        00:a1:63:53:6b:54:95:ac:3c:a4:4b:4b:6a:ba:c0:9c
                        11:ad:28:dd:03:a8:c0:f4:17:bf:18:cd:9f:b3:5a:d1
diff --git a/tests/cert-tests/no-ca-or-pathlen.pem 
b/tests/cert-tests/no-ca-or-pathlen.pem
index 258e61e..086feb4 100644
--- a/tests/cert-tests/no-ca-or-pathlen.pem
+++ b/tests/cert-tests/no-ca-or-pathlen.pem
@@ -7,7 +7,7 @@ X.509 Certificate Information:
                Not After: Fri Aug 25 23:59:59 UTC 2000
        Subject: O=VeriSign\, Inc.,OU=VeriSign Trust 
Network,OU=www.verisign.com/repository/RPA Incorp. by 
Ref.\,LIAB.LTD(c)98,OU=Persona Not Validated,OU=Digital ID Class 1 - 
Netscape,CN=Simon Josefsson,address@hidden
        Subject Public Key Algorithm: RSA
-       Certificate Security Level: Low (1024 bits)
+       Certificate Security Level: Weak (1024 bits)
                Modulus (bits 1024):
                        00:c9:0c:ce:8a:fe:71:46:9b:ca:1d:e5:90:12:a5:11
                        0b:c6:2d:c4:33:c6:19:e8:60:59:4e:3f:64:3d:e4:f7


hooks/post-receive
-- 
GNU gnutls



reply via email to

[Prev in Thread] Current Thread [Next in Thread]