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_7-32-g6773d2d


From: Nikos Mavrogiannopoulos
Subject: [SCM] GNU gnutls branch, master, updated. gnutls_2_9_7-32-g6773d2d
Date: Sun, 01 Nov 2009 00:58:58 +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=6773d2ddb01d86fa283ce154b419e989916ab3f7

The branch, master has been updated
       via  6773d2ddb01d86fa283ce154b419e989916ab3f7 (commit)
       via  9a262d093744f37b26f45c4e74d22f3a5a425211 (commit)
       via  03ebe989f1e9de794c32e2a78acc4774c1b4545e (commit)
       via  872c465b7c9f736684f122fbbcb4eef26f60908b (commit)
      from  6b4c3dc567fb1435c8392ec2160fdffc236f6b37 (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 6773d2ddb01d86fa283ce154b419e989916ab3f7
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun Nov 1 02:54:08 2009 +0200

    Improved TLS 1.2 support. Added support for the SignatureAlgorithm extension
    as well for the SignatureAlgorithm in certificate request.
    
    Limitation for TLS 1.2 clients:
     Only SHA1 or SHA256 are supported for generating signatures in
    certificate verify message. That is to avoid storing all handshake
    messages in memory. To be reconsidered in the future.

commit 9a262d093744f37b26f45c4e74d22f3a5a425211
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun Nov 1 01:52:14 2009 +0200

    fixes in order to compile with -Werror

commit 03ebe989f1e9de794c32e2a78acc4774c1b4545e
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat Oct 31 20:25:17 2009 +0200

    remove unnessesary warning.

commit 872c465b7c9f736684f122fbbcb4eef26f60908b
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat Oct 31 10:33:38 2009 +0200

    correctly check extension size.

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

Summary of changes:
 lib/Makefile.am                 |    4 +-
 lib/auth_cert.c                 |   90 +++++++-
 lib/auth_cert.h                 |    1 +
 lib/ext_cert_type.c             |    1 +
 lib/ext_signature.c             |  332 ++++++++++++++++++++++++++++
 lib/ext_signature.h             |   38 ++++
 lib/gnutls_algorithms.c         |    8 +-
 lib/gnutls_algorithms.h         |    3 +-
 lib/gnutls_cert.c               |    1 +
 lib/gnutls_cert.h               |    1 +
 lib/gnutls_cipher.c             |    1 -
 lib/gnutls_errors.c             |    2 +
 lib/gnutls_extensions.c         |    9 +
 lib/gnutls_global.c             |    5 -
 lib/gnutls_handshake.c          |   27 ++-
 lib/gnutls_int.h                |   10 +-
 lib/gnutls_priority.c           |   52 ++++-
 lib/gnutls_sig.c                |  458 ++++++++++++++++++++++++++-------------
 lib/gnutls_sig.h                |    3 +-
 lib/gnutls_state.c              |   56 +++++
 lib/gnutls_state.h              |    3 +-
 lib/gnutls_x509.c               |    9 +
 lib/includes/gnutls/gnutls.h.in |    3 +-
 lib/openpgp/gnutls_openpgp.c    |    2 +
 24 files changed, 923 insertions(+), 196 deletions(-)
 create mode 100644 lib/ext_signature.c
 create mode 100644 lib/ext_signature.h

diff --git a/lib/Makefile.am b/lib/Makefile.am
index 350a087..07d3a97 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -80,7 +80,7 @@ COBJECTS = gnutls_record.c gnutls_compress.c debug.c 
gnutls_cipher.c  \
        gnutls_rsa_export.c auth_rsa_export.c ext_server_name.c         \
        auth_dh_common.c gnutls_helper.c gnutls_supplemental.c          \
        crypto.c random.c pk-libgcrypt.c mpi-libgcrypt.c                \
-       rnd-libgcrypt.c cipher-libgcrypt.c mac-libgcrypt.c
+       rnd-libgcrypt.c cipher-libgcrypt.c mac-libgcrypt.c ext_signature.c
 
 if ENABLE_OPRFI
 COBJECTS += $(OPRFI_COBJECTS)
@@ -100,7 +100,7 @@ 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_session_ticket.h ext_signature.h
 
 # Separate so we can create the documentation
 
diff --git a/lib/auth_cert.c b/lib/auth_cert.c
index f447313..3affa32 100644
--- a/lib/auth_cert.c
+++ b/lib/auth_cert.c
@@ -43,6 +43,7 @@
 #include <gnutls_state.h>
 #include <gnutls_pk.h>
 #include <gnutls_x509.h>
+#include <ext_signature.h>
 #include "debug.h"
 
 #ifdef ENABLE_OPENPGP
@@ -112,6 +113,8 @@ _gnutls_copy_certificate_auth_info (cert_auth_info_t info,
   info->ncerts = ncerts;
 
   info->cert_type = cert[0].cert_type;
+  info->sign_algo = cert[0].sign_algo;
+
 #ifdef ENABLE_OPENPGP
   if (cert[0].cert_type == GNUTLS_CRT_OPENPGP)
     {
@@ -1023,6 +1026,14 @@ _gnutls_proc_x509_server_certificate (gnutls_session_t 
session,
          gnutls_assert ();
          goto cleanup;
        }
+      
+      /* check if signature algorithm is supported */
+      ret = _gnutls_session_sign_algo_supported(session, 
peer_certificate_list[j].sign_algo, 0);
+      if (ret < 0)
+        {
+          gnutls_assert();
+          goto cleanup;
+        }
 
       p += len;
     }
@@ -1356,8 +1367,15 @@ _gnutls_proc_cert_cert_req (gnutls_session_t session, 
opaque * data,
       DECR_LEN (dsize, 2);
       hash_num = _gnutls_read_uint16 (p);
       p += 2;
-
       DECR_LEN (dsize, hash_num);
+
+      ret = _gnutls_sign_algo_parse_data( session, p, hash_num);
+      if (ret < 0)
+        {
+          gnutls_assert();
+          return ret;
+        }
+
       p += hash_num;
     }
 
@@ -1401,6 +1419,10 @@ _gnutls_gen_cert_client_cert_vrfy (gnutls_session_t 
session, opaque ** data)
   gnutls_privkey *apr_pkey;
   int apr_cert_list_length, size;
   gnutls_datum_t signature;
+  int total_data;
+  opaque* p;
+  gnutls_sign_algorithm_t sign_algo;
+  gnutls_protocol_t ver = gnutls_protocol_get_version (session);
 
   *data = NULL;
 
@@ -1423,26 +1445,46 @@ _gnutls_gen_cert_client_cert_vrfy (gnutls_session_t 
session, opaque ** data)
          gnutls_assert ();
          return ret;
        }
+       sign_algo = ret;
     }
   else
     {
       return 0;
     }
 
-  *data = gnutls_malloc (signature.size + 2);
+  total_data = signature.size + 2;
+
+  /* add hash and signature algorithms */
+  if (_gnutls_version_has_selectable_sighash(ver))
+    {
+      total_data+=2;
+    }
+
+  *data = gnutls_malloc (total_data);
   if (*data == NULL)
     {
       _gnutls_free_datum (&signature);
       return GNUTLS_E_MEMORY_ERROR;
     }
+
+  p = *data;
+  if (_gnutls_version_has_selectable_sighash(ver))
+    {
+      /* error checking is not needed here since we have used those algorithms 
*/
+      p[0] = 
_gnutls_sign_algo_hash2num(_gnutls_sign_get_hash_algorithm(sign_algo));
+      p[1] = 
_gnutls_sign_algo_pk2num(_gnutls_sign_get_pk_algorithm(sign_algo));
+      p+=2;
+    }
+
   size = signature.size;
-  _gnutls_write_uint16 (size, *data);
+  _gnutls_write_uint16 (size, p);
 
-  memcpy (&(*data)[2], signature.data, size);
+  p+=2;
+  memcpy (p, signature.data, size);
 
   _gnutls_free_datum (&signature);
 
-  return size + 2;
+  return total_data;
 }
 
 int
