#include <utils/debug.h>
#include <plugins/plugin_feature.h>
#include <collections/hashtable.h>
+#include <collections/array.h>
ENUM_BEGIN(tls_cipher_suite_names, TLS_NULL_WITH_NULL_NULL,
TLS_DH_anon_WITH_3DES_EDE_CBC_SHA,
ht->destroy_function(ht, (void*)free);
}
-/*
- * See header.
+/**
+ * Create an enumerator over supported key types within a specific TLS range
*/
-enumerator_t *tls_get_supported_key_types(tls_version_t min_version,
+static enumerator_t *get_supported_key_types(tls_version_t min_version,
tls_version_t max_version)
{
hashtable_t *ht;
return enumerator_create_filter(ht->create_enumerator(ht),
filter_key_types, ht, destroy_key_types);
}
+
+/**
+ * Create an array of an intersection of server and peer supported key types
+ */
+static array_t *create_common_key_types(enumerator_t *enumerator, chunk_t hashsig)
+{
+ array_t *key_types;
+ key_type_t v, lookup;
+ uint16_t sig_scheme;
+
+ key_types = array_create(sizeof(key_type_t), 8);
+ 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);
+ }
+ return key_types;
+}
+
+typedef struct {
+ enumerator_t public;
+ array_t *key_types;
+ identification_t *peer;
+ private_key_t *key;
+ auth_cfg_t *auth;
+} private_key_enumerator_t;
+
+METHOD(enumerator_t, private_key_enumerate, bool,
+ private_key_enumerator_t *this, va_list args)
+{
+ key_type_t type;
+ auth_cfg_t **auth_out;
+ private_key_t **key_out;
+
+ VA_ARGS_VGET(args, key_out, auth_out);
+
+ DESTROY_IF(this->key);
+ DESTROY_IF(this->auth);
+ this->auth = auth_cfg_create();
+
+ while (array_remove(this->key_types, ARRAY_HEAD, &type))
+ {
+ this->key = lib->credmgr->get_private(lib->credmgr, type, this->peer,
+ this->auth);
+ if (this->key)
+ {
+ *key_out = this->key;
+ if (auth_out)
+ {
+ *auth_out = this->auth;
+ }
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+METHOD(enumerator_t, private_key_destroy, void,
+ private_key_enumerator_t *this)
+{
+ DESTROY_IF(this->key);
+ DESTROY_IF(this->auth);
+ array_destroy(this->key_types);
+ free(this);
+}
+
+/**
+ * See header.
+ */
+enumerator_t *tls_create_private_key_enumerator(tls_version_t min_version,
+ tls_version_t max_version,
+ chunk_t hashsig,
+ identification_t *peer)
+{
+ private_key_enumerator_t *enumerator;
+ enumerator_t *key_types;
+
+ key_types = get_supported_key_types(min_version, max_version);
+
+ INIT(enumerator,
+ .public = {
+ .enumerate = enumerator_enumerate_default,
+ .venumerate = _private_key_enumerate,
+ .destroy = _private_key_destroy,
+ },
+ .key_types = create_common_key_types(key_types, hashsig),
+ .peer = peer,
+ );
+ key_types->destroy(key_types);
+
+ if (!array_count(enumerator->key_types))
+ {
+ return NULL;
+ }
+ return &enumerator->public;
+}
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
+ * Find a private key to encrypt/verify key exchange data
*
* @param min_version minimum negotiated TLS version
* @param max_version maximum negotiated TLS version
- * @return hashtable of key types
+ * @param hashsig hash and signature algorithms supported by other peer
+ * @param peer this peer identification
+ * @return enumerator over private keys,
+ * NULL in case no common signature scheme
*/
-enumerator_t *tls_get_supported_key_types(tls_version_t min_version,
- tls_version_t max_version);
+enumerator_t *tls_create_private_key_enumerator(tls_version_t min_version,
+ tls_version_t max_version,
+ chunk_t hashsig,
+ identification_t *peer);
#endif /** TLS_CRYPTO_H_ @}*/
certificate_t *cert;
auth_rule_t rule;
bio_writer_t *certs;
+ private_key_t *key;
+ auth_cfg_t *auth;
chunk_t data;
+ tls_version_t version_min, version_max;
- this->private = find_private_key(this);
+ version_min = this->tls->get_version_min(this->tls);
+ version_max = this->tls->get_version_max(this->tls);
+ if (version_max > TLS_1_1)
+ {
+ enumerator = tls_create_private_key_enumerator(version_min, version_max,
+ this->hashsig, this->peer);
+ if (!enumerator)
+ {
+ DBG1(DBG_TLS, "no common signature algorithms found");
+ return FALSE;
+ }
+ if (enumerator->enumerate(enumerator, &key, &auth))
+ {
+ this->private = key->get_ref(key);
+ this->peer_auth->merge(this->peer_auth, auth, FALSE);
+ }
+ enumerator->destroy(enumerator);
+ }
+ else
+ {
+ this->private = find_private_key(this);
+ }
if (!this->private)
{
- DBG1(DBG_TLS, "no TLS peer certificate found for '%Y', "
- "skipping client authentication", this->peer);
+ DBG1(DBG_TLS, "no usable TLS client certificate found for '%Y'",
+ this->peer);
this->peer->destroy(this->peer);
this->peer = NULL;
}
}
/**
- * 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;
+ auth_cfg_t *auth;
+ enumerator_t *enumerator;
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))
+ enumerator = tls_create_private_key_enumerator(version_min, version_max,
+ this->hashsig, this->server);
+ if (!enumerator)
{
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)
+ if (!enumerator->enumerate(enumerator, &key, &auth))
{
DBG1(DBG_TLS, "no usable TLS server certificate found for '%Y'",
this->server);
- array_destroy(key_types);
+ enumerator->destroy(enumerator);
return FALSE;
}
else
{
this->suite = this->crypto->select_cipher_suite(this->crypto, suites,
- count, type);
- while (!this->suite && array_remove(key_types, ARRAY_HEAD, &type))
+ count, key->get_type(key));
+ while (!this->suite &&
+ enumerator->enumerate(enumerator, &key, &auth))
{ /* 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)
- {
- this->suite = this->crypto->select_cipher_suite(this->crypto,
- suites, count,
- type);
- }
+ this->suite = this->crypto->select_cipher_suite(this->crypto,
+ suites, count,
+ key->get_type(key));
}
}
- array_destroy(key_types);
- if (!this->suite || !key)
+ if (!this->suite)
{
DBG1(DBG_TLS, "received cipher suites or signature schemes unacceptable");
+ enumerator->destroy(enumerator);
return FALSE;
}
DBG1(DBG_TLS, "using key of type %N", key_type_names, key->get_type(key));
- this->private = key;
+ this->private = key->get_ref(key);
+ this->server_auth->merge(this->server_auth, auth, FALSE);
+ enumerator->destroy(enumerator);
return TRUE;
}