hashicorp/packer · error

decode keyless certificate: no PEM block found

Error message

decode keyless certificate: no PEM block found

What it means

certificateFromEnvelope iterates the envelope's signatures looking for one with a Cert field, and pem.Decode returned no block for the first non-empty Cert. This means the signature's certificate field is non-empty but is not valid PEM (missing -----BEGIN CERTIFICATE----- armor, base64-encoded instead of PEM-encoded, or corrupted). The function aborts instead of skipping to the next signature.

Source

Thrown at internal/attestation/sign_keyless.go:276

		return err
	}

	return v.signatureVerifier.Verify(ctx, payloadType, payload, signature)
}

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) {

View on GitHub (pinned to eb36e3c3e4)

Solutions

  1. Ensure EnvelopeSignature.Cert is PEM-encoded (pem.EncodeToMemory of the DER bytes) before building the envelope.
  2. If the value is base64, decode it with base64.StdEncoding.DecodeString and then PEM-encode the DER.
  3. Regenerate the attestation from the original signer so the certificate is emitted in the canonical PEM form.
  4. Check the producing tool version for known certificate-format changes.

Example fix

// before
sig.Cert = base64.StdEncoding.EncodeToString(certDER)
// after
sig.Cert = string(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER}))
Defensive patterns

Strategy: validation

Validate before calling

func isPEMCertificate(s string) bool {
    block, _ := pem.Decode([]byte(s))
    return block != nil && block.Type == "CERTIFICATE"
}
// check every signature before calling newKeylessVerifierForEnvelope
for _, sig := range env.Signatures {
    if strings.TrimSpace(sig.Cert) != "" && !isPEMCertificate(sig.Cert) {
        return fmt.Errorf("signature cert is not PEM-encoded")
    }
}

Type guard

func firstPEMCertificate(sig []EnvelopeSignature) (string, bool) {
    for _, s := range sig {
        if strings.TrimSpace(s.Cert) == "" {
            continue
        }
        block, _ := pem.Decode([]byte(s.Cert))
        if block != nil && block.Type == "CERTIFICATE" {
            return s.Cert, true
        }
    }
    return "", false
}

Try / catch

verifier, err := newKeylessVerifierForEnvelope(cfg, envelope)
if err != nil && strings.Contains(err.Error(), "no PEM block found") {
    return fmt.Errorf("attestation certificate is not PEM-encoded; re-produce the attestation: %w", err)
}

Prevention

When it happens

Trigger: newKeylessVerifierForEnvelope is called with an Envelope whose first signature with a non-empty Cert contains raw DER bytes, base64 text, or truncated PEM rather than PEM-encoded certificate text.

Common situations: Storing the certificate base64-encoded (from protobuf bundles) but forgetting to decode before placing it in EnvelopeSignature.Cert; hand-editing or truncating attestation JSON; an older producer version that emitted raw DER.

Understand the failure class

Related errors


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