قبول بيانات الاعتماد الرقمية على الإنترنت

يمكن قبول مستندات التعريف الرقمية في مسارات داخل التطبيق وعلى الويب. لقبول مستندات التعريف من "محفظة Google"، عليك استيفاء الشروط التالية:

  1. يمكنك الدمج باستخدام التطبيق أو الموقع الإلكتروني باتّباع التعليمات المقدَّمة.
  2. استخدِم معرّف الاختبار لاختبار مسار العمل باستخدام وضع الحماية في "محفظة Google".
  3. لإتاحة هذه الميزة، يُرجى ملء هذا النموذج لطلب الوصول إلى الميزة وقبول بنود خدمة بيانات الاعتماد في Google Wallet. عليك ملء هذا النموذج لكل كيان من كيانات نشاطك التجاري. سيتواصل معك فريقنا بعد ملء النموذج.
  4. إذا كانت لديك أسئلة، يمكنك التواصل معwallet-identity-rp-support@google.com.

تنسيقات بيانات الاعتماد المتوافقة

تتوفّر العديد من المعايير المقترَحة التي تحدّد تنسيق البيانات لمستندات الهوية الرقمية، وقد حظي اثنان منها باهتمام كبير في المجال:

  1. mdocs: تم تحديده من قِبل المنظمة الدولية للمعايير (ISO).
  2. شهادات اعتماد يمكن التحقّق منها من W3C: هي شهادات اعتماد تحدّدها W3C.

مع أنّ "إدارة بيانات الاعتماد على Android" تتيح كلا التنسيقين، لا تتيح "محفظة Google" حاليًا سوى مستندات التعريف الرقمية المستندة إلى mdoc.

بيانات الاعتماد المتوافقة

تتيح "محفظة Google" نوعَين من بيانات الاعتماد:

  1. رخصة القيادة الرقمية (mDL)
  2. بطاقة تعريف الهوية

يمكنك طلب أي من بيانات الاعتماد في مسارك من خلال تغيير مَعلمة واحدة.

تجربة المستخدم

يوضّح هذا القسم مسار العرض التقديمي المقترَح على الإنترنت. يوضّح المخطط عرض العمر على تطبيق لتوصيل المشروبات الكحولية، ولكن تجربة المستخدم تكون مشابهة على الويب وأنواع العروض الأخرى.

يُطلب من المستخدم تأكيد عمره في التطبيق أو الموقع الإلكتروني يطلع المستخدم على بيانات الاعتماد المؤهّلة المتاحة تظهر للمستخدم صفحة تأكيد في "محفظة Google" يصادق المستخدم لتأكيد المشاركة البيانات المُرسَلة إلى التطبيق أو الموقع الإلكتروني
يُطلب من المستخدم تأكيد عمره في التطبيق أو الموقع الإلكتروني يطلع المستخدم على بيانات الاعتماد المؤهّلة المتاحة تظهر للمستخدم صفحة تأكيد في "محفظة Google" يصادق المستخدم لتأكيد المشاركة البيانات المُرسَلة إلى التطبيق أو الموقع الإلكتروني

ملاحظات أساسية

  1. يتمتع التطبيق أو الموقع الإلكتروني بالمرونة في طريقة إنشاء نقطة الدخول إلى واجهة برمجة التطبيقات. كما هو موضّح في الخطوة 1، ننصح بعرض زر عام، مثل "إثبات الهوية باستخدام مستند تعريف رقمي"، لأنّنا نتوقّع أن تتوفّر خيارات أخرى غير "محفظة Google" من خلال واجهة برمجة التطبيقات بمرور الوقت.
  2. تعرض Android شاشة أداة الاختيار في الخطوة 2. يتم تحديد بيانات الاعتماد المؤهّلة من خلال مطابقة منطق التسجيل الذي توفّره كل "محفظة" مع الطلب الذي يرسله الطرف المعتمد.
  3. تعرض "محفظة Google" الخطوة 3. ستعرض "محفظة Google" الاسم والشعار وسياسة الخصوصية التي يقدّمها المطوّر على هذه الشاشة.

إضافة مسار بطاقة تعريف رقمية

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

يُطلب من المستخدم تأكيد عمره في التطبيق أو الموقع الإلكتروني يتم نقل المستخدم إلى "محفظة Google" للحصول على مستند تعريف رقمي
يُطلب من المستخدم تأكيد عمره في التطبيق أو الموقع الإلكتروني يتم نقل المستخدم إلى "محفظة Google" للحصول على مستند تعريف رقمي

