Akceptacja cyfrowych dokumentów tożsamości online

Dokumenty tożsamości w formie cyfrowej mogą być akceptowane zarówno w procesie w aplikacji, jak i w procesie w internecie. Aby zaakceptować dokumenty z Portfela Google:

  1. Zintegruj usługę za pomocą aplikacji lub internetu, postępując zgodnie z podanymi instrukcjami.
  2. Użyj testowego identyfikatora, aby przetestować proces w piaskownicy Portfela Google.
  3. Gdy wszystko będzie gotowe, wypełnij ten formularz, aby przesłać prośbę i zaakceptować warunki korzystania z usługi akceptowania dokumentów tożsamości z Portfela Google. Musisz wypełnić ten formularz w przypadku każdego podmiotu gospodarczego.
  4. W razie pytań skontaktuj się z firmą wallet-identity-rp-support@google.com.

Wymagania wstępne

Aby przetestować cyfrowe dokumenty tożsamości, musisz najpierw zarejestrować się w programie publicznych testów beta za pomocą konta testowego (musi to być konto Gmail). Następnie przekaż te informacje wyznaczonej osobie kontaktowej w Google.

  • Link do warunków korzystania z usługi
  • Logo
  • Witryna
  • Identyfikatory pakietów aplikacji (w przypadku integracji z aplikacjami na Androida)
    • W tym wersje deweloperskie i debugowania
  • Sygnatura aplikacji
    • $ $ANDROID_SDK/build-tools/$BUILD_TOOLS_VERSION/apksigner verify --print-certs -v $APK
  • Identyfikator Gmaila użyty do dołączenia do publicznej wersji beta

Obsługiwane formaty danych logowania

Istnieje kilka proponowanych standardów, które określają format danych dokumentów tożsamości cyfrowej. Dwa z nich zyskały znaczną popularność w branży:

  1. mdocs – zdefiniowane przez ISO.
  2. w3c Verifiable Credentials – zdefiniowane przez w3c.

Menedżer danych logowania na Androidzie obsługuje oba formaty, ale Portfel Google obsługuje obecnie tylko cyfrowe dokumenty tożsamości oparte na mdoc.

Obsługiwane dane logowania

Portfel Google obsługuje 2 rodzaje dokumentów:

  1. Cyfrowe prawo jazdy (mDL)
  2. dokument tożsamości,

Możesz poprosić o dowolne z tych poświadczeń, zmieniając tylko jeden parametr.

Interfejs użytkownika

W tej sekcji opisujemy zalecany przebieg prezentacji online. Proces pokazuje przekazywanie informacji o wieku do aplikacji do dostarczania alkoholu, ale UX jest podobny w przypadku internetu i innych typów prezentacji.

Użytkownik jest proszony o potwierdzenie wieku w aplikacji lub witrynie Użytkownik widzi dostępne kwalifikacje, które spełniają wymagania. Użytkownik widzi stronę potwierdzenia w Portfelu Google Uwierzytelnianie użytkownika w celu potwierdzenia udostępniania Dane wysyłane do aplikacji lub witryny
Użytkownik jest proszony o potwierdzenie wieku w aplikacji lub witrynie Użytkownik widzi dostępne kwalifikacje, które spełniają wymagania. Użytkownik widzi stronę potwierdzenia w Portfelu Google Uwierzytelnianie użytkownika w celu potwierdzenia udostępniania Dane wysyłane do aplikacji lub witryny

Kluczowe informacje

  1. Aplikacja lub witryna ma swobodę w tworzeniu punktu wejścia do interfejsu API. Jak pokazano w kroku 1, zalecamy wyświetlanie ogólnego przycisku, np. „Zweryfikuj za pomocą cyfrowego dokumentu tożsamości”, ponieważ z czasem w interfejsie API pojawią się opcje inne niż Portfel Google.
  2. Ekran selektora w kroku 2 jest renderowany przez Androida. Kwalifikujące się dane logowania są określane na podstawie dopasowania między logiką rejestracji dostarczoną przez każdy Portfel a żądaniem wysłanym przez podmiot polegający na tożsamości.
  3. Krok 3 jest renderowany przez Portfel Google. Na tym ekranie Portfel Google będzie wyświetlać nazwę, logo i politykę prywatności podane przez dewelopera.

Dodawanie procesu weryfikacji cyfrowego dokumentu tożsamości

Jeśli użytkownik nie ma dokumentu tożsamości, zalecamy umieszczenie linku obok przycisku „Zweryfikuj za pomocą dokumentu tożsamości w formie cyfrowej”, który będzie prowadzić do Portfela Google, aby umożliwić użytkownikowi dodanie dokumentu tożsamości w formie cyfrowej.

