hashicorp/packer · error

parse keyless certificate: %w

Error message

parse keyless certificate: %w

What it means

A PEM block was successfully decoded from the signature's Cert field, but x509.ParseCertificate rejected the DER bytes inside it. This means the PEM armor is present but its payload is not a parseable X.509 certificate (wrong block type, truncated bytes, or corrupted content).

Source

Thrown at internal/attestation/sign_keyless.go:281

func (v *keylessVerifier) KeyID() string {
	return v.signatureVerifier.KeyID()
}

func certificateFromEnvelope(envelope Envelope) (*x509.Certificate, error) {
	for _, signature := range envelope.Signatures {
		if strings.TrimSpace(signature.Cert) == "" {
			continue
		}

		block, _ := pem.Decode([]byte(signature.Cert))
		if block == nil {
			return nil, fmt.Errorf("decode keyless certificate: no PEM block found")
		}

		certificate, err := x509.ParseCertificate(block.Bytes)
		if err != nil {
			return nil, fmt.Errorf("parse keyless certificate: %w", err)
		}

		return certificate, nil
	}

	return nil, fmt.Errorf("keyless attestation does not contain a signing certificate")
}

type staticCertificateProvider struct {
	certDER []byte
}

func (p staticCertificateProvider) GetCertificate(context.Context, sigstoregosign.Keypair, *sigstoregosign.CertificateProviderOptions) ([]byte, error) {
	if len(p.certDER) == 0 {
		return nil, fmt.Errorf("static certificate provider is missing a certificate")
	}

	return append([]byte(nil), p.certDER...), nil

View on GitHub (pinned to eb36e3c3e4)

Solutions

  1. Check the wrapped x509 error for the specific ASN.1 failure (truncated, wrong type).
  2. Confirm the PEM block type is "CERTIFICATE" and the DER is complete (no missing final lines).
  3. Regenerate the attestation envelope from the original keyless signer.
  4. Validate the certificate with openssl x509 -in cert.pem -text -noout outside the library to isolate corruption.

Example fix

// before
block, _ := pem.Decode([]byte(sig.Cert))
cert, err := x509.ParseCertificate(block.Bytes) // fails on non-CERTIFICATE blocks
// after
block, _ := pem.Decode([]byte(sig.Cert))
if block == nil || block.Type != "CERTIFICATE" {
    return fmt.Errorf("expected CERTIFICATE PEM block, got %q", blockName(block))
}
cert, err := x509.ParseCertificate(block.Bytes)
Defensive patterns

Strategy: validation

Validate before calling

func validCertPEM(s string) (*x509.Certificate, error) {
    block, _ := pem.Decode([]byte(s))
    if block == nil || block.Type != "CERTIFICATE" {
        return nil, fmt.Errorf("not a CERTIFICATE PEM block")
    }
    return x509.ParseCertificate(block.Bytes)
}
// pre-validate
if _, err := validCertPEM(sig.Cert); err != nil {
    return fmt.Errorf("attestation certificate malformed: %w", err)
}

Type guard

func parsesAsCertificate(s string) bool {
    block, _ := pem.Decode([]byte(s))
    if block == nil || block.Type != "CERTIFICATE" {
        return false
    }
    _, err := x509.ParseCertificate(block.Bytes)
    return err == nil
}

Try / catch

verifier, err := newKeylessVerifierForEnvelope(cfg, envelope)
if err != nil && strings.Contains(err.Error(), "parse keyless certificate") {
    return fmt.Errorf("attestation certificate DER is corrupt or wrong type: %w", err)
}

Prevention

When it happens

Trigger: certificateFromEnvelope is called (via newKeylessVerifierForEnvelope or the TestKeylessBundleAndRekorIntegration test) with an envelope whose signature Cert decodes to PEM containing non-certificate DER, truncated DER, or a private key/CSR block.

Common situations: PEM block type mismatch (e.g. CERTIFICATE REQUEST or PRIVATE KEY instead of CERTIFICATE); copy/paste truncation of the final base64 lines; corruption during storage or transmission of the attestation JSON.

Understand the failure class

Related errors


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