Example #1
0
func TestGetRemoteSignedCertificate(t *testing.T) {
	tc := testutils.NewTestCA(t)
	defer tc.Stop()

	// Create a new CSR to be signed
	csr, _, err := ca.GenerateAndWriteNewKey(tc.Paths.Node)
	assert.NoError(t, err)

	certs, err := ca.GetRemoteSignedCertificate(context.Background(), csr, tc.ManagerToken, tc.RootCA.Pool, tc.Remotes, nil, nil)
	assert.NoError(t, err)
	assert.NotNil(t, certs)

	// Test the expiration for a manager certificate
	parsedCerts, err := helpers.ParseCertificatesPEM(certs)
	assert.NoError(t, err)
	assert.Len(t, parsedCerts, 2)
	assert.True(t, time.Now().Add(ca.DefaultNodeCertExpiration).AddDate(0, 0, -1).Before(parsedCerts[0].NotAfter))
	assert.True(t, time.Now().Add(ca.DefaultNodeCertExpiration).AddDate(0, 0, 1).After(parsedCerts[0].NotAfter))
	assert.Equal(t, parsedCerts[0].Subject.OrganizationalUnit[0], ca.ManagerRole)

	// Test the expiration for an agent certificate
	certs, err = ca.GetRemoteSignedCertificate(tc.Context, csr, tc.WorkerToken, tc.RootCA.Pool, tc.Remotes, nil, nil)
	assert.NoError(t, err)
	assert.NotNil(t, certs)
	parsedCerts, err = helpers.ParseCertificatesPEM(certs)
	assert.NoError(t, err)
	assert.Len(t, parsedCerts, 2)
	assert.True(t, time.Now().Add(ca.DefaultNodeCertExpiration).AddDate(0, 0, -1).Before(parsedCerts[0].NotAfter))
	assert.True(t, time.Now().Add(ca.DefaultNodeCertExpiration).AddDate(0, 0, 1).After(parsedCerts[0].NotAfter))
	assert.Equal(t, parsedCerts[0].Subject.OrganizationalUnit[0], ca.AgentRole)
}
Example #2
0
// NewBundlerFromPEM creates a new Bundler from PEM-encoded root certificates and
// intermediate certificates.
func NewBundlerFromPEM(caBundlePEM, intBundlePEM []byte) (*Bundler, error) {
	b := &Bundler{
		RootPool:         x509.NewCertPool(),
		IntermediatePool: x509.NewCertPool(),
		KnownIssuers:     map[string]bool{},
	}

	log.Debug("parsing root certificates from PEM")
	roots, err := helpers.ParseCertificatesPEM(caBundlePEM)
	if err != nil {
		log.Errorf("failed to parse root bundle: %v", err)
		return nil, errors.New(errors.RootError, errors.ParseFailed)
	}

	log.Debug("parse intermediate certificates from PEM")
	var intermediates []*x509.Certificate
	if intermediates, err = helpers.ParseCertificatesPEM(intBundlePEM); err != nil {
		log.Errorf("failed to parse intermediate bundle: %v", err)
		return nil, errors.New(errors.IntermediatesError, errors.ParseFailed)
	}

	log.Debug("building certificate pools")
	for _, c := range roots {
		b.RootPool.AddCert(c)
		b.KnownIssuers[string(c.Signature)] = true
	}

	for _, c := range intermediates {
		b.IntermediatePool.AddCert(c)
		b.KnownIssuers[string(c.Signature)] = true
	}

	log.Debug("bundler set up")
	return b, nil
}
Example #3
0
func TestIssueAndSaveNewCertificates(t *testing.T) {
	tc := testutils.NewTestCA(t)
	defer tc.Stop()

	// Test the creation of a manager certificate
	cert, err := tc.RootCA.IssueAndSaveNewCertificates(tc.Paths.Node, "CN", ca.ManagerRole, tc.Organization)
	assert.NoError(t, err)
	assert.NotNil(t, cert)
	perms, err := permbits.Stat(tc.Paths.Node.Cert)
	assert.NoError(t, err)
	assert.False(t, perms.GroupWrite())
	assert.False(t, perms.OtherWrite())

	certBytes, err := ioutil.ReadFile(tc.Paths.Node.Cert)
	assert.NoError(t, err)
	certs, err := helpers.ParseCertificatesPEM(certBytes)
	assert.NoError(t, err)
	assert.Len(t, certs, 2)
	assert.Equal(t, "CN", certs[0].Subject.CommonName)
	assert.Equal(t, ca.ManagerRole, certs[0].Subject.OrganizationalUnit[0])
	assert.Equal(t, tc.Organization, certs[0].Subject.Organization[0])
	assert.Equal(t, "swarm-test-CA", certs[1].Subject.CommonName)
	assert.Contains(t, certs[0].DNSNames, "CN")
	assert.Contains(t, certs[0].DNSNames, "swarm-ca")
	assert.Contains(t, certs[0].DNSNames, "swarm-manager")

	// Test the creation of a worker node cert
	cert, err = tc.RootCA.IssueAndSaveNewCertificates(tc.Paths.Node, "CN", ca.AgentRole, tc.Organization)
	assert.NoError(t, err)
	assert.NotNil(t, cert)
	perms, err = permbits.Stat(tc.Paths.Node.Cert)
	assert.NoError(t, err)
	assert.False(t, perms.GroupWrite())
	assert.False(t, perms.OtherWrite())

	certBytes, err = ioutil.ReadFile(tc.Paths.Node.Cert)
	assert.NoError(t, err)
	certs, err = helpers.ParseCertificatesPEM(certBytes)
	assert.NoError(t, err)
	assert.Len(t, certs, 2)
	assert.Equal(t, "CN", certs[0].Subject.CommonName)
	assert.Equal(t, ca.AgentRole, certs[0].Subject.OrganizationalUnit[0])
	assert.Equal(t, tc.Organization, certs[0].Subject.Organization[0])
	assert.Equal(t, "swarm-test-CA", certs[1].Subject.CommonName)
	assert.Contains(t, certs[0].DNSNames, "CN")
	assert.Contains(t, certs[0].DNSNames, "swarm-worker")

}
Example #4
0
// NewCFSSL produces a new CFSSL root.
func NewCFSSL(metadata map[string]string) ([]*x509.Certificate, error) {
	host, ok := metadata["host"]
	if !ok {
		return nil, errors.New("transport: CFSSL root provider requires a host")
	}

	label := metadata["label"]
	profile := metadata["profile"]
	cert, err := helpers.LoadClientCertificate(metadata["mutual-tls-cert"], metadata["mutual-tls-key"])
	if err != nil {
		return nil, err
	}
	remoteCAs, err := helpers.LoadPEMCertPool(metadata["tls-remote-ca"])
	if err != nil {
		return nil, err
	}
	srv := client.NewServerTLS(host, helpers.CreateTLSConfig(remoteCAs, cert))
	data, err := json.Marshal(info.Req{Label: label, Profile: profile})
	if err != nil {
		return nil, err
	}

	resp, err := srv.Info(data)
	if err != nil {
		return nil, err
	}

	return helpers.ParseCertificatesPEM([]byte(resp.Certificate))
}
Example #5
0
func TestGenerateAndSignNewTLSCert(t *testing.T) {
	tempBaseDir, err := ioutil.TempDir("", "swarm-ca-test-")
	assert.NoError(t, err)
	defer os.RemoveAll(tempBaseDir)

	paths := ca.NewConfigPaths(tempBaseDir)

	rootCA, err := ca.CreateAndWriteRootCA("rootCN", paths.RootCA)
	assert.NoError(t, err)

	_, err = ca.GenerateAndSignNewTLSCert(rootCA, "CN", "OU", "ORG", paths.Node)
	assert.NoError(t, err)

	perms, err := permbits.Stat(paths.Node.Cert)
	assert.NoError(t, err)
	assert.False(t, perms.GroupWrite())
	assert.False(t, perms.OtherWrite())
	perms, err = permbits.Stat(paths.Node.Key)
	assert.NoError(t, err)
	assert.False(t, perms.GroupRead())
	assert.False(t, perms.OtherRead())

	certBytes, err := ioutil.ReadFile(paths.Node.Cert)
	assert.NoError(t, err)
	certs, err := helpers.ParseCertificatesPEM(certBytes)
	assert.NoError(t, err)
	assert.Len(t, certs, 2)
	assert.Equal(t, "CN", certs[0].Subject.CommonName)
	assert.Equal(t, "OU", certs[0].Subject.OrganizationalUnit[0])
	assert.Equal(t, "ORG", certs[0].Subject.Organization[0])
	assert.Equal(t, "rootCN", certs[1].Subject.CommonName)
}
Example #6
0
func TestParseValidateAndSignCSR(t *testing.T) {
	tempBaseDir, err := ioutil.TempDir("", "swarm-ca-test-")
	assert.NoError(t, err)
	defer os.RemoveAll(tempBaseDir)

	paths := ca.NewConfigPaths(tempBaseDir)

	rootCA, err := ca.CreateAndWriteRootCA("rootCN", paths.RootCA)
	assert.NoError(t, err)

	csr, _, err := ca.GenerateAndWriteNewKey(paths.Node)
	assert.NoError(t, err)

	signedCert, err := rootCA.ParseValidateAndSignCSR(csr, "CN", "OU", "ORG")
	assert.NoError(t, err)
	assert.NotNil(t, signedCert)

	parsedCert, err := helpers.ParseCertificatesPEM(signedCert)
	assert.NoError(t, err)
	assert.Equal(t, 2, len(parsedCert))
	assert.Equal(t, "CN", parsedCert[0].Subject.CommonName)
	assert.Equal(t, 1, len(parsedCert[0].Subject.OrganizationalUnit))
	assert.Equal(t, "OU", parsedCert[0].Subject.OrganizationalUnit[0])
	assert.Equal(t, 3, len(parsedCert[0].Subject.Names))
	assert.Equal(t, "ORG", parsedCert[0].Subject.Organization[0])
	assert.Equal(t, "rootCN", parsedCert[1].Subject.CommonName)
}
Example #7
0
// Tests on verifying the rebundle flag and error code in Bundle.Status when rebundling.
func TestRebundleFromPEM(t *testing.T) {
	newBundler := newCustomizedBundlerFromFile(t, testCFSSLRootBundle, interL1, "")
	newBundle, err := newBundler.BundleFromPEMorDER(expiredBundlePEM, nil, Optimal, "")
	if err != nil {
		t.Fatalf("Re-bundle failed. %s", err.Error())
	}
	newChain := newBundle.Chain

	if len(newChain) != 2 {
		t.Fatalf("Expected bundle chain length is 2. Got %d.", len(newChain))
	}

	expiredChain, _ := helpers.ParseCertificatesPEM(expiredBundlePEM)
	for i, cert := range newChain {
		old := expiredChain[i]
		if i == 0 {
			if !bytes.Equal(old.Signature, cert.Signature) {
				t.Fatal("Leaf cert should be the same.")
			}
		} else {
			if bytes.Equal(old.Signature, cert.Signature) {
				t.Fatal("Intermediate cert should be different.")
			}
		}
	}
	// The status must be {Code: ExpiringBit is not set, IsRebundled:true, ExpiringSKIs:{}}
	if len(newBundle.Status.ExpiringSKIs) != 0 || !newBundle.Status.IsRebundled || newBundle.Status.Code&errors.BundleExpiringBit != 0 {
		t.Fatal("Rebundle Status is incorrect.")
	}

}
Example #8
0
// NewBundlerFromPEM creates a new Bundler from PEM-encoded root certificates and
// intermediate certificates.
// If caBundlePEM is nil, the resulting Bundler can only do "Force" bundle.
func NewBundlerFromPEM(caBundlePEM, intBundlePEM []byte) (*Bundler, error) {
	log.Debug("parsing root certificates from PEM")
	roots, err := helpers.ParseCertificatesPEM(caBundlePEM)
	if err != nil {
		log.Errorf("failed to parse root bundle: %v", err)
		return nil, errors.New(errors.RootError, errors.ParseFailed)
	}

	log.Debug("parse intermediate certificates from PEM")
	intermediates, err := helpers.ParseCertificatesPEM(intBundlePEM)
	if err != nil {
		log.Errorf("failed to parse intermediate bundle: %v", err)
		return nil, errors.New(errors.IntermediatesError, errors.ParseFailed)
	}

	b := &Bundler{
		KnownIssuers:     map[string]bool{},
		IntermediatePool: x509.NewCertPool(),
	}

	log.Debug("building certificate pools")

	// RootPool will be nil if caBundlePEM is nil, also
	// that translates to caBundleFile is "".
	// Systems root store will be used.
	if caBundlePEM != nil {
		b.RootPool = x509.NewCertPool()
	}

	for _, c := range roots {
		b.RootPool.AddCert(c)
		b.KnownIssuers[string(c.Signature)] = true
	}

	for _, c := range intermediates {
		b.IntermediatePool.AddCert(c)
		b.KnownIssuers[string(c.Signature)] = true
	}

	log.Debug("bundler set up")
	return b, nil
}
// TrustPEM takes a source file containing one or more certificates
// and adds them to the trust store.
func TrustPEM(metadata map[string]string) ([]*x509.Certificate, error) {
	sourceFile, ok := metadata["source"]
	if !ok {
		return nil, errors.New("transport: PEM source requires a source file")
	}

	in, err := ioutil.ReadFile(sourceFile)
	if err != nil {
		return nil, err
	}

	return helpers.ParseCertificatesPEM(in)
}
Example #10
0
func TestNewRootCANonDefaultExpiry(t *testing.T) {
	tempBaseDir, err := ioutil.TempDir("", "swarm-ca-test-")
	assert.NoError(t, err)
	defer os.RemoveAll(tempBaseDir)

	paths := ca.NewConfigPaths(tempBaseDir)

	rootCA, err := ca.CreateAndWriteRootCA("rootCN", paths.RootCA)
	assert.NoError(t, err)

	newRootCA, err := ca.NewRootCA(rootCA.Cert, rootCA.Key, 1*time.Hour)
	assert.NoError(t, err)

	// Create and sign a new CSR
	csr, _, err := ca.GenerateAndWriteNewKey(paths.Node)
	assert.NoError(t, err)
	cert, err := newRootCA.ParseValidateAndSignCSR(csr, "CN", ca.ManagerRole, "ORG")
	assert.NoError(t, err)

	parsedCerts, err := helpers.ParseCertificatesPEM(cert)
	assert.NoError(t, err)
	assert.Len(t, parsedCerts, 2)
	assert.True(t, time.Now().Add(time.Minute*59).Before(parsedCerts[0].NotAfter))
	assert.True(t, time.Now().Add(time.Hour).Add(time.Minute).After(parsedCerts[0].NotAfter))

	// Sign the same CSR again, this time with a 59 Minute expiration RootCA (under the 60 minute minimum).
	// This should use the default of 3 months
	newRootCA, err = ca.NewRootCA(rootCA.Cert, rootCA.Key, 59*time.Minute)
	assert.NoError(t, err)

	cert, err = newRootCA.ParseValidateAndSignCSR(csr, "CN", ca.ManagerRole, "ORG")
	assert.NoError(t, err)

	parsedCerts, err = helpers.ParseCertificatesPEM(cert)
	assert.NoError(t, err)
	assert.Len(t, parsedCerts, 2)
	assert.True(t, time.Now().Add(ca.DefaultNodeCertExpiration).AddDate(0, 0, -1).Before(parsedCerts[0].NotAfter))
	assert.True(t, time.Now().Add(ca.DefaultNodeCertExpiration).AddDate(0, 0, 1).After(parsedCerts[0].NotAfter))
}
Example #11
0
func TestNewRootCABundle(t *testing.T) {
	tempBaseDir, err := ioutil.TempDir("", "swarm-ca-test-")
	assert.NoError(t, err)
	defer os.RemoveAll(tempBaseDir)

	paths := ca.NewConfigPaths(tempBaseDir)

	// Write one root CA to disk, keep the bytes
	secondRootCA, err := ca.CreateAndWriteRootCA("rootCN2", paths.RootCA)
	assert.NoError(t, err)

	// Overwrite the first root CA on disk
	firstRootCA, err := ca.CreateAndWriteRootCA("rootCN1", paths.RootCA)
	assert.NoError(t, err)

	// Overwrite the bytes of the second Root CA with the bundle, creating a valid 2 cert bundle
	bundle := append(firstRootCA.Cert, secondRootCA.Cert...)
	err = ioutil.WriteFile(paths.RootCA.Cert, bundle, 0644)
	assert.NoError(t, err)

	newRootCA, err := ca.NewRootCA(bundle, firstRootCA.Key, ca.DefaultNodeCertExpiration)
	assert.NoError(t, err)
	assert.Equal(t, bundle, newRootCA.Cert)
	assert.Equal(t, 2, len(newRootCA.Pool.Subjects()))

	// Now load the bundle from disk
	diskRootCA, err := ca.GetLocalRootCA(tempBaseDir)
	assert.NoError(t, err)
	assert.Equal(t, bundle, diskRootCA.Cert)
	assert.Equal(t, 2, len(diskRootCA.Pool.Subjects()))

	// If I use GenerateAndSignNewTLSCert to sign certs, I'll get the correct CA in the chain
	_, err = ca.GenerateAndSignNewTLSCert(diskRootCA, "CN", "OU", "ORG", paths.Node)
	assert.NoError(t, err)

	certBytes, err := ioutil.ReadFile(paths.Node.Cert)
	assert.NoError(t, err)
	certs, err := helpers.ParseCertificatesPEM(certBytes)
	assert.NoError(t, err)
	assert.Len(t, certs, 2)
	assert.Equal(t, "CN", certs[0].Subject.CommonName)
	assert.Equal(t, "OU", certs[0].Subject.OrganizationalUnit[0])
	assert.Equal(t, "ORG", certs[0].Subject.Organization[0])
	assert.Equal(t, "rootCN1", certs[1].Subject.CommonName)

}
Example #12
0
func TestNewRootCABundle(t *testing.T) {
	tempBaseDir, err := ioutil.TempDir("", "swarm-ca-test-")
	assert.NoError(t, err)
	defer os.RemoveAll(tempBaseDir)

	paths := ca.NewConfigPaths(tempBaseDir)

	// make one rootCA
	secondRootCA, err := ca.CreateRootCA("rootCN2", paths.RootCA)
	assert.NoError(t, err)

	// make a second root CA
	firstRootCA, err := ca.CreateRootCA("rootCN1", paths.RootCA)
	assert.NoError(t, err)

	// Overwrite the bytes of the second Root CA with the bundle, creating a valid 2 cert bundle
	bundle := append(firstRootCA.Cert, secondRootCA.Cert...)
	err = ioutil.WriteFile(paths.RootCA.Cert, bundle, 0644)
	assert.NoError(t, err)

	newRootCA, err := ca.NewRootCA(bundle, firstRootCA.Key, ca.DefaultNodeCertExpiration)
	assert.NoError(t, err)
	assert.Equal(t, bundle, newRootCA.Cert)
	assert.Equal(t, 2, len(newRootCA.Pool.Subjects()))

	// If I use newRootCA's IssueAndSaveNewCertificates to sign certs, I'll get the correct CA in the chain
	kw := ca.NewKeyReadWriter(paths.Node, nil, nil)
	_, err = newRootCA.IssueAndSaveNewCertificates(kw, "CN", "OU", "ORG")
	assert.NoError(t, err)

	certBytes, err := ioutil.ReadFile(paths.Node.Cert)
	assert.NoError(t, err)
	certs, err := helpers.ParseCertificatesPEM(certBytes)
	assert.NoError(t, err)
	assert.Len(t, certs, 2)
	assert.Equal(t, "CN", certs[0].Subject.CommonName)
	assert.Equal(t, "OU", certs[0].Subject.OrganizationalUnit[0])
	assert.Equal(t, "ORG", certs[0].Subject.Organization[0])
	assert.Equal(t, "rootCN1", certs[1].Subject.CommonName)

}
Example #13
0
func TestParseValidateAndSignMaliciousCSR(t *testing.T) {
	tempBaseDir, err := ioutil.TempDir("", "swarm-ca-test-")
	assert.NoError(t, err)
	defer os.RemoveAll(tempBaseDir)

	paths := ca.NewConfigPaths(tempBaseDir)

	rootCA, err := ca.CreateAndWriteRootCA("rootCN", paths.RootCA)
	assert.NoError(t, err)

	req := &cfcsr.CertificateRequest{
		Names: []cfcsr.Name{
			{
				O:  "maliciousOrg",
				OU: "maliciousOU",
				L:  "maliciousLocality",
			},
		},
		CN:         "maliciousCN",
		Hosts:      []string{"docker.com"},
		KeyRequest: &cfcsr.BasicKeyRequest{A: "ecdsa", S: 256},
	}

	csr, _, err := cfcsr.ParseRequest(req)
	assert.NoError(t, err)

	signedCert, err := rootCA.ParseValidateAndSignCSR(csr, "CN", "OU", "ORG")
	assert.NoError(t, err)
	assert.NotNil(t, signedCert)

	parsedCert, err := helpers.ParseCertificatesPEM(signedCert)
	assert.NoError(t, err)
	assert.Equal(t, 2, len(parsedCert))
	assert.Equal(t, "CN", parsedCert[0].Subject.CommonName)
	assert.Equal(t, 1, len(parsedCert[0].Subject.OrganizationalUnit))
	assert.Equal(t, "OU", parsedCert[0].Subject.OrganizationalUnit[0])
	assert.Equal(t, 3, len(parsedCert[0].Subject.Names))
	assert.Empty(t, parsedCert[0].Subject.Locality)
	assert.Equal(t, "ORG", parsedCert[0].Subject.Organization[0])
	assert.Equal(t, "rootCN", parsedCert[1].Subject.CommonName)
}
// NewCFSSL produces a new CFSSL root.
func NewCFSSL(metadata map[string]string) ([]*x509.Certificate, error) {
	host, ok := metadata["host"]
	if !ok {
		return nil, errors.New("transport: CFSSL root provider requires a host")
	}

	label := metadata["label"]
	profile := metadata["profile"]

	srv := client.NewServer(host)
	data, err := json.Marshal(info.Req{Label: label, Profile: profile})
	if err != nil {
		return nil, err
	}

	resp, err := srv.Info(data)
	if err != nil {
		return nil, err
	}

	return helpers.ParseCertificatesPEM([]byte(resp.Certificate))
}
Example #15
0
// newCustomizedBundleCreator is a helper function that returns a new Bundler
// takes specified CA bundle, intermediate bundle, and any additional intermdiate certs  to generate a bundler.
func newCustomizedBundlerFromFile(t *testing.T, caBundle, intBundle, adhocInters string) (b *Bundler) {
	b, err := NewBundler(caBundle, intBundle)
	if err != nil {
		t.Fatal(err)
	}
	if adhocInters != "" {
		moreIntersPEM, err := ioutil.ReadFile(adhocInters)
		if err != nil {
			t.Fatal("Read additional intermediates failed. %s", err.Error())
		}
		intermediates, err := helpers.ParseCertificatesPEM(moreIntersPEM)
		if err != nil {
			t.Fatalf("Parsing additional intermediates failed. %s", err.Error())
		}
		for _, c := range intermediates {
			b.IntermediatePool.AddCert(c)
		}

	}
	return

}
Example #16
0
func TestIssueAndSaveNewCertificates(t *testing.T) {
	tc := testutils.NewTestCA(t)
	defer tc.Stop()

	// Copy the current RootCA without the signer
	cert, err := tc.RootCA.IssueAndSaveNewCertificates(tc.Paths.Node, "CN", ca.ManagerRole, tc.Organization)
	assert.NoError(t, err)
	assert.NotNil(t, cert)
	perms, err := permbits.Stat(tc.Paths.Node.Cert)
	assert.NoError(t, err)
	assert.False(t, perms.GroupWrite())
	assert.False(t, perms.OtherWrite())

	certBytes, err := ioutil.ReadFile(tc.Paths.Node.Cert)
	assert.NoError(t, err)
	certs, err := helpers.ParseCertificatesPEM(certBytes)
	assert.NoError(t, err)
	assert.Len(t, certs, 2)
	assert.Equal(t, "CN", certs[0].Subject.CommonName)
	assert.Equal(t, ca.ManagerRole, certs[0].Subject.OrganizationalUnit[0])
	assert.Equal(t, tc.Organization, certs[0].Subject.Organization[0])
	assert.Equal(t, "swarm-test-CA", certs[1].Subject.CommonName)
}
Example #17
0
// BundleFromPEMorDER builds a certificate bundle from the set of byte
// slices containing the PEM or DER-encoded certificate(s), private key.
func (b *Bundler) BundleFromPEMorDER(certsRaw, keyPEM []byte, flavor BundleFlavor, password string) (*Bundle, error) {
	log.Debug("bundling from PEM files")
	var key crypto.Signer
	var err error
	if len(keyPEM) != 0 {
		key, err = helpers.ParsePrivateKeyPEM(keyPEM)
		if err != nil {
			log.Debugf("failed to parse private key: %v", err)
			return nil, err
		}
	}

	certs, err := helpers.ParseCertificatesPEM(certsRaw)
	if err != nil {
		// If PEM doesn't work try DER
		var keyDER crypto.Signer
		var errDER error
		certs, keyDER, errDER = helpers.ParseCertificatesDER(certsRaw, password)
		// Only use DER key if no key read from file
		if key == nil && keyDER != nil {
			key = keyDER
		}
		if errDER != nil {
			log.Debugf("failed to parse certificates: %v", err)
			// If neither parser works pass along PEM error
			return nil, err
		}

	}
	if len(certs) == 0 {
		log.Debugf("no certificates found")
		return nil, errors.New(errors.CertificateError, errors.DecodeFailed)
	}

	log.Debugf("bundle ready")
	return b.Bundle(certs, key, flavor)
}
Example #18
0
// BundleFromPEM builds a certificate bundle from the set of byte
// slices containing the PEM-encoded certificate(s), private key.
func (b *Bundler) BundleFromPEM(certsPEM, keyPEM []byte, flavor BundleFlavor) (*Bundle, error) {
	log.Debug("bundling from PEM files")
	var key interface{}
	var err error
	if len(keyPEM) != 0 {
		key, err = helpers.ParsePrivateKeyPEM(keyPEM)
		log.Debugf("failed to parse private key: %v", err)
		if err != nil {
			return nil, err
		}
	}

	certs, err := helpers.ParseCertificatesPEM(certsPEM)
	if err != nil {
		log.Debugf("failed to parse certificates: %v", err)
		return nil, err
	} else if len(certs) == 0 {
		log.Debugf("no certificates found")
		return nil, errors.New(errors.CertificateError, errors.DecodeFailed, nil)
	}

	log.Debugf("bundle ready")
	return b.Bundle(certs, key, flavor)
}
Example #19
0
func displayAllCerts(in []byte, leafOnly bool) {
	certs, err := helpers.ParseCertificatesPEM(in)
	if err != nil {
		certs, _, err = helpers.ParseCertificatesDER(in, "")
		if err != nil {
			Warn(TranslateCFSSLError(err), "failed to parse certificates")
			return
		}
	}

	if len(certs) == 0 {
		Warnx("no certificates found")
		return
	}

	if leafOnly {
		displayCert(certs[0])
		return
	}

	for i := range certs {
		displayCert(certs[i])
	}
}
Example #20
0
// NewRootCA creates a new RootCA object from unparsed PEM cert bundle and key byte
// slices. key may be nil, and in this case NewRootCA will return a RootCA
// without a signer.
func NewRootCA(certBytes, keyBytes []byte, certExpiry time.Duration) (RootCA, error) {
	// Parse all the certificates in the cert bundle
	parsedCerts, err := helpers.ParseCertificatesPEM(certBytes)
	if err != nil {
		return RootCA{}, err
	}
	// Check to see if we have at least one valid cert
	if len(parsedCerts) < 1 {
		return RootCA{}, fmt.Errorf("no valid Root CA certificates found")
	}

	// Create a Pool with all of the certificates found
	pool := x509.NewCertPool()
	for _, cert := range parsedCerts {
		// Check to see if all of the certificates are valid, self-signed root CA certs
		if err := cert.CheckSignature(cert.SignatureAlgorithm, cert.RawTBSCertificate, cert.Signature); err != nil {
			return RootCA{}, fmt.Errorf("error while validating Root CA Certificate: %v", err)
		}
		pool.AddCert(cert)
	}

	// Calculate the digest for our Root CA bundle
	digest := digest.FromBytes(certBytes)

	if len(keyBytes) == 0 {
		// This RootCA does not have a valid signer.
		return RootCA{Cert: certBytes, Digest: digest, Pool: pool}, nil
	}

	var (
		passphraseStr              string
		passphrase, passphrasePrev []byte
		priv                       crypto.Signer
	)

	// Attempt two distinct passphrases, so we can do a hitless passphrase rotation
	if passphraseStr = os.Getenv(PassphraseENVVar); passphraseStr != "" {
		passphrase = []byte(passphraseStr)
	}

	if p := os.Getenv(PassphraseENVVarPrev); p != "" {
		passphrasePrev = []byte(p)
	}

	// Attempt to decrypt the current private-key with the passphrases provided
	priv, err = helpers.ParsePrivateKeyPEMWithPassword(keyBytes, passphrase)
	if err != nil {
		priv, err = helpers.ParsePrivateKeyPEMWithPassword(keyBytes, passphrasePrev)
		if err != nil {
			log.Debug("Malformed private key %v", err)
			return RootCA{}, err
		}
	}

	// We will always use the first certificate inside of the root bundle as the active one
	if err := ensureCertKeyMatch(parsedCerts[0], priv.Public()); err != nil {
		return RootCA{}, err
	}

	signer, err := local.NewSigner(priv, parsedCerts[0], cfsigner.DefaultSigAlgo(priv), SigningPolicy(certExpiry))
	if err != nil {
		return RootCA{}, err
	}

	// If the key was loaded from disk unencrypted, but there is a passphrase set,
	// ensure it is encrypted, so it doesn't hit raft in plain-text
	keyBlock, _ := pem.Decode(keyBytes)
	if keyBlock == nil {
		// This RootCA does not have a valid signer.
		return RootCA{Cert: certBytes, Digest: digest, Pool: pool}, nil
	}
	if passphraseStr != "" && !x509.IsEncryptedPEMBlock(keyBlock) {
		keyBytes, err = EncryptECPrivateKey(keyBytes, passphraseStr)
		if err != nil {
			return RootCA{}, err
		}
	}

	return RootCA{Signer: signer, Key: keyBytes, Digest: digest, Cert: certBytes, Pool: pool}, nil
}
Example #21
0
// RunAPITests runs a test suite based on on API Input and returns an API Result.
func RunAPITests(in *testapi.Input, c *client.Client, testLen time.Duration, workers int) (*testapi.Results, error) {
	log.Debugf("Testing %s", in.Keyserver)
	var err error
	var certs []*x509.Certificate

	if len(in.CertsPEM) > 0 {
		log.Debug("Parsing certificate PEM")
		certs, err = helpers.ParseCertificatesPEM([]byte(in.CertsPEM))
		if err != nil {
			log.Warning("Couldn't parse certificate PEM")
			return nil, err
		}
	}

	var sni string
	if in.Domain != "" {
		log.Debugf("Getting certificate from %s", in.Domain)
		if cert, err := getCertFromDomain(in.Domain); err == nil {
			certs = append(certs, cert)
		} else {
			log.Warningf("Couldn't get certificate from %s: %v", in.Domain, err)
		}

		if sni, _, err = net.SplitHostPort(in.Domain); err != nil {
			sni = in.Domain
		}
	}

	c.Config.InsecureSkipVerify = in.InsecureSkipVerify
	serverIP := net.ParseIP(in.ServerIP)

	if newTestLen, err := time.ParseDuration(in.TestLen); err == nil {
		if newTestLen > 0 && newTestLen < 30*time.Second {
			testLen = newTestLen
		}
	}

	if newWorkers, err := strconv.Atoi(in.Workers); err == nil {
		if newWorkers > 0 && newWorkers < 1024 {
			workers = newWorkers
		}
	}

	results := testapi.NewResults()

	if len(in.HashedToken) > 0 {
		results.RegisterTest("activate", NewActivateTest(c, in.Keyserver, in.HashedToken))
	}

	results.RegisterTest("ping", NewPingTest(c, in.Keyserver))

	for _, cert := range certs {
		priv, err := c.RegisterPublicKeyTemplate(in.Keyserver, cert.PublicKey, sni, serverIP)
		if err != nil {
			return nil, err
		}

		ski, err := gokeyless.GetSKICert(cert)
		if err != nil {
			return nil, err
		}

		if _, ok := priv.Public().(*rsa.PublicKey); ok {
			results.RegisterTest(ski.String()+"."+"decrypt", NewDecryptTest(priv))
		}

		for name, test := range NewSignTests(priv) {
			results.RegisterTest(ski.String()+"."+name, test)
		}
	}

	results.RunTests(testLen, workers)

	return results, nil
}
Example #22
0
func TestForceNewCluster(t *testing.T) {
	t.Parallel()

	// create an external CA so that we can use it to generate expired certificates
	tempDir, err := ioutil.TempDir("", "external-ca")
	require.NoError(t, err)
	defer os.RemoveAll(tempDir)
	rootCA, err := ca.CreateRootCA("externalRoot", ca.NewConfigPaths(tempDir).RootCA)
	require.NoError(t, err)

	// start a new cluster with the external CA bootstrapped
	numWorker, numManager := 0, 1
	cl := newTestCluster()
	defer func() {
		require.NoError(t, cl.Stop())
	}()
	require.NoError(t, cl.AddManager(false, &rootCA), "manager number 1")
	pollClusterReady(t, cl, numWorker, numManager)

	leader, err := cl.Leader()
	require.NoError(t, err)

	sid, err := cl.CreateService("test_service", 2)
	require.NoError(t, err)
	pollServiceReady(t, cl, sid)

	// generate an expired certificate
	rootKey, err := helpers.ParsePrivateKeyPEM(rootCA.Key)
	require.NoError(t, err)
	rootCert, err := helpers.ParseCertificatePEM(rootCA.Cert)
	require.NoError(t, err)

	managerCertFile := filepath.Join(leader.stateDir, "certificates", "swarm-node.crt")
	certBytes, err := ioutil.ReadFile(managerCertFile)
	require.NoError(t, err)
	managerCerts, err := helpers.ParseCertificatesPEM(certBytes)
	require.NoError(t, err)
	expiredCertTemplate := managerCerts[0]
	expiredCertTemplate.NotBefore = time.Now().Add(time.Hour * -5)
	expiredCertTemplate.NotAfter = time.Now().Add(time.Hour * -3)
	expiredCertDERBytes, err := x509.CreateCertificate(rand.Reader, expiredCertTemplate, rootCert, expiredCertTemplate.PublicKey, rootKey)
	require.NoError(t, err)
	expiredCertPEM := pem.EncodeToMemory(&pem.Block{
		Type:  "CERTIFICATE",
		Bytes: expiredCertDERBytes,
	})

	// restart node with an expired certificate while forcing a new cluster - it should start without error and the certificate should be renewed
	nodeID := leader.node.NodeID()
	require.NoError(t, leader.Pause(true))
	require.NoError(t, ioutil.WriteFile(managerCertFile, expiredCertPEM, 0644))
	require.NoError(t, cl.StartNode(nodeID))
	pollClusterReady(t, cl, numWorker, numManager)
	pollServiceReady(t, cl, sid)

	err = raftutils.PollFuncWithTimeout(nil, func() error {
		certBytes, err := ioutil.ReadFile(managerCertFile)
		if err != nil {
			return err
		}
		managerCerts, err := helpers.ParseCertificatesPEM(certBytes)
		if err != nil {
			return err
		}
		if managerCerts[0].NotAfter.Before(time.Now()) {
			return errors.New("certificate hasn't been renewed yet")
		}
		return nil
	}, opsTimeout)
	require.NoError(t, err)

	// restart node with an expired certificate without forcing a new cluster - it should error on start
	require.NoError(t, leader.Pause(true))
	require.NoError(t, ioutil.WriteFile(managerCertFile, expiredCertPEM, 0644))
	require.Error(t, cl.StartNode(nodeID))
}
Example #23
0
func TestGetRemoteCA(t *testing.T) {
	tc := testutils.NewTestCA(t)
	defer tc.Stop()

	shaHash := sha256.New()
	shaHash.Write(tc.RootCA.Cert)
	md := shaHash.Sum(nil)
	mdStr := hex.EncodeToString(md)

	d, err := digest.Parse("sha256:" + mdStr)
	require.NoError(t, err)

	downloadedRootCA, err := ca.GetRemoteCA(tc.Context, d, tc.ConnBroker)
	require.NoError(t, err)
	require.Equal(t, downloadedRootCA.Cert, tc.RootCA.Cert)

	// update the test CA to include a multi-certificate bundle as the root - the digest
	// we use to verify with must be the digest of the whole bundle
	tmpDir, err := ioutil.TempDir("", "GetRemoteCA")
	require.NoError(t, err)
	defer os.RemoveAll(tmpDir)
	paths := ca.NewConfigPaths(tmpDir)

	otherRootCA, err := ca.CreateRootCA("other", paths.RootCA)
	require.NoError(t, err)

	comboCertBundle := append(tc.RootCA.Cert, otherRootCA.Cert...)
	require.NoError(t, tc.MemoryStore.Update(func(tx store.Tx) error {
		cluster := store.GetCluster(tx, tc.Organization)
		cluster.RootCA.CACert = comboCertBundle
		cluster.RootCA.CAKey = tc.RootCA.Key
		return store.UpdateCluster(tx, cluster)
	}))
	require.NoError(t, raftutils.PollFunc(nil, func() error {
		_, err := ca.GetRemoteCA(tc.Context, d, tc.ConnBroker)
		if err == nil {
			return fmt.Errorf("testca's rootca hasn't updated yet")
		}
		require.Contains(t, err.Error(), "remote CA does not match fingerprint")
		return nil
	}))

	// If we provide the right digest, the root CA is updated and we can validate
	// certs signed by either one
	d = digest.FromBytes(comboCertBundle)
	downloadedRootCA, err = ca.GetRemoteCA(tc.Context, d, tc.ConnBroker)
	require.NoError(t, err)
	require.Equal(t, comboCertBundle, downloadedRootCA.Cert)
	require.Equal(t, 2, len(downloadedRootCA.Pool.Subjects()))

	for _, rootCA := range []ca.RootCA{tc.RootCA, otherRootCA} {
		krw := ca.NewKeyReadWriter(paths.Node, nil, nil)
		_, err := rootCA.IssueAndSaveNewCertificates(krw, "cn", "ou", "org")
		require.NoError(t, err)

		certPEM, _, err := krw.Read()
		require.NoError(t, err)

		cert, err := helpers.ParseCertificatesPEM(certPEM)
		require.NoError(t, err)

		chains, err := cert[0].Verify(x509.VerifyOptions{
			Roots: downloadedRootCA.Pool,
		})
		require.NoError(t, err)
		require.Len(t, chains, 1)
	}
}
Example #24
0
func main() {
	var caFile, intFile string
	var forceIntermediateBundle, revexp, verbose bool
	flag.StringVar(&caFile, "ca", "", "CA certificate `bundle`")
	flag.StringVar(&intFile, "i", "", "intermediate `bundle`")
	flag.BoolVar(&forceIntermediateBundle, "f", false,
		"force the use of the intermediate bundle, ignoring any intermediates bundled with certificate")
	flag.BoolVar(&revexp, "r", false, "print revocation and expiry information")
	flag.BoolVar(&verbose, "v", false, "verbose")
	flag.Parse()

	var roots *x509.CertPool
	if caFile != "" {
		var err error
		if verbose {
			fmt.Println("[+] loading root certificates from", caFile)
		}
		roots, err = helpers.LoadPEMCertPool(caFile)
		die.If(err)
	}

	var ints *x509.CertPool
	if intFile != "" {
		var err error
		if verbose {
			fmt.Println("[+] loading intermediate certificates from", intFile)
		}
		ints, err = helpers.LoadPEMCertPool(caFile)
		die.If(err)
	} else {
		ints = x509.NewCertPool()
	}

	if flag.NArg() != 1 {
		fmt.Fprintf(os.Stderr, "Usage: %s [-ca bundle] [-i bundle] cert",
			lib.ProgName())
	}

	fileData, err := ioutil.ReadFile(flag.Arg(0))
	die.If(err)

	chain, err := helpers.ParseCertificatesPEM(fileData)
	die.If(err)
	if verbose {
		fmt.Printf("[+] %s has %d certificates\n", flag.Arg(0), len(chain))
	}

	cert := chain[0]
	if len(chain) > 1 {
		if !forceIntermediateBundle {
			for _, intermediate := range chain[1:] {
				if verbose {
					fmt.Printf("[+] adding intermediate with SKI %x\n", intermediate.SubjectKeyId)
				}

				ints.AddCert(intermediate)
			}
		}
	}

	opts := x509.VerifyOptions{
		Intermediates: ints,
		Roots:         roots,
		KeyUsages:     []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
	}

	_, err = cert.Verify(opts)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Verification failed: %v\n", err)
		os.Exit(1)
	}

	if verbose {
		fmt.Println("OK")
	}

	if revexp {
		printRevocation(cert)
	}
}
func TestCreateCertificateChain(t *testing.T) {

	// N is the number of certificates that will be chained together.
	N := 10

	// --- TEST: Create a chain of one certificate. --- //

	encodedChainFromCode, _, err := CreateCertificateChain([]csr.CertificateRequest{CARequest})
	checkError(err, t)

	// Now compare to a pre-made certificate chain using a JSON file containing
	// the same request data.

	CLIOutputFile := preMadeOutput
	CLIOutput, err := ioutil.ReadFile(CLIOutputFile)
	checkError(err, t)
	encodedChainFromCLI, err := cleanCLIOutput(CLIOutput, "cert")
	checkError(err, t)

	chainFromCode, err := helpers.ParseCertificatesPEM(encodedChainFromCode)
	checkError(err, t)
	chainFromCLI, err := helpers.ParseCertificatesPEM(encodedChainFromCLI)
	checkError(err, t)

	if !chainsEqual(chainFromCode, chainFromCLI) {
		unequalFieldSlices := checkFieldsOfChains(chainFromCode, chainFromCLI)
		for i, unequalFields := range unequalFieldSlices {
			if len(unequalFields) > 0 {
				t.Log("The certificate chains held unequal fields for chain " + strconv.Itoa(i))
				t.Log("The following fields were unequal:")
				for _, field := range unequalFields {
					t.Log("\t" + field)
				}
			}
		}
		t.Fatal("Certificate chains unequal.")
	}

	// --- TEST: Create a chain of N certificates. --- //

	// First we make a slice of N requests. We make each slightly different.

	cnGrabBag := []string{"example", "invalid", "test"}
	topLevelDomains := []string{".com", ".net", ".org"}
	subDomains := []string{"www.", "secure.", "ca.", ""}
	countryGrabBag := []string{"USA", "China", "England", "Vanuatu"}
	stateGrabBag := []string{"California", "Texas", "Alaska", "London"}
	localityGrabBag := []string{"San Francisco", "Houston", "London", "Oslo"}
	orgGrabBag := []string{"Internet Widgets, LLC", "CloudFlare, Inc."}
	orgUnitGrabBag := []string{"Certificate Authority", "Systems Engineering"}

	requests := make([]csr.CertificateRequest, N)
	requests[0] = CARequest
	for i := 1; i < N; i++ {
		requests[i] = baseRequest

		cn := randomElement(cnGrabBag)
		tld := randomElement(topLevelDomains)
		subDomain1 := randomElement(subDomains)
		subDomain2 := randomElement(subDomains)
		country := randomElement(countryGrabBag)
		state := randomElement(stateGrabBag)
		locality := randomElement(localityGrabBag)
		org := randomElement(orgGrabBag)
		orgUnit := randomElement(orgUnitGrabBag)

		requests[i].CN = cn + "." + tld
		requests[i].Names = []csr.Name{
			{C: country,
				ST: state,
				L:  locality,
				O:  org,
				OU: orgUnit,
			},
		}
		hosts := []string{subDomain1 + requests[i].CN}
		if subDomain2 != subDomain1 {
			hosts = append(hosts, subDomain2+requests[i].CN)
		}
		requests[i].Hosts = hosts
	}

	// Now we make a certificate chain out of these requests.
	encodedCertChain, _, err := CreateCertificateChain(requests)
	checkError(err, t)

	// To test this chain, we compare the data encoded in each certificate to
	// each request we used to generate the chain.
	chain, err := helpers.ParseCertificatesPEM(encodedCertChain)
	checkError(err, t)

	if len(chain) != len(requests) {
		t.Log("Length of chain: " + strconv.Itoa(len(chain)))
		t.Log("Length of requests: " + strconv.Itoa(len(requests)))
		t.Fatal("Length of chain not equal to length of requests.")
	}

	mismatchOccurred := false
	for i := 0; i < len(chain); i++ {
		certEqualsRequest, unequalFields := certEqualsRequest(chain[i], requests[i])
		if !certEqualsRequest {
			mismatchOccurred = true
			t.Log(
				"Certificate " + strconv.Itoa(i) + " and request " +
					strconv.Itoa(i) + " unequal.",
			)
			t.Log("Unequal fields for index " + strconv.Itoa(i) + ":")
			for _, field := range unequalFields {
				t.Log("\t" + field)
			}
		}
	}

	// TODO: check that each certificate is actually signed by the previous one

	if mismatchOccurred {
		t.Fatal("Unequal certificate(s) and request(s) found.")
	}

	// --- TEST: Create a chain of certificates with invalid path lengths. --- //

	// Other invalid chains?
}