2 godlighty -- highly-customizable HTTP, HTTP/2, HTTPS server
3 Copyright (C) 2021-2023 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 HostToECDSACertificate map[string]*tls.Certificate
34 HostECDSAClientAuth map[string]*x509.CertPool
36 HostToEdDSACertificate map[string]*tls.Certificate
37 HostEdDSAClientAuth map[string]*x509.CertPool
39 HostToGOSTCertificate map[string]*tls.Certificate
40 HostGOSTClientAuth map[string]*x509.CertPool
43 func CHIHasTLS13(chi *tls.ClientHelloInfo) bool {
44 for _, v := range chi.SupportedVersions {
45 if v == tls.VersionTLS13 {
52 func CHIHasEdDSA(chi *tls.ClientHelloInfo) bool {
53 if !CHIHasTLS13(chi) {
56 for _, ss := range chi.SignatureSchemes {
57 if ss == tls.Ed25519 {
64 func GetCertificate(chi *tls.ClientHelloInfo) (*tls.Certificate, error) {
66 if cert := HostToGOSTCertificate[chi.ServerName]; cert != nil {
70 var cert *tls.Certificate
71 if len(HostToECDSACertificate) == 0 {
72 cert = HostToEdDSACertificate[chi.ServerName]
75 if cert := HostToEdDSACertificate[chi.ServerName]; cert != nil {
79 cert = HostToECDSACertificate[chi.ServerName]
82 return nil, errors.New("no certificate found")
87 func GetConfigForClient(chi *tls.ClientHelloInfo) (*tls.Config, error) {
88 var pool *x509.CertPool
90 pool = HostGOSTClientAuth[chi.ServerName]
92 if pool == nil && (CHIHasEdDSA(chi) || len(HostECDSAClientAuth) == 0) {
93 pool = HostEdDSAClientAuth[chi.ServerName]
96 pool = HostECDSAClientAuth[chi.ServerName]
102 GetCertificate: GetCertificate,
103 NextProtos: NextProtos,
105 ClientAuth: tls.RequireAndVerifyClientCert,
109 func loadCertificates(
112 hostToCertificate *map[string]*tls.Certificate,
113 hostClientAuth *map[string]*x509.CertPool,
118 cert, err := tls.LoadX509KeyPair(cfg.Cert, cfg.Key)
122 if cfg.CACert != "" {
123 data, err := os.ReadFile(cfg.CACert)
127 block, _ := pem.Decode(data)
129 log.Fatalln(fmt.Errorf("no PEM found: %s", cfg.CACert))
131 if block.Type != "CERTIFICATE" {
132 log.Fatalln(fmt.Errorf("non CERTIFICATE: %s", cfg.CACert))
134 cert.Certificate = append(cert.Certificate, block.Bytes)
136 (*hostToCertificate)[host] = &cert
137 pool := x509.NewCertPool()
138 for _, p := range cfg.ClientCAs {
139 data, err := os.ReadFile(p)
145 block, data = pem.Decode(data)
147 log.Fatalln("can not decode PEM:", p)
149 if block.Type != "CERTIFICATE" {
152 ca, err := x509.ParseCertificate(block.Bytes)
157 (*hostClientAuth)[host] = pool
162 func LoadCertificates() {
163 HostToECDSACertificate = make(map[string]*tls.Certificate, len(Hosts))
164 HostECDSAClientAuth = make(map[string]*x509.CertPool)
165 HostToEdDSACertificate = make(map[string]*tls.Certificate, len(Hosts))
166 HostEdDSAClientAuth = make(map[string]*x509.CertPool)
167 HostToGOSTCertificate = make(map[string]*tls.Certificate, len(Hosts))
168 HostGOSTClientAuth = make(map[string]*x509.CertPool)
169 for host, cfg := range Hosts {
170 loadCertificates(host, cfg.ECDSATLS, &HostToECDSACertificate, &HostECDSAClientAuth)
171 loadCertificates(host, cfg.EdDSATLS, &HostToEdDSACertificate, &HostEdDSAClientAuth)
172 loadCertificates(host, cfg.GOSTTLS, &HostToGOSTCertificate, &HostGOSTClientAuth)
176 func NewTLSConfig() *tls.Config {
178 MinVersion: tls.VersionTLS12,
179 NextProtos: NextProtos,
180 GetCertificate: GetCertificate,
181 GetConfigForClient: GetConfigForClient,