Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5f2523d6 authored by Treehugger Robot's avatar Treehugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Identity Credential: Add method to accept verification token." am: 1ac087e4 am: 40577ac4

Change-Id: I232a8c45dd5d94cf8a2a2215fa99dd54425a9789
parents 3048b32d 40577ac4
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
3b0b10b618dbc4bf283aa2bf78833ad3de0a5928
194e04be642728623d65ec8321a3764fdea52ae0
+1 −0
Original line number Diff line number Diff line
@@ -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);
}
+1 −0
Original line number Diff line number Diff line
@@ -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);
}
+30 −5
Original line number Diff line number Diff line
@@ -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);
}
+22 −21
Original line number Diff line number Diff line
@@ -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:
    //
    //   "[...] 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.
    // 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.
    //
    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) {
Loading