diff options
author | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2017-07-12 09:19:16 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2017-09-11 15:51:53 +0200 |
commit | c23100c3cb424a9f262fb2e854860ac78aed2975 (patch) | |
tree | 51bbf8485dd9d066d16a4e6350052bfa74fdbf94 | |
parent | a325f853b8a454a58b11cff0f8188bcf7fdfcbe2 (diff) | |
download | gnutls-c23100c3cb424a9f262fb2e854860ac78aed2975.tar.gz |
priority: do not include signature algorithms that apply to different TLS version
That is, when a signature algorithm that is only applicable
to specific TLS protocol semantics (e.g., ECDSA-SECP256R1-SHA256)
is enabled, under TLS 1.2, it will result to no code points being
added. That prevents connection errors due to "wrong" code
points being added that do not correspond to a usable signature
algorithm under the protocol.
Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
-rw-r--r-- | lib/priority.c | 56 |
1 files changed, 51 insertions, 5 deletions
diff --git a/lib/priority.c b/lib/priority.c index f8135aa7c0..e297f3fd2b 100644 --- a/lib/priority.c +++ b/lib/priority.c @@ -1180,7 +1180,7 @@ static void add_dh(gnutls_priority_t priority_cache) } } -static void set_ciphersuite_list(gnutls_priority_t priority_cache) +static int set_ciphersuite_list(gnutls_priority_t priority_cache) { unsigned i, j, z; const gnutls_cipher_suite_entry_st *ce; @@ -1188,12 +1188,29 @@ static void set_ciphersuite_list(gnutls_priority_t priority_cache) unsigned have_ec = 0; unsigned have_dh = 0; unsigned ecc_first = 0; + unsigned tls_sig_sem = 0; + const version_entry_st *tlsmax = NULL; + const version_entry_st *dtlsmax = NULL; priority_cache->cs.size = 0; priority_cache->sigalg.size = 0; priority_cache->groups.size = 0; priority_cache->groups.have_ffdhe = 0; + for (i = 0; i < priority_cache->protocol.algorithms; i++) { + if (priority_cache->protocol.priority[i] < GNUTLS_DTLS_VERSION_MIN) { + tlsmax = version_to_entry(priority_cache->protocol.priority[i]); + if (tlsmax) + tls_sig_sem = tlsmax->tls_sig_sem; + if (dtlsmax) + break; + } else { /* dtls */ + dtlsmax = version_to_entry(priority_cache->protocol.priority[i]); + if (tlsmax) + break; + } + } + for (i = 0; i < priority_cache->_kx.algorithms; i++) { for (j=0;j<priority_cache->_cipher.algorithms;j++) { for (z=0;z<priority_cache->_mac.algorithms;z++) { @@ -1219,6 +1236,10 @@ static void set_ciphersuite_list(gnutls_priority_t priority_cache) for (i = 0; i < priority_cache->_sign_algo.algorithms; i++) { se = _gnutls_sign_to_entry(priority_cache->_sign_algo.priority[i]); if (se != NULL && priority_cache->sigalg.size < sizeof(priority_cache->sigalg.entry)/sizeof(priority_cache->sigalg.entry[0])) { + /* if the signature algorithm semantics are higher than + * the protocol's, then skip. */ + if (se->aid.tls_sem > tls_sig_sem) + continue; priority_cache->sigalg.entry[priority_cache->sigalg.size++] = se; } } @@ -1238,6 +1259,22 @@ static void set_ciphersuite_list(gnutls_priority_t priority_cache) _gnutls_debug_log("added %d ciphersuites, %d sig algos and %d groups into priority list\n", priority_cache->cs.size, priority_cache->sigalg.size, priority_cache->groups.size); + + if (priority_cache->cs.size == 0) { + return gnutls_assert_val(GNUTLS_E_NO_PRIORITIES_WERE_SET); + } + + if (priority_cache->sigalg.size == 0) { + if ((tlsmax && tlsmax->id >= GNUTLS_TLS1_2) || (dtlsmax && dtlsmax->id >= GNUTLS_DTLS1_2)) { + return gnutls_assert_val(GNUTLS_E_NO_PRIORITIES_WERE_SET); + } + } + + /* when TLS 1.3 is available we must have groups set */ + if (tlsmax && tlsmax->id >= GNUTLS_TLS1_3 && priority_cache->groups.size == 0) + return gnutls_assert_val(GNUTLS_E_NO_PRIORITIES_WERE_SET); + + return 0; } /** @@ -1344,6 +1381,7 @@ gnutls_priority_init(gnutls_priority_t * priority_cache, char *darg = NULL; unsigned ikeyword_set = 0; int algo; + int ret; rmadd_func *fn; bulk_rmadd_func *bulk_fn; bulk_rmadd_func *bulk_given_fn; @@ -1551,24 +1589,32 @@ gnutls_priority_init(gnutls_priority_t * priority_cache, goto error; } - free(darg); + ret = set_ciphersuite_list(*priority_cache); + if (ret < 0) { + if (err_pos) + *err_pos = priorities; + goto error_cleanup; + } - set_ciphersuite_list(*priority_cache); + free(darg); return 0; - error: + error: if (err_pos != NULL && i < broken_list_size) { *err_pos = priorities; for (j = 0; j < i; j++) { (*err_pos) += strlen(broken_list[j]) + 1; } } + ret = GNUTLS_E_INVALID_REQUEST; + + error_cleanup: free(darg); gnutls_priority_deinit(*priority_cache); *priority_cache = NULL; - return GNUTLS_E_INVALID_REQUEST; + return ret; } |