About HSE Key Export

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

About HSE Key Export

1,565 Views
Changhawn
Contributor IV

Hi. 

I am implementing TLS 1.3 on NXP S32K314 Platform.

During the TLS handshake process, a SHARED SECRET is generated for hashing through HSE_GenerateDhSharedSecret() using the server's shared key and private key.

Can I extract the shared secret raw data through the created shared secret key handle?

When I export the shared secret key handle through HSE_ExportKey(), an HSE_SRV_RSP_NOT_ALLOWED error occurs. I need the shared secret key, not the key handle.

If it is not possible in HSE, please guide me on how to do this.

Below is debuggin code about this.

 

static psa_status_t hse_psa_raw_key_agreement(
    psa_algorithm_t alg, psa_key_id_t private_key, 
    const uint8_t *peer_key, size_t peer_key_length,
    uint8_t *output, size_t output_size, size_t *output_length)
{
    int ret = 0;
    uint8_t hseEccCurveId = 0;
    KeymgmtErrCodeT err;
    key_import_param_t key_import_param_shared;
    hseSrvResponse_t srvResponse = HSE_SRV_RSP_GENERAL_ERROR;
    hseKeyHandle_t peerKeyhandle = HSE_INVALID_KEY_HANDLE;
    hseKeyHandle_t sharedSecretKeyHandle = HSE_INVALID_KEY_HANDLE;
    psa_status_t status = PSA_SUCCESS;
hseKeyInfo_t reqKeyInfo = {0};
 
    // Validate input parameters
    if (peer_key == NULL || output == NULL || output_length == NULL)
    {
        return PSA_ERROR_INVALID_ARGUMENT;
    }
    
    // Only support ECDH algorithm for now
    if (alg != PSA_ALG_ECDH)
    {
        return PSA_ERROR_NOT_SUPPORTED;
    }
    
    // Get private key attributes to determine curve
    psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
    status = psa_get_key_attributes(private_key, &key_attributes);
    if (status != PSA_SUCCESS)
    {
        return status;
    }
 
    // PSA Key attribute 
    psa_key_type_t key_type = psa_get_key_type(&key_attributes);
    size_t key_bits = psa_get_key_bits(&key_attributes);
    
    // check the algorithm
    if (!PSA_ALG_IS_ECDH(alg))
    {
        return PSA_ERROR_NOT_SUPPORTED;
    }
    
    hseEccCurveId = HSE_EC_SEC_SECP521R1;
 
    // Import peer Public Key
    ret = hse_import_psa_public_key(peer_key, peer_key_length, 
                                   hseEccCurveId, &peerKeyhandle);
    if (ret != 0)
    {
        return PSA_ERROR_INVALID_ARGUMENT;
    }
 
    memset(&key_import_param_shared, 0x00, sizeof(key_import_param_t));    
    // Allocate the Slot for shared secret Key
 
    key_import_param_shared.key_type = HSE_KEY_TYPE_SHARED_SECRET;
    key_import_param_shared.key_catalog = HSE_KEY_CATALOG_ID_RAM;
    key_import_param_shared.key_param.sym_key_param.size = 521; //key_bits;
 
    //key_import_param_shared.key_flag = HSE_KF_USAGE_SIGN | HSE_KF_USAGE_VERIFY | HSE_KF_USAGE_EXCHANGE | HSE_KF_ACCESS_EXPORTABLE;
    key_import_param_shared.key_flag = HSE_KF_USAGE_EXCHANGE | HSE_KF_ACCESS_EXPORTABLE;
 
    /* key_import_param_shared.key_param.ecc_pubkey_param.size = key_bits / 8; */
    
    err = KeystoreMgmt_FindAllocateSlot(&key_import_param_shared, &sharedSecretKeyHandle);
    if (KEYMGMT_ERR_SUCCESS != err)
    {
        status = PSA_ERROR_HARDWARE_FAILURE;
        goto cleanup;
    }
    
    // Create EDCH Shared secret key handle 
    srvResponse = HSE_GenerateDhSharedSecret(private_key, peerKeyhandle, sharedSecretKeyHandle);
   
    /* Check the response */
switch(srvResponse)
{
case HSE_SRV_RSP_OK:
__printf("\nPrivate keyHandle 0x%02x | Peer KeyHandle : 0x%02x |"
" Shared Secret KeyHandle 0x%02x\r\n", private_key, peerKeyhandle, sharedSecretKeyHandle );
 
/* Copy shared secret key handle to Shared secret mpi z */
//ret = mbedtls_mpi_lset(output, (mbedtls_mpi_sint)sharedSecretKeyHandle );
            /* Copy shared secret key handle to Shared secret mpi z */
 
        srvResponse = HSE_GetKeyInfo(sharedSecretKeyHandle, &reqKeyInfo);
                __printf("keyFlags : 0x%x\r\n", reqKeyInfo.keyFlags);
                __printf("keyBitLen : 0x%x\r\n", reqKeyInfo.keyBitLen);
                __printf("keyCounter : 0x%x\r\n", reqKeyInfo.keyCounter);
                __printf("keyType : 0x%x\r\n", reqKeyInfo.keyType);
                __printf("eccCurveId : 0x%x\r\n", reqKeyInfo.specific.eccCurveId);
 
            if(reqKeyInfo.keyFlags & HSE_KF_ACCESS_EXPORTABLE)
                __printf("%s: target key is exportable\r\n", __func__);
 
            #ifdef GEN2_USING_SRAM_BUFF_FOR_HSE
            {
                uint8_t *output_data;
                output_data = pvPortMalloc(output_size);
                
                if (output_data)
                {
                    ret = HSE_ExportKey(sharedSecretKeyHandle, &reqKeyInfo, output_data, output_size, NULL, 0UL, NULL, 0U);
                    //ret = HSE_ExportEccPubKey(sharedSecretKeyHandle, HSE_EC_SEC_SECP521R1, output_size, output_data);
                
                    if(ret == HSE_SRV_RSP_OK)
                    {
                        memcpy(output, output_data, output_size);
                        *output_length = output_size;
                    }
                    vPortFree(output_data);
                }
                else
                {
                    ret = HSE_SRV_RSP_MEMORY_FAILURE;
                }
            }    
            #else
                ret = HSE_ExportKey(sharedSecretKeyHandle, NULL, output, output_size, NULL, 0UL, NULL, 0U);
            #endif
 
if(ret == HSE_SRV_RSP_OK)
{
                __printf("%s: shared secret output (%d bytes): ", __func__, output_length);
                for (size_t i = 0; i < output_length && i < 16; i++) {
                    __printf("%02x ", output[i]);
                }
                __printf("\n");
 
                *output_length = key_bits / 8;  // Set proper output length
                status = PSA_SUCCESS;
            }
            else
            {
                __printf("%s: Key export failed: 0x%x\r\n", __func__, ret);
                status = PSA_ERROR_INVALID_ARGUMENT;
            }
break;
 
        case HSE_SRV_RSP_INVALID_PARAM:
 
            status = PSA_ERROR_INVALID_ARGUMENT;
break;
 
default:
            status = PSA_ERROR_HARDWARE_FAILURE;
break;
}
 
cleanup:
 
    if (peerKeyhandle != HSE_INVALID_KEY_HANDLE) {
        nxp_hse_ecc_unloadkey(peerKeyhandle);
    }
    
    return status;
}
0 Kudos
Reply
3 Replies

