func (certSuite) TestVerify(c *gc.C) { now := time.Now() caCert, caKey, err := cert.NewCA("foo", now.Add(1*time.Minute)) c.Assert(err, jc.ErrorIsNil) var noHostnames []string srvCert, _, err := cert.NewServer(caCert, caKey, now.Add(3*time.Minute), noHostnames) c.Assert(err, jc.ErrorIsNil) err = cert.Verify(srvCert, caCert, now) c.Assert(err, jc.ErrorIsNil) err = cert.Verify(srvCert, caCert, now.Add(55*time.Second)) c.Assert(err, jc.ErrorIsNil) err = cert.Verify(srvCert, caCert, now.AddDate(0, 0, -8)) c.Check(err, gc.ErrorMatches, "x509: certificate has expired or is not yet valid") err = cert.Verify(srvCert, caCert, now.Add(2*time.Minute)) c.Check(err, gc.ErrorMatches, "x509: certificate has expired or is not yet valid") caCert2, caKey2, err := cert.NewCA("bar", now.Add(1*time.Minute)) c.Assert(err, jc.ErrorIsNil) // Check original server certificate against wrong CA. err = cert.Verify(srvCert, caCert2, now) c.Check(err, gc.ErrorMatches, "x509: certificate signed by unknown authority") srvCert2, _, err := cert.NewServer(caCert2, caKey2, now.Add(1*time.Minute), noHostnames) c.Assert(err, jc.ErrorIsNil) // Check new server certificate against original CA. err = cert.Verify(srvCert2, caCert, now) c.Check(err, gc.ErrorMatches, "x509: certificate signed by unknown authority") }
func (certSuite) TestNewServer(c *gc.C) { now := time.Now() expiry := roundTime(now.AddDate(1, 0, 0)) caCertPEM, caKeyPEM, err := cert.NewCA("foo", expiry) c.Assert(err, gc.IsNil) caCert, _, err := cert.ParseCertAndKey(caCertPEM, caKeyPEM) c.Assert(err, gc.IsNil) var noHostnames []string srvCertPEM, srvKeyPEM, err := cert.NewServer(caCertPEM, caKeyPEM, expiry, noHostnames) c.Assert(err, gc.IsNil) srvCert, srvKey, err := cert.ParseCertAndKey(srvCertPEM, srvKeyPEM) c.Assert(err, gc.IsNil) c.Assert(srvCert.Subject.CommonName, gc.Equals, "*") // Check that the certificate is valid from one week before today. c.Check(srvCert.NotBefore.Before(now), jc.IsTrue) c.Check(srvCert.NotBefore.Before(now.AddDate(0, 0, -6)), jc.IsTrue) c.Check(srvCert.NotBefore.After(now.AddDate(0, 0, -8)), jc.IsTrue) c.Assert(srvCert.NotAfter.Equal(expiry), gc.Equals, true) c.Assert(srvCert.BasicConstraintsValid, gc.Equals, false) c.Assert(srvCert.IsCA, gc.Equals, false) c.Assert(srvCert.ExtKeyUsage, gc.DeepEquals, []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}) checkTLSConnection(c, caCert, srvCert, srvKey) }
func (s *certPoolSuite) addCert(c *gc.C, filename string) { expiry := time.Now().UTC().AddDate(10, 0, 0) pem, _, err := cert.NewCA("random env name", "1", expiry) c.Assert(err, jc.ErrorIsNil) err = ioutil.WriteFile(filename, []byte(pem), 0644) c.Assert(err, jc.ErrorIsNil) }
func mustNewCA() (string, string) { cert.KeyBits = 512 caCert, caKey, err := cert.NewCA("juju testing", time.Now().AddDate(10, 0, 0)) if err != nil { panic(err) } return string(caCert), string(caKey) }
func createCerts(c *gc.C, serverName string) (*x509.CertPool, tls.Certificate) { certCaPem, keyCaPem, err := cert.NewCA("sender-test", "1", time.Now().Add(time.Minute)) c.Assert(err, jc.ErrorIsNil) certPem, keyPem, err := cert.NewServer(certCaPem, keyCaPem, time.Now().Add(time.Minute), []string{serverName}) c.Assert(err, jc.ErrorIsNil) cert, err := tls.X509KeyPair([]byte(certPem), []byte(keyPem)) c.Assert(err, jc.ErrorIsNil) certPool := x509.NewCertPool() certPool.AppendCertsFromPEM([]byte(certCaPem)) return certPool, cert }
func (certSuite) TestNewServer(c *gc.C) { now := time.Now() expiry := roundTime(now.AddDate(1, 0, 0)) caCertPEM, caKeyPEM, err := cert.NewCA("foo", expiry) c.Assert(err, jc.ErrorIsNil) caCert, _, err := cert.ParseCertAndKey(caCertPEM, caKeyPEM) c.Assert(err, jc.ErrorIsNil) srvCertPEM, srvKeyPEM, err := cert.NewServer(caCertPEM, caKeyPEM, expiry, nil) c.Assert(err, jc.ErrorIsNil) checkCertificate(c, caCert, srvCertPEM, srvKeyPEM, now, expiry) }
func (certSuite) TestWithNonUTCExpiry(c *gc.C) { expiry, err := time.Parse("2006-01-02 15:04:05.999999999 -0700 MST", "2012-11-28 15:53:57 +0100 CET") c.Assert(err, jc.ErrorIsNil) certPEM, keyPEM, err := cert.NewCA("foo", expiry) xcert, err := cert.ParseCert(certPEM) c.Assert(err, jc.ErrorIsNil) checkNotAfter(c, xcert, expiry) var noHostnames []string certPEM, _, err = cert.NewServer(certPEM, keyPEM, expiry, noHostnames) xcert, err = cert.ParseCert(certPEM) c.Assert(err, jc.ErrorIsNil) checkNotAfter(c, xcert, expiry) }
// ensureCertificates ensures that a CA certificate, // server certificate, and private key exist in the log // directory, and writes them if not. The CA certificate // is entered into the environment configuration to be // picked up by other agents. func (h *RsyslogConfigHandler) ensureCertificates() error { // We write ca-cert.pem last, after propagating into state. // If it's there, then there's nothing to do. Otherwise, // start over. caCertPEM := h.syslogConfig.CACertPath() if _, err := os.Stat(caCertPEM); err == nil { return nil } // Files must be chowned to syslog:adm. syslogUid, syslogGid, err := lookupUser("syslog") if err != nil { return err } // Generate a new CA and server cert/key pairs. // The CA key will be discarded after the server // cert has been generated. expiry := time.Now().UTC().AddDate(10, 0, 0) caCertPEM, caKeyPEM, err := cert.NewCA("rsyslog", expiry) if err != nil { return err } rsyslogCertPEM, rsyslogKeyPEM, err := cert.NewServer(caCertPEM, caKeyPEM, expiry, nil) if err != nil { return err } // Update the environment config with the CA cert, // so clients can configure rsyslog. if err := h.st.SetRsyslogCert(caCertPEM); err != nil { return err } // Write the certificates and key. The CA certificate must be written last for idempotency. for _, pair := range []struct { path string data string }{ {h.syslogConfig.ServerCertPath(), rsyslogCertPEM}, {h.syslogConfig.ServerKeyPath(), rsyslogKeyPEM}, {h.syslogConfig.CACertPath(), caCertPEM}, } { if err := writeFileAtomic(pair.path, []byte(pair.data), 0600, syslogUid, syslogGid); err != nil { return err } } return nil }
func (certSuite) TestNewCA(c *gc.C) { expiry := roundTime(time.Now().AddDate(0, 0, 1)) caCertPEM, caKeyPEM, err := cert.NewCA("foo", expiry) c.Assert(err, gc.IsNil) caCert, caKey, err := cert.ParseCertAndKey(caCertPEM, caKeyPEM) c.Assert(err, gc.IsNil) c.Assert(caKey, gc.FitsTypeOf, (*rsa.PrivateKey)(nil)) c.Assert(caCert.Subject.CommonName, gc.Equals, `juju-generated CA for environment "foo"`) c.Assert(caCert.NotAfter.Equal(expiry), gc.Equals, true) c.Assert(caCert.BasicConstraintsValid, gc.Equals, true) c.Assert(caCert.IsCA, gc.Equals, true) //c.Assert(caCert.MaxPathLen, Equals, 0) TODO it ends up as -1 - check that this is ok. }
func (certSuite) TestNewCA(c *gc.C) { now := time.Now() expiry := roundTime(now.AddDate(0, 0, 1)) caCertPEM, caKeyPEM, err := cert.NewCA("foo", expiry) c.Assert(err, jc.ErrorIsNil) caCert, caKey, err := cert.ParseCertAndKey(caCertPEM, caKeyPEM) c.Assert(err, jc.ErrorIsNil) c.Check(caKey, gc.FitsTypeOf, (*rsa.PrivateKey)(nil)) c.Check(caCert.Subject.CommonName, gc.Equals, `juju-generated CA for model "foo"`) checkNotBefore(c, caCert, now) checkNotAfter(c, caCert, expiry) c.Check(caCert.BasicConstraintsValid, jc.IsTrue) c.Check(caCert.IsCA, jc.IsTrue) //c.Assert(caCert.MaxPathLen, Equals, 0) TODO it ends up as -1 - check that this is ok. }
// ensureCertificate generates a new CA certificate and // attaches it to the given environment configuration, // unless the configuration already has one. func ensureCertificate(cfg *config.Config) (*config.Config, error) { _, hasCACert := cfg.CACert() _, hasCAKey := cfg.CAPrivateKey() if hasCACert && hasCAKey { return cfg, nil } if hasCACert && !hasCAKey { return nil, fmt.Errorf("environment configuration with a certificate but no CA private key") } caCert, caKey, err := cert.NewCA(cfg.Name(), time.Now().UTC().AddDate(10, 0, 0)) if err != nil { return nil, err } return cfg.Apply(map[string]interface{}{ "ca-cert": string(caCert), "ca-private-key": string(caKey), }) }
func (certSuite) TestNewCA(c *gc.C) { now := time.Now() expiry := roundTime(now.AddDate(0, 0, 1)) caCertPEM, caKeyPEM, err := cert.NewCA("foo", expiry) c.Assert(err, gc.IsNil) caCert, caKey, err := cert.ParseCertAndKey(caCertPEM, caKeyPEM) c.Assert(err, gc.IsNil) c.Check(caKey, gc.FitsTypeOf, (*rsa.PrivateKey)(nil)) c.Check(caCert.Subject.CommonName, gc.Equals, `juju-generated CA for environment "foo"`) // Check that the certificate is valid from one week before today. c.Check(caCert.NotBefore.Before(now), jc.IsTrue) c.Check(caCert.NotBefore.Before(now.AddDate(0, 0, -6)), jc.IsTrue) c.Check(caCert.NotBefore.After(now.AddDate(0, 0, -8)), jc.IsTrue) c.Check(caCert.NotAfter.Equal(expiry), gc.Equals, true) c.Check(caCert.BasicConstraintsValid, gc.Equals, true) c.Check(caCert.IsCA, gc.Equals, true) //c.Assert(caCert.MaxPathLen, Equals, 0) TODO it ends up as -1 - check that this is ok. }
// ensureCertificates ensures that a CA certificate, // server certificate, and private key exist in the log // directory, and writes them if not. The CA certificate // is entered into the environment configuration to be // picked up by other agents. func (h *RsyslogConfigHandler) ensureCertificates() error { // We write ca-cert.pem last, after propagating into state. // If it's there, then there's nothing to do. Otherwise, // start over. caCertPEM := h.syslogConfig.CACertPath() if _, err := os.Stat(caCertPEM); err == nil { return nil } // Generate a new CA and server cert/key pairs. // The CA key will be discarded after the server // cert has been generated. expiry := time.Now().UTC().AddDate(10, 0, 0) caCertPEM, caKeyPEM, err := cert.NewCA("rsyslog", expiry) if err != nil { return err } // Update the environment config with the CA cert, // so clients can configure rsyslog. if err := h.st.SetRsyslogCert(caCertPEM, caKeyPEM); err != nil { return err } rsyslogCertPEM, rsyslogKeyPEM, err := h.rsyslogServerCerts(caCertPEM, caKeyPEM) if err != nil { return err } if err := writeCertificates([]certPair{ {h.syslogConfig.ServerCertPath(), rsyslogCertPEM}, {h.syslogConfig.ServerKeyPath(), rsyslogKeyPEM}, {h.syslogConfig.CACertPath(), caCertPEM}, }); err != nil { return errors.Trace(err) } return nil }
func (certSuite) TestNewServer(c *gc.C) { expiry := roundTime(time.Now().AddDate(1, 0, 0)) caCertPEM, caKeyPEM, err := cert.NewCA("foo", expiry) c.Assert(err, gc.IsNil) caCert, _, err := cert.ParseCertAndKey(caCertPEM, caKeyPEM) c.Assert(err, gc.IsNil) var noHostnames []string srvCertPEM, srvKeyPEM, err := cert.NewServer(caCertPEM, caKeyPEM, expiry, noHostnames) c.Assert(err, gc.IsNil) srvCert, srvKey, err := cert.ParseCertAndKey(srvCertPEM, srvKeyPEM) c.Assert(err, gc.IsNil) c.Assert(srvCert.Subject.CommonName, gc.Equals, "*") c.Assert(srvCert.NotAfter.Equal(expiry), gc.Equals, true) c.Assert(srvCert.BasicConstraintsValid, gc.Equals, false) c.Assert(srvCert.IsCA, gc.Equals, false) c.Assert(srvCert.ExtKeyUsage, gc.DeepEquals, []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}) checkTLSConnection(c, caCert, srvCert, srvKey) }
// ensureCA ensures that a CA certificate and key exist in state, // to be picked up by all rsyslog workers in the environment. func (h *RsyslogConfigHandler) ensureCA() error { // We never write the CA key to local disk, so // we must check state to know whether or not // we need to generate new certs and keys. cfg, err := h.st.GetRsyslogConfig(h.tag.String()) if err != nil { return errors.Annotate(err, "cannot get environ config") } if cfg.CACert != "" && cfg.CAKey != "" { return nil } // Generate a new CA and server cert/key pairs, and // publish to state. Rsyslog workers will observe // this and generate certificates and keys for // rsyslog in response. expiry := time.Now().UTC().AddDate(10, 0, 0) caCertPEM, caKeyPEM, err := cert.NewCA("rsyslog", expiry) if err != nil { return err } return h.st.SetRsyslogCert(caCertPEM, caKeyPEM) }
// ensureCertificate generates a new CA certificate and // attaches it to the given controller configuration, // unless the configuration already has one. func ensureCertificate(cfg *config.Config) (*config.Config, string, error) { caCert, hasCACert := cfg.CACert() _, hasCAKey := cfg.CAPrivateKey() if hasCACert && hasCAKey { return cfg, caCert, nil } if hasCACert && !hasCAKey { return nil, "", errors.Errorf("controller configuration with a certificate but no CA private key") } caCert, caKey, err := cert.NewCA(cfg.Name(), cfg.UUID(), time.Now().UTC().AddDate(10, 0, 0)) if err != nil { return nil, "", errors.Trace(err) } cfg, err = cfg.Apply(map[string]interface{}{ config.CACertKey: string(caCert), "ca-private-key": string(caKey), }) if err != nil { return nil, "", errors.Trace(err) } return cfg, string(caCert), nil }
// NewConfig creates a new Config from the supplied attributes. // Default values will be used where defaults are available. // // If ca-cert or ca-private-key are not set, then we will check // if ca-cert-path or ca-private-key-path are set, and read the // contents. If none of those are set, we will look for files // in well-defined locations: $JUJU_DATA/ca-cert.pem, and // $JUJU_DATA/ca-private-key.pem. If none of these are set, an // error is returned. func NewConfig(attrs map[string]interface{}) (Config, error) { coerced, err := configChecker.Coerce(attrs, nil) if err != nil { return Config{}, errors.Trace(err) } attrs = coerced.(map[string]interface{}) config := Config{ BootstrapTimeout: time.Duration(attrs[BootstrapTimeoutKey].(int)) * time.Second, BootstrapRetryDelay: time.Duration(attrs[BootstrapRetryDelayKey].(int)) * time.Second, BootstrapAddressesDelay: time.Duration(attrs[BootstrapAddressesDelayKey].(int)) * time.Second, } if adminSecret, ok := attrs[AdminSecretKey].(string); ok { config.AdminSecret = adminSecret } else { // Generate a random admin secret. buf := make([]byte, 16) if _, err := io.ReadFull(rand.Reader, buf); err != nil { return Config{}, errors.Annotate(err, "generating random "+AdminSecretKey) } config.AdminSecret = fmt.Sprintf("%x", buf) } if caCert, ok := attrs[CACertKey].(string); ok { config.CACert = caCert } else { var userSpecified bool var err error config.CACert, userSpecified, err = readFileAttr(attrs, CACertKey, CACertKey+".pem") if err != nil && (userSpecified || !os.IsNotExist(errors.Cause(err))) { return Config{}, errors.Annotatef(err, "reading %q from file", CACertKey) } } if caPrivateKey, ok := attrs[CAPrivateKeyKey].(string); ok { config.CAPrivateKey = caPrivateKey } else { var userSpecified bool var err error config.CAPrivateKey, userSpecified, err = readFileAttr(attrs, CAPrivateKeyKey, CAPrivateKeyKey+".pem") if err != nil && (userSpecified || !os.IsNotExist(errors.Cause(err))) { return Config{}, errors.Annotatef(err, "reading %q from file", CAPrivateKeyKey) } } if config.CACert == "" && config.CAPrivateKey == "" { // Generate a new CA certificate and private key. // TODO(perrito666) 2016-05-02 lp:1558657 expiry := time.Now().UTC().AddDate(10, 0, 0) uuid, err := utils.NewUUID() if err != nil { return Config{}, errors.Annotate(err, "generating UUID for CA certificate") } caCert, caKey, err := cert.NewCA("juju-ca", uuid.String(), expiry) if err != nil { return Config{}, errors.Trace(err) } config.CACert = caCert config.CAPrivateKey = caKey } return config, config.Validate() }
// ensureCertificates ensures that a CA certificate, // server certificate, and private key exist in the log // directory, and writes them if not. The CA certificate // is entered into the environment configuration to be // picked up by other agents. func (h *RsyslogConfigHandler) ensureCertificates() error { // We write ca-cert.pem last, after propagating into state. // If it's there, then there's nothing to do. Otherwise, // start over. caCertPEM := h.syslogConfig.CACertPath() if _, err := os.Stat(caCertPEM); err == nil { return nil } // Files must be chowned to syslog:adm. syslogUid, syslogGid, err := lookupUser("syslog") if err != nil { return err } // Generate a new CA and server cert/key pairs. // The CA key will be discarded after the server // cert has been generated. expiry := time.Now().UTC().AddDate(10, 0, 0) caCertPEM, caKeyPEM, err := cert.NewCA("rsyslog", expiry) if err != nil { return err } // Add rsyslog servers in the subjectAltName so we can // successfully validate when connectiong via SSL hosts, err := h.rsyslogHosts() if err != nil { return err } // Add local IPs to SAN. When connecting via IP address, // the client will validate the server against any IP in // the subjectAltName. We add all local ips to make sure // this does not cause an error ips, err := localIPS() if err != nil { return err } hosts = append(hosts, ips...) rsyslogCertPEM, rsyslogKeyPEM, err := cert.NewServer(caCertPEM, caKeyPEM, expiry, hosts) if err != nil { return err } // Update the environment config with the CA cert, // so clients can configure rsyslog. if err := h.st.SetRsyslogCert(caCertPEM); err != nil { return err } // Write the certificates and key. The CA certificate must be written last for idempotency. for _, pair := range []struct { path string data string }{ {h.syslogConfig.ServerCertPath(), rsyslogCertPEM}, {h.syslogConfig.ServerKeyPath(), rsyslogKeyPEM}, {h.syslogConfig.CACertPath(), caCertPEM}, } { if err := writeFileAtomic(pair.path, []byte(pair.data), 0600, syslogUid, syslogGid); err != nil { return err } } return nil }