Penerimaan Kredensial Digital secara Langsung (Offline)

Panduan ini menjelaskan cara Pihak Pengandalkan (RP) dan developer pembaca dapat menerapkan verifikasi langsung (offline) kredensial digital yang ditampilkan dari Google Wallet sesuai dengan standar internasional ISO/IEC 18013-5.

Kredensial digital di Google Wallet dapat diverifikasi dengan aman di lingkungan fisik (seperti terminal tempat penjualan, tempat acara, gerbang transportasi umum, pembaca penegak hukum, dan aplikasi pembaca seluler) tanpa memerlukan koneksi internet aktif pada saat presentasi.

Ringkasan Presentasi Offline (ISO/IEC 18013-5)

Standar ISO/IEC 18013-5 menentukan protokol standar yang dapat dioperasikan untuk presentasi offline antara Pemegang (perangkat seluler pengguna yang menjalankan Google Wallet) dan Pembaca / Pemverifikasi (terminal fisik atau aplikasi seluler pendamping).

Alur presentasi terjadi dalam beberapa fase yang berbeda:

  1. Interaksi Perangkat: Pembaca dan dompet membuat kontak awal melalui Ketukan NFC (Handover Statis atau yang Dinegosiasikan) atau pemindaian Kode QR. Selama fase ini, metadata interaksi perangkat dan kunci publik sementara pembaca (EReaderKey) akan dipertukarkan.
  2. Koneksi Transportasi Data: Saluran Bluetooth Hemat Energi (BLE) yang aman dan terenkripsi dinegosiasikan (dengan pembaca yang bertindak dalam mode Klien Pusat atau Server Periferal).
  3. Permintaan Perangkat: Pembaca mengirimkan DeviceRequest yang dienkode CBOR yang menentukan jenis dokumen yang diminta (seperti org.iso.18013.5.1.mDL) serta namespace dan elemen data tertentu yang diminta.
  4. Izin Pengguna & Autentikasi Perangkat: Google Wallet meminta pengguna untuk meninjau elemen data yang diminta dan mengonfirmasi pembagian menggunakan autentikasi biometrik atau kunci layar.
  5. Respons Perangkat & Verifikasi Kriptografis: Dompet mengirimkan kembali DeviceResponse yang dienkode CBOR yang berisi Mobile Security Object (MSO) yang ditandatangani dan elemen data yang ditandatangani perangkat. Pembaca memverifikasi tanda tangan kriptografis berdasarkan root certificate tepercaya.

Multipaz Open-Source SDK

Untuk mengimplementasikan aplikasi pembaca atau pemverifikasi, Google merekomendasikan penggunaan Multipaz, SDK Kotlin Multiplatform (KMP) open source yang awalnya dikembangkan oleh Google dan dikontribusikan ke OpenWallet Foundation (OWF).

Multipaz menyediakan implementasi protokol dompet dan pembaca ISO/IEC 18013-5 yang siap produksi, pipeline verifikasi kriptografis, encoding/dekode CBOR, dan skema jenis dokumen yang dapat diperluas.

Mengintegrasikan Multipaz ke Aplikasi Pembaca Anda

Langkah-langkah berikut menunjukkan cara mengintegrasikan Multipaz SDK ke dalam aplikasi pembaca Android.

Langkah 1: Tambahkan Dependensi

Library Multipaz dipublikasikan di Maven Central. Tambahkan modul yang diperlukan ke file build.gradle.kts aplikasi Anda:

// build.gradle.kts
dependencies {
    // Core Multipaz library (protocol engine, CBOR, crypto)
    implementation("org.multipaz:multipaz:0.100.0")

    // Android-specific platform bindings (NFC, BLE, Keystore)
    implementation("org.multipaz:multipaz-android:0.100.0")

    // Standardized document types (mDL, EU PID, etc.)
    implementation("org.multipaz:multipaz-doctypes:0.100.0")
}

Langkah 2: Konfigurasikan Izin Android

Verifikasi langsung memerlukan izin hardware untuk interaksi NFC, pemindaian kamera (untuk interaksi QR), dan pengiriman data Bluetooth Hemat Energi. Tambahkan izin berikut ke AndroidManifest.xml Anda:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- NFC Engagement -->
    <uses-permission android:name="android.permission.NFC" />
    <uses-feature android:name="android.hardware.nfc" android:required="false" />

    <!-- Camera for QR Code Engagement -->
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-feature android:name="android.hardware.camera" android:required="false" />

    <!-- Bluetooth Low Energy Transport (Android 12+) -->
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN"
                     android:usesPermissionFlags="neverForLocation" />
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />

    <!-- Legacy Bluetooth Permissions for Android 11 and lower -->
    <uses-permission android:name="android.permission.BLUETOOTH"
                     android:maxSdkVersion="30" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
                     android:maxSdkVersion="30" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
                     android:maxSdkVersion="30" />
