diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index fad39342d..33090266f 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -96,7 +96,7 @@ }, { "ImportPath": "github.com/endophage/gotuf", - "Rev": "a8824e6565a316076fc738eaaccda6528c448a38" + "Rev": "876c31a61bc4aa0dae09bb8ef3946dc26dd04924" }, { "ImportPath": "github.com/go-sql-driver/mysql", diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/client/client.go b/Godeps/_workspace/src/github.com/endophage/gotuf/client/client.go index 2bcda4b74..532e47478 100644 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/client/client.go +++ b/Godeps/_workspace/src/github.com/endophage/gotuf/client/client.go @@ -175,19 +175,7 @@ func (c *Client) downloadRoot() error { var s *data.Signed var raw []byte if download { - logrus.Debug("downloading new root") - raw, err = c.remote.GetMeta(role, size) - if err != nil { - return err - } - hash := sha256.Sum256(raw) - if expectedSha256 != nil && !bytes.Equal(hash[:], expectedSha256) { - // if we don't have an expected sha256, we're going to trust the root - // based purely on signature and expiry time validation - return fmt.Errorf("Remote root sha256 did not match snapshot root sha256: %#x vs. %#x", hash, []byte(expectedSha256)) - } - s = &data.Signed{} - err = json.Unmarshal(raw, s) + raw, s, err = c.downloadSigned(role, size, expectedSha256) if err != nil { return err } @@ -247,6 +235,8 @@ func (c Client) verifyRoot(role string, s *data.Signed, minVersion int) error { } // downloadTimestamp is responsible for downloading the timestamp.json +// Timestamps are special in that we ALWAYS attempt to download and only +// use cache if the download fails (and the cache is still valid). func (c *Client) downloadTimestamp() error { logrus.Debug("downloadTimestamp") role := data.RoleName("timestamp") @@ -271,7 +261,6 @@ func (c *Client) downloadTimestamp() error { } // unlike root, targets and snapshot, always try and download timestamps // from remote, only using the cache one if we couldn't reach remote. - logrus.Debug("Downloading timestamp") raw, err := c.remote.GetMeta(role, maxSize) var s *data.Signed if err != nil || len(raw) == 0 { @@ -286,6 +275,7 @@ func (c *Client) downloadTimestamp() error { } return err } + logrus.Debug("using cached timestamp") s = old } else { download = true @@ -351,17 +341,7 @@ func (c *Client) downloadSnapshot() error { } var s *data.Signed if download { - logrus.Debug("downloading new snapshot") - raw, err = c.remote.GetMeta(role, size) - if err != nil { - return err - } - genHash := sha256.Sum256(raw) - if !bytes.Equal(genHash[:], expectedSha256) { - return fmt.Errorf("Retrieved snapshot did not verify against hash in timestamp.") - } - s = &data.Signed{} - err = json.Unmarshal(raw, s) + raw, s, err = c.downloadSigned(role, size, expectedSha256) if err != nil { return err } @@ -390,8 +370,7 @@ func (c *Client) downloadSnapshot() error { } // downloadTargets is responsible for downloading any targets file -// including delegates roles. It will download the whole tree of -// delegated roles below the given one +// including delegates roles. func (c *Client) downloadTargets(role string) error { role = data.RoleName(role) // this will really only do something for base targets role snap := c.local.Snapshot.Signed @@ -418,6 +397,24 @@ func (c *Client) downloadTargets(role string) error { return nil } +func (c *Client) downloadSigned(role string, size int64, expectedSha256 []byte) ([]byte, *data.Signed, error) { + logrus.Debugf("downloading new %s", role) + raw, err := c.remote.GetMeta(role, size) + if err != nil { + return nil, nil, err + } + genHash := sha256.Sum256(raw) + if !bytes.Equal(genHash[:], expectedSha256) { + 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 +} + func (c Client) GetTargetsFile(role string, keyIDs []string, snapshotMeta data.Files, consistent bool, threshold int) (*data.Signed, error) { // require role exists in snapshots roleMeta, ok := snapshotMeta[role] @@ -454,23 +451,17 @@ func (c Client) GetTargetsFile(role string, keyIDs []string, snapshotMeta data.F } else { download = true } - } + size := snapshotMeta[role].Length var s *data.Signed if download { rolePath, err := c.RoleTargetsPath(role, hex.EncodeToString(expectedSha256), consistent) if err != nil { return nil, err } - raw, err = c.remote.GetMeta(rolePath, snapshotMeta[role].Length) - if err != nil { - return nil, err - } - s = &data.Signed{} - err = json.Unmarshal(raw, s) + raw, s, err = c.downloadSigned(rolePath, size, expectedSha256) if err != nil { - logrus.Error("Error unmarshalling targets file:", err) return nil, err } } else { diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/client/errors.go b/Godeps/_workspace/src/github.com/endophage/gotuf/client/errors.go index 776e6a69e..311e74a8d 100644 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/client/errors.go +++ b/Godeps/_workspace/src/github.com/endophage/gotuf/client/errors.go @@ -10,6 +10,14 @@ var ( ErrInsufficientKeys = errors.New("tuf: insufficient keys to meet threshold") ) +type ErrChecksumMismatch struct { + role string +} + +func (e ErrChecksumMismatch) Error() string { + return fmt.Sprintf("tuf: checksum for %s did not match", e.role) +} + type ErrMissingRemoteMetadata struct { Name string } diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/store/httpstore.go b/Godeps/_workspace/src/github.com/endophage/gotuf/store/httpstore.go index 1a82b094c..730438267 100644 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/store/httpstore.go +++ b/Godeps/_workspace/src/github.com/endophage/gotuf/store/httpstore.go @@ -90,6 +90,7 @@ func (s HTTPStore) GetMeta(name string, size int64) ([]byte, error) { if resp.StatusCode == http.StatusNotFound { return nil, ErrMetaNotFound{} } else if resp.StatusCode != http.StatusOK { + logrus.Debugf("received HTTP status %d when requesting %s.", resp.StatusCode, name) return nil, ErrServerUnavailable{code: resp.StatusCode} } if resp.ContentLength > size {