// loadX509KeyPair is a copy of tls.LoadX509KeyPair but using wkfs. func loadX509KeyPair(certFile, keyFile string) (cert tls.Certificate, err error) { certPEMBlock, err := wkfs.ReadFile(certFile) if err != nil { return } keyPEMBlock, err := wkfs.ReadFile(keyFile) if err != nil { return } return tls.X509KeyPair(certPEMBlock, keyPEMBlock) }
func initGithubSyncing() error { if !inProd { return nil } keyData, err := wkfs.ReadFile(githubSSHKeyGCS) if err != nil { log.Printf("Not syncing to github, because no ssh key found: %v", err) return nil } u, err := user.Current() if err != nil { return fmt.Errorf("can't look up user: %v", err) } sshDir := filepath.Join(u.HomeDir, ".ssh") if err := os.MkdirAll(sshDir, 0700); err != nil { return fmt.Errorf("failed to create ssh config dir %v: %v", sshDir, err) } keyFileName := filepath.Base(githubSSHKeyGCS) keyFile := filepath.Join(sshDir, keyFileName) if err := ioutil.WriteFile(keyFile, keyData, 0600); err != nil { return fmt.Errorf("failed to create temp github SSH key %v: %v", keyFile, err) } if err := ioutil.WriteFile( filepath.Join(sshDir, "config"), []byte(githubSSHConfig(keyFileName)), 0600); err != nil { return fmt.Errorf("failed to create github SSH config: %v", err) } hostSSHDir = sshDir githubSSHKey = keyFileName return nil }
// 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) }
// cachedToken returns the token saved in cacheFile. It specifically returns // errTokenExpired if the token is expired. func cachedToken(cacheFile string) (*oauth2.Token, error) { tok := new(oauth2.Token) tokenData, err := wkfs.ReadFile(cacheFile) if err != nil { return nil, err } if err = json.Unmarshal(tokenData, tok); err != nil { return nil, err } if !tok.Valid() { if tok != nil && time.Now().After(tok.Expiry) { return nil, errExpiredToken } return nil, errors.New("invalid token") } return tok, nil }
// 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 }
// 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, }) }