EVP: Make EVP_PKEY_set_params() increment the dirty count
authorRichard Levitte <levitte@openssl.org>
Wed, 3 Feb 2021 12:50:23 +0000 (13:50 +0100)
committerPauli <ppzgs1@gmail.com>
Fri, 5 Feb 2021 05:53:29 +0000 (15:53 +1000)
When the internal key is changed, we must count it as muted, so that
next time the affected key is considered for an operation, it gets
re-exported to the signing provider.  In other words, this will clear
the EVP_PKEY export cache when the next export attempt occurs.

This also updates evp_keymgmt_util_export_to_provider() to actually
look at the dirty count for provider native origin keys, and act
appropriately.

Reviewed-by: Paul Dale <pauli@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/14056)

crypto/evp/keymgmt_lib.c
crypto/evp/p_lib.c

index 0c643b3b49fc6f57b81a5a782cfe0acb60ecd4fb..0112036263c7e6b7e2175205baf0cdebea2acf2f 100644 (file)
@@ -101,15 +101,22 @@ void *evp_keymgmt_util_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
     if (pk->keymgmt == keymgmt)
         return pk->keydata;
 
-    /* If this key is already exported to |keymgmt|, no more to do */
     CRYPTO_THREAD_read_lock(pk->lock);
-    i = evp_keymgmt_util_find_operation_cache_index(pk, keymgmt);
-    if (i < OSSL_NELEM(pk->operation_cache)
-        && pk->operation_cache[i].keymgmt != NULL) {
-        void *ret = pk->operation_cache[i].keydata;
+    /*
+     * If the provider native "origin" hasn't changed since last time, we
+     * try to find our keymgmt in the operation cache.  If it has changed,
+     * |i| remains zero, and we will clear the cache further down.
+     */
+    if (pk->dirty_cnt == pk->dirty_cnt_copy) {
+        /* If this key is already exported to |keymgmt|, no more to do */
+        i = evp_keymgmt_util_find_operation_cache_index(pk, keymgmt);
+        if (i < OSSL_NELEM(pk->operation_cache)
+            && pk->operation_cache[i].keymgmt != NULL) {
+            void *ret = pk->operation_cache[i].keydata;
 
-        CRYPTO_THREAD_unlock(pk->lock);
-        return ret;
+            CRYPTO_THREAD_unlock(pk->lock);
+            return ret;
+        }
     }
     CRYPTO_THREAD_unlock(pk->lock);
 
@@ -177,12 +184,22 @@ void *evp_keymgmt_util_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
         return ret;
     }
 
+    /*
+     * If the dirty counter changed since last time, then clear the
+     * operation cache.  In that case, we know that |i| is zero.
+     */
+    if (pk->dirty_cnt != pk->dirty_cnt_copy)
+        evp_keymgmt_util_clear_operation_cache(pk, 0);
+
     /* Add the new export to the operation cache */
     if (!evp_keymgmt_util_cache_keydata(pk, i, keymgmt, import_data.keydata)) {
         evp_keymgmt_freedata(keymgmt, import_data.keydata);
         return NULL;
     }
 
+    /* Synchronize the dirty count */
+    pk->dirty_cnt_copy = pk->dirty_cnt;
+
     CRYPTO_THREAD_unlock(pk->lock);
 
     return import_data.keydata;
index 558f3781689649ed75d97e6cb4ebf6bab3d0d8f1..b97a8d16fa2833a482ff7ff3acfb9449f6068e41 100644 (file)
@@ -2228,11 +2228,12 @@ const OSSL_PARAM *EVP_PKEY_settable_params(EVP_PKEY *pkey)
 
 int EVP_PKEY_set_params(EVP_PKEY *pkey, OSSL_PARAM params[])
 {
-    if (pkey == NULL
-        || pkey->keymgmt == NULL
-        || pkey->keydata == NULL)
+    if (pkey == NULL)
         return 0;
-    return evp_keymgmt_set_params(pkey->keymgmt, pkey->keydata, params);
+
+    pkey->dirty_cnt++;
+    return evp_pkey_is_provided(pkey)
+        && evp_keymgmt_set_params(pkey->keymgmt, pkey->keydata, params);
 }
 
 #ifndef FIPS_MODULE