Coder Social home page Coder Social logo

identity-credential's Introduction

Identity Credential

This repository contains libraries and applications for working with Real-World Identity. The initial focus for this work was mdoc/mDL according to ISO/IEC 18013-5:2021 and related standards (mainly ISO 23220 series and ISO 18013-7) but the current scope also include other credential formats.

Identity Credential Libraries

The project includes libraries written in Kotlin:

  • identity provides the core building blocks and which can also be used in server-side environments.
  • identity-mdoc provides data structures and routines for working with mdoc credentials. This library can also be used in server-side-environments
  • identity-android provides Android-specific extensions. It is designed to run on Android (API 24 or later) and will take advantage of Android-specific features including hardware-backed Keystore, NFC, Bluetooth Low Energy, and so on.
  • identity-android-legacy contains an older version of the APIs for applications not yet migrated to the newer libraries. At some point this library will be removed. Unlike the other libraries and applications, this library is in Java, not Kotlin.
  • identity-doctypes contains known credential document types (for example ISO/IEC 18013-5:2021 mDL and EU PID) along with human-readable descriptions of claims / data elements and also sample data. This is packaged separately from the core identity library because its size is non-negligible and not all applications need this or they may bring their own.

These libraries are intended to be used by Wallet Applications (mobile applications on the credential holder's device), Reader Applications (applications operated on device controlled by the verifier), and Issuance Systems (applications operated by the credential issuer or their agent). They provide the following building blocks

  • A light-weight Secure Area abstraction for hardware-backed keystore
    • Applications can create hardware-backed Elliptic Curve Cryptography keys which can be used for creating Signatures or performing Key Agreement. Each key will have an attestation which can be used to prove to Relying Parties (such as a credential issuer) that the private part of the key only exists in a Secure Area.
    • The identity-android library includes an implementation based on Android Keystore with support for requiring user authentication (biometric or lock-screen knowledge factor, e.g. system PIN) for unlocking the key and also can use StrongBox if available on the device. This is appropriate to use in Android applications implementing ISO/IEC 18013-5:2021 for storing DeviceKey.
    • The identity library includes an implementation backed by BouncyCastle with support for passphrase-protected keys. This isn't suitable for use in Mobile Applications as its not backed by Secure Hardware.
    • Applications can supply their own Secure Area implementations for e.g. externally attached dongles, cloud based HSMs, or whatever the issuer deems appropriate to protect key material associated with their credential.
  • A Credential Store for storage of one or more Credentials
    • Each Credential has a Credential Key which can be used by the issuer to bind a credential to a specific device which is useful when issuing updates or refreshing a credential.
    • Additionally, each Credential has one or more Authentication Keys which can be endorsed by the issuer and used at presentation time.
    • Finally, namespaced data and arbritrary key/value pairs can be stored in a Credential which can be used for credential data and claims. This data is stored encrypted at rest.
  • Data structures and code for provisioning of mdoc/mDLs
    • This code can can be used both on the device and issuer side. No networking protocol is defined, the application has to define its own.
  • Parsers and generators for all data structures used in ISO/IEC 18013-5:2021 presentations, including DeviceResponse, DeviceRequest, MobileSecurityObject and many other CBOR data structures.
  • An implementation of the ISO/IEC 18013-5:2021 presentation flows including QR engagement, NFC engagement (both static and negotiated), device retrieval (BLE, Wifi Aware, and NFC)

Currently these libraries require a Java runtime environment but the plan is to target Kotlin Multiplatform for the libraries and Compose Multiplatform for applications and samples.

Command-line tool

A command-line tool identityctl is included which can be used to generate ISO/IEC 18013-5:2021 IACA test certificates among other things. Use ./gradlew --quiet runIdentityCtl --args "help" for documentation on supported verbs and options.

Library releases, Versioning, and Documentation

Libraries are released on GMaven as needed and version numbers are encoded as YYYYMMDD. With each release, we also publish documentation at https://openwallet-foundation-labs.github.io/identity-credential/.

Wallet and Reader Android applications

This repository also contains two Android applications using this library in the appholder and appverifier modules. The Wallet application is a simple self-contained application which allows creating a number of mdoc credentials using four different mdoc Document Types:

  • org.iso.18013.5.1.mDL: Mobile Driving License
  • org.micov.1: mdoc for eHealth (link)
  • nl.rdw.mekb.1: mdoc for Vehicle Registration (link)
  • eu.europa.ec.eudiw.pid.1: mdoc for Personal Identification

and their associated mdoc name spaces. The first one is defined in ISO/IEC 18013-5:2021 and the other three have been used at mdoc/mDL test events organized by participants of the ISO/IEC JTC1 SC17 WG10 working group.

The appholder offers two flavors: wallet and purse. There is not much difference between the two, except they have different application id, so they can coexist in a single device. They also have different labels and icon color. To select the desired flavor when running the app on a device/emulator, inside the Android Studio open the Build Variants panel. It should be easily reachable on the left side bar of the Android Studio, or by selecting: View -> Tool Windows -> Build Variants. Inside the Build Variants panel, at the appholder row, the desired flavor can be chosen. Once a flavor is selected, by running the app it will install it on the target device/emulator.

The wallet module is a rewrite of the appholder reference application with an eye towards a production-quality and easily rebrandable identity wallet application.

Sample Applications

The samples/ directory contain a number of sample applications, intended primarily to show certain library features or assess performance or correctness. The following samples are included

  • preconsent-mdl - Simple mDL application without user consent authentication.
    • The main purpose of this sample is to assess performance of our libraries, Android, the device it's being run on, and the mDL reader requesting the mDL.
    • The application allows the user to easily configure which kind of data transfer method to use, including an idealized near-zero latency method (DataTransportUdp) to help pinpoint potential performance bottlenecks not related to data transfer.
  • age-verifier-mdl - a simple mDL reader for age attestations.
    • This application is just requesting the age_over_21 and portrait. It's intended to be used with the preconsent-mdl sample for performance evaluation.
  • simple-verifier - a simple mDL reader for age attestations.
    • This application requests either {age_over_21 and portrait} or {age_over_18 and portrait}. It's intended to demonstrate use of the MdocReaderPrompt class, which allows any app to easily act as a reader app for the common age-verification use case.

ISO 18013-7 Reader Website

The wwwverifier module contains the source code for a website acting as an mdoc reader according to the latest ISO 18013-7 working draft (as of Sep 2023) and it's implementing the so-called REST API. There is currently a test instance of this application available at https://mdoc-reader-external.uc.r.appspot.com/. The Wallet Android application also has support for the REST API and registers on Android for the mdoc:// URI scheme. This can be tested end-to-end by going to the reader website (URL above) and clicking on one of the "Request" buttons, and then hitting the mdoc:// link presented on the site. This will cause the browser to invoke the Wallet app which will then connect to the reader and send the credential after user consent.

Building and deploying the ISO 18013-7 Reader Website

First, a project must first be created at https://console.cloud.google.com. Afterwards, navigate to Cloud Shell (https://shell.cloud.google.com), and clone the Identity Credential Library repository:

git clone https://github.com/google/identity-credential.git

Open the file wwwverifier/build.gradle, and set the property projectId to the project ID that you used to create your Cloud project:

appengine {
    deploy {   // deploy configuration
      version = 'v1'
      projectId = '<YOUR_PROJECT_ID>'
      ...
    }
}

Grant Datastore Owner permissions to your AppEngine service account:

gcloud projects add-iam-policy-binding <YOUR_PROJECT_ID> \
    --member="serviceAccount:<YOUR_PROJECT_ID>@appspot.gserviceaccount.com" \
    --role="roles/datastore.owner"

Then, navigate to wwwverifier:

cd ~/identity-credential/wwwverifier

To run the website locally, execute the command:

gradle appengineRun

To deploy the website on a live server, execute the command:

gradle appengineDeploy

The above command will create a link to a live website. Then, navigate to the file ~/identity-credential/wwwverifier/src/main/java/com/android/identity/wwwreader/ServletConsts.java, and replace the following field with your website URL:

    public static final String BASE_URL = "<YOUR_WEBSITE_URL>";

Name

The name of the project is currently "Identity Credential" and it's using com.android.identity as the Java package name. This is because of the fact that the project was contributed from Google. Work is underway to find a new name and Java package name, see Issue #422.

identity-credential's People

Contributors

15characterlimi avatar advatar avatar andrewscull avatar davidz25 avatar dependabot[bot] avatar divegeek avatar dritan-x avatar dyiop avatar eduardo-flores avatar eduardo-flores-ul avatar garethcoliver avatar jos2237 avatar joshrl-clearme avatar justcallmec avatar keesgeluk avatar leecam avatar lilymzhou avatar miltolstoy avatar mitrejcevski avatar nikolayoleschuk avatar qzhelen avatar roffel avatar sethmoo avatar siriscac avatar skounis avatar sorotokin avatar spheroid avatar suzannajiwani avatar yanay-clear avatar zeylei avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

identity-credential's Issues

app holder crashes on start on Google Pixel 3a

Expected Behavior

App starts

Actual Behavior

App (app holder) crashes immediately

Steps to Reproduce the Problem

  1. build and run app holder on Pixel 3a
  2. yeah, that's it

Btw, I also tried on an OnePlus 8, and it's running.
Find the Logcat of the crash below:

2021-09-15 08:07:14.441 19198-19198/com.ul.ims.gmdl.appholder E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.ul.ims.gmdl.appholder, PID: 19198
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.ul.ims.gmdl.appholder/com.android.mdl.app.MainActivity}: android.view.InflateException: Binary XML file line #26 in com.ul.ims.gmdl.appholder:layout/activity_main: Binary XML file line #26 in com.ul.ims.gmdl.appholder:layout/activity_main: Error inflating class fragment
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3431)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3595)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7660)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
     Caused by: android.view.InflateException: Binary XML file line #26 in com.ul.ims.gmdl.appholder:layout/activity_main: Binary XML file line #26 in com.ul.ims.gmdl.appholder:layout/activity_main: Error inflating class fragment
     Caused by: android.view.InflateException: Binary XML file line #26 in com.ul.ims.gmdl.appholder:layout/activity_main: Error inflating class fragment
     Caused by: java.lang.UnsupportedOperationException
        at androidx.security.identity.IdentityCredential.storeStaticAuthenticationData(IdentityCredential.java:405)
        at androidx.security.identity.Helpers.provisionSelfSignedCredential(Helpers.java:358)
        at com.android.mdl.app.document.DocumentManager.createDummyCredential(DocumentManager.kt:103)
        at com.android.mdl.app.document.DocumentManager.access$createDummyCredential(DocumentManager.kt:40)
        at com.android.mdl.app.document.DocumentManager$1.invokeSuspend(DocumentManager.kt:71)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
        at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:274)
        at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:84)
        at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
        at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source:1)
        at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
        at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source:1)
        at com.android.mdl.app.document.DocumentManager.<init>(DocumentManager.kt:65)
        at com.android.mdl.app.document.DocumentManager.<init>(DocumentManager.kt:40)
        at com.android.mdl.app.document.DocumentManager$Companion.getInstance(DocumentManager.kt:53)
        at com.android.mdl.app.fragment.SelectDocumentFragment.onCreateView(SelectDocumentFragment.kt:59)
        at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2963)
        at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:518)
        at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:282)
        at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:112)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1647)
        at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3126)
        at androidx.fragment.app.FragmentManager.dispatchViewCreated(FragmentManager.java:3063)
        at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:2988)
        at androidx.fragment.app.FragmentStateManager.ensureInflatedView(FragmentStateManager.java:392)
        at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:281)
