Aceitação presencial de qualificações digitais (off-line)

Neste guia, explicamos como as partes confiáveis (RPs, na sigla em inglês) e os desenvolvedores de leitores podem implementar a verificação presencial (off-line) de credenciais digitais apresentadas na Carteira do Google de acordo com o padrão internacional ISO/IEC 18013-5.

As credenciais digitais na Carteira do Google podem ser verificadas com segurança em ambientes físicos (como terminais de ponto de venda, locais de eventos, catracas de transporte público, leitores de órgãos de segurança pública e apps de leitura para dispositivos móveis) sem precisar de uma conexão de internet ativa no momento da apresentação.

Visão geral da apresentação off-line (ISO/IEC 18013-5)

A norma ISO/IEC 18013-5 define um protocolo padronizado e interoperável para apresentação off-line entre um Titular (o dispositivo móvel do usuário com a Carteira do Google) e um Leitor / Verificador (um terminal físico ou app complementar para dispositivos móveis).

O fluxo de apresentação ocorre em fases distintas:

  1. Interação com o dispositivo:o leitor e a carteira estabelecem o contato inicial por toque NFC (transferência estática ou negociada) ou leitura de QR code. Durante essa fase, os metadados de engajamento do dispositivo e a chave pública temporária do leitor (EReaderKey) são trocados.
  2. Conexão de transporte de dados:um canal seguro e criptografado de Bluetooth de baixa energia (BLE) é negociado (com o leitor atuando no modo de cliente central ou servidor periférico).
  3. Solicitação do dispositivo:o leitor transmite um DeviceRequest codificado em CBOR especificando o tipo de documento solicitado (como org.iso.18013.5.1.mDL) e os namespaces e elementos de dados específicos solicitados.
  4. Consentimento do usuário e autenticação do dispositivo:a Carteira do Google pede que o usuário revise os elementos de dados solicitados e confirme o compartilhamento usando a autenticação biométrica ou o bloqueio de tela.
  5. Resposta do dispositivo e verificação criptográfica:a carteira envia de volta um DeviceResponse codificado em CBOR que contém o objeto de segurança para dispositivos móveis (MSO, na sigla em inglês) assinado e os elementos de dados assinados pelo dispositivo. O leitor verifica as assinaturas criptográficas em relação aos certificados raiz confiáveis.

SDK de código aberto Multipaz

Para implementar um aplicativo de leitor ou verificador, o Google recomenda o uso do Multipaz, um SDK de código aberto do Kotlin Multiplatform (KMP) desenvolvido originalmente pelo Google e contribuído para a OpenWallet Foundation (OWF).

O Multipaz oferece uma implementação pronta para produção de protocolos de leitor e carteira ISO/IEC 18013-5, pipelines de verificação criptográfica, codificação/decodificação CBOR e esquemas de tipo de documento extensíveis.

Como integrar o Multipaz ao seu app de leitura

As etapas a seguir demonstram como integrar o SDK do Multipaz a um aplicativo de leitura do Android.

Etapa 1: adicionar dependências

As bibliotecas Multipaz são publicadas no Maven Central. Adicione os módulos necessários ao arquivo build.gradle.kts do aplicativo:

// build.gradle.kts
dependencies {
    // Core Multipaz library (protocol engine, CBOR, crypto)
    implementation("org.multipaz:multipaz:0.100.0")

    // Android-specific platform bindings (NFC, BLE, Keystore)
    implementation("org.multipaz:multipaz-android:0.100.0")

    // Standardized document types (mDL, EU PID, etc.)
    implementation("org.multipaz:multipaz-doctypes:0.100.0")
}

Etapa 2: configurar as permissões do Android

A verificação presencial exige permissões de hardware para interação com NFC, leitura de câmera (para interação com QR) e transporte de dados por Bluetooth de baixa energia. Adicione as seguintes permissões ao AndroidManifest.xml:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- NFC Engagement -->
    <uses-permission android:name="android.permission.NFC" />
    <uses-feature android:name="android.hardware.nfc" android:required="false" />

    <!-- Camera for QR Code Engagement -->
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-feature android:name="android.hardware.camera" android:required="false" />

    <!-- Bluetooth Low Energy Transport (Android 12+) -->
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN"
                     android:usesPermissionFlags="neverForLocation" />
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />

    <!-- Legacy Bluetooth Permissions for Android 11 and lower -->
    <uses-permission android:name="android.permission.BLUETOOTH"
                     android:maxSdkVersion="30" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
                     android:maxSdkVersion="30" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
                     android:maxSdkVersion="30" />
