Blob Blame History Raw
From df874a780108fa1390e4cb99144b9acb0667f76b Mon Sep 17 00:00:00 2001
From: Ingo Franzki <ifranzki@linux.ibm.com>
Date: Fri, 4 Nov 2022 11:33:50 +0100
Subject: [PATCH 33/34] EP11: Supply CKA_PUBLIC_KEY_INFO with
 CKM_IBM_BTC_DERIVE of private key

When deriving a private EC key with the CKM_IBM_BTC_DERIVE mechanism,
also supply the SPKI in the CKA_PUBLIC_KEY_INFO attribute.

To get the SPKI, use m_GetAttributeValue() with CKA_PUBLIC_KEY_INFO.
On newer EP11 host libraries this returns the SPKI of the corresponding
public key of the private key blob. In case the EP11 host library fails
to get the SPKI from the blob, ignore and do not supply an SPKI.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
---
 usr/lib/ep11_stdll/ep11_specific.c | 266 +++++++++++++++++++++++--------------
 1 file changed, 168 insertions(+), 98 deletions(-)

diff --git a/usr/lib/ep11_stdll/ep11_specific.c b/usr/lib/ep11_stdll/ep11_specific.c
index 9efce053..d4ece223 100644
--- a/usr/lib/ep11_stdll/ep11_specific.c
+++ b/usr/lib/ep11_stdll/ep11_specific.c
@@ -5316,7 +5316,148 @@ static CK_RV ep11tok_kyber_mech_post_process(STDLL_TokData_t *tokdata,
     return CKR_OK;
 }
 
