तीसरा चरण: Relying Party के तौर पर इंटिग्रेट करना

इस गाइड में बताया गया है कि Direct Relying Parties (RPs)—व्यक्तिगत कारोबारी, कारोबार, और ऐप्लिकेशन डेवलपर—Android ऐप्लिकेशन और वेब पर डिजिटल पहचान के क्रेडेंशियल का अनुरोध करने और उनकी पुष्टि करने के लिए, Digital Credentials API को कैसे इंटिग्रेट करते हैं.

रिलाइंग पार्टी इंटिग्रेशन के काम करने का तरीका

भरोसा करने वाली हर पार्टी के इंटिग्रेशन में चार चरण होते हैं. चरण A और C आपके सर्वर पर चलते हैं; चरण B आपके Android ऐप्लिकेशन या ब्राउज़र में चलता है. किसी भी चरण को चुनकर, उसे लागू करने की जानकारी पर जाएं:

प्रोडक्शन क्रेडेंशियल का अनुरोध करने से पहले, सैंडबॉक्स में ऐप्लिकेशन बनाएं और उसकी जांच करें

A से D तक के चरणों को लागू करते समय, Google की पहले से भरोसेमंद सैंडबॉक्स ऐसेट का इस्तेमाल करें, ताकि आप तुरंत बिल्ड और टेस्ट कर सकें:

हस्ताक्षर करने का अनुरोध करना

Google के सैंडबॉक्स टेस्ट पासकी और मेटाडेटा का इस्तेमाल करके, OpenID4VP अनुरोधों पर हस्ताक्षर करें.

टेस्ट क्रेडेंशियल

Utopia Test ID Pass का इस्तेमाल करके, सैंडबॉक्स मोड में किसी Android डिवाइस पर टेस्ट करें.

जवाब की पुष्टि करना

Utopia Sandbox cert के हिसाब से, issuerAuth की पुष्टि करें.

ऑनलाइन पुष्टि के लिए, आपके बैकएंड सर्वर, क्लाइंट ऐप्लिकेशन या ब्राउज़र, और Google Wallet के बीच एंड-टू-एंड सीक्वेंस

इस्तेमाल किए जा सकने वाले फ़ॉर्मैट, क्रेडेंशियल, और सुविधाएं

Google Wallet, ISO mdoc पर आधारित डिजिटल आईडी के साथ काम करता है. इसके लिए, Android 9 (एपीआई लेवल 28) और इसके बाद के वर्शन पर OpenID4VP (वर्शन 1.0) का इस्तेमाल किया जाता है. साथ ही, यह इस्तेमाल किए जा सकने वाले ब्राउज़र पर भी काम करता है.

इस्तेमाल किए जा सकने वाले क्रेडेंशियल और एट्रिब्यूट

Google Wallet से अनुरोध किए जा सकने वाले doctype_value आइडेंटिफ़ायर (एमडीएल, आईडी पास, फ़ोटो आईडी) और एट्रिब्यूट क्लेम पाथ देखें.

कार्ड जारी करने वाली कंपनियां और आईएसीए सर्टिफ़िकेट

issuerAuth की पुष्टि करने के लिए, अमेरिका के राज्यों, अंतरराष्ट्रीय स्तर पर जारी करने वाली संस्थाओं, और Sandbox Utopia के लिए, आधिकारिक आईएसीए रूट सर्टिफ़िकेट डाउनलोड करें.


पहला चरण: अनुरोध को फ़ॉर्मैट करना और उस पर हस्ताक्षर करना (सर्वर-साइड)

किसी वॉलेट से क्रेडेंशियल का अनुरोध करने के लिए, आपको अपने सर्वर पर OpenID4VP का इस्तेमाल करके, अनुरोध को फ़ॉर्मैट करना होगा. एक dcql_query ऑब्जेक्ट में, एक या एक से ज़्यादा क्रेडेंशियल का अनुरोध किया जा सकता है.

JSON अनुरोध का उदाहरण