</manifest>

Langkah 3: Lakukan inisialisasi Mesin Verifikasi

Gunakan abstraksi koneksi VerificationHelper atau Reader Multipaz untuk menangani peristiwa engagement dan mengelola siklus proses komunikasi BLE:

import org.multipaz.verification.VerificationHelper
import org.multipaz.cbor.Cbor
import org.multipaz.crypto.Crypto

class ReaderManager(private val context: android.content.Context) {

    private var verificationHelper: VerificationHelper? = null

    fun startListeningForEngagement() {
        verificationHelper = VerificationHelper.Builder(
            context = context,
            listener = object : VerificationHelper.Listener {
                override fun onDeviceConnected() {
                    // BLE channel established, send request
                    sendDeviceRequest()
                }

                override fun onResponseReceived(deviceResponseBytes: ByteArray) {
                    // Process and verify the received credential payload
                    handleDeviceResponse(deviceResponseBytes)
                }

                override fun onError(error: Throwable) {
                    // Handle transport or protocol errors
                }

                override fun onDeviceDisconnected(transportTransportSpecificTermination: Boolean) {
                    // Connection closed
                }
            }
        ).build()
    }
}

Langkah 4: Buat DeviceRequest

Tentukan jenis dokumen dan elemen data individual yang perlu diverifikasi oleh aplikasi Anda. Selalu terapkan prinsip pengungkapan minimal (misalnya, hanya meminta age_over_21, bukan birth_date lengkap saat memverifikasi usia):

fun sendDeviceRequest() {
    // Specify the DocType and requested elements
    val docType = "org.iso.18013.5.1.mDL"
    val namespace = "org.iso.18013.5.1"

    // Map of requested elements: elementName -> intentToRetain
    val requestedElements = mapOf(
        "family_name" to false,
        "given_name" to false,
        "age_over_21" to false,
        "portrait" to false,
        "driving_privileges" to false
    )

    // Build ISO/IEC 18013-5 DeviceRequest structure
    val deviceRequestBytes = verificationHelper?.buildDeviceRequest(
        docType = docType,
        itemsToRequest = mapOf(namespace to requestedElements)
    )

    if (deviceRequestBytes != null) {
        verificationHelper?.sendDeviceRequest(deviceRequestBytes)
    }
}

Mendukung Jenis Dokumen (DocType) Tambahan

Multipaz mendukung kredensial standar secara langsung dan menyediakan arsitektur yang dapat diperluas untuk meminta jenis dokumen kustom atau khusus domain.

1. Jenis Dokumen Standar Bawaan

Library multipaz-doctypes menyediakan model skema yang telah ditentukan untuk kredensial standar:

ID Jenis Dokumen Standar / Cakupan Namespace Umum Elemen Umum
org.iso.18013.5.1.mDL Surat Izin Mengemudi Digital ISO/IEC 18013-5 org.iso.18013.5.1 family_name, given_name, birth_date, issue_date, expiry_date, issuing_authority, document_number, portrait, driving_privileges, age_over_18, age_over_21
eu.europa.ec.eudi.pid.1 Data Identifikasi Orang Dompet Identitas Digital Uni Eropa (EUDIW) eu.europa.ec.eudi.pid.1 family_name, first_name, birth_date, nationality, issuing_country, issuing_authority, personal_administrative_number
com.google.wallet.idcard.1 Tanda Pengenal Digital Google Wallet / ID Pengujian com.google.wallet.idcard.1 given_name, family_name, birth_date, document_number, portrait

2. Meminta Jenis Dokumen Kustom

Untuk meminta jenis dokumen kustom, tentukan string docType target dan pemetaan namespace yang sesuai saat membuat DeviceRequest:

// Example: Requesting a custom event ticket credential
val customDocType = "com.example.events.ticket"
val customNamespace = "com.example.events.ticket.1"

val customRequestedItems = mapOf(
    "ticket_id" to false,
    "event_name" to false,
    "seat_section" to false,
    "vip_access" to false
)

val multiDocRequestBytes = verificationHelper?.buildMultiDocDeviceRequest(
    documents = listOf(
        DocumentRequest(
            docType = customDocType,
            namespaces = mapOf(customNamespace to customRequestedItems)
        )
    )
)

Verifikasi Kriptografi & Pengelolaan Trust

Menerima payload respons hanyalah langkah pertama. Pembaca harus melakukan verifikasi kriptografis empat langkah untuk memvalidasi keaslian dan integritas kredensial yang ditampilkan.

