Онлайн-прием цифровых учетных данных

Цифровые удостоверения личности принимаются как в приложении , так и на сайте . Чтобы принять учётные данные из Google Wallet, вам необходимо:

  1. Выполните интеграцию с помощью приложения или веб-сайта, следуя предоставленным инструкциям.
  2. Используйте тестовый идентификатор для проверки вашего потока с помощью песочницы Google Wallet.
  3. Чтобы начать работу, заполните эту форму , чтобы запросить доступ и принять условия использования учётных данных Google Кошелька. Вам необходимо заполнить её для каждой вашей компании. Наша команда свяжется с вами после заполнения формы.
  4. Если у вас возникнут вопросы, вы можете обратиться по адресу wallet-identity-rp-support@google.com .

Поддерживаемые форматы учетных данных

Существует несколько предложенных стандартов, определяющих формат данных цифровых документов, удостоверяющих личность, два из которых получили значительную поддержку в отрасли:

  1. mdocs — определено ISO.
  2. Проверяемые учетные данные w3c — определены w3c.

В то время как Android Credential Manager поддерживает оба формата, Google Wallet на данный момент поддерживает только цифровые идентификаторы на основе mdoc.

Поддерживаемые учетные данные

Google Wallet поддерживает 2 типа учетных данных:

  1. Мобильные водительские права (mDL)
  2. удостоверение личности

Вы можете запросить любые учетные данные в своем потоке, изменив всего один параметр.

Пользовательский опыт

В этом разделе рассматривается рекомендуемый алгоритм онлайн-презентации. Он демонстрирует презентацию возраста в приложении для доставки алкоголя, но UX-дизайн аналогичен как для веб-сайтов, так и для других типов презентаций.

Пользователю предлагается подтвердить возраст в приложении или на сайтеПользователь видит доступные подходящие учетные данныеПользователь видит страницу подтверждения в Google WalletПользователь проходит аутентификацию для подтверждения совместного использованияДанные отправляются в приложение или на веб-сайт
Пользователю предлагается подтвердить возраст в приложении или на сайте Пользователь видит доступные подходящие учетные данные Пользователь видит страницу подтверждения в Google Wallet Пользователь проходит аутентификацию для подтверждения совместного использования Данные отправляются в приложение или на веб-сайт

Ключевые примечания

  1. Приложение или веб-сайт могут гибко создавать точку входа в API. Как показано в шаге 1, мы рекомендуем отображать стандартную кнопку, например «Подтвердить с помощью цифрового удостоверения», поскольку со временем мы ожидаем, что через API будут доступны и другие функции, помимо Google Wallet.
  2. Экран выбора на шаге 2 отображается на Android. Допустимые учетные данные определяются путем сопоставления логики регистрации, предоставленной каждым кошельком, и запроса, отправленного проверяющей стороной.
  3. Шаг 3 отображается в Google Wallet. На этом экране Google Wallet отобразит название, логотип и политику конфиденциальности разработчика.

Добавить поток цифрового удостоверения личности

Если у пользователя нет учетных данных, мы рекомендуем предоставить ссылку рядом с кнопкой «Подтвердить с помощью цифрового удостоверения», которая будет вести на Google Wallet, где пользователь сможет добавить цифровое удостоверение.

Пользователю предлагается подтвердить возраст в приложении или на сайтеПользователь перенаправлен в Google Wallet для получения цифрового идентификатора.
Пользователю предлагается подтвердить возраст в приложении или на сайте Пользователь перенаправлен в Google Wallet для получения цифрового идентификатора.

Цифровой идентификатор недоступен.

Если пользователь выберет опцию «Подтвердить с помощью цифрового удостоверения», не имея цифрового удостоверения, ему будет показано это сообщение об ошибке.

Пользователю предлагается подтвердить возраст в приложении или на сайтеПользователю отображается ошибка, если у него нет цифрового идентификатора.
Пользователю предлагается подтвердить возраст в приложении или на сайте Пользователю отображается ошибка, если у него нет цифрового идентификатора.

API не поддерживает функцию скрытого определения наличия у пользователя доступных цифровых идентификаторов для сохранения его конфиденциальности. Поэтому мы рекомендуем включить опцию ссылки для регистрации, как показано ниже.

Формат запроса для запроса идентификационных данных из кошелька

Ниже приведен пример запроса mdoc requestJson для получения учетных данных Identity из любого кошелька на устройстве Android или в Интернете.

{
      "requests" : [
        {
          "protocol": "openid4vp",
          "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",
  "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",
          "alg" : "ECDH-ES",
        }
      ]
    },
    "authorization_encrypted_response_alg": "ECDH-ES",
    "authorization_encrypted_response_enc": "A128GCM"
  }
}

Вы можете запросить любое количество поддерживаемых атрибутов из любых учетных данных, хранящихся в Google Wallet.

В приложении

Чтобы запросить идентификационные данные из приложений Android, выполните следующие действия:

