hashicorp/packer · error
marshal public key: %w
Error message
marshal public key: %w
What it means
marshalPublicKeyPEM wraps a failure from x509.MarshalPKIXPublicKey, the step that converts a parsed key into SubjectPublicKeyInfo DER before PEM-encoding. This function is used to derive the public counterpart of a loaded signer or Fulcio certificate. MarshalPKIXPublicKey fails almost exclusively when the crypto.PublicKey is of a type the standard library cannot serialize into SPKI form (in practice: unsupported key algorithms; RSA, ECDSA and Ed25519 always succeed).
Source
Thrown at internal/attestation/sign_key.go:229
}
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 {
return nil, fmt.Errorf("marshal public key: %w", err)
}
return pem.EncodeToMemory(&pem.Block{Type: "PUBLIC KEY", Bytes: encoded}), nil
}
func sha256Hex(value []byte) string {
digest := sha256.Sum256(value)
return hex.EncodeToString(digest[:])
}
View on GitHub (pinned to eb36e3c3e4)
Solutions
- Identify the key algorithm ('openssl pkey -in key.pem -text -noout'); if it is DSA, regenerate the key as RSA, ECDSA (P-256/384/521) or Ed25519.
- Convert the key to a supported algorithm: 'openssl genpkey -algorithm RSA ...' or 'openssl genpkey -algorithm ED25519', then update the configured signer.
- If the key is fine but the file is not, re-export it in PKCS#8 ('openssl pkcs8 -topk8 -nocrypt') so parsing yields a standard key type.
- If this happens with a certificate-derived key, check the certificate's Public Key Algorithm field ('openssl x509 -in cert.pem -noout -text'); use a certificate with an RSA/EC/Ed25519 key.
- Inspect the wrapped inner error from MarshalPKIXPublicKey — it names the specific marshal failure.
Example fix
// before: DSA key in PKCS#8 -> parses, but MarshalPKIXPublicKey fails // signer.pem: DSA PRIVATE KEY // after: generate a supported key and reconfigure // openssl genpkey -algorithm ED25519 -out signer.pem // signer ref = signer.pem
Defensive patterns
Strategy: validation
Validate before calling
// pre-flight: round-trip the key's public part through SPKI marshal
func canMarshalPublicKey(path string) error {
data, _ := os.ReadFile(path)
block, _ := pem.Decode(data)
if block == nil {
return fmt.Errorf("no PEM block")
}
key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return err
}
signer, ok := key.(crypto.Signer)
if !ok {
return fmt.Errorf("not a crypto.Signer")
}
if _, err := x509.MarshalPKIXPublicKey(signer.Public()); err != nil {
return fmt.Errorf("algorithm %T not SPKI-marshalable: %w", signer.Public(), err)
}
return nil
} Type guard
func isSPKIMarshalable(pub crypto.PublicKey) bool {
switch pub.(type) {
case *rsa.PublicKey, *ecdsa.PublicKey, ed25519.PublicKey:
return true
default:
return false // e.g. *dsa.PublicKey, custom key types
}
} Try / catch
signer, verifier, err := loadPEMSigner(keyPath)
if err != nil {
if strings.Contains(err.Error(), "marshal public key") {
return fmt.Errorf("signer %s: public key algorithm not supported by x509.MarshalPKIXPublicKey; regenerate as RSA/ECDSA/Ed25519: %w", keyPath, err)
}
return err
} Prevention
- Restrict key generation to RSA, ECDSA (P-256/384/521), or Ed25519; DSA keys are the classic trigger.
- Check the algorithm at key-provisioning time with 'openssl pkey -in key.pem -text -noout'.
- Keep keys in PKCS#8 PEM so ParsePKCS8PrivateKey yields a standard Go key type.
- Test key loading for every key format your pipeline can emit, not just the happy path.
When it happens
Trigger: Any caller — loadPEMSigner, loadPEMPrivateKeyAsPublic, or newSigstoreVerifierFromPublicKey — passes a crypto.PublicKey that x509.MarshalPKIXPublicKey cannot marshal, e.g. a DSA public key recovered from a PKCS#8 blob, or a custom/foreign key type implementing crypto.Signer with an exotic PublicKey().
Common situations: A DSA private key in PKCS#8 format parses fine via ParsePKCS8PrivateKey (implementing crypto.Signer) but its DSA public key cannot be marshalled to SPKI, producing this error. Also possible when a Fulcio certificate carries an unexpected public-key algorithm, or with exotic smartcard/HSM-backed signer types whose Public() returns a non-standard type.
Related errors
- unsupported private key in signer %q
- unsupported PEM verifier data
- unsupported private key data
- load verifier %q: %w
- signer %q does not implement crypto.Signer
AI-assisted analysis of hashicorp/packer@eb36e3c3e4 (2026-09-05).
Data as JSON: /api/errors/21edb2c33c7f6c1f.
Report an issue: GitHub.