Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kernel Panic with ECDSA P256: Signing Works, Not Verification #1378

Closed
cgshep opened this issue Mar 2, 2017 · 21 comments
Closed

Kernel Panic with ECDSA P256: Signing Works, Not Verification #1378

cgshep opened this issue Mar 2, 2017 · 21 comments

Comments

@cgshep
Copy link

cgshep commented Mar 2, 2017

I'm having issues with verifying signatures using ECDSA and the P256 algorithm. Signing works fine, yielding a digest/message of length 32 bytes (signature of length 64), but verifying the same digest and signature throws this kernel panic:

DEBUG:   USER-TA:sign:775: Successfully signed using ECDSA                      
DEBUG:   USER-TA: tee_user_mem_alloc:343: Allocate: link:[0x40018be0], buf:[0x4]
DEBUG:   USER-TA:sign:793: msg_len: 32                                          
DEBUG:   USER-TA:sign:794: result_len: 64                                       
ERROR:   USER-TA: Panic 0xffff0006                                              
ERROR:   TEE-CORE: TA panicked with code 0xffff0006 usr_sp 0x40000fb0 usr_lr 0xd
DEBUG:   [0x0] TEE-CORE:user_ta_enter:590: tee_user_ta_enter: TA panicked with 6
DEBUG:   [0x0] TEE-CORE:tee_ta_invoke_command:557:   => Error: ffff3024 of 3    
hello_world: TEEC_InvokeCommand failed with code 0xffff3024 origin 0x3          
DEBUG:   [0x0] TEE-CORE:tee_ta_close_session:318: tee_ta_close_session(0x3f05b4)
DEBUG:   [0x0] TEE-CORE:tee_ta_close_session:337:    ... Destroy session        
DEBUG:   [0x0] TEE-CORE:tee_ta_close_session:361:    ... Destroy TA ctx   

The offending function can be found below. Is this an OP-TEE issue or one of mine?

Thanks,
Carlton

#define CURVE_BITS 256
#define CURVE_BYTES 32

uint8_t ecdsa_private[CURVE_BYTES] = {0xcf, 0xbe, 0x8e, 0x67,
				      0x63, 0x34, 0x00, 0xa9,
				      0x8e, 0x14, 0x4c, 0x46,
				      0x41, 0x54, 0x25, 0x40,
				      0xbc, 0x96, 0x47, 0x86,
				      0x64, 0x0c, 0x7b, 0xc6,
				      0x94, 0xff, 0xea, 0xbc,
				      0x6b, 0xcd, 0x2a, 0x35};

uint8_t ecdsa_public_x[CURVE_BYTES] = {0x33, 0x96, 0xbe, 0xbc,
				       0xa1, 0x38, 0x72, 0x66,
				       0xf8, 0x3e, 0xa8, 0x7a,
				       0xb4, 0x9c, 0x6a, 0x2b,
				       0xee, 0x84, 0xab, 0x9f,
				       0x64, 0xc4, 0x5e, 0xf4,
				       0x92, 0x9d, 0xbc, 0x20,
				       0xd2, 0xe9, 0x0d, 0x23};

uint8_t ecdsa_public_y[CURVE_BYTES] = {0xda, 0x3c, 0xb1, 0x98,
				       0x6b, 0x84, 0x45, 0xc8,
				       0xdf, 0xe1, 0x16, 0xd7,
				       0xba, 0x03, 0xfc, 0x5e,
				       0x68, 0x33, 0xb5, 0x17,
				       0xbc, 0x1f, 0x5c, 0x6e,
				       0x56, 0xad, 0x0c, 0x02,
				       0xe0, 0xde, 0x7f, 0xed};

TEE_ObjectHandle ecdsa_key_pair = NULL;

