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_2_9_9-38-g5a92d28


From: Nikos Mavrogiannopoulos
Subject: [SCM] GNU gnutls branch, master, updated. gnutls_2_9_9-38-g5a92d28
Date: Tue, 12 Jan 2010 19:19:13 +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=5a92d28f74951356705d4e6698b9315980911f87

The branch, master has been updated
       via  5a92d28f74951356705d4e6698b9315980911f87 (commit)
       via  1344b312402d3b831f2839f4a58190fd4fa380f0 (commit)
       via  aee636d85d54d7d67e9dbaaa0b354f0ae3038b44 (commit)
       via  3275e1c09bc9c74946ebdaa87c71b71371aeccc4 (commit)
       via  a20d9828ae55f032752addcad4228c624f9094fa (commit)
       via  1a338cbaaeec11d958de8da4d1ae036979fccf3e (commit)
       via  581718c927838474200c305587241ae15511cb82 (commit)
      from  74d964c9f72bfa238ad485f20e46ece4336556eb (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 5a92d28f74951356705d4e6698b9315980911f87
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Tue Jan 12 20:17:07 2010 +0100

    When resuming no extensions were parsed thus the safe
    renegotiation extension was ignored as well causing a
    false detection of unsafe session. Corrected by making
    a special class of extensions called RESUMED. Those are
    parsed even when resuming (normally we don't do it to
    prevent clients overwriting capabilities and credentials).

commit 1344b312402d3b831f2839f4a58190fd4fa380f0
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Tue Jan 12 19:39:50 2010 +0100

    Added Steve Dispensa's patch for safe renegotiation (with artistic changes).
    Effectively reverted my previous patch 
1a338cbaaeec11d958de8da4d1ae036979fccf3e.

commit aee636d85d54d7d67e9dbaaa0b354f0ae3038b44
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Tue Jan 12 19:17:28 2010 +0100

    Updated thanks file.

commit 3275e1c09bc9c74946ebdaa87c71b71371aeccc4
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Tue Jan 12 18:34:39 2010 +0100

    When checking self signature also check the signatures of all subkeys.
    Ilari Liusvaara noticed and reported the issue and provided test vectors as 
well.
    
    certtool --pgp-certificate-info will check self signatures.
    
    Added self tests for self-sigs.

commit a20d9828ae55f032752addcad4228c624f9094fa
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Mon Jan 11 20:25:31 2010 +0100

    hash_fast -> hmac_fast

commit 1a338cbaaeec11d958de8da4d1ae036979fccf3e
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun Jan 10 14:21:42 2010 +0100

    Added safe renegotiation patch from Steve Dispensa, modified to suit gnutls
    code style and error checking. Modified to conform to 
draft-ietf-tls-renegotiation-03.txt.
    
    gnutls-cli will search input for **RENEGOTIATION** to perform a 
renegotiation
    and gnutls-serv will perform one if requested.

commit 581718c927838474200c305587241ae15511cb82
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun Jan 10 12:30:11 2010 +0100

    Corrections for --disable-extra-pki configure flag to work. Patch by Bill 
Randle.

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

Summary of changes:
 NEWS                                               |    4 +
 THANKS                                             |    2 +
 doc/manpages/gnutls-cli.1                          |    3 +
 doc/manpages/gnutls-serv.1                         |    3 +
 lib/Makefile.am                                    |    5 +-
 lib/ext_safe_renegotiation.c                       |  128 ++++++
 ...{auth_psk_passwd.h => ext_safe_renegotiation.h} |   15 +-
 lib/gnutls_alert.c                                 |    1 +
 lib/gnutls_algorithms.c                            |    7 +
 lib/gnutls_algorithms.h                            |    3 +
 lib/gnutls_errors.c                                |    2 +
 lib/gnutls_extensions.c                            |   12 +-
 lib/gnutls_extensions.h                            |    2 +
 lib/gnutls_handshake.c                             |  407 ++++++++++++++++----
 lib/gnutls_int.h                                   |   22 +-
 lib/gnutls_priority.c                              |   10 +
 lib/includes/gnutls/gnutls.h.in                    |    9 +-
 lib/opencdk/sig-check.c                            |   80 +++--
 lib/x509/mpi.c                                     |    4 +
 src/certtool.c                                     |   18 +-
 src/cli.c                                          |   11 +
 src/serv.c                                         |   24 +-
 tests/gc.c                                         |   16 +-
 tests/openpgp-certs/Makefile.am                    |   10 +-
 .../selfsigs/alice-mallory-badsig18.pub            |  Bin 0 -> 1118 bytes
 .../selfsigs/alice-mallory-irrelevantsig.pub       |  Bin 0 -> 1071 bytes
 .../selfsigs/alice-mallory-nosig18.pub             |  Bin 0 -> 971 bytes
 tests/openpgp-certs/selfsigs/alice.pub             |  Bin 0 -> 1118 bytes
 tests/openpgp-certs/testselfsigs                   |   24 ++
 tests/resume.c                                     |   21 +-
 30 files changed, 698 insertions(+), 145 deletions(-)
 create mode 100644 lib/ext_safe_renegotiation.c
 copy lib/{auth_psk_passwd.h => ext_safe_renegotiation.h} (72%)
 create mode 100644 tests/openpgp-certs/selfsigs/alice-mallory-badsig18.pub
 create mode 100644 tests/openpgp-certs/selfsigs/alice-mallory-irrelevantsig.pub
 create mode 100644 tests/openpgp-certs/selfsigs/alice-mallory-nosig18.pub
 create mode 100644 tests/openpgp-certs/selfsigs/alice.pub
 create mode 100755 tests/openpgp-certs/testselfsigs

diff --git a/NEWS b/NEWS
index eee6dd6..aa7f8d0 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,9 @@ See the end for copying conditions.
 
 * Version 2.9.10 (unreleased)
 
+** libgnutls: When checking self signature also check the signatures of all 
subkeys.                                                                        
                                     
+Ilari Liusvaara noticed and reported the issue and provided test vectors as 
well.
+
 ** libgnutls: Added cryptodev support (/dev/crypto). Tested with
 http://www.logix.cz/michal/devel/cryptodev/. Added benchmark utility 
 for AES. Exported API to access encryption and hash algorithms.
@@ -18,6 +21,7 @@ them does not seem to offer anything (anyway you need the 
signer's certificate
 to verify thus public key will be available). Found thanks to Boyan Kasarov.
 This however has the side-effect that public key IDs shown by certtool are
 now different than previous gnutls releases.
+(3) the option --pgp-certificate-info will verify self signatures
 
 ** certtool: Allow exporting of Certificate requests on DER format.
 
diff --git a/THANKS b/THANKS
index e08effa..a4a72f8 100644
--- a/THANKS
+++ b/THANKS
@@ -102,6 +102,8 @@ Daiki Ueno                      <address@hidden>
 Tomas Hoger                     <address@hidden>
 Fabian Keil                     <address@hidden>
 Jason Pettiss                   <address@hidden>
+Ilari Liusvaara                 <address@hidden>
+Steve Dispensa                  <address@hidden>
 
 ----------------------------------------------------------------------
 Copying and distribution of this file, with or without modification,
diff --git a/doc/manpages/gnutls-cli.1 b/doc/manpages/gnutls-cli.1
index 82823a3..6ca8da4 100644
--- a/doc/manpages/gnutls-cli.1
+++ b/doc/manpages/gnutls-cli.1
@@ -78,6 +78,9 @@ Special keywords:
 "%SSL3_RECORD_VERSION" force SSL3.0 record version in the first client
 hello. This is to avoid buggy servers from terminating connection.
 .IP
+"%UNSAFE_RENEGOTIATION" will enable unsafe renegotiation (default
+behaviour at 2.8.5 and earlier releases)
+.IP
 To avoid collisions in order to specify a compression algorithm in
 this string you have to prefix it with "COMP-", protocol versions
 with "VERS-" and certificate types with "CTYPE-". All other
diff --git a/doc/manpages/gnutls-serv.1 b/doc/manpages/gnutls-serv.1
index 9b8c425..e1b5bd1 100644
--- a/doc/manpages/gnutls-serv.1
+++ b/doc/manpages/gnutls-serv.1
@@ -75,6 +75,9 @@ Special keywords:
 .IP
 "%COMPAT" will enable compatibility features for a server.
 .IP
+"%UNSAFE_RENEGOTIATION" will enable unsafe renegotiation (default
+behaviour at 2.8.5 and earlier releases)
+.IP
 To avoid collisions in order to specify a compression algorithm in
 this string you have to prefix it with "COMP-", protocol versions
 with "VERS-" and certificate types with "CTYPE-". All other
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 54a91b7..fd366f0 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -81,7 +81,7 @@ COBJECTS = gnutls_record.c gnutls_compress.c debug.c 
gnutls_cipher.c  \
        auth_dh_common.c gnutls_helper.c gnutls_supplemental.c          \
        crypto.c random.c pk-libgcrypt.c mpi-libgcrypt.c cryptodev.c    \
        rnd-libgcrypt.c cipher-libgcrypt.c mac-libgcrypt.c ext_signature.c \
-       crypto-api.c
+       crypto-api.c ext_safe_renegotiation.c
 
 if ENABLE_OPRFI
 COBJECTS += $(OPRFI_COBJECTS)
@@ -101,7 +101,8 @@ HFILES = debug.h gnutls_compress.h gnutls_cipher.h 
gnutls_buffers.h \
        ext_srp.h gnutls_srp.h auth_srp.h auth_srp_passwd.h             \
        gnutls_helper.h auth_psk.h auth_psk_passwd.h                    \
        gnutls_supplemental.h ext_oprfi.h crypto.h random.h             \
-       ext_session_ticket.h ext_signature.h gnutls_cryptodev.h
+       ext_session_ticket.h ext_signature.h gnutls_cryptodev.h         \
+       ext_safe_renegotiation.h
 
 # Separate so we can create the documentation
 
diff --git a/lib/ext_safe_renegotiation.c b/lib/ext_safe_renegotiation.c
new file mode 100644
index 0000000..7cd362d
--- /dev/null
+++ b/lib/ext_safe_renegotiation.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2009 Free Software Foundation
+ *
+ * Author: Steve Dispensa (<address@hidden>)
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA
+ *
+ */
+
+#include <gnutls_int.h>
+#include <ext_safe_renegotiation.h>
+#include <gnutls_errors.h>
+
+int
+_gnutls_safe_renegotiation_recv_params (gnutls_session_t session, 
+               const opaque * data, size_t _data_size)
+{
+  tls_ext_st *ext = &session->security_parameters.extensions;
+
+  int len = data[0];
+  ssize_t data_size = _data_size;
+
+  DECR_LEN (data_size, len+1 /* count the first byte and payload */);
+
+  int conservative_len = len;
+  if (len > sizeof (ext->ri_extension_data))
+    conservative_len = sizeof (ext->ri_extension_data);
+
+  memcpy (ext->ri_extension_data, &data[1], conservative_len);
+  ext->ri_extension_data_len = conservative_len;
+
+  /* "safe renegotiation received" means on *this* handshake; "connection using
+   * safe renegotiation" means that the initial hello received on the 
connection
+   * indicatd safe renegotiation. 
+   */
+  ext->safe_renegotiation_received = 1;
+  ext->connection_using_safe_renegotiation = 1;
+
+  return 0;
+}
+
+int
+_gnutls_safe_renegotiation_send_params (gnutls_session_t session, 
+               opaque * data, size_t _data_size)
+{
+  /* The format of this extension is a one-byte length of verify data followed
+   * by the verify data itself. Note that the length byte does not include
+   * itself; IOW, empty verify data is represented as a length of 0. That means
+   * the minimum extension is one byte: 0x00.
+   */
+
+  ssize_t data_size = _data_size;
+  tls_ext_st *ext = &session->security_parameters.extensions;
+
+  /* Always offer the extension if we're a client */
+  if (ext->connection_using_safe_renegotiation ||
+     session->security_parameters.entity == GNUTLS_CLIENT)
+    {
+      DECR_LEN (data_size, 1);
+      data[0] = ext->client_verify_data_len;
+
+      DECR_LEN (data_size, ext->client_verify_data_len);
+
+      memcpy(&data[1], 
+            ext->client_verify_data, 
+            ext->client_verify_data_len);
+
+      if (session->security_parameters.entity == GNUTLS_SERVER)
+       {
+         data[0] += ext->server_verify_data_len;
+
+         DECR_LEN (data_size, ext->server_verify_data_len);
+
+         memcpy(&data[1 + ext->client_verify_data_len],
+                ext->server_verify_data,
+                ext->server_verify_data_len);
+       }
+    }
+
+  return 1 + data[0]; /* don't forget the length byte */
+}
+
+/**
+  * gnutls_safe_negotiation_set_initial - Used to enable and disable initial 
safe renegotiation
+  * @session: is a #gnutls_session_t structure.
+  * @value: 0 to disable and 1 to enable
+  *
+  * Used to enable and disable initial safe renegotiation for the current
+  * session. By default it is allowed for a client to not advertise safe
+  * renegotiation capability but there might be cases where signalling
+  * a client of its insecurity by rejecting session might be beneficial.
+  * This option has meaning only in server side.
+  **/
+void
+gnutls_safe_negotiation_set_initial (gnutls_session_t session, int value)
+{
+  session->internals.priorities.initial_safe_renegotiation = value;
+}
+
+/**
+  * gnutls_safe_negotiation_set - Used to enable and disable safe renegotiation
+  * @session: is a #gnutls_session_t structure.
+  * @value: 0 to disable and 1 to enable
+  *
+  * Used to enable and disable safe renegotiation for the current
+  * session. Normally you shouldn't cope with this function since the
+  * default (enable) is sufficient, but there might be servers that
+  * cannot handle or correctly handle the extension.
+  **/
+void gnutls_safe_renegotiation_set (gnutls_session_t session, int value)
+{
+       session->internals.priorities.unsafe_renegotiation = 1-value;
+}
diff --git a/lib/auth_psk_passwd.h b/lib/ext_safe_renegotiation.h
similarity index 72%
copy from lib/auth_psk_passwd.h
copy to lib/ext_safe_renegotiation.h
index 8e847c0..4551e80 100644
--- a/lib/auth_psk_passwd.h
+++ b/lib/ext_safe_renegotiation.h
@@ -1,7 +1,7 @@
 /*
- * Copyright (C) 2005, 2007 Free Software Foundation
+ * Copyright (C) 2009 Free Software Foundation
  *
- * Author: Nikos Mavrogiannopoulos
+ * Author: Steve Dispensa (<address@hidden>)
  *
  * This file is part of GNUTLS.
  *
@@ -22,10 +22,7 @@
  *
  */
 
-#ifdef ENABLE_PSK
-
-/* this is locally allocated. It should be freed using the provided function */
-int _gnutls_psk_pwd_find_entry (gnutls_session_t, char *username,
-                               gnutls_datum_t * key);
-
-#endif /* ENABLE_SRP */
+int _gnutls_safe_renegotiation_recv_params (gnutls_session_t state, 
+               const opaque * data, size_t data_size);
+int _gnutls_safe_renegotiation_send_params (gnutls_session_t state, 
+               opaque * data, size_t);
diff --git a/lib/gnutls_alert.c b/lib/gnutls_alert.c
index 0bb90a1..fa99a27 100644
--- a/lib/gnutls_alert.c
+++ b/lib/gnutls_alert.c
@@ -200,6 +200,7 @@ gnutls_error_to_alert (int err, int *level)
     case GNUTLS_E_NO_CIPHER_SUITES:
     case GNUTLS_E_NO_COMPRESSION_ALGORITHMS:
     case GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM:
+    case GNUTLS_E_SAFE_RENEGOTIATION_FAILED:
       ret = GNUTLS_A_HANDSHAKE_FAILURE;
       _level = GNUTLS_AL_FATAL;
       break;
diff --git a/lib/gnutls_algorithms.c b/lib/gnutls_algorithms.c
index 0faf4ac..35899ea 100644
--- a/lib/gnutls_algorithms.c
+++ b/lib/gnutls_algorithms.c
@@ -470,6 +470,10 @@ typedef struct
 #define GNUTLS_DHE_RSA_AES_128_CBC_SHA256 { 0x00, 0x67 }
 #define GNUTLS_DHE_RSA_AES_256_CBC_SHA256 { 0x00, 0x6B }
 
+/* Safe renegotiation */
+
+#define GNUTLS_RENEGO_PROTECTION_REQUEST { 
GNUTLS_RENEGO_PROTECTION_REQUEST_MAJOR, GNUTLS_RENEGO_PROTECTION_REQUEST_MINOR }
+
 #define CIPHER_SUITES_COUNT 
