pubkey-authenticator: Query private key for supported signature schemes
authorTobias Brunner <tobias@strongswan.org>
Fri, 12 Oct 2018 09:14:05 +0000 (11:14 +0200)
committerTobias Brunner <tobias@strongswan.org>
Fri, 26 Oct 2018 07:03:09 +0000 (09:03 +0200)
src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c

index 1fcef03..c1d562a 100644 (file)
@@ -111,6 +111,40 @@ static bool build_signature_auth_data(chunk_t *auth_data,
 }
 
 /**
+ * Check if the given scheme is supported by the key and, if so, add it to the
+ * first array (we add the scheme supported by the key in case the parameters
+ * are different)
+ */
+static void add_scheme_if_supported(array_t *selected, array_t *supported,
+                                                                       signature_params_t *config)
+{
+       signature_params_t *sup;
+       int i;
+
+       if (!supported)
+       {
+               array_insert(selected, ARRAY_TAIL, signature_params_clone(config));
+               return;
+       }
+
+       for (i = 0; i < array_count(supported); i++)
+       {
+               array_get(supported, i, &sup);
+               if (signature_params_comply(sup, config))
+               {
+                       array_insert(selected, ARRAY_TAIL, signature_params_clone(sup));
+                       return;
+               }
+       }
+}
+
+CALLBACK(destroy_scheme, void,
+       signature_params_t *params, int idx, void *user)
+{
+       signature_params_destroy(params);
+}
+
+/**
  * Selects possible signature schemes based on our configuration, the other
  * peer's capabilities and the private key
  */
@@ -123,10 +157,32 @@ static array_t *select_signature_schemes(keymat_v2_t *keymat,
        auth_rule_t rule;
        key_type_t key_type;
        bool have_config = FALSE;
-       array_t *selected;
+       array_t *supported = NULL, *selected;
 
        selected = array_create(0, 0);
        key_type = private->get_type(private);
+
+       if (private->supported_signature_schemes)
+       {
+               enumerator = private->supported_signature_schemes(private);
+               while (enumerator->enumerate(enumerator, &config))
+               {
+                       if (keymat->hash_algorithm_supported(keymat,
+                                                               hasher_from_signature_scheme(config->scheme,
+                                                                                                                        config->params)))
+                       {
+                               array_insert_create(&supported, ARRAY_TAIL,
+                                                                       signature_params_clone(config));
+                       }
+               }
+               enumerator->destroy(enumerator);
+
+               if (!supported)
+               {
+                       return selected;
+               }
+       }
+
        enumerator = auth->create_enumerator(auth);
        while (enumerator->enumerate(enumerator, &rule, &config))
        {
@@ -134,21 +190,32 @@ static array_t *select_signature_schemes(keymat_v2_t *keymat,
                {
                        continue;
                }
-               have_config = TRUE;
                if (key_type == key_type_from_signature_scheme(config->scheme) &&
                        keymat->hash_algorithm_supported(keymat,
                                                                hasher_from_signature_scheme(config->scheme,
                                                                                                                         config->params)))
                {
-                       array_insert(selected, ARRAY_TAIL, signature_params_clone(config));
+                       add_scheme_if_supported(selected, supported, config);
                }
+               have_config = TRUE;
        }
        enumerator->destroy(enumerator);
 
-       if (!have_config)
+       if (have_config)
        {
-               /* if no specific configuration, find schemes appropriate for the key
-                * and supported by the other peer */
+               array_destroy_function(supported, destroy_scheme, NULL);
+       }
+       else
+       {
+               /* if we have no config, return either whatever schemes the key (and
+                * peer) support or.. */
+               if (supported)
+               {
+                       array_destroy(selected);
+                       return supported;
+               }
+
+               /* ...find schemes appropriate for the key and supported by the peer */
                enumerator = signature_schemes_for_key(key_type,
                                                                                           private->get_keysize(private));
                while (enumerator->enumerate(enumerator, &config))
@@ -207,12 +274,6 @@ static array_t *select_signature_schemes(keymat_v2_t *keymat,
        return selected;
 }
 
-CALLBACK(destroy_scheme, void,
-       signature_params_t *params, int idx, void *user)
-{
-       signature_params_destroy(params);
-}
-
 /**
  * Adds the given auth data to the message, either in an AUTH payload or
  * a NO_PPK_AUTH notify.