pull/32571/merge
Tanvir Alam 3 days ago committed by GitHub
commit 68d8a476f0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -238,6 +238,11 @@ func (s *Signatory) ClearSign(archiveData []byte, filename string, metadataBytes
// Verify checks a signature and verifies that it is legit for package data.
// This is the core verification method that works with data in memory.
//
// filename is the local archive name. If that name is not in the signed Files
// map, a Files entry whose SHA matches the archive is accepted. helm package
// records Chart.yaml's name, which can differ from the repository path helm
// pull uses to name the downloaded file.
func (s *Signatory) Verify(archiveData, provData []byte, filename string) (*Verification, error) {
ver := &Verification{}
@ -264,19 +269,36 @@ func (s *Signatory) Verify(archiveData, provData []byte, filename string) (*Veri
}
sum = "sha256:" + sum
if sha, ok := sums.Files[filename]; !ok {
return ver, fmt.Errorf("provenance does not contain a SHA for a file named %q", filename)
} else if sha != sum {
return ver, fmt.Errorf("sha256 sum does not match for %s: %q != %q", filename, sha, sum)
signedName, err := matchSignedFile(sums.Files, filename, sum)
if err != nil {
return ver, err
}
ver.FileHash = sum
ver.FileName = filename
ver.FileName = signedName
// TODO: when image signing is added, verify that here.
return ver, nil
}
// matchSignedFile returns the Files key that covers archiveSum.
// If filename is present it must match; otherwise any signed name with the
// same hash is accepted (repository path vs Chart.yaml name).
func matchSignedFile(files map[string]string, filename, archiveSum string) (string, error) {
if sha, ok := files[filename]; ok {
if sha != archiveSum {
return "", fmt.Errorf("sha256 sum does not match for %s: %q != %q", filename, sha, archiveSum)
}
return filename, nil
}
for signedName, sha := range files {
if sha == archiveSum {
return signedName, nil
}
}
return "", fmt.Errorf("provenance does not contain a SHA for a file named %q", filename)
}
// verifySignature verifies that the given block is validly signed, and returns the signer.
func (s *Signatory) verifySignature(block *clearsign.Block) (*openpgp.Entity, error) {
return openpgp.CheckDetachedSignature(

@ -386,6 +386,32 @@ func TestVerify(t *testing.T) {
}
}
func TestVerifyFilenameDiffersFromProvenance(t *testing.T) {
signer, err := NewFromFiles(testKeyfile, testPubfile)
require.NoError(t, err)
archiveData, err := os.ReadFile(testChartfile)
require.NoError(t, err)
sigData, err := os.ReadFile(testSigBlock)
require.NoError(t, err)
// helm pull --verify names the archive from the repository path, which can
// differ from the Chart.yaml name recorded in the provenance Files map.
ver, err := signer.Verify(archiveData, sigData, "otherrepo-1.2.3.tgz")
require.NoError(t, err)
assert.Equal(t, "hashtest-1.2.3.tgz", ver.FileName)
assert.Equal(t, "sha256:c6841b3a895f1444a6738b5d04564a57e860ce42f8519c3be807fb6d9bee7888", ver.FileHash)
_, err = signer.Verify([]byte("not the signed archive"), sigData, "otherrepo-1.2.3.tgz")
require.Error(t, err)
assert.ErrorContains(t, err, `provenance does not contain a SHA for a file named "otherrepo-1.2.3.tgz"`)
_, err = signer.Verify([]byte("not the signed archive"), sigData, filepath.Base(testChartfile))
require.Error(t, err)
assert.ErrorContains(t, err, "sha256 sum does not match")
}
// TestVerifyKeyboxKeyring mirrors TestVerify with the keyring loaded from a
// GnuPG keybox instead of the legacy binary format.
func TestVerifyKeyboxKeyring(t *testing.T) {

Loading…
Cancel
Save