Langkah Verifikasi Target Verifikasi
1. Autentikasi Penerbit Memverifikasi IssuerAuth (COSE_Sign1) terhadap root certificate IACA tepercaya
2. Pemeriksaan Periode Validitas Pastikan validFrom ≤ waktu saat ini ≤ validUntil
3. Pemeriksaan Integritas Data Menghitung ringkasan SHA-256 dari elemen yang ditampilkan dan mencocokkannya dengan MSO ValueDigests
4. Autentikasi Perangkat Memverifikasi tanda tangan DeviceSigned atau MAC menggunakan DeviceKey yang terikat ke SessionTranscript

1. Pipeline Verifikasi 4 Langkah

  1. Autentikasi Penerbit (IssuerAuth):
    • Mobile Security Object (MSO) ditandatangani oleh Otoritas Penerbit (payload IssuerAuth).
    • Pembaca memverifikasi tanda tangan COSE_Sign1 menggunakan sertifikat Penanda Tangan Dokumen dan memastikan sertifikat tersebut terhubung ke root certificate Issuing Authority CA (IACA) tepercaya.
  2. Verifikasi Jendela Validitas:
    • Pembaca memeriksa stempel waktu validityInfo.validFrom dan validityInfo.validUntil di MSO terhadap jam pembaca saat ini untuk memastikan kredensial belum habis masa berlakunya.
  3. Verifikasi Integritas Data (ValueDigests):
    • Untuk setiap IssuerSignedItem yang diterima, pembaca menghitung ringkasannya (misalnya SHA-256) dan memverifikasi bahwa ringkasan tersebut cocok dengan entri hash yang sesuai dalam kamus ValueDigests MSO.
  4. Autentikasi Perangkat (DeviceSigned):
    • Pembaca memvalidasi bahwa perangkat yang menampilkan kredensial memiliki kunci pribadi yang sesuai dengan DeviceKey yang dipublikasikan di dalam MSO yang ditandatangani.
    • Hal ini dilakukan dengan memverifikasi DeviceAuth (DeviceSignature atau DeviceMac) melalui SessionTranscript, mengikat sesi ke kunci sementara pembaca, serta mencegah serangan replay dan man-in-the-middle.

2. Mengelola Root Certificate IACA Tepercaya

Pembaca produksi harus mengelola trust store lokal yang aman dan berisi root certificate IACA tepercaya:

  • Sertifikat IACA Produksi: Download dan konfigurasi root certificate dari otoritas penerbit resmi. Lihat daftar Penerbit dan Sertifikat IACA yang Didukung.
  • AAMVA VICAL: Untuk wilayah hukum AS, sistem pembaca dapat berintegrasi dengan layanan Verified Issuer Certificate Authority List (VICAL) American Association of Motor Vehicle Administrators (AAMVA) untuk otomatis menyinkronkan trust anchor negara bagian.
  • Root Pengujian Sandbox: Saat menguji kredensial sandbox, pastikan pembaca memercayai Root IACA Sandbox Google.
import org.multipaz.crypto.X509Cert

// Configure trusted IACA certificates in the trust store
val trustedCertificates = mutableListOf<X509Cert>()

// Add official state IACA certificates
trustedCertificates.add(X509Cert.fromPem(sampleStateIacaPem))

// Add Google Sandbox IACA root certificate for testing
trustedCertificates.add(X509Cert.fromPem(googleSandboxIacaPem))

val verifier = MultipazVerifier(trustStore = trustedCertificates)
val verificationResult = verifier.verify(deviceResponseBytes, sessionTranscript)

if (verificationResult.isIssuerAuthorized && verificationResult.isDeviceAuthenticated) {
    // Credential is valid and authentic
} else {
    // Reject presentation: cryptographic validation failed
}

Autentikasi Pembaca (Direkomendasikan)

Autentikasi Pembaca memungkinkan aplikasi pembaca membuktikan identitasnya secara kriptografis ke Google Wallet dengan menandatangani struktur ReaderAuthentication menggunakan sertifikat pembaca X.509 yang sah.

  • Alasan Direkomendasikan: Autentikasi Pembaca memungkinkan aplikasi atau terminal pembaca Anda menampilkan identitas tepercaya kepada pengguna. Meskipun bersifat opsional untuk atribut publik dasar (misalnya, memverifikasi age_over_21), langkah ini sangat direkomendasikan untuk integrasi pembaca guna meningkatkan kepercayaan pengguna dan mungkin diwajibkan secara hukum atau kebijakan saat meminta atribut sensitif (seperti Nomor Jaminan Sosial lengkap, alamat tempat tinggal, atau pengesahan negara bagian tertentu).
  • Cara Kerjanya: Pembaca menyertakan rantai sertifikatnya dan menandatangani transkrip sesi. Google Wallet menampilkan identitas dan nama organisasi pembaca yang terverifikasi kepada pengguna di layar izin sebelum data dirilis.

