diff --git a/identity/aidl/aidl_api/android.hardware.identity/2/.hash b/identity/aidl/aidl_api/android.hardware.identity/2/.hash index 1b2c1b6cdc..036ce8425a 100644 --- a/identity/aidl/aidl_api/android.hardware.identity/2/.hash +++ b/identity/aidl/aidl_api/android.hardware.identity/2/.hash @@ -1 +1 @@ -3b0b10b618dbc4bf283aa2bf78833ad3de0a5928 +194e04be642728623d65ec8321a3764fdea52ae0 diff --git a/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/IIdentityCredential.aidl b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/IIdentityCredential.aidl index e8e93f82f4..88104d9577 100644 --- a/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/IIdentityCredential.aidl +++ b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/IIdentityCredential.aidl @@ -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); } diff --git a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl index e8e93f82f4..88104d9577 100644 --- a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl +++ b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl @@ -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); } diff --git a/identity/aidl/android/hardware/identity/IIdentityCredential.aidl b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl index 7cd25e6942..d7f47e82c0 100644 --- a/identity/aidl/android/hardware/identity/IIdentityCredential.aidl +++ b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl @@ -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); } diff --git a/identity/aidl/default/IdentityCredential.cpp b/identity/aidl/default/IdentityCredential.cpp index ff4107a7b4..381eb8426f 100644 --- a/identity/aidl/default/IdentityCredential.cpp +++ b/identity/aidl/default/IdentityCredential.cpp @@ -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& accessControlProfiles, const HardwareAuthToken& authToken, const vector& 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) { diff --git a/identity/aidl/default/IdentityCredential.h b/identity/aidl/default/IdentityCredential.h index a8bad88f8f..a82531dd4b 100644 --- a/identity/aidl/default/IdentityCredential.h +++ b/identity/aidl/default/IdentityCredential.h @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -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& requestNamespaces) override; + ndk::ScopedAStatus setVerificationToken(const VerificationToken& verificationToken) override; ndk::ScopedAStatus startRetrieval( const vector& accessControlProfiles, const HardwareAuthToken& authToken, const vector& itemsRequest, @@ -93,6 +96,9 @@ class IdentityCredential : public BnIdentityCredential { // Set by setRequestedNamespaces() vector requestNamespaces_; + // Set by setVerificationToken(). + VerificationToken verificationToken_; + // Set at startRetrieval() time. map profileIdToAccessCheckResult_; vector signingKeyBlob_; diff --git a/identity/aidl/default/service.cpp b/identity/aidl/default/service.cpp index f05c615001..bf95df523a 100644 --- a/identity/aidl/default/service.cpp +++ b/identity/aidl/default/service.cpp @@ -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 store = ndk::SharedRefBase::make(); diff --git a/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp b/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp index 807feabf80..17145b4154 100644 --- a/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp +++ b/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp @@ -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 { 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 testEntries = { @@ -274,7 +288,10 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) { ASSERT_TRUE(credential->generateSigningKeyPair(&signingKeyBlob, &signingKeyCertificate).isOk()); vector 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, diff --git a/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h b/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h index 61645f853e..f585d6269e 100644 --- a/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h +++ b/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h @@ -18,6 +18,8 @@ #define HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_UTILS_H_ #include +#include +#include namespace android { namespace hardware { @@ -52,6 +54,15 @@ inline static hidl_vec blob2hidlVec(const std::vector& blob) { HardwareAuthToken hidlVec2AuthToken(const hidl_vec& buffer); hidl_vec 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 deserializeVerificationToken( + const std::vector& serializedToken); +std::optional> serializeVerificationToken(const VerificationToken& token); + uint32_t getOsVersion(); uint32_t getOsPatchlevel(); diff --git a/keymaster/4.0/support/keymaster_utils.cpp b/keymaster/4.0/support/keymaster_utils.cpp index 850a7767bf..366cd0e553 100644 --- a/keymaster/4.0/support/keymaster_utils.cpp +++ b/keymaster/4.0/support/keymaster_utils.cpp @@ -16,6 +16,7 @@ #include +#include #include #include #include @@ -110,6 +111,80 @@ HardwareAuthToken hidlVec2AuthToken(const hidl_vec& buffer) { return token; } +void appendUint64(std::vector& 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& 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& 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& 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> 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 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 deserializeVerificationToken( + const std::vector& 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(serializedToken.begin() + 24, serializedToken.end()); + } + return token; +} + namespace { constexpr char kPlatformVersionProp[] = "ro.build.version.release"; diff --git a/keymaster/aidl/Android.bp b/keymaster/aidl/Android.bp index 3011da67db..56a3ca99e7 100644 --- a/keymaster/aidl/Android.bp +++ b/keymaster/aidl/Android.bp @@ -15,5 +15,8 @@ aidl_interface { }, }, }, - versions: ["1"], + versions: [ + "1", + "2", + ], } diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/2/.hash b/keymaster/aidl/aidl_api/android.hardware.keymaster/2/.hash new file mode 100644 index 0000000000..9d5974e920 --- /dev/null +++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/2/.hash @@ -0,0 +1 @@ +91ab0be1887410935f564e3938ff12c5f5f8c59d diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/HardwareAuthToken.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/HardwareAuthToken.aidl new file mode 100644 index 0000000000..db1df2b050 --- /dev/null +++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/HardwareAuthToken.aidl @@ -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; +} diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/HardwareAuthenticatorType.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/HardwareAuthenticatorType.aidl new file mode 100644 index 0000000000..924567f95b --- /dev/null +++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/HardwareAuthenticatorType.aidl @@ -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, +} diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/SecurityLevel.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/SecurityLevel.aidl new file mode 100644 index 0000000000..127c1bf7cd --- /dev/null +++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/SecurityLevel.aidl @@ -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, +} diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/Timestamp.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/Timestamp.aidl new file mode 100644 index 0000000000..45fa1aed13 --- /dev/null +++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/Timestamp.aidl @@ -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; +} diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/VerificationToken.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/VerificationToken.aidl new file mode 100644 index 0000000000..0633765cac --- /dev/null +++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/VerificationToken.aidl @@ -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; +} diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/SecurityLevel.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/SecurityLevel.aidl new file mode 100644 index 0000000000..127c1bf7cd --- /dev/null +++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/SecurityLevel.aidl @@ -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, +} diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/VerificationToken.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/VerificationToken.aidl new file mode 100644 index 0000000000..0633765cac --- /dev/null +++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/VerificationToken.aidl @@ -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; +} diff --git a/keymaster/aidl/android/hardware/keymaster/SecurityLevel.aidl b/keymaster/aidl/android/hardware/keymaster/SecurityLevel.aidl new file mode 100644 index 0000000000..f1297831c1 --- /dev/null +++ b/keymaster/aidl/android/hardware/keymaster/SecurityLevel.aidl @@ -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, +} diff --git a/keymaster/aidl/android/hardware/keymaster/VerificationToken.aidl b/keymaster/aidl/android/hardware/keymaster/VerificationToken.aidl new file mode 100644 index 0000000000..eff9ca6f0c --- /dev/null +++ b/keymaster/aidl/android/hardware/keymaster/VerificationToken.aidl @@ -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; +}