لا يتوفّر أي مستند تعريف رقمي

إذا اختار المستخدم خيار "التحقّق من الهوية باستخدام بطاقة تعريف رقمية" بدون أن تكون لديه بطاقة تعريف رقمية، ستظهر له رسالة الخطأ هذه.

يُطلب من المستخدم تأكيد عمره في التطبيق أو الموقع الإلكتروني ظهور رسالة خطأ للمستخدم إذا لم يكن لديه مستند تعريف رقمي
يُطلب من المستخدم تأكيد عمره في التطبيق أو الموقع الإلكتروني ظهور رسالة خطأ للمستخدم إذا لم يكن لديه مستند تعريف رقمي

لا تتوافق واجهة برمجة التطبيقات مع ميزة تتيح معرفة ما إذا كان لدى المستخدم أي مستندات تعريف رقمية متاحة بدون إشعاره، وذلك للحفاظ على خصوصيته. لذلك، ننصحك بتضمين خيار رابط الإعداد على النحو الموضّح.

تنسيق الطلب لطلب مستندات تعريف الهوية من المحفظة

في ما يلي نموذج لطلب مستند تعريف شخصي requestJson للحصول على بيانات اعتماد الهوية من أي محفظة على جهاز Android أو الويب.

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

طلب التشفير

يحتوي client_metadata على مفتاح التشفير العام لكل طلب. عليك تخزين المفاتيح الخاصة لكل طلب واستخدامها للمصادقة على الرمز المميّز الذي تتلقّاه من تطبيق المحفظة ومنحه الإذن.

تحتوي المَعلمة credential_request في requestJson على الحقول التالية.

بيانات اعتماد محدّدة

{
  "response_type": "vp_token",
  "response_mode": "dc_api.jwt", // change this to dc_api if you want to demo with a non encrypted response.
  "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",  // This is required
          "alg" : "ECDH-ES",  // This is required
        }
      ]
    },
    "vp_formats_supported": {
      "mso_mdoc": {
        "deviceauth_alg_values": [
          -7
        ],
        "isserauth_alg_values": [
          -7
        ]
      }
    }
  }
}

أي بيانات اعتماد مؤهَّلة

في ما يلي مثال على الطلب لكلّ من mDL وبطاقة التعريف. يمكن للمستخدم المتابعة باستخدام أي منهما.

{
  "response_type": "vp_token",
  "response_mode": "dc_api.jwt", // change this to dc_api if you want to demo with a non encrypted response.
  "nonce": "1234",
  "dcql_query": {
    "credentials": [
      {
        "id": "mdl-request",
        "format": "mso_mdoc",
        "meta": {
          "doctype_value": "org.iso.18013.5.1.mDL"
        },
        "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
          }
        ]
      },
      {  // Credential type 2
        "id": "id_pass-request",
        "format": "mso_mdoc",
        "meta": {
          "doctype_value": "com.google.wallet.idcard.1"
        },
        "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
          }
        ]
      }
    ]
    credential_sets : [
      {
        "options": [
          [ "mdl-request" ],
          [ "id_pass-request" ]
        ]
      }
    ]
  },
  "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",  // This is required
          "alg" : "ECDH-ES",  // This is required
        }
      ]
    },
    "vp_formats_supported": {
      "mso_mdoc": {
        "deviceauth_alg_values": [
          -7
        ],
        "isserauth_alg_values": [
          -7
        ]
      }
    }
  }
}

يمكنك طلب أي عدد من السمات المتوافقة من أي مستند تعريف مخزَّن في "محفظة Google".

في التطبيق

لطلب مستندات إثبات الهوية من تطبيقات Android، اتّبِع الخطوات التالية:

تعديل العناصر التابعة

في ملف build.gradle الخاص بمشروعك، عدِّل التبعيات لاستخدام Credential Manager (الإصدار التجريبي):

dependencies {
    implementation("androidx.credentials:credentials:1.5.0-beta01")
    implementation("androidx.credentials:credentials-play-services-auth:1.5.0-beta01")
}

ضبط "إدارة بيانات الاعتماد"

لضبط كائن CredentialManager وتهيئته، أضِف منطقًا مشابهًا لما يلي:

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

سمات هوية الطلب

