Chấp nhận chứng chỉ kỹ thuật số trực tiếp (Khi không có mạng)

Hướng dẫn này giải thích cách Bên phụ thuộc (RP) và nhà phát triển trình đọc có thể triển khai quy trình xác minh trực tiếp (ngoại tuyến) thông tin xác thực dạng số được trình bày từ Google Wallet theo tiêu chuẩn quốc tế ISO/IEC 18013-5.

Bạn có thể xác minh giấy tờ tuỳ thân điện tử trong Google Wallet một cách an toàn trong môi trường thực tế (chẳng hạn như thiết bị thanh toán tại điểm bán hàng, địa điểm tổ chức sự kiện, cổng phương tiện công cộng, thiết bị đọc của cơ quan thực thi pháp luật và ứng dụng đọc trên thiết bị di động) mà không cần có kết nối Internet tại thời điểm xuất trình.

Tổng quan về tính năng Trình bày khi không có mạng (ISO/IEC 18013-5)

Tiêu chuẩn ISO/IEC 18013-5 xác định một giao thức chuẩn hoá, có khả năng tương tác để trình bày ngoại tuyến giữa Người sở hữu (thiết bị di động của người dùng đang chạy Google Wallet) và Trình đọc / Trình xác minh (thiết bị đầu cuối thực tế hoặc ứng dụng di động đồng hành).

Luồng trình bày diễn ra theo các giai đoạn riêng biệt:

  1. Tương tác với thiết bị: Máy đọc thẻ và ví thiết lập kết nối ban đầu thông qua Thao tác nhấn NFC (Chuyển giao tĩnh hoặc chuyển giao có thương lượng) hoặc Quét mã QR. Trong giai đoạn này, siêu dữ liệu về hoạt động tương tác của thiết bị và khoá công khai tạm thời của thiết bị đọc (EReaderKey) sẽ được trao đổi.
  2. Kết nối truyền dữ liệu: Một kênh Bluetooth năng lượng thấp (BLE) được mã hoá và bảo mật sẽ được thiết lập (với trình đọc hoạt động ở chế độ Máy khách trung tâm hoặc Máy chủ ngoại vi).
  3. Yêu cầu của thiết bị: Máy đọc truyền một DeviceRequest được mã hoá CBOR, trong đó chỉ định loại giấy tờ được yêu cầu (chẳng hạn như org.iso.18013.5.1.mDL) cũng như không gian tên và phần tử dữ liệu cụ thể được yêu cầu.
  4. Sự đồng ý của người dùng và xác thực thiết bị: Google Wallet nhắc người dùng xem lại các thành phần dữ liệu được yêu cầu và xác nhận việc chia sẻ bằng phương thức xác thực bằng sinh trắc học hoặc khoá màn hình.
  5. Phản hồi của thiết bị và xác minh mật mã: Ví gửi lại một DeviceResponse được mã hoá bằng CBOR chứa Đối tượng bảo mật di động (MSO) đã ký và các phần tử dữ liệu do thiết bị ký. Máy đọc xác minh chữ ký mật mã dựa trên chứng chỉ gốc đáng tin cậy.

SDK nguồn mở Multipaz

Để triển khai ứng dụng đọc hoặc xác minh, Google khuyên bạn nên sử dụng Multipaz, một SDK Kotlin Multiplatform (KMP) nguồn mở do Google phát triển và đóng góp cho OpenWallet Foundation (OWF).

Multipaz cung cấp một phương thức triển khai sẵn sàng cho môi trường thực tế của các giao thức ví và trình đọc ISO/IEC 18013-5, quy trình xác minh bằng mật mã, mã hoá/giải mã CBOR và giản đồ loại tài liệu có thể mở rộng.

Tích hợp Multipaz vào ứng dụng đọc của bạn

Các bước sau đây minh hoạ cách tích hợp Multipaz SDK vào ứng dụng đọc trên Android.

Bước 1: Thêm phần phụ thuộc

Thư viện Multipaz được phát hành trên Maven Central. Thêm các mô-đun bắt buộc vào tệp build.gradle.kts của ứng dụng:

// 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")
}

Bước 2: Định cấu hình quyền truy cập Android

Quy trình xác minh trực tiếp yêu cầu quyền truy cập vào phần cứng để tương tác qua NFC, quét bằng camera (để tương tác qua mã QR) và truyền dữ liệu qua Bluetooth năng lượng thấp. Thêm các quyền sau vào AndroidManifest.xml:

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