यहां Android डिवाइस या वेब पर मौजूद किसी वॉलेट से, पहचान की जानकारी पाने के लिए, mdoc requestJson के अनुरोध का सैंपल दिया गया है.

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

एन्क्रिप्ट करने का अनुरोध करना

client_metadata में हर अनुरोध के लिए, एन्क्रिप्ट करने का सार्वजनिक पासकोड होता है. आपको हर अनुरोध के लिए निजी पासकोड सेव करने होंगे. साथ ही, Wallet ऐप्लिकेशन से मिलने वाले टोकन की पुष्टि करने और उसे अनुमति देने के लिए, उनका इस्तेमाल करना होगा.

इंटिग्रेट किया गया OpenID4VP मेटाडेटा

क्रेडेंशियल के अनुरोध को फ़ॉर्मैट करते समय, आपको client_metadata ऑब्जेक्ट के अंदर gw_rp_metadata_bytes फ़ील्ड को शामिल करना होगा. इसके बारे में, अनुरोध के सैंपल कोड में बताया गया है. इस फ़ील्ड में, Base64URL-एन्कोड किया गया रिलाइंग पार्टी मेटाडेटा होता है. Google Wallet को आपकी पहचान की पुष्टि करने और उपयोगकर्ता को आपकी ब्रैंडिंग दिखाने के लिए, इस मेटाडेटा की ज़रूरत होती है.

क्रेडेंशियल के अनुरोध का पेलोड

requestJson में मौजूद credential_request पैरामीटर में ये फ़ील्ड शामिल होते हैं.

खास क्रेडेंशियल

{
  "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": {
          // Use org.iso.18013.5.1.mDL for mDL,
          // com.google.wallet.idcard.1 for ID pass, or
          // org.iso.23220.photoid.1 for ID pass (using photo ID document type)
          "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
          }
        ]
      }
    ]
  },
  "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
        ],
        "issuerauth_alg_values": [
          -7
        ]
      }
    },
    "gw_rp_metadata_bytes": "<base64url encoded metadata string>"
  }
}

ज़रूरी शर्तें पूरी करने वाला कोई भी क्रेडेंशियल

यहां एमडीएल, आईडी पास, और आईडी पास (फ़ोटो आईडी दस्तावेज़ टाइप का इस्तेमाल करके) के लिए अनुरोध का उदाहरण दिया गया है. उपयोगकर्ता इनमें से किसी भी विकल्प को चुन सकता है.

{
  "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 pass
        "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 type 3: ID pass (using photo ID document type)
        "id": "photo_id-request",
        "format": "mso_mdoc",
        "meta": {
          "doctype_value": "org.iso.23220.photoid.1"
        },
        "claims": [
          {
            "path": [
              "org.iso.23220.1",
              "family_name"
            ],
            "intent_to_retain": false // set this to true if you are saving the value of the field
          },
          {
            "path": [
              "org.iso.23220.1",
              "given_name"
            ],
            "intent_to_retain": false
          },
          {
            "path": [
              "org.iso.23220.1",
              "age_over_18"
            ],
            "intent_to_retain": false
          }
        ]
      }
    ]
    credential_sets : [
      {
        "options": [
          [ "mdl-request" ],
          [ "id_pass-request" ],
          [ "photo_id-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
        ],
        "issuerauth_alg_values": [
          -7
        ]
      }
    },
    "gw_rp_metadata_bytes": "<base64url encoded metadata string>"
  }
}

Google Wallet में सेव किए गए किसी भी आईडी क्रेडेंशियल से, इस्तेमाल किए जा सकने वाले एट्रिब्यूट के लिए अनुरोध किया जा सकता है.

हस्ताक्षर किए गए अनुरोध

साइन किए गए अनुरोध (JWT से सुरक्षित किए गए अनुमति के अनुरोध) में, पुष्टि किए जा सकने वाले प्रज़ेंटेशन के अनुरोध को क्रिप्टोग्राफ़िक तरीके से साइन किए गए JSON Web Token (JWT) में शामिल किया जाता है. इसके लिए, आपके पीकेआई इन्फ़्रास्ट्रक्चर का इस्तेमाल किया जाता है. इससे अनुरोध की सुरक्षा और Google Wallet को आपकी पहचान की पुष्टि करने में मदद मिलती है.