بدلاً من تحديد مَعلمات فردية لطلبات تحديد الهوية، يقدّم التطبيق جميع المَعلمات معًا كسلسلة JSON ضمن CredentialOption. يرسل &quot;مدير بيانات الاعتماد&quot; سلسلة JSON هذه إلى المحافظ الرقمية المتاحة بدون فحص محتوياتها. بعد ذلك، يكون كل محفظة مسؤولاً عمّا يلي: - تحليل سلسلة JSON لفهم طلب تحديد الهوية. - تحديد بيانات الاعتماد المخزَّنة التي تستوفي الطلب، إن وُجدت

ننصح الشركاء بإنشاء طلباتهم على الخادم حتى عند دمج تطبيقات Android.

ستستخدِم requestJson من تنسيق الطلب كـ request في استدعاء الدالة 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)
    }
}

التحقّق من صحة الردّ

بعد تلقّي ردّ من المحفظة، عليك التأكّد من أنّ الردّ ناجح ويتضمّن الردّ 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}")
    }
}

يجب أن تتضمّن استجابة credentialJson identityToken مشفّرة (رمز JWT)، محدّدة من قِبل W3C. تطبيق "محفظة Google" هو المسؤول عن صياغة هذا الردّ.

مثال:

{
  "protocol" : "openid4vp-v1-unsigned",
  "data" : {
    <encrpted_response>
  }
}

ستعيد هذا الردّ إلى الخادم للتحقّق من صحته. يمكنك الاطّلاع على خطوات التحقّق من صحة ردّ بيانات الاعتماد.

الويب

لطلب بيانات اعتماد الهوية باستخدام Digital Credentials API على Chrome أو متصفّحات أخرى متوافقة، أرسِل الطلب التالي.

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

أرسِل الردّ من واجهة برمجة التطبيقات هذه إلى خادمك للتحقّق من صحة الردّ على بيانات الاعتماد.

خطوات التحقّق من صحة رد بيانات الاعتماد

عند تلقّي identityToken المشفّر من تطبيقك أو موقعك الإلكتروني، عليك إجراء عمليات تحقّق متعدّدة قبل الوثوق بالردّ.

  1. فك تشفير الردّ باستخدام المفتاح الخاص

    تتمثل الخطوة الأولى في فك تشفير الرمز المميّز باستخدام المفتاح الخاص المحفوظ والحصول على ملف JSON للاستجابة.

    مثال على Python:

    from jwcrypto import jwe, jwk
    
    # Retrieve the Private Key from Datastore
    reader_private_jwk = jwk.JWK.from_json(jwe_private_key_json_str)
    # Save public key thumbprint for session transcript
    encryption_public_jwk_thumbprint = reader_private_jwk.thumbprint()
    
    # 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 إلى إنشاء ملف vp_token JSON يحتوي على بيانات الاعتماد

    {
      "vp_token":
      {
        "cred1": ["<base64UrlNoPadding_encoded_credential>"] // This applies to OpenID4VP 1.0 spec.
      }
    }
    
  2. إنشاء نص الجلسة

    الخطوة التالية هي إنشاء SessionTranscript من ISO/IEC 18013-5:2021 باستخدام بنية Handover خاصة بنظام التشغيل Android أو الويب:

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

    في عمليات التسليم على Android والويب، عليك استخدام قيمة nonce نفسها التي استخدمتها لإنشاء credential_request.

    Android Handover

        AndroidHandoverData = [
          origin,             // "android:apk-key-hash:<base64SHA256_ofAppSigningCert>",
          nonce,           // nonce that was used to generate credential request,
          encryption_public_jwk_thumbprint,  // Encryption public key (JWK) Thumbprint
        ]
    
        AndroidHandoverDataBytes = hashlib.sha256(cbor2.dumps(AndroidHandoverData)).digest()
        

    تسليم المتصفّح

        BrowserHandoverData =[
          origin,               // Origin URL
          nonce,               //  nonce that was used to generate credential request
          encryption_public_jwk_thumbprint,  // Encryption public key (JWK) Thumbprint
        ]
    
        BrowserHandoverDataBytes = hashlib.sha256(cbor2.dumps(BrowserHandoverData)).digest()
        

    باستخدام SessionTranscript، يجب التحقّق من صحة DeviceResponse وفقًا للبند 9 من معيار ISO/IEC 18013-5:2021. يتضمّن ذلك عدة خطوات، مثل:

  3. التحقّق من شهادة جهة إصدار البطاقة في الولاية راجِع شهادات IACA الصادرة عن الجهات المعتمدة.

  4. التحقّق من توقيع MSO (القسم 9.1.2 من معيار 18013-5)

  5. حساب ValueDigests والتحقّق منها لعناصر البيانات (القسم 9.1.2 من 18013-5)

  6. التحقّق من توقيع deviceSignature (القسم 9.1.3 من المعيار 18013-5)

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

