summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile.am4
-rw-r--r--lib/auth_cert.c90
-rw-r--r--lib/auth_cert.h1
-rw-r--r--lib/ext_signature.c332
-rw-r--r--lib/ext_signature.h38
-rw-r--r--lib/gnutls_algorithms.c8
-rw-r--r--lib/gnutls_algorithms.h3
-rw-r--r--lib/gnutls_cert.c1
-rw-r--r--lib/gnutls_cert.h1
-rw-r--r--lib/gnutls_errors.c2
-rw-r--r--lib/gnutls_extensions.c9
-rw-r--r--lib/gnutls_handshake.c27
-rw-r--r--lib/gnutls_int.h10
-rw-r--r--lib/gnutls_priority.c52
-rw-r--r--lib/gnutls_sig.c458
-rw-r--r--lib/gnutls_sig.h3
-rw-r--r--lib/gnutls_state.c56
-rw-r--r--lib/gnutls_state.h3
-rw-r--r--lib/gnutls_x509.c9
-rw-r--r--lib/includes/gnutls/gnutls.h.in3
-rw-r--r--lib/openpgp/gnutls_openpgp.c2
21 files changed, 922 insertions, 190 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 350a0875c0..07d3a97823 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 f44731356a..3affa32716 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 1b808dcfb6..f982bc7a18 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_signature.c b/lib/ext_signature.c
new file mode 100644
index 0000000000..5231174a38
--- /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 0000000000..46b6154f67
--- /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 8f1eb9fc05..873648e54c 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 0a2faac52f..8736dc8afc 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 42db17cb79..5b110ad298 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 2a752270fe..c153607d3f 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_errors.c b/lib/gnutls_errors.c
index 94be5af487..b5d8bb6cb1 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 b7baca28b9..5f2c47cc6b 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_handshake.c b/lib/gnutls_handshake.c
index 7423f2737c..b7d5af3310 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 ac1da9df3e..5f07164aac 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 f50eb8cccd..5248b4f1e1 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 c49f2eda2a..76e1f6da89 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 c338869d4a..4cc0df20c1 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 cd08f44a88..912cc60839 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 dbb2a51a09..bff0022820 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 4ee09841a5..ab7e44709f 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 a4fe3fc67f..26e6d86a8a 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 16d18d8946..fb50075390 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;