跳到主要内容
ecdsa.com
Go crypto/x509Go

错误信息

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)。括号中的提示给出了能解析这些字节的函数。密钥本身没有问题。

原因

修复方法

  1. 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. 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

相关错误

浏览完整的签名错误库