ज़रूरी शर्तें

साइन किए गए अनुरोधों के लिए कोड में बदलाव करने से पहले, पक्का करें कि आपके पास:

  • निजी पासकोड: अनुरोध पर हस्ताक्षर करने के लिए, आपको एक निजी पासकोड की ज़रूरत होगी. जैसे, एलिप्टिक कर्व ES256. इसे आपके सर्वर पर मैनेज किया जाता है. सैंडबॉक्स में, Relying Party के तौर पर टेस्टिंग करने के लिए, सैंडबॉक्स टेस्ट निजी पासकोड का इस्तेमाल करें.
  • सर्टिफ़िकेट: आपको अपने कुंजी के जोड़े से मिला स्टैंडर्ड X.509 सर्टिफ़िकेट चाहिए.
  • रजिस्ट्रेशन: पक्का करें कि Google Wallet आपके सार्वजनिक सर्टिफ़िकेट (या पुष्टि करने वाले रजिस्ट्रार के लिए रूट सीए) पर भरोसा करता हो.

अनुरोध बनाने का लॉजिक

OpenID4VP अनुरोध बनाते और उस पर हस्ताक्षर करते समय, हर फ़ील्ड के लिए ज़रूरी एन्कोडिंग फ़ॉर्मैट पर खास ध्यान दें. base64 और base64url को मिलाने या पैडिंग (=) करने से, हस्ताक्षर या ऑरिजिन की पुष्टि नहीं हो पाएगी:

