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

Commit f3e06003 authored by David Zeuthen's avatar David Zeuthen
Browse files

identity: Add support for ECDSA auth and don't require session encryption.

This adds a new method which allows applications to use mdoc ECDSA
authentication instead of mdoc MAC authentication. Additionally, also
relax requirements on SessionTranscript so the APIs can be used even
when mdoc session encryption isn't being used.

Also add new VTS test to check for this.

Since this is new API, bump API version to 5 and the Identity
Credential feature version to 202301.

Bug: 241912421
Test: atest VtsHalIdentityTargetTest
Test: atest android.security.identity.cts
Change-Id: I4085a89be0382c10f5449e13c6a92a46c74c225d
parent 1186b991
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@ aidl_interface {
        "android.hardware.security.rkp-V3",
    ],
    stability: "vintf",
    frozen: true,
    frozen: false,
    backend: {
        java: {
            platform_apis: true,
@@ -67,20 +67,20 @@ aidl_interface {
cc_defaults {
    name: "identity_use_latest_hal_aidl_ndk_static",
    static_libs: [
        "android.hardware.identity-V4-ndk",
        "android.hardware.identity-V5-ndk",
    ],
}

cc_defaults {
    name: "identity_use_latest_hal_aidl_ndk_shared",
    shared_libs: [
        "android.hardware.identity-V4-ndk",
        "android.hardware.identity-V5-ndk",
    ],
}

cc_defaults {
    name: "identity_use_latest_hal_aidl_cpp_static",
    static_libs: [
        "android.hardware.identity-V4-cpp",
        "android.hardware.identity-V5-cpp",
    ],
}
+1 −0
Original line number Diff line number Diff line
@@ -51,4 +51,5 @@ interface IIdentityCredential {
  byte[] deleteCredentialWithChallenge(in byte[] challenge);
  byte[] proveOwnership(in byte[] challenge);
  android.hardware.identity.IWritableIdentityCredential updateCredential();
  @SuppressWarnings(value={"out-array"}) void finishRetrievalWithSignature(out byte[] mac, out byte[] deviceNameSpaces, out byte[] ecdsaSignature);
}
+35 −16
Original line number Diff line number Diff line
@@ -194,7 +194,8 @@ interface IIdentityCredential {
     * is permissible for this to be empty in which case the readerSignature parameter
     * must also be empty. If this is not the case, the call fails with STATUS_FAILED.
     *
     * If the SessionTranscript CBOR is not empty, the X and Y coordinates of the public
     * If mdoc session encryption is used (e.g. createEphemeralKeyPair() has been called)
     * and the SessionTranscript CBOR is not empty, the X and Y coordinates of the public
     * part of the key-pair previously generated by createEphemeralKeyPair() must appear
     * somewhere in the bytes of the CBOR. Each of these coordinates must appear encoded
     * with the most significant bits first and use the exact amount of bits indicated by
@@ -271,8 +272,8 @@ interface IIdentityCredential {
     *     is given and this profile wasn't passed to startRetrieval() this call fails
     *     with STATUS_INVALID_DATA.
     */
    void startRetrieveEntryValue(in @utf8InCpp String nameSpace, in @utf8InCpp String name,
                                 in int entrySize, in int[] accessControlProfileIds);
    void startRetrieveEntryValue(in @utf8InCpp String nameSpace,
            in @utf8InCpp String name, in int entrySize, in int[] accessControlProfileIds);

    /**
     * Retrieves an entry value, or part of one, if the entry value is larger than gcmChunkSize.
@@ -293,11 +294,13 @@ interface IIdentityCredential {
     * returned data.
     *
     * If signingKeyBlob or the sessionTranscript parameter passed to startRetrieval() is
     * empty then the returned MAC will be empty.
     * empty or if mdoc session encryption is not being used (e.g. if createEphemeralKeyPair()
     * was not called) then the returned MAC will be empty.
     *
     * @param out mac is empty if signingKeyBlob or the sessionTranscript passed to
     *    startRetrieval() is empty. Otherwise it is a COSE_Mac0 with empty payload
     *    and the detached content is set to DeviceAuthenticationBytes as defined below.
     * @param out mac is empty if signingKeyBlob, or the sessionTranscript passed to
     *    startRetrieval() is empty, or if mdoc session encryption is not being used (e.g. if
     *    createEphemeralKeyPair() was not called). Otherwise it is a COSE_Mac0 with empty
     *    payload and the detached content is set to DeviceAuthenticationBytes as defined below.
     *    This code is produced by using the key agreement and key derivation function
     *    from the ciphersuite with the authentication private key and the reader
     *    ephemeral public key to compute a shared message authentication code (MAC)
@@ -485,4 +488,20 @@ interface IIdentityCredential {
     * @return an IWritableIdentityCredential
     */
    IWritableIdentityCredential updateCredential();

    /**
     * Like finishRetrieval() but also returns an ECDSA signature in addition to the MAC.
     *
     * See section 9.1.3.6 of ISO/IEC 18013-5:2021 for details of how the signature is calculated.
     *
     * Unlike MACing, an ECDSA signature will be returned even if mdoc session encryption isn't
     * being used.
     *
     * This method was introduced in API version 5.
     *
     * @param ecdsaSignature a COSE_Sign1 signature described above.
     */
    @SuppressWarnings(value={"out-array"})
    void finishRetrievalWithSignature(
            out byte[] mac, out byte[] deviceNameSpaces, out byte[] ecdsaSignature);
}
+11 −0
Original line number Diff line number Diff line
@@ -70,6 +70,17 @@ interface IPresentationSession {
     *
     * This can be empty but if it's non-empty it must be valid CBOR.
     *
     * If mdoc session encryption is used (e.g. getEphemeralKeyPair() has been called)
     * and the SessionTranscript CBOR is not empty, the X and Y coordinates of the public
     * part of the key-pair previously generated by createEphemeralKeyPair() must appear
     * somewhere in the bytes of the CBOR. Each of these coordinates must appear encoded
     * with the most significant bits first and use the exact amount of bits indicated by
     * the key size of the ephemeral keys. For example, if the ephemeral key is using the
     * P-256 curve then the 32 bytes for the X coordinate encoded with the most significant
     * bits first must appear somewhere in the CBOR and ditto for the 32 bytes for the Y
     * coordinate. If this is not satisfied, the call fails with
     * STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND.
     *
     * This method may only be called once per instance. If called more than once, STATUS_FAILED
     * must be returned.
     *
+25 −6
Original line number Diff line number Diff line
@@ -596,10 +596,10 @@ bool FakeSecureHardwarePresentationProxy::startRetrieveEntries() {
    return eicPresentationStartRetrieveEntries(&ctx_);
}

bool FakeSecureHardwarePresentationProxy::calcMacKey(
bool FakeSecureHardwarePresentationProxy::prepareDeviceAuthentication(
        const vector<uint8_t>& sessionTranscript, const vector<uint8_t>& readerEphemeralPublicKey,
        const vector<uint8_t>& signingKeyBlob, const string& docType,
        unsigned int numNamespacesWithValues, size_t expectedProofOfProvisioningSize) {
        unsigned int numNamespacesWithValues, size_t expectedDeviceNamespacesSize) {
    if (!validateId(__func__)) {
        return false;
    }
@@ -608,10 +608,10 @@ bool FakeSecureHardwarePresentationProxy::calcMacKey(
        eicDebug("Unexpected size %zd of signingKeyBlob, expected 60", signingKeyBlob.size());
        return false;
    }
    return eicPresentationCalcMacKey(&ctx_, sessionTranscript.data(), sessionTranscript.size(),
                                     readerEphemeralPublicKey.data(), signingKeyBlob.data(),
                                     docType.c_str(), docType.size(), numNamespacesWithValues,
                                     expectedProofOfProvisioningSize);
    return eicPresentationPrepareDeviceAuthentication(
            &ctx_, sessionTranscript.data(), sessionTranscript.size(),
            readerEphemeralPublicKey.data(), readerEphemeralPublicKey.size(), signingKeyBlob.data(),
            docType.c_str(), docType.size(), numNamespacesWithValues, expectedDeviceNamespacesSize);
}

AccessCheckResult FakeSecureHardwarePresentationProxy::startRetrieveEntryValue(
@@ -673,6 +673,25 @@ optional<vector<uint8_t>> FakeSecureHardwarePresentationProxy::retrieveEntryValu
    return content;
}

optional<pair<vector<uint8_t>, vector<uint8_t>>>
FakeSecureHardwarePresentationProxy::finishRetrievalWithSignature() {
    if (!validateId(__func__)) {
        return std::nullopt;
    }

    vector<uint8_t> mac(32);
    size_t macSize = 32;
    vector<uint8_t> ecdsaSignature(EIC_ECDSA_P256_SIGNATURE_SIZE);
    size_t ecdsaSignatureSize = EIC_ECDSA_P256_SIGNATURE_SIZE;
    if (!eicPresentationFinishRetrievalWithSignature(&ctx_, mac.data(), &macSize,
                                                     ecdsaSignature.data(), &ecdsaSignatureSize)) {
        return std::nullopt;
    }
    mac.resize(macSize);
    ecdsaSignature.resize(ecdsaSignatureSize);
    return std::make_pair(mac, ecdsaSignature);
}

optional<vector<uint8_t>> FakeSecureHardwarePresentationProxy::finishRetrieval() {
    if (!validateId(__func__)) {
        return std::nullopt;
Loading