エラーメッセージ
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 は、それが実際にはどのコンテナーなのかを認識しています。一般的なエンコーディングは 3 つあります。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` を呼び出します。新しいツールでは、その逆のことも起こります。
SEC 1 形式の EC 鍵
よくある`openssl ecparam -genkey` は `EC PRIVATE KEY`(SEC 1、RFC 5915)を書き出します。この鍵は `ParseECPrivateKey` に渡すか、PKCS#8 に変換しなければなりません。
PKCS#1 の RSA 公開鍵を ParsePKIXPublicKey に渡している
ときどき`-----BEGIN RSA PUBLIC KEY-----` は、`PUBLIC KEY`(SPKI)が持つアルゴリズム識別子を含まない、素の PKCS#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.
鍵を 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)