Merge "Identity Credential: Add method to accept verification token."

This commit is contained in:
Treehugger Robot 2020-05-11 17:28:43 +00:00 committed by Gerrit Code Review
commit 1ac087e4d6
21 changed files with 449 additions and 30 deletions

View file

@ -1 +1 @@
3b0b10b618dbc4bf283aa2bf78833ad3de0a5928
194e04be642728623d65ec8321a3764fdea52ae0

View file

@ -28,4 +28,5 @@ interface IIdentityCredential {
void finishRetrieval(out byte[] mac, out byte[] deviceNameSpaces);
android.hardware.identity.Certificate generateSigningKeyPair(out byte[] signingKeyBlob);
void setRequestedNamespaces(in android.hardware.identity.RequestNamespace[] requestNamespaces);
void setVerificationToken(in android.hardware.keymaster.VerificationToken verificationToken);
}

View file

@ -28,4 +28,5 @@ interface IIdentityCredential {
void finishRetrieval(out byte[] mac, out byte[] deviceNameSpaces);
android.hardware.identity.Certificate generateSigningKeyPair(out byte[] signingKeyBlob);
void setRequestedNamespaces(in android.hardware.identity.RequestNamespace[] requestNamespaces);
void setVerificationToken(in android.hardware.keymaster.VerificationToken verificationToken);
}

View file

