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  )