Skip to content
ecdsa.com
Go crypto/x509Go

Error message

x509: failed to parse private key (use ParsePKCS1PrivateKey instead for this key format)

Also printed as

  • 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)

The function in parentheses depends on what Go detected: `ParsePKCS1PrivateKey`, `ParseECPrivateKey` or `ParsePKCS8PrivateKey`. The public-key twin is "x509: failed to parse public key (use ParsePKCS1PublicKey instead for this key format)". Bytes that match none of the formats give an `asn1: structure error` instead.

Go crypto/x509 — ParsePKCS8PrivateKey / ParsePKCS1PrivateKey / ParseECPrivateKey / ParsePKIXPublicKey

What it means

You passed DER bytes of one private-key container to the parser for another, and Go recognised which container it actually is. There are three common encodings: PKCS#8 (`-----BEGIN PRIVATE KEY-----`, any algorithm), PKCS#1 (`-----BEGIN RSA PRIVATE KEY-----`, RSA only) and SEC 1 (`-----BEGIN EC PRIVATE KEY-----`, EC only). The hint in parentheses names the function that will parse your bytes. The key itself is fine.

Why it happens

How to fix it

  1. 1.

    Choose the parser from the PEM type

    The PEM label tells you the container. Dispatch on `block.Type` instead of assuming one format.

    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.

    Normalise keys to PKCS#8 and SPKI

    PKCS#8 for private keys and SPKI for public keys work for every algorithm and every modern library. Convert once at provisioning time.

    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

Related errors

Browse the full signature error database