github.com/dbernstein1/tyk@v2.9.0-beta9-dl-apic+incompatible/gateway/cert.go (about) 1 package gateway 2 3 import ( 4 "crypto/tls" 5 "crypto/x509" 6 "errors" 7 "io/ioutil" 8 "net" 9 "net/http" 10 "strings" 11 12 "github.com/TykTechnologies/tyk/certs" 13 "github.com/TykTechnologies/tyk/config" 14 15 "github.com/gorilla/mux" 16 ) 17 18 type APICertificateStatusMessage struct { 19 CertID string `json:"id"` 20 Status string `json:"status"` 21 Message string `json:"message"` 22 } 23 24 type APIAllCertificates struct { 25 CertIDs []string `json:"certs"` 26 } 27 28 var cipherSuites = map[string]uint16{ 29 "TLS_RSA_WITH_RC4_128_SHA": 0x0005, 30 "TLS_RSA_WITH_3DES_EDE_CBC_SHA": 0x000a, 31 "TLS_RSA_WITH_AES_128_CBC_SHA": 0x002f, 32 "TLS_RSA_WITH_AES_256_CBC_SHA": 0x0035, 33 "TLS_RSA_WITH_AES_128_CBC_SHA256": 0x003c, 34 "TLS_RSA_WITH_AES_128_GCM_SHA256": 0x009c, 35 "TLS_RSA_WITH_AES_256_GCM_SHA384": 0x009d, 36 "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA": 0xc007, 37 "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA": 0xc009, 38 "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA": 0xc00a, 39 "TLS_ECDHE_RSA_WITH_RC4_128_SHA": 0xc011, 40 "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA": 0xc012, 41 "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA": 0xc013, 42 "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA": 0xc014, 43 "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256": 0xc023, 44 "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256": 0xc027, 45 "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256": 0xc02f, 46 "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": 0xc02b, 47 "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384": 0xc030, 48 "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": 0xc02c, 49 "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305": 0xcca8, 50 "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305": 0xcca9, 51 } 52 53 var certLog = log.WithField("prefix", "certs") 54 55 func getUpstreamCertificate(host string, spec *APISpec) (cert *tls.Certificate) { 56 var certID string 57 58 certMaps := []map[string]string{config.Global().Security.Certificates.Upstream} 59 60 if spec != nil && spec.UpstreamCertificates != nil { 61 certMaps = append(certMaps, spec.UpstreamCertificates) 62 } 63 64 for _, m := range certMaps { 65 if len(m) == 0 { 66 continue 67 } 68 69 if id, ok := m["*"]; ok { 70 certID = id 71 } 72 73 hostParts := strings.SplitN(host, ".", 2) 74 if len(hostParts) > 1 { 75 hostPattern := "*." + hostParts[1] 76 77 if id, ok := m[hostPattern]; ok { 78 certID = id 79 } 80 } 81 82 if id, ok := m[host]; ok { 83 certID = id 84 } 85 } 86 87 if certID == "" { 88 return nil 89 } 90 91 certs := CertificateManager.List([]string{certID}, certs.CertificatePrivate) 92 93 if len(certs) == 0 { 94 return nil 95 } 96 97 return certs[0] 98 } 99 100 func verifyPeerCertificatePinnedCheck(spec *APISpec, tlsConfig *tls.Config) func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { 101 if (spec == nil || len(spec.PinnedPublicKeys) == 0) && len(config.Global().Security.PinnedPublicKeys) == 0 { 102 return nil 103 } 104 105 tlsConfig.InsecureSkipVerify = true 106 107 whitelist := getPinnedPublicKeys("*", spec) 108 if len(whitelist) == 0 { 109 return nil 110 } 111 112 return func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { 113 certLog.Debug("Checking certificate public key") 114 115 for _, rawCert := range rawCerts { 116 cert, _ := x509.ParseCertificate(rawCert) 117 pub, err := x509.MarshalPKIXPublicKey(cert.PublicKey) 118 if err != nil { 119 continue 120 } 121 122 fingerprint := certs.HexSHA256(pub) 123 124 for _, w := range whitelist { 125 if w == fingerprint { 126 return nil 127 } 128 } 129 } 130 131 return errors.New("Certificate public key pinning error. Public keys do not match.") 132 } 133 } 134 135 func dialTLSPinnedCheck(spec *APISpec, tc *tls.Config) func(network, addr string) (net.Conn, error) { 136 if (spec == nil || len(spec.PinnedPublicKeys) == 0) && len(config.Global().Security.PinnedPublicKeys) == 0 { 137 return nil 138 } 139 140 return func(network, addr string) (net.Conn, error) { 141 clone := tc.Clone() 142 clone.InsecureSkipVerify = true 143 144 c, err := tls.Dial(network, addr, clone) 145 if err != nil { 146 return c, err 147 } 148 149 host, _, _ := net.SplitHostPort(addr) 150 whitelist := getPinnedPublicKeys(host, spec) 151 if len(whitelist) == 0 { 152 return c, nil 153 } 154 155 certLog.Debug("Checking certificate public key for host:", host) 156 157 state := c.ConnectionState() 158 for _, peercert := range state.PeerCertificates { 159 der, err := x509.MarshalPKIXPublicKey(peercert.PublicKey) 160 if err != nil { 161 continue 162 } 163 fingerprint := certs.HexSHA256(der) 164 165 for _, w := range whitelist { 166 if w == fingerprint { 167 return c, nil 168 } 169 } 170 } 171 172 return nil, errors.New("https://" + host + " certificate public key pinning error. Public keys do not match.") 173 } 174 } 175 176 func getPinnedPublicKeys(host string, spec *APISpec) (fingerprint []string) { 177 var keyIDs string 178 179 pinMaps := []map[string]string{config.Global().Security.PinnedPublicKeys} 180 181 if spec != nil && spec.PinnedPublicKeys != nil { 182 pinMaps = append(pinMaps, spec.PinnedPublicKeys) 183 } 184 185 for _, m := range pinMaps { 186 if len(m) == 0 { 187 continue 188 } 189 190 if id, ok := m["*"]; ok { 191 keyIDs = id 192 } 193 194 hostParts := strings.SplitN(host, ".", 2) 195 if len(hostParts) > 1 { 196 hostPattern := "*." + hostParts[1] 197 198 if id, ok := m[hostPattern]; ok { 199 keyIDs = id 200 } 201 } 202 203 if id, ok := m[host]; ok { 204 keyIDs = id 205 } 206 } 207 208 if keyIDs == "" { 209 return nil 210 } 211 212 return CertificateManager.ListPublicKeys(strings.Split(keyIDs, ",")) 213 } 214 215 // dummyGetCertificate needed because TLSConfig require setting Certificates array or GetCertificate function from start, even if it get overriden by `getTLSConfigForClient` 216 func dummyGetCertificate(*tls.ClientHelloInfo) (*tls.Certificate, error) { 217 return nil, nil 218 } 219 220 func getTLSConfigForClient(baseConfig *tls.Config, listenPort int) func(hello *tls.ClientHelloInfo) (*tls.Config, error) { 221 222 // Supporting legacy certificate configuration 223 serverCerts := []tls.Certificate{} 224 certNameMap := map[string]*tls.Certificate{} 225 226 for _, certData := range config.Global().HttpServerOptions.Certificates { 227 cert, err := tls.LoadX509KeyPair(certData.CertFile, certData.KeyFile) 228 if err != nil { 229 log.Errorf("Server error: loadkeys: %s", err) 230 continue 231 } 232 serverCerts = append(serverCerts, cert) 233 certNameMap[certData.Name] = &cert 234 } 235 236 for _, cert := range CertificateManager.List(config.Global().HttpServerOptions.SSLCertificates, certs.CertificatePrivate) { 237 serverCerts = append(serverCerts, *cert) 238 } 239 240 baseConfig.Certificates = serverCerts 241 242 baseConfig.BuildNameToCertificate() 243 for name, cert := range certNameMap { 244 baseConfig.NameToCertificate[name] = cert 245 } 246 247 return func(hello *tls.ClientHelloInfo) (*tls.Config, error) { 248 newConfig := baseConfig.Clone() 249 250 isControlAPI := (listenPort != 0 && config.Global().ControlAPIPort == listenPort) || (config.Global().ControlAPIHostname == hello.ServerName) 251 252 if isControlAPI && config.Global().Security.ControlAPIUseMutualTLS { 253 newConfig.ClientAuth = tls.RequireAndVerifyClientCert 254 newConfig.ClientCAs = CertificateManager.CertPool(config.Global().Security.Certificates.ControlAPI) 255 256 return newConfig, nil 257 } 258 259 apisMu.RLock() 260 defer apisMu.RUnlock() 261 262 // Dynamically add API specific certificates 263 for _, spec := range apiSpecs { 264 if len(spec.Certificates) != 0 { 265 for _, cert := range CertificateManager.List(spec.Certificates, certs.CertificatePrivate) { 266 newConfig.Certificates = append(newConfig.Certificates, *cert) 267 268 if cert != nil { 269 if len(cert.Leaf.Subject.CommonName) > 0 { 270 newConfig.NameToCertificate[cert.Leaf.Subject.CommonName] = cert 271 } 272 for _, san := range cert.Leaf.DNSNames { 273 newConfig.NameToCertificate[san] = cert 274 } 275 } 276 } 277 } 278 } 279 280 for _, spec := range apiSpecs { 281 if spec.UseMutualTLSAuth && spec.Domain != "" && spec.Domain == hello.ServerName { 282 newConfig.ClientAuth = tls.RequireAndVerifyClientCert 283 certIDs := append(spec.ClientCertificates, config.Global().Security.Certificates.API...) 284 newConfig.ClientCAs = CertificateManager.CertPool(certIDs) 285 break 286 } 287 } 288 289 // No mutual tls APIs with matched domain found 290 // Check if one of APIs without domain, require asking client cert 291 if newConfig.ClientAuth == tls.NoClientCert { 292 for _, spec := range apiSpecs { 293 if spec.Auth.UseCertificate || (spec.Domain == "" && spec.UseMutualTLSAuth) { 294 newConfig.ClientAuth = tls.RequestClientCert 295 break 296 } 297 } 298 } 299 300 return newConfig, nil 301 } 302 } 303 304 func certHandler(w http.ResponseWriter, r *http.Request) { 305 certID := mux.Vars(r)["certID"] 306 307 switch r.Method { 308 case "POST": 309 content, err := ioutil.ReadAll(r.Body) 310 if err != nil { 311 doJSONWrite(w, 405, apiError("Malformed request body")) 312 return 313 } 314 315 orgID := r.URL.Query().Get("org_id") 316 var certID string 317 if certID, err = CertificateManager.Add(content, orgID); err != nil { 318 doJSONWrite(w, http.StatusForbidden, apiError(err.Error())) 319 return 320 } 321 322 doJSONWrite(w, http.StatusOK, &APICertificateStatusMessage{certID, "ok", "Certificate added"}) 323 case "GET": 324 if certID == "" { 325 orgID := r.URL.Query().Get("org_id") 326 327 certIds := CertificateManager.ListAllIds(orgID) 328 doJSONWrite(w, http.StatusOK, &APIAllCertificates{certIds}) 329 return 330 } 331 332 certIDs := strings.Split(certID, ",") 333 certificates := CertificateManager.List(certIDs, certs.CertificateAny) 334 335 if len(certIDs) == 1 { 336 if certificates[0] == nil { 337 doJSONWrite(w, http.StatusNotFound, apiError("Certificate with given SHA256 fingerprint not found")) 338 return 339 } 340 341 doJSONWrite(w, http.StatusOK, certs.ExtractCertificateMeta(certificates[0], certIDs[0])) 342 return 343 } else { 344 var meta []*certs.CertificateMeta 345 for ci, cert := range certificates { 346 if cert != nil { 347 meta = append(meta, certs.ExtractCertificateMeta(cert, certIDs[ci])) 348 } else { 349 meta = append(meta, nil) 350 } 351 } 352 353 doJSONWrite(w, http.StatusOK, meta) 354 return 355 } 356 case "DELETE": 357 CertificateManager.Delete(certID) 358 doJSONWrite(w, http.StatusOK, &apiStatusMessage{"ok", "removed"}) 359 } 360 } 361 362 func getCipherAliases(ciphers []string) (cipherCodes []uint16) { 363 for k, v := range cipherSuites { 364 for _, str := range ciphers { 365 if str == k { 366 cipherCodes = append(cipherCodes, v) 367 } 368 } 369 } 370 return cipherCodes 371 }