В обсуждениях сертификатов ходят два утверждения. Первое — что .p12 это надёжный вариант, а .pem — слабый; второе — что текстовый файл должен быть безопасным для отправки, потому что его можно прочитать. Ни одно не выдерживает минуты проверки.

PKCS12, PEM и DER описывают, как объекты сертификатов упаковываются и кодируются. Они не решают, кто вторая сторона, можно ли доверять издателю и нужен ли файлу пароль.

Что принимает клиент — вопрос совместимости. Что содержит файл — вопрос идентичности. Разделите эти два, и большинство ошибок импорта перестанут быть загадочными.

Три контейнера, одна объектная модель

Начните с того, что у вас действительно есть. Сертификат — это подписанное утверждение об открытом ключе. Закрытый ключ — отдельный материал, доказывающий, что вы владеете этим ключом. Цепочка — набор издателей, связывающих ваш сертификат с корнем, которому доверяет клиент. Все три существуют независимо от упаковки.

Файл PKCS12, обычно .p12 или .pfx, — это контейнер, определённый в RFC 7292, который может нести закрытый ключ, один или несколько сертификатов и цепочку в одном блоке, защищённом паролем, с псевдонимом, именующим идентичность. Файл PEM — это текстовая рамка по RFC 7468: тело base64 между строками BEGIN и END, и один файл может содержать несколько блоков подряд. DER — двоичное кодирование тех же структур ASN.1, а тело PEM — буквально DER, обёрнутый в base64.

Последнее предложение стоит запомнить. Преобразование PEM в DER переписывает рамку, а не содержимое, а обратное преобразование возвращает исходные байты.

ContainerCan holdDoes not decide
PKCS12 (.p12, .pfx)Key, leaf certificate, chain, alias, passwordWhich root the client trusts
PEM (.pem, .crt, .cer)Any number of base64 blocksWhether the private key is present
DER (.der, .cer)One binary structureThe object type, whatever the extension says

Кодирование — не шифрование

base64 — это транспортный алфавит. Он ничего не скрывает, и любой может декодировать блок PEM в оболочке. Файл DER двоичный и столь же публичный. Ни одно из свойств не является защитой, и ни одно не подразумевает наличие пароля.

Настоящая защита находится в материале ключа. Пакет PKCS12 может шифровать своё содержимое ключом, производным от пароля. Закрытый ключ PEM можно зашифровать старым блоком заголовка или хранить в PKCS#8 EncryptedPrivateKeyInfo. Сертификат сам по себе не хранит ничего секретного, поэтому экспорт, который дал только сертификат, оставляет клиента без возможности аутентификации, в каком бы формате вы его ни упаковали.

Расширение — подсказка, а не договор. Файлы, оканчивающиеся на .cer и .crt, встречаются в обеих кодировках, а устройства достаточно часто экспортируют сертификаты DER под именами .pem, так что угадывание по суффиксу стоит потраченного дня. Читайте первые байты: файл PEM начинается со строки BEGIN, а DER начинается с 0x30, потому что внешняя структура — SEQUENCE.

Почему импорт на самом деле не удаётся

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

Параметры шифрования вызывают четвёртую, и она выглядит точно как неверный пароль. Старые устройства экспортировали файлы PKCS12 с RC2-40 и 3DES, которые OpenSSL 3 отвергает, если не загружен legacy-провайдер. Повторный экспорт с устройства с AES-256-CBC и PBKDF2 — долговечное решение. Оставлять старые шифры постоянно включёнными на клиентской машине ради одного файла — плохая сделка.

Пятая — неоднозначность. Контейнер с двумя ключами и двумя сертификатами или файл PEM с тремя блоками CERTIFICATE заставляют клиента выбирать, и его выбор часто просто первый элемент. Когда туннель поднимается с неверной идентичностью, обычно это и есть причина.

Проверьте перед преобразованием

Читайте структуру, не печатая секретов. openssl pkcs12 -in bundle.p12 -info -noout сообщает алгоритмы шифрования и псевдонимы, подавляя вывод ключа и сертификата, а руководство openssl-pkcs12 описывает флаги. Убрать -noout и добавить -nodes — это для создания файлов, которые вы собираетесь хранить, а не для быстрого взгляда, потому что так закрытый ключ записывается открыто.

Для сертификата openssl x509 -in cert.pem -noout -subject -issuer -dates отвечает на то, на что не ответит диалог импорта, а добавление -ext subjectAltName показывает имена, для которых сертификат действительно действителен. Если файл DER, добавьте -inform DER; этот единственный флаг решает большинство ошибок unable-to-load.

Сопоставление ключа с сертификатом — механическая работа, и её стоит выполнить перед любым импортом:

openssl x509 -in cert.pem -noout -pubkey | openssl sha256
openssl pkey -in key.pem -pubout | openssl sha256

Одинаковые дайджесты означают, что пара подходит друг другу. Разные дайджесты означают, что у вас неверный ключ, и никакое преобразование формата это не изменит.

Что формат никогда не меняет

Решения о доверии принимаются над контейнером. Клиент проходит цепочку до корня в своём хранилище, проверяет окно действия, проверяет расширенное использование ключа для аутентификации клиента, а на стороне сервера проверяет, что имя, к которому он обратился, есть в сертификате. Ни один из этих шагов не читает расширение файла.

Поэтому переименование файла до исчезновения ошибки — такой надёжный способ терять время. Импорт удаётся, идентичность по-прежнему неверна, и сбой возвращается во время рукопожатия, где сообщение менее полезно. Поэтому же пакет, экспортированный два года назад, импортируется чисто и всё равно отклоняется: срок действия путешествовал внутри сертификата, а не в имени файла.

Порядок, избегающий переделки

Спросите в документации клиента, какие кодировки он принимает и какой контейнер ожидает для идентичности клиента, затем посмотрите, что вам дали. Если клиенту нужна одна импортируемая идентичность, а у вас отдельные файлы PEM, соберите пакет один раз с паролем, который вы контролируете, и сохраните исходники. Если нужен PEM, извлеките ключ и цепочку, а затем удалите промежуточные файлы тем процессом обработки учётных данных, который ваша команда уже использует.

После импорта проверяйте идентичность, а не диалог: субъект, издатель, срок действия и имя, которое клиент представит. Дружелюбное имя в списке — это метка, а не проверенная идентичность. Если затем туннель не работает, вы отлаживаете аутентификацию или маршрутизацию, а не упаковку, и это гораздо более короткий разговор.

Похожие статьи