| /* |
| * Copyright (C) 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <errno.h> |
| #include <stdio.h> |
| #include <time.h> |
| |
| #include <keymaster/android_keymaster.h> |
| #include <keymaster/authorization_set.h> |
| #include <keymaster/km_openssl/soft_keymaster_enforcement.h> |
| |
| #include "android_keymaster_test_utils.h" |
| |
| namespace keymaster { |
| namespace test { |
| |
| class TestKeymasterEnforcement : public SoftKeymasterEnforcement { |
| public: |
| TestKeymasterEnforcement() |
| : SoftKeymasterEnforcement(3, 3), current_time_(10000), report_token_valid_(true) {} |
| |
| keymaster_error_t AuthorizeOperation(const keymaster_purpose_t purpose, const km_id_t keyid, |
| const AuthProxy& auth_set) { |
| AuthorizationSet empty_set; |
| return KeymasterEnforcement::AuthorizeOperation( |
| purpose, keyid, auth_set, empty_set, 0 /* op_handle */, true /* is_begin_operation */); |
| } |
| using KeymasterEnforcement::AuthorizeOperation; |
| |
| uint64_t get_current_time_ms() const override { return current_time_ * 1000; } |
| bool activation_date_valid(uint64_t activation_date) const override { |
| // Convert java date to time_t, non-portably. |
| time_t activation_time = activation_date / 1000; |
| return difftime(time(NULL), activation_time) >= 0; |
| } |
| bool expiration_date_passed(uint64_t expiration_date) const override { |
| // Convert jave date to time_t, non-portably. |
| time_t expiration_time = expiration_date / 1000; |
| return difftime(time(NULL), expiration_time) > 0; |
| } |
| bool auth_token_timed_out(const hw_auth_token_t& token, uint32_t timeout) const override { |
| return current_time_ > ntoh(token.timestamp) + timeout; |
| } |
| bool ValidateTokenSignature(const hw_auth_token_t&) const override { |
| return report_token_valid_; |
| } |
| |
| void tick(unsigned seconds = 1) { current_time_ += seconds; } |
| uint32_t current_time() { return current_time_; } |
| void set_report_token_valid(bool report_token_valid) { |
| report_token_valid_ = report_token_valid; |
| } |
| |
| private: |
| uint32_t current_time_; |
| bool report_token_valid_; |
| }; |
| |
| class KeymasterBaseTest : public ::testing::Test { |
| protected: |
| KeymasterBaseTest() { |
| past_time = 0; |
| |
| time_t t = time(NULL); |
| future_tm = localtime(&t); |
| future_tm->tm_year += 1; |
| future_time = static_cast<uint64_t>(mktime(future_tm)) * 1000; |
| sign_param = Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN); |
| } |
| virtual ~KeymasterBaseTest() {} |
| |
| TestKeymasterEnforcement kmen; |
| |
| tm past_tm; |
| tm* future_tm; |
| uint64_t past_time; |
| uint64_t future_time; |
| static const km_id_t key_id = 0xa; |
| static const uid_t uid = 0xf; |
| keymaster_key_param_t sign_param; |
| AuthorizationSet empty; |
| }; |
| |
| TEST_F(KeymasterBaseTest, TestValidKeyPeriodNoTags) { |
| keymaster_key_param_t params[] = { |
| sign_param, |
| }; |
| AuthorizationSet single_auth_set(params, array_length(params)); |
| |
| keymaster_error_t kmer = |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, AuthProxy(single_auth_set, empty)); |
| ASSERT_EQ(KM_ERROR_OK, kmer); |
| } |
| |
| TEST_F(KeymasterBaseTest, TestInvalidActiveTime) { |
| keymaster_key_param_t params[] = { |
| Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), |
| Authorization(TAG_NO_AUTH_REQUIRED), Authorization(TAG_ACTIVE_DATETIME, future_time), |
| }; |
| |
| AuthorizationSet auth_set(params, array_length(params)); |
| |
| ASSERT_EQ(KM_ERROR_KEY_NOT_YET_VALID, |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty))); |
| |
| // Pubkey ops allowed. |
| ASSERT_EQ(KM_ERROR_OK, |
| kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, AuthProxy(auth_set, empty))); |
| } |
| |
| TEST_F(KeymasterBaseTest, TestValidActiveTime) { |
| keymaster_key_param_t params[] = { |
| Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_ACTIVE_DATETIME, past_time), |
| }; |
| |
| AuthorizationSet auth_set(params, array_length(params)); |
| |
| keymaster_error_t kmer_valid_time = |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty)); |
| ASSERT_EQ(KM_ERROR_OK, kmer_valid_time); |
| } |
| |
| TEST_F(KeymasterBaseTest, TestInvalidOriginationExpireTime) { |
| keymaster_key_param_t params[] = { |
| Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), |
| Authorization(TAG_ORIGINATION_EXPIRE_DATETIME, past_time), |
| }; |
| |
| AuthorizationSet auth_set(params, array_length(params)); |
| |
| ASSERT_EQ(KM_ERROR_KEY_EXPIRED, |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty))); |
| |
| // Pubkey ops allowed. |
| ASSERT_EQ(KM_ERROR_OK, |
| kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, AuthProxy(auth_set, empty))); |
| } |
| |
| TEST_F(KeymasterBaseTest, TestInvalidOriginationExpireTimeOnUsgae) { |
| keymaster_key_param_t params[] = { |
| Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY), |
| Authorization(TAG_ORIGINATION_EXPIRE_DATETIME, past_time), |
| }; |
| |
| AuthorizationSet auth_set(params, array_length(params)); |
| |
| keymaster_error_t kmer_invalid_origination = |
| kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, AuthProxy(auth_set, empty)); |
| ASSERT_EQ(KM_ERROR_OK, kmer_invalid_origination); |
| } |
| |
| TEST_F(KeymasterBaseTest, TestValidOriginationExpireTime) { |
| keymaster_key_param_t params[] = { |
| Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), |
| Authorization(TAG_ORIGINATION_EXPIRE_DATETIME, future_time), |
| }; |
| |
| AuthorizationSet auth_set(params, array_length(params)); |
| |
| keymaster_error_t kmer_valid_origination = |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty)); |
| ASSERT_EQ(KM_ERROR_OK, kmer_valid_origination); |
| } |
| |
| TEST_F(KeymasterBaseTest, TestInvalidUsageExpireTime) { |
| keymaster_key_param_t params[] = { |
| Authorization(TAG_ALGORITHM, KM_ALGORITHM_AES), |
| Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY), |
| Authorization(TAG_USAGE_EXPIRE_DATETIME, past_time), |
| }; |
| |
| AuthorizationSet auth_set(params, array_length(params)); |
| |
| keymaster_error_t kmer_invalid_origination = |
| kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, AuthProxy(auth_set, empty)); |
| ASSERT_EQ(KM_ERROR_KEY_EXPIRED, kmer_invalid_origination); |
| } |
| |
| TEST_F(KeymasterBaseTest, TestInvalidPubkeyUsageExpireTime) { |
| keymaster_key_param_t params[] = { |
| Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), |
| Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY), |
| Authorization(TAG_USAGE_EXPIRE_DATETIME, past_time), |
| }; |
| |
| AuthorizationSet auth_set(params, array_length(params)); |
| |
| keymaster_error_t kmer_invalid_origination = |
| kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, AuthProxy(auth_set, empty)); |
| // Pubkey ops allowed. |
| ASSERT_EQ(KM_ERROR_OK, kmer_invalid_origination); |
| } |
| |
| TEST_F(KeymasterBaseTest, TestInvalidUsageExpireTimeOnOrigination) { |
| keymaster_key_param_t params[] = { |
| Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), |
| Authorization(TAG_USAGE_EXPIRE_DATETIME, past_time), |
| }; |
| |
| AuthorizationSet auth_set(params, array_length(params)); |
| |
| keymaster_error_t kmer_invalid_origination = |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty)); |
| ASSERT_EQ(KM_ERROR_OK, kmer_invalid_origination); |
| } |
| |
| TEST_F(KeymasterBaseTest, TestValidUsageExpireTime) { |
| keymaster_key_param_t params[] = { |
| Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY), |
| Authorization(TAG_USAGE_EXPIRE_DATETIME, future_time), |
| }; |
| |
| AuthorizationSet auth_set(params, array_length(params)); |
| |
| keymaster_error_t kmer_valid_usage = |
| kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, AuthProxy(auth_set, empty)); |
| ASSERT_EQ(KM_ERROR_OK, kmer_valid_usage); |
| } |
| |
| TEST_F(KeymasterBaseTest, TestValidSingleUseAccesses) { |
| keymaster_key_param_t params[] = { |
| Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), |
| }; |
| |
| AuthorizationSet auth_set(params, array_length(params)); |
| |
| keymaster_error_t kmer1 = |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty)); |
| keymaster_error_t kmer2 = |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty)); |
| |
| ASSERT_EQ(KM_ERROR_OK, kmer1); |
| ASSERT_EQ(KM_ERROR_OK, kmer2); |
| } |
| |
| TEST_F(KeymasterBaseTest, TestInvalidMaxOps) { |
| keymaster_key_param_t params[] = { |
| Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), |
| Authorization(TAG_MAX_USES_PER_BOOT, 4), |
| }; |
| |
| AuthorizationSet auth_set(params, array_length(params)); |
| |
| ASSERT_EQ(KM_ERROR_OK, |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty))); |
| ASSERT_EQ(KM_ERROR_OK, |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty))); |
| ASSERT_EQ(KM_ERROR_OK, |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty))); |
| ASSERT_EQ(KM_ERROR_OK, |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty))); |
| ASSERT_EQ(KM_ERROR_KEY_MAX_OPS_EXCEEDED, |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty))); |
| // Pubkey ops allowed. |
| ASSERT_EQ(KM_ERROR_OK, |
| kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, AuthProxy(auth_set, empty))); |
| } |
| |
| TEST_F(KeymasterBaseTest, TestOverFlowMaxOpsTable) { |
| keymaster_key_param_t params[] = { |
| Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), |
| Authorization(TAG_MAX_USES_PER_BOOT, 2), |
| }; |
| |
| AuthorizationSet auth_set(params, array_length(params)); |
| |
| EXPECT_EQ(KM_ERROR_OK, |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 1 /* key_id */, AuthProxy(auth_set, empty))); |
| |
| EXPECT_EQ(KM_ERROR_OK, |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 2 /* key_id */, AuthProxy(auth_set, empty))); |
| |
| EXPECT_EQ(KM_ERROR_OK, |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 3 /* key_id */, AuthProxy(auth_set, empty))); |
| |
| // Key 4 should fail, because table is full. |
| EXPECT_EQ(KM_ERROR_TOO_MANY_OPERATIONS, |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 4 /* key_id */, AuthProxy(auth_set, empty))); |
| |
| // Key 1 still works, because it's already in the table and hasn't reached max. |
| EXPECT_EQ(KM_ERROR_OK, |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 1 /* key_id */, AuthProxy(auth_set, empty))); |
| |
| // Key 1 no longer works, because it's reached max. |
| EXPECT_EQ(KM_ERROR_KEY_MAX_OPS_EXCEEDED, |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 1 /* key_id */, AuthProxy(auth_set, empty))); |
| |
| // Key 4 should fail, because table is (still and forever) full. |
| EXPECT_EQ(KM_ERROR_TOO_MANY_OPERATIONS, |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 4 /* key_id */, AuthProxy(auth_set, empty))); |
| |
| // Pubkey ops allowed. |
| EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, |
| AuthProxy(auth_set, empty))); |
| EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 4 /* key_id */, |
| AuthProxy(auth_set, empty))); |
| } |
| |
| TEST_F(KeymasterBaseTest, TestInvalidTimeBetweenOps) { |
| keymaster_key_param_t params[] = { |
| Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), |
| Authorization(TAG_MIN_SECONDS_BETWEEN_OPS, 10), |
| }; |
| |
| AuthorizationSet auth_set(params, array_length(params)); |
| |
| keymaster_error_t kmer1 = |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty)); |
| keymaster_error_t kmer2 = |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty)); |
| keymaster_error_t kmer3 = |
| kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, AuthProxy(auth_set, empty)); |
| |
| ASSERT_EQ(KM_ERROR_OK, kmer1); |
| kmen.tick(2); |
| ASSERT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED, kmer2); |
| |
| // Allowed because it's a pubkey op. |
| ASSERT_EQ(KM_ERROR_OK, kmer3); |
| } |
| |
| TEST_F(KeymasterBaseTest, TestValidTimeBetweenOps) { |
| keymaster_key_param_t params[] = { |
| Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY), |
| Authorization(TAG_MIN_SECONDS_BETWEEN_OPS, 2), |
| }; |
| |
| AuthorizationSet auth_set(params, array_length(params)); |
| |
| EXPECT_EQ(KM_ERROR_OK, |
| kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, AuthProxy(auth_set, empty))); |
| kmen.tick(); |
| EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED, |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty))); |
| kmen.tick(); |
| EXPECT_EQ(KM_ERROR_OK, |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty))); |
| } |
| |
| TEST_F(KeymasterBaseTest, TestOptTimeoutTableOverflow) { |
| keymaster_key_param_t params[] = { |
| Authorization(TAG_ALGORITHM, KM_ALGORITHM_AES), |
| Authorization(TAG_MIN_SECONDS_BETWEEN_OPS, 4), |
| Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY), |
| }; |
| |
| AuthorizationSet auth_set(params, array_length(params)); |
| |
| EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, |
| AuthProxy(auth_set, empty))); |
| |
| kmen.tick(); |
| |
| // Key 1 fails because it's too soon |
| EXPECT_EQ( |
| KM_ERROR_KEY_RATE_LIMIT_EXCEEDED, |
| kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, AuthProxy(auth_set, empty))); |
| |
| EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 2 /* key_id */, |
| AuthProxy(auth_set, empty))); |
| |
| kmen.tick(); |
| |
| // Key 1 fails because it's too soon |
| EXPECT_EQ( |
| KM_ERROR_KEY_RATE_LIMIT_EXCEEDED, |
| kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, AuthProxy(auth_set, empty))); |
| // Key 2 fails because it's too soon |
| EXPECT_EQ( |
| KM_ERROR_KEY_RATE_LIMIT_EXCEEDED, |
| kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 2 /* key_id */, AuthProxy(auth_set, empty))); |
| |
| EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 3 /* key_id */, |
| AuthProxy(auth_set, empty))); |
| |
| kmen.tick(); |
| |
| // Key 1 fails because it's too soon |
| EXPECT_EQ( |
| KM_ERROR_KEY_RATE_LIMIT_EXCEEDED, |
| kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, AuthProxy(auth_set, empty))); |
| // Key 2 fails because it's too soon |
| EXPECT_EQ( |
| KM_ERROR_KEY_RATE_LIMIT_EXCEEDED, |
| kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 2 /* key_id */, AuthProxy(auth_set, empty))); |
| // Key 3 fails because it's too soon |
| EXPECT_EQ( |
| KM_ERROR_KEY_RATE_LIMIT_EXCEEDED, |
| kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 3 /* key_id */, AuthProxy(auth_set, empty))); |
| // Key 4 fails because the table is full |
| EXPECT_EQ( |
| KM_ERROR_TOO_MANY_OPERATIONS, |
| kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 4 /* key_id */, AuthProxy(auth_set, empty))); |
| |
| kmen.tick(); |
| |
| // Key 4 succeeds because key 1 expired. |
| EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 4 /* key_id */, |
| AuthProxy(auth_set, empty))); |
| |
| // Key 1 fails because the table is full... and key 1 is no longer in it. |
| EXPECT_EQ( |
| KM_ERROR_TOO_MANY_OPERATIONS, |
| kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, AuthProxy(auth_set, empty))); |
| // Key 2 fails because it's too soon |
| EXPECT_EQ( |
| KM_ERROR_KEY_RATE_LIMIT_EXCEEDED, |
| kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 2 /* key_id */, AuthProxy(auth_set, empty))); |
| // Key 3 fails because it's too soon |
| EXPECT_EQ( |
| KM_ERROR_KEY_RATE_LIMIT_EXCEEDED, |
| kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 3 /* key_id */, AuthProxy(auth_set, empty))); |
| |
| kmen.tick(); |
| |
| // Key 1 succeeds because key 2 expired |
| EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, |
| AuthProxy(auth_set, empty))); |
| // Key 2 fails because the table is full... and key 2 is no longer in it. |
| EXPECT_EQ( |
| KM_ERROR_TOO_MANY_OPERATIONS, |
| kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 2 /* key_id */, AuthProxy(auth_set, empty))); |
| // Key 3 fails because it's too soon |
| EXPECT_EQ( |
| KM_ERROR_KEY_RATE_LIMIT_EXCEEDED, |
| kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 3 /* key_id */, AuthProxy(auth_set, empty))); |
| // Key 4 fails because it's too soon |
| EXPECT_EQ( |
| KM_ERROR_KEY_RATE_LIMIT_EXCEEDED, |
| kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 4 /* key_id */, AuthProxy(auth_set, empty))); |
| |
| kmen.tick(4); |
| |
| EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, |
| AuthProxy(auth_set, empty))); |
| EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 2 /* key_id */, |
| AuthProxy(auth_set, empty))); |
| EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 3 /* key_id */, |
| AuthProxy(auth_set, empty))); |
| } |
| |
| TEST_F(KeymasterBaseTest, TestPubkeyOptTimeoutTableOverflow) { |
| keymaster_key_param_t params[] = { |
| Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), |
| Authorization(TAG_MIN_SECONDS_BETWEEN_OPS, 4), Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), |
| }; |
| |
| AuthorizationSet auth_set(params, array_length(params)); |
| |
| EXPECT_EQ(KM_ERROR_OK, |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 1 /* key_id */, AuthProxy(auth_set, empty))); |
| |
| kmen.tick(); |
| |
| // Key 1 fails because it's too soon |
| EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED, |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 1 /* key_id */, AuthProxy(auth_set, empty))); |
| // Too soo, but pubkey ops allowed. |
| EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, |
| AuthProxy(auth_set, empty))); |
| } |
| |
| TEST_F(KeymasterBaseTest, TestInvalidPurpose) { |
| keymaster_purpose_t invalidPurpose1 = static_cast<keymaster_purpose_t>(-1); |
| keymaster_purpose_t invalidPurpose2 = static_cast<keymaster_purpose_t>(4); |
| |
| AuthorizationSet auth_set( |
| AuthorizationSetBuilder().Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)); |
| |
| EXPECT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE, |
| kmen.AuthorizeOperation(invalidPurpose1, key_id, AuthProxy(auth_set, empty))); |
| EXPECT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE, |
| kmen.AuthorizeOperation(invalidPurpose2, key_id, AuthProxy(auth_set, empty))); |
| } |
| |
| TEST_F(KeymasterBaseTest, TestIncompatiblePurposeSymmetricKey) { |
| AuthorizationSet auth_set(AuthorizationSetBuilder() |
| .Authorization(TAG_ALGORITHM, KM_ALGORITHM_AES) |
| .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) |
| .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)); |
| |
| EXPECT_EQ(KM_ERROR_OK, |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty))); |
| EXPECT_EQ(KM_ERROR_OK, |
| kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, AuthProxy(auth_set, empty))); |
| |
| EXPECT_EQ(KM_ERROR_INCOMPATIBLE_PURPOSE, |
| kmen.AuthorizeOperation(KM_PURPOSE_ENCRYPT, key_id, AuthProxy(auth_set, empty))); |
| EXPECT_EQ(KM_ERROR_INCOMPATIBLE_PURPOSE, |
| kmen.AuthorizeOperation(KM_PURPOSE_DECRYPT, key_id, AuthProxy(auth_set, empty))); |
| } |
| |
| TEST_F(KeymasterBaseTest, TestIncompatiblePurposeAssymmetricKey) { |
| AuthorizationSet auth_set(AuthorizationSetBuilder() |
| .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA) |
| .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) |
| .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)); |
| |
| EXPECT_EQ(KM_ERROR_OK, |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty))); |
| EXPECT_EQ(KM_ERROR_OK, |
| kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, AuthProxy(auth_set, empty))); |
| |
| // This one is allowed because it's a pubkey op. |
| EXPECT_EQ(KM_ERROR_OK, |
| kmen.AuthorizeOperation(KM_PURPOSE_ENCRYPT, key_id, AuthProxy(auth_set, empty))); |
| EXPECT_EQ(KM_ERROR_INCOMPATIBLE_PURPOSE, |
| kmen.AuthorizeOperation(KM_PURPOSE_DECRYPT, key_id, AuthProxy(auth_set, empty))); |
| } |
| |
| TEST_F(KeymasterBaseTest, TestInvalidCallerNonce) { |
| AuthorizationSet no_caller_nonce(AuthorizationSetBuilder() |
| .Authorization(TAG_PURPOSE, KM_PURPOSE_ENCRYPT) |
| .Authorization(TAG_PURPOSE, KM_PURPOSE_DECRYPT) |
| .Authorization(TAG_ALGORITHM, KM_ALGORITHM_AES)); |
| AuthorizationSet caller_nonce(AuthorizationSetBuilder() |
| .Authorization(TAG_PURPOSE, KM_PURPOSE_ENCRYPT) |
| .Authorization(TAG_PURPOSE, KM_PURPOSE_DECRYPT) |
| .Authorization(TAG_ALGORITHM, KM_ALGORITHM_HMAC) |
| .Authorization(TAG_CALLER_NONCE)); |
| AuthorizationSet begin_params(AuthorizationSetBuilder().Authorization(TAG_NONCE, "foo", 3)); |
| |
| EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation( |
| KM_PURPOSE_ENCRYPT, key_id, AuthProxy(caller_nonce, empty), |
| begin_params, 0 /* challenge */, true /* is_begin_operation */)); |
| EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation( |
| KM_PURPOSE_DECRYPT, key_id, AuthProxy(caller_nonce, empty), |
| begin_params, 0 /* challenge */, true /* is_begin_operation */)); |
| EXPECT_EQ(KM_ERROR_CALLER_NONCE_PROHIBITED, |
| kmen.AuthorizeOperation(KM_PURPOSE_ENCRYPT, key_id, AuthProxy(no_caller_nonce, empty), |
| begin_params, 0 /* challenge */, |
| true /* is_begin_operation */)); |
| EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation( |
| KM_PURPOSE_DECRYPT, key_id, AuthProxy(no_caller_nonce, empty), |
| begin_params, 0 /* challenge */, true /* is_begin_operation */)); |
| } |
| |
| TEST_F(KeymasterBaseTest, TestBootloaderOnly) { |
| AuthorizationSet auth_set(AuthorizationSetBuilder() |
| .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN) |
| .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA) |
| .Authorization(TAG_BOOTLOADER_ONLY)); |
| EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty))); |
| |
| // Pubkey ops allowed. |
| EXPECT_EQ(KM_ERROR_OK, |
| kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, AuthProxy(auth_set, empty))); |
| } |
| |
| TEST_F(KeymasterBaseTest, TestInvalidTag) { |
| AuthorizationSet auth_set(AuthorizationSetBuilder() |
| .Authorization(TAG_INVALID) |
| .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)); |
| |
| EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty))); |
| } |
| |
| TEST_F(KeymasterBaseTest, TestAuthPerOpSuccess) { |
| hw_auth_token_t token; |
| memset(&token, 0, sizeof(token)); |
| token.version = HW_AUTH_TOKEN_VERSION; |
| token.challenge = 99; |
| token.user_id = 9; |
| token.authenticator_id = 0; |
| token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD)); |
| token.timestamp = 0; |
| |
| AuthorizationSet auth_set(AuthorizationSetBuilder() |
| .Authorization(TAG_USER_SECURE_ID, token.user_id) |
| .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY) |
| .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)); |
| |
| AuthorizationSet op_params; |
| op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token))); |
| |
| EXPECT_EQ(KM_ERROR_OK, |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty), |
| op_params, token.challenge, false /* is_begin_operation */)); |
| } |
| |
| TEST_F(KeymasterBaseTest, TestAuthPerOpInvalidTokenSignature) { |
| hw_auth_token_t token; |
| memset(&token, 0, sizeof(token)); |
| token.version = HW_AUTH_TOKEN_VERSION; |
| token.challenge = 99; |
| token.user_id = 9; |
| token.authenticator_id = 0; |
| token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD)); |
| token.timestamp = 0; |
| |
| AuthorizationSet auth_set(AuthorizationSetBuilder() |
| .Authorization(TAG_ALGORITHM, KM_ALGORITHM_EC) |
| .Authorization(TAG_USER_SECURE_ID, token.user_id) |
| .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY) |
| .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)); |
| |
| AuthorizationSet op_params; |
| op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token))); |
| |
| kmen.set_report_token_valid(false); |
| EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED, |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty), |
| op_params, token.challenge, false /* is_begin_operation */)); |
| // Pubkey ops allowed. |
| EXPECT_EQ(KM_ERROR_OK, |
| kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, AuthProxy(auth_set, empty), |
| op_params, token.challenge, false /* is_begin_operation */)); |
| } |
| |
| TEST_F(KeymasterBaseTest, TestAuthPerOpWrongChallenge) { |
| hw_auth_token_t token; |
| memset(&token, 0, sizeof(token)); |
| token.version = HW_AUTH_TOKEN_VERSION; |
| token.challenge = 99; |
| token.user_id = 9; |
| token.authenticator_id = 0; |
| token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD)); |
| token.timestamp = 0; |
| |
| AuthorizationSet auth_set(AuthorizationSetBuilder() |
| .Authorization(TAG_USER_SECURE_ID, token.user_id) |
| .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY) |
| .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)); |
| |
| AuthorizationSet op_params; |
| op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token))); |
| |
| EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED, |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty), |
| op_params, token.challenge + 1 /* doesn't match token */, |
| false /* is_begin_operation */)); |
| } |
| |
| TEST_F(KeymasterBaseTest, TestAuthPerOpNoAuthType) { |
| hw_auth_token_t token; |
| memset(&token, 0, sizeof(token)); |
| token.version = HW_AUTH_TOKEN_VERSION; |
| token.challenge = 99; |
| token.user_id = 9; |
| token.authenticator_id = 0; |
| token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD)); |
| token.timestamp = 0; |
| |
| AuthorizationSet auth_set(AuthorizationSetBuilder() |
| .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA) |
| .Authorization(TAG_USER_SECURE_ID, token.user_id) |
| .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)); |
| |
| AuthorizationSet op_params; |
| op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token))); |
| |
| EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED, |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty), |
| op_params, token.challenge, false /* is_begin_operation */)); |
| // Pubkey ops allowed. |
| EXPECT_EQ(KM_ERROR_OK, |
| kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, AuthProxy(auth_set, empty), |
| op_params, token.challenge, false /* is_begin_operation */)); |
| } |
| |
| TEST_F(KeymasterBaseTest, TestAuthPerOpWrongAuthType) { |
| hw_auth_token_t token; |
| memset(&token, 0, sizeof(token)); |
| token.version = HW_AUTH_TOKEN_VERSION; |
| token.challenge = 99; |
| token.user_id = 9; |
| token.authenticator_id = 0; |
| token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD)); |
| token.timestamp = 0; |
| |
| AuthorizationSet auth_set( |
| AuthorizationSetBuilder() |
| .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA) |
| .Authorization(TAG_USER_SECURE_ID, token.user_id) |
| .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_FINGERPRINT /* doesn't match token */) |
| .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)); |
| |
| AuthorizationSet op_params; |
| op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token))); |
| |
| EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED, |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty), |
| op_params, token.challenge, false /* is_begin_operation */)); |
| // Pubkey ops allowed. |
| EXPECT_EQ(KM_ERROR_OK, |
| kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, AuthProxy(auth_set, empty), |
| op_params, token.challenge, false /* is_begin_operation */)); |
| } |
| |
| TEST_F(KeymasterBaseTest, TestAuthPerOpWrongSid) { |
| hw_auth_token_t token; |
| memset(&token, 0, sizeof(token)); |
| token.version = HW_AUTH_TOKEN_VERSION; |
| token.challenge = 99; |
| token.user_id = 9; |
| token.authenticator_id = 0; |
| token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD)); |
| token.timestamp = 0; |
| |
| AuthorizationSet auth_set( |
| AuthorizationSetBuilder() |
| .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA) |
| .Authorization(TAG_USER_SECURE_ID, token.user_id + 1 /* doesn't match token */) |
| .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY) |
| .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)); |
| |
| AuthorizationSet op_params; |
| op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token))); |
| |
| EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED, |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty), |
| op_params, token.challenge, false /* is_begin_operation */)); |
| // Pubkey op allowed. |
| EXPECT_EQ(KM_ERROR_OK, |
| kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, AuthProxy(auth_set, empty), |
| op_params, token.challenge, false /* is_begin_operation */)); |
| } |
| |
| TEST_F(KeymasterBaseTest, TestAuthPerOpSuccessAlternateSid) { |
| hw_auth_token_t token; |
| memset(&token, 0, sizeof(token)); |
| token.version = HW_AUTH_TOKEN_VERSION; |
| token.challenge = 99; |
| token.user_id = 9; |
| token.authenticator_id = 10; |
| token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD)); |
| token.timestamp = 0; |
| |
| AuthorizationSet auth_set(AuthorizationSetBuilder() |
| .Authorization(TAG_USER_SECURE_ID, token.authenticator_id) |
| .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY) |
| .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)); |
| |
| AuthorizationSet op_params; |
| op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token))); |
| |
| EXPECT_EQ(KM_ERROR_OK, |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty), |
| op_params, token.challenge, false /* is_begin_operation */)); |
| } |
| |
| TEST_F(KeymasterBaseTest, TestAuthPerOpMissingToken) { |
| hw_auth_token_t token; |
| memset(&token, 0, sizeof(token)); |
| token.version = HW_AUTH_TOKEN_VERSION; |
| token.challenge = 99; |
| token.user_id = 9; |
| token.authenticator_id = 0; |
| token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD)); |
| token.timestamp = 0; |
| |
| AuthorizationSet auth_set(AuthorizationSetBuilder() |
| .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA) |
| .Authorization(TAG_USER_SECURE_ID, token.user_id) |
| .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY) |
| .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)); |
| |
| AuthorizationSet op_params; |
| |
| // During begin we can skip the auth token |
| EXPECT_EQ(KM_ERROR_OK, |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty), |
| op_params, token.challenge, true /* is_begin_operation */)); |
| // Afterwards we must have authentication |
| EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED, |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty), |
| op_params, token.challenge, false /* is_begin_operation */)); |
| // Pubkey ops allowed |
| EXPECT_EQ(KM_ERROR_OK, |
| kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, AuthProxy(auth_set, empty), |
| op_params, token.challenge, false /* is_begin_operation */)); |
| |
| auth_set.Reinitialize(AuthorizationSetBuilder() |
| .Authorization(TAG_ALGORITHM, KM_ALGORITHM_AES) |
| .Authorization(TAG_USER_SECURE_ID, token.user_id) |
| .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY) |
| .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN) |
| .build()); |
| |
| EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED, |
| kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, AuthProxy(auth_set, empty), |
| op_params, token.challenge, false /* is_begin_operation */)); |
| } |
| |
| TEST_F(KeymasterBaseTest, TestAuthAndNoAuth) { |
| AuthorizationSet auth_set(AuthorizationSetBuilder() |
| .Authorization(TAG_USER_SECURE_ID, 1) |
| .Authorization(TAG_NO_AUTH_REQUIRED) |
| .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)); |
| |
| EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty))); |
| } |
| |
| TEST_F(KeymasterBaseTest, TestTimedAuthSuccess) { |
| hw_auth_token_t token; |
| memset(&token, 0, sizeof(token)); |
| token.version = HW_AUTH_TOKEN_VERSION; |
| token.challenge = 99; |
| token.user_id = 9; |
| token.authenticator_id = 0; |
| token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD)); |
| token.timestamp = hton(kmen.current_time()); |
| |
| AuthorizationSet auth_set(AuthorizationSetBuilder() |
| .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA) |
| .Authorization(TAG_USER_SECURE_ID, token.user_id) |
| .Authorization(TAG_AUTH_TIMEOUT, 1) |
| .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY) |
| .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)); |
| |
| AuthorizationSet op_params; |
| op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token))); |
| |
| EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation( |
| KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty), op_params, |
| 0 /* irrelevant */, false /* is_begin_operation */)); |
| } |
| |
| TEST_F(KeymasterBaseTest, TestTimedAuthTimedOut) { |
| hw_auth_token_t token; |
| memset(&token, 0, sizeof(token)); |
| token.version = HW_AUTH_TOKEN_VERSION; |
| token.challenge = 99; |
| token.user_id = 9; |
| token.authenticator_id = 0; |
| token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD)); |
| token.timestamp = hton(static_cast<uint64_t>(kmen.current_time())); |
| |
| AuthorizationSet auth_set(AuthorizationSetBuilder() |
| .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA) |
| .Authorization(TAG_USER_SECURE_ID, token.user_id) |
| .Authorization(TAG_AUTH_TIMEOUT, 1) |
| .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY) |
| .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)); |
| |
| AuthorizationSet op_params; |
| op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token))); |
| |
| EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation( |
| KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty), op_params, |
| 0 /* irrelevant */, false /* is_begin_operation */)); |
| |
| kmen.tick(1); |
| |
| // token still good |
| EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation( |
| KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty), op_params, |
| 0 /* irrelevant */, false /* is_begin_operation */)); |
| |
| kmen.tick(1); |
| |
| // token expired, not allowed during begin. |
| EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED, |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty), |
| op_params, 0 /* irrelevant */, |
| true /* is_begin_operation */)); |
| |
| // token expired, afterwards it's okay. |
| EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation( |
| KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty), op_params, |
| 0 /* irrelevant */, false /* is_begin_operation */)); |
| |
| // Pubkey ops allowed. |
| EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation( |
| KM_PURPOSE_VERIFY, key_id, AuthProxy(auth_set, empty), op_params, |
| 0 /* irrelevant */, true /* is_begin_operation */)); |
| } |
| |
| TEST_F(KeymasterBaseTest, TestTimedAuthMissingToken) { |
| hw_auth_token_t token; |
| memset(&token, 0, sizeof(token)); |
| token.version = HW_AUTH_TOKEN_VERSION; |
| token.challenge = 99; |
| token.user_id = 9; |
| token.authenticator_id = 0; |
| token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD)); |
| token.timestamp = hton(static_cast<uint64_t>(kmen.current_time())); |
| |
| AuthorizationSet auth_set(AuthorizationSetBuilder() |
| .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA) |
| .Authorization(TAG_USER_SECURE_ID, token.user_id) |
| .Authorization(TAG_AUTH_TIMEOUT, 1) |
| .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY) |
| .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)); |
| |
| AuthorizationSet op_params; |
| |
| // Unlike auth-per-op, must have the auth token during begin. |
| EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED, |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty), |
| op_params, token.challenge, true /* is_begin_operation */)); |
| |
| // Later we don't check (though begin would fail, so there wouldn't be a later). |
| EXPECT_EQ(KM_ERROR_OK, |
| kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, AuthProxy(auth_set, empty), |
| op_params, token.challenge, false /* is_begin_operation */)); |
| |
| // Pubkey ops allowed. |
| EXPECT_EQ(KM_ERROR_OK, |
| kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, AuthProxy(auth_set, empty), |
| op_params, token.challenge, true /* is_begin_operation */)); |
| } |
| |
| TEST_F(KeymasterBaseTest, TestCreateKeyId) { |
| keymaster_key_blob_t blob = {reinterpret_cast<const uint8_t*>("foobar"), 6}; |
| |
| km_id_t key_id = 0; |
| EXPECT_TRUE(kmen.CreateKeyId(blob, &key_id)); |
| EXPECT_NE(0U, key_id); |
| } |
| |
| }; /* namespace test */ |
| }; /* namespace keymaster */ |