پذیرش آنلاین مدارک دیجیتال

شناسه‌های دیجیتال می‌توانند هم در جریان‌های درون برنامه‌ای و هم در جریان‌های وب پذیرفته شوند. برای پذیرش اعتبارنامه‌ها از Google Wallet، باید:

  1. با استفاده از برنامه یا وب و طبق دستورالعمل‌های ارائه شده، ادغام کنید.
  2. از شناسه آزمایشی برای آزمایش جریان خود با استفاده از جعبه شنی گوگل والت استفاده کنید.
  3. برای شروع به کار، این فرم را برای درخواست دسترسی و پذیرش شرایط خدمات اعتبارنامه Google Wallet پر کنید. شما ملزم به پر کردن این فرم برای هر یک از نهادهای تجاری خود هستید. تیم ما پس از پر کردن فرم با شما تماس خواهد گرفت.
  4. اگر سوالی دارید، می‌توانید با wallet-identity-rp-support@google.com تماس بگیرید.

قالب‌های اعتبارنامه پشتیبانی‌شده

چندین استاندارد پیشنهادی وجود دارد که قالب داده‌های اسناد هویت دیجیتال را تعریف می‌کنند، که دو مورد از آنها توجه زیادی را در صنعت به خود جلب کرده‌اند:

  1. mdocs - تعریف شده توسط ISO.
  2. اعتبارنامه‌های قابل تأیید w3c - تعریف شده توسط w3c.

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

اعتبارنامه‌های پشتیبانی‌شده

گوگل والت از دو نوع اعتبارنامه پشتیبانی می‌کند:

  1. گواهینامه رانندگی سیار (mDL)
  2. کارت شناسایی

شما می‌توانید با تغییر یک پارامتر، هر دو اعتبارنامه را در جریان خود درخواست کنید.

تجربه کاربری

این بخش در مورد جریان پیشنهادی ارائه آنلاین صحبت می‌کند. این جریان، ارائه سن به یک برنامه برای تحویل الکل را نشان می‌دهد، اما تجربه کاربری برای وب و سایر انواع ارائه مشابه است.

از کاربر خواسته می‌شود سن خود را در برنامه یا وب‌سایت تأیید کندکاربر اعتبارنامه‌های واجد شرایط موجود را می‌بیندکاربر صفحه تأیید را در Google Wallet مشاهده می‌کندکاربر برای تأیید اشتراک‌گذاری، احراز هویت می‌کندداده‌ها به برنامه یا وب‌سایت ارسال می‌شوند
از کاربر خواسته می‌شود سن خود را در برنامه یا وب‌سایت تأیید کند کاربر اعتبارنامه‌های واجد شرایط موجود را می‌بیند کاربر صفحه تأیید را در Google Wallet مشاهده می‌کند کاربر برای تأیید اشتراک‌گذاری، احراز هویت می‌کند داده‌ها به برنامه یا وب‌سایت ارسال می‌شوند

نکات کلیدی

  1. برنامه یا وب‌سایت در نحوه ایجاد نقطه ورود به API انعطاف‌پذیری دارد. همانطور که در مرحله 1 نشان داده شد، توصیه می‌کنیم یک دکمه عمومی مانند «تأیید با شناسه دیجیتال» را نمایش دهید، زیرا انتظار داریم در آینده گزینه‌هایی فراتر از Google Wallet از طریق API در دسترس باشند.
  2. صفحه انتخابگر در مرحله ۲ توسط اندروید رندر می‌شود. اعتبارنامه‌های واجد شرایط با تطابق بین منطق ثبت ارائه شده توسط هر کیف پول و درخواست ارسال شده توسط طرف اعتمادکننده تعیین می‌شوند.
  3. مرحله ۳ توسط گوگل والت رندر می‌شود. گوگل والت نام، لوگو و سیاست حفظ حریم خصوصی ارائه شده توسط توسعه‌دهنده را در این صفحه نمایش می‌دهد.

اضافه کردن یک جریان شناسه دیجیتال

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