2021-09-15 08:07:14.441 19198-19198/com.ul.ims.gmdl.appholder E/AndroidRuntime:     at androidx.fragment.app.FragmentLayoutInflaterFactory.onCreateView(FragmentLayoutInflaterFactory.java:140)
        at androidx.fragment.app.FragmentController.onCreateView(FragmentController.java:135)
        at androidx.fragment.app.FragmentActivity.dispatchFragmentsOnCreateView(FragmentActivity.java:319)
        at androidx.fragment.app.FragmentActivity.onCreateView(FragmentActivity.java:298)
        at android.view.LayoutInflater.tryCreateView(LayoutInflater.java:1067)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:995)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:959)
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:1121)
        at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1082)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:680)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:532)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:479)
        at androidx.appcompat.app.AppCompatDelegateImpl.setContentView(AppCompatDelegateImpl.java:696)
        at androidx.appcompat.app.AppCompatActivity.setContentView(AppCompatActivity.java:170)
        at com.android.mdl.app.MainActivity.onCreate(MainActivity.kt:22)
        at android.app.Activity.performCreate(Activity.java:8000)
        at android.app.Activity.performCreate(Activity.java:7984)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3404)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3595)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7660)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)

Specifications

  • Version: master (14.09.2021)
  • Platform: Android 11
  • Device: Google Pixel 3a

