mirror of https://github.com/docker/docs.git
Address review comments
Signed-off-by: Riyaz Faizullabhoy <riyaz.faizullabhoy@docker.com>
This commit is contained in:
parent
ca9fc99ba5
commit
ed1bf1a0a6
|
@ -881,12 +881,7 @@ func (r *NotaryRepository) validateRoot(rootJSON []byte, fromRemote bool) (*data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = trustpinning.ValidateRoot(prevRoot, root, r.gun, r.trustPinning)
|
return trustpinning.ValidateRoot(prevRoot, root, r.gun, r.trustPinning)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return data.RootFromSigned(root)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RotateKey removes all existing keys associated with the role, and either
|
// RotateKey removes all existing keys associated with the role, and either
|
||||||
|
|
|
@ -1374,7 +1374,7 @@ func TestValidateRootRotationWithOldRole(t *testing.T) {
|
||||||
keyIDs := make([]string, len(threeKeys))
|
keyIDs := make([]string, len(threeKeys))
|
||||||
for i := 0; i < len(threeKeys); i++ {
|
for i := 0; i < len(threeKeys); i++ {
|
||||||
threeKeys[i], err = testutils.CreateKey(
|
threeKeys[i], err = testutils.CreateKey(
|
||||||
serverSwizzler.CryptoService, "docker.com/notary", data.CanonicalRootRole)
|
serverSwizzler.CryptoService, "docker.com/notary", data.CanonicalRootRole, data.ECDSAKey)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
keyIDs[i] = threeKeys[i].ID()
|
keyIDs[i] = threeKeys[i].ID()
|
||||||
signedRoot.Signed.Keys[keyIDs[i]] = threeKeys[i]
|
signedRoot.Signed.Keys[keyIDs[i]] = threeKeys[i]
|
||||||
|
@ -1392,7 +1392,7 @@ func TestValidateRootRotationWithOldRole(t *testing.T) {
|
||||||
// --- threshold back to 1
|
// --- threshold back to 1
|
||||||
|
|
||||||
replacementKey, err := testutils.CreateKey(
|
replacementKey, err := testutils.CreateKey(
|
||||||
serverSwizzler.CryptoService, "docker.com/notary", data.CanonicalRootRole)
|
serverSwizzler.CryptoService, "docker.com/notary", data.CanonicalRootRole, data.ECDSAKey)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
signedRoot.Signed.Version++
|
signedRoot.Signed.Version++
|
||||||
signedRoot.Signed.Keys[replacementKey.ID()] = replacementKey
|
signedRoot.Signed.Keys[replacementKey.ID()] = replacementKey
|
||||||
|
@ -1416,7 +1416,7 @@ func TestValidateRootRotationWithOldRole(t *testing.T) {
|
||||||
// --- latest root role)
|
// --- latest root role)
|
||||||
signedRoot.Signed.Version++
|
signedRoot.Signed.Version++
|
||||||
snapKey, err := testutils.CreateKey(
|
snapKey, err := testutils.CreateKey(
|
||||||
serverSwizzler.CryptoService, "docker.com/notary", data.CanonicalSnapshotRole)
|
serverSwizzler.CryptoService, "docker.com/notary", data.CanonicalSnapshotRole, data.ECDSAKey)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
signedRoot.Signed.Keys[snapKey.ID()] = snapKey
|
signedRoot.Signed.Keys[snapKey.ID()] = snapKey
|
||||||
signedRoot.Signed.Roles[data.CanonicalSnapshotRole].KeyIDs = []string{snapKey.ID()}
|
signedRoot.Signed.Roles[data.CanonicalSnapshotRole].KeyIDs = []string{snapKey.ID()}
|
||||||
|
|
|
@ -53,8 +53,9 @@ func prettyFormatCertIDs(certs []*x509.Certificate) string {
|
||||||
ValidateRoot receives a new root, validates its correctness and attempts to
|
ValidateRoot receives a new root, validates its correctness and attempts to
|
||||||
do root key rotation if needed.
|
do root key rotation if needed.
|
||||||
|
|
||||||
First we list the current trusted certificates we have for a particular GUN. If
|
First we check if we have any trusted certificates for a particular GUN in
|
||||||
that list is non-empty means that we've already seen this repository before, and
|
a previous root, if we have one. If the previous root is not nil and we find
|
||||||
|
certificates for this GUN, we've already seen this repository before, and
|
||||||
have a list of trusted certificates for it. In this case, we use this list of
|
have a list of trusted certificates for it. In this case, we use this list of
|
||||||
certificates to attempt to validate this root file.
|
certificates to attempt to validate this root file.
|
||||||
|
|
||||||
|
@ -86,16 +87,16 @@ 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(prevRoot *data.SignedRoot, root *data.Signed, gun string, trustPinning TrustPinConfig) error {
|
func ValidateRoot(prevRoot *data.SignedRoot, root *data.Signed, gun string, trustPinning TrustPinConfig) (*data.SignedRoot, 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 {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
rootRole, err := signedRoot.BuildBaseRole(data.CanonicalRootRole)
|
rootRole, err := signedRoot.BuildBaseRole(data.CanonicalRootRole)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -103,29 +104,38 @@ func ValidateRoot(prevRoot *data.SignedRoot, root *data.Signed, gun string, trus
|
||||||
certsFromRoot, err := validRootLeafCerts(allLeafCerts, gun, true)
|
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 nil, &ErrValidationFail{Reason: "unable to retrieve valid leaf certificates"}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve all the trusted certificates from our previous root
|
// If we have a previous root, let's try to use it to validate that this new root is valid.
|
||||||
// Note that we do not validate expiries here since our originally trusted root might have expired certs
|
if prevRoot != nil {
|
||||||
allTrustedLeafCerts, allTrustedIntCerts := parseAllCerts(prevRoot)
|
// Retrieve all the trusted certificates from our previous root
|
||||||
trustedLeafCerts, err := validRootLeafCerts(allTrustedLeafCerts, gun, false)
|
// Note that we do not validate expiries here since our originally trusted root might have expired certs
|
||||||
// If we have certificates that match this specific GUN, let's make sure to
|
allTrustedLeafCerts, allTrustedIntCerts := parseAllCerts(prevRoot)
|
||||||
// use them first to validate that this new root is valid.
|
trustedLeafCerts, err := validRootLeafCerts(allTrustedLeafCerts, gun, false)
|
||||||
if len(trustedLeafCerts) != 0 {
|
|
||||||
|
// Use the certificates we found in the previous root for the GUN to verify its signatures
|
||||||
|
// This could potentially be an empty set, in which case we will fail to verify
|
||||||
logrus.Debugf("found %d valid root leaf certificates for %s: %s", len(trustedLeafCerts), gun,
|
logrus.Debugf("found %d valid root leaf certificates for %s: %s", len(trustedLeafCerts), gun,
|
||||||
prettyFormatCertIDs(trustedLeafCerts))
|
prettyFormatCertIDs(trustedLeafCerts))
|
||||||
|
|
||||||
|
// Extract the previous root's threshold for signature verification
|
||||||
|
prevRootRoleData, ok := prevRoot.Signed.Roles[data.CanonicalRootRole]
|
||||||
|
if !ok {
|
||||||
|
return nil, &ErrValidationFail{Reason: "could not retrieve previous root role data"}
|
||||||
|
}
|
||||||
|
|
||||||
err = signed.VerifySignatures(
|
err = signed.VerifySignatures(
|
||||||
root, data.BaseRole{Keys: trustmanager.CertsToKeys(trustedLeafCerts, allTrustedIntCerts), Threshold: 1})
|
root, data.BaseRole{Keys: trustmanager.CertsToKeys(trustedLeafCerts, allTrustedIntCerts), Threshold: prevRootRoleData.Threshold})
|
||||||
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 nil, &ErrValidationFail{Reason: "failed to validate data with current trusted certificates"}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logrus.Debugf("found no currently valid root certificates for %s, using trust_pinning config to bootstrap trust", gun)
|
logrus.Debugf("found no currently valid root certificates for %s, using trust_pinning config to bootstrap trust", gun)
|
||||||
trustPinCheckFunc, err := NewTrustPinChecker(trustPinning, gun)
|
trustPinCheckFunc, err := NewTrustPinChecker(trustPinning, gun)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &ErrValidationFail{Reason: err.Error()}
|
return nil, &ErrValidationFail{Reason: err.Error()}
|
||||||
}
|
}
|
||||||
|
|
||||||
validPinnedCerts := []*x509.Certificate{}
|
validPinnedCerts := []*x509.Certificate{}
|
||||||
|
@ -140,7 +150,7 @@ func ValidateRoot(prevRoot *data.SignedRoot, root *data.Signed, gun string, trus
|
||||||
validPinnedCerts = append(validPinnedCerts, cert)
|
validPinnedCerts = append(validPinnedCerts, cert)
|
||||||
}
|
}
|
||||||
if len(validPinnedCerts) == 0 {
|
if len(validPinnedCerts) == 0 {
|
||||||
return &ErrValidationFail{Reason: "unable to match any certificates to trust_pinning config"}
|
return nil, &ErrValidationFail{Reason: "unable to match any certificates to trust_pinning config"}
|
||||||
}
|
}
|
||||||
certsFromRoot = validPinnedCerts
|
certsFromRoot = validPinnedCerts
|
||||||
}
|
}
|
||||||
|
@ -152,11 +162,11 @@ func ValidateRoot(prevRoot *data.SignedRoot, root *data.Signed, gun string, trus
|
||||||
Keys: trustmanager.CertsToKeys(certsFromRoot, allIntCerts), Threshold: rootRole.Threshold})
|
Keys: trustmanager.CertsToKeys(certsFromRoot, allIntCerts), Threshold: rootRole.Threshold})
|
||||||
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 integrity of roots"}
|
return nil, &ErrValidationFail{Reason: "failed to validate integrity of roots"}
|
||||||
}
|
}
|
||||||
|
|
||||||
logrus.Debugf("Root validation succeeded for %s", gun)
|
logrus.Debugf("Root validation succeeded for %s", gun)
|
||||||
return nil
|
return signedRoot, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// validRootLeafCerts returns a list of possibly (if checkExpiry is true) non-expired, non-sha1 certificates
|
// validRootLeafCerts returns a list of possibly (if checkExpiry is true) non-expired, non-sha1 certificates
|
||||||
|
|
|
@ -22,6 +22,7 @@ import (
|
||||||
"github.com/docker/notary/trustmanager"
|
"github.com/docker/notary/trustmanager"
|
||||||
"github.com/docker/notary/tuf/data"
|
"github.com/docker/notary/tuf/data"
|
||||||
"github.com/docker/notary/tuf/signed"
|
"github.com/docker/notary/tuf/signed"
|
||||||
|
"github.com/docker/notary/tuf/testutils"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -61,12 +62,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(nil, &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(nil, &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"})
|
||||||
|
|
||||||
|
@ -80,7 +81,7 @@ func TestValidateRoot(t *testing.T) {
|
||||||
// Unmarshal our signedroot
|
// Unmarshal our signedroot
|
||||||
json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
|
json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
|
||||||
|
|
||||||
err = ValidateRoot(nil, &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")
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -93,7 +94,7 @@ func TestValidateRoot(t *testing.T) {
|
||||||
// Unmarshal our signedroot
|
// Unmarshal our signedroot
|
||||||
json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
|
json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
|
||||||
|
|
||||||
err = ValidateRoot(nil, &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"})
|
||||||
|
|
||||||
|
@ -108,7 +109,7 @@ func TestValidateRoot(t *testing.T) {
|
||||||
// Unmarshal our signedroot
|
// Unmarshal our signedroot
|
||||||
json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
|
json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
|
||||||
|
|
||||||
err = ValidateRoot(nil, &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"})
|
||||||
|
|
||||||
|
@ -127,7 +128,7 @@ func TestValidateRoot(t *testing.T) {
|
||||||
// Unmarshal our signedroot
|
// Unmarshal our signedroot
|
||||||
json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
|
json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
|
||||||
|
|
||||||
err = ValidateRoot(nil, &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"})
|
||||||
}
|
}
|
||||||
|
@ -149,7 +150,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(nil, &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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,14 +169,18 @@ func TestValidateRootWithPinnedCert(t *testing.T) {
|
||||||
|
|
||||||
// Unmarshal our signedroot
|
// Unmarshal our signedroot
|
||||||
json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
|
json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
|
||||||
|
typedSignedRoot, err := data.RootFromSigned(&testSignedRoot)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
// 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(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{Certs: map[string][]string{"docker.com/notary": {rootPubKeyID}}, DisableTOFU: true})
|
validatedSignedRoot, 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)
|
||||||
|
require.Equal(t, validatedSignedRoot, typedSignedRoot)
|
||||||
|
|
||||||
// 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(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{Certs: map[string][]string{"docker.com/notary": {rootPubKeyID, "invalidID"}}, DisableTOFU: true})
|
validatedSignedRoot, 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)
|
||||||
|
require.Equal(t, validatedSignedRoot, typedSignedRoot)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateRootWithPinnerCertAndIntermediates(t *testing.T) {
|
func TestValidateRootWithPinnerCertAndIntermediates(t *testing.T) {
|
||||||
|
@ -328,11 +333,14 @@ func TestValidateRootWithPinnerCertAndIntermediates(t *testing.T) {
|
||||||
err = signed.Sign(cs, signedRoot, []data.PublicKey{ecdsax509Key}, 1, nil)
|
err = signed.Sign(cs, signedRoot, []data.PublicKey{ecdsax509Key}, 1, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
typedSignedRoot, err := data.RootFromSigned(signedRoot)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
err = ValidateRoot(
|
validatedRoot, err := ValidateRoot(
|
||||||
nil,
|
nil,
|
||||||
signedRoot,
|
signedRoot,
|
||||||
"docker.io/notary/test",
|
"docker.io/notary/test",
|
||||||
|
@ -344,6 +352,7 @@ func TestValidateRootWithPinnerCertAndIntermediates(t *testing.T) {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
require.NoError(t, err, "failed to validate certID with intermediate")
|
require.NoError(t, err, "failed to validate certID with intermediate")
|
||||||
|
require.Equal(t, typedSignedRoot, validatedRoot)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateRootFailuresWithPinnedCert(t *testing.T) {
|
func TestValidateRootFailuresWithPinnedCert(t *testing.T) {
|
||||||
|
@ -361,26 +370,29 @@ func TestValidateRootFailuresWithPinnedCert(t *testing.T) {
|
||||||
|
|
||||||
// Unmarshal our signedroot
|
// Unmarshal our signedroot
|
||||||
json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
|
json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
|
||||||
|
typedSignedRoot, err := data.RootFromSigned(&testSignedRoot)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
// 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(nil, &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(nil, &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(nil, &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(nil, &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(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{Certs: map[string][]string{"not_a_gun": {rootPubKeyID}}, DisableTOFU: false})
|
validatedRoot, 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)
|
||||||
|
require.Equal(t, typedSignedRoot, validatedRoot)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateRootWithPinnedCA(t *testing.T) {
|
func TestValidateRootWithPinnedCA(t *testing.T) {
|
||||||
|
@ -396,31 +408,34 @@ func TestValidateRootWithPinnedCA(t *testing.T) {
|
||||||
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)
|
||||||
|
typedSignedRoot, err := data.RootFromSigned(&testSignedRoot)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
// 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(nil, &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(nil, &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(nil, &testSignedRoot, "docker.com/notary", TrustPinConfig{CA: map[string]string{"othergun": filepath.Join(tempBaseDir, "nonexistent")}, DisableTOFU: false})
|
validatedRoot, 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.Equal(t, typedSignedRoot, validatedRoot)
|
||||||
|
|
||||||
// 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(nil, &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(nil, &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
|
||||||
|
@ -469,10 +484,14 @@ func TestValidateRootWithPinnedCA(t *testing.T) {
|
||||||
err = signed.Sign(cs, newTestSignedRoot, []data.PublicKey{newRootKey}, 1, nil)
|
err = signed.Sign(cs, newTestSignedRoot, []data.PublicKey{newRootKey}, 1, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Check that we validate correctly against a pinned CA and provided bundle
|
newTypedSignedRoot, err := data.RootFromSigned(newTestSignedRoot)
|
||||||
err = ValidateRoot(nil, newTestSignedRoot, "notary-signer", TrustPinConfig{CA: map[string]string{"notary-signer": validCAFilepath}, DisableTOFU: true})
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Check that we validate correctly against a pinned CA and provided bundle
|
||||||
|
validatedRoot, err = ValidateRoot(nil, newTestSignedRoot, "notary-signer", TrustPinConfig{CA: map[string]string{"notary-signer": validCAFilepath}, DisableTOFU: true})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, newTypedSignedRoot, validatedRoot)
|
||||||
|
|
||||||
// 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
|
||||||
goodRootCABundle, err := trustmanager.LoadCertBundleFromFile(validCAFilepath)
|
goodRootCABundle, err := trustmanager.LoadCertBundleFromFile(validCAFilepath)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -490,8 +509,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(nil, newTestSignedRoot, "notary-signer", TrustPinConfig{CA: map[string]string{"notary-signer": bundleWithExpiredCertPath}, DisableTOFU: true})
|
validatedRoot, err = ValidateRoot(nil, newTestSignedRoot, "notary-signer", TrustPinConfig{CA: map[string]string{"notary-signer": bundleWithExpiredCertPath}, DisableTOFU: true})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, newTypedSignedRoot, validatedRoot)
|
||||||
|
|
||||||
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)
|
||||||
|
@ -504,7 +524,7 @@ 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(nil, 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
|
||||||
|
@ -518,7 +538,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(nil, 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -531,49 +551,16 @@ func TestValidateSuccessfulRootRotation(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generates certificates for two keys which have been added to the keystore.
|
|
||||||
// Also returns the temporary directory so it can be cleaned up.
|
|
||||||
func generateTwoCerts(t *testing.T, gun, keyAlg string) (
|
|
||||||
string, *cryptoservice.CryptoService, []*x509.Certificate) {
|
|
||||||
tempBaseDir, err := ioutil.TempDir("", "notary-test-")
|
|
||||||
require.NoError(t, err, "failed to create a temporary directory: %s", err)
|
|
||||||
|
|
||||||
fileKeyStore, err := trustmanager.NewKeyFileStore(tempBaseDir, passphraseRetriever)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
cryptoService := cryptoservice.NewCryptoService(fileKeyStore)
|
|
||||||
|
|
||||||
certificates := make([]*x509.Certificate, 2)
|
|
||||||
for i := 0; i < 2; i++ {
|
|
||||||
pubKey, err := cryptoService.Create("root", gun, keyAlg)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
key, _, err := fileKeyStore.GetKey(pubKey.ID())
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
cert, err := generateTestingCertificate(key, gun)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
certificates[i] = cert
|
|
||||||
}
|
|
||||||
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, cs, certificates := generateTwoCerts(t, gun, keyAlg)
|
memKeyStore := trustmanager.NewKeyMemoryStore(passphraseRetriever)
|
||||||
defer os.RemoveAll(tempBaseDir)
|
cs := cryptoservice.NewCryptoService(memKeyStore)
|
||||||
origRootCert := certificates[0]
|
|
||||||
replRootCert := certificates[1]
|
|
||||||
|
|
||||||
// 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, err := testutils.CreateKey(cs, gun, data.CanonicalRootRole, keyAlg)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
origRootRole, err := data.NewRole(data.CanonicalRootRole, 1, []string{origRootKey.ID()}, nil)
|
origRootRole, err := data.NewRole(data.CanonicalRootRole, 1, []string{origRootKey.ID()}, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -593,17 +580,14 @@ func testValidateSuccessfulRootRotation(t *testing.T, keyAlg, rootKeyType string
|
||||||
signedOrigTestRoot, err := origTestRoot.ToSigned()
|
signedOrigTestRoot, err := origTestRoot.ToSigned()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// We only sign with the new key, and not with the original one.
|
|
||||||
err = signed.Sign(cs, signedOrigTestRoot, []data.PublicKey{origRootKey}, 1, nil)
|
err = signed.Sign(cs, signedOrigTestRoot, []data.PublicKey{origRootKey}, 1, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
prevRoot, err := data.RootFromSigned(signedOrigTestRoot)
|
prevRoot, err := data.RootFromSigned(signedOrigTestRoot)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// We need the PEM representation of the replacement key to put it into the TUF data
|
|
||||||
replRootPEMCert := trustmanager.CertToPEM(replRootCert)
|
|
||||||
|
|
||||||
// Tuf key with PEM-encoded x509 certificate
|
// Tuf key with PEM-encoded x509 certificate
|
||||||
replRootKey := data.NewPublicKey(rootKeyType, replRootPEMCert)
|
replRootKey, err := testutils.CreateKey(cs, gun, data.CanonicalRootRole, keyAlg)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
rootRole, err := data.NewRole(data.CanonicalRootRole, 1, []string{replRootKey.ID()}, nil)
|
rootRole, err := data.NewRole(data.CanonicalRootRole, 1, []string{replRootKey.ID()}, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -625,10 +609,14 @@ func testValidateSuccessfulRootRotation(t *testing.T, keyAlg, rootKeyType string
|
||||||
err = signed.Sign(cs, signedTestRoot, []data.PublicKey{replRootKey, origRootKey}, 2, nil)
|
err = signed.Sign(cs, signedTestRoot, []data.PublicKey{replRootKey, origRootKey}, 2, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
typedSignedRoot, err := data.RootFromSigned(signedTestRoot)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
// 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(prevRoot, signedTestRoot, gun, TrustPinConfig{})
|
validatedRoot, err := ValidateRoot(prevRoot, signedTestRoot, gun, TrustPinConfig{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, typedSignedRoot, validatedRoot)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestValidateRootRotationMissingOrigSig runs through a full root certificate rotation
|
// TestValidateRootRotationMissingOrigSig runs through a full root certificate rotation
|
||||||
|
@ -644,18 +632,12 @@ 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, cryptoService, certificates := generateTwoCerts(
|
memKeyStore := trustmanager.NewKeyMemoryStore(passphraseRetriever)
|
||||||
t, gun, keyAlg)
|
cs := cryptoservice.NewCryptoService(memKeyStore)
|
||||||
defer os.RemoveAll(tempBaseDir)
|
|
||||||
origRootCert := certificates[0]
|
|
||||||
replRootCert := certificates[1]
|
|
||||||
|
|
||||||
// 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, err := testutils.CreateKey(cs, gun, data.CanonicalRootRole, keyAlg)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
origRootRole, err := data.NewRole(data.CanonicalRootRole, 1, []string{origRootKey.ID()}, nil)
|
origRootRole, err := data.NewRole(data.CanonicalRootRole, 1, []string{origRootKey.ID()}, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -675,17 +657,14 @@ func testValidateRootRotationMissingOrigSig(t *testing.T, keyAlg, rootKeyType st
|
||||||
signedOrigTestRoot, err := origTestRoot.ToSigned()
|
signedOrigTestRoot, err := origTestRoot.ToSigned()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// We only sign with the new key, and not with the original one.
|
err = signed.Sign(cs, signedOrigTestRoot, []data.PublicKey{origRootKey}, 1, nil)
|
||||||
err = signed.Sign(cryptoService, signedOrigTestRoot, []data.PublicKey{origRootKey}, 1, nil)
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
prevRoot, err := data.RootFromSigned(signedOrigTestRoot)
|
prevRoot, err := data.RootFromSigned(signedOrigTestRoot)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// We need the PEM representation of the replacement key to put it into the TUF data
|
|
||||||
replRootPEMCert := trustmanager.CertToPEM(replRootCert)
|
|
||||||
|
|
||||||
// Tuf key with PEM-encoded x509 certificate
|
// Tuf key with PEM-encoded x509 certificate
|
||||||
replRootKey := data.NewPublicKey(rootKeyType, replRootPEMCert)
|
replRootKey, err := testutils.CreateKey(cs, gun, data.CanonicalRootRole, keyAlg)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
rootRole, err := data.NewRole(data.CanonicalRootRole, 1, []string{replRootKey.ID()}, nil)
|
rootRole, err := data.NewRole(data.CanonicalRootRole, 1, []string{replRootKey.ID()}, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -706,12 +685,12 @@ func testValidateRootRotationMissingOrigSig(t *testing.T, keyAlg, rootKeyType st
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// We only sign with the new key, and not with the original one.
|
// We only sign with the new key, and not with the original one.
|
||||||
err = signed.Sign(cryptoService, signedTestRoot, []data.PublicKey{replRootKey}, 1, nil)
|
err = signed.Sign(cs, signedTestRoot, []data.PublicKey{replRootKey}, 1, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// 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(prevRoot, 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")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -728,21 +707,12 @@ 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, cryptoService, certificates := generateTwoCerts(
|
memKeyStore := trustmanager.NewKeyMemoryStore(passphraseRetriever)
|
||||||
t, gun, keyAlg)
|
cs := cryptoservice.NewCryptoService(memKeyStore)
|
||||||
defer os.RemoveAll(tempBaseDir)
|
|
||||||
origRootCert := certificates[0]
|
|
||||||
replRootCert := certificates[1]
|
|
||||||
|
|
||||||
// We need the PEM representation of the replacement key to put it into the TUF data
|
|
||||||
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, err := testutils.CreateKey(cs, gun, data.CanonicalRootRole, keyAlg)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
origRootRole, err := data.NewRole(data.CanonicalRootRole, 1, []string{origRootKey.ID()}, nil)
|
origRootRole, err := data.NewRole(data.CanonicalRootRole, 1, []string{origRootKey.ID()}, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -762,14 +732,14 @@ func testValidateRootRotationMissingNewSig(t *testing.T, keyAlg, rootKeyType str
|
||||||
signedOrigTestRoot, err := origTestRoot.ToSigned()
|
signedOrigTestRoot, err := origTestRoot.ToSigned()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// We only sign with the new key, and not with the original one.
|
err = signed.Sign(cs, signedOrigTestRoot, []data.PublicKey{origRootKey}, 1, nil)
|
||||||
err = signed.Sign(cryptoService, signedOrigTestRoot, []data.PublicKey{origRootKey}, 1, nil)
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
prevRoot, err := data.RootFromSigned(signedOrigTestRoot)
|
prevRoot, err := data.RootFromSigned(signedOrigTestRoot)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Tuf key with PEM-encoded x509 certificate
|
// Tuf key with PEM-encoded x509 certificate
|
||||||
replRootKey := data.NewPublicKey(rootKeyType, replRootPEMCert)
|
replRootKey, err := testutils.CreateKey(cs, gun, data.CanonicalRootRole, keyAlg)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
rootRole, err := data.NewRole(data.CanonicalRootRole, 1, []string{replRootKey.ID()}, nil)
|
rootRole, err := data.NewRole(data.CanonicalRootRole, 1, []string{replRootKey.ID()}, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -790,12 +760,12 @@ func testValidateRootRotationMissingNewSig(t *testing.T, keyAlg, rootKeyType str
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// We only sign with the old key, and not with the new one
|
// We only sign with the old key, and not with the new one
|
||||||
err = signed.Sign(cryptoService, signedTestRoot, []data.PublicKey{origRootKey}, 1, nil)
|
err = signed.Sign(cs, signedTestRoot, []data.PublicKey{origRootKey}, 1, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// 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(prevRoot, 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")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,8 +19,8 @@ import (
|
||||||
|
|
||||||
// CreateKey creates a new key inside the cryptoservice for the given role and gun,
|
// CreateKey creates a new key inside the cryptoservice for the given role and gun,
|
||||||
// returning the public key. If the role is a root role, create an x509 key.
|
// returning the public key. If the role is a root role, create an x509 key.
|
||||||
func CreateKey(cs signed.CryptoService, gun, role string) (data.PublicKey, error) {
|
func CreateKey(cs signed.CryptoService, gun, role, keyAlgorithm string) (data.PublicKey, error) {
|
||||||
key, err := cs.Create(role, gun, data.ECDSAKey)
|
key, err := cs.Create(role, gun, keyAlgorithm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,13 @@ func CreateKey(cs signed.CryptoService, gun, role string) (data.PublicKey, error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
key = data.NewECDSAx509PublicKey(trustmanager.CertToPEM(cert))
|
// Keep the x509 key type consistent with the key's algorithm
|
||||||
|
if keyAlgorithm == data.RSAKey {
|
||||||
|
key = data.NewRSAx509PublicKey(trustmanager.CertToPEM(cert))
|
||||||
|
} else {
|
||||||
|
key = data.NewECDSAx509PublicKey(trustmanager.CertToPEM(cert))
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return key, nil
|
return key, nil
|
||||||
}
|
}
|
||||||
|
@ -50,7 +56,7 @@ func EmptyRepo(gun string, delegationRoles ...string) (*tuf.Repo, signed.CryptoS
|
||||||
|
|
||||||
baseRoles := map[string]data.BaseRole{}
|
baseRoles := map[string]data.BaseRole{}
|
||||||
for _, role := range data.BaseRoles {
|
for _, role := range data.BaseRoles {
|
||||||
key, err := CreateKey(cs, gun, role)
|
key, err := CreateKey(cs, gun, role, data.ECDSAKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
@ -77,7 +83,7 @@ func EmptyRepo(gun string, delegationRoles ...string) (*tuf.Repo, signed.CryptoS
|
||||||
sort.Strings(delegationRoles)
|
sort.Strings(delegationRoles)
|
||||||
for _, delgName := range delegationRoles {
|
for _, delgName := range delegationRoles {
|
||||||
// create a delegations key and a delegation in the tuf repo
|
// create a delegations key and a delegation in the tuf repo
|
||||||
delgKey, err := CreateKey(cs, gun, delgName)
|
delgKey, err := CreateKey(cs, gun, delgName, data.ECDSAKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -269,7 +269,7 @@ func (m *MetadataSwizzler) SignMetadataWithInvalidKey(role string) error {
|
||||||
|
|
||||||
// create an invalid key, but not in the existing CryptoService
|
// create an invalid key, but not in the existing CryptoService
|
||||||
cs := cryptoservice.NewCryptoService(trustmanager.NewKeyMemoryStore(passphrase.ConstantRetriever("")))
|
cs := cryptoservice.NewCryptoService(trustmanager.NewKeyMemoryStore(passphrase.ConstantRetriever("")))
|
||||||
key, err := CreateKey(cs, m.Gun, role)
|
key, err := CreateKey(cs, m.Gun, role, data.ECDSAKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -466,7 +466,7 @@ func (m *MetadataSwizzler) RotateKey(role string, key data.PublicKey) error {
|
||||||
// ChangeRootKey swaps out the root key with a new key, and re-signs the metadata
|
// ChangeRootKey swaps out the root key with a new key, and re-signs the metadata
|
||||||
// with the new key
|
// with the new key
|
||||||
func (m *MetadataSwizzler) ChangeRootKey() error {
|
func (m *MetadataSwizzler) ChangeRootKey() error {
|
||||||
key, err := CreateKey(m.CryptoService, m.Gun, data.CanonicalRootRole)
|
key, err := CreateKey(m.CryptoService, m.Gun, data.CanonicalRootRole, data.ECDSAKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue