Infineon / optiga-trust-x

OPTIGA™ Trust X Software Framework
MIT License
37 stars 19 forks source link

Cannot verify signature using internal certificate #44

Closed boraozgen closed 3 years ago

boraozgen commented 4 years ago

I am trying to verify a signature using a certificate stored in the chip. I keep receiving INVALID_CERTIFICATE_FORMAT (0x29) device error although I tried both the IFX certificate and another certificate & key pair I wrote using the personalization scripts. In the solution reference manual it is mentioned that this code can also mean signature verification failure, but I use the following code snippet where the chip signs the digest itself, so that scenario is eliminated. Am I doing something wrong?

static uint8_t digest [] = {
    0x61, 0xC7, 0xDE, 0xF9, 0x0F, 0xD5, 0xCD, 0x7A, 
    0x8B, 0x7A, 0x36, 0x41, 0x04, 0xE0, 0x0D, 0x82, 
    0x38, 0x46, 0xBF, 0xB7, 0x70, 0xEE, 0xBF, 0x8F, 
    0x40, 0x25, 0x2E, 0x0A, 0x21, 0x42, 0xAF, 0x9C,
}; 

static uint8_t optigaSignature[72];
uint16_t optigaSignatureLen = sizeof(optigaSignature);
ret = optiga_crypt_ecdsa_sign(digest, sizeof(digest), OPTIGA_KEY_STORE_ID_E0F0, optigaSignature, &optigaSignatureLen);
if (ret != OPTIGA_LIB_SUCCESS)
{
    tr_error("optiga_crypt_ecdsa_sign failed with %x", (unsigned int)ret);
    return ret;
}
tr_debug("Generated signature length: %u", optigaSignatureLen);

eOID_d codesignCertificateOid = eDEVICE_PUBKEY_CERT_IFX;
ret = optiga_crypt_ecdsa_verify(digest, sizeof(digest), optigaSignature, optigaSignatureLen, OPTIGA_CRYPT_OID_DATA, &codesignCertificateOid);
if (ret != OPTIGA_LIB_SUCCESS)
{
    tr_error("optiga_crypt_ecdsa_verify failed with %x", (unsigned int)ret);
    return ret;
}
tr_debug("Success!");

And this is the output:

[1175ms][DBG ][optiga_trust_x_lib]: Generated signature length: 68
[1334ms][ERR ][optiga_trust_x_lib]: optiga_crypt_ecdsa_verify failed with 80010029
ayushev commented 4 years ago

The code looks fine, did you by any change changed the certificate stored on the chip eDEVICE_PUBKEY_CERT_IFX this one?

boraozgen commented 4 years ago

I do not remember exactly, but I tried a new slot that I flashed myself, which normally works for a TLS connection (where the public key is provided by host). That does not work either.

BTW I just tried the same procedure with OPTIGA_CRYPT_HOST_DATA and that works. Working code coming in a moment for comparison.

boraozgen commented 4 years ago

This one works. Using the same slot with OPTIGA_CRYPT_OID_DATA fails.

// Read client certificate
ret = optiga_util_read_data(eDEVICE_PUBKEY_CERT_PRJSPC_1, CERT_OFFSET, (uint8_t *)clientCert, (uint16_t *)&clientCertLen);
if (OPTIGA_LIB_SUCCESS != ret)
{
    tr_error("read client certificate failed with %x", (unsigned int)ret);
    return ret;
}

static mbedtls_x509_crt xCertCtx;
memset(&xCertCtx, 0, sizeof(mbedtls_x509_crt));
mbedtls_x509_crt_init(&xCertCtx);
ret = mbedtls_x509_crt_parse(&xCertCtx, (const unsigned char *)clientCert, clientCertLen);
if (0 != ret)
{
    tr_error("mbedtls_x509_crt_parse failed with %x", (unsigned int)ret);
    mbedtls_x509_crt_free(&xCertCtx);
    return ret;
}

static uint8_t optigaSignature[72];
uint16_t optigaSignatureLen = sizeof(optigaSignature);
ret = optiga_crypt_ecdsa_sign(digest, sizeof(digest), OPTIGA_KEY_STORE_ID_E0F1, optigaSignature, &optigaSignatureLen);
if (ret != OPTIGA_LIB_SUCCESS)
{
    tr_error("optiga_crypt_ecdsa_sign failed with %x", (unsigned int)ret);
    return ret;
}
tr_debug("Generated signature length: %u", optigaSignatureLen);