sizeof(cs_algorithms)/sizeof(gnutls_cipher_suite_entry)-1
 
 static const gnutls_cipher_suite_entry cs_algorithms[] = {
@@ -661,6 +665,9 @@ static const gnutls_cipher_suite_entry cs_algorithms[] = {
   GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_RSA_AES_256_CBC_SHA256,
                             GNUTLS_CIPHER_AES_256_CBC, GNUTLS_KX_RSA,
                             GNUTLS_MAC_SHA256, GNUTLS_TLS1_2),
+  GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_RENEGO_PROTECTION_REQUEST,
+                            GNUTLS_CIPHER_UNKNOWN, GNUTLS_KX_UNKNOWN,
+                            GNUTLS_MAC_UNKNOWN, GNUTLS_SSL3),
   {0, {{0, 0}}, 0, 0, 0, 0}
 };
 
diff --git a/lib/gnutls_algorithms.h b/lib/gnutls_algorithms.h
index 2b59908..307da61 100644
--- a/lib/gnutls_algorithms.h
+++ b/lib/gnutls_algorithms.h
@@ -27,6 +27,9 @@
 
 #include "gnutls_auth.h"
 
+#define GNUTLS_RENEGO_PROTECTION_REQUEST_MAJOR 0x00
+#define GNUTLS_RENEGO_PROTECTION_REQUEST_MINOR 0xFF
+
 /* Functions for version handling. */
 gnutls_protocol_t _gnutls_version_lowest (gnutls_session_t session);
 gnutls_protocol_t _gnutls_version_max (gnutls_session_t session);
