Merge "KeyMint/SecureClock: Reverse dependency between keymint and secureclock."

This commit is contained in:
Treehugger Robot
2021-01-20 16:03:59 +00:00
committed by Gerrit Code Review
16 changed files with 23 additions and 316 deletions

View File

@@ -4,6 +4,9 @@ aidl_interface {
srcs: [
"android/hardware/security/keymint/*.aidl",
],
imports: [
"android.hardware.security.secureclock",
],
stability: "vintf",
backend: {
java: {

View File

@@ -23,6 +23,6 @@ parcelable HardwareAuthToken {
long userId;
long authenticatorId;
android.hardware.security.keymint.HardwareAuthenticatorType authenticatorType;
android.hardware.security.keymint.Timestamp timestamp;
android.hardware.security.secureclock.Timestamp timestamp;
byte[] mac;
}

View File

@@ -20,7 +20,6 @@ package android.hardware.security.keymint;
@VintfStability
interface IKeyMintDevice {
android.hardware.security.keymint.KeyMintHardwareInfo getHardwareInfo();
android.hardware.security.keymint.VerificationToken verifyAuthorization(in long challenge, in android.hardware.security.keymint.HardwareAuthToken token);
void addRngEntropy(in byte[] data);
android.hardware.security.keymint.KeyCreationResult generateKey(in android.hardware.security.keymint.KeyParameter[] keyParams);
android.hardware.security.keymint.KeyCreationResult importKey(in android.hardware.security.keymint.KeyParameter[] keyParams, in android.hardware.security.keymint.KeyFormat keyFormat, in byte[] keyData);

View File

@@ -19,7 +19,7 @@
package android.hardware.security.keymint;
@VintfStability
interface IKeyMintOperation {
int update(in @nullable android.hardware.security.keymint.KeyParameterArray inParams, in @nullable byte[] input, in @nullable android.hardware.security.keymint.HardwareAuthToken inAuthToken, in @nullable android.hardware.security.keymint.VerificationToken inVerificationToken, out @nullable android.hardware.security.keymint.KeyParameterArray outParams, out @nullable android.hardware.security.keymint.ByteArray output);
byte[] finish(in @nullable android.hardware.security.keymint.KeyParameterArray inParams, in @nullable byte[] input, in @nullable byte[] inSignature, in @nullable android.hardware.security.keymint.HardwareAuthToken authToken, in @nullable android.hardware.security.keymint.VerificationToken inVerificationToken, out @nullable android.hardware.security.keymint.KeyParameterArray outParams);
int update(in @nullable android.hardware.security.keymint.KeyParameterArray inParams, in @nullable byte[] input, in @nullable android.hardware.security.keymint.HardwareAuthToken inAuthToken, in @nullable android.hardware.security.secureclock.TimeStampToken inTimeStampToken, out @nullable android.hardware.security.keymint.KeyParameterArray outParams, out @nullable android.hardware.security.keymint.ByteArray output);
byte[] finish(in @nullable android.hardware.security.keymint.KeyParameterArray inParams, in @nullable byte[] input, in @nullable byte[] inSignature, in @nullable android.hardware.security.keymint.HardwareAuthToken authToken, in @nullable android.hardware.security.secureclock.TimeStampToken inTimeStampToken, out @nullable android.hardware.security.keymint.KeyParameterArray outParams);
void abort();
}

View File

@@ -1,26 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.security.keymint;
@VintfStability
parcelable VerificationToken {
long challenge;
android.hardware.security.keymint.Timestamp timestamp;
android.hardware.security.keymint.SecurityLevel securityLevel;
byte[] mac;
}

View File

@@ -16,7 +16,7 @@
package android.hardware.security.keymint;
import android.hardware.security.keymint.Timestamp;
import android.hardware.security.secureclock.Timestamp;
import android.hardware.security.keymint.HardwareAuthenticatorType;
/**

View File

@@ -26,7 +26,7 @@ import android.hardware.security.keymint.KeyParameter;
import android.hardware.security.keymint.KeyMintHardwareInfo;
import android.hardware.security.keymint.KeyPurpose;
import android.hardware.security.keymint.SecurityLevel;
import android.hardware.security.keymint.VerificationToken;
import android.hardware.security.secureclock.TimeStampToken;
/**
* KeyMint device definition.
@@ -222,34 +222,6 @@ interface IKeyMintDevice {
*/
KeyMintHardwareInfo getHardwareInfo();
/**
* Verify authorizations for another IKeyMintDevice instance.
*
* On systems with both a StrongBox and a TEE IKeyMintDevice instance it is sometimes useful
* to ask the TEE KeyMintDevice to verify authorizations for a key hosted in StrongBox.
*
* For every StrongBox operation, Keystore is required to call this method on the TEE KeyMint,
* passing in the StrongBox key's hardwareEnforced authorization list and the challenge
* returned by StrongBox begin(). Keystore must then pass the VerificationToken to the
* subsequent invocations of StrongBox update() and finish().
*
* StrongBox implementations must return ErrorCode::UNIMPLEMENTED.
*
* @param the challenge returned by StrongBox's keyMint's begin().
*
* @param authToken A HardwareAuthToken if needed to authorize key usage.
*
* @return error ErrorCode::OK on success or ErrorCode::UNIMPLEMENTED if the KeyMintDevice is
* a StrongBox. If the IKeyMintDevice cannot verify one or more elements of
* parametersToVerify it must not return an error code, but just omit the unverified
* parameter from the VerificationToken.
*
* @return token the verification token. See VerificationToken in VerificationToken.aidl for
* details.
*/
VerificationToken verifyAuthorization(in long challenge,
in HardwareAuthToken token);
/**
* Adds entropy to the RNG used by KeyMint. Entropy added through this method must not be the
* only source of entropy used, and a secure mixing function must be used to mix the entropy

View File

@@ -20,7 +20,7 @@ import android.hardware.security.keymint.ByteArray;
import android.hardware.security.keymint.HardwareAuthToken;
import android.hardware.security.keymint.KeyParameter;
import android.hardware.security.keymint.KeyParameterArray;
import android.hardware.security.keymint.VerificationToken;
import android.hardware.security.secureclock.TimeStampToken;
@VintfStability
interface IKeyMintOperation {
@@ -119,10 +119,9 @@ interface IKeyMintOperation {
* @param input Data to be processed. Note that update() may or may not consume all of the data
* provided. See return value.
*
* @param verificationToken Verification token, used to prove that another IKeymasterDevice HAL
* has verified some parameters, and to deliver the other HAL's current timestamp, if
* needed. If not provided, all fields must be initialized to zero and vectors must be
* empty.
* @param inTimeStampToken timestamp token, certifies the freshness of an auth token in case
* the security domain of this KeyMint instance has a different clock than the
* authenticator issuing the auth token.
*
* @return error Returns ErrorCode encountered in keymint as service specific errors. See the
* ErrorCode enum in ErrorCode.aidl.
@@ -141,7 +140,7 @@ interface IKeyMintOperation {
int update(in @nullable KeyParameterArray inParams,
in @nullable byte[] input,
in @nullable HardwareAuthToken inAuthToken,
in @nullable VerificationToken inVerificationToken,
in @nullable TimeStampToken inTimeStampToken,
out @nullable KeyParameterArray outParams,
out @nullable ByteArray output);
@@ -241,9 +240,9 @@ interface IKeyMintOperation {
*
* @param authToken Authentication token. Can be nullable if not provided.
*
* @param verificationToken Verification token, used to prove that another IKeyMintDevice HAL
* has verified some parameters, and to deliver the other HAL's current timestamp, if
* needed. Can be nullable if not needed.
* @param inTimeStampToken timestamp token, certifies the freshness of an auth token in case
* the security domain of this KeyMint instance has a different clock than the
* authenticator issuing the auth token.
*
* @return outParams Any output parameters generated by finish().
*
@@ -252,7 +251,7 @@ interface IKeyMintOperation {
byte[] finish(in @nullable KeyParameterArray inParams, in @nullable byte[] input,
in @nullable byte[] inSignature,
in @nullable HardwareAuthToken authToken,
in @nullable VerificationToken inVerificationToken,
in @nullable TimeStampToken inTimeStampToken,
out @nullable KeyParameterArray outParams);
/**

View File

@@ -1,63 +0,0 @@
/*
* Copyright (C) 2020 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.
*/
package android.hardware.security.keymint;
import android.hardware.security.keymint.SecurityLevel;
import android.hardware.security.keymint.Timestamp;
/**
* VerificationToken instances are used for secure environments to authenticate one another.
*
* This version of the parcelable currently don't use the parametersVerified field since it's not
* needed for time-based verification. This can be added in a later version, if needed.
*/
@VintfStability
parcelable VerificationToken {
/**
* The operation handle, used to ensure freshness.
*/
long challenge;
/**
* The current time of the secure environment that generates the VerificationToken. This can be
* checked against auth tokens generated by the same secure environment, which avoids needing to
* synchronize clocks.
*/
Timestamp timestamp;
/**
* SecurityLevel of the secure environment that generated the token.
*/
SecurityLevel securityLevel;
/**
* 32-byte HMAC-SHA256 of the above values, computed as:
*
* HMAC(H,
* "Auth Verification" || challenge || timestamp || securityLevel)
*
* where:
*
* ``HMAC'' is the shared HMAC key (see computeSharedHmac() in IKeyMint).
*
* ``||'' represents concatenation
*
* The representation of challenge and timestamp is as 64-bit unsigned integers in big-endian
* order. securityLevel is represented as a 32-bit unsigned integer in big-endian order.
*/
byte[] mac;
}

View File

@@ -22,7 +22,6 @@ cc_test {
],
srcs: [
"KeyMintTest.cpp",
"VerificationTokenTest.cpp",
],
shared_libs: [
"libbinder_ndk",
@@ -32,6 +31,7 @@ cc_test {
],
static_libs: [
"android.hardware.security.keymint-unstable-ndk_platform",
"android.hardware.security.secureclock-unstable-ndk_platform",
"libcppbor_external",
"libkeymint_vts_test_utils",
],
@@ -61,6 +61,7 @@ cc_test_library {
],
static_libs: [
"android.hardware.security.keymint-unstable-ndk_platform",
"android.hardware.security.secureclock-unstable-ndk_platform",
"libcppbor",
],
}

View File

@@ -1,168 +0,0 @@
/*
* Copyright (C) 2020 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 "KeyMintAidlTestBase.h"
namespace aidl::android::hardware::security::keymint::test {
class VerificationTokenTest : public KeyMintAidlTestBase {
protected:
struct VerifyAuthorizationResult {
ErrorCode error;
VerificationToken token;
};
VerifyAuthorizationResult verifyAuthorization(uint64_t operationHandle,
const HardwareAuthToken& authToken) {
VerifyAuthorizationResult result;
Status err;
err = keyMint().verifyAuthorization(operationHandle, //
authToken, //
&result.token);
result.error = GetReturnErrorCode(err);
return result;
}
uint64_t getTime() {
struct timespec timespec;
EXPECT_EQ(0, clock_gettime(CLOCK_BOOTTIME, &timespec));
return timespec.tv_sec * 1000 + timespec.tv_nsec / 1000000;
}
int sleep_ms(uint32_t milliseconds) {
struct timespec sleep_time = {static_cast<time_t>(milliseconds / 1000),
static_cast<long>(milliseconds % 1000) * 1000000};
while (sleep_time.tv_sec || sleep_time.tv_nsec) {
if (nanosleep(&sleep_time /* to wait */,
&sleep_time /* remaining (on interrruption) */) == 0) {
sleep_time = {};
} else {
if (errno != EINTR) return errno;
}
}
return 0;
}
};
/*
* VerificationTokens exist to facilitate cross-KeyMint verification of requirements. As
* such, the precise capabilities required will vary depending on the specific vendor
* implementations. Essentially, VerificationTokens are a "hook" to enable vendor
* implementations to communicate, so the precise usage is defined by those vendors. The only
* thing we really can test is that tokens can be created by TEE keyMints, and that the
* timestamps increase as expected.
*/
TEST_P(VerificationTokenTest, TestCreation) {
auto result1 = verifyAuthorization(1 /* operation handle */, HardwareAuthToken());
auto result1_time = getTime();
if (SecLevel() == SecurityLevel::STRONGBOX) {
// StrongBox should not implement verifyAuthorization.
EXPECT_EQ(ErrorCode::UNIMPLEMENTED, result1.error);
return;
}
ASSERT_EQ(ErrorCode::OK, result1.error);
EXPECT_EQ(1U, result1.token.challenge);
EXPECT_EQ(SecLevel(), result1.token.securityLevel);
EXPECT_GT(result1.token.timestamp.milliSeconds, 0U);
constexpr uint32_t time_to_sleep = 200;
sleep_ms(time_to_sleep);
auto result2 = verifyAuthorization(2 /* operation handle */, HardwareAuthToken());
auto result2_time = getTime();
ASSERT_EQ(ErrorCode::OK, result2.error);
EXPECT_EQ(2U, result2.token.challenge);
EXPECT_EQ(SecLevel(), result2.token.securityLevel);
auto host_time_delta = result2_time - result1_time;
EXPECT_GE(host_time_delta, time_to_sleep)
<< "We slept for " << time_to_sleep << " ms, the clock must have advanced by that much";
EXPECT_LE(host_time_delta, time_to_sleep + 20)
<< "The verifyAuthorization call took " << (host_time_delta - time_to_sleep)
<< " ms? That's awful!";
auto km_time_delta =
result2.token.timestamp.milliSeconds - result1.token.timestamp.milliSeconds;
// If not too much else is going on on the system, the time delta should be quite close. Allow
// 2 ms of slop just to avoid test flakiness.
//
// TODO(swillden): see if we can output values so they can be gathered across many runs and
// report if times aren't nearly always <1ms apart.
EXPECT_LE(host_time_delta, km_time_delta + 2);
EXPECT_LE(km_time_delta, host_time_delta + 2);
ASSERT_EQ(result1.token.mac.size(), result2.token.mac.size());
ASSERT_NE(0,
memcmp(result1.token.mac.data(), result2.token.mac.data(), result1.token.mac.size()));
}
/*
* Test that the mac changes when the time stamp changes. This is does not guarantee that the time
* stamp is included in the mac but on failure we know that it is not. Other than in the test
* case above we call verifyAuthorization with the exact same set of parameters.
*/
TEST_P(VerificationTokenTest, MacChangesOnChangingTimestamp) {
auto result1 = verifyAuthorization(0 /* operation handle */, HardwareAuthToken());
auto result1_time = getTime();
if (SecLevel() == SecurityLevel::STRONGBOX) {
// StrongBox should not implement verifyAuthorization.
EXPECT_EQ(ErrorCode::UNIMPLEMENTED, result1.error);
return;
}
EXPECT_EQ(ErrorCode::OK, result1.error);
EXPECT_EQ(0U, result1.token.challenge);
EXPECT_EQ(SecLevel(), result1.token.securityLevel);
EXPECT_GT(result1.token.timestamp.milliSeconds, 0U);
constexpr uint32_t time_to_sleep = 200;
sleep_ms(time_to_sleep);
auto result2 = verifyAuthorization(0 /* operation handle */, HardwareAuthToken());
// ASSERT_TRUE(result2.callSuccessful);
auto result2_time = getTime();
EXPECT_EQ(ErrorCode::OK, result2.error);
EXPECT_EQ(0U, result2.token.challenge);
EXPECT_EQ(SecLevel(), result2.token.securityLevel);
auto host_time_delta = result2_time - result1_time;
EXPECT_GE(host_time_delta, time_to_sleep)
<< "We slept for " << time_to_sleep << " ms, the clock must have advanced by that much";
EXPECT_LE(host_time_delta, time_to_sleep + 20)
<< "The verifyAuthorization call took " << (host_time_delta - time_to_sleep)
<< " ms? That's awful!";
auto km_time_delta =
result2.token.timestamp.milliSeconds - result1.token.timestamp.milliSeconds;
EXPECT_LE(host_time_delta, km_time_delta + 2);
EXPECT_LE(km_time_delta, host_time_delta + 2);
ASSERT_EQ(result1.token.mac.size(), result2.token.mac.size());
ASSERT_NE(0,
memcmp(result1.token.mac.data(), result2.token.mac.data(), result1.token.mac.size()));
}
INSTANTIATE_KEYMINT_AIDL_TEST(VerificationTokenTest);
} // namespace aidl::android::hardware::security::keymint::test

