2 godlighty -- highly-customizable HTTP, HTTP/2, HTTPS server
3 Copyright (C) 2021-2022 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"}
33 HostToCertificate map[string]*tls.Certificate
34 HostClientAuth map[string]*x509.CertPool
36 HostToGOSTCertificate map[string]*tls.Certificate
37 HostGOSTClientAuth map[string]*x509.CertPool
40 func GetCertificate(chi *tls.ClientHelloInfo) (*tls.Certificate, error) {
42 if cert := HostToGOSTCertificate[chi.ServerName]; cert != nil {
46 cert := HostToCertificate[chi.ServerName]
48 return nil, errors.New("no certificate found")
53 func GetConfigForClient(chi *tls.ClientHelloInfo) (*tls.Config, error) {
54 var pool *x509.CertPool
56 pool = HostGOSTClientAuth[chi.ServerName]
59 pool = HostClientAuth[chi.ServerName]
65 GetCertificate: GetCertificate,
66 NextProtos: NextProtos,
68 ClientAuth: tls.RequireAndVerifyClientCert,
72 func loadCertificates(
75 hostToCertificate *map[string]*tls.Certificate,
76 hostClientAuth *map[string]*x509.CertPool,
81 cert, err := tls.LoadX509KeyPair(cfg.Cert, cfg.Key)
86 data, err := os.ReadFile(cfg.CACert)
90 block, _ := pem.Decode(data)
92 log.Fatalln(fmt.Errorf("no PEM found: %s", cfg.CACert))
94 if block.Type != "CERTIFICATE" {
95 log.Fatalln(fmt.Errorf("non CERTIFICATE: %s", cfg.CACert))
97 cert.Certificate = append(cert.Certificate, block.Bytes)
99 (*hostToCertificate)[host] = &cert
100 pool := x509.NewCertPool()
101 for _, p := range cfg.ClientCAs {
102 data, err := os.ReadFile(p)
108 block, data = pem.Decode(data)
110 log.Fatalln("can not decode PEM:", p)
112 if block.Type != "CERTIFICATE" {
115 ca, err := x509.ParseCertificate(block.Bytes)
122 if len(pool.Subjects()) > 0 {
123 (*hostClientAuth)[host] = pool
127 func LoadCertificates() {
128 HostToCertificate = make(map[string]*tls.Certificate, len(Hosts))
129 HostClientAuth = make(map[string]*x509.CertPool)
130 HostToGOSTCertificate = make(map[string]*tls.Certificate, len(Hosts))
131 HostGOSTClientAuth = make(map[string]*x509.CertPool)
132 for host, cfg := range Hosts {
133 loadCertificates(host, cfg.TLS, &HostToCertificate, &HostClientAuth)
134 loadCertificates(host, cfg.GOSTTLS, &HostToGOSTCertificate, &HostGOSTClientAuth)
138 func NewTLSConfig() *tls.Config {
140 NextProtos: NextProtos,
141 GetCertificate: GetCertificate,
142 GetConfigForClient: GetConfigForClient,