mirror of
https://github.com/containers/skopeo.git
synced 2025-07-17 16:21:40 +00:00
Use multiple fingerprint function
Allow comma separated fingerprint list To be squashed later Signed-off-by: James Hewitt <james.hewitt@uk.ibm.com>
This commit is contained in:
parent
c54f2025d8
commit
4ca2058d01
@ -6,11 +6,11 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/containers/image/v5/pkg/cli"
|
"github.com/containers/image/v5/pkg/cli"
|
||||||
"github.com/containers/image/v5/signature"
|
"github.com/containers/image/v5/signature"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"golang.org/x/exp/slices"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type standaloneSignOptions struct {
|
type standaloneSignOptions struct {
|
||||||
@ -74,11 +74,11 @@ type standaloneVerifyOptions struct {
|
|||||||
func standaloneVerifyCmd() *cobra.Command {
|
func standaloneVerifyCmd() *cobra.Command {
|
||||||
opts := standaloneVerifyOptions{}
|
opts := standaloneVerifyOptions{}
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "standalone-verify MANIFEST DOCKER-REFERENCE KEY-FINGERPRINT SIGNATURE",
|
Use: "standalone-verify MANIFEST DOCKER-REFERENCE KEY-FINGERPRINTS SIGNATURE",
|
||||||
Short: "Verify a signature using local files",
|
Short: "Verify a signature using local files",
|
||||||
Long: `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 public key file.`,
|
KEY-FINGERPRINTS can be a comma separated list of fingerprints, or "any" if you trust all the keys in the public key file.`,
|
||||||
RunE: commandAction(opts.run),
|
RunE: commandAction(opts.run),
|
||||||
}
|
}
|
||||||
flags := cmd.Flags()
|
flags := cmd.Flags()
|
||||||
@ -93,10 +93,10 @@ func (opts *standaloneVerifyOptions) run(args []string, stdout io.Writer) error
|
|||||||
}
|
}
|
||||||
manifestPath := args[0]
|
manifestPath := args[0]
|
||||||
expectedDockerReference := args[1]
|
expectedDockerReference := args[1]
|
||||||
expectedFingerprint := args[2]
|
expectedFingerprints := strings.Split(args[2], ",")
|
||||||
signaturePath := args[3]
|
signaturePath := args[3]
|
||||||
|
|
||||||
if opts.publicKeyFile == "" && expectedFingerprint == "any" {
|
if opts.publicKeyFile == "" && len(expectedFingerprints) == 1 && expectedFingerprints[0] == "any" {
|
||||||
return fmt.Errorf("Cannot use any fingerprint without a public key file")
|
return fmt.Errorf("Cannot use any fingerprint without a public key file")
|
||||||
}
|
}
|
||||||
unverifiedManifest, err := os.ReadFile(manifestPath)
|
unverifiedManifest, err := os.ReadFile(manifestPath)
|
||||||
@ -109,13 +109,13 @@ func (opts *standaloneVerifyOptions) run(args []string, stdout io.Writer) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
var mech signature.SigningMechanism
|
var mech signature.SigningMechanism
|
||||||
var fingerprints []string
|
var publicKeyfingerprints []string
|
||||||
if opts.publicKeyFile != "" {
|
if opts.publicKeyFile != "" {
|
||||||
publicKeys, err := os.ReadFile(opts.publicKeyFile)
|
publicKeys, err := os.ReadFile(opts.publicKeyFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Error reading public keys from %s: %w", opts.publicKeyFile, err)
|
return fmt.Errorf("Error reading public keys from %s: %w", opts.publicKeyFile, err)
|
||||||
}
|
}
|
||||||
mech, fingerprints, err = signature.NewEphemeralGPGSigningMechanism(publicKeys)
|
mech, publicKeyfingerprints, err = signature.NewEphemeralGPGSigningMechanism(publicKeys)
|
||||||
} else {
|
} else {
|
||||||
mech, err = signature.NewGPGSigningMechanism()
|
mech, err = signature.NewGPGSigningMechanism()
|
||||||
}
|
}
|
||||||
@ -124,23 +124,16 @@ func (opts *standaloneVerifyOptions) run(args []string, stdout io.Writer) error
|
|||||||
}
|
}
|
||||||
defer mech.Close()
|
defer mech.Close()
|
||||||
|
|
||||||
if opts.publicKeyFile != "" && expectedFingerprint == "any" {
|
if len(expectedFingerprints) == 1 && expectedFingerprints[0] == "any" {
|
||||||
_, expectedFingerprint, err = mech.Verify(unverifiedSignature)
|
expectedFingerprints = publicKeyfingerprints
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Could not determine fingerprint from signature: %w", err)
|
|
||||||
}
|
|
||||||
if !slices.Contains(fingerprints, expectedFingerprint) {
|
|
||||||
// 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)
|
sig, verificationFingerprint, err := signature.VerifyImageManifestSignatureUsingKeyIdentityList(unverifiedSignature, unverifiedManifest, expectedDockerReference, mech, expectedFingerprints)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Error verifying signature: %w", err)
|
return fmt.Errorf("Error verifying signature: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(stdout, "Signature verified using fingerprint %s, digest %s\n", expectedFingerprint, sig.DockerManifestDigest)
|
fmt.Fprintf(stdout, "Signature verified using fingerprint %s, digest %s\n", verificationFingerprint, sig.DockerManifestDigest)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,21 +136,27 @@ func TestStandaloneVerify(t *testing.T) {
|
|||||||
out, err = runSkopeo("standalone-verify", manifestPath,
|
out, err = runSkopeo("standalone-verify", manifestPath,
|
||||||
dockerReference, fixturesTestKeyFingerprint, signaturePath)
|
dockerReference, fixturesTestKeyFingerprint, signaturePath)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "Signature verified using fingerprint 1D8230F6CDB6A06716E414C1DB72F2188BB46CC8, digest "+fixturesTestImageManifestDigest.String()+"\n", out)
|
assert.Equal(t, "Signature verified using fingerprint "+fixturesTestKeyFingerprint+", digest "+fixturesTestImageManifestDigest.String()+"\n", out)
|
||||||
|
|
||||||
|
// Using multiple fingerprints
|
||||||
|
out, err = runSkopeo("standalone-verify", manifestPath,
|
||||||
|
dockerReference, "0123456789ABCDEF0123456789ABCDEF01234567,"+fixturesTestKeyFingerprint+",DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF", signaturePath)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "Signature verified using fingerprint "+fixturesTestKeyFingerprint+", digest "+fixturesTestImageManifestDigest.String()+"\n", out)
|
||||||
|
|
||||||
// Using a public key file
|
// Using a public key file
|
||||||
t.Setenv("GNUPGHOME", "")
|
t.Setenv("GNUPGHOME", "")
|
||||||
out, err = runSkopeo("standalone-verify", "--public-key-file", "fixtures/pubring.gpg", manifestPath,
|
out, err = runSkopeo("standalone-verify", "--public-key-file", "fixtures/pubring.gpg", manifestPath,
|
||||||
dockerReference, fixturesTestKeyFingerprint, signaturePath)
|
dockerReference, fixturesTestKeyFingerprint, signaturePath)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "Signature verified using fingerprint 1D8230F6CDB6A06716E414C1DB72F2188BB46CC8, digest "+fixturesTestImageManifestDigest.String()+"\n", out)
|
assert.Equal(t, "Signature verified using fingerprint "+fixturesTestKeyFingerprint+", digest "+fixturesTestImageManifestDigest.String()+"\n", out)
|
||||||
|
|
||||||
// Using a public key file matching any public key
|
// Using a public key file matching any public key
|
||||||
t.Setenv("GNUPGHOME", "")
|
t.Setenv("GNUPGHOME", "")
|
||||||
out, err = runSkopeo("standalone-verify", "--public-key-file", "fixtures/pubring.gpg", manifestPath,
|
out, err = runSkopeo("standalone-verify", "--public-key-file", "fixtures/pubring.gpg", manifestPath,
|
||||||
dockerReference, "any", signaturePath)
|
dockerReference, "any", signaturePath)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "Signature verified using fingerprint 1D8230F6CDB6A06716E414C1DB72F2188BB46CC8, digest "+fixturesTestImageManifestDigest.String()+"\n", out)
|
assert.Equal(t, "Signature verified using fingerprint "+fixturesTestKeyFingerprint+", digest "+fixturesTestImageManifestDigest.String()+"\n", out)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUntrustedSignatureDump(t *testing.T) {
|
func TestUntrustedSignatureDump(t *testing.T) {
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
skopeo\-standalone\-verify - Verify an image signature.
|
skopeo\-standalone\-verify - Verify an image signature.
|
||||||
|
|
||||||
## SYNOPSIS
|
## SYNOPSIS
|
||||||
**skopeo standalone-verify** _manifest_ _docker-reference_ _key-fingerprint_ _signature_
|
**skopeo standalone-verify** _manifest_ _docker-reference_ _key-fingerprints_ _signature_
|
||||||
|
|
||||||
## DESCRIPTION
|
## DESCRIPTION
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ as per containers-policy.json(5).
|
|||||||
|
|
||||||
_docker-reference_ A docker reference expected to identify the image in the signature
|
_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 when using a public key file
|
_key-fingerprints_ Identities of trusted signing keys (comma separated), or "any" to trust any known key when using a public key file
|
||||||
|
|
||||||
_signature_ Path to signature file
|
_signature_ Path to signature file
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user