From 489296abca9c8c5fb9ad3a2f2d15b6eff09fc9a0 Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Tue, 28 Apr 2020 13:24:00 +0200 Subject: [PATCH] aperture: extract TLS configuration into function --- aperture.go | 139 ++++++++++++++++++++++++++++------------------------ 1 file changed, 75 insertions(+), 64 deletions(-) diff --git a/aperture.go b/aperture.go index f21a7cb..c9da2e8 100644 --- a/aperture.go +++ b/aperture.go @@ -99,70 +99,11 @@ func start() error { Handler: handler, } - // Create TLS certificates. - switch { - // When using autocert, we set a TLSConfig on the server so the key and - // cert file we pass in are ignored and don't need to exist. - case cfg.AutoCert: - serverName := cfg.ServerName - if serverName == "" { - return fmt.Errorf("servername option is required for " + - "secure operation") - } - - certDir := filepath.Join(apertureDataDir, "autocert") - log.Infof("Configuring autocert for server %v with cache dir "+ - "%v", serverName, certDir) - - manager := autocert.Manager{ - Cache: autocert.DirCache(certDir), - Prompt: autocert.AcceptTOS, - HostPolicy: autocert.HostWhitelist(serverName), - } - - go func() { - err := http.ListenAndServe( - ":http", manager.HTTPHandler(nil), - ) - if err != nil { - log.Errorf("autocert http: %v", err) - } - }() - httpsServer.TLSConfig = &tls.Config{ - GetCertificate: manager.GetCertificate, - CipherSuites: http2TLSCipherSuites, - MinVersion: tls.VersionTLS12, - } - - // If we're not using autocert, we want to create self-signed TLS certs - // and save them at the specified location (if they don't already - // exist). - default: - tlsKeyFile := filepath.Join(apertureDataDir, defaultTLSKeyFilename) - tlsCertFile := filepath.Join(apertureDataDir, defaultTLSCertFilename) - if !fileExists(tlsCertFile) && !fileExists(tlsKeyFile) { - log.Infof("Generating TLS certificates...") - err := cert.GenCertPair( - "aperture autogenerated cert", tlsCertFile, - tlsKeyFile, nil, nil, - cert.DefaultAutogenValidity, - ) - if err != nil { - return err - } - log.Infof("Done generating TLS certificates") - } - - // Load the certs now so we can create a complete TLS config. - certData, _, err := cert.LoadCert(tlsCertFile, tlsKeyFile) - if err != nil { - return err - } - httpsServer.TLSConfig = &tls.Config{ - Certificates: []tls.Certificate{certData}, - CipherSuites: http2TLSCipherSuites, - MinVersion: tls.VersionTLS12, - } + // Create TLS configuration by either creating new self-signed certs or + // trying to obtain one through Let's Encrypt. + httpsServer.TLSConfig, err = getTLSConfig(cfg.ServerName, cfg.AutoCert) + if err != nil { + return err } // The ListenAndServeTLS below will block until shut down or an error @@ -258,6 +199,76 @@ func setupLogging(cfg *config) error { return build.ParseAndSetDebugLevels(cfg.DebugLevel, logWriter) } +// getTLSConfig returns a TLS configuration for either a self-signed certificate +// or one obtained through Let's Encrypt. +func getTLSConfig(serverName string, autoCert bool) (*tls.Config, error) { + var tlsKeyFile, tlsCertFile string + switch { + // When using autocert, we set a TLSConfig on the server so the key and + // cert file we pass in are ignored and don't need to exist. + case autoCert: + serverName := serverName + if serverName == "" { + return nil, fmt.Errorf("servername option is " + + "required for secure operation") + } + + certDir := filepath.Join(apertureDataDir, "autocert") + log.Infof("Configuring autocert for server %v with cache dir "+ + "%v", serverName, certDir) + + manager := autocert.Manager{ + Cache: autocert.DirCache(certDir), + Prompt: autocert.AcceptTOS, + HostPolicy: autocert.HostWhitelist(serverName), + } + + go func() { + err := http.ListenAndServe( + ":http", manager.HTTPHandler(nil), + ) + if err != nil { + log.Errorf("autocert http: %v", err) + } + }() + return &tls.Config{ + GetCertificate: manager.GetCertificate, + CipherSuites: http2TLSCipherSuites, + MinVersion: tls.VersionTLS12, + }, nil + + // If we're not using autocert, we want to create self-signed TLS certs + // and save them at the specified location (if they don't already + // exist). + default: + tlsKeyFile = filepath.Join(apertureDataDir, defaultTLSKeyFilename) + tlsCertFile = filepath.Join(apertureDataDir, defaultTLSCertFilename) + if !fileExists(tlsCertFile) && !fileExists(tlsKeyFile) { + log.Infof("Generating TLS certificates...") + err := cert.GenCertPair( + "aperture autogenerated cert", tlsCertFile, + tlsKeyFile, nil, nil, + cert.DefaultAutogenValidity, + ) + if err != nil { + return nil, err + } + log.Infof("Done generating TLS certificates") + } + + // Load the certs now so we can return a complete TLS config. + certData, _, err := cert.LoadCert(tlsCertFile, tlsKeyFile) + if err != nil { + return nil, err + } + return &tls.Config{ + Certificates: []tls.Certificate{certData}, + CipherSuites: http2TLSCipherSuites, + MinVersion: tls.VersionTLS12, + }, nil + } +} + // initTorListener initiates a Tor controller instance with the Tor server // specified in the config. Onion services will be created over which the proxy // can be reached at.