]> git.ipfire.org Git - thirdparty/strongswan.git/blobdiff - src/libtls/tls_crypto.c
Fixed some typos, courtesy of codespell
[thirdparty/strongswan.git] / src / libtls / tls_crypto.c
index 03d19fa00aaca7332022b0e475a43d154075a54b..0ec2f5cbef21ff3573634fff975e25fc530818a2 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * Copyright (C) 2010 Martin Willi
- * Copyright (C) 2010 revosec AG
+ * Copyright (C) 2010-2014 Martin Willi
+ * Copyright (C) 2010-2014 revosec AG
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -16,6 +16,7 @@
 #include "tls_crypto.h"
 
 #include <utils/debug.h>
+#include <plugins/plugin_feature.h>
 
 ENUM_BEGIN(tls_cipher_suite_names, TLS_NULL_WITH_NULL_NULL,
                                                                   TLS_DH_anon_WITH_3DES_EDE_CBC_SHA,
@@ -80,7 +81,7 @@ ENUM_NEXT(tls_cipher_suite_names, TLS_KRB5_WITH_DES_CBC_SHA,
        "TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
        "TLS_DH_anon_WITH_AES_256_CBC_SHA",
        "TLS_RSA_WITH_NULL_SHA256",
-       "TLS_RSA_WITH_AES_128_CBC_SHA256 ",
+       "TLS_RSA_WITH_AES_128_CBC_SHA256",
        "TLS_RSA_WITH_AES_256_CBC_SHA256",
        "TLS_DH_DSS_WITH_AES_128_CBC_SHA256",
        "TLS_DH_RSA_WITH_AES_128_CBC_SHA256",
@@ -111,13 +112,13 @@ ENUM_NEXT(tls_cipher_suite_names, TLS_RSA_WITH_CAMELLIA_256_CBC_SHA,
        "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA",
        "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA",
        "TLS_PSK_WITH_RC4_128_SHA",
-       "TLS_PSK_WITH_3DES_EDE_CBC_SHA2",
+       "TLS_PSK_WITH_3DES_EDE_CBC_SHA",
        "TLS_PSK_WITH_AES_128_CBC_SHA",
        "TLS_PSK_WITH_AES_256_CBC_SHA",
        "TLS_DHE_PSK_WITH_RC4_128_SHA",
        "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA",
        "TLS_DHE_PSK_WITH_AES_128_CBC_SHA",
-       "TLS_DHE_PSK_WITH_AES_256_CBC_SHA2",
+       "TLS_DHE_PSK_WITH_AES_256_CBC_SHA",
        "TLS_RSA_PSK_WITH_RC4_128_SHA",
        "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA",
        "TLS_RSA_PSK_WITH_AES_128_CBC_SHA",
@@ -375,7 +376,7 @@ struct private_tls_crypto_t {
        tls_cache_t *cache;
 
        /**
-        * All handshake data concatentated
+        * All handshake data concatenated
         */
        chunk_t handshake;
 
@@ -440,6 +441,16 @@ static suite_algs_t suite_algs[] = {
                HASH_SHA384, PRF_HMAC_SHA2_384,
                AUTH_HMAC_SHA2_384_384, ENCR_AES_CBC, 32
        },
+       { TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+               KEY_ECDSA, ECP_256_BIT,
+               HASH_SHA256, PRF_HMAC_SHA2_256,
+               AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 16
+       },
+       { TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+               KEY_ECDSA, ECP_384_BIT,
+               HASH_SHA384, PRF_HMAC_SHA2_384,
+               AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 32
+       },
        { TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
                KEY_RSA, ECP_256_BIT,
                HASH_SHA256, PRF_HMAC_SHA2_256,
@@ -460,6 +471,16 @@ static suite_algs_t suite_algs[] = {
                HASH_SHA384, PRF_HMAC_SHA2_384,
                AUTH_HMAC_SHA2_384_384, ENCR_AES_CBC, 32
        },
+       { TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+               KEY_RSA, ECP_256_BIT,
+               HASH_SHA256, PRF_HMAC_SHA2_256,
+               AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 16
+       },
+       { TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+               KEY_RSA, ECP_384_BIT,
+               HASH_SHA384, PRF_HMAC_SHA2_384,
+               AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 32
+       },
        { TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
                KEY_RSA, MODP_2048_BIT,
                HASH_SHA256,PRF_HMAC_SHA2_256,
@@ -480,6 +501,16 @@ static suite_algs_t suite_algs[] = {
                HASH_SHA256, PRF_HMAC_SHA2_256,
                AUTH_HMAC_SHA2_256_256, ENCR_AES_CBC, 32
        },
+       { TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
+               KEY_RSA, MODP_3072_BIT,
+               HASH_SHA256, PRF_HMAC_SHA2_256,
+               AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 16
+       },
+       { TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
+               KEY_RSA, MODP_4096_BIT,
+               HASH_SHA384, PRF_HMAC_SHA2_384,
+               AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 32
+       },
        { TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,
                KEY_RSA, MODP_2048_BIT,
                HASH_SHA256, PRF_HMAC_SHA2_256,
@@ -525,6 +556,16 @@ static suite_algs_t suite_algs[] = {
                HASH_SHA256, PRF_HMAC_SHA2_256,
                AUTH_HMAC_SHA2_256_256, ENCR_AES_CBC, 32
        },
+       { TLS_RSA_WITH_AES_128_GCM_SHA256,
+               KEY_RSA, MODP_NONE,
+               HASH_SHA256, PRF_HMAC_SHA2_256,
+               AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 16
+       },
+       { TLS_RSA_WITH_AES_256_GCM_SHA384,
+               KEY_RSA, MODP_NONE,
+               HASH_SHA384, PRF_HMAC_SHA2_384,
+               AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 32
+       },
        { TLS_RSA_WITH_CAMELLIA_128_CBC_SHA,
                KEY_RSA, MODP_NONE,
                HASH_SHA256, PRF_HMAC_SHA2_256,
@@ -607,8 +648,7 @@ static suite_algs_t *find_suite(tls_cipher_suite_t suite)
 /**
  * Filter a suite list using a transform enumerator
  */
-static void filter_suite(private_tls_crypto_t *this,
-                                                suite_algs_t suites[], int *count, int offset,
+static void filter_suite(suite_algs_t suites[], int *count, int offset,
                                                 enumerator_t*(*create_enumerator)(crypto_factory_t*))
 {
        const char *plugin_name;
@@ -621,21 +661,56 @@ static void filter_suite(private_tls_crypto_t *this,
 
        for (i = 0; i < *count; i++)
        {
+               if (create_enumerator == lib->crypto->create_crypter_enumerator &&
+                       encryption_algorithm_is_aead(suites[i].encr))
+               {       /* filtering crypters, but current suite uses an AEAD, apply */
+                       suites[remaining] = suites[i];
+                       remaining++;
+                       continue;
+               }
+               if (create_enumerator == lib->crypto->create_aead_enumerator &&
+                       !encryption_algorithm_is_aead(suites[i].encr))
+               {       /* filtering AEADs, but current suite doesn't use one, apply */
+                       suites[remaining] = suites[i];
+                       remaining++;
+                       continue;
+               }
                enumerator = create_enumerator(lib->crypto);
                while (enumerator->enumerate(enumerator, current_alg, &plugin_name))
                {
-                       if ((suites[i].encr == ENCR_NULL ||
-                                !current.encr || current.encr == suites[i].encr) &&
-                               (!current.mac  || current.mac  == suites[i].mac) &&
-                               (!current.prf  || current.prf  == suites[i].prf) &&
-                               (!current.hash || current.hash == suites[i].hash) &&
-                               (suites[i].dh == MODP_NONE ||
-                                !current.dh   || current.dh   == suites[i].dh))
+                       if (current.encr && current.encr != suites[i].encr)
                        {
-                               suites[remaining] = suites[i];
-                               remaining++;
-                               break;
+                               if (suites[i].encr != ENCR_NULL)
+                               {       /* skip, ENCR does not match nor is NULL */
+                                       continue;
+                               }
+                       }
+                       if (current.mac && current.mac != suites[i].mac)
+                       {
+                               if (suites[i].mac != AUTH_UNDEFINED)
+                               {       /* skip, MAC does not match nor is it undefined */
+                                       continue;
+                               }
+                       }
+                       if (current.prf && current.prf != suites[i].prf)
+                       {       /* skip, PRF does not match */
+                               continue;
                        }
+                       if (current.hash && current.hash != suites[i].hash)
+                       {       /* skip, hash does not match */
+                               continue;
+                       }
+                       if (current.dh && current.dh != suites[i].dh)
+                       {
+                               if (suites[i].dh != MODP_NONE)
+                               {       /* skip DH group, does not match nor NONE */
+                                       continue;
+                               }
+                       }
+                       /* suite supported, apply */
+                       suites[remaining] = suites[i];
+                       remaining++;
+                       break;
                }
                enumerator->destroy(enumerator);
        }
@@ -645,8 +720,7 @@ static void filter_suite(private_tls_crypto_t *this,
 /**
  * Purge NULL encryption cipher suites from list
  */
-static void filter_null_suites(private_tls_crypto_t *this,
-                                                          suite_algs_t suites[], int *count)
+static void filter_null_suites(suite_algs_t suites[], int *count)
 {
        int i, remaining = 0;
 
@@ -769,6 +843,20 @@ static void filter_cipher_config_suites(private_tls_crypto_t *this,
                                        suites[remaining++] = suites[i];
                                        break;
                                }
+                               if (strcaseeq(token, "aes128gcm") &&
+                                       suites[i].encr == ENCR_AES_GCM_ICV16 &&
+                                       suites[i].encr_size == 16)
+                               {
+                                       suites[remaining++] = suites[i];
+                                       break;
+                               }
+                               if (strcaseeq(token, "aes256gcm") &&
+                                       suites[i].encr == ENCR_AES_GCM_ICV16 &&
+                                       suites[i].encr_size == 32)
+                               {
+                                       suites[remaining++] = suites[i];
+                                       break;
+                               }
                                if (strcaseeq(token, "camellia128") &&
                                        suites[i].encr == ENCR_CAMELLIA_CBC &&
                                        suites[i].encr_size == 16)
@@ -871,8 +959,8 @@ static void filter_specific_config_suites(private_tls_crypto_t *this,
                        enumerator = enumerator_create_token(config, ",", " ");
                        while (enumerator->enumerate(enumerator, &token))
                        {
-                               suite = enum_from_name(tls_cipher_suite_names, token);
-                               if (suite == suites[i].suite)
+                               if (enum_from_name(tls_cipher_suite_names, token, &suite) &&
+                                       suite == suites[i].suite)
                                {
                                        suites[remaining++] = suites[i];
                                        break;
@@ -884,6 +972,26 @@ static void filter_specific_config_suites(private_tls_crypto_t *this,
        }
 }
 
+/**
+ * Filter out unsupported suites on given suite array
+ */
+static void filter_unsupported_suites(suite_algs_t suites[], int *count)
+{
+       /* filter suite list by each algorithm */
+       filter_suite(suites, count, offsetof(suite_algs_t, encr),
+                                lib->crypto->create_crypter_enumerator);
+       filter_suite(suites, count, offsetof(suite_algs_t, encr),
+                                lib->crypto->create_aead_enumerator);
+       filter_suite(suites, count, offsetof(suite_algs_t, mac),
+                                lib->crypto->create_signer_enumerator);
+       filter_suite(suites, count, offsetof(suite_algs_t, prf),
+                                lib->crypto->create_prf_enumerator);
+       filter_suite(suites, count, offsetof(suite_algs_t, hash),
+                                lib->crypto->create_hasher_enumerator);
+       filter_suite(suites, count, offsetof(suite_algs_t, dh),
+                                lib->crypto->create_dh_enumerator);
+}
+
 /**
  * Initialize the cipher suite list
  */
@@ -898,9 +1006,10 @@ static void build_cipher_suite_list(private_tls_crypto_t *this,
        {
                suites[i] = suite_algs[i];
        }
+
        if (require_encryption)
        {
-               filter_null_suites(this, suites, &count);
+               filter_null_suites(suites, &count);
        }
        if (!this->rsa)
        {
@@ -911,17 +1020,7 @@ static void build_cipher_suite_list(private_tls_crypto_t *this,
                filter_key_suites(this, suites, &count, KEY_ECDSA);
        }
 
-       /* filter suite list by each algorithm */
-       filter_suite(this, suites, &count, offsetof(suite_algs_t, encr),
-                                lib->crypto->create_crypter_enumerator);
-       filter_suite(this, suites, &count, offsetof(suite_algs_t, mac),
-                                lib->crypto->create_signer_enumerator);
-       filter_suite(this, suites, &count, offsetof(suite_algs_t, prf),
-                                lib->crypto->create_prf_enumerator);
-       filter_suite(this, suites, &count, offsetof(suite_algs_t, hash),
-                                lib->crypto->create_hasher_enumerator);
-       filter_suite(this, suites, &count, offsetof(suite_algs_t, dh),
-                                lib->crypto->create_dh_enumerator);
+       filter_unsupported_suites(suites, &count);
 
        /* filter suites with strongswan.conf options */
        filter_key_exchange_config_suites(this, suites, &count);
@@ -993,6 +1092,22 @@ static bool create_traditional(private_tls_crypto_t *this, suite_algs_t *algs)
        return TRUE;
 }
 
+/**
+ * Create AEAD transforms
+ */
+static bool create_aead(private_tls_crypto_t *this, suite_algs_t *algs)
+{
+       this->aead_in = tls_aead_create_aead(algs->encr, algs->encr_size);
+       this->aead_out = tls_aead_create_aead(algs->encr, algs->encr_size);
+       if (!this->aead_in || !this->aead_out)
+       {
+               DBG1(DBG_TLS, "selected TLS transforms %N-%u not supported",
+                        encryption_algorithm_names, algs->encr, algs->encr_size * 8);
+               return FALSE;
+       }
+       return TRUE;
+}
+
 /**
  * Clean up and unset AEAD transforms
  */
@@ -1030,6 +1145,13 @@ static bool create_ciphers(private_tls_crypto_t *this, suite_algs_t *algs)
                        return TRUE;
                }
        }
+       else if (encryption_algorithm_is_aead(algs->encr))
+       {
+               if (create_aead(this, algs))
+               {
+                       return TRUE;
+               }
+       }
        else
        {
                if (create_traditional(this, algs))
@@ -1085,60 +1207,81 @@ METHOD(tls_crypto_t, get_dh_group, diffie_hellman_group_t,
        return MODP_NONE;
 }
 
+/**
+ * Map signature schemes to TLS key types and hashes, ordered by preference
+ */
+static struct {
+       tls_signature_algorithm_t sig;
+       tls_hash_algorithm_t hash;
+       signature_scheme_t scheme;
+} schemes[] = {
+       { TLS_SIG_ECDSA,        TLS_HASH_SHA256,        SIGN_ECDSA_WITH_SHA256_DER   },
+       { TLS_SIG_ECDSA,        TLS_HASH_SHA384,        SIGN_ECDSA_WITH_SHA384_DER   },
+       { TLS_SIG_ECDSA,        TLS_HASH_SHA512,        SIGN_ECDSA_WITH_SHA512_DER   },
+       { TLS_SIG_ECDSA,        TLS_HASH_SHA1,          SIGN_ECDSA_WITH_SHA1_DER     },
+       { TLS_SIG_RSA,          TLS_HASH_SHA256,        SIGN_RSA_EMSA_PKCS1_SHA2_256 },
+       { TLS_SIG_RSA,          TLS_HASH_SHA384,        SIGN_RSA_EMSA_PKCS1_SHA2_384 },
+       { TLS_SIG_RSA,          TLS_HASH_SHA512,        SIGN_RSA_EMSA_PKCS1_SHA2_512 },
+       { TLS_SIG_RSA,          TLS_HASH_SHA224,        SIGN_RSA_EMSA_PKCS1_SHA2_224 },
+       { TLS_SIG_RSA,          TLS_HASH_SHA1,          SIGN_RSA_EMSA_PKCS1_SHA1     },
+       { TLS_SIG_RSA,          TLS_HASH_MD5,           SIGN_RSA_EMSA_PKCS1_MD5      },
+};
+
 METHOD(tls_crypto_t, get_signature_algorithms, void,
        private_tls_crypto_t *this, bio_writer_t *writer)
 {
        bio_writer_t *supported;
-       enumerator_t *enumerator;
-       hash_algorithm_t alg;
-       tls_hash_algorithm_t hash;
-       const char *plugin_name;
+       int i;
 
        supported = bio_writer_create(32);
-       enumerator = lib->crypto->create_hasher_enumerator(lib->crypto);
-       while (enumerator->enumerate(enumerator, &alg, &plugin_name))
+
+       for (i = 0; i < countof(schemes); i++)
        {
-               switch (alg)
+               if (schemes[i].sig == TLS_SIG_RSA && !this->rsa)
                {
-                       case HASH_MD5:
-                               hash = TLS_HASH_MD5;
-                               break;
-                       case HASH_SHA1:
-                               hash = TLS_HASH_SHA1;
-                               break;
-                       case HASH_SHA224:
-                               hash = TLS_HASH_SHA224;
-                               break;
-                       case HASH_SHA256:
-                               hash = TLS_HASH_SHA256;
-                               break;
-                       case HASH_SHA384:
-                               hash = TLS_HASH_SHA384;
-                               break;
-                       case HASH_SHA512:
-                               hash = TLS_HASH_SHA512;
-                               break;
-                       default:
-                               continue;
+                       continue;
                }
-               if (this->rsa)
+               if (schemes[i].sig == TLS_SIG_ECDSA && !this->ecdsa)
                {
-                       supported->write_uint8(supported, hash);
-                       supported->write_uint8(supported, TLS_SIG_RSA);
+                       continue;
                }
-               if (this->ecdsa && alg != HASH_MD5 && alg != HASH_SHA224)
-               {       /* currently we have no signature scheme for MD5/SHA224 */
-                       supported->write_uint8(supported, hash);
-                       supported->write_uint8(supported, TLS_SIG_ECDSA);
+               if (!lib->plugins->has_feature(lib->plugins,
+                                               PLUGIN_PROVIDE(PUBKEY_VERIFY, schemes[i].scheme)))
+               {
+                       continue;
                }
+               supported->write_uint8(supported, schemes[i].hash);
+               supported->write_uint8(supported, schemes[i].sig);
        }
-       enumerator->destroy(enumerator);
 
        supported->wrap16(supported);
        writer->write_data16(writer, supported->get_buf(supported));
        supported->destroy(supported);
 }
 
+/**
+ * Get the signature scheme from a TLS 1.2 hash/sig algorithm pair
+ */
+static signature_scheme_t hashsig_to_scheme(key_type_t type,
+                                                                                       tls_hash_algorithm_t hash,
+                                                                                       tls_signature_algorithm_t sig)
+{
+       int i;
+
+       if ((sig == TLS_SIG_RSA && type == KEY_RSA) ||
+               (sig == TLS_SIG_ECDSA && type == KEY_ECDSA))
+       {
+               for (i = 0; i < countof(schemes); i++)
+               {
+                       if (schemes[i].sig == sig && schemes[i].hash == hash)
+                       {
+                               return schemes[i].scheme;
+                       }
+               }
+       }
+       return SIGN_UNKNOWN;
+}
+
 /**
  * Mapping groups to TLS named curves
  */
@@ -1153,28 +1296,32 @@ static struct {
        { ECP_192_BIT, TLS_SECP192R1},
 };
 
-/**
- * Filter EC groups, add TLS curve
- */
-static bool group_filter(void *null,
-                                               diffie_hellman_group_t *in, diffie_hellman_group_t *out,
-                                               void* dummy1, tls_named_curve_t *curve)
+CALLBACK(group_filter, bool,
+       void *null, enumerator_t *orig, va_list args)
 {
+       diffie_hellman_group_t group, *out;
+       tls_named_curve_t *curve;
+       char *plugin;
        int i;
 
-       for (i = 0; i < countof(curves); i++)
+       VA_ARGS_VGET(args, out, curve);
+
+       while (orig->enumerate(orig, &group, &plugin))
        {
-               if (curves[i].group == *in)
+               for (i = 0; i < countof(curves); i++)
                {
-                       if (out)
+                       if (curves[i].group == group)
                        {
-                               *out = curves[i].group;
-                       }
-                       if (curve)
-                       {
-                               *curve = curves[i].curve;
+                               if (out)
+                               {
+                                       *out = curves[i].group;
+                               }
+                               if (curve)
+                               {
+                                       *curve = curves[i].curve;
+                               }
+                               return TRUE;
                        }
-                       return TRUE;
                }
        }
        return FALSE;
@@ -1184,8 +1331,8 @@ METHOD(tls_crypto_t, create_ec_enumerator, enumerator_t*,
        private_tls_crypto_t *this)
 {
        return enumerator_create_filter(
-                                       lib->crypto->create_dh_enumerator(lib->crypto),
-                                       (void*)group_filter, NULL, NULL);
+                                                       lib->crypto->create_dh_enumerator(lib->crypto),
+                                                       group_filter, NULL, NULL);
 }
 
 METHOD(tls_crypto_t, set_protection, void,
@@ -1197,7 +1344,7 @@ METHOD(tls_crypto_t, set_protection, void,
 METHOD(tls_crypto_t, append_handshake, void,
        private_tls_crypto_t *this, tls_handshake_type_t type, chunk_t data)
 {
-       u_int32_t header;
+       uint32_t header;
 
        /* reconstruct handshake header */
        header = htonl(data.len | (type << 24));
@@ -1256,59 +1403,6 @@ static bool hash_data(private_tls_crypto_t *this, chunk_t data, chunk_t *hash)
        return TRUE;
 }
 
-/**
- * Get the signature scheme from a TLS 1.2 hash/sig algorithm pair
- */
-static signature_scheme_t hashsig_to_scheme(key_type_t type,
-                                       tls_hash_algorithm_t hash, tls_signature_algorithm_t sig)
-{
-       switch (sig)
-       {
-               case TLS_SIG_RSA:
-                       if (type != KEY_RSA)
-                       {
-                               return SIGN_UNKNOWN;
-                       }
-                       switch (hash)
-                       {
-                               case TLS_HASH_MD5:
-                                       return SIGN_RSA_EMSA_PKCS1_MD5;
-                               case TLS_HASH_SHA1:
-                                       return SIGN_RSA_EMSA_PKCS1_SHA1;
-                               case TLS_HASH_SHA224:
-                                       return SIGN_RSA_EMSA_PKCS1_SHA224;
-                               case TLS_HASH_SHA256:
-                                       return SIGN_RSA_EMSA_PKCS1_SHA256;
-                               case TLS_HASH_SHA384:
-                                       return SIGN_RSA_EMSA_PKCS1_SHA384;
-                               case TLS_HASH_SHA512:
-                                       return SIGN_RSA_EMSA_PKCS1_SHA512;
-                               default:
-                                       return SIGN_UNKNOWN;
-                       }
-               case TLS_SIG_ECDSA:
-                       if (type != KEY_ECDSA)
-                       {
-                               return SIGN_UNKNOWN;
-                       }
-                       switch (hash)
-                       {
-                               case TLS_HASH_SHA224:
-                                       return SIGN_ECDSA_WITH_SHA1_DER;
-                               case TLS_HASH_SHA256:
-                                       return SIGN_ECDSA_WITH_SHA256_DER;
-                               case TLS_HASH_SHA384:
-                                       return SIGN_ECDSA_WITH_SHA384_DER;
-                               case TLS_HASH_SHA512:
-                                       return SIGN_ECDSA_WITH_SHA512_DER;
-                               default:
-                                       return SIGN_UNKNOWN;
-                       }
-               default:
-                       return SIGN_UNKNOWN;
-       }
-}
-
 METHOD(tls_crypto_t, sign, bool,
        private_tls_crypto_t *this, private_key_t *key, bio_writer_t *writer,
        chunk_t data, chunk_t hashsig)
@@ -1317,7 +1411,7 @@ METHOD(tls_crypto_t, sign, bool,
        {
                signature_scheme_t scheme;
                bio_reader_t *reader;
-               u_int8_t hash, alg;
+               uint8_t hash, alg;
                chunk_t sig;
                bool done = FALSE;
 
@@ -1334,7 +1428,7 @@ METHOD(tls_crypto_t, sign, bool,
                        {
                                scheme = hashsig_to_scheme(key->get_type(key), hash, alg);
                                if (scheme != SIGN_UNKNOWN &&
-                                       key->sign(key, scheme, data, &sig))
+                                       key->sign(key, scheme, NULL, data, &sig))
                                {
                                        done = TRUE;
                                        break;
@@ -1366,7 +1460,8 @@ METHOD(tls_crypto_t, sign, bool,
                                {
                                        return FALSE;
                                }
-                               done = key->sign(key, SIGN_RSA_EMSA_PKCS1_NULL, hash, &sig);
+                               done = key->sign(key, SIGN_RSA_EMSA_PKCS1_NULL, NULL, hash,
+                                                                &sig);
                                free(hash.ptr);
                                if (!done)
                                {
@@ -1375,7 +1470,7 @@ METHOD(tls_crypto_t, sign, bool,
                                DBG2(DBG_TLS, "created signature with MD5+SHA1/RSA");
                                break;
                        case KEY_ECDSA:
-                               if (!key->sign(key, SIGN_ECDSA_WITH_SHA1_DER, data, &sig))
+                               if (!key->sign(key, SIGN_ECDSA_WITH_SHA1_DER, NULL, data, &sig))
                                {
                                        return FALSE;
                                }
@@ -1397,7 +1492,7 @@ METHOD(tls_crypto_t, verify, bool,
        if (this->tls->get_version(this->tls) >= TLS_1_2)
        {
                signature_scheme_t scheme = SIGN_UNKNOWN;
-               u_int8_t hash, alg;
+               uint8_t hash, alg;
                chunk_t sig;
 
                if (!reader->read_uint8(reader, &hash) ||
@@ -1415,7 +1510,7 @@ METHOD(tls_crypto_t, verify, bool,
                                 tls_signature_algorithm_names, alg);
                        return FALSE;
                }
-               if (!key->verify(key, scheme, data, sig))
+               if (!key->verify(key, scheme, NULL, data, sig))
                {
                        return FALSE;
                }
@@ -1439,7 +1534,8 @@ METHOD(tls_crypto_t, verify, bool,
                                {
                                        return FALSE;
                                }
-                               done = key->verify(key, SIGN_RSA_EMSA_PKCS1_NULL, hash, sig);
+                               done = key->verify(key, SIGN_RSA_EMSA_PKCS1_NULL, NULL, hash,
+                                                                  sig);
                                free(hash.ptr);
                                if (!done)
                                {
@@ -1448,7 +1544,8 @@ METHOD(tls_crypto_t, verify, bool,
                                DBG2(DBG_TLS, "verified signature data with MD5+SHA1/RSA");
                                break;
                        case KEY_ECDSA:
-                               if (!key->verify(key, SIGN_ECDSA_WITH_SHA1_DER, data, sig))
+                               if (!key->verify(key, SIGN_ECDSA_WITH_SHA1_DER, NULL, data,
+                                                                sig))
                                {
                                        return FALSE;
                                }
@@ -1756,8 +1853,43 @@ tls_crypto_t *tls_crypto_create(tls_t *tls, tls_cache_t *cache)
                case TLS_PURPOSE_GENERIC:
                        build_cipher_suite_list(this, TRUE);
                        break;
+               case TLS_PURPOSE_GENERIC_NULLOK:
+                       build_cipher_suite_list(this, FALSE);
+                       break;
                default:
                        break;
        }
        return &this->public;
 }
+
+/**
+ * See header.
+ */
+int tls_crypto_get_supported_suites(bool null, tls_cipher_suite_t **out)
+{
+       suite_algs_t suites[countof(suite_algs)];
+       int count = countof(suite_algs), i;
+
+       /* initialize copy of suite list */
+       for (i = 0; i < count; i++)
+       {
+               suites[i] = suite_algs[i];
+       }
+
+       filter_unsupported_suites(suites, &count);
+
+       if (!null)
+       {
+               filter_null_suites(suites, &count);
+       }
+
+       if (out)
+       {
+               *out = calloc(count, sizeof(tls_cipher_suite_t));
+               for (i = 0; i < count; i++)
+               {
+                       (*out)[i] = suites[i].suite;
+               }
+       }
+       return count;
+}