قبول الشهادات الرقمية حضورًا شخصيًا (بلا إنترنت)

يوضّح هذا الدليل كيف يمكن للجهات المعتمِدة ومطوّري أجهزة القراءة تنفيذ عملية التحقّق من بيانات الاعتماد الرقمية المقدَّمة من "محفظة Google" شخصيًا (بلا إنترنت) وفقًا لمعيار ISO/IEC 18013-5 الدولي.

يمكن التحقّق من بيانات الاعتماد الرقمية في "محفظة Google" بأمان في البيئات المادية (مثل نقاط البيع وأماكن الفعاليات وبوابات النقل العام وأجهزة قراءة مستندات التعريف لدى سلطات إنفاذ القانون وتطبيقات القراءة على الأجهزة الجوّالة) بدون الحاجة إلى اتصال نشط بالإنترنت في وقت تقديمها.

نظرة عامة على العرض بلا إنترنت (ISO/IEC 18013-5)

يحدّد معيار ISO/IEC 18013-5 بروتوكولاً موحّدًا وقابلاً للتشغيل التفاعلي للعرض بلا إنترنت بين الحامل (جهاز المستخدم الجوّال الذي يشغّل "محفظة Google") والقارئ / المُتحقّق (جهاز طرفي أو تطبيق جوّال مصاحب).

يحدث تدفق العرض التقديمي في مراحل مختلفة:

  1. التفاعل مع الجهاز: ينشئ قارئ البطاقات والمحفظة اتصالاً أوليًا من خلال النقر على NFC (النقل الثابت أو التفاوضي) أو مسح رمز الاستجابة السريعة ضوئيًا. خلال هذه المرحلة، يتم تبادل البيانات الوصفية لتفاعل الجهاز والمفتاح العام المؤقت للقارئ (EReaderKey).
  2. اتصال نقل البيانات: يتم التفاوض على قناة بلوتوث منخفض الطاقة (BLE) آمنة ومشفّرة (مع عمل القارئ في وضع "العميل المركزي" أو "خادم الأجهزة الملحقة").
  3. طلب الجهاز: يرسل القارئ DeviceRequest بترميز CBOR يحدّد نوع المستند المطلوب (مثل org.iso.18013.5.1.mDL) ومساحات الأسماء وعناصر البيانات المحدّدة المطلوبة.
  4. موافقة المستخدم ومصادقة الجهاز: تطلب "محفظة Google" من المستخدم مراجعة عناصر البيانات المطلوبة وتأكيد المشاركة باستخدام المصادقة بالمقاييس الحيوية أو قفل الشاشة.
  5. استجابة الجهاز والتحقّق من التشفير: ترسل المحفظة ردًا بتنسيق DeviceResponse المرمّز وفقًا لبروتوكول CBOR، والذي يحتوي على عنصر أمان الجهاز الجوّال (MSO) الموقَّع وعناصر البيانات الموقَّعة من الجهاز. يتحقّق القارئ من التوقيعات المشفّرة مقارنةً بشهادات الجذر الموثوق بها.

حزمة تطوير البرامج (SDK) المفتوحة المصدر Multipaz

لتنفيذ تطبيق قارئ أو تطبيق تحقّق، تنصح Google باستخدام Multipaz، وهي حزمة تطوير برامج (SDK) مفتوحة المصدر من Kotlin Multiplatform (KMP) طوّرتها Google في الأصل وساهمت في مؤسسة OpenWallet Foundation (OWF).

توفّر Multipaz تنفيذًا جاهزًا للإنتاج لبروتوكولات القارئ والمحفظة ISO/IEC 18013-5، ومسارات التحقّق من التشفير، وترميز/فك ترميز CBOR، ومخططات أنواع المستندات القابلة للتوسيع.

دمج Multipaz في تطبيق القارئ

توضّح الخطوات التالية كيفية دمج حزمة Multipaz SDK في تطبيق قارئ Android.

الخطوة 1: إضافة التبعيات

يتم نشر مكتبات Multipaz على Maven Central. أضِف الوحدات المطلوبة إلى ملف build.gradle.kts الخاص بتطبيقك:

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

الخطوة 2: ضبط أذونات Android

