Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit beefae47 authored by Qi Wu's avatar Qi Wu
Browse files

Add more vts tests related to limited use key.

1. Fix test case for usage count limit tag = 1 case, when
  hardware cannot enforce it, the tag should by enforced by keystore.
2. Add test case for usage count limit tag > 1.
3. Add test case to verify the usage count limit tag appears
  correctly in the attestation certificate for asymmetic key.

Test: atest -c VtsAidlKeyMintTargetTest

Change-Id: I01df278b42a91a78c8888c13c4f81b7ec70cfa22
parent 06e5b50f
Loading
Loading
Loading
Loading
+20 −20
Original line number Original line Diff line number Diff line
@@ -82,7 +82,6 @@ enum Tag {
     */
     */
    BLOCK_MODE = (2 << 28) /* TagType:ENUM_REP */ | 4,
    BLOCK_MODE = (2 << 28) /* TagType:ENUM_REP */ | 4,



    /**
    /**
     * Tag::DIGEST specifies the digest algorithms that may be used with the key to perform signing
     * Tag::DIGEST specifies the digest algorithms that may be used with the key to perform signing
     * and verification operations.  This tag is relevant to RSA, ECDSA and HMAC keys.  Possible
     * and verification operations.  This tag is relevant to RSA, ECDSA and HMAC keys.  Possible
@@ -346,14 +345,14 @@ enum Tag {
     * At this point, if the caller specifies count > 1, it is not expected that any TEE will be
     * At this point, if the caller specifies count > 1, it is not expected that any TEE will be
     * able to enforce this feature in the hardware due to limited resources of secure
     * able to enforce this feature in the hardware due to limited resources of secure
     * storage. In this case, the tag with the value of maximum usage must be added to the key
     * storage. In this case, the tag with the value of maximum usage must be added to the key
     * characteristics with SecurityLevel::SOFTWARE by the IKeyMintDevice.
     * characteristics with SecurityLevel::KEYSTORE by the IKeyMintDevice.
     *
     *
     * On the other hand, if the caller specifies count = 1, some TEEs may have the ability
     * On the other hand, if the caller specifies count = 1, some TEEs may have the ability
     * to enforce this feature in the hardware with its secure storage. If the IKeyMintDevice
     * to enforce this feature in the hardware with its secure storage. If the IKeyMintDevice
     * implementation can enforce this feature, the tag with value = 1 must be added to the key
     * implementation can enforce this feature, the tag with value = 1 must be added to the key
     * characteristics with the SecurityLevel of the IKeyMintDevice. If the IKeyMintDevice can't
     * characteristics with the SecurityLevel of the IKeyMintDevice. If the IKeyMintDevice can't
     * enforce this feature even when the count = 1, the tag must be added to the key
     * enforce this feature even when the count = 1, the tag must be added to the key
     * characteristics with the SecurityLevel::SOFTWARE.
     * characteristics with the SecurityLevel::KEYSTORE.
     *
     *
     * When the key is attested, this tag with the same value must also be added to the attestation
     * When the key is attested, this tag with the same value must also be added to the attestation
     * record. This tag must have the same SecurityLevel as the tag that is added to the key
     * record. This tag must have the same SecurityLevel as the tag that is added to the key
@@ -497,7 +496,8 @@ enum Tag {
     */
     */
    TRUSTED_USER_PRESENCE_REQUIRED = (7 << 28) /* TagType:BOOL */ | 507,
    TRUSTED_USER_PRESENCE_REQUIRED = (7 << 28) /* TagType:BOOL */ | 507,


    /** Tag::TRUSTED_CONFIRMATION_REQUIRED is only applicable to keys with KeyPurpose SIGN, and
    /**
     * Tag::TRUSTED_CONFIRMATION_REQUIRED is only applicable to keys with KeyPurpose SIGN, and
     *  specifies that this key must not be usable unless the user provides confirmation of the data
     *  specifies that this key must not be usable unless the user provides confirmation of the data
     *  to be signed.  Confirmation is proven to keyMint via an approval token.  See
     *  to be signed.  Confirmation is proven to keyMint via an approval token.  See
     *  CONFIRMATION_TOKEN, as well as the ConfirmatinUI HAL.
     *  CONFIRMATION_TOKEN, as well as the ConfirmatinUI HAL.
+29 −12
Original line number Original line Diff line number Diff line
@@ -55,6 +55,9 @@ bool KeyCharacteristicsBasicallyValid(SecurityLevel secLevel,
    for (auto& entry : key_characteristics) {
    for (auto& entry : key_characteristics) {
        if (entry.authorizations.empty()) return false;
        if (entry.authorizations.empty()) return false;


        // Just ignore the SecurityLevel::KEYSTORE as the KM won't do any enforcement on this.
        if (entry.securityLevel == SecurityLevel::KEYSTORE) continue;

        if (levels_seen.find(entry.securityLevel) != levels_seen.end()) return false;
        if (levels_seen.find(entry.securityLevel) != levels_seen.end()) return false;
        levels_seen.insert(entry.securityLevel);
        levels_seen.insert(entry.securityLevel);


@@ -824,22 +827,36 @@ const vector<KeyParameter>& KeyMintAidlTestBase::SecLevelAuthorizations(
    return (found == key_characteristics.end()) ? kEmptyAuthList : found->authorizations;
    return (found == key_characteristics.end()) ? kEmptyAuthList : found->authorizations;
}
}


const vector<KeyParameter>& KeyMintAidlTestBase::HwEnforcedAuthorizations(
const vector<KeyParameter>& KeyMintAidlTestBase::SecLevelAuthorizations(
        const vector<KeyCharacteristics>& key_characteristics) {
        const vector<KeyCharacteristics>& key_characteristics, SecurityLevel securityLevel) {
    auto found =
    auto found = std::find_if(
            std::find_if(key_characteristics.begin(), key_characteristics.end(), [](auto& entry) {
            key_characteristics.begin(), key_characteristics.end(),
                return entry.securityLevel == SecurityLevel::STRONGBOX ||
            [securityLevel](auto& entry) { return entry.securityLevel == securityLevel; });
                       entry.securityLevel == SecurityLevel::TRUSTED_ENVIRONMENT;
            });
    return (found == key_characteristics.end()) ? kEmptyAuthList : found->authorizations;
    return (found == key_characteristics.end()) ? kEmptyAuthList : found->authorizations;
}
}


const vector<KeyParameter>& KeyMintAidlTestBase::SwEnforcedAuthorizations(
AuthorizationSet KeyMintAidlTestBase::HwEnforcedAuthorizations(
        const vector<KeyCharacteristics>& key_characteristics) {
        const vector<KeyCharacteristics>& key_characteristics) {
    auto found = std::find_if(
    AuthorizationSet authList;
            key_characteristics.begin(), key_characteristics.end(),
    for (auto& entry : key_characteristics) {
            [](auto& entry) { return entry.securityLevel == SecurityLevel::SOFTWARE; });
        if (entry.securityLevel == SecurityLevel::STRONGBOX ||
    return (found == key_characteristics.end()) ? kEmptyAuthList : found->authorizations;
            entry.securityLevel == SecurityLevel::TRUSTED_ENVIRONMENT) {
            authList.push_back(AuthorizationSet(entry.authorizations));
        }
    }
    return authList;
}

AuthorizationSet KeyMintAidlTestBase::SwEnforcedAuthorizations(
        const vector<KeyCharacteristics>& key_characteristics) {
    AuthorizationSet authList;
    for (auto& entry : key_characteristics) {
        if (entry.securityLevel == SecurityLevel::SOFTWARE ||
            entry.securityLevel == SecurityLevel::KEYSTORE) {
            authList.push_back(AuthorizationSet(entry.authorizations));
        }
    }
    return authList;
}
}


}  // namespace test
}  // namespace test
+5 −2
Original line number Original line Diff line number Diff line
@@ -175,9 +175,12 @@ class KeyMintAidlTestBase : public ::testing::TestWithParam<string> {
    inline const vector<KeyParameter>& SecLevelAuthorizations() {
    inline const vector<KeyParameter>& SecLevelAuthorizations() {
        return SecLevelAuthorizations(key_characteristics_);
        return SecLevelAuthorizations(key_characteristics_);
    }
    }
    const vector<KeyParameter>& HwEnforcedAuthorizations(
    const vector<KeyParameter>& SecLevelAuthorizations(
            const vector<KeyCharacteristics>& key_characteristics, SecurityLevel securityLevel);

    AuthorizationSet HwEnforcedAuthorizations(
            const vector<KeyCharacteristics>& key_characteristics);
            const vector<KeyCharacteristics>& key_characteristics);
    const vector<KeyParameter>& SwEnforcedAuthorizations(
    AuthorizationSet SwEnforcedAuthorizations(
            const vector<KeyCharacteristics>& key_characteristics);
            const vector<KeyCharacteristics>& key_characteristics);


  private:
  private:
+159 −18
Original line number Original line Diff line number Diff line
@@ -645,6 +645,61 @@ TEST_P(NewKeyGenerationTest, LimitedUsageRsa) {
    }
    }
}
}


/*
 * NewKeyGenerationTest.LimitedUsageRsaWithAttestation
 *
 * Verifies that KeyMint can generate all required RSA key sizes with limited usage, and that the
 * resulting keys have correct characteristics and attestation.
 */
TEST_P(NewKeyGenerationTest, LimitedUsageRsaWithAttestation) {
    for (auto key_size : ValidKeySizes(Algorithm::RSA)) {
        auto challenge = "hello";
        auto app_id = "foo";

        vector<uint8_t> key_blob;
        vector<KeyCharacteristics> key_characteristics;
        ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                                     .RsaSigningKey(key_size, 65537)
                                                     .Digest(Digest::NONE)
                                                     .Padding(PaddingMode::NONE)
                                                     .AttestationChallenge(challenge)
                                                     .AttestationApplicationId(app_id)
                                                     .Authorization(TAG_NO_AUTH_REQUIRED)
                                                     .Authorization(TAG_USAGE_COUNT_LIMIT, 1),
                                             &key_blob, &key_characteristics));

        ASSERT_GT(key_blob.size(), 0U);
        CheckBaseParams(key_characteristics);

        AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);

        EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::RSA));
        EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size))
                << "Key size " << key_size << "missing";
        EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U));

        // Check the usage count limit tag appears in the authorizations.
        AuthorizationSet auths;
        for (auto& entry : key_characteristics) {
            auths.push_back(AuthorizationSet(entry.authorizations));
        }
        EXPECT_TRUE(auths.Contains(TAG_USAGE_COUNT_LIMIT, 1U))
                << "key usage count limit " << 1U << " missing";

        // Check the usage count limit tag also appears in the attestation.
        EXPECT_TRUE(verify_chain(cert_chain_));
        ASSERT_GT(cert_chain_.size(), 0);

        AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
        AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
        EXPECT_TRUE(verify_attestation_record(challenge, app_id,  //
                                              sw_enforced, hw_enforced, SecLevel(),
                                              cert_chain_[0].encodedCertificate));

        CheckedDeleteKey(&key_blob);
    }
}

