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
This commit is contained in:
Kevin Chyn 2020-09-17 13:08:03 -07:00
parent e33abd6456
commit 571caa6a45
11 changed files with 240 additions and 42 deletions

View file

@ -20,7 +20,7 @@ package android.hardware.biometrics.fingerprint;
interface IFingerprint { interface IFingerprint {
android.hardware.biometrics.fingerprint.SensorProps[] getSensorProps(); 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); 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 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);
} }

View file

@ -18,5 +18,5 @@
package android.hardware.biometrics.fingerprint; package android.hardware.biometrics.fingerprint;
@VintfStability @VintfStability
interface IGenerateChallengeCallback { 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);
} }

View file

@ -17,6 +17,8 @@
package android.hardware.biometrics.fingerprint; package android.hardware.biometrics.fingerprint;
@VintfStability @VintfStability
interface IResetLockoutCallback { interface ILockoutCallback {
oneway void onLockoutReset(in int sensorId, in int userId, in long durationMilli); 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);
} }

View file

@ -17,7 +17,7 @@
package android.hardware.biometrics.fingerprint; package android.hardware.biometrics.fingerprint;
import android.hardware.biometrics.fingerprint.IGenerateChallengeCallback; 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.IRevokeChallengeCallback;
import android.hardware.biometrics.fingerprint.ISession; import android.hardware.biometrics.fingerprint.ISession;
import android.hardware.biometrics.fingerprint.ISessionCallback; import android.hardware.biometrics.fingerprint.ISessionCallback;
@ -25,13 +25,144 @@ import android.hardware.biometrics.fingerprint.SensorProps;
@VintfStability @VintfStability
interface IFingerprint { interface IFingerprint {
/**
* getSensorProps:
*
* @return A list of properties for all sensors that an instance of the
* HAL supports.
*/
SensorProps[] getSensorProps(); 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/<user>/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); 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 | <future_time> |
* | 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 | <Time1> | <Random1> |
* | 0 | 0 | <Time2> | <Random2> |
* | 1 | 0 | <Time3> | <Random3> |
* | 0 | 10 | <Time4> | <Random4> |
* ----------------------------------------------
*
* @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 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);
} }

View file

@ -18,6 +18,9 @@ package android.hardware.biometrics.fingerprint;
@VintfStability @VintfStability
oneway interface IGenerateChallengeCallback { 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);
} }

View file

@ -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);
}

View file

@ -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);
}

View file

@ -18,6 +18,9 @@ package android.hardware.biometrics.fingerprint;
@VintfStability @VintfStability
oneway interface IRevokeChallengeCallback { oneway interface IRevokeChallengeCallback {
/**
* Notifies the framework when a challenge has been revoked.
*/
void onChallengeRevoked(in int sensorId, in int userId, in long challenge); void onChallengeRevoked(in int sensorId, in int userId, in long challenge);
} }

View file

@ -82,12 +82,14 @@ interface ISession {
* The following only applies to sensors that are configured as * The following only applies to sensors that are configured as
* SensorStrength::STRONG. * 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: * following sequence of events:
* 1) Verify the authenticity and integrity of the provided HAT * 1) Verify the authenticity and integrity of the provided HAT
* 2) Update the authenticatorId with a new entropy-encoded random number * 2) Verify that the timestamp provided within the HAT is relatively
* 3) Persist the new authenticatorId to non-ephemeral storage * recent (e.g. on the order of minutes, not hours).
* 4) Notify the framework that the above is completed, via * 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 * ISessionCallback#onAuthenticatorInvalidated
* *
* A practical use case of invalidation would be when the user adds a new * 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); 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); void resetLockout(in int cookie, in HardwareAuthToken hat);

View file

@ -61,8 +61,8 @@ ndk::ScopedAStatus Fingerprint::createSession(int32_t /*sensorId*/, int32_t /*us
return ndk::ScopedAStatus::ok(); return ndk::ScopedAStatus::ok();
} }
ndk::ScopedAStatus Fingerprint::setResetLockoutCallback( ndk::ScopedAStatus Fingerprint::setLockoutCallback(
const std::shared_ptr<IResetLockoutCallback>& /*cb*/) { const std::shared_ptr<ILockoutCallback>& /*cb*/) {
return ndk::ScopedAStatus::ok(); return ndk::ScopedAStatus::ok();
} }
@ -73,7 +73,7 @@ ndk::ScopedAStatus Fingerprint::generateChallenge(
} }
ndk::ScopedAStatus Fingerprint::revokeChallenge( ndk::ScopedAStatus Fingerprint::revokeChallenge(
int32_t /*sensorId*/, int32_t /*userId*/, int32_t /*sensorId*/, int32_t /*userId*/, int64_t /*challenge*/,
const std::shared_ptr<IRevokeChallengeCallback>& /*cb*/) { const std::shared_ptr<IRevokeChallengeCallback>& /*cb*/) {
return ndk::ScopedAStatus::ok(); return ndk::ScopedAStatus::ok();
} }

View file

@ -28,15 +28,15 @@ class Fingerprint : public BnFingerprint {
const std::shared_ptr<ISessionCallback>& cb, const std::shared_ptr<ISessionCallback>& cb,
std::shared_ptr<ISession>* _aidl_return) override; std::shared_ptr<ISession>* _aidl_return) override;
ndk::ScopedAStatus setResetLockoutCallback( ndk::ScopedAStatus setLockoutCallback(
const std::shared_ptr<IResetLockoutCallback>& cb) override; const std::shared_ptr<ILockoutCallback>& cb) override;
ndk::ScopedAStatus generateChallenge( ndk::ScopedAStatus generateChallenge(
int32_t sensorId, int32_t userId, int32_t timeoutSec, int32_t sensorId, int32_t userId, int32_t timeoutSec,
const std::shared_ptr<IGenerateChallengeCallback>& cb) override; const std::shared_ptr<IGenerateChallengeCallback>& cb) override;
ndk::ScopedAStatus revokeChallenge( ndk::ScopedAStatus revokeChallenge(
int32_t sensorId, int32_t userId, int32_t sensorId, int32_t userId, int64_t challenge,
const std::shared_ptr<IRevokeChallengeCallback>& cb) override; const std::shared_ptr<IRevokeChallengeCallback>& cb) override;
}; };