summaryrefslogtreecommitdiff
path: root/lib/auth/cert.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/auth/cert.c')
-rw-r--r--lib/auth/cert.c68
1 files changed, 48 insertions, 20 deletions
diff --git a/lib/auth/cert.c b/lib/auth/cert.c
index b6bd3bf91e..5868ca244d 100644
--- a/lib/auth/cert.c
+++ b/lib/auth/cert.c
@@ -181,6 +181,7 @@ find_x509_client_cert(gnutls_session_t session,
ssize_t data_size = _data_size;
unsigned i, j;
int result, cert_pk;
+ unsigned key_usage;
*indx = -1;
@@ -191,8 +192,16 @@ find_x509_client_cert(gnutls_session_t session,
(data_size == 0
|| (session->internals.flags & GNUTLS_FORCE_CLIENT_CERT))) {
if (cred->certs[0].cert_list[0].type == GNUTLS_CRT_X509) {
- /* This check is necessary to prevent sending other certificate
- * credentials that are set (e.g. raw public-key). */
+
+ key_usage = get_key_usage(session, cred->certs[0].cert_list[0].pubkey);
+
+ /* For client certificates we require signatures */
+ result = _gnutls_check_key_usage_for_sig(session, key_usage, 1);
+ if (result < 0) {
+ _gnutls_debug_log("Client certificate is not suitable for signing\n");
+ return gnutls_assert_val(result);
+ }
+
*indx = 0;
return 0;
}
@@ -221,6 +230,14 @@ find_x509_client_cert(gnutls_session_t session,
if (odn.size == 0 || odn.size != asked_dn.size)
continue;
+ key_usage = get_key_usage(session, cred->certs[i].cert_list[0].pubkey);
+
+ /* For client certificates we require signatures */
+ if (_gnutls_check_key_usage_for_sig(session, key_usage, 1) < 0) {
+ _gnutls_debug_log("Client certificate is not suitable for signing\n");
+ continue;
+ }
+
/* If the DN matches and
* the *_SIGN algorithm matches
* the cert is our cert!
@@ -268,6 +285,7 @@ find_rawpk_client_cert(gnutls_session_t session,
int pk_algos_length, int* indx)
{
unsigned i;
+ int ret;
gnutls_pk_algorithm_t pk;
*indx = -1;
@@ -276,15 +294,22 @@ find_rawpk_client_cert(gnutls_session_t session,
/* We know that our list length will be 1, therefore we can
* ignore the rest.
*/
- if (cred->certs[i].cert_list_length == 1) {
- pk = gnutls_pubkey_get_pk_algorithm(cred->certs[i].
- cert_list[0].pubkey, NULL);
+ if (cred->certs[i].cert_list_length == 1 && cred->certs[i].cert_list[0].type == GNUTLS_CRT_RAWPK) {
+ pk = gnutls_pubkey_get_pk_algorithm(cred->certs[i].cert_list[0].pubkey, NULL);
+
+ /* For client certificates we require signatures */
+ ret = _gnutls_check_key_usage_for_sig(session, get_key_usage(session, cred->certs[i].cert_list[0].pubkey), 1);
+ if (ret < 0) {
+ /* we return an error instead of skipping so that the user is notified about
+ * the key incompatibility */
+ _gnutls_debug_log("Client certificate is not suitable for signing\n");
+ return gnutls_assert_val(ret);
+ }
/* Check whether the public-key algorithm of our credential is in
* the list with supported public-key algorithms and whether the
* cert type matches. */
- if ((check_pk_algo_in_list(pk_algos, pk_algos_length, pk) == 0)
- && (cred->certs[i].cert_list[0].type == GNUTLS_CRT_RAWPK)) {
+ if ((check_pk_algo_in_list(pk_algos, pk_algos_length, pk) == 0)) {
// We found a compatible credential
*indx = i;
break;
@@ -643,21 +668,24 @@ _gnutls_gen_rawpk_crt(gnutls_session_t session, gnutls_buffer_st* data)
/* Since we are transmitting a raw public key with no additional
* certificate credentials attached to it, it doesn't make sense to
* have more than one certificate set (i.e. to have a certificate chain).
- * This is enforced by the API so having a value other than 1 should
- * be an impossible situation.
*/
- assert(apr_cert_list_length == 1);
-
+ assert(apr_cert_list_length <= 1);
+
/* Write our certificate containing only the SubjectPublicKeyInfo to
* the output buffer. We always have exactly one certificate that
* contains our raw public key. Our message looks like:
* <length++certificate> where
- * length = 3 bytes and
+ * length = 3 bytes (or 24 bits) and
* certificate = length bytes.
*/
- ret = _gnutls_buffer_append_data_prefix(data, 24,
- apr_cert_list[0].cert.data,
- apr_cert_list[0].cert.size);
+ if (apr_cert_list_length == 0) {
+ ret = _gnutls_buffer_append_prefix(data, 24, 0);
+ } else {
+ ret = _gnutls_buffer_append_data_prefix(data, 24,
+ apr_cert_list[0].cert.data,
+ apr_cert_list[0].cert.size);
+ }
+
if (ret < 0) return gnutls_assert_val(ret);
@@ -1462,11 +1490,11 @@ int cert_select_sign_algorithm(gnutls_session_t session,
return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
}
- if (unlikely(session->internals.priorities->allow_server_key_usage_violation)) {
- key_usage = 0;
- } else {
- key_usage = pubkey->key_usage;
- }
+ key_usage = get_key_usage(session, pubkey);
+
+ /* In TLS1.3 we support only signatures; ensure the selected key supports them */
+ if (ver->tls13_sem && _gnutls_check_key_usage_for_sig(session, key_usage, 1) < 0)
+ return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
if (!ver->tls13_sem && !_gnutls_kx_supports_pk_usage(cs->kx_algorithm, pk, key_usage)) {
return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);