{"record":{"id":"28043e677d9463bf","repo":"hashicorp/packer","slug":"keyless-attestation-does-not-contain-a-signing-cer","errorCode":null,"errorMessage":"keyless attestation does not contain a signing certificate","messagePattern":"keyless attestation does not contain a signing certificate","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/attestation/sign_keyless.go","lineNumber":287,"sourceCode":"\tfor _, signature := range envelope.Signatures {\n\t\tif strings.TrimSpace(signature.Cert) == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tblock, _ := pem.Decode([]byte(signature.Cert))\n\t\tif block == nil {\n\t\t\treturn nil, fmt.Errorf(\"decode keyless certificate: no PEM block found\")\n\t\t}\n\n\t\tcertificate, err := x509.ParseCertificate(block.Bytes)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"parse keyless certificate: %w\", err)\n\t\t}\n\n\t\treturn certificate, nil\n\t}\n\n\treturn nil, fmt.Errorf(\"keyless attestation does not contain a signing certificate\")\n}\n\ntype staticCertificateProvider struct {\n\tcertDER []byte\n}\n\nfunc (p staticCertificateProvider) GetCertificate(context.Context, sigstoregosign.Keypair, *sigstoregosign.CertificateProviderOptions) ([]byte, error) {\n\tif len(p.certDER) == 0 {\n\t\treturn nil, fmt.Errorf(\"static certificate provider is missing a certificate\")\n\t}\n\n\treturn append([]byte(nil), p.certDER...), nil\n}\n\nfunc resolveAmbientIDToken(ctx context.Context, env map[string]string) (string, error) {\n\tif token := strings.TrimSpace(env[\"SIGSTORE_ID_TOKEN\"]); token != \"\" {\n\t\treturn token, nil\n\t}","sourceCodeStart":269,"sourceCodeEnd":305,"githubUrl":"https://github.com/hashicorp/packer/blob/eb36e3c3e48a036f3e8cc94087636ee72e1303c9/internal/attestation/sign_keyless.go#L269-L305","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify the attestation was produced with signing_mode=\"keyless\"; if it was key-backed, use the corresponding key-based verifier.","Check that the producer populated EnvelopeSignature.Cert with the PEM certificate (as keylessSigner.SignBundle does).","Re-sign/re-attest the payload if the source envelope is missing the certificate by design.","Log the number of signatures and their Cert lengths before calling to confirm the envelope shape."],"exampleFix":"// before\nv, err := newKeylessVerifierForEnvelope(cfg, envelope)\n// after\nhasCert := false\nfor _, s := range envelope.Signatures {\n    if strings.TrimSpace(s.Cert) != \"\" {\n        hasCert = true\n    }\n}\nif !hasCert {\n    return fmt.Errorf(\"envelope has no signing certificate; use the key-based verifier\")\n}\nv, err := newKeylessVerifierForEnvelope(cfg, envelope)","handlingStrategy":"validation","validationCode":"func envelopeHasCertificate(env Envelope) bool {\n    for _, s := range env.Signatures {\n        if strings.TrimSpace(s.Cert) != \"\" {\n            return true\n        }\n    }\n    return false\n}\nif !envelopeHasCertificate(envelope) {\n    return fmt.Errorf(\"envelope carries no signing certificate; use a key-based verifier\")\n}","typeGuard":"func isKeylessEnvelope(env Envelope) bool {\n    return envelopeHasCertificate(env)\n}","tryCatchPattern":"verifier, err := newKeylessVerifierForEnvelope(cfg, envelope)\nif err != nil && strings.Contains(err.Error(), \"does not contain a signing certificate\") {\n    // fall back to the key-based verifier for non-keyless attestations\n    verifier, err = newKeyVerifier(cfg, envelope)\n}","preventionTips":["Match the verifier mode to the producer's signing_mode before verification.","Require Cert to be populated in keyless attestation schemas.","Route key-backed and keyless attestations through different verification paths.","Record the signing mode alongside stored attestations."],"tags":["go","keyless-signing","attestation","envelope"],"backgroundTag":"missing-signing-certificate","analyzedSha":"eb36e3c3e48a036f3e8cc94087636ee72e1303c9","analyzedAt":"2026-09-05T13:20:43.127Z","contentChangedAt":"2026-09-05T13:20:43.127Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}