2 godlighty -- highly-customizable HTTP, HTTP/2, HTTPS server
3 Copyright (C) 2021 Sergey Matveev <stargrave@stargrave.org>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, version 3 of the License.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
31 NextProtos = []string{"h2", "http/1.1"}
32 HostToCertificate map[string]*tls.Certificate
33 HostClientAuth map[string]*x509.CertPool
36 func GetCertificate(chi *tls.ClientHelloInfo) (*tls.Certificate, error) {
37 cert := HostToCertificate[chi.ServerName]
39 return nil, errors.New("no certificate found")
44 func GetConfigForClient(chi *tls.ClientHelloInfo) (*tls.Config, error) {
45 pool := HostClientAuth[chi.ServerName]
50 GetCertificate: GetCertificate,
51 NextProtos: NextProtos,
53 ClientAuth: tls.RequireAndVerifyClientCert,
57 func LoadCertificates() {
58 HostToCertificate = make(map[string]*tls.Certificate, len(Hosts))
59 HostClientAuth = make(map[string]*x509.CertPool)
60 for host, cfg := range Hosts {
64 cert, err := tls.LoadX509KeyPair(cfg.TLS.Cert, cfg.TLS.Key)
68 if cfg.TLS.CACert != "" {
69 data, err := ioutil.ReadFile(cfg.TLS.CACert)
73 block, _ := pem.Decode(data)
75 log.Fatalln(fmt.Errorf("no PEM found: %s", cfg.TLS.CACert))
77 if block.Type != "CERTIFICATE" {
78 log.Fatalln(fmt.Errorf("non CERTIFICATE: %s", cfg.TLS.CACert))
80 cert.Certificate = append(cert.Certificate, block.Bytes)
82 HostToCertificate[host] = &cert
83 pool := x509.NewCertPool()
84 for _, p := range cfg.TLS.ClientCAs {
85 data, err := ioutil.ReadFile(p)
91 block, data = pem.Decode(data)
93 log.Fatalln("can not decode PEM:", p)
95 if block.Type != "CERTIFICATE" {
98 ca, err := x509.ParseCertificate(block.Bytes)
105 if len(pool.Subjects()) > 0 {
106 HostClientAuth[host] = pool
111 func NewTLSConfig() *tls.Config {
113 NextProtos: NextProtos,
114 GetCertificate: GetCertificate,
115 GetConfigForClient: GetConfigForClient,