hashicorp/packer · error

keyless attestation does not contain a signing certificate

Error message

keyless attestation does not contain a signing certificate

What it means

certificateFromEnvelope examined every signature in the envelope and found none with a non-empty Cert field. Keyless attestations must carry the Fulcio-issued signing certificate in the signature so the verifier can establish identity; an envelope without one cannot be verified in keyless mode.

Source

Thrown at internal/attestation/sign_keyless.go:287

	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
}

func resolveAmbientIDToken(ctx context.Context, env map[string]string) (string, error) {
	if token := strings.TrimSpace(env["SIGSTORE_ID_TOKEN"]); token != "" {
		return token, nil
	}

View on GitHub (pinned to eb36e3c3e4)

Solutions

  1. Verify the attestation was produced with signing_mode="keyless"; if it was key-backed, use the corresponding key-based verifier.
  2. Check that the producer populated EnvelopeSignature.Cert with the PEM certificate (as keylessSigner.SignBundle does).
  3. Re-sign/re-attest the payload if the source envelope is missing the certificate by design.
  4. Log the number of signatures and their Cert lengths before calling to confirm the envelope shape.

Example fix

// before
v, err := newKeylessVerifierForEnvelope(cfg, envelope)
// after
hasCert := false
for _, s := range envelope.Signatures {
    if strings.TrimSpace(s.Cert) != "" {
        hasCert = true
    }
}
if !hasCert {
    return fmt.Errorf("envelope has no signing certificate; use the key-based verifier")
}
v, err := newKeylessVerifierForEnvelope(cfg, envelope)
Defensive patterns

Strategy: validation

Validate before calling

func envelopeHasCertificate(env Envelope) bool {
    for _, s := range env.Signatures {
        if strings.TrimSpace(s.Cert) != "" {
            return true
        }
    }
    return false
}
if !envelopeHasCertificate(envelope) {
    return fmt.Errorf("envelope carries no signing certificate; use a key-based verifier")
}

Type guard

func isKeylessEnvelope(env Envelope) bool {
    return envelopeHasCertificate(env)
}

Try / catch

verifier, err := newKeylessVerifierForEnvelope(cfg, envelope)
if err != nil && strings.Contains(err.Error(), "does not contain a signing certificate") {
    // fall back to the key-based verifier for non-keyless attestations
    verifier, err = newKeyVerifier(cfg, envelope)
}

Prevention

When it happens

Trigger: newKeylessVerifierForEnvelope is called with an Envelope produced by a key-backed signer (signing_mode other than "keyless") or an envelope whose signatures all have empty/whitespace-only Cert fields.

Common situations: Mixing signing modes: verifying a key-signed or none-mode attestation with keyless verification config; an external tool produced a Sigstore bundle stripped of its certificate; deserialization dropped the Cert field.

Understand the failure class

Related errors


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