diff --git a/lib/gnutls_errors.c b/lib/gnutls_errors.c
index fdea4ef..086386c 100644
--- a/lib/gnutls_errors.c
+++ b/lib/gnutls_errors.c
@@ -220,6 +220,8 @@ static const gnutls_error_entry error_algorithms[] = {
               GNUTLS_E_OPENPGP_GETKEY_FAILED, 1),
   ERROR_ENTRY (N_("Could not find OpenPGP subkey."),
               GNUTLS_E_OPENPGP_SUBKEY_ERROR, 1),
+  ERROR_ENTRY (N_("Safe renegotiation failed."),
+              GNUTLS_E_SAFE_RENEGOTIATION_FAILED, 1),
 
   ERROR_ENTRY (N_("The SRP username supplied is illegal."),
               GNUTLS_E_ILLEGAL_SRP_USERNAME, 1),
diff --git a/lib/gnutls_extensions.c b/lib/gnutls_extensions.c
index b3f388c..2e8ad07 100644
--- a/lib/gnutls_extensions.c
+++ b/lib/gnutls_extensions.c
@@ -36,7 +36,9 @@
 #include <ext_oprfi.h>
 #include <ext_srp.h>
 #include <ext_session_ticket.h>
+#include <ext_safe_renegotiation.h>
 #include <ext_signature.h>
+#include <ext_safe_renegotiation.h>
 #include <gnutls_num.h>
 
 typedef struct
