github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cert/cert_test.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package cert_test 5 6 import ( 7 "bytes" 8 "crypto/rsa" 9 "crypto/tls" 10 "crypto/x509" 11 "io" 12 "io/ioutil" 13 "math/big" 14 "net" 15 "strings" 16 "testing" 17 "time" 18 19 jc "github.com/juju/testing/checkers" 20 "github.com/juju/utils" 21 utilscert "github.com/juju/utils/cert" 22 gc "gopkg.in/check.v1" 23 24 "github.com/juju/juju/cert" 25 ) 26 27 func TestAll(t *testing.T) { 28 gc.TestingT(t) 29 } 30 31 type certSuite struct{} 32 33 var _ = gc.Suite(certSuite{}) 34 35 func checkNotAfter(c *gc.C, cert *x509.Certificate, expiry time.Time) { 36 // Check the surrounding day. 37 c.Assert(cert.NotAfter.Before(expiry.AddDate(0, 0, 1)), jc.IsTrue) 38 c.Assert(cert.NotAfter.After(expiry.AddDate(0, 0, -1)), jc.IsTrue) 39 } 40 41 func checkNotBefore(c *gc.C, cert *x509.Certificate, now time.Time) { 42 // Check that the certificate is valid from one week before today. 43 c.Check(cert.NotBefore.Before(now), jc.IsTrue) 44 c.Check(cert.NotBefore.Before(now.AddDate(0, 0, -6)), jc.IsTrue) 45 c.Check(cert.NotBefore.After(now.AddDate(0, 0, -8)), jc.IsTrue) 46 } 47 48 type recordingConn struct { 49 net.Conn 50 io.Writer 51 } 52 53 func (c recordingConn) Write(buf []byte) (int, error) { 54 return c.Writer.Write(buf) 55 } 56 57 // checkTLSConnection checks that we can correctly perform a TLS 58 // handshake using the given credentials. 59 func checkTLSConnection(c *gc.C, caCert, srvCert *x509.Certificate, srvKey *rsa.PrivateKey) (caName string) { 60 clientCertPool := x509.NewCertPool() 61 clientCertPool.AddCert(caCert) 62 63 var outBytes bytes.Buffer 64 65 const msg = "hello to the server" 66 p0, p1 := net.Pipe() 67 p0 = &recordingConn{ 68 Conn: p0, 69 Writer: io.MultiWriter(p0, &outBytes), 70 } 71 72 var clientState tls.ConnectionState 73 done := make(chan error) 74 go func() { 75 config := utils.SecureTLSConfig() 76 config.Certificates = []tls.Certificate{{ 77 Certificate: [][]byte{srvCert.Raw}, 78 PrivateKey: srvKey, 79 }} 80 81 conn := tls.Server(p1, config) 82 defer conn.Close() 83 data, err := ioutil.ReadAll(conn) 84 c.Assert(err, jc.ErrorIsNil) 85 c.Assert(string(data), gc.Equals, msg) 86 close(done) 87 }() 88 89 tlsConfig := utils.SecureTLSConfig() 90 tlsConfig.ServerName = "anyServer" 91 tlsConfig.RootCAs = clientCertPool 92 clientConn := tls.Client(p0, tlsConfig) 93 defer clientConn.Close() 94 95 _, err := clientConn.Write([]byte(msg)) 96 c.Assert(err, jc.ErrorIsNil) 97 clientState = clientConn.ConnectionState() 98 clientConn.Close() 99 100 // wait for server to exit 101 <-done 102 103 outData := outBytes.String() 104 c.Assert(outData, gc.Not(gc.HasLen), 0) 105 if strings.Index(outData, msg) != -1 { 106 c.Fatalf("TLS connection not encrypted") 107 } 108 c.Assert(clientState.VerifiedChains, gc.HasLen, 1) 109 c.Assert(clientState.VerifiedChains[0], gc.HasLen, 2) 110 return clientState.VerifiedChains[0][1].Subject.CommonName 111 } 112 113 func checkCertificate(c *gc.C, caCert *x509.Certificate, srvCertPEM, srvKeyPEM string, now, expiry time.Time) { 114 srvCert, srvKey, err := utilscert.ParseCertAndKey(srvCertPEM, srvKeyPEM) 115 c.Assert(err, jc.ErrorIsNil) 116 c.Assert(srvCert.Subject.CommonName, gc.Equals, "*") 117 checkNotBefore(c, srvCert, now) 118 checkNotAfter(c, srvCert, expiry) 119 c.Assert(srvCert.BasicConstraintsValid, jc.IsFalse) 120 c.Assert(srvCert.IsCA, jc.IsFalse) 121 c.Assert(srvCert.ExtKeyUsage, gc.DeepEquals, []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}) 122 c.Assert(srvCert.SerialNumber, gc.NotNil) 123 if srvCert.SerialNumber.Cmp(big.NewInt(0)) == 0 { 124 c.Fatalf("zero serial number") 125 } 126 127 checkTLSConnection(c, caCert, srvCert, srvKey) 128 } 129 130 func (certSuite) TestVerify(c *gc.C) { 131 now := time.Now() 132 caCert, caKey, err := cert.NewCA("foo", "1", now.Add(1*time.Minute)) 133 c.Assert(err, jc.ErrorIsNil) 134 135 var noHostnames []string 136 srvCert, _, err := cert.NewServer(caCert, caKey, now.Add(3*time.Minute), noHostnames) 137 c.Assert(err, jc.ErrorIsNil) 138 139 err = cert.Verify(srvCert, caCert, now) 140 c.Assert(err, jc.ErrorIsNil) 141 142 err = cert.Verify(srvCert, caCert, now.Add(55*time.Second)) 143 c.Assert(err, jc.ErrorIsNil) 144 145 err = cert.Verify(srvCert, caCert, now.AddDate(0, 0, -8)) 146 c.Check(err, gc.ErrorMatches, "x509: certificate has expired or is not yet valid") 147 148 err = cert.Verify(srvCert, caCert, now.Add(2*time.Minute)) 149 c.Check(err, gc.ErrorMatches, "x509: certificate has expired or is not yet valid") 150 151 caCert2, caKey2, err := cert.NewCA("bar", "1", now.Add(1*time.Minute)) 152 c.Assert(err, jc.ErrorIsNil) 153 154 // Check original server certificate against wrong CA. 155 err = cert.Verify(srvCert, caCert2, now) 156 c.Check(err, gc.ErrorMatches, "x509: certificate signed by unknown authority") 157 158 srvCert2, _, err := cert.NewServer(caCert2, caKey2, now.Add(1*time.Minute), noHostnames) 159 c.Assert(err, jc.ErrorIsNil) 160 161 // Check new server certificate against original CA. 162 err = cert.Verify(srvCert2, caCert, now) 163 c.Check(err, gc.ErrorMatches, "x509: certificate signed by unknown authority") 164 } 165 166 func (certSuite) TestNewServer(c *gc.C) { 167 now := time.Now() 168 expiry := roundTime(now.AddDate(1, 0, 0)) 169 caCertPEM, caKeyPEM, err := cert.NewCA("foo", "1", expiry) 170 c.Assert(err, jc.ErrorIsNil) 171 172 caCert, _, err := utilscert.ParseCertAndKey(caCertPEM, caKeyPEM) 173 c.Assert(err, jc.ErrorIsNil) 174 175 srvCertPEM, srvKeyPEM, err := cert.NewServer(caCertPEM, caKeyPEM, expiry, nil) 176 c.Assert(err, jc.ErrorIsNil) 177 checkCertificate(c, caCert, srvCertPEM, srvKeyPEM, now, expiry) 178 } 179 180 func (certSuite) TestNewDefaultServer(c *gc.C) { 181 now := time.Now() 182 expiry := roundTime(now.AddDate(1, 0, 0)) 183 caCertPEM, caKeyPEM, err := cert.NewCA("foo", "1", expiry) 184 c.Assert(err, jc.ErrorIsNil) 185 186 caCert, _, err := utilscert.ParseCertAndKey(caCertPEM, caKeyPEM) 187 c.Assert(err, jc.ErrorIsNil) 188 189 srvCertPEM, srvKeyPEM, err := cert.NewDefaultServer(caCertPEM, caKeyPEM, nil) 190 c.Assert(err, jc.ErrorIsNil) 191 srvCertExpiry := roundTime(time.Now().AddDate(10, 0, 0)) 192 checkCertificate(c, caCert, srvCertPEM, srvKeyPEM, now, srvCertExpiry) 193 } 194 195 func (certSuite) TestWithNonUTCExpiry(c *gc.C) { 196 expiry, err := time.Parse("2006-01-02 15:04:05.999999999 -0700 MST", "2012-11-28 15:53:57 +0100 CET") 197 c.Assert(err, jc.ErrorIsNil) 198 certPEM, keyPEM, err := cert.NewCA("foo", "1", expiry) 199 xcert, err := utilscert.ParseCert(certPEM) 200 c.Assert(err, jc.ErrorIsNil) 201 checkNotAfter(c, xcert, expiry) 202 203 var noHostnames []string 204 certPEM, _, err = cert.NewServer(certPEM, keyPEM, expiry, noHostnames) 205 xcert, err = utilscert.ParseCert(certPEM) 206 c.Assert(err, jc.ErrorIsNil) 207 checkNotAfter(c, xcert, expiry) 208 } 209 210 func (certSuite) TestNewServerWithInvalidCert(c *gc.C) { 211 var noHostnames []string 212 srvCert, srvKey, err := cert.NewServer(nonCACert, nonCAKey, time.Now(), noHostnames) 213 c.Check(srvCert, gc.Equals, "") 214 c.Check(srvKey, gc.Equals, "") 215 c.Assert(err, gc.ErrorMatches, "CA certificate is not a valid CA") 216 } 217 218 func (certSuite) TestNewServerHostnames(c *gc.C) { 219 type test struct { 220 hostnames []string 221 expectedDNSNames []string 222 expectedIPAddresses []net.IP 223 } 224 tests := []test{ 225 { 226 []string{}, 227 nil, 228 nil, 229 }, { 230 []string{"example.com"}, 231 []string{"example.com"}, 232 nil, 233 }, { 234 []string{"example.com", "127.0.0.1"}, 235 []string{"example.com"}, 236 []net.IP{net.IPv4(127, 0, 0, 1).To4()}, 237 }, { 238 []string{"::1"}, 239 nil, 240 []net.IP{net.IPv6loopback}, 241 }, 242 } 243 for i, t := range tests { 244 c.Logf("test %d: %v", i, t.hostnames) 245 expiry := roundTime(time.Now().AddDate(1, 0, 0)) 246 srvCertPEM, srvKeyPEM, err := cert.NewServer(caCertPEM, caKeyPEM, expiry, t.hostnames) 247 c.Assert(err, jc.ErrorIsNil) 248 srvCert, _, err := utilscert.ParseCertAndKey(srvCertPEM, srvKeyPEM) 249 c.Assert(err, jc.ErrorIsNil) 250 c.Assert(srvCert.DNSNames, gc.DeepEquals, t.expectedDNSNames) 251 c.Assert(srvCert.IPAddresses, gc.DeepEquals, t.expectedIPAddresses) 252 } 253 } 254 255 // roundTime returns t rounded to the previous whole second. 256 func roundTime(t time.Time) time.Time { 257 return t.Add(time.Duration(-t.Nanosecond())) 258 } 259 260 var ( 261 nonCACert = ` 262 -----BEGIN CERTIFICATE----- 263 MIIB8jCCAZygAwIBAgIVANueMZWTFEIx6AcNAWsG4VL4sUn5MA0GCSqGSIb3DQEB 264 CwUAMGsxDTALBgNVBAoTBGp1anUxMzAxBgNVBAMMKmp1anUtZ2VuZXJhdGVkIENB 265 IGZvciBtb2RlbCAianVqdSB0ZXN0aW5nIjElMCMGA1UEBRMcMTIzNC1BQkNELUlT 266 LU5PVC1BLVJFQUwtVVVJRDAeFw0xNjA5MjExMDQ4MjdaFw0yNjA5MjgxMDQ4Mjda 267 MBsxDTALBgNVBAoTBGp1anUxCjAIBgNVBAMTASowXDANBgkqhkiG9w0BAQEFAANL 268 ADBIAkEAwZps3qpPu2FCAhbxolf/BvSa+dMal3AhPMe+lwTuSbtS81W+WSrbwUSI 269 ZKSGHYDpFRN6ytNjt1oPbDNKDIR30wIDAQABo2cwZTAOBgNVHQ8BAf8EBAMCA6gw 270 EwYDVR0lBAwwCgYIKwYBBQUHAwEwHQYDVR0OBBYEFNNUDrcyP/4RbGBpKeC3gmfL 271 kjlwMB8GA1UdIwQYMBaAFHueMLZ1QJ/2sKiPIJ28TzjIMRENMA0GCSqGSIb3DQEB 272 CwUAA0EALiurKx//Qh5TQQ0TmT0P5f7OFLIs5XPSS98Lseb92h12CPNO4kB000Yh 273 Xa7kZRGngwFbvjzqZ0eOfmo0l8M23A== 274 -----END CERTIFICATE----- 275 ` 276 277 nonCAKey = ` 278 -----BEGIN RSA PRIVATE KEY----- 279 MIIBOwIBAAJBAMGabN6qT7thQgIW8aJX/wb0mvnTGpdwITzHvpcE7km7UvNVvlkq 280 28FEiGSkhh2A6RUTesrTY7daD2wzSgyEd9MCAwEAAQJBAKfeuOvRjVUSneOl9Vsp 281 Je7oBcD9dR8+kPNc1zungN7YVhIuxqvzXJSPeMGsHloPI+BcFFXv3t+eVCDT9sPL 282 L+ECIQDq1nqVIEX3k5nn6eI0L5CQbIfEyvWGJ/mOGSo9TWdN+QIhANMMsopPb9ct 283 Z61LqPmTtNX4nhHyMEjxbUzqzsZzsRcrAiBeYyhP6fHVSXERopK1kOyU79o+Aalf 284 a4/FSl4M16CO2QIgOBQZpNKyvxRbhhqijZ6H4IstRUt7NQahqlyCEQ1Qsv0CIQDQ 285 tUzgFwUpd6NVButkqWGqnmBeKUOs97dqSyOzN9Nk8w== 286 -----END RSA PRIVATE KEY----- 287 ` 288 caKeyPEM = ` 289 -----BEGIN RSA PRIVATE KEY----- 290 MIIBOgIBAAJBAL+0X+1zl2vt1wI41Q+RnlltJyaJmtwCbHRhREXVGU7t0kTMMNER 291 xqLnuNUyWRz90Rg8s9XvOtCqNYW7mypGrFECAwEAAQJAMPa+JaUHgO6foxam/LIB 292 0u95N3OgFR+dWeBaEsgKDclpREdJ0rXNI+3C3kwqeEZR4omoPlBeSEewSkwHxpmI 293 0QIhAOjKiHZ5v6R8haleipbDzkGUnZW07hEwL5Ld4MNx/QQ1AiEA0tEzSSNAdM0C 294 M/vY0x5mekIYai8/tFSEG9PJ3ZkpEy0CIQCo9B3YxwI1Un777vbs903iQQeiWP+U 295 EAHnOQvhLgDxpQIgGkpml+9igW5zoOH+h02aQBLwEoXz7tw/YW0HFrCcE70CIGkS 296 ve4WjiEqnQaHNAPy0hY/1DfIgBOSpOfnkFHOk9vX 297 -----END RSA PRIVATE KEY----- 298 ` 299 caCertPEM = ` 300 -----BEGIN CERTIFICATE----- 301 MIICHDCCAcagAwIBAgIUfzWn5ktGMxD6OiTgfiZyvKdM+ZYwDQYJKoZIhvcNAQEL 302 BQAwazENMAsGA1UEChMEanVqdTEzMDEGA1UEAwwqanVqdS1nZW5lcmF0ZWQgQ0Eg 303 Zm9yIG1vZGVsICJqdWp1IHRlc3RpbmciMSUwIwYDVQQFExwxMjM0LUFCQ0QtSVMt 304 Tk9ULUEtUkVBTC1VVUlEMB4XDTE2MDkyMTEwNDgyN1oXDTI2MDkyODEwNDgyN1ow 305 azENMAsGA1UEChMEanVqdTEzMDEGA1UEAwwqanVqdS1nZW5lcmF0ZWQgQ0EgZm9y 306 IG1vZGVsICJqdWp1IHRlc3RpbmciMSUwIwYDVQQFExwxMjM0LUFCQ0QtSVMtTk9U 307 LUEtUkVBTC1VVUlEMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL+0X+1zl2vt1wI4 308 1Q+RnlltJyaJmtwCbHRhREXVGU7t0kTMMNERxqLnuNUyWRz90Rg8s9XvOtCqNYW7 309 mypGrFECAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgKkMA8GA1UdEwEB/wQFMAMBAf8w 310 HQYDVR0OBBYEFHueMLZ1QJ/2sKiPIJ28TzjIMRENMA0GCSqGSIb3DQEBCwUAA0EA 311 ovZN0RbUHrO8q9Eazh0qPO4mwW9jbGTDz126uNrLoz1g3TyWxIas1wRJ8IbCgxLy 312 XUrBZO5UPZab66lJWXyseA== 313 -----END CERTIFICATE----- 314 ` 315 )