diff --git a/cmd/skopeo/signing.go b/cmd/skopeo/signing.go index 07a3ab52..830ef05d 100644 --- a/cmd/skopeo/signing.go +++ b/cmd/skopeo/signing.go @@ -67,7 +67,7 @@ func (opts *standaloneSignOptions) run(args []string, stdout io.Writer) error { } type standaloneVerifyOptions struct { - truststore string + publickeyfile string } func standaloneVerifyCmd() *cobra.Command { @@ -77,11 +77,11 @@ func standaloneVerifyCmd() *cobra.Command { Short: "Verify a signature using local files", Long: `Verify a signature using local files -KEY-FINGERPRINT can be an exact fingerprint, or "any" if you trust all the keys in the trust store.`, +KEY-FINGERPRINT can be an exact fingerprint, or "any" if you trust all the keys in the public key file.`, RunE: commandAction(opts.run), } flags := cmd.Flags() - flags.StringVar(&opts.truststore, "truststore", "", "Trust store of public keys. Defaults to using local gpg keys.") + flags.StringVar(&opts.publickeyfile, "public-key-file", "", `File containing public keys. If not specified, will use local GPG keys. When using a public key file, you can specify "any" as the fingerprint to trust any key in the public key file.`) adjustUsage(cmd) return cmd } @@ -105,12 +105,13 @@ func (opts *standaloneVerifyOptions) run(args []string, stdout io.Writer) error } var mech signature.SigningMechanism - if opts.truststore != "" { - truststore, err := os.ReadFile(opts.truststore) + var fingerprints []string + if opts.publickeyfile != "" { + publicKeys, err := os.ReadFile(opts.publickeyfile) if err != nil { - return fmt.Errorf("Error reading trust store from %s: %v", opts.truststore, err) + return fmt.Errorf("Error reading public keys from %s: %v", opts.publickeyfile, err) } - mech, _, err = signature.NewEphemeralGPGSigningMechanism(truststore) + mech, fingerprints, err = signature.NewEphemeralGPGSigningMechanism(publicKeys) } else { mech, err = signature.NewGPGSigningMechanism() } @@ -119,11 +120,21 @@ func (opts *standaloneVerifyOptions) run(args []string, stdout io.Writer) error } defer mech.Close() - if expectedFingerprint == "any" { + if opts.publickeyfile != "" && expectedFingerprint == "any" { _, expectedFingerprint, err = mech.Verify(unverifiedSignature) if err != nil { return fmt.Errorf("Could not determine fingerprint from signature: %v", err) } + found := false + for _, fingerprint := range fingerprints { + if expectedFingerprint == fingerprint { + found = true + } + } + if !found { + // This is theoretically impossible because mech.Verify only works if it can identify the key based on the signature + return fmt.Errorf("Signature fingerprint not found in public key file: %s", expectedFingerprint) + } } sig, err := signature.VerifyDockerManifestSignature(unverifiedSignature, unverifiedManifest, expectedDockerReference, mech, expectedFingerprint) diff --git a/cmd/skopeo/signing_test.go b/cmd/skopeo/signing_test.go index 56732c8a..c0b0876c 100644 --- a/cmd/skopeo/signing_test.go +++ b/cmd/skopeo/signing_test.go @@ -133,15 +133,16 @@ func TestStandaloneVerify(t *testing.T) { assert.NoError(t, err) assert.Equal(t, "Signature verified using fingerprint 1D8230F6CDB6A06716E414C1DB72F2188BB46CC8, digest "+fixturesTestImageManifestDigest.String()+"\n", out) - // Using any known fingerprint - out, err = runSkopeo("standalone-verify", manifestPath, - dockerReference, "any", signaturePath) + // Using a public key file + t.Setenv("GNUPGHOME", "") + out, err = runSkopeo("standalone-verify", "--public-key-file", "fixtures/pubring.gpg", manifestPath, + dockerReference, fixturesTestKeyFingerprint, signaturePath) assert.NoError(t, err) assert.Equal(t, "Signature verified using fingerprint 1D8230F6CDB6A06716E414C1DB72F2188BB46CC8, digest "+fixturesTestImageManifestDigest.String()+"\n", out) - // Using a trust store + // Using a public key file matching any public key t.Setenv("GNUPGHOME", "") - out, err = runSkopeo("standalone-verify", "--truststore", "fixtures/pubring.gpg", manifestPath, + out, err = runSkopeo("standalone-verify", "--public-key-file", "fixtures/pubring.gpg", manifestPath, dockerReference, "any", signaturePath) assert.NoError(t, err) assert.Equal(t, "Signature verified using fingerprint 1D8230F6CDB6A06716E414C1DB72F2188BB46CC8, digest "+fixturesTestImageManifestDigest.String()+"\n", out) diff --git a/docs/skopeo-standalone-verify.1.md b/docs/skopeo-standalone-verify.1.md index 72ca4c10..aad71c98 100644 --- a/docs/skopeo-standalone-verify.1.md +++ b/docs/skopeo-standalone-verify.1.md @@ -16,7 +16,7 @@ as per containers-policy.json(5). _docker-reference_ A docker reference expected to identify the image in the signature - _key-fingerprint_ Expected identity of the signing key, or "any" to trust any known key + _key-fingerprint_ Expected identity of the signing key, or "any" to trust any known key when using a public key file _signature_ Path to signature file @@ -28,9 +28,9 @@ as per containers-policy.json(5). Print usage statement -**--truststore** _truststore_ +**--public-key-file** _public key file_ -Trust store of public keys to use when verifying signatures. If this is not specified, keys from gpg home are used. +File containing the public keys to use when verifying signatures. If this is not specified, keys from the GPG homedir are used. ## EXAMPLES