تتطلّب عملية إثبات الهوية حضورًا شخصيًا أذونات الأجهزة للتفاعل عبر NFC والمسح الضوئي بالكاميرا (للتفاعل عبر رمز الاستجابة السريعة) ونقل البيانات عبر البلوتوث منخفض الطاقة. أضِف الأذونات التالية إلى 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>

الخطوة 3: إعداد محرّك التحقّق

استخدِم تجريدات الاتصال VerificationHelper أو Reader في Multipaz للتعامل مع أحداث التفاعل وإدارة مراحل نشاط الاتصال عبر 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()
    }
}

الخطوة 4: إنشاء DeviceRequest

حدِّد نوع المستند وعناصر البيانات الفردية التي يحتاج تطبيقك إلى التحقّق منها. يجب دائمًا تطبيق مبدأ الحد الأدنى من الإفصاح (على سبيل المثال، طلب age_over_21 فقط بدلاً من birth_date بالكامل عند إثبات العمر):

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

إتاحة أنواع مستندات إضافية (DocTypes)

تتيح Multipaz استخدام بيانات الاعتماد العادية بشكل تلقائي، وتوفّر بنية قابلة للتوسيع لطلب أنواع مستندات مخصّصة أو خاصة بنطاق معيّن.

1. أنواع المستندات العادية المضمّنة

توفّر مكتبة multipaz-doctypes نماذج مخطّطات محدّدة مسبقًا لبيانات الاعتماد العادية:

معرّف نوع المستند المعيار / النطاق مساحة الاسم النموذجية العناصر الشائعة
org.iso.18013.5.1.mDL رخصة القيادة الرقمية 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 بيانات تعريف الشخص في "محفظة الهوية الرقمية للاتحاد الأوروبي" (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 بطاقة الهوية الرقمية في "محفظة Google" / مستندات التعريف الاختبارية com.google.wallet.idcard.1 given_name، وfamily_name، وbirth_date، وdocument_number، وportrait

2. طلب أنواع مستندات مخصّصة

لطلب أنواع مستندات مخصّصة، حدِّد سلسلة docType المستهدفة وعمليات ربط مساحة الاسم المقابلة عند إنشاء 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)
        )
    )
)

التحقّق من التشفير وإدارة الثقة

إنّ تلقّي حمولة الاستجابة هو الخطوة الأولى فقط. يجب أن تُجري أجهزة القراءة عملية تحقّق من التشفير تتألف من أربع خطوات لإثبات صحة بيانات الاعتماد المقدَّمة وسلامتها.

خطوة التحقّق الهدف من التحقّق
1. مصادقة جهة الإصدار التحقّق من IssuerAuth (COSE_Sign1) باستخدام شهادات الجذر الموثوق بها من IACA
2. التحقّق من فترة الصلاحية يُرجى التأكّد من أنّ validFrom ≤ الوقت الحالي ≤ validUntil
3. التحقّق من صحة البيانات احتساب ملخّصات SHA-256 للعناصر التي تم عرضها ومطابقتها مع MSO ValueDigests
4. مصادقة الجهاز التحقّق من توقيع DeviceSigned أو رمز MAC باستخدام DeviceKey المرتبط بـ SessionTranscript

1. مسار التحقّق المكوّن من 4 خطوات

  1. مصادقة جهة الإصدار (IssuerAuth):
    • توقّع "جهة الإصدار" على "عنصر أمان الأجهزة الجوّالة" (حمولة بيانات IssuerAuth).
    • يتحقّق القارئ من توقيع COSE_Sign1 باستخدام شهادة موقِّع المستند ويضمن أن الشهادة مرتبطة بشهادة جذر موثوقة من مرجع التصديق (IACA).
  2. التحقّق من فترة الصلاحية:
    • يتحقّق القارئ من الطوابع الزمنية validityInfo.validFrom وvalidityInfo.validUntil في كائن MSO مقارنةً بساعة القارئ الحالية للتأكّد من عدم انتهاء صلاحية بيانات الاعتماد.
  3. التحقّق من صحة البيانات (ValueDigests):
    • بالنسبة إلى كل IssuerSignedItem يتم تلقّيه، يحتسب القارئ ملخّصه (مثل SHA-256) ويتحقّق من تطابقه مع إدخال التجزئة المقابل في قاموس ValueDigests الخاص بـ MSO.
  4. مصادقة الجهاز (DeviceSigned):
    • يتحقّق القارئ من أنّ الجهاز الذي يقدّم بيانات الاعتماد يحمل المفتاح الخاص المقابل لـ DeviceKey المنشور داخل عنصر MSO الموقَّع.
    • يتم ذلك من خلال التحقّق من DeviceAuth (إما DeviceSignature أو DeviceMac) عبر SessionTranscript، وربط الجلسة بالمفتاح المؤقت للقارئ ومنع هجمات إعادة التشغيل وهجمات الوسيط.