static TEE_Result sign(uint32_t param_types,
		       TEE_Param params[4])
{
    TEE_OperationHandle operation = NULL;
    TEE_OperationHandle operation1 = NULL;
    TEE_Result res = TEE_ERROR_GENERIC;
    TEE_Attribute attrs[4];

    void *msg = NULL;
    uint32_t msg_len = 0;
    void *result = NULL;
    uint32_t result_len = 0;
    uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
					       TEE_PARAM_TYPE_MEMREF_OUTPUT,
					       TEE_PARAM_TYPE_NONE,
					       TEE_PARAM_TYPE_NONE);
    if (param_types != exp_param_types)
	return TEE_ERROR_BAD_PARAMETERS;

    msg = params[0].memref.buffer;
    msg_len = params[0].memref.size;
    result = params[1].memref.buffer;
    result_len = params[1].memref.size;
    
    /* Reset result */
    memset(result, 0, result_len);

    res = TEE_AllocateOperation(&operation, TEE_ALG_ECDSA_P256,
				TEE_MODE_SIGN, CURVE_BITS);
    if (res != TEE_SUCCESS) {
	DMSG("TEE_AllocateOperation failed! res: 0x%x", res);
	return res;
    }

    /* Allocate ECDSA key if necessary*/
    if (ecdsa_key_pair == NULL) {
	res = TEE_AllocateTransientObject(TEE_TYPE_ECDSA_KEYPAIR, CURVE_BITS, &ecdsa_key_pair);
	if (res != TEE_SUCCESS) {
	    return res;
	}

	TEE_InitRefAttribute(&attrs[0],
			     TEE_ATTR_ECC_PRIVATE_VALUE,
			     ecdsa_private,
			     CURVE_BITS);
	TEE_InitRefAttribute(&attrs[1],
			     TEE_ATTR_ECC_PUBLIC_VALUE_X,
			     ecdsa_public_x,
			     CURVE_BITS);
	TEE_InitRefAttribute(&attrs[2],
			     TEE_ATTR_ECC_PUBLIC_VALUE_Y,
			     ecdsa_public_y,
			     CURVE_BITS);
	TEE_InitValueAttribute(&attrs[3],
			     TEE_ATTR_ECC_CURVE,
			     TEE_ECC_CURVE_NIST_P256,
			     CURVE_BITS);

	res = TEE_PopulateTransientObject(ecdsa_key_pair, attrs, 4);
    
	if (res != TEE_SUCCESS) {
	    return res;
	}
    }

    res = TEE_SetOperationKey(operation, ecdsa_key_pair);
    if (res != TEE_SUCCESS) {
        return res;
    }

    res = TEE_AsymmetricSignDigest(operation, NULL, 0,
				   msg, msg_len,
				   result, &result_len);
    if (res != TEE_SUCCESS) {
        return res;
    }

    DMSG("Successfully signed using ECDSA");


    // New operation
    res = TEE_AllocateOperation(&operation1, TEE_ALG_ECDSA_P256,
				TEE_MODE_VERIFY, CURVE_BITS);

    if (res != TEE_SUCCESS) {
	DMSG("TEE_AllocateOperation failed! res: 0x%x", res);
	return res;
    }

    res = TEE_SetOperationKey(operation1, ecdsa_key_pair);

    if (res != TEE_SUCCESS) {
	DMSG("TEE_AllocateOperation failed! res: 0x%x", res);
	return res;
    }
    
    DMSG("msg_len: %d", msg_len);
    DMSG("result_len: %d", result_len);
    res = TEE_AsymmetricVerifyDigest(operation1, NULL, 0,
				     msg, msg_len,
				     result, result_len);
    
    if (res != TEE_SUCCESS) {
	DMSG("TEE_Verification failed! res: 0x%x", res);
	return res;
    }

    return res;
}

EDIT: I'm using the Hikey downstream.

@jforissier
Copy link
Contributor

Hi Carlton,

