Beispiel #1
0
// 1) We do not want to force the user to buy a cert.
// 2) We still want our client (camput) to be able to
// verify the cert's authenticity.
// 3) We want to avoid MITM attacks and warnings in
// the browser.
// Using a simple self-signed won't do because of 3),
// as Chrome offers no way to set a self-signed as
// trusted when importing it. (same on android).
// We could have created a self-signed CA (that we
// would import in the browsers) and create another
// cert (signed by that CA) which would be the one
// used in camlistore.
// We're doing even simpler: create a self-signed
// CA and directly use it as a self-signed cert
// (and install it as a CA in the browsers).
// 2) is satisfied by doing our own checks,
// See pkg/client
func setupTLS(ws *webserver.Server, config *serverinit.Config, hostname string) {
	cert, key := config.OptionalString("httpsCert", ""), config.OptionalString("httpsKey", "")
	if !config.OptionalBool("https", true) {
		return
	}
	if (cert != "") != (key != "") {
		exitf("httpsCert and httpsKey must both be either present or absent")
	}

	defCert := osutil.DefaultTLSCert()
	defKey := osutil.DefaultTLSKey()
	const hint = "You must add this certificate's fingerprint to your client's trusted certs list to use it. Like so:\n\"trustedCerts\": [\"%s\"],"
	if cert == defCert && key == defKey {
		_, err1 := wkfs.Stat(cert)
		_, err2 := wkfs.Stat(key)
		if err1 != nil || err2 != nil {
			if os.IsNotExist(err1) || os.IsNotExist(err2) {
				sig, err := httputil.GenSelfTLSFiles(hostname, defCert, defKey)
				if err != nil {
					exitf("Could not generate self-signed TLS cert: %q", err)
				}
				log.Printf(hint, sig)
			} else {
				exitf("Could not stat cert or key: %q, %q", err1, err2)
			}
		}
	}
	// Always generate new certificates if the config's httpsCert and httpsKey are empty.
	if cert == "" && key == "" {
		sig, err := httputil.GenSelfTLSFiles(hostname, defCert, defKey)
		if err != nil {
			exitf("Could not generate self signed creds: %q", err)
		}
		log.Printf(hint, sig)
		cert = defCert
		key = defKey
	}
	data, err := wkfs.ReadFile(cert)
	if err != nil {
		exitf("Failed to read pem certificate: %s", err)
	}
	sig, err := httputil.CertFingerprint(data)
	if err != nil {
		exitf("certificate error: %v", err)
	}
	log.Printf("TLS enabled, with SHA-256 certificate fingerprint: %v", sig)
	ws.SetTLS(cert, key)
}
Beispiel #2
0
// GenerateClientConfig retuns a client configuration which can be used to
// access a server defined by the provided low-level server configuration.
func GenerateClientConfig(serverConfig jsonconfig.Obj) (*Config, error) {
	missingConfig := func(param string) (*Config, error) {
		return nil, fmt.Errorf("required value for %q not found", param)
	}

	if serverConfig == nil {
		return nil, errors.New("server config is a required parameter")
	}
	param := "auth"
	auth := serverConfig.OptionalString(param, "")
	if auth == "" {
		return missingConfig(param)
	}

	listen := serverConfig.OptionalString("listen", "")
	baseURL := serverConfig.OptionalString("baseURL", "")
	if listen == "" {
		listen = baseURL
	}
	if listen == "" {
		return nil, errors.New("required value for 'listen' or 'baseURL' not found")
	}

	https := serverConfig.OptionalBool("https", false)
	if !strings.HasPrefix(listen, "http://") && !strings.HasPrefix(listen, "https://") {
		if !https {
			listen = "http://" + listen
		} else {
			listen = "https://" + listen
		}
	}

	httpsCert := serverConfig.OptionalString("httpsCert", "")
	// TODO(mpl): See if we can detect that the cert is not self-signed,and in
	// that case not add it to the trustedCerts
	var trustedList []string
	if https && httpsCert != "" {
		certPEMBlock, err := wkfs.ReadFile(httpsCert)
		if err != nil {
			return nil, fmt.Errorf("could not read certificate: %v", err)
		}
		sig, err := httputil.CertFingerprint(certPEMBlock)
		if err != nil {
			return nil, fmt.Errorf("could not get fingerprints of certificate: %v", err)
		}
		trustedList = []string{sig}
	}
	param = "prefixes"
	prefixes := serverConfig.OptionalObject(param)
	if len(prefixes) == 0 {
		return missingConfig(param)
	}

	param = "/sighelper/"
	sighelper := prefixes.OptionalObject(param)
	if len(sighelper) == 0 {
		return missingConfig(param)
	}

	param = "handlerArgs"
	handlerArgs := sighelper.OptionalObject(param)
	if len(handlerArgs) == 0 {
		return missingConfig(param)
	}

	param = "keyId"
	keyId := handlerArgs.OptionalString(param, "")
	if keyId == "" {
		return missingConfig(param)
	}

	param = "secretRing"
	secretRing := handlerArgs.OptionalString(param, "")
	if secretRing == "" {
		return missingConfig(param)
	}

	return &Config{
		Servers: map[string]*Server{
			"default": {
				Server:       listen,
				Auth:         auth,
				IsDefault:    true,
				TrustedCerts: trustedList,
			},
		},
		Identity:           keyId,
		IdentitySecretRing: secretRing,
		IgnoredFiles:       []string{".DS_Store", "*~"},
	}, nil
}
Beispiel #3
0
// If cert/key files are specified, and found, use them.
// If cert/key files are specified, not found, and the default values, generate
// them (self-signed CA used as a cert), and use them.
// If cert/key files are not specified, use Let's Encrypt.
func setupTLS(ws *webserver.Server, config *serverinit.Config, hostname string) {
	cert, key := config.OptionalString("httpsCert", ""), config.OptionalString("httpsKey", "")
	if !config.OptionalBool("https", true) {
		return
	}
	if (cert != "") != (key != "") {
		exitf("httpsCert and httpsKey must both be either present or absent")
	}

	defCert := osutil.DefaultTLSCert()
	defKey := osutil.DefaultTLSKey()
	const hint = "You must add this certificate's fingerprint to your client's trusted certs list to use it. Like so:\n\"trustedCerts\": [\"%s\"],"
	if cert == defCert && key == defKey {
		_, err1 := wkfs.Stat(cert)
		_, err2 := wkfs.Stat(key)
		if err1 != nil || err2 != nil {
			if os.IsNotExist(err1) || os.IsNotExist(err2) {
				sig, err := httputil.GenSelfTLSFiles(hostname, defCert, defKey)
				if err != nil {
					exitf("Could not generate self-signed TLS cert: %q", err)
				}
				log.Printf(hint, sig)
			} else {
				exitf("Could not stat cert or key: %q, %q", err1, err2)
			}
		}
	}
	if cert == "" && key == "" {
		// Use Let's Encrypt if no files are specified, and we have a usable hostname.
		if netutil.IsFQDN(hostname) {
			m := autocert.Manager{
				Prompt:     autocert.AcceptTOS,
				HostPolicy: autocert.HostWhitelist(hostname),
				Cache:      autocert.DirCache(osutil.DefaultLetsEncryptCache()),
			}
			log.Print("TLS enabled, with Let's Encrypt")
			ws.SetTLS(webserver.TLSSetup{
				CertManager: m.GetCertificate,
			})
			return
		}
		// Otherwise generate new certificates
		sig, err := httputil.GenSelfTLSFiles(hostname, defCert, defKey)
		if err != nil {
			exitf("Could not generate self signed creds: %q", err)
		}
		log.Printf(hint, sig)
		cert = defCert
		key = defKey
	}
	data, err := wkfs.ReadFile(cert)
	if err != nil {
		exitf("Failed to read pem certificate: %s", err)
	}
	sig, err := httputil.CertFingerprint(data)
	if err != nil {
		exitf("certificate error: %v", err)
	}
	log.Printf("TLS enabled, with SHA-256 certificate fingerprint: %v", sig)
	ws.SetTLS(webserver.TLSSetup{
		CertFile: cert,
		KeyFile:  key,
	})
}