Accettazione online delle credenziali digitali

Gli ID digitali possono essere accettati sia nei flussi in-app sia in quelli web. Per accettare le credenziali da Google Wallet, devi:

  1. Esegui l'integrazione utilizzando l'app o il web seguendo le istruzioni fornite.
  2. Utilizza l'ID test per testare il flusso utilizzando la sandbox di Google Wallet.
  3. Per pubblicare la tua soluzione, compila questo modulo per richiedere l'accesso e accettare i Termini di servizio delle credenziali Google Wallet. Devi compilare questo modulo per ciascuna delle tue entità aziendali. Il nostro team ti contatterà dopo che avrai compilato il modulo.
  4. Se hai domande, puoi contattarewallet-identity-rp-support@google.com.

Formati delle credenziali supportati

Esistono diversi standard proposti che definiscono il formato dei dati dei documenti di identità digitale, due dei quali stanno guadagnando una notevole popolarità nel settore:

  1. mdocs: definiti dalla norma ISO.
  2. Credenziali verificabili W3C: definite dal W3C.

Anche se Android Credential Manager supporta entrambi i formati, al momento Google Wallet supporta solo le identità digitali basate su mdoc.

Credenziali supportate

Google Wallet supporta due tipi di credenziali:

  1. Patente di guida digitale
  2. Tessera ID

Puoi richiedere una delle due credenziali nel flusso con una sola modifica del parametro.

Esperienza utente

Questa sezione descrive il flusso di presentazione online consigliato. Il flusso mostra la presentazione dell'età a un'app per la consegna di alcolici, ma l'esperienza utente è simile anche per il web e altri tipi di presentazioni.

All'utente viene chiesto di verificare l'età nell'app o sul sito web L'utente vede le credenziali idonee disponibili L'utente visualizza la pagina di conferma in Google Wallet L'utente esegue l'autenticazione per confermare la condivisione Dati inviati all'app o al sito web
All'utente viene chiesto di verificare l'età nell'app o sul sito web L'utente vede le credenziali idonee disponibili L'utente visualizza la pagina di conferma in Google Wallet L'utente esegue l'autenticazione per confermare la condivisione Dati inviati all'app o al sito web

Note chiave

  1. L'app o il sito web ha flessibilità nel modo in cui crea il punto di accesso all'API. Come mostrato nel passaggio 1, ti consigliamo di mostrare un pulsante generico come "Verifica con documento di identità digitale", poiché nel tempo prevediamo che saranno disponibili opzioni oltre a Google Wallet tramite l'API.
  2. La schermata del selettore nel passaggio 2 viene visualizzata da Android. Le credenziali idonee sono determinate da una corrispondenza tra la logica di registrazione fornita da ciascun Wallet e la richiesta inviata dalla relying party
  3. Il passaggio 3 viene eseguito da Google Wallet. Google Wallet mostrerà il nome, il logo e le norme sulla privacy forniti dallo sviluppatore in questa schermata.

Aggiungere un flusso di verifica dell'identità digitale

Se l'utente non dispone di una credenziale, ti consigliamo di fornire un link accanto al pulsante "Verifica con documento di identità digitale" che rimanda a Google Wallet per consentire all'utente di aggiungere un documento di identità digitale.

All'utente viene chiesto di verificare l'età nell'app o sul sito web L'utente viene indirizzato a Google Wallet per ottenere un documento di identità digitale
All'utente viene chiesto di verificare l'età nell'app o sul sito web L'utente viene indirizzato a Google Wallet per ottenere un documento di identità digitale

Nessun documento di identità digitale disponibile

Se l'utente seleziona l'opzione "Verifica con documento di identità digitale" senza disporre di un documento di identità digitale, verrà visualizzato questo messaggio di errore.

All'utente viene chiesto di verificare l'età nell'app o sul sito web L'utente visualizza un errore se non dispone di un documento di identità digitale
All'utente viene chiesto di verificare l'età nell'app o sul sito web L'utente visualizza un errore se non dispone di un documento di identità digitale

L'API non supporta una funzionalità per rilevare in modo silenzioso se l'utente dispone di ID digitali disponibili per preservare la privacy dell'utente. Pertanto, ti consigliamo di includere l'opzione del link di onboarding come mostrato.

Formato della richiesta per richiedere le credenziali di identità dal portafoglio

Di seguito è riportato un esempio di richiesta di mdoc requestJson per ottenere le credenziali dell'identità da qualsiasi portafoglio su un dispositivo Android o sul web.