</manifest>

Etapa 3: inicializar o mecanismo de verificação

Use as abstrações de conexão VerificationHelper ou Reader do Multipaz para processar eventos de engajamento e gerenciar o ciclo de vida da comunicação BLE:

import org.multipaz.verification.VerificationHelper
import org.multipaz.cbor.Cbor
import org.multipaz.crypto.Crypto

class ReaderManager(private val context: android.content.Context) {

    private var verificationHelper: VerificationHelper? = null

    fun startListeningForEngagement() {
        verificationHelper = VerificationHelper.Builder(
            context = context,
            listener = object : VerificationHelper.Listener {
                override fun onDeviceConnected() {
                    // BLE channel established, send request
                    sendDeviceRequest()
                }

                override fun onResponseReceived(deviceResponseBytes: ByteArray) {
                    // Process and verify the received credential payload
                    handleDeviceResponse(deviceResponseBytes)
                }

                override fun onError(error: Throwable) {
                    // Handle transport or protocol errors
                }

                override fun onDeviceDisconnected(transportTransportSpecificTermination: Boolean) {
                    // Connection closed
                }
            }
        ).build()
    }
}

Etapa 4: criar o DeviceRequest

Especifique o tipo de documento e os elementos de dados individuais que seu aplicativo precisa verificar. Sempre aplique o princípio de divulgação mínima (por exemplo, solicitar apenas age_over_21 em vez de birth_date completo ao verificar a idade):

fun sendDeviceRequest() {
    // Specify the DocType and requested elements
    val docType = "org.iso.18013.5.1.mDL"
    val namespace = "org.iso.18013.5.1"

    // Map of requested elements: elementName -> intentToRetain
    val requestedElements = mapOf(
        "family_name" to false,
        "given_name" to false,
        "age_over_21" to false,
        "portrait" to false,
        "driving_privileges" to false
    )

    // Build ISO/IEC 18013-5 DeviceRequest structure
    val deviceRequestBytes = verificationHelper?.buildDeviceRequest(
        docType = docType,
        itemsToRequest = mapOf(namespace to requestedElements)
    )

    if (deviceRequestBytes != null) {
        verificationHelper?.sendDeviceRequest(deviceRequestBytes)
    }
}

Suporte a outros tipos de documentos (DocTypes)

O Multipaz oferece suporte a credenciais padronizadas prontas para uso e uma arquitetura extensível para solicitar tipos de documentos personalizados ou específicos de um domínio.

1. Tipos de documentos padrão integrados

A biblioteca multipaz-doctypes fornece modelos de esquema predefinidos para credenciais padrão:

Identificador do tipo de documento Padrão / Escopo Namespace típico Elementos comuns
org.iso.18013.5.1.mDL Carteira de habilitação para dispositivos móveis ISO/IEC 18013-5 org.iso.18013.5.1 family_name, given_name, birth_date, issue_date, expiry_date, issuing_authority, document_number, portrait, driving_privileges, age_over_18, age_over_21
eu.europa.ec.eudi.pid.1 Dados de identificação pessoal da Carteira de Identidade Digital da UE (EUDIW, na sigla em inglês) eu.europa.ec.eudi.pid.1 family_name, first_name, birth_date, nationality, issuing_country, issuing_authority, personal_administrative_number
com.google.wallet.idcard.1 Passe de identificação / IDs de teste da Carteira do Google com.google.wallet.idcard.1 given_name, family_name, birth_date, document_number, portrait

2. Como solicitar tipos de documentos personalizados

Para solicitar tipos de documentos personalizados, defina a string docType de destino e os mapeamentos de namespace correspondentes ao criar o DeviceRequest:

// Example: Requesting a custom event ticket credential
val customDocType = "com.example.events.ticket"
val customNamespace = "com.example.events.ticket.1"

val customRequestedItems = mapOf(
    "ticket_id" to false,
    "event_name" to false,
    "seat_section" to false,
    "vip_access" to false
)

val multiDocRequestBytes = verificationHelper?.buildMultiDocDeviceRequest(
    documents = listOf(
        DocumentRequest(
            docType = customDocType,
            namespaces = mapOf(customNamespace to customRequestedItems)
        )
    )
)