NFC static handover issue

Expected Behavior

NFC static handover should be working fine with NFC +BLE mode

Actual Behavior

on Doing NFC static handover , the device engagement data create twice and holder app tries to decrypt the data with keys from first created Device engagemet data result in request decryption failure at holder end . Have attached the logs for the google holder app

Steps to Reproduce the Problem

Google Holder app logs.txt
verifier app-logs-2023-01-17232107_NFC _Static with google.txt

Specifications

  • Version:
  • Platform: Android

IllegalStateException when multiple requests are received subsequently

Expected Behavior

While it would not make much sense to send a second request before the previous has been answered and the ISO standard implicitly states that the request should be followed by a response (and then further back and forth communication may resume), I think the library still shouldn't crash if that happens.

Actual Behavior

If the verifier application sends multiple requests in sequence, before the response has been sent, the identity-credential library crashes with:

java.lang.IllegalStateException: SessionTranscript already set
        at com.android.identity.SoftwarePresentationSession.setSessionTranscript(SoftwarePresentationSession.java:98)
        at com.android.identity.PresentationHelper$1.onMessageReceived(PresentationHelper.java:451)
        at com.android.identity.DataTransport.lambda$reportMessageReceived$6(DataTransport.java:343)
        at com.android.identity.DataTransport$$ExternalSyntheticLambda8.run(Unknown Source:4)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:233)
        at android.app.ActivityThread.main(ActivityThread.java:8030)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:631)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:978)

Steps to Reproduce the Problem

  1. Pair the devices and send a request
  2. Before accepting the request, send another request from the verifier
  3. Holder app crashes because the session transcript is attempted to re-set

If the BLE connection is lost after the 'State' characteristic is set to value '0x01', the mdoc still scans for the UUID

Expected Behavior

If the BLE connection is lost after the 'State' characteristic is set to value '0x01' then the mdoc should stop scanning for UUID and opens a new session if required as per ISO-18013-5

Actual Behavior

The mDoc is still in central client mode scanning for the UUID.

Steps to Reproduce the Problem

  1. Perform device engagement using QR code or NFC and set up BLE for device retrieval
    2.Sending the device request message from the reader
  2. Disconnect the BLE connection immediately after sending the response from the holder

Specifications

  • Version: Android 10(Quince Tart)
  • Platform: Android
    image-2022-03-22-17-18-58-609
    :

If BLE connection is lost before the 'State' characteristic is set to value '0x01', the mdoc doesn't try to reconnect

Expected Behavior

As per ISO 18013-5(8.3.3.1.1.3) Standard
If BLE connection is lost before the 'State' characteristic is set to value '0x01', the mdoc should try to reconnect.

Actual Behavior

No reconnection is taking place

Steps to Reproduce the Problem

  1. Perform device engagement using QR code or NFC and set up BLE for device retrieval
  2. Disconnect the connection before the State characteristic is set to value '0x01'. Verify that the mdoc(Holder App) terminates the current BLE connection and tries to re-connect

Specifications

  • Version: Android 10(Quince Tart)
  • Platform:Android
    image-2022-03-22-17-18-58-609
    :

"Auto close connection" enabled close the connection before draining the queue

Expected Behavior

Termination session bytes send AFTER draining the queue and transmitting all the deviceResponse bytes.

Actual Behavior

The termination message was sent while draining the queue and caused the reader to receive only partial deviceResponse

Steps to Reproduce the Problem

  1. Enable "Auto close connection" in the settings screen
  2. Start flow
  3. Observe the logs after the scope consents
  4. After sending 2 chunks it closes the connection instead of transmitting all the chunks.

Specifications

ErrorCode with value 0 missing in the device retrieval mdoc response for the missing data element

Expected Behavior

As per ISO 18013-5(8.3.3.1.1.3) Standard
Device retrieval mdoc response should contain an error code 0 for the missed item that are requested from the verifier.

Actual Behavior

A response without any error code for the missed items(requested items that are not present in Holder) is returned

This has been added in the TODO bucket list

Steps to Reproduce the Problem

  1. Perform device engagement using QR code or NFC and set up BLE for device retrieval
  2. De-select/remove some of the requested data items and share it

Specifications

  • Version: Android 12
  • Platform: Android

Screenshot 2022-08-01 at 6 12 31 PM

Execution failed for task ':app:generateSafeArgsDebug'

Expected Behavior

App run successfully.

Actual Behavior

Execution failed for task ':appreader:generateSafeArgsDebug'.

Could not read '\mdl-ref-apps\app\build\intermediates\metadata_application_id\debug\application-id.txt' as it does not exist.

Fails to install and run app.

Steps to Reproduce the Problem

  1. Click Run 'app'

Specifications

Android Studio 4.1.1
Windows 10 Enterprise

Others:

Same issue when running 'appreader' app.

DeviceEngagement for NFC is malformed

18013-5 8.2.1.1 Device engagement structure" says DeviceEngagement should not contain DeviceRetrievalMethods map at all for NFC, however our implementation inserts this with an empty list of methods.

ProofOfBinding certificate extension

The 'Android Identity Credential Authentication Key' certificate contains a custom extension 1.3.6.1.4.1.11129.2.1.26 with the ProofOfBinding.

Example:

A3 44 (68)
	30 42 (66)
		30 40 (64)
			06 0A (10): 2B06010401D67902011A
			04 32 (50): 826E50726F6F664F6642696E64696E675820F6098091A6CCA59DA9512B262515440750B757C2E1EB30C7B5FA93E59127FAFB

Is this valid format according to X.509? I think the content should also be ASN.1 encoded, but currently it is just raw bytes of ProofOfContent.
The certificate is generated in CredentialData.java, generateAuthenticatoinKeyCert method.

CoseSign1 missing AccessControlProfiles(?)

Expected Behavior

The personalize method of the WritableIdentityCredential creates a COSE_Sign1 structure including the Credential data and its AccessControlProfiles.

Actual Behavior

The output of wc.personalize(personalizationBuilderAuth.build()) contains the CBOR COSE_Sign1 data and some information about the AccessControlProfiles. This seems to be correct. However, when loading this data in a Kotlin COSE_Sign1 object (package com.ul.ims.gmdl.cbordata.security.CoseSign1) the AccessControlProfile are missing.

