1package tls 2 3import ( 4 "os" 5 "path/filepath" 6 "testing" 7 8 "github.com/stretchr/testify/assert" 9 "github.com/stretchr/testify/require" 10) 11 12// certPEM and keyPEM are copied from the golang crypto/tls library 13// https://github.com/golang/go/blob/7eb5941b95a588a23f18fa4c22fe42ff0119c311/src/crypto/tls/example_test.go#L127 14const certPEM = `-----BEGIN CERTIFICATE----- 15MIIBhTCCASugAwIBAgIQIRi6zePL6mKjOipn+dNuaTAKBggqhkjOPQQDAjASMRAw 16DgYDVQQKEwdBY21lIENvMB4XDTE3MTAyMDE5NDMwNloXDTE4MTAyMDE5NDMwNlow 17EjEQMA4GA1UEChMHQWNtZSBDbzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABD0d 187VNhbWvZLWPuj/RtHFjvtJBEwOkhbN/BnnE8rnZR8+sbwnc/KhCk3FhnpHZnQz7B 195aETbbIgmuvewdjvSBSjYzBhMA4GA1UdDwEB/wQEAwICpDATBgNVHSUEDDAKBggr 20BgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1UdEQQiMCCCDmxvY2FsaG9zdDo1 21NDUzgg4xMjcuMC4wLjE6NTQ1MzAKBggqhkjOPQQDAgNIADBFAiEA2zpJEPQyz6/l 22Wf86aX6PepsntZv2GYlA5UpabfT2EZICICpJ5h/iI+i341gBmLiAFQOyTDT+/wQc 236MF9+Yw1Yy0t 24-----END CERTIFICATE-----` 25const keyPEM = `-----BEGIN EC PRIVATE KEY----- 26MHcCAQEEIIrYSSNQFaA2Hwf1duRSxKtLYX5CB04fSeQ6tF1aY/PuoAoGCCqGSM49 27AwEHoUQDQgAEPR3tU2Fta9ktY+6P9G0cWO+0kETA6SFs38GecTyudlHz6xvCdz8q 28EKTcWGekdmdDPsHloRNtsiCa697B2O9IFA== 29-----END EC PRIVATE KEY-----` 30 31// caPEM is CA certificate of Let's Encrypt 32// https://letsencrypt.org/certs/isrgrootx1.pem.txt 33const caPEM = `-----BEGIN CERTIFICATE----- 34MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw 35TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh 36cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 37WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu 38ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY 39MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc 40h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ 410TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U 42A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW 43T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH 44B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC 45B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv 46KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn 47OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn 48jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw 49qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI 50rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV 51HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq 52hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL 53ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ 543BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK 55NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 56ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur 57TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC 58jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc 59oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq 604RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA 61mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d 62emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= 63-----END CERTIFICATE-----` 64 65type x509Paths struct { 66 cert string 67 key string 68 ca string 69} 70 71func newTestX509Files(t *testing.T, cert, key, ca []byte) x509Paths { 72 t.Helper() 73 74 certsPath := t.TempDir() 75 76 paths := x509Paths{ 77 cert: filepath.Join(certsPath, "cert.pem"), 78 key: filepath.Join(certsPath, "key.pem"), 79 ca: filepath.Join(certsPath, "ca.pem"), 80 } 81 82 if cert != nil { 83 err := os.WriteFile(paths.cert, cert, 0600) 84 require.NoError(t, err) 85 } 86 87 if key != nil { 88 err := os.WriteFile(paths.key, key, 0600) 89 require.NoError(t, err) 90 } 91 92 if ca != nil { 93 err := os.WriteFile(paths.ca, ca, 0600) 94 require.NoError(t, err) 95 } 96 97 return paths 98} 99 100func TestGetTLSConfig_ClientCerts(t *testing.T) { 101 paths := newTestX509Files(t, []byte(certPEM), []byte(keyPEM), nil) 102 103 // test working certificate passed 104 c := &ClientConfig{ 105 CertPath: paths.cert, 106 KeyPath: paths.key, 107 } 108 tlsConfig, err := c.GetTLSConfig() 109 assert.NoError(t, err) 110 assert.Equal(t, false, tlsConfig.InsecureSkipVerify, "make sure we default to not skip verification") 111 assert.Equal(t, 1, len(tlsConfig.Certificates), "ensure a certificate is returned") 112 113 // expect error with key and cert swapped passed along 114 c = &ClientConfig{ 115 CertPath: paths.key, 116 KeyPath: paths.cert, 117 } 118 _, err = c.GetTLSConfig() 119 assert.Error(t, err) 120 assert.Contains(t, err.Error(), "failed to find certificate PEM data in certificate input, but did find a private key") 121 122 // expect error with only key passed along 123 c = &ClientConfig{ 124 KeyPath: paths.key, 125 } 126 _, err = c.GetTLSConfig() 127 assert.EqualError(t, err, errCertMissing.Error()) 128 129 // expect error with only cert passed along 130 c = &ClientConfig{ 131 CertPath: paths.cert, 132 } 133 _, err = c.GetTLSConfig() 134 assert.EqualError(t, err, errKeyMissing.Error()) 135} 136 137func TestGetTLSConfig_CA(t *testing.T) { 138 paths := newTestX509Files(t, nil, nil, []byte(certPEM)) 139 140 // test single ca passed 141 c := &ClientConfig{ 142 CAPath: paths.ca, 143 } 144 tlsConfig, err := c.GetTLSConfig() 145 assert.NoError(t, err) 146 assert.Equal(t, 1, len(tlsConfig.RootCAs.Subjects()), "ensure one CA is returned") 147 assert.Equal(t, false, tlsConfig.InsecureSkipVerify, "make sure we default to not skip verification") 148 149 // test two cas passed 150 paths = newTestX509Files(t, nil, nil, []byte(certPEM+"\n"+caPEM)) 151 c = &ClientConfig{ 152 CAPath: paths.ca, 153 } 154 tlsConfig, err = c.GetTLSConfig() 155 assert.NoError(t, err) 156 assert.Equal(t, 2, len(tlsConfig.RootCAs.Subjects()), "ensure two CAs are returned") 157 assert.False(t, tlsConfig.InsecureSkipVerify, "make sure we default to not skip verification") 158 159 // expect errors to be passed 160 c = &ClientConfig{ 161 CAPath: paths.ca + "not-existing", 162 } 163 _, err = c.GetTLSConfig() 164 assert.Error(t, err) 165 assert.Contains(t, err.Error(), "error loading ca cert") 166} 167 168func TestGetTLSConfig_InsecureSkipVerify(t *testing.T) { 169 c := &ClientConfig{ 170 InsecureSkipVerify: true, 171 } 172 tlsConfig, err := c.GetTLSConfig() 173 assert.NoError(t, err) 174 assert.True(t, tlsConfig.InsecureSkipVerify) 175} 176 177func TestGetTLSConfig_ServerName(t *testing.T) { 178 c := &ClientConfig{ 179 ServerName: "myserver.com", 180 } 181 tlsConfig, err := c.GetTLSConfig() 182 assert.NoError(t, err) 183 assert.Equal(t, "myserver.com", tlsConfig.ServerName) 184} 185