Verificação criptográfica e gerenciamento de confiança

Receber um payload de resposta é apenas a primeira etapa. Os leitores precisam realizar uma verificação criptográfica em quatro etapas para validar a autenticidade e a integridade da credencial apresentada.

Etapa de verificação Destino da verificação
1. Autenticação do emissor Verificar IssuerAuth (COSE_Sign1) em relação aos certificados raiz confiáveis da IACA
2. Verificação do período de validade Verifique se validFrom ≤ horário atual ≤ validUntil
3. Verificação de integridade de dados Calcular resumos SHA-256 de elementos retornados e comparar com o MSO ValueDigests
4. Autenticação do dispositivo Verificar a assinatura ou o MAC de DeviceSigned usando o DeviceKey vinculado ao SessionTranscript

1. O pipeline de verificação em quatro etapas

  1. Autenticação do emissor (IssuerAuth):
    • O objeto de segurança móvel (MSO, na sigla em inglês) é assinado pela autoridade emissora (payload IssuerAuth).
    • O leitor verifica a assinatura de COSE_Sign1 usando o certificado do assinante do documento e garante que as cadeias de certificados cheguem até um certificado raiz confiável da autoridade de certificação emissora (IACA, na sigla em inglês).
  2. Verificação da janela de validade:
    • O leitor verifica os carimbos de data/hora validityInfo.validFrom e validityInfo.validUntil no MSO em relação ao relógio atual do leitor para garantir que a credencial não tenha expirado.
  3. Verificação de integridade de dados (ValueDigests):
    • Para cada IssuerSignedItem recebido, o leitor calcula o resumo (por exemplo, SHA-256) e verifica se ele corresponde à entrada de hash correspondente no dicionário ValueDigests do MSO.
  4. Autenticação do dispositivo (DeviceSigned):
    • O leitor valida se o dispositivo que apresenta a credencial tem a chave privada correspondente ao DeviceKey publicado no MSO assinado.
    • Isso é feito verificando o DeviceAuth (DeviceSignature ou DeviceMac) no SessionTranscript, vinculando a sessão à chave temporária do leitor e impedindo ataques de repetição e de interceptação.

2. Gerenciar certificados raiz confiáveis da IACA

Os leitores de produção precisam manter um repositório de confiança local e seguro com certificados raiz confiáveis da IACA:

  • Certificados IACA de produção:faça o download e configure certificados raiz de autoridades emissoras oficiais. Consulte nossa lista de emissores compatíveis e certificados da IACA.
  • AAMVA VICAL:para jurisdições dos EUA, os sistemas de leitura podem ser integrados ao serviço de Lista de Autoridades de Certificação de Emissores Verificados (VICAL, na sigla em inglês) da Associação Americana de Administradores de Veículos Automotores (AAMVA, na sigla em inglês) para sincronizar automaticamente as âncoras de confiança estaduais.
  • Raízes de teste do sandbox:ao testar com credenciais de sandbox, verifique se o leitor confia na raiz da IACA do sandbox do Google.
import org.multipaz.crypto.X509Cert

// Configure trusted IACA certificates in the trust store
val trustedCertificates = mutableListOf<X509Cert>()

// Add official state IACA certificates
trustedCertificates.add(X509Cert.fromPem(sampleStateIacaPem))

// Add Google Sandbox IACA root certificate for testing
trustedCertificates.add(X509Cert.fromPem(googleSandboxIacaPem))

val verifier = MultipazVerifier(trustStore = trustedCertificates)
val verificationResult = verifier.verify(deviceResponseBytes, sessionTranscript)

if (verificationResult.isIssuerAuthorized && verificationResult.isDeviceAuthenticated) {
    // Credential is valid and authentic
} else {
    // Reject presentation: cryptographic validation failed
}

Autenticação do leitor (recomendado)

A autenticação do leitor permite que o aplicativo leitor comprove criptograficamente a identidade dele para a Carteira do Google assinando a estrutura ReaderAuthentication com um certificado de leitor X.509 autorizado.

  • Por que é recomendado:a autenticação do leitor permite que o app ou terminal de leitura apresente uma identidade confiável ao usuário. Embora seja opcional para atributos públicos básicos (por exemplo, verificar age_over_21), é altamente recomendável que as integrações de leitor aumentem a confiança do usuário. Além disso, pode ser exigido por lei ou política ao solicitar atributos sensíveis (como CPF ou CNPJ completo, endereço residencial ou endossos estaduais específicos).
  • Como funciona:o leitor inclui a cadeia de certificados e assina a transcrição da sessão. A Carteira do Google mostra a identidade verificada e o nome da organização do leitor ao usuário na tela de permissão antes da liberação dos dados.

