gitea
Зеркало из https://github.com/go-gitea/gitea
1// Copyright 2021 The Gitea Authors. All rights reserved.
2// SPDX-License-Identifier: MIT
3
4package cmd
5
6import (
7"crypto/tls"
8"net/http"
9"os"
10"strings"
11
12"code.gitea.io/gitea/modules/graceful"
13"code.gitea.io/gitea/modules/log"
14"code.gitea.io/gitea/modules/setting"
15
16"github.com/klauspost/cpuid/v2"
17)
18
19var tlsVersionStringMap = map[string]uint16{
20"": tls.VersionTLS12, // Default to tls.VersionTLS12
21"tlsv1.0": tls.VersionTLS10,
22"tlsv1.1": tls.VersionTLS11,
23"tlsv1.2": tls.VersionTLS12,
24"tlsv1.3": tls.VersionTLS13,
25}
26
27func toTLSVersion(version string) uint16 {
28tlsVersion, ok := tlsVersionStringMap[strings.TrimSpace(strings.ToLower(version))]
29if !ok {
30log.Warn("Unknown tls version: %s", version)
31return 0
32}
33return tlsVersion
34}
35
36var curveStringMap = map[string]tls.CurveID{
37"x25519": tls.X25519,
38"p256": tls.CurveP256,
39"p384": tls.CurveP384,
40"p521": tls.CurveP521,
41}
42
43func toCurvePreferences(preferences []string) []tls.CurveID {
44ids := make([]tls.CurveID, 0, len(preferences))
45for _, pref := range preferences {
46id, ok := curveStringMap[strings.TrimSpace(strings.ToLower(pref))]
47if !ok {
48log.Warn("Unknown curve: %s", pref)
49}
50if id != 0 {
51ids = append(ids, id)
52}
53}
54return ids
55}
56
57var cipherStringMap = map[string]uint16{
58"rsa_with_rc4_128_sha": tls.TLS_RSA_WITH_RC4_128_SHA,
59"rsa_with_3des_ede_cbc_sha": tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
60"rsa_with_aes_128_cbc_sha": tls.TLS_RSA_WITH_AES_128_CBC_SHA,
61"rsa_with_aes_256_cbc_sha": tls.TLS_RSA_WITH_AES_256_CBC_SHA,
62"rsa_with_aes_128_cbc_sha256": tls.TLS_RSA_WITH_AES_128_CBC_SHA256,
63"rsa_with_aes_128_gcm_sha256": tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
64"rsa_with_aes_256_gcm_sha384": tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
65"ecdhe_ecdsa_with_rc4_128_sha": tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
66"ecdhe_ecdsa_with_aes_128_cbc_sha": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
67"ecdhe_ecdsa_with_aes_256_cbc_sha": tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
68"ecdhe_rsa_with_rc4_128_sha": tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
69"ecdhe_rsa_with_3des_ede_cbc_sha": tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
70"ecdhe_rsa_with_aes_128_cbc_sha": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
71"ecdhe_rsa_with_aes_256_cbc_sha": tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
72"ecdhe_ecdsa_with_aes_128_cbc_sha256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
73"ecdhe_rsa_with_aes_128_cbc_sha256": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
74"ecdhe_rsa_with_aes_128_gcm_sha256": tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
75"ecdhe_ecdsa_with_aes_128_gcm_sha256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
76"ecdhe_rsa_with_aes_256_gcm_sha384": tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
77"ecdhe_ecdsa_with_aes_256_gcm_sha384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
78"ecdhe_rsa_with_chacha20_poly1305_sha256": tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
79"ecdhe_ecdsa_with_chacha20_poly1305_sha256": tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
80"ecdhe_rsa_with_chacha20_poly1305": tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
81"ecdhe_ecdsa_with_chacha20_poly1305": tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
82"aes_128_gcm_sha256": tls.TLS_AES_128_GCM_SHA256,
83"aes_256_gcm_sha384": tls.TLS_AES_256_GCM_SHA384,
84"chacha20_poly1305_sha256": tls.TLS_CHACHA20_POLY1305_SHA256,
85}
86
87func toTLSCiphers(cipherStrings []string) []uint16 {
88ciphers := make([]uint16, 0, len(cipherStrings))
89for _, cipherString := range cipherStrings {
90cipher, ok := cipherStringMap[strings.TrimSpace(strings.ToLower(cipherString))]
91if !ok {
92log.Warn("Unknown cipher: %s", cipherString)
93}
94if cipher != 0 {
95ciphers = append(ciphers, cipher)
96}
97}
98
99return ciphers
100}
101
102// defaultCiphers uses hardware support to check if AES is specifically
103// supported by the CPU.
104//
105// If AES is supported AES ciphers will be preferred over ChaCha based ciphers
106// (This code is directly inspired by the certmagic code.)
107func defaultCiphers() []uint16 {
108if cpuid.CPU.Supports(cpuid.AESNI) {
109return defaultCiphersAESfirst
110}
111return defaultCiphersChaChaFirst
112}
113
114var (
115defaultCiphersAES = []uint16{
116tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
117tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
118tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
119tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
120}
121
122defaultCiphersChaCha = []uint16{
123tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
124tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
125}
126
127defaultCiphersAESfirst = append(defaultCiphersAES, defaultCiphersChaCha...)
128defaultCiphersChaChaFirst = append(defaultCiphersChaCha, defaultCiphersAES...)
129)
130
131// runHTTPS listens on the provided network address and then calls
132// Serve to handle requests on incoming TLS connections.
133//
134// Filenames containing a certificate and matching private key for the server must
135// be provided. If the certificate is signed by a certificate authority, the
136// certFile should be the concatenation of the server's certificate followed by the
137// CA's certificate.
138func runHTTPS(network, listenAddr, name, certFile, keyFile string, m http.Handler, useProxyProtocol, proxyProtocolTLSBridging bool) error {
139tlsConfig := &tls.Config{}
140if tlsConfig.NextProtos == nil {
141tlsConfig.NextProtos = []string{"h2", "http/1.1"}
142}
143
144if version := toTLSVersion(setting.SSLMinimumVersion); version != 0 {
145tlsConfig.MinVersion = version
146}
147if version := toTLSVersion(setting.SSLMaximumVersion); version != 0 {
148tlsConfig.MaxVersion = version
149}
150
151// Set curve preferences
152tlsConfig.CurvePreferences = []tls.CurveID{
153tls.X25519,
154tls.CurveP256,
155}
156if curves := toCurvePreferences(setting.SSLCurvePreferences); len(curves) > 0 {
157tlsConfig.CurvePreferences = curves
158}
159
160// Set cipher suites
161tlsConfig.CipherSuites = defaultCiphers()
162if ciphers := toTLSCiphers(setting.SSLCipherSuites); len(ciphers) > 0 {
163tlsConfig.CipherSuites = ciphers
164}
165
166tlsConfig.Certificates = make([]tls.Certificate, 1)
167
168certPEMBlock, err := os.ReadFile(certFile)
169if err != nil {
170log.Error("Failed to load https cert file %s for %s:%s: %v", certFile, network, listenAddr, err)
171return err
172}
173
174keyPEMBlock, err := os.ReadFile(keyFile)
175if err != nil {
176log.Error("Failed to load https key file %s for %s:%s: %v", keyFile, network, listenAddr, err)
177return err
178}
179
180tlsConfig.Certificates[0], err = tls.X509KeyPair(certPEMBlock, keyPEMBlock)
181if err != nil {
182log.Error("Failed to create certificate from cert file %s and key file %s for %s:%s: %v", certFile, keyFile, network, listenAddr, err)
183return err
184}
185
186return graceful.HTTPListenAndServeTLSConfig(network, listenAddr, name, tlsConfig, m, useProxyProtocol, proxyProtocolTLSBridging)
187}
188
189func runHTTPSWithTLSConfig(network, listenAddr, name string, tlsConfig *tls.Config, m http.Handler, useProxyProtocol, proxyProtocolTLSBridging bool) error {
190return graceful.HTTPListenAndServeTLSConfig(network, listenAddr, name, tlsConfig, m, useProxyProtocol, proxyProtocolTLSBridging)
191}
192