// Starts listening for client connections. // When a new application connects, launches listeners in a goroutine. // Returns an error when error occurs. func StartListen(port int, useTls bool, crtPath string, keyPath string, sname string) error { // Create a listening address addr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf(":%d", port)) if err != nil { return err } // start a new server and listen on the address var l net.Listener l, err = net.ListenTCP("tcp", addr) if err != nil { return err } // wrap with TLS if required if useTls { cert, err := tls.LoadX509KeyPair(crtPath, keyPath) if err != nil { return err } conf := tls.Config{} certs := make([]tls.Certificate, 1) certs[0] = cert conf.Certificates = certs cp := x509.NewCertPool() caCert, err := ioutil.ReadFile(crtPath) if err != nil { return err } if !cp.AppendCertsFromPEM(caCert) { return errors.New("Could not append PEM cert") } conf.RootCAs = cp conf.ServerName = sname conf.ClientAuth = tls.RequireAndVerifyClientCert conf.ClientCAs = cp l = tls.NewListener(l, &conf) } // at the end of this function close the server connection defer l.Close() logging.Debug("Starting listen loop") for { a, err := acceptApp(l) if err != nil { return err } else { logging.Debug("Got connection") go ListenForCommands(a) } } return nil }
// Generates a tls.Config object for a server from the given files. func (info TLSInfo) ServerConfig() (*tls.Config, error) { // Both the key and cert must be present. if info.KeyFile == "" || info.CertFile == "" { return nil, fmt.Errorf("KeyFile and CertFile must both be present[key: %v, cert: %v]", info.KeyFile, info.CertFile) } var cfg tls.Config tlsCert, err := tls.LoadX509KeyPair(info.CertFile, info.KeyFile) if err != nil { return nil, err } cfg.Certificates = []tls.Certificate{tlsCert} if info.CAFile != "" { cfg.ClientAuth = tls.RequireAndVerifyClientCert cp, err := newCertPool(info.CAFile) if err != nil { return nil, err } cfg.RootCAs = cp cfg.ClientCAs = cp } else { cfg.ClientAuth = tls.NoClientCert } return &cfg, nil }
// setupClientAuth sets up TLS client authentication only if // any of the TLS configs specified at least one cert file. func setupClientAuth(tlsConfigs []TLSConfig, config *tls.Config) error { whatClientAuth := tls.NoClientCert for _, cfg := range tlsConfigs { if whatClientAuth < cfg.ClientAuth { // Use the most restrictive. whatClientAuth = cfg.ClientAuth } } if whatClientAuth != tls.NoClientCert { pool := x509.NewCertPool() for _, cfg := range tlsConfigs { if len(cfg.ClientCerts) == 0 { continue } for _, caFile := range cfg.ClientCerts { caCrt, err := ioutil.ReadFile(caFile) // Anyone that gets a cert from this CA can connect if err != nil { return err } if !pool.AppendCertsFromPEM(caCrt) { return fmt.Errorf("error loading client certificate '%s': no certificates were successfully parsed", caFile) } } } config.ClientCAs = pool config.ClientAuth = whatClientAuth } return nil }
// GetServerTLSConfig returns a TLS config for using with ListenAndServeTLS // This sets up the Root and Client CAs for verification func GetServerTLSConfig(caCert, serverCert, serverKey []byte, allowInsecure bool) (*tls.Config, error) { // TLS config var tlsConfig tls.Config tlsConfig.InsecureSkipVerify = allowInsecure certPool := x509.NewCertPool() // load system certs if err := loadSystemCertificates(certPool); err != nil { return nil, err } // append custom CA certPool.AppendCertsFromPEM(caCert) tlsConfig.RootCAs = certPool tlsConfig.ClientCAs = certPool log.Debugf("tls root CAs: %d", len(tlsConfig.RootCAs.Subjects())) // require client auth tlsConfig.ClientAuth = tls.VerifyClientCertIfGiven // server cert keypair, err := tls.X509KeyPair(serverCert, serverKey) if err != nil { return &tlsConfig, err } tlsConfig.Certificates = []tls.Certificate{keypair} return &tlsConfig, nil }
// setupClientAuth sets up TLS client authentication only if // any of the TLS configs specified at least one cert file. func setupClientAuth(tlsConfigs []TLSConfig, config *tls.Config) error { var clientAuth bool for _, cfg := range tlsConfigs { if len(cfg.ClientCerts) > 0 { clientAuth = true break } } if clientAuth { pool := x509.NewCertPool() for _, cfg := range tlsConfigs { for _, caFile := range cfg.ClientCerts { caCrt, err := ioutil.ReadFile(caFile) // Anyone that gets a cert from Matt Holt can connect if err != nil { return err } if !pool.AppendCertsFromPEM(caCrt) { return fmt.Errorf("error loading client certificate '%s': no certificates were successfully parsed", caFile) } } } config.ClientCAs = pool config.ClientAuth = tls.RequireAndVerifyClientCert } return nil }
// SecureListen obtains a listener that accepts // secure connections func SecureServe(addr string, certFile, keyFile, caFile string) { config := tls.Config{} // load the server cert / key cert, err := tls.LoadX509KeyPair(certFile, keyFile) if err != nil { log.Fatalf("%s", err) } config.Certificates = []tls.Certificate{cert} // load the ca if necessary // FIXME(alainjobart) this doesn't quite work yet, have // to investigate if caFile != "" { config.ClientCAs = x509.NewCertPool() pemCerts, err := ioutil.ReadFile(caFile) if err != nil { log.Fatalf("%s", err) } if !config.ClientCAs.AppendCertsFromPEM(pemCerts) { log.Fatalf("%s", err) } config.ClientAuth = tls.RequireAndVerifyClientCert } l, err := tls.Listen("tcp", addr, &config) if err != nil { log.Fatalf("%s", err) } throttled := NewThrottledListener(l, *secureThrottle, *secureMaxBuffer) cl := proc.Published(throttled, "SecureConnections", "SecureAccepts") go http.Serve(cl, nil) }
// NewTLSConfig returns an initialized TLS configuration suitable for client // authentication. If caFile is non-empty, it will be loaded. func NewTLSConfig(caFile string, mutualTLS bool) (*tls.Config, error) { var c tls.Config // TLS 1.0 at a minimum (for mysql) c.MinVersion = tls.VersionTLS10 c.PreferServerCipherSuites = true if mutualTLS { log.Info("MutualTLS requested, client certificates will be verified") c.ClientAuth = tls.VerifyClientCertIfGiven } if caFile != "" { data, err := ioutil.ReadFile(caFile) if err != nil { return &c, err } c.ClientCAs = x509.NewCertPool() if !c.ClientCAs.AppendCertsFromPEM(data) { return &c, errors.New("No certificates parsed") } log.Info("Read in CA file:", caFile) } c.BuildNameToCertificate() return &c, nil }
// HandleStartTLS is the companion to StartTLS, and will do the connection upgrade. It assumes // that the TLS command byte has already been read. Like StartTLS it returns the peer name, or // an error func (p *Protocol) HandleStartTLS(identity *security.Identity, caCertificate *security.Certificate) (string, error) { var ( err error tlsConn *tls.Conn ) // Build the config config := new(tls.Config) config.ClientAuth = tls.RequireAndVerifyClientCert // Setup the tls connection if err := p.tlsSetup(config, identity, caCertificate); err != nil { return "", err } // Upgrade the connection to TLS // TODO: Add a deadline here? tlsConn = tls.Server(p.conn, config) if err = tlsConn.Handshake(); err != nil { return "", err } // Capture the connection state cs := tlsConn.ConnectionState() // And replace the original connection p.conn = net.Conn(tlsConn) p.setupBuffers() // Send an Ack p.Ack() return cs.PeerCertificates[0].Subject.CommonName, nil }
// NewTestServer wraps a Service as an httptest.Server. func NewTestServer(s Service, cert, key, caCert []byte) (*httptest.Server, error) { var tlsConfig *tls.Config if cert != nil { cert, err := tls.X509KeyPair(cert, key) if err != nil { return nil, err } tlsConfig = &tls.Config{Certificates: []tls.Certificate{cert}} } if caCert != nil { rootCAs := x509.NewCertPool() rootCAs.AppendCertsFromPEM(caCert) if tlsConfig == nil { tlsConfig = &tls.Config{} } tlsConfig.ClientCAs = rootCAs tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert } serveHTTP := func(w http.ResponseWriter, r *http.Request) { var review v1beta1.TokenReview if err := json.NewDecoder(r.Body).Decode(&review); err != nil { http.Error(w, fmt.Sprintf("failed to decode body: %v", err), http.StatusBadRequest) return } s.Review(&review) type userInfo struct { Username string `json:"username"` UID string `json:"uid"` Groups []string `json:"groups"` } type status struct { Authenticated bool `json:"authenticated"` User userInfo `json:"user"` } resp := struct { APIVersion string `json:"apiVersion"` Status status `json:"status"` }{ APIVersion: v1beta1.SchemeGroupVersion.String(), Status: status{ review.Status.Authenticated, userInfo{ Username: review.Status.User.Username, UID: review.Status.User.UID, Groups: review.Status.User.Groups, }, }, } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(resp) } server := httptest.NewUnstartedServer(http.HandlerFunc(serveHTTP)) server.TLS = tlsConfig server.StartTLS() return server, nil }
// ServerSecurePort obtains a listener that accepts secure connections. // If the provided port is zero, the listening is disabled. func ServeSecurePort(securePort int, certFile, keyFile, caCertFile string) { if securePort == 0 { log.Info("Not listening on secure port") return } config := tls.Config{} // load the server cert / key cert, err := tls.LoadX509KeyPair(certFile, keyFile) if err != nil { log.Fatalf("SecureServe.LoadX509KeyPair(%v, %v) failed: %v", certFile, keyFile, err) } config.Certificates = []tls.Certificate{cert} // load the ca if necessary // FIXME(alainjobart) this doesn't quite work yet, have // to investigate if caCertFile != "" { config.ClientCAs = x509.NewCertPool() pemCerts, err := ioutil.ReadFile(caCertFile) if err != nil { log.Fatalf("SecureServe: cannot read ca file %v: %v", caCertFile, err) } if !config.ClientCAs.AppendCertsFromPEM(pemCerts) { log.Fatalf("SecureServe: AppendCertsFromPEM failed: %v", err) } config.ClientAuth = tls.RequireAndVerifyClientCert } l, err := tls.Listen("tcp", fmt.Sprintf(":%d", securePort), &config) if err != nil { log.Fatalf("Error listening on secure port %v: %v", securePort, err) } log.Infof("Listening on secure port %v", securePort) throttled := NewThrottledListener(l, *secureThrottle, *secureMaxBuffer) cl := proc.Published(throttled, "SecureConnections", "SecureAccepts") // rpc.HandleHTTP registers the default GOB handler at /_goRPC_ // and the debug RPC service at /debug/rpc (it displays a list // of registered services and their methods). if ServiceMap["gob-vts"] { log.Infof("Registering GOB handler and /debug/rpc URL for vts port") secureRpcServer.HandleHTTP(rpcwrap.GetRpcPath("gob", false), rpcplus.DefaultDebugPath) } if ServiceMap["gob-auth-vts"] { log.Infof("Registering GOB handler and /debug/rpcs URL for SASL vts port") authenticatedSecureRpcServer.HandleHTTP(rpcwrap.GetRpcPath("gob", true), rpcplus.DefaultDebugPath+"s") } handler := http.NewServeMux() bsonrpc.ServeCustomRPC(handler, secureRpcServer, false) bsonrpc.ServeCustomRPC(handler, authenticatedSecureRpcServer, true) httpServer := http.Server{ Handler: handler, } go httpServer.Serve(cl) }
// ListenAnonymous returns a new Tao-based net.Listener that does not require // its peer to attest to its identity. func ListenAnonymous(network, laddr string, config *tls.Config, g Guard, v *Verifier, del *Attestation) (net.Listener, error) { config.ClientAuth = tls.NoClientCert inner, err := tls.Listen(network, laddr, config) if err != nil { return nil, err } return &anonymousListener{listener{inner, g, v, del}}, nil }
func Init(messageQueue chan *bl.Message, conf map[string]interface{}) bl.Input { var tlsConfig tls.Config tag := bl.GString("tag", conf) bind := bl.GString("bind", conf) timeout := int64(bl.GInt("timeout", conf)) if timeout <= 0 { log.Fatalf("[ERROR] [%s] You must specify right timeout (%d)", module, timeout) } SSLCertificate := bl.GString("ssl_cert", conf) SSLKey := bl.GString("ssl_key", conf) SSLCA := bl.GString("ssl_ca", conf) if len(SSLCertificate) > 0 && len(SSLKey) > 0 { tlsConfig.MinVersion = tls.VersionTLS12 log.Printf("[INFO] [%s] Loading server ssl certificate and key from \"%s\" and \"%s\"", tag, SSLCertificate, SSLKey) cert, err := tls.LoadX509KeyPair(SSLCertificate, SSLKey) if err != nil { log.Fatalf("[ERROR] [%s] Failed loading server ssl certificate: %s", tag, err) } tlsConfig.Certificates = []tls.Certificate{cert} if len(SSLCA) > 0 { log.Printf("[INFO] [%s] Loading CA certificate from file: %s\n", tag, SSLCA) tlsConfig.ClientCAs = x509.NewCertPool() tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert pemdata, err := ioutil.ReadFile(SSLCA) if err != nil { log.Fatalf("[ERROR] [%s] Failure reading CA certificate: %s\n", tag, err) } block, _ := pem.Decode(pemdata) if block == nil { log.Fatalf("[ERROR] [%s] Failed to decode PEM data of CA certificate from \"%s\"\n", tag, SSLCA) } if block.Type != "CERTIFICATE" { log.Fatalf("[ERROR] [%s] This is not a certificate file: %s\n", tag, SSLCA) } cacert, err := x509.ParseCertificate(block.Bytes) if err != nil { log.Fatalf("[ERROR] [%s] Failed to parse CA certificate: %s\n", tag, SSLCA) } tlsConfig.ClientCAs.AddCert(cacert) } v := &In_logear_forwarder{tag: tag, messageQueue: messageQueue, tlsConfig: tlsConfig, bind: bind, timeout: time.Second * time.Duration(timeout)} return v } else { log.Fatalf("[ERROR] [%s] You must specify ssl_cert and ssl_key", module) } return nil }
// NewTestServer wraps a Service as an httptest.Server. func NewTestServer(s Service, cert, key, caCert []byte) (*httptest.Server, error) { var tlsConfig *tls.Config if cert != nil { cert, err := tls.X509KeyPair(cert, key) if err != nil { return nil, err } tlsConfig = &tls.Config{Certificates: []tls.Certificate{cert}} } if caCert != nil { rootCAs := x509.NewCertPool() rootCAs.AppendCertsFromPEM(caCert) if tlsConfig == nil { tlsConfig = &tls.Config{} } tlsConfig.ClientCAs = rootCAs tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert } serveHTTP := func(w http.ResponseWriter, r *http.Request) { var review v1alpha1.ImageReview if err := json.NewDecoder(r.Body).Decode(&review); err != nil { http.Error(w, fmt.Sprintf("failed to decode body: %v", err), http.StatusBadRequest) return } if s.HTTPStatusCode() < 200 || s.HTTPStatusCode() >= 300 { http.Error(w, "HTTP Error", s.HTTPStatusCode()) return } s.Review(&review) type status struct { Allowed bool `json:"allowed"` Reason string `json:"reason"` } resp := struct { APIVersion string `json:"apiVersion"` Kind string `json:"kind"` Status status `json:"status"` }{ APIVersion: v1alpha1.SchemeGroupVersion.String(), Kind: "ImageReview", Status: status{review.Status.Allowed, review.Status.Reason}, } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(resp) } server := httptest.NewUnstartedServer(http.HandlerFunc(serveHTTP)) server.TLS = tlsConfig server.StartTLS() return server, nil }
func (c Config) TLSConfig() *tls.Config { certs := []tls.Certificate{c.TLSCertificate()} tlsConfig := tls.Config{ Certificates: certs, } if c.TLSClientAuthEnabled() { tlsConfig.ClientCAs = c.ClientCAsPool() tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert } return &tlsConfig }
func tlsConfig() *tls.Config { cfg := new(tls.Config) cfg.ClientCAs = x509.NewCertPool() cfg.ClientCAs.AppendCertsFromPEM([]byte(caCert)) cert, err := tls.X509KeyPair([]byte(serverCert), []byte(serverKey)) if err != nil { panic(err) } cfg.Certificates = append(cfg.Certificates, cert) cfg.ClientAuth = tls.RequireAndVerifyClientCert return cfg }
// StartHttpsServer binds and starts an https server. func StartHttpsServer(addr string, certFile, keyFile, caFile string) { config := tls.Config{} // load the server cert / key cert, err := tls.LoadX509KeyPair(certFile, keyFile) if err != nil { relog.Fatal("StartHttpsServer.LoadX509KeyPair failed: %v", err) } config.Certificates = []tls.Certificate{cert} // load the ca if necessary // FIXME(alainjobart) this doesn't quite work yet, have // to investigate if caFile != "" { config.ClientCAs = x509.NewCertPool() ca, err := os.Open(caFile) if err != nil { relog.Fatal("StartHttpsServer failed to open caFile %v: %v", caFile, err) } defer ca.Close() fi, err := ca.Stat() if err != nil { relog.Fatal("StartHttpsServer failed to stat caFile %v: %v", caFile, err) } pemCerts := make([]byte, fi.Size()) if _, err = ca.Read(pemCerts); err != nil { relog.Fatal("StartHttpsServer failed to read caFile %v: %v", caFile, err) } if !config.ClientCAs.AppendCertsFromPEM(pemCerts) { relog.Fatal("StartHttpsServer failed to parse caFile %v", caFile) } config.ClientAuth = tls.RequireAndVerifyClientCert } httpsListener, err := tls.Listen("tcp", addr, &config) if err != nil { relog.Fatal("StartHttpsServer failed: %v", err) } go asyncListener(httpsListener) }
func setupTls(caFile, certFile, keyFile string) { if caFile == "" || certFile == "" || keyFile == "" { return } // Load certificates and key. caData, err := ioutil.ReadFile(caFile) if os.IsNotExist(err) { return } if err != nil { fmt.Fprintf(os.Stderr, "Unable to load CA file\t%s\n", err) os.Exit(1) } caCertPool := x509.NewCertPool() if !caCertPool.AppendCertsFromPEM(caData) { fmt.Fprintln(os.Stderr, "Unable to parse CA file") os.Exit(1) } // Setup server. serverConfig := new(tls.Config) serverConfig.ClientAuth = tls.RequireAndVerifyClientCert serverConfig.MinVersion = tls.VersionTLS12 serverConfig.ClientCAs = caCertPool cert, err := tls.LoadX509KeyPair(certFile, keyFile) if os.IsNotExist(err) { return } if err != nil { fmt.Fprintf(os.Stderr, "Unable to load keypair\t%s\n", err) os.Exit(1) } serverConfig.Certificates = append(serverConfig.Certificates, cert) srpc.RegisterServerTlsConfig(serverConfig, true) // Setup client. clientConfig := new(tls.Config) clientConfig.InsecureSkipVerify = true clientConfig.MinVersion = tls.VersionTLS12 clientConfig.Certificates = append(clientConfig.Certificates, cert) srpc.RegisterClientTlsConfig(clientConfig) }
// GenTLSConfig loads TLS related configuration parameters. func GenTLSConfig(tc *TLSConfigOpts) (*tls.Config, error) { // Now load in cert and private key cert, err := tls.LoadX509KeyPair(tc.CertFile, tc.KeyFile) if err != nil { return nil, fmt.Errorf("error parsing X509 certificate/key pair: %v", err) } cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0]) if err != nil { return nil, fmt.Errorf("error parsing certificate: %v", err) } // Create TLSConfig // We will determine the cipher suites that we prefer. config := tls.Config{ Certificates: []tls.Certificate{cert}, PreferServerCipherSuites: true, MinVersion: tls.VersionTLS12, CipherSuites: tc.Ciphers, } // Require client certificates as needed if tc.Verify { config.ClientAuth = tls.RequireAndVerifyClientCert } // Add in CAs if applicable. if tc.CaFile != "" { rootPEM, err := ioutil.ReadFile(tc.CaFile) if err != nil || rootPEM == nil { return nil, err } pool := x509.NewCertPool() ok := pool.AppendCertsFromPEM([]byte(rootPEM)) if !ok { return nil, fmt.Errorf("failed to parse root ca certificate") } config.ClientCAs = pool } return &config, nil }
// serverSecurePort obtains a listener that accepts secure connections. // All of this is based on *SecurePort being non-zero. func serveSecurePort() { if *SecurePort == 0 { log.Info("Not listening on secure port") return } config := tls.Config{} // load the server cert / key cert, err := tls.LoadX509KeyPair(*certFile, *keyFile) if err != nil { log.Fatalf("SecureServe.LoadX509KeyPair(%v, %v) failed: %v", *certFile, *keyFile, err) } config.Certificates = []tls.Certificate{cert} // load the ca if necessary // FIXME(alainjobart) this doesn't quite work yet, have // to investigate if *caCertFile != "" { config.ClientCAs = x509.NewCertPool() pemCerts, err := ioutil.ReadFile(*caCertFile) if err != nil { log.Fatalf("SecureServe: cannot read ca file %v: %v", *caCertFile, err) } if !config.ClientCAs.AppendCertsFromPEM(pemCerts) { log.Fatalf("SecureServe: AppendCertsFromPEM failed: %v", err) } config.ClientAuth = tls.RequireAndVerifyClientCert } l, err := tls.Listen("tcp", fmt.Sprintf(":%d", *SecurePort), &config) if err != nil { log.Fatalf("Error listening on secure port %v: %v", *SecurePort, err) } log.Infof("Listening on secure port %v", *SecurePort) throttled := NewThrottledListener(l, *secureThrottle, *secureMaxBuffer) cl := proc.Published(throttled, "SecureConnections", "SecureAccepts") go http.Serve(cl, nil) }
// setupTLSConfig returns a tls.Config for a credential set func setupTLSConfig(cert []byte, key []byte, ca []byte) (*tls.Config, error) { // TLS config var tlsConfig tls.Config //Use only modern ciphers tlsConfig.CipherSuites = []uint16{ tls.TLS_RSA_WITH_AES_128_CBC_SHA, tls.TLS_RSA_WITH_AES_256_CBC_SHA, tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, } // Use only TLS v1.2 tlsConfig.MinVersion = tls.VersionTLS12 // Don't allow session resumption tlsConfig.SessionTicketsDisabled = true certPool := x509.NewCertPool() certPool.AppendCertsFromPEM(ca) tlsConfig.RootCAs = certPool tlsConfig.ClientCAs = certPool tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert keypair, err := tls.X509KeyPair(cert, key) if err != nil { return &tlsConfig, err } tlsConfig.Certificates = []tls.Certificate{keypair} return &tlsConfig, nil }
func GetConfig(ca_f []byte, ee_f []byte, key_f []byte) (*tls.Config, error) { ca, err := x509.ParseCertificate(ca_f) if err != nil { return nil, err } pkey, err := x509.ParsePKCS1PrivateKey(key_f) if err != nil { return nil, err } ca_pool := x509.NewCertPool() ca_pool.AddCert(ca) ee_cert := tls.Certificate{ Certificate: [][]byte{ee_f}, PrivateKey: pkey, } config := new(tls.Config) config.ClientAuth = tls.RequireAndVerifyClientCert config.Certificates = []tls.Certificate{ee_cert} config.ClientCAs = ca_pool config.RootCAs = ca_pool config.Rand = rand.Reader config.BuildNameToCertificate() return config, nil }
// MakeTLSConfig reduces configs into a single tls.Config. // If TLS is to be disabled, a nil tls.Config will be returned. func MakeTLSConfig(configs []*Config) (*tls.Config, error) { if configs == nil || len(configs) == 0 { return nil, nil } config := new(tls.Config) ciphersAdded := make(map[uint16]struct{}) configMap := make(configGroup) for i, cfg := range configs { if cfg == nil { // avoid nil pointer dereference below configs[i] = new(Config) continue } // Key this config by its hostname; this // overwrites configs with the same hostname configMap[cfg.Hostname] = cfg // Can't serve TLS and not-TLS on same port if i > 0 && cfg.Enabled != configs[i-1].Enabled { thisConfProto, lastConfProto := "not TLS", "not TLS" if cfg.Enabled { thisConfProto = "TLS" } if configs[i-1].Enabled { lastConfProto = "TLS" } return nil, fmt.Errorf("cannot multiplex %s (%s) and %s (%s) on same listener", configs[i-1].Hostname, lastConfProto, cfg.Hostname, thisConfProto) } // Union cipher suites for _, ciph := range cfg.Ciphers { if _, ok := ciphersAdded[ciph]; !ok { ciphersAdded[ciph] = struct{}{} config.CipherSuites = append(config.CipherSuites, ciph) } } // Can't resolve conflicting PreferServerCipherSuites settings if i > 0 && cfg.PreferServerCipherSuites != configs[i-1].PreferServerCipherSuites { return nil, fmt.Errorf("cannot both use PreferServerCipherSuites and not use it") } config.PreferServerCipherSuites = cfg.PreferServerCipherSuites // Go with the widest range of protocol versions if config.MinVersion == 0 || cfg.ProtocolMinVersion < config.MinVersion { config.MinVersion = cfg.ProtocolMinVersion } if cfg.ProtocolMaxVersion > config.MaxVersion { config.MaxVersion = cfg.ProtocolMaxVersion } // Go with the strictest ClientAuth type if cfg.ClientAuth > config.ClientAuth { config.ClientAuth = cfg.ClientAuth } } // Is TLS disabled? If so, we're done here. // By now, we know that all configs agree // whether it is or not, so we can just look // at the first one. if len(configs) == 0 || !configs[0].Enabled { return nil, nil } // Default cipher suites if len(config.CipherSuites) == 0 { config.CipherSuites = defaultCiphers } // For security, ensure TLS_FALLBACK_SCSV is always included if config.CipherSuites[0] != tls.TLS_FALLBACK_SCSV { config.CipherSuites = append([]uint16{tls.TLS_FALLBACK_SCSV}, config.CipherSuites...) } // Set up client authentication if enabled if config.ClientAuth != tls.NoClientCert { pool := x509.NewCertPool() clientCertsAdded := make(map[string]struct{}) for _, cfg := range configs { for _, caFile := range cfg.ClientCerts { // don't add cert to pool more than once if _, ok := clientCertsAdded[caFile]; ok { continue } clientCertsAdded[caFile] = struct{}{} // Any client with a certificate from this CA will be allowed to connect caCrt, err := ioutil.ReadFile(caFile) if err != nil { return nil, err } if !pool.AppendCertsFromPEM(caCrt) { return nil, fmt.Errorf("error loading client certificate '%s': no certificates were successfully parsed", caFile) } } } config.ClientCAs = pool } // Associate the GetCertificate callback, or almost nothing we just did will work config.GetCertificate = configMap.GetCertificate return config, nil }
// NewServer starts an HTTPS server the handles the redoctober JSON // API. Each of the URIs in the functions map above is setup with a // separate HandleFunc. Each HandleFunc is an instance of queueRequest // above. // // Returns a valid http.Server handling redoctober JSON requests (and // its associated listener) or an error func NewServer(process chan<- userRequest, staticPath, addr, certPath, keyPath, caPath string) (*http.Server, *net.Listener, error) { cert, err := tls.LoadX509KeyPair(certPath, keyPath) if err != nil { return nil, nil, fmt.Errorf("Error loading certificate (%s, %s): %s", certPath, keyPath, err) } config := tls.Config{ Certificates: []tls.Certificate{cert}, Rand: rand.Reader, PreferServerCipherSuites: true, SessionTicketsDisabled: true, MinVersion: tls.VersionTLS10, } // If a caPath has been specified then a local CA is being used // and not the system configuration. if caPath != "" { pemCert, err := ioutil.ReadFile(caPath) if err != nil { return nil, nil, fmt.Errorf("Error reading %s: %s\n", caPath, err) } derCert, _ := pem.Decode(pemCert) if derCert == nil { return nil, nil, fmt.Errorf("No PEM data was found in the CA certificate file\n") } cert, err := x509.ParseCertificate(derCert.Bytes) if err != nil { return nil, nil, fmt.Errorf("Error parsing CA certificate: %s\n", err) } rootPool := x509.NewCertPool() rootPool.AddCert(cert) config.ClientAuth = tls.RequireAndVerifyClientCert config.ClientCAs = rootPool } conn, err := net.Listen("tcp", addr) if err != nil { return nil, nil, fmt.Errorf("Error starting TCP listener on %s: %s\n", addr, err) } lstnr := tls.NewListener(conn, &config) mux := http.NewServeMux() // queue up post URIs for current := range functions { // copy this so reference does not get overwritten requestType := current mux.HandleFunc(requestType, func(w http.ResponseWriter, r *http.Request) { log.Printf("http.server: endpoint=%s remote=%s", requestType, r.RemoteAddr) queueRequest(process, requestType, w, r) }) } // queue up web frontend idxHandler := &indexHandler{staticPath} mux.HandleFunc("/index", idxHandler.handle) mux.HandleFunc("/", idxHandler.handle) srv := http.Server{ Addr: addr, Handler: mux, } return &srv, &lstnr, nil }
// Helper function to parse TLS configs. func parseTLS(tlsm map[string]interface{}) (*tls.Config, error) { tc := tlsConfig{} for mk, mv := range tlsm { switch strings.ToLower(mk) { case "cert_file": certFile, ok := mv.(string) if !ok { return nil, fmt.Errorf("error parsing tls config, expected 'cert_file' to be filename") } tc.certFile = certFile case "key_file": keyFile, ok := mv.(string) if !ok { return nil, fmt.Errorf("error parsing tls config, expected 'key_file' to be filename") } tc.keyFile = keyFile case "ca_file": caFile, ok := mv.(string) if !ok { return nil, fmt.Errorf("error parsing tls config, expected 'ca_file' to be filename") } tc.caFile = caFile case "verify": verify, ok := mv.(bool) if !ok { return nil, fmt.Errorf("error parsing tls config, expected 'verify' to be a boolean") } tc.verify = verify default: return nil, fmt.Errorf("error parsing tls config, unknown field [%q]", mk) } } // Now load in cert and private key cert, err := tls.LoadX509KeyPair(tc.certFile, tc.keyFile) if err != nil { return nil, fmt.Errorf("error parsing X509 certificate/key pair: %v", err) } cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0]) if err != nil { return nil, fmt.Errorf("error parsing certificate: %v", err) } // Create TLSConfig // We will determine the cipher suites that we prefer. config := tls.Config{ Certificates: []tls.Certificate{cert}, PreferServerCipherSuites: true, MinVersion: tls.VersionTLS12, CipherSuites: []uint16{ // The SHA384 versions are only in Go1.5 // tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, // tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, }, } // Require client certificates as needed if tc.verify == true { config.ClientAuth = tls.RequireAnyClientCert } // Add in CAs if applicable. if tc.caFile != "" { rootPEM, err := ioutil.ReadFile(tc.caFile) if err != nil || rootPEM == nil { return nil, err } pool := x509.NewCertPool() ok := pool.AppendCertsFromPEM([]byte(rootPEM)) if !ok { return nil, fmt.Errorf("failed to parse root ca certificate") } config.RootCAs = pool } return &config, nil }
func realMain() int { flag.Parse() config := DefaultConfig() if *flConfig != "" { in, err := ioutil.ReadFile(*flConfig) if err != nil { log.Println(err) return 1 } if err := toml.Unmarshal(in, config); err != nil { log.Println(err) return 1 } } l, err := net.Listen("tcp", ":8700") if err != nil { log.Println(err) return 1 } if config.SSL.Enabled { cert, err := tls.LoadX509KeyPair(config.SSL.Certificate, config.SSL.PrivateKey) if err != nil { log.Println(err) return 1 } tlsConfig := tls.Config{ Certificates: []tls.Certificate{cert}, ClientCAs: x509.NewCertPool(), ClientAuth: tls.NoClientCert, } if config.SSL.ClientCA != "" { data, err := ioutil.ReadFile(config.SSL.ClientCA) if err != nil { log.Println(err) return 1 } tlsConfig.ClientCAs.AppendCertsFromPEM(data) tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert } l = tls.NewListener(l, &tlsConfig) } server := ansible.NewServer() if config.Ldap.Enabled { if err := server.ConfigureLDAP(&config.Ldap); err != nil { log.Println(err) return 1 } } if err := server.Serve(l); err != nil { log.Println(err) return 1 } return 0 }
// NewTestServer wraps a Service as an httptest.Server. func NewTestServer(s Service, cert, key, caCert []byte) (*httptest.Server, error) { const webhookPath = "/testserver" var tlsConfig *tls.Config if cert != nil { cert, err := tls.X509KeyPair(cert, key) if err != nil { return nil, err } tlsConfig = &tls.Config{Certificates: []tls.Certificate{cert}} } if caCert != nil { rootCAs := x509.NewCertPool() rootCAs.AppendCertsFromPEM(caCert) if tlsConfig == nil { tlsConfig = &tls.Config{} } tlsConfig.ClientCAs = rootCAs tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert } serveHTTP := func(w http.ResponseWriter, r *http.Request) { if r.Method != "POST" { http.Error(w, fmt.Sprintf("unexpected method: %v", r.Method), http.StatusMethodNotAllowed) return } if r.URL.Path != webhookPath { http.Error(w, fmt.Sprintf("unexpected path: %v", r.URL.Path), http.StatusNotFound) return } var review v1beta1.TokenReview bodyData, _ := ioutil.ReadAll(r.Body) if err := json.Unmarshal(bodyData, &review); err != nil { http.Error(w, fmt.Sprintf("failed to decode body: %v", err), http.StatusBadRequest) return } // ensure we received the serialized tokenreview as expected if review.APIVersion != "authentication.k8s.io/v1beta1" { http.Error(w, fmt.Sprintf("wrong api version: %s", string(bodyData)), http.StatusBadRequest) return } // once we have a successful request, always call the review to record that we were called s.Review(&review) if s.HTTPStatusCode() < 200 || s.HTTPStatusCode() >= 300 { http.Error(w, "HTTP Error", s.HTTPStatusCode()) return } type userInfo struct { Username string `json:"username"` UID string `json:"uid"` Groups []string `json:"groups"` Extra map[string][]string `json:"extra"` } type status struct { Authenticated bool `json:"authenticated"` User userInfo `json:"user"` } var extra map[string][]string if review.Status.User.Extra != nil { extra = map[string][]string{} for k, v := range review.Status.User.Extra { extra[k] = v } } resp := struct { Kind string `json:"kind"` APIVersion string `json:"apiVersion"` Status status `json:"status"` }{ Kind: "TokenReview", APIVersion: v1beta1.SchemeGroupVersion.String(), Status: status{ review.Status.Authenticated, userInfo{ Username: review.Status.User.Username, UID: review.Status.User.UID, Groups: review.Status.User.Groups, Extra: extra, }, }, } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(resp) } server := httptest.NewUnstartedServer(http.HandlerFunc(serveHTTP)) server.TLS = tlsConfig server.StartTLS() // Adjust the path to point to our custom path serverURL, _ := url.Parse(server.URL) serverURL.Path = webhookPath server.URL = serverURL.String() return server, nil }
func ServiceRequests() { var sockConfig tls.Config // resolve the bind address bindAddressStr := GetStringOpt("bind address") var bindAddr *net.IPAddr if bindAddressStr != "" { var err error bindAddr, err = net.ResolveIPAddr("ip", bindAddressStr) if err != nil { o.Warn("Ignoring bind address. Couldn't resolve \"%s\": %s", bindAddressStr, err) } else { bindAddr = nil } } // load the x509 certificate and key, then attach it to the tls config. x509CertFilename := GetStringOpt("x509 certificate") x509PrivateKeyFilename := GetStringOpt("x509 private key") serverCert, err := tls.LoadX509KeyPair(x509CertFilename, x509PrivateKeyFilename) o.MightFail(err, "Couldn't load certificates") sockConfig.Certificates = append(sockConfig.Certificates, serverCert) // load the CA certs CACertPool = x509.NewCertPool() caCertNames := GetCACertList() if caCertNames != nil { for _, filename := range caCertNames { fh, err := os.Open(filename) if err != nil { o.Warn("Whilst parsing CA certs, couldn't open %s: %s", filename, err) continue } defer fh.Close() fi, err := fh.Stat() o.MightFail(err, "Couldn't stat CA certificate file: %s", filename) data := make([]byte, fi.Size()) fh.Read(data) CACertPool.AppendCertsFromPEM(data) } } sockConfig.ClientCAs = CACertPool // determine the server hostname. servername := GetStringOpt("server name") if servername != "" { o.Info("Using %s as the server name", servername) sockConfig.ServerName = servername } else { if bindAddr != nil { o.Warn("Probing for FQDN for bind address as none was provided") hostnames, err := net.LookupAddr(bindAddr.String()) o.MightFail(err, "Failed to get full hostname for bind address") sockConfig.ServerName = hostnames[0] } else { o.Warn("Probing for FQDN as no server name was provided") sockConfig.ServerName = o.ProbeHostname() } } // ask the client to authenticate sockConfig.ClientAuth = tls.RequireAndVerifyClientCert if *DontVerifyPeer { sockConfig.ClientAuth = tls.RequestClientCert } /* convert the bindAddress to a string suitable for the Listen call */ var laddr string if bindAddr == nil { laddr = fmt.Sprintf(":%d", o.DefaultMasterPort) } else { laddr = fmt.Sprintf("%s:%d", bindAddr.String(), o.DefaultMasterPort) } o.Info("Binding to %s...", laddr) listener, err := tls.Listen("tcp", laddr, &sockConfig) o.MightFail(err, "Couldn't bind TLS listener") for { o.Info("Waiting for connection...") c, err := listener.Accept() o.MightFail(err, "Couldn't accept TLS connection") o.Info("Connection received from %s", c.RemoteAddr().String()) HandleConnection(c) } }
// Blocks listening for connections of that given protocol type, // and calls the specified handler when one is received, // passing the node ID of the connecting node, or 0 for the Client Protocol. func Listen(protocol int, handler func(id uint16, b *BaseConn)) { ip := config.NodeIP(config.Id()) ipStr := ip.String() port := getProtocolPort(protocol) portStr := strconv.FormatInt(int64(port), 10) tlsConfig := new(tls.Config) tlsConfig.Certificates = []tls.Certificate{*config.Certificate()} if protocol != CLIENT_PROTOCOL { tlsConfig.ClientAuth = tls.RequireAnyClientCert } listener, err := tls.Listen("tcp", ipStr+":"+portStr, tlsConfig) if err != nil { log.Fatal(err) } for { conn, err := listener.Accept() if err != nil { log.Fatal(err) } tlsConn := conn.(*tls.Conn) err = tlsConn.Handshake() if err != nil { tlsConn.Close() continue } if protocol != CLIENT_PROTOCOL { // Check this connecting node has authenticated. state := tlsConn.ConnectionState() if len(state.PeerCertificates) == 0 { tlsConn.Close() continue } cert := state.PeerCertificates[0] // Identify which node they authenticated as. matched := false for _, node := range config.Nodes() { var verifyOpts x509.VerifyOptions verifyOpts.Intermediates = new(x509.CertPool) verifyOpts.Roots = config.NodeCertPool(node) chains, err := cert.Verify(verifyOpts) if err != nil { continue } // Matched the node. Start the handler. if len(chains) > 0 { matched = true go handler(node, newBaseConn(tlsConn)) break } } // No matching node found. Close the connection. if !matched { tlsConn.Close() } } else { // We don't authenticate clients. // Just run the handler. handler(0, newBaseConn(tlsConn)) } } }