از کاربر خواسته می‌شود سن خود را در برنامه یا وب‌سایت تأیید کندکاربر برای دریافت شناسه دیجیتال به کیف پول گوگل هدایت شد
از کاربر خواسته می‌شود سن خود را در برنامه یا وب‌سایت تأیید کند کاربر برای دریافت شناسه دیجیتال به کیف پول گوگل هدایت شد

هیچ شناسه دیجیتالی در دسترس نیست

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

از کاربر خواسته می‌شود سن خود را در برنامه یا وب‌سایت تأیید کندکاربر با خطایی مواجه شده است که نشان می‌دهد او شناسه دیجیتال ندارد.
از کاربر خواسته می‌شود سن خود را در برنامه یا وب‌سایت تأیید کند کاربر با خطایی مواجه شده است که نشان می‌دهد او شناسه دیجیتال ندارد.

این API از قابلیتی برای تشخیص مخفیانه‌ی وجود شناسه‌های دیجیتال کاربر به منظور حفظ حریم خصوصی او پشتیبانی نمی‌کند. از این رو، توصیه می‌کنیم گزینه‌ی لینک ورود به سیستم (onboarding link) را همانطور که نشان داده شده است، لحاظ کنید.

قالب درخواست برای درخواست اعتبارنامه‌های شناسایی از کیف پول

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

{
      "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 و idpass آمده است و کاربر می‌تواند با هر یک از آنها ادامه دهد.

{
  "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 Wallet درخواست کنید.

در برنامه

برای درخواست اعتبارنامه هویت از برنامه‌های اندروید خود، این مراحل را دنبال کنید:

به‌روزرسانی وابستگی‌ها

در فایل build.gradle پروژه خود، وابستگی‌های خود را برای استفاده از Credential Manager (نسخه بتا) به‌روزرسانی کنید:

dependencies {
    implementation("androidx.credentials:credentials:1.5.0-beta01")
    // optional - needed for credentials support from play services, for devices running Android 13 and below.
    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 ارائه می‌دهد. Credential Manager این رشته JSON را بدون بررسی محتویات آن، به کیف پول‌های دیجیتال موجود ارسال می‌کند. سپس هر کیف پول مسئول موارد زیر است: - تجزیه رشته JSON برای درک درخواست هویت. - تعیین اینکه کدام یک از اعتبارنامه‌های ذخیره شده در آن، در صورت وجود، درخواست را برآورده می‌کند.

ما به شرکا توصیه می‌کنیم که درخواست‌های خود را حتی برای ادغام برنامه‌های اندروید، روی سرور ایجاد کنند.

شما از requestJson از Request Format که شامل 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 تعریف شده است. برنامه Wallet مسئول ساخت این پاسخ است.

مثال:

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

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

وب

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

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

پاسخ این API را برای اعتبارسنجی پاسخ اعتبارنامه به سرور خود ارسال کنید.

مراحل اعتبارسنجی پاسخ اعتبارنامه

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

  1. رمزگشایی پاسخ با استفاده از کلید خصوصی

    اولین قدم رمزگشایی توکن با استفاده از کلید خصوصی ذخیره شده و دریافت پاسخ JSON است.

    مثال پایتون:

    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": "<credential_token>"
      }
    }
    
  2. متن جلسه را ایجاد کنید

    مرحله بعدی ایجاد SessionTranscript از ISO/IEC 18013-5:2021 با ساختار Handover مخصوص اندروید یا وب است:

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

    برای هر دو روش تحویل اندروید/وب، باید از همان nonce که برای تولید credential_request استفاده کردید، استفاده کنید.

    تحویل اندروید

        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) باید مطابق بند ۹ استاندارد 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
}

راه حل خود را آزمایش کنید

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

  • مخزن برنامه‌های مرجع را کلون کنید
  • پروژه را در اندروید استودیو باز کنید
  • هدف appholder را روی دستگاه اندروید یا شبیه‌ساز خود بسازید و اجرا کنید.

تأیید مبتنی بر اثبات دانش صفر (ZKP)