Użytkownik jest proszony o potwierdzenie wieku w aplikacji lub witrynie Użytkownik zostaje przekierowany do Portfela Google, aby uzyskać cyfrowy dokument tożsamości.
Użytkownik jest proszony o potwierdzenie wieku w aplikacji lub witrynie Użytkownik zostaje przekierowany do Portfela Google, aby uzyskać cyfrowy dokument tożsamości.

Brak dostępnego cyfrowego dokumentu tożsamości

Jeśli użytkownik wybierze opcję „Zweryfikuj za pomocą cyfrowego dokumentu tożsamości”, ale nie będzie mieć cyfrowego dokumentu tożsamości, zobaczy ten komunikat o błędzie.

Użytkownik jest proszony o potwierdzenie wieku w aplikacji lub witrynie Wyświetlanie użytkownikowi błędu, jeśli nie ma on cyfrowego dokumentu tożsamości
Użytkownik jest proszony o potwierdzenie wieku w aplikacji lub witrynie Wyświetlanie użytkownikowi błędu, jeśli nie ma on cyfrowego dokumentu tożsamości

Interfejs API nie obsługuje funkcji, która pozwalałaby w sposób niewidoczny dla użytkownika sprawdzać, czy ma on dostępne cyfrowe dokumenty tożsamości, aby chronić jego prywatność. Dlatego zalecamy uwzględnienie opcji linku do wprowadzenia, jak pokazano.

Format żądania danych logowania z portfela

Oto przykładowe żądanie mdoc requestJson dotyczące uzyskania danych logowania tożsamości z dowolnego portfela na urządzeniu z Androidem lub w internecie.

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

Prośba o szyfrowanie

client_metadata zawiera publiczny klucz szyfrowania dla każdego żądania. Musisz przechowywać klucze prywatne dla każdego żądania i używać ich do uwierzytelniania i autoryzowania tokena otrzymywanego z aplikacji portfela.

Parametr credential_requestrequestJson będzie zawierać te pola:

{
  "response_type": "vp_token",
  "response_mode": "dc_api.jwt",
  "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"
  }
}

Możesz poprosić o dowolną liczbę obsługiwanych atrybutów z dowolnego dokumentu tożsamości przechowywanego w Portfelu Google.

W aplikacji

Aby poprosić o dane logowania w aplikacjach na Androida:

Aktualizowanie zależności

W pliku build.gradle projektu zaktualizuj zależności, aby używać Credential Manager (wersja 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")
}

Konfigurowanie Menedżera danych logowania

Aby skonfigurować i zainicjować obiekt CredentialManager, dodaj logikę podobną do tej:

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

Żądanie atrybutów tożsamości

Zamiast określać poszczególne parametry żądań tożsamości, aplikacja podaje je wszystkie razem jako ciąg znaków JSON w ramach CredentialOption. Menedżer danych logowania przekazuje ten ciąg znaków JSON do dostępnych cyfrowych portfeli bez sprawdzania jego zawartości. Każdy portfel jest odpowiedzialny za:<ul><li> parsowanie ciągu JSON w celu zrozumienia żądania tożsamości; – określanie, które z zapisanych danych logowania spełniają żądanie;

Zalecamy partnerom tworzenie żądań na serwerze nawet w przypadku integracji z aplikacjami na Androida.

użyjesz requestJson z sekcji Format żądania, która zawiera request w wywołaniu funkcji 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)
    }
}

Weryfikowanie i sprawdzanie odpowiedzi

Po otrzymaniu odpowiedzi z portfela sprawdź, czy jest ona prawidłowa i zawiera odpowiedź 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}")
    }
}

Odpowiedź credentialJson zawiera zaszyfrowany identityToken (JWT) zdefiniowany przez W3C. Za przygotowanie tej odpowiedzi odpowiada aplikacja Portfel.

Przykład:

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

Przekaż tę odpowiedź z powrotem na serwer, aby potwierdzić jej autentyczność. Możesz zapoznać się z instrukcjami weryfikacji odpowiedzi dotyczącej danych logowania.

Sieć

Aby poprosić o dane logowania za pomocą interfejsu Digital Credentials API w Chrome, musisz zarejestrować się w testowaniu origin interfejsu Digital Credentials API.

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

Wyślij odpowiedź z tego interfejsu API z powrotem na serwer, aby zweryfikować odpowiedź dotyczącą danych logowania.

Kroki weryfikacji odpowiedzi dotyczącej danych logowania

