Penerimaan Kredensial Digital secara Online

ID digital dapat diterima dalam alur dalam aplikasi dan web. Untuk menerima kredensial dari Google Wallet, Anda harus:

  1. Integrasikan menggunakan aplikasi atau web dengan mengikuti petunjuk yang diberikan dan
  2. Isi formulir ini untuk meminta dan menyetujui persyaratan layanan penerimaan kredensial dari Google Wallet.

Prasyarat

Untuk menguji presentasi tanda pengenal secara digital, Anda harus mendaftar ke program beta publik terlebih dahulu menggunakan akun pengujian yang diinginkan (harus akun Gmail). Selanjutnya, berikan detail yang dihasilkan kepada kontak Google yang ditetapkan bagi Anda.

  • Link Persyaratan Layanan
  • Logo
  • Situs
  • ID paket aplikasi (untuk integrasi aplikasi Android)
    • Menyertakan build dev / debug
  • Tanda tangan aplikasi
    • $ $ANDROID_SDK/build-tools/$BUILD_TOOLS_VERSION/apksigner verify --print-certs -v $APK
  • ID Gmail yang digunakan untuk bergabung ke versi beta publik

Format Kredensial yang Didukung

Ada beberapa standar yang diusulkan yang menentukan format data dokumen identitas digital, dengan dua standar yang mendapatkan daya tarik industri yang signifikan:

  1. mdocs - ditentukan oleh ISO.
  2. Kredensial Verifiable w3c - ditentukan oleh w3c.

Meskipun Pengelola Kredensial Android mendukung kedua format tersebut, saat ini Google Wallet hanya mendukung ID Digital berbasis mdoc.

Kredensial yang Didukung

Google Wallet mendukung 2 jenis kredensial:

  1. Surat Izin Mengemudi Digital (mDL)
  2. Kartu tanda pengenal

Anda dapat meminta kredensial dalam alur dengan satu perubahan parameter.

Pengalaman pengguna

Bagian ini membahas alur presentasi online yang direkomendasikan. Alur ini menunjukkan presentasi usia ke aplikasi untuk pengiriman alkohol, tetapi UX serupa untuk web serta jenis presentasi lainnya.

Pengguna diminta untuk memverifikasi usia di aplikasi atau situs Pengguna melihat kredensial yang memenuhi syarat yang tersedia Pengguna melihat halaman konfirmasi di Google Wallet Pengguna Mengautentikasi untuk mengonfirmasi berbagi Data yang dikirim ke aplikasi atau situs
Pengguna diminta untuk memverifikasi usia di aplikasi atau situs Pengguna melihat kredensial yang memenuhi syarat yang tersedia Pengguna melihat halaman konfirmasi di Google Wallet Pengguna Mengautentikasi untuk mengonfirmasi berbagi Data yang dikirim ke aplikasi atau situs

Catatan Penting

  1. Aplikasi atau situs memiliki fleksibilitas dalam cara membuat titik entri ke API. Seperti yang ditunjukkan pada Langkah 1, sebaiknya tampilkan tombol umum seperti "Verifikasi dengan tanda pengenal digital" karena seiring waktu, kami berharap opsi di luar Google Wallet tersedia melalui API.
  2. Layar pemilih di langkah 2 dirender oleh Android. Kredensial yang memenuhi syarat ditentukan oleh kecocokan antara logika pendaftaran yang disediakan oleh setiap Wallet dan permintaan yang dikirim oleh pihak yang mengandalkan
  3. Langkah 3 dirender oleh Google Wallet. Google Wallet akan menampilkan nama, logo, dan kebijakan privasi yang diberikan developer di layar ini.

Menambahkan alur tanda pengenal digital

Jika pengguna tidak memiliki kredensial, sebaiknya berikan link di samping tombol "Verifikasi dengan tanda pengenal digital" yang akan melakukan deep link ke Google Wallet untuk memungkinkan pengguna menambahkan tanda pengenal digital.

Pengguna diminta untuk memverifikasi usia di aplikasi atau situs Pengguna diarahkan ke Google Wallet untuk mendapatkan tanda pengenal digital
Pengguna diminta untuk memverifikasi usia di aplikasi atau situs Pengguna diarahkan ke Google Wallet untuk mendapatkan tanda pengenal digital