The message "Panic 0xffff0006" indicates that the Trusted Application was killed by the TEE, due to bad parameters (somewhere). So I see two possibilities:

  1. Either the parameters given to TEE_AsymmetricVerifyDigest() are invalid (unexpected msg_len, bad operation...), which would be an application issue ;
  2. Or, there's a bug inside OP-TEE and an intermediate operation fails, resulting in this "bad parameter" code. This, you could probably trace using DMSG(), or you may run your app in QEMU in which case you can attach a debugger and step into the TEE Core.

@ghost
Copy link

ghost commented Oct 6, 2017

We are closing this issue/question, why?

  • We believe the question has been answered.
  • Quite often when we have answered the questions, the issuer forget to close the issue which results in many open issues for us which makes it hard to keep track of the ones actually waiting for an answer.
  • In some cases we ask follow-up questions, but do not hear back from the one creating the issue.

If you however feel that you have additional questions or still thinks this is an issue, then please feel free to re-open the issue again. When closing issues we will only show this entire message once.

// OP-TEE admins

@ghost ghost closed this as completed Oct 6, 2017
@akbarsaleemt
Copy link

can we write code in C++ for application for compile which toolchain we need

@jbech-linaro
Copy link
Contributor

@akbarsaleemt , please see #1708 and https://github.com/OP-TEE/optee_website/tree/master/faq#can-i-use-c-libraries-in-op-tee regarding C++ support in OP-TEE (which is the source for the official optee.org page.

@Parradox27
Copy link

Parradox27 commented Jul 16, 2020

Hello,
I have been attempting to create and verify messages (digests), however I am having the same issue as the original author.

I created a simple function that generates a new key pair, signs a fixed message and attempts to verify it, whereas the kernel keeps panicking. Here's the code snippet:

    static TEE_Result gen_key(uint32_t param_types, TEE_Param params[4])
    {
        (void)&params;
	const uint32_t exp_param_types =
		TEE_PARAM_TYPES(TEE_PARAM_TYPE_NONE,
				TEE_PARAM_TYPE_NONE,
				TEE_PARAM_TYPE_NONE,
				TEE_PARAM_TYPE_NONE);
	TEE_ObjectHandle object;
	TEE_Result res;
	
	if (param_types != exp_param_types)
		return TEE_ERROR_BAD_PARAMETERS;

	printf("Checking if private key exists\n");

	res = TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE,
					"privkey", 7,
					TEE_DATA_FLAG_ACCESS_READ |
					TEE_DATA_FLAG_SHARE_READ,
					&object);
	if (res != TEE_SUCCESS) 
	{

		printf("Creating key\n");

		TEE_ObjectHandle ecdsa_keypair = (TEE_ObjectHandle)NULL;
		TEE_Attribute ecdsa_attrs[1];
		uint32_t curve = TEE_ECC_CURVE_NIST_P256;
		uint32_t keysize = 256;
	
		printf("Setting parameters\n");

		ecdsa_attrs[0].attributeID = TEE_ATTR_ECC_CURVE;
		ecdsa_attrs[0].content.value.a = curve;
		ecdsa_attrs[0].content.value.b = 0;

		printf("Allocating object memory\n");

		res = TEE_AllocateTransientObject(TEE_TYPE_ECDSA_KEYPAIR, keysize, &ecdsa_keypair);
		if (res != TEE_SUCCESS) 
		{
			EMSG("Failed to alloc transient object handle : 0x%x", res);
			TEE_FreeTransientObject(ecdsa_keypair);
			return res;
		}

		printf("Generating keys\n");

		res = TEE_GenerateKey(ecdsa_keypair, keysize, ecdsa_attrs, 1);
		if (res != TEE_SUCCESS) 
		{
			EMSG("Generate key failure : 0x%x", res);
			TEE_FreeTransientObject(ecdsa_keypair);
			return res;
		}

		printf("Keys generated, attempting to create a signature\n");

		TEE_OperationHandle operation = NULL;
		const char *msg = "2CF24DBA5FB0A30E26E83B2AC5B9E29E1B161E5C1FA7425E73043362938B9824";
	        uint32_t msg_len = 32;
	        char result[64] = {0};
	        uint32_t result_len = 64;


		printf("Allocating signing operation\n");

		res = TEE_AllocateOperation(&operation, TEE_ALG_ECDSA_P256,
					TEE_MODE_SIGN, keysize);
	        if (res != TEE_SUCCESS) 
	        {
		   	EMSG("TEE_AllocateOperation failed! res: 0x%x", res);
			return res;
	        }

	        printf("Setting key for signing\n");

	        res = TEE_SetOperationKey(operation, ecdsa_keypair);
	        if (res != TEE_SUCCESS) 
	        {
	    	    EMSG("Failed setting operation key");
	            return res;
	        }

	        printf("Signing..\n");

	        res = TEE_AsymmetricSignDigest(operation, NULL, 0,
					   msg, msg_len,
					   result, &result_len);
	        if (res != TEE_SUCCESS) 
	        {
	        	EMSG("Failed signing operation");
	                return res;
	        }

	        TEE_FreeOperation(operation);

	        printf("Allocating verification operation\n");

		res = TEE_AllocateOperation(&operation, TEE_ALG_ECDSA_P256,
					TEE_MODE_VERIFY, keysize);
	        if (res != TEE_SUCCESS) 
	        {
			EMSG("TEE_AllocateOperation failed! res: 0x%x", res);
			return res;
	        }

	        printf("Setting key for verification\n");

	        res = TEE_SetOperationKey(operation, ecdsa_keypair);
	        if (res != TEE_SUCCESS) 
	        {
	    	        EMSG("Failed setting operation key");
	                return res;
	        }

	        printf("Verifying..\n");
	        res = TEE_AsymmetricVerifyDigest(operation, NULL, 0,
					   msg, msg_len,
					   result, result_len);
	        if (res != TEE_SUCCESS) 
	        {
	                EMSG("Failed verification operation");
	                return res;
	        }


		TEE_FreeTransientObject(ecdsa_keypair);
		TEE_FreeOperation(operation);
         }
       return TEE_SUCCESS;
   }

