github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/swarmkit/ca/certificates_test.go (about)

     1  package ca_test
     2  
     3  import (
     4  	"context"
     5  	"crypto/ecdsa"
     6  	"crypto/elliptic"
     7  	cryptorand "crypto/rand"
     8  	"crypto/sha256"
     9  	"crypto/tls"
    10  	"crypto/x509"
    11  	"encoding/hex"
    12  	"encoding/pem"
    13  	"fmt"
    14  	"io/ioutil"
    15  	"net"
    16  	"os"
    17  	"sync"
    18  	"sync/atomic"
    19  	"testing"
    20  	"time"
    21  
    22  	"google.golang.org/grpc"
    23  	"google.golang.org/grpc/codes"
    24  
    25  	cfcsr "github.com/cloudflare/cfssl/csr"
    26  	"github.com/cloudflare/cfssl/helpers"
    27  	"github.com/cloudflare/cfssl/initca"
    28  	"github.com/docker/go-events"
    29  	"github.com/docker/swarmkit/api"
    30  	"github.com/docker/swarmkit/ca"
    31  	cautils "github.com/docker/swarmkit/ca/testutils"
    32  	"github.com/docker/swarmkit/connectionbroker"
    33  	"github.com/docker/swarmkit/identity"
    34  	"github.com/docker/swarmkit/manager/state"
    35  	"github.com/docker/swarmkit/manager/state/store"
    36  	"github.com/docker/swarmkit/remotes"
    37  	"github.com/docker/swarmkit/testutils"
    38  	"github.com/opencontainers/go-digest"
    39  	"github.com/phayes/permbits"
    40  	"github.com/stretchr/testify/assert"
    41  	"github.com/stretchr/testify/require"
    42  	"google.golang.org/grpc/status"
    43  )
    44  
    45  func init() {
    46  	ca.RenewTLSExponentialBackoff = events.ExponentialBackoffConfig{
    47  		Base:   250 * time.Millisecond,
    48  		Factor: 250 * time.Millisecond,
    49  		Max:    1 * time.Hour,
    50  	}
    51  	ca.GetCertRetryInterval = 50 * time.Millisecond
    52  }
    53  
    54  func checkLeafCert(t *testing.T, certBytes []byte, issuerName, cn, ou, org string, additionalDNSNames ...string) []*x509.Certificate {
    55  	certs, err := helpers.ParseCertificatesPEM(certBytes)
    56  	require.NoError(t, err)
    57  	require.NotEmpty(t, certs)
    58  	require.Equal(t, issuerName, certs[0].Issuer.CommonName)
    59  	require.Equal(t, cn, certs[0].Subject.CommonName)
    60  	require.Equal(t, []string{ou}, certs[0].Subject.OrganizationalUnit)
    61  	require.Equal(t, []string{org}, certs[0].Subject.Organization)
    62  
    63  	require.Len(t, certs[0].DNSNames, len(additionalDNSNames)+2)
    64  	for _, dnsName := range append(additionalDNSNames, cn, ou) {
    65  		require.Contains(t, certs[0].DNSNames, dnsName)
    66  	}
    67  	return certs
    68  }
    69  
    70  // TestMain runs every test in this file twice - once with a local CA and
    71  // again with an external CA server.
    72  func TestMain(m *testing.M) {
    73  	if status := m.Run(); status != 0 {
    74  		os.Exit(status)
    75  	}
    76  
    77  	cautils.External = true
    78  	os.Exit(m.Run())
    79  }
    80  
    81  func TestCreateRootCASaveRootCA(t *testing.T) {
    82  	tempBaseDir, err := ioutil.TempDir("", "swarm-ca-test-")
    83  	assert.NoError(t, err)
    84  	defer os.RemoveAll(tempBaseDir)
    85  
    86  	paths := ca.NewConfigPaths(tempBaseDir)
    87  
    88  	rootCA, err := ca.CreateRootCA("rootCN")
    89  	assert.NoError(t, err)
    90  
    91  	err = ca.SaveRootCA(rootCA, paths.RootCA)
    92  	assert.NoError(t, err)
    93  
    94  	perms, err := permbits.Stat(paths.RootCA.Cert)
    95  	assert.NoError(t, err)
    96  	assert.False(t, perms.GroupWrite())
    97  	assert.False(t, perms.OtherWrite())
    98  
    99  	_, err = permbits.Stat(paths.RootCA.Key)
   100  	assert.True(t, os.IsNotExist(err))
   101  
   102  	// ensure that the cert that was written is already normalized
   103  	written, err := ioutil.ReadFile(paths.RootCA.Cert)
   104  	assert.NoError(t, err)
   105  	assert.Equal(t, written, ca.NormalizePEMs(written))
   106  }
   107  
   108  func TestCreateRootCAExpiry(t *testing.T) {
   109  	rootCA, err := ca.CreateRootCA("rootCN")
   110  	assert.NoError(t, err)
   111  
   112  	// Convert the certificate into an object to create a RootCA
   113  	parsedCert, err := helpers.ParseCertificatePEM(rootCA.Certs)
   114  	assert.NoError(t, err)
   115  	duration, err := time.ParseDuration(ca.RootCAExpiration)
   116  	assert.NoError(t, err)
   117  	assert.True(t, time.Now().Add(duration).AddDate(0, -1, 0).Before(parsedCert.NotAfter))
   118  }
   119  
   120  func TestGetLocalRootCA(t *testing.T) {
   121  	tempBaseDir, err := ioutil.TempDir("", "swarm-ca-test-")
   122  	assert.NoError(t, err)
   123  	defer os.RemoveAll(tempBaseDir)
   124  
   125  	paths := ca.NewConfigPaths(tempBaseDir)
   126  
   127  	// First, try to load the local Root CA with the certificate missing.
   128  	_, err = ca.GetLocalRootCA(paths.RootCA)
   129  	assert.Equal(t, ca.ErrNoLocalRootCA, err)
   130  
   131  	// Create the local Root CA to ensure that we can reload it correctly.
   132  	rootCA, err := ca.CreateRootCA("rootCN")
   133  	assert.NoError(t, err)
   134  	s, err := rootCA.Signer()
   135  	assert.NoError(t, err)
   136  	err = ca.SaveRootCA(rootCA, paths.RootCA)
   137  	assert.NoError(t, err)
   138  
   139  	// No private key here
   140  	rootCA2, err := ca.GetLocalRootCA(paths.RootCA)
   141  	assert.NoError(t, err)
   142  	assert.Equal(t, rootCA.Certs, rootCA2.Certs)
   143  	_, err = rootCA2.Signer()
   144  	assert.Equal(t, err, ca.ErrNoValidSigner)
   145  
   146  	// write private key and assert we can load it and sign
   147  	assert.NoError(t, ioutil.WriteFile(paths.RootCA.Key, s.Key, os.FileMode(0600)))
   148  	rootCA3, err := ca.GetLocalRootCA(paths.RootCA)
   149  	assert.NoError(t, err)
   150  	assert.Equal(t, rootCA.Certs, rootCA3.Certs)
   151  	_, err = rootCA3.Signer()
   152  	assert.NoError(t, err)
   153  
   154  	// Try with a private key that does not match the CA cert public key.
   155  	privKey, err := ecdsa.GenerateKey(elliptic.P256(), cryptorand.Reader)
   156  	assert.NoError(t, err)
   157  	privKeyBytes, err := x509.MarshalECPrivateKey(privKey)
   158  	assert.NoError(t, err)
   159  	privKeyPem := pem.EncodeToMemory(&pem.Block{
   160  		Type:  "EC PRIVATE KEY",
   161  		Bytes: privKeyBytes,
   162  	})
   163  	assert.NoError(t, ioutil.WriteFile(paths.RootCA.Key, privKeyPem, os.FileMode(0600)))
   164  
   165  	_, err = ca.GetLocalRootCA(paths.RootCA)
   166  	assert.EqualError(t, err, "certificate key mismatch")
   167  }
   168  
   169  func TestGetLocalRootCAInvalidCert(t *testing.T) {
   170  	tempBaseDir, err := ioutil.TempDir("", "swarm-ca-test-")
   171  	assert.NoError(t, err)
   172  	defer os.RemoveAll(tempBaseDir)
   173  
   174  	paths := ca.NewConfigPaths(tempBaseDir)
   175  
   176  	// Write some garbage to the CA cert
   177  	require.NoError(t, ioutil.WriteFile(paths.RootCA.Cert, []byte(`-----BEGIN CERTIFICATE-----\n
   178  some random garbage\n
   179  -----END CERTIFICATE-----`), 0644))
   180  
   181  	_, err = ca.GetLocalRootCA(paths.RootCA)
   182  	require.Error(t, err)
   183  }
   184  
   185  func TestGetLocalRootCAInvalidKey(t *testing.T) {
   186  	tempBaseDir, err := ioutil.TempDir("", "swarm-ca-test-")
   187  	assert.NoError(t, err)
   188  	defer os.RemoveAll(tempBaseDir)
   189  
   190  	paths := ca.NewConfigPaths(tempBaseDir)
   191  	// Create the local Root CA to ensure that we can reload it correctly.
   192  	rootCA, err := ca.CreateRootCA("rootCN")
   193  	require.NoError(t, err)
   194  	require.NoError(t, ca.SaveRootCA(rootCA, paths.RootCA))
   195  
   196  	// Write some garbage to the root key - this will cause the loading to fail
   197  	require.NoError(t, ioutil.WriteFile(paths.RootCA.Key, []byte(`-----BEGIN PRIVATE KEY-----\n
   198  some random garbage\n
   199  -----END PRIVATE KEY-----`), 0600))
   200  
   201  	_, err = ca.GetLocalRootCA(paths.RootCA)
   202  	require.Error(t, err)
   203  }
   204  
   205  func TestParseValidateAndSignCSR(t *testing.T) {
   206  	rootCA, err := ca.CreateRootCA("rootCN")
   207  	assert.NoError(t, err)
   208  
   209  	csr, _, err := ca.GenerateNewCSR()
   210  	assert.NoError(t, err)
   211  
   212  	signedCert, err := rootCA.ParseValidateAndSignCSR(csr, "CN", "OU", "ORG")
   213  	assert.NoError(t, err)
   214  	assert.NotNil(t, signedCert)
   215  
   216  	assert.Len(t, checkLeafCert(t, signedCert, "rootCN", "CN", "OU", "ORG"), 1)
   217  }
   218  
   219  func TestParseValidateAndSignMaliciousCSR(t *testing.T) {
   220  	rootCA, err := ca.CreateRootCA("rootCN")
   221  	assert.NoError(t, err)
   222  
   223  	req := &cfcsr.CertificateRequest{
   224  		Names: []cfcsr.Name{
   225  			{
   226  				O:  "maliciousOrg",
   227  				OU: "maliciousOU",
   228  				L:  "maliciousLocality",
   229  			},
   230  		},
   231  		CN:         "maliciousCN",
   232  		Hosts:      []string{"docker.com"},
   233  		KeyRequest: &cfcsr.BasicKeyRequest{A: "ecdsa", S: 256},
   234  	}
   235  
   236  	csr, _, err := cfcsr.ParseRequest(req)
   237  	assert.NoError(t, err)
   238  
   239  	signedCert, err := rootCA.ParseValidateAndSignCSR(csr, "CN", "OU", "ORG")
   240  	assert.NoError(t, err)
   241  	assert.NotNil(t, signedCert)
   242  
   243  	assert.Len(t, checkLeafCert(t, signedCert, "rootCN", "CN", "OU", "ORG"), 1)
   244  }
   245  
   246  func TestGetRemoteCA(t *testing.T) {
   247  	tc := cautils.NewTestCA(t)
   248  	defer tc.Stop()
   249  
   250  	shaHash := sha256.New()
   251  	shaHash.Write(tc.RootCA.Certs)
   252  	md := shaHash.Sum(nil)
   253  	mdStr := hex.EncodeToString(md)
   254  
   255  	d, err := digest.Parse("sha256:" + mdStr)
   256  	require.NoError(t, err)
   257  
   258  	downloadedRootCA, err := ca.GetRemoteCA(tc.Context, d, tc.ConnBroker)
   259  	require.NoError(t, err)
   260  	require.Equal(t, downloadedRootCA.Certs, tc.RootCA.Certs)
   261  
   262  	// update the test CA to include a multi-certificate bundle as the root - the digest
   263  	// we use to verify with must be the digest of the whole bundle
   264  	tmpDir, err := ioutil.TempDir("", "GetRemoteCA")
   265  	require.NoError(t, err)
   266  	defer os.RemoveAll(tmpDir)
   267  	paths := ca.NewConfigPaths(tmpDir)
   268  	otherRootCA, err := ca.CreateRootCA("other")
   269  	require.NoError(t, err)
   270  
   271  	comboCertBundle := append(tc.RootCA.Certs, otherRootCA.Certs...)
   272  	s, err := tc.RootCA.Signer()
   273  	require.NoError(t, err)
   274  	require.NoError(t, tc.MemoryStore.Update(func(tx store.Tx) error {
   275  		cluster := store.GetCluster(tx, tc.Organization)
   276  		cluster.RootCA.CACert = comboCertBundle
   277  		cluster.RootCA.CAKey = s.Key
   278  		return store.UpdateCluster(tx, cluster)
   279  	}))
   280  	require.NoError(t, testutils.PollFunc(nil, func() error {
   281  		_, err := ca.GetRemoteCA(tc.Context, d, tc.ConnBroker)
   282  		if err == nil {
   283  			return fmt.Errorf("testca's rootca hasn't updated yet")
   284  		}
   285  		require.Contains(t, err.Error(), "remote CA does not match fingerprint")
   286  		return nil
   287  	}))
   288  
   289  	// If we provide the right digest, the root CA is updated and we can validate
   290  	// certs signed by either one
   291  	d = digest.FromBytes(comboCertBundle)
   292  	downloadedRootCA, err = ca.GetRemoteCA(tc.Context, d, tc.ConnBroker)
   293  	require.NoError(t, err)
   294  	require.Equal(t, comboCertBundle, downloadedRootCA.Certs)
   295  	require.Equal(t, 2, len(downloadedRootCA.Pool.Subjects()))
   296  
   297  	for _, rootCA := range []ca.RootCA{tc.RootCA, otherRootCA} {
   298  		krw := ca.NewKeyReadWriter(paths.Node, nil, nil)
   299  		_, _, err := rootCA.IssueAndSaveNewCertificates(krw, "cn", "ou", "org")
   300  		require.NoError(t, err)
   301  
   302  		certPEM, _, err := krw.Read()
   303  		require.NoError(t, err)
   304  
   305  		cert, err := helpers.ParseCertificatesPEM(certPEM)
   306  		require.NoError(t, err)
   307  
   308  		chains, err := cert[0].Verify(x509.VerifyOptions{
   309  			Roots: downloadedRootCA.Pool,
   310  		})
   311  		require.NoError(t, err)
   312  		require.Len(t, chains, 1)
   313  	}
   314  }
   315  
   316  func TestGetRemoteCAInvalidHash(t *testing.T) {
   317  	tc := cautils.NewTestCA(t)
   318  	defer tc.Stop()
   319  
   320  	_, err := ca.GetRemoteCA(tc.Context, "sha256:2d2f968475269f0dde5299427cf74348ee1d6115b95c6e3f283e5a4de8da445b", tc.ConnBroker)
   321  	assert.Error(t, err)
   322  }
   323  
   324  // returns the issuer as well as all the parsed certs returned from the request
   325  func testRequestAndSaveNewCertificates(t *testing.T, tc *cautils.TestCA) (*ca.IssuerInfo, []*x509.Certificate) {
   326  	// Copy the current RootCA without the signer
   327  	rca := ca.RootCA{Certs: tc.RootCA.Certs, Pool: tc.RootCA.Pool}
   328  	tlsCert, issuerInfo, err := rca.RequestAndSaveNewCertificates(tc.Context, tc.KeyReadWriter,
   329  		ca.CertificateRequestConfig{
   330  			Token:      tc.ManagerToken,
   331  			ConnBroker: tc.ConnBroker,
   332  		})
   333  	require.NoError(t, err)
   334  	require.NotNil(t, tlsCert)
   335  	require.NotNil(t, issuerInfo)
   336  	perms, err := permbits.Stat(tc.Paths.Node.Cert)
   337  	require.NoError(t, err)
   338  	require.False(t, perms.GroupWrite())
   339  	require.False(t, perms.OtherWrite())
   340  
   341  	certs, err := ioutil.ReadFile(tc.Paths.Node.Cert)
   342  	require.NoError(t, err)
   343  	require.Equal(t, certs, ca.NormalizePEMs(certs))
   344  
   345  	// ensure that the same number of certs was written
   346  	parsedCerts, err := helpers.ParseCertificatesPEM(certs)
   347  	require.NoError(t, err)
   348  	return issuerInfo, parsedCerts
   349  }
   350  
   351  func TestRequestAndSaveNewCertificatesNoIntermediate(t *testing.T) {
   352  	t.Parallel()
   353  
   354  	tc := cautils.NewTestCA(t)
   355  	defer tc.Stop()
   356  	issuerInfo, parsedCerts := testRequestAndSaveNewCertificates(t, tc)
   357  	require.Len(t, parsedCerts, 1)
   358  
   359  	root, err := helpers.ParseCertificatePEM(tc.RootCA.Certs)
   360  	require.NoError(t, err)
   361  	require.Equal(t, root.RawSubject, issuerInfo.Subject)
   362  }
   363  
   364  func TestRequestAndSaveNewCertificatesWithIntermediates(t *testing.T) {
   365  	t.Parallel()
   366  
   367  	// use a RootCA with an intermediate
   368  	apiRootCA := api.RootCA{
   369  		CACert: cautils.ECDSACertChain[2],
   370  		CAKey:  cautils.ECDSACertChainKeys[2],
   371  		RootRotation: &api.RootRotation{
   372  			CACert:            cautils.ECDSACertChain[1],
   373  			CAKey:             cautils.ECDSACertChainKeys[1],
   374  			CrossSignedCACert: concat([]byte("   "), cautils.ECDSACertChain[1]),
   375  		},
   376  	}
   377  	tempdir, err := ioutil.TempDir("", "test-request-and-save-new-certificates")
   378  	require.NoError(t, err)
   379  	defer os.RemoveAll(tempdir)
   380  
   381  	tc := cautils.NewTestCAFromAPIRootCA(t, tempdir, apiRootCA, nil)
   382  	defer tc.Stop()
   383  	issuerInfo, parsedCerts := testRequestAndSaveNewCertificates(t, tc)
   384  	require.Len(t, parsedCerts, 2)
   385  
   386  	intermediate, err := helpers.ParseCertificatePEM(tc.RootCA.Intermediates)
   387  	require.NoError(t, err)
   388  	require.Equal(t, intermediate, parsedCerts[1])
   389  	require.Equal(t, intermediate.RawSubject, issuerInfo.Subject)
   390  	require.Equal(t, intermediate.RawSubjectPublicKeyInfo, issuerInfo.PublicKey)
   391  }
   392  
   393  func TestRequestAndSaveNewCertificatesWithKEKUpdate(t *testing.T) {
   394  	t.Parallel()
   395  
   396  	tc := cautils.NewTestCA(t)
   397  	defer tc.Stop()
   398  
   399  	// Copy the current RootCA without the signer
   400  	rca := ca.RootCA{Certs: tc.RootCA.Certs, Pool: tc.RootCA.Pool}
   401  
   402  	unencryptedKeyReader := ca.NewKeyReadWriter(tc.Paths.Node, nil, nil)
   403  
   404  	// key for the manager and worker are both unencrypted
   405  	for _, token := range []string{tc.ManagerToken, tc.WorkerToken} {
   406  		_, _, err := rca.RequestAndSaveNewCertificates(tc.Context, tc.KeyReadWriter,
   407  			ca.CertificateRequestConfig{
   408  				Token:      token,
   409  				ConnBroker: tc.ConnBroker,
   410  			})
   411  		require.NoError(t, err)
   412  
   413  		// there was no encryption config in the remote, so the key should be unencrypted
   414  		_, _, err = unencryptedKeyReader.Read()
   415  		require.NoError(t, err)
   416  	}
   417  
   418  	// If there is a different kek in the remote store, when TLS certs are renewed the new key will
   419  	// be encrypted with that kek
   420  	require.NoError(t, tc.MemoryStore.Update(func(tx store.Tx) error {
   421  		cluster := store.GetCluster(tx, tc.Organization)
   422  		cluster.Spec.EncryptionConfig.AutoLockManagers = true
   423  		cluster.UnlockKeys = []*api.EncryptionKey{{
   424  			Subsystem: ca.ManagerRole,
   425  			Key:       []byte("kek!"),
   426  		}}
   427  		return store.UpdateCluster(tx, cluster)
   428  	}))
   429  	require.NoError(t, os.RemoveAll(tc.Paths.Node.Cert))
   430  	require.NoError(t, os.RemoveAll(tc.Paths.Node.Key))
   431  
   432  	// key for the manager will be encrypted, but certs for the worker will not be
   433  	for _, token := range []string{tc.ManagerToken, tc.WorkerToken} {
   434  		_, _, err := rca.RequestAndSaveNewCertificates(tc.Context, tc.KeyReadWriter,
   435  			ca.CertificateRequestConfig{
   436  				Token:      token,
   437  				ConnBroker: tc.ConnBroker,
   438  			})
   439  		require.NoError(t, err)
   440  
   441  		// there was no encryption config in the remote, so the key should be unencrypted
   442  		_, _, err = unencryptedKeyReader.Read()
   443  
   444  		if token == tc.ManagerToken {
   445  			require.Error(t, err)
   446  			_, _, err = ca.NewKeyReadWriter(tc.Paths.Node, []byte("kek!"), nil).Read()
   447  			require.NoError(t, err)
   448  		} else {
   449  			require.NoError(t, err)
   450  		}
   451  	}
   452  }
   453  
   454  // returns the issuer of the issued certificate and the parsed certs of the issued certificate
   455  func testIssueAndSaveNewCertificates(t *testing.T, rca *ca.RootCA) {
   456  	tempdir, err := ioutil.TempDir("", "test-issue-and-save-new-certificates")
   457  	require.NoError(t, err)
   458  	defer os.RemoveAll(tempdir)
   459  	paths := ca.NewConfigPaths(tempdir)
   460  	krw := ca.NewKeyReadWriter(paths.Node, nil, nil)
   461  
   462  	var issuer *x509.Certificate
   463  	if len(rca.Intermediates) > 0 {
   464  		issuer, err = helpers.ParseCertificatePEM(rca.Intermediates)
   465  		require.NoError(t, err)
   466  	} else {
   467  		issuer, err = helpers.ParseCertificatePEM(rca.Certs)
   468  		require.NoError(t, err)
   469  	}
   470  
   471  	// Test the creation of a manager and worker certificate
   472  	for _, role := range []string{ca.ManagerRole, ca.WorkerRole} {
   473  		var additionalNames []string
   474  		if role == ca.ManagerRole {
   475  			additionalNames = []string{ca.CARole}
   476  		}
   477  
   478  		cert, issuerInfo, err := rca.IssueAndSaveNewCertificates(krw, "CN", role, "org")
   479  		require.NoError(t, err)
   480  		require.NotNil(t, cert)
   481  		require.Equal(t, issuer.RawSubjectPublicKeyInfo, issuerInfo.PublicKey)
   482  		require.Equal(t, issuer.RawSubject, issuerInfo.Subject)
   483  		perms, err := permbits.Stat(paths.Node.Cert)
   484  		require.NoError(t, err)
   485  		require.False(t, perms.GroupWrite())
   486  		require.False(t, perms.OtherWrite())
   487  
   488  		certBytes, err := ioutil.ReadFile(paths.Node.Cert)
   489  		require.NoError(t, err)
   490  		parsed := checkLeafCert(t, certBytes, issuer.Subject.CommonName, "CN", role, "org", additionalNames...)
   491  		if len(rca.Intermediates) > 0 {
   492  			require.Len(t, parsed, 2)
   493  			require.Equal(t, parsed[1], issuer)
   494  		} else {
   495  			require.Len(t, parsed, 1)
   496  		}
   497  	}
   498  }
   499  
   500  func TestIssueAndSaveNewCertificatesNoIntermediates(t *testing.T) {
   501  	if cautils.External {
   502  		return // this does not use the test CA at all
   503  	}
   504  	rca, err := ca.CreateRootCA("rootCN")
   505  	require.NoError(t, err)
   506  	testIssueAndSaveNewCertificates(t, &rca)
   507  }
   508  
   509  func TestIssueAndSaveNewCertificatesWithIntermediates(t *testing.T) {
   510  	if cautils.External {
   511  		return // this does not use the test CA at all
   512  	}
   513  	rca, err := ca.NewRootCA(cautils.ECDSACertChain[2], cautils.ECDSACertChain[1], cautils.ECDSACertChainKeys[1],
   514  		ca.DefaultNodeCertExpiration, cautils.ECDSACertChain[1])
   515  	require.NoError(t, err)
   516  	testIssueAndSaveNewCertificates(t, &rca)
   517  }
   518  
   519  func TestGetRemoteSignedCertificate(t *testing.T) {
   520  	tc := cautils.NewTestCA(t)
   521  	defer tc.Stop()
   522  
   523  	// Create a new CSR to be signed
   524  	csr, _, err := ca.GenerateNewCSR()
   525  	assert.NoError(t, err)
   526  
   527  	certs, err := ca.GetRemoteSignedCertificate(tc.Context, csr, tc.RootCA.Pool,
   528  		ca.CertificateRequestConfig{
   529  			Token:      tc.ManagerToken,
   530  			ConnBroker: tc.ConnBroker,
   531  		})
   532  	assert.NoError(t, err)
   533  	assert.NotNil(t, certs)
   534  
   535  	// Test the expiration for a manager certificate
   536  	parsedCerts, err := helpers.ParseCertificatesPEM(certs)
   537  	assert.NoError(t, err)
   538  	assert.Len(t, parsedCerts, 1)
   539  	assert.True(t, time.Now().Add(ca.DefaultNodeCertExpiration).AddDate(0, 0, -1).Before(parsedCerts[0].NotAfter))
   540  	assert.True(t, time.Now().Add(ca.DefaultNodeCertExpiration).AddDate(0, 0, 1).After(parsedCerts[0].NotAfter))
   541  	assert.Equal(t, parsedCerts[0].Subject.OrganizationalUnit[0], ca.ManagerRole)
   542  
   543  	// Test the expiration for an worker certificate
   544  	certs, err = ca.GetRemoteSignedCertificate(tc.Context, csr, tc.RootCA.Pool,
   545  		ca.CertificateRequestConfig{
   546  			Token:      tc.WorkerToken,
   547  			ConnBroker: tc.ConnBroker,
   548  		})
   549  	assert.NoError(t, err)
   550  	assert.NotNil(t, certs)
   551  	parsedCerts, err = helpers.ParseCertificatesPEM(certs)
   552  	assert.NoError(t, err)
   553  	assert.Len(t, parsedCerts, 1)
   554  	assert.True(t, time.Now().Add(ca.DefaultNodeCertExpiration).AddDate(0, 0, -1).Before(parsedCerts[0].NotAfter))
   555  	assert.True(t, time.Now().Add(ca.DefaultNodeCertExpiration).AddDate(0, 0, 1).After(parsedCerts[0].NotAfter))
   556  	assert.Equal(t, parsedCerts[0].Subject.OrganizationalUnit[0], ca.WorkerRole)
   557  }
   558  
   559  func TestGetRemoteSignedCertificateNodeInfo(t *testing.T) {
   560  	tc := cautils.NewTestCA(t)
   561  	defer tc.Stop()
   562  
   563  	// Create a new CSR to be signed
   564  	csr, _, err := ca.GenerateNewCSR()
   565  	assert.NoError(t, err)
   566  
   567  	cert, err := ca.GetRemoteSignedCertificate(tc.Context, csr, tc.RootCA.Pool,
   568  		ca.CertificateRequestConfig{
   569  			Token:      tc.WorkerToken,
   570  			ConnBroker: tc.ConnBroker,
   571  		})
   572  	assert.NoError(t, err)
   573  	assert.NotNil(t, cert)
   574  }
   575  
   576  // A CA Server implementation that doesn't actually sign anything - something else
   577  // will have to update the memory store to have a valid value for a node
   578  type nonSigningCAServer struct {
   579  	tc               *cautils.TestCA
   580  	server           *grpc.Server
   581  	addr             string
   582  	nodeStatusCalled int64
   583  }
   584  
   585  func newNonSigningCAServer(t *testing.T, tc *cautils.TestCA) *nonSigningCAServer {
   586  	secConfig, err := tc.NewNodeConfig(ca.ManagerRole)
   587  	require.NoError(t, err)
   588  	serverOpts := []grpc.ServerOption{grpc.Creds(secConfig.ServerTLSCreds)}
   589  	grpcServer := grpc.NewServer(serverOpts...)
   590  	l, err := net.Listen("tcp", "127.0.0.1:0")
   591  	require.NoError(t, err)
   592  
   593  	n := &nonSigningCAServer{
   594  		tc:     tc,
   595  		addr:   l.Addr().String(),
   596  		server: grpcServer,
   597  	}
   598  
   599  	api.RegisterNodeCAServer(grpcServer, n)
   600  	go grpcServer.Serve(l)
   601  	return n
   602  }
   603  
   604  func (n *nonSigningCAServer) stop(t *testing.T) {
   605  	n.server.Stop()
   606  }
   607  
   608  func (n *nonSigningCAServer) getConnBroker() *connectionbroker.Broker {
   609  	return connectionbroker.New(remotes.NewRemotes(api.Peer{Addr: n.addr}))
   610  }
   611  
   612  // only returns the status in the store
   613  func (n *nonSigningCAServer) NodeCertificateStatus(ctx context.Context, request *api.NodeCertificateStatusRequest) (*api.NodeCertificateStatusResponse, error) {
   614  	atomic.AddInt64(&n.nodeStatusCalled, 1)
   615  	for {
   616  		var node *api.Node
   617  		n.tc.MemoryStore.View(func(tx store.ReadTx) {
   618  			node = store.GetNode(tx, request.NodeID)
   619  		})
   620  		if node != nil && node.Certificate.Status.State == api.IssuanceStateIssued {
   621  			return &api.NodeCertificateStatusResponse{
   622  				Status:      &node.Certificate.Status,
   623  				Certificate: &node.Certificate,
   624  			}, nil
   625  		}
   626  		select {
   627  		case <-ctx.Done():
   628  			return nil, ctx.Err()
   629  		case <-time.After(500 * time.Millisecond):
   630  		}
   631  	}
   632  }
   633  
   634  func (n *nonSigningCAServer) IssueNodeCertificate(ctx context.Context, request *api.IssueNodeCertificateRequest) (*api.IssueNodeCertificateResponse, error) {
   635  	nodeID := identity.NewID()
   636  	role := api.NodeRoleWorker
   637  	if n.tc.ManagerToken == request.Token {
   638  		role = api.NodeRoleManager
   639  	}
   640  
   641  	// Create a new node
   642  	err := n.tc.MemoryStore.Update(func(tx store.Tx) error {
   643  		node := &api.Node{
   644  			Role: role,
   645  			ID:   nodeID,
   646  			Certificate: api.Certificate{
   647  				CSR:  request.CSR,
   648  				CN:   nodeID,
   649  				Role: role,
   650  				Status: api.IssuanceStatus{
   651  					State: api.IssuanceStatePending,
   652  				},
   653  			},
   654  			Spec: api.NodeSpec{
   655  				DesiredRole:  role,
   656  				Membership:   api.NodeMembershipAccepted,
   657  				Availability: request.Availability,
   658  			},
   659  		}
   660  
   661  		return store.CreateNode(tx, node)
   662  	})
   663  	if err != nil {
   664  		return nil, err
   665  	}
   666  	return &api.IssueNodeCertificateResponse{
   667  		NodeID:         nodeID,
   668  		NodeMembership: api.NodeMembershipAccepted,
   669  	}, nil
   670  }
   671  
   672  func TestGetRemoteSignedCertificateWithPending(t *testing.T) {
   673  	t.Parallel()
   674  	if cautils.External {
   675  		// we don't actually need an external signing server, since we're faking a CA server which doesn't really sign
   676  		return
   677  	}
   678  
   679  	tc := cautils.NewTestCA(t)
   680  	defer tc.Stop()
   681  	require.NoError(t, tc.CAServer.Stop())
   682  
   683  	// Create a new CSR to be signed
   684  	csr, _, err := ca.GenerateNewCSR()
   685  	require.NoError(t, err)
   686  
   687  	updates, cancel := state.Watch(tc.MemoryStore.WatchQueue(), api.EventCreateNode{})
   688  	defer cancel()
   689  
   690  	fakeCAServer := newNonSigningCAServer(t, tc)
   691  	defer fakeCAServer.stop(t)
   692  
   693  	completed := make(chan error)
   694  	defer close(completed)
   695  	go func() {
   696  		_, err := ca.GetRemoteSignedCertificate(tc.Context, csr, tc.RootCA.Pool,
   697  			ca.CertificateRequestConfig{
   698  				Token:      tc.WorkerToken,
   699  				ConnBroker: fakeCAServer.getConnBroker(),
   700  				// ensure the RPC call to get state is cancelled after 500 milliseconds
   701  				NodeCertificateStatusRequestTimeout: 500 * time.Millisecond,
   702  			})
   703  		completed <- err
   704  	}()
   705  
   706  	var node *api.Node
   707  	// wait for a new node to show up
   708  	for node == nil {
   709  		event := <-updates // we want to skip the first node, which is the test CA
   710  		n := event.(api.EventCreateNode).Node.Copy()
   711  		if n.Certificate.Status.State == api.IssuanceStatePending {
   712  			node = n
   713  		}
   714  	}
   715  
   716  	// wait for the calls to NodeCertificateStatus to begin on the first signing server before we start timing
   717  	require.NoError(t, testutils.PollFuncWithTimeout(nil, func() error {
   718  		if atomic.LoadInt64(&fakeCAServer.nodeStatusCalled) == 0 {
   719  			return fmt.Errorf("waiting for NodeCertificateStatus to be called")
   720  		}
   721  		return nil
   722  	}, time.Second*2))
   723  
   724  	// wait for 2.5 seconds and ensure that GetRemoteSignedCertificate has not returned with an error yet -
   725  	// the first attempt to get the certificate status should have timed out after 500 milliseconds, but
   726  	// it should have tried to poll again.  Add a few seconds for fudge time to make sure it's actually
   727  	// still polling.
   728  	select {
   729  	case <-completed:
   730  		require.FailNow(t, "GetRemoteSignedCertificate should wait at least 500 milliseconds")
   731  	case <-time.After(2500 * time.Millisecond):
   732  		// good, it's still polling so we can proceed with the test
   733  	}
   734  	require.True(t, atomic.LoadInt64(&fakeCAServer.nodeStatusCalled) > 1, "expected NodeCertificateStatus to have been polled more than once")
   735  
   736  	// Directly update the status of the store
   737  	err = tc.MemoryStore.Update(func(tx store.Tx) error {
   738  		node.Certificate.Status.State = api.IssuanceStateIssued
   739  		return store.UpdateNode(tx, node)
   740  	})
   741  	require.NoError(t, err)
   742  
   743  	// Make sure GetRemoteSignedCertificate didn't return an error
   744  	require.NoError(t, <-completed)
   745  
   746  	// make sure if we time out the GetRemoteSignedCertificate call, it cancels immediately and doesn't keep
   747  	// polling the status
   748  	go func() {
   749  		ctx, cancel := context.WithTimeout(tc.Context, 1*time.Second)
   750  		defer cancel()
   751  		_, err := ca.GetRemoteSignedCertificate(ctx, csr, tc.RootCA.Pool,
   752  			ca.CertificateRequestConfig{
   753  				Token:      tc.WorkerToken,
   754  				ConnBroker: fakeCAServer.getConnBroker(),
   755  			})
   756  		completed <- err
   757  	}()
   758  
   759  	// wait for 3 seconds and ensure that GetRemoteSignedCertificate has returned with a context DeadlineExceeded
   760  	// error - it should have returned after 1 second, but add some more for rudge time.
   761  	select {
   762  	case err = <-completed:
   763  		s, _ := status.FromError(err)
   764  		require.Equal(t, s.Code(), codes.DeadlineExceeded)
   765  	case <-time.After(3 * time.Second):
   766  		require.FailNow(t, "GetRemoteSignedCertificate should have been canceled after 1 second, and it has been 3")
   767  	}
   768  }
   769  
   770  // fake remotes interface that just selects the remotes in order
   771  type fakeRemotes struct {
   772  	mu    sync.Mutex
   773  	peers []api.Peer
   774  }
   775  
   776  func (f *fakeRemotes) Weights() map[api.Peer]int {
   777  	panic("this is not called")
   778  }
   779  
   780  func (f *fakeRemotes) Select(...string) (api.Peer, error) {
   781  	f.mu.Lock()
   782  	defer f.mu.Unlock()
   783  	if len(f.peers) > 0 {
   784  		return f.peers[0], nil
   785  	}
   786  	return api.Peer{}, fmt.Errorf("no more peers")
   787  }
   788  
   789  func (f *fakeRemotes) Observe(peer api.Peer, weight int) {
   790  	panic("this is not called")
   791  }
   792  
   793  // just removes a peer if the weight is negative
   794  func (f *fakeRemotes) ObserveIfExists(peer api.Peer, weight int) {
   795  	f.mu.Lock()
   796  	defer f.mu.Unlock()
   797  	if weight < 0 {
   798  		var newPeers []api.Peer
   799  		for _, p := range f.peers {
   800  			if p != peer {
   801  				newPeers = append(newPeers, p)
   802  			}
   803  		}
   804  		f.peers = newPeers
   805  	}
   806  }
   807  
   808  func (f *fakeRemotes) Remove(addrs ...api.Peer) {
   809  	panic("this is not called")
   810  }
   811  
   812  var _ remotes.Remotes = &fakeRemotes{}
   813  
   814  // On connection errors, so long as they happen after IssueNodeCertificate is successful, GetRemoteSignedCertificate
   815  // tries to open a new connection and continue polling for NodeCertificateStatus.  If there are no more connections,
   816  // then fail.
   817  func TestGetRemoteSignedCertificateConnectionErrors(t *testing.T) {
   818  	t.Parallel()
   819  	if cautils.External {
   820  		// we don't actually need an external signing server, since we're faking a CA server which doesn't really sign
   821  		return
   822  	}
   823  
   824  	tc := cautils.NewTestCA(t)
   825  	defer tc.Stop()
   826  	require.NoError(t, tc.CAServer.Stop())
   827  
   828  	// Create a new CSR to be signed
   829  	csr, _, err := ca.GenerateNewCSR()
   830  	require.NoError(t, err)
   831  
   832  	// create 2 CA servers referencing the same memory store, so we can have multiple connections
   833  	fakeSigningServers := []*nonSigningCAServer{newNonSigningCAServer(t, tc), newNonSigningCAServer(t, tc)}
   834  	defer fakeSigningServers[0].stop(t)
   835  	defer fakeSigningServers[1].stop(t)
   836  	multiBroker := connectionbroker.New(&fakeRemotes{
   837  		peers: []api.Peer{
   838  			{Addr: fakeSigningServers[0].addr},
   839  			{Addr: fakeSigningServers[1].addr},
   840  		},
   841  	})
   842  
   843  	completed, done := make(chan error), make(chan struct{})
   844  	defer close(completed)
   845  	defer close(done)
   846  	go func() {
   847  		_, err := ca.GetRemoteSignedCertificate(tc.Context, csr, tc.RootCA.Pool,
   848  			ca.CertificateRequestConfig{
   849  				Token:      tc.WorkerToken,
   850  				ConnBroker: multiBroker,
   851  			})
   852  		select {
   853  		case <-done:
   854  		case completed <- err:
   855  		}
   856  	}()
   857  
   858  	// wait for the calls to NodeCertificateStatus to begin on the first signing server
   859  	require.NoError(t, testutils.PollFuncWithTimeout(nil, func() error {
   860  		if atomic.LoadInt64(&fakeSigningServers[0].nodeStatusCalled) == 0 {
   861  			return fmt.Errorf("waiting for NodeCertificateStatus to be called")
   862  		}
   863  		return nil
   864  	}, time.Second*2))
   865  
   866  	// stop 1 server, because it will have been the remote GetRemoteSignedCertificate first connected to, and ensure
   867  	// that GetRemoteSignedCertificate is still going
   868  	fakeSigningServers[0].stop(t)
   869  	select {
   870  	case <-completed:
   871  		require.FailNow(t, "GetRemoteSignedCertificate should still be going after 2.5 seconds")
   872  	case <-time.After(2500 * time.Millisecond):
   873  		// good, it's still polling so we can proceed with the test
   874  	}
   875  
   876  	// wait for the calls to NodeCertificateStatus to begin on the second signing server
   877  	require.NoError(t, testutils.PollFuncWithTimeout(nil, func() error {
   878  		if atomic.LoadInt64(&fakeSigningServers[1].nodeStatusCalled) == 0 {
   879  			return fmt.Errorf("waiting for NodeCertificateStatus to be called")
   880  		}
   881  		return nil
   882  	}, time.Second*2))
   883  
   884  	// kill the last server - this should cause GetRemoteSignedCertificate to fail because there are no more peers
   885  	fakeSigningServers[1].stop(t)
   886  	// wait for 5 seconds and ensure that GetRemoteSignedCertificate has returned with an error.
   887  	select {
   888  	case err = <-completed:
   889  		require.Contains(t, err.Error(), "no more peers")
   890  	case <-time.After(5 * time.Second):
   891  		require.FailNow(t, "GetRemoteSignedCertificate should errored after 5 seconds")
   892  	}
   893  
   894  	// calling GetRemoteSignedCertificate with a connection that doesn't work with IssueNodeCertificate will fail
   895  	// immediately without retrying with a new connection
   896  	fakeSigningServers[1] = newNonSigningCAServer(t, tc)
   897  	defer fakeSigningServers[1].stop(t)
   898  	multiBroker = connectionbroker.New(&fakeRemotes{
   899  		peers: []api.Peer{
   900  			{Addr: fakeSigningServers[0].addr},
   901  			{Addr: fakeSigningServers[1].addr},
   902  		},
   903  	})
   904  	_, err = ca.GetRemoteSignedCertificate(tc.Context, csr, tc.RootCA.Pool,
   905  		ca.CertificateRequestConfig{
   906  			Token:      tc.WorkerToken,
   907  			ConnBroker: multiBroker,
   908  		})
   909  	require.Error(t, err)
   910  }
   911  
   912  func TestNewRootCA(t *testing.T) {
   913  	for _, pair := range []struct{ cert, key []byte }{
   914  		{cert: cautils.ECDSA256SHA256Cert, key: cautils.ECDSA256Key},
   915  		{cert: cautils.RSA2048SHA256Cert, key: cautils.RSA2048Key},
   916  	} {
   917  		rootCA, err := ca.NewRootCA(pair.cert, pair.cert, pair.key, ca.DefaultNodeCertExpiration, nil)
   918  		require.NoError(t, err, string(pair.key))
   919  		require.Equal(t, pair.cert, rootCA.Certs)
   920  		s, err := rootCA.Signer()
   921  		require.NoError(t, err)
   922  		require.Equal(t, pair.key, s.Key)
   923  		_, err = rootCA.Digest.Verifier().Write(pair.cert)
   924  		require.NoError(t, err)
   925  	}
   926  }
   927  
   928  func TestNewRootCABundle(t *testing.T) {
   929  	tempBaseDir, err := ioutil.TempDir("", "swarm-ca-test-")
   930  	assert.NoError(t, err)
   931  	defer os.RemoveAll(tempBaseDir)
   932  
   933  	paths := ca.NewConfigPaths(tempBaseDir)
   934  
   935  	// make one rootCA
   936  	firstRootCA, err := ca.CreateRootCA("rootCN1")
   937  	assert.NoError(t, err)
   938  
   939  	// make a second root CA
   940  	secondRootCA, err := ca.CreateRootCA("rootCN2")
   941  	assert.NoError(t, err)
   942  	s, err := firstRootCA.Signer()
   943  	require.NoError(t, err)
   944  
   945  	// Overwrite the bytes of the second Root CA with the bundle, creating a valid 2 cert bundle
   946  	bundle := append(firstRootCA.Certs, secondRootCA.Certs...)
   947  	err = ioutil.WriteFile(paths.RootCA.Cert, bundle, 0644)
   948  	assert.NoError(t, err)
   949  
   950  	newRootCA, err := ca.NewRootCA(bundle, firstRootCA.Certs, s.Key, ca.DefaultNodeCertExpiration, nil)
   951  	assert.NoError(t, err)
   952  	assert.Equal(t, bundle, newRootCA.Certs)
   953  	assert.Equal(t, 2, len(newRootCA.Pool.Subjects()))
   954  
   955  	// If I use newRootCA's IssueAndSaveNewCertificates to sign certs, I'll get the correct CA in the chain
   956  	kw := ca.NewKeyReadWriter(paths.Node, nil, nil)
   957  	_, _, err = newRootCA.IssueAndSaveNewCertificates(kw, "CN", "OU", "ORG")
   958  	assert.NoError(t, err)
   959  
   960  	certBytes, err := ioutil.ReadFile(paths.Node.Cert)
   961  	assert.NoError(t, err)
   962  	assert.Len(t, checkLeafCert(t, certBytes, "rootCN1", "CN", "OU", "ORG"), 1)
   963  }
   964  
   965  func TestNewRootCANonDefaultExpiry(t *testing.T) {
   966  	rootCA, err := ca.CreateRootCA("rootCN")
   967  	assert.NoError(t, err)
   968  	s, err := rootCA.Signer()
   969  	require.NoError(t, err)
   970  
   971  	newRootCA, err := ca.NewRootCA(rootCA.Certs, rootCA.Certs, s.Key, 1*time.Hour, nil)
   972  	assert.NoError(t, err)
   973  
   974  	// Create and sign a new CSR
   975  	csr, _, err := ca.GenerateNewCSR()
   976  	assert.NoError(t, err)
   977  	cert, err := newRootCA.ParseValidateAndSignCSR(csr, "CN", ca.ManagerRole, "ORG")
   978  	assert.NoError(t, err)
   979  
   980  	parsedCerts, err := helpers.ParseCertificatesPEM(cert)
   981  	assert.NoError(t, err)
   982  	assert.Len(t, parsedCerts, 1)
   983  	assert.True(t, time.Now().Add(time.Minute*59).Before(parsedCerts[0].NotAfter))
   984  	assert.True(t, time.Now().Add(time.Hour).Add(time.Minute).After(parsedCerts[0].NotAfter))
   985  
   986  	// Sign the same CSR again, this time with a 59 Minute expiration RootCA (under the 60 minute minimum).
   987  	// This should use the default of 3 months
   988  	newRootCA, err = ca.NewRootCA(rootCA.Certs, rootCA.Certs, s.Key, 59*time.Minute, nil)
   989  	assert.NoError(t, err)
   990  
   991  	cert, err = newRootCA.ParseValidateAndSignCSR(csr, "CN", ca.ManagerRole, "ORG")
   992  	assert.NoError(t, err)
   993  
   994  	parsedCerts, err = helpers.ParseCertificatesPEM(cert)
   995  	assert.NoError(t, err)
   996  	assert.Len(t, parsedCerts, 1)
   997  	assert.True(t, time.Now().Add(ca.DefaultNodeCertExpiration).AddDate(0, 0, -1).Before(parsedCerts[0].NotAfter))
   998  	assert.True(t, time.Now().Add(ca.DefaultNodeCertExpiration).AddDate(0, 0, 1).After(parsedCerts[0].NotAfter))
   999  }
  1000  
  1001  type invalidNewRootCATestCase struct {
  1002  	roots, cert, key, intermediates []byte
  1003  	errorStr                        string
  1004  }
  1005  
  1006  func TestNewRootCAInvalidCertAndKeys(t *testing.T) {
  1007  	now := time.Now()
  1008  
  1009  	expiredIntermediate := cautils.ReDateCert(t, cautils.ECDSACertChain[1],
  1010  		cautils.ECDSACertChain[2], cautils.ECDSACertChainKeys[2], now.Add(-10*time.Hour), now.Add(-1*time.Minute))
  1011  	notYetValidIntermediate := cautils.ReDateCert(t, cautils.ECDSACertChain[1],
  1012  		cautils.ECDSACertChain[2], cautils.ECDSACertChainKeys[2], now.Add(time.Hour), now.Add(2*time.Hour))
  1013  
  1014  	certChainRootCA, err := ca.NewRootCA(cautils.ECDSACertChain[2], cautils.ECDSACertChain[2], cautils.ECDSACertChainKeys[2],
  1015  		ca.DefaultNodeCertExpiration, nil)
  1016  	require.NoError(t, err)
  1017  
  1018  	cert, _, _ := cautils.CreateRootCertAndKey("alternateIntermediate")
  1019  	alternateIntermediate, err := certChainRootCA.CrossSignCACertificate(cert)
  1020  	require.NoError(t, err)
  1021  
  1022  	invalids := []invalidNewRootCATestCase{
  1023  		// invalid root or signer cert
  1024  		{
  1025  			roots:    []byte("malformed"),
  1026  			cert:     cautils.ECDSA256SHA256Cert,
  1027  			key:      cautils.ECDSA256Key,
  1028  			errorStr: "Failed to decode certificate",
  1029  		},
  1030  		{
  1031  			roots:    cautils.ECDSA256SHA256Cert,
  1032  			cert:     []byte("malformed"),
  1033  			key:      cautils.ECDSA256Key,
  1034  			errorStr: "Failed to decode certificate",
  1035  		},
  1036  		{
  1037  			roots:    []byte("  "),
  1038  			cert:     cautils.ECDSA256SHA256Cert,
  1039  			key:      cautils.ECDSA256Key,
  1040  			errorStr: "no valid root CA certificates found",
  1041  		},
  1042  		{
  1043  			roots:    cautils.ECDSA256SHA256Cert,
  1044  			cert:     []byte("  "),
  1045  			key:      cautils.ECDSA256Key,
  1046  			errorStr: "no valid signing CA certificates found",
  1047  		},
  1048  		{
  1049  			roots:    cautils.NotYetValidCert,
  1050  			cert:     cautils.ECDSA256SHA256Cert,
  1051  			key:      cautils.ECDSA256Key,
  1052  			errorStr: "not yet valid",
  1053  		},
  1054  		{
  1055  			roots:    cautils.ECDSA256SHA256Cert,
  1056  			cert:     cautils.NotYetValidCert,
  1057  			key:      cautils.NotYetValidKey,
  1058  			errorStr: "not yet valid",
  1059  		},
  1060  		{
  1061  			roots:    cautils.ExpiredCert,
  1062  			cert:     cautils.ECDSA256SHA256Cert,
  1063  			key:      cautils.ECDSA256Key,
  1064  			errorStr: "expired",
  1065  		},
  1066  		{
  1067  			roots:    cautils.ExpiredCert,
  1068  			cert:     cautils.ECDSA256SHA256Cert,
  1069  			key:      cautils.ECDSA256Key,
  1070  			errorStr: "expired",
  1071  		},
  1072  		{
  1073  			roots:    cautils.RSA2048SHA1Cert,
  1074  			cert:     cautils.ECDSA256SHA256Cert,
  1075  			key:      cautils.ECDSA256Key,
  1076  			errorStr: "unsupported signature algorithm",
  1077  		},
  1078  		{
  1079  			roots:    cautils.ECDSA256SHA256Cert,
  1080  			cert:     cautils.RSA2048SHA1Cert,
  1081  			key:      cautils.RSA2048Key,
  1082  			errorStr: "unsupported signature algorithm",
  1083  		},
  1084  		{
  1085  			roots:    cautils.ECDSA256SHA256Cert,
  1086  			cert:     cautils.ECDSA256SHA1Cert,
  1087  			key:      cautils.ECDSA256Key,
  1088  			errorStr: "unsupported signature algorithm",
  1089  		},
  1090  		{
  1091  			roots:    cautils.ECDSA256SHA1Cert,
  1092  			cert:     cautils.ECDSA256SHA256Cert,
  1093  			key:      cautils.ECDSA256Key,
  1094  			errorStr: "unsupported signature algorithm",
  1095  		},
  1096  		{
  1097  			roots:    cautils.ECDSA256SHA256Cert,
  1098  			cert:     cautils.DSA2048Cert,
  1099  			key:      cautils.DSA2048Key,
  1100  			errorStr: "unsupported signature algorithm",
  1101  		},
  1102  		{
  1103  			roots:    cautils.DSA2048Cert,
  1104  			cert:     cautils.ECDSA256SHA256Cert,
  1105  			key:      cautils.ECDSA256Key,
  1106  			errorStr: "unsupported signature algorithm",
  1107  		},
  1108  		// invalid signer
  1109  		{
  1110  			roots:    cautils.ECDSA256SHA256Cert,
  1111  			cert:     cautils.ECDSA256SHA256Cert,
  1112  			key:      []byte("malformed"),
  1113  			errorStr: "malformed private key",
  1114  		},
  1115  		{
  1116  			roots:    cautils.RSA1024Cert,
  1117  			cert:     cautils.RSA1024Cert,
  1118  			key:      cautils.RSA1024Key,
  1119  			errorStr: "unsupported RSA key parameters",
  1120  		},
  1121  		{
  1122  			roots:    cautils.ECDSA224Cert,
  1123  			cert:     cautils.ECDSA224Cert,
  1124  			key:      cautils.ECDSA224Key,
  1125  			errorStr: "unsupported ECDSA key parameters",
  1126  		},
  1127  		{
  1128  			roots:    cautils.ECDSA256SHA256Cert,
  1129  			cert:     cautils.ECDSA256SHA256Cert,
  1130  			key:      cautils.ECDSA224Key,
  1131  			errorStr: "certificate key mismatch",
  1132  		},
  1133  		{
  1134  			roots:    cautils.ECDSA256SHA256Cert,
  1135  			cert:     cautils.ECDSACertChain[1],
  1136  			key:      cautils.ECDSACertChainKeys[1],
  1137  			errorStr: "unknown authority", // signer cert doesn't chain up to the root
  1138  		},
  1139  		// invalid intermediates
  1140  		{
  1141  			roots:         cautils.ECDSACertChain[2],
  1142  			cert:          cautils.ECDSACertChain[1],
  1143  			key:           cautils.ECDSACertChainKeys[1],
  1144  			intermediates: []byte("malformed"),
  1145  			errorStr:      "Failed to decode certificate",
  1146  		},
  1147  		{
  1148  			roots:         cautils.ECDSACertChain[2],
  1149  			cert:          cautils.ECDSACertChain[1],
  1150  			key:           cautils.ECDSACertChainKeys[1],
  1151  			intermediates: expiredIntermediate,
  1152  			errorStr:      "expired",
  1153  		},
  1154  		{
  1155  			roots:         cautils.ECDSACertChain[2],
  1156  			cert:          cautils.ECDSACertChain[1],
  1157  			key:           cautils.ECDSACertChainKeys[1],
  1158  			intermediates: notYetValidIntermediate,
  1159  			errorStr:      "expired",
  1160  		},
  1161  		{
  1162  			roots:         cautils.ECDSACertChain[2],
  1163  			cert:          cautils.ECDSACertChain[1],
  1164  			key:           cautils.ECDSACertChainKeys[1],
  1165  			intermediates: append(cautils.ECDSACertChain[1], cautils.ECDSA256SHA256Cert...),
  1166  			errorStr:      "do not form a chain",
  1167  		},
  1168  		{
  1169  			roots:         cautils.ECDSACertChain[2],
  1170  			cert:          cautils.ECDSACertChain[1],
  1171  			key:           cautils.ECDSACertChainKeys[1],
  1172  			intermediates: cautils.ECDSA256SHA256Cert,
  1173  			errorStr:      "unknown authority", // intermediates don't chain up to root
  1174  		},
  1175  		{
  1176  			roots:         cautils.ECDSACertChain[2],
  1177  			cert:          cautils.ECDSACertChain[1],
  1178  			key:           cautils.ECDSACertChainKeys[1],
  1179  			intermediates: alternateIntermediate,
  1180  			errorStr:      "the first intermediate must have the same subject and public key as the signing cert",
  1181  		},
  1182  	}
  1183  
  1184  	for i, invalid := range invalids {
  1185  		_, err := ca.NewRootCA(invalid.roots, invalid.cert, invalid.key, ca.DefaultNodeCertExpiration, invalid.intermediates)
  1186  		require.Error(t, err, fmt.Sprintf("expected error containing: \"%s\", test case (%d)", invalid.errorStr, i))
  1187  		require.Contains(t, err.Error(), invalid.errorStr, fmt.Sprintf("%d", i))
  1188  	}
  1189  }
  1190  
  1191  func TestRootCAWithCrossSignedIntermediates(t *testing.T) {
  1192  	tempdir, err := ioutil.TempDir("", "swarm-ca-test-")
  1193  	require.NoError(t, err)
  1194  	defer os.RemoveAll(tempdir)
  1195  
  1196  	// re-generate the intermediate to be a self-signed root, and use that as the second root
  1197  	parsedKey, err := helpers.ParsePrivateKeyPEM(cautils.ECDSACertChainKeys[1])
  1198  	require.NoError(t, err)
  1199  	parsedIntermediate, err := helpers.ParseCertificatePEM(cautils.ECDSACertChain[1])
  1200  	require.NoError(t, err)
  1201  	fauxRootDER, err := x509.CreateCertificate(cryptorand.Reader, parsedIntermediate, parsedIntermediate, parsedKey.Public(), parsedKey)
  1202  	require.NoError(t, err)
  1203  	fauxRootCert := pem.EncodeToMemory(&pem.Block{
  1204  		Type:  "CERTIFICATE",
  1205  		Bytes: fauxRootDER,
  1206  	})
  1207  
  1208  	// It is not required, but not wrong, for the intermediate chain to terminate with a self-signed root
  1209  	signWithIntermediate, err := ca.NewRootCA(cautils.ECDSACertChain[2], cautils.ECDSACertChain[1], cautils.ECDSACertChainKeys[1],
  1210  		ca.DefaultNodeCertExpiration, append(cautils.ECDSACertChain[1], cautils.ECDSACertChain[2]...))
  1211  	require.NoError(t, err)
  1212  
  1213  	// just the intermediate, without a terminating self-signed root, is also ok
  1214  	signWithIntermediate, err = ca.NewRootCA(cautils.ECDSACertChain[2], cautils.ECDSACertChain[1], cautils.ECDSACertChainKeys[1],
  1215  		ca.DefaultNodeCertExpiration, cautils.ECDSACertChain[1])
  1216  	require.NoError(t, err)
  1217  
  1218  	paths := ca.NewConfigPaths(tempdir)
  1219  	krw := ca.NewKeyReadWriter(paths.Node, nil, nil)
  1220  	_, _, err = signWithIntermediate.IssueAndSaveNewCertificates(krw, "cn", "ou", "org")
  1221  	require.NoError(t, err)
  1222  	tlsCert, _, err := krw.Read()
  1223  	require.NoError(t, err)
  1224  
  1225  	parsedCerts, chains, err := ca.ValidateCertChain(signWithIntermediate.Pool, tlsCert, false)
  1226  	require.NoError(t, err)
  1227  	require.Len(t, parsedCerts, 2)
  1228  	require.Len(t, chains, 1)
  1229  	require.Equal(t, parsedIntermediate.Raw, parsedCerts[1].Raw)
  1230  	require.Equal(t, parsedCerts, chains[0][:len(chains[0])-1]) // the last one is the root
  1231  
  1232  	oldRoot, err := ca.NewRootCA(cautils.ECDSACertChain[2], cautils.ECDSACertChain[2], cautils.ECDSACertChainKeys[2], ca.DefaultNodeCertExpiration, nil)
  1233  	require.NoError(t, err)
  1234  
  1235  	newRoot, err := ca.NewRootCA(fauxRootCert, fauxRootCert, cautils.ECDSACertChainKeys[1], ca.DefaultNodeCertExpiration, nil)
  1236  	require.NoError(t, err)
  1237  	apiNewRoot := api.RootCA{
  1238  		CACert: fauxRootCert,
  1239  		CAKey:  cautils.ECDSACertChainKeys[1],
  1240  	}
  1241  
  1242  	checkValidateAgainstAllRoots := func(cert []byte) {
  1243  		for i, root := range []ca.RootCA{signWithIntermediate, oldRoot, newRoot} {
  1244  			parsedCerts, chains, err := ca.ValidateCertChain(root.Pool, cert, false)
  1245  			require.NoError(t, err)
  1246  			require.Len(t, parsedCerts, 2)
  1247  			require.Len(t, chains, 1)
  1248  			require.True(t, len(chains[0]) >= 2) // there are always at least 2 certs at minimum: the leaf and the root
  1249  			require.Equal(t, parsedCerts[0], chains[0][0])
  1250  			require.Equal(t, parsedIntermediate.Raw, parsedCerts[1].Raw)
  1251  
  1252  			chainWithoutRoot := chains[0][:len(chains[0])-1]
  1253  			if i == 2 {
  1254  				// against the new root, the cert can chain directly up to the root without the intermediate
  1255  				require.Equal(t, parsedCerts[0:1], chainWithoutRoot)
  1256  			} else {
  1257  				require.Equal(t, parsedCerts, chainWithoutRoot)
  1258  			}
  1259  		}
  1260  	}
  1261  	checkValidateAgainstAllRoots(tlsCert)
  1262  
  1263  	if !cautils.External {
  1264  		return
  1265  	}
  1266  
  1267  	// create an external signing server that generates leaf certs with the new root (but does not append the intermediate)
  1268  	tc := cautils.NewTestCAFromAPIRootCA(t, tempdir, apiNewRoot, nil)
  1269  	defer tc.Stop()
  1270  
  1271  	// we need creds that trust both the old and new root in order to connect to the test CA, and we want this root CA to
  1272  	// append certificates
  1273  	connectToExternalRootCA, err := ca.NewRootCA(append(cautils.ECDSACertChain[2], fauxRootCert...), cautils.ECDSACertChain[1],
  1274  		cautils.ECDSACertChainKeys[1], ca.DefaultNodeCertExpiration, cautils.ECDSACertChain[1])
  1275  	require.NoError(t, err)
  1276  	tlsKeyPair, _, err := connectToExternalRootCA.IssueAndSaveNewCertificates(krw, "cn", ca.ManagerRole, tc.Organization)
  1277  	require.NoError(t, err)
  1278  	externalCA := ca.NewExternalCA(cautils.ECDSACertChain[1],
  1279  		ca.NewExternalCATLSConfig([]tls.Certificate{*tlsKeyPair}, connectToExternalRootCA.Pool), tc.ExternalSigningServer.URL)
  1280  
  1281  	newCSR, _, err := ca.GenerateNewCSR()
  1282  	require.NoError(t, err)
  1283  
  1284  	tlsCert, err = externalCA.Sign(tc.Context, ca.PrepareCSR(newCSR, "cn", ca.ManagerRole, tc.Organization))
  1285  	require.NoError(t, err)
  1286  
  1287  	checkValidateAgainstAllRoots(tlsCert)
  1288  }
  1289  
  1290  type certTestCase struct {
  1291  	cert        []byte
  1292  	errorStr    string
  1293  	root        []byte
  1294  	allowExpiry bool
  1295  }
  1296  
  1297  func TestValidateCertificateChain(t *testing.T) {
  1298  	leaf, intermediate, root := cautils.ECDSACertChain[0], cautils.ECDSACertChain[1], cautils.ECDSACertChain[2]
  1299  	intermediateKey, rootKey := cautils.ECDSACertChainKeys[1], cautils.ECDSACertChainKeys[2] // we don't care about the leaf key
  1300  
  1301  	chain := func(certs ...[]byte) []byte {
  1302  		var all []byte
  1303  		for _, cert := range certs {
  1304  			all = append(all, cert...)
  1305  		}
  1306  		return all
  1307  	}
  1308  
  1309  	now := time.Now()
  1310  	expiredLeaf := cautils.ReDateCert(t, leaf, intermediate, intermediateKey, now.Add(-10*time.Hour), now.Add(-1*time.Minute))
  1311  	expiredIntermediate := cautils.ReDateCert(t, intermediate, root, rootKey, now.Add(-10*time.Hour), now.Add(-1*time.Minute))
  1312  	notYetValidLeaf := cautils.ReDateCert(t, leaf, intermediate, intermediateKey, now.Add(time.Hour), now.Add(2*time.Hour))
  1313  	notYetValidIntermediate := cautils.ReDateCert(t, intermediate, root, rootKey, now.Add(time.Hour), now.Add(2*time.Hour))
  1314  
  1315  	rootPool := x509.NewCertPool()
  1316  	rootPool.AppendCertsFromPEM(root)
  1317  
  1318  	invalids := []certTestCase{
  1319  		{
  1320  			cert:     nil,
  1321  			root:     root,
  1322  			errorStr: "no certificates to validate",
  1323  		},
  1324  		{
  1325  			cert:     []byte("malformed"),
  1326  			root:     root,
  1327  			errorStr: "Failed to decode certificate",
  1328  		},
  1329  		{
  1330  			cert:     chain(leaf, intermediate, leaf),
  1331  			root:     root,
  1332  			errorStr: "certificates do not form a chain",
  1333  		},
  1334  		{
  1335  			cert:     chain(leaf, intermediate),
  1336  			root:     cautils.ECDSA256SHA256Cert,
  1337  			errorStr: "unknown authority",
  1338  		},
  1339  		{
  1340  			cert:     chain(expiredLeaf, intermediate),
  1341  			root:     root,
  1342  			errorStr: "not valid after",
  1343  		},
  1344  		{
  1345  			cert:     chain(leaf, expiredIntermediate),
  1346  			root:     root,
  1347  			errorStr: "not valid after",
  1348  		},
  1349  		{
  1350  			cert:     chain(notYetValidLeaf, intermediate),
  1351  			root:     root,
  1352  			errorStr: "not valid before",
  1353  		},
  1354  		{
  1355  			cert:     chain(leaf, notYetValidIntermediate),
  1356  			root:     root,
  1357  			errorStr: "not valid before",
  1358  		},
  1359  
  1360  		// if we allow expiry, we still don't allow not yet valid certs or expired certs that don't chain up to the root
  1361  		{
  1362  			cert:        chain(notYetValidLeaf, intermediate),
  1363  			root:        root,
  1364  			allowExpiry: true,
  1365  			errorStr:    "not valid before",
  1366  		},
  1367  		{
  1368  			cert:        chain(leaf, notYetValidIntermediate),
  1369  			root:        root,
  1370  			allowExpiry: true,
  1371  			errorStr:    "not valid before",
  1372  		},
  1373  		{
  1374  			cert:        chain(expiredLeaf, intermediate),
  1375  			root:        cautils.ECDSA256SHA256Cert,
  1376  			allowExpiry: true,
  1377  			errorStr:    "unknown authority",
  1378  		},
  1379  
  1380  		// construct a weird cases where one cert is expired, we allow expiry, but the other cert is not yet valid at the first cert's expiry
  1381  		// (this is not something that can happen unless we allow expiry, because if the cert periods don't overlap, one or the other will
  1382  		// be either not yet valid or already expired)
  1383  		{
  1384  			cert: chain(
  1385  				cautils.ReDateCert(t, leaf, intermediate, intermediateKey, now.Add(-3*helpers.OneDay), now.Add(-2*helpers.OneDay)),
  1386  				cautils.ReDateCert(t, intermediate, root, rootKey, now.Add(-1*helpers.OneDay), now.Add(helpers.OneDay))),
  1387  			root:        root,
  1388  			allowExpiry: true,
  1389  			errorStr:    "there is no time span",
  1390  		},
  1391  		// similarly, but for root pool
  1392  		{
  1393  			cert:        chain(expiredLeaf, expiredIntermediate),
  1394  			root:        cautils.ReDateCert(t, root, root, rootKey, now.Add(-3*helpers.OneYear), now.Add(-2*helpers.OneYear)),
  1395  			allowExpiry: true,
  1396  			errorStr:    "there is no time span",
  1397  		},
  1398  	}
  1399  
  1400  	for _, invalid := range invalids {
  1401  		pool := x509.NewCertPool()
  1402  		pool.AppendCertsFromPEM(invalid.root)
  1403  		_, _, err := ca.ValidateCertChain(pool, invalid.cert, invalid.allowExpiry)
  1404  		require.Error(t, err, invalid.errorStr)
  1405  		require.Contains(t, err.Error(), invalid.errorStr)
  1406  	}
  1407  
  1408  	// these will default to using the root pool, so we don't have to specify the root pool
  1409  	valids := []certTestCase{
  1410  		{cert: chain(leaf, intermediate, root)},
  1411  		{cert: chain(leaf, intermediate)},
  1412  		{cert: intermediate},
  1413  		{
  1414  			cert:        chain(expiredLeaf, intermediate),
  1415  			allowExpiry: true,
  1416  		},
  1417  		{
  1418  			cert:        chain(leaf, expiredIntermediate),
  1419  			allowExpiry: true,
  1420  		},
  1421  		{
  1422  			cert:        chain(expiredLeaf, expiredIntermediate),
  1423  			allowExpiry: true,
  1424  		},
  1425  	}
  1426  
  1427  	for _, valid := range valids {
  1428  		parsedCerts, chains, err := ca.ValidateCertChain(rootPool, valid.cert, valid.allowExpiry)
  1429  		require.NoError(t, err)
  1430  		require.NotEmpty(t, chain)
  1431  		for _, chain := range chains {
  1432  			require.Equal(t, parsedCerts[0], chain[0]) // the leaf certs are equal
  1433  			require.True(t, len(chain) >= 2)
  1434  		}
  1435  	}
  1436  }
  1437  
  1438  // Tests cross-signing an RSA cert with an ECDSA cert and vice versa, and an ECDSA
  1439  // cert with another ECDSA cert and a RSA cert with another RSA cert
  1440  func TestRootCACrossSignCACertificate(t *testing.T) {
  1441  	t.Parallel()
  1442  	if cautils.External {
  1443  		return
  1444  	}
  1445  
  1446  	oldCAs := []struct {
  1447  		cert, key []byte
  1448  	}{
  1449  		{
  1450  			cert: cautils.ECDSA256SHA256Cert,
  1451  			key:  cautils.ECDSA256Key,
  1452  		},
  1453  		{
  1454  			cert: cautils.RSA2048SHA256Cert,
  1455  			key:  cautils.RSA2048Key,
  1456  		},
  1457  	}
  1458  
  1459  	cert1, key1, err := cautils.CreateRootCertAndKey("rootCNECDSA")
  1460  	require.NoError(t, err)
  1461  
  1462  	rsaReq := cfcsr.CertificateRequest{
  1463  		CN: "rootCNRSA",
  1464  		KeyRequest: &cfcsr.BasicKeyRequest{
  1465  			A: "rsa",
  1466  			S: 2048,
  1467  		},
  1468  		CA: &cfcsr.CAConfig{Expiry: ca.RootCAExpiration},
  1469  	}
  1470  
  1471  	// Generate the CA and get the certificate and private key
  1472  	cert2, _, key2, err := initca.New(&rsaReq)
  1473  	require.NoError(t, err)
  1474  
  1475  	newCAs := []struct {
  1476  		cert, key []byte
  1477  	}{
  1478  		{
  1479  			cert: cert1,
  1480  			key:  key1,
  1481  		},
  1482  		{
  1483  			cert: cert2,
  1484  			key:  key2,
  1485  		},
  1486  	}
  1487  
  1488  	tempdir, err := ioutil.TempDir("", "cross-sign-cert")
  1489  	require.NoError(t, err)
  1490  	defer os.RemoveAll(tempdir)
  1491  	paths := ca.NewConfigPaths(tempdir)
  1492  	krw := ca.NewKeyReadWriter(paths.Node, nil, nil)
  1493  
  1494  	for _, oldRoot := range oldCAs {
  1495  		for _, newRoot := range newCAs {
  1496  			rootCA1, err := ca.NewRootCA(oldRoot.cert, oldRoot.cert, oldRoot.key, ca.DefaultNodeCertExpiration, nil)
  1497  			require.NoError(t, err)
  1498  
  1499  			rootCA2, err := ca.NewRootCA(newRoot.cert, newRoot.cert, newRoot.key, ca.DefaultNodeCertExpiration, nil)
  1500  			require.NoError(t, err)
  1501  
  1502  			_, _, err = rootCA2.IssueAndSaveNewCertificates(krw, "cn", "ou", "org")
  1503  			require.NoError(t, err)
  1504  			certBytes, keyBytes, err := krw.Read()
  1505  			require.NoError(t, err)
  1506  			leafCert, err := helpers.ParseCertificatePEM(certBytes)
  1507  			require.NoError(t, err)
  1508  
  1509  			// cross-signing a non-CA fails
  1510  			_, err = rootCA1.CrossSignCACertificate(certBytes)
  1511  			require.Error(t, err)
  1512  
  1513  			// cross-signing some non-cert PEM bytes fail
  1514  			_, err = rootCA1.CrossSignCACertificate(keyBytes)
  1515  			require.Error(t, err)
  1516  
  1517  			intermediate, err := rootCA1.CrossSignCACertificate(newRoot.cert)
  1518  			require.NoError(t, err)
  1519  			parsedIntermediate, err := helpers.ParseCertificatePEM(intermediate)
  1520  			require.NoError(t, err)
  1521  			parsedRoot2, err := helpers.ParseCertificatePEM(newRoot.cert)
  1522  			require.NoError(t, err)
  1523  			require.Equal(t, parsedRoot2.RawSubject, parsedIntermediate.RawSubject)
  1524  			require.Equal(t, parsedRoot2.RawSubjectPublicKeyInfo, parsedIntermediate.RawSubjectPublicKeyInfo)
  1525  			require.True(t, parsedIntermediate.IsCA)
  1526  
  1527  			intermediatePool := x509.NewCertPool()
  1528  			intermediatePool.AddCert(parsedIntermediate)
  1529  
  1530  			// we can validate a chain from the leaf to the first root through the intermediate,
  1531  			// or from the leaf cert to the second root with or without the intermediate
  1532  			_, err = leafCert.Verify(x509.VerifyOptions{Roots: rootCA1.Pool})
  1533  			require.Error(t, err)
  1534  			_, err = leafCert.Verify(x509.VerifyOptions{Roots: rootCA1.Pool, Intermediates: intermediatePool})
  1535  			require.NoError(t, err)
  1536  
  1537  			_, err = leafCert.Verify(x509.VerifyOptions{Roots: rootCA2.Pool})
  1538  			require.NoError(t, err)
  1539  			_, err = leafCert.Verify(x509.VerifyOptions{Roots: rootCA2.Pool, Intermediates: intermediatePool})
  1540  			require.NoError(t, err)
  1541  		}
  1542  	}
  1543  }
  1544  
  1545  func concat(byteSlices ...[]byte) []byte {
  1546  	var results []byte
  1547  	for _, slice := range byteSlices {
  1548  		results = append(results, slice...)
  1549  	}
  1550  	return results
  1551  }
  1552  
  1553  func TestNormalizePEMs(t *testing.T) {
  1554  	pemBlock, _ := pem.Decode(cautils.ECDSA256SHA256Cert)
  1555  	pemBlock.Headers = map[string]string{
  1556  		"hello": "world",
  1557  	}
  1558  	withHeaders := pem.EncodeToMemory(pemBlock)
  1559  	for _, testcase := range []struct{ input, expect []byte }{
  1560  		{
  1561  			input:  nil,
  1562  			expect: nil,
  1563  		},
  1564  		{
  1565  			input:  []byte("garbage"),
  1566  			expect: nil,
  1567  		},
  1568  		{
  1569  			input:  concat([]byte("garbage\n\t\n\n"), cautils.ECDSA256SHA256Cert, []byte("   \n")),
  1570  			expect: ca.NormalizePEMs(cautils.ECDSA256SHA256Cert),
  1571  		},
  1572  		{
  1573  			input:  concat([]byte("\n\t\n     "), withHeaders, []byte("\t\n\n"), cautils.ECDSACertChain[0]),
  1574  			expect: ca.NormalizePEMs(append(cautils.ECDSA256SHA256Cert, cautils.ECDSACertChain[0]...)),
  1575  		},
  1576  	} {
  1577  		require.Equal(t, testcase.expect, ca.NormalizePEMs(testcase.input))
  1578  	}
  1579  }