Onde a ICP-Brasil esconde os dados
Se você já leu um certificado X.509 comum, sabe que o nome do titular fica no campo Subject (o Distinguished Name). O reflexo natural é procurar o CPF ali. Não está lá — pelo menos não de forma confiável e estruturada.
A ICP-Brasil define, na sua normativa, que os dados da pessoa física ou jurídica ficam em extensões próprias do certificado, identificadas por OIDs (Object Identifiers) sob o arco 2.16.76.1.3, que é o ramo brasileiro. Dentro dessas extensões, os campos não vêm rotulados: vêm concatenados numa string, por posição fixa. Quem lê precisa saber, de antemão, qual pedaço é o quê e quantos caracteres ocupa.
Os OIDs que você precisa conhecer
Cada tipo de titular e cada dado tem seu próprio OID. Os principais que você vai encontrar ao ler um certificado de autenticação:
Note que um e-CNPJ carrega os dois: o CNPJ da empresa e os dados do responsável pessoa física. Já um e-CPF só tem a pessoa física. Isso muda como você trata cada caso na aplicação.
Fazendo o parsing da extensão
O fluxo é sempre o mesmo: localizar a extensão pelo OID, pegar os bytes brutos, e fatiar por posição. Um exemplo em Python (o mesmo raciocínio vale para C#, Java ou qualquer linguagem):
from cryptography import x509
from cryptography.x509.oid import ObjectIdentifier
OID_PESSOA_FISICA = ObjectIdentifier("2.16.76.1.3.1")
def ler_dados_ecpf(cert: x509.Certificate):
for ext in cert.extensions:
if ext.oid == OID_PESSOA_FISICA:
raw = ext.value.value # bytes da extensão (UnrecognizedExtension)
texto = raw.decode("latin-1", errors="ignore")
# campos por posição (offsets conforme a normativa ICP-Brasil):
# 8 dígitos -> data de nascimento (DDMMAAAA)
# 11 dígitos -> CPF
# 11 dígitos -> NIS/PIS/PASEP
# 15 dígitos -> RG
# 6 dígitos -> órgão emissor + UF
nascimento = texto[0:8]
cpf = texto[8:19]
return {"nascimento": nascimento, "cpf": cpf}
return None
O que muda entre e-CPF e e-CNPJ
Na prática, sua aplicação precisa primeiro detectar o tipo (procurando qual OID está presente) e só então aplicar o parsing correto. Tratar os dois com o mesmo código é a origem clássica de "o CNPJ veio no lugar do CPF".
Armadilhas de parsing
- Preenchimento inconsistente. Campos opcionais vazios podem vir como espaços, zeros ou simplesmente ausentes, deslocando todos os offsets seguintes.
- Codificação. Acentos no nome do titular podem estar em Latin-1, UTF-8 ou variações — decodificar errado corrompe o nome.
- Versões da normativa. Certificados antigos e novos seguem revisões diferentes da especificação; um parser que cobre só a versão atual quebra num certificado emitido anos atrás.
- Certificado de aplicação vs. de pessoa. Nem todo certificado ICP-Brasil é e-CPF/e-CNPJ; há certificados de servidor e de aplicação que não carregam esses OIDs. Seu código precisa lidar com a ausência.
Por que isso quebra com o tempo
O parser que você escreve hoje funciona para os certificados que você testou hoje. O problema aparece depois, e sempre da mesma forma: um cliente novo tenta entrar, tem um certificado de uma AC ou versão que seu código não previu, e o parsing devolve lixo — ou um CPF sutilmente errado que passa despercebido até virar um problema de dados sério.
Manter esse componente exige:
- Acompanhar as revisões normativas do ITI sobre formato dos campos e OIDs.
- Testar contra certificados reais de todas as ACs, porque cada uma tem suas particularidades de preenchimento.
- Cobrir e-CPF, e-CNPJ, A1 e A3 e suas combinações.
- Tratar com robustez os casos de dado ausente ou malformado, sem devolver informação incorreta.
É um pedaço pequeno de código com um custo de manutenção desproporcional — porque erro aqui não é um bug de tela, é um dado de identidade errado entrando no seu sistema.
CPF, CNPJ e nome do titular — já estruturados
O IHub-Auth faz todo esse parsing por você e devolve os dados do titular já limpos e validados, via verificação server-to-server. Sem OID proprietário, sem contagem de offset, sem surpresa com o certificado de um cliente específico. A cadeia ICP-Brasil completa e as regras de formato ficam do nosso lado — você recebe um JSON pronto para o login.