/* * 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 #include #include #include #include #include #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(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(-1); keymaster_purpose_t invalidPurpose2 = static_cast(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(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(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(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(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(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(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(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(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(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(HW_AUTH_PASSWORD)); token.timestamp = hton(static_cast(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(HW_AUTH_PASSWORD)); token.timestamp = hton(static_cast(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("foobar"), 6}; km_id_t key_id = 0; EXPECT_TRUE(kmen.CreateKeyId(blob, &key_id)); EXPECT_NE(0U, key_id); } }; /* namespace test */ }; /* namespace keymaster */