Netflix/chaosmonkey · critical
pkcs.ToPEM failed
Error message
pkcs.ToPEM failed
What it means
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.
Source
Thrown at spinnaker/spinnaker.go:70
// as represented by Spinnaker API
type spinnakerServerGroup struct {
Name string
Region string
Disabled bool
Instances []spinnakerInstance
}
// spinnakerInstance represents an instance as represented by Spinnaker API
type spinnakerInstance struct {
Name string
}
// getClient takes PKCS#12 data (encrypted cert data in .p12 format) and the
// password for the encrypted cert, and returns an http client that does TLS client auth
func getClient(pfxData []byte, password string) (*http.Client, error) {
blocks, err := pkcs12.ToPEM(pfxData, password)
if err != nil {
return nil, errors.Wrap(err, "pkcs.ToPEM failed")
}
// The first block is the cert and the last block is the private key
certPEMBlock := pem.EncodeToMemory(blocks[0])
keyPEMBlock := pem.EncodeToMemory(blocks[len(blocks)-1])
cert, err := tls.X509KeyPair(certPEMBlock, keyPEMBlock)
if err != nil {
return nil, errors.Wrap(err, "tls.X509KeyPair failed")
}
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
}
transport := &http.Transport{TLSClientConfig: tlsConfig}
return &http.Client{Transport: transport}, nil
}
View on GitHub (pinned to eaa28fb761)
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
Example fix
// before openssl pkcs12 -export -out spinnaker.p12 -inkey key.pem -in cert.pem # wrong password stored in config // after openssl pkcs12 -export -passout pass:correctpass -out spinnaker.p12 -inkey key.pem -in cert.pem # and ensure cfg.SpinnakerEncryptedPassword() decrypts to "correctpass"
Defensive patterns
Strategy: validation
Validate before calling
pfx, err := ioutil.ReadFile(certPath)
if err != nil {
return fmt.Errorf("cannot read cert file: %w", err)
}
// Probe decode/decrypt before calling spinnaker.New
if _, err := pkcs12.ToPEM(pfx, password); err != nil {
return fmt.Errorf("p12 decode failed (bad file or wrong password): %w", err)
} Type guard
func looksLikePKCS12(data []byte) bool {
// PKCS#12 is a DER ASN.1 structure; pfx starts with SEQUENCE 0x30
return len(data) > 4 && data[0] == 0x30
} Try / catch
sp, err := spinnaker.New(endpoint, certPath, password, "", "", user)
if err != nil && strings.Contains(err.Error(), "pkcs.ToPEM failed") {
return fmt.Errorf("check that %s is a valid .p12 and the password is correct: %w", certPath, err)
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- tls.X509KeyPair failed
- failed to read file %s
- schedule already exists
- 'attributes' field missing
- 'attributes.chaosMonkey' field missing
AI-assisted analysis of Netflix/chaosmonkey@eaa28fb761 (2026-09-03).
Data as JSON: /api/errors/cfe8f63cb909b5f8.
Report an issue: GitHub.