I am not sure what I might be missing, any help would be greatly appreciated.

@jforissier
Copy link
Contributor

@Parradox27 please post the panic message. Use ./optee_os/scripts/symbolize.py -d optee_os/out/arm/core -d <path to your TA ELF file> to add debug information to the stack dump.

@Parradox27
Copy link

Parradox27 commented Jul 17, 2020

@jforissier The panic message is:

E/TC:? 0
E/TC:? 0 TA panicked with code 0xffff0006
E/LD: Status of TA f4e750bb-1437-4fbf-8785-8d3580c34994
E/LD: arch: arm
E/LD: region 0: va 0x40002000 pa 0x00000000 size 0x002000 flags rw-s (ldelf)
E/LD: region 1: va 0x40004000 pa 0x00000000 size 0x005000 flags r-xs (ldelf)
E/LD: region 2: va 0x40009000 pa 0x00000000 size 0x001000 flags rw-s (ldelf)
E/LD: region 3: va 0x4000a000 pa 0x00000000 size 0x003000 flags rw-s (ldelf)
E/LD: region 4: va 0x4000d000 pa 0x00000000 size 0x001000 flags r--s
E/LD: region 5: va 0x4000e000 pa 0x00000000 size 0x001000 flags rw-s (stack)
E/LD: region 6: va 0x4002b000 pa 0x00001000 size 0x00b000 flags r-xs [0]
E/LD: region 7: va 0x40036000 pa 0x0000c000 size 0x00c000 flags rw-s [0
E/LD: [0] f4e750bb-1437-4fbf-8785-8d3580c34994 @ 0x4006d000

@jforissier
Copy link
Contributor

No call stack?

@Parradox27
Copy link

Parradox27 commented Jul 17, 2020

Except for my printf messages, this is everything I get.

EDIT: Maybe it is good to mention that I am using an STM32MP1 that has op-tee in its distribution package, if it makes any difference.

@jforissier
Copy link
Contributor

OK, what is the OP-TEE version?

@Parradox27
Copy link

The distribution package recipe for optee states version 3.9.0.r1.

@Parradox27
Copy link

Parradox27 commented Jul 18, 2020

@jforissier If the API does not work, is it possible to use a 3rd party library as an alternative? I would like to use OpenSSL within the TA, but I am unsure how to build the library and link it during compilation. I already have some code ready and working on the Linux side, but I would like to transfer it to the secure environment and do the signing there, if that is possible.

EDIT: I extracted the X and Y coordinates from the key using function TEE_GetObjectBufferAttribute and passed both values to the host application. On there I used OpenSSL to create a new key structure using these coordinates with function EC_KEY_set_public_key_affine_coordinates, however the function kept failing. In the documentation it is stated that this function performs some sanity checks to see if the key is valid, which raises the question whether the key generator in OP-TEE is generating correct keys to begin with? It could possibly explain the verification issues as well.

@jforissier
Copy link
Contributor

jforissier commented Jul 18, 2020

I tried you code with QEMU (pasted in hello_word_ta.c) and it seems it worked fine:

D/LD:  ldelf:169 ELF (8aaaf200-2450-11e4-abe2-0002a5d5c51b) at 0x17f000
D/TC:? 0 tee_ta_close_session:499 csess 0x1bda08d0 id 1
D/TC:? 0 tee_ta_close_session:518 Destroy session
Checking if private key exists
Creating key
Setting parameters
Allocating object memory
Generating keys
Keys generated, attempting to create a signature
Allocating signing operation
Setting key for signing
Signing..
Allocating verification operation
Setting key for verification
Verifying..
D/TC:? 0 tee_ta_close_session:499 csess 0x1bda0cd8 id 1

OP-TEE master branch (at commit 1d205e2).

Same thing with QEMUv8 (64 bits).

@Parradox27
Copy link

Seems like there was some error on my side, now it finally works, thanks for your help. Regarding my last question though, is it possible to use OpenSSL standard C library in the OP-TEE?

@jforissier
Copy link
Contributor

OK.
Using OpenSSL is certainly possible but not completely straightforward, because if I remember correctly, it has quite a lot of dependencies on libc functions that may not be available in OP-TEE's libutils.

@jforissier
Copy link
Contributor

One more thing: TA can use MBedTLS too, it is contained in the SDK.

@Parradox27
Copy link

Thanks for your help, the procedure is now implemented via API. However, it is a shame that OP-TEE is capable of generating only a single signature per second, whereas on Linux side with OpenSSL I am getting around 500 per second depending on data size, and OP-TEE does not even need to hash. Is this performance expected or is there something wrong?

@jforissier
Copy link
Contributor

With OP-TEE there is some overhead as Normal World invokes Secure World (EL0 - EL1 - (EL3) - SEL1 - SEL0 and back), but a 500x performance hit doesn't seem right at all.

@Parradox27
Copy link

Is there anything to do about it, to check whether it could be improved, if there is a problem that slows it down?

@jforissier
Copy link
Contributor

jforissier commented Jul 21, 2020

Does OpenSSL benefit from hardware acceleration on your platform perhaps?
You could try profiling the code as explained in https://optee.readthedocs.io/en/latest/debug/benchmark.html.

@Parradox27
Copy link

Yes, OpenSSL does benefit from hardware acceleration of hashing starting from a certain size of message size, but hashing is done on the client side of the application anyway. Signing itself is on Linux side done in software and the performance depends purely on the hashing speed, whereas hashing does not affect OP-TEE as it signs a hash that is already created, yet it manages only a single signature per second.

Thank you for your help anyway @jforissier, it is hugely appreciated.

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants