راهنمای آماده‌سازی ثبت‌کننده درستی‌سنج

نمای کلی

این بخش فرایند گام‌به‌گام ثبت‌نام درستی‌سنج‌ها برای استفاده از سرویس «هویت کیف پول Google» را شرح می‌دهد.

به‌عنوان ثبت‌کننده درستی‌سنج (برای مثال، شرکت IDV که ازطرف نهادهای دیگر درستی‌سنجی می‌کند)، شما به‌عنوان «مرجع گواهینامه» (CA) خودتان عمل می‌کنید و درخواست‌های هویت را برای «طرف‌های اتکاکننده نهایی» (RPs) پایین‌دستی که مدیریت می‌کنید امضا می‌کنید.

فرایند آماده‌سازی

مرحله ۱: ارسال «فرم پذیرش»، «گواهینامه‌های ریشه»، و پذیرفتن «شرایط خدمات»

فرم پذیرش آماده‌سازی ثبت‌کننده درستی‌سنج را تکمیل و ارسال کنید. در این فرم، هم گواهینامه‌های ریشه «جعبه امن» و «تولید» خود را ارائه خواهید داد. با ارسال این فرم پذیرش آماده‌سازی، به‌طور رسمی شرایط خدمات ثبت‌کننده درستی‌سنج کیف پول Google را نیز می‌پذیرید.

مرحله ۲: اعتماد و آزمایش جعبه شنی

پس‌از ارسال فرم پذیرش، Google گواهینامه ریشه جعبه ایمنی شما را به فروشگاه اعتماد جعبه ایمنی «کیف پول Google» اضافه می‌کند و به شما اطلاع می‌دهد. سپس می‌توانید آزمایش یکپارچه‌سازی خود را در «جعبه شنی» بااستفاده از گواهینامه‌های امضاشده توسط ریشه جعبه شنی خود شروع کنید.

مرحله ۳: ضبط کردن نمایش ویدیو E2E

وقتی آزمایش محیط آزمایشی تکمیل شد، نمایش‌های ویدیویی سرتاسری از جریان درستی‌سنجی برای «طرف اتکای» اولیه (اولین) خود ضبط کنید و آن‌ها را به Google ارسال کنید.

  • الزامات ویدیو:
    • نمایش‌های عملی را برای هر دو جریان میزبان درستی‌سنج (میزبان خود) و میزبان فروشنده (میزبان RP) درصورت لزوم ضبط کنید.
    • از دارایی‌های نمایش فروشنده واقعی (نام، نشان‌واره، نشانی وب «شرایط خدمات») و دارایی‌های نمایش تجمیع‌کننده در ویدیوها استفاده کنید.
    • واسط کاربر و صفحه‌هایی را که جریان درستی‌سنجی راه‌اندازی می‌کنند به‌وضوح نشان دهید.

مرحله ۴: تأیید و اعتماد به ریشه تولید

پس‌از دریافت نمایش‌های ویدیویی سرتاسری شما، Google فرایند بازبینی و تأیید ویدیو را راه‌اندازی می‌کند و به‌طور موازی فرایند اعتماد به گواهینامه ریشه تولید را آغاز می‌کند. پس‌از تکمیل و تأیید هر دو فرایند، می‌توانید راه‌اندازی سرویس را برای «شرکای نهایی» پایین‌دست خود شروع کنید.

مرحله ۵: آماده‌سازی مداوم «نقطه پایان»

برای هر «نماینده پایان» که امضا می‌کنید، باید:

  • به Google اطلاع دهید: از فرم آماده‌سازی مشتری ثبت‌کننده درستی‌سنج برای اطلاع دادن به Google درباره RP جدید و مورد استفاده موردنظر آن استفاده کنید.
  • پیکربندی فراداده: اطلاعات نمایش RP (نام، نشان‌واره، نشانی وب خط‌مشی رازداری) را تکمیل کنید و نام متمایز (موضوع) منحصربه‌فرد جهانی را در گواهینامه‌اش تنظیم کنید.

مشخصات فنی

الف. نمایه گواهینامه

درخواست‌ها باید با گواهینامه‌های استاندارد X.509 v3 که بااستفاده از P-256 / ECDSA تولید شده‌اند امضا شوند و حاوی افزونه سفارشی Google باشند:

  • شناسه شیء افزونه سفارشی: 1.3.6.1.4.1.11129.10.1
  • شدت: غیربحرانی.
  • محتوا: درهم‌سازی SHA256 از RelyingPartyMetadataBytes، کدبندی‌شده در ASN.1 OCTET STRING.

ب. طرحواره فراداده (CBOR)

فراداده باید در قالب CBOR کدبندی شود.

; in CDDL for CBOR encoding
; schemaVersion = "v1"

RelyingPartyMetadataBytes = #6.24(bstr .cbor RelyingPartyMetadata)


RelyingPartyMetadata = {
  "schema_version": tstr,
  "display": DisplayInfo,
  "aggregator_info": DisplayInfo  ; Optional: include to show your branding alongside the RP
}

DisplayInfo = {
  "display_name": tstr,
  "logo_uri": tstr,             ; See brand guidelines link in following paragraph
  "privacy_policy_uri": tstr
}

logo_uri باید از دستورالعمل‌های نمانام «کیف پول Google» پیروی کند.

پ. یکپارچه‌سازی OpenID4VP

هنگام قالب‌بندی درخواست گواهینامه OpenID4VP امضاشده، فراداده کدبندی‌شده base64url را در فیلد gw_rp_metadata_bytes در داخل شیء client_metadata (همان‌طور که در کد درخواست نمونه در بخش زیر نشان داده شده است) اضافه کنید.

رعایت استانداردها و ابطال

  • نظارت بر سوءاستفاده: Google فعالیت‌های مخرب RP را نظارت می‌کند و درصورت شناسایی هرگونه سوءاستفاده به شما اطلاع خواهد داد.
  • لغو فوری: ملزم هستید گواهینامه‌های «طرف‌های متکی» سوءاستفاده‌گر را فوراً لغو کنید و «فهرست لغو گواهینامه» (CRL) به‌روزشده را منتشر کنید.
  • حسابرسی: Google گزارش‌های ناشناس‌سازی‌شده‌ای را نگهداری می‌کند تا مطمئن شود درخواست‌های RP با موارد استفاده ثبت‌شده آن‌ها مطابقت دارد.

مراحل بعدی

برای شروع پذیرش به‌عنوان «ثبت‌کننده درستی‌سنجی»، فرم پذیرش ثبت‌کننده درستی‌سنجی را تکمیل و ارسال کنید. برای آماده‌سازی کارخواه‌های پایین‌دستی بعدی، از فرم آماده‌سازی کارخواه ثبت‌کننده درستی‌سنج استفاده کنید.

برای پرسشگان درباره آماده‌سازی و یکپارچه‌سازی، به پرسشگان هویت دیجیتال و اعتبارنامه‌ها مراجعه کنید.

جزئیات یکپارچه‌سازی ثبت‌کننده درستی‌سنج

بخش زیر جزئیات ادغام فنی «ثبت‌کنندگان درستی‌سنج» با «میانای برنامه‌سازی کاربردی اعتبارنامه‌های دیجیتال» (ازجمله قالب‌بندی درخواست، رمزگذاری درخواست، راه‌اندازی میانای برنامه‌سازی کاربردی، اعتبارسنجی پاسخ‌ها، و پیاده‌سازی «اثبات‌های بدون دانش») را پوشش می‌دهد.

قالب‌ها و قابلیت‌های پشتیبانی‌شده

«کیف پول Google» از «مدارک شناسایی دیجیتال» مبتنی بر ISO mdoc پشتیبانی می‌کند.

قالب‌بندی درخواست

برای درخواست اطلاعات اعتباری از هر کیف پولی، باید درخواستتان را بااستفاده از OpenID4VP قالب‌بندی کنید. می‌توانید اعتبارنامه‌های خاص یا اعتبارنامه‌های متعدد را در یک شیء dcql_query درخواست کنید.

نمونه درخواست JSON

در اینجا نمونه‌ای از درخواست mdoc requestJson برای دریافت اطلاعات اعتباری هویتی از هر کیف پولی در دستگاه Android یا وب آورده شده است.

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

درخواست رمزگذاری

client_metadata حاوی کلید عمومی رمزگذاری برای هر درخواست است. باید کلیدهای خصوصی را برای هر درخواست ذخیره کنید و از آن‌ها برای اصالت‌سنجی و مجوزدهی به نشان دریافتی از برنامه کیف پول استفاده کنید.

فراداده OpenID4VP یکپارچه

هنگام قالب‌بندی درخواست اطلاعات اعتباری، باید فیلد gw_rp_metadata_bytes را در داخل شیء client_metadata (همان‌طور که در کد درخواست نمونه زیر نشان داده شده است) اضافه کنید. این فیلد حاوی فراداده‌های طرف اعتماد با کدبندی Base64URL است که «کیف پول Google» برای درستی‌سنجی هویت شما و نمایش نمانام شما به کاربر به آن نیاز دارد.

پارامتر 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": {
          // 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» درخواست کنید.

درخواست‌های امضاشده

