mirror of
https://github.com/helm/helm.git
synced 2026-08-09 01:21:20 +00:00
fix(provenance): migrate to ProtonMail/go-crypto to resolve GO-2026-5932
Backport of the openpgp migration already merged to main (7c9176ae3)
to dev-v3.
golang.org/x/crypto/openpgp is frozen and flagged by govulncheck as
GO-2026-5932 with no fixed release, leaving the govulncheck check red
on every Go PR targeting dev-v3. Replace it with the maintained
drop-in fork github.com/ProtonMail/go-crypto in pkg/provenance, the
only consumer on this branch.
The only API difference is openpgp.CheckDetachedSignature, which now
takes an io.Reader and a *packet.Config.
Pin the indirect github.com/cloudflare/circl at v1.6.3, as v1.6.2
pulled in by default is itself flagged (GO-2026-4550, fixed in
v1.6.3).
Also backport the mixed RSA/ed25519 keyring sign/verify regression
test from main, adapted to the v3 Signatory API, since keyrings with
modern key algorithms are the main behavioral surface of this swap.
govulncheck ./... now reports 0 vulnerabilities.
Fixes #32361
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Karan V <karanvknarayanan@gmail.com>
This commit is contained in:
2
go.mod
2
go.mod
@@ -10,6 +10,7 @@ require (
|
||||
github.com/Masterminds/sprig/v3 v3.3.0
|
||||
github.com/Masterminds/squirrel v1.5.4
|
||||
github.com/Masterminds/vcs v1.13.3
|
||||
github.com/ProtonMail/go-crypto v1.4.1
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2
|
||||
github.com/cyphar/filepath-securejoin v0.7.0
|
||||
github.com/distribution/distribution/v3 v3.1.1
|
||||
@@ -59,6 +60,7 @@ require (
|
||||
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/chai2010/gettext-go v1.0.2 // indirect
|
||||
github.com/cloudflare/circl v1.6.3 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.7.0 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
|
||||
4
go.sum
4
go.sum
@@ -22,6 +22,8 @@ github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8
|
||||
github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10=
|
||||
github.com/Masterminds/vcs v1.13.3 h1:IIA2aBdXvfbIM+yl/eTnL4hb1XwdpvuQLglAix1gweE=
|
||||
github.com/Masterminds/vcs v1.13.3/go.mod h1:TiE7xuEjl1N4j016moRd6vezp6e6Lz23gypeXfzXeW8=
|
||||
github.com/ProtonMail/go-crypto v1.4.1 h1:9RfcZHqEQUvP8RzecWEUafnZVtEvrBVL9BiF67IQOfM=
|
||||
github.com/ProtonMail/go-crypto v1.4.1/go.mod h1:e1OaTyu5SYVrO9gKOEhTc+5UcXtTUa+P3uLudwcgPqo=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alicebob/miniredis/v2 v2.35.0 h1:QwLphYqCEAo1eu1TqPRN2jgVMPBweeQcR21jeqDCONI=
|
||||
@@ -49,6 +51,8 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk=
|
||||
github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA=
|
||||
github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8=
|
||||
github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4=
|
||||
github.com/coreos/go-systemd/v22 v22.7.0 h1:LAEzFkke61DFROc7zNLX/WA2i5J8gYqe0rSj9KI28KA=
|
||||
github.com/coreos/go-systemd/v22 v22.7.0/go.mod h1:xNUYtjHu2EDXbsxz1i41wouACIwT7Ybq9o0BQhMwD0w=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0=
|
||||
|
||||
@@ -24,10 +24,10 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/ProtonMail/go-crypto/openpgp"
|
||||
"github.com/ProtonMail/go-crypto/openpgp/clearsign"
|
||||
"github.com/ProtonMail/go-crypto/openpgp/packet"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/crypto/openpgp" //nolint
|
||||
"golang.org/x/crypto/openpgp/clearsign" //nolint
|
||||
"golang.org/x/crypto/openpgp/packet" //nolint
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
hapi "helm.sh/helm/v3/pkg/chart"
|
||||
@@ -314,8 +314,9 @@ func (s *Signatory) decodeSignature(filename string) (*clearsign.Block, error) {
|
||||
func (s *Signatory) verifySignature(block *clearsign.Block) (*openpgp.Entity, error) {
|
||||
return openpgp.CheckDetachedSignature(
|
||||
s.KeyRing,
|
||||
bytes.NewBuffer(block.Bytes),
|
||||
bytes.NewReader(block.Bytes),
|
||||
block.ArmoredSignature.Body,
|
||||
&defaultPGPConfig,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
pgperrors "golang.org/x/crypto/openpgp/errors" //nolint
|
||||
pgperrors "github.com/ProtonMail/go-crypto/openpgp/errors"
|
||||
"github.com/ProtonMail/go-crypto/openpgp/packet"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -56,6 +57,9 @@ const (
|
||||
// testTamperedSigBlock is a tampered copy of msgblock.yaml.asc
|
||||
testTamperedSigBlock = "testdata/msgblock.yaml.tampered"
|
||||
|
||||
// testMixedKeyring points to a keyring containing RSA and ed25519 keys.
|
||||
testMixedKeyring = "testdata/helm-mixed-keyring.pub"
|
||||
|
||||
// testSumfile points to a SHA256 sum generated by an external tool.
|
||||
// We always want to validate against an external tool's representation to
|
||||
// verify that we haven't done something stupid. This file was generated
|
||||
@@ -232,6 +236,56 @@ func TestClearSign(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMixedKeyringRSASigningAndVerification(t *testing.T) {
|
||||
signer, err := NewFromFiles(testKeyfile, testMixedKeyring)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if signer.Entity == nil {
|
||||
t.Fatal("expected signer entity to be loaded")
|
||||
}
|
||||
|
||||
if signer.Entity.PrivateKey == nil {
|
||||
t.Fatal("expected signer private key to be loaded")
|
||||
}
|
||||
|
||||
if signer.Entity.PrivateKey.PubKeyAlgo != packet.PubKeyAlgoRSA {
|
||||
t.Fatalf("expected RSA key but got %v", signer.Entity.PrivateKey.PubKeyAlgo)
|
||||
}
|
||||
|
||||
sig, err := signer.ClearSign(testChartfile)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to sign chart: %v", err)
|
||||
}
|
||||
|
||||
sigpath := filepath.Join(t.TempDir(), "hashtest-1.2.3.tgz.prov")
|
||||
if err := os.WriteFile(sigpath, []byte(sig), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
verification, err := signer.Verify(testChartfile, sigpath)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to verify chart signature: %v", err)
|
||||
}
|
||||
|
||||
if verification.SignedBy == nil {
|
||||
t.Fatal("expected verification to include signer")
|
||||
}
|
||||
|
||||
if verification.SignedBy.PrimaryKey == nil {
|
||||
t.Fatal("expected verification to include signer primary key")
|
||||
}
|
||||
|
||||
if verification.SignedBy.PrimaryKey.PubKeyAlgo != packet.PubKeyAlgoRSA {
|
||||
t.Fatalf("expected verification to report RSA key but got %v", verification.SignedBy.PrimaryKey.PubKeyAlgo)
|
||||
}
|
||||
|
||||
if _, ok := verification.SignedBy.Identities[testKeyName]; !ok {
|
||||
t.Fatalf("expected verification to be signed by %q", testKeyName)
|
||||
}
|
||||
}
|
||||
|
||||
// failSigner always fails to sign and returns an error
|
||||
type failSigner struct{}
|
||||
|
||||
|
||||
BIN
pkg/provenance/testdata/helm-mixed-keyring.pub
vendored
Normal file
BIN
pkg/provenance/testdata/helm-mixed-keyring.pub
vendored
Normal file
Binary file not shown.
Reference in New Issue
Block a user