github.com/Tyktechnologies/tyk@v2.9.5+incompatible/gateway/cert_test.go (about)

     1  package gateway
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/rand"
     6  	"crypto/rsa"
     7  	"crypto/tls"
     8  	"crypto/x509"
     9  	"crypto/x509/pkix"
    10  	"encoding/pem"
    11  	"fmt"
    12  	"io/ioutil"
    13  	"math/big"
    14  	"net"
    15  	"net/http"
    16  	"net/http/httptest"
    17  	"os"
    18  	"path/filepath"
    19  	"strings"
    20  	"sync"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/TykTechnologies/tyk/apidef"
    25  	"github.com/TykTechnologies/tyk/certs"
    26  	"github.com/TykTechnologies/tyk/config"
    27  	"github.com/TykTechnologies/tyk/test"
    28  	"github.com/TykTechnologies/tyk/user"
    29  )
    30  
    31  func genCertificate(template *x509.Certificate) ([]byte, []byte, []byte, tls.Certificate) {
    32  	priv, _ := rsa.GenerateKey(rand.Reader, 512)
    33  
    34  	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
    35  	serialNumber, _ := rand.Int(rand.Reader, serialNumberLimit)
    36  	template.SerialNumber = serialNumber
    37  	template.BasicConstraintsValid = true
    38  	template.NotBefore = time.Now()
    39  	template.NotAfter = template.NotBefore.Add(time.Hour)
    40  
    41  	derBytes, _ := x509.CreateCertificate(rand.Reader, template, template, &priv.PublicKey, priv)
    42  
    43  	var certPem, keyPem bytes.Buffer
    44  	pem.Encode(&certPem, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
    45  	pem.Encode(&keyPem, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
    46  
    47  	clientCert, _ := tls.X509KeyPair(certPem.Bytes(), keyPem.Bytes())
    48  
    49  	combinedPEM := bytes.Join([][]byte{certPem.Bytes(), keyPem.Bytes()}, []byte("\n"))
    50  
    51  	return certPem.Bytes(), keyPem.Bytes(), combinedPEM, clientCert
    52  }
    53  
    54  func genServerCertificate() ([]byte, []byte, []byte, tls.Certificate) {
    55  	certPem, privPem, combinedPEM, cert := genCertificate(&x509.Certificate{
    56  		DNSNames:    []string{"localhost"},
    57  		IPAddresses: []net.IP{net.ParseIP("127.0.0.1"), net.ParseIP("::")},
    58  	})
    59  
    60  	return certPem, privPem, combinedPEM, cert
    61  }
    62  
    63  const (
    64  	internalTLSErr  = "tls: internal error"
    65  	badcertErr      = "tls: bad certificate"
    66  	certNotMatchErr = "Client TLS certificate is required"
    67  )
    68  
    69  func TestGatewayTLS(t *testing.T) {
    70  	// Configure server
    71  	serverCertPem, serverPrivPem, combinedPEM, _ := genServerCertificate()
    72  
    73  	dir, _ := ioutil.TempDir("", "certs")
    74  	defer os.RemoveAll(dir)
    75  
    76  	client := GetTLSClient(nil, nil)
    77  
    78  	t.Run("Without certificates", func(t *testing.T) {
    79  		globalConf := config.Global()
    80  		globalConf.HttpServerOptions.UseSSL = true
    81  		config.SetGlobal(globalConf)
    82  		defer ResetTestConfig()
    83  
    84  		ts := StartTest()
    85  		defer ts.Close()
    86  
    87  		BuildAndLoadAPI(func(spec *APISpec) {
    88  			spec.Proxy.ListenPath = "/"
    89  		})
    90  
    91  		ts.Run(t, test.TestCase{ErrorMatch: internalTLSErr, Client: client})
    92  	})
    93  
    94  	t.Run("Legacy TLS certificate path", func(t *testing.T) {
    95  		certFilePath := filepath.Join(dir, "server.crt")
    96  		ioutil.WriteFile(certFilePath, serverCertPem, 0666)
    97  
    98  		certKeyPath := filepath.Join(dir, "server.key")
    99  		ioutil.WriteFile(certKeyPath, serverPrivPem, 0666)
   100  
   101  		globalConf := config.Global()
   102  		globalConf.HttpServerOptions.Certificates = []config.CertData{{
   103  			Name:     "localhost",
   104  			CertFile: certFilePath,
   105  			KeyFile:  certKeyPath,
   106  		}}
   107  		globalConf.HttpServerOptions.UseSSL = true
   108  		config.SetGlobal(globalConf)
   109  		defer ResetTestConfig()
   110  
   111  		ts := StartTest()
   112  		defer ts.Close()
   113  
   114  		BuildAndLoadAPI(func(spec *APISpec) {
   115  			spec.Proxy.ListenPath = "/"
   116  		})
   117  
   118  		ts.Run(t, test.TestCase{Code: 200, Client: client})
   119  
   120  		CertificateManager.FlushCache()
   121  		tlsConfigCache.Flush()
   122  	})
   123  
   124  	t.Run("File certificate path", func(t *testing.T) {
   125  		certPath := filepath.Join(dir, "server.pem")
   126  		ioutil.WriteFile(certPath, combinedPEM, 0666)
   127  
   128  		globalConf := config.Global()
   129  		globalConf.HttpServerOptions.SSLCertificates = []string{certPath}
   130  		globalConf.HttpServerOptions.UseSSL = true
   131  		config.SetGlobal(globalConf)
   132  		defer ResetTestConfig()
   133  
   134  		ts := StartTest()
   135  		defer ts.Close()
   136  
   137  		BuildAndLoadAPI(func(spec *APISpec) {
   138  			spec.Proxy.ListenPath = "/"
   139  		})
   140  
   141  		ts.Run(t, test.TestCase{Code: 200, Client: client})
   142  
   143  		CertificateManager.FlushCache()
   144  		tlsConfigCache.Flush()
   145  	})
   146  
   147  	t.Run("Redis certificate", func(t *testing.T) {
   148  		certID, err := CertificateManager.Add(combinedPEM, "")
   149  		if err != nil {
   150  			t.Fatal(err)
   151  		}
   152  		defer CertificateManager.Delete(certID, "")
   153  
   154  		globalConf := config.Global()
   155  		globalConf.HttpServerOptions.SSLCertificates = []string{certID}
   156  		globalConf.HttpServerOptions.UseSSL = true
   157  		config.SetGlobal(globalConf)
   158  		defer ResetTestConfig()
   159  
   160  		ts := StartTest()
   161  		defer ts.Close()
   162  
   163  		BuildAndLoadAPI(func(spec *APISpec) {
   164  			spec.Proxy.ListenPath = "/"
   165  		})
   166  
   167  		ts.Run(t, test.TestCase{Code: 200, Client: client})
   168  
   169  		CertificateManager.FlushCache()
   170  		tlsConfigCache.Flush()
   171  	})
   172  }
   173  
   174  func TestGatewayControlAPIMutualTLS(t *testing.T) {
   175  	// Configure server
   176  	serverCertPem, _, combinedPEM, _ := genServerCertificate()
   177  
   178  	globalConf := config.Global()
   179  	globalConf.HttpServerOptions.UseSSL = true
   180  	globalConf.Security.ControlAPIUseMutualTLS = true
   181  	config.SetGlobal(globalConf)
   182  	defer ResetTestConfig()
   183  
   184  	dir, _ := ioutil.TempDir("", "certs")
   185  
   186  	defer func() {
   187  		os.RemoveAll(dir)
   188  		CertificateManager.FlushCache()
   189  		tlsConfigCache.Flush()
   190  	}()
   191  
   192  	clientCertPem, _, _, clientCert := genCertificate(&x509.Certificate{})
   193  	clientWithCert := GetTLSClient(&clientCert, serverCertPem)
   194  
   195  	clientWithoutCert := GetTLSClient(nil, nil)
   196  
   197  	t.Run("Separate domain", func(t *testing.T) {
   198  		certID, _ := CertificateManager.Add(combinedPEM, "")
   199  		defer CertificateManager.Delete(certID, "")
   200  
   201  		globalConf := config.Global()
   202  		globalConf.ControlAPIHostname = "localhost"
   203  		globalConf.HttpServerOptions.SSLCertificates = []string{certID}
   204  		config.SetGlobal(globalConf)
   205  
   206  		ts := StartTest()
   207  		defer ts.Close()
   208  
   209  		defer func() {
   210  			CertificateManager.FlushCache()
   211  			tlsConfigCache.Flush()
   212  			globalConf := config.Global()
   213  			globalConf.HttpServerOptions.SSLCertificates = nil
   214  			globalConf.Security.Certificates.ControlAPI = nil
   215  			config.SetGlobal(globalConf)
   216  		}()
   217  
   218  		unknownErr := "x509: certificate signed by unknown authority"
   219  
   220  		ts.Run(t, []test.TestCase{
   221  			// Should acess tyk without client certificates
   222  			{Client: clientWithoutCert},
   223  			// Should raise error for ControlAPI without certificate
   224  			{ControlRequest: true, ErrorMatch: unknownErr},
   225  			// Should raise error for for unknown certificate
   226  			{ControlRequest: true, ErrorMatch: badcertErr, Client: clientWithCert},
   227  		}...)
   228  
   229  		clientCertID, _ := CertificateManager.Add(clientCertPem, "")
   230  		defer CertificateManager.Delete(clientCertID, "")
   231  
   232  		globalConf = config.Global()
   233  		globalConf.Security.Certificates.ControlAPI = []string{clientCertID}
   234  		config.SetGlobal(globalConf)
   235  
   236  		// Should pass request with valid client cert
   237  		ts.Run(t, test.TestCase{
   238  			Path: "/tyk/certs", Code: 200, ControlRequest: true, AdminAuth: true, Client: clientWithCert,
   239  		})
   240  	})
   241  }
   242  
   243  func TestAPIMutualTLS(t *testing.T) {
   244  	// Configure server
   245  	serverCertPem, _, combinedPEM, _ := genServerCertificate()
   246  	certID, _ := CertificateManager.Add(combinedPEM, "")
   247  	defer CertificateManager.Delete(certID, "")
   248  
   249  	globalConf := config.Global()
   250  	globalConf.EnableCustomDomains = true
   251  	globalConf.HttpServerOptions.UseSSL = true
   252  	globalConf.ListenPort = 0
   253  	globalConf.HttpServerOptions.SSLCertificates = []string{certID}
   254  	config.SetGlobal(globalConf)
   255  	defer ResetTestConfig()
   256  
   257  	ts := StartTest()
   258  	defer ts.Close()
   259  
   260  	// Initialize client certificates
   261  	clientCertPem, _, _, clientCert := genCertificate(&x509.Certificate{})
   262  	clientCertPem2, _, _, clientCert2 := genCertificate(&x509.Certificate{})
   263  
   264  	t.Run("SNI and domain per API", func(t *testing.T) {
   265  		t.Run("API without mutual TLS", func(t *testing.T) {
   266  			client := GetTLSClient(&clientCert, serverCertPem)
   267  
   268  			BuildAndLoadAPI(func(spec *APISpec) {
   269  				spec.Domain = "localhost"
   270  				spec.Proxy.ListenPath = "/"
   271  			})
   272  
   273  			ts.Run(t, test.TestCase{Path: "/", Code: 200, Client: client, Domain: "localhost"})
   274  		})
   275  
   276  		t.Run("MutualTLSCertificate not set", func(t *testing.T) {
   277  			client := GetTLSClient(nil, nil)
   278  
   279  			BuildAndLoadAPI(func(spec *APISpec) {
   280  				spec.Domain = "localhost"
   281  				spec.Proxy.ListenPath = "/"
   282  				spec.UseMutualTLSAuth = true
   283  			})
   284  
   285  			ts.Run(t, test.TestCase{
   286  				ErrorMatch: badcertErr,
   287  				Client:     client,
   288  				Domain:     "localhost",
   289  			})
   290  		})
   291  
   292  		t.Run("Client certificate match", func(t *testing.T) {
   293  			client := GetTLSClient(&clientCert, serverCertPem)
   294  			clientCertID, _ := CertificateManager.Add(clientCertPem, "")
   295  
   296  			BuildAndLoadAPI(func(spec *APISpec) {
   297  				spec.Domain = "localhost"
   298  				spec.Proxy.ListenPath = "/"
   299  				spec.UseMutualTLSAuth = true
   300  				spec.ClientCertificates = []string{clientCertID}
   301  			})
   302  
   303  			ts.Run(t, test.TestCase{
   304  				Code: 200, Client: client, Domain: "localhost",
   305  			})
   306  
   307  			CertificateManager.Delete(clientCertID, "")
   308  			CertificateManager.FlushCache()
   309  			tlsConfigCache.Flush()
   310  
   311  			client = GetTLSClient(&clientCert, serverCertPem)
   312  			ts.Run(t, test.TestCase{
   313  				Client: client, Domain: "localhost", ErrorMatch: badcertErr,
   314  			})
   315  		})
   316  
   317  		t.Run("Client certificate differ", func(t *testing.T) {
   318  			client := GetTLSClient(&clientCert, serverCertPem)
   319  
   320  			clientCertPem2, _, _, _ := genCertificate(&x509.Certificate{})
   321  			clientCertID2, _ := CertificateManager.Add(clientCertPem2, "")
   322  			defer CertificateManager.Delete(clientCertID2, "")
   323  
   324  			BuildAndLoadAPI(func(spec *APISpec) {
   325  				spec.Domain = "localhost"
   326  				spec.Proxy.ListenPath = "/"
   327  				spec.UseMutualTLSAuth = true
   328  				spec.ClientCertificates = []string{clientCertID2}
   329  			})
   330  
   331  			ts.Run(t, test.TestCase{
   332  				Client: client, ErrorMatch: badcertErr, Domain: "localhost",
   333  			})
   334  		})
   335  	})
   336  
   337  	t.Run("Multiple APIs on same domain", func(t *testing.T) {
   338  		testSameDomain := func(t *testing.T, domain string) {
   339  			clientCertID, _ := CertificateManager.Add(clientCertPem, "")
   340  			defer CertificateManager.Delete(clientCertID, "")
   341  
   342  			loadAPIS := func(certs ...string) {
   343  				BuildAndLoadAPI(
   344  					func(spec *APISpec) {
   345  						spec.Proxy.ListenPath = "/without_mutual"
   346  						spec.Domain = domain
   347  					},
   348  					func(spec *APISpec) {
   349  						spec.Proxy.ListenPath = "/with_mutual"
   350  						spec.UseMutualTLSAuth = true
   351  						spec.ClientCertificates = certs
   352  						spec.Domain = domain
   353  					},
   354  				)
   355  			}
   356  
   357  			t.Run("Without certificate", func(t *testing.T) {
   358  				clientWithoutCert := GetTLSClient(nil, nil)
   359  
   360  				loadAPIS()
   361  
   362  				ts.Run(t, []test.TestCase{
   363  					{
   364  						Path:      "/with_mutual",
   365  						Client:    clientWithoutCert,
   366  						Domain:    domain,
   367  						Code:      403,
   368  						BodyMatch: `"error": "` + certNotMatchErr,
   369  					},
   370  					{
   371  						Path:   "/without_mutual",
   372  						Client: clientWithoutCert,
   373  						Domain: domain,
   374  						Code:   200,
   375  					},
   376  				}...)
   377  			})
   378  
   379  			t.Run("Client certificate not match", func(t *testing.T) {
   380  				client := GetTLSClient(&clientCert, serverCertPem)
   381  
   382  				loadAPIS()
   383  
   384  				certNotAllowedErr := `Certificate with SHA256 ` + certs.HexSHA256(clientCert.Certificate[0]) + ` not allowed`
   385  
   386  				ts.Run(t, test.TestCase{
   387  					Path:      "/with_mutual",
   388  					Client:    client,
   389  					Domain:    domain,
   390  					Code:      403,
   391  					BodyMatch: `"error": "` + certNotAllowedErr,
   392  				})
   393  			})
   394  
   395  			t.Run("Client certificate match", func(t *testing.T) {
   396  				loadAPIS(clientCertID)
   397  				client := GetTLSClient(&clientCert, serverCertPem)
   398  
   399  				ts.Run(t, test.TestCase{
   400  					Path:   "/with_mutual",
   401  					Domain: domain,
   402  					Client: client,
   403  					Code:   200,
   404  				})
   405  			})
   406  		}
   407  
   408  		t.Run("Empty domain", func(t *testing.T) {
   409  			testSameDomain(t, "")
   410  		})
   411  
   412  		t.Run("Custom domain", func(t *testing.T) {
   413  			testSameDomain(t, "localhost")
   414  		})
   415  	})
   416  
   417  	t.Run("Multiple APIs with Mutual TLS on the same domain", func(t *testing.T) {
   418  		testSameDomain := func(t *testing.T, domain string) {
   419  			clientCertID, _ := CertificateManager.Add(clientCertPem, "")
   420  			defer CertificateManager.Delete(clientCertID, "")
   421  
   422  			clientCertID2, _ := CertificateManager.Add(clientCertPem2, "")
   423  			defer CertificateManager.Delete(clientCertID2, "")
   424  
   425  			loadAPIS := func(certs []string, certs2 []string) {
   426  				BuildAndLoadAPI(
   427  					func(spec *APISpec) {
   428  						spec.Proxy.ListenPath = "/with_mutual"
   429  						spec.UseMutualTLSAuth = true
   430  						spec.ClientCertificates = certs
   431  						spec.Domain = domain
   432  					},
   433  					func(spec *APISpec) {
   434  						spec.Proxy.ListenPath = "/with_mutual_2"
   435  						spec.UseMutualTLSAuth = true
   436  						spec.ClientCertificates = certs2
   437  						spec.Domain = domain
   438  					},
   439  				)
   440  			}
   441  
   442  			t.Run("Without certificate", func(t *testing.T) {
   443  				clientWithoutCert := GetTLSClient(nil, nil)
   444  
   445  				loadAPIS([]string{}, []string{})
   446  
   447  				ts.Run(t, []test.TestCase{
   448  					{
   449  						Path:       "/with_mutual",
   450  						Client:     clientWithoutCert,
   451  						Domain:     domain,
   452  						ErrorMatch: badcertErr,
   453  					},
   454  					{
   455  						Path:       "/with_mutual_2",
   456  						Client:     clientWithoutCert,
   457  						Domain:     domain,
   458  						ErrorMatch: badcertErr,
   459  					},
   460  				}...)
   461  			})
   462  
   463  			t.Run("Client certificate not match", func(t *testing.T) {
   464  				client := GetTLSClient(&clientCert, serverCertPem)
   465  
   466  				loadAPIS([]string{}, []string{})
   467  
   468  				ts.Run(t, test.TestCase{
   469  					Path:       "/with_mutual",
   470  					Client:     client,
   471  					Domain:     domain,
   472  					ErrorMatch: badcertErr,
   473  				})
   474  
   475  				ts.Run(t, test.TestCase{
   476  					Path:       "/with_mutual_2",
   477  					Client:     client,
   478  					Domain:     domain,
   479  					ErrorMatch: badcertErr,
   480  				})
   481  			})
   482  
   483  			t.Run("Client certificate match", func(t *testing.T) {
   484  				loadAPIS([]string{clientCertID}, []string{clientCertID2})
   485  				client := GetTLSClient(&clientCert, serverCertPem)
   486  				client2 := GetTLSClient(&clientCert2, serverCertPem)
   487  
   488  				ts.Run(t,
   489  					[]test.TestCase{
   490  						{
   491  							Path:   "/with_mutual",
   492  							Domain: domain,
   493  							Client: client,
   494  							Code:   200,
   495  						},
   496  						{
   497  							Path:      "/with_mutual_2",
   498  							Domain:    domain,
   499  							Client:    client,
   500  							Code:      403,
   501  							BodyMatch: `"error": "` + `Certificate with SHA256 ` + certs.HexSHA256(clientCert.Certificate[0]) + ` not allowed`,
   502  						},
   503  						{
   504  							Path:   "/with_mutual_2",
   505  							Domain: domain,
   506  							Client: client2,
   507  							Code:   200,
   508  						},
   509  						{
   510  							Path:      "/with_mutual",
   511  							Domain:    domain,
   512  							Client:    client2,
   513  							Code:      403,
   514  							BodyMatch: `"error": "` + `Certificate with SHA256 ` + certs.HexSHA256(clientCert2.Certificate[0]) + ` not allowed`,
   515  						},
   516  					}...,
   517  				)
   518  			})
   519  		}
   520  
   521  		t.Run("Empty domain", func(t *testing.T) {
   522  			testSameDomain(t, "")
   523  		})
   524  
   525  		t.Run("Custom domain", func(t *testing.T) {
   526  			testSameDomain(t, "localhost")
   527  		})
   528  	})
   529  
   530  	t.Run("Multiple APIs, mutual on custom", func(t *testing.T) {
   531  		testSameDomain := func(t *testing.T, domain string) {
   532  			clientCertID, _ := CertificateManager.Add(clientCertPem, "")
   533  			defer CertificateManager.Delete(clientCertID, "")
   534  
   535  			loadAPIS := func(certs ...string) {
   536  				BuildAndLoadAPI(
   537  					func(spec *APISpec) {
   538  						spec.Proxy.ListenPath = "/with_mutual"
   539  						spec.UseMutualTLSAuth = true
   540  						spec.ClientCertificates = certs
   541  						spec.Domain = domain
   542  					},
   543  					func(spec *APISpec) {
   544  						spec.Proxy.ListenPath = "/without_mutual"
   545  					},
   546  				)
   547  			}
   548  
   549  			t.Run("Without certificate", func(t *testing.T) {
   550  				clientWithoutCert := GetTLSClient(nil, nil)
   551  
   552  				loadAPIS()
   553  
   554  				if domain == "" {
   555  					ts.Run(t, test.TestCase{
   556  						Path:      "/with_mutual",
   557  						Client:    clientWithoutCert,
   558  						Domain:    domain,
   559  						Code:      403,
   560  						BodyMatch: `"error": "` + certNotMatchErr,
   561  					})
   562  				} else {
   563  					ts.Run(t, test.TestCase{
   564  						Path:       "/with_mutual",
   565  						Client:     clientWithoutCert,
   566  						Domain:     domain,
   567  						ErrorMatch: badcertErr,
   568  					})
   569  				}
   570  
   571  				ts.Run(t, test.TestCase{
   572  					Path:   "/without_mutual",
   573  					Client: clientWithoutCert,
   574  					Code:   200,
   575  				})
   576  			})
   577  
   578  			t.Run("Client certificate not match", func(t *testing.T) {
   579  				client := GetTLSClient(&clientCert, serverCertPem)
   580  
   581  				loadAPIS()
   582  
   583  				if domain == "" {
   584  					certNotAllowedErr := `Certificate with SHA256 ` + certs.HexSHA256(clientCert.Certificate[0]) + ` not allowed`
   585  					ts.Run(t, test.TestCase{
   586  						Path:      "/with_mutual",
   587  						Client:    client,
   588  						Domain:    domain,
   589  						Code:      403,
   590  						BodyMatch: `"error": "` + certNotAllowedErr,
   591  					})
   592  				} else {
   593  					ts.Run(t, test.TestCase{
   594  						Path:       "/with_mutual",
   595  						Client:     client,
   596  						Domain:     domain,
   597  						ErrorMatch: badcertErr,
   598  					})
   599  				}
   600  			})
   601  
   602  			t.Run("Client certificate match", func(t *testing.T) {
   603  				loadAPIS(clientCertID)
   604  				client := GetTLSClient(&clientCert, serverCertPem)
   605  
   606  				ts.Run(t, test.TestCase{
   607  					Path:   "/with_mutual",
   608  					Domain: domain,
   609  					Client: client,
   610  					Code:   200,
   611  				})
   612  			})
   613  		}
   614  
   615  		t.Run("Empty domain", func(t *testing.T) {
   616  			testSameDomain(t, "")
   617  		})
   618  
   619  		t.Run("Custom domain", func(t *testing.T) {
   620  			testSameDomain(t, "localhost")
   621  		})
   622  	})
   623  
   624  	t.Run("Multiple APIs, mutual on empty", func(t *testing.T) {
   625  		testSameDomain := func(t *testing.T, domain string) {
   626  			clientCertID, _ := CertificateManager.Add(clientCertPem, "")
   627  			defer CertificateManager.Delete(clientCertID, "")
   628  
   629  			loadAPIS := func(certs ...string) {
   630  				BuildAndLoadAPI(
   631  					func(spec *APISpec) {
   632  						spec.Proxy.ListenPath = "/with_mutual"
   633  						spec.UseMutualTLSAuth = true
   634  						spec.ClientCertificates = certs
   635  					},
   636  					func(spec *APISpec) {
   637  						spec.Proxy.ListenPath = "/without_mutual"
   638  						spec.Domain = domain
   639  					},
   640  				)
   641  			}
   642  
   643  			t.Run("Without certificate", func(t *testing.T) {
   644  				clientWithoutCert := GetTLSClient(nil, nil)
   645  
   646  				loadAPIS()
   647  
   648  				if domain == "" {
   649  					ts.Run(t, test.TestCase{
   650  						Path:      "/with_mutual",
   651  						Client:    clientWithoutCert,
   652  						Code:      403,
   653  						BodyMatch: `"error": "` + certNotMatchErr,
   654  					})
   655  				} else {
   656  					ts.Run(t, test.TestCase{
   657  						Path:       "/with_mutual",
   658  						Client:     clientWithoutCert,
   659  						ErrorMatch: badcertErr,
   660  					})
   661  				}
   662  
   663  				ts.Run(t, test.TestCase{
   664  					Path:   "/without_mutual",
   665  					Client: clientWithoutCert,
   666  					Domain: domain,
   667  					Code:   200,
   668  				})
   669  			})
   670  
   671  			t.Run("Client certificate not match", func(t *testing.T) {
   672  				client := GetTLSClient(&clientCert, serverCertPem)
   673  
   674  				loadAPIS()
   675  
   676  				if domain == "" {
   677  					certNotAllowedErr := `Certificate with SHA256 ` + certs.HexSHA256(clientCert.Certificate[0]) + ` not allowed`
   678  					ts.Run(t, test.TestCase{
   679  						Path:      "/with_mutual",
   680  						Client:    client,
   681  						Code:      403,
   682  						BodyMatch: `"error": "` + certNotAllowedErr,
   683  					})
   684  				} else {
   685  					ts.Run(t, test.TestCase{
   686  						Path:       "/with_mutual",
   687  						Client:     client,
   688  						ErrorMatch: badcertErr,
   689  					})
   690  				}
   691  			})
   692  
   693  			t.Run("Client certificate match", func(t *testing.T) {
   694  				loadAPIS(clientCertID)
   695  				client := GetTLSClient(&clientCert, serverCertPem)
   696  
   697  				ts.Run(t, test.TestCase{
   698  					Path:   "/with_mutual",
   699  					Client: client,
   700  					Code:   200,
   701  				})
   702  			})
   703  		}
   704  
   705  		t.Run("Empty domain", func(t *testing.T) {
   706  			testSameDomain(t, "")
   707  		})
   708  
   709  		t.Run("Custom domain", func(t *testing.T) {
   710  			testSameDomain(t, "localhost")
   711  		})
   712  	})
   713  }
   714  
   715  func TestUpstreamMutualTLS(t *testing.T) {
   716  	_, _, combinedClientPEM, clientCert := genCertificate(&x509.Certificate{})
   717  	clientCert.Leaf, _ = x509.ParseCertificate(clientCert.Certificate[0])
   718  
   719  	upstream := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   720  	}))
   721  
   722  	// Mutual TLS protected upstream
   723  	pool := x509.NewCertPool()
   724  	upstream.TLS = &tls.Config{
   725  		ClientAuth:         tls.RequireAndVerifyClientCert,
   726  		ClientCAs:          pool,
   727  		InsecureSkipVerify: true,
   728  	}
   729  
   730  	upstream.StartTLS()
   731  	defer upstream.Close()
   732  
   733  	t.Run("Without API", func(t *testing.T) {
   734  		client := GetTLSClient(&clientCert, nil)
   735  
   736  		if _, err := client.Get(upstream.URL); err == nil {
   737  			t.Error("Should reject without certificate")
   738  		}
   739  
   740  		pool.AddCert(clientCert.Leaf)
   741  
   742  		if _, err := client.Get(upstream.URL); err != nil {
   743  			t.Error("Should pass with valid certificate")
   744  		}
   745  	})
   746  
   747  	t.Run("Upstream API", func(t *testing.T) {
   748  		globalConf := config.Global()
   749  		globalConf.ProxySSLInsecureSkipVerify = true
   750  		config.SetGlobal(globalConf)
   751  		defer ResetTestConfig()
   752  
   753  		ts := StartTest()
   754  		defer ts.Close()
   755  
   756  		clientCertID, _ := CertificateManager.Add(combinedClientPEM, "")
   757  		defer CertificateManager.Delete(clientCertID, "")
   758  
   759  		pool.AddCert(clientCert.Leaf)
   760  
   761  		BuildAndLoadAPI(func(spec *APISpec) {
   762  			spec.Proxy.ListenPath = "/"
   763  			spec.Proxy.TargetURL = upstream.URL
   764  			spec.UpstreamCertificates = map[string]string{
   765  				"*": clientCertID,
   766  			}
   767  		})
   768  
   769  		// Should pass with valid upstream certificate
   770  		ts.Run(t, test.TestCase{Code: 200})
   771  	})
   772  
   773  }
   774  
   775  func TestSSLForceCommonName(t *testing.T) {
   776  	upstream := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   777  	}))
   778  
   779  	// generate certificate Common Name as valid hostname and SAN as non-empty value
   780  	_, _, _, cert := genCertificate(&x509.Certificate{
   781  		EmailAddresses: []string{"test@test.com"},
   782  		Subject:        pkix.Name{CommonName: "host1.local"},
   783  	})
   784  
   785  	upstream.TLS = &tls.Config{
   786  		Certificates: []tls.Certificate{cert},
   787  	}
   788  
   789  	upstream.StartTLS()
   790  	defer upstream.Close()
   791  
   792  	// test case to ensure that Golang doesn't check against CommonName if SAN is non empty
   793  	t.Run("Force Common Name Check is Disabled", func(t *testing.T) {
   794  		ts := StartTest()
   795  		defer ts.Close()
   796  
   797  		targetURL := strings.Replace(upstream.URL, "127.0.0.1", "localhost", 1)
   798  		BuildAndLoadAPI(func(spec *APISpec) {
   799  			spec.Proxy.ListenPath = "/"
   800  			spec.Proxy.TargetURL = targetURL
   801  		})
   802  		ts.Run(t, test.TestCase{Code: 500, BodyMatch: "There was a problem proxying the request"})
   803  	})
   804  
   805  	t.Run("Force Common Name Check is Enabled", func(t *testing.T) {
   806  		globalConf := config.Global()
   807  		globalConf.SSLForceCommonNameCheck = true
   808  		config.SetGlobal(globalConf)
   809  		defer ResetTestConfig()
   810  
   811  		ts := StartTest()
   812  		defer ts.Close()
   813  
   814  		targetURL := strings.Replace(upstream.URL, "127.0.0.1", "host1.local", 1)
   815  		BuildAndLoadAPI(func(spec *APISpec) {
   816  			spec.Proxy.ListenPath = "/"
   817  			spec.Proxy.TargetURL = targetURL
   818  		})
   819  
   820  		ts.Run(t, test.TestCase{Code: 200})
   821  	})
   822  }
   823  
   824  func TestKeyWithCertificateTLS(t *testing.T) {
   825  	_, _, combinedPEM, _ := genServerCertificate()
   826  	serverCertID, _ := CertificateManager.Add(combinedPEM, "")
   827  	defer CertificateManager.Delete(serverCertID, "")
   828  
   829  	globalConf := config.Global()
   830  	globalConf.HttpServerOptions.UseSSL = true
   831  	globalConf.EnableCustomDomains = true
   832  	globalConf.HttpServerOptions.SSLCertificates = []string{serverCertID}
   833  	config.SetGlobal(globalConf)
   834  	defer ResetTestConfig()
   835  
   836  	ts := StartTest()
   837  	defer ts.Close()
   838  
   839  	t.Run("Without domain", func(t *testing.T) {
   840  		_, _, _, clientCert := genCertificate(&x509.Certificate{})
   841  		clientCertID := certs.HexSHA256(clientCert.Certificate[0])
   842  
   843  		BuildAndLoadAPI(func(spec *APISpec) {
   844  			spec.UseKeylessAccess = false
   845  			spec.BaseIdentityProvidedBy = apidef.AuthToken
   846  			spec.Auth.UseCertificate = true
   847  			spec.Proxy.ListenPath = "/"
   848  			spec.OrgID = "default"
   849  		})
   850  
   851  		client := GetTLSClient(&clientCert, nil)
   852  
   853  		t.Run("Cert unknown", func(t *testing.T) {
   854  			ts.Run(t, test.TestCase{Code: 403, Client: client})
   855  		})
   856  
   857  		t.Run("Cert known", func(t *testing.T) {
   858  			_, key := ts.CreateSession(func(s *user.SessionState) {
   859  				s.Certificate = clientCertID
   860  				s.SetAccessRights(map[string]user.AccessDefinition{"test": {
   861  					APIID: "test", Versions: []string{"v1"},
   862  				}})
   863  				s.Mutex = &sync.RWMutex{}
   864  			})
   865  
   866  			if key == "" {
   867  				t.Fatal("Should create key based on certificate")
   868  			}
   869  
   870  			_, key = ts.CreateSession(func(s *user.SessionState) {
   871  				s.Certificate = clientCertID
   872  				s.SetAccessRights(map[string]user.AccessDefinition{"test": {
   873  					APIID: "test", Versions: []string{"v1"},
   874  				}})
   875  				s.Mutex = &sync.RWMutex{}
   876  			})
   877  
   878  			if key != "" {
   879  				t.Fatal("Should not allow create key based on the same certificate")
   880  			}
   881  
   882  			ts.Run(t, test.TestCase{Path: "/", Code: 200, Client: client})
   883  
   884  			// Domain is not set, but we still pass it, it should still work
   885  			ts.Run(t, test.TestCase{Path: "/", Code: 200, Domain: "localhost", Client: client})
   886  		})
   887  	})
   888  
   889  	t.Run("With custom domain", func(t *testing.T) {
   890  		_, _, _, clientCert := genCertificate(&x509.Certificate{})
   891  		clientCertID := certs.HexSHA256(clientCert.Certificate[0])
   892  
   893  		BuildAndLoadAPI(
   894  			func(spec *APISpec) {
   895  				spec.UseKeylessAccess = false
   896  				spec.BaseIdentityProvidedBy = apidef.AuthToken
   897  				spec.Auth.UseCertificate = true
   898  				spec.Proxy.ListenPath = "/test1"
   899  				spec.OrgID = "default"
   900  				spec.Domain = "localhost"
   901  			},
   902  			func(spec *APISpec) {
   903  				spec.Proxy.ListenPath = "/test2"
   904  				spec.OrgID = "default"
   905  			},
   906  		)
   907  
   908  		client := GetTLSClient(&clientCert, nil)
   909  
   910  		t.Run("Cert unknown", func(t *testing.T) {
   911  			ts.Run(t,
   912  				test.TestCase{Code: 404, Path: "/test1", Client: client},
   913  				test.TestCase{Code: 403, Path: "/test1", Domain: "localhost", Client: client},
   914  			)
   915  		})
   916  
   917  		t.Run("Cert known", func(t *testing.T) {
   918  			_, key := ts.CreateSession(func(s *user.SessionState) {
   919  				s.Certificate = clientCertID
   920  				s.SetAccessRights(map[string]user.AccessDefinition{"test": {
   921  					APIID: "test", Versions: []string{"v1"},
   922  				}})
   923  				s.Mutex = &sync.RWMutex{}
   924  			})
   925  
   926  			if key == "" {
   927  				t.Fatal("Should create key based on certificate")
   928  			}
   929  
   930  			_, key = ts.CreateSession(func(s *user.SessionState) {
   931  				s.Certificate = clientCertID
   932  				s.SetAccessRights(map[string]user.AccessDefinition{"test": {
   933  					APIID: "test", Versions: []string{"v1"},
   934  				}})
   935  				s.Mutex = &sync.RWMutex{}
   936  			})
   937  
   938  			if key != "" {
   939  				t.Fatal("Should not allow create key based on the same certificate")
   940  			}
   941  
   942  			ts.Run(t, test.TestCase{Path: "/test1", Code: 404, Client: client})
   943  
   944  			// Domain is not set, but we still pass it, it should still work
   945  			ts.Run(t, test.TestCase{Path: "/test1", Code: 200, Domain: "localhost", Client: client})
   946  		})
   947  	})
   948  }
   949  
   950  func TestAPICertificate(t *testing.T) {
   951  	_, _, combinedPEM, _ := genServerCertificate()
   952  	serverCertID, _ := CertificateManager.Add(combinedPEM, "")
   953  	defer CertificateManager.Delete(serverCertID, "")
   954  
   955  	globalConf := config.Global()
   956  	globalConf.HttpServerOptions.UseSSL = true
   957  	globalConf.HttpServerOptions.SSLCertificates = []string{}
   958  	config.SetGlobal(globalConf)
   959  	defer ResetTestConfig()
   960  
   961  	ts := StartTest()
   962  	defer ts.Close()
   963  
   964  	client := &http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{
   965  		InsecureSkipVerify: true,
   966  	}}}
   967  
   968  	t.Run("Cert set via API", func(t *testing.T) {
   969  		BuildAndLoadAPI(func(spec *APISpec) {
   970  			spec.Certificates = []string{serverCertID}
   971  			spec.UseKeylessAccess = true
   972  			spec.Proxy.ListenPath = "/"
   973  		})
   974  
   975  		ts.Run(t, test.TestCase{Code: 200, Client: client})
   976  	})
   977  
   978  	t.Run("Cert unknown", func(t *testing.T) {
   979  		BuildAndLoadAPI(func(spec *APISpec) {
   980  			spec.UseKeylessAccess = true
   981  			spec.Proxy.ListenPath = "/"
   982  		})
   983  
   984  		ts.Run(t, test.TestCase{ErrorMatch: "tls: internal error"})
   985  	})
   986  }
   987  
   988  func TestCertificateHandlerTLS(t *testing.T) {
   989  	_, _, combinedServerPEM, serverCert := genServerCertificate()
   990  	serverCertID := certs.HexSHA256(serverCert.Certificate[0])
   991  
   992  	clientPEM, _, _, clientCert := genCertificate(&x509.Certificate{})
   993  	clientCertID := certs.HexSHA256(clientCert.Certificate[0])
   994  
   995  	ts := StartTest()
   996  	defer ts.Close()
   997  
   998  	t.Run("List certificates, empty", func(t *testing.T) {
   999  		ts.Run(t, test.TestCase{
  1000  			Path: "/tyk/certs", Code: 200, AdminAuth: true, BodyMatch: `{"certs":null}`,
  1001  		})
  1002  	})
  1003  
  1004  	t.Run("Should add certificates with and without private keys", func(t *testing.T) {
  1005  		ts.Run(t, []test.TestCase{
  1006  			// Public Certificate
  1007  			{Method: "POST", Path: "/tyk/certs", Data: string(clientPEM), AdminAuth: true, Code: 200, BodyMatch: `"id":"` + clientCertID},
  1008  			// Public + Private
  1009  			{Method: "POST", Path: "/tyk/certs", Data: string(combinedServerPEM), AdminAuth: true, Code: 200, BodyMatch: `"id":"` + serverCertID},
  1010  		}...)
  1011  	})
  1012  
  1013  	t.Run("List certificates, non empty", func(t *testing.T) {
  1014  		ts.Run(t, []test.TestCase{
  1015  			{Method: "GET", Path: "/tyk/certs", AdminAuth: true, Code: 200, BodyMatch: clientCertID},
  1016  			{Method: "GET", Path: "/tyk/certs", AdminAuth: true, Code: 200, BodyMatch: serverCertID},
  1017  		}...)
  1018  	})
  1019  
  1020  	certMetaTemplate := `{"id":"%s","fingerprint":"%s","has_private":%s`
  1021  
  1022  	t.Run("Certificate meta info", func(t *testing.T) {
  1023  		clientCertMeta := fmt.Sprintf(certMetaTemplate, clientCertID, clientCertID, "false")
  1024  		serverCertMeta := fmt.Sprintf(certMetaTemplate, serverCertID, serverCertID, "true")
  1025  
  1026  		ts.Run(t, []test.TestCase{
  1027  			{Method: "GET", Path: "/tyk/certs/" + clientCertID, AdminAuth: true, Code: 200, BodyMatch: clientCertMeta},
  1028  			{Method: "GET", Path: "/tyk/certs/" + serverCertID, AdminAuth: true, Code: 200, BodyMatch: serverCertMeta},
  1029  			{Method: "GET", Path: "/tyk/certs/" + serverCertID + "," + clientCertID, AdminAuth: true, Code: 200, BodyMatch: `\[` + serverCertMeta},
  1030  			{Method: "GET", Path: "/tyk/certs/" + serverCertID + "," + clientCertID, AdminAuth: true, Code: 200, BodyMatch: clientCertMeta},
  1031  		}...)
  1032  	})
  1033  
  1034  	t.Run("Certificate removal", func(t *testing.T) {
  1035  		ts.Run(t, []test.TestCase{
  1036  			{Method: "DELETE", Path: "/tyk/certs/" + serverCertID, AdminAuth: true, Code: 200},
  1037  			{Method: "DELETE", Path: "/tyk/certs/" + clientCertID, AdminAuth: true, Code: 200},
  1038  			{Method: "GET", Path: "/tyk/certs", AdminAuth: true, Code: 200, BodyMatch: `{"certs":null}`},
  1039  		}...)
  1040  	})
  1041  }
  1042  
  1043  func TestCipherSuites(t *testing.T) {
  1044  	//configure server so we can useSSL and utilize the logic, but skip verification in the clients
  1045  	_, _, combinedPEM, _ := genServerCertificate()
  1046  	serverCertID, _ := CertificateManager.Add(combinedPEM, "")
  1047  	defer CertificateManager.Delete(serverCertID, "")
  1048  
  1049  	globalConf := config.Global()
  1050  	globalConf.HttpServerOptions.UseSSL = true
  1051  	globalConf.HttpServerOptions.Ciphers = []string{"TLS_RSA_WITH_RC4_128_SHA", "TLS_RSA_WITH_3DES_EDE_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA"}
  1052  	globalConf.HttpServerOptions.SSLCertificates = []string{serverCertID}
  1053  	config.SetGlobal(globalConf)
  1054  	defer ResetTestConfig()
  1055  
  1056  	ts := StartTest()
  1057  	defer ts.Close()
  1058  
  1059  	BuildAndLoadAPI(func(spec *APISpec) {
  1060  		spec.Proxy.ListenPath = "/"
  1061  	})
  1062  
  1063  	//matching ciphers
  1064  	t.Run("Cipher match", func(t *testing.T) {
  1065  
  1066  		client := &http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{
  1067  			CipherSuites:       getCipherAliases([]string{"TLS_RSA_WITH_RC4_128_SHA", "TLS_RSA_WITH_3DES_EDE_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA"}),
  1068  			InsecureSkipVerify: true,
  1069  		}}}
  1070  
  1071  		// If there is an internal TLS error it will fail test
  1072  		ts.Run(t, test.TestCase{Client: client, Path: "/"})
  1073  	})
  1074  
  1075  	t.Run("Cipher non-match", func(t *testing.T) {
  1076  
  1077  		client := &http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{
  1078  			CipherSuites:       getCipherAliases([]string{"TLS_RSA_WITH_AES_256_CBC_SHA"}), // not matching ciphers
  1079  			InsecureSkipVerify: true,
  1080  		}}}
  1081  
  1082  		ts.Run(t, test.TestCase{Client: client, Path: "/", ErrorMatch: "tls: handshake failure"})
  1083  	})
  1084  }