درخواست‌های امضاشده (درخواست‌های مجوز امن با JWT) درخواست ارائه قابل‌تأیید شما را در یک «رمز وب JSON» (JWT) با امضای رمزنگاری‌شده بااستفاده از زیرساخت PKI شما کپسوله می‌کند و تمامیت درخواست را تضمین می‌کند و هویت شما را به «کیف پول Google» اثبات می‌کند.

الزامی است

پیش‌نیازها

قبل‌از پیاده‌سازی تغییرات کد برای درخواست امضاشده، مطمئن شوید که موارد زیر را دارید:

  • کلید خصوصی: برای امضای درخواست که در سرورتان مدیریت می‌شود، به کلید خصوصی (مثلاً «منحنی بیضوی ES256») نیاز دارید.
  • گواهینامه: به گواهینامه استاندارد X.509 که از جفت کلید شما استخراج شده است نیاز دارید.
  • ثبت: مطمئن شوید گواهی عمومی‌تان در «کیف پول Google» ثبت شده باشد.

منطق ساخت درخواست

برای ساختن درخواست باید از کلید خصوصی خود استفاده کنید و محتوای پیام را در 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()

            # Create a URL-safe Base64 hash (removing padding '=')
            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
            # Format for android origin: origin = android:apk-key-hash:<base64SHA256_ofAppSigningCert>
            # Format for web origin: origin = <origin_url>
            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.
            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")
}

پیکربندی «مدیر اطلاعات اعتباری»

برای پیکربندی و مقداردهی اولیه کردن شیء CredentialManager، منطقی مشابه منطق زیر اضافه کنید:

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

درخواست شاخصه‌های «هویت»

برنامه به‌جای مشخص کردن پارامترهای جداگانه برای درخواست‌های هویت، همه آن‌ها را به‌صورت یک رشته JSON در CredentialOption ارائه می‌دهد. «مدیر اطلاعات اعتباری» این رشته 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 تعریف شده است. برنامه «کیف پول» مسئول ساختن این پاسخ است.

مثال:

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

این پاسخ را به سرور برمی‌گردانید تا اصالت آن را تأیید کند. می‌توانید مراحل تأیید پاسخ اعتبارنامه را پیدا کنید

وب

برای درخواست «اطلاعات اعتباری هویتی» بااستفاده از «میانای برنامه‌سازی کاربردی اعتبارنامه‌های دیجیتال» در Chrome یا مرورگرهای پشتیبانی‌شده دیگر، درخواست زیر را ارسال کنید.

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

پاسخ این api را برای اعتبارسنجی اطلاعات اعتباری پاسخ به سرورتان برگردانید

تأیید کردن پاسخ

وقتی کیف پول identityToken (JWT) رمزگذاری‌شده را برمی‌گرداند، باید قبل‌از اعتماد کردن به داده‌ها، اعتبارسنجی دقیق سمت سرور انجام دهید.

رمزگشایی کردن پاسخ

از کلید خصوصی مربوط به کلید عمومی ارسال‌شده در درخواست client_metadata برای رمزگشایی JWE استفاده کنید. این کار 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.
    }
  }
  1. ایجاد ترانویسی جلسه

    مرحله بعدی ایجاد SessionTranscript از ISO/IEC 18013-5:2021 با ساختار «واگذاری» ویژه Android یا «وب» است:

    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 اعتبارسنجی شود.

    این اعتبارسنجی شامل چندین مرحله است:

  2. بررسی گواهینامه صادرکننده: زنجیره گواهینامه امضای صادرکننده را از issuerAuth استخراج کنید و آن را دربرابر گواهینامه‌های ریشه مورداعتماد IACA اعتبارسنجی کنید. به گواهینامه‌های IACA صادرکننده پشتیبانی‌شده مراجعه کنید.

  3. درستی‌سنجی امضای MSO (بخش ۹.۱.۲ از ۱۸۰۱۳-۵)

  4. محاسبه و بررسی ValueDigests برای «عناصر داده» (18013-5 بخش 9.1.2)

  5. درستی‌سنجی امضای deviceSignature (بخش ۹.۱.۳ از 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
}

درستی‌سنجی سن با حفظ حریم خصوصی (ZKP)

برای پشتیبانی از «اثبات بدون دانش» (برای نمونه، تأیید اینکه کاربر بالای ۱۸ سال است بدون اینکه تاریخ تولد دقیق او را ببینید)، قالب درخواستتان را به mso_mdoc_zk تغییر دهید و پیکربندی zk_system_type موردنیاز را ارائه دهید.

برای نمای کلی سطح بالا از اینکه ZKP چیست و قابلیت‌های آن، به پرسشگان مراجعه کنید.

  ...
  "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 را که می‌خواهید به آن‌ها اعتماد کنید مدیریت کنید.

منابع و پشتیبانی