{
      "requests" : [
        {
          "protocol": "openid4vp",
          "data": {<credential_request>} // This is an object, shouldn't be a string.
        }
      ]
}

Richiedi crittografia

client_metadata contiene la chiave pubblica di crittografia per ogni richiesta. Dovrai memorizzare le chiavi private per ogni richiesta e utilizzarle per autenticare e autorizzare il token che ricevi dall'app Wallet.

Il parametro credential_request in requestJson è composto dai seguenti campi.

{
  "response_type": "vp_token",
  "response_mode": "dc_api",
  "nonce": "1234",
  "dcql_query": {
    "credentials": [
      {
        "id": "cred1",
        "format": "mso_mdoc",
        "meta": {
          "doctype_value": "org.iso.18013.5.1.mDL"  // this is for mDL. Use com.google.wallet.idcard.1 for ID pass
        },
        "claims": [
          {
            "path": [
              "org.iso.18013.5.1",
              "family_name"
            ],
            "intent_to_retain": false // set this to true if you are saving the value of the field
          },
          {
            "path": [
              "org.iso.18013.5.1",
              "given_name"
            ],
            "intent_to_retain": false
          },
          {
            "path": [
              "org.iso.18013.5.1",
              "age_over_18"
            ],
            "intent_to_retain": false
          }
        ]
      }
    ]
  },
  "client_metadata": {
    "jwks": {
      "keys": [ // sample request encryption key
        {
          "kty": "EC",
          "crv": "P-256",
          "x": "pDe667JupOe9pXc8xQyf_H03jsQu24r5qXI25x_n1Zs",
          "y": "w-g0OrRBN7WFLX3zsngfCWD3zfor5-NLHxJPmzsSvqQ",
          "use": "enc",
          "kid" : "1",
          "alg" : "ECDH-ES",
        }
      ]
    },
    "authorization_encrypted_response_alg": "ECDH-ES",
    "authorization_encrypted_response_enc": "A128GCM"
  }
}

Puoi richiedere un numero qualsiasi di attributi supportati da qualsiasi documento di identità memorizzato in Google Wallet.

In-app

Per richiedere le credenziali dell'identità dalle tue app per Android:

Aggiorna le dipendenze

In build.gradle del tuo progetto, aggiorna le dipendenze per utilizzare Gestore delle credenziali (beta):

dependencies {
    implementation("androidx.credentials:credentials:1.5.0-beta01")
    // optional - needed for credentials support from play services, for devices running Android 13 and below.
    implementation("androidx.credentials:credentials-play-services-auth:1.5.0-beta01")
}

Configurare Credential Manager

Per configurare e inizializzare un oggetto CredentialManager, aggiungi una logica simile alla seguente:

// Use your app or activity context to instantiate a client instance of CredentialManager.
val credentialManager = CredentialManager.create(context)

Richiedi attributi riguardanti l'identità

Anziché specificare singoli parametri per le richieste di identità, l'app li fornisce tutti insieme come stringa JSON all'interno di CredentialOption. Credential Manager trasmette questa stringa JSON ai portafogli digitali disponibili senza esaminarne i contenuti. Ogni portafoglio è quindi responsabile di: - Analizzare la stringa JSON per comprendere la richiesta di identità. - Determinare quali delle credenziali memorizzate, se presenti, soddisfano la richiesta.

Consigliamo ai partner di creare le richieste sul server anche per le integrazioni di app per Android.

utilizzerai requestJson da Request Format che include request nella chiamata di funzione GetDigitalCredentialOption()

// The request in the JSON format to conform with
// the JSON-ified Digital Credentials API request definition.
val requestJson = generateRequestFromServer()
val digitalCredentialOption =
    GetDigitalCredentialOption(requestJson = requestJson)

// Use the option from the previous step to build the `GetCredentialRequest`.
val getCredRequest = GetCredentialRequest(
    listOf(digitalCredentialOption)
)

coroutineScope.launch {
    try {
        val result = credentialManager.getCredential(
            context = activityContext,
            request = getCredRequest
        )
        verifyResult(result)
    } catch (e : GetCredentialException) {
        handleFailure(e)
    }
}

Verifica e convalida la risposta

Una volta ricevuta una risposta dal wallet, verificherai se la risposta è andata a buon fine e contiene la risposta credentialJson.