-CK_RV ep11tok_derive_key(STDLL_TokData_t * tokdata, SESSION * session,
+static CK_RV ep11tok_btc_mech_pre_process(STDLL_TokData_t *tokdata,
+                                          OBJECT *key_obj,
+                                          CK_ATTRIBUTE **new_attrs,
+                                          CK_ULONG *new_attrs_len)
+{
+    CK_ATTRIBUTE *ec_params;
+    CK_ULONG i, privlen;
+    CK_RV rc;
+
+    UNUSED(tokdata);
+
+    /*
+     * CKM_IBM_BTC_DERIVE requires CKA_VALUE_LEN to specify the byte length
+     * of the to be derived EC key. CKA_VALUE_LEN is dependent on the
+     * curve used.
+     * CKA_VALUE_LEN can not be already in the user supplied template,
+     * since this is not allowed by the key template check routines.
+     */
+    rc = template_attribute_get_non_empty(key_obj->template, CKA_EC_PARAMS,
+                                          &ec_params);
+    if (rc != CKR_OK) {
+        TRACE_ERROR("CKA_EC_PARAMS is required in derive template\n");
+        return rc;
+    }
+
+    for (i = 0; i < NUMEC; i++) {
+        if (der_ec_supported[i].data_size == ec_params->ulValueLen &&
+            memcmp(ec_params->pValue, der_ec_supported[i].data,
+                   ec_params->ulValueLen) == 0) {
+            privlen = (der_ec_supported[i].len_bits + 7) / 8;
+            rc = add_to_attribute_array(new_attrs, new_attrs_len,
+                                        CKA_VALUE_LEN,
+                                        (CK_BYTE_PTR)&privlen,
+                                        sizeof(privlen));
+            if (rc != CKR_OK) {
+                TRACE_ERROR("Adding attribute failed type=CKA_VALUE_LEN "
+                            "rc=0x%lx\n", rc);
+                return rc;
+            }
+            break;
+        }
+    }
+
+    return CKR_OK;
+}
+
+static CK_RV ep11tok_btc_mech_post_process(STDLL_TokData_t *tokdata,
+                                           SESSION *session, CK_MECHANISM *mech,
+                                           CK_ULONG class, CK_ULONG ktype,
+                                           OBJECT *key_obj,
+                                           CK_BYTE *blob, CK_ULONG bloblen,
+                                           CK_BYTE *csum, CK_ULONG cslen)
+{
+    CK_IBM_BTC_DERIVE_PARAMS *btc_params = NULL;
+    CK_BYTE *spki = NULL;
+    CK_ULONG spki_length = 0;
+    CK_BYTE buf[MAX_BLOBSIZE];
+    CK_ATTRIBUTE get_attr[1] = {{ CKA_PUBLIC_KEY_INFO, &buf, sizeof(buf) }};
+    CK_ATTRIBUTE *spki_attr = NULL;
+    CK_BBOOL allocated = FALSE;
+    CK_RV rc = CKR_OK;
+
+    if (mech->ulParameterLen != sizeof(CK_IBM_BTC_DERIVE_PARAMS) ||
+        mech->pParameter == NULL) {
+        TRACE_ERROR("%s Param NULL or len for %s wrong: %lu\n",
+                    __func__, ep11_get_ckm(tokdata, mech->mechanism),
+                    mech->ulParameterLen);
+        return CKR_MECHANISM_PARAM_INVALID;
+    }
+
+    btc_params = (CK_IBM_BTC_DERIVE_PARAMS *)mech->pParameter;
+
+    if (btc_params != NULL && btc_params->pChainCode != NULL &&
+        cslen >= CK_IBM_BTC_CHAINCODE_LENGTH) {
+        memcpy(btc_params->pChainCode, csum, CK_IBM_BTC_CHAINCODE_LENGTH);
+        btc_params->ulChainCodeLen = CK_IBM_BTC_CHAINCODE_LENGTH;
+    }
+
+    switch (class) {
+    case CKO_PUBLIC_KEY:
+        /* Derived blob is an SPKI, extract public EC key attributes */
+        rc = ecdsa_priv_unwrap_get_data(key_obj->template, blob, bloblen);
+        if (rc != CKR_OK) {
+            TRACE_ERROR("%s ecdsa_priv_unwrap_get_data failed with "
+                        "rc=0x%lx\n", __func__, rc);
+            return rc;
+        }
+
+        /* Extract the SPKI and add CKA_PUBLIC_KEY_INFO to key */
+        rc = publ_key_get_spki(key_obj->template, ktype, FALSE,
+                               &spki, &spki_length);
+        if (rc != CKR_OK) {
+            TRACE_DEVEL("publ_key_get_spki failed\n");
+            return rc;
+        }
+
+        allocated = TRUE;
+        break;
+
+    case CKO_PRIVATE_KEY:
+        RETRY_START(rc, tokdata)
+            rc = dll_m_GetAttributeValue(blob, bloblen, get_attr, 1,
+                                         target_info->target);
+        RETRY_END(rc, tokdata, session)
+
+        /* Only newer EP11 libs support this, ignore if error */
+        if (rc != CKR_OK)
+            return CKR_OK;
+
+        spki = get_attr[0].pValue;
+        spki_length = get_attr[0].ulValueLen;
+        break;
+
+    default:
+        /* do nothing */
+        return CKR_OK;
+    }
+
+    rc = build_attribute(CKA_PUBLIC_KEY_INFO, spki, spki_length,
+                         &spki_attr);
+    if (rc != CKR_OK) {
+        TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n",
+                    __func__, rc);
+        goto out;
+    }
+
+    rc = template_update_attribute(key_obj->template, spki_attr);
+    if (rc != CKR_OK) {
+        TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n",
+                    __func__, rc);
+        free(spki_attr);
+        goto out;
+    }
+
+out:
+    if (allocated && spki != NULL)
+        free(spki);
+
+    return rc;
+}
+
+CK_RV ep11tok_derive_key(STDLL_TokData_t *tokdata, SESSION *session,
                          CK_MECHANISM_PTR mech, CK_OBJECT_HANDLE hBaseKey,
                          CK_OBJECT_HANDLE_PTR handle, CK_ATTRIBUTE_PTR attrs,
                          CK_ULONG attrs_len)