اثبات دانش صفر (ZKP) یک روش رمزنگاری است که به یک فرد (اثبات‌کننده) اجازه می‌دهد تا به یک تأییدکننده ثابت کند که دارای یک قطعه اطلاعات هویتی خاص است یا یک معیار خاص (مثلاً بالای ۱۸ سال سن دارد، دارای مدرک معتبر است) را بدون آشکار کردن داده‌های اصلی، برآورده می‌کند. اساساً، این روشی برای تأیید صحت یک جمله در مورد هویت فرد و در عین حال خصوصی نگه داشتن جزئیات حساس است.

سیستم‌های هویت دیجیتال که بر اشتراک‌گذاری مستقیم داده‌های هویتی متکی هستند، اغلب کاربران را ملزم به اشتراک‌گذاری اطلاعات شخصی بیش از حد می‌کنند که این امر خطر نقض داده‌ها و سرقت هویت را افزایش می‌دهد. اثبات دانش صفر (ZKP) با ارائه یک تغییر الگو، امکان تأیید هویت را با حداقل افشا فراهم می‌کند.

مفاهیم کلیدی اثبات دانش صفر در هویت دیجیتال:

  • اثبات‌کننده: فردی که سعی در اثبات جنبه‌ای از هویت خود دارد.
  • تأییدکننده: موجودیتی که درخواست اثبات یک ویژگی هویتی را دارد.
  • اثبات: یک پروتکل رمزنگاری که به اثبات‌کننده اجازه می‌دهد تا تأییدکننده را در مورد صحت ادعای خود متقاعد کند، بدون اینکه اطلاعات مخفی را فاش کند.

ویژگی‌های اصلی اثبات‌های دانش صفر:

  • کامل بودن: اگر گزاره درست باشد و هم اثبات‌کننده و هم تأییدکننده صادق باشند، تأییدکننده متقاعد خواهد شد.
  • صحت: اگر گزاره نادرست باشد، یک اثبات‌کننده‌ی نادرست نمی‌تواند (با احتمال بسیار بالا) یک تأییدکننده‌ی صادق را متقاعد کند که گزاره درست است.
  • دانش صفر: تأییدکننده چیزی فراتر از این واقعیت که گزاره درست است، نمی‌فهمد. هیچ داده واقعی از هویت اثبات‌کننده فاش نمی‌شود.

برای دریافت گواهی عدم سوء پیشینه از گوگل والت، باید فرمت درخواست را به 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": "bd3168ea0a9096b4f7b9b61d1c210dac1b7126a9ec40b8bc770d4d485efce4e9", // This will differ if you need more than 1 attribute.
          "num_attributes": 1, // number of attributes (in claims) this has can support
          "version": 3
        },
        {
          "system": "longfellow-libzk-v1",
          "circuit_hash": "89288b9aa69d2120d211618fcca8345deb4f85d2e710c220cc9c059bbee4c91f", // This will differ if you need more than 1 attribute.
          "num_attributes": 1, // number of attributes (in claims) this has can support
          "version": 4
        }
        {
          "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
        }
        {
          "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
        }
       ],
       "verifier_message": "challenge"
      },
     "claims": [{
         ...
      "client_metadata": {
        "jwks": {
          "keys": [ // sample request encryption key
            {
              ...

شما یک اثبات دانش صفر رمزگذاری شده از کیف پول دریافت خواهید کرد. می‌توانید این اثبات را با استفاده از کتابخانه longfellow-zk گوگل، در برابر گواهی‌های IACA صادرکنندگان اعتبارسنجی کنید.

سرویس تأییدکننده شامل یک سرور مبتنی بر داکر آماده برای استقرار است که به شما امکان می‌دهد پاسخ را در برابر برخی از گواهی‌های IACA صادرکننده اعتبارسنجی کنید.

شما می‌توانید certs.pem را برای مدیریت گواهی‌های صادرکننده IACA که می‌خواهید به آنها اعتماد کنید، تغییر دهید.

برای اطلاعات بیشتر می‌توانید با ایمیل پشتیبانی wallet-identity-rp-support@google.com تماس بگیرید.