// 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 // "validity" alone does not imply any measure of trust. func validRootLeafCerts(allLeafCerts map[string]*x509.Certificate, gun string, checkExpiry bool) (map[string]*x509.Certificate, error) { validLeafCerts := make(map[string]*x509.Certificate) // Go through every leaf certificate and check that the CN matches the gun for id, cert := range allLeafCerts { // Validate that this leaf certificate has a CN that matches the exact gun if cert.Subject.CommonName != gun { logrus.Debugf("error leaf certificate CN: %s doesn't match the given GUN: %s", cert.Subject.CommonName, gun) continue } // Make sure the certificate is not expired if checkExpiry is true // and warn if it hasn't expired yet but is within 6 months of expiry if err := utils.ValidateCertificate(cert, checkExpiry); err != nil { logrus.Debugf("%s is invalid: %s", id, err.Error()) continue } validLeafCerts[id] = cert } if len(validLeafCerts) < 1 { logrus.Debugf("didn't find any valid leaf certificates for %s", gun) return nil, errors.New("no valid leaf certificates found in any of the root keys") } logrus.Debugf("found %d valid leaf certificates for %s: %s", len(validLeafCerts), gun, prettyFormatCertIDs(validLeafCerts)) return validLeafCerts, nil }
// validRootIntCerts filters the passed in structure of intermediate certificates to only include non-expired, non-sha1 certificates // Note that this "validity" alone does not imply any measure of trust. func validRootIntCerts(allIntCerts map[string][]*x509.Certificate) map[string][]*x509.Certificate { validIntCerts := make(map[string][]*x509.Certificate) // Go through every leaf cert ID, and build its valid intermediate certificate list for leafID, intCertList := range allIntCerts { for _, intCert := range intCertList { if err := utils.ValidateCertificate(intCert, true); err != nil { continue } validIntCerts[leafID] = append(validIntCerts[leafID], intCert) } } return validIntCerts }
// NewTrustPinChecker returns a new certChecker function from a TrustPinConfig for a GUN func NewTrustPinChecker(trustPinConfig TrustPinConfig, gun string, firstBootstrap bool) (CertChecker, error) { t := trustPinChecker{gun: gun, config: trustPinConfig} // Determine the mode, and if it's even valid if pinnedCerts, ok := trustPinConfig.Certs[gun]; ok { logrus.Debugf("trust-pinning using Cert IDs") t.pinnedCertIDs = pinnedCerts return t.certsCheck, nil } if caFilepath, err := getPinnedCAFilepathByPrefix(gun, trustPinConfig); err == nil { logrus.Debugf("trust-pinning using root CA bundle at: %s", caFilepath) // Try to add the CA certs from its bundle file to our certificate store, // and use it to validate certs in the root.json later caCerts, err := utils.LoadCertBundleFromFile(caFilepath) if err != nil { return nil, fmt.Errorf("could not load root cert from CA path") } // Now only consider certificates that are direct children from this CA cert chain caRootPool := x509.NewCertPool() for _, caCert := range caCerts { if err = utils.ValidateCertificate(caCert, true); err != nil { logrus.Debugf("ignoring root CA certificate with CN %s in bundle: %s", caCert.Subject.CommonName, err) continue } caRootPool.AddCert(caCert) } // If we didn't have any valid CA certs, error out if len(caRootPool.Subjects()) == 0 { return nil, fmt.Errorf("invalid CA certs provided") } t.pinnedCAPool = caRootPool return t.caCheck, nil } // If TOFUs is disabled and we don't have any previous trusted root data for this GUN, we error out if trustPinConfig.DisableTOFU && firstBootstrap { return nil, fmt.Errorf("invalid trust pinning specified") } return t.tofusCheck, nil }
// GetDelegationRole gets a delegation role from this repo's metadata, walking from the targets role down to the delegation itself func (tr *Repo) GetDelegationRole(name string) (data.DelegationRole, error) { if !data.IsDelegation(name) { return data.DelegationRole{}, data.ErrInvalidRole{Role: name, Reason: "invalid delegation name"} } if tr.Root == nil { return data.DelegationRole{}, ErrNotLoaded{data.CanonicalRootRole} } _, ok := tr.Root.Signed.Roles[data.CanonicalTargetsRole] if !ok { return data.DelegationRole{}, ErrNotLoaded{data.CanonicalTargetsRole} } // Traverse target metadata, down to delegation itself // Get all public keys for the base role from TUF metadata _, ok = tr.Targets[data.CanonicalTargetsRole] if !ok { return data.DelegationRole{}, ErrNotLoaded{data.CanonicalTargetsRole} } // Start with top level roles in targets. Walk the chain of ancestors // until finding the desired role, or we run out of targets files to search. var foundRole *data.DelegationRole buildDelegationRoleVisitor := func(tgt *data.SignedTargets, validRole data.DelegationRole) interface{} { // Try to find the delegation and build a DelegationRole structure for _, role := range tgt.Signed.Delegations.Roles { if role.Name == name { delgRole, err := tgt.BuildDelegationRole(name) if err != nil { return err } // Check all public key certificates in the role for expiry // Currently we do not reject expired delegation keys but warn if they might expire soon or have already for keyID, pubKey := range delgRole.Keys { certFromKey, err := utils.LoadCertFromPEM(pubKey.Public()) if err != nil { continue } if err := utils.ValidateCertificate(certFromKey, true); err != nil { if _, ok := err.(data.ErrCertExpired); !ok { // do not allow other invalid cert errors return err } logrus.Warnf("error with delegation %s key ID %d: %s", delgRole.Name, keyID, err) } } foundRole = &delgRole return StopWalk{} } } return nil } // Walk to the parent of this delegation, since that is where its role metadata exists err := tr.WalkTargets("", path.Dir(name), buildDelegationRoleVisitor) if err != nil { return data.DelegationRole{}, err } // We never found the delegation. In the context of this repo it is considered // invalid. N.B. it may be that it existed at one point but an ancestor has since // been modified/removed. if foundRole == nil { return data.DelegationRole{}, data.ErrInvalidRole{Role: name, Reason: "delegation does not exist"} } return *foundRole, nil }