@@ -5345,17 +5486,12 @@ CK_RV ep11tok_derive_key(STDLL_TokData_t * tokdata, SESSION * session,
     CK_ULONG ecpoint_len, field_len, key_len = 0;
     CK_ATTRIBUTE *new_attrs1 = NULL, *new_attrs2 = NULL;
     CK_ULONG new_attrs1_len = 0, new_attrs2_len = 0;
-    CK_ULONG privlen, i;
+    CK_ULONG privlen;
     int curve_type;
     CK_BBOOL allocated = FALSE;
     ep11_target_info_t* target_info;
     CK_ULONG used_firmware_API_version;
     CK_MECHANISM_PTR mech_orig = mech;
-    CK_ATTRIBUTE *ec_params;
-    CK_IBM_BTC_DERIVE_PARAMS *btc_params = NULL;
-    CK_BYTE *spki = NULL;
-    CK_ULONG spki_length = 0;
-    CK_ATTRIBUTE *spki_attr = NULL;
     struct EP11_KYBER_MECH mech_ep11;
     OBJECT *kyber_secret_obj = NULL;
 
@@ -5476,18 +5612,6 @@ CK_RV ep11tok_derive_key(STDLL_TokData_t * tokdata, SESSION * session,
         }
     }
 
-    if (mech->mechanism == CKM_IBM_BTC_DERIVE) {
-        if (mech->ulParameterLen != sizeof(CK_IBM_BTC_DERIVE_PARAMS) ||
-            mech->pParameter == NULL) {
-            TRACE_ERROR("%s Param NULL or len for %s wrong: %lu\n",
-                        __func__, ep11_get_ckm(tokdata, mech->mechanism),
-                        mech->ulParameterLen);
-            return CKR_MECHANISM_PARAM_INVALID;
-        }
-
-        btc_params = (CK_IBM_BTC_DERIVE_PARAMS *)mech->pParameter;
-    }
-
     rc = h_opaque_2_blob(tokdata, hBaseKey, &keyblob, &keyblobsize,
                          &base_key_obj, READ_LOCK);
     if (rc != CKR_OK) {
@@ -5605,46 +5729,24 @@ CK_RV ep11tok_derive_key(STDLL_TokData_t * tokdata, SESSION * session,
         goto error;
     }
 
-    if (mech->mechanism == CKM_IBM_BTC_DERIVE) {
-        /*
-         * CKM_IBM_BTC_DERIVE requires CKA_VALUE_LEN to specify the byte length
-         * of the to be derived EC key. CKA_VALUE_LEN is dependent on the
-         * curve used.
-         * CKA_VALUE_LEN can not be already in the user supplied template,
-         * since this is not allowed by the key template check routines.
-         */
-        rc = template_attribute_get_non_empty(key_obj->template, CKA_EC_PARAMS,
-                                              &ec_params);
-        if (rc != CKR_OK) {
-            TRACE_ERROR("CKA_EC_PARAMS is required in derive template\n");
+    switch (mech->mechanism) {
+    case CKM_IBM_BTC_DERIVE:
+        rc = ep11tok_btc_mech_pre_process(tokdata, key_obj, &new_attrs2,
+                                          &new_attrs2_len);
+        if (rc != CKR_OK)
             goto error;
-        }
-
-        for (i = 0; i < NUMEC; i++) {
-            if (der_ec_supported[i].data_size == ec_params->ulValueLen &&
-                memcmp(ec_params->pValue, der_ec_supported[i].data,
-                       ec_params->ulValueLen) == 0) {
-                privlen = (der_ec_supported[i].len_bits + 7) / 8;
-                rc = add_to_attribute_array(&new_attrs2, &new_attrs2_len,
-                                            CKA_VALUE_LEN,
-                                            (CK_BYTE_PTR)&privlen,
-                                            sizeof(privlen));
-                if (rc != CKR_OK) {
-                    TRACE_ERROR("Adding attribute failed type=CKA_VALUE_LEN "
-                                "rc=0x%lx\n", rc);
-                    goto error;
-                }
-                break;
-            }
-        }
-    }
+        break;
 
-    if (mech->mechanism == CKM_IBM_KYBER) {
+    case CKM_IBM_KYBER:
         rc = ep11tok_kyber_mech_pre_process(tokdata, mech, &mech_ep11,
                                             &kyber_secret_obj);
         if (rc != CKR_OK)
             goto error;
         mech = &mech_ep11.mech;
+        break;
+
+    default:
+        break;
     }
 
     trace_attributes(__func__, "Derive:", new_attrs2, new_attrs2_len);
@@ -5695,47 +5797,6 @@ CK_RV ep11tok_derive_key(STDLL_TokData_t * tokdata, SESSION * session,
     }
     opaque_attr = NULL;
 
-    if (mech->mechanism == CKM_IBM_BTC_DERIVE &&
-        btc_params != NULL && btc_params->pChainCode != NULL &&
-        cslen >= CK_IBM_BTC_CHAINCODE_LENGTH) {
-        memcpy(btc_params->pChainCode, csum, CK_IBM_BTC_CHAINCODE_LENGTH);
-        btc_params->ulChainCodeLen = CK_IBM_BTC_CHAINCODE_LENGTH;
-    }
-
-    if (mech->mechanism == CKM_IBM_BTC_DERIVE && class == CKO_PUBLIC_KEY) {
-        /* Derived blob is an SPKI, extract public EC key attributes */
-        rc = ecdsa_priv_unwrap_get_data(key_obj->template,
-                                        newblob, newblobsize);
-        if (rc != CKR_OK) {
-            TRACE_ERROR("%s ecdsa_priv_unwrap_get_data failed with rc=0x%lx\n",
-                        __func__, rc);
-            goto error;
-        }
-
-        /* Extract the SPKI and add CKA_PUBLIC_KEY_INFO to key */
-        rc = publ_key_get_spki(key_obj->template, ktype, FALSE,
-                               &spki, &spki_length);
-        if (rc != CKR_OK) {
-            TRACE_DEVEL("publ_key_get_spki failed\n");
-            goto error;
-        }
-
-        rc = build_attribute(CKA_PUBLIC_KEY_INFO, spki, spki_length, &spki_attr);
-        if (rc != CKR_OK) {
-            TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n",
-                        __func__, rc);
-            goto error;
-        }
-
-        rc = template_update_attribute(key_obj->template, spki_attr);
-        if (rc != CKR_OK) {
-            TRACE_ERROR("%s template_update_attribute failed with "
-                        "rc=0x%lx\n", __func__, rc);
-            goto error;
-        }
-        spki_attr = NULL;
-    }
-
     if (class == CKO_SECRET_KEY || class == CKO_PRIVATE_KEY) {
         rc = update_ep11_attrs_from_blob(tokdata, session, key_obj->template);
         if (rc != CKR_OK) {
@@ -5745,10 +5806,23 @@ CK_RV ep11tok_derive_key(STDLL_TokData_t * tokdata, SESSION * session,
         }
     }
 
-    if (mech->mechanism == CKM_IBM_KYBER) {
+    switch (mech->mechanism) {
+    case CKM_IBM_BTC_DERIVE:
+        rc = ep11tok_btc_mech_post_process(tokdata, session, mech, class, ktype,
+                                           key_obj, newblob, newblobsize,
+                                           csum, cslen);
+        if (rc != CKR_OK)
+            goto error;
+        break;
+
+    case CKM_IBM_KYBER:
         rc = ep11tok_kyber_mech_post_process(tokdata, mech_orig, csum, cslen);
         if (rc != CKR_OK)
             goto error;
+        break;
+
+    default:
+        break;
     }
 
     if (class == CKO_SECRET_KEY && cslen >= EP11_CSUMSIZE) {
@@ -5792,10 +5866,6 @@ error:
         free(opaque_attr);
     if (chk_attr != NULL)
         free(chk_attr);
-    if (spki_attr != NULL)
-        free(spki_attr);
-    if (spki != NULL)
-        free(spki);
     if (new_attrs)
         free_attribute_array(new_attrs, new_attrs_len);
     if (new_attrs1)
-- 
2.16.2.windows.1