OPTEE-OS+mbedTLS环境下,如何用ECC私钥二进制值创建CSR?
I'm building a CSR using OPTEE-OS and mbedTLS, and I've hit a roadblock with loading the private key. Here's my workflow so far:
- Generated an EC key pair via GlobalPlatform API:
res = TEE_AllocateTransientObject( TEE_TYPE_ECDSA_KEYPAIR, DSEC_ECDSA_SHA256_KEY_BITS, &key_pair); if (res != TEE_SUCCESS) { return res; } - Extracted the raw private key binary value:
res = TEE_GetObjectBufferAttribute( key_pair, TEE_ATTR_ECC_PRIVATE_VALUE, buffer, &bufferlen); if (res != TEE_SUCCESS) { return res; } - Tried parsing this value with mbedTLS to set up a key context:
mbedtls_pk_context priv_key; mbedtls_pk_init(&priv_key); ret = mbedtls_pk_parse_key( &priv_key, key, size, NULL , 0 );
The extracted value is a raw binary array (no PEM headers/footers or ASN.1 formatting), and I'm getting the error: -15616: PK - Invalid key tag or value.
Question: Is it possible to create an mbedtls_pk_context using just this raw private key binary?
Got it, let’s fix this. The problem is that mbedtls_pk_parse_key is designed to handle formatted keys—either PEM-encoded strings or DER-encoded ASN.1 structures. But what you’re pulling from OP-TEE is just the raw EC private key scalar (the big integer that’s the core of the private key), not a properly formatted key blob.
Luckily, you absolutely can create an mbedtls_pk_context from this raw value—you just need to build the EC key structure manually instead of relying on the parser. Here’s how to do it step by step:
Step 1: Set up the mbedTLS PK context for EC
First, initialize the PK context and configure it to use an EC key:
mbedtls_pk_context priv_key; mbedtls_ecp_keypair *ec_key; int ret; mbedtls_pk_init(&priv_key); // Tell the PK context we're using an EC key if ((ret = mbedtls_pk_setup(&priv_key, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY))) != 0) { // Clean up and return error mbedtls_pk_free(&priv_key); return ret; } // Get a pointer to the underlying EC keypair structure ec_key = mbedtls_pk_ec(priv_key);
Step 2: Load the correct EC curve parameters
You used DSEC_ECDSA_SHA256_KEY_BITS in OP-TEE, which corresponds to the secp256r1 (NIST P-256) curve. Load that into the EC group:
if ((ret = mbedtls_ecp_group_load(&ec_key->grp, MBEDTLS_ECP_DP_SECP256R1)) != 0) { mbedtls_pk_free(&priv_key); return ret; }
Step 3: Import the raw private key scalar
Copy the raw binary value from your OP-TEE buffer into the EC key's private value (d). Make sure the buffer length matches the curve's private key size (32 bytes for secp256r1):
// Verify the private key length matches the curve's expected size if (bufferlen != mbedtls_ecp_group_get_size(&ec_key->grp)) { mbedtls_pk_free(&priv_key); return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; } // Read the raw binary into the mbedTLS multi-precision integer (MPI) mbedtls_mpi_read_binary(&ec_key->d, buffer, bufferlen);
Step 4: Compute the public key (required for CSR)
To generate a CSR, you need the public key too. Instead of extracting it from OP-TEE (though you could), you can compute it directly from the private key in mbedTLS:
if ((ret = mbedtls_ecp_mul(&ec_key->grp, &ec_key->Q, &ec_key->d, &ec_key->grp.G, NULL, NULL)) != 0) { mbedtls_pk_free(&priv_key); return ret; }
Step 5: Generate your CSR
Now your priv_key context is fully set up and ready to use with mbedTLS's CSR generation functions. You can use mbedtls_x509write_csr_init, mbedtls_x509write_csr_set_key, and the rest of the CSR writing API to build your certificate signing request.
Quick Notes:
- Double-check that the EC curve in mbedTLS exactly matches what you used in OP-TEE. If you ever use a different curve (like secp384r1), you’ll need to swap out
MBEDTLS_ECP_DP_SECP256R1for the corresponding mbedTLS curve constant. - Always validate the raw key length—mismatched lengths will cause hard-to-debug errors later.
- Don’t forget to call
mbedtls_pk_free(&priv_key)when you’re done to avoid memory leaks.
内容的提问来源于stack exchange,提问作者Stoogy