I have added a small test settings below. Please compare the output of debug1 and debug2. I honestly don't know if I am missing something or if it is a bug.

Steps to Reproduce the Problem

package com.google.x

import android.util.Log
import androidx.security.identity.*
import androidx.test.platform.app.InstrumentationRegistry
import com.ul.ims.gmdl.cbordata.security.CoseSign1
import org.junit.Test

class PopTest {

    @Test
    fun testProofOfProvisioning() {
        val context = InstrumentationRegistry.getInstrumentation().context
        val store = IdentityCredentialStore.getInstance(context)
        val wc: WritableIdentityCredential?

        try {
            store.deleteCredentialByName("test_credential")
        } catch(npe: NullPointerException) {
            // Ignore, document not created yet. Only for recurring tests
        }

        wc = store.createCredential(
            "test_credential",
            "testDoc"
        )

        val personalizationBuilderAuth = PersonalizationData.Builder()
        val namespace = "namespace.test"

        val acpid = AccessControlProfileId(1)

        val acp = AccessControlProfile.Builder(acpid)
            .setUserAuthenticationRequired(false)
            .setUserAuthenticationTimeout(0)
            .build()

        personalizationBuilderAuth.addAccessControlProfile(
            acp
        )

        personalizationBuilderAuth.putEntryString(
            namespace,
            "id1",
            arrayListOf(acpid),
            "test1"
        )

        personalizationBuilderAuth.putEntryString(
            namespace,
            "id2",
            arrayListOf(acpid),
            "test2"
        )

        personalizationBuilderAuth.putEntryString(
            namespace,
            "id3",
            arrayListOf(acpid),
            "test3"
        )

        personalizationBuilderAuth.putEntryString(
            namespace,
            "id4",
            arrayListOf(acpid),
            "test4"
        )

        personalizationBuilderAuth.putEntryString(
            namespace,
            "id5",
            arrayListOf(acpid),
            "test5"
        )

        val data = personalizationBuilderAuth.build()

        val proofOfProvisioningCbor = wc.personalize(data)
        val coseSign1 = CoseSign1.Builder().decode(proofOfProvisioningCbor).build()
        val debug1 = String(proofOfProvisioningCbor)
        val debug2 = String(coseSign1.payloadData!!)
    }
}

Specifications

  • Platform: Android 11 (Google Pixel 5)

mDL Close Procedure was not followed if the L2cap is not supported

Expected Behavior

If the mdoc is acting as the GATT client during device retrieval using BLE and does not support the L2CAP transmission profile, the mdoc follows the correct close procedure which is mdoc should write the value 0x0000 to descriptor of 'Server2Client'.

Actual Behavior

The mDL did not write value 0x0000 to descriptor of 'Server2Client and it closes the BLE connection

Steps to Reproduce the Problem

1.if the mdoc is acting as the GATT client during device retrieval using BLE and does not support the L2CAP transmission profile,
2.Set the value of the 'State' characteristic of the mdoc reader service to 0x02 (End) to signal the end of data transmission

Specifications

  • Version:12.0
  • Platform:Android

Android 13 crash with hardware backed storage (Pixel 6)

Expected Behavior
The app shouldn’t be crashing while trying to writing the credential with hardware backed storage with all devices

Actual Behavior
The app is crashing on some of the devices while trying to write the credential with hardware backed

Steps to Reproduce the Problem

  1. Open the holder app
  2. Click add document
  3. Choose Hardware-backed and click next
  4. Click next and the app crashes with the below mentioned error

Device: Google pixel 6
Android OS : 13.0

E/AndroidRuntime: FATAL EXCEPTION: DefaultDispatcher-worker-1
Process: com.android.mdl.app, PID: 15986
java.lang.RuntimeException: Unexpected ServiceSpecificException with code 1
at android.security.identity.CredstoreIdentityCredentialStore.createCredential(CredstoreIdentityCredentialStore.java:129)
at com.android.identity.HardwareIdentityCredentialStore.createCredential(HardwareIdentityCredentialStore.java:109)
at com.android.identity.Utility.provisionSelfSignedCredential(Utility.java:273)
at com.android.mdl.app.document.DocumentManager.provisionSelfSigned(DocumentManager.kt:694)
at com.android.mdl.app.document.DocumentManager.provisionSelfSignedMdl(DocumentManager.kt:356)
at com.android.mdl.app.document.DocumentManager.access$provisionSelfSignedMdl(DocumentManager.kt:24)
at com.android.mdl.app.document.DocumentManager$createSelfSignedCredential$1.invokeSuspend(DocumentManager.kt:188)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:284)
at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:85)
at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source:1)
at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source:1)
at com.android.mdl.app.document.DocumentManager.createSelfSignedCredential(DocumentManager.kt:181)
at com.android.mdl.app.viewmodel.SelfSignedViewModel$createSelfSigned$1.invokeSuspend(SelfSignedViewModel.kt:206)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42)
at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)
Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@7420abd, Dispatchers.IO]
Caused by: android.os.ServiceSpecificException: HAL failed with exception code -8 (EX_SERVICE_SPECIFIC), service-specific error code 1, message 'Error initializing WritableIdentityCredential' (code 1)
at android.os.Parcel.createExceptionOrNull(Parcel.java:3025)
at android.os.Parcel.createException(Parcel.java:2995)
at android.os.Parcel.readException(Parcel.java:2978)
at android.os.Parcel.readException(Parcel.java:2920)
at android.security.identity.ICredentialStore$Stub$Proxy.createCredential(ICredentialStore.java:197)
at android.security.identity.CredstoreIdentityCredentialStore.createCredential(CredstoreIdentityCredentialStore.java:109)
... 24 more
D/OpenGLRenderer: endAllActiveAnimators on 0xb40000711a06b560 (RippleDrawable) with handle 0xb40000702a36b8c0




MicrosoftTeams-image

Crash when resuming "Sharing Document"