Alat Pengujian & Pengembangan

Untuk mempercepat integrasi, gunakan alat developer dan implementasi referensi berikut:

  1. Aplikasi Referensi Multipaz:
    • Buat clone repositori Multipaz dan jalankan aplikasi contoh Android IdentityReader untuk menguji alur verifikasi fisik.
  2. Membuat Tanda Pengenal Pengujian di Google Wallet:
  3. Pengujian Verifikasi Berbasis Web:
    • Gunakan verifier.multipaz.org untuk memeriksa permintaan CBOR, mempelajari kueri klaim, dan menguji presentasi berbasis web W3C / ISO 18013-7.

Pemecahan Masalah & Diagnostik Lapangan

Tabel berikut mencantumkan masalah umum yang terjadi selama verifikasi offline dan solusi yang direkomendasikan:

Masalah / Gejala Penyebab Utama Resolusi yang Direkomendasikan
Waktu tunggu koneksi BLE habis / Gagal terhubung
  • Interferensi RF di lingkungan dengan kepadatan tinggi.
  • Ketidaksesuaian mode Periferal vs. Pusat pada hardware pembaca tertentu.
  • Waktu tunggu pemindaian.
  • Pastikan pembaca mendukung mode BLE Central Client dan Peripheral Server.
  • Sesuaikan periode dan interval pemindaian BLE untuk pemindaian agresif selama interaksi aktif.
  • Pastikan negosiasi ukuran MTU berhasil diselesaikan.
Interaksi ketuk NFC gagal atau terhenti Pengguna menarik perangkat seluler dari antena pembaca sebelum data pengalihan BLE ditransfer sepenuhnya.
  • Berikan respons visual/audio/haptic langsung di terminal segera setelah interaksi NFC dimulai.
  • Minta pengguna untuk menahan ponsel dengan stabil di target NFC hingga koneksi BLE dibuat.
UNTRUSTED_ISSUER / Kegagalan rantai sertifikat Sertifikat Document Signer tidak terhubung ke sertifikat IACA tepercaya di trust store lokal pembaca.
  • Pastikan root certificate penerbit dimuat ke trust store pembaca.
  • Jika melakukan pengujian di sandbox, pastikan Google Sandbox IACA Root dimuat.
  • Pastikan daftar sertifikat IACA (misalnya, AAMVA VICAL) diperbarui secara berkala.
INVALID_VALIDITY_INFO / MSO yang Sudah Tidak Berlaku
  • Jam sistem pembaca tidak sinkron.
  • Masa berlaku tanda tangan MSO telah berakhir.
  • Pastikan perangkat pembaca menyinkronkan waktu sistemnya secara rutin melalui NTP.
  • Minta pengguna untuk membuka Google Wallet saat terhubung ke internet untuk memperbarui token kredensial.
DEVICE_AUTHENTICATION_FAILED Transkrip sesi tidak cocok antara pembaca dan dompet, atau tanda tangan perangkat sementara tidak valid.
  • Pastikan byte mentah persis dari DeviceEngagementBytes dan EReaderKeyBytes dipertahankan dalam struktur SessionTranscript tanpa encoding ulang.
Error izin Android 12+ Aplikasi mencoba memindai atau memberitahukan melalui BLE tanpa izin runtime.
  • Periksa dan minta BLUETOOTH_SCAN, BLUETOOTH_CONNECT, dan BLUETOOTH_ADVERTISE saat runtime sebelum memulai sesi pembaca.

Panduan UX & Privasi untuk Pembaca Langsung

Saat mendesain pembaca fisik dan aplikasi pendamping:

  • Terapkan Pengungkapan Selektif di UI: Hanya tampilkan keputusan atau atribut minimum yang diperlukan kepada operator (misalnya, tampilkan tanda centang hijau yang jelas dan "Usia 21+ Terverifikasi", bukan menampilkan tanggal lahir, alamat, dan nomor lisensi lengkap pengguna).
  • Indikator Interaksi Fisik yang Jelas: Beri label zona target NFC dengan jelas dan tampilkan petunjuk visual (seperti animasi atau status progres) yang menunjukkan setiap tahap: Ketuk / Pindai → Menghubungkan → Memverifikasi → Selesai.
  • Penanganan Data Sementara: Jangan menyimpan atau mencatat elemen data pribadi yang diterima dari dompet, kecuali jika diwajibkan secara eksplisit oleh hukum yang berlaku dan diungkapkan melalui intentToRetain = true.