本文へスキップ
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 は、それが実際にはどのコンテナーなのかを認識しています。一般的なエンコーディングは 3 つあります。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

関連するエラー

署名エラーデータベースをすべて見る