// checkRoot determines if the hash, and size are still those reported // in the snapshot file. It will also check the expiry, however, if the // hash and size in snapshot are unchanged but the root file has expired, // there is little expectation that the situation can be remedied. func (c Client) checkRoot() error { role := data.CanonicalRootRole size := c.local.Snapshot.Signed.Meta[role].Length expectedHashes := c.local.Snapshot.Signed.Meta[role].Hashes raw, err := c.cache.GetMeta(data.CanonicalRootRole, size) if err != nil { return err } if err := data.CheckHashes(raw, expectedHashes); err != nil { return fmt.Errorf("Cached root hashes did not match snapshot root hashes") } if int64(len(raw)) != size { return fmt.Errorf("Cached root size did not match snapshot size") } root := &data.SignedRoot{} err = json.Unmarshal(raw, root) if err != nil { return ErrCorruptedCache{file: "root.json"} } if signed.IsExpired(root.Signed.Expires) { return tuf.ErrLocalRootExpired{} } return nil }
func (rb *repoBuilder) validateChecksumsFromTimestamp(ts *data.SignedTimestamp) error { sn, ok := rb.loadedNotChecksummed[data.CanonicalSnapshotRole] if ok { // by this point, the SignedTimestamp has been validated so it must have a snapshot hash snMeta := ts.Signed.Meta[data.CanonicalSnapshotRole].Hashes if err := data.CheckHashes(sn, data.CanonicalSnapshotRole, snMeta); err != nil { return err } delete(rb.loadedNotChecksummed, data.CanonicalSnapshotRole) } return nil }
func (rb *repoBuilder) validateChecksumFor(content []byte, roleName string) error { // validate the bootstrap checksum for root, if provided if roleName == data.CanonicalRootRole && rb.bootstrappedRootChecksum != nil { if err := data.CheckHashes(content, roleName, rb.bootstrappedRootChecksum.Hashes); err != nil { return err } } // but we also want to cache the root content, so that when the snapshot is // loaded it is validated (to make sure everything in the repo is self-consistent) checksums := rb.getChecksumsFor(roleName) if checksums != nil { // as opposed to empty, in which case hash check should fail if err := data.CheckHashes(content, roleName, *checksums); err != nil { return err } } else if roleName != data.CanonicalTimestampRole { // timestamp is the only role which does not need to be checksummed, but // for everything else, cache the contents in the list of roles that have // not been checksummed by the snapshot/timestamp yet rb.loadedNotChecksummed[roleName] = content } return nil }
func (t *tufCommander) tufVerify(cmd *cobra.Command, args []string) error { if len(args) < 2 { cmd.Usage() return fmt.Errorf("Must specify a GUN and target") } config, err := t.configGetter() if err != nil { return err } payload, err := getPayload(t) if err != nil { return err } gun := args[0] targetName := args[1] rt, err := getTransport(config, gun, true) if err != nil { return err } trustPin, err := getTrustPinning(config) if err != nil { return err } nRepo, err := notaryclient.NewNotaryRepository( config.GetString("trust_dir"), gun, getRemoteTrustServer(config), rt, t.retriever, trustPin) if err != nil { return err } target, err := nRepo.GetTargetByName(targetName) if err != nil { return fmt.Errorf("error retrieving target by name:%s, error:%v", targetName, err) } if err := data.CheckHashes(payload, targetName, target.Hashes); err != nil { return fmt.Errorf("data not present in the trusted collection, %v", err) } return feedback(t, payload) }
func (rb *repoBuilder) validateChecksumsFromSnapshot(sn *data.SignedSnapshot) error { var goodRoles []string for roleName, loadedBytes := range rb.loadedNotChecksummed { switch roleName { case data.CanonicalSnapshotRole, data.CanonicalTimestampRole: break default: if err := data.CheckHashes(loadedBytes, roleName, sn.Signed.Meta[roleName].Hashes); err != nil { return err } goodRoles = append(goodRoles, roleName) } } for _, roleName := range goodRoles { delete(rb.loadedNotChecksummed, roleName) } return nil }
func (c *Client) downloadSigned(role string, size int64, expectedHashes data.Hashes) ([]byte, *data.Signed, error) { rolePath := utils.ConsistentName(role, expectedHashes["sha256"]) raw, err := c.remote.GetMeta(rolePath, size) if err != nil { return nil, nil, err } if expectedHashes != nil { if err := data.CheckHashes(raw, expectedHashes); err != nil { return nil, nil, ErrChecksumMismatch{role: role} } } s := &data.Signed{} err = json.Unmarshal(raw, s) if err != nil { return nil, nil, err } return raw, s, nil }
// snapshotExpired verifies the checksum(s) for the given snapshot using metadata from the timestamp func snapshotExpired(ts *data.SignedTimestamp, snapshot []byte) bool { // If this check failed, it means the current snapshot was not exactly what we expect // via the timestamp. So we can consider it to be "expired." return data.CheckHashes(snapshot, data.CanonicalSnapshotRole, ts.Signed.Meta[data.CanonicalSnapshotRole].Hashes) != nil }
func (c Client) getTargetsFile(role string, snapshotMeta data.Files, consistent bool) (*data.Signed, error) { // require role exists in snapshots roleMeta, ok := snapshotMeta[role] if !ok { return nil, data.ErrMissingMeta{Role: role} } expectedHashes := snapshotMeta[role].Hashes if len(expectedHashes) == 0 { return nil, data.ErrMissingMeta{Role: role} } // try to get meta file from content addressed cache var download bool old := &data.Signed{} version := 0 raw, err := c.cache.GetMeta(role, roleMeta.Length) if err != nil || raw == nil { logrus.Debugf("Couldn't not find cached %s, must download", role) download = true } else { // file may have been tampered with on disk. Always check the hash! if err := data.CheckHashes(raw, expectedHashes); err != nil { download = true } err := json.Unmarshal(raw, old) if err == nil { targ, err := data.TargetsFromSigned(old, role) if err == nil { version = targ.Signed.Version } else { download = true } } else { download = true } } size := snapshotMeta[role].Length var s *data.Signed if download { raw, s, err = c.downloadSigned(role, size, expectedHashes) if err != nil { return nil, err } } else { logrus.Debug("using cached ", role) s = old } var targetOrDelgRole data.BaseRole if data.IsDelegation(role) { delgRole, err := c.local.GetDelegationRole(role) if err != nil { logrus.Debugf("no %s delegation role loaded", role) return nil, err } targetOrDelgRole = delgRole.BaseRole } else { targetOrDelgRole, err = c.local.GetBaseRole(role) if err != nil { logrus.Debugf("no %s role loaded", role) return nil, err } } if err = signed.Verify(s, targetOrDelgRole, version); err != nil { return nil, err } logrus.Debugf("successfully verified %s", role) if download { // if we error when setting meta, we should continue. err = c.cache.SetMeta(role, raw) if err != nil { logrus.Errorf("Failed to write %s to local cache: %s", role, err.Error()) } } return s, nil }
// downloadSnapshot is responsible for downloading the snapshot.json func (c *Client) downloadSnapshot() error { logrus.Debug("Downloading Snapshot...") role := data.CanonicalSnapshotRole if c.local.Timestamp == nil { return tuf.ErrNotLoaded{Role: data.CanonicalTimestampRole} } size := c.local.Timestamp.Signed.Meta[role].Length expectedHashes := c.local.Timestamp.Signed.Meta[role].Hashes if len(expectedHashes) == 0 { return data.ErrMissingMeta{Role: data.CanonicalSnapshotRole} } var download bool old := &data.Signed{} version := 0 raw, err := c.cache.GetMeta(role, size) if raw == nil || err != nil { logrus.Debug("no snapshot in cache, must download") download = true } else { // file may have been tampered with on disk. Always check the hash! if err := data.CheckHashes(raw, expectedHashes); err != nil { logrus.Debug("hash of snapshot in cache did not match expected hash, must download") download = true } err := json.Unmarshal(raw, old) if err == nil { snap, err := data.SnapshotFromSigned(old) if err == nil { version = snap.Signed.Version } else { logrus.Debug("Could not parse Signed part of snapshot, must download") download = true } } else { logrus.Debug("Could not parse snapshot, must download") download = true } } var s *data.Signed if download { raw, s, err = c.downloadSigned(role, size, expectedHashes) if err != nil { return err } } else { logrus.Debug("using cached snapshot") s = old } snapshotRole, err := c.local.GetBaseRole(role) if err != nil { logrus.Debug("no snapshot role loaded") return err } err = signed.Verify(s, snapshotRole, version) if err != nil { return err } logrus.Debug("successfully verified snapshot") snap, err := data.SnapshotFromSigned(s) if err != nil { return err } c.local.SetSnapshot(snap) if download { err = c.cache.SetMeta(role, raw) if err != nil { logrus.Errorf("Failed to write snapshot to local cache: %s", err.Error()) } } return nil }
// downloadRoot is responsible for downloading the root.json func (c *Client) downloadRoot() error { logrus.Debug("Downloading Root...") role := data.CanonicalRootRole // We can't read an exact size for the root metadata without risking getting stuck in the TUF update cycle // since it's possible that downloading timestamp/snapshot metadata may fail due to a signature mismatch var size int64 = -1 // We could not expect what the "snapshot" meta has specified. // // In some old clients, there is only the "sha256", // but both "sha256" and "sha512" in the newer ones. // // And possibly more in the future. var expectedHashes data.Hashes if c.local.Snapshot != nil { if prevRootMeta, ok := c.local.Snapshot.Signed.Meta[role]; ok { size = prevRootMeta.Length expectedHashes = prevRootMeta.Hashes } } // if we're bootstrapping we may not have a cached root, an // error will result in the "previous root version" being // interpreted as 0. var download bool var err error var cachedRoot []byte old := &data.Signed{} version := 0 // Due to the same reason, we don't really know how many hashes are there. if len(expectedHashes) != 0 { // can only trust cache if we have an expected sha256(for example) to trust cachedRoot, err = c.cache.GetMeta(role, size) } if cachedRoot == nil || err != nil { logrus.Debug("didn't find a cached root, must download") download = true } else { if err := data.CheckHashes(cachedRoot, expectedHashes); err != nil { logrus.Debug("cached root's hash didn't match expected, must download") download = true } err := json.Unmarshal(cachedRoot, old) if err == nil { root, err := data.RootFromSigned(old) if err == nil { version = root.Signed.Version } else { logrus.Debug("couldn't parse Signed part of cached root, must download") download = true } } else { logrus.Debug("couldn't parse cached root, must download") download = true } } var s *data.Signed var raw []byte if download { // use consistent download if we have the checksum. raw, s, err = c.downloadSigned(role, size, expectedHashes) if err != nil { return err } } else { logrus.Debug("using cached root") s = old } if err := c.verifyRoot(role, s, version); err != nil { return err } if download { logrus.Debug("caching downloaded root") // Now that we have accepted new root, write it to cache if err = c.cache.SetMeta(role, raw); err != nil { logrus.Errorf("Failed to write root to local cache: %s", err.Error()) } } return nil }