Ferramentas para desenvolvedores e de teste

Para acelerar a integração, use as seguintes ferramentas para desenvolvedores e implementações de referência:

  1. Apps de referência do Multipaz:
    • Clone o repositório Multipaz e execute o app de exemplo do Android IdentityReader para testar os fluxos de verificação física.
  2. Crie um documento de identificação de teste na Carteira do Google:
  3. Teste do Verificador baseado na Web:
    • Use verifier.multipaz.org para inspecionar solicitações CBOR, analisar consultas de declaração e testar apresentações baseadas na Web do W3C / ISO 18013-7.

Solução de problemas e diagnósticos de campo

A tabela a seguir lista problemas comuns encontrados durante a verificação off-line e as soluções recomendadas:

Problema / sintoma Causa principal Resolução recomendada
Tempo limite de conexão BLE / Falha ao conectar
  • Interferência de RF em ambientes de alta densidade.
  • Incompatibilidade entre o modo periférico e o central em hardware de leitor específico.
  • Verificação de tempos limite.
  • Verifique se o leitor é compatível com os modos de cliente central e servidor periférico do BLE.
  • Ajuste a janela e o intervalo de verificação de BLE para uma verificação agressiva durante o engajamento ativo.
  • Verifique se a negociação do tamanho da MTU foi concluída.
O engajamento por toque NFC falha ou cai O usuário afasta o dispositivo móvel da antena do leitor antes que o registro de transferência de BLE seja totalmente transferido.
  • Forneça feedback visual/auditivo/tátil imediato no terminal assim que o engajamento NFC começar.
  • Oriente os usuários a manter o smartphone firme contra o alvo NFC até que a conexão BLE seja estabelecida.
UNTRUSTED_ISSUER / Falha na cadeia de certificados O certificado do signatário do documento não está vinculado a nenhum certificado IACA confiável no repositório de confiança local do leitor.
  • Verifique se o certificado raiz do emissor está carregado no repositório de confiança do leitor.
  • Se estiver testando no sandbox, verifique se a raiz da IACA do sandbox do Google está carregada.
  • Verifique se as listas de certificados da IACA (por exemplo, VICAL da AAMVA) são atualizadas periodicamente.
INVALID_VALIDITY_INFO / MSO expirado
  • O relógio do sistema do leitor está fora de sincronia.
  • A assinatura do MSO expirou.
  • Verifique se o dispositivo leitor sincroniza o horário do sistema regularmente via NTP.
  • Peça ao usuário para abrir a Carteira do Google enquanto estiver conectado à Internet para atualizar os tokens de credencial.
DEVICE_AUTHENTICATION_FAILED Incompatibilidade de transcrição de sessão entre o leitor e a carteira ou assinatura de dispositivo temporária inválida.
  • Verifique se os bytes brutos exatos de DeviceEngagementBytes e EReaderKeyBytes são preservados na estrutura SessionTranscript sem recodificação.
Falha de permissão do Android 12 ou mais recente O aplicativo tentou verificar ou anunciar por BLE sem permissões de execução.
  • Verifique e solicite BLUETOOTH_SCAN, BLUETOOTH_CONNECT e BLUETOOTH_ADVERTISE no momento da execução antes de iniciar as sessões do leitor.

Diretrizes de UX e privacidade para leitores presenciais

Ao projetar leitores físicos e apps complementares:

  • Pratique a divulgação seletiva na interface:mostre apenas a decisão ou o atributo mínimo necessário ao operador (por exemplo, mostre uma marca de seleção verde em destaque e "Idade maior que 21 anos verificada" em vez de mostrar a data de nascimento completa, o endereço e o número da carteira de habilitação do usuário).
  • Indicadores claros de interação física:identifique claramente a zona de destino da NFC e mostre dicas visuais (como animações ou barras de progresso) mostrando cada etapa: Toque / Leitura → Conectando → Verificando → Concluído.
  • Tratamento de dados temporários:não armazene nem registre elementos de dados pessoais recebidos da carteira, a menos que seja explicitamente exigido pela legislação aplicável e divulgado por meio de intentToRetain = true.