github.com/djenriquez/nomad-1@v0.8.1/helper/tlsutil/config_test.go (about) 1 package tlsutil 2 3 import ( 4 "crypto/tls" 5 "crypto/x509" 6 "io" 7 "io/ioutil" 8 "net" 9 "testing" 10 11 "github.com/hashicorp/nomad/nomad/structs/config" 12 "github.com/hashicorp/yamux" 13 "github.com/stretchr/testify/assert" 14 ) 15 16 const ( 17 // See README.md for documentation 18 cacert = "./testdata/ca.pem" 19 foocert = "./testdata/nomad-foo.pem" 20 fookey = "./testdata/nomad-foo-key.pem" 21 badcert = "./testdata/nomad-bad.pem" 22 badkey = "./testdata/nomad-bad-key.pem" 23 ) 24 25 func TestConfig_AppendCA_None(t *testing.T) { 26 conf := &Config{} 27 pool := x509.NewCertPool() 28 err := conf.AppendCA(pool) 29 if err != nil { 30 t.Fatalf("err: %v", err) 31 } 32 if len(pool.Subjects()) != 0 { 33 t.Fatalf("bad: %v", pool.Subjects()) 34 } 35 } 36 37 func TestConfig_CACertificate_Valid(t *testing.T) { 38 conf := &Config{ 39 CAFile: cacert, 40 } 41 pool := x509.NewCertPool() 42 err := conf.AppendCA(pool) 43 if err != nil { 44 t.Fatalf("err: %v", err) 45 } 46 if len(pool.Subjects()) == 0 { 47 t.Fatalf("expected cert") 48 } 49 } 50 51 func TestConfig_LoadKeyPair_None(t *testing.T) { 52 conf := &Config{ 53 KeyLoader: &config.KeyLoader{}, 54 } 55 cert, err := conf.LoadKeyPair() 56 if err != nil { 57 t.Fatalf("err: %v", err) 58 } 59 if cert != nil { 60 t.Fatalf("bad: %v", cert) 61 } 62 } 63 64 func TestConfig_LoadKeyPair_Valid(t *testing.T) { 65 conf := &Config{ 66 CertFile: foocert, 67 KeyFile: fookey, 68 KeyLoader: &config.KeyLoader{}, 69 } 70 cert, err := conf.LoadKeyPair() 71 if err != nil { 72 t.Fatalf("err: %v", err) 73 } 74 if cert == nil { 75 t.Fatalf("expected cert") 76 } 77 } 78 79 func TestConfig_OutgoingTLS_MissingCA(t *testing.T) { 80 conf := &Config{ 81 VerifyOutgoing: true, 82 } 83 tls, err := conf.OutgoingTLSConfig() 84 if err == nil { 85 t.Fatalf("expected err") 86 } 87 if tls != nil { 88 t.Fatalf("bad: %v", tls) 89 } 90 } 91 92 func TestConfig_OutgoingTLS_OnlyCA(t *testing.T) { 93 conf := &Config{ 94 CAFile: cacert, 95 } 96 tls, err := conf.OutgoingTLSConfig() 97 if err != nil { 98 t.Fatalf("err: %v", err) 99 } 100 if tls != nil { 101 t.Fatalf("expected no config") 102 } 103 } 104 105 func TestConfig_OutgoingTLS_VerifyOutgoing(t *testing.T) { 106 conf := &Config{ 107 VerifyOutgoing: true, 108 CAFile: cacert, 109 } 110 tls, err := conf.OutgoingTLSConfig() 111 if err != nil { 112 t.Fatalf("err: %v", err) 113 } 114 if tls == nil { 115 t.Fatalf("expected config") 116 } 117 if len(tls.RootCAs.Subjects()) != 1 { 118 t.Fatalf("expect root cert") 119 } 120 if !tls.InsecureSkipVerify { 121 t.Fatalf("should skip built-in verification") 122 } 123 } 124 125 func TestConfig_OutgoingTLS_VerifyHostname(t *testing.T) { 126 conf := &Config{ 127 VerifyServerHostname: true, 128 CAFile: cacert, 129 } 130 tls, err := conf.OutgoingTLSConfig() 131 if err != nil { 132 t.Fatalf("err: %v", err) 133 } 134 if tls == nil { 135 t.Fatalf("expected config") 136 } 137 if len(tls.RootCAs.Subjects()) != 1 { 138 t.Fatalf("expect root cert") 139 } 140 if tls.InsecureSkipVerify { 141 t.Fatalf("should not skip built-in verification") 142 } 143 } 144 145 func TestConfig_OutgoingTLS_WithKeyPair(t *testing.T) { 146 assert := assert.New(t) 147 148 conf := &Config{ 149 VerifyOutgoing: true, 150 CAFile: cacert, 151 CertFile: foocert, 152 KeyFile: fookey, 153 KeyLoader: &config.KeyLoader{}, 154 } 155 tlsConf, err := conf.OutgoingTLSConfig() 156 assert.Nil(err) 157 assert.NotNil(tlsConf) 158 assert.Equal(len(tlsConf.RootCAs.Subjects()), 1) 159 assert.True(tlsConf.InsecureSkipVerify) 160 161 clientHelloInfo := &tls.ClientHelloInfo{} 162 cert, err := tlsConf.GetCertificate(clientHelloInfo) 163 assert.Nil(err) 164 assert.NotNil(cert) 165 } 166 167 func startTLSServer(config *Config) (net.Conn, chan error) { 168 errc := make(chan error, 1) 169 170 tlsConfigServer, err := config.IncomingTLSConfig() 171 if err != nil { 172 errc <- err 173 return nil, errc 174 } 175 176 client, server := net.Pipe() 177 178 // Use yamux to buffer the reads, otherwise it's easy to deadlock 179 muxConf := yamux.DefaultConfig() 180 serverSession, _ := yamux.Server(server, muxConf) 181 clientSession, _ := yamux.Client(client, muxConf) 182 clientConn, _ := clientSession.Open() 183 serverConn, _ := serverSession.Accept() 184 185 go func() { 186 tlsServer := tls.Server(serverConn, tlsConfigServer) 187 if err := tlsServer.Handshake(); err != nil { 188 errc <- err 189 } 190 close(errc) 191 // Because net.Pipe() is unbuffered, if both sides 192 // Close() simultaneously, we will deadlock as they 193 // both send an alert and then block. So we make the 194 // server read any data from the client until error or 195 // EOF, which will allow the client to Close(), and 196 // *then* we Close() the server. 197 io.Copy(ioutil.Discard, tlsServer) 198 tlsServer.Close() 199 }() 200 return clientConn, errc 201 } 202 203 // TODO sign the certificates for "server.regionFoo.nomad 204 func TestConfig_outgoingWrapper_OK(t *testing.T) { 205 config := &Config{ 206 CAFile: cacert, 207 CertFile: foocert, 208 KeyFile: fookey, 209 VerifyServerHostname: true, 210 VerifyOutgoing: true, 211 KeyLoader: &config.KeyLoader{}, 212 } 213 214 client, errc := startTLSServer(config) 215 if client == nil { 216 t.Fatalf("startTLSServer err: %v", <-errc) 217 } 218 219 wrap, err := config.OutgoingTLSWrapper() 220 if err != nil { 221 t.Fatalf("OutgoingTLSWrapper err: %v", err) 222 } 223 224 tlsClient, err := wrap("regionFoo", client) 225 if err != nil { 226 t.Fatalf("wrapTLS err: %v", err) 227 } 228 defer tlsClient.Close() 229 if err := tlsClient.(*tls.Conn).Handshake(); err != nil { 230 t.Fatalf("write err: %v", err) 231 } 232 233 err = <-errc 234 if err != nil { 235 t.Fatalf("server: %v", err) 236 } 237 } 238 239 func TestConfig_outgoingWrapper_BadCert(t *testing.T) { 240 // TODO this test is currently hanging, need to investigate more. 241 t.SkipNow() 242 config := &Config{ 243 CAFile: cacert, 244 CertFile: foocert, 245 KeyFile: fookey, 246 VerifyServerHostname: true, 247 VerifyOutgoing: true, 248 } 249 250 client, errc := startTLSServer(config) 251 if client == nil { 252 t.Fatalf("startTLSServer err: %v", <-errc) 253 } 254 255 wrap, err := config.OutgoingTLSWrapper() 256 if err != nil { 257 t.Fatalf("OutgoingTLSWrapper err: %v", err) 258 } 259 260 tlsClient, err := wrap("regionFoo", client) 261 if err != nil { 262 t.Fatalf("wrapTLS err: %v", err) 263 } 264 defer tlsClient.Close() 265 err = tlsClient.(*tls.Conn).Handshake() 266 267 if _, ok := err.(x509.HostnameError); !ok { 268 t.Fatalf("should get hostname err: %v", err) 269 } 270 271 <-errc 272 } 273 274 func TestConfig_wrapTLS_OK(t *testing.T) { 275 config := &Config{ 276 CAFile: cacert, 277 CertFile: foocert, 278 KeyFile: fookey, 279 VerifyOutgoing: true, 280 KeyLoader: &config.KeyLoader{}, 281 } 282 283 client, errc := startTLSServer(config) 284 if client == nil { 285 t.Fatalf("startTLSServer err: %v", <-errc) 286 } 287 288 clientConfig, err := config.OutgoingTLSConfig() 289 if err != nil { 290 t.Fatalf("OutgoingTLSConfig err: %v", err) 291 } 292 293 tlsClient, err := WrapTLSClient(client, clientConfig) 294 if err != nil { 295 t.Fatalf("wrapTLS err: %v", err) 296 } else { 297 tlsClient.Close() 298 } 299 err = <-errc 300 if err != nil { 301 t.Fatalf("server: %v", err) 302 } 303 } 304 305 func TestConfig_wrapTLS_BadCert(t *testing.T) { 306 serverConfig := &Config{ 307 CAFile: cacert, 308 CertFile: badcert, 309 KeyFile: badkey, 310 KeyLoader: &config.KeyLoader{}, 311 } 312 313 client, errc := startTLSServer(serverConfig) 314 if client == nil { 315 t.Fatalf("startTLSServer err: %v", <-errc) 316 } 317 318 clientConfig := &Config{ 319 CAFile: cacert, 320 VerifyOutgoing: true, 321 } 322 323 clientTLSConfig, err := clientConfig.OutgoingTLSConfig() 324 if err != nil { 325 t.Fatalf("OutgoingTLSConfig err: %v", err) 326 } 327 328 tlsClient, err := WrapTLSClient(client, clientTLSConfig) 329 if err == nil { 330 t.Fatalf("wrapTLS no err") 331 } 332 if tlsClient != nil { 333 t.Fatalf("returned a client") 334 } 335 336 err = <-errc 337 if err != nil { 338 t.Fatalf("server: %v", err) 339 } 340 } 341 342 func TestConfig_IncomingTLS(t *testing.T) { 343 assert := assert.New(t) 344 345 conf := &Config{ 346 VerifyIncoming: true, 347 CAFile: cacert, 348 CertFile: foocert, 349 KeyFile: fookey, 350 KeyLoader: &config.KeyLoader{}, 351 } 352 tlsC, err := conf.IncomingTLSConfig() 353 if err != nil { 354 t.Fatalf("err: %v", err) 355 } 356 if tlsC == nil { 357 t.Fatalf("expected config") 358 } 359 if len(tlsC.ClientCAs.Subjects()) != 1 { 360 t.Fatalf("expect client cert") 361 } 362 if tlsC.ClientAuth != tls.RequireAndVerifyClientCert { 363 t.Fatalf("should not skip verification") 364 } 365 366 clientHelloInfo := &tls.ClientHelloInfo{} 367 cert, err := tlsC.GetCertificate(clientHelloInfo) 368 assert.Nil(err) 369 assert.NotNil(cert) 370 } 371 372 func TestConfig_IncomingTLS_MissingCA(t *testing.T) { 373 conf := &Config{ 374 VerifyIncoming: true, 375 CertFile: foocert, 376 KeyFile: fookey, 377 KeyLoader: &config.KeyLoader{}, 378 } 379 _, err := conf.IncomingTLSConfig() 380 if err == nil { 381 t.Fatalf("expected err") 382 } 383 } 384 385 func TestConfig_IncomingTLS_MissingKey(t *testing.T) { 386 conf := &Config{ 387 VerifyIncoming: true, 388 CAFile: cacert, 389 } 390 _, err := conf.IncomingTLSConfig() 391 if err == nil { 392 t.Fatalf("expected err") 393 } 394 } 395 396 func TestConfig_IncomingTLS_NoVerify(t *testing.T) { 397 conf := &Config{} 398 tlsC, err := conf.IncomingTLSConfig() 399 if err != nil { 400 t.Fatalf("err: %v", err) 401 } 402 if tlsC == nil { 403 t.Fatalf("expected config") 404 } 405 if len(tlsC.ClientCAs.Subjects()) != 0 { 406 t.Fatalf("do not expect client cert") 407 } 408 if tlsC.ClientAuth != tls.NoClientCert { 409 t.Fatalf("should skip verification") 410 } 411 if len(tlsC.Certificates) != 0 { 412 t.Fatalf("unexpected client cert") 413 } 414 }