Press "Show QR Code" to get to the "Sharing Document" screen. Lock and unlock the device and the app crashes because it tried to start a new transfer even though one is already underway.

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.android.mdl.app, PID: 10791
    java.lang.RuntimeException: Unable to resume activity {com.android.mdl.app/com.android.mdl.app.MainActivity}: java.lang.IllegalStateException: Transfer has already started.
        at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4894)
        at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4927)
        at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:57)
        at android.app.servertransaction.ActivityTransactionItem.execute(ActivityTransactionItem.java:45)
        at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:179)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2380)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loopOnce(Looper.java:205)
        at android.os.Looper.loop(Looper.java:294)
        at android.app.ActivityThread.main(ActivityThread.java:8098)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:578)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:946)
     Caused by: java.lang.IllegalStateException: Transfer has already started.
        at com.android.mdl.app.transfer.TransferManager.startQrEngagement(TransferManager.kt:102)
        at com.android.mdl.app.viewmodel.ShareDocumentViewModel.triggerQrEngagement(ShareDocumentViewModel.kt:45)
        at com.android.mdl.app.fragment.ShareDocumentFragment.onResume(ShareDocumentFragment.kt:77)
        at androidx.fragment.app.Fragment.performResume(Fragment.java:3180)
        at androidx.fragment.app.FragmentStateManager.resume(FragmentStateManager.java:606)
        at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:285)
        at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:113)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1433)
        at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2977)
        at androidx.fragment.app.FragmentManager.dispatchResume(FragmentManager.java:2909)
        at androidx.fragment.app.Fragment.performResume(Fragment.java:3189)
        at androidx.fragment.app.FragmentStateManager.resume(FragmentStateManager.java:606)
        at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:285)
        at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:113)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1433)
        at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2977)
        at androidx.fragment.app.FragmentManager.dispatchResume(FragmentManager.java:2909)
        at androidx.fragment.app.FragmentController.dispatchResume(FragmentController.java:285)
        at androidx.fragment.app.FragmentActivity.onResumeFragments(FragmentActivity.java:334)
        at androidx.fragment.app.FragmentActivity.onPostResume(FragmentActivity.java:323)
        at androidx.appcompat.app.AppCompatActivity.onPostResume(AppCompatActivity.java:242)
        at android.app.Activity.performResume(Activity.java:8626)
        at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4884)
        at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4927) 
        at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:57) 
        at android.app.servertransaction.ActivityTransactionItem.execute(ActivityTransactionItem.java:45) 
        at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:179) 
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2380) 
        at android.os.Handler.dispatchMessage(Handler.java:106) 
        at android.os.Looper.loopOnce(Looper.java:205) 
        at android.os.Looper.loop(Looper.java:294) 
        at android.app.ActivityThread.main(ActivityThread.java:8098) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:578) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:946) 

WebAPI & OIDC

Hi

Building an app from this base. I noticed that WebAPI and OIDC has not been implemented. Do you happen to have the spec for this protocols so I can build it myself?

Bluetooth connection never starts

Expected Behavior

After scanning the deviceengagement qr-code with the verifier, the two devices connect to each other.

Actual Behavior

verifier shows spinner next to "Connection Setup", but nothing else happens.

Steps to Reproduce the Problem

  1. Install Appholder and App reader
  2. Scan deviceengagement code

Specifications

  • Version: current master (14.09.2021)
  • Platform: Android 11
  • Used device combinations:
    | Verifier | Holder |
    | --- | --- |
    | Google Pixel 3a | OnePlus 8 |
    | Xiaomi Redmi Note 9 | OnePlus 8 |
    | Google Pixel 3a | Xiaomi MiA2lite |
    | OnePlus8 | Xiaomi MiA2lite |

If the device retrieval mdoc request contains an incorrect version number, the mdoc doesn't communicate the correct status code in the DeviceResponse

Expected Behavior

1)If the device retrieval mdoc request from the verifier contains an incorrect version number i.e 1.1
2) The mdoc should communicates the correct status code which is 10 or 12 without document key pair in the DeviceResponse by validating against the major version number as per ISO 18013-5 (8.1 Encoding of data structures and data elements)

Actual Behaviour

1)The validation of version number doesn't takes place properly
2) successful engagement takes place with status code as 0 and document key pair is present with empty array

Steps to Reproduce the Problem

  1. Perform device engagement using QR code or NFC and set up BLE for device retrieval
  2. Generate a DeviceRequest message with version number as 1.1 which doesn't matches the major version number as per ISO 18013

Specifications

  • Version: Android 10(Quince Tart)
  • Platform: Android

Get hardware instance throws runtime exception instead of return null when unsupported

Steps to Reproduce the Problem

  1. Using a device that does not support hardware backed store (eg. Android API Level 30)
  2. Call IdentityCredentialStore.getHardwareInstance()

Expected Behavior

