Parse a ECC private key buffer

2.7k views Asked by At

I am using OPTEE-OS and mbedTLS and want to create a CSR. I am creating my EC key using the Global Platform API:

res = TEE_AllocateTransientObject(
    TEE_TYPE_ECDSA_KEYPAIR,
    DSEC_ECDSA_SHA256_KEY_BITS,
    &key_pair);
if (res != TEE_SUCCESS) {
    return res;
}

Then extract the private key:

res = TEE_GetObjectBufferAttribute(
    key_pair,
    TEE_ATTR_ECC_PRIVATE_VALUE,
    buffer,
    &bufferlen);
if (res != TEE_SUCCESS) {
    return res;
}

Then use mbedTLS to parse this value and create a to create a CSR:

mbedtls_pk_context priv_key;
mbedtls_pk_init(&priv_key);

ret = mbedtls_pk_parse_key(
    &priv_key,
    key,
    size,
    NULL ,
    0
  );

However, the extracted value from TEE_GetObjectBufferAttribute does not have the headers and footpage:

"-----BEGIN EC PRIVATE KEY-----"
"-----END EC PRIVATE KEY-----"

and is only a binary array (not a string). I am currently getting the following error code: "-15616: PK - Invalid key tag or value".

Is there any way to create a mbedtls_pk_context with only the binary value of my private key?

2

There are 2 answers

0
Gilles 'SO- stop being evil' On BEST ANSWER

The parsing functions in Mbed TLS's pk.h expect DER or PEM input. If you can find ready-made code to export a key as DER (or PEM) from OPTEE, that'll be easier (but possibly marginally less efficient). On the other hand, it's easier to do the import manually than to write a DER export function.

You need to call mbedtls_pk_setup() to declare that the context will contain an ECC key, then build the ECC key directly using the interface in ecp.h. Convert the curve designation from the TEE encoding to the Mbed TLS encoding, and calculate the public key from the private value. (Alternatively, you could export TEE_ATTR_ECC_PUBLIC_VALUE and set ec->Q, but that's more work.)

mbedtls_ecp_grp_id grp_id = …; // you need to convert this from the `TEE_ATTR_ECC_CURVE`
mbedtls_pk_context pk;
mbedtls_ecp_keypair *ec = malloc(sizeof(mbedtls_ecp_keypair));
mbedtls_pk_init(&pk);
mbedtls_pk_setup(&pk, mbedtls_pk_info_from_type(MBEDTLS_PK_ECDSA));
mbedtls_ecp_keypair_init(ec);
mbedtls_ecp_group_load(&ec->grp, grp_id);
mbedtls_mpi_read_binary(&ec->d, buffer, bufferlen);
mbedtls_ecp_check_privkey(&ec->grp, &ec->d);
mbedtls_ecp_mul(&ec->grp, &ec->Q, &ec->d, &ec->grp.G, mbedtls_ctr_drbg_random, &ctr_drbg);
pk->pk_ctx = ec;

Completely untested. Error checking omitted. ctr_drbg is a CTR_DRBG instance, used for blinding during the calculation of the public key.

0
Alex D On

To add to the accepted answer here is the code to import Q if there are X and Y available as buffers. And I guess those are available since in order to create an ECDSA key in OPTEE using GlobalPlatform crypto API all 4 attributes (TEE_ATTR_xxx) are required (d, Q(X,Y) and the curve id)

rc = mbedtls_mpi_read_binary(&ec->Q.X, buffer_x, buffer_x_size);
rc = mbedtls_mpi_read_binary(&ec->Q.Y, buffer_y, buffer_y_size);
rc = mbedtls_mpi_lset(&ec->Q.Z, 1);
rc = mbedtls_ecp_check_pubkey(&ec->grp, &ec->Q);