Перейти к содержимому
ecdsa.com

PEM или DER: один сертификат в текстовом или двоичном виде

DER — двоичная кодировка ASN.1, в которой определены сертификаты и ключи. PEM — тот же DER, закодированный в base64 и помещённый между строками BEGIN и END. При конвертации внутри ничего не меняется.

Выбор между PEM и DER — это не выбор между разными данными: сертификат, ключ, CSR или CRL всегда определяется как ASN.1 в кодировке DER, а PEM — текстовая обёртка вокруг тех же самых байтов. Вопрос лишь в том, какое представление нужно инструменту, протоколу или платформе и как распознать и конвертировать каждое из них.

Коротко о главном

DERPEM
Что этоDistinguished Encoding Rules для ASN.1 (ITU-T X.690): двоичный формат тег-длина-значениеТекст по RFC 7468: base64 от DER между метками
Начинается сБайта 0x30 (SEQUENCE) у сертификатов и ключей-----BEGIN CERTIFICATE-----, -----BEGIN PRIVATE KEY----- и т. д.
Размер (сертификат P-256, замер)389 байт583 байта (примерно 4/3 плюс переводы строк и метки)
Объектов в файлеОдинСколько угодно блоков (цепочки, ключ вместе с сертификатом)
СамоописываемостьМетки нет; тип известен из контекстаМетка называет структуру
Типичные расширения.der, .cer, .crt (неоднозначно).pem, .crt, .cer, .key, .csr (неоднозначно)
ОтпечатокSHA-256 от этих байтовТо же значение: отпечатки вычисляются по DER внутри
Можно без опаски вставлять в письма, YAML, переменные окруженияНетДа

Что представляет собой каждый формат

DER — каноническая двоичная кодировка данных ASN.1: каждое значение состоит из тега, длины и содержимого, и у каждого значения ровно одна допустимая кодировка. Именно благодаря каноничности работают подписи: подпись сертификата покрывает DER-байты его tbsCertificate, и проверяющим сторонам ничего не нужно перекодировать.

PEM (название восходит к стандарту Privacy-Enhanced Mail 1993 года, а для объектов PKIX формат определён в RFC 7468) кодирует эти байты стандартным base64, по традиции по 64 символа в строке, и помещает их между строками BEGIN и END, которые называют структуру: CERTIFICATE, X509 CRL, CERTIFICATE REQUEST, PUBLIC KEY, PRIVATE KEY, ENCRYPTED PRIVATE KEY, а также устаревшие метки OpenSSL RSA PRIVATE KEY и EC PRIVATE KEY. Текст до блоков, между ними и после них игнорируется, поэтому и работают пакеты с комментариями и вывод openssl x509 -text.

Конвертация и проверка

Скрипт ниже, запущенный с OpenSSL 3.6.5, создаёт одноразовый сертификат и показывает, что обе кодировки содержат один и тот же объект.

OpenSSL: один сертификат в PEM и в DER
#!/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 x509 -in cert.pem -outform DER -out cert.der
printf 'cert.pem %s bytes, cert.der %s bytes\n' "$(wc -c < cert.pem | tr -d ' ')" "$(wc -c < cert.der | tr -d ' ')"
head -1 cert.pem
openssl x509 -in cert.der -inform DER -noout -fingerprint -sha256 | cut -c1-40
openssl x509 -in cert.pem -noout -fingerprint -sha256 | cut -c1-40
cd / && rm -rf "$dir"
Результат
cert.pem 583 bytes, cert.der 389 bytes
-----BEGIN CERTIFICATE-----
sha256 Fingerprint=FE:8B:DC:19:30:EE:A8:
sha256 Fingerprint=FE:8B:DC:19:30:EE:A8:

Так же конвертируются ключи (openssl pkey -in key.pem -outform DER), CSR (openssl req -outform DER) и CRL (openssl crl -outform DER). Как определить формат неизвестного файла: если он начинается с -----BEGIN, это PEM; если xxd file | head -1 показывает 3082 в начале, это почти наверняка DER.

