Pular para o conteúdo
ecdsa.com

PKCS#12 (.pfx/.p12) vs PEM: agrupar chaves e certificados

O PEM guarda chaves e certificados como blocos de texto separados. O PKCS#12 reúne tudo em um único arquivo binário protegido por senha, que o Windows, o macOS, o Java e os navegadores importam diretamente.
Itens comparadosPKCS #12 (PFX)PEM

A questão PKCS#12 vs PEM aparece sempre que uma chave e um certificado circulam entre servidores Unix e plataformas com repositórios de chaves próprios. Arquivos PEM são blocos separados e legíveis que softwares baseados em OpenSSL carregam diretamente; um arquivo PKCS#12 (.p12 ou .pfx) é um único contêiner criptografado que os sistemas operacionais e o Java importam em uma só etapa. As chaves e os certificados são os mesmos, a embalagem é diferente, e são os algoritmos da embalagem que decidem se uma importação funciona.

Visão geral

PEMPKCS#12 (PFX)
EspecificaçãoRFC 7468 (codificação em texto do DER)RFC 7292 (PKCS #12 v1.1), RFC 9579 (PBMAC1)
FormatoTexto, um ou mais blocos BEGIN … ENDContêiner DER binário de “safe bags”
ConteúdoO que você colocar no arquivo: chave, certificados, CRLsChaves privadas, certificados, CRLs, segredos, com nomes amigáveis e IDs de chave
ProteçãoOpcional, por chave (PKCS#8 criptografado)Criptografia dos bags baseada em senha, mais um MAC de integridade
Proteção padrão no OpenSSL 3.6PBES2 com AES-256-CBC para chaves criptografadasPBES2, PBKDF2-HMAC-SHA256, AES-256-CBC, 2.048 iterações; MAC HMAC-SHA256
-legacy do OpenSSLNão se aplicaRC2-40 para certificados, 3DES para chaves, MAC HMAC-SHA1
Extensões típicas.pem, .crt, .key.p12, .pfx
Usado porOpenSSL, servidores web, proxies, Go, Python, Node.jsRepositório de certificados do Windows, Keychain do macOS, KeyStore do Java, navegadores, signtool

O que há dentro de um .pfx

Um arquivo PKCS#12 é uma estrutura PFX: um cofre autenticado (authenticated safe) formado por blocos de conteúdo, cada um com seus bags. As chaves privadas ficam em entradas pkcs8ShroudedKeyBag (PKCS#8 criptografado), os certificados em entradas certBag (muitas vezes também em um bloco criptografado), e os bags carregam atributos como friendlyName e localKeyId, que vinculam uma chave ao seu certificado. Um MAC derivado da senha protege a integridade do arquivo inteiro; a RFC 9579 (2024) acrescenta o PBMAC1, que deriva a chave do MAC com PBKDF2 em vez da KDF legada do PKCS#12.

O PEM não tem contêiner: um servidor é configurado com um arquivo de chave e um arquivo de certificado (ou de cadeia), ou com um único arquivo com vários blocos. A proteção é a que o arquivo de chave tiver, normalmente nenhuma nos servidores, porque o processo precisa ler a chave sem que uma pessoa digite uma senha.

Conversão

O script abaixo, executado com o OpenSSL 3.6.5, empacota uma chave e um certificado descartáveis em um arquivo PKCS#12 e depois os desempacota.

OpenSSL 3.6: de PEM para PKCS#12 e de volta
#!/bin/sh
dir=$(mktemp -d)
cd "$dir" || exit 1
openssl req -new -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes -keyout key.pem \
  -subj "/CN=example.com" -days 30 -out cert.pem 2>/dev/null
openssl pkcs12 -export -inkey key.pem -in cert.pem -name demo -passout pass:demo -out bundle.p12
openssl pkcs12 -in bundle.p12 -passin pass:demo -info -noout 2>&1 | grep -E "MAC:|Shrouded|PKCS7 Encrypted"
openssl pkcs12 -in bundle.p12 -passin pass:demo -nodes -out extracted.pem 2>/dev/null
grep -E "^-----BEGIN" extracted.pem
cd / && rm -rf "$dir"
Saída
MAC: sha256, Iteration 2048
PKCS7 Encrypted data: PBES2, PBKDF2, AES-256-CBC, Iteration 2048, PRF hmacWithSHA256
Shrouded Keybag: PBES2, PBKDF2, AES-256-CBC, Iteration 2048, PRF hmacWithSHA256
-----BEGIN CERTIFICATE-----
-----BEGIN PRIVATE KEY-----

Para incluir os intermediários, passe-os com -certfile chain.pem; para extrair apenas os certificados, use -nokeys, e apenas a chave, -nocerts. A flag -nodes (chamada -noenc nas versões mais novas) grava a chave sem criptografia, então trate a saída com o devido cuidado.

Compatibilidade: algoritmos modernos versus legados

O OpenSSL 3.0 trocou os padrões de exportação: de RC2-40 e 3DES com MAC HMAC-SHA1 para AES-256 com MAC HMAC-SHA256. Muitos consumidores só se adaptaram depois:

  • macOS: o framework Security da Apple importa arquivos PKCS#12 modernos a partir do macOS 15; o macOS 14 e anteriores falham com “MAC verification failed during PKCS12 import (wrong password?)”, mesmo com a senha certa.
  • Java: o JDK 9 tornou o PKCS#12 o tipo de keystore padrão; o JDK 16 (e as atualizações de 2021 do 8 e do 11) mudou o padrão do próprio Java para PBES2 com AES-256 e MAC HMAC-SHA256, e as versões atuais leem arquivos do OpenSSL 3.
  • Windows: as versões atuais importam arquivos PFX com AES-256; versões muito antigas do Windows Server podem precisar da forma legada.
  • OpenSSL 3 lendo arquivos antigos: arquivos cujos certificados estão criptografados com RC2-40 (o padrão do OpenSSL 1.1, e o que as exportações com -legacy usam quando o RC2 está compilado) só carregam com -legacy, que carrega o provedor legacy. Sem ele, o OpenSSL 3.6.5 imprime error:0308010C:digital envelope routines:inner_evp_generic_fetch:unsupported para RC2-40-CBC, e o Node.js 26 rejeita o arquivo com Unsupported PKCS12 PFX data. Arquivos que usam apenas 3DES e MAC HMAC-SHA1 carregam sem o provedor legacy.

Quando um arquivo moderno falha em um destino reconhecidamente antigo, exporte com openssl pkcs12 -export -legacy … ou escolha os algoritmos explicitamente (-keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES -macalg SHA1), e trate esse arquivo como fracamente protegido durante o transporte.

Aqui as mensagens de erro enganam: “MAC verification failed” ou “wrong password” geralmente significam que o leitor não oferece suporte ao algoritmo de MAC ou de criptografia, e não que a senha esteja errada. Inspecione o arquivo com openssl pkcs12 -info -noout (acrescente -legacy para arquivos antigos) e veja quais algoritmos foram usados antes de sair tentando senhas.

PKCS#12 como keystore

O Java trata um arquivo PKCS#12 como um keystore: keytool -list -keystore bundle.p12 -storetype PKCS12 mostra as entradas dele, e o friendlyName vira o alias. Um keystore pode conter várias entradas de chave e certificados confiáveis, o que um arquivo PEM não consegue expressar sem convenções de nomes. Os truststores são um caso especial: um truststore PKCS#12 que contém apenas certificados precisa de atributos específicos do Java para marcá-los como confiáveis, por isso keytool -importcert é a forma confiável de montar um. A maioria das outras plataformas ignora esses atributos do Java e importa chaves e certificados pela correspondência do localKeyId.

Quando escolher cada um

  • TLS em servidores Linux, proxies reversos, ingress do Kubernetes: chave PEM e certificado com a cadeia completa.
  • Importação de certificados no IIS do Windows, no Azure App Service e no Key Vault: PKCS#12.
  • TLS em Java e Spring Boot: um keystore PKCS#12 (ou PEM, que as versões recentes do Spring Boot aceitam diretamente).
  • Certificados de cliente para navegadores e dispositivos móveis: PKCS#12 com uma senha forte, e o arquivo entregue separadamente da senha.
  • Assinatura de código com signtool ou jarsigner: PKCS#12, se é que a chave está em um arquivo; desde 2023, chaves de assinatura de código publicamente confiáveis precisam ficar em hardware.
  • Inspeção e depuração: PEM, ou o inspetor de PFX, que lista os bags e os algoritmos localmente, sem revelar a chave.

Notas de migração

  1. Inclua a cadeia completa ao montar um PKCS#12 para servidores ou clientes, na ordem com o certificado folha primeiro; intermediários ausentes são a falha mais comum depois da importação.
  2. Confira se a chave corresponde ao certificado antes de empacotar: o verificador de correspondência de chave e certificado compara as chaves públicas dos dois.
  3. Escolha os algoritmos pensando no consumidor mais antigo e depois atualize: exporte de novo com os padrões modernos quando as plataformas antigas saírem de cena.
  4. Use senhas fortes e aleatórias em arquivos PKCS#12 que circulam, já que o arquivo pode ser atacado offline; as 2.048 iterações de PBKDF2 que o OpenSSL usa por padrão são poucas pelos critérios de armazenamento de senhas.
  5. Não deixe chaves extraídas largadas por aí: depois de converter um .pfx em PEM para um servidor, restrinja as permissões do arquivo e apague as cópias temporárias.

Referências

Todas as comparações