From 571caa6a45fe43c384a7ba424ba182ff3db4fe06 Mon Sep 17 00:00:00 2001 From: Kevin Chyn Date: Thu, 17 Sep 2020 13:08:03 -0700 Subject: [PATCH] Start adding documentation for IFingerprint Minor changes to interface: 1) IResetLockoutCallback renamed to ILockoutCallback 2) Removes unnecessary parameter from onChallengeGenerated 3) Adds "challenge" param to revokeChallenge to support multiple in-flight challenges Bug: 168842956 Bug: 168843220 Test: make -j56 android.hardware.biometrics.fingerprint-update-api Test: make -j Test: make -j56 VtsHalBiometricsFingerprintTargetTest Change-Id: If1f63a6d0c135d7b59690a31728b4d3fc8c2d2c4 --- .../biometrics/fingerprint/IFingerprint.aidl | 4 +- .../IGenerateChallengeCallback.aidl | 2 +- ...outCallback.aidl => ILockoutCallback.aidl} | 6 +- .../biometrics/fingerprint/IFingerprint.aidl | 137 +++++++++++++++++- .../IGenerateChallengeCallback.aidl | 5 +- .../fingerprint/ILockoutCallback.aidl | 60 ++++++++ .../fingerprint/IResetLockoutCallback.aidl | 23 --- .../fingerprint/IRevokeChallengeCallback.aidl | 3 + .../biometrics/fingerprint/ISession.aidl | 30 +++- .../fingerprint/aidl/default/Fingerprint.cpp | 6 +- .../fingerprint/aidl/default/Fingerprint.h | 6 +- 11 files changed, 240 insertions(+), 42 deletions(-) rename biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/{IResetLockoutCallback.aidl => ILockoutCallback.aidl} (81%) create mode 100644 biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ILockoutCallback.aidl delete mode 100644 biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IResetLockoutCallback.aidl diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IFingerprint.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IFingerprint.aidl index 85d1f57e05..9cbf343181 100644 --- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IFingerprint.aidl +++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IFingerprint.aidl @@ -20,7 +20,7 @@ package android.hardware.biometrics.fingerprint; interface IFingerprint { android.hardware.biometrics.fingerprint.SensorProps[] getSensorProps(); android.hardware.biometrics.fingerprint.ISession createSession(in int sensorId, in int userId, in android.hardware.biometrics.fingerprint.ISessionCallback cb); - void setResetLockoutCallback(in android.hardware.biometrics.fingerprint.IResetLockoutCallback cb); + void setLockoutCallback(in android.hardware.biometrics.fingerprint.ILockoutCallback cb); void generateChallenge(in int sensorId, in int userId, in int timeoutSec, in android.hardware.biometrics.fingerprint.IGenerateChallengeCallback cb); - void revokeChallenge(in int sensorId, in int userId, in android.hardware.biometrics.fingerprint.IRevokeChallengeCallback cb); + void revokeChallenge(in int sensorId, in int userId, in long challenge, in android.hardware.biometrics.fingerprint.IRevokeChallengeCallback cb); } diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IGenerateChallengeCallback.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IGenerateChallengeCallback.aidl index eaf27d2235..063be60a0f 100644 --- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IGenerateChallengeCallback.aidl +++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IGenerateChallengeCallback.aidl @@ -18,5 +18,5 @@ package android.hardware.biometrics.fingerprint; @VintfStability interface IGenerateChallengeCallback { - oneway void onChallengeGenerated(in int sensorId, in int userId, in long keystoreOperationId, in long challenge); + oneway void onChallengeGenerated(in int sensorId, in int userId, in long challenge); } diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IResetLockoutCallback.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ILockoutCallback.aidl similarity index 81% rename from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IResetLockoutCallback.aidl rename to biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ILockoutCallback.aidl index ac0decda6b..88aabbf487 100644 --- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IResetLockoutCallback.aidl +++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ILockoutCallback.aidl @@ -17,6 +17,8 @@ package android.hardware.biometrics.fingerprint; @VintfStability -interface IResetLockoutCallback { - oneway void onLockoutReset(in int sensorId, in int userId, in long durationMilli); +interface ILockoutCallback { + oneway void onLockoutTimed(in int sensorId, in int userId, in long durationMillis); + oneway void onLockoutPermanent(in int sensorId, in int userId); + oneway void onLockoutCleared(in int sensorId, in int userId); } diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IFingerprint.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IFingerprint.aidl index 47097785b5..57319b2906 100644 --- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IFingerprint.aidl +++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IFingerprint.aidl @@ -17,7 +17,7 @@ package android.hardware.biometrics.fingerprint; import android.hardware.biometrics.fingerprint.IGenerateChallengeCallback; -import android.hardware.biometrics.fingerprint.IResetLockoutCallback; +import android.hardware.biometrics.fingerprint.ILockoutCallback; import android.hardware.biometrics.fingerprint.IRevokeChallengeCallback; import android.hardware.biometrics.fingerprint.ISession; import android.hardware.biometrics.fingerprint.ISessionCallback; @@ -25,13 +25,144 @@ import android.hardware.biometrics.fingerprint.SensorProps; @VintfStability interface IFingerprint { + /** + * getSensorProps: + * + * @return A list of properties for all sensors that an instance of the + * HAL supports. + */ SensorProps[] getSensorProps(); + /** + * createSession: + * + * Creates a session which can then be used by the framework to perform + * operations such as enroll, authenticate, etc for the given sensorId + * and userId. + * + * A physical sensor identified by sensorId typically supports only a + * single in-flight session at a time. As such, if a session is currently + * in a state other than SessionState::IDLING, the HAL MUST finish or + * cancel the current operation and return to SessionState::IDLING before + * the new session is created. For example: + * 1) If a session for sensorId=0, userId=0 + * is currently in a cancellable state (see ICancellationSignal) such + * as SessionState::AUTHENTICATING and the framework requests a new + * session for sensorId=0, userId=10, the HAL must end the current + * session with Error::CANCELED, invoke + * ISessionCallback#onStateChanged with SessionState::IDLING, and + * then return a new session for sensorId=0, userId=10. + * 2) If a session for sensorId=0, userId=0 is currently in a + * non-cancellable state such as SessionState::REMOVING_ENROLLMENTS, + * and the framework requests a new session for sensorId=0, userId=10, + * the HAL must finish the current operation before invoking + * ISessionCallback#onStateChanged with SessionState::IDLING, and + * return a new session for sensorId=0, userId=10. + * + * Implementations must store user-specific state or metadata in + * /data/vendor_de//fpdata as specified by the SeLinux policy. This + * directory is created/removed by vold (see vold_prepare_subdirs.cpp). + * Implementations may store additional user-specific data, such as + * embeddings or templates in StrongBox. + * + * @param sensorId The sensor with which this session is being created. + * @param userId The userId with which this session is being created. + * @param cb Used to notify the framework. + * @return A new session + */ ISession createSession(in int sensorId, in int userId, in ISessionCallback cb); - void setResetLockoutCallback(in IResetLockoutCallback cb); + /** + * setLockoutCallback: + * + * Sets a callback to notify the framework lockout changes. Note + * that lockout is user AND sensor specific. In other words, there is a + * separate lockout state for each (user, sensor) pair. For example, the + * following is a valid state on a multi-sensor device: + * ------------------------------------------------------------------ + * | SensorId | UserId | FailedAttempts | LockedOut | LockedUntil | + * |----------|--------|----------------|-----------|---------------| + * | 0 | 0 | 1 | false | x | + * | 1 | 0 | 5 | true | | + * | 0 | 10 | 0 | false | x | + * | 1 | 10 | 0 | false | x | + * ------------------------------------------------------------------ + * + * Lockout may be cleared in the following ways: + * 1) ISession#resetLockout + * 2) After a period of time, according to a rate-limiter. + * + * In addition, lockout states MUST persist after device reboots, HAL + * crashes, etc. + * + * See the Android CDD section 7.3.10 for the full set of lockout and + * rate-limiting requirements. + * + * @param cb Used to notify the framework of lockout changes. + */ + void setLockoutCallback(in ILockoutCallback cb); + /** + * generateChallenge: + * + * Begins a secure transaction request. Note that the challenge by itself + * is not useful. It only becomes useful when wrapped in a verifiable + * message such as a HardwareAuthToken. + * + * Canonical example: + * 1) User requests an operation, such as fingerprint enrollment. + * 2) Fingerprint enrollment cannot happen until the user confirms + * their lockscreen credential (PIN/Pattern/Password). + * 3) However, the biometric subsystem does not want just "any" + * proof of credential confirmation. It needs proof that the + * user explicitly authenticated credential in order to allow + * addition of biometric enrollments. + * To secure this path, the following path is taken: + * 1) Upon user requesting fingerprint enroll, the framework requests + * IFingerprint#generateChallenge + * 2) Framework sends the challenge to the credential subsystem, and upon + * credential confirmation, a HAT is created, containing the challenge + * in the "challenge" field. + * 3) Framework sends the HAT to the HAL, e.g. ISession#enroll. + * 4) Implementation verifies the authenticity and integrity of the HAT. + * 5) Implementation now has confidence that the user entered their + * credential to allow biometric enrollment. + * + * Note that the interface allows multiple in-flight challenges. For + * example, invoking generateChallenge(0, 0, timeoutSec, cb) twice + * does not invalidate the first challenge. The challenge is invalidated + * only when: + * 1) The provided timeout expires, or + * 2) IFingerprint#revokeChallenge is invoked + * + * For example, the following is a possible table of valid challenges: + * ---------------------------------------------- + * | SensorId | UserId | ValidUntil | Challenge | + * |----------|--------|------------|-----------| + * | 0 | 0 | | | + * | 0 | 0 | | | + * | 1 | 0 | | | + * | 0 | 10 | | | + * ---------------------------------------------- + * + * @param sensorId Sensor to associate the challenge with + * @param userId User to associate the challenge with + * @param timeoutSec Duration for which the challenge is valid for + * @param cb Callback to notify the framework + */ void generateChallenge(in int sensorId, in int userId, in int timeoutSec, in IGenerateChallengeCallback cb); - void revokeChallenge(in int sensorId, in int userId, in IRevokeChallengeCallback cb); + /** + * revokeChallenge: + * + * Revokes a challenge that was previously generated. Note that if an + * invalid combination of parameters is requested, the implementation + * must still notify the framework using the provided callback. + * + * @param sensorId Sensor that the revocation should apply to. + * @param userId User that the revocation should apply to. + * @param challenge Challenge that should be revoked. + * @param cb Used to notify the framework. + */ + void revokeChallenge(in int sensorId, in int userId, in long challenge, in IRevokeChallengeCallback cb); } diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IGenerateChallengeCallback.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IGenerateChallengeCallback.aidl index 93a2d7bdc4..a51b188fcf 100644 --- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IGenerateChallengeCallback.aidl +++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IGenerateChallengeCallback.aidl @@ -18,6 +18,9 @@ package android.hardware.biometrics.fingerprint; @VintfStability oneway interface IGenerateChallengeCallback { - void onChallengeGenerated(in int sensorId, in int userId, in long keystoreOperationId, in long challenge); + /** + * Notifies the framework when a challenge is successfully generated. + */ + void onChallengeGenerated(in int sensorId, in int userId, in long challenge); } diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ILockoutCallback.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ILockoutCallback.aidl new file mode 100644 index 0000000000..4b31a38e52 --- /dev/null +++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ILockoutCallback.aidl @@ -0,0 +1,60 @@ +/* + * 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.biometrics.fingerprint; + +@VintfStability +oneway interface ILockoutCallback { + /** + * Notifies the framework that the user has just entered the Error::LOCKOUT state. This must be + * sent in the following scenarios: + * 1) The user just attempted authentication and was rejected, resulting in a timed lockout. + * 2) The framework just created a session for a sensorId/userId pair that has not been + * created since the HAL started (e.g. there is no active or idle session for this + * sensorId/userId pair. + * + * @param sensorId Sensor for which the user is locked out. + * @param userId User for which the sensor is locked out. + * @param durationMillis Remaining duration of the lockout. + */ + void onLockoutTimed(in int sensorId, in int userId, in long durationMillis); + + /** + * Notifies the framework that the user has just entered the Error::LOCKOUT_PERMANENT state. + * This must be sent in the following scenarios: + * 1) The user just attempted authentication and was rejected, resulting in a permanent lockout. + * 2) The framework just created a session for a sensorId/userId pair that has not been + * created since the HAL started (e.g. there is no active or idle session for this + * sensorId/userId pair. + * + * @param sensorId Sensor for which the user is locked out. + * @param userId User for which the sensor is locked out. + */ + void onLockoutPermanent(in int sensorId, in int userId); + + /** + * Notifies the framework that lockout has been cleared for this sensorId/userId pair. This + * can happen in the following scenarios: + * 1) A timed lockout has ended (e.g. original durationMillis specified in #onLockoutTimed + * has expired. + * 2) See ISession#resetLockout. + * + * @param sensorId Sensor for which the user's lockout is cleared. + * @param userId User for the sensor's lockout is cleared. + */ + void onLockoutCleared(in int sensorId, in int userId); +} + diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IResetLockoutCallback.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IResetLockoutCallback.aidl deleted file mode 100644 index d97a701c73..0000000000 --- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IResetLockoutCallback.aidl +++ /dev/null @@ -1,23 +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.biometrics.fingerprint; - -@VintfStability -oneway interface IResetLockoutCallback { - void onLockoutReset(in int sensorId, in int userId, in long durationMilli); -} - diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IRevokeChallengeCallback.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IRevokeChallengeCallback.aidl index cca3453e39..eadba526b3 100644 --- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IRevokeChallengeCallback.aidl +++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IRevokeChallengeCallback.aidl @@ -18,6 +18,9 @@ package android.hardware.biometrics.fingerprint; @VintfStability oneway interface IRevokeChallengeCallback { + /** + * Notifies the framework when a challenge has been revoked. + */ void onChallengeRevoked(in int sensorId, in int userId, in long challenge); } diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl index dd340e8e8c..e2d23a6160 100644 --- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl +++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl @@ -82,12 +82,14 @@ interface ISession { * The following only applies to sensors that are configured as * SensorStrength::STRONG. * - * When invoked by the framework, the HAL implementation must perform the + * When invoked by the framework, the implementation must perform the * following sequence of events: * 1) Verify the authenticity and integrity of the provided HAT - * 2) Update the authenticatorId with a new entropy-encoded random number - * 3) Persist the new authenticatorId to non-ephemeral storage - * 4) Notify the framework that the above is completed, via + * 2) Verify that the timestamp provided within the HAT is relatively + * recent (e.g. on the order of minutes, not hours). + * 3) Update the authenticatorId with a new entropy-encoded random number + * 4) Persist the new authenticatorId to non-ephemeral storage + * 5) Notify the framework that the above is completed, via * ISessionCallback#onAuthenticatorInvalidated * * A practical use case of invalidation would be when the user adds a new @@ -105,6 +107,26 @@ interface ISession { */ void invalidateAuthenticatorId(in int cookie, in HardwareAuthToken hat); + /** + * resetLockout: + * + * Requests the implementation to clear the lockout counter. Upon receiving + * this request, the implementation must perform the following: + * 1) Verify the authenticity and integrity of the provided HAT + * 2) Verify that the timestamp provided within the HAT is relatively + * recent (e.g. on the order of minutes, not hours). + * + * Upon successful verification, the HAL must notify the framework via + * ILockoutCallback#onLockoutChanged(sensorId, userId, 0). + * + * If verification was uncessful, the HAL must notify the framework via + * ILockoutCallback#onLockoutChanged(sensorId, userId, remaining_time). + * + * @param cookie An identifier used to track subsystem operations related + * to this call path. The framework will guarantee that it is + * unique per ISession. + * @param hat HardwareAuthToken See above documentation. + */ void resetLockout(in int cookie, in HardwareAuthToken hat); diff --git a/biometrics/fingerprint/aidl/default/Fingerprint.cpp b/biometrics/fingerprint/aidl/default/Fingerprint.cpp index a1d9d0a006..b3bd4e7a29 100644 --- a/biometrics/fingerprint/aidl/default/Fingerprint.cpp +++ b/biometrics/fingerprint/aidl/default/Fingerprint.cpp @@ -61,8 +61,8 @@ ndk::ScopedAStatus Fingerprint::createSession(int32_t /*sensorId*/, int32_t /*us return ndk::ScopedAStatus::ok(); } -ndk::ScopedAStatus Fingerprint::setResetLockoutCallback( - const std::shared_ptr& /*cb*/) { +ndk::ScopedAStatus Fingerprint::setLockoutCallback( + const std::shared_ptr& /*cb*/) { return ndk::ScopedAStatus::ok(); } @@ -73,7 +73,7 @@ ndk::ScopedAStatus Fingerprint::generateChallenge( } ndk::ScopedAStatus Fingerprint::revokeChallenge( - int32_t /*sensorId*/, int32_t /*userId*/, + int32_t /*sensorId*/, int32_t /*userId*/, int64_t /*challenge*/, const std::shared_ptr& /*cb*/) { return ndk::ScopedAStatus::ok(); } diff --git a/biometrics/fingerprint/aidl/default/Fingerprint.h b/biometrics/fingerprint/aidl/default/Fingerprint.h index b5b09c0b74..463d07db13 100644 --- a/biometrics/fingerprint/aidl/default/Fingerprint.h +++ b/biometrics/fingerprint/aidl/default/Fingerprint.h @@ -28,15 +28,15 @@ class Fingerprint : public BnFingerprint { const std::shared_ptr& cb, std::shared_ptr* _aidl_return) override; - ndk::ScopedAStatus setResetLockoutCallback( - const std::shared_ptr& cb) override; + ndk::ScopedAStatus setLockoutCallback( + const std::shared_ptr& cb) override; ndk::ScopedAStatus generateChallenge( int32_t sensorId, int32_t userId, int32_t timeoutSec, const std::shared_ptr& cb) override; ndk::ScopedAStatus revokeChallenge( - int32_t sensorId, int32_t userId, + int32_t sensorId, int32_t userId, int64_t challenge, const std::shared_ptr& cb) override; };