Типичные ошибки

  • no start line / Expecting: TRUSTED CERTIFICATE от OpenSSL: инструмент ожидал PEM, а получил DER или блок PEM с другой меткой. Добавьте -inform DER или проверьте метку.
  • header too long / wrong tag: инструмент ожидал DER, а получил текст PEM или обрезанный файл.
  • Переводы строк в стиле Windows или лишние пробелы внутри блока PEM, вставленного в веб-форму или YAML; строгие парсеры такие блоки отклоняют. Перекодируйте данные, а не правьте их вручную.
  • PEM-пакет там, где ожидался один сертификат: многие инструменты читают только первый блок, поэтому порядок важен (для серверов первым идёт конечный сертификат).
  • Base64url вместо base64: PEM использует стандартный алфавит с +, / и дополнением, а JOSE и WebAuthn — base64url. Сертификат, скопированный из элемента x5c в JWK, — это DER в стандартном base64, и если обернуть его строками PEM, получится корректный PEM-файл.

Просмотр структуры ASN.1 принимает обе кодировки и показывает структуру, а разделитель PEM-пакетов разбирает файлы с несколькими сертификатами на отдельные блоки.

Пакеты и цепочки

Поскольку DER вмещает ровно один объект, всё, что требует нескольких объектов в одном файле, использует склейку блоков PEM или формат-контейнер. Файл сервера fullchain.pem — это конечный сертификат, за которым следуют промежуточные; пакет сертификатов CA, например /etc/ssl/certs/ca-certificates.crt, — это сотни корневых сертификатов в одном PEM-файле. Альтернативы на основе DER — пакеты сертификатов PKCS #7 (.p7b, структура CMS SignedData без содержимого, только с сертификатами; распространены в Windows) и PKCS #12 (.pfx), когда вместе с цепочкой передаётся закрытый ключ. .p7b конвертируется в PEM командой openssl pkcs7 -print_certs -in bundle.p7b, которая записывает каждый сертификат отдельным блоком PEM.

Порядок и полнота важнее кодировки: сервер должен отправлять сначала свой конечный сертификат, а затем все промежуточные, которые нужны, чтобы дойти до корневого сертификата, которому доверяют клиенты; без нужного промежуточного сертификата перестают работать клиенты, которые не загружают его сами, в каком бы формате ни был файл.

Что когда выбирать

  • Веб-серверы, обратные прокси, клиенты ACME: PEM (fullchain.pem, privkey.pem).
  • Java (keytool -importcert, CertificateFactory): подходят оба, но каноническими входными данными считается DER; в хранилищах ключей ключ вместе с цепочкой хранится в формате PKCS #12.
  • Импорт сертификатов в Windows: .cer в DER или .cer в кодировке PEM; ключ вместе с сертификатом помещают в .pfx.
  • Встраивание в исходный код, переменные окружения, секреты Kubernetes: текст PEM (или DER в base64, если этого требует поле).
  • Сетевые протоколы и двоичные контейнеры: всегда DER; в TLS, CMS, OCSP и расширениях X.509 PEM не встречается никогда.
  • Архивирование и аудит: DER для хранения с точностью до байта; PEM, если файлы должны просматривать люди.

Заметки о миграции

В криптографическом смысле мигрировать нечего: смена кодировки — деталь развёртывания.

  1. Унифицируйте имена файлов: .pem для PEM, .der для DER; в собственных инструментах избегайте неоднозначных .crt и .cer.
  2. Конвертируйте при развёртывании, а единственный источник истины (обычно PEM) храните в репозитории или хранилище секретов.
  3. Сверяйте отпечатки после конвертации командой openssl x509 -noout -fingerprint -sha256: они должны совпадать.
  4. Не отключайте шифрование закрытых ключей: openssl pkey -outform DER записывает ключ без шифрования, если не указать шифр, а ключи в DER инструменты часто обрабатывают с меньшим числом предупреждений.
  5. Фиксируйте ожидаемые форматы в конфигурации (для ssl_certificate нужен PEM, для хранилищ доверенных сертификатов Java — DER или PKCS #12): большинство ошибок формата возникает из-за догадок.

Источники

Все сравнения