फ़ील्ड ज़रूरी एन्कोडिंग / फ़ॉर्मैट वर्ण और पैडिंग
client_id (x509_hash:<hash>) बिना पैडिंग के base64url यूआरएल के लिए सुरक्षित वर्णमाला (-, _) का इस्तेमाल करता है; आखिर में मौजूद = को हटाता है
expected_origins (android:apk-key-hash:<hash>) बिना पैडिंग के स्टैंडर्ड base64 स्टैंडर्ड वर्णमाला (+, /) का इस्तेमाल करता है; आखिर में मौजूद = को हटाता है
expected_origins (https://...) लोअरकेस यूआरएल, जिनके आखिर में स्लैश न हों उदाहरण: https://example.com (आखिर में / नहीं)
x5c जेडब्ल्यूएस हेडर पैडिंग के साथ स्टैंडर्ड base64 स्टैंडर्ड वर्णमाला (+, /) का इस्तेमाल करता है; आखिर में = पैडिंग रखें

अनुरोध बनाने के लिए, अपने निजी पासकोड का इस्तेमाल करें और पेलोड को JWS में रैप करें:

def construct_openid4vp_request(
    doctypes: list[str],
    requested_fields: list[dict],
    nonce_base64: str,
    jwe_encryption_public_jwk: jwk.JWK,
    is_zkp_request: bool,
    is_signed_request: bool,
    state: dict,
    origin: str
) -> dict:

    # ... [Existing logic to build 'presentation_definition' and basic 'request_payload'] ...

    # ------------------------------------------------------------------
    # SIGNED REQUEST IMPLEMENTATION (JAR)
    # ------------------------------------------------------------------
    if is_signed_request:
        try:
            # 1. Load the Verifier's Certificate
            # We must load the PEM string into a cryptography x509 object
            verifier_cert_obj = x509.load_pem_x509_certificate(
                CERTIFICATE.encode('utf-8'),
                backend=default_backend()
            )

            # 2. Calculate Client ID (x509_hash)
            # We calculate the SHA-256 hash of the DER-encoded certificate.
            cert_der = verifier_cert_obj.public_bytes(serialization.Encoding.DER)
            verifier_fingerprint_bytes = hashlib.sha256(cert_der).digest()

            # Important: Use URL-safe Base64 (base64url: '-', '_') without padding ('=') for client_id
            verifier_fingerprint_b64 = base64.urlsafe_b64encode(verifier_fingerprint_bytes).decode('utf-8').rstrip("=")

            # Format the client_id as required by the spec
            client_id = f'x509_hash:{verifier_fingerprint_b64}'

            # 3. Update Request Payload with JAR specific fields
            request_payload["client_id"] = client_id

            # Explicitly set expected origins to prevent relay attacks
            # Important: Use standard Base64 (not URL-safe) without padding for android:apk-key-hash:
            # origin = f"android:apk-key-hash:{base64.b64encode(apk_cert_hash).decode('utf-8').rstrip('=')}"
            # Format for web origin (lowercase URL without trailing slash): origin = "https://example.com"
            if origin:
                request_payload["expected_origins"] = [origin]

            # 4. Create Signed JWT (JWS)
            # Load the signing private key
            signing_key = jwk.JWK.from_pem(PRIVATE_KEY.encode('utf-8'))

            # Initialize JWS with the JSON payload
            jws_token = jws.JWS(json.dumps(request_payload).encode('utf-8'))

            # Construct the JOSE Header
            # 'x5c' (X.509 Certificate Chain) is critical: it allows the wallet
            # to validate your key against the one registered in the console.
            # Important: Use standard Base64 ('+', '/') WITH padding ('=') for x5c
            x5c_value = base64.b64encode(cert_der).decode('utf-8')

            protected_header = {
                "alg": "ES256",                 # Algorithm (e.g., ES256 or RS256)
                "typ": "oauth-authz-req+jwt",   # Standard type for JAR
                "kid": "1",                     # Key ID
                "x5c": [x5c_value]              # Embed the certificate
            }

            # Sign the token
            jws_token.add_signature(
                key=signing_key,
                alg=None,
                protected=json_encode(protected_header)
            )

            # 5. Return the Request Object
            # Instead of returning the raw JSON, we return the signed JWT string
            # under the 'request' key.
            return {"request": jws_token.serialize(compact=True)}

        except Exception as e:
            print(f"Error signing OpenID4VP request: {e}")
            return None

    # ... [Fallback for unsigned requests] ...
    return request_payload

दूसरा चरण: एपीआई को ट्रिगर करना (क्लाइंट-साइड)

पूरा एपीआई अनुरोध, सर्वर-साइड पर जनरेट किया जाना चाहिए. प्लैटफ़ॉर्म के हिसाब से, जनरेट किए गए JSON को प्लैटफ़ॉर्म एपीआई में पास करें.

इन-ऐप्लिकेशन (Android)

अपने 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")
}

Credential Manager को कॉन्फ़िगर करना

CredentialManager ऑब्जेक्ट को कॉन्फ़िगर और शुरू करने के लिए, यहां दिए गए लॉजिक जैसा लॉजिक जोड़ें:

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

पहचान बताने वाले एट्रिब्यूट का अनुरोध करना

ऐप्लिकेशन, पहचान की पुष्टि करने के अनुरोधों के लिए अलग-अलग पैरामीटर तय करने के बजाय, उन्हें CredentialOption में JSON स्ट्रिंग के तौर पर एक साथ उपलब्ध कराता है. Credential Manager, इस JSON स्ट्रिंग को उपलब्ध डिजिटल वॉलेट को पास करता है. इसके लिए, वह इसके कॉन्टेंट की जांच नहीं करता. इसके बाद, हर वॉलेट की ज़िम्मेदारी होती है कि वह:

  • पहचान की पुष्टि करने के अनुरोध को समझने के लिए, JSON स्ट्रिंग को पार्स करना.
  • यह तय करना कि सेव किए गए क्रेडेंशियल में से कौनसे क्रेडेंशियल, अनुरोध को पूरा करते हैं.

हमारा सुझाव है कि पार्टनर, Android ऐप्लिकेशन इंटिग्रेशन के लिए भी सर्वर पर अपने अनुरोध बनाएं.

GetDigitalCredentialOption() फ़ंक्शन कॉल में request के तौर पर, Format & Sign the Request से requestJson का इस्तेमाल किया जाएगा.

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

