optee km4.0 VTS: PerInstance/SigningOperationsTest.RsaGetKeyCharacteristicsRequiresCorrectAppIdAppData/0_default
异常日志:
# ./VtsHalKeymasterV4_0TargetTest --gtest_filter=PerInstance/SigningOperationsTest.RsaGetKeyCharacteristicsRequiresCorrectAppIdAppData/0_default Note: Google Test filter = PerInstance/SigningOperationsTest.RsaGetKeyCharacteristicsRequiresCorrectAppIdAppData/0_default [==========] Running 1 test from 1 test suite. [----------] Global test environment set-up. [----------] 1 test from PerInstance/SigningOperationsTest [ RUN ] PerInstance/SigningOperationsTest.RsaGetKeyCharacteristicsRequiresCorrectAppIdAppData/0_default hardware/interfaces/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp:258: Failure Expected equality of these values: ErrorCode::INVALID_KEY_BLOB Which is: INVALID_KEY_BLOB GetCharacteristics(key_blob, empty_buf, app_data, key_characteristics) Which is: OK hardware/interfaces/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp:259: Failure Expected equality of these values: key_characteristics->hardwareEnforced.size() Which is: 11 0 hardware/interfaces/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp:260: Failure Expected equality of these values: key_characteristics->softwareEnforced.size() Which is: 1 0 hardware/interfaces/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp:263: Failure Expected equality of these values: ErrorCode::INVALID_KEY_BLOB Which is: INVALID_KEY_BLOB GetCharacteristics(key_blob, client_id, empty_buf, key_characteristics) Which is: OK hardware/interfaces/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp:264: Failure Expected equality of these values: key_characteristics->hardwareEnforced.size() Which is: 11 0 hardware/interfaces/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp:265: Failure Expected equality of these values: key_characteristics->softwareEnforced.size() Which is: 1 0 hardware/interfaces/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp:268: Failure Expected equality of these values: ErrorCode::INVALID_KEY_BLOB Which is: INVALID_KEY_BLOB GetCharacteristics(key_blob, empty_buf, empty_buf, key_characteristics) Which is: OK hardware/interfaces/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp:269: Failure Expected equality of these values: key_characteristics->hardwareEnforced.size() Which is: 11 0 hardware/interfaces/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp:270: Failure Expected equality of these values: key_characteristics->softwareEnforced.size() Which is: 1 0 [ FAILED ] PerInstance/SigningOperationsTest.RsaGetKeyCharacteristicsRequiresCorrectAppIdAppData/0_default, where GetParam() = "default" (24382 ms) [----------] 1 test from PerInstance/SigningOperationsTest (24382 ms total) [----------] Global test environment tear-down [==========] 1 test from 1 test suite ran. (24382 ms total) [ PASSED ] 0 tests. [ FAILED ] 1 test, listed below: [ FAILED ] PerInstance/SigningOperationsTest.RsaGetKeyCharacteristicsRequiresCorrectAppIdAppData/0_default, where GetParam() = "default" 1 FAILED TEST
对应测试代码:
void KeymasterHidlTest::CheckGetCharacteristics(const HidlBuf& key_blob, const HidlBuf& client_id, const HidlBuf& app_data, KeyCharacteristics* key_characteristics) { HidlBuf empty_buf = {}; EXPECT_EQ(ErrorCode::OK, GetCharacteristics(key_blob, client_id, app_data, key_characteristics)); if (SecLevel() != SecurityLevel::SOFTWARE) { EXPECT_GT(key_characteristics->hardwareEnforced.size(), 0); } EXPECT_GT(key_characteristics->softwareEnforced.size(), 0); EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB, GetCharacteristics(key_blob, empty_buf, app_data, key_characteristics)); EXPECT_EQ(key_characteristics->hardwareEnforced.size(), 0); EXPECT_EQ(key_characteristics->softwareEnforced.size(), 0); EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB, GetCharacteristics(key_blob, client_id, empty_buf, key_characteristics)); EXPECT_EQ(key_characteristics->hardwareEnforced.size(), 0); EXPECT_EQ(key_characteristics->softwareEnforced.size(), 0); EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB, GetCharacteristics(key_blob, empty_buf, empty_buf, key_characteristics)); EXPECT_EQ(key_characteristics->hardwareEnforced.size(), 0); EXPECT_EQ(key_characteristics->softwareEnforced.size(), 0); }
核查代码,GetKeyCharacteristicsRequest的封装和TA中的解析对不上:
GetKeyCharacteristicsRequest封装过程:
system/keymaster/android_keymaster/android_keymaster_messages.cpp
uint8_t* GetKeyCharacteristicsRequest::Serialize(uint8_t* buf, const uint8_t* end) const { buf = serialize_key_blob(key_blob, buf, end); return additional_params.Serialize(buf, end); }
//先封装了keymaster_key_blob_t,再封装AuthorizationSet
关键数据结构:
struct GetKeyCharacteristicsRequest : public KeymasterMessage { explicit GetKeyCharacteristicsRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) { key_blob.key_material = nullptr; key_blob.key_material_size = 0; } ~GetKeyCharacteristicsRequest(); void SetKeyMaterial(const void* key_material, size_t length); void SetKeyMaterial(const keymaster_key_blob_t& blob) { SetKeyMaterial(blob.key_material, blob.key_material_size); } size_t SerializedSize() const override; uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override; bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override; keymaster_key_blob_t key_blob; AuthorizationSet additional_params; }
TA侧解析过程:
//Return key parameters and characteristics associated during generation static keymaster_error_t TA_getKeyCharacteristics( TEE_Param params[TEE_NUM_PARAMS]) { uint8_t *in = NULL; uint8_t *in_end = NULL; uint8_t *out = NULL; uint8_t *key_material = NULL; keymaster_key_blob_t key_blob = EMPTY_KEY_BLOB; /* IN */ keymaster_blob_t client_id = EMPTY_BLOB; /* IN */ keymaster_blob_t app_data = EMPTY_BLOB; /* IN */ keymaster_key_characteristics_t chr = EMPTY_CHARACTS; /* OUT */ keymaster_key_param_set_t params_t = EMPTY_PARAM_SET; keymaster_error_t res = KM_ERROR_OK; TEE_ObjectHandle obj_h = TEE_HANDLE_NULL; uint32_t characts_size = 0; uint32_t key_size = 0; uint32_t type = 0; bool exportable = false; in = (uint8_t *) params[0].memref.buffer; in_end = in + params[0].memref.size; out = (uint8_t *) params[1].memref.buffer; in += TA_deserialize_key_blob_akms(in, in_end, &key_blob, &res);//先解析出一个keymaster_key_blob_t对象 if (res != KM_ERROR_OK) goto exit; in += TA_deserialize_blob_akms(in, in_end, &client_id, false, &res, false);//接着解析keymaster_blob_t if (res != KM_ERROR_OK) goto exit; in += TA_deserialize_blob_akms(in, in_end, &app_data, false, &res, false);//再解析keymaster_blob_t if (res != KM_ERROR_OK) goto exit; if (key_blob.key_material_size == 0) { EMSG("Bad key blob"); res = KM_ERROR_UNSUPPORTED_KEY_FORMAT; goto exit; } .........return res; }
修复一:
从上述代码来看,CA侧的serialize和TA侧的deserialize两者是匹配不上了。
所以先需要使两端匹配起来,TA侧有现成的反序列化authorization set的函数:TA_deserialize_auth_set
修改之后测试时还会报错。从打印出来的log看,client_id和app_data解析正常了。那么就是后续的check流程出现了异常。
继续跟踪:
keymaster_error_t TA_check_permission(const keymaster_key_param_set_t *params, const keymaster_blob_t client_id, const keymaster_blob_t app_data, bool *exportable) { bool client_id_checked = false; bool app_data_checked = false; bool client_id_same = false;//看看这个初始值 bool app_data_same = false; for (size_t i = 0; i < params->length; i++) { DMSG("in_params->params[%zu].tag = %d", i, params->params[i].tag); if (client_id_checked && app_data_checked && *exportable) break; switch (params->params[i].tag) { case KM_TAG_APPLICATION_ID: client_id_checked = true; if (client_id.data_length != params->params[i]. key_param.blob.data_length) break; client_id_same = TEE_MemCompare(client_id.data, params->params[i].key_param.blob.data, client_id.data_length); break; case KM_TAG_APPLICATION_DATA: app_data_checked = true; if (app_data.data_length != params->params[i].key_param.blob.data_length) break; app_data_same = TEE_MemCompare(app_data.data, params->params[i].key_param.blob.data, app_data.data_length); break; case KM_TAG_EXPORTABLE: *exportable = params->params[i].key_param.boolean; break; default: break; } } if ((app_data_checked && app_data_same != 0) || (client_id_checked && client_id_same != 0)) { EMSG("Invalid client id or app data!"); return KM_ERROR_INVALID_KEY_BLOB; } return KM_ERROR_OK; }
在TEE Internal Core API Specification中,看下TEE_MemCompare的定义:
4.11.8 TEE_MemCompare
int32_t TEE_MemCompare(
[inbuf(size)] void* buffer1,
[inbuf(size)] void* buffer2,
uint32_t size);
Description
The TEE_MemCompare function compares the first size bytes of the buffer pointed to by buffer1 to the
first size bytes of the buffer pointed to by buffer2.
Parameters
buffer1: A pointer to the first buffer
buffer2: A pointer to the second buffer
size: The number of bytes to be compared
Specification Number: 10 Function Number: 0x605
Return Value
The sign of a non-zero return value is determined by the sign of the difference between the values of the first
pair of bytes (both interpreted as type uint8_t) that differ in the objects being compared.
If the first byte that differs is higher in buffer1, then return an integer greater than zero.
If the first size bytes of the two buffers are identical, then return zero.
If the first byte that differs is higher in buffer2, then return an integer lower than zero.
Panic Reasons
If the Implementation detects any error.
两者相同,则TEE_MemCompare返回0,而app_data_same 和client_id_same 这两变量,给定义为了bool值,那么0表示false。怎么说呢,定义和含义有种违和感。
client_id_checked和app_data_checked表示这两个TAG是否存在,一旦存在,就需要检查。
所以默认返回值设定为KM_ERROR_OK,表达的意思是假设TAG不存在,不需要检查,那么这个permission check通过。
修改思路:按照字面定义,xxx_same变量的值需要符合名称,所以xxx_same =(TEE_MemCompare == 0),这样后续判断根据same含义来调整。
修复二:
最终修改的版本贴一个上来:
keymaster_error_t TA_check_permission(const keymaster_key_param_set_t *params, const keymaster_blob_t client_id, const keymaster_blob_t app_data, bool *exportable) { bool client_id_checked = false; bool app_data_checked = false; bool client_id_same = false; bool app_data_same = false; for (size_t i = 0; i < params->length; i++) { DMSG("in_params->params[%zu].tag = %d", i, params->params[i].tag); if (client_id_checked && app_data_checked && *exportable) break; switch (params->params[i].tag) { case KM_TAG_APPLICATION_ID: DMSG("KM_TAG_APPLICATION_ID client_id.data_length = %zu", client_id.data_length); DMSG("KM_TAG_APPLICATION_ID blob.data_length = %zu", params->params[i].key_param.blob.data_length); client_id_checked = true; if (client_id.data_length != params->params[i]. key_param.blob.data_length) break; client_id_same = (TEE_MemCompare(client_id.data, params->params[i].key_param.blob.data, client_id.data_length) == 0); break; case KM_TAG_APPLICATION_DATA: DMSG("KM_TAG_APPLICATION_DATA app_data.data = %zu", app_data.data_length); DMSG("KM_TAG_APPLICATION_DATA blob.data_length = %zu", params->params[i].key_param.blob.data_length); app_data_checked = true; if (app_data.data_length != params->params[i].key_param.blob.data_length) break; app_data_same = (TEE_MemCompare(app_data.data, params->params[i].key_param.blob.data, app_data.data_length) == 0); break; case KM_TAG_EXPORTABLE: *exportable = params->params[i].key_param.boolean; break; default: break; } } DMSG("app_data_checked = %d, app_data_same = %d", app_data_checked, app_data_same); DMSG("client_id_checked = %d, client_id_same = %d", client_id_checked, client_id_same); if ((app_data_checked && !app_data_same) || (client_id_checked && !client_id_same)) { EMSG("Invalid client id or app data!"); return KM_ERROR_INVALID_KEY_BLOB; } return KM_ERROR_OK; }
测试结果:
如此修改之后,最终测试成功:
# ./VtsHalKeymasterV4_0TargetTest --gtest_filter=PerInstance/SigningOperationsTest.RsaGetKeyCharacteristicsRequiresCorrectAppIdAppData/0_default Note: Google Test filter = PerInstance/SigningOperationsTest.RsaGetKeyCharacteristicsRequiresCorrectAppIdAppData/0_default [==========] Running 1 test from 1 test suite. [----------] Global test environment set-up. [----------] 1 test from PerInstance/SigningOperationsTest [ RUN ] PerInstance/SigningOperationsTest.RsaGetKeyCharacteristicsRequiresCorrectAppIdAppData/0_default [ OK ] PerInstance/SigningOperationsTest.RsaGetKeyCharacteristicsRequiresCorrectAppIdAppData/0_default (24820 ms) [----------] 1 test from PerInstance/SigningOperationsTest (24820 ms total) [----------] Global test environment tear-down [==========] 1 test from 1 test suite ran. (24820 ms total) [ PASSED ] 1 test.