{"record":{"id":"1ce27d7187fac6c6","repo":"hashicorp/packer","slug":"decode-signer-q-no-pem-block-found","errorCode":null,"errorMessage":"decode signer %q: no PEM block found","messagePattern":"decode signer %q: no PEM block found","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/attestation/sign_key.go","lineNumber":142,"sourceCode":"\t\treturn nil, err\n\t}\n\n\treturn &pemVerifier{\n\t\tpublicKey: publicKey,\n\t\tkeyID:     sha256Hex(rawVerifier),\n\t}, nil\n\n}\n\nfunc loadPEMSigner(path string) (crypto.Signer, *pemVerifier, error) {\n\tcontents, err := os.ReadFile(path)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"read signer %q: %w\", path, err)\n\t}\n\n\tblock, _ := pem.Decode(contents)\n\tif block == nil {\n\t\treturn nil, nil, fmt.Errorf(\"decode signer %q: no PEM block found\", path)\n\t}\n\n\tvar signer crypto.Signer\n\tif key, err := x509.ParsePKCS8PrivateKey(block.Bytes); err == nil {\n\t\tvar ok bool\n\t\tsigner, ok = key.(crypto.Signer)\n\t\tif !ok {\n\t\t\treturn nil, nil, fmt.Errorf(\"signer %q does not implement crypto.Signer\", path)\n\t\t}\n\t} else if key, err := x509.ParsePKCS1PrivateKey(block.Bytes); err == nil {\n\t\tsigner = key\n\t} else if key, err := x509.ParseECPrivateKey(block.Bytes); err == nil {\n\t\tsigner = key\n\t} else {\n\t\treturn nil, nil, fmt.Errorf(\"unsupported private key in signer %q\", path)\n\t}\n\n\tpublicKeyPEM, err := marshalPublicKeyPEM(signer.Public())","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/hashicorp/packer/blob/eb36e3c3e48a036f3e8cc94087636ee72e1303c9/internal/attestation/sign_key.go#L124-L160","documentation":"loadPEMSigner read the file but pem.Decode returned nil, meaning the contents contain no valid PEM block at all. PEM requires the '-----BEGIN ...-----'/'-----END ...-----' ASCII armor; raw DER bytes, JSON, or an empty file all fail here. The message is static (not wrapped), so the path is included for identification only.","triggerScenarios":"Calling newPEMSigner(path) with a file containing raw DER-encoded key bytes, base64 without armor lines, an empty file, or text where the BEGIN line is malformed (e.g. wrong number of dashes or extra leading bytes before the header).","commonSituations":"Exported key with 'openssl pkcs8 -topk8 -outform DER'; base64 blob pasted into a file without armor; downloading a key through a tool that stripped newlines; truncated/corrupted file after a failed transfer.","solutions":["Verify the file literally starts with '-----BEGIN' (head -1 key.pem); convert raw DER with 'openssl pkcs8 -inform DER -in key.der -out key.pem'.","Re-export or re-download the key ensuring PEM (base64 armor) output.","Check the file is not empty and was not truncated (compare byte size with the source).","Call pem.Decode yourself in a pre-check to validate the file before invoking the signer."],"exampleFix":"// before\n$ openssl pkcs8 -topk8 -in key.pem -outform DER -out key.der  // no armor\nsigner, _, err := attestation.NewSigner(\"key.der\") // no PEM block found\n// after\n$ openssl pkcs8 -topk8 -in key.pem -out key.pem.new // PEM armor kept\nsigner, _, err := attestation.NewSigner(\"key.pem.new\")","handlingStrategy":"validation","validationCode":"raw, err := os.ReadFile(keyPath)\nif err != nil {\n\treturn err\n}\nblock, _ := pem.Decode(raw)\nif block == nil {\n\treturn fmt.Errorf(\"%s: no PEM armor; expected -----BEGIN ... PRIVATE KEY-----\", keyPath)\n}","typeGuard":"func isPEM(b []byte) bool {\n\tblock, _ := pem.Decode(b)\n\treturn block != nil\n}","tryCatchPattern":"signer, verifier, err := attestation.NewSigner(keyPath)\nif err != nil && strings.Contains(err.Error(), \"no PEM block found\") {\n\treturn fmt.Errorf(\"%s must be PEM-encoded; convert DER with: openssl pkcs8 -inform DER -in key.der -out key.pem\", keyPath)\n}","preventionTips":["Always export keys with PEM output (avoid -outform DER for files consumed by this library).","Check 'head -1 key.pem' shows '-----BEGIN' after every key transfer.","Never paste base64 blobs into key files without the BEGIN/END armor lines.","Verify file size/checksum after download or copy to catch truncation."],"tags":["go","pem","encoding","signing"],"backgroundTag":"pem-decode-failed","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"}