错误信息
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)。括号中的提示给出了能解析这些字节的函数。密钥本身没有问题。
原因
PKCS#1 格式的 RSA 密钥,代码却按 PKCS#8 解析
常见`openssl genrsa`(OpenSSL 1.x)和许多旧工具输出的是 `RSA PRIVATE KEY`;而针对 `openssl genpkey` 的输出编写的代码调用的是 `ParsePKCS8PrivateKey`。使用较新的工具时,也会出现相反的情况。
SEC 1 格式的 EC 密钥
常见`openssl ecparam -genkey` 输出的是 `EC PRIVATE KEY`(SEC 1,RFC 5915)。它必须交给 `ParseECPrivateKey` 解析,或者先转换为 PKCS#8。
把 PKCS#1 RSA 公钥传给了 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)