1
0
mirror of https://github.com/docker/docs.git synced 2026-11-05 00:14:17 +03:00

[PATCH 6/8] Add sha512 check when downloading TUF roles

Since the timestamp role need not the hash checking during the downloading,
thi patch only includes:
- snapshot.json
- root.json
- target.json

Signed-off-by: Hu Keping <hukeping@huawei.com>
This commit is contained in:
HuKeping
2016-02-27 19:22:27 +08:00
parent 95ed108c12
commit bf97855897
2 changed files with 51 additions and 38 deletions

View File

@@ -1,8 +1,6 @@
package client
import (
"bytes"
"crypto/sha256"
"encoding/json"
"fmt"
"path"
@@ -92,16 +90,16 @@ func (c *Client) update() error {
func (c Client) checkRoot() error {
role := data.CanonicalRootRole
size := c.local.Snapshot.Signed.Meta[role].Length
hashSha256 := c.local.Snapshot.Signed.Meta[role].Hashes["sha256"]
expectedHashes := c.local.Snapshot.Signed.Meta[role].Hashes
raw, err := c.cache.GetMeta("root", size)
if err != nil {
return err
}
hash := sha256.Sum256(raw)
if !bytes.Equal(hash[:], hashSha256) {
return fmt.Errorf("Cached root sha256 did not match snapshot root sha256")
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 {
@@ -127,11 +125,19 @@ func (c *Client) downloadRoot() error {
// 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
var expectedSha256 []byte
// 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
expectedSha256 = prevRootMeta.Hashes["sha256"]
expectedHashes = prevRootMeta.Hashes
}
}
@@ -144,8 +150,9 @@ func (c *Client) downloadRoot() error {
old := &data.Signed{}
version := 0
if expectedSha256 != nil {
// can only trust cache if we have an expected sha256 to trust
// 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)
}
@@ -153,11 +160,11 @@ func (c *Client) downloadRoot() error {
logrus.Debug("didn't find a cached root, must download")
download = true
} else {
hash := sha256.Sum256(cachedRoot)
if !bytes.Equal(hash[:], expectedSha256) {
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)
@@ -176,7 +183,7 @@ func (c *Client) downloadRoot() error {
var raw []byte
if download {
// use consistent download if we have the checksum.
raw, s, err = c.downloadSigned(role, size, expectedSha256)
raw, s, err = c.downloadSigned(role, size, expectedHashes)
if err != nil {
return err
}
@@ -322,8 +329,8 @@ func (c *Client) downloadSnapshot() error {
return tuf.ErrNotLoaded{Role: data.CanonicalTimestampRole}
}
size := c.local.Timestamp.Signed.Meta[role].Length
expectedSha256, ok := c.local.Timestamp.Signed.Meta[role].Hashes["sha256"]
if !ok {
expectedHashes := c.local.Timestamp.Signed.Meta[role].Hashes
if len(expectedHashes) == 0 {
return data.ErrMissingMeta{Role: "snapshot"}
}
@@ -336,11 +343,11 @@ func (c *Client) downloadSnapshot() error {
download = true
} else {
// file may have been tampered with on disk. Always check the hash!
genHash := sha256.Sum256(raw)
if !bytes.Equal(genHash[:], expectedSha256) {
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)
@@ -357,7 +364,7 @@ func (c *Client) downloadSnapshot() error {
}
var s *data.Signed
if download {
raw, s, err = c.downloadSigned(role, size, expectedSha256)
raw, s, err = c.downloadSigned(role, size, expectedHashes)
if err != nil {
return err
}
@@ -439,18 +446,19 @@ func (c *Client) downloadTargets(role string) error {
return nil
}
func (c *Client) downloadSigned(role string, size int64, expectedSha256 []byte) ([]byte, *data.Signed, error) {
rolePath := utils.ConsistentName(role, expectedSha256)
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 expectedSha256 != nil {
genHash := sha256.Sum256(raw)
if !bytes.Equal(genHash[:], expectedSha256) {
if len(expectedHashes) != 0 {
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 {
@@ -465,8 +473,8 @@ func (c Client) getTargetsFile(role string, snapshotMeta data.Files, consistent
if !ok {
return nil, data.ErrMissingMeta{Role: role}
}
expectedSha256, ok := snapshotMeta[role].Hashes["sha256"]
if !ok {
expectedHashes := snapshotMeta[role].Hashes
if len(expectedHashes) == 0 {
return nil, data.ErrMissingMeta{Role: role}
}
@@ -480,10 +488,10 @@ func (c Client) getTargetsFile(role string, snapshotMeta data.Files, consistent
download = true
} else {
// file may have been tampered with on disk. Always check the hash!
genHash := sha256.Sum256(raw)
if !bytes.Equal(genHash[:], expectedSha256) {
if err := data.CheckHashes(raw, expectedHashes); err != nil {
download = true
}
err := json.Unmarshal(raw, old)
if err == nil {
targ, err := data.TargetsFromSigned(old, role)
@@ -500,7 +508,7 @@ func (c Client) getTargetsFile(role string, snapshotMeta data.Files, consistent
size := snapshotMeta[role].Length
var s *data.Signed
if download {
raw, s, err = c.downloadSigned(role, size, expectedSha256)
raw, s, err = c.downloadSigned(role, size, expectedHashes)
if err != nil {
return nil, err
}

View File

@@ -250,12 +250,13 @@ func TestChecksumMismatch(t *testing.T) {
sampleTargets := data.NewTargets()
orig, err := json.Marshal(sampleTargets)
origSha256 := sha256.Sum256(orig)
assert.NoError(t, err)
origHashes := data.GetSupportedHashes(orig)
remoteStorage.SetMeta("targets", orig)
_, _, err = client.downloadSigned("targets", int64(len(orig)), origSha256[:])
_, _, err = client.downloadSigned("targets", int64(len(orig)), origHashes)
assert.IsType(t, ErrChecksumMismatch{}, err)
}
@@ -267,12 +268,13 @@ func TestChecksumMatch(t *testing.T) {
sampleTargets := data.NewTargets()
orig, err := json.Marshal(sampleTargets)
origSha256 := sha256.Sum256(orig)
assert.NoError(t, err)
origHashes := data.GetSupportedHashes(orig)
remoteStorage.SetMeta("targets", orig)
_, _, err = client.downloadSigned("targets", int64(len(orig)), origSha256[:])
_, _, err = client.downloadSigned("targets", int64(len(orig)), origHashes)
assert.NoError(t, err)
}
@@ -284,13 +286,14 @@ func TestSizeMismatchLong(t *testing.T) {
sampleTargets := data.NewTargets()
orig, err := json.Marshal(sampleTargets)
origSha256 := sha256.Sum256(orig)
assert.NoError(t, err)
l := int64(len(orig))
origHashes := data.GetSupportedHashes(orig)
remoteStorage.SetMeta("targets", orig)
_, _, err = client.downloadSigned("targets", l, origSha256[:])
_, _, err = client.downloadSigned("targets", l, origHashes)
// size just limits the data received, the error is caught
// either during checksum verification or during json deserialization
assert.IsType(t, ErrChecksumMismatch{}, err)
@@ -304,13 +307,13 @@ func TestSizeMismatchShort(t *testing.T) {
sampleTargets := data.NewTargets()
orig, err := json.Marshal(sampleTargets)
origSha256 := sha256.Sum256(orig)
assert.NoError(t, err)
l := int64(len(orig))
origHashes := data.GetSupportedHashes(orig)
remoteStorage.SetMeta("targets", orig)
_, _, err = client.downloadSigned("targets", l, origSha256[:])
_, _, err = client.downloadSigned("targets", l, origHashes)
// size just limits the data received, the error is caught
// either during checksum verification or during json deserialization
assert.IsType(t, ErrChecksumMismatch{}, err)
@@ -512,6 +515,7 @@ func TestDownloadTargetsNoChecksum(t *testing.T) {
assert.NoError(t, err)
delete(repo.Snapshot.Signed.Meta["targets"].Hashes, "sha256")
delete(repo.Snapshot.Signed.Meta["targets"].Hashes, "sha512")
err = client.downloadTargets("targets")
assert.IsType(t, data.ErrMissingMeta{}, err)
@@ -721,8 +725,6 @@ func TestDownloadSnapshotLarge(t *testing.T) {
assert.NoError(t, err)
}
// TestDownloadSnapshotNoChecksum: It should never be valid to download a
// snapshot if we don't have a checksum
func TestDownloadSnapshotNoTimestamp(t *testing.T) {
repo, _, err := testutils.EmptyRepo("docker.com/notary")
assert.NoError(t, err)
@@ -744,6 +746,8 @@ func TestDownloadSnapshotNoTimestamp(t *testing.T) {
assert.IsType(t, tuf.ErrNotLoaded{}, err)
}
// TestDownloadSnapshotNoChecksum: It should never be valid to download a
// snapshot if we don't have a checksum
func TestDownloadSnapshotNoChecksum(t *testing.T) {
repo, _, err := testutils.EmptyRepo("docker.com/notary")
assert.NoError(t, err)
@@ -760,6 +764,7 @@ func TestDownloadSnapshotNoChecksum(t *testing.T) {
assert.NoError(t, err)
delete(repo.Timestamp.Signed.Meta["snapshot"].Hashes, "sha256")
delete(repo.Timestamp.Signed.Meta["snapshot"].Hashes, "sha512")
err = client.downloadSnapshot()
assert.IsType(t, data.ErrMissingMeta{}, err)