Skip to content

Commit

Permalink
fixup! Verify release signatures
Browse files Browse the repository at this point in the history
  • Loading branch information
woky committed Oct 24, 2023
1 parent c74cfe0 commit 5453759
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 40 deletions.
16 changes: 5 additions & 11 deletions internal/archive/archive.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package archive
import (
"bytes"
"compress/gzip"
"errors"
"fmt"
"io"
"net/http"
Expand All @@ -12,7 +11,6 @@ import (

"github.com/ProtonMail/go-crypto/openpgp"
"github.com/ProtonMail/go-crypto/openpgp/clearsign"
pgperrors "github.com/ProtonMail/go-crypto/openpgp/errors"

"github.com/canonical/chisel/internal/cache"
"github.com/canonical/chisel/internal/control"
Expand All @@ -32,7 +30,7 @@ type Options struct {
Suites []string
Components []string
CacheDir string
PublicKeys []openpgp.KeyRing
PublicKeys openpgp.KeyRing
}

func Open(options *Options) (Archive, error) {
Expand Down Expand Up @@ -141,6 +139,9 @@ func openUbuntu(options *Options) (Archive, error) {
if len(options.Version) == 0 {
return nil, fmt.Errorf("archive options missing version")
}
if options.PublicKeys == nil {
return nil, fmt.Errorf("archive has no public keys")
}

archive := &ubuntuArchive{
options: *options,
Expand Down Expand Up @@ -197,14 +198,7 @@ func (index *ubuntuIndex) verifyRelease(signedData []byte) ([]byte, error) {
if block == nil {
return nil, fmt.Errorf("cannot decode InRelease clear-sign block")
}
err := pgperrors.ErrUnknownIssuer
for _, pubkey := range index.archive.options.PublicKeys {
_, err = block.VerifySignature(pubkey, nil)
if err == nil || !errors.Is(err, pgperrors.ErrUnknownIssuer) {
break
}
}
if err != nil {
if _, err := block.VerifySignature(index.archive.options.PublicKeys, nil); err != nil {
return nil, fmt.Errorf("signature verification failed: %w", err)
}
return block.Plaintext, nil
Expand Down
72 changes: 59 additions & 13 deletions internal/archive/archive_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ type httpSuite struct {

var _ = Suite(&httpSuite{})

func parseKeyring(ascii string) openpgp.KeyRing {
func parseKeyring(ascii string) openpgp.EntityList {
keyring, err := openpgp.ReadArmoredKeyRing(strings.NewReader(ascii))
if err != nil {
panic(err)
Expand Down Expand Up @@ -105,6 +105,7 @@ func (s *httpSuite) TestDoError(c *C) {
Suites: []string{"jammy"},
Components: []string{"main"},
CacheDir: c.MkDir(),
PublicKeys: testKeyring,
}

_, err := archive.Open(&options)
Expand Down Expand Up @@ -166,7 +167,7 @@ var optionErrorTests = []optionErrorTest{{
Arch: "amd64",
Suites: []string{"jammy"},
Components: []string{"main", "other"},
PublicKeys: []openpgp.KeyRing{testKeyring},
PublicKeys: testKeyring,
},
error: `archive has no component "other"`,
}, {
Expand All @@ -175,7 +176,7 @@ var optionErrorTests = []optionErrorTest{{
Version: "22.04",
Arch: "amd64",
Suites: []string{"jammy"},
PublicKeys: []openpgp.KeyRing{testKeyring},
PublicKeys: testKeyring,
},
error: "archive options missing components",
}, {
Expand All @@ -184,7 +185,7 @@ var optionErrorTests = []optionErrorTest{{
Version: "22.04",
Arch: "amd64",
Components: []string{"main", "other"},
PublicKeys: []openpgp.KeyRing{testKeyring},
PublicKeys: testKeyring,
},
error: `archive options missing suites`,
}, {
Expand All @@ -194,7 +195,7 @@ var optionErrorTests = []optionErrorTest{{
Arch: "foo",
Suites: []string{"jammy"},
Components: []string{"main", "other"},
PublicKeys: []openpgp.KeyRing{testKeyring},
PublicKeys: testKeyring,
},
error: `invalid package architecture: foo`,
}}
Expand All @@ -220,7 +221,7 @@ func (s *httpSuite) TestFetchPackage(c *C) {
Suites: []string{"jammy"},
Components: []string{"main", "universe"},
CacheDir: c.MkDir(),
PublicKeys: []openpgp.KeyRing{testKeyring},
PublicKeys: testKeyring,
}

archive, err := archive.Open(&options)
Expand Down Expand Up @@ -250,7 +251,7 @@ func (s *httpSuite) TestFetchPortsPackage(c *C) {
Suites: []string{"jammy"},
Components: []string{"main", "universe"},
CacheDir: c.MkDir(),
PublicKeys: []openpgp.KeyRing{testKeyring},
PublicKeys: testKeyring,
}

archive, err := archive.Open(&options)
Expand Down Expand Up @@ -288,7 +289,7 @@ func (s *httpSuite) TestFetchSecurityPackage(c *C) {
Arch: "amd64",
Suites: []string{"jammy", "jammy-security", "jammy-updates"},
Components: []string{"main", "universe"},
PublicKeys: []openpgp.KeyRing{testKeyring},
PublicKeys: testKeyring,
}

archive, err := archive.Open(&options)
Expand Down Expand Up @@ -319,7 +320,7 @@ func (s *httpSuite) TestArchiveLabels(c *C) {
Suites: []string{"jammy"},
Components: []string{"main", "universe"},
CacheDir: c.MkDir(),
PublicKeys: []openpgp.KeyRing{testKeyring},
PublicKeys: testKeyring,
}

_, err := archive.Open(&options)
Expand All @@ -334,7 +335,7 @@ func (s *httpSuite) TestArchiveLabels(c *C) {
Suites: []string{"jammy"},
Components: []string{"main", "universe"},
CacheDir: c.MkDir(),
PublicKeys: []openpgp.KeyRing{testKeyring},
PublicKeys: testKeyring,
}

_, err = archive.Open(&options)
Expand All @@ -349,7 +350,7 @@ func (s *httpSuite) TestArchiveLabels(c *C) {
Suites: []string{"jammy"},
Components: []string{"main", "universe"},
CacheDir: c.MkDir(),
PublicKeys: []openpgp.KeyRing{testKeyring},
PublicKeys: testKeyring,
}

_, err = archive.Open(&options)
Expand All @@ -364,13 +365,58 @@ func (s *httpSuite) TestArchiveLabels(c *C) {
Suites: []string{"jammy"},
Components: []string{"main", "universe"},
CacheDir: c.MkDir(),
PublicKeys: []openpgp.KeyRing{testKeyring},
PublicKeys: testKeyring,
}

_, err = archive.Open(&options)
c.Assert(err, ErrorMatches, `.*\bno Ubuntu section`)
}

func (s *httpSuite) TestArchiveSignature(c *C) {
var err error

entityA, err := openpgp.NewEntity("chisel-key-1", "", "", nil)
if err != nil {
panic(err)
}
entityB, err := openpgp.NewEntity("chisel-key-2", "", "", nil)
if err != nil {
panic(err)
}

o := archive.Options{
Label: "ubuntu",
Version: "22.04",
Arch: "amd64",
Suites: []string{"jammy"},
Components: []string{"main"},
CacheDir: c.MkDir(),
}

s.keyring = openpgp.EntityList{entityA}
s.signingKeyID = entityA.PrimaryKey.KeyId

o.PublicKeys = openpgp.EntityList{entityA}
s.prepareArchiveAdjustRelease(o.Suites[0], o.Version, o.Arch, o.Components, nil)
_, err = archive.Open(&o)
c.Assert(err, IsNil)

o.PublicKeys = openpgp.EntityList{entityA, entityB}
s.prepareArchiveAdjustRelease(o.Suites[0], o.Version, o.Arch, o.Components, nil)
_, err = archive.Open(&o)
c.Assert(err, IsNil)

o.PublicKeys = openpgp.EntityList{entityB, entityA}
s.prepareArchiveAdjustRelease(o.Suites[0], o.Version, o.Arch, o.Components, nil)
_, err = archive.Open(&o)
c.Assert(err, IsNil)

o.PublicKeys = openpgp.EntityList{entityB}
s.prepareArchiveAdjustRelease(o.Suites[0], o.Version, o.Arch, o.Components, nil)
_, err = archive.Open(&o)
c.Assert(err, ErrorMatches, "cannot verify release: signature verification failed: openpgp: signature made by unknown entity")
}

func read(r io.Reader) string {
data, err := io.ReadAll(r)
if err != nil {
Expand Down Expand Up @@ -426,7 +472,7 @@ func (s *S) testOpenArchiveArch(c *C, arch string) {
Suites: []string{"jammy"},
Components: []string{"main", "universe"},
CacheDir: c.MkDir(),
PublicKeys: []openpgp.KeyRing{ubuntuArchiveKeyring},
PublicKeys: ubuntuArchiveKeyring,
}

archive, err := archive.Open(&options)
Expand Down
30 changes: 17 additions & 13 deletions internal/setup/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ type Archive struct {
Version string
Suites []string
Components []string
PublicKeys []openpgp.KeyRing
PublicKeys openpgp.KeyRing
}

// Package holds a collection of slices that represent parts of themselves.
Expand Down Expand Up @@ -418,14 +418,14 @@ func parseRelease(baseDir, filePath string, data []byte) (*Release, error) {
return nil, fmt.Errorf("%s: no archives defined", fileName)
}

pubkeysByName := make(map[string]openpgp.KeyRing, 0)
pubKeysByName := make(map[string]openpgp.EntityList, 0)

for pubkeyName, pubkeyArmored := range yamlVar.PublicKeys {
pubkey, err := openpgp.ReadArmoredKeyRing(strings.NewReader(pubkeyArmored))
for pubKeysName, pubKeyArmored := range yamlVar.PublicKeys {
pubKeys, err := openpgp.ReadArmoredKeyRing(strings.NewReader(pubKeyArmored))
if err != nil {
return nil, fmt.Errorf("%s: cannot parse public key %q: %w", fileName, pubkeyName, err)
return nil, fmt.Errorf("%s: cannot parse public key %q: %w", fileName, pubKeysName, err)
}
pubkeysByName[pubkeyName] = pubkey
pubKeysByName[pubKeysName] = pubKeys
}

for archiveName, details := range yamlVar.Archives {
Expand All @@ -442,13 +442,17 @@ func parseRelease(baseDir, filePath string, data []byte) (*Release, error) {
if len(details.Components) == 0 {
return nil, fmt.Errorf("%s: archive %q missing components field", fileName, archiveName)
}
var archivePubkeys []openpgp.KeyRing
for _, pubkeyName := range details.PublicKeys {
pubkey := pubkeysByName[pubkeyName]
if pubkey == nil {
return nil, fmt.Errorf("%s: archive %q references unknown public key %q", fileName, archiveName, pubkeyName)
var archivePubKeysTmp openpgp.EntityList
for _, pubKeysName := range details.PublicKeys {
pubKeys := pubKeysByName[pubKeysName]
if pubKeys == nil {
return nil, fmt.Errorf("%s: archive %q references unknown public key %q", fileName, archiveName, pubKeysName)
}
archivePubkeys = append(archivePubkeys, pubkey)
archivePubKeysTmp = append(archivePubKeysTmp, pubKeys...)
}
var archivePubKeys openpgp.KeyRing
if archivePubKeysTmp != nil {
archivePubKeys = archivePubKeysTmp
}
if len(yamlVar.Archives) == 1 {
details.Default = true
Expand All @@ -463,7 +467,7 @@ func parseRelease(baseDir, filePath string, data []byte) (*Release, error) {
Version: details.Version,
Suites: details.Suites,
Components: details.Components,
PublicKeys: archivePubkeys,
PublicKeys: (openpgp.KeyRing)(archivePubKeys),
}
}

Expand Down
6 changes: 3 additions & 3 deletions internal/setup/setup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
"github.com/canonical/chisel/internal/testutil"
)

func parseKeyring(ascii string) openpgp.KeyRing {
func parseKeyring(ascii string) openpgp.EntityList {
keyring, err := openpgp.ReadArmoredKeyRing(strings.NewReader(ascii))
if err != nil {
panic(err)
Expand Down Expand Up @@ -855,14 +855,14 @@ var setupTests = []setupTest{{
Version: "22.04",
Suites: []string{"jammy"},
Components: []string{"main", "universe"},
PublicKeys: []openpgp.KeyRing{testKeyringUbuntuArchive},
PublicKeys: testKeyringUbuntuArchive,
},
"bar": {
Name: "bar",
Version: "22.04",
Suites: []string{"jammy-updates"},
Components: []string{"universe"},
PublicKeys: []openpgp.KeyRing{testKeyringUbuntuArchive, testKeyringUbuntuMaster},
PublicKeys: append(testKeyringUbuntuArchive, testKeyringUbuntuMaster...),
},
},
Packages: map[string]*setup.Package{
Expand Down

0 comments on commit 5453759

Please sign in to comment.