{"record":{"id":"5a63d65d49aaf3a7","repo":"hashicorp/packer","slug":"decode-keyless-certificate-no-pem-block-found","errorCode":null,"errorMessage":"decode keyless certificate: no PEM block found","messagePattern":"decode keyless certificate: no PEM block found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/attestation/sign_keyless.go","lineNumber":276,"sourceCode":"\t\treturn err\n\t}\n\n\treturn v.signatureVerifier.Verify(ctx, payloadType, payload, signature)\n}\n\nfunc (v *keylessVerifier) KeyID() string {\n\treturn v.signatureVerifier.KeyID()\n}\n\nfunc certificateFromEnvelope(envelope Envelope) (*x509.Certificate, error) {\n\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) {","sourceCodeStart":258,"sourceCodeEnd":294,"githubUrl":"https://github.com/hashicorp/packer/blob/eb36e3c3e48a036f3e8cc94087636ee72e1303c9/internal/attestation/sign_keyless.go#L258-L294","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Ensure EnvelopeSignature.Cert is PEM-encoded (pem.EncodeToMemory of the DER bytes) before building the envelope.","If the value is base64, decode it with base64.StdEncoding.DecodeString and then PEM-encode the DER.","Regenerate the attestation from the original signer so the certificate is emitted in the canonical PEM form.","Check the producing tool version for known certificate-format changes."],"exampleFix":"// before\nsig.Cert = base64.StdEncoding.EncodeToString(certDER)\n// after\nsig.Cert = string(pem.EncodeToMemory(&pem.Block{Type: \"CERTIFICATE\", Bytes: certDER}))","handlingStrategy":"validation","validationCode":"func isPEMCertificate(s string) bool {\n    block, _ := pem.Decode([]byte(s))\n    return block != nil && block.Type == \"CERTIFICATE\"\n}\n// check every signature before calling newKeylessVerifierForEnvelope\nfor _, sig := range env.Signatures {\n    if strings.TrimSpace(sig.Cert) != \"\" && !isPEMCertificate(sig.Cert) {\n        return fmt.Errorf(\"signature cert is not PEM-encoded\")\n    }\n}","typeGuard":"func firstPEMCertificate(sig []EnvelopeSignature) (string, bool) {\n    for _, s := range sig {\n        if strings.TrimSpace(s.Cert) == \"\" {\n            continue\n        }\n        block, _ := pem.Decode([]byte(s.Cert))\n        if block != nil && block.Type == \"CERTIFICATE\" {\n            return s.Cert, true\n        }\n    }\n    return \"\", false\n}","tryCatchPattern":"verifier, err := newKeylessVerifierForEnvelope(cfg, envelope)\nif err != nil && strings.Contains(err.Error(), \"no PEM block found\") {\n    return fmt.Errorf(\"attestation certificate is not PEM-encoded; re-produce the attestation: %w\", err)\n}","preventionTips":["Always emit EnvelopeSignature.Cert via pem.EncodeToMemory, mirroring keylessSigner.SignBundle.","Never store base64 DER directly in the Cert field; PEM-encode it.","Round-trip test envelopes through certificateFromEnvelope in CI.","Validate attestation JSON schema before verification."],"tags":["go","pem","x509","attestation"],"backgroundTag":"invalid-pem-block","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"}