Should return null if hardware backed is not supported (it's marked @nullable and javadoc states unsupported will return null).

Actual Behavior

Throws a runtime exception with message "HW-backed IdentityCredential not supported"

Specifications

  • Version: master
  • Platform: Android API Level 30

Util.fromHex() fails to reject invalid hex characters

Expected Behavior

Util.fromHex("XX") throws IllegalArgumentException

Actual Behavior

Util.fromHex("XX") returns -17 (= 0xEF)

This is because Util.fromHex() is built on top of Character.digit(), and Character.digit('X', 16) returns -1.

I already have a commit to fix this, I'm just filing this issue first so I can reference it from my fix commit.

Crash if holder closes connection right after sending response

In some cases our reader crashes if the holder closes the connection right after sending the response. This has been observed when using Wifi Aware but I believe it also applies to other transports.

java.lang.IllegalArgumentException: Navigation action/destination com.android.mdl.appreader:id/action_Transfer_to_RequestOptions cannot be found from the current destination Destination(com.android.mdl.appreader:id/ShowDocument) label=Show Document class=com.android.mdl.appreader.fragment.ShowDocumentFragment

Crash when replacing portrait

Expected Behavior

The portrait in the self-signed document details can be replaced from the camera.

Actual Behavior

After taking a picture, the app crashes.

Steps to Reproduce the Problem

  1. Open app > Add Document > Next
  2. Tap on the picture and take a new picture (in portrait)
  3. Confirm the picture and see the app crash

Specifications

  • Version: HEAD
  • Platform: AOSP 13

Remove extra identity library files from wwwverifier/

There are currently a set of duplicate files copied over from the identity/ library that are located at wwwverifier/src/main/java/com/google/sps/identity, as there were some difficulties in importing classes from identity/ to wwwverifier/. In the future, these extra files should be removed, and the file RequestServlet.java should be modified accordingly.

No error code send to verifier during exception while decrypting request

Expected Behavior

A response with appropriate error code should be send to verifier when an exception occurs while decrypting request.

According to document ISO 18013-5, section 9.1.1.4 Table 20(attached): An error code should be send when there is an exception while processing the request before terminating the session. But in the IC API when an exception occurred while decrypting a request(PresentationHelper->onMessageReceived()) there is no response with error codes send to the verifier. The DataTransport session is closed and an error message is send to the reportError method which gets communicated to the onError callback. When the implementing app tries to send the response with error code the below 2 issues blocks it.

  1. As only the message was sent its not feasible to identify the error code with error message in the onError callback.
  2. As the transport is closed its not possible to send the response even with some error code(hardcoded) In order to solve this a response with appropriate error code should be sent to the verifier before closing the transport.
    Also with this the error callback should be modified in a way to communicate the error with error codes.

Actual Behavior

No response with appropriate error code has been send to verifier during exception while decrypting request

Steps to Reproduce the Problem

There are more than 5 exception handling in PresentationHelper->onMessageReceived() method and all the cases should be covered. One such case is listed below
While sending an encrypted device retrieval mdoc request to the mdoc in a SessionEstablishment message make sure the mdoc reader ephemeral public point is not on the curve

  1. Generate an mdoc reader ephemeral key pair, using the curve communicated by the mdoc in the device engagement structure
  2. Add 1 to the value of the y-coordinate of the resulting public point, and verify that the new point is not on the curve. If it is, add 1 again.
  3. Send the request.

Specifications

  • Version: Android 10(Quince Tart)
  • Platform: Android

Screenshot 2022-08-30 at 7 40 39 PM

How do I add my DL to the holder?

Expected Behavior I am trying to add my driver license to the holder. How do I do that? Thank you.

Actual Behavior The provisioning screen is asking for a server connection. What is the server role? How do I configure the server?

Steps to Reproduce the Problem

  1. Click Add Document button
  2. The server connection fails.
  3. Where do I add my driver license?

Specifications

  • Version:
  • Platform:

Build fails on Android Studio MAC

An exception has occurred in the compiler (1.8.0_202). Please file a bug against the Java compiler via the Java bug reporting page (http://bugreport.java.com) after checking the Bug Database (http://bugs.java.com) for duplicates. Include your program and the following diagnostic in your report. Thank you.
java.lang.AssertionError: annotationType(): unrecognized Attribute name MODULE (class com.sun.tools.javac.util.UnsharedNameTable$NameImpl)
at com.sun.tools.javac.util.Assert.error(Assert.java:133)
at com.sun.tools.javac.code.TypeAnnotations.annotationType(TypeAnnotations.java:231)
at com.sun.tools.javac.code.TypeAnnotations$TypeAnnotationPositions.separateAnnotationsKinds(TypeAnnotations.java:294)
at com.sun.tools.javac.code.TypeAnnotations$TypeAnnotationPositions.visitMethodDef(TypeAnnotations.java:1066)
at com.sun.tools.javac.tree.JCTree$JCMethodDecl.accept(JCTree.java:778)
at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
at com.sun.tools.javac.code.TypeAnnotations$TypeAnnotationPositions.scan(TypeAnnotations.java:275)
at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:57)
at com.sun.tools.javac.code.TypeAnnotations$TypeAnnotationPositions.visitClassDef(TypeAnnotations.java:1042)
at com.sun.tools.javac.tree.JCTree$JCClassDecl.accept(JCTree.java:693)
at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
at com.sun.tools.javac.code.TypeAnnotations$TypeAnnotationPositions.scan(TypeAnnotations.java:275)
at com.sun.tools.javac.code.TypeAnnotations$1.run(TypeAnnotations.java:127)
at com.sun.tools.javac.comp.Annotate.flush(Annotate.java:152)
at com.sun.tools.javac.comp.Annotate.enterDone(Annotate.java:129)
at com.sun.tools.javac.comp.Enter.complete(Enter.java:512)
at com.sun.tools.javac.comp.Enter.main(Enter.java:471)
at com.sun.tools.javac.main.JavaCompiler.enterTrees(JavaCompiler.java:982)
at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:857)
at com.sun.tools.javac.main.Main.compile(Main.java:523)
at com.sun.tools.javac.api.JavacTaskImpl.doCall(JavacTaskImpl.java:129)
at com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:138)
at org.gradle.internal.compiler.java.IncrementalCompileTask.call(IncrementalCompileTask.java:74)
at org.gradle.api.internal.tasks.compile.AnnotationProcessingCompileTask.call(AnnotationProcessingCompileTask.java:93)
at org.gradle.api.internal.tasks.compile.ResourceCleaningCompilationTask.call(ResourceCleaningCompilationTask.java:57)
at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.execute(JdkJavaCompiler.java:55)
at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.execute(JdkJavaCompiler.java:40)
at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.delegateAndHandleErrors(NormalizingJavaCompiler.java:97)
at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.execute(NormalizingJavaCompiler.java:51)
at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.execute(NormalizingJavaCompiler.java:37)
at org.gradle.api.internal.tasks.compile.AnnotationProcessorDiscoveringCompiler.execute(AnnotationProcessorDiscoveringCompiler.java:51)
at org.gradle.api.internal.tasks.compile.AnnotationProcessorDiscoveringCompiler.execute(AnnotationProcessorDiscoveringCompiler.java:37)
at org.gradle.api.internal.tasks.compile.ModuleApplicationNameWritingCompiler.execute(ModuleApplicationNameWritingCompiler.java:46)
at org.gradle.api.internal.tasks.compile.ModuleApplicationNameWritingCompiler.execute(ModuleApplicationNameWritingCompiler.java:36)
at org.gradle.api.internal.tasks.compile.CleaningJavaCompiler.execute(CleaningJavaCompiler.java:53)
at org.gradle.api.internal.tasks.compile.incremental.IncrementalCompilerFactory.lambda$createRebuildAllCompiler$0(IncrementalCompilerFactory.java:98)
at org.gradle.api.internal.tasks.compile.incremental.IncrementalResultStoringCompiler.execute(IncrementalResultStoringCompiler.java:60)
at org.gradle.api.internal.tasks.compile.incremental.IncrementalResultStoringCompiler.execute(IncrementalResultStoringCompiler.java:44)
at org.gradle.api.internal.tasks.compile.CompileJavaBuildOperationReportingCompiler$2.call(CompileJavaBuildOperationReportingCompiler.java:59)
at org.gradle.api.internal.tasks.compile.CompileJavaBuildOperationReportingCompiler$2.call(CompileJavaBuildOperationReportingCompiler.java:51)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:409)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:399)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:157)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:242)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:150)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:94)
at org.gradle.internal.operations.DelegatingBuildOperationExecutor.call(DelegatingBuildOperationExecutor.java:36)
at org.gradle.api.internal.tasks.compile.CompileJavaBuildOperationReportingCompiler.execute(CompileJavaBuildOperationReportingCompiler.java:51)
at org.gradle.api.tasks.compile.JavaCompile.performCompilation(JavaCompile.java:293)
at org.gradle.api.tasks.compile.JavaCompile.performIncrementalCompilation(JavaCompile.java:203)
at org.gradle.api.tasks.compile.JavaCompile.compile(JavaCompile.java:183)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:104)
at org.gradle.api.internal.project.taskfactory.IncrementalInputsTaskAction.doExecute(IncrementalInputsTaskAction.java:32)
at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:42)
at org.gradle.api.internal.project.taskfactory.AbstractIncrementalTaskAction.execute(AbstractIncrementalTaskAction.java:25)
at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:28)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$3.run(ExecuteActionsTaskExecuter.java:569)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:395)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:387)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:157)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:242)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:150)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:84)
at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:554)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:537)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.access$300(ExecuteActionsTaskExecuter.java:108)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$TaskExecution.executeWithPreviousOutputFiles(ExecuteActionsTaskExecuter.java:278)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$TaskExecution.execute(ExecuteActionsTaskExecuter.java:267)
at org.gradle.internal.execution.steps.ExecuteStep.lambda$execute$0(ExecuteStep.java:32)
at java.util.Optional.map(Optional.java:215)
at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:32)
at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:26)
at org.gradle.internal.execution.steps.CleanupOutputsStep.execute(CleanupOutputsStep.java:67)
at org.gradle.internal.execution.steps.CleanupOutputsStep.execute(CleanupOutputsStep.java:36)
at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:49)
at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:34)
at org.gradle.internal.execution.steps.CancelExecutionStep.execute(CancelExecutionStep.java:43)
at org.gradle.internal.execution.steps.TimeoutStep.executeWithoutTimeout(TimeoutStep.java:73)
at org.gradle.internal.execution.steps.TimeoutStep.execute(TimeoutStep.java:54)
at org.gradle.internal.execution.steps.CatchExceptionStep.execute(CatchExceptionStep.java:34)
at org.gradle.internal.execution.steps.CreateOutputsStep.execute(CreateOutputsStep.java:44)
at org.gradle.internal.execution.steps.SnapshotOutputsStep.execute(SnapshotOutputsStep.java:54)
at org.gradle.internal.execution.steps.SnapshotOutputsStep.execute(SnapshotOutputsStep.java:38)
at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:49)
at org.gradle.internal.execution.steps.CacheStep.executeWithoutCache(CacheStep.java:159)
at org.gradle.internal.execution.steps.CacheStep.execute(CacheStep.java:72)
at org.gradle.internal.execution.steps.CacheStep.execute(CacheStep.java:43)
at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:44)
at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:33)
at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:38)
at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:24)
at org.gradle.internal.execution.steps.SkipUpToDateStep.executeBecause(SkipUpToDateStep.java:92)
at org.gradle.internal.execution.steps.SkipUpToDateStep.lambda$execute$0(SkipUpToDateStep.java:85)
at java.util.Optional.map(Optional.java:215)
at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:55)
at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:39)
at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:76)
at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:37)
at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:36)
at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:26)
at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:94)
at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:49)
at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:79)
at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:53)
at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:74)
at org.gradle.internal.execution.steps.SkipEmptyWorkStep.lambda$execute$2(SkipEmptyWorkStep.java:78)
at java.util.Optional.orElseGet(Optional.java:267)
at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:78)
at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:34)
at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsStartedStep.execute(MarkSnapshottingInputsStartedStep.java:39)
at org.gradle.internal.execution.steps.LoadExecutionStateStep.execute(LoadExecutionStateStep.java:40)
at org.gradle.internal.execution.steps.LoadExecutionStateStep.execute(LoadExecutionStateStep.java:28)
at org.gradle.internal.execution.impl.DefaultWorkExecutor.execute(DefaultWorkExecutor.java:33)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:194)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:186)
at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:114)
at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46)
at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:62)
at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57)
at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:56)
at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36)
at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77)
at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55)
at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:409)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:399)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:157)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:242)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:150)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:94)
at org.gradle.internal.operations.DelegatingBuildOperationExecutor.call(DelegatingBuildOperationExecutor.java:36)
at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52)
at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:41)
at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:356)
at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:343)
at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:336)
at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:322)
at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.lambda$run$0(DefaultPlanExecutor.java:127)
at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:191)
at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.executeNextNode(DefaultPlanExecutor.java:182)
at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:124)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
at java.lang.Thread.run(Thread.java:748)