// Handle the successfully returned credential.
fun verifyResult(result: GetCredentialResponse) {
    val credential = result.credential
    when (credential) {
        is DigitalCredential -> {
            val responseJson = credential.credentialJson
            validateResponseOnServer(responseJson) // make a server call to validate the response
        }
        else -> {
            // Catch any unrecognized credential type here.
            Log.e(TAG, "Unexpected type of credential ${credential.type}")
        }
    }
}

// Handle failure.
fun handleFailure(e: GetCredentialException) {
  when (e) {
        is GetCredentialCancellationException -> {
            // The user intentionally canceled the operation and chose not
            // to share the credential.
        }
        is GetCredentialInterruptedException -> {
            // Retry-able error. Consider retrying the call.
        }
        is NoCredentialException -> {
            // No credential was available.
        }
        else -> Log.w(TAG, "Unexpected exception type ${e::class.java}")
    }
}

La risposta credentialJson contiene un identityToken (JWT) criptato, definito dal W3C. L'app Wallet è responsabile della creazione di questa risposta.

Esempio:

{
  "protocol" : "openid4vp",
  "data" : {
    <encrpted_response>
  }
}

Passerai questa risposta al server per convalidarne l'autenticità. Puoi trovare i passaggi per convalidare la risposta delle credenziali.

Web

Per richiedere le credenziali dell'identità utilizzando l'API Digital Credentials su Chrome, dovrai registrarti alla prova dell'origine dell'API Digital Credentials.

const credentialResponse = await navigator.credentials.get({
          digital : {
          requests : [
            {
              protocol: "openid4vp",
              data: {<credential_request>} // This is an object, shouldn't be a string.
            }
          ]
        }
      })

Invia la risposta di questa API al tuo server per convalidare la risposta delle credenziali

Passaggi per convalidare la risposta delle credenziali

Dopo aver ricevuto l'identityToken criptato dalla tua app o dal tuo sito web, devi eseguire diverse convalide prima di considerare attendibile la risposta.

  1. Decripta la risposta utilizzando la chiave privata

    Il primo passaggio consiste nel decriptare il token utilizzando la chiave privata salvata e ottenere un JSON di risposta.

    Esempio Python:

    from jwcrypto import jwe, jwk
    
    # Retrieve the Private Key from Datastore
    reader_private_jwk = jwk.JWK.from_json(jwe_private_key_json_str)
    
    # Decrypt the JWE encrypted response from Google Wallet
    jwe_object = jwe.JWE()
    jwe_object.deserialize(encrypted_jwe_response_from_wallet)
    jwe_object.decrypt(reader_private_jwk)
    decrypted_payload_bytes = jwe_object.payload
    decrypted_data = json.loads(decrypted_payload_bytes)
    

    decrypted_data genererà un JSON vp_token contenente la credenziale

    {
      "vp_token":
      {
        "cred1": "<credential_token>"
      }
    }
    
  2. Creare la trascrizione della sessione

    Il passaggio successivo consiste nel creare SessionTranscript da ISO/IEC 18013-5:2021 con una struttura di trasferimento specifica per Android o il web:

    SessionTranscript = [
      null,                // DeviceEngagementBytes not available
      null,                // EReaderKeyBytes not available
      [
        "OpenID4VPDCAPIHandover",
        AndroidHandoverDataBytes   // BrowserHandoverDataBytes for Web
      ]
    ]
    

    Per i trasferimenti su Android / web, devi utilizzare lo stesso nonce che hai utilizzato per generare credential_request.

    Android Handover

        AndroidHandoverData = [
          origin,             // "android:apk-key-hash:<base64SHA256_ofAppSigningCert>",
          clientId,           // "android-origin:<app_package_name>",
          nonce,              // nonce that was used to generate credential request
        ]
    
        AndroidHandoverDataBytes = hashlib.sha256(cbor2.dumps(AndroidHandoverData)).digest()
        

    Trasferimento al browser

        BrowserHandoverData =[
          origin,               // Origin URL
          clientId,             // "web-origin:<origin>"
          nonce,               //  nonce that was used to generate credential request
        ]
    
        BrowserHandoverDataBytes = hashlib.sha256(cbor2.dumps(BrowserHandoverData)).digest()
        

    Utilizzando SessionTranscript, la risposta del dispositivo deve essere convalidata in base alla clausola 9 della norma ISO/IEC 18013-5:2021. che include diversi passaggi, ad esempio:

  3. Controlla il certificato dell'emittente statale. Consulta i certificati IACA dell'emittente supportato.

  4. Verifica della firma MSO (18013-5 Sezione 9.1.2)

  5. Calcola e controlla i ValueDigest per gli elementi di dati (sezione 9.1.2 di 18013-5)

  6. Verifica della firma deviceSignature (sezione 9.1.3 di 18013-5)