Po otrzymaniu zaszyfrowanego tokena identityToken z aplikacji lub witryny musisz przeprowadzić kilka weryfikacji, zanim uznasz odpowiedź za wiarygodną.

  1. Odszyfrowywanie odpowiedzi za pomocą klucza prywatnego

    Pierwszym krokiem jest odszyfrowanie tokena za pomocą zapisanego klucza prywatnego i uzyskanie odpowiedzi w formacie JSON.

    Przykład w Pythonie:

    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 spowoduje utworzenie pliku JSON vp_token zawierającego dane logowania.

    {
      "vp_token":
      {
        "cred1": "<credential_token>"
      }
    }
    
  2. Tworzenie transkrypcji sesji

    Następnym krokiem jest utworzenie SessionTranscript zgodnie z ISO/IEC 18013-5:2021 z strukturą przekazywania specyficzną dla Androida lub internetu:

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

    W przypadku przekazywania połączenia zarówno na Androida, jak i do internetu musisz użyć tego samego jednorazowego kodu, którego użyto do wygenerowania parametru credential_request.

    Przekazywanie połączeń na Androidzie

        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()
        

    Przekazywanie przeglądarki

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

    W przypadku korzystania z SessionTranscript odpowiedź DeviceResponse musi zostać zweryfikowana zgodnie z klauzulą 9 normy ISO/IEC 18013-5:2021. Obejmuje to kilka kroków, takich jak:

  3. Sprawdź certyfikat wydawcy stanowego. Sprawdź certyfikaty IACA obsługiwanego wydawcy

  4. Weryfikacja podpisu MSO (18013-5 Section 9.1.2)

  5. Obliczanie i sprawdzanie wartości ValueDigests dla elementów danych (18013-5, sekcja 9.1.2)

  6. Weryfikacja podpisu deviceSignature (18013-5 Section 9.1.3)

{
  "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
}

Testowanie rozwiązania

Aby przetestować rozwiązanie, skompiluj i uruchom naszą referencyjną aplikację na Androida o otwartym kodzie źródłowym. Aby skompilować i uruchomić aplikację do przechowywania referencji:

  • Sklonuj repozytorium aplikacji referencyjnych
  • Otwórz projekt w Android Studio.
  • Skompiluj i uruchom element docelowy appholder na urządzeniu z Androidem lub w emulatorze.

Weryfikacja oparta na dowodzie z zerową wiedzą

Dowód zerowej wiedzy (ZKP) to metoda kryptograficzna, która umożliwia osobie (udowadniającej) udowodnienie weryfikatorowi, że posiada określone informacje tożsamości lub spełnia określone kryterium (np. ma ukończone 18 lat, posiada ważne poświadczenie), bez ujawniania rzeczywistych danych bazowych. Jest to sposób na potwierdzenie prawdziwości oświadczenia dotyczącego tożsamości przy jednoczesnym zachowaniu prywatności danych wrażliwych.

Systemy tożsamości cyfrowej, które opierają się na bezpośrednim udostępnianiu danych tożsamości, często wymagają od użytkowników udostępniania nadmiernej ilości danych osobowych, co zwiększa ryzyko naruszenia ochrony danych i kradzieży tożsamości. Protokół ZKP to przełomowe rozwiązanie, które umożliwia weryfikację przy minimalnym ujawnianiu informacji.

Kluczowe pojęcia dotyczące dowodów o zerowej wiedzy w kontekście tożsamości cyfrowej:

  • Osoba weryfikująca: osoba, która próbuje udowodnić aspekt swojej tożsamości.
  • Weryfikator: podmiot, który prosi o dowód atrybutu tożsamości.
  • Dowód: protokół kryptograficzny, który umożliwia osobie udowadniającej przekonanie osoby weryfikującej o prawdziwości jej twierdzenia bez ujawniania tajnych informacji.

Podstawowe właściwości dowodów z zerową wiedzą:

  • Kompletność: jeśli stwierdzenie jest prawdziwe, a zarówno dowodzący, jak i weryfikujący są uczciwi, weryfikujący będzie przekonany.
  • Rzetelność: jeśli stwierdzenie jest fałszywe, nieuczciwy dowodzący nie może (z bardzo dużym prawdopodobieństwem) przekonać uczciwego weryfikatora, że jest ono prawdziwe.
  • Zero-Knowledge: weryfikator nie dowiaduje się niczego poza tym, że stwierdzenie jest prawdziwe. Nie są ujawniane żadne rzeczywiste dane z tożsamości weryfikującego.

Aby otrzymać od Portfela Google dowód Zero Knowledge, musisz zmienić format żądania na mso_mdoc_zk i dodać zk_system_type do żądania.

  ...
  "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
            {
              ...

Z portfela otrzymasz zaszyfrowany dowód o zerowej wiedzy. Możesz zweryfikować ten dowód na podstawie certyfikatów IACA wydawców za pomocą biblioteki longfellow-zk od Google. Aby dowiedzieć się więcej, skontaktuj się z zespołem pomocy, wysyłając e-maila na adres:wallet-identity-rp-support@google.com