mirror of
https://github.com/strongswan/strongswan.git
synced 2025-10-04 00:00:14 -04:00
tls-server: Consider supported signature algorithms when selecting key/certificate
This won't work if the client doesn't send a `signature_algorithms` extension. But since the default is SHA1/RSA, most will send it to at least announce stronger hash algorithms if not ECDSA.
This commit is contained in:
parent
06112f3fe2
commit
9803fb82f4
@ -23,6 +23,7 @@
|
||||
|
||||
#include <utils/debug.h>
|
||||
#include <plugins/plugin_feature.h>
|
||||
#include <collections/hashtable.h>
|
||||
|
||||
ENUM_BEGIN(tls_cipher_suite_names, TLS_NULL_WITH_NULL_NULL,
|
||||
TLS_DH_anon_WITH_3DES_EDE_CBC_SHA,
|
||||
@ -2423,3 +2424,87 @@ tls_named_group_t tls_ec_group_to_curve(diffie_hellman_group_t group)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* See header.
|
||||
*/
|
||||
key_type_t tls_signature_scheme_to_key_type(tls_signature_scheme_t sig)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < countof(schemes); i++)
|
||||
{
|
||||
if (schemes[i].sig == sig)
|
||||
{
|
||||
return key_type_from_signature_scheme(schemes[i].params.scheme);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hashtable hash function
|
||||
*/
|
||||
static u_int hash_key_type(key_type_t *type)
|
||||
{
|
||||
return chunk_hash(chunk_from_thing(*type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Hashtable equals function
|
||||
*/
|
||||
static bool equals_key_type(key_type_t *key1, key_type_t *key2)
|
||||
{
|
||||
return *key1 == *key2;
|
||||
}
|
||||
|
||||
CALLBACK(filter_key_types, bool,
|
||||
void *data, enumerator_t *orig, va_list args)
|
||||
{
|
||||
key_type_t *key_type, *out;
|
||||
|
||||
VA_ARGS_VGET(args, out);
|
||||
|
||||
if (orig->enumerate(orig, NULL, &key_type))
|
||||
{
|
||||
*out = *key_type;
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CALLBACK(destroy_key_types, void,
|
||||
hashtable_t *ht)
|
||||
{
|
||||
ht->destroy_function(ht, (void*)free);
|
||||
}
|
||||
|
||||
/*
|
||||
* See header.
|
||||
*/
|
||||
enumerator_t *tls_get_supported_key_types(tls_version_t min_version,
|
||||
tls_version_t max_version)
|
||||
{
|
||||
hashtable_t *ht;
|
||||
key_type_t *type, lookup;
|
||||
int i;
|
||||
|
||||
ht = hashtable_create((hashtable_hash_t)hash_key_type,
|
||||
(hashtable_equals_t)equals_key_type, 4);
|
||||
for (i = 0; i < countof(schemes); i++)
|
||||
{
|
||||
if (schemes[i].min_version <= max_version &&
|
||||
schemes[i].max_version >= min_version)
|
||||
{
|
||||
lookup = key_type_from_signature_scheme(schemes[i].params.scheme);
|
||||
if (!ht->get(ht, &lookup))
|
||||
{
|
||||
type = malloc_thing(key_type_t);
|
||||
*type = lookup;
|
||||
ht->put(ht, type, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
return enumerator_create_filter(ht->create_enumerator(ht),
|
||||
filter_key_types, ht, destroy_key_types);
|
||||
}
|
||||
|
@ -691,4 +691,24 @@ int tls_crypto_get_supported_groups(diffie_hellman_group_t **groups);
|
||||
*/
|
||||
tls_named_group_t tls_ec_group_to_curve(diffie_hellman_group_t group);
|
||||
|
||||
/**
|
||||
* Get the key type from a TLS signature scheme
|
||||
*
|
||||
* @param sig TLS signature algorithm scheme
|
||||
* @return type of a key
|
||||
*/
|
||||
key_type_t tls_signature_scheme_to_key_type(tls_signature_scheme_t sig);
|
||||
|
||||
/**
|
||||
* Create an enumerator over supported key types within a specific TLS version range
|
||||
*
|
||||
* Enumerates over key_type_t
|
||||
*
|
||||
* @param min_version minimum negotiated TLS version
|
||||
* @param max_version maximum negotiated TLS version
|
||||
* @return hashtable of key types
|
||||
*/
|
||||
enumerator_t *tls_get_supported_key_types(tls_version_t min_version,
|
||||
tls_version_t max_version);
|
||||
|
||||
#endif /** TLS_CRYPTO_H_ @}*/
|
||||
|
@ -169,71 +169,109 @@ struct private_tls_server_t {
|
||||
bool curves_received;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an array of an intersection of server and peer supported key types
|
||||
*/
|
||||
static array_t *create_common_key_types(chunk_t hashsig,
|
||||
tls_version_t version_min,
|
||||
tls_version_t version_max)
|
||||
{
|
||||
array_t *key_types;
|
||||
enumerator_t *enumerator;
|
||||
key_type_t v, lookup;
|
||||
uint16_t sig_scheme;
|
||||
|
||||
key_types = array_create(sizeof(key_type_t), 8);
|
||||
enumerator = tls_get_supported_key_types(version_min, version_max);
|
||||
while (enumerator->enumerate(enumerator, &v))
|
||||
{
|
||||
bio_reader_t *reader;
|
||||
|
||||
reader = bio_reader_create(hashsig);
|
||||
while (reader->remaining(reader) &&
|
||||
reader->read_uint16(reader, &sig_scheme))
|
||||
{
|
||||
lookup = tls_signature_scheme_to_key_type(sig_scheme);
|
||||
if (v == lookup)
|
||||
{
|
||||
array_insert(key_types, ARRAY_TAIL, &lookup);
|
||||
break;
|
||||
}
|
||||
}
|
||||
reader->destroy(reader);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
return key_types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a cipher suite and a server key
|
||||
*/
|
||||
static bool select_suite_and_key(private_tls_server_t *this,
|
||||
tls_cipher_suite_t *suites, int count)
|
||||
{
|
||||
array_t *key_types;
|
||||
tls_version_t version_min, version_max;
|
||||
private_key_t *key;
|
||||
key_type_t type;
|
||||
|
||||
key = lib->credmgr->get_private(lib->credmgr, KEY_ANY, this->server,
|
||||
this->server_auth);
|
||||
version_min = this->tls->get_version_min(this->tls);
|
||||
version_max = this->tls->get_version_max(this->tls);
|
||||
key_types = create_common_key_types(this->hashsig, version_min, version_max);
|
||||
if (!array_count(key_types))
|
||||
{
|
||||
DBG1(DBG_TLS, "no common signature algorithms found");
|
||||
array_destroy(key_types);
|
||||
return FALSE;
|
||||
}
|
||||
while (array_remove(key_types, ARRAY_HEAD, &type))
|
||||
{
|
||||
key = lib->credmgr->get_private(lib->credmgr, type, this->server,
|
||||
this->server_auth);
|
||||
if (key)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!key)
|
||||
{
|
||||
DBG1(DBG_TLS, "no usable TLS server certificate found for '%Y'",
|
||||
this->server);
|
||||
array_destroy(key_types);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (this->tls->get_version_max(this->tls) >= TLS_1_3)
|
||||
if (version_max >= TLS_1_3)
|
||||
{
|
||||
/* currently no support to derive key based on client supported
|
||||
* signature schemes */
|
||||
this->suite = this->crypto->select_cipher_suite(this->crypto, suites,
|
||||
count, KEY_ANY);
|
||||
if (!this->suite)
|
||||
{
|
||||
DBG1(DBG_TLS, "received cipher suites unacceptable");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this->suite = this->crypto->select_cipher_suite(this->crypto, suites,
|
||||
count,
|
||||
key->get_type(key));
|
||||
if (!this->suite)
|
||||
{ /* no match for this key, try to find another type */
|
||||
if (key->get_type(key) == KEY_ECDSA)
|
||||
{
|
||||
type = KEY_RSA;
|
||||
}
|
||||
else
|
||||
{
|
||||
type = KEY_ECDSA;
|
||||
}
|
||||
key->destroy(key);
|
||||
|
||||
this->suite = this->crypto->select_cipher_suite(this->crypto, suites,
|
||||
count, type);
|
||||
if (!this->suite)
|
||||
{
|
||||
DBG1(DBG_TLS, "received cipher suites unacceptable");
|
||||
return FALSE;
|
||||
}
|
||||
count, type);
|
||||
while (!this->suite && array_remove(key_types, ARRAY_HEAD, &type))
|
||||
{ /* find a key and cipher suite for one of the remaining key types */
|
||||
DESTROY_IF(key);
|
||||
this->server_auth->destroy(this->server_auth);
|
||||
this->server_auth = auth_cfg_create();
|
||||
key = lib->credmgr->get_private(lib->credmgr, type, this->server,
|
||||
this->server_auth);
|
||||
if (!key)
|
||||
if (key)
|
||||
{
|
||||
DBG1(DBG_TLS, "received cipher suites unacceptable");
|
||||
return FALSE;
|
||||
this->suite = this->crypto->select_cipher_suite(this->crypto,
|
||||
suites, count,
|
||||
type);
|
||||
}
|
||||
}
|
||||
}
|
||||
array_destroy(key_types);
|
||||
if (!this->suite || !key)
|
||||
{
|
||||
DBG1(DBG_TLS, "received cipher suites or signature schemes unacceptable");
|
||||
return FALSE;
|
||||
}
|
||||
DBG1(DBG_TLS, "using key of type %N", key_type_names, key->get_type(key));
|
||||
this->private = key;
|
||||
return TRUE;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user