Tidak ada tanda pengenal digital yang tersedia

Jika pengguna memilih opsi "Verifikasi dengan tanda pengenal digital" tanpa memiliki tanda pengenal digital, mereka akan melihat pesan error ini.

Pengguna diminta untuk memverifikasi usia di aplikasi atau situs Pengguna akan melihat pesan error jika tidak memiliki ID digital
Pengguna diminta untuk memverifikasi usia di aplikasi atau situs Pengguna akan melihat pesan error jika tidak memiliki ID digital

API ini tidak mendukung fitur untuk mempelajari secara diam-diam apakah pengguna memiliki ID digital yang tersedia untuk menjaga privasi pengguna. Oleh karena itu, sebaiknya sertakan opsi link orientasi seperti yang ditampilkan.

Format Permintaan untuk meminta kredensial ID dari dompet

Berikut adalah contoh permintaan requestJson mdoc untuk mendapatkan kredensial Identity dari dompet apa pun di perangkat Android atau web.

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

Meminta Enkripsi

client_metadata berisi kunci publik enkripsi untuk setiap permintaan. Anda harus menyimpan kunci pribadi untuk setiap permintaan dan menggunakannya untuk mengautentikasi dan memberikan otorisasi token yang Anda terima dari aplikasi dompet.

Parameter credential_request di requestJson akan terdiri dari kolom berikut.

{
  "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"
            ]
          },
          {
            "path": [
              "org.iso.18013.5.1",
              "given_name"
            ]
          },
          {
            "path": [
              "org.iso.18013.5.1",
              "age_over_18"
            ]
          }
        ]
      }
    ]
  },
  "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"
  }
}

Anda dapat meminta sejumlah atribut yang didukung dari kredensial identitas apa pun yang disimpan di Google Wallet.

Dalam Aplikasi

Untuk meminta kredensial identitas dari aplikasi Android Anda, ikuti langkah-langkah berikut:

Memperbarui dependensi

Dalam build.gradle project, perbarui dependensi untuk menggunakan Pengelola Kredensial (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")
}

Mengonfigurasi Pengelola Kredensial

Untuk mengonfigurasi dan melakukan inisialisasi objek CredentialManager, tambahkan logika yang mirip dengan berikut ini:

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

Meminta Atribut identitas

Daripada menentukan parameter individual untuk permintaan identitas, aplikasi menyediakan semuanya bersama-sama sebagai string JSON dalam CredentialOption. Pengelola Kredensial meneruskan string JSON ini ke dompet digital yang tersedia tanpa memeriksa kontennya. Setiap dompet kemudian bertanggung jawab untuk: - Mengurai string JSON untuk memahami permintaan identitas. - Menentukan kredensial yang disimpan, jika ada, yang memenuhi permintaan.

Sebaiknya partner membuat permintaan mereka di server bahkan untuk integrasi aplikasi Android.

Anda akan menggunakan requestJson dari Format Permintaan yang terdiri dari request dalam panggilan fungsi 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)
    }
}

Memverifikasi dan Memvalidasi respons

Setelah mendapatkan respons dari dompet, Anda akan memverifikasi apakah respons tersebut berhasil dan berisi respons 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}")
    }
}

Respons credentialJson berisi identityToken (JWT) terenkripsi, yang ditentukan oleh W3C. Aplikasi Wallet bertanggung jawab untuk membuat respons ini.

Contoh:

"response" : {
  <encrpted_response>
}

Anda akan meneruskan respons ini kembali ke server untuk memvalidasi keasliannya. Anda dapat menemukan langkah-langkah untuk memvalidasi respons kredensial.

Web

Untuk meminta Kredensial Identitas menggunakan Digital Credentials API di Chrome, Anda harus mendaftar ke uji coba origin 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.
            }
          ]
        }
      })

Kirim respons dari API ini kembali ke server Anda untuk memvalidasi respons kredensial

Langkah-langkah untuk Memvalidasi respons kredensial