Обновление зависимостей

В файле build.gradle вашего проекта обновите зависимости для использования Credential Manager (beta):

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. Диспетчер учётных данных передаёт эту JSON-строку доступным цифровым кошелькам, не проверяя её содержимое. Каждый кошелёк отвечает за: - анализ JSON-строки для понимания запроса на идентификацию; - определение того, какие из сохранённых учётных данных, если таковые имеются, удовлетворяют запросу.

Мы рекомендуем партнерам создавать свои запросы на сервере даже для интеграции приложений Android.

вы будете использовать 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",
  "data" : {
    <encrpted_response>
  }
}

Вы передадите этот ответ обратно на сервер для проверки его подлинности. Инструкции по проверке ответа с учётными данными см . здесь.

Интернет

Чтобы запросить идентификационные данные с помощью API цифровых учетных данных в Chrome, вам необходимо зарегистрироваться для участия в пробной версии API цифровых учетных данных.

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

Отправьте ответ этого API обратно на ваш сервер для проверки ответа на учетные данные.

Действия по проверке ответа на учетные данные

Получив зашифрованный 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)
    
    # 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 со структурой передачи данных, специфичной для Android или веб-приложений:

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

    Для обеих передач Android/web вам нужно будет использовать тот же одноразовый номер, который вы использовали для генерации credential_request .

    Android Handover

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

    Передача браузера

        BrowserHandoverData =[
          origin,               // Origin URL
          clientId,             // "web-origin:<origin>"
          nonce,               //  nonce that was used to generate credential request
        ]
    
        BrowserHandoverDataBytes = hashlib.sha256(cbor2.dumps(BrowserHandoverData)).digest()
        

    Используя SessionTranscript , DeviceResponse должен быть проверен в соответствии с пунктом 9 стандарта ISO/IEC 18013-5:2021. Это включает в себя несколько шагов, таких как:

  3. Проверьте сертификат эмитента штата. Проверьте сертификаты IACA поддерживаемого эмитента.

  4. Проверка подписи MSO (18013-5 Раздел 9.1.2)

  5. Вычислите и проверьте ValueDigests для элементов данных (18013-5 Раздел 9.1.2)

  6. Проверка подписи deviceSignature (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
}

Проверьте свое решение

Чтобы протестировать свое решение, соберите и запустите наше приложение-держатель ссылок с открытым исходным кодом для Android . Вот шаги для сборки и запуска приложения-держателя ссылок:

  • Клонировать репозиторий эталонных приложений
  • Откройте проект в Android Studio.
  • Создайте и запустите целевой объект appholder на вашем Android-устройстве или эмуляторе.

Проверка на основе доказательства нулевого разглашения (ZKP)

Доказательство с нулевым разглашением (ZKP) — это криптографический метод, позволяющий человеку (доказывающей стороне) доказать проверяющей стороне, что он обладает определённой информацией, подтверждающей его личность, или соответствует определённому критерию (например, достиг 18 лет, имеет действительные учётные данные), не раскрывая при этом сами данные. По сути, это способ подтвердить истинность заявления о своей личности, сохраняя конфиденциальность конфиденциальной информации.

Системы цифровой идентификации, основанные на прямом обмене идентификационными данными, часто требуют от пользователей предоставления чрезмерного объема личной информации, что повышает риск утечек данных и кражи личных данных. ZKP предлагают смену парадигмы, позволяя проводить верификацию с минимальным раскрытием информации.

Ключевые концепции ZKP в цифровой идентичности:

  • Доказывающий: Человек, пытающийся доказать какой-либо аспект своей личности.
  • Проверяющий: субъект, запрашивающий подтверждение атрибута идентичности.
  • Доказательство: криптографический протокол, который позволяет доказывающей стороне убедить проверяющую сторону в истинности своего утверждения, не раскрывая секретную информацию.

Основные свойства доказательств с нулевым разглашением:

  • Полнота: Если утверждение истинно и оба, и доказывающий, и проверяющий, честны, то проверяющий будет убежден.
  • Обоснованность: Если утверждение ложно, то нечестный доказывающий не сможет (с очень высокой вероятностью) убедить честного проверяющего в его истинности.
  • Нулевое разглашение: проверяющая сторона не узнает ничего, кроме того факта, что утверждение истинно. Никакие фактические данные о личности доказывающей стороны не раскрываются.

Чтобы получить доказательство нулевого разглашения от Google Wallet, вам необходимо изменить формат запроса на 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
        }
       ],
       "verifier_message": "challenge"
      },
     "claims": [{
         ...
      "client_metadata": {
        "jwks": {
          "keys": [ // sample request encryption key
            {
              ...

Вы получите зашифрованное доказательство с нулевым разглашением из кошелька. Вы можете проверить это доказательство с помощью сертификатов IACA эмитентов, используя библиотеку longfellow-zk от Google. Для получения дополнительной информации обратитесь в службу поддержки по адресу wallet-identity-rp-support@google.com