Aceitação on-line de credenciais digitais

Os IDs digitais podem ser aceitos em fluxos no app e na Web. Para aceitar credenciais da Carteira do Google, você precisa:

  1. Faça a integração usando o app ou a Web seguindo as instruções fornecidas.
  2. Use o ID de teste para testar seu fluxo usando o sandbox da Carteira do Google.
  3. Para ativar, preencha este formulário para solicitar acesso e aceite os Termos de Serviço das credenciais da Carteira do Google. É necessário preencher esse formulário para cada uma das suas entidades comerciais. Nossa equipe vai entrar em contato com você depois que você preencher o formulário.
  4. Se tiver dúvidas, entre em contato comwallet-identity-rp-support@google.com.

Formatos de credenciais compatíveis

Existem vários padrões propostos que definem o formato de dados dos documentos de identidade digital, e dois deles estão ganhando muita força no setor:

  1. mdocs: definidos pela ISO.
  2. Credenciais verificáveis do W3C: definidas pelo W3C.

Embora o Gerenciador de credenciais do Android seja compatível com os dois formatos, a Carteira do Google só aceita IDs digitais baseados em mdoc no momento.

Credenciais aceitas

A Carteira do Google aceita dois tipos de credenciais:

  1. Carteira de habilitação para dispositivos móveis (mDL)
  2. Documento de identificação

É possível solicitar qualquer uma das credenciais no seu fluxo com uma única mudança de parâmetro.

Experiência do usuário

Esta seção fala sobre o fluxo recomendado de apresentação on-line. O fluxo mostra a apresentação da idade para um app de entrega de bebidas alcoólicas, mas a UX é semelhante para a Web e outros tipos de apresentações.

O usuário é solicitado a verificar a idade no app ou site O usuário vê as credenciais qualificadas disponíveis O usuário vê a página de confirmação na Carteira do Google O usuário faz a autenticação para confirmar o compartilhamento Dados enviados para o app ou site
O usuário é solicitado a verificar a idade no app ou site O usuário vê as credenciais qualificadas disponíveis O usuário vê a página de confirmação na Carteira do Google O usuário faz a autenticação para confirmar o compartilhamento Dados enviados para o app ou site

Observações importantes

  1. O app ou site tem flexibilidade na forma como cria o ponto de entrada para a API. Como mostrado na etapa 1, recomendamos exibir um botão genérico, como "Verificar com documento de identificação digital", já que esperamos que opções além da Carteira do Google estejam disponíveis na API com o tempo.
  2. A tela do seletor na etapa 2 é renderizada pelo Android. As credenciais qualificadas são determinadas por uma correspondência entre a lógica de registro fornecida por cada carteira e a solicitação enviada pela parte confiante.
  3. A etapa 3 é renderizada pela Carteira do Google. A Carteira do Google vai mostrar o nome, o logotipo e a Política de Privacidade que o desenvolvedor fornecer nessa tela.

Adicionar um fluxo de documento de identificação digital

Se o usuário não tiver uma credencial, recomendamos fornecer um link ao lado do botão "Verificar com documento de identificação digital", que fará um link direto para a Carteira do Google para permitir que o usuário adicione um documento de identificação digital.

O usuário é solicitado a verificar a idade no app ou site O usuário é direcionado para a Carteira do Google para receber um documento de identificação digital.
O usuário é solicitado a verificar a idade no app ou site O usuário é direcionado para a Carteira do Google para receber um documento de identificação digital.

Nenhum documento de identificação digital disponível

Se o usuário selecionar a opção "Verificar com ID digital" sem ter um ID digital, esta mensagem de erro será exibida.

O usuário é solicitado a verificar a idade no app ou site Um erro é mostrado ao usuário se ele não tiver um documento de identificação digital
O usuário é solicitado a verificar a idade no app ou site Um erro é mostrado ao usuário se ele não tiver um documento de identificação digital

A API não oferece suporte a um recurso para saber silenciosamente se o usuário tem alguma identidade digital disponível para preservar a privacidade dele. Por isso, recomendamos incluir a opção de link de integração, conforme mostrado.

Formato da solicitação para pedir credenciais de ID da carteira

Confira um exemplo de solicitação de mdoc requestJson para receber credenciais de identidade de qualquer carteira em um dispositivo Android ou na Web.

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

Solicitar criptografia

O client_metadata contém a chave pública de criptografia para cada solicitação. Você precisa armazenar chaves privadas para cada solicitação e usá-las para autenticar e autorizar o token recebido do app Carteira.

O parâmetro credential_request em requestJson consistiria nos seguintes campos.

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

Você pode solicitar qualquer número de atributos compatíveis de qualquer credencial de identidade armazenada na Carteira do Google.

No app

Para solicitar credenciais de identidade dos seus apps Android, siga estas etapas:

Atualizar dependências

No build.gradle do projeto, atualize as dependências para usar o Gerenciador de credenciais (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")
}

Configurar o Gerenciador de credenciais

Para configurar e inicializar um objeto CredentialManager, adicione uma lógica parecida com esta:

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

Solicitar atributos de identidade