2. إدارة شهادات الجذر الموثوقة الصادرة عن IACA

يجب أن تحتفظ أجهزة القراءة في بيئة الإنتاج بمخزن شهادات الجذر الموثوق بها محليًا وآمنًا يحتوي على شهادات الجذر الموثوق بها من هيئة IACA:

  • شهادات IACA للإنتاج: نزِّل شهادات الجذر من هيئات الإصدار الرسمية واضبطها. يُرجى الرجوع إلى قائمة جهات الإصدار وشهادات IACA المعتمَدة.
  • قائمة VICAL الصادرة عن جمعية AAMVA: في الولايات المتحدة، يمكن دمج أنظمة القراءة مع خدمة قائمة جهات إصدار الشهادات الموثوقة (VICAL) الصادرة عن جمعية AAMVA لمزامنة نقاط الارتكاز الموثوقة في الولاية تلقائيًا.
  • جذور اختبار وضع الحماية: عند الاختبار باستخدام بيانات اعتماد وضع الحماية، تأكَّد من أنّ القارئ يثق في جذر Google Sandbox IACA.
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
}

مصادقة القارئ (إجراء يُنصح به)

تسمح ميزة "مصادقة القارئ" لتطبيق القارئ بإثبات هويته بشكل مشفّر لـ "محفظة Google" من خلال توقيع بنية ReaderAuthentication باستخدام شهادة قارئ X.509 معتمَدة.

  • أهمية هذه الميزة: تتيح ميزة "مصادقة القارئ" لتطبيق القارئ أو الجهاز تقديم هوية موثوقة للمستخدم. على الرغم من أنّ هذه الخطوة اختيارية للسمات العامة الأساسية (مثل التحقّق من age_over_21)، ننصح بشدة باستخدامها في عمليات دمج قارئ المستندات لزيادة ثقة المستخدمين، وقد تكون مطلوبة قانونيًا أو بموجب السياسات عند طلب سمات حساسة (مثل رقم التأمين الاجتماعي الكامل أو عنوان السكن أو موافقات محدّدة من الولاية).
  • طريقة العمل: يتضمّن القارئ سلسلة الشهادات ويوقّع على نص الجلسة. تعرض "محفظة Google" الهوية التي تم إثبات صحتها واسم المؤسسة الخاص بالقارئ للمستخدم على شاشة طلب الموافقة قبل إصدار البيانات.

أدوات الاختبار والتطوير

لتسريع عملية الدمج، استخدِم الأدوات التالية المخصّصة للمطوّرين وعمليات التنفيذ المرجعية:

  1. تطبيقات Multipaz المرجعية:
    • استنسِخ مستودع Multipaz وشغِّل نموذج تطبيق IdentityReader Android لاختبار مسارات التحقّق من الهوية الشخصية.
  2. إنشاء مستند تعريف تجريبي في "محفظة Google":
  3. اختبار أداة التحقّق المستندة إلى الويب:
    • استخدِم verifier.multipaz.org لفحص طلبات CBOR واستكشاف طلبات البحث عن المطالبات واختبار العروض التقديمية المستندة إلى الويب وفقًا لمعيار W3C / ISO 18013-7.

تحديد المشاكل وحلّها وبيانات التشخيص الميدانية

يسرد الجدول التالي المشاكل الشائعة التي تحدث أثناء عملية التحقّق من الهوية بلا إنترنت والحلول المقترَحة:

