예제 #1
0
파일: config.go 프로젝트: FiloSottile/caddy
// 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
}
예제 #2
0
파일: acme.go 프로젝트: ldez/traefik
// CreateConfig creates a tls.config from using ACME configuration
func (a *ACME) CreateConfig(tlsConfig *tls.Config, CheckOnDemandDomain func(domain string) bool) error {
	acme.Logger = fmtlog.New(ioutil.Discard, "", 0)

	if len(a.StorageFile) == 0 {
		return errors.New("Empty StorageFile, please provide a filename for certs storage")
	}

	log.Debugf("Generating default certificate...")
	if len(tlsConfig.Certificates) == 0 {
		// no certificates in TLS config, so we add a default one
		cert, err := generateDefaultCertificate()
		if err != nil {
			return err
		}
		tlsConfig.Certificates = append(tlsConfig.Certificates, *cert)
	}
	var account *Account
	var needRegister bool

	// if certificates in storage, load them
	if fileInfo, err := os.Stat(a.StorageFile); err == nil && fileInfo.Size() != 0 {
		log.Infof("Loading ACME certificates...")
		// load account
		account, err = a.loadAccount(a)
		if err != nil {
			return err
		}
	} else {
		log.Infof("Generating ACME Account...")
		// Create a user. New accounts need an email and private key to start
		privateKey, err := rsa.GenerateKey(rand.Reader, 4096)
		if err != nil {
			return err
		}
		account = &Account{
			Email:      a.Email,
			PrivateKey: x509.MarshalPKCS1PrivateKey(privateKey),
		}
		account.DomainsCertificate = DomainsCertificates{Certs: []*DomainsCertificate{}, lock: &sync.RWMutex{}}
		needRegister = true
	}

	client, err := a.buildACMEClient(account)
	if err != nil {
		return err
	}
	client.ExcludeChallenges([]acme.Challenge{acme.HTTP01, acme.DNS01})
	wrapperChallengeProvider := newWrapperChallengeProvider()
	client.SetChallengeProvider(acme.TLSSNI01, wrapperChallengeProvider)

	if needRegister {
		// New users will need to register; be sure to save it
		reg, err := client.Register()
		if err != nil {
			return err
		}
		account.Registration = reg
	}

	// The client has a URL to the current Let's Encrypt Subscriber
	// Agreement. The user will need to agree to it.
	err = client.AgreeToTOS()
	if err != nil {
		return err
	}

	safe.Go(func() {
		a.retrieveCertificates(client, account)
	})

	tlsConfig.GetCertificate = func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
		if challengeCert, ok := wrapperChallengeProvider.getCertificate(clientHello.ServerName); ok {
			return challengeCert, nil
		}
		if domainCert, ok := account.DomainsCertificate.getCertificateForDomain(clientHello.ServerName); ok {
			return domainCert.tlsCert, nil
		}
		if a.OnDemand {
			if CheckOnDemandDomain != nil && !CheckOnDemandDomain(clientHello.ServerName) {
				return nil, nil
			}
			return a.loadCertificateOnDemand(client, account, clientHello)
		}
		return nil, nil
	}

	ticker := time.NewTicker(24 * time.Hour)
	safe.Go(func() {
		for {
			select {
			case <-ticker.C:

				if err := a.renewCertificates(client, account); err != nil {
					log.Errorf("Error renewing ACME certificate %+v: %s", account, err.Error())
				}
			}
		}

	})
	return nil
}
예제 #3
0
파일: main.go 프로젝트: nhooyr/goWiki
func main() {
	http.HandleFunc("/", newLoggingHandleFunc(rootHandler))
	http.HandleFunc("/new", newLoggingHandleFunc(newHandler))
	http.HandleFunc("/view/", newLoggingHandleFunc(newGzipHandleFunc(titleHandler(viewHandler))))
	http.HandleFunc("/edit/", newLoggingHandleFunc(newGzipHandleFunc(titleHandler(editHandler))))
	http.HandleFunc("/save/", newLoggingHandleFunc(titleHandler(saveHandler)))
	http.HandleFunc("/del/", newLoggingHandleFunc(titleHandler(delHandler)))
	http.HandleFunc("/front", newLoggingHandleFunc(newGzipHandleFunc(frontHandler)))
	http.HandleFunc("/hsts_hpkp", hsts_hpkp)
	log.SetPrefix("goWiki: ")
	log.Println("listening... on port", HTTPS_PORT)
	go func() {
		for {
			err := func() error {
				var OCSPC OCSPCert
				var err error
				cert, err := tls.LoadX509KeyPair(CERT, KEY)
				if err != nil {
					return err
				}
				OCSPC.cert = &cert
				if OCSPC.cert.Leaf, err = x509.ParseCertificate(OCSPC.cert.Certificate[0]); err != nil {
					return err
				}
				issuerRAW, err := ioutil.ReadFile(ISSUER)
				if err != nil {
					return err
				}
				for {
					var issuerPEM *pem.Block
					issuerPEM, issuerRAW = pem.Decode(issuerRAW)
					if issuerPEM == nil {
						break
					}
					if issuerPEM.Type == "CERTIFICATE" {
						OCSPC.issuer, err = x509.ParseCertificate(issuerPEM.Bytes)
						if err != nil {
							return err
						}
					}
				}
				if OCSPC.issuer == nil {
					return errors.New("no issuer")
				}
				OCSPC.req, err = ocsp.CreateRequest(OCSPC.cert.Leaf, OCSPC.issuer, nil)
				if err != nil {
					return err
				}
				err = OCSPC.updateStaple()
				if err != nil {
					return err
				}
				go OCSPC.stapleLoop()
				TLSConfig := new(tls.Config)
				TLSConfig.Certificates = []tls.Certificate{cert}
				TLSConfig.CipherSuites = []uint16{
					tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
					tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
					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_RSA_WITH_AES_128_CBC_SHA,
					tls.TLS_RSA_WITH_AES_256_CBC_SHA,
					tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
					tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA}
				TLSConfig.PreferServerCipherSuites = true
				TLSConfig.MinVersion = tls.VersionTLS11
				//MaxVersion needed because of bug with TLS_FALLBACK_SCSV gonna be fixed in go 1.5
				TLSConfig.MaxVersion = tls.VersionTLS12
				TLSConfig.NextProtos = []string{"http/1.1"}
				TLSConfig.GetCertificate = func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
					OCSPC.RLock()
					defer OCSPC.RUnlock()
					return OCSPC.cert, nil
				}
				ln, err := net.Listen("tcp", HTTPS_PORT)
				if err != nil {
					return err
				}
				tlsListener := tls.NewListener(tcpKeepAliveListener{ln.(*net.TCPListener)}, TLSConfig)
				return new(http.Server).Serve(tlsListener)
			}()
			if err != nil {
				log.Println(err)
			}
			time.Sleep(time.Second * TIMEOUT)
		}
	}()
	for {
		log.Println("redirecting from port", HTTP_PORT, "to", HTTPS_PORT)
		err := http.ListenAndServe(HTTP_PORT, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("X-Frame-Options", "SAMEORIGIN")
			w.Header().Set("Server", "Jesus")
			log.Println("redirecting http", r.RemoteAddr, "to https", DOMAIN+HTTPS_PORT+r.URL.Path)
			http.Redirect(w, r, "https://"+DOMAIN+HTTPS_PORT+r.URL.Path, http.StatusMovedPermanently)
		}))
		if err != nil {
			log.Println(err)
		}
		time.Sleep(time.Second * TIMEOUT)
	}
}
예제 #4
0
func main() {
	flag.Usage = usage

	port := flag.Uint("port", 443, "https port")
	certsPath := flag.String("letsencrypt-path", "/etc/letsencrypt/live", "path at which an 'xyz.example.com' containing 'fullchain.pem' and 'privkey.pem' can be found")
	defaultHost := flag.String("default-hostname", "localhost.daplie.com", "the default folder to find certificates to use when no matches are found")

	flag.Parse()

	host := strings.ToLower(*defaultHost)
	// See https://groups.google.com/a/letsencrypt.org/forum/#!topic/ca-dev/l1Dd6jzWeu8
	/*
		if strings.HasPrefix("www.", host) {
			fmt.Println("TODO: 'www.' prefixed certs should be obtained for every 'example.com' domain.")
		}
		host = strings.TrimPrefix("www.", host)
	*/

	fmt.Printf("Loading Certificates %s/%s/{privkey.pem,fullchain.pem}\n", *certsPath, *defaultHost)
	privkeyPath := filepath.Join(*certsPath, *defaultHost, "privkey.pem")
	certPath := filepath.Join(*certsPath, *defaultHost, "fullchain.pem")
	defaultCert, err := tls.LoadX509KeyPair(certPath, privkeyPath)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Couldn't load default certificates: %s\n", err)
		os.Exit(1)
	}

	addr := ":" + strconv.Itoa(int(*port))

	conn, err := net.Listen("tcp", addr)
	if nil != err {
		fmt.Fprintf(os.Stderr, "Couldn't bind to TCP socket %q: %s\n", addr, err)
		os.Exit(1)
	}

	certMap := make(map[string]myCert)
	tlsConfig := new(tls.Config)
	tlsConfig.Certificates = []tls.Certificate{defaultCert}
	tlsConfig.GetCertificate = func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {

		// Load from memory
		// TODO unload untouched certificates every x minutes
		if myCert, ok := certMap[clientHello.ServerName]; ok {
			myCert.touchedAt = time.Now()
			return myCert.cert, nil
		}

		privkeyPath := filepath.Join(*certsPath, clientHello.ServerName, "privkey.pem")
		certPath := filepath.Join(*certsPath, clientHello.ServerName, "fullchain.pem")

		loadCert := func() *tls.Certificate {
			// TODO handle race condition (ask Matt)
			// the transaction is idempotent, however, so it shouldn't matter
			if _, err := os.Stat(privkeyPath); err == nil {
				fmt.Printf("Loading Certificates %s/%s/{privkey.pem,fullchain.pem}\n\n", *certsPath, clientHello.ServerName)
				cert, err := tls.LoadX509KeyPair(certPath, privkeyPath)
				if nil != err {
					return &cert
				}
				return nil
			}

			return nil
		}

		if cert := loadCert(); nil != cert {
			certMap[clientHello.ServerName] = myCert{
				cert:      cert,
				touchedAt: time.Now(),
			}
			return cert, nil
		}

		// TODO try to get cert via letsencrypt python client
		// TODO check for a hosting directory before attempting this
		/*
			cmd := exec.Command(
				"./venv/bin/letsencrypt",
				"--text",
				"--agree-eula",
				"--email", "*****@*****.**",
				"--authenticator", "standalone",
				"--domains", "www.example.com",
				"--domains", "example.com",
				"--dvsni-port", "65443",
				"auth",
			)
			err := cmd.Run()
			if nil != err {
				if cert := loadCert(); nil != cert {
					return cert, nil
				}
			}
		*/

		fmt.Fprintf(os.Stderr, "Failed to load certificates for %q.\n", clientHello.ServerName)
		fmt.Fprintf(os.Stderr, "\tTried %s/{privkey.pem,fullchain.pem}\n", filepath.Join(*certsPath, clientHello.ServerName))
		//fmt.Fprintf(os.Stderr, "\tand letsencrypt api\n")
		fmt.Fprintf(os.Stderr, "\n")
		// TODO how to prevent attack and still enable retry?
		// perhaps check DNS and hosting directory, wait 5 minutes?
		certMap[clientHello.ServerName] = myCert{
			cert:      &defaultCert,
			touchedAt: time.Now(),
		}
		return &defaultCert, nil
	}
	tlsListener := tls.NewListener(conn, tlsConfig)

	server := &http.Server{
		Addr:    addr,
		Handler: &myHandler{},
	}
	fmt.Printf("Listening on https://%s:%d\n\n", host, *port)
	server.Serve(tlsListener)
}
예제 #5
0
파일: acme.go 프로젝트: vdemeester/traefik
// CreateLocalConfig creates a tls.config using local ACME configuration
func (a *ACME) CreateLocalConfig(tlsConfig *tls.Config, checkOnDemandDomain func(domain string) bool) error {
	err := a.init()
	if err != nil {
		return err
	}
	if len(a.Storage) == 0 {
		return errors.New("Empty Store, please provide a filename for certs storage")
	}
	a.checkOnDemandDomain = checkOnDemandDomain
	tlsConfig.Certificates = append(tlsConfig.Certificates, *a.defaultCertificate)
	tlsConfig.GetCertificate = a.getCertificate

	localStore := NewLocalStore(a.Storage)
	a.store = localStore
	a.challengeProvider = &challengeProvider{store: a.store}

	var needRegister bool
	var account *Account

	if fileInfo, fileErr := os.Stat(a.Storage); fileErr == nil && fileInfo.Size() != 0 {
		log.Infof("Loading ACME Account...")
		// load account
		object, err := localStore.Load()
		if err != nil {
			return err
		}
		account = object.(*Account)
	} else {
		log.Infof("Generating ACME Account...")
		account, err = NewAccount(a.Email)
		if err != nil {
			return err
		}
		needRegister = true
	}

	a.client, err = a.buildACMEClient(account)
	if err != nil {
		return err
	}

	if needRegister {
		// New users will need to register; be sure to save it
		log.Infof("Register...")
		reg, err := a.client.Register()
		if err != nil {
			return err
		}
		account.Registration = reg
	}

	// The client has a URL to the current Let's Encrypt Subscriber
	// Agreement. The user will need to agree to it.
	log.Debugf("AgreeToTOS...")
	err = a.client.AgreeToTOS()
	if err != nil {
		// Let's Encrypt Subscriber Agreement renew ?
		reg, err := a.client.QueryRegistration()
		if err != nil {
			return err
		}
		account.Registration = reg
		err = a.client.AgreeToTOS()
		if err != nil {
			log.Errorf("Error sending ACME agreement to TOS: %+v: %s", account, err.Error())
		}
	}
	// save account
	transaction, _, err := a.store.Begin()
	if err != nil {
		return err
	}
	err = transaction.Commit(account)
	if err != nil {
		return err
	}

	safe.Go(func() {
		a.retrieveCertificates()
		if err := a.renewCertificates(); err != nil {
			log.Errorf("Error renewing ACME certificate %+v: %s", account, err.Error())
		}
	})

	ticker := time.NewTicker(24 * time.Hour)
	safe.Go(func() {
		for range ticker.C {
			if err := a.renewCertificates(); err != nil {
				log.Errorf("Error renewing ACME certificate %+v: %s", account, err.Error())
			}
		}

	})
	return nil
}
예제 #6
0
파일: acme.go 프로젝트: vdemeester/traefik
// CreateClusterConfig creates a tls.config using ACME configuration in cluster mode
func (a *ACME) CreateClusterConfig(leadership *cluster.Leadership, tlsConfig *tls.Config, checkOnDemandDomain func(domain string) bool) error {
	err := a.init()
	if err != nil {
		return err
	}
	if len(a.Storage) == 0 {
		return errors.New("Empty Store, please provide a key for certs storage")
	}
	a.checkOnDemandDomain = checkOnDemandDomain
	tlsConfig.Certificates = append(tlsConfig.Certificates, *a.defaultCertificate)
	tlsConfig.GetCertificate = a.getCertificate
	listener := func(object cluster.Object) error {
		account := object.(*Account)
		account.Init()
		if !leadership.IsLeader() {
			a.client, err = a.buildACMEClient(account)
			if err != nil {
				log.Errorf("Error building ACME client %+v: %s", object, err.Error())
			}
		}
		return nil
	}

	datastore, err := cluster.NewDataStore(
		leadership.Pool.Ctx(),
		staert.KvSource{
			Store:  leadership.Store,
			Prefix: a.Storage,
		},
		&Account{},
		listener)
	if err != nil {
		return err
	}

	a.store = datastore
	a.challengeProvider = &challengeProvider{store: a.store}

	ticker := time.NewTicker(24 * time.Hour)
	leadership.Pool.AddGoCtx(func(ctx context.Context) {
		log.Infof("Starting ACME renew job...")
		defer log.Infof("Stopped ACME renew job...")
		for {
			select {
			case <-ctx.Done():
				return
			case <-ticker.C:
				if err := a.renewCertificates(); err != nil {
					log.Errorf("Error renewing ACME certificate: %s", err.Error())
				}
			}
		}
	})

	leadership.AddListener(func(elected bool) error {
		if elected {
			object, err := a.store.Load()
			if err != nil {
				return err
			}
			transaction, object, err := a.store.Begin()
			if err != nil {
				return err
			}
			account := object.(*Account)
			account.Init()
			var needRegister bool
			if account == nil || len(account.Email) == 0 {
				account, err = NewAccount(a.Email)
				if err != nil {
					return err
				}
				needRegister = true
			}
			if err != nil {
				return err
			}
			a.client, err = a.buildACMEClient(account)
			if err != nil {
				return err
			}
			if needRegister {
				// New users will need to register; be sure to save it
				log.Debugf("Register...")
				reg, err := a.client.Register()
				if err != nil {
					return err
				}
				account.Registration = reg
			}
			// The client has a URL to the current Let's Encrypt Subscriber
			// Agreement. The user will need to agree to it.
			log.Debugf("AgreeToTOS...")
			err = a.client.AgreeToTOS()
			if err != nil {
				// Let's Encrypt Subscriber Agreement renew ?
				reg, err := a.client.QueryRegistration()
				if err != nil {
					return err
				}
				account.Registration = reg
				err = a.client.AgreeToTOS()
				if err != nil {
					log.Errorf("Error sending ACME agreement to TOS: %+v: %s", account, err.Error())
				}
			}
			err = transaction.Commit(account)
			if err != nil {
				return err
			}
			safe.Go(func() {
				a.retrieveCertificates()
				if err := a.renewCertificates(); err != nil {
					log.Errorf("Error renewing ACME certificate %+v: %s", account, err.Error())
				}
			})
		}
		return nil
	})
	return nil
}