/*
/*
 * NewKeyGenerationTest.NoInvalidRsaSizes
 * NewKeyGenerationTest.NoInvalidRsaSizes
 *
 *
@@ -4297,11 +4352,11 @@ INSTANTIATE_KEYMINT_AIDL_TEST(MaxOperationsTest);
typedef KeyMintAidlTestBase UsageCountLimitTest;
typedef KeyMintAidlTestBase UsageCountLimitTest;


/*
/*
 * UsageCountLimitTest.TestLimitAes
 * UsageCountLimitTest.TestSingleUseAes
 *
 *
 * Verifies that the usage count limit tag works correctly with AES keys.
 * Verifies that the usage count limit tag = 1 works correctly with AES keys.
 */
 */
TEST_P(UsageCountLimitTest, TestLimitAes) {
TEST_P(UsageCountLimitTest, TestSingleUseAes) {
    if (SecLevel() == SecurityLevel::STRONGBOX) return;
    if (SecLevel() == SecurityLevel::STRONGBOX) return;


    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
@@ -4322,31 +4377,75 @@ TEST_P(UsageCountLimitTest, TestLimitAes) {
    string message = "1234567890123456";
    string message = "1234567890123456";
    auto params = AuthorizationSetBuilder().EcbMode().Padding(PaddingMode::NONE);
    auto params = AuthorizationSetBuilder().EcbMode().Padding(PaddingMode::NONE);


    AuthorizationSet hardware_auths = HwEnforcedAuthorizations(key_characteristics_);
    AuthorizationSet keystore_auths =
            SecLevelAuthorizations(key_characteristics_, SecurityLevel::KEYSTORE);

    // First usage of AES key should work.
    // First usage of AES key should work.
    EncryptMessage(message, params);
    EncryptMessage(message, params);


    AuthorizationSet hardware_auths;
    if (hardware_auths.Contains(TAG_USAGE_COUNT_LIMIT, 1U)) {
        // Usage count limit tag is enforced by hardware. After using the key, the key blob
        // must be invalidated from secure storage (such as RPMB partition).
        EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB, Begin(KeyPurpose::ENCRYPT, params));
    } else {
        // Usage count limit tag is enforced by keystore, keymint does nothing.
        EXPECT_TRUE(keystore_auths.Contains(TAG_USAGE_COUNT_LIMIT, 1U));
        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
    }
}

/*
 * UsageCountLimitTest.TestLimitedUseAes
 *
 * Verifies that the usage count limit tag > 1 works correctly with AES keys.
 */
TEST_P(UsageCountLimitTest, TestLimitedUseAes) {
    if (SecLevel() == SecurityLevel::STRONGBOX) return;

    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
                                                 .AesEncryptionKey(128)
                                                 .EcbMode()
                                                 .Padding(PaddingMode::NONE)
                                                 .Authorization(TAG_USAGE_COUNT_LIMIT, 3)));

    // Check the usage count limit tag appears in the authorizations.
    AuthorizationSet auths;
    for (auto& entry : key_characteristics_) {
    for (auto& entry : key_characteristics_) {
        if (entry.securityLevel != SecurityLevel::SOFTWARE) {
        auths.push_back(AuthorizationSet(entry.authorizations));
        auths.push_back(AuthorizationSet(entry.authorizations));
    }
    }
    }
    EXPECT_TRUE(auths.Contains(TAG_USAGE_COUNT_LIMIT, 3U))
    if (hardware_auths.Contains(TAG_USAGE_COUNT_LIMIT, 1U)) {
            << "key usage count limit " << 3U << " missing";

    string message = "1234567890123456";
    auto params = AuthorizationSetBuilder().EcbMode().Padding(PaddingMode::NONE);

    AuthorizationSet hardware_auths = HwEnforcedAuthorizations(key_characteristics_);
    AuthorizationSet keystore_auths =
            SecLevelAuthorizations(key_characteristics_, SecurityLevel::KEYSTORE);

    EncryptMessage(message, params);
    EncryptMessage(message, params);
    EncryptMessage(message, params);

    if (hardware_auths.Contains(TAG_USAGE_COUNT_LIMIT, 3U)) {
        // Usage count limit tag is enforced by hardware. After using the key, the key blob
        // Usage count limit tag is enforced by hardware. After using the key, the key blob
        // must be invalidated from secure storage (such as RPMB partition).
        // must be invalidated from secure storage (such as RPMB partition).
        EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB, Begin(KeyPurpose::ENCRYPT, params));
        EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB, Begin(KeyPurpose::ENCRYPT, params));
    } else {
    } else {
        // Usage count limit tag is enforced by software, keymint does nothing.
        // Usage count limit tag is enforced by keystore, keymint does nothing.
        EXPECT_TRUE(keystore_auths.Contains(TAG_USAGE_COUNT_LIMIT, 3U));
        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
    }
    }
}
}