// Add sequence tag since mbed TLS requires it
static uint8_t signatureWithTag[72];
signatureWithTag[0] = 0x30;
signatureWithTag[1] = optigaSignatureLen;
memcpy(signatureWithTag + 2, optigaSignature, optigaSignatureLen);

ret = mbedtls_pk_verify(
    &xCertCtx.pk,
    MBEDTLS_MD_SHA256,
    digest,
    sizeof(digest),
    signatureWithTag,
    optigaSignatureLen + 2);
if (0 != ret)
{
    tr_error("mbedtls_pk_verify failed with %x", (unsigned int)ret);
    mbedtls_x509_crt_free(&xCertCtx);
    return ret;
}

mbedtls_x509_crt_free(&xCertCtx);
ayushev commented 4 years ago

for better understanding can you read out completly the certificate from this OID? You can use this example it should be without any offest. If you would like to write something back to the chip, you can use either the personalize-optiga-trust repo 8the one where you raised the PR), or the python library directly. For the latter you can use this function which does take care of a proper formating. The format is required if you instruct your OPTIGA to verify data using an internally stored certificate.

ayushev commented 4 years ago

But you shouldn't have this error (the one you showed before), if you use an Infineon provisioned certificate. If you used your certificate, you need to add 9 bytes of tags prior the certificate to let optiga properly read it and understand internally.

boraozgen commented 4 years ago

I used the script you mentioned to provision the eDEVICE_PUBKEY_CERT_PRJSPC_1 and OPTIGA_KEY_STORE_ID_E0F1. Therefore it has the said offset. It still gives 0x29 error.

ayushev commented 4 years ago

So let me understand, the snippet you showed originally doesn't give the mentioned error, to get this error you used a user defined certificate, the one you wrote to the trust anchor? Could you please provide if not the whole pubic certificate, but at least first 16 bytes?

boraozgen commented 4 years ago

First snippet does not work with any slot, even with the eDEVICE_PUBKEY_CERT_PRJSPC_1 slot which is provisioned by personalize-optiga-trust repo.

Here is the first 16 bytes of my certificate:

C0:2:6F:0:2:6C:0:2:69:30:82:2:65:30:82

pwiegele commented 4 years ago

@boraozgen have you tried extracting the public key from the certificate and feeding it directly to the verify function?

boraozgen commented 4 years ago

@boraozgen have you tried extracting the public key from the certificate and feeding it directly to the verify function?

Yes, that is what the mbedtls_pk_verify in my latter example does. Mbedtls extracts the public key and the mbedtls port calls the verify function with OPTIGA_CRYPT_HOST_DATA and by feeding the public key:

https://github.com/Infineon/optiga-trust-x/blob/6342c317b31e55f50bfa9598b703878cb348d60d/examples/mbedtls_port/trustx_ecdsa.c#L130-L132

This approach works but the issue is that it does not work using OPTIGA_CRYPT_OID_DATA, i.e. verifying using the stored certificate.

pwiegele commented 4 years ago

Understood, what happens if you write a plain x509 certificate to eDEVICE_PUBKEY_CERT_PRJSPC_2 and reference it when calling the verify function? Does it work for you?

boraozgen commented 4 years ago

What do you mean by "plain"? I use the personalize-optiga-trust scripts to write the certificates. It automatically adds the offset before the certificate. Should try to write without the offset?

Is there a difference between eDEVICE_PUBKEY_CERT_PRJSPC_1 and eDEVICE_PUBKEY_CERT_PRJSPC_2? As I mentioned before, I tried with the slot 1 and it did not work.

pwiegele commented 4 years ago

Should try to write without the offset?

Yes

Is there a difference between eDEVICE_PUBKEY_CERT_PRJSPC_1 and eDEVICE_PUBKEY_CERT_PRJSPC_2? As I mentioned before, I tried with the slot 1 and it did not work

No

boraozgen commented 4 years ago

I will try it out when I have the time.

boraozgen commented 3 years ago

The updated python scripts (https://github.com/infineon/python-optiga-trust) write the certificate without the offset. I used it to provision the chip, but I still could not get the verification from OID working.

ayushev commented 3 years ago

Hello @boraozgen

good to have you back here! In order to use an OID to verify a signature, you need to have there a DER encoded certficate with no tags prepended, the first byte should be 0x30 (Solution Reference Manual page 77). Can you please confirm this?

boraozgen commented 3 years ago

You're right, this time I am using a PEM encoded certificate due to chaining requirements in the firmware. It would explain why it does not work this time. I currently cannot try it out with a DER certificate, therefore I will assume this issue is closed. Thank you for your support.