Bước 3: Khởi chạy Công cụ xác minh

Sử dụng các lớp trừu tượng VerificationHelper hoặc kết nối Trình đọc của Multipaz để xử lý các sự kiện tương tác và quản lý vòng đời giao tiếp 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()
    }
}

Bước 4: Tạo DeviceRequest

Chỉ định loại giấy tờ và các thành phần dữ liệu riêng lẻ mà ứng dụng của bạn cần xác minh. Luôn áp dụng nguyên tắc tiết lộ tối thiểu (ví dụ: chỉ yêu cầu age_over_21 thay vì toàn bộ birth_date khi xác minh độ tuổi):

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

Hỗ trợ các loại tài liệu bổ sung (DocTypes)

Multipaz hỗ trợ thông tin xác thực chuẩn hoá ngay từ đầu và cung cấp một cấu trúc có thể mở rộng để yêu cầu các loại giấy tờ tuỳ chỉnh hoặc theo miền cụ thể.

1. Loại tài liệu tiêu chuẩn tích hợp sẵn

Thư viện multipaz-doctypes cung cấp các mô hình giản đồ được xác định trước cho thông tin xác thực tiêu chuẩn:

Giá trị nhận dạng loại tài liệu Tiêu chuẩn / Phạm vi Không gian tên thông thường Các thành phần phổ biến
org.iso.18013.5.1.mDL Giấy phép lái xe trên thiết bị di động theo tiêu chuẩn 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 Dữ liệu nhận dạng cá nhân trong Ví danh tính kỹ thuật số của Liên minh Châu Âu (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 Giấy tờ tuỳ thân điện tử trong Google Wallet / Giấy tờ tuỳ thân thử nghiệm com.google.wallet.idcard.1 given_name, family_name, birth_date, document_number, portrait

2. Yêu cầu loại tài liệu tuỳ chỉnh

Để yêu cầu các loại tài liệu tuỳ chỉnh, hãy xác định chuỗi docType mục tiêu và các mối liên kết không gian tên tương ứng khi tạo 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)
        )
    )
)

Xác minh bằng mật mã và quản lý độ tin cậy

Việc nhận tải trọng phản hồi chỉ là bước đầu tiên. Thiết bị đọc phải thực hiện quy trình xác minh bằng mật mã gồm 4 bước để xác thực tính xác thực và tính toàn vẹn của thông tin xác thực được trình bày.

Bước xác minh Mục tiêu xác minh
1. Xác thực tổ chức phát hành Xác minh IssuerAuth (COSE_Sign1) dựa trên chứng chỉ gốc IACA đáng tin cậy
2. Kiểm tra thời hạn hiệu lực Đảm bảo validFrom ≤ thời gian hiện tại ≤ validUntil
3. Kiểm tra tính toàn vẹn của dữ liệu Tính toán chuỗi đại diện SHA-256 của các phần tử được trả về và so khớp với ValueDigests của MSO
4. Xác thực thiết bị Xác minh chữ ký DeviceSigned hoặc MAC bằng DeviceKey liên kết với SessionTranscript

1. Quy trình xác minh 4 bước

  1. Xác thực tổ chức phát hành (IssuerAuth):
    • Đối tượng bảo mật di động (MSO) được ký bởi Cơ quan phát hành (gói dữ liệu IssuerAuth).
    • Máy đọc xác minh chữ ký COSE_Sign1 bằng chứng chỉ Người ký tài liệu và đảm bảo chuỗi chứng chỉ liên kết với một chứng chỉ gốc đáng tin cậy của Tổ chức phát hành chứng chỉ (IACA).
  2. Xác minh thời hạn hiệu lực:
    • Trình đọc kiểm tra dấu thời gian validityInfo.validFrom và validityInfo.validUntil trong MSO so với đồng hồ hiện tại của trình đọc để đảm bảo thông tin xác thực chưa hết hạn.
  3. Xác minh tính toàn vẹn của dữ liệu (ValueDigests):
    • Đối với mỗi IssuerSignedItem nhận được, trình đọc sẽ tính toán chuỗi đại diện (ví dụ: SHA-256) và xác minh rằng chuỗi đó khớp với mục băm tương ứng trong từ điển ValueDigests của MSO.
  4. Xác thực thiết bị (DeviceSigned):
    • Trình đọc xác thực rằng thiết bị trình bày thông tin xác thực giữ khoá riêng tư tương ứng với DeviceKey được xuất bản bên trong MSO đã ký.
    • Việc này được thực hiện bằng cách xác minh DeviceAuth (DeviceSignature hoặc DeviceMac) qua SessionTranscript, liên kết phiên với khoá tạm thời của trình đọc và ngăn chặn các cuộc tấn công phát lại và tấn công xen giữa.