المشكلة / العَرَض السبب الأساسي الحلّ المقترَح
انتهت مهلة اتصال BLE / تعذّر الاتصال
  • تداخُل الترددات اللاسلكية في البيئات العالية الكثافة
  • عدم توافق وضع "الطرفي" مع وضع "المركزي" على أجهزة قارئ معيّنة
  • مهلات البحث
  • تأكَّد من أنّ القارئ يتوافق مع وضعَي "العميل المركزي" (Central Client) و"الخادم الطرفي" (Peripheral Server) في تقنية BLE.
  • ضبط نافذة وفترة البحث عن أجهزة BLE لإجراء بحث مكثّف أثناء التفاعل النشط
  • تأكَّد من اكتمال عملية التفاوض على حجم وحدة الإرسال الكبرى (MTU) بنجاح.
تعذُّر أو انخفاض معدّل التفاعل مع ميزة النقر عبر NFC يبعد المستخدم الجهاز الجوّال عن هوائي القارئ قبل نقل سجلّ نقل البيانات عبر BLE بالكامل.
  • تقديم ملاحظات مرئية أو صوتية أو تجاوب حسّي فوري على الجهاز فور بدء التفاعل عبر تقنية NFC
  • اطلب من المستخدمين تثبيت الهاتف على هدف NFC إلى أن يتم إنشاء اتصال BLE.
UNTRUSTED_ISSUER / تعذُّر سلسلة الشهادات لا ترتبط شهادة موقِّع المستند بأي شهادة IACA موثوق بها في مخزن شهادات الجذر الموثوق بها المحلي الخاص بالقارئ.
  • تأكَّد من تحميل شهادة الجذر الخاصة بجهة الإصدار في مخزن شهادات الجذر الموثوق بها الخاص بالقارئ.
  • في حال الاختبار في وضع الحماية، تأكَّد من تحميل Google Sandbox IACA Root.
  • تأكَّد من تعديل قوائم شهادات IACA (مثل AAMVA VICAL) بشكل دوري.
INVALID_VALIDITY_INFO / انتهت صلاحية العرض الترويجي من مشغّل خدمات متعددة
  • ساعة نظام القارئ غير متزامنة.
  • انتهت صلاحية توقيع MSO.
  • تأكَّد من أنّ جهاز القارئ يزامن وقت نظامه بانتظام من خلال بروتوكول وقت الشبكة (NTP).
  • اطلب من المستخدم فتح "محفظة Google" أثناء الاتصال بالإنترنت لإعادة تحميل رموز بيانات الاعتماد.
DEVICE_AUTHENTICATION_FAILED هناك عدم تطابق في نص الجلسة بين القارئ والمحفظة، أو توقيع الجهاز المؤقت غير صالح.
  • تأكَّد من الاحتفاظ بوحدات البايت الأولية الدقيقة لـ DeviceEngagementBytes وEReaderKeyBytes في بنية SessionTranscript بدون إعادة الترميز.
تعطُّل التطبيق بسبب أذونات Android 12 والإصدارات الأحدث حاول التطبيق إجراء مسح ضوئي أو الإعلان عبر BLE بدون أذونات التشغيل.
  • التحقّق من أذونات BLUETOOTH_SCAN وBLUETOOTH_CONNECT وBLUETOOTH_ADVERTISE وطلبها في وقت التشغيل قبل بدء جلسات القارئ

إرشادات تجربة المستخدم وإرشادات الخصوصيّة لأجهزة قراءة البطاقات الشخصية

عند تصميم أجهزة القراءة المادية والتطبيقات المصاحبة:

  • تطبيق مبدأ الإفصاح الانتقائي في واجهة المستخدم: يجب عرض القرار أو الحد الأدنى من السمات المطلوبة فقط للمشغّل (على سبيل المثال، عرض علامة صح خضراء بارزة وعبارة "تم التحقّق من أنّ العمر أكبر من 21 عامًا" بدلاً من عرض تاريخ ميلاد المستخدم الكامل وعنوانه ورقم رخصته).
  • مؤشرات واضحة للتفاعل المادي: يجب تصنيف منطقة الاستهداف في NFC بوضوح وعرض إشارات مرئية (مثل الصور المتحركة أو أشرطة التقدم) توضّح كل مرحلة: النقر / المسح الضوئي ← جارٍ الاتصال ← جارٍ التحقق ← اكتملت العملية.
  • معالجة البيانات المؤقتة: لا يجوز تخزين أو تسجيل عناصر البيانات الشخصية التي يتم تلقّيها من المحفظة ما لم يتطلّب القانون الساري ذلك صراحةً ويتم الإفصاح عنه من خلال intentToRetain = true.