Review comments (to be squashed later

Signed-off-by: James Hewitt <james.hewitt@uk.ibm.com>
This commit is contained in:
James Hewitt 2023-03-30 09:39:30 +01:00
parent 9b1f1fa1a9
commit c54f2025d8
No known key found for this signature in database
GPG Key ID: EA6C3C654B6193E4
2 changed files with 26 additions and 23 deletions

View File

@ -10,6 +10,7 @@ import (
"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 {
@ -41,12 +42,12 @@ func (opts *standaloneSignOptions) run(args []string, stdout io.Writer) error {
manifest, err := os.ReadFile(manifestPath) manifest, err := os.ReadFile(manifestPath)
if err != nil { if err != nil {
return fmt.Errorf("Error reading %s: %v", manifestPath, err) return fmt.Errorf("Error reading %s: %w", manifestPath, err)
} }
mech, err := signature.NewGPGSigningMechanism() mech, err := signature.NewGPGSigningMechanism()
if err != nil { if err != nil {
return fmt.Errorf("Error initializing GPG: %v", err) return fmt.Errorf("Error initializing GPG: %w", err)
} }
defer mech.Close() defer mech.Close()
@ -57,17 +58,17 @@ func (opts *standaloneSignOptions) run(args []string, stdout io.Writer) error {
signature, err := signature.SignDockerManifestWithOptions(manifest, dockerReference, mech, fingerprint, &signature.SignOptions{Passphrase: passphrase}) signature, err := signature.SignDockerManifestWithOptions(manifest, dockerReference, mech, fingerprint, &signature.SignOptions{Passphrase: passphrase})
if err != nil { if err != nil {
return fmt.Errorf("Error creating signature: %v", err) return fmt.Errorf("Error creating signature: %w", err)
} }
if err := os.WriteFile(opts.output, signature, 0644); err != nil { if err := os.WriteFile(opts.output, signature, 0644); err != nil {
return fmt.Errorf("Error writing signature to %s: %v", opts.output, err) return fmt.Errorf("Error writing signature to %s: %w", opts.output, err)
} }
return nil return nil
} }
type standaloneVerifyOptions struct { type standaloneVerifyOptions struct {
publickeyfile string publicKeyFile string
} }
func standaloneVerifyCmd() *cobra.Command { func standaloneVerifyCmd() *cobra.Command {
@ -81,7 +82,7 @@ KEY-FINGERPRINT can be an exact fingerprint, or "any" if you trust all the keys
RunE: commandAction(opts.run), RunE: commandAction(opts.run),
} }
flags := cmd.Flags() flags := cmd.Flags()
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.`) flags.StringVar(&opts.publicKeyFile, "public-key-file", "", `File containing public keys. If not specified, will use local GPG keys.`)
adjustUsage(cmd) adjustUsage(cmd)
return cmd return cmd
} }
@ -95,43 +96,40 @@ func (opts *standaloneVerifyOptions) run(args []string, stdout io.Writer) error
expectedFingerprint := args[2] expectedFingerprint := args[2]
signaturePath := args[3] signaturePath := args[3]
if opts.publicKeyFile == "" && expectedFingerprint == "any" {
return fmt.Errorf("Cannot use any fingerprint without a public key file")
}
unverifiedManifest, err := os.ReadFile(manifestPath) unverifiedManifest, err := os.ReadFile(manifestPath)
if err != nil { if err != nil {
return fmt.Errorf("Error reading manifest from %s: %v", manifestPath, err) return fmt.Errorf("Error reading manifest from %s: %w", manifestPath, err)
} }
unverifiedSignature, err := os.ReadFile(signaturePath) unverifiedSignature, err := os.ReadFile(signaturePath)
if err != nil { if err != nil {
return fmt.Errorf("Error reading signature from %s: %v", signaturePath, err) return fmt.Errorf("Error reading signature from %s: %w", signaturePath, err)
} }
var mech signature.SigningMechanism var mech signature.SigningMechanism
var fingerprints []string var fingerprints []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: %v", opts.publickeyfile, err) return fmt.Errorf("Error reading public keys from %s: %w", opts.publicKeyFile, err)
} }
mech, fingerprints, err = signature.NewEphemeralGPGSigningMechanism(publicKeys) mech, fingerprints, err = signature.NewEphemeralGPGSigningMechanism(publicKeys)
} else { } else {
mech, err = signature.NewGPGSigningMechanism() mech, err = signature.NewGPGSigningMechanism()
} }
if err != nil { if err != nil {
return fmt.Errorf("Error initializing GPG: %v", err) return fmt.Errorf("Error initializing GPG: %w", err)
} }
defer mech.Close() defer mech.Close()
if opts.publickeyfile != "" && expectedFingerprint == "any" { if opts.publicKeyFile != "" && expectedFingerprint == "any" {
_, expectedFingerprint, err = mech.Verify(unverifiedSignature) _, expectedFingerprint, err = mech.Verify(unverifiedSignature)
if err != nil { if err != nil {
return fmt.Errorf("Could not determine fingerprint from signature: %v", err) return fmt.Errorf("Could not determine fingerprint from signature: %w", err)
} }
found := false if !slices.Contains(fingerprints, expectedFingerprint) {
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 // 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) return fmt.Errorf("Signature fingerprint not found in public key file: %s", expectedFingerprint)
} }
@ -139,7 +137,7 @@ func (opts *standaloneVerifyOptions) run(args []string, stdout io.Writer) error
sig, err := signature.VerifyDockerManifestSignature(unverifiedSignature, unverifiedManifest, expectedDockerReference, mech, expectedFingerprint) sig, err := signature.VerifyDockerManifestSignature(unverifiedSignature, unverifiedManifest, expectedDockerReference, mech, expectedFingerprint)
if err != nil { if err != nil {
return fmt.Errorf("Error verifying signature: %v", 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", expectedFingerprint, sig.DockerManifestDigest)
@ -175,7 +173,7 @@ func (opts *untrustedSignatureDumpOptions) run(args []string, stdout io.Writer)
untrustedSignature, err := os.ReadFile(untrustedSignaturePath) untrustedSignature, err := os.ReadFile(untrustedSignaturePath)
if err != nil { if err != nil {
return fmt.Errorf("Error reading untrusted signature from %s: %v", untrustedSignaturePath, err) return fmt.Errorf("Error reading untrusted signature from %s: %w", untrustedSignaturePath, err)
} }
untrustedInfo, err := signature.GetUntrustedSignatureInformationWithoutVerifying(untrustedSignature) untrustedInfo, err := signature.GetUntrustedSignatureInformationWithoutVerifying(untrustedSignature)

View File

@ -127,6 +127,11 @@ func TestStandaloneVerify(t *testing.T) {
dockerReference, fixturesTestKeyFingerprint, "fixtures/corrupt.signature") dockerReference, fixturesTestKeyFingerprint, "fixtures/corrupt.signature")
assertTestFailed(t, out, err, "Error verifying signature") assertTestFailed(t, out, err, "Error verifying signature")
// Error using any without a public key file
out, err = runSkopeo("standalone-verify", manifestPath,
dockerReference, "any", signaturePath)
assertTestFailed(t, out, err, "Cannot use any fingerprint without a public key file")
// Success // Success
out, err = runSkopeo("standalone-verify", manifestPath, out, err = runSkopeo("standalone-verify", manifestPath,
dockerReference, fixturesTestKeyFingerprint, signaturePath) dockerReference, fixturesTestKeyFingerprint, signaturePath)