Пример #1
0
// checkTLSConnection checks that we can correctly perform a TLS
// handshake using the given credentials.
func checkTLSConnection(c *gc.C, caCert, srvCert *x509.Certificate, srvKey *rsa.PrivateKey) (caName string) {
	clientCertPool := x509.NewCertPool()
	clientCertPool.AddCert(caCert)

	var outBytes bytes.Buffer

	const msg = "hello to the server"
	p0, p1 := net.Pipe()
	p0 = &recordingConn{
		Conn:   p0,
		Writer: io.MultiWriter(p0, &outBytes),
	}

	var clientState tls.ConnectionState
	done := make(chan error)
	go func() {
		config := utils.SecureTLSConfig()
		config.Certificates = []tls.Certificate{{
			Certificate: [][]byte{srvCert.Raw},
			PrivateKey:  srvKey,
		}}

		conn := tls.Server(p1, config)
		defer conn.Close()
		data, err := ioutil.ReadAll(conn)
		c.Assert(err, jc.ErrorIsNil)
		c.Assert(string(data), gc.Equals, msg)
		close(done)
	}()

	tlsConfig := utils.SecureTLSConfig()
	tlsConfig.ServerName = "anyServer"
	tlsConfig.RootCAs = clientCertPool
	clientConn := tls.Client(p0, tlsConfig)
	defer clientConn.Close()

	_, err := clientConn.Write([]byte(msg))
	c.Assert(err, jc.ErrorIsNil)
	clientState = clientConn.ConnectionState()
	clientConn.Close()

	// wait for server to exit
	<-done

	outData := outBytes.String()
	c.Assert(outData, gc.Not(gc.HasLen), 0)
	if strings.Index(outData, msg) != -1 {
		c.Fatalf("TLS connection not encrypted")
	}
	c.Assert(clientState.VerifiedChains, gc.HasLen, 1)
	c.Assert(clientState.VerifiedChains[0], gc.HasLen, 2)
	return clientState.VerifiedChains[0][1].Subject.CommonName
}
Пример #2
0
func (cl *changeCertListener) tlsConfig() *tls.Config {
	cl.m.Lock()
	defer cl.m.Unlock()
	tlsConfig := utils.SecureTLSConfig()
	tlsConfig.Certificates = []tls.Certificate{cl.cert}
	return tlsConfig
}
Пример #3
0
// connectWebsocket establishes a websocket connection to the RPC
// API websocket on the API server using Info. If multiple API addresses
// are provided in Info they will be tried concurrently - the first successful
// connection wins.
//
// It also returns the TLS configuration that it has derived from the Info.
func connectWebsocket(info *Info, opts DialOpts) (*websocket.Conn, *tls.Config, error) {
	if len(info.Addrs) == 0 {
		return nil, nil, errors.New("no API addresses to connect to")
	}
	tlsConfig := utils.SecureTLSConfig()
	// We want to be specific here (rather than just using "anything".
	// See commit 7fc118f015d8480dfad7831788e4b8c0432205e8 (PR 899).
	tlsConfig.ServerName = "juju-apiserver"
	tlsConfig.InsecureSkipVerify = opts.InsecureSkipVerify

	if !tlsConfig.InsecureSkipVerify {
		certPool, err := CreateCertPool(info.CACert)
		if err != nil {
			return nil, nil, errors.Annotate(err, "cert pool creation failed")
		}
		tlsConfig.RootCAs = certPool
	}
	path := "/"
	if info.ModelTag.Id() != "" {
		path = apiPath(info.ModelTag, "/api")
	}
	conn, err := dialWebSocket(info.Addrs, path, tlsConfig, opts)
	if err != nil {
		return nil, nil, errors.Trace(err)
	}
	logger.Infof("connection established to %q", conn.RemoteAddr())
	return conn, tlsConfig, nil
}
Пример #4
0
func newServer(s *state.State, lis *net.TCPListener, cfg ServerConfig) (_ *Server, err error) {
	tlsCert, err := tls.X509KeyPair(cfg.Cert, cfg.Key)
	if err != nil {
		return nil, err
	}
	// TODO(rog) check that *srvRoot is a valid type for using
	// as an RPC server.
	tlsConfig := utils.SecureTLSConfig()
	tlsConfig.Certificates = []tls.Certificate{tlsCert}

	stPool := cfg.StatePool
	if stPool == nil {
		stPool = state.NewStatePool(s)
	}

	srv := &Server{
		state:     s,
		statePool: stPool,
		lis:       newChangeCertListener(lis, cfg.CertChanged, tlsConfig),
		tag:       cfg.Tag,
		dataDir:   cfg.DataDir,
		logDir:    cfg.LogDir,
		limiter:   utils.NewLimiter(loginRateLimit),
		validator: cfg.Validator,
		adminApiFactories: map[int]adminApiFactory{
			3: newAdminApiV3,
		},
	}
	srv.authCtxt, err = newAuthContext(s)
	if err != nil {
		return nil, errors.Trace(err)
	}
	go srv.run()
	return srv, nil
}
Пример #5
0
func (s *authHttpSuite) makeWebsocketConfigFromURL(c *gc.C, server string, header http.Header) *websocket.Config {
	config, err := websocket.NewConfig(server, "http://localhost/")
	c.Assert(err, jc.ErrorIsNil)
	config.Header = header
	caCerts := x509.NewCertPool()
	c.Assert(caCerts.AppendCertsFromPEM([]byte(testing.CACert)), jc.IsTrue)
	config.TlsConfig = utils.SecureTLSConfig()
	config.TlsConfig.RootCAs = caCerts
	config.TlsConfig.ServerName = "anything"
	return config
}
Пример #6
0
Файл: open.go Проект: bac/juju
// DialInfo returns information on how to dial
// the state's mongo server with the given info
// and dial options.
func DialInfo(info Info, opts DialOpts) (*mgo.DialInfo, error) {
	if len(info.Addrs) == 0 {
		return nil, stderrors.New("no mongo addresses")
	}
	if len(info.CACert) == 0 {
		return nil, stderrors.New("missing CA certificate")
	}
	xcert, err := cert.ParseCert(info.CACert)
	if err != nil {
		return nil, fmt.Errorf("cannot parse CA certificate: %v", err)
	}
	pool := x509.NewCertPool()
	pool.AddCert(xcert)
	tlsConfig := utils.SecureTLSConfig()

	// TODO(natefinch): revisit this when are full-time on mongo 3.
	// We have to add non-ECDHE suites because mongo doesn't support ECDHE.
	moreSuites := []uint16{
		tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
		tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
	}

	tlsConfig.CipherSuites = append(tlsConfig.CipherSuites, moreSuites...)
	tlsConfig.RootCAs = pool
	tlsConfig.ServerName = "juju-mongodb"

	dial := func(server *mgo.ServerAddr) (net.Conn, error) {
		addr := server.TCPAddr().String()
		c, err := net.DialTimeout("tcp", addr, opts.Timeout)
		if err != nil {
			logger.Warningf("mongodb connection failed, will retry: %v", err)
			return nil, err
		}
		cc := tls.Client(c, tlsConfig)
		if err := cc.Handshake(); err != nil {
			logger.Warningf("TLS handshake failed: %v", err)
			return nil, err
		}
		logger.Debugf("dialled mongodb server at %q", addr)
		return cc, nil
	}

	return &mgo.DialInfo{
		Addrs:      info.Addrs,
		Timeout:    opts.Timeout,
		DialServer: dial,
		Direct:     opts.Direct,
	}, nil
}
Пример #7
0
func dialWebsocket(c *gc.C, addr, path string, tlsVersion uint16) (*websocket.Conn, error) {
	origin := "http://localhost/"
	url := fmt.Sprintf("wss://%s%s", addr, path)
	config, err := websocket.NewConfig(url, origin)
	c.Assert(err, jc.ErrorIsNil)
	pool := x509.NewCertPool()
	xcert, err := cert.ParseCert(coretesting.CACert)
	c.Assert(err, jc.ErrorIsNil)
	pool.AddCert(xcert)
	config.TlsConfig = utils.SecureTLSConfig()
	if tlsVersion > 0 {
		// This is for testing only. Please don't muck with the maxtlsversion in
		// production.
		config.TlsConfig.MaxVersion = tlsVersion
	}
	config.TlsConfig.RootCAs = pool
	return websocket.DialConfig(config)
}
Пример #8
0
// bakeryDo provides a function suitable for using in httpRequestParams.Do
// that will use the given http client (or utils.GetNonValidatingHTTPClient()
// if client is nil) and use the given getBakeryError function
// to translate errors in responses.
func bakeryDo(client *http.Client, getBakeryError func(*http.Response) error) func(*http.Request) (*http.Response, error) {
	bclient := httpbakery.NewClient()
	if client != nil {
		bclient.Client = client
	} else {
		// Configure the default client to skip verification/
		tlsConfig := utils.SecureTLSConfig()
		tlsConfig.InsecureSkipVerify = true
		bclient.Client.Transport = utils.NewHttpTLSTransport(tlsConfig)
	}
	return func(req *http.Request) (*http.Response, error) {
		var body io.ReadSeeker
		if req.Body != nil {
			body = req.Body.(io.ReadSeeker)
			req.Body = nil
		}
		return bclient.DoWithBodyAndCustomError(req, body, getBakeryError)
	}
}
Пример #9
0
// dialAPI establishes a websocket connection to the RPC
// API websocket on the API server using Info. If multiple API addresses
// are provided in Info they will be tried concurrently - the first successful
// connection wins.
//
// It also returns the TLS configuration that it has derived from the Info.
func dialAPI(info *Info, opts DialOpts) (*websocket.Conn, *tls.Config, error) {
	// Set opts.DialWebsocket here rather than in open because
	// some tests call dialAPI directly.
	if opts.DialWebsocket == nil {
		opts.DialWebsocket = websocket.DialConfig
	}
	if len(info.Addrs) == 0 {
		return nil, nil, errors.New("no API addresses to connect to")
	}
	tlsConfig := utils.SecureTLSConfig()
	tlsConfig.InsecureSkipVerify = opts.InsecureSkipVerify

	if info.CACert != "" {
		// We want to be specific here (rather than just using "anything".
		// See commit 7fc118f015d8480dfad7831788e4b8c0432205e8 (PR 899).
		tlsConfig.ServerName = "juju-apiserver"
		certPool, err := CreateCertPool(info.CACert)
		if err != nil {
			return nil, nil, errors.Annotate(err, "cert pool creation failed")
		}
		tlsConfig.RootCAs = certPool
	} else {
		// No CA certificate so use the SNI host name for all
		// connections (if SNIHostName is empty, the host
		// name in the address will be used as usual).
		tlsConfig.ServerName = info.SNIHostName
	}
	path, err := apiPath(info.ModelTag, "/api")
	if err != nil {
		return nil, nil, errors.Trace(err)
	}
	conn, err := dialWebsocketMulti(info.Addrs, path, tlsConfig, opts)
	if err != nil {
		return nil, nil, errors.Trace(err)
	}
	logger.Infof("connection established to %q", conn.RemoteAddr())
	return conn, tlsConfig, nil
}
Пример #10
0
func (srv *Server) newTLSConfig(cfg ServerConfig) *tls.Config {
	tlsConfig := utils.SecureTLSConfig()
	if cfg.AutocertDNSName == "" {
		// No official DNS name, no certificate.
		tlsConfig.GetCertificate = func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
			cert, _ := srv.localCertificate(clientHello.ServerName)
			return cert, nil
		}
		return tlsConfig
	}
	m := autocert.Manager{
		Prompt:     autocert.AcceptTOS,
		Cache:      srv.state.AutocertCache(),
		HostPolicy: autocert.HostWhitelist(cfg.AutocertDNSName),
	}
	if cfg.AutocertURL != "" {
		m.Client = &acme.Client{
			DirectoryURL: cfg.AutocertURL,
		}
	}
	tlsConfig.GetCertificate = func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
		logger.Infof("getting certificate for server name %q", clientHello.ServerName)
		// Get the locally created certificate and whether it's appropriate
		// for the SNI name. If not, we'll try to get an acme cert and
		// fall back to the local certificate if that fails.
		cert, shouldUse := srv.localCertificate(clientHello.ServerName)
		if shouldUse {
			return cert, nil
		}
		acmeCert, err := m.GetCertificate(clientHello)
		if err == nil {
			return acmeCert, nil
		}
		logger.Errorf("cannot get autocert certificate for %q: %v", clientHello.ServerName, err)
		return cert, nil
	}
	return tlsConfig
}
Пример #11
0
// NewAPIServer serves RPC methods on a localhost HTTP server.
// When a connection is made to the API, the newRoot function
// is called with the requested model UUID and the returned
// value defines the API (see the juju/rpc package).
//
// Note that the root value accepts any facade version number - it
// is not currently possible to use this to serve several different
// facade versions.
//
// The server uses testing.ServerCert and testing.ServerKey
// to host the server.
//
// The returned server must be closed after use.
func NewAPIServer(newRoot func(modelUUID string) interface{}) *Server {
	tlsCert, err := tls.X509KeyPair([]byte(testing.ServerCert), []byte(testing.ServerKey))
	if err != nil {
		panic("bad key pair")
	}

	srv := &Server{
		newRoot: newRoot,
	}
	pmux := pat.New()
	pmux.Get("/model/:modeluuid/api", http.HandlerFunc(srv.serveAPI))

	srv.Server = httptest.NewUnstartedServer(pmux)

	tlsConfig := utils.SecureTLSConfig()
	tlsConfig.Certificates = []tls.Certificate{tlsCert}
	srv.Server.TLS = tlsConfig

	srv.StartTLS()
	u, _ := url.Parse(srv.URL)
	srv.Addrs = []string{u.Host}
	return srv
}