@@ -183,7 +185,7 @@ _gnutls_parse_extensions (gnutls_session_t session,
  * This list is used to check whether the (later) received
  * extensions are the ones we requested.
  */
-static void
+void
 _gnutls_extension_list_add (gnutls_session_t session, uint16_t type)
 {
 
@@ -320,6 +322,14 @@ _gnutls_ext_init (void)
   if (ret != GNUTLS_E_SUCCESS)
     return ret;
 
+  ret = gnutls_ext_register (GNUTLS_EXTENSION_SAFE_RENEGOTIATION,
+                            "SAFE_RENEGOTIATION",
+                            GNUTLS_EXT_RESUMED,
+                            _gnutls_safe_renegotiation_recv_params,
+                            _gnutls_safe_renegotiation_send_params);
+  if (ret != GNUTLS_E_SUCCESS)
+    return ret;
+
 #ifdef ENABLE_OPRFI
   ret = gnutls_ext_register (GNUTLS_EXTENSION_OPAQUE_PRF_INPUT,
                             "OPAQUE_PRF_INPUT",
diff --git a/lib/gnutls_extensions.h b/lib/gnutls_extensions.h
index e049340..cb672e3 100644
--- a/lib/gnutls_extensions.h
+++ b/lib/gnutls_extensions.h
@@ -29,3 +29,5 @@ int _gnutls_gen_extensions (gnutls_session_t session, opaque 
* data,
                            size_t data_size);
 int _gnutls_ext_init (void);
 void _gnutls_ext_deinit (void);
+
+void _gnutls_extension_list_add (gnutls_session_t session, uint16_t type);
diff --git a/lib/gnutls_handshake.c b/lib/gnutls_handshake.c
index aca1aab..3620a29 100644
--- a/lib/gnutls_handshake.c
+++ b/lib/gnutls_handshake.c
@@ -450,8 +450,36 @@ _gnutls_read_client_hello (gnutls_session_t session, 
opaque * data,
 
   if (ret == 0)
     {                          /* resumed! */
+      /* Parse only the safe renegotiation extension
+       * We don't want to parse any other extensions since
+       * we don't want new extension values to overwrite the
+       * resumed ones.
+       */
+       
+      /* move forward to extensions */
+      DECR_LEN (len, 2);
+      suite_size = _gnutls_read_uint16 (&data[pos]);
+      pos += 2;
+
+      DECR_LEN (len, suite_size);
+      pos += suite_size;
+      
+      DECR_LEN (len, 1);
+      comp_size = data[pos++]; /* z is the number of compression methods */
+      DECR_LEN (len, comp_size);
+      pos += comp_size;
+
+      ret = _gnutls_parse_extensions (session, GNUTLS_EXT_RESUMED,
+                                 &data[pos], len);
+      if (ret < 0)
+        {
+          gnutls_assert ();
+          return ret;
+        }
+
       resume_copy_required_values (session);
       session->internals.resumed = RESUME_TRUE;
+      
       return _gnutls_user_hello_func (session, adv_version);
     }
   else
@@ -483,17 +511,17 @@ _gnutls_read_client_hello (gnutls_session_t session, 
opaque * data,
   pos += comp_size;
 
   /* Parse the extensions (if any)
+   *
+   * Unconditionally try to parse extensions; safe renegotiation uses them in
+   * sslv3 and higher, even though sslv3 doesn't officially support them.
    */
-  if (_gnutls_version_has_extensions (neg_version))
+  ret = _gnutls_parse_extensions (session, GNUTLS_EXT_APPLICATION,
+                                 &data[pos], len);
+  /* len is the rest of the parsed length */
+  if (ret < 0)
     {
-      ret = _gnutls_parse_extensions (session, GNUTLS_EXT_APPLICATION,
-                                     &data[pos], len);
-      /* len is the rest of the parsed length */
-      if (ret < 0)
-       {
-         gnutls_assert ();
-         return ret;
-       }
+      gnutls_assert ();
+      return ret;
     }
 
   ret = _gnutls_user_hello_func (session, adv_version);
@@ -503,36 +531,40 @@ _gnutls_read_client_hello (gnutls_session_t session, 
opaque * data,
       return ret;
     }
 
-  if (_gnutls_version_has_extensions (neg_version))
+  ret = _gnutls_parse_extensions (session, GNUTLS_EXT_RESUMED,
+                                 &data[pos], len);
+  if (ret < 0)
     {
-      ret = _gnutls_parse_extensions (session, GNUTLS_EXT_TLS,
-                                     &data[pos], len);
-      /* len is the rest of the parsed length */
-      if (ret < 0)
-       {
-         gnutls_assert ();
-         return ret;
-       }
+      gnutls_assert ();
+      return ret;
+    }
 
-      /* resumed by session_ticket extension */
-      if (session->internals.resumed == RESUME_TRUE)
-       {
-         /* to indicate the client that the current session is resumed */
-         memcpy (session->internals.resumed_security_parameters.session_id,
-                 session_id, session_id_len);
-         session->internals.resumed_security_parameters.session_id_size =
-           session_id_len;
+  ret = _gnutls_parse_extensions (session, GNUTLS_EXT_TLS,
+                                 &data[pos], len);
+  if (ret < 0)
+    {
+      gnutls_assert ();
+      return ret;
+    }
+
+  /* resumed by session_ticket extension */
+  if (session->internals.resumed == RESUME_TRUE)
+    {
+      /* to indicate the client that the current session is resumed */
+      memcpy (session->internals.resumed_security_parameters.session_id,
+             session_id, session_id_len);
+      session->internals.resumed_security_parameters.session_id_size =
+              session_id_len;
 
-         session->internals.
-           resumed_security_parameters.max_record_recv_size =
-           session->security_parameters.max_record_recv_size;
-         session->internals.
-           resumed_security_parameters.max_record_send_size =
-           session->security_parameters.max_record_send_size;
+      session->internals.
+       resumed_security_parameters.max_record_recv_size =
+       session->security_parameters.max_record_recv_size;
+      session->internals.
+       resumed_security_parameters.max_record_send_size =
+       session->security_parameters.max_record_send_size;
 
-         resume_copy_required_values (session);
-         return 0;
-       }
+      resume_copy_required_values (session);
+       return 0;
     }
 
   /* select an appropriate cipher suite
@@ -611,7 +643,7 @@ _gnutls_handshake_hash_pending (gnutls_session_t session)
 static int
 _gnutls_send_finished (gnutls_session_t session, int again)
 {
-  uint8_t data[36];
+  uint8_t data[MAX_VERIFY_DATA_SIZE];
   int ret;
   int data_size = 0;
 
@@ -636,7 +668,7 @@ _gnutls_send_finished (gnutls_session_t session, int again)
          data_size = 36;
        }
       else
-       {                       /* TLS 1.0 */
+       { /* TLS 1.0+ */
          ret = _gnutls_finished (session,
                                  session->security_parameters.entity, data);
          data_size = 12;
@@ -652,6 +684,31 @@ _gnutls_send_finished (gnutls_session_t session, int again)
        session->internals.finished_func (session, data, data_size);
     }
 
+  /* Save data for safe renegotiation. 
+   */
+  if (data_size > MAX_VERIFY_DATA_SIZE) 
+    {
+      gnutls_assert ();
+      return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+    }
+
+  if (session->security_parameters.entity == GNUTLS_CLIENT)
+    {
+      session->security_parameters.extensions.client_verify_data_len = 
+             data_size;
+
+      memcpy (session->security_parameters.extensions.client_verify_data,
+             data, data_size);
+    }
+  else
+    {
+      session->security_parameters.extensions.server_verify_data_len = 
+             data_size;
+
+      memcpy (session->security_parameters.extensions.server_verify_data,
+             data, data_size);
+    }
+
   ret =
     _gnutls_send_handshake (session, data_size ? data : NULL, data_size,
                            GNUTLS_HANDSHAKE_FINISHED);
@@ -665,7 +722,7 @@ _gnutls_send_finished (gnutls_session_t session, int again)
 static int
 _gnutls_recv_finished (gnutls_session_t session)
 {
-  uint8_t data[36], *vrfy;
+  uint8_t data[MAX_VERIFY_DATA_SIZE], *vrfy;
   int data_size;
   int ret;
   int vrfysize;
@@ -726,6 +783,28 @@ _gnutls_recv_finished (gnutls_session_t session)
     }
   gnutls_free (vrfy);
 
+  /* Save peer's verify data for safe renegotiation */
+  if (data_size > MAX_VERIFY_DATA_SIZE)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+    }
+
+  tls_ext_st *ext = &session->security_parameters.extensions;
+
+  if (session->security_parameters.entity == GNUTLS_CLIENT)
+    {
+      memcpy (ext->server_verify_data, data, data_size);
+      ext->server_verify_data_len = data_size;
+    }
+  else
+    {
+      memcpy (ext->client_verify_data, data, data_size);
+      ext->client_verify_data_len = data_size;
+    }
+
+  ext->initial_negotiation_completed = 1;
+
   return ret;
 }
 
@@ -765,7 +844,6 @@ _gnutls_server_find_pk_algos_in_ciphersuites (const opaque *
   return algo;
 }
 
-
 /* This selects the best supported ciphersuite from the given ones. Then
  * it adds the suite to the session and performs some checks.
  */
@@ -780,11 +858,30 @@ _gnutls_server_select_suite (gnutls_session_t session, 
opaque * data,
                                         * supported by the peer.
                                         */
 
+  /* First, check for safe renegotiation SCSV.
+   */
+  {
+    int offset;
+
+    for(offset = 0; offset < datalen; offset += 2)
+      {
+       /* TLS_RENEGO_PROTECTION_REQUEST = { 0x00, 0xff } */
+        if (data[offset]   == GNUTLS_RENEGO_PROTECTION_REQUEST_MAJOR &&
+            data[offset+1] == GNUTLS_RENEGO_PROTECTION_REQUEST_MINOR)
+          {
+           _gnutls_handshake_log ("HSK[%p]: Received safe renegotiation CS\n", 
session);
+            
session->security_parameters.extensions.safe_renegotiation_received = 1;
+            
session->security_parameters.extensions.connection_using_safe_renegotiation = 1;
+           break;
+          }
+      }
+  }
+
   pk_algo = _gnutls_server_find_pk_algos_in_ciphersuites (data, datalen);
 
   x = _gnutls_supported_ciphersuites (session, &ciphers);
   if (x < 0)
-    {                          /* the case x==0 is handled within the 
function. */
+    { /* the case x==0 is handled within the function. */
       gnutls_assert ();
       return x;
     }
@@ -832,21 +929,21 @@ _gnutls_server_select_suite (gnutls_session_t session, 
opaque * data,
 
   for (j = 0; j < datalen; j += 2)
     {
-      for (i = 0; i < x; i++)
-       {
-         if (memcmp (ciphers[i].suite, &data[j], 2) == 0)
-           {
-             memcpy (&cs.suite, &data[j], 2);
-
-             _gnutls_handshake_log
-               ("HSK[%p]: Selected cipher suite: %s\n", session,
-                _gnutls_cipher_suite_get_name (&cs));
-             memcpy (session->security_parameters.current_cipher_suite.suite,
-                     ciphers[i].suite, 2);
-             retval = 0;
-             goto finish;
-           }
-       }
+         for (i = 0; i < x; i++)
+               {
+                 if (memcmp (ciphers[i].suite, &data[j], 2) == 0)
+                       {
+                         memcpy (&cs.suite, &data[j], 2);
+
+                         _gnutls_handshake_log
+                       ("HSK[%p]: Selected cipher suite: %s\n", session,
+                        _gnutls_cipher_suite_get_name (&cs));
+                         memcpy 
(session->security_parameters.current_cipher_suite.suite,
+                                 ciphers[i].suite, 2);
+                         retval = 0;
+                         goto finish;
+                       }
+               }
     }
 
 finish:
@@ -1065,7 +1162,7 @@ _gnutls_send_handshake (gnutls_session_t session, void 
*i_data,
   if (i_datasize > 0)
     memcpy (&data[pos], i_data, i_datasize);
 
-  _gnutls_handshake_log ("HSK[%p]: %s was send [%ld bytes]\n",
+  _gnutls_handshake_log ("HSK[%p]: %s was sent [%ld bytes]\n",
                         session, _gnutls_handshake2str (type),
                         (long) datasize);
 
@@ -1655,9 +1752,21 @@ _gnutls_read_server_hello (gnutls_session_t session,
    */
   if (_gnutls_client_check_if_resuming
       (session, &data[pos], session_id_len) == 0)
-    return 0;
-  pos += session_id_len;
+    {
+      pos += session_id_len + 2 + 1;
+      DECR_LEN (len, 2+1);
 
+      ret = _gnutls_parse_extensions (session, GNUTLS_EXT_RESUMED,
+                                 &data[pos], len);
+      if (ret < 0)
+        {
+          gnutls_assert ();
+          return ret;
+        }
+      return 0;
+    }
+
+  pos += session_id_len;
 
   /* Check if the given cipher suite is supported and copy
    * it to the session.
@@ -1687,27 +1796,26 @@ _gnutls_read_server_hello (gnutls_session_t session,
 
   /* Parse extensions.
    */
-  if (_gnutls_version_has_extensions (version))
+  ret = _gnutls_parse_extensions (session, GNUTLS_EXT_ANY,
+                                 &data[pos], len);
+  if (ret < 0)
     {
-      ret = _gnutls_parse_extensions (session, GNUTLS_EXT_ANY,
-                                     &data[pos], len);
-      /* len is the rest of the parsed length */
-      if (ret < 0)
-       {
-         gnutls_assert ();
-         return ret;
-       }
+      gnutls_assert ();
+      return ret;
     }
+
   return ret;
 }
 
 
 /* This function copies the appropriate ciphersuites to a locally allocated 
buffer
- * Needed in client hello messages. Returns the new data length.
+ * Needed in client hello messages. Returns the new data length. If add_scsv is
+ * true, add the special safe renegotiation CS.
  */
 static int
 _gnutls_copy_ciphersuites (gnutls_session_t session,
-                          opaque * ret_data, size_t ret_data_size)
+                          opaque * ret_data, size_t ret_data_size,
+                          int add_scsv)
 {
   int ret, i;
   cipher_suite_st *cipher_suites;
@@ -1743,6 +1851,9 @@ _gnutls_copy_ciphersuites (gnutls_session_t session,
       return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
     }
 
+  if (add_scsv)
+    ++ret;
+
   cipher_num = ret;
 
   cipher_num *= sizeof (uint16_t);     /* in order to get bytes */
@@ -1760,11 +1871,21 @@ _gnutls_copy_ciphersuites (gnutls_session_t session,
   _gnutls_write_uint16 (cipher_num, ret_data);
   pos += 2;
 
-  for (i = 0; i < (cipher_num / 2); i++)
+  uint16_t loop_max = add_scsv ? cipher_num - 2 : cipher_num;
+
+  for (i = 0; i < (loop_max / 2); i++)
     {
       memcpy (&ret_data[pos], cipher_suites[i].suite, 2);
       pos += 2;
     }
+
+  if (add_scsv)
+    {
+      /* Safe renegotiation signalling CS value is { 0x00, 0xff } */
+      ret_data[pos++] = 0x00;
+      ret_data[pos++] = 0xff;
+    }
+
   gnutls_free (cipher_suites);
 
   return datalen;
@@ -1939,8 +2060,20 @@ _gnutls_send_client_hello (gnutls_session_t session, int 
again)
 
 
       /* Copy the ciphersuites.
+       *
+       * If using SSLv3 Send TLS_RENEGO_PROTECTION_REQUEST SCSV for MITM
+       * prevention on initial negotiation (but not renegotiation; that's
+       * handled with the RI extension below).
        */
-      ret = _gnutls_copy_ciphersuites (session, extdata, extdatalen);
+      
if(!session->security_parameters.extensions.initial_negotiation_completed &&
+        session->security_parameters.entity == GNUTLS_CLIENT)
+        {
+         ret = _gnutls_copy_ciphersuites (session, extdata, extdatalen, TRUE);
+         _gnutls_extension_list_add (session, 
GNUTLS_EXTENSION_SAFE_RENEGOTIATION);
+       }
+      else
+       ret = _gnutls_copy_ciphersuites (session, extdata, extdatalen, FALSE);
+
       if (ret > 0)
        {
          datalen += ret;
@@ -2022,6 +2155,53 @@ _gnutls_send_client_hello (gnutls_session_t session, int 
again)
              return ret;
            }
        }
+      else 
if(session->security_parameters.extensions.initial_negotiation_completed)
+        {
+         /* For SSLv3 only, we will (only) to send the RI extension; we must
+          * send it every time we renegotiate. We don't want to send anything
+          * else, out of concern for interoperability.
+          *
+          * If this is an initial negotiation, we already sent SCSV above.
+          */
+          
+         opaque buf[256]; /* opaque renegotiated_connection<0..255> */
+         ret = _gnutls_safe_renegotiation_send_params (session, buf, 
sizeof(buf));
+
+         if (ret < 0)
+           {
+             gnutls_assert ();
+             gnutls_free (data);
+             gnutls_free (extdata);
+             return ret;
+           }
+
+         datalen += ret + 6; /* extlen(2) + type(2) + len(2) + ret */
+
+         data = gnutls_realloc_fast (data, datalen);
+         if (data == NULL)
+           {
+             gnutls_assert ();
+             gnutls_free (extdata);
+             return GNUTLS_E_MEMORY_ERROR;
+           }
+
+         /* total extensions length (one extension, with type(2) + len(2)) */
+         _gnutls_write_uint16 (4 + ret, &data[pos]);
+         pos += 2;
+
+         /* TLS RI extension type is 0xff01 */
+         data[pos++] = 0xff;
+         data[pos++] = 0x01;
+
+         _gnutls_write_uint16 (ret, &data[pos]);
+         pos += 2;
+
+         memcpy(&data[pos], buf, ret);
+         pos += ret;
+
+         _gnutls_debug_log ("EXT[%p]: Sending extension safe renegotiation 
(SSLv3)\n",
+                                session);
+       }
       gnutls_free (extdata);
     }
 
@@ -2147,6 +2327,8 @@ _gnutls_send_hello (gnutls_session_t session, int again)
 {
   int ret;
 
+  session->security_parameters.extensions.safe_renegotiation_received = 0;
+
   if (session->security_parameters.entity == GNUTLS_CLIENT)
     {
       ret = _gnutls_send_client_hello (session, again);
@@ -2179,7 +2361,7 @@ _gnutls_recv_hello (gnutls_session_t session, opaque * 
data, int datalen)
        }
     }
   else
-    {                          /* Server side reading a client hello */
+    { /* Server side reading a client hello */
 
       ret = _gnutls_read_client_hello (session, data, datalen);
       if (ret < 0)
@@ -2188,6 +2370,83 @@ _gnutls_recv_hello (gnutls_session_t session, opaque * 
data, int datalen)
          return ret;
        }
     }
+           
+  /* Safe renegotiation */
+  tls_ext_st *ext = &session->security_parameters.extensions;
+
+  if (ext->safe_renegotiation_received)
+    {
+      if ((ext->ri_extension_data_len < ext->client_verify_data_len) ||
+         (memcmp (ext->ri_extension_data,
+                  ext->client_verify_data,
+                  ext->client_verify_data_len)))
+       {
+         gnutls_assert();
+         _gnutls_handshake_log ("Safe renegotiation failed (1)\n");
+         return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
+       }
+      if (session->security_parameters.entity == GNUTLS_CLIENT)
+        {
+         if ((ext->ri_extension_data_len !=
+              ext->client_verify_data_len + ext->server_verify_data_len) ||
+              memcmp (ext->ri_extension_data + ext->client_verify_data_len,
+                      ext->server_verify_data, ext->server_verify_data_len))
+           {
+             gnutls_assert();
+             _gnutls_handshake_log ("Safe renegotiation failed (2)\n");
+             return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
+           }
+       }
+      else /* Make sure there are 0 extra bytes */
+       {
+         if (ext->ri_extension_data_len != ext->client_verify_data_len)
+           {
+             gnutls_assert();
+             _gnutls_handshake_log ("Safe renegotiation failed (3)\n");
+             return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
+           }
+       }
+
+      _gnutls_handshake_log ("Safe renegotiation succeeded.\n");
+    }
+  else /* safe renegotiation not received... */
+    {
+      if (ext->connection_using_safe_renegotiation)
+       {
+         gnutls_assert();
+         _gnutls_handshake_log ("Peer previously asked for safe 
renegotiation!\n");
+         return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
+       }
+
+      /* Clients can't tell if it's an initial negotiation */
+      if (ext->initial_negotiation_completed ||
+         session->security_parameters.entity == GNUTLS_CLIENT)
+       {
+         if (session->internals.priorities.unsafe_renegotiation != 0)
+           {
+             _gnutls_handshake_log ("Allowing unsafe renegotiation!\n");
+           }
+         else
+           {
+             gnutls_assert();
+             _gnutls_handshake_log ("Denying unsafe renegotiation.\n");
+             return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
+           }
+       }
+      else
+       {
+         if (session->internals.priorities.initial_safe_renegotiation==0)
+           {
+             _gnutls_handshake_log ("Allowing unsafe initial negotiation!\n");
+           }
+         else
+           {
+             gnutls_assert();
+             _gnutls_handshake_log ("Denying unsafe initial negotiation.\n");
+             return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
+           }
+       }
+    }
 
   return ret;
 }
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index a097bea..ba8ed9b 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -177,7 +177,8 @@ typedef enum extensions_t
   GNUTLS_EXTENSION_SRP = 12,
   GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS = 13,
   GNUTLS_EXTENSION_SESSION_TICKET = 35,
-  GNUTLS_EXTENSION_INNER_APPLICATION = 37703
+  GNUTLS_EXTENSION_INNER_APPLICATION = 37703,
+  GNUTLS_EXTENSION_SAFE_RENEGOTIATION = 65281, /* aka: 0xff01 */
 } extensions_t;
 
 typedef enum
@@ -306,6 +307,8 @@ struct gnutls_session_ticket_key_st {
   opaque mac_secret[SESSION_TICKET_MAC_SECRET_SIZE];
 };
 
+#define MAX_VERIFY_DATA_SIZE 36 /* in SSL 3.0, 12 in TLS 1.0 */
+
 typedef struct
 {
   server_name_st server_names[MAX_SERVER_NAME_EXTENSIONS];
@@ -333,10 +336,23 @@ typedef struct
   opaque *oprfi_server;
   uint16_t oprfi_server_len;
 
+  /* Session Ticket */
   opaque *session_ticket;
   uint16_t session_ticket_len;
   struct gnutls_session_ticket_key_st *session_ticket_key;
   opaque session_ticket_IV[SESSION_TICKET_IV_SIZE];
+
+  /* Safe renegotiation. */
+  int connection_using_safe_renegotiation:1;
+  int safe_renegotiation_received:1;
+  int initial_negotiation_completed:1;
+  uint8_t client_verify_data[MAX_VERIFY_DATA_SIZE]; 
+  size_t client_verify_data_len;
+  uint8_t server_verify_data[MAX_VERIFY_DATA_SIZE];
+  size_t server_verify_data_len;
+  uint8_t ri_extension_data[MAX_VERIFY_DATA_SIZE*2]; /* max signal is 72 bytes 
in s->c sslv3 */
+  size_t ri_extension_data_len;
+
 } tls_ext_st;
 
 /* auth_info_t structures now MAY contain malloced 
@@ -446,7 +462,9 @@ struct gnutls_priority_st
   priority_st sign_algo;
 
   /* to disable record padding */
-  int no_padding;
+  int no_padding:1;
+  int unsafe_renegotiation:1;
+  int initial_safe_renegotiation:1;
   int ssl3_record_version;
   int additional_verify_flags;
 };
diff --git a/lib/gnutls_priority.c b/lib/gnutls_priority.c
index 8700f90..f12660b 100644
--- a/lib/gnutls_priority.c
+++ b/lib/gnutls_priority.c
@@ -522,6 +522,10 @@ gnutls_priority_set (gnutls_session_t session, 
gnutls_priority_t priority)
  *
  * "%COMPAT" will enable compatibility features for a server.
  *
+ * "%UNSAFE_RENEGOTIATION" will allow unsafe renegotiation.
+ *
+ * "%INITIAL_SAFE_RENEGOTIATION" will force initial safe negotiation even if 
renegotiation wasn't requested.
+ *
  * "%SSL3_RECORD_VERSION" will use SSL3.0 record version in client hello.
  *
  * "%VERIFY_ALLOW_SIGN_RSA_MD5" will allow RSA-MD5 signatures in
@@ -711,6 +715,12 @@ gnutls_priority_init (gnutls_priority_t * priority_cache,
                               "VERIFY_ALLOW_X509_V1_CA_CRT") == 0)
            (*priority_cache)->additional_verify_flags |=
              GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT;
+         else if (strcasecmp (&broken_list[i][1],
+                              "UNSAFE_RENEGOTIATION") == 0)
+           (*priority_cache)->unsafe_renegotiation = 1;
+         else if (strcasecmp (&broken_list[i][1],
+                              "INITIAL_SAFE_RENEGOTIATION") == 0)
+           (*priority_cache)->initial_safe_renegotiation = 1;
          else
            goto error;
        }
diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in
index f148c16..ea691e6 100644
--- a/lib/includes/gnutls/gnutls.h.in
+++ b/lib/includes/gnutls/gnutls.h.in
@@ -511,7 +511,8 @@ extern "C" {
     {
       GNUTLS_EXT_ANY,
       GNUTLS_EXT_APPLICATION,
-      GNUTLS_EXT_TLS
+      GNUTLS_EXT_TLS,
+      GNUTLS_EXT_RESUMED, /* parse even if resuming */
     } gnutls_ext_parse_type_t;
 
   int gnutls_ext_register (int type,
@@ -533,6 +534,11 @@ extern "C" {
                              void *data, size_t * data_length,
                              unsigned int *type, unsigned int indx);
 
+  /* Safe renegotiation */
+  void gnutls_safe_negotiation_set_initial (gnutls_session_t session, int 
value);
+
+  void gnutls_safe_renegotiation_set (gnutls_session_t session, int value);
+
   /* Opaque PRF Input
    * http://tools.ietf.org/id/draft-rescorla-tls-opaque-prf-input-00.txt
    */
@@ -1382,6 +1388,7 @@ extern "C" {
 #define GNUTLS_E_IA_VERIFY_FAILED -104
 #define GNUTLS_E_UNKNOWN_ALGORITHM -105
 #define GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM -106
+#define GNUTLS_E_SAFE_RENEGOTIATION_FAILED -107
 
 #define GNUTLS_E_BASE64_ENCODING_ERROR -201
 #define GNUTLS_E_INCOMPATIBLE_GCRYPT_LIBRARY -202      /* obsolete */
diff --git a/lib/opencdk/sig-check.c b/lib/opencdk/sig-check.c
index 5dc9da6..f4e8ccf 100644
--- a/lib/opencdk/sig-check.c
+++ b/lib/opencdk/sig-check.c
@@ -288,7 +288,8 @@ _cdk_pk_check_sig (cdk_keydb_hd_t keydb,
 
   if (is_selfsig)
     *is_selfsig = 0;
-  if (knode->pkt->pkttype != CDK_PKT_PUBLIC_KEY ||
+  if ((knode->pkt->pkttype != CDK_PKT_PUBLIC_KEY &&
+      knode->pkt->pkttype != CDK_PKT_PUBLIC_SUBKEY) ||
       snode->pkt->pkttype != CDK_PKT_SIGNATURE)
     {
       gnutls_assert ();
@@ -591,45 +592,56 @@ cdk_pk_check_self_sig (cdk_kbnode_t key, int *r_status)
   cdk_error_t rc;
   u32 keyid[2], sigid[2];
   int is_selfsig, sig_ok;
+  cdk_kbnode_t p, ctx = NULL;
+  cdk_packet_t pkt;
 
   if (!key || !r_status)
     return CDK_Inv_Value;
 
-  node = cdk_kbnode_find (key, CDK_PKT_PUBLIC_KEY);
-  if (!node)
-    return CDK_Error_No_Key;
-  /* FIXME: we should set expire/revoke here also but callers
-     expect CDK_KEY_VALID=0 if the key is okay. */
   cdk_pk_get_keyid (key->pkt->pkt.public_key, keyid);
-  sig_ok = 0;
-  for (node = key; node; node = node->next)
-    {
-      if (node->pkt->pkttype != CDK_PKT_SIGNATURE)
-       continue;
-      sig = node->pkt->pkt.signature;
-      if (!IS_UID_SIG (sig))
-       continue;
-      cdk_sig_get_keyid (sig, sigid);
-      if (sigid[0] != keyid[0] || sigid[1] != keyid[1])
-       continue;
-      /* FIXME: Now we check all self signatures. */
-      rc = _cdk_pk_check_sig (NULL, key, node, &is_selfsig, NULL);
-      if (rc)
-       {
-         *r_status = CDK_KEY_INVALID;
-         return rc;
-       }
-      else                     /* For each valid self sig we increase this 
counter. */
-       sig_ok++;
-    }
 
-  /* A key without a self signature is not valid. */
-  if (!sig_ok)
+  while ((p = cdk_kbnode_walk (key, &ctx, 0)))
     {
-      *r_status = CDK_KEY_INVALID;
-      return CDK_General_Error;
+      pkt = cdk_kbnode_get_packet (p);
+      if (pkt->pkttype != CDK_PKT_PUBLIC_SUBKEY && pkt->pkttype != 
CDK_PKT_PUBLIC_KEY)
+        continue;
+
+      /* FIXME: we should set expire/revoke here also but callers
+         expect CDK_KEY_VALID=0 if the key is okay. */
+      sig_ok = 0;
+      for (node = p; node; node = node->next)
+        {
+          if (node->pkt->pkttype != CDK_PKT_SIGNATURE)
+           continue;
+          sig = node->pkt->pkt.signature;
+
+          cdk_sig_get_keyid (sig, sigid);
+          if (sigid[0] != keyid[0] || sigid[1] != keyid[1])
+           continue;
+          /* FIXME: Now we check all self signatures. */
+          rc = _cdk_pk_check_sig (NULL, p, node, &is_selfsig, NULL);
+          if (rc)
+           {
+             *r_status = CDK_KEY_INVALID;
+             return rc;
+           }
+          else                 /* For each valid self sig we increase this 
counter. */
+           sig_ok++;
+        }
+
+      /* A key without a self signature is not valid. At least one
+       * signature for the given key has to be found.
+       */
+      if (!sig_ok)
+        {
+          *r_status = CDK_KEY_INVALID;
+          return CDK_General_Error;
+        }
+
     }
-  /* No flags indicate a valid key. */
-  *r_status = CDK_KEY_VALID;
-  return 0;
+
+    /* No flags indicate a valid key. */
+    *r_status = CDK_KEY_VALID;
+
+    return 0;
 }
diff --git a/lib/x509/mpi.c b/lib/x509/mpi.c
index 6e567f6..b26e539 100644
--- a/lib/x509/mpi.c
+++ b/lib/x509/mpi.c
@@ -331,6 +331,8 @@ _gnutls_x509_crt_get_mpis (gnutls_x509_crt_t cert,
                   params_size);
 }
 
+#ifdef ENABLE_PKI
+
 /* Extracts DSA and RSA parameters from a certificate.
  */
 int
@@ -348,6 +350,8 @@ _gnutls_x509_crq_get_mpis (gnutls_x509_crq_t cert,
                   params_size);
 }
 
+#endif
+
 /*
  * some x509 certificate functions that relate to MPI parameter
  * setting. This writes the BIT STRING subjectPublicKey.
diff --git a/src/certtool.c b/src/certtool.c
index 826aff7..8f37360 100644
--- a/src/certtool.c
+++ b/src/certtool.c
@@ -1094,6 +1094,7 @@ pgp_certificate_info (void)
   size_t size;
   int ret;
   gnutls_datum_t pem, out_data;
+  unsigned int verify_status;
 
   pem.data = fread_file (infile, &size);
   pem.size = size;
@@ -1120,6 +1121,22 @@ pgp_certificate_info (void)
        }
     }
 
+
+  ret = gnutls_openpgp_crt_verify_self(crt, 0, &verify_status);
+  if (ret < 0) 
+    {
+      error (EXIT_FAILURE, 0, "verify signature error: %s", gnutls_strerror 
(ret));
+    }
+
+  if (verify_status & GNUTLS_CERT_INVALID)
+    {
+      fprintf (outfile, "Self Signature verification: failed\n\n");
+    }
+  else
+    {
+      fprintf (outfile, "Self Signature verification: ok (%x)\n\n", 
verify_status);
+    }
+
   size = sizeof (buffer);
   ret = gnutls_openpgp_crt_export (crt, info.outcert_format, buffer, &size);
   if (ret < 0)
@@ -1129,7 +1146,6 @@ pgp_certificate_info (void)
     }
 
   fprintf (outfile, "%s\n", buffer);
-
   gnutls_openpgp_crt_deinit (crt);
 }
 
diff --git a/src/cli.c b/src/cli.c
index 2aa2da4..4e5bebe 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -826,6 +826,17 @@ after_handshake:
              continue;
            }
 
+          if (strstr(buffer, "**REHANDSHAKE**") != NULL) {
+           fprintf (stderr, "*** Starting TLS rehandshake\n");
+           ret = do_handshake (&hd);
+           if (ret < 0)
+             {
+               fprintf (stderr, "*** Rehandshake has failed\n");
+               user_term = 1;
+               retval = 1;
+               break;
+             }
+          }
          if (crlf != 0)
            {
              char *b = strchr (buffer, '\n');
diff --git a/src/serv.c b/src/serv.c
index 12c5ec7..f8c78a6 100644
--- a/src/serv.c
+++ b/src/serv.c
@@ -1240,14 +1240,24 @@ main (int argc, char **argv)
                  }
                else if (r <= 0)
                  {
-                   j->http_state = HTTP_STATE_CLOSING;
-                   if (r < 0 && r != GNUTLS_E_UNEXPECTED_PACKET_LENGTH)
+                   if (r == GNUTLS_E_REHANDSHAKE) 
                      {
-                       check_alert (j->tls_session, r);
-                       fprintf (stderr, "Error while receiving data\n");
-                       GERR (r);
-                     }
-
+                       do 
+                         {
+                           r = gnutls_handshake (j->tls_session);
+                          } 
+                        while (r == GNUTLS_E_INTERRUPTED || r == 
GNUTLS_E_AGAIN);
+                      }
+                    else
+                      { 
+                       j->http_state = HTTP_STATE_CLOSING;
+                       if (r < 0 && r != GNUTLS_E_UNEXPECTED_PACKET_LENGTH)
+                         {
+                           check_alert (j->tls_session, r);
+                           fprintf (stderr, "Error while receiving data\n");
+                           GERR (r);
+                         }
+                        }
                  }
                else
                  {
diff --git a/tests/gc.c b/tests/gc.c
index 86614ac..70c6180 100644
--- a/tests/gc.c
+++ b/tests/gc.c
@@ -42,36 +42,36 @@ doit (void)
   gnutls_global_init ();
 
   err =
-    _gnutls_hash_fast (GNUTLS_MAC_MD5, "keykeykey", 9, "abcdefgh", 8, digest);
+    _gnutls_hmac_fast (GNUTLS_MAC_MD5, "keykeykey", 9, "abcdefgh", 8, digest);
   if (err < 0)
-    fail ("_gnutls_hash_fast(MD5) failed: %d\n", err);
+    fail ("_gnutls_hmac_fast(MD5) failed: %d\n", err);
   else
     {
       if (memcmp (digest, "\x3c\xb0\x9d\x83\x28\x01\xef\xc0"
                  "\x7b\xb3\xaf\x42\x69\xe5\x93\x9a", 16) == 0)
-       success ("_gnutls_hash_fast(MD5) OK\n");
+       success ("_gnutls_hmac_fast(MD5) OK\n");
       else
        {
          hexprint (digest, 16);
-         fail ("_gnutls_hash_fast(MD5) failure\n");
+         fail ("_gnutls_hmac_fast(MD5) failure\n");
        }
     }
 
   err =
-    _gnutls_hash_fast (GNUTLS_MAC_SHA1, "keykeykey", 9, "abcdefgh", 8,
+    _gnutls_hmac_fast (GNUTLS_MAC_SHA1, "keykeykey", 9, "abcdefgh", 8,
                       digest);
   if (err < 0)
-    fail ("_gnutls_hash_fast(SHA1) failed: %d\n", err);
+    fail ("_gnutls_hmac_fast(SHA1) failed: %d\n", err);
   else
     {
       if (memcmp (digest, "\x58\x93\x7a\x58\xfe\xea\x82\xf8"
                  "\x0e\x64\x62\x01\x40\x2b\x2c\xed\x5d\x54\xc1\xfa",
                  20) == 0)
-       success ("_gnutls_hash_fast(SHA1) OK\n");
+       success ("_gnutls_hmac_fast(SHA1) OK\n");
       else
        {
          hexprint (digest, 20);
-         fail ("_gnutls_hash_fast(SHA1) failure\n");
+         fail ("_gnutls_hmac_fast(SHA1) failure\n");
        }
     }
 
diff --git a/tests/openpgp-certs/Makefile.am b/tests/openpgp-certs/Makefile.am
index d437dc5..76fbf3a 100644
--- a/tests/openpgp-certs/Makefile.am
+++ b/tests/openpgp-certs/Makefile.am
@@ -21,13 +21,15 @@ if ENABLE_OPENPGP
 
 EXTRA_DIST = ca-public.gpg srv-public-all-signed.gpg srv-secret.gpg    \
        ca-secret.gpg srv-public.gpg srv-public-127.0.0.1-signed.gpg    \
-       srv-public-localhost-signed.gpg
+       srv-public-localhost-signed.gpg selfsigs/alice-mallory-badsig18.pub \
+       selfsigs/alice-mallory-irrelevantsig.pub 
selfsigs/alice-mallory-nosig18.pub \
+       selfsigs/alice.pub
 
 # The selftest is disabled until we can make it work under Wine and
 # under Debian buildds (problem with 127.0.0.2?).  Just extra-dist it
 # for now.
-EXTRA_DIST += testcerts
-#dist_check_SCRIPTS = testcerts
-#TESTS = testcerts
+EXTRA_DIST += testcerts testselfsigs
+dist_check_SCRIPTS = testselfsigs #testcerts
+TESTS = testselfsigs #testcerts
 
 endif
diff --git a/tests/openpgp-certs/selfsigs/alice-mallory-badsig18.pub 
b/tests/openpgp-certs/selfsigs/alice-mallory-badsig18.pub
new file mode 100644
index 0000000..dd4dab1
Binary files /dev/null and 
b/tests/openpgp-certs/selfsigs/alice-mallory-badsig18.pub differ
diff --git a/tests/openpgp-certs/selfsigs/alice-mallory-irrelevantsig.pub 
b/tests/openpgp-certs/selfsigs/alice-mallory-irrelevantsig.pub
new file mode 100644
index 0000000..03caa9d
Binary files /dev/null and 
b/tests/openpgp-certs/selfsigs/alice-mallory-irrelevantsig.pub differ
diff --git a/tests/openpgp-certs/selfsigs/alice-mallory-nosig18.pub 
b/tests/openpgp-certs/selfsigs/alice-mallory-nosig18.pub
new file mode 100644
index 0000000..59f077a
Binary files /dev/null and 
b/tests/openpgp-certs/selfsigs/alice-mallory-nosig18.pub differ
diff --git a/tests/openpgp-certs/selfsigs/alice.pub 
b/tests/openpgp-certs/selfsigs/alice.pub
new file mode 100644
index 0000000..399a0ba
Binary files /dev/null and b/tests/openpgp-certs/selfsigs/alice.pub differ
diff --git a/tests/openpgp-certs/testselfsigs b/tests/openpgp-certs/testselfsigs
new file mode 100755
index 0000000..51acd86
--- /dev/null
+++ b/tests/openpgp-certs/testselfsigs
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+srcdir="${srcdir:-.}"
+CERTTOOL="${certtool:-../../src/certtool} -q"
+unset RETCODE
+
+fail() {
+   echo "Failure: $1" >&2
+   RETCODE=${RETCODE:-${2:-1}}
+}
+
+echo "Checking OpenPGP certificate self verification"
+
+( $CERTTOOL --pgp-certificate-info <$srcdir/selfsigs/alice.pub | grep -e 
"^Self Signature verification: ok" ) >/dev/null ||
+  fail "Self sig Verification should have succeeded!"
+
+( $CERTTOOL --pgp-certificate-info 
<$srcdir/selfsigs/alice-mallory-badsig18.pub | grep -e "^Self Signature 
verification: failed" ) >/dev/null ||
+  fail "Self sig Verification should have failed!"
+( $CERTTOOL --pgp-certificate-info 
<$srcdir/selfsigs/alice-mallory-irrelevantsig.pub | grep -e "^Self Signature 
verification: failed" ) >/dev/null ||
+  fail "Self sig Verification should have failed!"
+( $CERTTOOL --pgp-certificate-info <$srcdir/selfsigs/alice-mallory-nosig18.pub 
| grep -e "^Self Signature verification: failed" ) >/dev/null ||
+  fail "Self sig Verification should have failed!"
+
+exit ${RETCODE:-0}
diff --git a/tests/resume.c b/tests/resume.c
index c52c1d6..80a4c7d 100644
--- a/tests/resume.c
+++ b/tests/resume.c
@@ -58,6 +58,8 @@ struct params_res
   int expect_resume;
 };
 
+pid_t child;
+
 struct params_res resume_tests[] = {
   {"try to resume from db", 50, 0, 0, 1},
 #ifdef ENABLE_SESSION_TICKET
@@ -75,6 +77,12 @@ struct params_res resume_tests[] = {
 #define MSG "Hello TLS"
 
 static void
+tls_log_func (int level, const char *str)
+{
+  fprintf (stderr, "%s |<%d>| %s", child ? "server" : "client", level, str);
+}
+
+static void
 client (struct params_res *params)
 {
   int ret, sd, ii;
@@ -89,6 +97,11 @@ client (struct params_res *params)
   int t;
   gnutls_datum_t session_data;
 
+  if (debug)
+    {
+      gnutls_global_set_log_function (tls_log_func);
+      gnutls_global_set_log_level (4);
+    }
   gnutls_global_init ();
 
   gnutls_anon_allocate_client_credentials (&anoncred);
@@ -336,8 +349,13 @@ server (struct params_res *params)
 
   /* this must be called once in the program, it is mostly for the server.
    */
-  gnutls_global_init ();
+  if (debug)
+    {
+      gnutls_global_set_log_function (tls_log_func);
+      gnutls_global_set_log_level (4);
+    }
 
+  gnutls_global_init ();
   gnutls_anon_allocate_server_credentials (&anoncred);
 
   success ("Launched, generating DH parameters...\n");
@@ -430,7 +448,6 @@ server (struct params_res *params)
 void
 doit (void)
 {
-  pid_t child;
   int i;
 
   for (i = 0; resume_tests[i].desc; i++)


hooks/post-receive
-- 
GNU gnutls




reply via email to

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