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.
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)
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
#include <gnutls_state.h>
#include <gnutls_pk.h>
#include <gnutls_x509.h>
+#include <ext_signature.h>
#include "debug.h"
#ifdef ENABLE_OPENPGP
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)
{
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;
}
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;
}
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;
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
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)
{
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;
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);
_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
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);
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 &&
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;
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;
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
#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}},
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}},
}
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);
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,
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))
{
/* holds the type (PGP, X509)
*/
gnutls_certificate_type_t cert_type;
+ gnutls_sign_algorithm_t sign_algo;
gnutls_datum_t raw;
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,
#include <ext_oprfi.h>
#include <ext_srp.h>
#include <ext_session_ticket.h>
+#include <ext_signature.h>
#include <gnutls_num.h>
typedef struct
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;
}
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;
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 ();
}
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);
}
}
}
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);
}
}
/* 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;
}
}
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;
} 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];
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;
priority_st compression;
priority_st protocol;
priority_st cert_type;
+ priority_st sign_algo;
/* to disable record padding */
int no_padding;
} 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 */
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,
0
};
+
static const int mac_priority_secure[] = {
GNUTLS_MAC_SHA256,
GNUTLS_MAC_SHA1,
* 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:
_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
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)
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)
{
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] == '-')
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)
{
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)
{
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;
(*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;
#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,
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.
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 ();
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;
}
+/* 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];
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 =
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 ();
}
-/* 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;
-
}
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,
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.
*/
{
gnutls_record_disable_padding (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);
return ret;
}
+
+ if (ret < 0)
+ {
+ gnutls_assert();
+ CLEAR_CERTS;
+ return ret;
+ }
+
ret = check_bits (peer_certificate_list[i], cred->verify_bits);
if (ret < 0)
{
/* Verify certificate
*/
+
ret = gnutls_x509_crt_list_verify (peer_certificate_list,
peer_certificate_list_size,
cred->x509_ca_list, cred->x509_ncas,
*/
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,
#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 */
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;