1,534 Views
davidtosenovjan
NXP TechSupport
NXP TechSupport

The error HSE_SRV_RSP_NOT_ALLOWED typically indicates that the operation is not permitted by the HSE firmware, even if the key is marked as exportable. This could be due to:

- HSE policy restrictions on exporting certain key types (e.g., shared secrets).
- Key usage flags not being sufficient or properly configured.
- Security level or lifecycle state of the device not allowing export.

0 Kudos
Reply

1,485 Views
Changhawn
Contributor IV

Dear

In the Below above, when using EXPAND(HSE_KDF_ALGO_HKDF_EXPAND) among HSE's KDF Services(HSE_HKDFExpand), why does HSE return HSE_SRV_RSP_INVALID_ID_PARAM?

Could you give me an example program for the case where the KDF algorithm is HSE_KDF_ALGO_HKDF_EXPAND?

Thank you.

Chang

 

hseSrvResponse_t HSE_HKDFExpand
(
    hseHKDF_ExpandScheme_t *pKdfScheme
)
{
    uint8_t u8MuChannel;
    hseSrvResponse_t srvResponse = HSE_SRV_RSP_GENERAL_ERROR;
 
    /* Get a free channel on u8MuInstance */
    u8MuChannel = Hse_Ip_GetFreeChannel(APP_MU_INSTANCE_U8);
    if(HSE_IP_INVALID_MU_CHANNEL_U8 == u8MuChannel)
    {
        goto exit;
    }
 
    hseSrvDescriptor_t *pHseSrvDesc = &Hse_aSrvDescriptor[u8MuChannel];
    hseKeyDeriveSrv_t* pDeriveKeySrv = &(pHseSrvDesc->hseSrv.keyDeriveReq);
    memset(pHseSrvDesc, 0, sizeof(hseSrvDescriptor_t));
 
    /* Prepare Descriptor */
    pHseSrvDesc->srvId = HSE_SRV_ID_KEY_DERIVE;
    pDeriveKeySrv->kdfAlgo = HSE_KDF_ALGO_HKDF_EXPAND;
    
    /* Set KDF common parameters */
    pDeriveKeySrv->sch.HKDF_Expand.kdfCommon.srcKeyHandle = pKdfScheme->kdfCommon.srcKeyHandle;
    pDeriveKeySrv->sch.HKDF_Expand.kdfCommon.targetKeyHandle = pKdfScheme->kdfCommon.targetKeyHandle;
    pDeriveKeySrv->sch.HKDF_Expand.kdfCommon.keyMatLen = pKdfScheme->kdfCommon.keyMatLen;
    pDeriveKeySrv->sch.HKDF_Expand.kdfCommon.kdfPrf = pKdfScheme->kdfCommon.kdfPrf;
    pDeriveKeySrv->sch.HKDF_Expand.kdfCommon.prfAlgo = pKdfScheme->kdfCommon.prfAlgo;
    pDeriveKeySrv->sch.HKDF_Expand.kdfCommon.infoLength = pKdfScheme->kdfCommon.infoLength;
 
    pDeriveKeySrv->sch.HKDF_Expand.kdfCommon.pInfo = pKdfScheme->kdfCommon.pInfo;
    pDeriveKeySrv->sch.HKDF_Expand.pIvOutput = pKdfScheme->pIvOutput;
 
    /* Build the request to be sent to Hse Ip layer */
    HseIp_aRequest[u8MuChannel].eReqType = HSE_IP_REQTYPE_SYNC;
    HseIp_aRequest[u8MuChannel].u32Timeout = TIMEOUT_TICKS_U32;
 
    /* Send request to HSE */
    srvResponse = Hse_Ip_ServiceRequest(APP_MU_INSTANCE_U8, MU_CH1, &HseIp_aRequest[u8MuChannel], pHseSrvDesc);
 
 
exit:
 
    return srvResponse;
}
 
 
int nxp_hse_tls13_hkdf_expand_label(mbedtls_md_type_t md_type, hseKeyHandle_t secret_key_handle,
    const unsigned char *label, size_t label_len, unsigned char *buf, size_t buf_len)
{
    int ret = 0;
    hseSrvResponse_t hse_result;
    hseHmacPrfAlgo_t       hmacHash;
    // HSE HKDF-Expand parameter setting
    hseHKDF_ExpandScheme_t hkdf_scheme = {0};
 
switch(md_type)
{
case MBEDTLS_MD_SHA256:    /**< The SHA-256 message digest. */
{
hmacHash = HSE_KDF_SHA2_256;
break;
}
case MBEDTLS_MD_SHA384:    /**< The SHA-384 message digest. */
{
hmacHash = HSE_KDF_SHA2_384;
break;
}
case MBEDTLS_MD_SHA512:    /**< The SHA-512 message digest. */
{
hmacHash = HSE_KDF_SHA2_512;
break;
}
default:
{
NXP_HSE_MBEDTLS_SSL_DEBUG_MSG(1, ("HASH algorithm 0x%02x not supported", md_type));
ret = MBEDTLS_ERR_SSL_INVALID_MAC;
goto exit;
}
}
 
// Check if Key handle is valid 
    if (secret_key_handle == HSE_INVALID_KEY_HANDLE) {
        NXP_HSE_MBEDTLS_SSL_DEBUG_MSG(1, ("Invalid source key handle"));
        ret = MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
        goto exit;
    }
 
    if (buf_len == 0 || buf_len > 1024) {
        NXP_HSE_MBEDTLS_SSL_DEBUG_MSG(1, ("Invalid output length: %zu", buf_len));
        ret = MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
        goto exit;
    }
    hkdf_scheme.kdfCommon.srcKeyHandle = secret_key_handle;
    hkdf_scheme.kdfCommon.targetKeyHandle = HSE_INVALID_KEY_HANDLE;
    hkdf_scheme.kdfCommon.keyMatLen = (uint16_t)buf_len;
    hkdf_scheme.kdfCommon.kdfPrf = HSE_KDF_PRF_HMAC;
    hkdf_scheme.kdfCommon.prfAlgo.hmacHash = hmacHash;
    hkdf_scheme.kdfCommon.infoLength = (uint32_t)label_len;
    hkdf_scheme.kdfCommon.pInfo = HSE_PTR_TO_HOST_ADDR(label);
    
    hkdf_scheme.pIvOutput = HSE_PTR_TO_HOST_ADDR(buf);
    
    hse_result = HSE_HKDFExpand(&hkdf_scheme);
    
    if (hse_result != HSE_SRV_RSP_OK) {
NXP_HSE_MBEDTLS_SSL_DEBUG_MSG(1, ("HSE_HKDFExpand is failed 0x%02x", hse_result));
        ret = MBEDTLS_ERR_SSL_HW_ACCEL_FAILED;
goto exit;
    }
 
exit:
 
    return ret;
}
 
 
session_key_exchange()
{
~
 
/* Secret is key handle */
    if (sizeof(secret) == sizeof(hseKeyHandle_t))
    {
        __printf("%s secret is key handle(%s) label_len(%d), ctx_len(%d), buf_len(%d)\r\n", __func__, hkdf_label, label_len, ctx_len, buf_len);
        /* secret should be key handle value */
 
        rc = nxp_hse_tls13_hkdf_expand_label(MBEDTLS_MD_SHA512, secret, hkdf_label, hkdf_label_len, buf, buf_len );
 
    }
    else /* secret is key value */
    {
        __printf("%s secret is key raw data\n", __func__);
        rc = mbedtls_hkdf(mbedtls_md_info_from_type(MBEDTLS_MD_SHA512),
                       NULL, 0,     //ctx, ctx_len,             /* salt */
                       secret, secret_len, //(32 | KEYLOADED_FLAG),
                       hkdf_label, hkdf_label_len,    
                       buf, (int)sizeof(buf));        // output key
    }
 
~
}
0 Kudos
Reply

1,536 Views
Changhawn
Contributor IV

Dear NXP Engineer.

When I get the shared secret, that is, when I get the shared secret handle value,

is there a way to know the shared secret string?


Which key type can export the key? 

HSE_KEY_TYPE_SHARED_SECRET is not possbile.
HSE_KEY_TYPE_HMAC is also not possible.
 

If there is, I think I can export it by deriving and copying the key.
When I do that with hmac, HSE_SRV_RSP_NOT_ALLOWED is printed.

It seems like an important technology or something that HSE should support, but I don't know how to implement it.

thank you.

 

0 Kudos
Reply