ca: improve RenewIntermediate tests

Use the new verifyLearfCert to show the cert verifies with intermediates
from both sources. This required using the RPC interface so that the
leaf pem was constructed correctly.

Add IndexedCARoots.Active since that is a common operation we see in a
few places.
This commit is contained in:
Daniel Nephin 2021-12-07 16:21:23 -05:00
parent a4ba1f348d
commit 2e4e8bd791
3 changed files with 34 additions and 58 deletions

View File

@ -57,8 +57,6 @@ func TestCAManager_Initialize_Vault_Secondary_SharedVault(t *testing.T) {
testrpc.WaitForTestAgent(t, serverDC1.RPC, "dc1") testrpc.WaitForTestAgent(t, serverDC1.RPC, "dc1")
codec := rpcClient(t, serverDC1) codec := rpcClient(t, serverDC1)
defer codec.Close()
roots := structs.IndexedCARoots{} roots := structs.IndexedCARoots{}
err := msgpackrpc.CallWithCodec(codec, "ConnectCA.Roots", &structs.DCSpecificRequest{}, &roots) err := msgpackrpc.CallWithCodec(codec, "ConnectCA.Roots", &structs.DCSpecificRequest{}, &roots)
require.NoError(t, err) require.NoError(t, err)
@ -87,8 +85,6 @@ func TestCAManager_Initialize_Vault_Secondary_SharedVault(t *testing.T) {
testrpc.WaitForActiveCARoot(t, serverDC2.RPC, "dc2", nil) testrpc.WaitForActiveCARoot(t, serverDC2.RPC, "dc2", nil)
codec := rpcClient(t, serverDC2) codec := rpcClient(t, serverDC2)
defer codec.Close()
roots := structs.IndexedCARoots{} roots := structs.IndexedCARoots{}
err := msgpackrpc.CallWithCodec(codec, "ConnectCA.Roots", &structs.DCSpecificRequest{}, &roots) err := msgpackrpc.CallWithCodec(codec, "ConnectCA.Roots", &structs.DCSpecificRequest{}, &roots)
require.NoError(t, err) require.NoError(t, err)

View File

@ -420,8 +420,13 @@ func TestCAManager_RenewIntermediate_Vault_Primary(t *testing.T) {
intermediatePEM = newIntermediatePEM intermediatePEM = newIntermediatePEM
}) })
_, activeRoot, err = store.CARootActive(nil) codec := rpcClient(t, s1)
roots := structs.IndexedCARoots{}
err = msgpackrpc.CallWithCodec(codec, "ConnectCA.Roots", &structs.DCSpecificRequest{}, &roots)
require.NoError(err) require.NoError(err)
require.Len(roots.Roots, 1)
activeRoot = roots.Active()
require.Equal(intermediatePEM, s1.caManager.getLeafSigningCertFromRoot(activeRoot)) require.Equal(intermediatePEM, s1.caManager.getLeafSigningCertFromRoot(activeRoot))
require.Equal(connect.HexString(intermediateCert.SubjectKeyId), activeRoot.SigningKeyID) require.Equal(connect.HexString(intermediateCert.SubjectKeyId), activeRoot.SigningKeyID)
@ -431,36 +436,18 @@ func TestCAManager_RenewIntermediate_Vault_Primary(t *testing.T) {
// Have the new intermediate sign a leaf cert and make sure the chain is correct. // Have the new intermediate sign a leaf cert and make sure the chain is correct.
spiffeService := &connect.SpiffeIDService{ spiffeService := &connect.SpiffeIDService{
Host: "node1", Host: roots.TrustDomain,
Namespace: "default", Namespace: "default",
Datacenter: "dc1", Datacenter: "dc1",
Service: "foo", Service: "foo",
} }
raw, _ := connect.TestCSR(t, spiffeService) csr, _ := connect.TestCSR(t, spiffeService)
leafCsr, err := connect.ParseCSR(raw) req := structs.CASignRequest{CSR: csr}
require.NoError(err) cert := structs.IssuedCert{}
err = msgpackrpc.CallWithCodec(codec, "ConnectCA.Sign", &req, &cert)
leafPEM, err := provider.Sign(leafCsr)
require.NoError(err)
cert, err := connect.ParseCert(leafPEM)
require.NoError(err)
// Check that the leaf signed by the new intermediate can be verified using the
// returned cert chain (signed intermediate + remote root).
intermediatePool := x509.NewCertPool()
// TODO: do not explicitly add the intermediatePEM, we should have it available
// from leafPEM. Use connect.ParseLeafCerts to do the right thing.
intermediatePool.AppendCertsFromPEM([]byte(intermediatePEM))
rootPool := x509.NewCertPool()
rootPool.AppendCertsFromPEM([]byte(caRoot.RootCert))
_, err = cert.Verify(x509.VerifyOptions{
Intermediates: intermediatePool,
Roots: rootPool,
})
require.NoError(err) require.NoError(err)
verifyLeafCert(t, caRoot, cert.CertPEM)
} }
func TestCAManager_RenewIntermediate_Secondary(t *testing.T) { func TestCAManager_RenewIntermediate_Secondary(t *testing.T) {
@ -570,47 +557,31 @@ func TestCAManager_RenewIntermediate_Secondary(t *testing.T) {
intermediateCert = cert intermediateCert = cert
}) })
codec := rpcClient(t, s2)
roots := structs.IndexedCARoots{}
err = msgpackrpc.CallWithCodec(codec, "ConnectCA.Roots", &structs.DCSpecificRequest{}, &roots)
require.NoError(err)
require.Len(roots.Roots, 1)
_, activeRoot, err = store.CARootActive(nil) _, activeRoot, err = store.CARootActive(nil)
require.NoError(err) require.NoError(err)
require.Equal(intermediatePEM, s2.caManager.getLeafSigningCertFromRoot(activeRoot)) require.Equal(intermediatePEM, s2.caManager.getLeafSigningCertFromRoot(activeRoot))
require.Equal(connect.HexString(intermediateCert.SubjectKeyId), activeRoot.SigningKeyID) require.Equal(connect.HexString(intermediateCert.SubjectKeyId), activeRoot.SigningKeyID)
// Get the root from dc1 and validate a chain of:
// dc2 leaf -> dc2 intermediate -> dc1 root
_, caRoot := getCAProviderWithLock(s1)
// Have dc2 sign a leaf cert and make sure the chain is correct. // Have dc2 sign a leaf cert and make sure the chain is correct.
spiffeService := &connect.SpiffeIDService{ spiffeService := &connect.SpiffeIDService{
Host: "node1", Host: roots.TrustDomain,
Namespace: "default", Namespace: "default",
Datacenter: "dc1", Datacenter: "dc2",
Service: "foo", Service: "foo",
} }
raw, _ := connect.TestCSR(t, spiffeService) csr, _ := connect.TestCSR(t, spiffeService)
leafCsr, err := connect.ParseCSR(raw) req := structs.CASignRequest{CSR: csr}
require.NoError(err) cert := structs.IssuedCert{}
err = msgpackrpc.CallWithCodec(codec, "ConnectCA.Sign", &req, &cert)
leafPEM, err := secondaryProvider.Sign(leafCsr)
require.NoError(err)
intermediateCert, err = connect.ParseCert(leafPEM)
require.NoError(err)
// Check that the leaf signed by the new intermediate can be verified using the
// returned cert chain (signed intermediate + remote root).
intermediatePool := x509.NewCertPool()
// TODO: do not explicitly add the intermediatePEM, we should have it available
// from leafPEM. Use connect.ParseLeafCerts to do the right thing.
intermediatePool.AppendCertsFromPEM([]byte(intermediatePEM))
rootPool := x509.NewCertPool()
rootPool.AppendCertsFromPEM([]byte(caRoot.RootCert))
_, err = intermediateCert.Verify(x509.VerifyOptions{
Intermediates: intermediatePool,
Roots: rootPool,
})
require.NoError(err) require.NoError(err)
verifyLeafCert(t, activeRoot, cert.CertPEM)
} }
func TestConnectCA_ConfigurationSet_RootRotation_Secondary(t *testing.T) { func TestConnectCA_ConfigurationSet_RootRotation_Secondary(t *testing.T) {

View File

@ -55,6 +55,15 @@ type IndexedCARoots struct {
QueryMeta `json:"-"` QueryMeta `json:"-"`
} }
func (r IndexedCARoots) Active() *CARoot {
for _, root := range r.Roots {
if root.ID == r.ActiveRootID {
return root
}
}
return nil
}
// CARoot represents a root CA certificate that is trusted. // CARoot represents a root CA certificate that is trusted.
type CARoot struct { type CARoot struct {
// ID is a globally unique ID (UUID) representing this CA root. // ID is a globally unique ID (UUID) representing this CA root.