Task :identity:bundleLibResDebug NO-SOURCE
Task :appholder:mergeDebugNativeLibs UP-TO-DATE
Task :appholder:stripDebugDebugSymbols NO-SOURCE
Task :appverifier:processDebugResources
Task :appverifier:mergeDebugNativeLibs UP-TO-DATE
Task :appverifier:stripDebugDebugSymbols NO-SOURCE
Task :appverifier:mergeExtDexDebug

Crash when sharing document with bluetooth is disabled

Pressing "Show QR Code" with bluetooth disabled results in an ungraceful crash and doesn't explain that you need to turn BT on in order to make it work. There's an example stack trace below and there are TODOs in the code for this same issue.

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.android.mdl.app, PID: 10229
    java.lang.NullPointerException: Attempt to invoke virtual method 'void android.bluetooth.le.BluetoothLeScanner.startScan(java.util.List, android.bluetooth.le.ScanSettings, android.bluetooth.le.ScanCallback)' on a null object reference
        at com.android.identity.DataTransportBleCentralClientMode.connectAsMdoc(DataTransportBleCentralClientMode.java:195)
        at com.android.identity.DataTransportBleCentralClientMode.connect(DataTransportBleCentralClientMode.java:292)
        at com.android.identity.QrEngagementHelper.startListening(QrEngagementHelper.java:144)
        at com.android.identity.QrEngagementHelper.<init>(QrEngagementHelper.java:46)
        at com.android.mdl.app.transfer.QrCommunicationSetup.configure(QrCommunicationSetup.kt:91)
        at com.android.mdl.app.transfer.TransferManager.startQrEngagement(TransferManager.kt:125)
        at com.android.mdl.app.viewmodel.ShareDocumentViewModel.triggerQrEngagement(ShareDocumentViewModel.kt:45)
        at com.android.mdl.app.fragment.ShareDocumentFragment.onResume(ShareDocumentFragment.kt:77)
        at androidx.fragment.app.Fragment.performResume(Fragment.java:3180)
        at androidx.fragment.app.FragmentStateManager.resume(FragmentStateManager.java:606)
        at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:285)
        at androidx.fragment.app.SpecialEffectsController$FragmentStateManagerOperation.complete(SpecialEffectsController.java:771)
        at androidx.fragment.app.SpecialEffectsController$Operation.completeSpecialEffect(SpecialEffectsController.java:690)
        at androidx.fragment.app.DefaultSpecialEffectsController$SpecialEffectsInfo.completeSpecialEffect(DefaultSpecialEffectsController.java:877)
        at androidx.fragment.app.DefaultSpecialEffectsController.startAnimations(DefaultSpecialEffectsController.java:176)
        at androidx.fragment.app.DefaultSpecialEffectsController.executeOperations(DefaultSpecialEffectsController.java:126)
        at androidx.fragment.app.SpecialEffectsController.executePendingOperations(SpecialEffectsController.java:306)
        at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1912)
        at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1823)
        at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1760)
        at androidx.fragment.app.FragmentManager$5.run(FragmentManager.java:547)
        at android.os.Handler.handleCallback(Handler.java:958)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loopOnce(Looper.java:205)
        at android.os.Looper.loop(Looper.java:294)
        at android.app.ActivityThread.main(ActivityThread.java:8098)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:578)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:946)

