diff --git a/.gitignore b/.gitignore index f25dfbb24..a4dedf903 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,6 @@ system/env/ # created by make build for release artifacts build/ + +pgp/keyrings/aptly2*.gpg +pgp/keyrings/aptly2*.gpg~ diff --git a/.travis.yml b/.travis.yml index 9ce86b751..d2f673f5b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,8 @@ addons: packages: - python-virtualenv - graphviz + - gnupg2 + - gpgv2 env: global: diff --git a/cmd/cmd.go b/cmd/cmd.go index e00668015..187193928 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -119,7 +119,7 @@ package environment to new version.`, cmd.Flag.Bool("dep-verbose-resolve", false, "when processing dependencies, print detailed logs") cmd.Flag.String("architectures", "", "list of architectures to consider during (comma-separated), default to all available") cmd.Flag.String("config", "", "location of configuration file (default locations are /etc/aptly.conf, ~/.aptly.conf)") - cmd.Flag.String("gpg-provider", "", "PGP implementation (\"gpg\" for external gpg or \"internal\" for Go internal implementation)") + cmd.Flag.String("gpg-provider", "", "PGP implementation (\"gpg\", \"gpg1\", \"gpg2\" for external gpg or \"internal\" for Go internal implementation)") if aptly.EnableDebug { cmd.Flag.String("cpuprofile", "", "write cpu profile to file") diff --git a/context/context.go b/context/context.go index eae6f1b53..eb7c88854 100644 --- a/context/context.go +++ b/context/context.go @@ -387,23 +387,42 @@ func (context *AptlyContext) pgpProvider() string { provider = context.config().GpgProvider } - if !(provider == "gpg" || provider == "internal") { // nolint: goconst + switch provider { + case "gpg": // nolint: goconst + case "gpg1": // nolint: goconst + case "gpg2": // nolint: goconst + case "internal": // nolint: goconst + default: Fatal(fmt.Errorf("unknown gpg provider: %v", provider)) } return provider } +func (context *AptlyContext) getGPGFinder(provider string) pgp.GPGFinder { + switch context.pgpProvider() { + case "gpg1": + return pgp.GPG1Finder() + case "gpg2": + return pgp.GPG2Finder() + case "gpg": + return pgp.GPGDefaultFinder() + } + + panic("uknown GPG provider type") +} + // GetSigner returns Signer with respect to provider func (context *AptlyContext) GetSigner() pgp.Signer { context.Lock() defer context.Unlock() - if context.pgpProvider() == "gpg" { // nolint: goconst - return pgp.NewGpgSigner() + provider := context.pgpProvider() + if provider == "internal" { // nolint: goconst + return &pgp.GoSigner{} } - return &pgp.GoSigner{} + return pgp.NewGpgSigner(context.getGPGFinder(provider)) } // GetVerifier returns Verifier with respect to provider @@ -411,11 +430,12 @@ func (context *AptlyContext) GetVerifier() pgp.Verifier { context.Lock() defer context.Unlock() - if context.pgpProvider() == "gpg" { // nolint: goconst - return pgp.NewGpgVerifier() + provider := context.pgpProvider() + if provider == "internal" { // nolint: goconst + return &pgp.GoVerifier{} } - return &pgp.GoVerifier{} + return pgp.NewGpgVerifier(context.getGPGFinder(provider)) } // UpdateFlags sets internal copy of flags in the context diff --git a/man/aptly.1 b/man/aptly.1 index ec5d991e6..25aaf337e 100644 --- a/man/aptly.1 +++ b/man/aptly.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "APTLY" "1" "November 2017" "" "" +.TH "APTLY" "1" "September 2018" "" "" . .SH "NAME" \fBaptly\fR \- Debian repository management tool @@ -150,7 +150,7 @@ don\(cqt verify remote mirrors with gpg(1), also can be disabled on per\-mirror . .TP \fBgpgProvider\fR -implementation of PGP signing/validation \- \fBgpg\fR for external \fBgpg\fR utility or \fBinternal\fR to use Go internal implementation +implementation of PGP signing/validation \- \fBgpg\fR for external \fBgpg\fR utility or \fBinternal\fR to use Go internal implementation; \fBgpg1\fR might be used to force use of GnuPG 1\.x, \fBgpg2\fR enables GnuPG 2\.x only; default is to use GnuPG 1\.x if available and GnuPG 2\.x otherwise . .TP \fBdownloadSourcePackages\fR @@ -434,7 +434,7 @@ when processing dependencies, print detailed logs . .TP \-\fBgpg\-provider\fR= -PGP implementation ("gpg" for external gpg or "internal" for Go internal implementation) +PGP implementation ("gpg", "gpg1", "gpg2" for external gpg or "internal" for Go internal implementation) . .SH "CREATE NEW MIRROR" \fBaptly\fR \fBmirror\fR \fBcreate\fR \fIname\fR \fIarchive url\fR \fIdistribution\fR [\fIcomponent1\fR \|\.\|\.\|\.] @@ -2030,5 +2030,17 @@ Matt Martyn (https://github\.com/MMartyn) .IP "\[ci]" 4 Ludovico Cavedon (https://github\.com/cavedon) . +.IP "\[ci]" 4 +Petr Jediny (https://github\.com/pjediny) +. +.IP "\[ci]" 4 +Maximilian Stein (https://github\.com/steinymity) +. +.IP "\[ci]" 4 +Strajan Sebastian (https://github\.com/strajansebastian) +. +.IP "\[ci]" 4 +Artem Smirnov (https://github\.com/urpylka) +. .IP "" 0 diff --git a/man/aptly.1.ronn.tmpl b/man/aptly.1.ronn.tmpl index b640d9d8f..29b0b44ff 100644 --- a/man/aptly.1.ronn.tmpl +++ b/man/aptly.1.ronn.tmpl @@ -130,7 +130,9 @@ Options: * `gpgProvider`: implementation of PGP signing/validation - `gpg` for external `gpg` utility or - `internal` to use Go internal implementation + `internal` to use Go internal implementation; `gpg1` might be used to force use + of GnuPG 1.x, `gpg2` enables GnuPG 2.x only; default is to use GnuPG 1.x if + available and GnuPG 2.x otherwise * `downloadSourcePackages`: if enabled, all mirrors created would have flag set to download source packages; diff --git a/pgp/gnupg.go b/pgp/gnupg.go index ba5f24b3e..82be859e5 100644 --- a/pgp/gnupg.go +++ b/pgp/gnupg.go @@ -3,6 +3,7 @@ package pgp import ( "bufio" "bytes" + "errors" "fmt" "io" "io/ioutil" @@ -18,12 +19,10 @@ var ( _ Verifier = &GpgVerifier{} ) -// Skip GPG version check for GPG 1.x -var skipGPGVersionCheck bool - // GpgSigner is implementation of Signer interface using gpg as external program type GpgSigner struct { gpg string + version GPGVersion keyRef string keyring, secretKeyring string passphrase, passphraseFile string @@ -55,7 +54,7 @@ func (g *GpgSigner) gpgArgs() []string { if g.keyring != "" { args = append(args, "--no-auto-check-trustdb", "--no-default-keyring", "--keyring", g.keyring) } - if g.secretKeyring != "" { + if g.secretKeyring != "" && g.version == GPG1x { args = append(args, "--secret-keyring", g.secretKeyring) } @@ -64,7 +63,9 @@ func (g *GpgSigner) gpgArgs() []string { } if g.passphrase != "" || g.passphraseFile != "" { - args = append(args, "--no-use-agent") + if g.version == GPG1x { + args = append(args, "--no-use-agent") + } } if g.passphrase != "" { @@ -77,53 +78,21 @@ func (g *GpgSigner) gpgArgs() []string { if g.batch { args = append(args, "--no-tty", "--batch") - } - - return args -} - -func cliVersionCheck(cmd string, marker string) bool { - output, err := exec.Command(cmd, "--version").CombinedOutput() - if err != nil { - return false - } - return skipGPGVersionCheck || strings.Contains(string(output), marker) -} - -func findSuitableCLI(cmds []string, versionMarker string) string { - for _, cmd := range cmds { - if cliVersionCheck(cmd, versionMarker) { - return cmd + if g.version == GPG21xPlus { + args = append(args, "--pinentry-mode", "loopback") } } - return "" -} - -// We only support gpg1 at this time. Make sure we find a suitable binary. -func findGPG1() (string, error) { - cmd := findSuitableCLI([]string{"gpg", "gpg1"}, "gpg (GnuPG) 1.") - if cmd != "" { - return cmd, nil - } - return "", fmt.Errorf("Couldn't find a suitable gpg executable. Make sure gnupg1 is available as either gpg or gpg1 in $PATH") -} -// We only support gpgv1 at this time. Make sure we find a suitable binary. -func findGPGV1() (string, error) { - cmd := findSuitableCLI([]string{"gpgv", "gpgv1"}, "gpgv (GnuPG) 1.") - if cmd != "" { - return cmd, nil - } - return "", fmt.Errorf("Couldn't find a suitable gpgv executable. Make sure gpgv1 is available as either gpgv or gpgv1 in $PATH") + return args } // NewGpgSigner creates a new gpg signer -func NewGpgSigner() *GpgSigner { - gpg, err := findGPG1() +func NewGpgSigner(finder GPGFinder) *GpgSigner { + gpg, version, err := finder.FindGPG() if err != nil { panic(err) } - return &GpgSigner{gpg: gpg} + return &GpgSigner{gpg: gpg, version: version} } // Init verifies availability of gpg & presence of keys @@ -171,22 +140,27 @@ func (g *GpgSigner) ClearSign(source string, destination string) error { type GpgVerifier struct { gpg string gpgv string + version GPGVersion keyRings []string } // NewGpgVerifier creates a new gpg verifier -func NewGpgVerifier() *GpgVerifier { - gpg, err := findGPG1() +func NewGpgVerifier(finder GPGFinder) *GpgVerifier { + gpg, versionGPG, err := finder.FindGPG() if err != nil { panic(err) } - gpgv, err := findGPGV1() + gpgv, versionGPGV, err := finder.FindGPGV() if err != nil { panic(err) } - return &GpgVerifier{gpg: gpg, gpgv: gpgv} + if versionGPG != versionGPGV { + panic(errors.New("gpg and gpgv versions don't match")) + } + + return &GpgVerifier{gpg: gpg, gpgv: gpgv, version: versionGPG} } // InitKeyring verifies that gpg is installed and some keys are trusted @@ -417,11 +391,3 @@ func (g *GpgVerifier) ExtractClearsigned(clearsigned io.Reader) (text *os.File, return } - -func init() { - skipCheck := os.Getenv("APTLY_SKIP_GPG_VERSION_CHECK") - switch strings.ToLower(skipCheck) { - case "1", "y", "yes", "true": - skipGPGVersionCheck = true - } -} diff --git a/pgp/gnupg_finder.go b/pgp/gnupg_finder.go new file mode 100644 index 000000000..683bba82f --- /dev/null +++ b/pgp/gnupg_finder.go @@ -0,0 +1,149 @@ +package pgp + +import ( + "errors" + "os/exec" + "regexp" + "strings" +) + +// GPGVersion stores discovered GPG version +type GPGVersion int + +// GPG version as discovered +const ( + GPG1x GPGVersion = 1 + GPG20x GPGVersion = 2 + GPG21xPlus GPGVersion = 3 +) + +var gpgVersionRegex = regexp.MustCompile(`\(GnuPG\) (\d)\.(\d)`) + +// GPGFinder implement search for gpg executables and returns version of discovered executables +type GPGFinder interface { + FindGPG() (gpg string, version GPGVersion, err error) + FindGPGV() (gpgv string, version GPGVersion, err error) +} + +type pathGPGFinder struct { + gpgNames []string + gpgvNames []string + errorMessage string + + expectedVersionSubstring string +} + +type iteratingGPGFinder struct { + finders []GPGFinder + errorMessage string +} + +// GPGDefaultFinder looks for GPG1 first, but falls back to GPG2 if GPG1 is not available +func GPGDefaultFinder() GPGFinder { + return &iteratingGPGFinder{ + finders: []GPGFinder{GPG1Finder(), GPG2Finder()}, + errorMessage: "Couldn't find a suitable gpg executable. Make sure gnupg is installed", + } +} + +// GPG1Finder looks for GnuPG1.x only +func GPG1Finder() GPGFinder { + return &pathGPGFinder{ + gpgNames: []string{"gpg", "gpg1"}, + gpgvNames: []string{"gpgv", "gpgv1"}, + expectedVersionSubstring: "(GnuPG) 1.", + errorMessage: "Couldn't find a suitable gpg executable. Make sure gnupg1 is available as either gpg(v) or gpg(v)1 in $PATH", + } +} + +// GPG2Finder looks for GnuPG2.x only +func GPG2Finder() GPGFinder { + return &pathGPGFinder{ + gpgNames: []string{"gpg", "gpg2"}, + gpgvNames: []string{"gpgv", "gpgv2"}, + expectedVersionSubstring: "(GnuPG) 2.", + errorMessage: "Couldn't find a suitable gpg executable. Make sure gnupg2 is available as either gpg(v) or gpg(v)2 in $PATH", + } +} + +func (pgf *pathGPGFinder) FindGPG() (gpg string, version GPGVersion, err error) { + for _, cmd := range pgf.gpgNames { + var result bool + result, version = cliVersionCheck(cmd, pgf.expectedVersionSubstring) + if result { + gpg = cmd + break + } + } + + if gpg == "" { + err = errors.New(pgf.errorMessage) + } + + return +} + +func (pgf *pathGPGFinder) FindGPGV() (gpgv string, version GPGVersion, err error) { + for _, cmd := range pgf.gpgvNames { + var result bool + result, version = cliVersionCheck(cmd, pgf.expectedVersionSubstring) + if result { + gpgv = cmd + break + } + } + + if gpgv == "" { + err = errors.New(pgf.errorMessage) + } + + return +} + +func (it *iteratingGPGFinder) FindGPG() (gpg string, version GPGVersion, err error) { + for _, finder := range it.finders { + gpg, version, err = finder.FindGPG() + if err == nil { + return + } + } + + err = errors.New(it.errorMessage) + + return +} + +func (it *iteratingGPGFinder) FindGPGV() (gpg string, version GPGVersion, err error) { + for _, finder := range it.finders { + gpg, version, err = finder.FindGPGV() + if err == nil { + return + } + } + + err = errors.New(it.errorMessage) + + return +} + +func cliVersionCheck(cmd string, marker string) (result bool, version GPGVersion) { + output, err := exec.Command(cmd, "--version").CombinedOutput() + if err != nil { + return + } + + strOutput := string(output) + result = strings.Contains(strOutput, marker) + + version = GPG21xPlus + matches := gpgVersionRegex.FindStringSubmatch(strOutput) + if matches != nil { + if matches[1] == "1" { + version = GPG1x + } else if matches[1] == "2" && matches[2] == "0" { + version = GPG20x + } + } + + return +} diff --git a/pgp/gnupg_test.go b/pgp/gnupg_test.go index 30e93ca30..655ef33ba 100644 --- a/pgp/gnupg_test.go +++ b/pgp/gnupg_test.go @@ -2,6 +2,7 @@ package pgp import ( "os" + "os/exec" "path/filepath" "runtime" @@ -26,7 +27,7 @@ func (s *GnupgSuite) TestGPG1(c *C) { os.Setenv("PATH", filepath.Join(s.bins, "gpg1")) defer func() { os.Setenv("PATH", origPath) }() - signer := NewGpgSigner() + signer := NewGpgSigner(GPG1Finder()) c.Assert(signer.gpg, Equals, "gpg") } @@ -36,7 +37,7 @@ func (s *GnupgSuite) TestGPG1Not2(c *C) { os.Setenv("PATH", filepath.Join(s.bins, "gpg2-and-1")) defer func() { os.Setenv("PATH", origPath) }() - signer := NewGpgSigner() + signer := NewGpgSigner(GPG1Finder()) c.Assert(signer.gpg, Equals, "gpg1") } @@ -46,7 +47,7 @@ func (s *GnupgSuite) TestGPGNothing(c *C) { os.Setenv("PATH", filepath.Join(s.bins, "gpg2-only")) defer func() { os.Setenv("PATH", origPath) }() - c.Assert(func() { NewGpgSigner() }, PanicMatches, `Couldn't find a suitable gpg executable.+`) + c.Assert(func() { NewGpgSigner(GPG1Finder()) }, PanicMatches, `Couldn't find a suitable gpg executable.+`) } // If gpgv == gpgv1 = pick gpgv @@ -55,7 +56,7 @@ func (s *GnupgSuite) TestGPGV1(c *C) { os.Setenv("PATH", filepath.Join(s.bins, "gpgv1")+":"+filepath.Join(s.bins, "gpg1")) defer func() { os.Setenv("PATH", origPath) }() - verifier := NewGpgVerifier() + verifier := NewGpgVerifier(GPG1Finder()) c.Assert(verifier.gpgv, Equals, "gpgv") } @@ -65,7 +66,7 @@ func (s *GnupgSuite) TestGPGV1Not2(c *C) { os.Setenv("PATH", filepath.Join(s.bins, "gpgv2-and-1")+":"+filepath.Join(s.bins, "gpg1")) defer func() { os.Setenv("PATH", origPath) }() - verifier := NewGpgVerifier() + verifier := NewGpgVerifier(GPG1Finder()) c.Assert(verifier.gpgv, Equals, "gpgv1") } @@ -75,7 +76,7 @@ func (s *GnupgSuite) TestGPGVNothing(c *C) { os.Setenv("PATH", filepath.Join(s.bins, "gpgv2-only")+":"+filepath.Join(s.bins, "gpg1")) defer func() { os.Setenv("PATH", origPath) }() - c.Assert(func() { NewGpgVerifier() }, PanicMatches, `Couldn't find a suitable gpgv executable.+`) + c.Assert(func() { NewGpgVerifier(GPG1Finder()) }, PanicMatches, `Couldn't find a suitable gpg executable.+`) } type Gnupg1VerifierSuite struct { @@ -85,7 +86,13 @@ type Gnupg1VerifierSuite struct { var _ = Suite(&Gnupg1VerifierSuite{}) func (s *Gnupg1VerifierSuite) SetUpTest(c *C) { - s.verifier = NewGpgVerifier() + finder := GPG1Finder() + _, _, err := finder.FindGPG() + if err != nil { + c.Skip(err.Error()) + } + + s.verifier = NewGpgVerifier(finder) s.verifier.AddKeyring("./trusted.gpg") c.Assert(s.verifier.InitKeyring(), IsNil) @@ -98,7 +105,18 @@ type Gnupg1SignerSuite struct { var _ = Suite(&Gnupg1SignerSuite{}) func (s *Gnupg1SignerSuite) SetUpTest(c *C) { - s.signer = NewGpgSigner() + finder := GPG1Finder() + _, _, err := finder.FindGPG() + if err != nil { + c.Skip(err.Error()) + } + + s.keyringNoPassphrase = [2]string{"keyrings/aptly.pub", "keyrings/aptly.sec"} + s.keyringPassphrase = [2]string{"keyrings/aptly_passphrase.pub", "keyrings/aptly_passphrase.sec"} + s.passphraseKey = "F30E8CB9CDDE2AF8" + s.noPassphraseKey = "21DBB89C16DB3E6D" + + s.signer = NewGpgSigner(finder) s.signer.SetBatch(true) s.verifier = &GoVerifier{} @@ -109,3 +127,95 @@ func (s *Gnupg1SignerSuite) SetUpTest(c *C) { s.SignerSuite.SetUpTest(c) } + +type Gnupg2VerifierSuite struct { + VerifierSuite +} + +var _ = Suite(&Gnupg2VerifierSuite{}) + +func (s *Gnupg2VerifierSuite) SetUpTest(c *C) { + finder := GPG2Finder() + _, _, err := finder.FindGPG() + if err != nil { + c.Skip(err.Error()) + } + + s.verifier = NewGpgVerifier(finder) + s.verifier.AddKeyring("./trusted.gpg") + + c.Assert(s.verifier.InitKeyring(), IsNil) +} + +type Gnupg2SignerSuite struct { + SignerSuite +} + +var _ = Suite(&Gnupg2SignerSuite{}) + +func (s *Gnupg2SignerSuite) SetUpTest(c *C) { + finder := GPG2Finder() + gpg, ver, err := finder.FindGPG() + if err != nil { + c.Skip(err.Error()) + } + + // import private keys into gpg2, they're stored outside of keyring files + for _, item := range []struct { + suffix string + key string + }{ + {"", "751DF85C2B220D45"}, + {"_passphrase", "6656CD181E92D2D5"}, + } { + if _, err := exec.Command(gpg, "--list-secret-keys", item.key).CombinedOutput(); err == nil { + // key already exists + continue + } + + args := []string{"--import", "--no-default-keyring"} + + if item.suffix == "_passprhase" { + args = append(args, "--passphrase", "verysecret", "--no-tty", "--batch") + if ver == GPG21xPlus { + args = append(args, "--pinentry-mode", "loopback") + } + } + args = append(args, "keyrings/aptly2"+item.suffix+".sec.armor") + + output, err := exec.Command(gpg, args...).CombinedOutput() + c.Log(string(output)) + c.Check(err, IsNil) + } + + // import public keys into gpg2 + // we can't use pre-built keyrings as gpg 2.0.x and 2.1+ have different keyring formats + for _, suffix := range []string{"", "_passphrase"} { + output, err := exec.Command(gpg, "--no-default-keyring", "--keyring", "./keyrings/aptly2"+suffix+".gpg", + "--import", "keyrings/aptly2"+suffix+".pub.armor").CombinedOutput() + c.Log(string(output)) + c.Check(err, IsNil) + } + + s.keyringNoPassphrase = [2]string{"./keyrings/aptly2.gpg", ""} + s.keyringPassphrase = [2]string{"./keyrings/aptly2_passphrase.gpg", ""} + s.noPassphraseKey = "751DF85C2B220D45" + s.passphraseKey = "6656CD181E92D2D5" + + s.signer = NewGpgSigner(finder) + s.signer.SetBatch(true) + + s.verifier = &GoVerifier{} + s.verifier.AddKeyring("./keyrings/aptly2_trusted.pub") + + c.Assert(s.verifier.InitKeyring(), IsNil) + + s.SignerSuite.SetUpTest(c) +} + +func (s *Gnupg2SignerSuite) TearDownTest(c *C) { + s.SignerSuite.TearDownTest(c) + + os.Remove("./keyrings/aptly2.gpg") + os.Remove("./keyrings/aptly2_passphrase.gpg") +} diff --git a/pgp/internal_test.go b/pgp/internal_test.go index 79fd60d57..1780e73dc 100644 --- a/pgp/internal_test.go +++ b/pgp/internal_test.go @@ -24,6 +24,11 @@ type GoSignerSuite struct { var _ = Suite(&GoSignerSuite{}) func (s *GoSignerSuite) SetUpTest(c *C) { + s.keyringNoPassphrase = [2]string{"keyrings/aptly.pub", "keyrings/aptly.sec"} + s.keyringPassphrase = [2]string{"keyrings/aptly_passphrase.pub", "keyrings/aptly_passphrase.sec"} + s.passphraseKey = "F30E8CB9CDDE2AF8" + s.noPassphraseKey = "21DBB89C16DB3E6D" + s.signer = &GoSigner{} s.signer.SetBatch(true) diff --git a/pgp/keyrings/aptly2.pub.armor b/pgp/keyrings/aptly2.pub.armor new file mode 100644 index 000000000..689a3b359 --- /dev/null +++ b/pgp/keyrings/aptly2.pub.armor @@ -0,0 +1,30 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQENBFuAfvMBCACuElVMZctaYEMSIoYLAefC2ygH/MUWA41h/MT/kMakexK7B2N/ +noPUhA0Z7xWiqxnvJqaOGuT2Bp2SSOuw8hXD870VMNNAVuvg63Zvj5DGhWAjR8Sm +zHaZ09+hkD+MB7+WJnyDJb0deGpJ7cFaUgS4fz1BlTWHpJX8wMBi3iqA2tulcoNn +L/pUomusNGiD+4TuWkEeYb3/ygXvfocuE0Ji7UFrijU4Dcrh7T7L7qzHDMy8hyEr +t3oZlFDlwRkr+1LrT1QBnndaddPRt1h3Av59WpasTUC8m/It0NvLpq9mqij3TNTx +OyZNJLqHrUsz1/cg3boiT4puY8gm2jpQpNLXABEBAAG0HkFwdGx5IFRlc3RlciA8 +dGVzdEBhcHRseS5pbmZvPokBTgQTAQgAOBYhBOivfuFBYsLWPPwa1XUd+FwrIg1F +BQJbgH7zAhsDBQsJCAcCBhUICQoLAgQWAgMBAh4BAheAAAoJEHUd+FwrIg1FWRwH +/RmXNwgh6DEj7wN7hILL15iXOrOIjEJ2GH0cWvPdyzc/qbL552QovcaK3yb/r3V+ ++1wDJ2CuBtc/CoVFq1CN/i92wIDl+Cuozny5qcd8O6EjgdmLgeANRwqyMjiPiDz9 +cuabD3JPRHIqEv26PQ+qkmad42E5mipHmbA+iOE9OEWSvhDudAlYzNXECUWlNQ9+ +gWnLB6hONz5jnRDZHpcKeBcQ2aJ7r5L6qDzBIybAu3jiZfl5KlT6hArXi5vDi8DK +B5is80nWPTAEb2+CfBiY80mLScNe5jG/sgOOrTqWL681RfjRtTnRe7DFKIm8guqp +tbYrv4OzkFHJ/JbWAKsBruS5AQ0EW4B+8wEIANWaf4BWY2or9oyu001EmIdFiwu2 +cxGA2y8bZiqmerk+2BXDEZN4OaLu1a9RWpwo1Mc+KuXpeJNv60SG0zRFBLVrvPyg +irhaue1p+SSuisxMdTOZrciYjWriTU4WKw+NOdiGHr5LJegE9hvW66ZYJHtYgkfB +mBuIQQ90h6qnXKGtV4FK8Fo+hr04Wh7gDGZxTRFNo3MO0a18Y87uiU5j8i/VxyfI +DSA2Uh92kPbItuEKtl23PhCSecZa4YkkWMILS7frMEbM9wDK/JFqPVPSUwQhV5jn +wwq9hwQrUimrhZjJn1EImK2QVYeJ1CVxc3K7bdlxPd8fi6zfTQ8AfpALDWkAEQEA +AYkBNgQYAQgAIBYhBOivfuFBYsLWPPwa1XUd+FwrIg1FBQJbgH7zAhsMAAoJEHUd ++FwrIg1FzpEH/2xi/DCaYRgbC4RrICebeC8FBTwI2RyBuOQJr5CIPrpWaWV4+5Ds +sIgPxU9E3QgNRjP9pzAzH2Z8WwJtRY0oYNWLFruNeg9Xl1Tf9pCK/0Csamyf/h3F +6NKfDTwNBWTsD5ttNyRx2nfDPaU4j2BZqU3kOzdwiXnmtvtxEoH059EMgQFLv91W +U7NydHYd8xcWlHIZx1uFB8HKRWB+AMXebkdLVXlUtJfZfxZr5Jb5eR77ojfsduYI +YmbV4jkDxuidSkYogYyXMO2jY2PAhx29iaZrDsNdsCsg8OmwEjCPEGWdp7tFA1QI +JrGSOnwXujoUwuqh53+n3bcVuuuKyPBW9b4= +=Tu5z +-----END PGP PUBLIC KEY BLOCK----- diff --git a/pgp/keyrings/aptly2.sec.armor b/pgp/keyrings/aptly2.sec.armor new file mode 100644 index 000000000..b3a96f09c --- /dev/null +++ b/pgp/keyrings/aptly2.sec.armor @@ -0,0 +1,57 @@ +-----BEGIN PGP PRIVATE KEY BLOCK----- + +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 +=vqFY +-----END PGP PRIVATE KEY BLOCK----- diff --git a/pgp/keyrings/aptly2_passphrase.pub.armor b/pgp/keyrings/aptly2_passphrase.pub.armor new file mode 100644 index 000000000..04484c7a9 --- /dev/null +++ b/pgp/keyrings/aptly2_passphrase.pub.armor @@ -0,0 +1,30 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQENBFuAgf0BCADhVDnKyR5G6RzgFb7QseLqOzjvGotmbYYTuYinwLC+GGgOBD54 +DTtzBk6PmU1/QW7x0yvffyeQWUXD+/zIuBLrkG2QXv9qRdADH6rCsVChtVsTRwHT +ZgJJXgfcjsZ2UUDQ43Jkb4dMaAIJTS0dASXgyLIRaN/1h4SsdKZUZY16lMH9kSxb +XI86qujCdC9WS7CWu8sLX7qKqmmAt8fTGTnTgyQCnIYtS1/je0ZfX4Z3ovzYyajJ +LA/jtCD6L+3qj9Y7desj1AvNKRCGYB8nzayYYVqozNFvlubDePinFqJThrICviNS +cNZuNmZjToPmSMF/B6zz1CkrR6Q0CIM5zkuxABEBAAG0HkFwdGx5IFRlc3RlciA8 +dGVzdEBhcHRseS5pbmZvPokBTgQTAQgAOBYhBAvV0vLk0JvPtsmaFGZWzRgektLV +BQJbgIH9AhsDBQsJCAcCBhUICQoLAgQWAgMBAh4BAheAAAoJEGZWzRgektLVAHoH +/jwdhMCDmgBR3vhS/i7ym5HFUx7o1cCv0cSoGQwgnRGLrTG4Ua4ds+FxAKjNAspC +hgxGGfTCmD1cYB4lx85I0XcpfT4ZA0ZCQ1I9m5/AJ9WWYoy2FFZNxZ7fCd2d+sm1 +ydyJLCTRgJd0D2MD58vxF2+IWAkZTOridyyZP1qxfzcnSACTjbcrQFc1Bp7G1xJR +T135mcxtBSD2JeXbvq/UkeOE+LCIF5EIHUlwOdanyyHTyO86R2rU7qO0bylNyLGi +0SE3Y+j+qhg6Ns4I2SPo0JDBDrSVfPKcob1DYFF0K1yH6Cj3aGVUthsahNrP3K9S +NOVRC1JUg5an0eWcayIPpte5AQ0EW4CB/QEIAMrLVpvc2Syuhtov6mBTuIB9SUHy +9tyqK6WhyDAB7iQPC5Xrb4GXHM4z+2Vt7Pgabr630B6ySsmrKNfDB1EcUcY4aJ5Q +LBIttR25CB8PkmvllycjKp49hLXOruwx6t23/J3REyapQXLKpXDhzmMTmoGpAPcu +YTVMiiOFi0MNBI5ok9iQoG9Dbgf7F0Ie1MiLJzqfaf2dlRuh2JBayIMJ9VrtlThB +5v2CsV73Mj7EgE7oetZgH2I9Tl/2vv70VYnoXn/YL2xgfghWWlTvDTvg9s7sRnDI +4oor7SHaRZIWxqSuvVOchnlBjLADn902bFIPEanqBiAnPAHPwPOMKnBoR78AEQEA +AYkBNgQYAQgAIBYhBAvV0vLk0JvPtsmaFGZWzRgektLVBQJbgIH9AhsMAAoJEGZW +zRgektLVetQH/1QiJqu6JmEbJ4Z8mmwr25iqeC/9G1Llo6q4VAoLFygFU1EVW+wX +tPwz5RZpqoZ5K4NVFJcgLH1ExqgKW9MflPK+6ltYqH3Kgg73I5gnP9SX12hJ3oMZ +X15uGm8pN+na4fcu9rwvk87EBfXXmtP9oqdCPZ49DtkngyahTXFK/h5CbcgCx1Fw +rm1QXyH/sB8O3f6GOVly40u7CV0hzWAB98KLgEP093OI3AJjmINxErCt6cigxQzO +jgbiTMVgLKHidnpeOcKNXIlmIBFpBM4oaKFZ0qt5jiKz/QtmX7Uj+rTfCjaC1G7f +fGE72fE3nL5TcbwRyD7g9zRV3ddU5uvCnlg= +=075D +-----END PGP PUBLIC KEY BLOCK----- diff --git a/pgp/keyrings/aptly2_passphrase.sec.armor b/pgp/keyrings/aptly2_passphrase.sec.armor new file mode 100644 index 000000000..09bc6df5f --- /dev/null +++ b/pgp/keyrings/aptly2_passphrase.sec.armor @@ -0,0 +1,59 @@ +-----BEGIN PGP PRIVATE KEY BLOCK----- + +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 +bt98YTvZ8TecvlNxvBHIPuD3NFXd11Tm68KeWA== +=YDL1 +-----END PGP PRIVATE KEY BLOCK----- diff --git a/pgp/keyrings/aptly2_trusted.pub b/pgp/keyrings/aptly2_trusted.pub new file mode 100644 index 000000000..9da33ce3d Binary files /dev/null and b/pgp/keyrings/aptly2_trusted.pub differ diff --git a/pgp/sign_test.go b/pgp/sign_test.go index 583329e77..8cd064e0d 100644 --- a/pgp/sign_test.go +++ b/pgp/sign_test.go @@ -20,6 +20,12 @@ type SignerSuite struct { cleartext []byte passwordFile string + + keyringNoPassphrase [2]string + keyringPassphrase [2]string + + noPassphraseKey Key + passphraseKey Key } func (s *SignerSuite) SetUpTest(c *C) { @@ -70,20 +76,23 @@ func (s *SignerSuite) testSignDetached(c *C) { } func (s *SignerSuite) TestSignDetachedNoPassphrase(c *C) { - s.signer.SetKeyRing("keyrings/aptly.pub", "keyrings/aptly.sec") + s.signer.SetKey(string(s.noPassphraseKey)) + s.signer.SetKeyRing(s.keyringNoPassphrase[0], s.keyringNoPassphrase[1]) s.testSignDetached(c) } func (s *SignerSuite) TestSignDetachedPassphrase(c *C) { - s.signer.SetKeyRing("keyrings/aptly_passphrase.pub", "keyrings/aptly_passphrase.sec") + s.signer.SetKey(string(s.passphraseKey)) + s.signer.SetKeyRing(s.keyringPassphrase[0], s.keyringPassphrase[1]) s.signer.SetPassphrase("verysecret", "") s.testSignDetached(c) } func (s *SignerSuite) TestSignDetachedPassphraseFile(c *C) { - s.signer.SetKeyRing("keyrings/aptly_passphrase.pub", "keyrings/aptly_passphrase.sec") + s.signer.SetKey(string(s.passphraseKey)) + s.signer.SetKeyRing(s.keyringPassphrase[0], s.keyringPassphrase[1]) s.signer.SetPassphrase("", s.passwordFile) s.testSignDetached(c) @@ -114,21 +123,24 @@ func (s *SignerSuite) testClearSign(c *C, expectedKey Key) { } func (s *SignerSuite) TestClearSignNoPassphrase(c *C) { - s.signer.SetKeyRing("keyrings/aptly.pub", "keyrings/aptly.sec") + s.signer.SetKey(string(s.noPassphraseKey)) + s.signer.SetKeyRing(s.keyringNoPassphrase[0], s.keyringNoPassphrase[1]) - s.testClearSign(c, "21DBB89C16DB3E6D") + s.testClearSign(c, s.noPassphraseKey) } func (s *SignerSuite) TestClearSignPassphrase(c *C) { - s.signer.SetKeyRing("keyrings/aptly_passphrase.pub", "keyrings/aptly_passphrase.sec") + s.signer.SetKey(string(s.passphraseKey)) + s.signer.SetKeyRing(s.keyringPassphrase[0], s.keyringPassphrase[1]) s.signer.SetPassphrase("verysecret", "") - s.testClearSign(c, "F30E8CB9CDDE2AF8") + s.testClearSign(c, s.passphraseKey) } func (s *SignerSuite) TestClearSignPassphraseFile(c *C) { - s.signer.SetKeyRing("keyrings/aptly_passphrase.pub", "keyrings/aptly_passphrase.sec") + s.signer.SetKey(string(s.passphraseKey)) + s.signer.SetKeyRing(s.keyringPassphrase[0], s.keyringPassphrase[1]) s.signer.SetPassphrase("", s.passwordFile) - s.testClearSign(c, "F30E8CB9CDDE2AF8") + s.testClearSign(c, s.passphraseKey) } diff --git a/system/gpg-gen-key b/system/gpg-gen-key index 6af211b92..6970209ad 100644 --- a/system/gpg-gen-key +++ b/system/gpg-gen-key @@ -10,4 +10,4 @@ Expire-Date: 0 %secring aptly.sec # Do a commit here, so that we can later print "done" :-) %commit -%echo done \ No newline at end of file +%echo done diff --git a/system/lib.py b/system/lib.py index d2cd4f12e..5ca8d4e3c 100644 --- a/system/lib.py +++ b/system/lib.py @@ -141,7 +141,16 @@ def prepare_fixture(self): self.fixtureWebServer)) if self.fixtureGpg: - self.run_cmd(["gpg", "--no-default-keyring", "--trust-model", "always", "--batch", "--keyring", "aptlytest.gpg", "--import"] + + # try to find gpg1 as that's what aptly prefers by default to build trusted keys in DB + # in lowest supported format + gpg = "gpg1" + try: + subprocess.check_output(["gpg1", "--version"]) + except Exception: + gpg = "gpg" + + # TODO: fixme + self.run_cmd([gpg, "--no-default-keyring", "--trust-model", "always", "--batch", "--keyring", "aptlytest.gpg", "--import"] + [os.path.join(os.path.dirname(inspect.getsourcefile(BaseTest)), "files", key) for key in self.fixtureGpgKeys]) if hasattr(self, "fixtureCmds"): diff --git a/system/t03_help/MainHelpTest_gold b/system/t03_help/MainHelpTest_gold index 6fcd5eb7f..004f140e1 100644 --- a/system/t03_help/MainHelpTest_gold +++ b/system/t03_help/MainHelpTest_gold @@ -19,5 +19,5 @@ Options: -dep-follow-source: when processing dependencies, follow from binary to Source packages -dep-follow-suggests: when processing dependencies, follow Suggests -dep-verbose-resolve: when processing dependencies, print detailed logs - -gpg-provider="": PGP implementation ("gpg" for external gpg or "internal" for Go internal implementation) + -gpg-provider="": PGP implementation ("gpg", "gpg1", "gpg2" for external gpg or "internal" for Go internal implementation) diff --git a/system/t03_help/MainTest_gold b/system/t03_help/MainTest_gold index e7efbc938..5452f3f18 100644 --- a/system/t03_help/MainTest_gold +++ b/system/t03_help/MainTest_gold @@ -27,5 +27,5 @@ Options: -dep-follow-source: when processing dependencies, follow from binary to Source packages -dep-follow-suggests: when processing dependencies, follow Suggests -dep-verbose-resolve: when processing dependencies, print detailed logs - -gpg-provider="": PGP implementation ("gpg" for external gpg or "internal" for Go internal implementation) + -gpg-provider="": PGP implementation ("gpg", "gpg1", "gpg2" for external gpg or "internal" for Go internal implementation) ERROR: unable to parse command diff --git a/system/t03_help/MirrorCreateHelpTest_gold b/system/t03_help/MirrorCreateHelpTest_gold index 8830ee1e2..e08d409dd 100644 --- a/system/t03_help/MirrorCreateHelpTest_gold +++ b/system/t03_help/MirrorCreateHelpTest_gold @@ -25,7 +25,7 @@ Options: -filter-with-deps: when filtering, include dependencies of matching packages as well -force-architectures: (only with architecture list) skip check that requested architectures are listed in Release file -force-components: (only with component list) skip check that requested components are listed in Release file - -gpg-provider="": PGP implementation ("gpg" for external gpg or "internal" for Go internal implementation) + -gpg-provider="": PGP implementation ("gpg", "gpg1", "gpg2" for external gpg or "internal" for Go internal implementation) -ignore-signatures: disable verification of Release file signatures -keyring=: gpg keyring to use when verifying Release file (could be specified multiple times) -with-sources: download source packages in addition to binary packages diff --git a/system/t03_help/MirrorCreateTest_gold b/system/t03_help/MirrorCreateTest_gold index ced808083..5fe099b3e 100644 --- a/system/t03_help/MirrorCreateTest_gold +++ b/system/t03_help/MirrorCreateTest_gold @@ -16,7 +16,7 @@ Options: -filter-with-deps: when filtering, include dependencies of matching packages as well -force-architectures: (only with architecture list) skip check that requested architectures are listed in Release file -force-components: (only with component list) skip check that requested components are listed in Release file - -gpg-provider="": PGP implementation ("gpg" for external gpg or "internal" for Go internal implementation) + -gpg-provider="": PGP implementation ("gpg", "gpg1", "gpg2" for external gpg or "internal" for Go internal implementation) -ignore-signatures: disable verification of Release file signatures -keyring=: gpg keyring to use when verifying Release file (could be specified multiple times) -with-sources: download source packages in addition to binary packages diff --git a/system/t03_help/MirrorHelpTest_gold b/system/t03_help/MirrorHelpTest_gold index 4faee9a0b..08f6f55ad 100644 --- a/system/t03_help/MirrorHelpTest_gold +++ b/system/t03_help/MirrorHelpTest_gold @@ -23,4 +23,4 @@ Options: -dep-follow-source: when processing dependencies, follow from binary to Source packages -dep-follow-suggests: when processing dependencies, follow Suggests -dep-verbose-resolve: when processing dependencies, print detailed logs - -gpg-provider="": PGP implementation ("gpg" for external gpg or "internal" for Go internal implementation) + -gpg-provider="": PGP implementation ("gpg", "gpg1", "gpg2" for external gpg or "internal" for Go internal implementation) diff --git a/system/t03_help/MirrorTest_gold b/system/t03_help/MirrorTest_gold index 6be6e8340..e48251040 100644 --- a/system/t03_help/MirrorTest_gold +++ b/system/t03_help/MirrorTest_gold @@ -23,5 +23,5 @@ Options: -dep-follow-source: when processing dependencies, follow from binary to Source packages -dep-follow-suggests: when processing dependencies, follow Suggests -dep-verbose-resolve: when processing dependencies, print detailed logs - -gpg-provider="": PGP implementation ("gpg" for external gpg or "internal" for Go internal implementation) + -gpg-provider="": PGP implementation ("gpg", "gpg1", "gpg2" for external gpg or "internal" for Go internal implementation) ERROR: unable to parse command diff --git a/system/t03_help/WrongFlagTest_gold b/system/t03_help/WrongFlagTest_gold index 8824d9ae2..4d2dbf73f 100644 --- a/system/t03_help/WrongFlagTest_gold +++ b/system/t03_help/WrongFlagTest_gold @@ -17,7 +17,7 @@ Options: -filter-with-deps: when filtering, include dependencies of matching packages as well -force-architectures: (only with architecture list) skip check that requested architectures are listed in Release file -force-components: (only with component list) skip check that requested components are listed in Release file - -gpg-provider="": PGP implementation ("gpg" for external gpg or "internal" for Go internal implementation) + -gpg-provider="": PGP implementation ("gpg", "gpg1", "gpg2" for external gpg or "internal" for Go internal implementation) -ignore-signatures: disable verification of Release file signatures -keyring=: gpg keyring to use when verifying Release file (could be specified multiple times) -with-sources: download source packages in addition to binary packages