Сообщение об ошибке
x509: failed to parse private key (use ParsePKCS1PrivateKey instead for this key format)
Также выводится как
- x509: failed to parse private key (use ParseECPrivateKey instead for this key format)
- x509: failed to parse private key (use ParsePKCS8PrivateKey instead for this key format)
- x509: failed to parse public key (use ParsePKCS1PublicKey instead for this key format)
Функция в скобках зависит от того, что обнаружил Go: `ParsePKCS1PrivateKey`, `ParseECPrivateKey` или `ParsePKCS8PrivateKey`. Аналогичная ошибка для открытого ключа: «x509: failed to parse public key (use ParsePKCS1PublicKey instead for this key format)». Байты, которые не подходят ни к одному из форматов, вместо этого дают `asn1: structure error`.
Go crypto/x509 — ParsePKCS8PrivateKey / ParsePKCS1PrivateKey / ParseECPrivateKey / ParsePKIXPublicKey
Что это означает
Вы передали DER-байты закрытого ключа в одном контейнере парсеру для другого контейнера, и Go распознал, какой это контейнер на самом деле. Распространены три кодировки: PKCS#8 (`-----BEGIN PRIVATE KEY-----`, любой алгоритм), PKCS#1 (`-----BEGIN RSA PRIVATE KEY-----`, только RSA) и SEC 1 (`-----BEGIN EC PRIVATE KEY-----`, только EC). Подсказка в скобках называет функцию, которая разберёт ваши байты. С самим ключом всё в порядке.
Почему это происходит
Ключ RSA в PKCS#1, а код ожидает PKCS#8
часто`openssl genrsa` (OpenSSL 1.x) и многие старые инструменты записывают `RSA PRIVATE KEY`; код, написанный под вывод `openssl genpkey`, вызывает `ParsePKCS8PrivateKey`. С более новыми инструментами бывает и наоборот.
Ключ EC в формате SEC 1
часто`openssl ecparam -genkey` записывает `EC PRIVATE KEY` (SEC 1, RFC 5915). Такой ключ нужно передавать в `ParseECPrivateKey` или преобразовать в PKCS#8.
Открытый ключ RSA в PKCS#1 передан в ParsePKIXPublicKey
иногда`-----BEGIN RSA PUBLIC KEY-----` — голая структура PKCS#1 без идентификатора алгоритма, который есть в `PUBLIC KEY` (SPKI).
Как исправить
- 1.
Выбирайте парсер по типу PEM
Метка PEM указывает на контейнер. Выбирайте парсер по `block.Type`, а не рассчитывайте на один формат.
go func parsePrivateKeyPEM(data []byte) (crypto.Signer, error) { block, _ := pem.Decode(data) if block == nil { return nil, errors.New("no PEM block found") } switch block.Type { case "PRIVATE KEY": // PKCS#8: RSA, ECDSA, Ed25519, X25519 key, err := x509.ParsePKCS8PrivateKey(block.Bytes) if err != nil { return nil, err } signer, ok := key.(crypto.Signer) if !ok { return nil, fmt.Errorf("%T cannot sign", key) } return signer, nil case "RSA PRIVATE KEY": // PKCS#1 return x509.ParsePKCS1PrivateKey(block.Bytes) case "EC PRIVATE KEY": // SEC 1 return x509.ParseECPrivateKey(block.Bytes) default: return nil, fmt.Errorf("unsupported PEM type %q", block.Type) } } - 2.
Приведите ключи к PKCS#8 и SPKI
PKCS#8 для закрытых ключей и SPKI для открытых ключей подходят для любого алгоритма и любой современной библиотеки. Преобразуйте ключи один раз, при их подготовке и развёртывании.
bash # Normalise any private key to PKCS#8 ("-----BEGIN PRIVATE KEY-----") openssl pkcs8 -topk8 -nocrypt -in legacy.pem -out key.pk8.pem # Public keys: PKCS#1 "RSA PUBLIC KEY" -> SPKI "PUBLIC KEY" openssl rsa -RSAPublicKey_in -in rsa-pub.pem -pubout -out spki.pem
Связанные ошибки
asn1: structure error: tags don't matchGo encoding/asn1algid parse error, not a sequenceJava (JDK)System.Security.Cryptography.CryptographicException: ASN1 corrupted data..NET System.Security.Cryptographytoken signature is invalid: key is of invalid type: ECDSA verify expects *ecdsa…golang-jwt/jwt (Go)