Setelah menerima identityToken terenkripsi dari aplikasi atau situs Anda, ada beberapa validasi yang perlu Anda lakukan sebelum memercayai respons.

  1. Mendekripsi respons menggunakan kunci pribadi

    Langkah pertama adalah mendekripsi token menggunakan kunci pribadi yang disimpan dan mendapatkan JSON respons.

    Contoh 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 akan menghasilkan JSON vp_token yang berisi kredensial

    {
      "vp_token":
      {
        "cred1": "<credential_token>"
      }
    }
    
  2. Membuat transkrip sesi

    Langkah berikutnya adalah membuat SessionTranscript dari ISO/IEC 18013-5:2021 dengan struktur Handover khusus Android atau Web:

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

    Untuk pengalihan Android / web, Anda harus menggunakan nonce yang sama dengan yang digunakan untuk membuat 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()
        

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

    Dengan menggunakan SessionTranscript, DeviceResponse harus divalidasi sesuai dengan klausul 9 ISO/IEC 18013-5:2021. Hal ini mencakup beberapa langkah, seperti:

  3. Periksa Sertifikat Penerbit Negara Bagian. Lihat sertifikat IACA penerbit yang didukung

  4. Memverifikasi tanda tangan MSO (18013-5 Bagian 9.1.2)

  5. Menghitung dan memeriksa ValueDigests untuk Elemen Data (18013-5 Bagian 9.1.2)

  6. Memverifikasi tanda tangan deviceSignature (18013-5 Bagian 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
}

Menguji solusi Anda

Untuk menguji solusi Anda, build dan jalankan aplikasi Android holder referensi open source kami. Berikut adalah langkah-langkah untuk mem-build dan menjalankan aplikasi holder referensi:

  • Meng-clone repositori aplikasi referensi
  • Buka project di Android Studio
  • Build dan jalankan target appholder di perangkat Android atau emulator.

Verifikasi berbasis Bukti Pengetahuan Nol (ZKP)

Bukti Tanpa Pengetahuan (ZKP) adalah metode kriptografi yang memungkinkan individu (pembuktip) membuktikan kepada verifier bahwa mereka memiliki bagian tertentu informasi identitas atau memenuhi kriteria tertentu (misalnya, berusia di atas 18 tahun, memiliki kredensial yang valid) tanpa mengungkapkan data pokok yang sebenarnya. Pada dasarnya, ini adalah cara untuk mengonfirmasi kebenaran pernyataan tentang identitas seseorang sekaligus menjaga kerahasiaan detail sensitif.

Sistem identitas digital yang mengandalkan pembagian langsung data identitas sering kali memerlukan pengguna untuk membagikan informasi pribadi yang berlebihan, sehingga meningkatkan risiko penyalahgunaan data dan pencurian identitas. ZKP menawarkan perubahan paradigma, yang memungkinkan verifikasi dengan pengungkapan minimal.

Konsep Utama ZKP dalam Identitas Digital:

  • Pembuktip: Individu yang mencoba membuktikan aspek identitasnya.
  • Verifikator: Entitas yang meminta bukti atribut identitas.
  • Bukti: Protokol kriptografi yang memungkinkan pembuktip meyakinkan verifier tentang kebenaran klaimnya tanpa mengungkapkan informasi rahasia.

Properti Inti dari Bukti Tanpa Pengetahuan:

  • Kelengkapan: Jika pernyataan tersebut benar dan pembuk dan verifier jujur, verifier akan yakin.
  • Keandalan: Jika pernyataan tersebut salah, pembuktian yang tidak jujur tidak dapat (dengan probabilitas sangat tinggi) meyakinkan verifier yang jujur bahwa pernyataan tersebut benar.
  • Zero-Knowledge: Pengverifikasi tidak mengetahui apa pun selain fakta bahwa pernyataan tersebut benar. Tidak ada data sebenarnya dari identitas pemberi bukti yang terekspos.

Untuk mendapatkan bukti Zero Knowledge kembali dari Google Wallet, Anda perlu mengubah format permintaan menjadi mso_mdoc_zk dan menambahkan zk_system_type ke Permintaan

  ...
  "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": "2b8e0c49b08eb1801b9bd7a82aa9eb3736a7519fc2b409asdhj1237034", // This will differ if you need more than 1 attribute.
           "num_attributes": 1,
           "version": 1
         }
       ],
       "verifier_message": "challenge"
      },
     "claims": [{
         ...