View File

@@ -5,9 +5,6 @@ aidl_interface {
"android/hardware/security/secureclock/*.aidl",
],
stability: "vintf",
imports: [
"android.hardware.security.keymint",
],
backend: {
java: {
sdk_version: "module_current",

View File

@@ -20,7 +20,6 @@ package android.hardware.security.secureclock;
@VintfStability
parcelable TimeStampToken {
long challenge;
android.hardware.security.keymint.Timestamp timestamp;
android.hardware.security.keymint.SecurityLevel securityLevel;
android.hardware.security.secureclock.Timestamp timestamp;
byte[] mac;
}

View File

@@ -16,7 +16,7 @@
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.security.keymint;
package android.hardware.security.secureclock;
@VintfStability
parcelable Timestamp {
long milliSeconds;

View File

@@ -16,8 +16,7 @@
package android.hardware.security.secureclock;
import android.hardware.security.keymint.SecurityLevel;
import android.hardware.security.keymint.Timestamp;
import android.hardware.security.secureclock.Timestamp;
/**
* TimeStampToken instances are used for secure environments that requires secure time information.
@@ -35,11 +34,6 @@ parcelable TimeStampToken {
*/
Timestamp timestamp;
/**
* SecurityLevel of the secure environment that generated the token.
*/
SecurityLevel securityLevel;
/**
* 32-byte HMAC-SHA256 of the above values, computed as:
*

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package android.hardware.security.keymint;
package android.hardware.security.secureclock;
/**
* Time in milliseconds since some arbitrary point in time. Time must be monotonically increasing,