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
RSA key in PKCS#1, code expects PKCS#8
common`openssl genrsa` (OpenSSL 1.x) and many older tools write `RSA PRIVATE KEY`; code written for `openssl genpkey` output calls `ParsePKCS8PrivateKey`. The reverse also happens with newer tools.
EC key in SEC 1 format
common`openssl ecparam -genkey` writes `EC PRIVATE KEY` (SEC 1, RFC 5915). It must go to `ParseECPrivateKey`, or be converted to PKCS#8.
PKCS#1 RSA public key passed to ParsePKIXPublicKey
occasional`-----BEGIN RSA PUBLIC KEY-----` is the bare PKCS#1 structure without the algorithm identifier that `PUBLIC KEY` (SPKI) carries.
How to fix it
- 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.
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
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)