Сообщение об ошибке
Failed to read asymmetric key
Node.js crypto — e.g. code ERR_OSSL_ASN1_WRONG_TAG
Что это означает
createPublicKey() (или любой вызов, который принимает открытый ключ в DER, например crypto.verify()) получил байты, чья структура ASN.1 не соответствует заявленному типу: например, указан type: "spki", а в байтах на самом деле закрытый ключ EC в формате SEC1. OpenSSL разобрал данные достаточно, чтобы понять, что теги неверные, и остановился. (createPrivateKey() и PEM с неправильной меткой сообщают о таком же несоответствии формулировками самого OpenSSL, например «error:068000A8:asn1 encoding routines::wrong tag».) Сопутствующий код (ERR_OSSL_ASN1_WRONG_TAG и родственные ему коды) называет несоответствие на уровне ASN.1. В отличие от ошибки декодера «unsupported» (DECODER routines), которая означает, что ничего пригодного для разбора не нашлось вообще, эта ошибка означает, что в байтах распознаётся структура, но не та, что соответствует заявленному типу.
Почему это происходит
Заявленный тип не соответствует байтам
частоВ мире DER несколько контейнеров: SPKI для открытых ключей, PKCS#8 для закрытых ключей, SEC1 для устаревших закрытых ключей EC, PKCS#1 для устаревших ключей RSA. Если указать type: "spki" для закрытого ключа SEC1 или PKCS#8 или для целого сертификата, проверка тегов сразу завершится ошибкой.
Base64 не декодирован или декодирован дважды
частоИ текст base64, переданный с format: "der" (OpenSSL тогда разбирает ASCII как ASN.1), и Buffer.from(pem, "base64") от целого PEM вместе с его строками заголовка дают байтовую кашу с неверными тегами.
Голая точка EC вместо структуры ключа
иногда65 байт несжатой точки (0x04‖X‖Y) — не DER, а полезная нагрузка, которая хранится внутри SPKI. Если передать их напрямую в createPublicKey, будет ошибка: их нужно обернуть в структуру или импортировать через JWK либо raw-импорт WebCrypto.
Как исправить
- 1.
Определите структуру и укажите её правильно
asn1parse выводит внешнюю структуру. SPKI начинается с SEQUENCE, содержащей AlgorithmIdentifier; PKCS#8 — с версии INTEGER 0; ключи EC в SEC1 — с INTEGER 1.
bash openssl asn1parse -inform der -in key.der | head -5 - 2.
Подберите параметры Node под контейнер
Когда контейнер известен, сопоставление становится механическим.
js // SPKI public key createPublicKey({ key: der, format: "der", type: "spki" }); // PKCS#8 private key createPrivateKey({ key: der, format: "der", type: "pkcs8" }); // SEC1 (BEGIN EC PRIVATE KEY) private key createPrivateKey({ key: der, format: "der", type: "sec1" }); - 3.
Преобразуйте устаревшие контейнеры один раз, на границе системы
Храните ключи только в PKCS#8/SPKI, чтобы коду приложения никогда не приходилось угадывать.
bash openssl pkey -in legacy-ec.pem -out key-pkcs8.pem # any private → PKCS#8 openssl pkey -in key-pkcs8.pem -pubout -out pub-spki.pem # derive SPKI public