/*
/*
 * UsageCountLimitTest.TestLimitRsa
 * UsageCountLimitTest.TestSingleUseRsa
 *
 *
 * Verifies that the usage count limit tag works correctly with RSA keys.
 * Verifies that the usage count limit tag = 1 works correctly with RSA keys.
 */
 */
TEST_P(UsageCountLimitTest, TestLimitRsa) {
TEST_P(UsageCountLimitTest, TestSingleUseRsa) {
    if (SecLevel() == SecurityLevel::STRONGBOX) return;
    if (SecLevel() == SecurityLevel::STRONGBOX) return;


    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
@@ -4366,22 +4465,64 @@ TEST_P(UsageCountLimitTest, TestLimitRsa) {
    string message = "1234567890123456";
    string message = "1234567890123456";
    auto params = AuthorizationSetBuilder().NoDigestOrPadding();
    auto params = AuthorizationSetBuilder().NoDigestOrPadding();


    AuthorizationSet hardware_auths = HwEnforcedAuthorizations(key_characteristics_);
    AuthorizationSet keystore_auths =
            SecLevelAuthorizations(key_characteristics_, SecurityLevel::KEYSTORE);

    // First usage of RSA key should work.
    // First usage of RSA key should work.
    SignMessage(message, params);
    SignMessage(message, params);


    AuthorizationSet hardware_auths;
    if (hardware_auths.Contains(TAG_USAGE_COUNT_LIMIT, 1U)) {
        // Usage count limit tag is enforced by hardware. After using the key, the key blob
        // must be invalidated from secure storage (such as RPMB partition).
        EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB, Begin(KeyPurpose::SIGN, params));
    } else {
        // Usage count limit tag is enforced by keystore, keymint does nothing.
        EXPECT_TRUE(keystore_auths.Contains(TAG_USAGE_COUNT_LIMIT, 1U));
        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, params));
    }
}

