hashicorp/packer · error
unsupported private key data
Error message
unsupported private key data
What it means
This error comes from loadPEMPrivateKeyAsPublic, which is a fallback path used when loading a verifier: the supplied PEM block failed to parse as a PKIX public key, a certificate, PKCS#8, PKCS#1, or SEC1/EC private key. The library only supports RSA (PKCS#1/PKCS#8) and EC (SEC1/PKCS#8) private keys here, so any other DER payload — malformed bytes, an Ed25519 PKCS#8 body that fails to decode, a DSA key, or a completely different PEM type (e.g. a CSR or encrypted key) — falls through to this error.
Source
Thrown at internal/attestation/sign_key.go:210
func loadPEMPrivateKeyAsPublic(contents []byte) (crypto.PublicKey, []byte, error) {
block, _ := pem.Decode(contents)
if block == nil {
return nil, nil, fmt.Errorf("no PEM block found")
}
var signer crypto.Signer
if key, err := x509.ParsePKCS8PrivateKey(block.Bytes); err == nil {
var ok bool
signer, ok = key.(crypto.Signer)
if !ok {
return nil, nil, fmt.Errorf("private key does not implement crypto.Signer")
}
} else if key, err := x509.ParsePKCS1PrivateKey(block.Bytes); err == nil {
signer = key
} else if key, err := x509.ParseECPrivateKey(block.Bytes); err == nil {
signer = key
} else {
return nil, nil, fmt.Errorf("unsupported private key data")
}
publicKeyPEM, err := marshalPublicKeyPEM(signer.Public())
if err != nil {
return nil, nil, err
}
publicKey, _, err := loadPEMPublicKey(publicKeyPEM)
if err != nil {
return nil, nil, err
}
return publicKey, publicKeyPEM, nil
}
func marshalPublicKeyPEM(publicKey crypto.PublicKey) ([]byte, error) {
encoded, err := x509.MarshalPKIXPublicKey(publicKey)
if err != nil {View on GitHub (pinned to eb36e3c3e4)
Solutions
- Convert the key to a supported format: for RSA use PKCS#1 or PKCS#8 PEM ('openssl rsa -in key.pem -traditional' or 'openssl pkcs8 -topk8 -nocrypt'), for EC use SEC1 or PKCS#8 ('openssl ec -in key.pem').
- If using an Ed25519 key from OpenSSH, convert it: 'ssh-keygen -p -m PKCS8 -f id_ed25519' so it parses as PKCS#8.
- If the file is meant to be a public key, export it as SubjectPublicKeyInfo: 'openssl pkey -pubin' / 'openssl pkey -in key.pem -pubout'.
- Decrypt the key first if it is passphrase-protected (encrypted PEM blocks never parse); supply the key unencrypted to the verifier path.
- Verify the file is not truncated or corrupted by checking it with 'openssl pkey -in file.pem -noout -check'.
Example fix
// before: verifier pointed at OpenSSH-format private key // -----BEGIN OPENSSH PRIVATE KEY----- ... // after: convert once, then reference the PKCS#8 file // ssh-keygen -p -m PKCS8 -f ~/.ssh/id_ed25519 // verifier_pem = "~/.ssh/id_ed25519" // now parses via x509.ParsePKCS8PrivateKey
Defensive patterns
Strategy: validation
Validate before calling
// pre-check before handing PEM to LoadPEMVerifier
func pemKeySupported(path string) error {
data, err := os.ReadFile(path)
if err != nil {
return err
}
block, _ := pem.Decode(data)
if block == nil {
return fmt.Errorf("no PEM block")
}
switch {
case x509.IsEncryptedPEMBlock(block): //nolint:staticcheck
return fmt.Errorf("encrypted PEM not supported")
}
if _, err := x509.ParsePKIXPublicKey(block.Bytes); err == nil {
return nil
}
if _, err := x509.ParseCertificate(block.Bytes); err == nil {
return nil
}
if _, err := x509.ParsePKCS8PrivateKey(block.Bytes); err == nil {
return nil
}
if _, err := x509.ParsePKCS1PrivateKey(block.Bytes); err == nil {
return nil
}
if _, err := x509.ParseECPrivateKey(block.Bytes); err == nil {
return nil
}
return fmt.Errorf("%s: unsupported PEM type %q; use PKCS#8/PKCS#1/SEC1 key or SPKI public key", path, block.Type)
} Type guard
// narrow parsed PKCS#8 content to a supported signer key
func isSupportedSignerKey(key any) bool {
switch key.(type) {
case *rsa.PrivateKey, *ecdsa.PrivateKey, ed25519.PrivateKey:
return true
default:
return false
}
} Try / catch
verifier, err := attestation.LoadPEMVerifier(keyPath)
if err != nil {
var unsupported = strings.Contains(err.Error(), "unsupported")
switch {
case unsupported:
return fmt.Errorf("verifier key %s: convert to PKCS#8 PEM ('openssl pkcs8 -topk8 -nocrypt'); got: %w", keyPath, err)
default:
return fmt.Errorf("load verifier: %w", err)
}
} Prevention
- Store verifier/verifying keys as PKCS#8 ('BEGIN PRIVATE KEY') or SPKI ('BEGIN PUBLIC KEY') PEM, never OpenSSH ('BEGIN OPENSSH PRIVATE KEY') or encrypted PEM.
- Validate every key file with 'openssl pkey -in f.pem -noout' as part of config setup or CI.
- Use LoadPEMVerifier only for public keys/certificates; keep signing keys out of verifier paths.
- Pin key algorithms to RSA, ECDSA, or Ed25519 in your provisioning docs; reject DSA keys.
When it happens
Trigger: Calling LoadPEMVerifier(path) or LoadPEMVerifierBytes(contents) with a PEM file whose block.Bytes does not parse as PKIX public key, x509 certificate, PKCS#8 private key, PKCS#1 RSA private key, or EC private key. Reached only via the loadPEMPublicKey fallback chain, so it is wrapped as "load verifier %q: ..." or surfaces after the earlier parse attempts fail.
Common situations: Pointing the verifier at a full signing key in an unusual format (e.g. OpenSSH "OPENSSH PRIVATE KEY" format instead of PKCS#8/PEM), passing a certificate request or encrypted ("ENCRYPTED PRIVATE KEY") PEM, a truncated or corrupt key file, or a DSA key. Note PKCS#8 keys that decode but do not implement crypto.Signer produce a different message, so this specific error means even DER-level parsing failed.
Related errors
- unsupported private key in signer %q
- unsupported PEM verifier data
- marshal public key: %w
- read verifier %q: %w
- load verifier %q: %w
AI-assisted analysis of hashicorp/packer@eb36e3c3e4 (2026-09-05).
Data as JSON: /api/errors/ce9109e30744373a.
Report an issue: GitHub.