Holder disconnects from the UL verifier

Expected Behavior

If there is incorrect session establishment data then the holder should send status code as 20 for termination

Actual Behaviour

Instead Holder disconnect from the verifier without sending session termination

Steps to Reproduce the Problem

1.Establish a successful device engagement between holder and reader using QR (BLE mode)
2.Send an invalid session establishment message from the reader to the holder
3.Expect the above failure i.e the holder disconnected without sending status code as 20 for termination

Specifications

  • Version:12.0
  • Platform:Android
    image-2022-03-22-17-51-45-733

java.lang.IllegalArgumentException: Navigation action/destination com.android.mdl.appreader:id/action_Transfer_to_RequestOptions cannot be found from the current destination Destination(com.android.mdl.appreader:id/RequestOptions)

When I tap with another device which installs App Holder apk, I meet this exception. Galaxy S7 run Android 8.0:
java.lang.IllegalArgumentException: Navigation action/destination com.android.mdl.appreader:id/action_Transfer_to_RequestOptions cannot be found from the current destination Destination(com.android.mdl.appreader:id/RequestOptions) label=Mdoc Verifier class=com.android.mdl.appreader.fragment.RequestOptionsFragment
at androidx.navigation.NavController.navigate(NavController.kt:1540)
at com.android.mdl.appreader.fragment.TransferFragment.onViewCreated$lambda-0(TransferFragment.kt:114)

AppHolder crashes without notifying a user when the lock is not set

Expected Behavior

The app notifies the user the screen lock is not set and letting users know the screenlock has to be set in order to use the application.

Actual Behavior

The app crashes without notifying

Steps to Reproduce the Problem

  1. Launch the app

Specifications

  • Version: Android 12
  • Platform: Android

Provisioning specification

Are there any public specification regarding the provisioning? I don't think ISO 18013 talks about provisioning, and the ISO/IEC 23220 isn't available to public yet.

I am looking mainly at the ProvisioningSession and CertifyAuthKeysSession. For example

  • why first provisioning and then certify auth keys?
  • why two separate steps ('StartProvisioning' and 'com.android.identity_credential.StartProvisioning')? Looks like it could be done in one request.
  • should the challenge really be fixed (FixedChallenge)?
  • and many many more questions like that...

The only 'specification' I found is in the mdl-ref-server/README.md file. Where can I find more info about it?

Interop with iOS

Expected Behavior

You should be able to verify and present between iOS and Android

Actual Behavior

Nothing happens unless you add some calls to super

Steps to Reproduce the Problem

Specifications

  • Version:
  • Platform:

So, I have implemented all of this stuff in Swift for iOS including all the unit tests etc. It all works fine but interop between Android and iOS versions does not. I looked at some other BLE examples and saw that usually you need to invoke the super class f.i here:

https://github.com/google/mdl-ref-apps/blob/5c7dce58f475cfa1ff7f444f32a70b520db1d147/bleofflinetransfer/src/main/java/com/ul/ims/gmdl/bleofflinetransfer/peripheral/GattServer.kt#L226
like this:

super.onCharacteristicReadRequest(device, requestId, offset, characteristic)

When I do this it works (although a bit intermittently, I get timeouts) but when running Android as reader/verifier I get the request over the iOS holder, can decrypt the session and reply but the reader never gets the notification on the server2client characteristic. I wonder why it works Android-Android without this though.

So, I wonder if there is some other difference between iOS/Android. Setting up for notification is simpler on IOS and does not involve the CLIENT_CHARACTERISTIC_CONFIG descriptor. Why else should I look for here? Think I already tried invoking super. on the Central.

NFC Reader does not working on Samsung Galaxy S7

I install app holder on Samsung Galaxy S7 which runs on Android 8.0 and create a mDoc.
I install app verifier on Samsung Galaxy S10 which runs on Android 12.0.
I use NFC option for Data retrieval method.
I tap two devices to read mDoc. But nothing happens.

coseSign1Sign inconsistent with SECP521R1

Expected Behavior

When calculating the ECDSA value for SECP521R1, the "keySize" should be "66":
https://github.com/google/identity-credential/blob/b3388ede2f2541b3dc33d5417d5268ed19801b4d/identity/src/main/java/com/android/identity/Util.java#L576

Actual Behavior

Any leading zeros are trimmed but not replaced: causing a signature value of less than 132 bytes in such cases

Steps to Reproduce the Problem

  1. Set Reader Authentication to SECP521R1
  2. Perform a few reads
  3. Notice that when the signature computed has leading zeros the coseSign1Sign returns less than 132 bytes

Note: you may get a signature with no leading zeros (for neither R nor S) - in which case the value returned by coseSign1Sign will be correct

Specifications

  • Version: Android 10
  • Platform: Android

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.