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 {
71 if cert := HostToEdDSACertificate[chi.ServerName]; cert != nil {
75 cert := HostToECDSACertificate[chi.ServerName]
77 return nil, errors.New("no certificate found")
82 func GetConfigForClient(chi *tls.ClientHelloInfo) (*tls.Config, error) {
83 var pool *x509.CertPool
85 pool = HostGOSTClientAuth[chi.ServerName]
87 if pool == nil && CHIHasEdDSA(chi) {
88 pool = HostEdDSAClientAuth[chi.ServerName]
91 pool = HostECDSAClientAuth[chi.ServerName]
97 GetCertificate: GetCertificate,
98 NextProtos: NextProtos,
100 ClientAuth: tls.RequireAndVerifyClientCert,
104 func loadCertificates(
107 hostToCertificate *map[string]*tls.Certificate,
108 hostClientAuth *map[string]*x509.CertPool,
113 cert, err := tls.LoadX509KeyPair(cfg.Cert, cfg.Key)
117 if cfg.CACert != "" {
118 data, err := os.ReadFile(cfg.CACert)
122 block, _ := pem.Decode(data)
124 log.Fatalln(fmt.Errorf("no PEM found: %s", cfg.CACert))
126 if block.Type != "CERTIFICATE" {
127 log.Fatalln(fmt.Errorf("non CERTIFICATE: %s", cfg.CACert))
129 cert.Certificate = append(cert.Certificate, block.Bytes)
131 (*hostToCertificate)[host] = &cert
132 pool := x509.NewCertPool()
133 for _, p := range cfg.ClientCAs {
134 data, err := os.ReadFile(p)
140 block, data = pem.Decode(data)
142 log.Fatalln("can not decode PEM:", p)
144 if block.Type != "CERTIFICATE" {
147 ca, err := x509.ParseCertificate(block.Bytes)
154 if len(pool.Subjects()) > 0 {
155 (*hostClientAuth)[host] = pool
159 func LoadCertificates() {
160 HostToECDSACertificate = make(map[string]*tls.Certificate, len(Hosts))
161 HostECDSAClientAuth = make(map[string]*x509.CertPool)
162 HostToEdDSACertificate = make(map[string]*tls.Certificate, len(Hosts))
163 HostEdDSAClientAuth = make(map[string]*x509.CertPool)
164 HostToGOSTCertificate = make(map[string]*tls.Certificate, len(Hosts))
165 HostGOSTClientAuth = make(map[string]*x509.CertPool)
166 for host, cfg := range Hosts {
167 loadCertificates(host, cfg.ECDSATLS, &HostToECDSACertificate, &HostECDSAClientAuth)
168 loadCertificates(host, cfg.EdDSATLS, &HostToEdDSACertificate, &HostEdDSAClientAuth)
169 loadCertificates(host, cfg.GOSTTLS, &HostToGOSTCertificate, &HostGOSTClientAuth)
173 func NewTLSConfig() *tls.Config {
175 MinVersion: tls.VersionTLS12,
176 NextProtos: NextProtos,
177 GetCertificate: GetCertificate,
178 GetConfigForClient: GetConfigForClient,