hashicorp/packer · error

verify keyless certificate identity

Error message

verify keyless certificate identity: %w

What it means

This error wraps a failed identity.Verify(summary) call: the Fulcio certificate's summarized identities (SANs, issuer) did not match the expected keyless identity policy built from the configured keyless_identity and keyless_oidc_issuer. The library throws it during keyless attestation verification to reject certificates that were issued to a different identity or OIDC provider than the one configured, preventing signature forgery by an unrelated valid certificate.

Solutions

  1. Compare the certificate's actual SAN and issuer (from the Fulcio cert or Rekor entry) and set keyless_identity / keyless_oidc_issuer to exactly those values.
  2. Re-sign the artifact from the intended workflow/identity if the artifact came from an unintended source.
  3. If the identity includes workflow ref/sha, ensure the expectation matches the sigstore SAN format (e.g. https://github.com/org/repo/.github/workflows/wf.yml@refs/heads/main) or relax to the repo-level URI.
  4. Verify the trusted root corresponds to the OIDC provider that issued the signing token.

Example fix

// before
keyless_identity = "https://github.com/org/other-repo/..."
keyless_oidc_issuer = "https://token.actions.githubusercontent.com"
// after
keyless_identity = "https://github.com/org/repo/.github/workflows/release.yml@refs/tags/v1.0.0"
keyless_oidc_issuer = "https://token.actions.githubusercontent.com"
Defensive patterns

Strategy: validation

Validate before calling

// Before verifying, confirm the expected identity matches the signing workflow:
// expected: "https://github.com/org/repo/.github/workflows/release.yml@refs/tags/v1.0.0"
// issuer:   "https://token.actions.githubusercontent.com"
if !strings.HasPrefix(expectedIdentity, "https://github.com/org/repo/.github/workflows/") {
    return fmt.Errorf("expected identity does not match the signing workflow")
}

Try / catch

err := verifier.Verify(ctx, payloadType, payload, sig)
if err != nil && strings.Contains(err.Error(), "verify keyless certificate identity") {
    // inspect cert SAN/issuer vs configured identity; fail closed, do not retry
}

Prevention

When it happens

Trigger: keylessVerifier.Verify -> verifyKeylessCertificate -> identity.Verify(summary) returns mismatch when the certificate's SAN does not equal cfg.KeylessIdentity or its OIDC issuer does not equal cfg.KeylessOIDCIssuer (internal/attestation/sign_keyless.go:75-77).

Common situations: Verifying an artifact signed by a different workflow/repo than configured (e.g. identity set to repo A but signed from repo B); using the wrong OIDC issuer (GitLab vs GitHub); expected identity includes a ref/branch while the cert SAN omits it; case or trailing-slash differences in the issuer URL.

Understand the failure class

Related errors


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

Appendix: source

Thrown at internal/attestation/sign_keyless.go:76

	// When using the public Sigstore root (no custom trusted root configured),
	// require a valid SCT so certificates issued outside a public CT log are rejected.
	if strings.TrimSpace(trustedRootPath) == "" {
		if err := sigstoreverify.VerifySignedCertificateTimestamp(chains, 1, trustedMaterial); err != nil {
			return fmt.Errorf("verify Fulcio certificate SCT: %w", err)
		}
	}

	summary, err := fulciocertificate.SummarizeCertificate(certificate)
	if err != nil {
		return fmt.Errorf("summarize Fulcio certificate: %w", err)
	}

	identity, err := sigstoreverify.NewShortCertificateIdentity(expectedOIDCIssuer, "", expectedIdentity, "")
	if err != nil {
		return fmt.Errorf("build keyless identity policy: %w", err)
	}
	if err := identity.Verify(summary); err != nil {
		return fmt.Errorf("verify keyless certificate identity: %w", err)
	}

	return nil
}

func init() {
	RegisterSigner(SigningModeKeyless, newKeylessSigner)
}

type keylessSigner struct {
	keypair  sigstoregosign.Keypair
	certPEM  []byte
	cert     *x509.Certificate
	verifier Verifier
	keyID    string
}

func newKeylessSigner(ctx context.Context, cfg BackendConfig) (Signer, error) {

View on GitHub (pinned to eb36e3c3e4)