@ -20,6 +20,7 @@ import android.hardware.identity.Certificate;
import android.hardware.identity.RequestNamespace;
import android.hardware.identity.SecureAccessControlProfile;
import android.hardware.keymaster.HardwareAuthToken;
import android.hardware.keymaster.VerificationToken;
@VintfStability
interface IIdentityCredential {
@ -71,10 +72,11 @@ interface IIdentityCredential {
/**
* Creates a challenge value to be used for proving successful user authentication. This
* is included in the authToken passed to the startRetrieval() method.
* is included in the authToken passed to the startRetrieval() method and the
* verificationToken passed to the setVerificationToken() method.
*
* This method may only be called once per instance. If called more than once, STATUS_FAILED
* will be returned.
* will be returned. If user authentication is not needed, this method may not be called.
*
* @return challenge, a non-zero number.
*/
@ -83,7 +85,8 @@ interface IIdentityCredential {
/**
* Start an entry retrieval process.
*
* The setRequestedNamespaces() method will be called before this method.
* The setRequestedNamespaces() and setVerificationToken() methods will be called before
* this method is called.
*
* This method be called after createEphemeralKeyPair(), setReaderEphemeralPublicKey(),
* createAuthChallenge() and before startRetrieveEntry(). This method call is followed by
@ -96,7 +99,19 @@ interface IIdentityCredential {
* must be identical for each startRetrieval() invocation. If this is not the case, this call
* fails with the STATUS_SESSION_TRANSCRIPT_MISMATCH error.
*
* If the provided authToken is not valid this method fails with STATUS_INVALID_AUTH_TOKEN.
* If either authToken or verificationToken (as passed with setVerificationToken())
* is not valid this method fails with STATUS_INVALID_AUTH_TOKEN. Note that valid tokens
* are only passed if they are actually needed and available (this can be detected by
* the timestamp being set to zero). For example, if no data items with access control
* profiles using user authentication are requested, the tokens are not filled in.
* It's also possible that no usable auth token is actually available (it could be the user
* never unlocked the device within the timeouts in the access control profiles) and
* in this case the tokens aren't filled in either.
*
* For test credentials (identified by the testCredential boolean in the CredentialData
* CBOR created at provisioning time), the |mac| field in both the authToken and
* verificationToken should not be checked against the shared HMAC key (see IKeyMasterDevice
* for details). This is to enable VTS tests to check for correct behavior.
*
* Each of the provided accessControlProfiles is checked in this call. If they are not
* all valid, the call fails with STATUS_INVALID_DATA.
@ -179,7 +194,8 @@ interface IIdentityCredential {
*
* @param authToken
* The authentication token that proves the user was authenticated, as required
* by one or more of the provided accessControlProfiles. See above.
* by one or more of the provided accessControlProfiles. This token is only valid
* if the timestamp field is non-zero. See above.
*
* @param itemsRequest
* If non-empty, contains request data that is signed by the reader. See above.
@ -358,4 +374,13 @@ interface IIdentityCredential {
* @param requestNamespaces Namespaces and data items which will be requested.
*/
void setRequestedNamespaces(in RequestNamespace[] requestNamespaces);
/**
* Sets the VerificationToken. This method must be called before startRetrieval() is
* called. This token uses the same challenge as returned by createAuthChallenge().
*
* @param verificationToken
* The verification token. This token is only valid if the timestamp field is non-zero.
*/
void setVerificationToken(in VerificationToken verificationToken);
}

View file

@ -198,15 +198,8 @@ bool checkReaderAuthentication(const SecureAccessControlProfile& profile,
return false;
}
Timestamp clockGetTime() {
struct timespec time;
clock_gettime(CLOCK_MONOTONIC, &time);
Timestamp ts;
ts.milliSeconds = time.tv_sec * 1000 + time.tv_nsec / 1000000;
return ts;
}
bool checkUserAuthentication(const SecureAccessControlProfile& profile,
const VerificationToken& verificationToken,
const HardwareAuthToken& authToken, uint64_t authChallenge) {
if (profile.secureUserId != authToken.userId) {
LOG(ERROR) << "secureUserId in profile (" << profile.secureUserId
@ -214,6 +207,15 @@ bool checkUserAuthentication(const SecureAccessControlProfile& profile,
return false;
}
if (verificationToken.timestamp.milliSeconds == 0) {
LOG(ERROR) << "VerificationToken is not set";
return false;
}
if (authToken.timestamp.milliSeconds == 0) {
LOG(ERROR) << "AuthToken is not set";
return false;
}
if (profile.timeoutMillis == 0) {
if (authToken.challenge == 0) {
LOG(ERROR) << "No challenge in authToken";
@ -227,19 +229,11 @@ bool checkUserAuthentication(const SecureAccessControlProfile& profile,
return true;
}
// Note that the Epoch for timestamps in HardwareAuthToken is at the
// discretion of the vendor:
// Timeout-based user auth follows. The verification token conveys what the
// time is right now in the environment which generated the auth token. This
// is what makes it possible to do timeout-based checks.
//
// "[...] since some starting point (generally the most recent device
// boot) which all of the applications within one secure environment
// must agree upon."
//
// Therefore, if this software implementation is used on a device which isn't
// the emulator then the assumption that the epoch is the same as used in
// clockGetTime above will not hold. This is OK as this software
// implementation should never be used on a real device.
//
Timestamp now = clockGetTime();
const Timestamp now = verificationToken.timestamp;
if (authToken.timestamp.milliSeconds > now.milliSeconds) {
LOG(ERROR) << "Timestamp in authToken (" << authToken.timestamp.milliSeconds
<< ") is in the future (now: " << now.milliSeconds << ")";
@ -261,6 +255,12 @@ ndk::ScopedAStatus IdentityCredential::setRequestedNamespaces(
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus IdentityCredential::setVerificationToken(
const VerificationToken& verificationToken) {
verificationToken_ = verificationToken;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus IdentityCredential::startRetrieval(
const vector<SecureAccessControlProfile>& accessControlProfiles,
const HardwareAuthToken& authToken, const vector<uint8_t>& itemsRequest,
@ -483,7 +483,8 @@ ndk::ScopedAStatus IdentityCredential::startRetrieval(
}
int accessControlCheck = IIdentityCredentialStore::STATUS_OK;
if (profile.userAuthenticationRequired) {
if (!haveAuthToken || !checkUserAuthentication(profile, authToken, authChallenge_)) {
if (!haveAuthToken ||
!checkUserAuthentication(profile, verificationToken_, authToken, authChallenge_)) {
accessControlCheck = IIdentityCredentialStore::STATUS_USER_AUTHENTICATION_FAILED;
}
} else if (profile.readerCertificate.encodedCertificate.size() > 0) {

View file

@ -19,6 +19,7 @@
#include <aidl/android/hardware/identity/BnIdentityCredential.h>
#include <aidl/android/hardware/keymaster/HardwareAuthToken.h>
#include <aidl/android/hardware/keymaster/VerificationToken.h>
#include <android/hardware/identity/support/IdentityCredentialSupport.h>
#include <map>
@ -31,6 +32,7 @@
namespace aidl::android::hardware::identity {
using ::aidl::android::hardware::keymaster::HardwareAuthToken;
using ::aidl::android::hardware::keymaster::VerificationToken;
using ::std::map;
using ::std::set;
using ::std::string;
@ -55,6 +57,7 @@ class IdentityCredential : public BnIdentityCredential {
ndk::ScopedAStatus createAuthChallenge(int64_t* outChallenge) override;
ndk::ScopedAStatus setRequestedNamespaces(
const vector<RequestNamespace>& requestNamespaces) override;
ndk::ScopedAStatus setVerificationToken(const VerificationToken& verificationToken) override;
ndk::ScopedAStatus startRetrieval(
const vector<SecureAccessControlProfile>& accessControlProfiles,
const HardwareAuthToken& authToken, const vector<uint8_t>& itemsRequest,
@ -93,6 +96,9 @@ class IdentityCredential : public BnIdentityCredential {
// Set by setRequestedNamespaces()
vector<RequestNamespace> requestNamespaces_;
// Set by setVerificationToken().
VerificationToken verificationToken_;
// Set at startRetrieval() time.
map<int32_t, int> profileIdToAccessCheckResult_;
vector<uint8_t> signingKeyBlob_;

View file

@ -22,9 +22,14 @@
#include "IdentityCredentialStore.h"
using ::android::base::InitLogging;
using ::android::base::StderrLogger;
using aidl::android::hardware::identity::IdentityCredentialStore;
int main() {
int main(int /*argc*/, char* argv[]) {
InitLogging(argv, StderrLogger);
ABinderProcess_setThreadPoolMaxThreadCount(0);
std::shared_ptr<IdentityCredentialStore> store =
ndk::SharedRefBase::make<IdentityCredentialStore>();

View file

@ -43,6 +43,7 @@ using ::android::String16;
using ::android::binder::Status;
using ::android::hardware::keymaster::HardwareAuthToken;
using ::android::hardware::keymaster::VerificationToken;
class IdentityAidl : public testing::TestWithParam<std::string> {
public:
@ -82,7 +83,20 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) {
// Profile 1 (no authentication)
{1, {}, false, 0}};
// It doesn't matter since no user auth is needed in this particular test,
// but for good measure, clear out the tokens we pass to the HAL.
HardwareAuthToken authToken;
VerificationToken verificationToken;
authToken.challenge = 0;
authToken.userId = 0;
authToken.authenticatorId = 0;
authToken.authenticatorType = ::android::hardware::keymaster::HardwareAuthenticatorType::NONE;
authToken.timestamp.milliSeconds = 0;
authToken.mac.clear();
verificationToken.challenge = 0;
verificationToken.timestamp.milliSeconds = 0;
verificationToken.securityLevel = ::android::hardware::keymaster::SecurityLevel::SOFTWARE;
verificationToken.mac.clear();
// Here's the actual test data:
const vector<test_utils::TestEntryData> testEntries = {
@ -274,7 +288,10 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) {
ASSERT_TRUE(credential->generateSigningKeyPair(&signingKeyBlob, &signingKeyCertificate).isOk());
vector<RequestNamespace> requestedNamespaces = test_utils::buildRequestNamespaces(testEntries);
ASSERT_TRUE(credential->setRequestedNamespaces(requestedNamespaces).isOk());
// OK to fail, not available in v1 HAL
credential->setRequestedNamespaces(requestedNamespaces).isOk();
// OK to fail, not available in v1 HAL
credential->setVerificationToken(verificationToken);
ASSERT_TRUE(credential
->startRetrieval(secureProfiles.value(), authToken, itemsRequestBytes,
signingKeyBlob, sessionTranscriptBytes,

View file

@ -18,6 +18,8 @@
#define HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_UTILS_H_
#include <android/hardware/keymaster/4.0/types.h>
#include <optional>
#include <vector>
namespace android {
namespace hardware {
@ -52,6 +54,15 @@ inline static hidl_vec<uint8_t> blob2hidlVec(const std::vector<uint8_t>& blob) {
HardwareAuthToken hidlVec2AuthToken(const hidl_vec<uint8_t>& buffer);
hidl_vec<uint8_t> authToken2HidlVec(const HardwareAuthToken& token);
// Serializes and deserializes a verification token. This format is private and
// not stable between releases and should not be persisted to disk.
//
// Currently doesn't support the |parametersVerified| field, will fail if set.
//
std::optional<VerificationToken> deserializeVerificationToken(
const std::vector<uint8_t>& serializedToken);
std::optional<std::vector<uint8_t>> serializeVerificationToken(const VerificationToken& token);
uint32_t getOsVersion();
uint32_t getOsPatchlevel();

View file

@ -16,6 +16,7 @@
#include <regex.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <hardware/hw_auth_token.h>
#include <keymasterV4_0/keymaster_utils.h>
@ -110,6 +111,80 @@ HardwareAuthToken hidlVec2AuthToken(const hidl_vec<uint8_t>& buffer) {
return token;
}
void appendUint64(std::vector<uint8_t>& vec, uint64_t value) {
for (size_t n = 0; n < sizeof(uint64_t); n++) {
uint8_t byte = (value >> (n * 8)) & 0xff;
vec.push_back(byte);
}
}
uint64_t extractUint64(const std::vector<uint8_t>& data, size_t offset) {
uint64_t value = 0;
for (size_t n = 0; n < sizeof(uint64_t); n++) {
uint8_t byte = data[offset + n];
value |= byte << (n * 8);
}
return value;
}
void appendUint32(std::vector<uint8_t>& vec, uint32_t value) {
for (size_t n = 0; n < sizeof(uint32_t); n++) {
uint8_t byte = (value >> (n * 8)) & 0xff;
vec.push_back(byte);
}
}
uint32_t extractUint32(const std::vector<uint8_t>& data, size_t offset) {
uint32_t value = 0;
for (size_t n = 0; n < sizeof(uint32_t); n++) {
uint8_t byte = data[offset + n];
value |= byte << (n * 8);
}
return value;
}
std::optional<std::vector<uint8_t>> serializeVerificationToken(const VerificationToken& token) {
if (token.parametersVerified.size() > 0) {
LOG(ERROR) << "Serializing verification tokens with parametersVerified is not supported";
return {};
}
if (!(token.mac.size() == 0 || token.mac.size() == 32)) {
LOG(ERROR) << "Unexpected MAC size " << token.mac.size() << ", expected 0 or 32";
return {};
}
std::vector<uint8_t> serializedToken;
appendUint64(serializedToken, token.challenge);
appendUint64(serializedToken, token.timestamp);
appendUint32(serializedToken, uint32_t(token.securityLevel));
appendUint32(serializedToken, token.mac.size());
serializedToken.insert(serializedToken.end(), token.mac.begin(), token.mac.end());
return serializedToken;
}
std::optional<VerificationToken> deserializeVerificationToken(
const std::vector<uint8_t>& serializedToken) {
if (serializedToken.size() < 24) {
LOG(ERROR) << "Unexpected serialized VerificationToken size " << serializedToken.size()
<< ", expected at least 24 bytes";
return {};
}
VerificationToken token;
token.challenge = extractUint64(serializedToken, 0);
token.timestamp = extractUint64(serializedToken, 8);
token.securityLevel = SecurityLevel(extractUint32(serializedToken, 16));
size_t macSize = extractUint32(serializedToken, 20);
size_t expectedSerializedSize = 24 + macSize;
if (serializedToken.size() != expectedSerializedSize) {
LOG(ERROR) << "Unexpected serialized VerificationToken size " << serializedToken.size()
<< ", expected " << expectedSerializedSize;
return {};
}
if (macSize > 0) {
token.mac = std::vector<uint8_t>(serializedToken.begin() + 24, serializedToken.end());
}
return token;
}
namespace {
constexpr char kPlatformVersionProp[] = "ro.build.version.release";

View file

@ -15,5 +15,8 @@ aidl_interface {
},
},
},
versions: ["1"],
versions: [
"1",
"2",
],
}

View file

@ -0,0 +1 @@
91ab0be1887410935f564e3938ff12c5f5f8c59d

View file

@ -0,0 +1,27 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files 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.keymaster;
@VintfStability
parcelable HardwareAuthToken {
long challenge;
long userId;
long authenticatorId;
android.hardware.keymaster.HardwareAuthenticatorType authenticatorType;
android.hardware.keymaster.Timestamp timestamp;
byte[] mac;
}

View file

@ -0,0 +1,25 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files 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.keymaster;
@Backing(type="int") @VintfStability
enum HardwareAuthenticatorType {
NONE = 0,
PASSWORD = 1,
FINGERPRINT = 2,
ANY = -1,
}

View file

@ -0,0 +1,24 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files 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.keymaster;
@Backing(type="int") @VintfStability
enum SecurityLevel {
SOFTWARE = 0,
TRUSTED_ENVIRONMENT = 1,
STRONGBOX = 2,
}

View file

@ -0,0 +1,22 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files 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.keymaster;
@VintfStability
parcelable Timestamp {
long milliSeconds;
}

View file

@ -0,0 +1,25 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files 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.keymaster;
@VintfStability
parcelable VerificationToken {
long challenge;
android.hardware.keymaster.Timestamp timestamp;
android.hardware.keymaster.SecurityLevel securityLevel;
byte[] mac;
}

View file

@ -0,0 +1,24 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files 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.keymaster;
@Backing(type="int") @VintfStability
enum SecurityLevel {
SOFTWARE = 0,
TRUSTED_ENVIRONMENT = 1,
STRONGBOX = 2,
}

View file

@ -0,0 +1,25 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files 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.keymaster;
@VintfStability
parcelable VerificationToken {
long challenge;
android.hardware.keymaster.Timestamp timestamp;
android.hardware.keymaster.SecurityLevel securityLevel;
byte[] mac;
}

View file

@ -0,0 +1,32 @@
/*
* Copyright 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.keymaster;
/**
* Device security levels.
*/
@VintfStability
@Backing(type="int")
enum SecurityLevel {
SOFTWARE = 0,
TRUSTED_ENVIRONMENT = 1,
/**
* STRONGBOX specifies that the secure hardware satisfies the requirements specified in CDD
* 9.11.2.
*/
STRONGBOX = 2,
}

View file

@ -0,0 +1,69 @@
/*
* Copyright 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.keymaster;
import android.hardware.keymaster.SecurityLevel;
import android.hardware.keymaster.Timestamp;
import android.hardware.keymaster.HardwareAuthenticatorType;
/**
* 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 || parametersVerified)
*
* where:
*
* ``HMAC'' is the shared HMAC key (see computeSharedHmac() in IKeymaster).
*
* ``||'' 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.
*
* If parametersVerified is non-empty, the representation of parametersVerified is an ASN.1 DER
* encoded representation of the values. The ASN.1 schema used is the AuthorizationList schema
* from the Keystore attestation documentation. If parametersVerified is empty, it is simply
* omitted from the HMAC computation.
*/
byte[] mac;
}