mirror of https://github.com/docker/docs.git
Foundation for removing certstore
Signed-off-by: Riyaz Faizullabhoy <riyaz.faizullabhoy@docker.com>
This commit is contained in:
parent
dc445b4a3a
commit
9da40f07da
|
@ -812,7 +812,7 @@ func (r *NotaryRepository) bootstrapClient(checkInitialized bool) (*tufclient.Cl
|
||||||
rootJSON, cachedRootErr := r.fileStore.GetMeta(data.CanonicalRootRole, -1)
|
rootJSON, cachedRootErr := r.fileStore.GetMeta(data.CanonicalRootRole, -1)
|
||||||
|
|
||||||
if cachedRootErr == nil {
|
if cachedRootErr == nil {
|
||||||
signedRoot, cachedRootErr = r.validateRoot(rootJSON)
|
signedRoot, cachedRootErr = r.validateRoot(rootJSON, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
remote, remoteErr := getRemoteStore(r.baseURL, r.gun, r.roundTrip)
|
remote, remoteErr := getRemoteStore(r.baseURL, r.gun, r.roundTrip)
|
||||||
|
@ -833,7 +833,7 @@ func (r *NotaryRepository) bootstrapClient(checkInitialized bool) (*tufclient.Cl
|
||||||
if cachedRootErr != nil {
|
if cachedRootErr != nil {
|
||||||
// we always want to use the downloaded root if there was a cache
|
// we always want to use the downloaded root if there was a cache
|
||||||
// error.
|
// error.
|
||||||
signedRoot, err = r.validateRoot(tmpJSON)
|
signedRoot, err = r.validateRoot(tmpJSON, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -868,7 +868,7 @@ func (r *NotaryRepository) bootstrapClient(checkInitialized bool) (*tufclient.Cl
|
||||||
// signatures of the root based on known keys, not expiry or other metadata.
|
// signatures of the root based on known keys, not expiry or other metadata.
|
||||||
// This is so that an out of date root can be loaded to be used in a rotation
|
// This is so that an out of date root can be loaded to be used in a rotation
|
||||||
// should the TUF update process detect a problem.
|
// should the TUF update process detect a problem.
|
||||||
func (r *NotaryRepository) validateRoot(rootJSON []byte) (*data.SignedRoot, error) {
|
func (r *NotaryRepository) validateRoot(rootJSON []byte, fromRemote bool) (*data.SignedRoot, error) {
|
||||||
// can't just unmarshal into SignedRoot because validate root
|
// can't just unmarshal into SignedRoot because validate root
|
||||||
// needs the root.Signed field to still be []byte for signature
|
// needs the root.Signed field to still be []byte for signature
|
||||||
// validation
|
// validation
|
||||||
|
@ -878,7 +878,25 @@ func (r *NotaryRepository) validateRoot(rootJSON []byte) (*data.SignedRoot, erro
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = trustpinning.ValidateRoot(r.CertStore, root, r.gun, r.trustPinning)
|
// If we're downloading a root from a remote source, attempt to load a local root
|
||||||
|
// to ensure that we consider old roots when validating this new one
|
||||||
|
var prevRoot *data.SignedRoot
|
||||||
|
if fromRemote {
|
||||||
|
prevRootJSON, err := r.fileStore.GetMeta(data.CanonicalRootRole, -1)
|
||||||
|
if err == nil {
|
||||||
|
prevSignedRoot := &data.Signed{}
|
||||||
|
err = json.Unmarshal(prevRootJSON, prevSignedRoot)
|
||||||
|
if err == nil {
|
||||||
|
prevRoot, err = data.RootFromSigned(prevSignedRoot)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If we had any errors while trying to retrieve the previous root, just set it to nil
|
||||||
|
if err != nil {
|
||||||
|
prevRoot = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err = trustpinning.ValidateRoot(prevRoot, root, r.gun, r.trustPinning)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,7 +86,7 @@ We shall call this: TOFUS.
|
||||||
|
|
||||||
Validation failure at any step will result in an ErrValidationFailed error.
|
Validation failure at any step will result in an ErrValidationFailed error.
|
||||||
*/
|
*/
|
||||||
func ValidateRoot(certStore trustmanager.X509Store, root *data.Signed, gun string, trustPinning TrustPinConfig) error {
|
func ValidateRoot(prevRoot *data.SignedRoot, root *data.Signed, gun string, trustPinning TrustPinConfig) error {
|
||||||
logrus.Debugf("entered ValidateRoot with dns: %s", gun)
|
logrus.Debugf("entered ValidateRoot with dns: %s", gun)
|
||||||
signedRoot, err := data.RootFromSigned(root)
|
signedRoot, err := data.RootFromSigned(root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -100,30 +100,23 @@ func ValidateRoot(certStore trustmanager.X509Store, root *data.Signed, gun strin
|
||||||
|
|
||||||
// Retrieve all the leaf and intermediate certificates in root for which the CN matches the GUN
|
// Retrieve all the leaf and intermediate certificates in root for which the CN matches the GUN
|
||||||
allLeafCerts, allIntCerts := parseAllCerts(signedRoot)
|
allLeafCerts, allIntCerts := parseAllCerts(signedRoot)
|
||||||
certsFromRoot, err := validRootLeafCerts(allLeafCerts, gun)
|
certsFromRoot, err := validRootLeafCerts(allLeafCerts, gun, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Debugf("error retrieving valid leaf certificates for: %s, %v", gun, err)
|
logrus.Debugf("error retrieving valid leaf certificates for: %s, %v", gun, err)
|
||||||
return &ErrValidationFail{Reason: "unable to retrieve valid leaf certificates"}
|
return &ErrValidationFail{Reason: "unable to retrieve valid leaf certificates"}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve all the trusted certificates that match this gun
|
// Retrieve all the trusted certificates from our previous root
|
||||||
trustedCerts, err := certStore.GetCertificatesByCN(gun)
|
// Note that we do not validate expiries here since our originally trusted root might have expired certs
|
||||||
if err != nil {
|
allTrustedLeafCerts, allTrustedIntCerts := parseAllCerts(prevRoot)
|
||||||
// If the error that we get back is different than ErrNoCertificatesFound
|
trustedLeafCerts, err := validRootLeafCerts(allTrustedLeafCerts, gun, false)
|
||||||
// we couldn't check if there are any certificates with this CN already
|
|
||||||
// trusted. Let's take the conservative approach and return a failed validation
|
|
||||||
if _, ok := err.(*trustmanager.ErrNoCertificatesFound); !ok {
|
|
||||||
logrus.Debugf("error retrieving trusted certificates for: %s, %v", gun, err)
|
|
||||||
return &ErrValidationFail{Reason: "unable to retrieve trusted certificates"}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If we have certificates that match this specific GUN, let's make sure to
|
// If we have certificates that match this specific GUN, let's make sure to
|
||||||
// use them first to validate that this new root is valid.
|
// use them first to validate that this new root is valid.
|
||||||
if len(trustedCerts) != 0 {
|
if len(trustedLeafCerts) != 0 {
|
||||||
logrus.Debugf("found %d valid root certificates for %s: %s", len(trustedCerts), gun,
|
logrus.Debugf("found %d valid root leaf certificates for %s: %s", len(trustedLeafCerts), gun,
|
||||||
prettyFormatCertIDs(trustedCerts))
|
prettyFormatCertIDs(trustedLeafCerts))
|
||||||
err = signed.VerifySignatures(
|
err = signed.VerifySignatures(
|
||||||
root, data.BaseRole{Keys: trustmanager.CertsToKeys(trustedCerts, allIntCerts), Threshold: 1})
|
root, data.BaseRole{Keys: trustmanager.CertsToKeys(trustedLeafCerts, allTrustedIntCerts), Threshold: 1})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Debugf("failed to verify TUF data for: %s, %v", gun, err)
|
logrus.Debugf("failed to verify TUF data for: %s, %v", gun, err)
|
||||||
return &ErrValidationFail{Reason: "failed to validate data with current trusted certificates"}
|
return &ErrValidationFail{Reason: "failed to validate data with current trusted certificates"}
|
||||||
|
@ -162,49 +155,14 @@ func ValidateRoot(certStore trustmanager.X509Store, root *data.Signed, gun strin
|
||||||
return &ErrValidationFail{Reason: "failed to validate integrity of roots"}
|
return &ErrValidationFail{Reason: "failed to validate integrity of roots"}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getting here means:
|
|
||||||
// A) we had trusted certificates and both the old and new validated this root.
|
|
||||||
// or
|
|
||||||
// B) we had no trusted certificates but the new set of certificates has integrity (self-signed).
|
|
||||||
logrus.Debugf("entering root certificate rotation for: %s", gun)
|
|
||||||
|
|
||||||
// Do root certificate rotation: we trust only the certs present in the new root
|
|
||||||
// First we add all the new certificates (even if they already exist)
|
|
||||||
for _, cert := range certsFromRoot {
|
|
||||||
err := certStore.AddCert(cert)
|
|
||||||
if err != nil {
|
|
||||||
// If the error is already exists we don't fail the rotation
|
|
||||||
if _, ok := err.(*trustmanager.ErrCertExists); ok {
|
|
||||||
logrus.Debugf("ignoring certificate addition to: %s", gun)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
logrus.Debugf("error adding new trusted certificate for: %s, %v", gun, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now we delete old certificates that aren't present in the new root
|
|
||||||
oldCertsToRemove, err := certsToRemove(trustedCerts, certsFromRoot)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Debugf("inconsistency when removing old certificates: %v", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for certID, cert := range oldCertsToRemove {
|
|
||||||
logrus.Debugf("removing certificate with certID: %s", certID)
|
|
||||||
err = certStore.RemoveCert(cert)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Debugf("failed to remove trusted certificate with keyID: %s, %v", certID, err)
|
|
||||||
return &ErrRootRotationFail{Reason: "failed to rotate root keys"}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugf("Root validation succeeded for %s", gun)
|
logrus.Debugf("Root validation succeeded for %s", gun)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// validRootLeafCerts returns a list of non-expired, non-sha1 certificates
|
// validRootLeafCerts returns a list of possibly (if checkExpiry is true) non-expired, non-sha1 certificates
|
||||||
// found in root whose Common-Names match the provided GUN. Note that this
|
// found in root whose Common-Names match the provided GUN. Note that this
|
||||||
// "validity" alone does not imply any measure of trust.
|
// "validity" alone does not imply any measure of trust.
|
||||||
func validRootLeafCerts(allLeafCerts map[string]*x509.Certificate, gun string) ([]*x509.Certificate, error) {
|
func validRootLeafCerts(allLeafCerts map[string]*x509.Certificate, gun string, checkExpiry bool) ([]*x509.Certificate, error) {
|
||||||
var validLeafCerts []*x509.Certificate
|
var validLeafCerts []*x509.Certificate
|
||||||
|
|
||||||
// Go through every leaf certificate and check that the CN matches the gun
|
// Go through every leaf certificate and check that the CN matches the gun
|
||||||
|
@ -215,8 +173,8 @@ func validRootLeafCerts(allLeafCerts map[string]*x509.Certificate, gun string) (
|
||||||
cert.Subject.CommonName, gun)
|
cert.Subject.CommonName, gun)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Make sure the certificate is not expired
|
// Make sure the certificate is not expired if checkExpiry is true
|
||||||
if time.Now().After(cert.NotAfter) {
|
if checkExpiry && time.Now().After(cert.NotAfter) {
|
||||||
logrus.Debugf("error leaf certificate is expired")
|
logrus.Debugf("error leaf certificate is expired")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -246,6 +204,10 @@ func validRootLeafCerts(allLeafCerts map[string]*x509.Certificate, gun string) (
|
||||||
// parseAllCerts returns two maps, one with all of the leafCertificates and one
|
// parseAllCerts returns two maps, one with all of the leafCertificates and one
|
||||||
// with all the intermediate certificates found in signedRoot
|
// with all the intermediate certificates found in signedRoot
|
||||||
func parseAllCerts(signedRoot *data.SignedRoot) (map[string]*x509.Certificate, map[string][]*x509.Certificate) {
|
func parseAllCerts(signedRoot *data.SignedRoot) (map[string]*x509.Certificate, map[string][]*x509.Certificate) {
|
||||||
|
if signedRoot == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
leafCerts := make(map[string]*x509.Certificate)
|
leafCerts := make(map[string]*x509.Certificate)
|
||||||
intCerts := make(map[string][]*x509.Certificate)
|
intCerts := make(map[string][]*x509.Certificate)
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,6 @@ import (
|
||||||
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/notary"
|
|
||||||
"github.com/docker/notary/cryptoservice"
|
"github.com/docker/notary/cryptoservice"
|
||||||
"github.com/docker/notary/trustmanager"
|
"github.com/docker/notary/trustmanager"
|
||||||
"github.com/docker/notary/tuf/data"
|
"github.com/docker/notary/tuf/data"
|
||||||
|
@ -133,14 +132,6 @@ func TestValidateRoot(t *testing.T) {
|
||||||
defer os.RemoveAll(tempBaseDir)
|
defer os.RemoveAll(tempBaseDir)
|
||||||
require.NoError(t, err, "failed to create a temporary directory: %s", err)
|
require.NoError(t, err, "failed to create a temporary directory: %s", err)
|
||||||
|
|
||||||
// Create a X509Store
|
|
||||||
trustPath := filepath.Join(tempBaseDir, notary.TrustedCertsDir)
|
|
||||||
certStore, err := trustmanager.NewX509FilteredFileStore(
|
|
||||||
trustPath,
|
|
||||||
trustmanager.FilterCertsExpiredSha1,
|
|
||||||
)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// Execute our template
|
// Execute our template
|
||||||
templ, _ := template.New("SignedRSARootTemplate").Parse(signedRSARootTemplate)
|
templ, _ := template.New("SignedRSARootTemplate").Parse(signedRSARootTemplate)
|
||||||
templ.Execute(&signedRootBytes, SignedRSARootTemplate{RootPem: validPEMEncodedRSARoot})
|
templ.Execute(&signedRootBytes, SignedRSARootTemplate{RootPem: validPEMEncodedRSARoot})
|
||||||
|
@ -150,12 +141,12 @@ func TestValidateRoot(t *testing.T) {
|
||||||
|
|
||||||
// This call to ValidateRoot will succeed since we are using a valid PEM
|
// This call to ValidateRoot will succeed since we are using a valid PEM
|
||||||
// encoded certificate, and have no other certificates for this CN
|
// encoded certificate, and have no other certificates for this CN
|
||||||
err = ValidateRoot(certStore, &testSignedRoot, "docker.com/notary", TrustPinConfig{})
|
err = ValidateRoot(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// This call to ValidateRoot will fail since we are passing in a dnsName that
|
// This call to ValidateRoot will fail since we are passing in a dnsName that
|
||||||
// doesn't match the CN of the certificate.
|
// doesn't match the CN of the certificate.
|
||||||
err = ValidateRoot(certStore, &testSignedRoot, "diogomonica.com/notary", TrustPinConfig{})
|
err = ValidateRoot(nil, &testSignedRoot, "diogomonica.com/notary", TrustPinConfig{})
|
||||||
require.Error(t, err, "An error was expected")
|
require.Error(t, err, "An error was expected")
|
||||||
require.Equal(t, err, &ErrValidationFail{Reason: "unable to retrieve valid leaf certificates"})
|
require.Equal(t, err, &ErrValidationFail{Reason: "unable to retrieve valid leaf certificates"})
|
||||||
|
|
||||||
|
@ -169,7 +160,7 @@ func TestValidateRoot(t *testing.T) {
|
||||||
// Unmarshal our signedroot
|
// Unmarshal our signedroot
|
||||||
json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
|
json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
|
||||||
|
|
||||||
err = ValidateRoot(certStore, &testSignedRoot, "docker.com/notary", TrustPinConfig{})
|
err = ValidateRoot(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{})
|
||||||
require.Error(t, err, "illegal base64 data at input byte")
|
require.Error(t, err, "illegal base64 data at input byte")
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -182,7 +173,7 @@ func TestValidateRoot(t *testing.T) {
|
||||||
// Unmarshal our signedroot
|
// Unmarshal our signedroot
|
||||||
json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
|
json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
|
||||||
|
|
||||||
err = ValidateRoot(certStore, &testSignedRoot, "docker.com/notary", TrustPinConfig{})
|
err = ValidateRoot(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{})
|
||||||
require.Error(t, err, "An error was expected")
|
require.Error(t, err, "An error was expected")
|
||||||
require.Equal(t, err, &ErrValidationFail{Reason: "unable to retrieve valid leaf certificates"})
|
require.Equal(t, err, &ErrValidationFail{Reason: "unable to retrieve valid leaf certificates"})
|
||||||
|
|
||||||
|
@ -197,7 +188,7 @@ func TestValidateRoot(t *testing.T) {
|
||||||
// Unmarshal our signedroot
|
// Unmarshal our signedroot
|
||||||
json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
|
json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
|
||||||
|
|
||||||
err = ValidateRoot(certStore, &testSignedRoot, "docker.com/notary", TrustPinConfig{})
|
err = ValidateRoot(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{})
|
||||||
require.Error(t, err, "An error was expected")
|
require.Error(t, err, "An error was expected")
|
||||||
require.Equal(t, err, &ErrValidationFail{Reason: "unable to retrieve valid leaf certificates"})
|
require.Equal(t, err, &ErrValidationFail{Reason: "unable to retrieve valid leaf certificates"})
|
||||||
|
|
||||||
|
@ -216,7 +207,7 @@ func TestValidateRoot(t *testing.T) {
|
||||||
// Unmarshal our signedroot
|
// Unmarshal our signedroot
|
||||||
json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
|
json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
|
||||||
|
|
||||||
err = ValidateRoot(certStore, &testSignedRoot, "secure.example.com", TrustPinConfig{})
|
err = ValidateRoot(nil, &testSignedRoot, "secure.example.com", TrustPinConfig{})
|
||||||
require.Error(t, err, "An error was expected")
|
require.Error(t, err, "An error was expected")
|
||||||
require.Equal(t, err, &ErrValidationFail{Reason: "unable to retrieve valid leaf certificates"})
|
require.Equal(t, err, &ErrValidationFail{Reason: "unable to retrieve valid leaf certificates"})
|
||||||
}
|
}
|
||||||
|
@ -230,14 +221,6 @@ func TestValidateRootWithoutTOFUS(t *testing.T) {
|
||||||
defer os.RemoveAll(tempBaseDir)
|
defer os.RemoveAll(tempBaseDir)
|
||||||
require.NoError(t, err, "failed to create a temporary directory: %s", err)
|
require.NoError(t, err, "failed to create a temporary directory: %s", err)
|
||||||
|
|
||||||
// Create a X509Store
|
|
||||||
trustPath := filepath.Join(tempBaseDir, notary.TrustedCertsDir)
|
|
||||||
certStore, err := trustmanager.NewX509FilteredFileStore(
|
|
||||||
trustPath,
|
|
||||||
trustmanager.FilterCertsExpiredSha1,
|
|
||||||
)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// Execute our template
|
// Execute our template
|
||||||
templ, _ := template.New("SignedRSARootTemplate").Parse(signedRSARootTemplate)
|
templ, _ := template.New("SignedRSARootTemplate").Parse(signedRSARootTemplate)
|
||||||
templ.Execute(&signedRootBytes, SignedRSARootTemplate{RootPem: validPEMEncodedRSARoot})
|
templ.Execute(&signedRootBytes, SignedRSARootTemplate{RootPem: validPEMEncodedRSARoot})
|
||||||
|
@ -246,7 +229,7 @@ func TestValidateRootWithoutTOFUS(t *testing.T) {
|
||||||
json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
|
json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
|
||||||
|
|
||||||
// This call to ValidateRoot will fail since we are explicitly disabling TOFU and have no local certs
|
// This call to ValidateRoot will fail since we are explicitly disabling TOFU and have no local certs
|
||||||
err = ValidateRoot(certStore, &testSignedRoot, "docker.com/notary", TrustPinConfig{DisableTOFU: true})
|
err = ValidateRoot(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{DisableTOFU: true})
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,14 +242,6 @@ func TestValidateRootWithPinnedCert(t *testing.T) {
|
||||||
defer os.RemoveAll(tempBaseDir)
|
defer os.RemoveAll(tempBaseDir)
|
||||||
require.NoError(t, err, "failed to create a temporary directory: %s", err)
|
require.NoError(t, err, "failed to create a temporary directory: %s", err)
|
||||||
|
|
||||||
// Create a X509Store
|
|
||||||
trustPath := filepath.Join(tempBaseDir, notary.TrustedCertsDir)
|
|
||||||
certStore, err := trustmanager.NewX509FilteredFileStore(
|
|
||||||
trustPath,
|
|
||||||
trustmanager.FilterCertsExpiredSha1,
|
|
||||||
)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// Execute our template
|
// Execute our template
|
||||||
templ, _ := template.New("SignedRSARootTemplate").Parse(signedRSARootTemplate)
|
templ, _ := template.New("SignedRSARootTemplate").Parse(signedRSARootTemplate)
|
||||||
templ.Execute(&signedRootBytes, SignedRSARootTemplate{RootPem: validPEMEncodedRSARoot})
|
templ.Execute(&signedRootBytes, SignedRSARootTemplate{RootPem: validPEMEncodedRSARoot})
|
||||||
|
@ -275,14 +250,11 @@ func TestValidateRootWithPinnedCert(t *testing.T) {
|
||||||
json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
|
json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
|
||||||
|
|
||||||
// This call to ValidateRoot should succeed with the correct Cert ID (same as root public key ID)
|
// This call to ValidateRoot should succeed with the correct Cert ID (same as root public key ID)
|
||||||
err = ValidateRoot(certStore, &testSignedRoot, "docker.com/notary", TrustPinConfig{Certs: map[string][]string{"docker.com/notary": {rootPubKeyID}}, DisableTOFU: true})
|
err = ValidateRoot(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{Certs: map[string][]string{"docker.com/notary": {rootPubKeyID}}, DisableTOFU: true})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// purge the cert store to check another valid certs trust pinning
|
|
||||||
certStore.RemoveAll()
|
|
||||||
|
|
||||||
// This call to ValidateRoot should also succeed with the correct Cert ID (same as root public key ID), even though we passed an extra bad one
|
// This call to ValidateRoot should also succeed with the correct Cert ID (same as root public key ID), even though we passed an extra bad one
|
||||||
err = ValidateRoot(certStore, &testSignedRoot, "docker.com/notary", TrustPinConfig{Certs: map[string][]string{"docker.com/notary": {rootPubKeyID, "invalidID"}}, DisableTOFU: true})
|
err = ValidateRoot(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{Certs: map[string][]string{"docker.com/notary": {rootPubKeyID, "invalidID"}}, DisableTOFU: true})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -439,16 +411,9 @@ func TestValidateRootWithPinnerCertAndIntermediates(t *testing.T) {
|
||||||
tempBaseDir, err := ioutil.TempDir("", "notary-test-")
|
tempBaseDir, err := ioutil.TempDir("", "notary-test-")
|
||||||
defer os.RemoveAll(tempBaseDir)
|
defer os.RemoveAll(tempBaseDir)
|
||||||
require.NoError(t, err, "failed to create a temporary directory: %s", err)
|
require.NoError(t, err, "failed to create a temporary directory: %s", err)
|
||||||
// Create a X509Store
|
|
||||||
trustPath := filepath.Join(tempBaseDir, notary.TrustedCertsDir)
|
|
||||||
certStore, err := trustmanager.NewX509FilteredFileStore(
|
|
||||||
trustPath,
|
|
||||||
trustmanager.FilterCertsExpiredSha1,
|
|
||||||
)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
err = ValidateRoot(
|
err = ValidateRoot(
|
||||||
certStore,
|
nil,
|
||||||
signedRoot,
|
signedRoot,
|
||||||
"docker.io/notary/test",
|
"docker.io/notary/test",
|
||||||
TrustPinConfig{
|
TrustPinConfig{
|
||||||
|
@ -470,14 +435,6 @@ func TestValidateRootFailuresWithPinnedCert(t *testing.T) {
|
||||||
defer os.RemoveAll(tempBaseDir)
|
defer os.RemoveAll(tempBaseDir)
|
||||||
require.NoError(t, err, "failed to create a temporary directory: %s", err)
|
require.NoError(t, err, "failed to create a temporary directory: %s", err)
|
||||||
|
|
||||||
// Create a X509Store
|
|
||||||
trustPath := filepath.Join(tempBaseDir, notary.TrustedCertsDir)
|
|
||||||
certStore, err := trustmanager.NewX509FilteredFileStore(
|
|
||||||
trustPath,
|
|
||||||
trustmanager.FilterCertsExpiredSha1,
|
|
||||||
)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// Execute our template
|
// Execute our template
|
||||||
templ, _ := template.New("SignedRSARootTemplate").Parse(signedRSARootTemplate)
|
templ, _ := template.New("SignedRSARootTemplate").Parse(signedRSARootTemplate)
|
||||||
templ.Execute(&signedRootBytes, SignedRSARootTemplate{RootPem: validPEMEncodedRSARoot})
|
templ.Execute(&signedRootBytes, SignedRSARootTemplate{RootPem: validPEMEncodedRSARoot})
|
||||||
|
@ -486,23 +443,23 @@ func TestValidateRootFailuresWithPinnedCert(t *testing.T) {
|
||||||
json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
|
json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
|
||||||
|
|
||||||
// This call to ValidateRoot should fail due to an incorrect cert ID
|
// This call to ValidateRoot should fail due to an incorrect cert ID
|
||||||
err = ValidateRoot(certStore, &testSignedRoot, "docker.com/notary", TrustPinConfig{Certs: map[string][]string{"docker.com/notary": {"ABSOLUTELY NOT A CERT ID"}}, DisableTOFU: true})
|
err = ValidateRoot(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{Certs: map[string][]string{"docker.com/notary": {"ABSOLUTELY NOT A CERT ID"}}, DisableTOFU: true})
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|
||||||
// This call to ValidateRoot should fail due to an empty cert ID
|
// This call to ValidateRoot should fail due to an empty cert ID
|
||||||
err = ValidateRoot(certStore, &testSignedRoot, "docker.com/notary", TrustPinConfig{Certs: map[string][]string{"docker.com/notary": {""}}, DisableTOFU: true})
|
err = ValidateRoot(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{Certs: map[string][]string{"docker.com/notary": {""}}, DisableTOFU: true})
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|
||||||
// This call to ValidateRoot should fail due to an invalid GUN (even though the cert ID is correct), and TOFUS is set to false
|
// This call to ValidateRoot should fail due to an invalid GUN (even though the cert ID is correct), and TOFUS is set to false
|
||||||
err = ValidateRoot(certStore, &testSignedRoot, "docker.com/notary", TrustPinConfig{Certs: map[string][]string{"not_a_gun": {rootPubKeyID}}, DisableTOFU: true})
|
err = ValidateRoot(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{Certs: map[string][]string{"not_a_gun": {rootPubKeyID}}, DisableTOFU: true})
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|
||||||
// This call to ValidateRoot should fail due to an invalid cert ID, even though it's a valid key ID for targets
|
// This call to ValidateRoot should fail due to an invalid cert ID, even though it's a valid key ID for targets
|
||||||
err = ValidateRoot(certStore, &testSignedRoot, "docker.com/notary", TrustPinConfig{Certs: map[string][]string{"docker.com/notary": {targetsPubKeyID}}, DisableTOFU: true})
|
err = ValidateRoot(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{Certs: map[string][]string{"docker.com/notary": {targetsPubKeyID}}, DisableTOFU: true})
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|
||||||
// This call to ValidateRoot should succeed because we fall through to TOFUS because we have no matching GUNs under Certs
|
// This call to ValidateRoot should succeed because we fall through to TOFUS because we have no matching GUNs under Certs
|
||||||
err = ValidateRoot(certStore, &testSignedRoot, "docker.com/notary", TrustPinConfig{Certs: map[string][]string{"not_a_gun": {rootPubKeyID}}, DisableTOFU: false})
|
err = ValidateRoot(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{Certs: map[string][]string{"not_a_gun": {rootPubKeyID}}, DisableTOFU: false})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -515,44 +472,35 @@ func TestValidateRootWithPinnedCA(t *testing.T) {
|
||||||
defer os.RemoveAll(tempBaseDir)
|
defer os.RemoveAll(tempBaseDir)
|
||||||
require.NoError(t, err, "failed to create a temporary directory: %s", err)
|
require.NoError(t, err, "failed to create a temporary directory: %s", err)
|
||||||
|
|
||||||
// Create a X509Store
|
|
||||||
trustPath := filepath.Join(tempBaseDir, notary.TrustedCertsDir)
|
|
||||||
certStore, err := trustmanager.NewX509FilteredFileStore(
|
|
||||||
trustPath,
|
|
||||||
trustmanager.FilterCertsExpiredSha1,
|
|
||||||
)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
templ, _ := template.New("SignedRSARootTemplate").Parse(signedRSARootTemplate)
|
templ, _ := template.New("SignedRSARootTemplate").Parse(signedRSARootTemplate)
|
||||||
templ.Execute(&signedRootBytes, SignedRSARootTemplate{RootPem: validPEMEncodedRSARoot})
|
templ.Execute(&signedRootBytes, SignedRSARootTemplate{RootPem: validPEMEncodedRSARoot})
|
||||||
// Unmarshal our signedRoot
|
// Unmarshal our signedRoot
|
||||||
json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
|
json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
|
||||||
|
|
||||||
// This call to ValidateRoot will fail because we have an invalid path for the CA
|
// This call to ValidateRoot will fail because we have an invalid path for the CA
|
||||||
err = ValidateRoot(certStore, &testSignedRoot, "docker.com/notary", TrustPinConfig{CA: map[string]string{"docker.com/notary": filepath.Join(tempBaseDir, "nonexistent")}})
|
err = ValidateRoot(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{CA: map[string]string{"docker.com/notary": filepath.Join(tempBaseDir, "nonexistent")}})
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|
||||||
// This call to ValidateRoot will fail because we have no valid GUNs to use, and TOFUS is disabled
|
// This call to ValidateRoot will fail because we have no valid GUNs to use, and TOFUS is disabled
|
||||||
err = ValidateRoot(certStore, &testSignedRoot, "docker.com/notary", TrustPinConfig{CA: map[string]string{"othergun": filepath.Join(tempBaseDir, "nonexistent")}, DisableTOFU: true})
|
err = ValidateRoot(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{CA: map[string]string{"othergun": filepath.Join(tempBaseDir, "nonexistent")}, DisableTOFU: true})
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|
||||||
// This call to ValidateRoot will succeed because we have no valid GUNs to use and we fall back to enabled TOFUS
|
// This call to ValidateRoot will succeed because we have no valid GUNs to use and we fall back to enabled TOFUS
|
||||||
err = ValidateRoot(certStore, &testSignedRoot, "docker.com/notary", TrustPinConfig{CA: map[string]string{"othergun": filepath.Join(tempBaseDir, "nonexistent")}, DisableTOFU: false})
|
err = ValidateRoot(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{CA: map[string]string{"othergun": filepath.Join(tempBaseDir, "nonexistent")}, DisableTOFU: false})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NoError(t, certStore.RemoveAll())
|
|
||||||
|
|
||||||
// Write an invalid CA cert (not even a PEM) to the tempDir and ensure validation fails when using it
|
// Write an invalid CA cert (not even a PEM) to the tempDir and ensure validation fails when using it
|
||||||
invalidCAFilepath := filepath.Join(tempBaseDir, "invalid.ca")
|
invalidCAFilepath := filepath.Join(tempBaseDir, "invalid.ca")
|
||||||
require.NoError(t, ioutil.WriteFile(invalidCAFilepath, []byte("ABSOLUTELY NOT A PEM"), 0644))
|
require.NoError(t, ioutil.WriteFile(invalidCAFilepath, []byte("ABSOLUTELY NOT A PEM"), 0644))
|
||||||
|
|
||||||
// Using this invalid CA cert should fail on ValidateRoot
|
// Using this invalid CA cert should fail on ValidateRoot
|
||||||
err = ValidateRoot(certStore, &testSignedRoot, "docker.com/notary", TrustPinConfig{CA: map[string]string{"docker.com/notary": invalidCAFilepath}, DisableTOFU: true})
|
err = ValidateRoot(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{CA: map[string]string{"docker.com/notary": invalidCAFilepath}, DisableTOFU: true})
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|
||||||
validCAFilepath := "../fixtures/root-ca.crt"
|
validCAFilepath := "../fixtures/root-ca.crt"
|
||||||
|
|
||||||
// If we pass an invalid Certs entry in addition to this valid CA entry, since Certs has priority for pinning we will fail
|
// If we pass an invalid Certs entry in addition to this valid CA entry, since Certs has priority for pinning we will fail
|
||||||
err = ValidateRoot(certStore, &testSignedRoot, "docker.com/notary", TrustPinConfig{Certs: map[string][]string{"docker.com/notary": {"invalidID"}}, CA: map[string]string{"docker.com/notary": validCAFilepath}, DisableTOFU: true})
|
err = ValidateRoot(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{Certs: map[string][]string{"docker.com/notary": {"invalidID"}}, CA: map[string]string{"docker.com/notary": validCAFilepath}, DisableTOFU: true})
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|
||||||
// Now construct a new root with a valid cert chain, such that signatures are correct over the 'notary-signer' GUN. Pin the root-ca and validate
|
// Now construct a new root with a valid cert chain, such that signatures are correct over the 'notary-signer' GUN. Pin the root-ca and validate
|
||||||
|
@ -602,11 +550,10 @@ func TestValidateRootWithPinnedCA(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Check that we validate correctly against a pinned CA and provided bundle
|
// Check that we validate correctly against a pinned CA and provided bundle
|
||||||
err = ValidateRoot(certStore, newTestSignedRoot, "notary-signer", TrustPinConfig{CA: map[string]string{"notary-signer": validCAFilepath}, DisableTOFU: true})
|
err = ValidateRoot(nil, newTestSignedRoot, "notary-signer", TrustPinConfig{CA: map[string]string{"notary-signer": validCAFilepath}, DisableTOFU: true})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Add an expired CA for the same gun to our previous pinned bundle, ensure that we still validate correctly
|
// Add an expired CA for the same gun to our previous pinned bundle, ensure that we still validate correctly
|
||||||
certStore.RemoveAll()
|
|
||||||
goodRootCABundle, err := trustmanager.LoadCertBundleFromFile(validCAFilepath)
|
goodRootCABundle, err := trustmanager.LoadCertBundleFromFile(validCAFilepath)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
memKeyStore := trustmanager.NewKeyMemoryStore(passphraseRetriever)
|
memKeyStore := trustmanager.NewKeyMemoryStore(passphraseRetriever)
|
||||||
|
@ -623,10 +570,9 @@ func TestValidateRootWithPinnedCA(t *testing.T) {
|
||||||
require.NoError(t, ioutil.WriteFile(bundleWithExpiredCertPath, bundleWithExpiredCert, 0644))
|
require.NoError(t, ioutil.WriteFile(bundleWithExpiredCertPath, bundleWithExpiredCert, 0644))
|
||||||
|
|
||||||
// Check that we validate correctly against a pinned CA and provided bundle
|
// Check that we validate correctly against a pinned CA and provided bundle
|
||||||
err = ValidateRoot(certStore, newTestSignedRoot, "notary-signer", TrustPinConfig{CA: map[string]string{"notary-signer": bundleWithExpiredCertPath}, DisableTOFU: true})
|
err = ValidateRoot(nil, newTestSignedRoot, "notary-signer", TrustPinConfig{CA: map[string]string{"notary-signer": bundleWithExpiredCertPath}, DisableTOFU: true})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
certStore.RemoveAll()
|
|
||||||
testPubKey2, err := cryptoService.Create("root", "notary-signer", data.ECDSAKey)
|
testPubKey2, err := cryptoService.Create("root", "notary-signer", data.ECDSAKey)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
testPrivKey2, _, err := memKeyStore.GetKey(testPubKey2.ID())
|
testPrivKey2, _, err := memKeyStore.GetKey(testPubKey2.ID())
|
||||||
|
@ -638,11 +584,10 @@ func TestValidateRootWithPinnedCA(t *testing.T) {
|
||||||
allExpiredCertPath := filepath.Join(tempBaseDir, "all_expired_cert.pem")
|
allExpiredCertPath := filepath.Join(tempBaseDir, "all_expired_cert.pem")
|
||||||
require.NoError(t, ioutil.WriteFile(allExpiredCertPath, allExpiredCertBundle, 0644))
|
require.NoError(t, ioutil.WriteFile(allExpiredCertPath, allExpiredCertBundle, 0644))
|
||||||
// Now only use expired certs in the bundle, we should fail
|
// Now only use expired certs in the bundle, we should fail
|
||||||
err = ValidateRoot(certStore, newTestSignedRoot, "notary-signer", TrustPinConfig{CA: map[string]string{"notary-signer": allExpiredCertPath}, DisableTOFU: true})
|
err = ValidateRoot(nil, newTestSignedRoot, "notary-signer", TrustPinConfig{CA: map[string]string{"notary-signer": allExpiredCertPath}, DisableTOFU: true})
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|
||||||
// Add a CA cert for a that won't validate against the root leaf certificate
|
// Add a CA cert for a that won't validate against the root leaf certificate
|
||||||
certStore.RemoveAll()
|
|
||||||
testPubKey3, err := cryptoService.Create("root", "notary-signer", data.ECDSAKey)
|
testPubKey3, err := cryptoService.Create("root", "notary-signer", data.ECDSAKey)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
testPrivKey3, _, err := memKeyStore.GetKey(testPubKey3.ID())
|
testPrivKey3, _, err := memKeyStore.GetKey(testPubKey3.ID())
|
||||||
|
@ -653,7 +598,7 @@ func TestValidateRootWithPinnedCA(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
bundleWithWrongCertPath := filepath.Join(tempBaseDir, "bundle_with_expired_cert.pem")
|
bundleWithWrongCertPath := filepath.Join(tempBaseDir, "bundle_with_expired_cert.pem")
|
||||||
require.NoError(t, ioutil.WriteFile(bundleWithWrongCertPath, bundleWithWrongCert, 0644))
|
require.NoError(t, ioutil.WriteFile(bundleWithWrongCertPath, bundleWithWrongCert, 0644))
|
||||||
err = ValidateRoot(certStore, newTestSignedRoot, "notary-signer", TrustPinConfig{CA: map[string]string{"notary-signer": bundleWithWrongCertPath}, DisableTOFU: true})
|
err = ValidateRoot(nil, newTestSignedRoot, "notary-signer", TrustPinConfig{CA: map[string]string{"notary-signer": bundleWithWrongCertPath}, DisableTOFU: true})
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -666,11 +611,10 @@ func TestValidateSuccessfulRootRotation(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generates a X509Store in a temporary directory and returns the
|
// Generates certificates for two keys which have been added to the keystore.
|
||||||
// store and certificates for two keys which have been added to the keystore.
|
|
||||||
// Also returns the temporary directory so it can be cleaned up.
|
// Also returns the temporary directory so it can be cleaned up.
|
||||||
func filestoreWithTwoCerts(t *testing.T, gun, keyAlg string) (
|
func generateTwoCerts(t *testing.T, gun, keyAlg string) (
|
||||||
string, trustmanager.X509Store, *cryptoservice.CryptoService, []*x509.Certificate) {
|
string, *cryptoservice.CryptoService, []*x509.Certificate) {
|
||||||
tempBaseDir, err := ioutil.TempDir("", "notary-test-")
|
tempBaseDir, err := ioutil.TempDir("", "notary-test-")
|
||||||
require.NoError(t, err, "failed to create a temporary directory: %s", err)
|
require.NoError(t, err, "failed to create a temporary directory: %s", err)
|
||||||
|
|
||||||
|
@ -679,14 +623,6 @@ func filestoreWithTwoCerts(t *testing.T, gun, keyAlg string) (
|
||||||
|
|
||||||
cryptoService := cryptoservice.NewCryptoService(fileKeyStore)
|
cryptoService := cryptoservice.NewCryptoService(fileKeyStore)
|
||||||
|
|
||||||
// Create a store
|
|
||||||
trustPath := filepath.Join(tempBaseDir, notary.TrustedCertsDir)
|
|
||||||
certStore, err := trustmanager.NewX509FilteredFileStore(
|
|
||||||
trustPath,
|
|
||||||
trustmanager.FilterCertsExpiredSha1,
|
|
||||||
)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
certificates := make([]*x509.Certificate, 2)
|
certificates := make([]*x509.Certificate, 2)
|
||||||
for i := 0; i < 2; i++ {
|
for i := 0; i < 2; i++ {
|
||||||
pubKey, err := cryptoService.Create("root", gun, keyAlg)
|
pubKey, err := cryptoService.Create("root", gun, keyAlg)
|
||||||
|
@ -700,21 +636,18 @@ func filestoreWithTwoCerts(t *testing.T, gun, keyAlg string) (
|
||||||
|
|
||||||
certificates[i] = cert
|
certificates[i] = cert
|
||||||
}
|
}
|
||||||
return tempBaseDir, certStore, cryptoService, certificates
|
return tempBaseDir, cryptoService, certificates
|
||||||
}
|
}
|
||||||
|
|
||||||
func testValidateSuccessfulRootRotation(t *testing.T, keyAlg, rootKeyType string) {
|
func testValidateSuccessfulRootRotation(t *testing.T, keyAlg, rootKeyType string) {
|
||||||
// The gun to test
|
// The gun to test
|
||||||
gun := "docker.com/notary"
|
gun := "docker.com/notary"
|
||||||
|
|
||||||
tempBaseDir, certStore, cs, certificates := filestoreWithTwoCerts(t, gun, keyAlg)
|
tempBaseDir, cs, certificates := generateTwoCerts(t, gun, keyAlg)
|
||||||
defer os.RemoveAll(tempBaseDir)
|
defer os.RemoveAll(tempBaseDir)
|
||||||
origRootCert := certificates[0]
|
origRootCert := certificates[0]
|
||||||
replRootCert := certificates[1]
|
replRootCert := certificates[1]
|
||||||
|
|
||||||
// Add the old root cert part of trustedCertificates
|
|
||||||
certStore.AddCert(origRootCert)
|
|
||||||
|
|
||||||
// We need the PEM representation of the replacement key to put it into the TUF data
|
// We need the PEM representation of the replacement key to put it into the TUF data
|
||||||
origRootPEMCert := trustmanager.CertToPEM(origRootCert)
|
origRootPEMCert := trustmanager.CertToPEM(origRootCert)
|
||||||
replRootPEMCert := trustmanager.CertToPEM(replRootCert)
|
replRootPEMCert := trustmanager.CertToPEM(replRootCert)
|
||||||
|
@ -745,13 +678,8 @@ func testValidateSuccessfulRootRotation(t *testing.T, keyAlg, rootKeyType string
|
||||||
|
|
||||||
// This call to ValidateRoot will succeed since we are using a valid PEM
|
// This call to ValidateRoot will succeed since we are using a valid PEM
|
||||||
// encoded certificate, and have no other certificates for this CN
|
// encoded certificate, and have no other certificates for this CN
|
||||||
err = ValidateRoot(certStore, signedTestRoot, gun, TrustPinConfig{})
|
err = ValidateRoot(nil, signedTestRoot, gun, TrustPinConfig{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Finally, validate the only trusted certificate that exists is the new one
|
|
||||||
certificates = certStore.GetCertificates()
|
|
||||||
require.Len(t, certificates, 1)
|
|
||||||
require.Equal(t, certificates[0], replRootCert)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestValidateRootRotationMissingOrigSig runs through a full root certificate rotation
|
// TestValidateRootRotationMissingOrigSig runs through a full root certificate rotation
|
||||||
|
@ -767,14 +695,42 @@ func TestValidateRootRotationMissingOrigSig(t *testing.T) {
|
||||||
func testValidateRootRotationMissingOrigSig(t *testing.T, keyAlg, rootKeyType string) {
|
func testValidateRootRotationMissingOrigSig(t *testing.T, keyAlg, rootKeyType string) {
|
||||||
gun := "docker.com/notary"
|
gun := "docker.com/notary"
|
||||||
|
|
||||||
tempBaseDir, certStore, cryptoService, certificates := filestoreWithTwoCerts(
|
tempBaseDir, cryptoService, certificates := generateTwoCerts(
|
||||||
t, gun, keyAlg)
|
t, gun, keyAlg)
|
||||||
defer os.RemoveAll(tempBaseDir)
|
defer os.RemoveAll(tempBaseDir)
|
||||||
origRootCert := certificates[0]
|
origRootCert := certificates[0]
|
||||||
replRootCert := certificates[1]
|
replRootCert := certificates[1]
|
||||||
|
|
||||||
// Add the old root cert part of trustedCertificates
|
// Set up the previous root prior to rotating
|
||||||
certStore.AddCert(origRootCert)
|
// We need the PEM representation of the original key to put it into the TUF data
|
||||||
|
origRootPEMCert := trustmanager.CertToPEM(origRootCert)
|
||||||
|
|
||||||
|
// Tuf key with PEM-encoded x509 certificate
|
||||||
|
origRootKey := data.NewPublicKey(rootKeyType, origRootPEMCert)
|
||||||
|
|
||||||
|
origRootRole, err := data.NewRole(data.CanonicalRootRole, 1, []string{origRootKey.ID()}, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
origTestRoot, err := data.NewRoot(
|
||||||
|
map[string]data.PublicKey{origRootKey.ID(): origRootKey},
|
||||||
|
map[string]*data.RootRole{
|
||||||
|
data.CanonicalRootRole: &origRootRole.RootRole,
|
||||||
|
data.CanonicalTargetsRole: &origRootRole.RootRole,
|
||||||
|
data.CanonicalSnapshotRole: &origRootRole.RootRole,
|
||||||
|
data.CanonicalTimestampRole: &origRootRole.RootRole,
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
require.NoError(t, err, "Failed to create new root")
|
||||||
|
|
||||||
|
signedOrigTestRoot, err := origTestRoot.ToSigned()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// We only sign with the new key, and not with the original one.
|
||||||
|
err = signed.Sign(cryptoService, signedOrigTestRoot, []data.PublicKey{origRootKey}, 1, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
prevRoot, err := data.RootFromSigned(signedOrigTestRoot)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
// We need the PEM representation of the replacement key to put it into the TUF data
|
// We need the PEM representation of the replacement key to put it into the TUF data
|
||||||
replRootPEMCert := trustmanager.CertToPEM(replRootCert)
|
replRootPEMCert := trustmanager.CertToPEM(replRootCert)
|
||||||
|
@ -806,14 +762,8 @@ func testValidateRootRotationMissingOrigSig(t *testing.T, keyAlg, rootKeyType st
|
||||||
|
|
||||||
// This call to ValidateRoot will succeed since we are using a valid PEM
|
// This call to ValidateRoot will succeed since we are using a valid PEM
|
||||||
// encoded certificate, and have no other certificates for this CN
|
// encoded certificate, and have no other certificates for this CN
|
||||||
err = ValidateRoot(certStore, signedTestRoot, gun, TrustPinConfig{})
|
err = ValidateRoot(prevRoot, signedTestRoot, gun, TrustPinConfig{})
|
||||||
require.Error(t, err, "insuficient signatures on root")
|
require.Error(t, err, "insuficient signatures on root")
|
||||||
|
|
||||||
// Finally, validate the only trusted certificate that exists is still
|
|
||||||
// the old one
|
|
||||||
certificates = certStore.GetCertificates()
|
|
||||||
require.Len(t, certificates, 1)
|
|
||||||
require.Equal(t, certificates[0], origRootCert)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestValidateRootRotationMissingNewSig runs through a full root certificate rotation
|
// TestValidateRootRotationMissingNewSig runs through a full root certificate rotation
|
||||||
|
@ -829,21 +779,47 @@ func TestValidateRootRotationMissingNewSig(t *testing.T) {
|
||||||
func testValidateRootRotationMissingNewSig(t *testing.T, keyAlg, rootKeyType string) {
|
func testValidateRootRotationMissingNewSig(t *testing.T, keyAlg, rootKeyType string) {
|
||||||
gun := "docker.com/notary"
|
gun := "docker.com/notary"
|
||||||
|
|
||||||
tempBaseDir, certStore, cryptoService, certificates := filestoreWithTwoCerts(
|
tempBaseDir, cryptoService, certificates := generateTwoCerts(
|
||||||
t, gun, keyAlg)
|
t, gun, keyAlg)
|
||||||
defer os.RemoveAll(tempBaseDir)
|
defer os.RemoveAll(tempBaseDir)
|
||||||
origRootCert := certificates[0]
|
origRootCert := certificates[0]
|
||||||
replRootCert := certificates[1]
|
replRootCert := certificates[1]
|
||||||
|
|
||||||
// Add the old root cert part of trustedCertificates
|
|
||||||
certStore.AddCert(origRootCert)
|
|
||||||
|
|
||||||
// We need the PEM representation of the replacement key to put it into the TUF data
|
// We need the PEM representation of the replacement key to put it into the TUF data
|
||||||
origRootPEMCert := trustmanager.CertToPEM(origRootCert)
|
|
||||||
replRootPEMCert := trustmanager.CertToPEM(replRootCert)
|
replRootPEMCert := trustmanager.CertToPEM(replRootCert)
|
||||||
|
|
||||||
|
// Set up the previous root prior to rotating
|
||||||
|
// We need the PEM representation of the original key to put it into the TUF data
|
||||||
|
origRootPEMCert := trustmanager.CertToPEM(origRootCert)
|
||||||
|
|
||||||
// Tuf key with PEM-encoded x509 certificate
|
// Tuf key with PEM-encoded x509 certificate
|
||||||
origRootKey := data.NewPublicKey(rootKeyType, origRootPEMCert)
|
origRootKey := data.NewPublicKey(rootKeyType, origRootPEMCert)
|
||||||
|
|
||||||
|
origRootRole, err := data.NewRole(data.CanonicalRootRole, 1, []string{origRootKey.ID()}, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
origTestRoot, err := data.NewRoot(
|
||||||
|
map[string]data.PublicKey{origRootKey.ID(): origRootKey},
|
||||||
|
map[string]*data.RootRole{
|
||||||
|
data.CanonicalRootRole: &origRootRole.RootRole,
|
||||||
|
data.CanonicalTargetsRole: &origRootRole.RootRole,
|
||||||
|
data.CanonicalSnapshotRole: &origRootRole.RootRole,
|
||||||
|
data.CanonicalTimestampRole: &origRootRole.RootRole,
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
require.NoError(t, err, "Failed to create new root")
|
||||||
|
|
||||||
|
signedOrigTestRoot, err := origTestRoot.ToSigned()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// We only sign with the new key, and not with the original one.
|
||||||
|
err = signed.Sign(cryptoService, signedOrigTestRoot, []data.PublicKey{origRootKey}, 1, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
prevRoot, err := data.RootFromSigned(signedOrigTestRoot)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Tuf key with PEM-encoded x509 certificate
|
||||||
replRootKey := data.NewPublicKey(rootKeyType, replRootPEMCert)
|
replRootKey := data.NewPublicKey(rootKeyType, replRootPEMCert)
|
||||||
|
|
||||||
rootRole, err := data.NewRole(data.CanonicalRootRole, 1, []string{replRootKey.ID()}, nil)
|
rootRole, err := data.NewRole(data.CanonicalRootRole, 1, []string{replRootKey.ID()}, nil)
|
||||||
|
@ -870,14 +846,8 @@ func testValidateRootRotationMissingNewSig(t *testing.T, keyAlg, rootKeyType str
|
||||||
|
|
||||||
// This call to ValidateRoot will succeed since we are using a valid PEM
|
// This call to ValidateRoot will succeed since we are using a valid PEM
|
||||||
// encoded certificate, and have no other certificates for this CN
|
// encoded certificate, and have no other certificates for this CN
|
||||||
err = ValidateRoot(certStore, signedTestRoot, gun, TrustPinConfig{})
|
err = ValidateRoot(prevRoot, signedTestRoot, gun, TrustPinConfig{})
|
||||||
require.Error(t, err, "insuficient signatures on root")
|
require.Error(t, err, "insuficient signatures on root")
|
||||||
|
|
||||||
// Finally, validate the only trusted certificate that exists is still
|
|
||||||
// the old one
|
|
||||||
certificates = certStore.GetCertificates()
|
|
||||||
require.Len(t, certificates, 1)
|
|
||||||
require.Equal(t, certificates[0], origRootCert)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateTestingCertificate(rootKey data.PrivateKey, gun string) (*x509.Certificate, error) {
|
func generateTestingCertificate(rootKey data.PrivateKey, gun string) (*x509.Certificate, error) {
|
||||||
|
|
Loading…
Reference in New Issue