mirror of https://github.com/docker/docs.git
Handle cert bundles as key IDs
Signed-off-by: Riyaz Faizullabhoy <riyaz.faizullabhoy@docker.com>
This commit is contained in:
parent
4776700215
commit
26a95ef5a3
|
@ -556,12 +556,34 @@ func CertToKey(cert *x509.Certificate) data.PublicKey {
|
|||
}
|
||||
}
|
||||
|
||||
// CertsToKeys transforms each of the input certificates into it's corresponding
|
||||
// CertsToKeys transforms each of the input certificate chains into its corresponding
|
||||
// PublicKey
|
||||
func CertsToKeys(certs []*x509.Certificate) map[string]data.PublicKey {
|
||||
func CertsToKeys(leafCerts []*x509.Certificate, intCerts map[string][]*x509.Certificate) map[string]data.PublicKey {
|
||||
keys := make(map[string]data.PublicKey)
|
||||
for _, cert := range certs {
|
||||
newKey := CertToKey(cert)
|
||||
for _, leafCert := range leafCerts {
|
||||
certBundle := []*x509.Certificate{leafCert}
|
||||
certID, err := FingerprintCert(leafCert)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if intCertsForLeafs, ok := intCerts[certID]; ok {
|
||||
certBundle = append(certBundle, intCertsForLeafs...)
|
||||
}
|
||||
certChainPEM, err := CertChainToPEM(certBundle)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
var newKey data.PublicKey
|
||||
// Use the leaf cert's public key algorithm for typing
|
||||
switch leafCert.PublicKeyAlgorithm {
|
||||
case x509.RSA:
|
||||
newKey = data.NewRSAx509PublicKey(certChainPEM)
|
||||
case x509.ECDSA:
|
||||
newKey = data.NewECDSAx509PublicKey(certChainPEM)
|
||||
default:
|
||||
logrus.Debugf("Unknown key type parsed from certificate: %v", leafCert.PublicKeyAlgorithm)
|
||||
continue
|
||||
}
|
||||
keys[newKey.ID()] = newKey
|
||||
}
|
||||
return keys
|
||||
|
@ -593,6 +615,7 @@ func NewCertificate(gun string, startTime, endTime time.Time) (*x509.Certificate
|
|||
// X509PublicKeyID returns a public key ID as a string, given a
|
||||
// data.PublicKey that contains an X509 Certificate
|
||||
func X509PublicKeyID(certPubKey data.PublicKey) (string, error) {
|
||||
// Note that this only loads the first certificate from the public key
|
||||
cert, err := LoadCertFromPEM(certPubKey.Public())
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
|
|
@ -30,8 +30,8 @@ func TestCertsToKeys(t *testing.T) {
|
|||
// Get our certList with Leaf Cert and Intermediate
|
||||
certList := []*x509.Certificate{leafCert, intermediateCA, rootCA}
|
||||
|
||||
// Call CertsToKEys
|
||||
keys := CertsToKeys(certList)
|
||||
// Call CertsToKeys
|
||||
keys := CertsToKeys(certList, make(map[string][]*x509.Certificate))
|
||||
require.NotNil(t, keys)
|
||||
require.Len(t, keys, 3)
|
||||
|
||||
|
@ -44,6 +44,13 @@ func TestCertsToKeys(t *testing.T) {
|
|||
newKeys = GetIntermediateCerts(certList)
|
||||
require.NotNil(t, newKeys)
|
||||
require.Len(t, newKeys, 2)
|
||||
|
||||
// Try calling CertToKeys on a junk leaf cert that won't fingerprint
|
||||
emptyCert := x509.Certificate{}
|
||||
// Also try changing the pre-existing leaf cert into an invalid algorithm
|
||||
leafCert.PublicKeyAlgorithm = x509.DSA
|
||||
keys = CertsToKeys([]*x509.Certificate{&emptyCert, leafCert}, make(map[string][]*x509.Certificate))
|
||||
require.Empty(t, keys)
|
||||
}
|
||||
|
||||
func TestNewCertificate(t *testing.T) {
|
||||
|
|
|
@ -117,7 +117,7 @@ func ValidateRoot(certStore trustmanager.X509Store, root *data.Signed, gun strin
|
|||
if len(trustedCerts) != 0 {
|
||||
logrus.Debugf("found %d valid root certificates for %s: %s", len(trustedCerts), gun,
|
||||
prettyFormatCertIDs(trustedCerts))
|
||||
err = signed.VerifyRoot(root, 0, trustmanager.CertsToKeys(trustedCerts))
|
||||
err = signed.VerifyRoot(root, 0, trustmanager.CertsToKeys(trustedCerts, allIntCerts))
|
||||
if err != nil {
|
||||
logrus.Debugf("failed to verify TUF data for: %s, %v", gun, err)
|
||||
return &ErrValidationFail{Reason: "failed to validate data with current trusted certificates"}
|
||||
|
@ -149,7 +149,7 @@ func ValidateRoot(certStore trustmanager.X509Store, root *data.Signed, gun strin
|
|||
// Validate the integrity of the new root (does it have valid signatures)
|
||||
// Note that certsFromRoot is guaranteed to be unchanged only if we had prior cert data for this GUN or enabled TOFUS
|
||||
// If we attempted to pin a certain certificate or CA, certsFromRoot could have been pruned accordingly
|
||||
err = signed.VerifyRoot(root, 0, trustmanager.CertsToKeys(certsFromRoot))
|
||||
err = signed.VerifyRoot(root, 0, trustmanager.CertsToKeys(certsFromRoot, allIntCerts))
|
||||
if err != nil {
|
||||
logrus.Debugf("failed to verify TUF data for: %s, %v", gun, err)
|
||||
return &ErrValidationFail{Reason: "failed to validate integrity of roots"}
|
||||
|
|
|
@ -409,19 +409,19 @@ func TestValidateRootWithPinnerCertAndIntermediates(t *testing.T) {
|
|||
otherKey.ID(): otherKey,
|
||||
},
|
||||
Roles: map[string]*data.RootRole{
|
||||
"root": &data.RootRole{
|
||||
"root": {
|
||||
KeyIDs: []string{ecdsax509Key.ID()},
|
||||
Threshold: 1,
|
||||
},
|
||||
"targets": &data.RootRole{
|
||||
"targets": {
|
||||
KeyIDs: []string{otherKey.ID()},
|
||||
Threshold: 1,
|
||||
},
|
||||
"snapshot": &data.RootRole{
|
||||
"snapshot": {
|
||||
KeyIDs: []string{otherKey.ID()},
|
||||
Threshold: 1,
|
||||
},
|
||||
"timestamp": &data.RootRole{
|
||||
"timestamp": {
|
||||
KeyIDs: []string{otherKey.ID()},
|
||||
Threshold: 1,
|
||||
},
|
||||
|
@ -557,8 +557,6 @@ func TestValidateRootWithPinnedCA(t *testing.T) {
|
|||
// 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
|
||||
leafCert, err := trustmanager.LoadCertFromFile("../fixtures/notary-signer.crt")
|
||||
require.NoError(t, err)
|
||||
pemLeafBytes := trustmanager.CertToPEM(leafCert)
|
||||
newRootLeafKey := data.NewPublicKey(data.RSAx509Key, pemLeafBytes)
|
||||
|
||||
intermediateCert, err := trustmanager.LoadCertFromFile("../fixtures/intermediate-ca.crt")
|
||||
require.NoError(t, err)
|
||||
|
@ -599,7 +597,7 @@ func TestValidateRootWithPinnedCA(t *testing.T) {
|
|||
newTestSignedRoot, err := testRoot.ToSigned()
|
||||
require.NoError(t, err)
|
||||
|
||||
err = signed.Sign(cs, newTestSignedRoot, []data.PublicKey{newRootLeafKey}, 1, nil)
|
||||
err = signed.Sign(cs, newTestSignedRoot, []data.PublicKey{newRootKey}, 1, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Check that we validate correctly against a pinned CA and provided bundle
|
||||
|
|
|
@ -65,11 +65,19 @@ func NewTrustPinChecker(trustPinConfig TrustPinConfig, gun string) (CertChecker,
|
|||
}
|
||||
|
||||
func (t trustPinChecker) certsCheck(leafCert *x509.Certificate, intCerts []*x509.Certificate) bool {
|
||||
certID, err := trustmanager.FingerprintCert(leafCert)
|
||||
// reconstruct the leaf + intermediate cert chain, which is bundled as {leaf, intermediates...},
|
||||
// in order to get the matching id in the root file
|
||||
leafCertID, err := trustmanager.FingerprintCert(leafCert)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return utils.StrSliceContains(t.pinnedCertIDs, certID)
|
||||
rootKeys := trustmanager.CertsToKeys([]*x509.Certificate{leafCert}, map[string][]*x509.Certificate{leafCertID: intCerts})
|
||||
for keyID := range rootKeys {
|
||||
if utils.StrSliceContains(t.pinnedCertIDs, keyID) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (t trustPinChecker) caCheck(leafCert *x509.Certificate, intCerts []*x509.Certificate) bool {
|
||||
|
|
|
@ -36,7 +36,6 @@ func VerifyRoot(s *data.Signed, minVersion int, keys map[string]data.PublicKey)
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, sig := range s.Signatures {
|
||||
// method lookup is consistent due to Unmarshal JSON doing lower case for us.
|
||||
method := sig.Method
|
||||
|
@ -45,7 +44,6 @@ func VerifyRoot(s *data.Signed, minVersion int, keys map[string]data.PublicKey)
|
|||
logrus.Debugf("continuing b/c signing method is not supported for verify root: %s\n", sig.Method)
|
||||
continue
|
||||
}
|
||||
|
||||
key, ok := keys[sig.KeyID]
|
||||
if !ok {
|
||||
logrus.Debugf("continuing b/c signing key isn't present in keys: %s\n", sig.KeyID)
|
||||
|
|
|
@ -98,7 +98,7 @@ func HashedPaths(path string, hashes data.Hashes) []string {
|
|||
|
||||
// CanonicalKeyID returns the ID of the public bytes version of a TUF key.
|
||||
// On regular RSA/ECDSA TUF keys, this is just the key ID. On X509 RSA/ECDSA
|
||||
// TUF keys, this is the key ID of the public key part of the key.
|
||||
// TUF keys, this is the key ID of the public key part of the key in the leaf cert
|
||||
func CanonicalKeyID(k data.PublicKey) (string, error) {
|
||||
switch k.Algorithm() {
|
||||
case data.ECDSAx509Key, data.RSAx509Key:
|
||||
|
|
Loading…
Reference in New Issue