/*
 * UsageCountLimitTest.TestLimitUseRsa
 *
 * Verifies that the usage count limit tag > 1 works correctly with RSA keys.
 */
TEST_P(UsageCountLimitTest, TestLimitUseRsa) {
    if (SecLevel() == SecurityLevel::STRONGBOX) return;

    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
                                                 .RsaSigningKey(1024, 65537)
                                                 .NoDigestOrPadding()
                                                 .Authorization(TAG_USAGE_COUNT_LIMIT, 3)));

    // Check the usage count limit tag appears in the authorizations.
    AuthorizationSet auths;
    for (auto& entry : key_characteristics_) {
    for (auto& entry : key_characteristics_) {
        if (entry.securityLevel != SecurityLevel::SOFTWARE) {
        auths.push_back(AuthorizationSet(entry.authorizations));
        auths.push_back(AuthorizationSet(entry.authorizations));
    }
    }
    }
    EXPECT_TRUE(auths.Contains(TAG_USAGE_COUNT_LIMIT, 3U))
            << "key usage count limit " << 3U << " missing";


    if (hardware_auths.Contains(TAG_USAGE_COUNT_LIMIT, 1U)) {
    string message = "1234567890123456";
    auto params = AuthorizationSetBuilder().NoDigestOrPadding();

    AuthorizationSet hardware_auths = HwEnforcedAuthorizations(key_characteristics_);
    AuthorizationSet keystore_auths =
            SecLevelAuthorizations(key_characteristics_, SecurityLevel::KEYSTORE);

    SignMessage(message, params);
    SignMessage(message, params);
    SignMessage(message, params);

    if (hardware_auths.Contains(TAG_USAGE_COUNT_LIMIT, 3U)) {
        // Usage count limit tag is enforced by hardware. After using the key, the key blob
        // Usage count limit tag is enforced by hardware. After using the key, the key blob
        // must be invalidated from secure storage (such as RPMB partition).
        // must be invalidated from secure storage (such as RPMB partition).
        EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB, Begin(KeyPurpose::SIGN, params));
        EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB, Begin(KeyPurpose::SIGN, params));
    } else {
    } else {
        // Usage count limit tag is enforced by software, keymint does nothing.
        // Usage count limit tag is enforced by keystore, keymint does nothing.
        EXPECT_TRUE(keystore_auths.Contains(TAG_USAGE_COUNT_LIMIT, 3U));
        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, params));
        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, params));
    }
    }
}
}
+4 −1
Original line number Original line Diff line number Diff line
@@ -97,6 +97,7 @@ typedef struct km_auth_list {
    ASN1_NULL* device_unique_attestation;
    ASN1_NULL* device_unique_attestation;
    ASN1_NULL* storage_key;
    ASN1_NULL* storage_key;
    ASN1_NULL* identity_credential;
    ASN1_NULL* identity_credential;
    ASN1_INTEGER* usage_count_limit;
} KM_AUTH_LIST;
} KM_AUTH_LIST;


