1 // godlighty -- highly-customizable HTTP, HTTP/2, HTTPS server
2 // Copyright (C) 2021-2024 Sergey Matveev <stargrave@stargrave.org>
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, version 3 of the License.
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License for more details.
13 // You should have received a copy of the GNU General Public License
14 // along with this program. If not, see <http://www.gnu.org/licenses/>.
29 NextProtos = []string{"h2", "http/1.1"}
31 HostToECDSACertificate map[string]*tls.Certificate
32 HostECDSAClientAuth map[string]*x509.CertPool
34 HostToEdDSACertificate map[string]*tls.Certificate
35 HostEdDSAClientAuth map[string]*x509.CertPool
37 HostToGOSTCertificate map[string]*tls.Certificate
38 HostGOSTClientAuth map[string]*x509.CertPool
41 func CHIHasTLS13(chi *tls.ClientHelloInfo) bool {
42 for _, v := range chi.SupportedVersions {
43 if v == tls.VersionTLS13 {
50 func CHIHasEdDSA(chi *tls.ClientHelloInfo) bool {
51 if !CHIHasTLS13(chi) {
54 for _, ss := range chi.SignatureSchemes {
55 if ss == tls.Ed25519 {
62 func GetCertificate(chi *tls.ClientHelloInfo) (*tls.Certificate, error) {
64 if cert := HostToGOSTCertificate[chi.ServerName]; cert != nil {
68 var cert *tls.Certificate
69 if len(HostToECDSACertificate) == 0 {
70 cert = HostToEdDSACertificate[chi.ServerName]
73 if cert := HostToEdDSACertificate[chi.ServerName]; cert != nil {
77 cert = HostToECDSACertificate[chi.ServerName]
80 return nil, errors.New("no certificate found")
85 func GetConfigForClient(chi *tls.ClientHelloInfo) (*tls.Config, error) {
86 var pool *x509.CertPool
88 pool = HostGOSTClientAuth[chi.ServerName]
90 if pool == nil && (CHIHasEdDSA(chi) || len(HostECDSAClientAuth) == 0) {
91 pool = HostEdDSAClientAuth[chi.ServerName]
94 pool = HostECDSAClientAuth[chi.ServerName]
100 GetCertificate: GetCertificate,
101 NextProtos: NextProtos,
103 ClientAuth: tls.RequireAndVerifyClientCert,
107 func loadCertificates(
110 hostToCertificate *map[string]*tls.Certificate,
111 hostClientAuth *map[string]*x509.CertPool,
116 cert, err := tls.LoadX509KeyPair(cfg.Cert, cfg.Key)
120 if cfg.CACert != "" {
121 data, err := os.ReadFile(cfg.CACert)
125 block, _ := pem.Decode(data)
127 log.Fatalln(fmt.Errorf("no PEM found: %s", cfg.CACert))
129 if block.Type != "CERTIFICATE" {
130 log.Fatalln(fmt.Errorf("non CERTIFICATE: %s", cfg.CACert))
132 cert.Certificate = append(cert.Certificate, block.Bytes)
134 (*hostToCertificate)[host] = &cert
135 pool := x509.NewCertPool()
136 for _, p := range cfg.ClientCAs {
137 data, err := os.ReadFile(p)
143 block, data = pem.Decode(data)
145 log.Fatalln("can not decode PEM:", p)
147 if block.Type != "CERTIFICATE" {
150 ca, err := x509.ParseCertificate(block.Bytes)
155 (*hostClientAuth)[host] = pool
160 func LoadCertificates() {
161 HostToECDSACertificate = make(map[string]*tls.Certificate, len(Hosts))
162 HostECDSAClientAuth = make(map[string]*x509.CertPool)
163 HostToEdDSACertificate = make(map[string]*tls.Certificate, len(Hosts))
164 HostEdDSAClientAuth = make(map[string]*x509.CertPool)
165 HostToGOSTCertificate = make(map[string]*tls.Certificate, len(Hosts))
166 HostGOSTClientAuth = make(map[string]*x509.CertPool)
167 for host, cfg := range Hosts {
168 loadCertificates(host, cfg.ECDSATLS, &HostToECDSACertificate, &HostECDSAClientAuth)
169 loadCertificates(host, cfg.EdDSATLS, &HostToEdDSACertificate, &HostEdDSAClientAuth)
170 loadCertificates(host, cfg.GOSTTLS, &HostToGOSTCertificate, &HostGOSTClientAuth)
174 func NewTLSConfig() *tls.Config {
176 MinVersion: tls.VersionTLS12,
177 NextProtos: NextProtos,
178 GetCertificate: GetCertificate,
179 GetConfigForClient: GetConfigForClient,