إنشاء الحلّ

لإنشاء الحلّ، يمكنك الرجوع إلى التنفيذ المرجعي لأداة التحقّق من الهوية على GitHub.

التحقّق المستند إلى Zero Knowledge Proof (ZKP)

التحقّق بدون إفشاء المعلومات هو طريقة تشفير تتيح للمستخدم (المثبت) أن يثبت للمتحقّق أنّه يملك معلومات هوية معيّنة أو يستوفي معيارًا محدّدًا (مثل أن يكون عمره أكثر من 18 عامًا أو أن يحمل مستند تعريف صالحًا) بدون الكشف عن البيانات الأساسية الفعلية نفسها. بشكل أساسي، هي طريقة لتأكيد صحة بيان حول هوية الشخص مع الحفاظ على سرية التفاصيل الحساسة.

تتطلّب أنظمة الهوية الرقمية التي تعتمد على المشاركة المباشرة لبيانات الهوية غالبًا أن يشارك المستخدمون معلومات شخصية مفرطة، ما يزيد من خطر اختراق البيانات وسرقة الهوية. توفّر ZKP تغييرًا جذريًا في المفاهيم، ما يتيح إجراء عمليات التحقّق مع الحد الأدنى من الإفصاح.

المفاهيم الأساسية لبروتوكولات إثبات المعرفة الصفرية في الهوية الرقمية:

  • المُثبِت: هو الشخص الذي يحاول إثبات أحد جوانب هويته.
  • جهة التحقّق: الجهة التي تطلب إثبات صحة سمة هوية.
  • الإثبات: بروتوكول تشفير يتيح للمثبت إقناع المدقق بصحة ادعائه بدون الكشف عن المعلومات السرية.

الخصائص الأساسية لإثبات صحة المعلومات بدون الكشف عنها:

  • الاكتمال: إذا كانت العبارة صحيحة وكان كل من المُثبِت والمُتحقّق صادقَين، سيقتنع المُتحقّق.
  • الصحة: إذا كانت الجملة خاطئة، لا يمكن للمثبت المخادع (باحتمالية عالية جدًا) إقناع المدقق الصادق بأنّها صحيحة.
  • إثبات المعرفة الصفرية: لا يعرف المدقّق أي شيء سوى أنّ العبارة صحيحة. لا يتم عرض أي بيانات فعلية من هوية مقدّم الإثبات.

للحصول على Zero Knowledge proof من "محفظة Google"، عليك تغيير تنسيق الطلب إلى mso_mdoc_zk وإضافة zk_system_type إلى الطلب.

  ...
  "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": "f88a39e561ec0be02bb3dfe38fb609ad154e98decbbe632887d850fc612fea6f", // This will differ if you need more than 1 attribute.
          "num_attributes": 1, // number of attributes (in claims) this has can support
          "version": 5,
          "block_enc_hash": 4096,
          "block_enc_sig": 2945,
        }
        {
          "system": "longfellow-libzk-v1",
          "circuit_hash": "137e5a75ce72735a37c8a72da1a8a0a5df8d13365c2ae3d2c2bd6a0e7197c7c6", // This will differ if you need more than 1 attribute.
          "num_attributes": 1, // number of attributes (in claims) this has can support
          "version": 6,
          "block_enc_hash": 4096,
          "block_enc_sig": 2945,
        }
       ],
       "verifier_message": "challenge"
      },
     "claims": [{
         ...
      "client_metadata": {
        "jwks": {
          "keys": [ // sample request encryption key
            {
              ...

ستتلقّى إثباتًا مشفّرًا بمعرفة معدومة من المحفظة. يمكنك التحقّق من صحة هذا المستند باستخدام شهادات IACA الصادرة عن الجهات المعنية من خلال مكتبة longfellow-zk من Google.

يحتوي verifier-service على خادم جاهز للنشر يستند إلى Docker ويتيح لك التحقّق من صحة الردّ مقارنةً بشهادات IACA معيّنة صادرة عن جهة إصدار.

يمكنك تعديل ملف certs.pem لإدارة شهادات جهات إصدار IACA التي تريد الوثوق بها.

يمكنك التواصل مع فريق الدعم عبر البريد الإلكتروني للحصول على مزيد من التفاصيل: wallet-identity-rp-support@google.com