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:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user