Em vez de especificar parâmetros individuais para solicitações de identidade, o app fornece todos eles juntos como uma string JSON dentro do CredentialOption. O Credential Manager transmite essa string JSON para as carteiras digitais disponíveis sem examinar o conteúdo dela. Cada carteira é responsável por: - Analisar a string JSON para entender a solicitação de identidade. - Determinar quais das credenciais armazenadas, se houver, atendem à solicitação.

Recomendamos que os parceiros criem as solicitações no servidor, mesmo para integrações de apps Android.

você vai usar o requestJson do Formato da solicitação que consiste no request na chamada de função 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)
    }
}

Verificar e validar a resposta

Depois de receber uma resposta da carteira, verifique se ela foi bem-sucedida e contém a resposta 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}")
    }
}

A resposta credentialJson contém um identityToken (JWT) criptografado, definido pelo W3C. O app Carteira é responsável por criar essa resposta.

Exemplo:

{
  "protocol" : "openid4vp",
  "data" : {
    <encrpted_response>
  }
}

Você vai transmitir essa resposta de volta ao servidor para validar a autenticidade dela. Confira as etapas para validar a resposta da credencial.

Web

Para solicitar credenciais de identidade usando a API Digital Credentials no Chrome, é necessário se inscrever no teste de origem da API Digital Credentials.

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

Envie a resposta dessa API de volta ao servidor para validar a resposta de credencial.

Etapas para validar a resposta da credencial

Ao receber o identityToken criptografado do seu app ou site, você precisa realizar várias validações antes de confiar na resposta.

  1. Descriptografar a resposta usando a chave privada

    A primeira etapa é descriptografar o token usando a chave privada salva e receber um JSON de resposta.

    Exemplo em 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 vai resultar em um JSON vp_token que contém a credencial

    {
      "vp_token":
      {
        "cred1": "<credential_token>"
      }
    }
    
  2. Criar a transcrição da sessão

    A próxima etapa é criar o SessionTranscript da ISO/IEC 18013-5:2021 com uma estrutura de transferência específica para Android ou Web:

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

    Para transferências no Android e na Web, use o mesmo nonce que você usou para gerar credential_request.

    Transferência do Android

        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()
        

    Transferência de navegador

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

    Usando o SessionTranscript, o DeviceResponse precisa ser validado de acordo com a cláusula 9 da norma ISO/IEC 18013-5:2021. Isso inclui várias etapas, como:

  3. Verificar o certificado do emissor do estado. Confira os certificados IACA dos emissores aceitos.

  4. Verificar assinatura da MSO (seção 9.1.2 da norma 18013-5)

  5. Calcular e verificar ValueDigests para elementos de dados (seção 9.1.2 da norma 18013-5)

  6. Verificar a assinatura deviceSignature (18013-5, seção 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
}

Testar a solução

Para testar sua solução, crie e execute o app Android detentor da referência de código aberto. Confira abaixo as etapas para criar e executar o app detentor de referência:

  • Clone o repositório dos apps de referência.
  • Abra o projeto no Android Studio.
  • Crie e execute o rótulo appholder no dispositivo ou emulador Android.

Verificação com base em prova de conhecimento zero (ZKP, na sigla em inglês)

A prova de conhecimento zero (ZKP) é um método criptográfico que permite que um indivíduo (o provador) demonstre a um verificador que ele possui uma determinada informação de identidade ou atende a um critério específico (por exemplo, tem mais de 18 anos, possui uma credencial válida) sem revelar os dados reais. Basicamente, é uma maneira de confirmar a veracidade de uma declaração sobre a identidade de alguém mantendo os detalhes sensíveis em sigilo.

Os sistemas de identidade digital que dependem do compartilhamento direto de dados de identidade geralmente exigem que os usuários compartilhem informações pessoais em excesso, aumentando o risco de violações de dados e roubo de identidade. As ZKPs oferecem uma mudança de paradigma, permitindo a verificação com divulgação mínima.

Principais conceitos de ZKPs em identidade digital:

  • Proponente: o indivíduo que tenta provar um aspecto da própria identidade.
  • Verificador: a entidade que solicita comprovação de um atributo de identidade.
  • A prova: um protocolo criptográfico que permite ao provador convencer o verificador da veracidade da declaração sem revelar as informações secretas.

Propriedades principais das provas de conhecimento zero:

  • Completude: se a declaração for verdadeira e o provador e o verificador forem honestos, o verificador será convencido.
  • Solidez: se a declaração for falsa, um provador desonesto não poderá (com probabilidade muito alta) convencer um verificador honesto de que ela é verdadeira.
  • Conhecimento zero: o verificador não aprende nada além do fato de que a declaração é verdadeira. Nenhum dado real da identidade do provador é exposto.

Para receber uma prova de conhecimento zero da Carteira do Google, mude o formato da solicitação para mso_mdoc_zk e adicione zk_system_type à sua Solicitação

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

Você vai receber uma prova de conhecimento zero criptografada da carteira. É possível validar essa prova em relação aos certificados IACA dos emissores usando a biblioteca longfellow-zk do Google. Entre em contato com o e-mail de suporte para mais detalhes wallet-identity-rp-support@google.com