{
  "version": "1.0",
  "documents": [
    {
      "docType": "org.iso.18013.5.1.mDL",
      "issuerSigned": {
        "nameSpaces": {...}, // contains data elements
        "issuerAuth": [...]  // COSE_Sign1 w/ issuer PK, mso + sig
      },
      "deviceSigned": {
        "nameSpaces": 24(<< {} >>), // empty
        "deviceAuth": {
          "deviceSignature": [...] // COSE_Sign1 w/ device signature
        }
      }
    }
  ],
  "status": 0
}

Testare la soluzione

Per testare la tua soluzione, crea ed esegui la nostra applicazione Android di riferimento open source. Ecco i passaggi per creare ed eseguire l'app di riferimento:

  • Clona il repository delle app di riferimento
  • Apri il progetto in Android Studio.
  • Crea ed esegui la destinazione appholder sul tuo dispositivo Android o emulatore.

Verifica basata su Zero Knowledge Proof (ZKP)

La prova a conoscenza zero (ZKP) è un metodo crittografico che consente a un individuo (il dimostratore) di dimostrare a un verificatore di possedere un determinato dato di identità o di soddisfare un criterio specifico (ad es. avere più di 18 anni, possedere una credenziale valida) senza rivelare i dati sottostanti effettivi. In sostanza, è un modo per confermare la veridicità di un'affermazione sulla propria identità mantenendo privati i dettagli sensibili.

I sistemi di identità digitale che si basano sulla condivisione diretta dei dati di identità spesso richiedono agli utenti di condividere informazioni personali eccessive, aumentando il rischio di violazioni dei dati e furto di identità. Le prove a conoscenza zero offrono un cambio di paradigma, consentendo la verifica con una divulgazione minima.

Concetti chiave delle prove a conoscenza zero nell'identità digitale:

  • Prover: la persona che tenta di dimostrare un aspetto della propria identità.
  • Verificatore: la persona giuridica che richiede la prova di un attributo di identità.
  • La prova: un protocollo crittografico che consente al dimostratore di convincere il verificatore della veridicità della sua affermazione senza rivelare le informazioni segrete.

Proprietà principali delle prove zero-knowledge:

  • Completezza: se l'affermazione è vera e sia il dimostratore che il verificatore sono onesti, il verificatore sarà convinto.
  • Integrità: se l'affermazione è falsa, un dimostratore disonesto non può (con probabilità molto elevata) convincere un verificatore onesto che è vera.
  • Zero-Knowledge: il verificatore non apprende nulla oltre al fatto che l'affermazione è vera. Non vengono esposti dati effettivi sull'identità del richiedente.

Per ricevere una prova Zero Knowledge da Google Wallet, devi modificare il formato della richiesta in mso_mdoc_zk e aggiungere zk_system_type alla tua richiesta.

  ...
  "dcql_query": {
    "credentials": [{
      "id": "cred1",
      "format": "mso_mdoc_zk",
      "meta": {
        "doctype_value": "org.iso.18013.5.1.mDL"
        "zk_system_type": [
        {
          "system": "longfellow-libzk-v1",
          "circuit_hash": "bd3168ea0a9096b4f7b9b61d1c210dac1b7126a9ec40b8bc770d4d485efce4e9", // This will differ if you need more than 1 attribute.
          "num_attributes": 1, // number of attributes (in claims) this has can support
          "version": 3
        },
        {
          "system": "longfellow-libzk-v1",
          "circuit_hash": "89288b9aa69d2120d211618fcca8345deb4f85d2e710c220cc9c059bbee4c91f", // This will differ if you need more than 1 attribute.
          "num_attributes": 1, // number of attributes (in claims) this has can support
          "version": 4
        }
       ],
       "verifier_message": "challenge"
      },
     "claims": [{
         ...
      "client_metadata": {
        "jwks": {
          "keys": [ // sample request encryption key
            {
              ...

Riceverai una prova a conoscenza zero criptata dal wallet. Puoi convalidare questa prova rispetto ai certificati IACA degli emittenti utilizzando la libreria longfellow-zk di Google. Per maggiori dettagli, puoi contattare l'indirizzo email dell'assistenza wallet-identity-rp-support@google.com