fix(nodes): validate every certificate in the node mTLS trust bundle (#6188)

* fix(nodes): validate every certificate in the node mTLS trust bundle

AppendCertsFromPEM reports success once a single certificate parses, so a
trust bundle whose later entries are damaged or truncated was accepted with
those entries silently absent from the pool. Parse and validate every PEM
block instead, and reject the bundle if any of them is malformed.

* fix(mtls): reject malformed certificate bundle layout

---------

Co-authored-by: n0ctal <293235942+n0ctal@users.noreply.github.com>
This commit is contained in:
n0ctal
2026-08-16 00:31:31 +05:00
committed by GitHub
parent 338822ab07
commit bab39393f1
3 changed files with 116 additions and 14 deletions
+4 -12
View File
@@ -2,8 +2,6 @@ package service
import (
"crypto/tls"
"crypto/x509"
"encoding/pem"
"strings"
"github.com/mhsanaei/3x-ui/v3/internal/util/common"
@@ -42,19 +40,13 @@ func (s *NodeService) ReloadMasterMtlsClient() error {
return nil
}
// SetNodeMtlsTrustCA stores the CA certificate this panel trusts for incoming
// node-API client certificates. An empty value clears it (mTLS off). A
// non-empty value must be a PEM certificate (fail closed). Takes effect on the
// next panel restart, when the listener's ClientCAs is rebuilt.
// SetNodeMtlsTrustCA stores the CA certificate bundle trusted for incoming
// node-API clients. An empty value clears it; changes apply after restart.
func (s *NodeService) SetNodeMtlsTrustCA(caPem string) error {
caPem = strings.TrimSpace(caPem)
if caPem != "" {
block, _ := pem.Decode([]byte(caPem))
if block == nil || block.Type != "CERTIFICATE" {
return common.NewError("trust CA must be a PEM-encoded certificate")
}
if _, err := x509.ParseCertificate(block.Bytes); err != nil {
return common.NewError("invalid trust CA certificate: " + err.Error())
if _, err := parseCertificateBundlePEM([]byte(caPem)); err != nil {
return common.NewError("invalid trust CA certificate bundle: ", err)
}
}
return (&SettingService{}).setString(settingNodeMtlsClientCA, caPem)