2. Quản lý chứng chỉ gốc IACA đáng tin cậy

Máy đọc trong môi trường thực tế phải duy trì một kho lưu trữ uy tín cục bộ và an toàn, chứa các chứng chỉ gốc IACA đáng tin cậy:

  • Chứng chỉ IACA chính thức: Tải xuống và định cấu hình chứng chỉ gốc từ các cơ quan cấp chứng chỉ chính thức. Tham khảo danh sách Tổ chức phát hành và chứng chỉ IACA được hỗ trợ của chúng tôi.
  • AAMVA VICAL: Đối với các khu vực tài phán của Hoa Kỳ, hệ thống trình đọc có thể tích hợp với dịch vụ Danh sách tổ chức phát hành chứng chỉ đã xác minh (VICAL) của Hiệp hội quản trị viên xe cơ giới Hoa Kỳ (AAMVA) để tự động đồng bộ hoá neo tin cậy của tiểu bang.
  • Chứng chỉ gốc để thử nghiệm trong hộp cát: Khi thử nghiệm với thông tin xác thực trong hộp cát, hãy đảm bảo rằng thiết bị đọc tin tưởng Chứng chỉ gốc IACA trong hộp cát của 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
}

Xác thực độc giả (Nên dùng)

Tính năng Xác thực ứng dụng đọc cho phép ứng dụng đọc chứng minh danh tính của mình với Google Wallet bằng phương pháp mã hoá thông qua việc ký cấu trúc ReaderAuthentication bằng chứng chỉ ứng dụng đọc X.509 được uỷ quyền.

  • Lý do nên dùng: Tính năng Xác thực thiết bị đọc cho phép ứng dụng hoặc thiết bị đọc của bạn trình bày danh tính đáng tin cậy cho người dùng. Mặc dù không bắt buộc đối với các thuộc tính công khai cơ bản (ví dụ: xác minh age_over_21), nhưng bạn nên sử dụng tính năng này cho các hoạt động tích hợp với thiết bị đọc để tăng độ tin cậy của người dùng. Ngoài ra, bạn có thể phải sử dụng tính năng này theo luật hoặc chính sách khi yêu cầu các thuộc tính nhạy cảm (chẳng hạn như Số an sinh xã hội đầy đủ, địa chỉ cư trú hoặc chứng thực cụ thể của tiểu bang).
  • Cách hoạt động: Thiết bị đọc bao gồm chuỗi chứng chỉ và ký bản chép lời của phiên. Google Wallet hiển thị danh tính và tên tổ chức đã xác minh của thiết bị đọc cho người dùng trên màn hình xin phép trước khi chia sẻ dữ liệu.

Công cụ kiểm thử và phát triển

Để đẩy nhanh quá trình tích hợp, hãy sử dụng các công cụ cho nhà phát triển và cách triển khai tham khảo sau đây:

  1. Ứng dụng tham khảo Multipaz:
    • Sao chép kho lưu trữ Multipaz và chạy ứng dụng mẫu IdentityReader Android để kiểm thử quy trình xác minh thực tế.
  2. Tạo giấy tờ tuỳ thân thử nghiệm trong Google Wallet:
  3. Kiểm thử trình xác minh dựa trên nền tảng web:
    • Sử dụng verifier.multipaz.org để kiểm tra các yêu cầu CBOR, khám phá các truy vấn xác nhận quyền sở hữu và kiểm tra các bản trình bày chạy trên nền tảng web W3C / ISO 18013-7.

Khắc phục sự cố và chẩn đoán tại chỗ

Bảng sau đây liệt kê các vấn đề thường gặp trong quá trình xác minh ngoại tuyến và cách giải quyết được đề xuất:

