hashicorp/packer · error

signer %q does not implement crypto.Signer

Error message

signer %q does not implement crypto.Signer

What it means

The PEM block parsed successfully as a PKCS#8 private key, but the resulting Go value does not implement crypto.Signer, so it cannot be used to sign attestations. loadPEMSigner rejects it rather than returning a signer that cannot Sign(). This typically means the PKCS#8 payload wraps a key type the signer path cannot use.

Source

Thrown at internal/attestation/sign_key.go:150

}

func loadPEMSigner(path string) (crypto.Signer, *pemVerifier, error) {
	contents, err := os.ReadFile(path)
	if err != nil {
		return nil, nil, fmt.Errorf("read signer %q: %w", path, err)
	}

	block, _ := pem.Decode(contents)
	if block == nil {
		return nil, nil, fmt.Errorf("decode signer %q: no PEM block found", path)
	}

	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("signer %q does not implement crypto.Signer", path)
		}
	} 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 in signer %q", path)
	}

	publicKeyPEM, err := marshalPublicKeyPEM(signer.Public())
	if err != nil {
		return nil, nil, err
	}

	verifier, err := LoadPEMVerifierBytes(publicKeyPEM)
	if err != nil {
		return nil, nil, err
	}

View on GitHub (pinned to eb36e3c3e4)

Solutions

  1. Regenerate a standard signing key: 'openssl genpkey -algorithm ED25519' or '-algorithm RSA' / 'EC', then export as PKCS#8 PEM.
  2. Re-export the key so the PKCS#8 payload contains a normal RSA/EC/Ed25519 private key.
  3. Confirm what Go parsed by running x509.ParsePKCS8PrivateKey on the block bytes in a small test and printing the concrete type.
  4. If the key lives in an HSM, use a crypto.Signer handle (PKCS#11) rather than a PEM file, or export a software signing key.

Example fix

// before
$ openssl genpkey -algorithm <non-signing KEM> -out signer.pem
signer, _, err := attestation.NewSigner("signer.pem") // does not implement crypto.Signer
// after
$ openssl genpkey -algorithm ED25519 -out signer.pem
signer, _, err := attestation.NewSigner("signer.pem") // ok
Defensive patterns

Strategy: validation

Validate before calling

raw, _ := os.ReadFile(keyPath)
block, _ := pem.Decode(raw)
if block == nil {
	return fmt.Errorf("%s: no PEM block", keyPath)
}
key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
	return err // falls through to PKCS1/EC handling in the library
}
if _, ok := key.(crypto.Signer); !ok {
	return fmt.Errorf("%s: PKCS#8 key type %T cannot sign; regenerate with RSA/EC/Ed25519", keyPath, key)
}

Type guard

func isCryptoSigner(key any) bool {
	_, ok := key.(crypto.Signer)
	return ok
}

Try / catch

signer, verifier, err := attestation.NewSigner(keyPath)
if err != nil && strings.Contains(err.Error(), "does not implement crypto.Signer") {
	return fmt.Errorf("%s holds a non-signing key; regenerate: openssl genpkey -algorithm ED25519 -out %s", keyPath, keyPath)
}

Prevention

When it happens

Trigger: Calling newPEMSigner(path) where the file holds a PKCS#8 structure whose parsed key is not a crypto.Signer (e.g. certain PKCS#8-wrapped key agreement/key encapsulation payloads, or unusual key types like ed25519ph containers depending on the Go version).

Common situations: Key exported from an HSM or PKCS#12 bundle with an unusual algorithm identifier; a key generated for encryption-only use; mismatch between the declared OID in the PKCS#8 blob and an actual signing key.

Related errors


AI-assisted analysis of hashicorp/packer@eb36e3c3e4 (2026-09-05). Data as JSON: /api/errors/0dcd477b8b30f387. Report an issue: GitHub.