X.509 e ASN.1

seed

Formato canônico de certificado digital. RFC 5280 (Internet X.509 PKI Certificate and CRL Profile) é a referência. Tudo que envolve TLS, S/MIME, code signing, ICP-Brasil deriva daqui.

Estrutura de um cert X.509 v3

Certificate  ::=  SEQUENCE  {
    tbsCertificate       TBSCertificate,        -- "to be signed"
    signatureAlgorithm   AlgorithmIdentifier,
    signatureValue       BIT STRING
}

TBSCertificate  ::=  SEQUENCE  {
    version              [0] EXPLICIT Version DEFAULT v1,
    serialNumber         CertificateSerialNumber,
    signature            AlgorithmIdentifier,
    issuer               Name,
    validity             Validity,         -- notBefore + notAfter
    subject              Name,
    subjectPublicKeyInfo SubjectPublicKeyInfo,
    extensions           [3] EXPLICIT Extensions OPTIONAL
}

Codificação: ASN.1 DER (Distinguished Encoding Rules) — binário canônico. PEM = base64 de DER com -----BEGIN CERTIFICATE----- envelope. Inspeção: openssl x509 -in cert.pem -text -noout.

Extensões críticas (v3)

Extensão OID Pra que serve
BasicConstraints 2.5.29.19 CA:TRUE/FALSE + pathLenConstraint. Diferencia CA de end-entity. CA forjado por end-entity foi a base de diversos ataques históricos
SubjectAltName (SAN) 2.5.29.17 DNS names, IPs, emails. CN do subject está deprecated pra hostname matching desde 2017 (CA/B BR). Browsers só olham SAN
KeyUsage 2.5.29.15 digitalSignature, keyEncipherment, keyCertSign, … restringe operações
ExtKeyUsage (EKU) 2.5.29.37 serverAuth, clientAuth, codeSigning, emailProtection, timeStamping, OCSPSigning
CRLDistributionPoints 2.5.29.31 Onde buscar CRL pra revogação
AuthorityInfoAccess (AIA) 1.3.6.1.5.5.7.1.1 URLs do OCSP responder + cert do issuer
CertificatePolicies 2.5.29.32 OIDs de política (ex: ICP-Brasil A1A3A4 têm OIDs específicos)
SCTList 1.3.6.1.4.1.11129.2.4.2 Embarcamento de Signed Certificate Timestamps (CT logs)
NameConstraints 2.5.29.30 Restringe domínios que um sub-CA pode emitir (CRÍTICO em sub-CAs delegados, ignorado em campo)

Trust path validation

RFC 5280 §6 define o algoritmo. Resumo:

  1. Cadeia: end-entity → intermediate(s) → root. Root é trust anchor (já confiável por config).
  2. Cada par (cert, issuer) checa: assinatura válida (issuer.publicKey verifica cert.signatureValue), notBefore ≤ now ≤ notAfter, BasicConstraintsKeyUsageEKU compatíveis, não revogado (OCSPCRLCRLite/embedded SCTs).
  3. Pitfall comum: confundir "está na cadeia enviada pelo servidor" com "está no trust store". TLS server envia a cadeia até (e excluindo) o root; o client cola seu root local.

Pitfalls operacionais

  • CN ≠ SAN: nunca dependa do CN. Cert moderno sem SAN é inválido pra hostname binding.
  • Validade longa: máximo público em 2026 é 398 dias (CA/B BR §6.3.2). Roadmap em direção a 90 dias (Apple proposal 2024) e 47 dias (Google proposal).
  • Algoritmo de assinatura: SHA-1 banido em CAs públicos desde 2017. Cert com sha1WithRSAEncryption em produção é red flag.
  • Cross-sign: um mesmo subject+key pode ter múltiplos certs emitidos por issuers diferentes — útil pra transição de root, ver 06-ssl-and-tls/05-creating-a-letsencrypt-style-ca.kmd §Cross-signing.
  • Path building: dado um pool de intermediários, achar a cadeia certa é NP-hard no pior caso; libs sérias têm heurísticas. Falhas reais quando intermediates estão faltando.

ASN.1 — o suficiente pra sobreviver

ASN.1 = linguagem de descrição de tipos abstratos. DER = encoding binário canônico (TLV: Tag + Length + Value).

  • SEQUENCE = struct ordenado
  • SET = struct não-ordenado
  • OCTET STRING = bytes
  • BIT STRING = bits (com offset de padding)
  • OBJECT IDENTIFIER (OID) = identificador hierárquico de tipo (1.2.840.113549.1.1.11 = sha256WithRSAEncryption)
  • UTCTime (YYMMDDHHMMSSZ, válido até 2049) vs GeneralizedTime (YYYYMMDDHHMMSSZ)

Tooling pra inspecionar: openssl asn1parse, dumpasn1, lapo.it/asn1js (browser).

Libs canônicas

  • Go: crypto/x509 (stdlib) — completo e ergonômico
  • Rust: rustls-webpki (path validation), x509-parser (parsing)
  • Dart: package:basic_utils (parsing limitado; pra ops pesadas, ponte FFI)
  • Python: cryptography.x509

Referências