package busauth import ( "crypto/tls" "crypto/x509" "fmt" "os" ) // LoadCATLSConfig builds a *tls.Config that trusts ONLY the given CA certificate // (PEM file), for a bus client pinning the project's self-signed CA. Because the // bus uses a private CA rather than a public one, clients must pin it explicitly; // trusting the system roots would reject the server cert. This is the single // helper every client (Go peers, the mobile binding, the gateway) uses to turn a // ca.crt path into a connection config. func LoadCATLSConfig(caPEMPath string) (*tls.Config, error) { pem, err := os.ReadFile(caPEMPath) if err != nil { return nil, fmt.Errorf("busauth: read CA %q: %w", caPEMPath, err) } pool := x509.NewCertPool() if !pool.AppendCertsFromPEM(pem) { return nil, fmt.Errorf("busauth: CA %q contains no valid PEM certificate", caPEMPath) } return &tls.Config{RootCAs: pool, MinVersion: tls.VersionTLS12}, nil } // ServerTLSConfig loads the bus NATS server's certificate and private key (PEM // files) into a *tls.Config to present to clients. The private key never leaves // the host; only the CA cert travels to clients. func ServerTLSConfig(certPEMPath, keyPEMPath string) (*tls.Config, error) { cert, err := tls.LoadX509KeyPair(certPEMPath, keyPEMPath) if err != nil { return nil, fmt.Errorf("busauth: load server keypair: %w", err) } return &tls.Config{Certificates: []tls.Certificate{cert}, MinVersion: tls.VersionTLS12}, nil } // RouteTLSConfig builds the mutual-TLS config for the NATS CLUSTER route layer // (issue 0003a). Unlike the client data plane, where the server presents a cert // and only the client verifies it, routes are server-to-server: each node both // presents its own node certificate AND verifies the connecting node's // certificate against the bus CA. So this single config carries: // // - Certificates: this node's CA-signed certificate (presented in both the // server and the client role of a route handshake), // - RootCAs: the bus CA, to verify the certificate of a node we dial out to, // - ClientCAs + ClientAuth=RequireAndVerifyClientCert: the bus CA, to verify // the certificate of a node dialing in. // // The effect: a node that lacks a certificate signed by the bus CA cannot // establish a route in either direction, even if it knows the cluster password. // Reuse the same CA as the client data plane (deploy/tls) but a per-node cert // whose SAN covers that node's route address. func RouteTLSConfig(certPEMPath, keyPEMPath, caPEMPath string) (*tls.Config, error) { cert, err := tls.LoadX509KeyPair(certPEMPath, keyPEMPath) if err != nil { return nil, fmt.Errorf("busauth: load route keypair: %w", err) } pem, err := os.ReadFile(caPEMPath) if err != nil { return nil, fmt.Errorf("busauth: read route CA %q: %w", caPEMPath, err) } pool := x509.NewCertPool() if !pool.AppendCertsFromPEM(pem) { return nil, fmt.Errorf("busauth: route CA %q contains no valid PEM certificate", caPEMPath) } return &tls.Config{ Certificates: []tls.Certificate{cert}, RootCAs: pool, ClientCAs: pool, ClientAuth: tls.RequireAndVerifyClientCert, MinVersion: tls.VersionTLS12, }, nil }