Skip to content

Commit

Permalink
storage: change Artifact checksum to SHA256
Browse files Browse the repository at this point in the history
This changes the format of the Artifact checksum from SHA1 to SHA256 to
mitigate chosen-prefix and length extension attacks, and ensures it can
be used to secure content against malicious modifications.

Source consumers (including our own {kustomize,helm}-controllers)
should ensure the SHA256 of a downloaded artifact matches the
advertised checksum before making use of it.

Signed-off-by: Hidde Beydals <hello@hidde.co>
  • Loading branch information
hiddeco committed Aug 10, 2021
1 parent f9995ee commit e79b573
Show file tree
Hide file tree
Showing 8 changed files with 16 additions and 16 deletions.
2 changes: 1 addition & 1 deletion api/v1beta1/artifact_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ type Artifact struct {
// +optional
Revision string `json:"revision"`

// Checksum is the SHA1 checksum of the artifact.
// Checksum is the SHA256 checksum of the artifact.
// +optional
Checksum string `json:"checksum"`

Expand Down
2 changes: 1 addition & 1 deletion config/crd/bases/source.toolkit.fluxcd.io_buckets.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ spec:
description: Artifact represents the output of the last successful Bucket sync.
properties:
checksum:
description: Checksum is the SHA1 checksum of the artifact.
description: Checksum is the SHA256 checksum of the artifact.
type: string
lastUpdateTime:
description: LastUpdateTime is the timestamp corresponding to the last update of this artifact.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ spec:
description: Artifact represents the output of the last successful repository sync.
properties:
checksum:
description: Checksum is the SHA1 checksum of the artifact.
description: Checksum is the SHA256 checksum of the artifact.
type: string
lastUpdateTime:
description: LastUpdateTime is the timestamp corresponding to the last update of this artifact.
Expand Down Expand Up @@ -224,7 +224,7 @@ spec:
description: Artifact represents the output of a source synchronisation.
properties:
checksum:
description: Checksum is the SHA1 checksum of the artifact.
description: Checksum is the SHA256 checksum of the artifact.
type: string
lastUpdateTime:
description: LastUpdateTime is the timestamp corresponding to the last update of this artifact.
Expand Down
2 changes: 1 addition & 1 deletion config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ spec:
description: Artifact represents the output of the last successful chart sync.
properties:
checksum:
description: Checksum is the SHA1 checksum of the artifact.
description: Checksum is the SHA256 checksum of the artifact.
type: string
lastUpdateTime:
description: LastUpdateTime is the timestamp corresponding to the last update of this artifact.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ spec:
description: Artifact represents the output of the last successful repository sync.
properties:
checksum:
description: Checksum is the SHA1 checksum of the artifact.
description: Checksum is the SHA256 checksum of the artifact.
type: string
lastUpdateTime:
description: LastUpdateTime is the timestamp corresponding to the last update of this artifact.
Expand Down
10 changes: 5 additions & 5 deletions controllers/gitrepository_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,7 @@ func TestGitRepositoryReconciler_reconcileArtifact(t *testing.T) {
},
afterFunc: func(t *WithT, obj *sourcev1.GitRepository, artifact sourcev1.Artifact) {
t.Expect(obj.GetArtifact()).ToNot(BeNil())
t.Expect(obj.GetArtifact().Checksum).To(Equal("b1fab897a1a0fb8094ce3ae0e9743a4b72bd7268"))
t.Expect(obj.GetArtifact().Checksum).To(Equal("ef9c34eab0584035ac8b8a4070876954ea46f270250d60648672feef3e943426"))
t.Expect(obj.Status.URL).ToNot(BeEmpty())
},
want: ctrl.Result{RequeueAfter: interval},
Expand All @@ -595,7 +595,7 @@ func TestGitRepositoryReconciler_reconcileArtifact(t *testing.T) {
},
afterFunc: func(t *WithT, obj *sourcev1.GitRepository, artifact sourcev1.Artifact) {
t.Expect(obj.GetArtifact()).ToNot(BeNil())
t.Expect(obj.GetArtifact().Checksum).To(Equal("b1fab897a1a0fb8094ce3ae0e9743a4b72bd7268"))
t.Expect(obj.GetArtifact().Checksum).To(Equal("ef9c34eab0584035ac8b8a4070876954ea46f270250d60648672feef3e943426"))
t.Expect(obj.Status.IncludedArtifacts).ToNot(BeEmpty())
t.Expect(obj.Status.URL).ToNot(BeEmpty())
},
Expand Down Expand Up @@ -630,7 +630,7 @@ func TestGitRepositoryReconciler_reconcileArtifact(t *testing.T) {
},
afterFunc: func(t *WithT, obj *sourcev1.GitRepository, artifact sourcev1.Artifact) {
t.Expect(obj.GetArtifact()).ToNot(BeNil())
t.Expect(obj.GetArtifact().Checksum).To(Equal("a71f8c076db814bc21c16cecc960c4fcaf970ac5"))
t.Expect(obj.GetArtifact().Checksum).To(Equal("dc95ae14c19d335b693bbba58ae2a562242b0cf33893baffd1b7605ba578e0d6"))
},
want: ctrl.Result{RequeueAfter: interval},
assertConditions: []metav1.Condition{
Expand All @@ -646,7 +646,7 @@ func TestGitRepositoryReconciler_reconcileArtifact(t *testing.T) {
},
afterFunc: func(t *WithT, obj *sourcev1.GitRepository, artifact sourcev1.Artifact) {
t.Expect(obj.GetArtifact()).ToNot(BeNil())
t.Expect(obj.GetArtifact().Checksum).To(Equal("b1fab897a1a0fb8094ce3ae0e9743a4b72bd7268"))
t.Expect(obj.GetArtifact().Checksum).To(Equal("ef9c34eab0584035ac8b8a4070876954ea46f270250d60648672feef3e943426"))
t.Expect(obj.Status.URL).ToNot(BeEmpty())
},
want: ctrl.Result{RequeueAfter: interval},
Expand All @@ -663,7 +663,7 @@ func TestGitRepositoryReconciler_reconcileArtifact(t *testing.T) {
},
afterFunc: func(t *WithT, obj *sourcev1.GitRepository, artifact sourcev1.Artifact) {
t.Expect(obj.GetArtifact()).ToNot(BeNil())
t.Expect(obj.GetArtifact().Checksum).To(Equal("b1fab897a1a0fb8094ce3ae0e9743a4b72bd7268"))
t.Expect(obj.GetArtifact().Checksum).To(Equal("ef9c34eab0584035ac8b8a4070876954ea46f270250d60648672feef3e943426"))
t.Expect(obj.Status.URL).ToNot(BeEmpty())
},
want: ctrl.Result{RequeueAfter: interval},
Expand Down
8 changes: 4 additions & 4 deletions controllers/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ package controllers
import (
"archive/tar"
"compress/gzip"
"crypto/sha1"
"crypto/sha256"
"fmt"
"hash"
"io"
Expand Down Expand Up @@ -425,7 +425,7 @@ func (s *Storage) Symlink(artifact sourcev1.Artifact, linkName string) (string,
return url, nil
}

// Checksum returns the SHA1 checksum for the data of the given io.Reader as a string.
// Checksum returns the SHA256 checksum for the data of the given io.Reader as a string.
func (s *Storage) Checksum(reader io.Reader) string {
h := newHash()
_, _ = io.Copy(h, reader)
Expand All @@ -451,7 +451,7 @@ func (s *Storage) LocalPath(artifact sourcev1.Artifact) string {
return path
}

// newHash returns a new SHA1 hash.
// newHash returns a new SHA256 hash.
func newHash() hash.Hash {
return sha1.New()
return sha256.New()
}
2 changes: 1 addition & 1 deletion docs/api/source.md
Original file line number Diff line number Diff line change
Expand Up @@ -839,7 +839,7 @@ string
</td>
<td>
<em>(Optional)</em>
<p>Checksum is the SHA1 checksum of the artifact.</p>
<p>Checksum is the SHA256 checksum of the artifact.</p>
</td>
</tr>
<tr>
Expand Down

0 comments on commit e79b573

Please sign in to comment.