summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2017-05-29 16:22:27 +0200
committerNikos Mavrogiannopoulos <nmav@redhat.com>2017-05-31 14:50:22 +0200
commit7288a41662fd8c17fd2af6417b64ff97ee8fee93 (patch)
treef51c20cb6effebd1190b7a1720353187e2228ca2
parent3ffcff8ddf994e94c6c9c693be0a520ea825fa91 (diff)
downloadgnutls-7288a41662fd8c17fd2af6417b64ff97ee8fee93.tar.gz
tls-sig: re-organize and simplify the TLS signature generation and verification
That makes sure that the high level APIs are used when possible, and separate the TLS 1.2 from other code paths. This will allow supporting signature schemes like EdDSA and others. Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
-rw-r--r--lib/auth/cert.c26
-rw-r--r--lib/auth/srp_rsa.c13
-rw-r--r--lib/pubkey.c2
-rw-r--r--lib/tls-sig.c504
-rw-r--r--lib/tls-sig.h2
5 files changed, 310 insertions, 237 deletions
diff --git a/lib/auth/cert.c b/lib/auth/cert.c
index 0f7ff4bbc7..cf75111f9d 100644
--- a/lib/auth/cert.c
+++ b/lib/auth/cert.c
@@ -1527,6 +1527,8 @@ _gnutls_proc_cert_client_crt_vrfy(gnutls_session_t session,
gnutls_pcert_st peer_cert;
gnutls_sign_algorithm_t sign_algo = GNUTLS_SIGN_UNKNOWN;
const version_entry_st *ver = get_version(session);
+ gnutls_certificate_credentials_t cred;
+ unsigned vflags;
if (unlikely(info == NULL || info->ncerts == 0 || ver == NULL)) {
gnutls_assert();
@@ -1534,6 +1536,15 @@ _gnutls_proc_cert_client_crt_vrfy(gnutls_session_t session,
return GNUTLS_E_INTERNAL_ERROR;
}
+ cred = (gnutls_certificate_credentials_t)
+ _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
+ if (cred == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
+ }
+
+ vflags = cred->verify_flags | session->internals.additional_verify_flags;
+
if (_gnutls_version_has_selectable_sighash(ver)) {
sign_algorithm_st aid;
@@ -1572,7 +1583,7 @@ _gnutls_proc_cert_client_crt_vrfy(gnutls_session_t session,
}
if ((ret =
- _gnutls_handshake_verify_crt_vrfy(session, &peer_cert, &sig,
+ _gnutls_handshake_verify_crt_vrfy(session, vflags, &peer_cert, &sig,
sign_algo)) < 0) {
gnutls_assert();
gnutls_pcert_deinit(&peer_cert);
@@ -2171,6 +2182,8 @@ _gnutls_proc_dhe_signature(gnutls_session_t session, uint8_t * data,
gnutls_pcert_st peer_cert;
gnutls_sign_algorithm_t sign_algo = GNUTLS_SIGN_UNKNOWN;
const version_entry_st *ver = get_version(session);
+ gnutls_certificate_credentials_t cred;
+ unsigned vflags;
if (unlikely(info == NULL || info->ncerts == 0 || ver == NULL)) {
gnutls_assert();
@@ -2178,6 +2191,15 @@ _gnutls_proc_dhe_signature(gnutls_session_t session, uint8_t * data,
return GNUTLS_E_INTERNAL_ERROR;
}
+ cred = (gnutls_certificate_credentials_t)
+ _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
+ if (cred == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
+ }
+
+ vflags = cred->verify_flags | session->internals.additional_verify_flags;
+
/* VERIFY SIGNATURE */
if (_gnutls_version_has_selectable_sighash(ver)) {
sign_algorithm_st aid;
@@ -2212,7 +2234,7 @@ _gnutls_proc_dhe_signature(gnutls_session_t session, uint8_t * data,
}
ret =
- _gnutls_handshake_verify_data(session, &peer_cert, vparams,
+ _gnutls_handshake_verify_data(session, vflags, &peer_cert, vparams,
&signature, sign_algo);
gnutls_pcert_deinit(&peer_cert);
diff --git a/lib/auth/srp_rsa.c b/lib/auth/srp_rsa.c
index 33359967da..f7e9cccf02 100644
--- a/lib/auth/srp_rsa.c
+++ b/lib/auth/srp_rsa.c
@@ -177,6 +177,8 @@ proc_srp_cert_server_kx(gnutls_session_t session, uint8_t * data,
gnutls_pcert_st peer_cert;
uint8_t *p;
gnutls_sign_algorithm_t sign_algo = GNUTLS_SIGN_UNKNOWN;
+ gnutls_certificate_credentials_t cred;
+ unsigned vflags;
const version_entry_st *ver = get_version(session);
if (unlikely(ver == NULL))
@@ -188,6 +190,15 @@ proc_srp_cert_server_kx(gnutls_session_t session, uint8_t * data,
data_size = _data_size - ret;
+ cred = (gnutls_certificate_credentials_t)
+ _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
+ if (cred == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
+ }
+
+ vflags = cred->verify_flags | session->internals.additional_verify_flags;
+
info = _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE);
if (info == NULL || info->ncerts == 0) {
gnutls_assert();
@@ -236,7 +247,7 @@ proc_srp_cert_server_kx(gnutls_session_t session, uint8_t * data,
}
ret =
- _gnutls_handshake_verify_data(session, &peer_cert, &vparams,
+ _gnutls_handshake_verify_data(session, vflags, &peer_cert, &vparams,
&signature, sign_algo);
gnutls_pcert_deinit(&peer_cert);
diff --git a/lib/pubkey.c b/lib/pubkey.c
index feb99a14b7..ab211e4cb0 100644
--- a/lib/pubkey.c
+++ b/lib/pubkey.c
@@ -1756,7 +1756,7 @@ gnutls_pubkey_verify_hash2(gnutls_pubkey_t key,
}
}
- if (gnutls_sign_is_secure(algo) == 0 && _gnutls_is_broken_sig_allowed(algo, flags) == 0) {
+ if (algo != GNUTLS_SIGN_UNKNOWN && gnutls_sign_is_secure(algo) == 0 && _gnutls_is_broken_sig_allowed(algo, flags) == 0) {
return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_SECURITY);
}
diff --git a/lib/tls-sig.c b/lib/tls-sig.c
index e13d19a028..32210650c8 100644
--- a/lib/tls-sig.c
+++ b/lib/tls-sig.c
@@ -39,57 +39,116 @@
#include <x509/common.h>
#include <abstract_int.h>
-static int
-sign_tls_hash(gnutls_session_t session,
- gnutls_pk_algorithm_t pk,
- const mac_entry_st * hash_algo,
- gnutls_pcert_st * cert, gnutls_privkey_t pkey,
- const gnutls_datum_t * hash_concat,
- gnutls_datum_t * signature);
+static
+int check_key_usage_for_sig(gnutls_session_t session, unsigned key_usage, unsigned our_cert)
+{
+ const char *lstr;
+ unsigned allow_key_usage_violation;
+ if (our_cert) {
+ lstr = "Local";
+ allow_key_usage_violation = session->internals.priorities.allow_server_key_usage_violation;
+ } else {
+ lstr = "Peer's";
+ allow_key_usage_violation = session->internals.priorities.allow_key_usage_violation;
+ }
+
+ if (key_usage != 0) {
+ if (!(key_usage & GNUTLS_KEY_DIGITAL_SIGNATURE)) {
+ gnutls_assert();
+ if (likely(allow_key_usage_violation == 0)) {
+ _gnutls_audit_log(session,
+ "%s certificate does not allow digital signatures. Key usage violation detected.\n", lstr);
+ return GNUTLS_E_KEY_USAGE_VIOLATION;
+ } else {
+ _gnutls_audit_log(session,
+ "%s certificate does not allow digital signatures. Key usage violation detected (ignored).\n", lstr);
+ }
+ }
+ }
+ return 0;
+}
/* Generates a signature of all the random data and the parameters.
- * Used in DHE_* ciphersuites.
+ * Used in *DHE_* ciphersuites for TLS 1.2.
*/
-int
-_gnutls_handshake_sign_data(gnutls_session_t session,
+static int
+_gnutls_handshake_sign_data12(gnutls_session_t session,
gnutls_pcert_st * cert, gnutls_privkey_t pkey,
gnutls_datum_t * params,
gnutls_datum_t * signature,
- gnutls_sign_algorithm_t * sign_algo)
+ gnutls_sign_algorithm_t sign_algo)
{
gnutls_datum_t dconcat;
int ret;
- digest_hd_st td_sha;
- uint8_t concat[MAX_SIG_SIZE];
- const version_entry_st *ver = get_version(session);
const mac_entry_st *hash_algo;
gnutls_pk_algorithm_t pk_algo;
+ unsigned flags = 0;
- *sign_algo = _gnutls_session_get_sign_algo(session, cert, 0);
- if (*sign_algo == GNUTLS_SIGN_UNKNOWN) {
+ hash_algo = hash_to_entry(gnutls_sign_get_hash_algorithm(sign_algo));
+ if (hash_algo == NULL)
+ return gnutls_assert_val(GNUTLS_E_UNKNOWN_HASH_ALGORITHM);
+
+ pk_algo = gnutls_sign_get_pk_algorithm(sign_algo);
+ if (pk_algo == GNUTLS_PK_UNKNOWN)
+ return gnutls_assert_val(GNUTLS_E_UNKNOWN_PK_ALGORITHM);
+
+ _gnutls_handshake_log
+ ("HSK[%p]: signing TLS 1.2 handshake data: using %s/%s\n", session,
+ gnutls_pk_get_name(pk_algo), gnutls_sign_algorithm_get_name(sign_algo));
+
+ dconcat.size = GNUTLS_RANDOM_SIZE*2 + params->size;
+ dconcat.data = gnutls_malloc(dconcat.size);
+ if (dconcat.data == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ memcpy(dconcat.data, session->security_parameters.client_random, GNUTLS_RANDOM_SIZE);
+ memcpy(dconcat.data+GNUTLS_RANDOM_SIZE, session->security_parameters.server_random, GNUTLS_RANDOM_SIZE);
+ memcpy(dconcat.data+GNUTLS_RANDOM_SIZE*2, params->data, params->size);
+
+ if (pk_algo == GNUTLS_PK_RSA_PSS)
+ flags |= GNUTLS_PRIVKEY_SIGN_FLAG_RSA_PSS;
+
+ ret = gnutls_privkey_sign_data(pkey, (gnutls_digest_algorithm_t)hash_algo->id,
+ flags, &dconcat, signature);
+ if (ret < 0) {
gnutls_assert();
- return GNUTLS_E_UNKNOWN_PK_ALGORITHM;
}
+ gnutls_free(dconcat.data);
- gnutls_sign_algorithm_set_server(session, *sign_algo);
+ return ret;
- if (!_gnutls_version_has_selectable_sighash(ver) &&
- gnutls_privkey_get_pk_algorithm(pkey, NULL) == GNUTLS_PK_RSA)
+}
+
+static int
+_gnutls_handshake_sign_data10(gnutls_session_t session,
+ gnutls_pcert_st * cert, gnutls_privkey_t pkey,
+ gnutls_datum_t * params,
+ gnutls_datum_t * signature,
+ gnutls_sign_algorithm_t sign_algo)
+{
+ gnutls_datum_t dconcat;
+ int ret;
+ digest_hd_st td_sha;
+ uint8_t concat[MAX_SIG_SIZE];
+ const mac_entry_st *hash_algo;
+ gnutls_pk_algorithm_t pk_algo;
+
+ if (gnutls_privkey_get_pk_algorithm(pkey, NULL) == GNUTLS_PK_RSA)
hash_algo = hash_to_entry(GNUTLS_DIG_MD5_SHA1);
else
hash_algo = hash_to_entry(
- gnutls_sign_get_hash_algorithm(*sign_algo));
+ gnutls_sign_get_hash_algorithm(sign_algo));
if (hash_algo == NULL)
return gnutls_assert_val(GNUTLS_E_UNKNOWN_HASH_ALGORITHM);
- pk_algo = gnutls_sign_get_pk_algorithm(*sign_algo);
+ pk_algo = gnutls_sign_get_pk_algorithm(sign_algo);
if (pk_algo == GNUTLS_PK_UNKNOWN)
return gnutls_assert_val(GNUTLS_E_UNKNOWN_PK_ALGORITHM);
_gnutls_handshake_log
("HSK[%p]: signing handshake data: using %s\n", session,
- gnutls_sign_algorithm_get_name(*sign_algo));
+ gnutls_sign_algorithm_get_name(sign_algo));
ret = _gnutls_hash_init(&td_sha, hash_algo);
if (ret < 0) {
@@ -108,131 +167,54 @@ _gnutls_handshake_sign_data(gnutls_session_t session,
dconcat.data = concat;
dconcat.size = _gnutls_hash_get_algo_len(hash_algo);
- ret =
- sign_tls_hash(session, pk_algo, hash_algo, cert, pkey, &dconcat,
- signature);
+ ret = gnutls_privkey_sign_raw_data(pkey, 0, &dconcat, signature);
if (ret < 0) {
gnutls_assert();
}
return ret;
-
-}
-
-static
-int check_key_usage_for_sig(gnutls_session_t session, unsigned key_usage, unsigned our_cert)
-{
- const char *lstr;
- unsigned allow_key_usage_violation;
-
- if (our_cert) {
- lstr = "Local";
- allow_key_usage_violation = session->internals.priorities.allow_server_key_usage_violation;
- } else {
- lstr = "Peer's";
- allow_key_usage_violation = session->internals.priorities.allow_key_usage_violation;
- }
-
- if (key_usage != 0) {
- if (!(key_usage & GNUTLS_KEY_DIGITAL_SIGNATURE)) {
- gnutls_assert();
- if (likely(allow_key_usage_violation == 0)) {
- _gnutls_audit_log(session,
- "%s certificate does not allow digital signatures. Key usage violation detected.\n", lstr);
- return GNUTLS_E_KEY_USAGE_VIOLATION;
- } else {
- _gnutls_audit_log(session,
- "%s certificate does not allow digital signatures. Key usage violation detected (ignored).\n", lstr);
- }
- }
- }
- return 0;
}
-/* This will create a PKCS1 or DSA signature, as defined in the TLS protocol.
- * Cert is the certificate of the corresponding private key. It is only checked if
- * it supports signing.
+/* Generates a signature of all the random data and the parameters.
+ * Used in DHE_* ciphersuites.
*/
-static int
-sign_tls_hash(gnutls_session_t session,
- gnutls_pk_algorithm_t pk,
- const mac_entry_st * hash_algo,
- gnutls_pcert_st * cert, gnutls_privkey_t pkey,
- const gnutls_datum_t * hash_concat,
- gnutls_datum_t * signature)
+int
+_gnutls_handshake_sign_data(gnutls_session_t session,
+ gnutls_pcert_st * cert, gnutls_privkey_t pkey,
+ gnutls_datum_t * params,
+ gnutls_datum_t * signature,
+ gnutls_sign_algorithm_t * sign_algo)
{
const version_entry_st *ver = get_version(session);
- unsigned int key_usage = 0;
- unsigned flags = 0;
- int ret;
-
- /* If our certificate supports signing
- */
- if (cert != NULL) {
- gnutls_pubkey_get_key_usage(cert->pubkey, &key_usage);
-
- ret = check_key_usage_for_sig(session, key_usage, 1);
- if (ret < 0)
- return gnutls_assert_val(ret);
- }
-
- if (!_gnutls_version_has_selectable_sighash(ver)) {
- return gnutls_privkey_sign_raw_data(pkey, 0, hash_concat,
- signature);
- } else {
- assert(hash_algo != NULL);
- if (pk == GNUTLS_PK_RSA_PSS)
- flags |= GNUTLS_PRIVKEY_SIGN_FLAG_RSA_PSS;
-
- return gnutls_privkey_sign_hash(pkey,
- (gnutls_digest_algorithm_t)hash_algo->id,
- flags, hash_concat, signature);
- }
-}
-
-static int
-verify_tls_hash(gnutls_session_t session,
- gnutls_pcert_st * cert,
- const gnutls_datum_t * hash_concat,
- gnutls_datum_t * signature,
- gnutls_sign_algorithm_t sign_algo,
- unsigned flags)
-{
+ unsigned key_usage = 0;
int ret;
- unsigned int key_usage = 0;
- if (cert == NULL) {
+ *sign_algo = _gnutls_session_get_sign_algo(session, cert, 0);
+ if (*sign_algo == GNUTLS_SIGN_UNKNOWN) {
gnutls_assert();
- return GNUTLS_E_CERTIFICATE_ERROR;
+ return GNUTLS_E_UNKNOWN_PK_ALGORITHM;
}
- gnutls_pubkey_get_key_usage(cert->pubkey, &key_usage);
-
- ret = check_key_usage_for_sig(session, key_usage, 0);
- if (ret < 0)
- return gnutls_assert_val(ret);
-
- /* verify signature */
-
- if (session->security_parameters.entity == GNUTLS_CLIENT)
- gnutls_sign_algorithm_set_server(session, sign_algo);
+ gnutls_sign_algorithm_set_server(session, *sign_algo);
- ret = gnutls_pubkey_verify_hash2(cert->pubkey, sign_algo, flags,
- hash_concat, signature);
+ gnutls_pubkey_get_key_usage(cert->pubkey, &key_usage);
+ ret = check_key_usage_for_sig(session, key_usage, 1);
if (ret < 0)
return gnutls_assert_val(ret);
-
- return 0;
+ if (_gnutls_version_has_selectable_sighash(ver))
+ return _gnutls_handshake_sign_data12(session, cert, pkey, params, signature, *sign_algo);
+ else
+ return _gnutls_handshake_sign_data10(session, cert, pkey, params, signature, *sign_algo);
}
-
/* Generates a signature of all the random data and the parameters.
* Used in DHE_* ciphersuites.
*/
-int
-_gnutls_handshake_verify_data(gnutls_session_t session,
+static int
+_gnutls_handshake_verify_data10(gnutls_session_t session,
+ unsigned verify_flags,
gnutls_pcert_st * cert,
const gnutls_datum_t * params,
gnutls_datum_t * signature,
@@ -242,38 +224,17 @@ _gnutls_handshake_verify_data(gnutls_session_t session,
int ret;
digest_hd_st td_sha;
uint8_t concat[MAX_SIG_SIZE];
- const version_entry_st *ver = get_version(session);
gnutls_digest_algorithm_t hash_algo;
const mac_entry_st *me;
gnutls_pk_algorithm_t pk_algo;
- unsigned flags = 0;
-
- if (_gnutls_version_has_selectable_sighash(ver)) {
- _gnutls_handshake_log
- ("HSK[%p]: verify handshake data: using %s\n", session,
- gnutls_sign_algorithm_get_name(sign_algo));
-
- ret =
- _gnutls_pubkey_compatible_with_sig(session,
- cert->pubkey, ver,
- sign_algo);
- if (ret < 0)
- return gnutls_assert_val(ret);
- ret =
- _gnutls_session_sign_algo_enabled(session, sign_algo);
- if (ret < 0)
- return gnutls_assert_val(ret);
+ pk_algo = gnutls_pubkey_get_pk_algorithm(cert->pubkey, NULL);
+ if (pk_algo == GNUTLS_PK_RSA) {
+ hash_algo = GNUTLS_DIG_MD5_SHA1;
+ verify_flags |= GNUTLS_PUBKEY_VERIFY_FLAG_TLS1_RSA;
+ } else
+ hash_algo = GNUTLS_DIG_SHA1;
- hash_algo = gnutls_sign_get_hash_algorithm(sign_algo);
- } else {
- pk_algo = gnutls_pubkey_get_pk_algorithm(cert->pubkey, NULL);
- if (pk_algo == GNUTLS_PK_RSA) {
- hash_algo = GNUTLS_DIG_MD5_SHA1;
- flags = GNUTLS_PUBKEY_VERIFY_FLAG_TLS1_RSA;
- } else
- hash_algo = GNUTLS_DIG_SHA1;
- }
me = hash_to_entry(hash_algo);
ret = _gnutls_hash_init(&td_sha, me);
@@ -293,17 +254,94 @@ _gnutls_handshake_verify_data(gnutls_session_t session,
dconcat.data = concat;
dconcat.size = _gnutls_hash_get_algo_len(me);
- ret = verify_tls_hash(session, cert, &dconcat, signature,
- sign_algo, flags);
- if (ret < 0) {
+ ret = gnutls_pubkey_verify_hash2(cert->pubkey, sign_algo,
+ GNUTLS_VERIFY_ALLOW_SIGN_WITH_SHA1|verify_flags,
+ &dconcat, signature);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ return ret;
+}
+
+static int
+_gnutls_handshake_verify_data12(gnutls_session_t session,
+ unsigned verify_flags,
+ gnutls_pcert_st * cert,
+ const gnutls_datum_t * params,
+ gnutls_datum_t * signature,
+ gnutls_sign_algorithm_t sign_algo)
+{
+ gnutls_datum_t dconcat;
+ int ret;
+ const version_entry_st *ver = get_version(session);
+
+ _gnutls_handshake_log
+ ("HSK[%p]: verify TLS 1.2 handshake data: using %s\n", session,
+ gnutls_sign_algorithm_get_name(sign_algo));
+
+ ret =
+ _gnutls_pubkey_compatible_with_sig(session,
+ cert->pubkey, ver,
+ sign_algo);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret =
+ _gnutls_session_sign_algo_enabled(session, sign_algo);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ dconcat.size = GNUTLS_RANDOM_SIZE*2+params->size;
+ dconcat.data = gnutls_malloc(dconcat.size);
+ if (dconcat.data == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ memcpy(dconcat.data, session->security_parameters.client_random, GNUTLS_RANDOM_SIZE);
+ memcpy(dconcat.data+GNUTLS_RANDOM_SIZE, session->security_parameters.server_random, GNUTLS_RANDOM_SIZE);
+ memcpy(dconcat.data+GNUTLS_RANDOM_SIZE*2, params->data, params->size);
+
+ ret = gnutls_pubkey_verify_data2(cert->pubkey, sign_algo, verify_flags,
+ &dconcat, signature);
+ if (ret < 0)
gnutls_assert();
- return ret;
- }
+
+ gnutls_free(dconcat.data);
return ret;
+}
+
+int
+_gnutls_handshake_verify_data(gnutls_session_t session,
+ unsigned verify_flags,
+ gnutls_pcert_st * cert,
+ const gnutls_datum_t * params,
+ gnutls_datum_t * signature,
+ gnutls_sign_algorithm_t sign_algo)
+{
+ unsigned key_usage;
+ int ret;
+ const version_entry_st *ver = get_version(session);
+
+ if (cert == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_CERTIFICATE_ERROR;
+ }
+
+ gnutls_pubkey_get_key_usage(cert->pubkey, &key_usage);
+ ret = check_key_usage_for_sig(session, key_usage, 0);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ gnutls_sign_algorithm_set_server(session, sign_algo);
+
+ if (_gnutls_version_has_selectable_sighash(ver))
+ return _gnutls_handshake_verify_data12(session, verify_flags, cert, params, signature, sign_algo);
+ else
+ return _gnutls_handshake_verify_data10(session, verify_flags, cert, params, signature, sign_algo);
}
+
/* Client certificate verify calculations
*/
@@ -311,42 +349,25 @@ _gnutls_handshake_verify_data(gnutls_session_t session,
*/
static int
_gnutls_handshake_verify_crt_vrfy12(gnutls_session_t session,
+ unsigned verify_flags,
gnutls_pcert_st * cert,
gnutls_datum_t * signature,
gnutls_sign_algorithm_t sign_algo)
{
int ret;
- uint8_t concat[MAX_HASH_SIZE];
gnutls_datum_t dconcat;
- const mac_entry_st *me;
ret = _gnutls_session_sign_algo_enabled(session, sign_algo);
if (ret < 0)
return gnutls_assert_val(ret);
- gnutls_sign_algorithm_set_client(session, sign_algo);
+ dconcat.data = session->internals.handshake_hash_buffer.data;
+ dconcat.size = session->internals.handshake_hash_buffer_prev_len;
- me = hash_to_entry(gnutls_sign_get_hash_algorithm(sign_algo));
-
- ret =
- _gnutls_hash_fast((gnutls_digest_algorithm_t)me->id,
- session->internals.handshake_hash_buffer.
- data,
- session->internals.
- handshake_hash_buffer_prev_len, concat);
+ ret = gnutls_pubkey_verify_data2(cert->pubkey, sign_algo, verify_flags,
+ &dconcat, signature);
if (ret < 0)
- return gnutls_assert_val(ret);
-
- dconcat.data = concat;
- dconcat.size = _gnutls_hash_get_algo_len(me);
-
- ret =
- verify_tls_hash(session, cert, &dconcat, signature,
- sign_algo, 0);
- if (ret < 0) {
gnutls_assert();
- return ret;
- }
return ret;
@@ -358,6 +379,7 @@ _gnutls_handshake_verify_crt_vrfy12(gnutls_session_t session,
#ifdef ENABLE_SSL3
static int
_gnutls_handshake_verify_crt_vrfy3(gnutls_session_t session,
+ unsigned verify_flags,
gnutls_pcert_st * cert,
gnutls_datum_t * signature,
gnutls_sign_algorithm_t sign_algo)
@@ -396,6 +418,7 @@ _gnutls_handshake_verify_crt_vrfy3(gnutls_session_t session,
if (ret < 0)
return gnutls_assert_val(ret);
+ verify_flags |= GNUTLS_PUBKEY_VERIFY_FLAG_TLS1_RSA;
dconcat.size = 16;
}
@@ -421,14 +444,11 @@ _gnutls_handshake_verify_crt_vrfy3(gnutls_session_t session,
dconcat.size += 20;
- ret =
- verify_tls_hash(session, cert, &dconcat, signature,
- GNUTLS_SIGN_UNKNOWN,
- GNUTLS_PUBKEY_VERIFY_FLAG_TLS1_RSA);
- if (ret < 0) {
- gnutls_assert();
- return ret;
- }
+ ret = gnutls_pubkey_verify_hash2(cert->pubkey, GNUTLS_SIGN_UNKNOWN,
+ GNUTLS_VERIFY_ALLOW_SIGN_WITH_SHA1|verify_flags,
+ &dconcat, signature);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
return ret;
}
@@ -439,6 +459,7 @@ _gnutls_handshake_verify_crt_vrfy3(gnutls_session_t session,
*/
int
_gnutls_handshake_verify_crt_vrfy(gnutls_session_t session,
+ unsigned verify_flags,
gnutls_pcert_st * cert,
gnutls_datum_t * signature,
gnutls_sign_algorithm_t sign_algo)
@@ -450,7 +471,18 @@ _gnutls_handshake_verify_crt_vrfy(gnutls_session_t session,
const version_entry_st *ver = get_version(session);
gnutls_pk_algorithm_t pk_algo;
const mac_entry_st *me;
- unsigned flags = 0;
+ unsigned key_usage;
+
+ if (cert == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_CERTIFICATE_ERROR;
+ }
+
+ gnutls_pubkey_get_key_usage(cert->pubkey, &key_usage);
+
+ ret = check_key_usage_for_sig(session, key_usage, 0);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
_gnutls_handshake_log("HSK[%p]: verify cert vrfy: using %s\n",
session,
@@ -459,21 +491,29 @@ _gnutls_handshake_verify_crt_vrfy(gnutls_session_t session,
if (unlikely(ver == NULL))
return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+ gnutls_sign_algorithm_set_client(session, sign_algo);
+
+ /* TLS 1.2 */
if (_gnutls_version_has_selectable_sighash(ver))
- return _gnutls_handshake_verify_crt_vrfy12(session, cert,
+ return _gnutls_handshake_verify_crt_vrfy12(session,
+ verify_flags,
+ cert,
signature,
sign_algo);
#ifdef ENABLE_SSL3
if (ver->id == GNUTLS_SSL3)
- return _gnutls_handshake_verify_crt_vrfy3(session, cert,
+ return _gnutls_handshake_verify_crt_vrfy3(session,
+ verify_flags,
+ cert,
signature,
sign_algo);
#endif
+ /* TLS 1.0 and TLS 1.1 */
pk_algo = gnutls_pubkey_get_pk_algorithm(cert->pubkey, NULL);
if (pk_algo == GNUTLS_PK_RSA) {
me = hash_to_entry(GNUTLS_DIG_MD5_SHA1);
- flags = GNUTLS_PUBKEY_VERIFY_FLAG_TLS1_RSA;
+ verify_flags |= GNUTLS_PUBKEY_VERIFY_FLAG_TLS1_RSA;
} else
me = hash_to_entry(GNUTLS_DIG_SHA1);
ret = _gnutls_hash_init(&td_sha, me);
@@ -491,18 +531,17 @@ _gnutls_handshake_verify_crt_vrfy(gnutls_session_t session,
dconcat.data = concat;
dconcat.size = _gnutls_hash_get_algo_len(me);
- ret =
- verify_tls_hash(session, cert, &dconcat, signature,
- GNUTLS_SIGN_UNKNOWN, flags);
- if (ret < 0) {
+ ret = gnutls_pubkey_verify_hash2(cert->pubkey, GNUTLS_SIGN_UNKNOWN,
+ GNUTLS_VERIFY_ALLOW_SIGN_WITH_SHA1|verify_flags,
+ &dconcat, signature);
+ if (ret < 0)
gnutls_assert();
- return ret;
- }
return ret;
}
-/* the same as _gnutls_handshake_sign_crt_vrfy except that it is made for TLS 1.2
+/* the same as _gnutls_handshake_sign_crt_vrfy except that it is made for TLS 1.2.
+ * Returns the used signature algorihm, or a negative error code.
*/
static int
_gnutls_handshake_sign_crt_vrfy12(gnutls_session_t session,
@@ -511,11 +550,11 @@ _gnutls_handshake_sign_crt_vrfy12(gnutls_session_t session,
gnutls_datum_t * signature)
{
gnutls_datum_t dconcat;
- int ret;
- uint8_t concat[MAX_SIG_SIZE];
gnutls_sign_algorithm_t sign_algo;
const mac_entry_st *me;
gnutls_pk_algorithm_t pk_algo;
+ unsigned flags = 0;
+ int ret;
sign_algo = _gnutls_privkey_get_preferred_sign_algo(pkey);
if (sign_algo == GNUTLS_SIGN_UNKNOWN ||
@@ -535,24 +574,21 @@ _gnutls_handshake_sign_crt_vrfy12(gnutls_session_t session,
gnutls_sign_algorithm_set_client(session, sign_algo);
me = hash_to_entry(gnutls_sign_get_hash_algorithm(sign_algo));
+ if (me == NULL)
+ return gnutls_assert_val(GNUTLS_E_UNKNOWN_HASH_ALGORITHM);
_gnutls_debug_log("sign handshake cert vrfy: picked %s with %s\n",
gnutls_sign_algorithm_get_name(sign_algo),
_gnutls_mac_get_name(me));
- ret =
- _gnutls_hash_fast((gnutls_digest_algorithm_t)me->id,
- session->internals.handshake_hash_buffer.
- data,
- session->internals.handshake_hash_buffer.
- length, concat);
- if (ret < 0)
- return gnutls_assert_val(ret);
+ dconcat.data = session->internals.handshake_hash_buffer.data;
+ dconcat.size = session->internals.handshake_hash_buffer.length;
- dconcat.data = concat;
- dconcat.size = _gnutls_hash_get_algo_len(me);
+ if (pk_algo == GNUTLS_PK_RSA_PSS)
+ flags |= GNUTLS_PRIVKEY_SIGN_FLAG_RSA_PSS;
- ret = sign_tls_hash(session, pk_algo, me, cert, pkey, &dconcat, signature);
+ ret = gnutls_privkey_sign_data(pkey, (gnutls_digest_algorithm_t)me->id,
+ flags, &dconcat, signature);
if (ret < 0) {
gnutls_assert();
return ret;
@@ -572,7 +608,6 @@ _gnutls_handshake_sign_crt_vrfy3(gnutls_session_t session,
int ret;
uint8_t concat[MAX_SIG_SIZE];
digest_hd_st td_sha;
- const version_entry_st *ver = get_version(session);
gnutls_pk_algorithm_t pk =
gnutls_privkey_get_pk_algorithm(pkey, NULL);
@@ -582,13 +617,6 @@ _gnutls_handshake_sign_crt_vrfy3(gnutls_session_t session,
return ret;
}
- /* ensure 1024 bit DSA keys are used */
- ret =
- _gnutls_pubkey_compatible_with_sig(session, cert->pubkey, ver,
- GNUTLS_SIGN_UNKNOWN);
- if (ret < 0)
- return gnutls_assert_val(ret);
-
dconcat.data = concat;
dconcat.size = 0;
@@ -636,12 +664,11 @@ _gnutls_handshake_sign_crt_vrfy3(gnutls_session_t session,
dconcat.size += 20;
- ret = sign_tls_hash(session, 0, NULL, cert, pkey, &dconcat, signature);
- if (ret < 0) {
- gnutls_assert();
- }
+ ret = gnutls_privkey_sign_raw_data(pkey, 0, &dconcat, signature);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
- return ret;
+ return GNUTLS_SIGN_UNKNOWN;
}
#endif
@@ -652,6 +679,8 @@ _gnutls_handshake_sign_crt_vrfy3(gnutls_session_t session,
*
* 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 error code;
+ *
+ * Returns the used signature algorihm, or a negative error code.
*/
int
_gnutls_handshake_sign_crt_vrfy(gnutls_session_t session,
@@ -667,14 +696,30 @@ _gnutls_handshake_sign_crt_vrfy(gnutls_session_t session,
gnutls_pk_algorithm_t pk =
gnutls_privkey_get_pk_algorithm(pkey, NULL);
const mac_entry_st *me;
+ unsigned key_usage = 0;
if (unlikely(ver == NULL))
return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+ gnutls_pubkey_get_key_usage(cert->pubkey, &key_usage);
+
+ ret = check_key_usage_for_sig(session, key_usage, 1);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ /* TLS 1.2 */
if (_gnutls_version_has_selectable_sighash(ver))
return _gnutls_handshake_sign_crt_vrfy12(session, cert,
pkey, signature);
+ /* ensure 1024 bit DSA keys are used */
+ ret =
+ _gnutls_pubkey_compatible_with_sig(session, cert->pubkey, ver,
+ GNUTLS_SIGN_UNKNOWN);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ /* TLS 1.1 or earlier */
#ifdef ENABLE_SSL3
if (ver->id == GNUTLS_SSL3)
return _gnutls_handshake_sign_crt_vrfy3(session, cert,
@@ -701,20 +746,13 @@ _gnutls_handshake_sign_crt_vrfy(gnutls_session_t session,
dconcat.data = concat;
dconcat.size = _gnutls_hash_get_algo_len(me);
-
- /* ensure 1024 bit DSA keys are used */
- ret =
- _gnutls_pubkey_compatible_with_sig(session, cert->pubkey, ver,
- GNUTLS_SIGN_UNKNOWN);
- if (ret < 0)
- return gnutls_assert_val(ret);
-
- ret =
- sign_tls_hash(session, 0, NULL, cert, pkey, &dconcat, signature);
+ ret = gnutls_privkey_sign_raw_data(pkey, 0, &dconcat, signature);
if (ret < 0) {
gnutls_assert();
+ return ret;
}
- return ret;
+ return GNUTLS_SIGN_UNKNOWN;
}
+
diff --git a/lib/tls-sig.h b/lib/tls-sig.h
index 5ba37128be..afea4ebaf9 100644
--- a/lib/tls-sig.h
+++ b/lib/tls-sig.h
@@ -45,11 +45,13 @@ int _gnutls_handshake_sign_data(gnutls_session_t session,
gnutls_sign_algorithm_t * algo);
int _gnutls_handshake_verify_crt_vrfy(gnutls_session_t session,
+ unsigned verify_flags,
gnutls_pcert_st * cert,
gnutls_datum_t * signature,
gnutls_sign_algorithm_t);
int _gnutls_handshake_verify_data(gnutls_session_t session,
+ unsigned verify_flags,
gnutls_pcert_st * cert,
const gnutls_datum_t * params,
gnutls_datum_t * signature,