क्रेडेंशियल के जवाब को मैनेज करना

Wallet से जवाब मिलने के बाद, पुष्टि करें कि जवाब सही है या नहीं. साथ ही, यह भी देखें कि उसमें 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 ने तय किया है. Wallet ऐप्लिकेशन, इस जवाब को तैयार करने के लिए ज़िम्मेदार है.

उदाहरण:

{
  "protocol" : "openid4vp-v1-signed",
  "data" : {
    <encrypted_response>
  }
}

इस जवाब को अपने सर्वर पर वापस भेजें, ताकि इसकी प्रामाणिकता की पुष्टि की जा सके. जवाब को डिक्रिप्ट करना और उसकी पुष्टि करना देखें.

वेब

Chrome या अन्य ब्राउज़र पर Digital Credentials API का इस्तेमाल करके, आइडेंटिटी क्रेडेंशियल का अनुरोध करने के लिए, यह अनुरोध करें:

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

क्रेडेंशियल की पुष्टि करने के लिए, इस एपीआई से मिले रिस्पॉन्स को अपने सर्वर पर वापस भेजें.


तीसरा चरण: जवाब को डिक्रिप्ट करना और उसकी पुष्टि करना (सर्वर-साइड)

जब वॉलेट, एन्क्रिप्ट (सुरक्षित) किया गया identityToken (JWT) दिखाता है, तो डेटा पर भरोसा करने से पहले, आपको सर्वर-साइड से होने वाली पुष्टि करनी होगी.

जवाब को डिक्रिप्ट करना

जेडब्ल्यूई को डिक्रिप्ट करने के लिए, अनुरोध के client_metadata में भेजे गए सार्वजनिक पासकोड से जुड़े निजी पासकोड का इस्तेमाल करें. इससे vp_token मिलता है.

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

SessionTranscript को फिर से बनाना और DeviceResponse की पुष्टि करना

  1. Android या वेब के लिए खास हैंडओवर स्ट्रक्चर के साथ, ISO/IEC 18013-5:2021 से SessionTranscript बनाएं:
SessionTranscript = [
  null,                // DeviceEngagementBytes not available
  null,                // EReaderKeyBytes not available
  [
    "OpenID4VPDCAPIHandover",
    AndroidHandoverDataBytes   // BrowserHandoverDataBytes for Web
  ]
]

Android और वेब, दोनों पर हैंडओवर के लिए, उसी nonce का इस्तेमाल करें जिसका इस्तेमाल आपने credential_request जनरेट करने के लिए किया था.

Android हैंडओवर

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 का इस्तेमाल करके, डिवाइस के रिस्पॉन्स की पुष्टि ISO/IEC 18013-5:2021 के क्लॉज़ 9 के मुताबिक की जानी चाहिए.

इस पुष्टि में चार जांच शामिल हैं:

  1. सर्टिफ़िकेट जारी करने वाली इकाई की जांच करें: issuerAuth से, सर्टिफ़िकेट जारी करने वाली इकाई की साइनिंग सर्टिफ़िकेट चेन को निकालें. इसके बाद, भरोसेमंद आईएसीए रूट सर्टिफ़िकेट की मदद से इसकी पुष्टि करें. इश्यूअर और आईएसीए सर्टिफ़िकेट देखें. साथ ही, सैंडबॉक्स टेस्ट आईडी से टेस्ट करते समय, Utopia Sandbox सर्टिफ़िकेट जोड़ें.
  2. MSO के हस्ताक्षर की पुष्टि करना (ISO/IEC 18013-5 सेक्शन 9.1.2).
  3. डेटा एलिमेंट के लिए ValueDigests को कैलकुलेट करें और उसकी जांच करें (ISO/IEC 18013-5 सेक्शन 9.1.2).
  4. deviceSignature के हस्ताक्षर की पुष्टि करना (ISO/IEC 18013-5 सेक्शन 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
}

चौथा चरण (ज़रूरी नहीं): निजता बनाए रखते हुए उम्र की पुष्टि से जुड़ी प्रोसेस (ज़ेडकेपी)