ASN1_SEQUENCE(KM_AUTH_LIST) = {
ASN1_SEQUENCE(KM_AUTH_LIST) = {
@@ -143,7 +144,8 @@ ASN1_SEQUENCE(KM_AUTH_LIST) = {
        ASN1_EXP_OPT(KM_AUTH_LIST, storage_key, ASN1_NULL, TAG_STORAGE_KEY.maskedTag()),
        ASN1_EXP_OPT(KM_AUTH_LIST, storage_key, ASN1_NULL, TAG_STORAGE_KEY.maskedTag()),
        ASN1_EXP_OPT(KM_AUTH_LIST, identity_credential, ASN1_NULL,
        ASN1_EXP_OPT(KM_AUTH_LIST, identity_credential, ASN1_NULL,
                     TAG_IDENTITY_CREDENTIAL_KEY.maskedTag()),
                     TAG_IDENTITY_CREDENTIAL_KEY.maskedTag()),

        ASN1_EXP_OPT(KM_AUTH_LIST, usage_count_limit, ASN1_INTEGER,
                     TAG_USAGE_COUNT_LIMIT.maskedTag()),
} ASN1_SEQUENCE_END(KM_AUTH_LIST);
} ASN1_SEQUENCE_END(KM_AUTH_LIST);
IMPLEMENT_ASN1_FUNCTIONS(KM_AUTH_LIST);
IMPLEMENT_ASN1_FUNCTIONS(KM_AUTH_LIST);


@@ -285,6 +287,7 @@ static ErrorCode extract_auth_list(const KM_AUTH_LIST* record, AuthorizationSet*
    copyAuthTag(record->device_unique_attestation, TAG_DEVICE_UNIQUE_ATTESTATION, auth_list);
    copyAuthTag(record->device_unique_attestation, TAG_DEVICE_UNIQUE_ATTESTATION, auth_list);
    copyAuthTag(record->storage_key, TAG_STORAGE_KEY, auth_list);
    copyAuthTag(record->storage_key, TAG_STORAGE_KEY, auth_list);
    copyAuthTag(record->identity_credential, TAG_IDENTITY_CREDENTIAL_KEY, auth_list);
    copyAuthTag(record->identity_credential, TAG_IDENTITY_CREDENTIAL_KEY, auth_list);
    copyAuthTag(record->usage_count_limit, TAG_USAGE_COUNT_LIMIT, auth_list);


    return ErrorCode::OK;
    return ErrorCode::OK;
}
}