@@ -1455,6 +1497,8 @@ _gnutls_proc_cert_client_cert_vrfy (gnutls_session_t 
session,
   gnutls_datum_t sig;
   cert_auth_info_t info = _gnutls_get_auth_info (session);
   gnutls_cert peer_cert;
+  gnutls_sign_algorithm_t sign_algo = GNUTLS_SIGN_UNKNOWN;
+  gnutls_protocol_t ver = gnutls_protocol_get_version (session);
 
   if (info == NULL || info->ncerts == 0)
     {
@@ -1463,6 +1507,18 @@ _gnutls_proc_cert_client_cert_vrfy (gnutls_session_t 
session,
       return GNUTLS_E_INTERNAL_ERROR;
     }
 
+  if (_gnutls_version_has_selectable_sighash(ver))
+    {
+      DECR_LEN (dsize, 2);
+      sign_algo = _gnutls_sign_algo_num2sig (pdata[0], pdata[1]);
+      if (sign_algo == GNUTLS_PK_UNKNOWN)
+        {
+          gnutls_assert();
+          return GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM;
+        }
+      pdata+=2;
+    }
+
   DECR_LEN (dsize, 2);
   size = _gnutls_read_uint16 (pdata);
   pdata += 2;
@@ -1482,7 +1538,7 @@ _gnutls_proc_cert_client_cert_vrfy (gnutls_session_t 
session,
       return ret;
     }
 
-  if ((ret = _gnutls_verify_sig_hdata (session, &peer_cert, &sig)) < 0)
+  if ((ret = _gnutls_verify_sig_hdata (session, &peer_cert, &sig, sign_algo)) 
< 0)
     {
       gnutls_assert ();
       _gnutls_gcert_deinit (&peer_cert);
@@ -1498,9 +1554,10 @@ int
 _gnutls_gen_cert_server_cert_req (gnutls_session_t session, opaque ** data)
 {
   gnutls_certificate_credentials_t cred;
-  int size;
+  int size, ret;
   opaque *pdata;
   gnutls_protocol_t ver = gnutls_protocol_get_version (session);
+  const int signalgosize = 2+MAX_SIGNATURE_ALGORITHMS*2;
 
   /* Now we need to generate the RDN sequence. This is
    * already in the CERTIFICATE_CRED structure, to improve
@@ -1525,7 +1582,7 @@ _gnutls_gen_cert_server_cert_req (gnutls_session_t 
session, opaque ** data)
   if (_gnutls_version_has_selectable_sighash(ver))
     /* Need two bytes to announce the number of supported hash
        functions (see below).  */
-    size += 2;
+    size += signalgosize;
 
   (*data) = gnutls_malloc (size);
   pdata = (*data);
@@ -1544,9 +1601,16 @@ _gnutls_gen_cert_server_cert_req (gnutls_session_t 
session, opaque ** data)
 
   if (_gnutls_version_has_selectable_sighash(ver))
     {
-      /* Supported hashes (nothing for now -- FIXME). */
-      _gnutls_write_uint16 (0, pdata);
-      pdata += 2;
+      ret = _gnutls_sign_algo_write_params(session, pdata, signalgosize);
+      if (ret < 0)
+        {
+          gnutls_assert();
+          return ret;
+        }
+      
+      /* recalculate size */
+      size=size-signalgosize+ret;
+      pdata += ret;
     }
 
   if (session->security_parameters.cert_type == GNUTLS_CRT_X509 &&
@@ -1842,10 +1906,10 @@ _gnutls_server_select_cert (gnutls_session_t session,
       if (requested_algo == GNUTLS_PK_ANY ||
          requested_algo == cred->cert_list[i][0].subject_pk_algorithm)
        {
-         /* if cert type matches 
+         /* if cert type and signature algorithm matches 
           */
          if (session->security_parameters.cert_type ==
-             cred->cert_list[i][0].cert_type)
+             cred->cert_list[i][0].cert_type && 
_gnutls_session_sign_algo_requested(session, cred->cert_list[i][0].sign_algo) 
== 0)
            {
              idx = i;
              break;
diff --git a/lib/auth_cert.h b/lib/auth_cert.h
index 1b808dc..f982bc7 100644
--- a/lib/auth_cert.h
+++ b/lib/auth_cert.h
@@ -117,6 +117,7 @@ typedef struct cert_auth_info_st
   unsigned int ncerts;         /* holds the size of the list above */
 
   gnutls_certificate_type_t cert_type;
+  gnutls_sign_algorithm_t sign_algo;
 #ifdef ENABLE_OPENPGP
   int use_subkey;
   gnutls_openpgp_keyid_t subkey_id;
diff --git a/lib/ext_cert_type.c b/lib/ext_cert_type.c
index 6d3e441..c5a5a35 100644
--- a/lib/ext_cert_type.c
+++ b/lib/ext_cert_type.c
@@ -88,6 +88,7 @@ _gnutls_cert_type_recv_params (gnutls_session_t session,
        {
          uint8_t len;
 
+         DECR_LEN (data_size, 1);
          len = data[0];
          DECR_LEN (data_size, len);
 
diff --git a/lib/ext_signature.c b/lib/ext_signature.c
new file mode 100644
index 0000000..5231174
--- /dev/null
+++ b/lib/ext_signature.c
@@ -0,0 +1,332 @@
+/*
+ * Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * 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
+ *
+ */
+
+/* This file contains the code the Certificate Type TLS extension.
+ * This extension is currently gnutls specific.
+ */
+
+#include "gnutls_int.h"
+#include "gnutls_errors.h"
+#include "gnutls_num.h"
+#include <ext_signature.h>
+#include <gnutls_state.h>
+#include <gnutls_num.h>
+#include <gnutls_algorithms.h>
+
+int _gnutls_sign_algo_pk2num (gnutls_pk_algorithm_t pk)
+{
+  switch (pk)
+    {
+    case GNUTLS_PK_RSA:
+      return 1;
+    case GNUTLS_PK_DSA:
+      return 2;
+    default:
+      gnutls_assert ();
+      return GNUTLS_E_INTERNAL_ERROR;
+    }
+}
+
+int _gnutls_sign_algo_hash2num (gnutls_digest_algorithm_t hash)
+{
+  switch (hash)
+    {
+    case GNUTLS_DIG_MD5:
+      return 1;
+    case GNUTLS_DIG_SHA1:
+      return 2;
+    case GNUTLS_DIG_SHA224:
+      return 3;
+    case GNUTLS_DIG_SHA256:
+      return 4;
+    case GNUTLS_DIG_SHA384:
+      return 5;
+    case GNUTLS_DIG_SHA512:
+      return 6;
+    default:
+      gnutls_assert ();
+      return GNUTLS_E_INTERNAL_ERROR;
+    }
+}
+
+gnutls_sign_algorithm_t
+_gnutls_sign_algo_num2sig (int hash, int sig)
+{
+  if (sig == 1)                 /* rsa */
+    {
+      switch (hash)
+        {
+        case 2:                /* sha1 */
+          return GNUTLS_SIGN_RSA_SHA1;
+        case 3:
+          return GNUTLS_SIGN_RSA_SHA224;
+        case 4:
+          return GNUTLS_SIGN_RSA_SHA256;
+        case 5:
+          return GNUTLS_SIGN_RSA_SHA384;
+        case 6:
+          return GNUTLS_SIGN_RSA_SHA512;
+        default:
+          return GNUTLS_SIGN_UNKNOWN;
+        }
+    }
+
+  if (sig == 2)                 /* DSA */
+    {
+      switch (hash)
+        {
+        case 2:                /* sha1 */
+          return GNUTLS_SIGN_DSA_SHA1;
+        default:
+          return GNUTLS_SIGN_UNKNOWN;
+        }
+    }
+
+  return GNUTLS_SIGN_UNKNOWN;
+}
+
+/* generates a SignatureAndHashAlgorithm structure with length as prefix
+ * by using the setup priorities.
+ */
+int _gnutls_sign_algo_write_params(gnutls_session_t session, opaque *data, 
size_t max_data_size)
+{
+opaque* p = data;
+int len, i ,j;
+int ret, hash, pk;
+
+          len = session->internals.priorities.sign_algo.algorithms * 2;
+          if (max_data_size < len + 2)
+            {
+              gnutls_assert ();
+              return GNUTLS_E_SHORT_MEMORY_BUFFER;
+            }
+
+          _gnutls_write_uint16 (len, p);
+          p += 2;
+
+          for (i = j = 0; i < len; i += 2, j++)
+            {
+              hash =
+                _gnutls_sign_get_hash_algorithm (session->
+                                                 internals.priorities.
+                                                 sign_algo.priority[j]);
+              if (hash == GNUTLS_DIG_UNKNOWN)
+                {
+                  gnutls_assert ();
+                  return GNUTLS_E_INTERNAL_ERROR;
+                }
+              pk =
+                _gnutls_sign_get_pk_algorithm (session->internals.priorities.
+                                               sign_algo.priority[j]);
+              if (pk == GNUTLS_PK_UNKNOWN)
+                {
+                  gnutls_assert ();
+                  return GNUTLS_E_INTERNAL_ERROR;
+                }
+              ret = _gnutls_sign_algo_hash2num (hash);
+              if (ret < 0)
+                {
+                  gnutls_assert ();
+                  return ret;
+                }
+              *p = ret;
+              p++;
+
+              ret = _gnutls_sign_algo_pk2num (pk);
+              if (ret < 0)
+                {
+                  gnutls_assert ();
+                  return ret;
+                }
+
+              *p = ret;
+              p++;
+
+            }
+          return len + 2;
+}
+
+/* Parses the Signature Algorithm structure and stores data into
+ * session->security_parameters.extensions. 
+ */
+int
+_gnutls_sign_algo_parse_data (gnutls_session_t session, const opaque * data,
+                              size_t data_size)
+{
+  int sig, i;
+
+  session->security_parameters.extensions.sign_algorithms_size = 0;
+
+  for (i = 0; i < data_size; i += 2)
+    {
+      sig = _gnutls_sign_algo_num2sig (data[i], data[i + 1]);
+      if (sig != GNUTLS_SIGN_UNKNOWN)
+        {
+          session->security_parameters.extensions.sign_algorithms[session->
+                                                                  
security_parameters.extensions.
+                                                                  
sign_algorithms_size++]
+            = sig;
+          if (session->security_parameters.extensions.sign_algorithms_size ==
+              MAX_SIGNATURE_ALGORITHMS)
+            break;
+        }
+    }
+
+  return 0;
+}
+
+/* 
+ * In case of a server: if a SIGNATURE_ALGORITHMS extension type is received 
then it stores
+ * into the session security parameters the new value. 
+ *
+ * In case of a client: If a signature_algorithms have been specified then it 
is an error;
+ *
+ */
+
+int
+_gnutls_signature_algorithm_recv_params (gnutls_session_t session,
+                                         const opaque * data,
+                                         size_t _data_size)
+{
+  ssize_t data_size = _data_size;
+
+  if (session->security_parameters.entity == GNUTLS_CLIENT)
+    {
+      /* nothing for now */
+      gnutls_assert ();
+      return GNUTLS_E_UNEXPECTED_PACKET;
+    }
+  else
+    {
+      /* SERVER SIDE - we must check if the sent cert type is the right one 
+       */
+      if (data_size > 2)
+        {
+          uint16_t len;
+
+
+          DECR_LEN (data_size, 2);
+          len = _gnutls_read_uint16 (data);
+          DECR_LEN (data_size, len);
+
+          _gnutls_sign_algo_parse_data (session, data + 2, len);
+
+        }
+    }
+
+  return 0;
+}
+
+/* returns data_size or a negative number on failure
+ */
+int
+_gnutls_signature_algorithm_send_params (gnutls_session_t session,
+                                         opaque * data, size_t data_size)
+{
+  int ret;
+  gnutls_protocol_t ver = gnutls_protocol_get_version (session);
+
+  /* this function sends the client extension data */
+  if (session->security_parameters.entity == GNUTLS_CLIENT
+      && _gnutls_version_has_selectable_sighash (ver))
+    {
+
+      if (session->internals.priorities.sign_algo.algorithms > 0)
+        {
+          ret = _gnutls_sign_algo_write_params(session, data, data_size);
+          if (ret < 0)
+            {
+              gnutls_assert();
+              return ret;
+            }
+        }
+    }
+
+  /* if we are here it means we don't send the extension */
+  return 0;
+}
+
+/* Returns a requested by the peer signature algorithm that
+ * matches the given public key algorithm. Index can be increased
+ * to return the second choice etc.
+ */
+gnutls_sign_algorithm_t
+_gnutls_session_get_sign_algo (gnutls_session_t session,
+                               gnutls_pk_algorithm_t pk,
+                               gnutls_digest_algorithm_t * hash)
+{
+  unsigned i;
+  gnutls_protocol_t ver = gnutls_protocol_get_version (session);
+
+
+  if (!_gnutls_version_has_selectable_sighash (ver) || 
session->security_parameters.extensions.sign_algorithms_size == 0)       /* 
none set, allow all */
+    {
+      *hash = GNUTLS_DIG_SHA1;
+      return _gnutls_x509_pk_to_sign (pk, *hash);
+    }
+
+  for (i = 0;
+       i < session->security_parameters.extensions.sign_algorithms_size; i++)
+    {
+      if (_gnutls_sign_get_pk_algorithm
+          (session->security_parameters.extensions.sign_algorithms[i]) == pk)
+        {
+          *hash =
+            _gnutls_sign_get_hash_algorithm (session->security_parameters.
+                                             extensions.sign_algorithms[i]);
+          return session->security_parameters.extensions.sign_algorithms[i];
+        }
+    }
+
+  return GNUTLS_SIGN_UNKNOWN;
+}
+
+
+/* Check if the given signature algorithm is accepted by
+ * the peer. Returns 0 on success or a negative value
+ * on error.
+ */
+int
+_gnutls_session_sign_algo_requested (gnutls_session_t session,
+                                     gnutls_sign_algorithm_t sig)
+{
+  unsigned i;
+  gnutls_protocol_t ver = gnutls_protocol_get_version (session);
+
+  if (!_gnutls_version_has_selectable_sighash (ver) || 
session->security_parameters.extensions.sign_algorithms_size == 0)       /* 
none set, allow all */
+    {
+      return 0;
+    }
+
+  for (i = 0;
+       i < session->security_parameters.extensions.sign_algorithms_size; i++)
+    {
+      if (session->security_parameters.extensions.sign_algorithms[i] == sig)
+        {
+          return 0;             /* ok */
+        }
+    }
+
+  return GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM;
+}
diff --git a/lib/ext_signature.h b/lib/ext_signature.h
new file mode 100644
index 0000000..46b6154
--- /dev/null
+++ b/lib/ext_signature.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * 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
+ *
+ */
+
+/* signature algorithms extension
+ */
+int _gnutls_signature_algorithm_recv_params (gnutls_session_t session,
+                                  const opaque * data, size_t data_size);
+int _gnutls_signature_algorithm_send_params (gnutls_session_t session, opaque 
* data,
+                                  size_t);
+int _gnutls_session_sign_algo_requested (gnutls_session_t session,
+                                     gnutls_sign_algorithm_t sig);
+gnutls_sign_algorithm_t _gnutls_session_get_sign_algo (gnutls_session_t 
session, gnutls_pk_algorithm_t pk, gnutls_digest_algorithm_t *hash);
+int _gnutls_sign_algo_parse_data(gnutls_session_t session, const opaque* data, 
size_t data_size);
+int _gnutls_sign_algo_write_params(gnutls_session_t session, opaque *data, 
size_t max_data_size);
+int _gnutls_sign_algo_pk2num (gnutls_pk_algorithm_t pk);
+int _gnutls_sign_algo_hash2num (gnutls_digest_algorithm_t hash);
+gnutls_sign_algorithm_t _gnutls_sign_algo_num2sig (int hash, int sig);
diff --git a/lib/gnutls_algorithms.c b/lib/gnutls_algorithms.c
index 8f1eb9f..873648e 100644
--- a/lib/gnutls_algorithms.c
+++ b/lib/gnutls_algorithms.c
@@ -1833,7 +1833,7 @@ typedef struct gnutls_sign_entry gnutls_sign_entry;
 #define TLS_SIGN_AID_UNKNOWN {255, 255}
 
 static const gnutls_sign_entry sign_algorithms[] = {
-  {"RSA-SHA", SIG_RSA_SHA1_OID, GNUTLS_SIGN_RSA_SHA1, GNUTLS_PK_RSA,
+  {"RSA-SHA1", SIG_RSA_SHA1_OID, GNUTLS_SIGN_RSA_SHA1, GNUTLS_PK_RSA,
    GNUTLS_MAC_SHA1, {2, 1}},
   {"RSA-SHA256", SIG_RSA_SHA256_OID, GNUTLS_SIGN_RSA_SHA256, GNUTLS_PK_RSA,
    GNUTLS_MAC_SHA256, {4, 1}},
@@ -1843,7 +1843,7 @@ static const gnutls_sign_entry sign_algorithms[] = {
    GNUTLS_MAC_SHA512, {6, 1}},
   {"RSA-RMD160", SIG_RSA_RMD160_OID, GNUTLS_SIGN_RSA_RMD160, GNUTLS_PK_RSA,
    GNUTLS_MAC_RMD160, TLS_SIGN_AID_UNKNOWN},
-  {"DSA-SHA", SIG_DSA_SHA1_OID, GNUTLS_SIGN_DSA_SHA1, GNUTLS_PK_DSA,
+  {"DSA-SHA1", SIG_DSA_SHA1_OID, GNUTLS_SIGN_DSA_SHA1, GNUTLS_PK_DSA,
    GNUTLS_MAC_SHA1, {2, 2}},
   {"RSA-MD5", SIG_RSA_MD5_OID, GNUTLS_SIGN_RSA_MD5, GNUTLS_PK_RSA,
    GNUTLS_MAC_MD5, {1, 1}},
@@ -2001,9 +2001,9 @@ _gnutls_x509_sign_to_oid (gnutls_pk_algorithm_t pk,
 }
 
 gnutls_mac_algorithm_t
-_gnutls_sign_get_mac_algorithm (gnutls_sign_algorithm_t sign)
+_gnutls_sign_get_hash_algorithm (gnutls_sign_algorithm_t sign)
 {
-  gnutls_mac_algorithm_t ret = GNUTLS_MAC_UNKNOWN;
+  gnutls_mac_algorithm_t ret = GNUTLS_DIG_UNKNOWN;
 
   GNUTLS_SIGN_ALG_LOOP (ret = p->mac);
 
diff --git a/lib/gnutls_algorithms.h b/lib/gnutls_algorithms.h
index 0a2faac..8736dc8 100644
--- a/lib/gnutls_algorithms.h
+++ b/lib/gnutls_algorithms.h
@@ -103,11 +103,12 @@ enum encipher_type _gnutls_kx_encipher_type 
(gnutls_kx_algorithm_t algorithm);
 gnutls_sign_algorithm_t _gnutls_x509_oid2sign_algorithm (const char *oid);
 gnutls_sign_algorithm_t _gnutls_x509_pk_to_sign (gnutls_pk_algorithm_t pk,
                                                 gnutls_mac_algorithm_t mac);
+gnutls_pk_algorithm_t _gnutls_x509_sign_to_pk (gnutls_sign_algorithm_t sign);
 const char *_gnutls_x509_sign_to_oid (gnutls_pk_algorithm_t,
                                      gnutls_mac_algorithm_t mac);
 gnutls_sign_algorithm_t _gnutls_tls_aid_to_sign (sign_algorithm_st aid);
 sign_algorithm_st _gnutls_sign_to_tls_aid (gnutls_sign_algorithm_t sign);
-gnutls_mac_algorithm_t _gnutls_sign_get_mac_algorithm 
(gnutls_sign_algorithm_t);
+gnutls_mac_algorithm_t _gnutls_sign_get_hash_algorithm 
(gnutls_sign_algorithm_t);
 gnutls_pk_algorithm_t _gnutls_sign_get_pk_algorithm (gnutls_sign_algorithm_t);
 
 int _gnutls_mac_priority (gnutls_session_t session,
diff --git a/lib/gnutls_cert.c b/lib/gnutls_cert.c
index 42db17c..5b110ad 100644
--- a/lib/gnutls_cert.c
+++ b/lib/gnutls_cert.c
@@ -817,6 +817,7 @@ _gnutls_x509_crt_to_gcert (gnutls_cert * gcert,
 
   memset (gcert, 0, sizeof (gnutls_cert));
   gcert->cert_type = GNUTLS_CRT_X509;
+  gcert->sign_algo = gnutls_x509_crt_get_signature_algorithm(cert);
 
   if (!(flags & CERT_NO_COPY))
     {
diff --git a/lib/gnutls_cert.h b/lib/gnutls_cert.h
index 2a75227..c153607 100644
--- a/lib/gnutls_cert.h
+++ b/lib/gnutls_cert.h
@@ -71,6 +71,7 @@ typedef struct gnutls_cert
   /* holds the type (PGP, X509)
    */
   gnutls_certificate_type_t cert_type;
+  gnutls_sign_algorithm_t sign_algo;
 
   gnutls_datum_t raw;
 
diff --git a/lib/gnutls_cipher.c b/lib/gnutls_cipher.c
index 7519821..525540e 100644
--- a/lib/gnutls_cipher.c
+++ b/lib/gnutls_cipher.c
@@ -201,7 +201,6 @@ mac_init (digest_hd_st * td, gnutls_mac_algorithm_t mac, 
opaque * secret,
 
   if (mac == GNUTLS_MAC_NULL)
     {
-      gnutls_assert ();
       return GNUTLS_E_HASH_FAILED;
     }
 
diff --git a/lib/gnutls_errors.c b/lib/gnutls_errors.c
index 94be5af..b5d8bb6 100644
--- a/lib/gnutls_errors.c
+++ b/lib/gnutls_errors.c
@@ -226,6 +226,8 @@ static const gnutls_error_entry error_algorithms[] = {
 
   ERROR_ENTRY (N_("The OpenPGP fingerprint is not supported."),
               GNUTLS_E_OPENPGP_FINGERPRINT_UNSUPPORTED, 1),
+  ERROR_ENTRY (N_("The signature algorithm is not supported."),
+              GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM, 1),
   ERROR_ENTRY (N_("The certificate has unsupported attributes."),
               GNUTLS_E_X509_UNSUPPORTED_ATTRIBUTE, 1),
   ERROR_ENTRY (N_("The OID is not supported."), GNUTLS_E_X509_UNSUPPORTED_OID,
diff --git a/lib/gnutls_extensions.c b/lib/gnutls_extensions.c
index b7baca2..5f2c47c 100644
--- a/lib/gnutls_extensions.c
+++ b/lib/gnutls_extensions.c
@@ -36,6 +36,7 @@
 #include <ext_oprfi.h>
 #include <ext_srp.h>
 #include <ext_session_ticket.h>
+#include <ext_signature.h>
 #include <gnutls_num.h>
 
 typedef struct
@@ -349,6 +350,14 @@ _gnutls_ext_init (void)
     return ret;
 #endif
 
+  ret = gnutls_ext_register (GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS,
+                             "SIGNATURE_ALGORITHMS",
+                             GNUTLS_EXT_TLS,
+                             _gnutls_signature_algorithm_recv_params,
+                             _gnutls_signature_algorithm_send_params);
+  if (ret != GNUTLS_E_SUCCESS)
+    return ret;
+
   return GNUTLS_E_SUCCESS;
 }
 
diff --git a/lib/gnutls_global.c b/lib/gnutls_global.c
index d98f510..8930de2 100644
--- a/lib/gnutls_global.c
+++ b/lib/gnutls_global.c
@@ -38,11 +38,6 @@
 #define GNUTLS_MIN_LIBGCRYPT_VERSION "1.2.4"
 #define GNUTLS_MIN_LIBTASN1_VERSION "0.3.4"
 
-/* Remove this when we require libtasn1 v1.6 or later. */
-#ifndef ASN1_VERSION
-# define ASN1_VERSION LIBTASN1_VERSION
-#endif
-
 /* created by asn1c */
 extern const ASN1_ARRAY_TYPE gnutls_asn1_tab[];
 extern const ASN1_ARRAY_TYPE pkix_asn1_tab[];
diff --git a/lib/gnutls_handshake.c b/lib/gnutls_handshake.c
index 7423f27..b7d5af3 100644
--- a/lib/gnutls_handshake.c
+++ b/lib/gnutls_handshake.c
@@ -90,7 +90,9 @@ _gnutls_handshake_hash_buffers_clear (gnutls_session_t 
session)
           handshake_mac_handle_type == HANDSHAKE_MAC_TYPE_12)
     {
       _gnutls_hash_deinit (&session->internals.
-                          handshake_mac_handle.tls12.mac, NULL);
+                          handshake_mac_handle.tls12.sha256, NULL);
+      _gnutls_hash_deinit (&session->internals.
+                          handshake_mac_handle.tls12.sha1, NULL);
     }
   session->security_parameters.handshake_mac_handle_type = 0;
   session->internals.handshake_mac_handle_init = 0;
@@ -261,7 +263,7 @@ _gnutls_finished (gnutls_session_t session, int type, void 
*ret)
           handshake_mac_handle_type == HANDSHAKE_MAC_TYPE_12)
     {
       rc = _gnutls_hash_copy (&td_sha, &session->internals.
-                             handshake_mac_handle.tls12.mac);
+                             handshake_mac_handle.tls12.sha256);
       if (rc < 0)
        {
          gnutls_assert ();
@@ -574,7 +576,8 @@ _gnutls_handshake_hash_pending (gnutls_session_t session)
         } 
       else if (session->security_parameters.handshake_mac_handle_type == 
HANDSHAKE_MAC_TYPE_12)
         {
-          _gnutls_hash (&session->internals.handshake_mac_handle.tls12.mac, 
data, siz);
+          _gnutls_hash (&session->internals.handshake_mac_handle.tls12.sha256, 
data, siz);
+          _gnutls_hash (&session->internals.handshake_mac_handle.tls12.sha1, 
data, siz);
         }
     }
 
@@ -984,7 +987,9 @@ _gnutls_handshake_hash_add_sent (gnutls_session_t session,
         }
       else if (session->security_parameters.handshake_mac_handle_type == 
HANDSHAKE_MAC_TYPE_12) 
         { 
-          _gnutls_hash (&session->internals.handshake_mac_handle.tls12.mac, 
dataptr,
+          _gnutls_hash (&session->internals.handshake_mac_handle.tls12.sha256, 
dataptr,
+                   datalen);
+          _gnutls_hash (&session->internals.handshake_mac_handle.tls12.sha1, 
dataptr,
                    datalen);
         }
     }
@@ -2301,14 +2306,22 @@ _gnutls_handshake_hash_init (gnutls_session_t session)
         /* The algorithm to compute hash over handshake messages must be
           same as the one used as the basis for PRF.  By now we use
           SHA256. */
-          gnutls_digest_algorithm_t hash_algo = GNUTLS_MAC_SHA256;
+          ret =
+           _gnutls_hash_init 
(&session->internals.handshake_mac_handle.tls12.sha256,
+                          GNUTLS_DIG_SHA256);
+           if (ret < 0)
+            {
+              gnutls_assert ();
+              return GNUTLS_E_MEMORY_ERROR;
+            }
 
           ret =
-           _gnutls_hash_init 
(&session->internals.handshake_mac_handle.tls12.mac,
-                          hash_algo);
+           _gnutls_hash_init 
(&session->internals.handshake_mac_handle.tls12.sha1,
+                          GNUTLS_DIG_SHA1);
            if (ret < 0)
             {
               gnutls_assert ();
+              
_gnutls_hash_deinit(&session->internals.handshake_mac_handle.tls12.sha256, 
NULL);
               return GNUTLS_E_MEMORY_ERROR;
             }
         }
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index ac1da9d..5f07164 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -175,6 +175,7 @@ typedef enum extensions_t
   GNUTLS_EXTENSION_OPAQUE_PRF_INPUT = ENABLE_OPRFI,
 #endif
   GNUTLS_EXTENSION_SRP = 12,
+  GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS = 13,
   GNUTLS_EXTENSION_SESSION_TICKET = 35,
   GNUTLS_EXTENSION_INNER_APPLICATION = 37703
 } extensions_t;
@@ -297,6 +298,7 @@ typedef struct
 } server_name_st;
 
 #define MAX_SERVER_NAME_EXTENSIONS 3
+#define MAX_SIGNATURE_ALGORITHMS 16
 
 struct gnutls_session_ticket_key_st {
   opaque key_name[SESSION_TICKET_KEY_NAME_SIZE];
@@ -312,6 +314,10 @@ typedef struct
 
   opaque srp_username[MAX_SRP_USERNAME + 1];
 
+  /* TLS 1.2 signature algorithms */
+  gnutls_sign_algorithm_t sign_algorithms[MAX_SIGNATURE_ALGORITHMS];
+  uint16_t sign_algorithms_size;
+
   /* TLS/IA data. */
   int gnutls_ia_enable, gnutls_ia_peer_enable;
   int gnutls_ia_allowskip, gnutls_ia_peer_allowskip;
@@ -437,6 +443,7 @@ struct gnutls_priority_st
   priority_st compression;
   priority_st protocol;
   priority_st cert_type;
+  priority_st sign_algo;
 
   /* to disable record padding */
   int no_padding;
@@ -489,7 +496,8 @@ typedef struct
         } tls10;
       struct
         {
-          digest_hd_st mac;    /* hash of the handshake messages for TLS 1.2+ 
*/
+          digest_hd_st sha1;   /* hash of the handshake messages for TLS 1.2+ 
*/
+          digest_hd_st sha256; /* hash of the handshake messages for TLS 1.2+ 
*/
         } tls12;
     } handshake_mac_handle;
   int handshake_mac_handle_init; /* 1 when the previous union and type were 
initialized */
diff --git a/lib/gnutls_priority.c b/lib/gnutls_priority.c
index f50eb8c..5248b4f 100644
--- a/lib/gnutls_priority.c
+++ b/lib/gnutls_priority.c
@@ -338,6 +338,27 @@ static const int comp_priority[] = {
   0
 };
 
+static const int sign_priority_default[] = {
+  GNUTLS_SIGN_RSA_SHA1,
+  GNUTLS_SIGN_DSA_SHA1,
+  GNUTLS_SIGN_RSA_SHA256,
+  GNUTLS_SIGN_RSA_SHA384,
+  GNUTLS_SIGN_RSA_SHA512,
+  0
+};
+
+static const int sign_priority_secure128[] = {
+  GNUTLS_SIGN_RSA_SHA256,
+  GNUTLS_SIGN_RSA_SHA384,
+  GNUTLS_SIGN_RSA_SHA512,
+  GNUTLS_SIGN_DSA_SHA1,
+  0
+};
+
+static const int sign_priority_secure256[] = {
+  GNUTLS_SIGN_RSA_SHA512,
+  0
+};
 
 static const int mac_priority_performance[] = {
   GNUTLS_MAC_MD5,
@@ -345,6 +366,7 @@ static const int mac_priority_performance[] = {
   0
 };
 
+
 static const int mac_priority_secure[] = {
   GNUTLS_MAC_SHA256,
   GNUTLS_MAC_SHA1,
@@ -509,7 +531,7 @@ gnutls_priority_set (gnutls_session_t session, 
gnutls_priority_t priority)
  * Namespace concern:
  * 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
+ * with "VERS-", signature algorithms with "SIGN-" and certificate types with 
"CTYPE-". All other
  * algorithms don't need a prefix.
  *
  * Examples:
@@ -561,6 +583,7 @@ gnutls_priority_init (gnutls_priority_t * priority_cache,
       _set_priority (&(*priority_cache)->protocol, protocol_priority);
       _set_priority (&(*priority_cache)->compression, comp_priority);
       _set_priority (&(*priority_cache)->cert_type, cert_type_priority);
+      _set_priority (&(*priority_cache)->sign_algo, sign_priority_default);
       i = 0;
     }
   else
@@ -576,12 +599,14 @@ gnutls_priority_init (gnutls_priority_t * priority_cache,
                         cipher_priority_performance);
          _set_priority (&(*priority_cache)->kx, kx_priority_performance);
          _set_priority (&(*priority_cache)->mac, mac_priority_performance);
+          _set_priority (&(*priority_cache)->sign_algo, sign_priority_default);
        }
       else if (strcasecmp (broken_list[i], "NORMAL") == 0)
        {
          _set_priority (&(*priority_cache)->cipher, cipher_priority_normal);
          _set_priority (&(*priority_cache)->kx, kx_priority_secure);
          _set_priority (&(*priority_cache)->mac, mac_priority_secure);
+          _set_priority (&(*priority_cache)->sign_algo, sign_priority_default);
        }
       else if (strcasecmp (broken_list[i], "SECURE256") == 0
               || strcasecmp (broken_list[i], "SECURE") == 0)
@@ -590,6 +615,7 @@ gnutls_priority_init (gnutls_priority_t * priority_cache,
                         cipher_priority_secure256);
          _set_priority (&(*priority_cache)->kx, kx_priority_secure);
          _set_priority (&(*priority_cache)->mac, mac_priority_secure);
+          _set_priority (&(*priority_cache)->sign_algo, 
sign_priority_secure256);
        }
       else if (strcasecmp (broken_list[i], "SECURE128") == 0)
        {
@@ -597,12 +623,14 @@ gnutls_priority_init (gnutls_priority_t * priority_cache,
                         cipher_priority_secure128);
          _set_priority (&(*priority_cache)->kx, kx_priority_secure);
          _set_priority (&(*priority_cache)->mac, mac_priority_secure);
+          _set_priority (&(*priority_cache)->sign_algo, 
sign_priority_secure128);
        }
       else if (strcasecmp (broken_list[i], "EXPORT") == 0)
        {
          _set_priority (&(*priority_cache)->cipher, cipher_priority_export);
          _set_priority (&(*priority_cache)->kx, kx_priority_export);
          _set_priority (&(*priority_cache)->mac, mac_priority_secure);
+          _set_priority (&(*priority_cache)->sign_algo, sign_priority_default);
        }                       /* now check if the element is something like 
-ALGO */
       else if (broken_list[i][0] == '!' || broken_list[i][0] == '+'
               || broken_list[i][0] == '-')
@@ -627,6 +655,8 @@ gnutls_priority_init (gnutls_priority_t * priority_cache,
                   gnutls_protocol_get_id (&broken_list[i][6])) !=
                  GNUTLS_VERSION_UNKNOWN)
                fn (&(*priority_cache)->protocol, algo);
+              else
+                goto error;
            }                   /* now check if the element is something like 
-ALGO */
          else if (strncasecmp (&broken_list[i][1], "COMP-", 5) == 0)
            {
@@ -634,6 +664,8 @@ gnutls_priority_init (gnutls_priority_t * priority_cache,
                   gnutls_compression_get_id (&broken_list[i][6])) !=
                  GNUTLS_COMP_UNKNOWN)
                fn (&(*priority_cache)->compression, algo);
+              else
+                goto error;
            }                   /* now check if the element is something like 
-ALGO */
          else if (strncasecmp (&broken_list[i][1], "CTYPE-", 6) == 0)
            {
@@ -641,6 +673,17 @@ gnutls_priority_init (gnutls_priority_t * priority_cache,
                   gnutls_certificate_type_get_id (&broken_list[i][7])) !=
                  GNUTLS_CRT_UNKNOWN)
                fn (&(*priority_cache)->cert_type, algo);
+              else
+                goto error;
+           }                   /* now check if the element is something like 
-ALGO */
+         else if (strncasecmp (&broken_list[i][1], "SIGN-", 5) == 0)
+           {
+             if ((algo =
+                  gnutls_sign_get_id (&broken_list[i][6])) !=
+                 GNUTLS_SIGN_UNKNOWN)
+               fn (&(*priority_cache)->sign_algo, algo);
+              else
+                goto error;
            }                   /* now check if the element is something like 
-ALGO */
          else
            goto error;
@@ -651,8 +694,11 @@ gnutls_priority_init (gnutls_priority_t * priority_cache,
            (*priority_cache)->no_padding = 1;
          else if (strcasecmp (&broken_list[i][1],
                               "VERIFY_ALLOW_SIGN_RSA_MD5") == 0)
-           (*priority_cache)->additional_verify_flags |=
-             GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5;
+            {
+             prio_add (&(*priority_cache)->sign_algo, GNUTLS_SIGN_RSA_MD5);
+             (*priority_cache)->additional_verify_flags |=
+               GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5;
+            }
          else if (strcasecmp (&broken_list[i][1],
                               "SSL3_RECORD_VERSION") == 0)
            (*priority_cache)->ssl3_record_version = 1;
diff --git a/lib/gnutls_sig.c b/lib/gnutls_sig.c
index c49f2ed..76e1f6d 100644
--- a/lib/gnutls_sig.c
+++ b/lib/gnutls_sig.c
@@ -37,6 +37,8 @@
 #include <gnutls_sig.h>
 #include <gnutls_kx.h>
 #include <libtasn1.h>
+#include <ext_signature.h>
+#include <gnutls_state.h>
 
 static int
 _gnutls_tls_sign (gnutls_session_t session,
@@ -117,93 +119,6 @@ _gnutls_rsa_encode_sig (gnutls_mac_algorithm_t algo,
   return 0;
 }
 
-/* Generates a signature of all the previous sent packets in the 
- * handshake procedure. (20040227: now it works for SSL 3.0 as well)
- */
-int
-_gnutls_tls_sign_hdata (gnutls_session_t session,
-                       gnutls_cert * cert, gnutls_privkey * pkey,
-                       gnutls_datum_t * signature)
-{
-  gnutls_datum_t dconcat;
-  int ret;
-  opaque concat[MAX_SIG_SIZE];
-  digest_hd_st td_md5;
-  digest_hd_st td_sha;
-  gnutls_protocol_t ver = gnutls_protocol_get_version (session);
-
-  /* FIXME: This is not compliant to TLS 1.2. We should use an algorithm from 
the
-   * SignatureAndHashAlgorithm field of Certificate Request.
-   */
-  if (session->security_parameters.handshake_mac_handle_type != 
HANDSHAKE_MAC_TYPE_10)
-    {
-      gnutls_assert();
-      return GNUTLS_E_UNIMPLEMENTED_FEATURE;
-    }
-  
-  ret =
-    _gnutls_hash_copy (&td_sha, 
&session->internals.handshake_mac_handle.tls10.sha);
-  if (ret < 0)
-    {
-      gnutls_assert ();
-      return ret;
-    }
-
-  if (ver == GNUTLS_SSL3)
-    {
-      ret = _gnutls_generate_master (session, 1);
-      if (ret < 0)
-       {
-         gnutls_assert ();
-         return ret;
-       }
-
-      _gnutls_mac_deinit_ssl3_handshake (&td_sha, &concat[16],
-                                        session->security_parameters.
-                                        master_secret, GNUTLS_MASTER_SIZE);
-    }
-  else
-    _gnutls_hash_deinit (&td_sha, &concat[16]);
-
-  switch (cert->subject_pk_algorithm)
-    {
-    case GNUTLS_PK_RSA:
-      ret =
-       _gnutls_hash_copy (&td_md5,
-                          &session->internals.handshake_mac_handle.tls10.md5);
-      if (ret < 0)
-       {
-         gnutls_assert ();
-         return ret;
-       }
-
-      if (ver == GNUTLS_SSL3)
-       _gnutls_mac_deinit_ssl3_handshake (&td_md5, concat,
-                                          session->security_parameters.
-                                          master_secret, GNUTLS_MASTER_SIZE);
-      else
-       _gnutls_hash_deinit (&td_md5, concat);
-
-      dconcat.data = concat;
-      dconcat.size = 36;
-      break;
-    case GNUTLS_PK_DSA:
-      dconcat.data = &concat[16];
-      dconcat.size = 20;
-      break;
-
-    default:
-      gnutls_assert ();
-      return GNUTLS_E_INTERNAL_ERROR;
-    }
-  ret = _gnutls_tls_sign (session, cert, pkey, &dconcat, signature);
-  if (ret < 0)
-    {
-      gnutls_assert ();
-    }
-
-  return ret;
-}
 
 
 /* Generates a signature of all the random data and the parameters.
@@ -220,22 +135,17 @@ _gnutls_tls_sign_params (gnutls_session_t session, 
gnutls_cert * cert,
   digest_hd_st td_sha;
   opaque concat[MAX_SIG_SIZE];
   gnutls_protocol_t ver = gnutls_protocol_get_version (session);
-  gnutls_mac_algorithm_t mac_algo = GNUTLS_MAC_SHA1;
-  gnutls_sign_algorithm_t _sign_algo = GNUTLS_SIGN_UNKNOWN;
+  gnutls_digest_algorithm_t hash_algo;
 
-  if (_gnutls_version_has_selectable_prf (ver))
+  *sign_algo = _gnutls_session_get_sign_algo(session, 
cert->subject_pk_algorithm,
+                                           &hash_algo);
+  if (*sign_algo == GNUTLS_SIGN_UNKNOWN)
     {
-      _sign_algo = _gnutls_x509_pk_to_sign (cert->subject_pk_algorithm,
-                                           mac_algo);
-      if (_sign_algo == GNUTLS_SIGN_UNKNOWN)
-       {
-         gnutls_assert ();
-         return GNUTLS_E_UNKNOWN_PK_ALGORITHM;
-       }
+      gnutls_assert ();
+      return GNUTLS_E_UNKNOWN_PK_ALGORITHM;
     }
-  *sign_algo = _sign_algo;
 
-  ret = _gnutls_hash_init (&td_sha, mac_algo);
+  ret = _gnutls_hash_init (&td_sha, hash_algo);
   if (ret < 0)
     {
       gnutls_assert ();
@@ -275,21 +185,27 @@ _gnutls_tls_sign_params (gnutls_session_t session, 
gnutls_cert * cert,
          dconcat.size = 36;
        }
       else
-       {
+       { /* TLS 1.2 way */
          gnutls_datum_t hash;
 
          _gnutls_hash_deinit (&td_sha, concat);
 
          hash.data = concat;
-         hash.size = _gnutls_hash_get_algo_len (mac_algo);
+         hash.size = _gnutls_hash_get_algo_len (hash_algo);
          dconcat.data = concat;
          dconcat.size = sizeof concat;
 
-         _gnutls_rsa_encode_sig (mac_algo, &hash, &dconcat);
+         _gnutls_rsa_encode_sig (hash_algo, &hash, &dconcat);
        }
       break;
     case GNUTLS_PK_DSA:
       _gnutls_hash_deinit (&td_sha, concat);
+
+      if (hash_algo != GNUTLS_DIG_SHA1)
+        {
+          gnutls_assert();
+          return GNUTLS_E_INTERNAL_ERROR;
+        }
       dconcat.data = concat;
       dconcat.size = 20;
       break;
@@ -459,12 +375,160 @@ _gnutls_verify_sig (gnutls_cert * cert,
 }
 
 
+/* Generates a signature of all the random data and the parameters.
+ * Used in DHE_* ciphersuites.
+ */
+int
+_gnutls_verify_sig_params (gnutls_session_t session, gnutls_cert * cert,
+                          const gnutls_datum_t * params,
+                          gnutls_datum_t * signature,
+                          gnutls_sign_algorithm_t algo)
+{
+  gnutls_datum_t dconcat;
+  int ret;
+  digest_hd_st td_md5;
+  digest_hd_st td_sha;
+  opaque concat[MAX_SIG_SIZE];
+  gnutls_protocol_t ver = gnutls_protocol_get_version (session);
+  gnutls_digest_algorithm_t hash_algo = GNUTLS_DIG_SHA1;
+
+  ret = _gnutls_session_sign_algo_supported(session, algo, 0);
+  if (ret < 0)
+    {
+      gnutls_assert();
+      return ret;
+    }
+
+  if (!_gnutls_version_has_selectable_prf (ver))
+    {
+      ret = _gnutls_hash_init (&td_md5, GNUTLS_MAC_MD5);
+      if (ret < 0)
+       {
+         gnutls_assert ();
+         return ret;
+       }
+
+      _gnutls_hash (&td_md5, session->security_parameters.client_random,
+                   GNUTLS_RANDOM_SIZE);
+      _gnutls_hash (&td_md5, session->security_parameters.server_random,
+                   GNUTLS_RANDOM_SIZE);
+      _gnutls_hash (&td_md5, params->data, params->size);
+    }
+
+  if (algo != GNUTLS_SIGN_UNKNOWN)
+    hash_algo = _gnutls_sign_get_hash_algorithm (algo);
+
+  ret = _gnutls_hash_init (&td_sha, hash_algo);
+  if (ret < 0)
+    {
+      gnutls_assert ();
+      if (!_gnutls_version_has_selectable_prf (ver))
+       _gnutls_hash_deinit (&td_md5, NULL);
+      return ret;
+    }
+
+  _gnutls_hash (&td_sha, session->security_parameters.client_random,
+               GNUTLS_RANDOM_SIZE);
+  _gnutls_hash (&td_sha, session->security_parameters.server_random,
+               GNUTLS_RANDOM_SIZE);
+  _gnutls_hash (&td_sha, params->data, params->size);
+
+  if (!_gnutls_version_has_selectable_prf (ver))
+    {
+      _gnutls_hash_deinit (&td_md5, concat);
+      _gnutls_hash_deinit (&td_sha, &concat[16]);
+      dconcat.data = concat;
+      dconcat.size = 36;
+    }
+  else
+    {
+      gnutls_datum_t hash;
+
+      _gnutls_hash_deinit (&td_sha, concat);
+
+      hash.data = concat;
+      hash.size = _gnutls_hash_get_algo_len (hash_algo);
+      dconcat.data = concat;
+      dconcat.size = sizeof concat;
+
+      _gnutls_rsa_encode_sig (hash_algo, &hash, &dconcat);
+    }
+
+  ret = _gnutls_verify_sig (cert, &dconcat, signature,
+                           dconcat.size - _gnutls_hash_get_algo_len 
(hash_algo),
+                           _gnutls_sign_get_pk_algorithm (algo));
+  if (ret < 0)
+    {
+      gnutls_assert ();
+      return ret;
+    }
+
+  return ret;
+
+}
+
+/* Client certificate verify calculations
+ */
+
+/* this is _gnutls_verify_sig_hdata for TLS 1.2
+ */
+static int _gnutls_tls12_verify_sig_hdata (gnutls_session_t session, 
gnutls_cert * cert,
+                         gnutls_datum_t * signature, gnutls_sign_algorithm_t 
sign_algo)
+{
+  int ret;
+  opaque concat[MAX_SIG_SIZE];
+  digest_hd_st td;
+  gnutls_datum_t dconcat;
+  gnutls_sign_algorithm_t _sign_algo;
+  gnutls_digest_algorithm_t hash_algo;
+  digest_hd_st* handshake_td;
+
+  handshake_td = &session->internals.handshake_mac_handle.tls12.sha1;
+  hash_algo = handshake_td->algorithm;
+  _sign_algo = _gnutls_x509_pk_to_sign( cert->subject_pk_algorithm, hash_algo);
+
+  if (_sign_algo != sign_algo)
+    {
+      handshake_td = &session->internals.handshake_mac_handle.tls12.sha256;
+      hash_algo = handshake_td->algorithm;
+      _sign_algo = _gnutls_x509_pk_to_sign( cert->subject_pk_algorithm, 
hash_algo);
+      if (sign_algo != _sign_algo)
+        {
+          gnutls_assert();
+          return GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM;
+        }
+    }
+
+  ret =
+    _gnutls_hash_copy (&td, handshake_td);
+  if (ret < 0)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_HASH_FAILED;
+    }
+
+  _gnutls_hash_deinit (&td, concat);
+
+  dconcat.data = concat;
+  dconcat.size = _gnutls_hash_get_algo_len (hash_algo);
+
+  ret = _gnutls_verify_sig (cert, &dconcat, signature, 0, 
cert->subject_pk_algorithm);
+  if (ret < 0)
+    {
+      gnutls_assert ();
+      return ret;
+    }
+
+  return ret;
+
+}
+
 /* Verifies a TLS signature (like the one in the client certificate
  * verify message). 
  */
 int
 _gnutls_verify_sig_hdata (gnutls_session_t session, gnutls_cert * cert,
-                         gnutls_datum_t * signature)
+                         gnutls_datum_t * signature, gnutls_sign_algorithm_t 
sign_algo)
 {
   int ret;
   opaque concat[MAX_SIG_SIZE];
@@ -473,10 +537,14 @@ _gnutls_verify_sig_hdata (gnutls_session_t session, 
gnutls_cert * cert,
   gnutls_datum_t dconcat;
   gnutls_protocol_t ver = gnutls_protocol_get_version (session);
 
-  if (session->security_parameters.handshake_mac_handle_type != 
HANDSHAKE_MAC_TYPE_10)
+  if (session->security_parameters.handshake_mac_handle_type == 
HANDSHAKE_MAC_TYPE_12)
+    {
+      return _gnutls_tls12_verify_sig_hdata(session, cert, signature, 
sign_algo);
+    }
+  else if (session->security_parameters.handshake_mac_handle_type != 
HANDSHAKE_MAC_TYPE_10)
     {
       gnutls_assert();
-      return GNUTLS_E_UNIMPLEMENTED_FEATURE;
+      return GNUTLS_E_INTERNAL_ERROR;
     }
 
   ret =
@@ -521,7 +589,7 @@ _gnutls_verify_sig_hdata (gnutls_session_t session, 
gnutls_cert * cert,
   dconcat.data = concat;
   dconcat.size = 20 + 16;      /* md5+ sha */
 
-  ret = _gnutls_verify_sig (cert, &dconcat, signature, 16, 
GNUTLS_SIGN_UNKNOWN);
+  ret = _gnutls_verify_sig (cert, &dconcat, signature, 16, 
cert->subject_pk_algorithm);
   if (ret < 0)
     {
       gnutls_assert ();
@@ -532,86 +600,164 @@ _gnutls_verify_sig_hdata (gnutls_session_t session, 
gnutls_cert * cert,
 
 }
 
-/* Generates a signature of all the random data and the parameters.
- * Used in DHE_* ciphersuites.
+/* the same as _gnutls_tls_sign_hdata except that it is made for TLS 1.2
  */
-int
-_gnutls_verify_sig_params (gnutls_session_t session, gnutls_cert * cert,
-                          const gnutls_datum_t * params,
-                          gnutls_datum_t * signature,
-                          gnutls_sign_algorithm_t algo)
+static int _gnutls_tls12_sign_hdata (gnutls_session_t session,
+                       gnutls_cert * cert, gnutls_privkey * pkey,
+                       gnutls_datum_t * signature)
 {
   gnutls_datum_t dconcat;
   int ret;
-  digest_hd_st td_md5;
-  digest_hd_st td_sha;
   opaque concat[MAX_SIG_SIZE];
-  gnutls_protocol_t ver = gnutls_protocol_get_version (session);
-  gnutls_mac_algorithm_t mac_algo = GNUTLS_MAC_SHA1;
-
-  if (!_gnutls_version_has_selectable_prf (ver))
+  digest_hd_st td;
+  gnutls_sign_algorithm_t sign_algo;
+  gnutls_digest_algorithm_t hash_algo;
+  digest_hd_st* handshake_td;
+
+  handshake_td = &session->internals.handshake_mac_handle.tls12.sha1;
+  hash_algo = handshake_td->algorithm;
+  sign_algo = _gnutls_x509_pk_to_sign( cert->subject_pk_algorithm, hash_algo);
+
+  /* The idea here is to try signing with the one of the algorithms
+   * that have been initiated at handshake (SHA1, SHA256). If they
+   * are not requested by peer... tough luck
+   */
+  ret = _gnutls_session_sign_algo_requested(session, sign_algo);
+  if (sign_algo == GNUTLS_SIGN_UNKNOWN || ret < 0)
     {
-      ret = _gnutls_hash_init (&td_md5, GNUTLS_MAC_MD5);
+      handshake_td = &session->internals.handshake_mac_handle.tls12.sha256;
+      hash_algo = handshake_td->algorithm;
+      sign_algo = _gnutls_x509_pk_to_sign( cert->subject_pk_algorithm, 
hash_algo);
+      if (sign_algo == GNUTLS_SIGN_UNKNOWN)
+        {
+          gnutls_assert();
+          return GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM;
+        }
+      
+      ret = _gnutls_session_sign_algo_requested(session, sign_algo);  
       if (ret < 0)
-       {
-         gnutls_assert ();
-         return ret;
-       }
+        {
+          gnutls_assert();
+          _gnutls_x509_log("Server did not allow either '%s' or '%s' for 
signing\n", gnutls_mac_get_name(hash_algo), 
gnutls_mac_get_name(session->internals.handshake_mac_handle.tls12.sha1.algorithm));
+          return ret;
+        }
+    }
+  
+  _gnutls_x509_log("sign hash data: picked %s with %s\n", 
gnutls_sign_algorithm_get_name(sign_algo), gnutls_mac_get_name(hash_algo));
 
-      _gnutls_hash (&td_md5, session->security_parameters.client_random,
-                   GNUTLS_RANDOM_SIZE);
-      _gnutls_hash (&td_md5, session->security_parameters.server_random,
-                   GNUTLS_RANDOM_SIZE);
-      _gnutls_hash (&td_md5, params->data, params->size);
+  ret =
+    _gnutls_hash_copy (&td, handshake_td);
+  if (ret < 0)
+    {
+      gnutls_assert ();
+      return ret;
     }
 
-  if (algo != GNUTLS_SIGN_UNKNOWN)
-    mac_algo = _gnutls_sign_get_mac_algorithm (algo);
-  ret = _gnutls_hash_init (&td_sha, mac_algo);
+  _gnutls_hash_deinit (&td, concat);
+
+  dconcat.data = concat;
+  dconcat.size = _gnutls_hash_get_algo_len (hash_algo);
+
+  ret = _gnutls_tls_sign (session, cert, pkey, &dconcat, signature);
   if (ret < 0)
     {
       gnutls_assert ();
-      if (!_gnutls_version_has_selectable_prf (ver))
-       _gnutls_hash_deinit (&td_md5, NULL);
       return ret;
     }
 
-  _gnutls_hash (&td_sha, session->security_parameters.client_random,
-               GNUTLS_RANDOM_SIZE);
-  _gnutls_hash (&td_sha, session->security_parameters.server_random,
-               GNUTLS_RANDOM_SIZE);
-  _gnutls_hash (&td_sha, params->data, params->size);
+  return sign_algo;
+}
 
-  if (!_gnutls_version_has_selectable_prf (ver))
+/* Generates a signature of all the previous sent packets in the 
+ * handshake procedure. 
+ * 20040227: now it works for SSL 3.0 as well
+ * 20091031: works for TLS 1.2 too!
+ *
+ * For TLS1.x, x<2 returns negative for failure and zero or unspecified for 
success.
+ * For TLS1.2 returns the signature algorithm used on success, or a negative 
value;
+ */
+int
+_gnutls_tls_sign_hdata (gnutls_session_t session,
+                       gnutls_cert * cert, gnutls_privkey * pkey,
+                       gnutls_datum_t * signature)
+{
+  gnutls_datum_t dconcat;
+  int ret;
+  opaque concat[MAX_SIG_SIZE];
+  digest_hd_st td_md5;
+  digest_hd_st td_sha;
+  gnutls_protocol_t ver = gnutls_protocol_get_version (session);
+
+  if (session->security_parameters.handshake_mac_handle_type == 
HANDSHAKE_MAC_TYPE_12)
     {
-      _gnutls_hash_deinit (&td_md5, concat);
-      _gnutls_hash_deinit (&td_sha, &concat[16]);
-      dconcat.data = concat;
-      dconcat.size = 36;
+      return _gnutls_tls12_sign_hdata(session, cert, pkey, signature);
+    }
+  else if (session->security_parameters.handshake_mac_handle_type != 
HANDSHAKE_MAC_TYPE_10)
+    {
+      gnutls_assert();
+      return GNUTLS_E_INTERNAL_ERROR;
+    }
+  
+  ret =
+    _gnutls_hash_copy (&td_sha, 
&session->internals.handshake_mac_handle.tls10.sha);
+  if (ret < 0)
+    {
+      gnutls_assert ();
+      return ret;
+    }
+
+  if (ver == GNUTLS_SSL3)
+    {
+      ret = _gnutls_generate_master (session, 1);
+      if (ret < 0)
+       {
+         gnutls_assert ();
+         return ret;
+       }
+
+      _gnutls_mac_deinit_ssl3_handshake (&td_sha, &concat[16],
+                                        session->security_parameters.
+                                        master_secret, GNUTLS_MASTER_SIZE);
     }
   else
+    _gnutls_hash_deinit (&td_sha, &concat[16]);
+
+  switch (cert->subject_pk_algorithm)
     {
-      gnutls_datum_t hash;
+    case GNUTLS_PK_RSA:
+      ret =
+       _gnutls_hash_copy (&td_md5,
+                          &session->internals.handshake_mac_handle.tls10.md5);
+      if (ret < 0)
+       {
+         gnutls_assert ();
+         return ret;
+       }
 
-      _gnutls_hash_deinit (&td_sha, concat);
+      if (ver == GNUTLS_SSL3)
+       _gnutls_mac_deinit_ssl3_handshake (&td_md5, concat,
+                                          session->security_parameters.
+                                          master_secret, GNUTLS_MASTER_SIZE);
+      else
+       _gnutls_hash_deinit (&td_md5, concat);
 
-      hash.data = concat;
-      hash.size = _gnutls_hash_get_algo_len (mac_algo);
       dconcat.data = concat;
-      dconcat.size = sizeof concat;
+      dconcat.size = 36;
+      break;
+    case GNUTLS_PK_DSA:
+      dconcat.data = &concat[16];
+      dconcat.size = 20;
+      break;
 
-      _gnutls_rsa_encode_sig (mac_algo, &hash, &dconcat);
+    default:
+      gnutls_assert ();
+      return GNUTLS_E_INTERNAL_ERROR;
     }
-
-  ret = _gnutls_verify_sig (cert, &dconcat, signature,
-                           dconcat.size - _gnutls_hash_get_algo_len (mac_algo),
-                           _gnutls_sign_get_pk_algorithm (algo));
+  ret = _gnutls_tls_sign (session, cert, pkey, &dconcat, signature);
   if (ret < 0)
     {
       gnutls_assert ();
-      return ret;
     }
 
   return ret;
-
 }
diff --git a/lib/gnutls_sig.h b/lib/gnutls_sig.h
index c338869..4cc0df2 100644
--- a/lib/gnutls_sig.h
+++ b/lib/gnutls_sig.h
@@ -38,7 +38,8 @@ int _gnutls_tls_sign_params (gnutls_session_t session,
                             gnutls_sign_algorithm_t * algo);
 
 int _gnutls_verify_sig_hdata (gnutls_session_t session,
-                             gnutls_cert * cert, gnutls_datum_t * signature);
+                             gnutls_cert * cert, gnutls_datum_t * signature,
+                             gnutls_sign_algorithm_t);
 
 int _gnutls_verify_sig_params (gnutls_session_t session,
                               gnutls_cert * cert,
diff --git a/lib/gnutls_state.c b/lib/gnutls_state.c
index cd08f44..912cc60 100644
--- a/lib/gnutls_state.c
+++ b/lib/gnutls_state.c
@@ -189,6 +189,61 @@ _gnutls_session_cert_type_supported (gnutls_session_t 
session,
   return GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE;
 }
 
+/* Check if the given signature algorithm is supported.
+ * This means that it is enabled by the priority functions,
+ * and in case of a server a matching certificate exists.
+ */
+int
+_gnutls_session_sign_algo_supported (gnutls_session_t session,
+                                    gnutls_sign_algorithm_t sig, int 
check_certs)
+{
+  unsigned i;
+  unsigned cert_found = 0;
+  gnutls_certificate_credentials_t cred;
+
+  if (check_certs != 0 && session->security_parameters.entity == GNUTLS_SERVER)
+    {
+      cred = (gnutls_certificate_credentials_t)
+       _gnutls_get_cred (session->key, GNUTLS_CRD_CERTIFICATE, NULL);
+
+      if (cred == NULL)
+       return GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM;
+
+      if (cred->server_get_cert_callback == NULL)
+       {
+         for (i = 0; i < cred->ncerts; i++)
+           {
+             if (cred->cert_list[i][0].sign_algo == sig)
+               {
+                 cert_found = 1;
+                 break;
+               }
+           }
+
+         if (cert_found == 0)
+           /* no certificate is of that type.
+            */
+           return GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM;
+       }
+    }
+
+  if (session->internals.priorities.sign_algo.algorithms == 0) /* none set, 
allow all */
+    {
+      gnutls_assert();
+      return 0;
+    }
+
+  for (i = 0; i < session->internals.priorities.sign_algo.algorithms; i++)
+    {
+      if (session->internals.priorities.sign_algo.priority[i] == sig)
+       {
+         return 0;             /* ok */
+       }
+    }
+
+  return GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM;
+}
+
 /* this function deinitializes all the internal parameters stored
  * in a session struct.
  */
@@ -1360,3 +1415,4 @@ gnutls_session_enable_compatibility_mode 
(gnutls_session_t session)
 {
   gnutls_record_disable_padding (session);
 }
+
diff --git a/lib/gnutls_state.h b/lib/gnutls_state.h
index dbb2a51..bff0022 100644
--- a/lib/gnutls_state.h
+++ b/lib/gnutls_state.h
@@ -41,7 +41,8 @@ void _gnutls_session_cert_type_set (gnutls_session_t session,
 
 int _gnutls_session_cert_type_supported (gnutls_session_t,
                                         gnutls_certificate_type_t);
-
+int _gnutls_session_sign_algo_supported (gnutls_session_t session,
+                                     gnutls_sign_algorithm_t sig, int 
check_certs);
 int _gnutls_dh_set_secret_bits (gnutls_session_t session, unsigned bits);
 
 int _gnutls_dh_set_peer_public (gnutls_session_t session, bigint_t public);
diff --git a/lib/gnutls_x509.c b/lib/gnutls_x509.c
index 4ee0984..ab7e447 100644
--- a/lib/gnutls_x509.c
+++ b/lib/gnutls_x509.c
@@ -159,6 +159,14 @@ _gnutls_x509_cert_verify_peers (gnutls_session_t session,
          return ret;
        }
 
+      
+      if (ret < 0)
+        {
+          gnutls_assert();
+          CLEAR_CERTS;
+          return ret;
+        }
+
       ret = check_bits (peer_certificate_list[i], cred->verify_bits);
       if (ret < 0)
        {
@@ -171,6 +179,7 @@ _gnutls_x509_cert_verify_peers (gnutls_session_t session,
 
   /* Verify certificate 
    */
+  
   ret = gnutls_x509_crt_list_verify (peer_certificate_list,
                                     peer_certificate_list_size,
                                     cred->x509_ca_list, cred->x509_ncas,
diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in
index a4fe3fc..26e6d86 100644
--- a/lib/includes/gnutls/gnutls.h.in
+++ b/lib/includes/gnutls/gnutls.h.in
@@ -145,6 +145,7 @@ extern "C" {
    */
   typedef enum
   {
+    GNUTLS_DIG_UNKNOWN = GNUTLS_MAC_UNKNOWN,
     GNUTLS_DIG_NULL = GNUTLS_MAC_NULL,
     GNUTLS_DIG_MD5 = GNUTLS_MAC_MD5,
     GNUTLS_DIG_SHA1 = GNUTLS_MAC_SHA1,
@@ -1374,8 +1375,8 @@ extern "C" {
 #define GNUTLS_E_WARNING_IA_FPHF_RECEIVED -103
 
 #define GNUTLS_E_IA_VERIFY_FAILED -104
-
 #define GNUTLS_E_UNKNOWN_ALGORITHM -105
+#define GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM -106
 
 #define GNUTLS_E_BASE64_ENCODING_ERROR -201
 #define GNUTLS_E_INCOMPATIBLE_GCRYPT_LIBRARY -202      /* obsolete */
diff --git a/lib/openpgp/gnutls_openpgp.c b/lib/openpgp/gnutls_openpgp.c
index 16d18d8..fb50075 100644
--- a/lib/openpgp/gnutls_openpgp.c
+++ b/lib/openpgp/gnutls_openpgp.c
@@ -800,6 +800,8 @@ _gnutls_openpgp_crt_to_gcert (gnutls_cert * gcert, 
gnutls_openpgp_crt_t cert)
 
   memset (gcert, 0, sizeof (gnutls_cert));
   gcert->cert_type = GNUTLS_CRT_OPENPGP;
+  gcert->sign_algo = GNUTLS_SIGN_UNKNOWN; /* N/A here */
+
   gcert->version = gnutls_openpgp_crt_get_version (cert);
   gcert->params_size = MAX_PUBLIC_PARAMS_SIZE;
 


hooks/post-receive
-- 
GNU gnutls




reply via email to

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