ज़ीरो-नॉलेज प्रूफ़ की सुविधा देने के लिए, अपने अनुरोध के फ़ॉर्मैट को mso_mdoc_zk में बदलें और ज़रूरी zk_system_type कॉन्फ़िगरेशन उपलब्ध कराएं. उदाहरण के लिए, उपयोगकर्ता की जन्म की तारीख देखे बिना, यह पुष्टि करना कि उसकी उम्र 18 साल से ज़्यादा है.

ज़ेडकेपी क्या है और इसकी क्षमताएं क्या हैं, इस बारे में खास जानकारी पाने के लिए, अक्सर पूछे जाने वाले सवाल देखें.

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

आपको वॉलेट से, एन्क्रिप्ट (सुरक्षित) किया गया ज़ीरो-नॉलेज प्रूफ़ मिलेगा. Google की longfellow-zk लाइब्रेरी का इस्तेमाल करके, इस सबूत की पुष्टि, जारी करने वाली कंपनी के आईएसीए सर्टिफ़िकेट से की जा सकती है.

verifier-service में, डिप्लॉयमेंट के लिए तैयार Docker-आधारित सर्वर होता है. इसकी मदद से, जारी करने वाले आईएसीए सर्टिफ़िकेट के आधार पर रिस्पॉन्स की पुष्टि की जा सकती है.

certs.pem में बदलाव करके, IACA जारी करने वाले सर्टिफ़िकेट को मैनेज किया जा सकता है. इससे यह तय किया जा सकता है कि आपको किन सर्टिफ़िकेट पर भरोसा करना है.


एसडीके, रेफ़रंस इंप्लिमेंटेशन, और सहायता

लागू करने की प्रोसेस को तेज़ करने के लिए, हमारी ओपन-सोर्स लाइब्रेरी, रेफ़रंस सर्वर, और वेब की पुष्टि करने वाले टूल का इस्तेमाल करें:

संसाधन / लाइब्रेरी इससे क्या फ़ायदा होता है लिंक
Identity Verifiers Reference Implementation सैंपल सर्वर और क्लाइंट, OpenID4VP अनुरोध जनरेट करने, JWS साइनिंग, JWE डिक्रिप्शन, और mdoc रिस्पॉन्स की पुष्टि करने का तरीका बताते हैं. GitHub रिपॉज़िटरी
Multipaz SDK ओपन-सोर्स लाइब्रेरी (OpenWallet Foundation). इसमें CBOR डिकोडिंग के लिए DeviceResponseParser, SessionTranscript को फिर से बनाने, और ISO/IEC 18013-5/7 के हस्ताक्षर की पुष्टि करने की सुविधा शामिल है. openwallet-foundation/multipaz
Longfellow ZKP Library & Verifier Service ओपन-सोर्स लाइब्रेरी और Docker पर आधारित सर्वर, ताकि ज़ीरो-नॉलेज प्रूफ़ (mso_mdoc_zk) की मदद से उम्र और एट्रिब्यूट के दावों की पुष्टि की जा सके. google/longfellow-zk
इंटरैक्टिव वेब वेरिफ़ायर टूल Google Wallet के लिए, W3C Digital Credentials API / OpenID4VP के अनुरोधों की जांच करने के लिए, होस्ट किया गया वेब वेरिफ़ायर. verifier.multipaz.org
OpenID4VP 1.0 स्पेसिफ़िकेशन पुष्टि की जा सकने वाली प्रज़ेंटेशन 1.0 प्रोटोकॉल की खास जानकारी के लिए आधिकारिक OpenID. OpenID4VP स्पेसिफ़िकेशन
अक्सर पूछे जाने वाले सवाल और डेवलपर के लिए सहायता तकनीकी इंटिग्रेशन से जुड़े अक्सर पूछे जाने वाले सवालों के जवाब पाएं या डीबग करने में मदद पाने के लिए, wallet-identity-rp-support@google.com पर ईमेल करें. तकनीकी इंटिग्रेशन के बारे में अक्सर पूछे जाने वाले सवाल

अगला चरण