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.

 

posted @ 2023-02-14 10:08  xiululu  阅读(70)  评论(0编辑  收藏  举报