{"record":{"id":"e2ad5915988a78da","repo":"cilium/cilium","slug":"failed-to-parse-certificate-w","errorCode":null,"errorMessage":"failed to parse certificate: %w","messagePattern":"failed to parse certificate: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/auth/mutual_authhandler.go","lineNumber":133,"sourceCode":"\n\t// set up TLS socket\n\n\t//nolint:gosec // InsecureSkipVerify is not insecure as we do the verification in VerifyPeerCertificate\n\ttlsConn := tls.Client(conn, &tls.Config{\n\t\tServerName: m.cert.NumericIdentityToSNI(ar.remoteIdentity),\n\t\tGetClientCertificate: func(info *tls.CertificateRequestInfo) (*tls.Certificate, error) {\n\t\t\treturn clientCert, nil\n\t\t},\n\t\tMinVersion:         tls.VersionTLS13,\n\t\tInsecureSkipVerify: true, // not insecure as we do the verification in VerifyPeerCertificate\n\t\tVerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {\n\t\t\t// verifiedChains will be nil as we set InsecureSkipVerify to true\n\n\t\t\tchain := make([]*x509.Certificate, len(rawCerts))\n\t\t\tfor i, rawCert := range rawCerts {\n\t\t\t\tcert, err := x509.ParseCertificate(rawCert)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to parse certificate: %w\", err)\n\t\t\t\t}\n\t\t\t\tchain[i] = cert\n\t\t\t}\n\n\t\t\tpeerExpirationTime, err := m.verifyPeerCertificate(&ar.remoteIdentity, caBundle, [][]*x509.Certificate{chain})\n\t\t\tif peerExpirationTime != nil && peerExpirationTime.Before(*expirationTime) {\n\t\t\t\texpirationTime = peerExpirationTime // send down the lowest expiration time of the two certificates\n\t\t\t}\n\t\t\treturn err\n\t\t},\n\t\tClientCAs: caBundle,\n\t\tRootCAs:   caBundle,\n\t})\n\tdefer tlsConn.Close()\n\n\tif err := tlsConn.Handshake(); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to perform TLS handshake: %w\", err)\n\t}","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/cilium/cilium/blob/ac7b90affa4baf0642e6685319d56907b3a73a6d/pkg/auth/mutual_authhandler.go#L115-L151","documentation":"During the TLS handshake the peer presented certificates in raw (DER) form which the handler parses with x509.ParseCertificate; one of the peer's certificates is malformed and cannot be parsed into an x509.Certificate. This happens inside the handshake verification callback, so the handshake is aborted.","triggerScenarios":"the VerifyPeerCertificate callback receives rawCerts from the TLS stack and x509.ParseCertificate(rawCert) errors — truncated or corrupted certificate bytes, or a peer sending a non-X.509/unexpected certificate format.","commonSituations":"remote agent serving a corrupt or truncated certificate after a failed rotation; a middlebox/proxy interfering with TLS; version mismatch where peers negotiate unexpected cert formats; memory corruption during cert storage.","solutions":["Restart the remote node's Cilium agent so it re-issues/re-loads its certificate","Force certificate re-issuance via the certificate provider (SPIRE re-attestation) on the peer","Verify no proxy/TLS-terminating middlebox sits between the nodes on the auth port","Capture the peer's certificate bytes (tls debug) and confirm they are valid DER; upgrade Cilium if a known parsing bug matches"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := authManager.Authenticate(ctx, key); err != nil {\n\tif strings.Contains(err.Error(), \"failed to parse certificate\") {\n\t\t// peer certificate corrupt: trigger remote agent cert re-issuance, then retry\n\t}\n}","preventionTips":["Avoid TLS-intercepting middleboxes on the auth port","Monitor certificate rotation success on all nodes","Keep agent versions consistent across the mesh"],"tags":["tls","x509","certificate","cilium"],"backgroundTag":"certificate-parse-failed","analyzedSha":"ac7b90affa4baf0642e6685319d56907b3a73a6d","analyzedAt":"2026-08-31T18:27:15.868Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}