Vấn đề / Dấu hiệu Nguyên nhân gốc Giải pháp đề xuất
Hết thời gian chờ kết nối BLE / Không kết nối được
  • Nhiễu tần số vô tuyến trong môi trường có mật độ cao.
  • Sự không tương thích giữa chế độ Ngoại vi và Trung tâm trên phần cứng đầu đọc cụ thể.
  • Hết thời gian quét.
  • Đảm bảo thiết bị đọc hỗ trợ cả chế độ Máy khách trung tâm BLE và Máy chủ ngoại vi.
  • Điều chỉnh khoảng thời gian và khoảng thời gian quét BLE để quét mạnh mẽ trong quá trình tương tác tích cực.
  • Xác minh rằng quá trình thương lượng kích thước MTU đã hoàn tất thành công.
Lượt tương tác bằng cách chạm NFC không thành công hoặc giảm Người dùng kéo thiết bị di động ra khỏi ăng-ten của đầu đọc trước khi bản ghi chuyển giao BLE được chuyển hoàn toàn.
  • Cung cấp phản hồi ngay lập tức bằng hình ảnh/âm thanh/phản hồi xúc giác trên thiết bị đầu cuối ngay khi bắt đầu tương tác NFC.
  • Hướng dẫn người dùng giữ điện thoại cố định vào mục tiêu NFC cho đến khi thiết lập được kết nối BLE.
UNTRUSTED_ISSUER / Lỗi chuỗi chứng chỉ Chứng chỉ của Người ký tài liệu không liên kết với bất kỳ chứng chỉ IACA đáng tin cậy nào trong kho lưu trữ uy tín cục bộ của thiết bị đọc.
  • Kiểm tra để đảm bảo chứng chỉ gốc của tổ chức phát hành đã được tải vào kho lưu trữ uy tín của thiết bị đọc.
  • Nếu bạn đang thử nghiệm trong hộp cát, hãy xác minh rằng Google Sandbox IACA Root đã được tải.
  • Đảm bảo danh sách chứng chỉ IACA (ví dụ: AAMVA VICAL) được cập nhật định kỳ.
INVALID_VALIDITY_INFO / MSO đã hết hạn
  • Đồng hồ hệ thống của máy đọc không đồng bộ.
  • Chữ ký MSO đã hết hạn.
  • Đảm bảo thiết bị đọc đồng bộ hoá thời gian hệ thống thường xuyên qua NTP.
  • Nhắc người dùng mở Google Wallet khi có kết nối Internet để làm mới mã thông báo thông tin xác thực.
DEVICE_AUTHENTICATION_FAILED Bản chép lời phiên không khớp giữa thiết bị đọc và ví, hoặc chữ ký tạm thời của thiết bị không hợp lệ.
  • Đảm bảo các byte thô chính xác của DeviceEngagementBytes và EReaderKeyBytes được giữ nguyên trong cấu trúc SessionTranscript mà không cần mã hoá lại.
Sự cố về quyền trên Android 12 trở lên Ứng dụng đã cố quét hoặc quảng cáo qua BLE mà không có quyền khi bắt đầu chạy.
  • Kiểm tra và yêu cầu BLUETOOTH_SCAN, BLUETOOTH_CONNECT và BLUETOOTH_ADVERTISE trong thời gian chạy trước khi bắt đầu phiên đọc.

Nguyên tắc về trải nghiệm người dùng và quyền riêng tư đối với máy đọc thẻ tại cửa hàng

Khi thiết kế máy đọc thẻ vật lý và ứng dụng đồng hành:

  • Thực hành tiết lộ có chọn lọc trong giao diện người dùng: Chỉ hiển thị quyết định hoặc thuộc tính bắt buộc tối thiểu cho người vận hành (ví dụ: hiển thị dấu kiểm màu xanh lục nổi bật và "Đã xác minh trên 21 tuổi" thay vì hiển thị ngày sinh, địa chỉ và số giấy phép đầy đủ của người dùng).
  • Chỉ báo tương tác vật lý rõ ràng: Gắn nhãn rõ ràng cho vùng mục tiêu NFC và hiển thị các dấu hiệu trực quan (chẳng hạn như ảnh động hoặc thanh tiến trình) cho thấy từng giai đoạn: Nhấn / Quét → Đang kết nối → Đang xác minh → Hoàn tất.
  • Xử lý dữ liệu tạm thời: Không lưu trữ hoặc ghi lại các thành phần dữ liệu cá nhân nhận được từ ví, trừ phi luật hiện hành yêu cầu rõ ràng và được công bố thông qua intentToRetain = true.