mirror of
https://github.com/containers/skopeo.git
synced 2025-09-17 07:19:37 +00:00
Add --sign-by-sq-fingerprint and an integration test
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
This commit is contained in:
@@ -26,6 +26,7 @@ import (
|
|||||||
"go.podman.io/image/v5/pkg/cli/sigstore"
|
"go.podman.io/image/v5/pkg/cli/sigstore"
|
||||||
"go.podman.io/image/v5/pkg/compression"
|
"go.podman.io/image/v5/pkg/compression"
|
||||||
"go.podman.io/image/v5/signature/signer"
|
"go.podman.io/image/v5/signature/signer"
|
||||||
|
"go.podman.io/image/v5/signature/simplesequoia"
|
||||||
"go.podman.io/image/v5/storage"
|
"go.podman.io/image/v5/storage"
|
||||||
"go.podman.io/image/v5/transports/alltransports"
|
"go.podman.io/image/v5/transports/alltransports"
|
||||||
"go.podman.io/image/v5/types"
|
"go.podman.io/image/v5/types"
|
||||||
@@ -329,6 +330,7 @@ func (opts *imageDestOptions) warnAboutIneffectiveOptions(destTransport types.Im
|
|||||||
type sharedCopyOptions struct {
|
type sharedCopyOptions struct {
|
||||||
removeSignatures bool // Do not copy signatures from the source image
|
removeSignatures bool // Do not copy signatures from the source image
|
||||||
signByFingerprint string // Sign the image using a GPG key with the specified fingerprint
|
signByFingerprint string // Sign the image using a GPG key with the specified fingerprint
|
||||||
|
signBySequoiaFingerprint string // Sign the image using a Sequoia-PGP key with the specified fingerprint
|
||||||
signBySigstoreParamFile string // Sign the image using a sigstore signature per configuration in a param file
|
signBySigstoreParamFile string // Sign the image using a sigstore signature per configuration in a param file
|
||||||
signBySigstorePrivateKey string // Sign the image using a sigstore private key
|
signBySigstorePrivateKey string // Sign the image using a sigstore private key
|
||||||
signPassphraseFile string // Path pointing to a passphrase file when signing
|
signPassphraseFile string // Path pointing to a passphrase file when signing
|
||||||
@@ -342,6 +344,7 @@ func sharedCopyFlags() (pflag.FlagSet, *sharedCopyOptions) {
|
|||||||
fs := pflag.FlagSet{}
|
fs := pflag.FlagSet{}
|
||||||
fs.BoolVar(&opts.removeSignatures, "remove-signatures", false, "Do not copy signatures from source")
|
fs.BoolVar(&opts.removeSignatures, "remove-signatures", false, "Do not copy signatures from source")
|
||||||
fs.StringVar(&opts.signByFingerprint, "sign-by", "", "Sign the image using a GPG key with the specified `FINGERPRINT`")
|
fs.StringVar(&opts.signByFingerprint, "sign-by", "", "Sign the image using a GPG key with the specified `FINGERPRINT`")
|
||||||
|
fs.StringVar(&opts.signBySequoiaFingerprint, "sign-by-sq-fingerprint", "", "Sign the image using a Sequoia-PGP key with the specified `FINGERPRINT`")
|
||||||
fs.StringVar(&opts.signBySigstoreParamFile, "sign-by-sigstore", "", "Sign the image using a sigstore parameter file at `PATH`")
|
fs.StringVar(&opts.signBySigstoreParamFile, "sign-by-sigstore", "", "Sign the image using a sigstore parameter file at `PATH`")
|
||||||
fs.StringVar(&opts.signBySigstorePrivateKey, "sign-by-sigstore-private-key", "", "Sign the image using a sigstore private key at `PATH`")
|
fs.StringVar(&opts.signBySigstorePrivateKey, "sign-by-sigstore-private-key", "", "Sign the image using a sigstore private key at `PATH`")
|
||||||
fs.StringVar(&opts.signPassphraseFile, "sign-passphrase-file", "", "Read a passphrase for signing an image from `PATH`")
|
fs.StringVar(&opts.signPassphraseFile, "sign-passphrase-file", "", "Read a passphrase for signing an image from `PATH`")
|
||||||
@@ -365,8 +368,20 @@ func (opts *sharedCopyOptions) copyOptions(stdout io.Writer) (*copy.Options, fun
|
|||||||
// c/image/copy.Image does allow creating both simple signing and sigstore signatures simultaneously,
|
// c/image/copy.Image does allow creating both simple signing and sigstore signatures simultaneously,
|
||||||
// with independent passphrases, but that would make the CLI probably too confusing.
|
// with independent passphrases, but that would make the CLI probably too confusing.
|
||||||
// For now, use the passphrase with either, but only one of them.
|
// For now, use the passphrase with either, but only one of them.
|
||||||
if opts.signPassphraseFile != "" && opts.signByFingerprint != "" && opts.signBySigstorePrivateKey != "" {
|
if opts.signPassphraseFile != "" {
|
||||||
return nil, nil, fmt.Errorf("Only one of --sign-by and sign-by-sigstore-private-key can be used with sign-passphrase-file")
|
count := 0
|
||||||
|
if opts.signByFingerprint != "" {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
if opts.signBySequoiaFingerprint != "" {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
if opts.signBySigstorePrivateKey != "" {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
if count > 1 {
|
||||||
|
return nil, nil, fmt.Errorf("Only one of --sign-by, --sign-by-sq-fingerprint and --sign-by-sigstore-private-key can be used with --sign-passphrase-file")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var passphrase string
|
var passphrase string
|
||||||
if opts.signPassphraseFile != "" {
|
if opts.signPassphraseFile != "" {
|
||||||
@@ -382,6 +397,7 @@ func (opts *sharedCopyOptions) copyOptions(stdout io.Writer) (*copy.Options, fun
|
|||||||
}
|
}
|
||||||
passphrase = p
|
passphrase = p
|
||||||
} // opts.signByFingerprint triggers a GPG-agent passphrase prompt, possibly using a more secure channel, so we usually shouldn’t prompt ourselves if no passphrase was explicitly provided.
|
} // opts.signByFingerprint triggers a GPG-agent passphrase prompt, possibly using a more secure channel, so we usually shouldn’t prompt ourselves if no passphrase was explicitly provided.
|
||||||
|
// With opts.signBySequoiaFingerprint, we don’t prompt for a passphrase (for now??): We don’t know whether the key requires a passphrase.
|
||||||
var passphraseBytes []byte
|
var passphraseBytes []byte
|
||||||
if passphrase != "" {
|
if passphrase != "" {
|
||||||
passphraseBytes = []byte(passphrase)
|
passphraseBytes = []byte(passphrase)
|
||||||
@@ -412,6 +428,19 @@ func (opts *sharedCopyOptions) copyOptions(stdout io.Writer) (*copy.Options, fun
|
|||||||
}
|
}
|
||||||
signers = append(signers, signer)
|
signers = append(signers, signer)
|
||||||
}
|
}
|
||||||
|
if opts.signBySequoiaFingerprint != "" {
|
||||||
|
sqOpts := []simplesequoia.Option{
|
||||||
|
simplesequoia.WithKeyFingerprint(opts.signBySequoiaFingerprint),
|
||||||
|
}
|
||||||
|
if passphrase != "" {
|
||||||
|
sqOpts = append(sqOpts, simplesequoia.WithPassphrase(passphrase))
|
||||||
|
}
|
||||||
|
signer, err := simplesequoia.NewSigner(sqOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("Error using --sign-by-sq-fingerprint: %w", err)
|
||||||
|
}
|
||||||
|
signers = append(signers, signer)
|
||||||
|
}
|
||||||
|
|
||||||
succeeded = true
|
succeeded = true
|
||||||
return ©.Options{
|
return ©.Options{
|
||||||
|
5
cmd/skopeo/utils_nosequoia_test.go
Normal file
5
cmd/skopeo/utils_nosequoia_test.go
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
//go:build !containers_image_sequoia
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
const buildWithSequoia = false
|
5
cmd/skopeo/utils_sequoia_test.go
Normal file
5
cmd/skopeo/utils_sequoia_test.go
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
//go:build containers_image_sequoia
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
const buildWithSequoia = true
|
@@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
|
"slices"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
|
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
@@ -378,6 +379,7 @@ func TestSharedCopyOptionsCopyOptions(t *testing.T) {
|
|||||||
// Set most flags to non-default values
|
// Set most flags to non-default values
|
||||||
// This should also test --sign-by-sigstore and --sign-by-sigstore-private-key; we would have
|
// This should also test --sign-by-sigstore and --sign-by-sigstore-private-key; we would have
|
||||||
// to create test keys for that.
|
// to create test keys for that.
|
||||||
|
// This does not test --sign-by-sq-fingerprint, because that needs to be conditional based on buildWithSequoia.
|
||||||
opts = fakeSharedCopyOptions(t, []string{
|
opts = fakeSharedCopyOptions(t, []string{
|
||||||
"--remove-signatures",
|
"--remove-signatures",
|
||||||
"--sign-by", "gpgFingerprint",
|
"--sign-by", "gpgFingerprint",
|
||||||
@@ -395,12 +397,13 @@ func TestSharedCopyOptionsCopyOptions(t *testing.T) {
|
|||||||
ForceManifestMIMEType: imgspecv1.MediaTypeImageManifest,
|
ForceManifestMIMEType: imgspecv1.MediaTypeImageManifest,
|
||||||
}, res)
|
}, res)
|
||||||
|
|
||||||
// --sign-passphrase-file + --sign-by work
|
// --sign-passphrase-file:
|
||||||
passphraseFile, err := os.CreateTemp("", "passphrase") // Eventually we could refer to a passphrase fixture instead
|
passphraseFile, err := os.CreateTemp("", "passphrase") // Eventually we could refer to a passphrase fixture instead
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer os.Remove(passphraseFile.Name())
|
defer os.Remove(passphraseFile.Name())
|
||||||
_, err = passphraseFile.WriteString("test-passphrase")
|
_, err = passphraseFile.WriteString("test-passphrase")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
// --sign-passphrase-file + --sign-by work
|
||||||
opts = fakeSharedCopyOptions(t, []string{
|
opts = fakeSharedCopyOptions(t, []string{
|
||||||
"--sign-by", "gpgFingerprint",
|
"--sign-by", "gpgFingerprint",
|
||||||
"--sign-passphrase-file", passphraseFile.Name(),
|
"--sign-passphrase-file", passphraseFile.Name(),
|
||||||
@@ -414,14 +417,42 @@ func TestSharedCopyOptionsCopyOptions(t *testing.T) {
|
|||||||
SignSigstorePrivateKeyPassphrase: []byte("test-passphrase"),
|
SignSigstorePrivateKeyPassphrase: []byte("test-passphrase"),
|
||||||
ReportWriter: &someStdout,
|
ReportWriter: &someStdout,
|
||||||
}, res)
|
}, res)
|
||||||
// --sign-passphrase-file + --sign-by-sigstore-private-key should be tested here.
|
// If Sequoia is supported, --sign-passphrase-file + --sign-by-sq-fingerprint work
|
||||||
|
if buildWithSequoia {
|
||||||
|
opts = fakeSharedCopyOptions(t, []string{
|
||||||
|
"--sign-by-sq-fingerprint", "sqFingerprint",
|
||||||
|
"--sign-passphrase-file", passphraseFile.Name(),
|
||||||
|
})
|
||||||
|
res, cleanup, err = opts.copyOptions(&someStdout)
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer cleanup()
|
||||||
|
assert.NotNil(t, res.Signers) // Contains a Sequoia signer
|
||||||
|
res.Signers = nil // To allow the comparison below
|
||||||
|
assert.Equal(t, ©.Options{
|
||||||
|
SignPassphrase: "test-passphrase",
|
||||||
|
SignSigstorePrivateKeyPassphrase: []byte("test-passphrase"),
|
||||||
|
ReportWriter: &someStdout,
|
||||||
|
}, res)
|
||||||
|
}
|
||||||
|
|
||||||
// Invalid --format
|
// Invalid --format
|
||||||
opts = fakeSharedCopyOptions(t, []string{"--format", "invalid"})
|
opts = fakeSharedCopyOptions(t, []string{"--format", "invalid"})
|
||||||
_, _, err = opts.copyOptions(&someStdout)
|
_, _, err = opts.copyOptions(&someStdout)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
// More --sign-passphrase-file, --sign-by-sigstore-private-key, --sign-by-sigstore failure cases should be tested here.
|
// More --sign-by-sigstore-private-key, --sign-by-sigstore failure cases should be tested here.
|
||||||
|
// --sign-passphrase-file + more than one key option
|
||||||
|
for _, opts := range [][]string{
|
||||||
|
{"--sign-by", "gpgFingerprint", "--sign-by-sq-fingerprint", "sqFingerprint"},
|
||||||
|
{"--sign-by", "gpgFingerprint", "--sign-by-sigstore-private-key", "sigstorePrivateKey"},
|
||||||
|
{"--sign-by-sq-fingerprint", "sqFingerprint", "--sign-by-sigstore-private-key", "sigstorePrivateKey"},
|
||||||
|
} {
|
||||||
|
opts := fakeSharedCopyOptions(t, slices.Concat(opts, []string{
|
||||||
|
"--sign-passphrase-file", passphraseFile.Name(),
|
||||||
|
}))
|
||||||
|
_, _, err = opts.copyOptions(&someStdout)
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
// --sign-passphrase-file not found
|
// --sign-passphrase-file not found
|
||||||
opts = fakeSharedCopyOptions(t, []string{
|
opts = fakeSharedCopyOptions(t, []string{
|
||||||
|
@@ -107,9 +107,14 @@ See containers-sigstore-signing-params.yaml(5) for details about the file format
|
|||||||
|
|
||||||
Add a sigstore signature using a private key at _path_ for an image name corresponding to _destination-image_
|
Add a sigstore signature using a private key at _path_ for an image name corresponding to _destination-image_
|
||||||
|
|
||||||
|
**--sign-by-sq-fingerprint** _fingerprint_
|
||||||
|
|
||||||
|
Add a “simple signing” signature using a Sequoia-PGP key with the specified _fingerprint_.
|
||||||
|
|
||||||
**--sign-passphrase-file** _path_
|
**--sign-passphrase-file** _path_
|
||||||
|
|
||||||
The passphare to use when signing with `--sign-by` or `--sign-by-sigstore-private-key`. Only the first line will be read. A passphrase stored in a file is of questionable security if other users can read this file. Do not use this option if at all avoidable.
|
The passphrase to use when signing with `--sign-by`, `--sign-by-sigstore-private-key` or `--sign-by-sq-fingerprint`.
|
||||||
|
Only the first line will be read. A passphrase stored in a file is of questionable security if other users can read this file. Do not use this option if at all avoidable.
|
||||||
|
|
||||||
**--sign-identity** _reference_
|
**--sign-identity** _reference_
|
||||||
|
|
||||||
|
@@ -103,9 +103,14 @@ See containers-sigstore-signing-params.yaml(5) for details about the file format
|
|||||||
|
|
||||||
Add a sigstore signature using a private key at _path_ for an image name corresponding to _destination-image_
|
Add a sigstore signature using a private key at _path_ for an image name corresponding to _destination-image_
|
||||||
|
|
||||||
|
**--sign-by-sq-fingerprint** _fingerprint_
|
||||||
|
|
||||||
|
Add a “simple signing” signature using a Sequoia-PGP key with the specified _fingerprint_.
|
||||||
|
|
||||||
**--sign-passphrase-file** _path_
|
**--sign-passphrase-file** _path_
|
||||||
|
|
||||||
The passphare to use when signing with `--sign-by` or `--sign-by-sigstore-private-key`. Only the first line will be read. A passphrase stored in a file is of questionable security if other users can read this file. Do not use this option if at all avoidable.
|
The passphrase to use when signing with `--sign-by`, `--sign-by-sigstore-private-key` or `--sign-by-sq-fingerprint`.
|
||||||
|
Only the first line will be read. A passphrase stored in a file is of questionable security if other users can read this file. Do not use this option if at all avoidable.
|
||||||
|
|
||||||
**--src-creds** _username[:password]_ for accessing the source registry.
|
**--src-creds** _username[:password]_ for accessing the source registry.
|
||||||
|
|
||||||
|
@@ -24,6 +24,7 @@ import (
|
|||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
"go.podman.io/image/v5/manifest"
|
"go.podman.io/image/v5/manifest"
|
||||||
"go.podman.io/image/v5/signature"
|
"go.podman.io/image/v5/signature"
|
||||||
|
"go.podman.io/image/v5/signature/simplesequoia"
|
||||||
"go.podman.io/image/v5/types"
|
"go.podman.io/image/v5/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -106,7 +107,9 @@ func (s *copySuite) TearDownSuite() {
|
|||||||
// and returns a path to a policy, which will be automatically removed when the test completes.
|
// and returns a path to a policy, which will be automatically removed when the test completes.
|
||||||
func (s *copySuite) policyFixture(extraSubstitutions map[string]string) string {
|
func (s *copySuite) policyFixture(extraSubstitutions map[string]string) string {
|
||||||
t := s.T()
|
t := s.T()
|
||||||
edits := map[string]string{"@keydir@": s.gpgHome}
|
fixtureDir, err := filepath.Abs("fixtures")
|
||||||
|
require.NoError(t, err)
|
||||||
|
edits := map[string]string{"@keydir@": s.gpgHome, "@fixturedir@": fixtureDir}
|
||||||
maps.Copy(edits, extraSubstitutions)
|
maps.Copy(edits, extraSubstitutions)
|
||||||
policyPath := fileFromFixture(t, "fixtures/policy.json", edits)
|
policyPath := fileFromFixture(t, "fixtures/policy.json", edits)
|
||||||
return policyPath
|
return policyPath
|
||||||
@@ -849,6 +852,39 @@ func (s *copySuite) TestCopyDirSignatures() {
|
|||||||
"--policy", policy, "copy", topDirDest+"/restricted/badidentity", topDirDest+"/dest")
|
"--policy", policy, "copy", topDirDest+"/restricted/badidentity", topDirDest+"/dest")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *copySuite) TestCopySequoiaSignatures() {
|
||||||
|
t := s.T()
|
||||||
|
signer, err := simplesequoia.NewSigner(simplesequoia.WithSequoiaHome(testSequoiaHome), simplesequoia.WithKeyFingerprint(testSequoiaKeyFingerprint))
|
||||||
|
if err != nil {
|
||||||
|
t.Skipf("Sequoia not supported: %v", err)
|
||||||
|
}
|
||||||
|
signer.Close()
|
||||||
|
|
||||||
|
const ourRegistry = "docker://" + v2DockerRegistryURL + "/"
|
||||||
|
|
||||||
|
dirDest := "dir:" + t.TempDir()
|
||||||
|
|
||||||
|
policy := s.policyFixture(nil)
|
||||||
|
registriesDir := t.TempDir()
|
||||||
|
registriesFile := fileFromFixture(t, "fixtures/registries.yaml",
|
||||||
|
map[string]string{"@lookaside@": t.TempDir(), "@split-staging@": "/var/empty", "@split-read@": "file://var/empty"})
|
||||||
|
err = os.Symlink(registriesFile, filepath.Join(registriesDir, "registries.yaml"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Sign the images
|
||||||
|
absSequoiaHome, err := filepath.Abs(testSequoiaHome)
|
||||||
|
require.NoError(t, err)
|
||||||
|
t.Setenv("SEQUOIA_HOME", absSequoiaHome)
|
||||||
|
assertSkopeoSucceeds(t, "", "copy", "--retry-times", "3", "--dest-tls-verify=false", "--sign-by-sq-fingerprint", testSequoiaKeyFingerprint,
|
||||||
|
testFQIN+":1.26", ourRegistry+"sequoia-no-passphrase")
|
||||||
|
assertSkopeoSucceeds(t, "", "copy", "--retry-times", "3", "--dest-tls-verify=false", "--sign-by-sq-fingerprint", testSequoiaKeyFingerprintWithPassphrase,
|
||||||
|
"--sign-passphrase-file", filepath.Join(absSequoiaHome, "with-passphrase.passphrase"),
|
||||||
|
testFQIN+":1.26.1", ourRegistry+"sequoia-with-passphrase")
|
||||||
|
// Verify that we can pull them
|
||||||
|
assertSkopeoSucceeds(t, "", "--policy", policy, "copy", "--src-tls-verify=false", ourRegistry+"sequoia-no-passphrase", dirDest)
|
||||||
|
assertSkopeoSucceeds(t, "", "--policy", policy, "copy", "--src-tls-verify=false", ourRegistry+"sequoia-with-passphrase", dirDest)
|
||||||
|
}
|
||||||
|
|
||||||
// Compression during copy
|
// Compression during copy
|
||||||
func (s *copySuite) TestCopyCompression() {
|
func (s *copySuite) TestCopyCompression() {
|
||||||
t := s.T()
|
t := s.T()
|
||||||
|
1
integration/fixtures/.gitignore
vendored
Normal file
1
integration/fixtures/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/data/pgp.cert.d/_sequoia*
|
0
integration/fixtures/data/keystore/keystore.cookie
Normal file
0
integration/fixtures/data/keystore/keystore.cookie
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
integration/fixtures/data/pgp.cert.d/trust-root
Normal file
BIN
integration/fixtures/data/pgp.cert.d/trust-root
Normal file
Binary file not shown.
0
integration/fixtures/data/pgp.cert.d/writelock
Normal file
0
integration/fixtures/data/pgp.cert.d/writelock
Normal file
38
integration/fixtures/no-passphrase.pub
Normal file
38
integration/fixtures/no-passphrase.pub
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
||||||
|
xjMEaGwFVhYJKwYBBAHaRw8BAQdAZzfnqEAgvE3RoCtPWEOc3Xp8oMURR0qjq+Ru
|
||||||
|
PHJrc6TCwAsEHxYKAH0FgmhsBVYDCwkHCRD2+Qi2+kiiKUcUAAAAAAAeACBzYWx0
|
||||||
|
QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmcEjRQtILaFnIhczxeUkcfW0KMHEZ30
|
||||||
|
wTdJ1v1iHB7NKQMVCggCmwECHgkWIQRQ3eiY305IdVyMK3r2+Qi2+kiiKQAA86gA
|
||||||
|
/1ZkXWPHUxh3nQu/EL72ZeP9k/SLWkEuNKs6dJrmRud9AQCHbWwSUwKyt12EFVt/
|
||||||
|
QvMFSQ95brUxsWLHgFMPpNfWAc0aU2tvcGVvIFNlcXVvaWEgdGVzdGluZyBrZXnC
|
||||||
|
wA4EExYKAIAFgmhsBVYDCwkHCRD2+Qi2+kiiKUcUAAAAAAAeACBzYWx0QG5vdGF0
|
||||||
|
aW9ucy5zZXF1b2lhLXBncC5vcmctF7xuY06GUyedOGjd2iNKwab85gV64zEAGKgi
|
||||||
|
ExHRxgMVCggCmQECmwECHgkWIQRQ3eiY305IdVyMK3r2+Qi2+kiiKQAA3SEBAMe1
|
||||||
|
y6rWaPjDpkeiDthLV1Umr6NsXVBv/IJTcP9RM4quAQCwmlsdQMddCsc+K3Y5KH88
|
||||||
|
saIG0/MRZaPJdsd8vRGUCs4zBGhsBVYWCSsGAQQB2kcPAQEHQLN8yt/21QDMzcB4
|
||||||
|
2bzFRg1LpkFZWECjkb2ty7Iju/aOwsC/BBgWCgExBYJobAVWCRD2+Qi2+kiiKUcU
|
||||||
|
AAAAAAAeACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmce9QEurrtI24ys
|
||||||
|
vXssO/40rI5rlsNokEEFr7CVwVgWvAKbAr6gBBkWCgBvBYJobAVWCRB63Ra9Qdgp
|
||||||
|
tkcUAAAAAAAeACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmcBWCJsdUfj
|
||||||
|
oYpld4qcYBqjxsyScwpID2vkNlYMLmS+IhYhBKyZqvZ6WI3zgaapXHrdFr1B2Cm2
|
||||||
|
AAAEZwEA/UhpNN1XElYx6Xq+JMKlXywoIgButkQy1+H2EcRBeHsBAM7lq8BXvRKz
|
||||||
|
bDjRlgxiIAYl77p7ihVQ5NYcuZcAlH0CFiEEUN3omN9OSHVcjCt69vkItvpIoikA
|
||||||
|
AJcwAP9D4spfb28k16w2cemrWAtAE1WUgV8V+OEpE7+gpV+17gEA+0Kzf7jBHgd3
|
||||||
|
pBAWwttuRd8OHlZZzKs3f26z28I6mgLOMwRobAVWFgkrBgEEAdpHDwEBB0DPyS14
|
||||||
|
jQk1mSWNmuYR4P9M5zOfU2mkhwaqx1l3OWTZD8LAvwQYFgoBMQWCaGwFVgkQ9vkI
|
||||||
|
tvpIoilHFAAAAAAAHgAgc2FsdEBub3RhdGlvbnMuc2VxdW9pYS1wZ3Aub3Jn+wfK
|
||||||
|
FmPmtrsi0sY5zIq9KFmbrQyhXz/VZIw6K8D1zdECmyC+oAQZFgoAbwWCaGwFVgkQ
|
||||||
|
bwujLUxU69BHFAAAAAAAHgAgc2FsdEBub3RhdGlvbnMuc2VxdW9pYS1wZ3Aub3Jn
|
||||||
|
xF3KXB4+dN9suOhCD2XkYlAWUJ4GVBVV2wAmdQAueyEWIQTv1sMw2eUTIMQmb7Zv
|
||||||
|
C6MtTFTr0AAA/LYA/iBkRh6dGbp76VzuuHVNUNgTqvXgz9FjizZGJKnVZctXAPwL
|
||||||
|
TlHxcH6XX96AuiCy9QAMUpm8ZvMu8TAgjgOrlFPKCBYhBFDd6JjfTkh1XIwrevb5
|
||||||
|
CLb6SKIpAAA0rQD9HWbBeSoshjH6/k5ntZjOfIAha4/TLlBrMq2w+t4LWD0A/2q5
|
||||||
|
DEbYh6PwMidDxXteyHWf4Qnr0vH8vip9d+WHbDYEzjgEaGwFVhIKKwYBBAGXVQEF
|
||||||
|
AQEHQLxXHw9STOAhb2PLEjrl3uQDwpaXIdigg67vId0jSstVAwEIB8LAAAQYFgoA
|
||||||
|
cgWCaGwFVgkQ9vkItvpIoilHFAAAAAAAHgAgc2FsdEBub3RhdGlvbnMuc2VxdW9p
|
||||||
|
YS1wZ3Aub3Jn8bvuQCv3uEYJtK6h5y5e4AY9lJtVXx3brexR5bmFCwcCmwwWIQRQ
|
||||||
|
3eiY305IdVyMK3r2+Qi2+kiiKQAAEzkA/Az97rdlp3hf97S6a5AxU8pTry4gKI63
|
||||||
|
lwKtBAT+uF/pAP9lAziQRlNEa1sX6qCXrQqeA/aQ0nj9gRJ1Wvi1PMxWBA==
|
||||||
|
=7jmE
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
@@ -13,6 +13,20 @@
|
|||||||
"keyPath": "@keydir@/personal-pubkey.gpg"
|
"keyPath": "@keydir@/personal-pubkey.gpg"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"localhost:5555/sequoia-no-passphrase": [
|
||||||
|
{
|
||||||
|
"type": "signedBy",
|
||||||
|
"keyType": "GPGKeys",
|
||||||
|
"keyPath": "@fixturedir@/no-passphrase.pub"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"localhost:5555/sequoia-with-passphrase": [
|
||||||
|
{
|
||||||
|
"type": "signedBy",
|
||||||
|
"keyType": "GPGKeys",
|
||||||
|
"keyPath": "@fixturedir@/with-passphrase.pub"
|
||||||
|
}
|
||||||
|
],
|
||||||
"localhost:5000/myns/extension": [
|
"localhost:5000/myns/extension": [
|
||||||
{
|
{
|
||||||
"type": "signedBy",
|
"type": "signedBy",
|
||||||
|
1
integration/fixtures/with-passphrase.passphrase
Normal file
1
integration/fixtures/with-passphrase.passphrase
Normal file
@@ -0,0 +1 @@
|
|||||||
|
WithPassphrase123
|
39
integration/fixtures/with-passphrase.pub
Normal file
39
integration/fixtures/with-passphrase.pub
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
||||||
|
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
|
||||||
|
Dii+5qsdk0HFcgA=
|
||||||
|
=YS7U
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
@@ -3,4 +3,12 @@ package main
|
|||||||
const (
|
const (
|
||||||
// TestImageManifestDigest is the Docker manifest digest of "fixtures/image.manifest.json"
|
// TestImageManifestDigest is the Docker manifest digest of "fixtures/image.manifest.json"
|
||||||
TestImageManifestDigest = "sha256:20bf21ed457b390829cdbeec8795a7bea1626991fda603e0d01b4e7f60427e55"
|
TestImageManifestDigest = "sha256:20bf21ed457b390829cdbeec8795a7bea1626991fda603e0d01b4e7f60427e55"
|
||||||
|
|
||||||
|
testSequoiaHome = "./fixtures"
|
||||||
|
// testSequoiaKeyFingerprint is a fingerprint of a test key in testSequoiaHome, generated using
|
||||||
|
// > sq --home $(pwd)/signature/simplesequoia/testdata key generate --name 'Skopeo Sequoia testing key' --own-key --expiration=never
|
||||||
|
testSequoiaKeyFingerprint = "50DDE898DF4E48755C8C2B7AF6F908B6FA48A229"
|
||||||
|
// testSequoiaKeyFingerprintWithPassphrase is a fingerprint of a test key in testSequoiaHome, generated using
|
||||||
|
// > sq --home $(pwd)/signature/simplesequoia/testdata key generate --name 'Skopeo Sequoia testing key with passphrase' --own-key --expiration=never
|
||||||
|
testSequoiaKeyFingerprintWithPassphrase = "1F5825285B785E1DB13BF36D2D11A19ABA41C6AE"
|
||||||
)
|
)
|
||||||
|
52
vendor/go.podman.io/image/v5/signature/simplesequoia/mechanism.go
generated
vendored
Normal file
52
vendor/go.podman.io/image/v5/signature/simplesequoia/mechanism.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
//go:build containers_image_sequoia
|
||||||
|
|
||||||
|
package simplesequoia
|
||||||
|
|
||||||
|
// This implements a signature.signingMechanismWithPassphrase that only supports signing.
|
||||||
|
//
|
||||||
|
// FIXME: Consider restructuring the simple signing signature creation code path
|
||||||
|
// not to require this indirection and all those unimplemented methods.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go.podman.io/image/v5/signature/internal/sequoia"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A GPG/OpenPGP signing mechanism, implemented using Sequoia.
|
||||||
|
type sequoiaSigningOnlyMechanism struct {
|
||||||
|
inner *sequoia.SigningMechanism
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *sequoiaSigningOnlyMechanism) Close() error {
|
||||||
|
panic("Should never be called")
|
||||||
|
}
|
||||||
|
|
||||||
|
// SupportsSigning returns nil if the mechanism supports signing, or a SigningNotSupportedError.
|
||||||
|
func (m *sequoiaSigningOnlyMechanism) SupportsSigning() error {
|
||||||
|
panic("Should never be called")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign creates a (non-detached) signature of input using keyIdentity and passphrase.
|
||||||
|
// Fails with a SigningNotSupportedError if the mechanism does not support signing.
|
||||||
|
func (m *sequoiaSigningOnlyMechanism) SignWithPassphrase(input []byte, keyIdentity string, passphrase string) ([]byte, error) {
|
||||||
|
return m.inner.SignWithPassphrase(input, keyIdentity, passphrase)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign creates a (non-detached) signature of input using keyIdentity.
|
||||||
|
// Fails with a SigningNotSupportedError if the mechanism does not support signing.
|
||||||
|
func (m *sequoiaSigningOnlyMechanism) Sign(input []byte, keyIdentity string) ([]byte, error) {
|
||||||
|
panic("Should never be called")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify parses unverifiedSignature and returns the content and the signer's identity
|
||||||
|
func (m *sequoiaSigningOnlyMechanism) Verify(unverifiedSignature []byte) (contents []byte, keyIdentity string, err error) {
|
||||||
|
panic("Should never be called")
|
||||||
|
}
|
||||||
|
|
||||||
|
// UntrustedSignatureContents returns UNTRUSTED contents of the signature WITHOUT ANY VERIFICATION,
|
||||||
|
// along with a short identifier of the key used for signing.
|
||||||
|
// WARNING: The short key identifier (which corresponds to "Key ID" for OpenPGP keys)
|
||||||
|
// is NOT the same as a "key identity" used in other calls to this interface, and
|
||||||
|
// the values may have no recognizable relationship if the public key is not available.
|
||||||
|
func (m *sequoiaSigningOnlyMechanism) UntrustedSignatureContents(untrustedSignature []byte) (untrustedContents []byte, shortKeyIdentifier string, err error) {
|
||||||
|
panic("Should never be called")
|
||||||
|
}
|
37
vendor/go.podman.io/image/v5/signature/simplesequoia/options.go
generated
vendored
Normal file
37
vendor/go.podman.io/image/v5/signature/simplesequoia/options.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
package simplesequoia
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Option func(*simpleSequoiaSigner) error
|
||||||
|
|
||||||
|
// WithSequoiaHome returns an Option for NewSigner, specifying a Sequoia home directory to use.
|
||||||
|
func WithSequoiaHome(sequoiaHome string) Option {
|
||||||
|
return func(s *simpleSequoiaSigner) error {
|
||||||
|
s.sequoiaHome = sequoiaHome
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithKeyFingerprint returns an Option for NewSigner, specifying a key to sign with, using the provided Sequoia-PGP key fingerprint.
|
||||||
|
func WithKeyFingerprint(keyFingerprint string) Option {
|
||||||
|
return func(s *simpleSequoiaSigner) error {
|
||||||
|
s.keyFingerprint = keyFingerprint
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithPassphrase returns an Option for NewSigner, specifying a passphrase for the private key.
|
||||||
|
func WithPassphrase(passphrase string) Option {
|
||||||
|
return func(s *simpleSequoiaSigner) error {
|
||||||
|
// The gpgme implementation can’t use passphrase with \n; reject it here for consistent behavior.
|
||||||
|
// FIXME: We don’t need it in this API at all, but the "\n" check exists in the current call stack. That should go away.
|
||||||
|
if strings.Contains(passphrase, "\n") {
|
||||||
|
return errors.New("invalid passphrase: must not contain a line break")
|
||||||
|
}
|
||||||
|
s.passphrase = passphrase
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
88
vendor/go.podman.io/image/v5/signature/simplesequoia/signer.go
generated
vendored
Normal file
88
vendor/go.podman.io/image/v5/signature/simplesequoia/signer.go
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
//go:build containers_image_sequoia
|
||||||
|
|
||||||
|
package simplesequoia
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"go.podman.io/image/v5/docker/reference"
|
||||||
|
internalSig "go.podman.io/image/v5/internal/signature"
|
||||||
|
internalSigner "go.podman.io/image/v5/internal/signer"
|
||||||
|
"go.podman.io/image/v5/signature"
|
||||||
|
"go.podman.io/image/v5/signature/internal/sequoia"
|
||||||
|
"go.podman.io/image/v5/signature/signer"
|
||||||
|
)
|
||||||
|
|
||||||
|
// simpleSequoiaSigner is a signer.SignerImplementation implementation for simple signing signatures using Sequoia.
|
||||||
|
type simpleSequoiaSigner struct {
|
||||||
|
mech *sequoia.SigningMechanism
|
||||||
|
sequoiaHome string // "" if using the system’s default
|
||||||
|
keyFingerprint string
|
||||||
|
passphrase string // "" if not provided.
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSigner returns a signature.Signer which creates “simple signing” signatures using the user’s default
|
||||||
|
// Sequoia PGP configuration.
|
||||||
|
//
|
||||||
|
// The set of options must identify a key to sign with, probably using a WithKeyFingerprint.
|
||||||
|
//
|
||||||
|
// The caller must call Close() on the returned Signer.
|
||||||
|
func NewSigner(opts ...Option) (*signer.Signer, error) {
|
||||||
|
s := simpleSequoiaSigner{}
|
||||||
|
for _, o := range opts {
|
||||||
|
if err := o(&s); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if s.keyFingerprint == "" {
|
||||||
|
return nil, errors.New("no key identity provided for simple signing")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := sequoia.Init(); err != nil {
|
||||||
|
return nil, err // Coverage: This is impractical to test in-process, with the static go_sequoia_dlhandle.
|
||||||
|
}
|
||||||
|
mech, err := sequoia.NewMechanismFromDirectory(s.sequoiaHome)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("initializing Sequoia: %w", err)
|
||||||
|
}
|
||||||
|
s.mech = mech
|
||||||
|
succeeded := false
|
||||||
|
defer func() {
|
||||||
|
if !succeeded {
|
||||||
|
s.mech.Close() // Coverage: This is currently unreachable.
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Ideally, we should look up (and unlock?) the key at this point already. FIXME: is that possible? Anyway, low-priority.
|
||||||
|
|
||||||
|
succeeded = true
|
||||||
|
return internalSigner.NewSigner(&s), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProgressMessage returns a human-readable sentence that makes sense to write before starting to create a single signature.
|
||||||
|
func (s *simpleSequoiaSigner) ProgressMessage() string {
|
||||||
|
return "Signing image using Sequoia-PGP simple signing"
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignImageManifest creates a new signature for manifest m as dockerReference.
|
||||||
|
func (s *simpleSequoiaSigner) SignImageManifest(ctx context.Context, m []byte, dockerReference reference.Named) (internalSig.Signature, error) {
|
||||||
|
if reference.IsNameOnly(dockerReference) {
|
||||||
|
return nil, fmt.Errorf("reference %s can’t be signed, it has neither a tag nor a digest", dockerReference.String())
|
||||||
|
}
|
||||||
|
wrapped := sequoiaSigningOnlyMechanism{
|
||||||
|
inner: s.mech,
|
||||||
|
}
|
||||||
|
simpleSig, err := signature.SignDockerManifestWithOptions(m, dockerReference.String(), &wrapped, s.keyFingerprint, &signature.SignOptions{
|
||||||
|
Passphrase: s.passphrase,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return internalSig.SimpleSigningFromBlob(simpleSig), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *simpleSequoiaSigner) Close() error {
|
||||||
|
return s.mech.Close()
|
||||||
|
}
|
28
vendor/go.podman.io/image/v5/signature/simplesequoia/signer_stub.go
generated
vendored
Normal file
28
vendor/go.podman.io/image/v5/signature/simplesequoia/signer_stub.go
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
//go:build !containers_image_sequoia
|
||||||
|
|
||||||
|
package simplesequoia
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"go.podman.io/image/v5/signature/signer"
|
||||||
|
)
|
||||||
|
|
||||||
|
// simpleSequoiaSigner is a signer.SignerImplementation implementation for simple signing signatures using Sequoia.
|
||||||
|
type simpleSequoiaSigner struct {
|
||||||
|
// This is not really used, we just keep the struct fields so that the With… Option functions can be compiled.
|
||||||
|
|
||||||
|
sequoiaHome string // "" if using the system's default
|
||||||
|
keyFingerprint string
|
||||||
|
passphrase string // "" if not provided.
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSigner returns a signature.Signer which creates "simple signing" signatures using the user's default
|
||||||
|
// Sequoia PGP configuration.
|
||||||
|
//
|
||||||
|
// The set of options must identify a key to sign with, probably using a WithKeyFingerprint.
|
||||||
|
//
|
||||||
|
// The caller must call Close() on the returned Signer.
|
||||||
|
func NewSigner(opts ...Option) (*signer.Signer, error) {
|
||||||
|
return nil, errors.New("Sequoia-PGP support is not enabled in this build")
|
||||||
|
}
|
1
vendor/modules.txt
vendored
1
vendor/modules.txt
vendored
@@ -431,6 +431,7 @@ go.podman.io/image/v5/signature/sigstore
|
|||||||
go.podman.io/image/v5/signature/sigstore/fulcio
|
go.podman.io/image/v5/signature/sigstore/fulcio
|
||||||
go.podman.io/image/v5/signature/sigstore/internal
|
go.podman.io/image/v5/signature/sigstore/internal
|
||||||
go.podman.io/image/v5/signature/sigstore/rekor
|
go.podman.io/image/v5/signature/sigstore/rekor
|
||||||
|
go.podman.io/image/v5/signature/simplesequoia
|
||||||
go.podman.io/image/v5/signature/simplesigning
|
go.podman.io/image/v5/signature/simplesigning
|
||||||
go.podman.io/image/v5/storage
|
go.podman.io/image/v5/storage
|
||||||
go.podman.io/image/v5/tarball
|
go.podman.io/image/v5/tarball
|
||||||
|
Reference in New Issue
Block a user