code.gitea.io/gitea@v1.21.7/cmd/web_https.go (about) 1 // Copyright 2021 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package cmd 5 6 import ( 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 19 var 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 27 func toTLSVersion(version string) uint16 { 28 tlsVersion, ok := tlsVersionStringMap[strings.TrimSpace(strings.ToLower(version))] 29 if !ok { 30 log.Warn("Unknown tls version: %s", version) 31 return 0 32 } 33 return tlsVersion 34 } 35 36 var curveStringMap = map[string]tls.CurveID{ 37 "x25519": tls.X25519, 38 "p256": tls.CurveP256, 39 "p384": tls.CurveP384, 40 "p521": tls.CurveP521, 41 } 42 43 func toCurvePreferences(preferences []string) []tls.CurveID { 44 ids := make([]tls.CurveID, 0, len(preferences)) 45 for _, pref := range preferences { 46 id, ok := curveStringMap[strings.TrimSpace(strings.ToLower(pref))] 47 if !ok { 48 log.Warn("Unknown curve: %s", pref) 49 } 50 if id != 0 { 51 ids = append(ids, id) 52 } 53 } 54 return ids 55 } 56 57 var 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 87 func toTLSCiphers(cipherStrings []string) []uint16 { 88 ciphers := make([]uint16, 0, len(cipherStrings)) 89 for _, cipherString := range cipherStrings { 90 cipher, ok := cipherStringMap[strings.TrimSpace(strings.ToLower(cipherString))] 91 if !ok { 92 log.Warn("Unknown cipher: %s", cipherString) 93 } 94 if cipher != 0 { 95 ciphers = append(ciphers, cipher) 96 } 97 } 98 99 return 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.) 107 func defaultCiphers() []uint16 { 108 if cpuid.CPU.Supports(cpuid.AESNI) { 109 return defaultCiphersAESfirst 110 } 111 return defaultCiphersChaChaFirst 112 } 113 114 var ( 115 defaultCiphersAES = []uint16{ 116 tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 117 tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 118 tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 119 tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 120 } 121 122 defaultCiphersChaCha = []uint16{ 123 tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, 124 tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, 125 } 126 127 defaultCiphersAESfirst = append(defaultCiphersAES, defaultCiphersChaCha...) 128 defaultCiphersChaChaFirst = 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. 138 func runHTTPS(network, listenAddr, name, certFile, keyFile string, m http.Handler, useProxyProtocol, proxyProtocolTLSBridging bool) error { 139 tlsConfig := &tls.Config{} 140 if tlsConfig.NextProtos == nil { 141 tlsConfig.NextProtos = []string{"h2", "http/1.1"} 142 } 143 144 if version := toTLSVersion(setting.SSLMinimumVersion); version != 0 { 145 tlsConfig.MinVersion = version 146 } 147 if version := toTLSVersion(setting.SSLMaximumVersion); version != 0 { 148 tlsConfig.MaxVersion = version 149 } 150 151 // Set curve preferences 152 tlsConfig.CurvePreferences = []tls.CurveID{ 153 tls.X25519, 154 tls.CurveP256, 155 } 156 if curves := toCurvePreferences(setting.SSLCurvePreferences); len(curves) > 0 { 157 tlsConfig.CurvePreferences = curves 158 } 159 160 // Set cipher suites 161 tlsConfig.CipherSuites = defaultCiphers() 162 if ciphers := toTLSCiphers(setting.SSLCipherSuites); len(ciphers) > 0 { 163 tlsConfig.CipherSuites = ciphers 164 } 165 166 tlsConfig.Certificates = make([]tls.Certificate, 1) 167 168 certPEMBlock, err := os.ReadFile(certFile) 169 if err != nil { 170 log.Error("Failed to load https cert file %s for %s:%s: %v", certFile, network, listenAddr, err) 171 return err 172 } 173 174 keyPEMBlock, err := os.ReadFile(keyFile) 175 if err != nil { 176 log.Error("Failed to load https key file %s for %s:%s: %v", keyFile, network, listenAddr, err) 177 return err 178 } 179 180 tlsConfig.Certificates[0], err = tls.X509KeyPair(certPEMBlock, keyPEMBlock) 181 if err != nil { 182 log.Error("Failed to create certificate from cert file %s and key file %s for %s:%s: %v", certFile, keyFile, network, listenAddr, err) 183 return err 184 } 185 186 return graceful.HTTPListenAndServeTLSConfig(network, listenAddr, name, tlsConfig, m, useProxyProtocol, proxyProtocolTLSBridging) 187 } 188 189 func runHTTPSWithTLSConfig(network, listenAddr, name string, tlsConfig *tls.Config, m http.Handler, useProxyProtocol, proxyProtocolTLSBridging bool) error { 190 return graceful.HTTPListenAndServeTLSConfig(network, listenAddr, name, tlsConfig, m, useProxyProtocol, proxyProtocolTLSBridging) 191 }