{"record":{"id":"cfe8f63cb909b5f8","repo":"Netflix/chaosmonkey","slug":"pkcs-topem-failed","errorCode":null,"errorMessage":"pkcs.ToPEM failed","messagePattern":"pkcs\\.ToPEM failed","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"spinnaker/spinnaker.go","lineNumber":70,"sourceCode":"// as represented by Spinnaker API\ntype spinnakerServerGroup struct {\n\tName      string\n\tRegion    string\n\tDisabled  bool\n\tInstances []spinnakerInstance\n}\n\n// spinnakerInstance represents an instance as represented by Spinnaker API\ntype spinnakerInstance struct {\n\tName string\n}\n\n// getClient takes PKCS#12 data (encrypted cert data in .p12 format) and the\n// password for the encrypted cert, and returns an http client that does TLS client auth\nfunc getClient(pfxData []byte, password string) (*http.Client, error) {\n\tblocks, err := pkcs12.ToPEM(pfxData, password)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"pkcs.ToPEM failed\")\n\t}\n\n\t// The first block is the cert and the last block is the private key\n\tcertPEMBlock := pem.EncodeToMemory(blocks[0])\n\tkeyPEMBlock := pem.EncodeToMemory(blocks[len(blocks)-1])\n\n\tcert, err := tls.X509KeyPair(certPEMBlock, keyPEMBlock)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"tls.X509KeyPair failed\")\n\t}\n\n\ttlsConfig := &tls.Config{\n\t\tCertificates: []tls.Certificate{cert},\n\t}\n\ttransport := &http.Transport{TLSClientConfig: tlsConfig}\n\treturn &http.Client{Transport: transport}, nil\n}\n","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/Netflix/chaosmonkey/blob/eaa28fb761c0ebe8644d1333e5d164e9cc3071e9/spinnaker/spinnaker.go#L52-L88","documentation":"spinnaker.getClient builds an mTLS http client from PKCS#12 (.p12) data. golang.org/x/crypto/pkcs12.ToPEM failed to decode/decrypt the pfx blob into PEM blocks — typically the data is not valid PKCS#12, is corrupted, or the supplied password is wrong. The library wraps the underlying pkcs12 error with this message.","triggerScenarios":"Calling spinnaker.New with a non-empty certPath whose file bytes are not valid PKCS#12 (e.g. a PEM file, truncated download, or HTML error page saved as .p12), or a password that does not decrypt the pfx (via NewFromConfig with a wrong/undecryptable spinnaker encrypted password).","commonSituations":"Config points spinnaker.certificate at the wrong file; cert re-exported in a format pkcs12 (as implemented) can't parse (e.g. newer OpenSSL 3 defaults like AES-based p12 that older x/crypto can't decrypt, or MAC mismatch); KMS/credstash decryption returns the wrong password string; file mounted empty in a container.","solutions":["Verify the password: decrypt the spinnaker encrypted password correctly (check KMS/decryptor config) and confirm it opens the .p12 (e.g. `openssl pkcs12 -info -in cert.p12`)","Confirm certPath points to an actual PKCS#12 file, not a PEM/certificate chain; re-export with `openssl pkcs12 -export`","Re-download/copy the file and check it is not truncated or empty","If using a modern OpenSSL-generated p12 that fails to parse, re-export with `-legacy` or legacy algorithms compatible with golang.org/x/crypto/pkcs12"],"exampleFix":"// before\nopenssl pkcs12 -export -out spinnaker.p12 -inkey key.pem -in cert.pem   # wrong password stored in config\n// after\nopenssl pkcs12 -export -passout pass:correctpass -out spinnaker.p12 -inkey key.pem -in cert.pem\n# and ensure cfg.SpinnakerEncryptedPassword() decrypts to \"correctpass\"","handlingStrategy":"validation","validationCode":"pfx, err := ioutil.ReadFile(certPath)\nif err != nil {\n\treturn fmt.Errorf(\"cannot read cert file: %w\", err)\n}\n// Probe decode/decrypt before calling spinnaker.New\nif _, err := pkcs12.ToPEM(pfx, password); err != nil {\n\treturn fmt.Errorf(\"p12 decode failed (bad file or wrong password): %w\", err)\n}","typeGuard":"func looksLikePKCS12(data []byte) bool {\n\t// PKCS#12 is a DER ASN.1 structure; pfx starts with SEQUENCE 0x30\n\treturn len(data) > 4 && data[0] == 0x30\n}","tryCatchPattern":"sp, err := spinnaker.New(endpoint, certPath, password, \"\", \"\", user)\nif err != nil && strings.Contains(err.Error(), \"pkcs.ToPEM failed\") {\n\treturn fmt.Errorf(\"check that %s is a valid .p12 and the password is correct: %w\", certPath, err)\n}","preventionTips":["Pre-decrypt the p12 with `openssl pkcs12 -info -in cert.p12 -passin pass:$PASS` in CI before deploy","Keep the cert password in a secret manager and verify the decryptor (KMS etc.) returns the plaintext, not ciphertext","Ensure the file is a real PKCS#12 blob (magic byte 0x30 DER), not a PEM cert saved with a .p12 extension","Re-export p12 with legacy-compatible algorithms if using OpenSSL 3+ with older x/crypto"],"tags":["go","tls","pkcs12","certificate","mtls"],"backgroundTag":"pkcs12-decode-failed","analyzedSha":"eaa28fb761c0ebe8644d1333e5d164e9cc3071e9","analyzedAt":"2026-09-03T17:04:39.020Z","contentChangedAt":"2026-09-03T17:04:39.020Z","schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}