From 3b79cee592743568c2139bc01bcb51eda7ceca39 Mon Sep 17 00:00:00 2001 From: Ivan Wallis Date: Sat, 13 Nov 2021 12:24:10 -0800 Subject: [PATCH 01/14] initial cmd structure Signed-off-by: Ivan Wallis --- cmd/cosign/cli/commands.go | 1 + cmd/cosign/cli/import_key_pair.go | 48 +++++++ .../cli/importkeypair/import_key_pair.go | 133 ++++++++++++++++++ .../cli/importkeypair/import_key_pair_test.go | 47 +++++++ cmd/cosign/cli/options/import_key_pair.go | 34 +++++ pkg/cosign/keys.go | 5 + 6 files changed, 268 insertions(+) create mode 100644 cmd/cosign/cli/import_key_pair.go create mode 100644 cmd/cosign/cli/importkeypair/import_key_pair.go create mode 100644 cmd/cosign/cli/importkeypair/import_key_pair_test.go create mode 100644 cmd/cosign/cli/options/import_key_pair.go diff --git a/cmd/cosign/cli/commands.go b/cmd/cosign/cli/commands.go index 75019f6062b..bbc2f599a55 100644 --- a/cmd/cosign/cli/commands.go +++ b/cmd/cosign/cli/commands.go @@ -67,6 +67,7 @@ func New() *cobra.Command { cmd.AddCommand(Download()) cmd.AddCommand(Generate()) cmd.AddCommand(GenerateKeyPair()) + cmd.AddCommand(ImportKeyPair()) cmd.AddCommand(Initialize()) cmd.AddCommand(Manifest()) cmd.AddCommand(PIVTool()) diff --git a/cmd/cosign/cli/import_key_pair.go b/cmd/cosign/cli/import_key_pair.go new file mode 100644 index 00000000000..8a12e5ca579 --- /dev/null +++ b/cmd/cosign/cli/import_key_pair.go @@ -0,0 +1,48 @@ +// +// Copyright 2021 The Sigstore Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cli + +import ( + "github.com/spf13/cobra" + + "github.com/sigstore/cosign/cmd/cosign/cli/importkeypair" + "github.com/sigstore/cosign/cmd/cosign/cli/options" +) + +func ImportKeyPair() *cobra.Command { + o := &options.ImportKeyPairOptions{} + + cmd := &cobra.Command{ + Use: "import-key-pair", + Short: "Imports an RSA key-pair.", + Long: "Imports an RSA key-pair for signing.", + Example: ` cosign import-key-pair + + # import key-pair and write to cosign.key and cosign.pub files + cosign import-key-pair + +CAVEATS: + This command interactively prompts for a password. You can use + the COSIGN_PASSWORD environment variable to provide one.`, + + RunE: func(cmd *cobra.Command, args []string) error { + return importkeypair.ImportKeyPairCmd(cmd.Context(), o.KMS, args) + }, + } + + o.AddFlags(cmd) + return cmd +} diff --git a/cmd/cosign/cli/importkeypair/import_key_pair.go b/cmd/cosign/cli/importkeypair/import_key_pair.go new file mode 100644 index 00000000000..10e65144807 --- /dev/null +++ b/cmd/cosign/cli/importkeypair/import_key_pair.go @@ -0,0 +1,133 @@ +// +// Copyright 2021 The Sigstore Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package importkeypair + +import ( + "context" + //"crypto" + "fmt" + "io" + "os" + + //"strings" + + "github.com/pkg/errors" + "golang.org/x/term" + //"github.com/sigstore/sigstore/pkg/cryptoutils" + //"github.com/sigstore/sigstore/pkg/signature/kms" +) + +var ( + // Read is for fuzzing + Read = readPasswordFn +) + +// nolint +func ImportKeyPairCmd(ctx context.Context, kmsVal string, args []string) error { + + print("hello importkeypair!") + return nil + + /*keys, err := cosign.ImportKeyPair(GetPass) + if err != nil { + return err + } + + if fileExists("cosign.key") { + var overwrite string + fmt.Fprint(os.Stderr, "File cosign.key already exists. Overwrite (y/n)? ") + fmt.Scanf("%s", &overwrite) + switch overwrite { + case "y", "Y": + case "n", "N": + return nil + default: + fmt.Fprintln(os.Stderr, "Invalid input") + return nil + } + } + // TODO: make sure the perms are locked down first. + if err := os.WriteFile("cosign.key", keys.PrivateBytes, 0600); err != nil { + return err + } + fmt.Fprintln(os.Stderr, "Private key written to cosign.key") + + if err := os.WriteFile("cosign.pub", keys.PublicBytes, 0644); err != nil { + return err + } // #nosec G306 + fmt.Fprintln(os.Stderr, "Public key written to cosign.pub") + return nil*/ +} + +func GetPass(confirm bool) ([]byte, error) { + read := Read(confirm) + return read() +} + +func readPasswordFn(confirm bool) func() ([]byte, error) { + pw, ok := os.LookupEnv("COSIGN_PASSWORD") + switch { + case ok: + return func() ([]byte, error) { + return []byte(pw), nil + } + case isTerminal(): + return func() ([]byte, error) { + return getPassFromTerm(confirm) + } + // Handle piped in passwords. + default: + return func() ([]byte, error) { + return io.ReadAll(os.Stdin) + } + } +} + +func isTerminal() bool { + stat, _ := os.Stdin.Stat() + return (stat.Mode() & os.ModeCharDevice) != 0 +} + +func getPassFromTerm(confirm bool) ([]byte, error) { + fmt.Fprint(os.Stderr, "Enter password for private key: ") + pw1, err := term.ReadPassword(0) + if err != nil { + return nil, err + } + if !confirm { + return pw1, nil + } + fmt.Fprintln(os.Stderr) + fmt.Fprint(os.Stderr, "Enter password for private key again: ") + pw2, err := term.ReadPassword(0) + fmt.Fprintln(os.Stderr) + if err != nil { + return nil, err + } + + if string(pw1) != string(pw2) { + return nil, errors.New("passwords do not match") + } + return pw1, nil +} + +func fileExists(filename string) bool { + info, err := os.Stat(filename) + if os.IsNotExist(err) { + return false + } + return !info.IsDir() +} diff --git a/cmd/cosign/cli/importkeypair/import_key_pair_test.go b/cmd/cosign/cli/importkeypair/import_key_pair_test.go new file mode 100644 index 00000000000..29101df9aa8 --- /dev/null +++ b/cmd/cosign/cli/importkeypair/import_key_pair_test.go @@ -0,0 +1,47 @@ +// +// Copyright 2021 The Sigstore Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package importkeypair + +import ( + "os" + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestReadPasswordFn_env(t *testing.T) { + os.Setenv("COSIGN_PASSWORD", "foo") + defer os.Unsetenv("COSIGN_PASSWORD") + b, err := readPasswordFn(true)() + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if diff := cmp.Diff("foo", string(b)); diff != "" { + t.Fatal(diff) + } +} + +func TestReadPasswordFn_envEmptyVal(t *testing.T) { + os.Setenv("COSIGN_PASSWORD", "") + defer os.Unsetenv("COSIGN_PASSWORD") + b, err := readPasswordFn(true)() + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(b) > 0 { + t.Fatalf("expected empty string; got %q", string(b)) + } +} diff --git a/cmd/cosign/cli/options/import_key_pair.go b/cmd/cosign/cli/options/import_key_pair.go new file mode 100644 index 00000000000..19e6b33a9b9 --- /dev/null +++ b/cmd/cosign/cli/options/import_key_pair.go @@ -0,0 +1,34 @@ +// +// Copyright 2021 The Sigstore Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package options + +import ( + "github.com/spf13/cobra" +) + +// GenerateKeyPairOptions is the top level wrapper for the generate-key-pair command. +type ImportKeyPairOptions struct { + // KMS Key Management Service + KMS string +} + +var _ Interface = (*ImportKeyPairOptions)(nil) + +// AddFlags implements Interface +func (o *ImportKeyPairOptions) AddFlags(cmd *cobra.Command) { + cmd.Flags().StringVar(&o.KMS, "kms", "", + "create key pair in KMS service to use for signing") +} diff --git a/pkg/cosign/keys.go b/pkg/cosign/keys.go index 02edfd37327..890f9f94243 100644 --- a/pkg/cosign/keys.go +++ b/pkg/cosign/keys.go @@ -51,6 +51,11 @@ func GeneratePrivateKey() (*ecdsa.PrivateKey, error) { return ecdsa.GenerateKey(elliptic.P256(), rand.Reader) } +func ImportKeyPair(pf PassFunc) (*Keys, error) { + + return nil, nil +} + func GenerateKeyPair(pf PassFunc) (*Keys, error) { priv, err := GeneratePrivateKey() if err != nil { From 28e8b78797970da8d3ef996608cc66294bed7d15 Mon Sep 17 00:00:00 2001 From: Ivan Wallis Date: Sat, 13 Nov 2021 22:16:12 -0800 Subject: [PATCH 02/14] import rsa and ec keypairs into cosign Signed-off-by: Ivan Wallis --- cmd/cosign/cli/import_key_pair.go | 8 +- .../cli/importkeypair/import_key_pair.go | 27 ++-- cmd/cosign/cli/options/import_key_pair.go | 10 +- pkg/cosign/keys.go | 139 +++++++++++++++++- pkg/signature/keys.go | 5 +- 5 files changed, 154 insertions(+), 35 deletions(-) diff --git a/cmd/cosign/cli/import_key_pair.go b/cmd/cosign/cli/import_key_pair.go index 8a12e5ca579..a966d66ffe2 100644 --- a/cmd/cosign/cli/import_key_pair.go +++ b/cmd/cosign/cli/import_key_pair.go @@ -27,11 +27,11 @@ func ImportKeyPair() *cobra.Command { cmd := &cobra.Command{ Use: "import-key-pair", - Short: "Imports an RSA key-pair.", - Long: "Imports an RSA key-pair for signing.", + Short: "Imports an RSA or EC key-pair.", + Long: "Imports an RSA or EC key-pair for signing.", Example: ` cosign import-key-pair - # import key-pair and write to cosign.key and cosign.pub files + # import key-pair and write to import-cosign.key and import-cosign.pub files cosign import-key-pair CAVEATS: @@ -39,7 +39,7 @@ CAVEATS: the COSIGN_PASSWORD environment variable to provide one.`, RunE: func(cmd *cobra.Command, args []string) error { - return importkeypair.ImportKeyPairCmd(cmd.Context(), o.KMS, args) + return importkeypair.ImportKeyPairCmd(cmd.Context(), o.Key, args) }, } diff --git a/cmd/cosign/cli/importkeypair/import_key_pair.go b/cmd/cosign/cli/importkeypair/import_key_pair.go index 10e65144807..d1819802a31 100644 --- a/cmd/cosign/cli/importkeypair/import_key_pair.go +++ b/cmd/cosign/cli/importkeypair/import_key_pair.go @@ -17,17 +17,13 @@ package importkeypair import ( "context" - //"crypto" "fmt" "io" "os" - //"strings" - "github.com/pkg/errors" + "github.com/sigstore/cosign/pkg/cosign" "golang.org/x/term" - //"github.com/sigstore/sigstore/pkg/cryptoutils" - //"github.com/sigstore/sigstore/pkg/signature/kms" ) var ( @@ -36,19 +32,16 @@ var ( ) // nolint -func ImportKeyPairCmd(ctx context.Context, kmsVal string, args []string) error { - - print("hello importkeypair!") - return nil +func ImportKeyPairCmd(ctx context.Context, keyVal string, args []string) error { - /*keys, err := cosign.ImportKeyPair(GetPass) + keys, err := cosign.ImportKeyPair(keyVal, GetPass) if err != nil { return err } - if fileExists("cosign.key") { + if fileExists("import-cosign.key") { var overwrite string - fmt.Fprint(os.Stderr, "File cosign.key already exists. Overwrite (y/n)? ") + fmt.Fprint(os.Stderr, "File import-cosign.key already exists. Overwrite (y/n)? ") fmt.Scanf("%s", &overwrite) switch overwrite { case "y", "Y": @@ -60,16 +53,16 @@ func ImportKeyPairCmd(ctx context.Context, kmsVal string, args []string) error { } } // TODO: make sure the perms are locked down first. - if err := os.WriteFile("cosign.key", keys.PrivateBytes, 0600); err != nil { + if err := os.WriteFile("import-cosign.key", keys.PrivateBytes, 0600); err != nil { return err } - fmt.Fprintln(os.Stderr, "Private key written to cosign.key") + fmt.Fprintln(os.Stderr, "Private key written to import-cosign.key") - if err := os.WriteFile("cosign.pub", keys.PublicBytes, 0644); err != nil { + if err := os.WriteFile("import-cosign.pub", keys.PublicBytes, 0644); err != nil { return err } // #nosec G306 - fmt.Fprintln(os.Stderr, "Public key written to cosign.pub") - return nil*/ + fmt.Fprintln(os.Stderr, "Public key written to import-cosign.pub") + return nil } func GetPass(confirm bool) ([]byte, error) { diff --git a/cmd/cosign/cli/options/import_key_pair.go b/cmd/cosign/cli/options/import_key_pair.go index 19e6b33a9b9..b4d3ac3d4bf 100644 --- a/cmd/cosign/cli/options/import_key_pair.go +++ b/cmd/cosign/cli/options/import_key_pair.go @@ -19,16 +19,16 @@ import ( "github.com/spf13/cobra" ) -// GenerateKeyPairOptions is the top level wrapper for the generate-key-pair command. +// ImportKeyPairOptions is the top level wrapper for the import-key-pair command. type ImportKeyPairOptions struct { - // KMS Key Management Service - KMS string + // Local key file generated by external program such as OpenSSL + Key string } var _ Interface = (*ImportKeyPairOptions)(nil) // AddFlags implements Interface func (o *ImportKeyPairOptions) AddFlags(cmd *cobra.Command) { - cmd.Flags().StringVar(&o.KMS, "kms", "", - "create key pair in KMS service to use for signing") + cmd.Flags().StringVar(&o.Key, "key", "", + "import key pair to use for signing") } diff --git a/pkg/cosign/keys.go b/pkg/cosign/keys.go index 890f9f94243..b909ca0047d 100644 --- a/pkg/cosign/keys.go +++ b/pkg/cosign/keys.go @@ -20,10 +20,13 @@ import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rand" + "crypto/rsa" _ "crypto/sha256" // for `crypto.SHA256` "crypto/x509" "encoding/pem" "fmt" + "os" + "path/filepath" "github.com/pkg/errors" "github.com/theupdateframework/go-tuf/encrypted" @@ -34,13 +37,19 @@ import ( ) const ( - PrivakeKeyPemType = "ENCRYPTED COSIGN PRIVATE KEY" - - BundleKey = static.BundleAnnotationKey + PrivateKeyPemType = "ENCRYPTED COSIGN PRIVATE KEY" + RSAPrivateKeyPemType = "RSA PRIVATE KEY" + ECPrivateKeyPemType = "EC PRIVATE KEY" + BundleKey = static.BundleAnnotationKey ) type PassFunc func(bool) ([]byte, error) +type Key struct { + private crypto.PrivateKey + public crypto.PublicKey +} + type Keys struct { PrivateBytes []byte PublicBytes []byte @@ -51,9 +60,72 @@ func GeneratePrivateKey() (*ecdsa.PrivateKey, error) { return ecdsa.GenerateKey(elliptic.P256(), rand.Reader) } -func ImportKeyPair(pf PassFunc) (*Keys, error) { +func ImportKeyPair(keyPath string, pf PassFunc) (*Keys, error) { + + kb, err := os.ReadFile(filepath.Clean(keyPath)) + if err != nil { + return nil, err + } + + p, _ := pem.Decode(kb) + if p == nil { + return nil, errors.New("invalid pem block") + } + if p.Type != RSAPrivateKeyPemType && p.Type != ECPrivateKeyPemType { + return nil, fmt.Errorf("unsupported pem type: %s", p.Type) + } + + if p.Type == RSAPrivateKeyPemType { + pk, err := x509.ParsePKCS1PrivateKey(p.Bytes) + if err != nil { + return nil, fmt.Errorf("parsing error") + } + return MarshallKeyPair(Key{pk, pk.Public()}, pf) + } else { + + pk, err := x509.ParseECPrivateKey(p.Bytes) + if err != nil { + return nil, fmt.Errorf("parsing error") + } + return MarshallKeyPair(Key{pk, pk.Public()}, pf) + } + +} + +func MarshallKeyPair(keypair Key, pf PassFunc) (*Keys, error) { + + x509Encoded, err := x509.MarshalPKCS8PrivateKey(keypair.private) + if err != nil { + return nil, errors.Wrap(err, "x509 encoding private key") + } - return nil, nil + password, err := pf(true) + if err != nil { + return nil, err + } + + encBytes, err := encrypted.Encrypt(x509Encoded, password) + if err != nil { + return nil, err + } + + // store in PEM format + privBytes := pem.EncodeToMemory(&pem.Block{ + Bytes: encBytes, + Type: PrivateKeyPemType, + }) + + // Now do the public key + pubBytes, err := cryptoutils.MarshalPublicKeyToPEM(keypair.public) + if err != nil { + return nil, err + } + + return &Keys{ + PrivateBytes: privBytes, + PublicBytes: pubBytes, + password: password, + }, nil } func GenerateKeyPair(pf PassFunc) (*Keys, error) { @@ -78,7 +150,7 @@ func GenerateKeyPair(pf PassFunc) (*Keys, error) { // store in PEM format privBytes := pem.EncodeToMemory(&pem.Block{ Bytes: encBytes, - Type: PrivakeKeyPemType, + Type: PrivateKeyPemType, }) // Now do the public key @@ -110,13 +182,42 @@ func PemToECDSAKey(pemBytes []byte) (*ecdsa.PublicKey, error) { return ecdsaPub, nil } +func LoadPrivateKey(key []byte, pass []byte) (signature.SignerVerifier, error) { + + // Decrypt first + p, _ := pem.Decode(key) + if p == nil { + return nil, errors.New("invalid pem block") + } + if p.Type != PrivateKeyPemType { + return nil, fmt.Errorf("unsupported pem type: %s", p.Type) + } + + x509Encoded, err := encrypted.Decrypt(p.Bytes, pass) + if err != nil { + return nil, errors.Wrap(err, "decrypt") + } + + pk, err := x509.ParsePKCS8PrivateKey(x509Encoded) + if err != nil { + return nil, errors.Wrap(err, "parsing private key") + } + switch pk.(type) { + case *rsa.PrivateKey: + return LoadRSAPrivateKey(key, pass) + case *ecdsa.PrivateKey: + return LoadECDSAPrivateKey(key, pass) + } + return nil, errors.Wrap(err, "loading private key") +} + func LoadECDSAPrivateKey(key []byte, pass []byte) (*signature.ECDSASignerVerifier, error) { // Decrypt first p, _ := pem.Decode(key) if p == nil { return nil, errors.New("invalid pem block") } - if p.Type != PrivakeKeyPemType { + if p.Type != PrivateKeyPemType { return nil, fmt.Errorf("unsupported pem type: %s", p.Type) } @@ -135,3 +236,27 @@ func LoadECDSAPrivateKey(key []byte, pass []byte) (*signature.ECDSASignerVerifie } return signature.LoadECDSASignerVerifier(epk, crypto.SHA256) } + +func LoadRSAPrivateKey(key []byte, pass []byte) (*signature.RSAPKCS1v15SignerVerifier, error) { + // Decrypt first + p, _ := pem.Decode(key) + if p == nil { + return nil, errors.New("invalid pem block") + } + if p.Type != PrivateKeyPemType { + return nil, fmt.Errorf("unsupported pem type: %s", p.Type) + } + + x509Encoded, err := encrypted.Decrypt(p.Bytes, pass) + if err != nil { + return nil, errors.Wrap(err, "decrypt") + } + + pk, err := x509.ParsePKCS8PrivateKey(x509Encoded) + + if err != nil { + return nil, errors.Wrap(err, "parsing private key") + } + + return signature.LoadRSAPKCS1v15SignerVerifier(pk.(*rsa.PrivateKey), crypto.SHA256) +} diff --git a/pkg/signature/keys.go b/pkg/signature/keys.go index 99a12136afb..768286782fe 100644 --- a/pkg/signature/keys.go +++ b/pkg/signature/keys.go @@ -56,7 +56,7 @@ func LoadPublicKey(ctx context.Context, keyRef string) (verifier signature.Verif return signature.LoadVerifier(pubKey, crypto.SHA256) } -func loadKey(keyPath string, pf cosign.PassFunc) (*signature.ECDSASignerVerifier, error) { +func loadKey(keyPath string, pf cosign.PassFunc) (signature.SignerVerifier, error) { kb, err := os.ReadFile(filepath.Clean(keyPath)) if err != nil { return nil, err @@ -65,7 +65,8 @@ func loadKey(keyPath string, pf cosign.PassFunc) (*signature.ECDSASignerVerifier if err != nil { return nil, err } - return cosign.LoadECDSAPrivateKey(kb, pass) + + return cosign.LoadPrivateKey(kb, pass) } func loadPublicKey(raw []byte) (signature.Verifier, error) { From c55d69e8aee27b74f3d0a4b3ffc2f6d56067cba3 Mon Sep 17 00:00:00 2001 From: Ivan Wallis Date: Sat, 13 Nov 2021 22:33:34 -0800 Subject: [PATCH 03/14] added IMPORT.md for instructions Signed-off-by: Ivan Wallis --- IMPORT.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 IMPORT.md diff --git a/IMPORT.md b/IMPORT.md new file mode 100644 index 00000000000..85446c0f980 --- /dev/null +++ b/IMPORT.md @@ -0,0 +1,11 @@ +# Import RSA and EC Keypairs + +### Import a keypair + +```shell +$ cosign import-key-pair --key opensslrsakey.pem +Enter password for private key: +Enter password for private key again: +Private key written to import-cosign.key +Public key written to import-cosign.pub +``` \ No newline at end of file From e899afd20c753bff20723ce561cca1258b2e051f Mon Sep 17 00:00:00 2001 From: Ivan Wallis Date: Mon, 15 Nov 2021 08:46:36 -0800 Subject: [PATCH 04/14] whitespace fix Signed-off-by: Ivan Wallis --- IMPORT.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IMPORT.md b/IMPORT.md index 85446c0f980..add697498b4 100644 --- a/IMPORT.md +++ b/IMPORT.md @@ -8,4 +8,4 @@ Enter password for private key: Enter password for private key again: Private key written to import-cosign.key Public key written to import-cosign.pub -``` \ No newline at end of file +``` From 34b5becec752e6781da38a726f97412e07dbed88 Mon Sep 17 00:00:00 2001 From: Ivan Wallis Date: Mon, 15 Nov 2021 22:36:47 -0800 Subject: [PATCH 05/14] PR #1050 fixes Signed-off-by: Ivan Wallis --- IMPORT.md | 6 + cmd/cosign/cli/import_key_pair.go | 10 +- .../cli/importkeypair/import_key_pair.go | 4 +- pkg/cosign/keys.go | 66 ++-------- pkg/cosign/keys_test.go | 6 +- pkg/signature/keys.go | 4 +- test/import_test.sh | 115 ++++++++++++++++++ 7 files changed, 141 insertions(+), 70 deletions(-) create mode 100755 test/import_test.sh diff --git a/IMPORT.md b/IMPORT.md index add697498b4..56b8be1188a 100644 --- a/IMPORT.md +++ b/IMPORT.md @@ -1,4 +1,5 @@ # Import RSA and EC Keypairs +* Currently only supports RSA and ECDSA private keys ### Import a keypair @@ -9,3 +10,8 @@ Enter password for private key again: Private key written to import-cosign.key Public key written to import-cosign.pub ``` +### Sign a container with imported keypair + +```shell +$ cosign sign --key import import-cosign.key dlorenc/demo +``` diff --git a/cmd/cosign/cli/import_key_pair.go b/cmd/cosign/cli/import_key_pair.go index a966d66ffe2..7c5a017eed4 100644 --- a/cmd/cosign/cli/import_key_pair.go +++ b/cmd/cosign/cli/import_key_pair.go @@ -27,12 +27,12 @@ func ImportKeyPair() *cobra.Command { cmd := &cobra.Command{ Use: "import-key-pair", - Short: "Imports an RSA or EC key-pair.", - Long: "Imports an RSA or EC key-pair for signing.", - Example: ` cosign import-key-pair + Short: "Imports a PEM-encoded RSA or EC private key.", + Long: "Imports a PEM-encoded RSA or EC private key for signing.", + Example: ` cosign import-key-pair --key openssl.key - # import key-pair and write to import-cosign.key and import-cosign.pub files - cosign import-key-pair + # import PEM-encoded RSA or EC private key and write to import-cosign.key and import-cosign.pub files + cosign import-key-pair --key CAVEATS: This command interactively prompts for a password. You can use diff --git a/cmd/cosign/cli/importkeypair/import_key_pair.go b/cmd/cosign/cli/importkeypair/import_key_pair.go index d1819802a31..39c2ee88516 100644 --- a/cmd/cosign/cli/importkeypair/import_key_pair.go +++ b/cmd/cosign/cli/importkeypair/import_key_pair.go @@ -105,13 +105,13 @@ func getPassFromTerm(confirm bool) ([]byte, error) { } fmt.Fprintln(os.Stderr) fmt.Fprint(os.Stderr, "Enter password for private key again: ") - pw2, err := term.ReadPassword(0) + confirmpw, err := term.ReadPassword(0) fmt.Fprintln(os.Stderr) if err != nil { return nil, err } - if string(pw1) != string(pw2) { + if string(pw1) != string(confirmpw) { return nil, errors.New("passwords do not match") } return pw1, nil diff --git a/pkg/cosign/keys.go b/pkg/cosign/keys.go index b909ca0047d..8f2a352e906 100644 --- a/pkg/cosign/keys.go +++ b/pkg/cosign/keys.go @@ -71,9 +71,6 @@ func ImportKeyPair(keyPath string, pf PassFunc) (*Keys, error) { if p == nil { return nil, errors.New("invalid pem block") } - if p.Type != RSAPrivateKeyPemType && p.Type != ECPrivateKeyPemType { - return nil, fmt.Errorf("unsupported pem type: %s", p.Type) - } if p.Type == RSAPrivateKeyPemType { pk, err := x509.ParsePKCS1PrivateKey(p.Bytes) @@ -81,13 +78,15 @@ func ImportKeyPair(keyPath string, pf PassFunc) (*Keys, error) { return nil, fmt.Errorf("parsing error") } return MarshallKeyPair(Key{pk, pk.Public()}, pf) - } else { + } else if p.Type == ECPrivateKeyPemType { pk, err := x509.ParseECPrivateKey(p.Bytes) if err != nil { return nil, fmt.Errorf("parsing error") } return MarshallKeyPair(Key{pk, pk.Public()}, pf) + } else { + return nil, fmt.Errorf("unsupported pem type: %s", p.Type) } } @@ -202,61 +201,12 @@ func LoadPrivateKey(key []byte, pass []byte) (signature.SignerVerifier, error) { if err != nil { return nil, errors.Wrap(err, "parsing private key") } - switch pk.(type) { + switch pk := pk.(type) { case *rsa.PrivateKey: - return LoadRSAPrivateKey(key, pass) + return signature.LoadRSAPKCS1v15SignerVerifier(pk, crypto.SHA256) case *ecdsa.PrivateKey: - return LoadECDSAPrivateKey(key, pass) - } - return nil, errors.Wrap(err, "loading private key") -} - -func LoadECDSAPrivateKey(key []byte, pass []byte) (*signature.ECDSASignerVerifier, error) { - // Decrypt first - p, _ := pem.Decode(key) - if p == nil { - return nil, errors.New("invalid pem block") - } - if p.Type != PrivateKeyPemType { - return nil, fmt.Errorf("unsupported pem type: %s", p.Type) - } - - x509Encoded, err := encrypted.Decrypt(p.Bytes, pass) - if err != nil { - return nil, errors.Wrap(err, "decrypt") - } - - pk, err := x509.ParsePKCS8PrivateKey(x509Encoded) - if err != nil { - return nil, errors.Wrap(err, "parsing private key") + return signature.LoadECDSASignerVerifier(pk, crypto.SHA256) + default: + return nil, errors.Wrap(err, "unsupported key type") } - epk, ok := pk.(*ecdsa.PrivateKey) - if !ok { - return nil, errors.New("invalid private key") - } - return signature.LoadECDSASignerVerifier(epk, crypto.SHA256) -} - -func LoadRSAPrivateKey(key []byte, pass []byte) (*signature.RSAPKCS1v15SignerVerifier, error) { - // Decrypt first - p, _ := pem.Decode(key) - if p == nil { - return nil, errors.New("invalid pem block") - } - if p.Type != PrivateKeyPemType { - return nil, fmt.Errorf("unsupported pem type: %s", p.Type) - } - - x509Encoded, err := encrypted.Decrypt(p.Bytes, pass) - if err != nil { - return nil, errors.Wrap(err, "decrypt") - } - - pk, err := x509.ParsePKCS8PrivateKey(x509Encoded) - - if err != nil { - return nil, errors.Wrap(err, "parsing private key") - } - - return signature.LoadRSAPKCS1v15SignerVerifier(pk.(*rsa.PrivateKey), crypto.SHA256) } diff --git a/pkg/cosign/keys_test.go b/pkg/cosign/keys_test.go index e85d5e61730..369b5adf4d8 100644 --- a/pkg/cosign/keys_test.go +++ b/pkg/cosign/keys_test.go @@ -34,12 +34,12 @@ func TestLoadECDSAPrivateKey(t *testing.T) { } // Load the private key with the right password - if _, err := LoadECDSAPrivateKey(keys.PrivateBytes, []byte("hello")); err != nil { + if _, err := LoadPrivateKey(keys.PrivateBytes, []byte("hello")); err != nil { t.Errorf("unexpected error decrypting key: %s", err) } // Try it with the wrong one - if _, err := LoadECDSAPrivateKey(keys.PrivateBytes, []byte("wrong")); err == nil { + if _, err := LoadPrivateKey(keys.PrivateBytes, []byte("wrong")); err == nil { t.Error("expected error decrypting key!") } @@ -48,7 +48,7 @@ func TestLoadECDSAPrivateKey(t *testing.T) { if _, err := rand.Read(buf[:]); err != nil { t.Fatal(err) } - if _, err := LoadECDSAPrivateKey(buf[:], []byte("wrong")); err == nil { + if _, err := LoadPrivateKey(buf[:], []byte("wrong")); err == nil { t.Error("expected error decrypting key!") } } diff --git a/pkg/signature/keys.go b/pkg/signature/keys.go index 768286782fe..3d864aff393 100644 --- a/pkg/signature/keys.go +++ b/pkg/signature/keys.go @@ -117,7 +117,7 @@ func SignerVerifierFromKeyRef(ctx context.Context, keyRef string, pf cosign.Pass } if len(s.Data) > 0 { - return cosign.LoadECDSAPrivateKey(s.Data["cosign.key"], s.Data["cosign.password"]) + return cosign.LoadPrivateKey(s.Data["cosign.key"], s.Data["cosign.password"]) } case strings.HasPrefix(keyRef, gitlab.ReferenceScheme): split := strings.Split(keyRef, "://") @@ -138,7 +138,7 @@ func SignerVerifierFromKeyRef(ctx context.Context, keyRef string, pf cosign.Pass return nil, err } - return cosign.LoadECDSAPrivateKey([]byte(pk), []byte(pass)) + return cosign.LoadPrivateKey([]byte(pk), []byte(pass)) default: } diff --git a/test/import_test.sh b/test/import_test.sh new file mode 100755 index 00000000000..7634cecab62 --- /dev/null +++ b/test/import_test.sh @@ -0,0 +1,115 @@ +#!/bin/bash +# +# Copyright 2021 The Sigstore Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -ex + +RSAPRIVKEY="-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAx5piWVlE62NnZ0UzJ8Z6oKiKOC4dbOZ1HsNhIRtqkM+Oq4G+ +25yq6P+0JU/Qvr9veOGEb3R/J9u8JBo+hv2i5X8OtgvP2V2pi6f1s6vK7L0+6uRb +4YTT/UdMshaVf97MgEqbq41Jf/cuvh+3AV0tZ1BpixZg4aXMKpY6HUP69lbsu27o +SUN1myMv7TSgZiV4CYs3l/gkEfpysBptWlcHRuw5RsB+C0RbjRtbJ/5VxmE/vd3M +lafd5t1WSpMb8yf0a84u5NFaXwZ7CweMfXeOddS0yb19ShSuW3PPRadruBM1mq15 +js9GfagPxDS75Imcs+fA62lWvHxEujTGjYHxawIDAQABAoIBAH+sgLwmHa9zJfEo +klAe5NFe/QpydN/ziXbkAnzqzH9URC3wD+TpkWj4JoK3Sw635NWtasjf+3XDV9S/ +9L7j/g5N91r6sziWcJykEsWaXXKQmm4lI6BdFjwsHyLKz1W7bZOiJXDWLu1rbrqu +DqEQuLoc9WXCKrYrFy0maoXNtfla/1p05kKN0bMigcnnyAQ+xBTwoyco4tkIz5se +IYxorz7qzXrkHQI+knz5BawmNe3ekoSaXUPoLoOR7TRTGsLteL5yukvWAi8S/0rE +gftC+PZCQpoQhSUYq7wXe7RowJ1f+kXb7HsSedOTfTSW1D/pUb/uW+CcRKig42ZI +I9H9TAECgYEA5XGBML6fJyWVqx64sHbUAjQsmQ0RwU6Zo7sqHIEPf6tYVYp7KtzK +KOfi8seOOL5FSy4pjCo11Dzyrh9bn45RNmtjSYTgOnVPSoCfuRNfOcpG+/wCHjYf +EjDvdrCpbg59kVUeaMeBDiyWAlM48HJAn8O7ez2U/iKQCyJmOIwFhSkCgYEA3rSz +Fi1NzqYWxWos4NBmg8iKcQ9SMkmPdgRLAs/WNnZJ8fdgJZwihevkXGytRGJEmav2 +GMKRx1g6ey8fjXTQH9WM8X/kJC5fv8wLHnUCH/K3Mcp9CYwn7PFvSnBr4kQoc/el +bURhcF1+/opEC8vNX/Wk3zAG7Xs1PREXlH2SIHMCgYBV/3kgwBH/JkM25EjtO1yz +hsLAivmAruk/SUO7c1RP0fVF+qW3pxHOyztxLALOmeJ3D1JbSubqKf377Zz17O3b +q9yHDdrNjnKtxhAX2n7ytjJs+EQC9t4mf1kB761RpvTBqFnBhCWHHocLUA4jcW9v +cnmu86IIrwO2aKpPv4vCIQKBgHU9gY3qOazRSOmSlJ+hdmZn+2G7pBTvHsQNTIPl +cCrpqNHl3crO4GnKHkT9vVVjuiOAIKU2QNJFwzu4Og8Y8LvhizpTjoHxm9x3iV72 +UDELcJ+YrqyJCTe2flUcy96o7Pbn50GXnwgtYD6WAW6IUszyn2ITgYIhu4wzZEt6 +s6O7AoGAPTKbRA87L34LMlXyUBJma+etMARIP1zu8bXJ7hSJeMcog8zaLczN7ruT +pGAaLxggvtvuncMuTrG+cdmsR9SafSFKRS92NCxhOUonQ+NP6mLskIGzJZoQ5JvQ +qGzRVIDGbNkrVHM0IsAtHRpC0rYrtZY+9OwiraGcsqUMLwwQdCA= +-----END RSA PRIVATE KEY-----" + +INVALID_RSAPRIVKEY1="-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx5piWVlE62NnZ0UzJ8Z6 +oKiKOC4dbOZ1HsNhIRtqkM+Oq4G+25yq6P+0JU/Qvr9veOGEb3R/J9u8JBo+hv2i +5X8OtgvP2V2pi6f1s6vK7L0+6uRb4YTT/UdMshaVf97MgEqbq41Jf/cuvh+3AV0t +Z1BpixZg4aXMKpY6HUP69lbsu27oSUN1myMv7TSgZiV4CYs3l/gkEfpysBptWlcH +Ruw5RsB+C0RbjRtbJ/5VxmE/vd3Mlafd5t1WSpMb8yf0a84u5NFaXwZ7CweMfXeO +ddS0yb19ShSuW3PPRadruBM1mq15js9GfagPxDS75Imcs+fA62lWvHxEujTGjYHx +awIDAQAB +-----END PUBLIC KEY-----" + +INVALID_RSAPRIVKEY2="-----BEGIN PGP PRIVATE KEY BLOCK----- +Version: BCPG C# v1.6.1.0 + +lQOsBGGTOVkBCACbhVqCN55SElw1rZxI9LQDf91sU5FmrSybGh5r1xGV8rOhpKe+ +eGirYVY3KeI6XUdZoJEIRtXtd6IJWn3msFRgO/MwkUQ4CibORSXPjCwHnseJmh5D +axgZbXpzjP90fW03R+sBqm2AvrUANaWIKIXk8bWWdK5yUhB7TubIxpOZKg/nLlIE +1j6+XdCWIfo56z0mpJWRASzZRGuncfvkHRz73YfA00FpflQykiUDi6+vDV7KTh49 +7nkivRwyx5JcsAT3W1MCXNjCEXsdmdtNah3mN7SMbzSh3RF+IMaonxT4KM5nmEj/ +wGKJ4xUPtKy7kgIPYP+LMOj7j1qCsndYWILzABEBAAH/AwMC5uUvFLMg8b9gVFGU +B1Ak38tCEBPtON9gSIxg9HX80WyMI8/MdfaisEsnFvy4X3UolhTlFJ9v3aqK1Zc8 +JSkEw7cgY0NmFWDr6k8y8LhLN1ATjnKr9J9jzr8G9XvQfgaFbtcuFOF35ylQdeoL +IKKa8GqrXL75rolg+p/OSw52n/7fb17fDXLNyeGQ0g8wjIVTv+7vuvr9Z0kxfIgG +Y9oGIV/SeJvXjoWZWG3GbpTXx+ktmtwCY+tAlxJUt23OwWRfsnC9rS2DAsnJLlG2 +r3Exfl80MUza1sQ/7u1svcHbFuZZOrJ1S9OjRQAWMsfQHFcav34Yrbb3aFweXLjs +iT9BJOMR4W/nyXvKAnMt/6vHKfO6kbxCtDFstH5qZAKbSceWX1Y6UaGimHXCnTYi +tlUMRNWlf6fFLdYBrRCh+MpLs5tSLc6NAYaQXTe3dJrjTRyzkxzYxeE/Y6Mii8KR +gF3Fu5OwkJ39jKdWZf17i/LUofgQHzW4ymuDMWcrqX1kZXPjD6WN8c8NmNCGvlsT +n1V6jPGb8tORIn8+CX+mCyJcxLpbG3ke90DIPnMol7WJ+3xV7J9peJqp0fY4jkmF +I96EUhY1HTZcy4SnhiPwKb8NDpdqwFx1qwytf7eM+65Cf+rj9Nh6ShVOjIfOT9gh +zEp0W0SFTU7p5af9ULnONCJABvRB8Gneosc6iwVclgHhTJcUzILRqNjcrJQu1j1v +oK9Ls+VANww4zEOqx8g+T/P4pHmGTIYTDErzyDmBw8aFD7fDl+kPUtanqC1oTvnJ +qZvoJ3JJ9Z2edW7Ulc1+BhnB8Cfs/jEJQHCngciUjW8yLUcVKdmFKkd9cajhoeQz +bJp6/t9dRUVXo2ulZzvdN93TWV66rTxHQAI4OBZKqbQLYm9iQGJvYi5jb22JARwE +EAECAAYFAmGTOVkACgkQSL3lExF3kQq7swf+Ndhd9iogkofT9ihMuMksoSDituN+ +7hZY5zCj0UzCS8o2vHU+XJCRCpRlOc7gxl+44S60YmwqKtTjT5eqXCXrqa1XTyZz +xYpRfRjwnS6coQbdREQUvIgKapHII+b5gmnNhVX8niO11KyUHc29RWRiLFvMMcYO +urG06WshDewpqrBdq0MYBSSWO7myQLR5xEW6ld6CKkU0153LHgVdlGVIzrLM7sRo +NoHsidPbBIYv+aQxSVHxdKpFEpCHi9vckLSew+8LG5sDA/X3G4l9P3c1KusXP248 +hfOiWo/4tMCN8XJpe0L+99ubcnHjQR7C8htFB4DnIA8KhMBSDdF/Vgp97g== +=8+cN +-----END PGP PRIVATE KEY BLOCK-----" + +ECPRIVKEY="-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIIGhcmCI5F7BPMH4r3pWCpQdAsveErdU5DjvVQerErJuoAoGCCqGSM49 +AwEHoUQDQgAE+9E3Qe+h25ofmz3Uo2T004Dfy49iX06MMbxf9rsGmLkOPrS0KYDl +1QMfFuSbrtf8wTWNT9HNxrW/Foz39mDhHw== +-----END EC PRIVATE KEY-----" + +ED25519PRIVKEY="-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEIALEbo1EFnWFqBK/wC+hhypG/8hXEerwdNetAoFoFVdv +-----END PRIVATE KEY-----" + +#Test importing valid RSA PEM +./../cosign import-key-pair --key <(echo "$RSAPRIVKEY") + +#Test importing an invalid RSA PEM +#Expected output: invalid pem block +./../cosign import-key-pair --key <(echo "$INVALID_RSAPRVKEY1") +./../cosign import-key-pair --key <(echo "$INVALID_RSAPRVKEY2") + +#Test importing valid EC PEM +./../cosign import-key-pair --key <(echo "$ECPRIVKEY") + +#Test importing an Ed25519 key generated using OpenSSL 1.1 +#Expected output: parsing error +./../cosign import-key-pair --key <(echo "$ED25519PRIVKEY") + +#Test signing container with imported keypair: +./../cosign sign --key import-cosign.key dlorenc/demo From db13da252728057ceaca6643895141be0fe9e337 Mon Sep 17 00:00:00 2001 From: Ivan Wallis Date: Tue, 16 Nov 2021 22:13:58 -0800 Subject: [PATCH 06/14] fixes and added more tests Signed-off-by: Ivan Wallis --- pkg/cosign/keys.go | 58 ++++---------- pkg/cosign/keys_test.go | 109 +++++++++++++++++++++++++++ pkg/cosign/kubernetes/secret.go | 2 +- pkg/cosign/kubernetes/secret_test.go | 4 +- test/e2e_test.go | 97 +++++++++++++++++++++++- 5 files changed, 221 insertions(+), 49 deletions(-) diff --git a/pkg/cosign/keys.go b/pkg/cosign/keys.go index 8f2a352e906..5c1487141b8 100644 --- a/pkg/cosign/keys.go +++ b/pkg/cosign/keys.go @@ -45,12 +45,12 @@ const ( type PassFunc func(bool) ([]byte, error) -type Key struct { +type Keys struct { private crypto.PrivateKey public crypto.PublicKey } -type Keys struct { +type KeysBytes struct { PrivateBytes []byte PublicBytes []byte password []byte @@ -60,7 +60,7 @@ func GeneratePrivateKey() (*ecdsa.PrivateKey, error) { return ecdsa.GenerateKey(elliptic.P256(), rand.Reader) } -func ImportKeyPair(keyPath string, pf PassFunc) (*Keys, error) { +func ImportKeyPair(keyPath string, pf PassFunc) (*KeysBytes, error) { kb, err := os.ReadFile(filepath.Clean(keyPath)) if err != nil { @@ -72,26 +72,25 @@ func ImportKeyPair(keyPath string, pf PassFunc) (*Keys, error) { return nil, errors.New("invalid pem block") } - if p.Type == RSAPrivateKeyPemType { + switch p.Type { + + case RSAPrivateKeyPemType: pk, err := x509.ParsePKCS1PrivateKey(p.Bytes) if err != nil { return nil, fmt.Errorf("parsing error") } - return MarshallKeyPair(Key{pk, pk.Public()}, pf) - } else if p.Type == ECPrivateKeyPemType { - + return marshalKeyPair(Keys{pk, pk.Public()}, pf) + default: pk, err := x509.ParseECPrivateKey(p.Bytes) if err != nil { return nil, fmt.Errorf("parsing error") } - return MarshallKeyPair(Key{pk, pk.Public()}, pf) - } else { - return nil, fmt.Errorf("unsupported pem type: %s", p.Type) + return marshalKeyPair(Keys{pk, pk.Public()}, pf) } } -func MarshallKeyPair(keypair Key, pf PassFunc) (*Keys, error) { +func marshalKeyPair(keypair Keys, pf PassFunc) (*KeysBytes, error) { x509Encoded, err := x509.MarshalPKCS8PrivateKey(keypair.private) if err != nil { @@ -120,52 +119,23 @@ func MarshallKeyPair(keypair Key, pf PassFunc) (*Keys, error) { return nil, err } - return &Keys{ + return &KeysBytes{ PrivateBytes: privBytes, PublicBytes: pubBytes, password: password, }, nil } -func GenerateKeyPair(pf PassFunc) (*Keys, error) { +func GenerateKeyPair(pf PassFunc) (*KeysBytes, error) { priv, err := GeneratePrivateKey() if err != nil { return nil, err } - x509Encoded, err := x509.MarshalPKCS8PrivateKey(priv) - if err != nil { - return nil, errors.Wrap(err, "x509 encoding private key") - } - // Encrypt the private key and store it. - password, err := pf(true) - if err != nil { - return nil, err - } - encBytes, err := encrypted.Encrypt(x509Encoded, password) - if err != nil { - return nil, err - } - // store in PEM format - privBytes := pem.EncodeToMemory(&pem.Block{ - Bytes: encBytes, - Type: PrivateKeyPemType, - }) - - // Now do the public key - pubBytes, err := cryptoutils.MarshalPublicKeyToPEM(&priv.PublicKey) - if err != nil { - return nil, err - } - - return &Keys{ - PrivateBytes: privBytes, - PublicBytes: pubBytes, - password: password, - }, nil + return marshalKeyPair(Keys{priv, priv.Public()}, pf) } -func (k *Keys) Password() []byte { +func (k *KeysBytes) Password() []byte { return k.password } diff --git a/pkg/cosign/keys_test.go b/pkg/cosign/keys_test.go index 369b5adf4d8..feb999b34d2 100644 --- a/pkg/cosign/keys_test.go +++ b/pkg/cosign/keys_test.go @@ -17,9 +17,90 @@ package cosign import ( "crypto/rand" + "os" "testing" ) +const validrsa1 = `-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAx5piWVlE62NnZ0UzJ8Z6oKiKOC4dbOZ1HsNhIRtqkM+Oq4G+ +25yq6P+0JU/Qvr9veOGEb3R/J9u8JBo+hv2i5X8OtgvP2V2pi6f1s6vK7L0+6uRb +4YTT/UdMshaVf97MgEqbq41Jf/cuvh+3AV0tZ1BpixZg4aXMKpY6HUP69lbsu27o +SUN1myMv7TSgZiV4CYs3l/gkEfpysBptWlcHRuw5RsB+C0RbjRtbJ/5VxmE/vd3M +lafd5t1WSpMb8yf0a84u5NFaXwZ7CweMfXeOddS0yb19ShSuW3PPRadruBM1mq15 +js9GfagPxDS75Imcs+fA62lWvHxEujTGjYHxawIDAQABAoIBAH+sgLwmHa9zJfEo +klAe5NFe/QpydN/ziXbkAnzqzH9URC3wD+TpkWj4JoK3Sw635NWtasjf+3XDV9S/ +9L7j/g5N91r6sziWcJykEsWaXXKQmm4lI6BdFjwsHyLKz1W7bZOiJXDWLu1rbrqu +DqEQuLoc9WXCKrYrFy0maoXNtfla/1p05kKN0bMigcnnyAQ+xBTwoyco4tkIz5se +IYxorz7qzXrkHQI+knz5BawmNe3ekoSaXUPoLoOR7TRTGsLteL5yukvWAi8S/0rE +gftC+PZCQpoQhSUYq7wXe7RowJ1f+kXb7HsSedOTfTSW1D/pUb/uW+CcRKig42ZI +I9H9TAECgYEA5XGBML6fJyWVqx64sHbUAjQsmQ0RwU6Zo7sqHIEPf6tYVYp7KtzK +KOfi8seOOL5FSy4pjCo11Dzyrh9bn45RNmtjSYTgOnVPSoCfuRNfOcpG+/wCHjYf +EjDvdrCpbg59kVUeaMeBDiyWAlM48HJAn8O7ez2U/iKQCyJmOIwFhSkCgYEA3rSz +Fi1NzqYWxWos4NBmg8iKcQ9SMkmPdgRLAs/WNnZJ8fdgJZwihevkXGytRGJEmav2 +GMKRx1g6ey8fjXTQH9WM8X/kJC5fv8wLHnUCH/K3Mcp9CYwn7PFvSnBr4kQoc/el +bURhcF1+/opEC8vNX/Wk3zAG7Xs1PREXlH2SIHMCgYBV/3kgwBH/JkM25EjtO1yz +hsLAivmAruk/SUO7c1RP0fVF+qW3pxHOyztxLALOmeJ3D1JbSubqKf377Zz17O3b +q9yHDdrNjnKtxhAX2n7ytjJs+EQC9t4mf1kB761RpvTBqFnBhCWHHocLUA4jcW9v +cnmu86IIrwO2aKpPv4vCIQKBgHU9gY3qOazRSOmSlJ+hdmZn+2G7pBTvHsQNTIPl +cCrpqNHl3crO4GnKHkT9vVVjuiOAIKU2QNJFwzu4Og8Y8LvhizpTjoHxm9x3iV72 +UDELcJ+YrqyJCTe2flUcy96o7Pbn50GXnwgtYD6WAW6IUszyn2ITgYIhu4wzZEt6 +s6O7AoGAPTKbRA87L34LMlXyUBJma+etMARIP1zu8bXJ7hSJeMcog8zaLczN7ruT +pGAaLxggvtvuncMuTrG+cdmsR9SafSFKRS92NCxhOUonQ+NP6mLskIGzJZoQ5JvQ +qGzRVIDGbNkrVHM0IsAtHRpC0rYrtZY+9OwiraGcsqUMLwwQdCA= +-----END RSA PRIVATE KEY-----` + +const invalidrsa2 = `-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx5piWVlE62NnZ0UzJ8Z6 +oKiKOC4dbOZ1HsNhIRtqkM+Oq4G+25yq6P+0JU/Qvr9veOGEb3R/J9u8JBo+hv2i +5X8OtgvP2V2pi6f1s6vK7L0+6uRb4YTT/UdMshaVf97MgEqbq41Jf/cuvh+3AV0t +Z1BpixZg4aXMKpY6HUP69lbsu27oSUN1myMv7TSgZiV4CYs3l/gkEfpysBptWlcH +Ruw5RsB+C0RbjRtbJ/5VxmE/vd3Mlafd5t1WSpMb8yf0a84u5NFaXwZ7CweMfXeO +ddS0yb19ShSuW3PPRadruBM1mq15js9GfagPxDS75Imcs+fA62lWvHxEujTGjYHx +awIDAQAB +-----END PUBLIC KEY-----` + +const invalidkey = `-----BEGIN PGP PRIVATE KEY BLOCK----- +Version: BCPG C# v1.6.1.0 + +lQOsBGGTOVkBCACbhVqCN55SElw1rZxI9LQDf91sU5FmrSybGh5r1xGV8rOhpKe+ +eGirYVY3KeI6XUdZoJEIRtXtd6IJWn3msFRgO/MwkUQ4CibORSXPjCwHnseJmh5D +axgZbXpzjP90fW03R+sBqm2AvrUANaWIKIXk8bWWdK5yUhB7TubIxpOZKg/nLlIE +1j6+XdCWIfo56z0mpJWRASzZRGuncfvkHRz73YfA00FpflQykiUDi6+vDV7KTh49 +7nkivRwyx5JcsAT3W1MCXNjCEXsdmdtNah3mN7SMbzSh3RF+IMaonxT4KM5nmEj/ +wGKJ4xUPtKy7kgIPYP+LMOj7j1qCsndYWILzABEBAAH/AwMC5uUvFLMg8b9gVFGU +B1Ak38tCEBPtON9gSIxg9HX80WyMI8/MdfaisEsnFvy4X3UolhTlFJ9v3aqK1Zc8 +JSkEw7cgY0NmFWDr6k8y8LhLN1ATjnKr9J9jzr8G9XvQfgaFbtcuFOF35ylQdeoL +IKKa8GqrXL75rolg+p/OSw52n/7fb17fDXLNyeGQ0g8wjIVTv+7vuvr9Z0kxfIgG +Y9oGIV/SeJvXjoWZWG3GbpTXx+ktmtwCY+tAlxJUt23OwWRfsnC9rS2DAsnJLlG2 +r3Exfl80MUza1sQ/7u1svcHbFuZZOrJ1S9OjRQAWMsfQHFcav34Yrbb3aFweXLjs +iT9BJOMR4W/nyXvKAnMt/6vHKfO6kbxCtDFstH5qZAKbSceWX1Y6UaGimHXCnTYi +tlUMRNWlf6fFLdYBrRCh+MpLs5tSLc6NAYaQXTe3dJrjTRyzkxzYxeE/Y6Mii8KR +gF3Fu5OwkJ39jKdWZf17i/LUofgQHzW4ymuDMWcrqX1kZXPjD6WN8c8NmNCGvlsT +n1V6jPGb8tORIn8+CX+mCyJcxLpbG3ke90DIPnMol7WJ+3xV7J9peJqp0fY4jkmF +I96EUhY1HTZcy4SnhiPwKb8NDpdqwFx1qwytf7eM+65Cf+rj9Nh6ShVOjIfOT9gh +zEp0W0SFTU7p5af9ULnONCJABvRB8Gneosc6iwVclgHhTJcUzILRqNjcrJQu1j1v +oK9Ls+VANww4zEOqx8g+T/P4pHmGTIYTDErzyDmBw8aFD7fDl+kPUtanqC1oTvnJ +qZvoJ3JJ9Z2edW7Ulc1+BhnB8Cfs/jEJQHCngciUjW8yLUcVKdmFKkd9cajhoeQz +bJp6/t9dRUVXo2ulZzvdN93TWV66rTxHQAI4OBZKqbQLYm9iQGJvYi5jb22JARwE +EAECAAYFAmGTOVkACgkQSL3lExF3kQq7swf+Ndhd9iogkofT9ihMuMksoSDituN+ +7hZY5zCj0UzCS8o2vHU+XJCRCpRlOc7gxl+44S60YmwqKtTjT5eqXCXrqa1XTyZz +xYpRfRjwnS6coQbdREQUvIgKapHII+b5gmnNhVX8niO11KyUHc29RWRiLFvMMcYO +urG06WshDewpqrBdq0MYBSSWO7myQLR5xEW6ld6CKkU0153LHgVdlGVIzrLM7sRo +NoHsidPbBIYv+aQxSVHxdKpFEpCHi9vckLSew+8LG5sDA/X3G4l9P3c1KusXP248 +hfOiWo/4tMCN8XJpe0L+99ubcnHjQR7C8htFB4DnIA8KhMBSDdF/Vgp97g== +=8+cN +-----END PGP PRIVATE KEY BLOCK-----` + +const validec = `-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIIGhcmCI5F7BPMH4r3pWCpQdAsveErdU5DjvVQerErJuoAoGCCqGSM49 +AwEHoUQDQgAE+9E3Qe+h25ofmz3Uo2T004Dfy49iX06MMbxf9rsGmLkOPrS0KYDl +1QMfFuSbrtf8wTWNT9HNxrW/Foz39mDhHw== +-----END EC PRIVATE KEY-----` + +const ed25519key = `-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEIALEbo1EFnWFqBK/wC+hhypG/8hXEerwdNetAoFoFVdv +-----END PRIVATE KEY-----` + func pass(s string) PassFunc { return func(_ bool) ([]byte, error) { return []byte(s), nil @@ -52,3 +133,31 @@ func TestLoadECDSAPrivateKey(t *testing.T) { t.Error("expected error decrypting key!") } } + +func TestImportPrivateKey(t *testing.T) { + + err := os.WriteFile("validrsa1.key", []byte(validrsa1), 0600) + if err != nil { + t.Fatal(err) + } + + _, err = ImportKeyPair("validrsa1.key", pass("hello")) + if err != nil { + t.Errorf("unexpected error importing key: %s", err) + } + + os.Remove("validrsa1.key") + + err = os.WriteFile("ed25519.key", []byte(ed25519key), 0600) + if err != nil { + t.Fatal(err) + } + + _, err = ImportKeyPair("ed25519.key", pass("hello")) + if err != nil { + t.Errorf("unexpected error importing key: %s", err) + } + + os.Remove("ed25519.key") + +} diff --git a/pkg/cosign/kubernetes/secret.go b/pkg/cosign/kubernetes/secret.go index 04215b17c6a..7f6f843c61f 100644 --- a/pkg/cosign/kubernetes/secret.go +++ b/pkg/cosign/kubernetes/secret.go @@ -96,7 +96,7 @@ func KeyPairSecret(ctx context.Context, k8sRef string, pf cosign.PassFunc) error // * cosign.key // * cosign.pub // * cosign.password -func secret(keys *cosign.Keys, namespace, name string, data map[string][]byte) *v1.Secret { +func secret(keys *cosign.KeysBytes, namespace, name string, data map[string][]byte) *v1.Secret { if data == nil { data = map[string][]byte{} } diff --git a/pkg/cosign/kubernetes/secret_test.go b/pkg/cosign/kubernetes/secret_test.go index 900a7233346..5da4d80dd6d 100644 --- a/pkg/cosign/kubernetes/secret_test.go +++ b/pkg/cosign/kubernetes/secret_test.go @@ -25,7 +25,7 @@ import ( ) func TestSecret(t *testing.T) { - keys := &cosign.Keys{ + keys := &cosign.KeysBytes{ PrivateBytes: []byte("private"), PublicBytes: []byte("public"), } @@ -49,7 +49,7 @@ func TestSecret(t *testing.T) { } func TestSecretUpdate(t *testing.T) { - keys := &cosign.Keys{ + keys := &cosign.KeysBytes{ PrivateBytes: []byte("private"), PublicBytes: []byte("public"), } diff --git a/test/e2e_test.go b/test/e2e_test.go index 38ec1917dc2..997b916e61d 100644 --- a/test/e2e_test.go +++ b/test/e2e_test.go @@ -153,6 +153,35 @@ func TestSignVerifyClean(t *testing.T) { mustErr(verify(pubKeyPath, imgName, true, nil, ""), t) } +func TestImportSignVerifyClean(t *testing.T) { + + repo, stop := reg(t) + defer stop() + td := t.TempDir() + + imgName := path.Join(repo, "cosign-e2e") + + _, _, _ = mkimage(t, imgName) + + _, privKeyPath, pubKeyPath := importKeyPair(t, td) + + ctx := context.Background() + + // Now sign the image + ko := sign.KeyOpts{KeyRef: privKeyPath, PassFunc: passFunc} + must(sign.SignCmd(ctx, ko, options.RegistryOptions{}, nil, []string{imgName}, "", true, "", false, false, ""), t) + + // Now verify and download should work! + must(verify(pubKeyPath, imgName, true, nil, ""), t) + must(download.SignatureCmd(ctx, options.RegistryOptions{}, imgName), t) + + // Now clean signature from the given image + must(cli.CleanCmd(ctx, options.RegistryOptions{}, imgName), t) + + // It doesn't work + mustErr(verify(pubKeyPath, imgName, true, nil, ""), t) +} + func TestAttestVerify(t *testing.T) { repo, stop := reg(t) defer stop() @@ -299,7 +328,7 @@ func TestGenerateKeyPairEnvVar(t *testing.T) { if err != nil { t.Fatal(err) } - if _, err := cosign.LoadECDSAPrivateKey(keys.PrivateBytes, []byte("foo")); err != nil { + if _, err := cosign.LoadPrivateKey(keys.PrivateBytes, []byte("foo")); err != nil { t.Fatal(err) } } @@ -444,7 +473,7 @@ func TestGenerate(t *testing.T) { equals(ss.Optional["foo"], "bar", t) } -func keypair(t *testing.T, td string) (*cosign.Keys, string, string) { +func keypair(t *testing.T, td string) (*cosign.KeysBytes, string, string) { wd, err := os.Getwd() if err != nil { t.Fatal(err) @@ -472,6 +501,70 @@ func keypair(t *testing.T, td string) (*cosign.Keys, string, string) { return keys, privKeyPath, pubKeyPath } +func importKeyPair(t *testing.T, td string) (*cosign.KeysBytes, string, string) { + + const validrsa1 = `-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAx5piWVlE62NnZ0UzJ8Z6oKiKOC4dbOZ1HsNhIRtqkM+Oq4G+ +25yq6P+0JU/Qvr9veOGEb3R/J9u8JBo+hv2i5X8OtgvP2V2pi6f1s6vK7L0+6uRb +4YTT/UdMshaVf97MgEqbq41Jf/cuvh+3AV0tZ1BpixZg4aXMKpY6HUP69lbsu27o +SUN1myMv7TSgZiV4CYs3l/gkEfpysBptWlcHRuw5RsB+C0RbjRtbJ/5VxmE/vd3M +lafd5t1WSpMb8yf0a84u5NFaXwZ7CweMfXeOddS0yb19ShSuW3PPRadruBM1mq15 +js9GfagPxDS75Imcs+fA62lWvHxEujTGjYHxawIDAQABAoIBAH+sgLwmHa9zJfEo +klAe5NFe/QpydN/ziXbkAnzqzH9URC3wD+TpkWj4JoK3Sw635NWtasjf+3XDV9S/ +9L7j/g5N91r6sziWcJykEsWaXXKQmm4lI6BdFjwsHyLKz1W7bZOiJXDWLu1rbrqu +DqEQuLoc9WXCKrYrFy0maoXNtfla/1p05kKN0bMigcnnyAQ+xBTwoyco4tkIz5se +IYxorz7qzXrkHQI+knz5BawmNe3ekoSaXUPoLoOR7TRTGsLteL5yukvWAi8S/0rE +gftC+PZCQpoQhSUYq7wXe7RowJ1f+kXb7HsSedOTfTSW1D/pUb/uW+CcRKig42ZI +I9H9TAECgYEA5XGBML6fJyWVqx64sHbUAjQsmQ0RwU6Zo7sqHIEPf6tYVYp7KtzK +KOfi8seOOL5FSy4pjCo11Dzyrh9bn45RNmtjSYTgOnVPSoCfuRNfOcpG+/wCHjYf +EjDvdrCpbg59kVUeaMeBDiyWAlM48HJAn8O7ez2U/iKQCyJmOIwFhSkCgYEA3rSz +Fi1NzqYWxWos4NBmg8iKcQ9SMkmPdgRLAs/WNnZJ8fdgJZwihevkXGytRGJEmav2 +GMKRx1g6ey8fjXTQH9WM8X/kJC5fv8wLHnUCH/K3Mcp9CYwn7PFvSnBr4kQoc/el +bURhcF1+/opEC8vNX/Wk3zAG7Xs1PREXlH2SIHMCgYBV/3kgwBH/JkM25EjtO1yz +hsLAivmAruk/SUO7c1RP0fVF+qW3pxHOyztxLALOmeJ3D1JbSubqKf377Zz17O3b +q9yHDdrNjnKtxhAX2n7ytjJs+EQC9t4mf1kB761RpvTBqFnBhCWHHocLUA4jcW9v +cnmu86IIrwO2aKpPv4vCIQKBgHU9gY3qOazRSOmSlJ+hdmZn+2G7pBTvHsQNTIPl +cCrpqNHl3crO4GnKHkT9vVVjuiOAIKU2QNJFwzu4Og8Y8LvhizpTjoHxm9x3iV72 +UDELcJ+YrqyJCTe2flUcy96o7Pbn50GXnwgtYD6WAW6IUszyn2ITgYIhu4wzZEt6 +s6O7AoGAPTKbRA87L34LMlXyUBJma+etMARIP1zu8bXJ7hSJeMcog8zaLczN7ruT +pGAaLxggvtvuncMuTrG+cdmsR9SafSFKRS92NCxhOUonQ+NP6mLskIGzJZoQ5JvQ +qGzRVIDGbNkrVHM0IsAtHRpC0rYrtZY+9OwiraGcsqUMLwwQdCA= +-----END RSA PRIVATE KEY-----` + + wd, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + if err := os.Chdir(td); err != nil { + t.Fatal(err) + } + defer func() { + os.Chdir(wd) + }() + + err = os.WriteFile("/Users/iwallis-dev/validrsa1.key", []byte(validrsa1), 0600) + if err != nil { + t.Fatal(err) + } + + keys, err := cosign.ImportKeyPair("/Users/iwallis-dev/validrsa1.key", passFunc) + if err != nil { + t.Fatal(err) + } + + privKeyPath := filepath.Join(td, "import-cosign.key") + if err := os.WriteFile(privKeyPath, keys.PrivateBytes, 0600); err != nil { + t.Fatal(err) + } + + pubKeyPath := filepath.Join(td, "import-cosign.pub") + if err := os.WriteFile(pubKeyPath, keys.PublicBytes, 0600); err != nil { + t.Fatal(err) + } + return keys, privKeyPath, pubKeyPath + +} + func TestUploadDownload(t *testing.T) { repo, stop := reg(t) defer stop() From ddb2235e8cb17328d0538408b963a16c15c2a29b Mon Sep 17 00:00:00 2001 From: Ivan Wallis Date: Thu, 18 Nov 2021 17:22:54 -0800 Subject: [PATCH 07/14] fixes and test updates Signed-off-by: Ivan Wallis --- cmd/cosign/cli/generate/generate_key_pair.go | 2 + .../cli/importkeypair/import_key_pair.go | 2 + doc/cosign.md | 1 + doc/cosign_import-key-pair.md | 44 +++++++ pkg/cosign/keys.go | 4 - pkg/cosign/keys_test.go | 50 ++++++-- test/e2e_test.go | 4 +- test/import_test.sh | 115 ------------------ 8 files changed, 94 insertions(+), 128 deletions(-) create mode 100644 doc/cosign_import-key-pair.md delete mode 100755 test/import_test.sh diff --git a/cmd/cosign/cli/generate/generate_key_pair.go b/cmd/cosign/cli/generate/generate_key_pair.go index 086d1ead2dd..b432dd03593 100644 --- a/cmd/cosign/cli/generate/generate_key_pair.go +++ b/cmd/cosign/cli/generate/generate_key_pair.go @@ -141,6 +141,7 @@ func isTerminal() bool { return (stat.Mode() & os.ModeCharDevice) != 0 } +// TODO centralize password prompt logic for code reuse across more use cases -> https://github.com/sigstore/cosign/issues/1078 func getPassFromTerm(confirm bool) ([]byte, error) { fmt.Fprint(os.Stderr, "Enter password for private key: ") pw1, err := term.ReadPassword(0) @@ -164,6 +165,7 @@ func getPassFromTerm(confirm bool) ([]byte, error) { return pw1, nil } +// TODO need to centralize this logic func fileExists(filename string) bool { info, err := os.Stat(filename) if os.IsNotExist(err) { diff --git a/cmd/cosign/cli/importkeypair/import_key_pair.go b/cmd/cosign/cli/importkeypair/import_key_pair.go index 39c2ee88516..cc9fc7ba2c6 100644 --- a/cmd/cosign/cli/importkeypair/import_key_pair.go +++ b/cmd/cosign/cli/importkeypair/import_key_pair.go @@ -94,6 +94,7 @@ func isTerminal() bool { return (stat.Mode() & os.ModeCharDevice) != 0 } +// TODO centralize password prompt logic for code reuse across more use cases -> https://github.com/sigstore/cosign/issues/1078 func getPassFromTerm(confirm bool) ([]byte, error) { fmt.Fprint(os.Stderr, "Enter password for private key: ") pw1, err := term.ReadPassword(0) @@ -117,6 +118,7 @@ func getPassFromTerm(confirm bool) ([]byte, error) { return pw1, nil } +// TODO need to centralize this logic func fileExists(filename string) bool { info, err := os.Stat(filename) if os.IsNotExist(err) { diff --git a/doc/cosign.md b/doc/cosign.md index 1d270624151..b678804d952 100644 --- a/doc/cosign.md +++ b/doc/cosign.md @@ -23,6 +23,7 @@ cosign clean * [cosign download](cosign_download.md) - Provides utilities for downloading artifacts and attached artifacts in a registry * [cosign generate](cosign_generate.md) - Generates (unsigned) signature payloads from the supplied container image. * [cosign generate-key-pair](cosign_generate-key-pair.md) - Generates a key-pair. +* [cosign import-key-pair](cosign_import-key-pair.md) - Imports a PEM-encoded RSA or EC private key. * [cosign initialize](cosign_initialize.md) - Initializes SigStore root to retrieve trusted certificate and key targets for verification. * [cosign manifest](cosign_manifest.md) - Provides utilities for discovering images in and performing operations on Kubernetes manifests * [cosign piv-tool](cosign_piv-tool.md) - Provides utilities for managing a hardware token diff --git a/doc/cosign_import-key-pair.md b/doc/cosign_import-key-pair.md new file mode 100644 index 00000000000..a1ed70e7396 --- /dev/null +++ b/doc/cosign_import-key-pair.md @@ -0,0 +1,44 @@ +## cosign import-key-pair + +Imports a PEM-encoded RSA or EC private key. + +### Synopsis + +Imports a PEM-encoded RSA or EC private key for signing. + +``` +cosign import-key-pair [flags] +``` + +### Examples + +``` + cosign import-key-pair --key openssl.key + + # import PEM-encoded RSA or EC private key and write to import-cosign.key and import-cosign.pub files + cosign import-key-pair --key + +CAVEATS: + This command interactively prompts for a password. You can use + the COSIGN_PASSWORD environment variable to provide one. +``` + +### Options + +``` + -h, --help help for import-key-pair + --key string import key pair to use for signing +``` + +### Options inherited from parent commands + +``` + --azure-container-registry-config string Path to the file containing Azure container registry configuration information. + --output-file string log output to a file + -d, --verbose log debug output +``` + +### SEE ALSO + +* [cosign](cosign.md) - + diff --git a/pkg/cosign/keys.go b/pkg/cosign/keys.go index 5c1487141b8..4bd4c90d0e0 100644 --- a/pkg/cosign/keys.go +++ b/pkg/cosign/keys.go @@ -61,7 +61,6 @@ func GeneratePrivateKey() (*ecdsa.PrivateKey, error) { } func ImportKeyPair(keyPath string, pf PassFunc) (*KeysBytes, error) { - kb, err := os.ReadFile(filepath.Clean(keyPath)) if err != nil { return nil, err @@ -73,7 +72,6 @@ func ImportKeyPair(keyPath string, pf PassFunc) (*KeysBytes, error) { } switch p.Type { - case RSAPrivateKeyPemType: pk, err := x509.ParsePKCS1PrivateKey(p.Bytes) if err != nil { @@ -91,7 +89,6 @@ func ImportKeyPair(keyPath string, pf PassFunc) (*KeysBytes, error) { } func marshalKeyPair(keypair Keys, pf PassFunc) (*KeysBytes, error) { - x509Encoded, err := x509.MarshalPKCS8PrivateKey(keypair.private) if err != nil { return nil, errors.Wrap(err, "x509 encoding private key") @@ -152,7 +149,6 @@ func PemToECDSAKey(pemBytes []byte) (*ecdsa.PublicKey, error) { } func LoadPrivateKey(key []byte, pass []byte) (signature.SignerVerifier, error) { - // Decrypt first p, _ := pem.Decode(key) if p == nil { diff --git a/pkg/cosign/keys_test.go b/pkg/cosign/keys_test.go index feb999b34d2..4ffbe5b84a8 100644 --- a/pkg/cosign/keys_test.go +++ b/pkg/cosign/keys_test.go @@ -21,7 +21,7 @@ import ( "testing" ) -const validrsa1 = `-----BEGIN RSA PRIVATE KEY----- +const validrsa = `-----BEGIN RSA PRIVATE KEY----- MIIEogIBAAKCAQEAx5piWVlE62NnZ0UzJ8Z6oKiKOC4dbOZ1HsNhIRtqkM+Oq4G+ 25yq6P+0JU/Qvr9veOGEb3R/J9u8JBo+hv2i5X8OtgvP2V2pi6f1s6vK7L0+6uRb 4YTT/UdMshaVf97MgEqbq41Jf/cuvh+3AV0tZ1BpixZg4aXMKpY6HUP69lbsu27o @@ -49,7 +49,7 @@ pGAaLxggvtvuncMuTrG+cdmsR9SafSFKRS92NCxhOUonQ+NP6mLskIGzJZoQ5JvQ qGzRVIDGbNkrVHM0IsAtHRpC0rYrtZY+9OwiraGcsqUMLwwQdCA= -----END RSA PRIVATE KEY-----` -const invalidrsa2 = `-----BEGIN PUBLIC KEY----- +const invalidrsa = `-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx5piWVlE62NnZ0UzJ8Z6 oKiKOC4dbOZ1HsNhIRtqkM+Oq4G+25yq6P+0JU/Qvr9veOGEb3R/J9u8JBo+hv2i 5X8OtgvP2V2pi6f1s6vK7L0+6uRb4YTT/UdMshaVf97MgEqbq41Jf/cuvh+3AV0t @@ -136,25 +136,61 @@ func TestLoadECDSAPrivateKey(t *testing.T) { func TestImportPrivateKey(t *testing.T) { - err := os.WriteFile("validrsa1.key", []byte(validrsa1), 0600) + err := os.WriteFile("validrsa.key", []byte(validrsa), 0600) if err != nil { t.Fatal(err) } - _, err = ImportKeyPair("validrsa1.key", pass("hello")) + // Test valid RSA private key + if _, err = ImportKeyPair("validrsa.key", pass("hello")); err != nil { + + t.Errorf("unexpected error importing key: %s", err) + } + os.Remove("validrsa.key") + + err = os.WriteFile("invalidrsa.key", []byte(invalidrsa), 0600) if err != nil { + t.Fatal(err) + } + + // Test invalid RSA private key + if _, err = ImportKeyPair("invalidrsa.key", pass("hello")); err == nil { + t.Errorf("unexpected error importing key: %s", err) } + os.Remove("invalidrsa.key") - os.Remove("validrsa1.key") + err = os.WriteFile("invalidkey.key", []byte(invalidkey), 0600) + if err != nil { + t.Fatal(err) + } - err = os.WriteFile("ed25519.key", []byte(ed25519key), 0600) + // Test invalid PGP private key + if _, err = ImportKeyPair("invalidkey.key", pass("hello")); err == nil { + + t.Errorf("unexpected error importing key: %s", err) + } + os.Remove("invalidkey.key") + + err = os.WriteFile("validec.key", []byte(validec), 0600) if err != nil { t.Fatal(err) } - _, err = ImportKeyPair("ed25519.key", pass("hello")) + // Test valid EC private key + if _, err = ImportKeyPair("validec.key", pass("hello")); err != nil { + + t.Errorf("unexpected error importing key: %s", err) + } + os.Remove("validec.key") + + err = os.WriteFile("ed25519.key", []byte(ed25519key), 0600) if err != nil { + t.Fatal(err) + } + + // Test invalid EC private key + if _, err = ImportKeyPair("ed25519.key", pass("hello")); err == nil { t.Errorf("unexpected error importing key: %s", err) } diff --git a/test/e2e_test.go b/test/e2e_test.go index 997b916e61d..168465b6335 100644 --- a/test/e2e_test.go +++ b/test/e2e_test.go @@ -542,12 +542,12 @@ qGzRVIDGbNkrVHM0IsAtHRpC0rYrtZY+9OwiraGcsqUMLwwQdCA= os.Chdir(wd) }() - err = os.WriteFile("/Users/iwallis-dev/validrsa1.key", []byte(validrsa1), 0600) + err = os.WriteFile("validrsa1.key", []byte(validrsa1), 0600) if err != nil { t.Fatal(err) } - keys, err := cosign.ImportKeyPair("/Users/iwallis-dev/validrsa1.key", passFunc) + keys, err := cosign.ImportKeyPair("validrsa1.key", passFunc) if err != nil { t.Fatal(err) } diff --git a/test/import_test.sh b/test/import_test.sh deleted file mode 100755 index 7634cecab62..00000000000 --- a/test/import_test.sh +++ /dev/null @@ -1,115 +0,0 @@ -#!/bin/bash -# -# Copyright 2021 The Sigstore Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -ex - -RSAPRIVKEY="-----BEGIN RSA PRIVATE KEY----- -MIIEogIBAAKCAQEAx5piWVlE62NnZ0UzJ8Z6oKiKOC4dbOZ1HsNhIRtqkM+Oq4G+ -25yq6P+0JU/Qvr9veOGEb3R/J9u8JBo+hv2i5X8OtgvP2V2pi6f1s6vK7L0+6uRb -4YTT/UdMshaVf97MgEqbq41Jf/cuvh+3AV0tZ1BpixZg4aXMKpY6HUP69lbsu27o -SUN1myMv7TSgZiV4CYs3l/gkEfpysBptWlcHRuw5RsB+C0RbjRtbJ/5VxmE/vd3M -lafd5t1WSpMb8yf0a84u5NFaXwZ7CweMfXeOddS0yb19ShSuW3PPRadruBM1mq15 -js9GfagPxDS75Imcs+fA62lWvHxEujTGjYHxawIDAQABAoIBAH+sgLwmHa9zJfEo -klAe5NFe/QpydN/ziXbkAnzqzH9URC3wD+TpkWj4JoK3Sw635NWtasjf+3XDV9S/ -9L7j/g5N91r6sziWcJykEsWaXXKQmm4lI6BdFjwsHyLKz1W7bZOiJXDWLu1rbrqu -DqEQuLoc9WXCKrYrFy0maoXNtfla/1p05kKN0bMigcnnyAQ+xBTwoyco4tkIz5se -IYxorz7qzXrkHQI+knz5BawmNe3ekoSaXUPoLoOR7TRTGsLteL5yukvWAi8S/0rE -gftC+PZCQpoQhSUYq7wXe7RowJ1f+kXb7HsSedOTfTSW1D/pUb/uW+CcRKig42ZI -I9H9TAECgYEA5XGBML6fJyWVqx64sHbUAjQsmQ0RwU6Zo7sqHIEPf6tYVYp7KtzK -KOfi8seOOL5FSy4pjCo11Dzyrh9bn45RNmtjSYTgOnVPSoCfuRNfOcpG+/wCHjYf -EjDvdrCpbg59kVUeaMeBDiyWAlM48HJAn8O7ez2U/iKQCyJmOIwFhSkCgYEA3rSz -Fi1NzqYWxWos4NBmg8iKcQ9SMkmPdgRLAs/WNnZJ8fdgJZwihevkXGytRGJEmav2 -GMKRx1g6ey8fjXTQH9WM8X/kJC5fv8wLHnUCH/K3Mcp9CYwn7PFvSnBr4kQoc/el -bURhcF1+/opEC8vNX/Wk3zAG7Xs1PREXlH2SIHMCgYBV/3kgwBH/JkM25EjtO1yz -hsLAivmAruk/SUO7c1RP0fVF+qW3pxHOyztxLALOmeJ3D1JbSubqKf377Zz17O3b -q9yHDdrNjnKtxhAX2n7ytjJs+EQC9t4mf1kB761RpvTBqFnBhCWHHocLUA4jcW9v -cnmu86IIrwO2aKpPv4vCIQKBgHU9gY3qOazRSOmSlJ+hdmZn+2G7pBTvHsQNTIPl -cCrpqNHl3crO4GnKHkT9vVVjuiOAIKU2QNJFwzu4Og8Y8LvhizpTjoHxm9x3iV72 -UDELcJ+YrqyJCTe2flUcy96o7Pbn50GXnwgtYD6WAW6IUszyn2ITgYIhu4wzZEt6 -s6O7AoGAPTKbRA87L34LMlXyUBJma+etMARIP1zu8bXJ7hSJeMcog8zaLczN7ruT -pGAaLxggvtvuncMuTrG+cdmsR9SafSFKRS92NCxhOUonQ+NP6mLskIGzJZoQ5JvQ -qGzRVIDGbNkrVHM0IsAtHRpC0rYrtZY+9OwiraGcsqUMLwwQdCA= ------END RSA PRIVATE KEY-----" - -INVALID_RSAPRIVKEY1="-----BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx5piWVlE62NnZ0UzJ8Z6 -oKiKOC4dbOZ1HsNhIRtqkM+Oq4G+25yq6P+0JU/Qvr9veOGEb3R/J9u8JBo+hv2i -5X8OtgvP2V2pi6f1s6vK7L0+6uRb4YTT/UdMshaVf97MgEqbq41Jf/cuvh+3AV0t -Z1BpixZg4aXMKpY6HUP69lbsu27oSUN1myMv7TSgZiV4CYs3l/gkEfpysBptWlcH -Ruw5RsB+C0RbjRtbJ/5VxmE/vd3Mlafd5t1WSpMb8yf0a84u5NFaXwZ7CweMfXeO -ddS0yb19ShSuW3PPRadruBM1mq15js9GfagPxDS75Imcs+fA62lWvHxEujTGjYHx -awIDAQAB ------END PUBLIC KEY-----" - -INVALID_RSAPRIVKEY2="-----BEGIN PGP PRIVATE KEY BLOCK----- -Version: BCPG C# v1.6.1.0 - -lQOsBGGTOVkBCACbhVqCN55SElw1rZxI9LQDf91sU5FmrSybGh5r1xGV8rOhpKe+ -eGirYVY3KeI6XUdZoJEIRtXtd6IJWn3msFRgO/MwkUQ4CibORSXPjCwHnseJmh5D -axgZbXpzjP90fW03R+sBqm2AvrUANaWIKIXk8bWWdK5yUhB7TubIxpOZKg/nLlIE -1j6+XdCWIfo56z0mpJWRASzZRGuncfvkHRz73YfA00FpflQykiUDi6+vDV7KTh49 -7nkivRwyx5JcsAT3W1MCXNjCEXsdmdtNah3mN7SMbzSh3RF+IMaonxT4KM5nmEj/ -wGKJ4xUPtKy7kgIPYP+LMOj7j1qCsndYWILzABEBAAH/AwMC5uUvFLMg8b9gVFGU -B1Ak38tCEBPtON9gSIxg9HX80WyMI8/MdfaisEsnFvy4X3UolhTlFJ9v3aqK1Zc8 -JSkEw7cgY0NmFWDr6k8y8LhLN1ATjnKr9J9jzr8G9XvQfgaFbtcuFOF35ylQdeoL -IKKa8GqrXL75rolg+p/OSw52n/7fb17fDXLNyeGQ0g8wjIVTv+7vuvr9Z0kxfIgG -Y9oGIV/SeJvXjoWZWG3GbpTXx+ktmtwCY+tAlxJUt23OwWRfsnC9rS2DAsnJLlG2 -r3Exfl80MUza1sQ/7u1svcHbFuZZOrJ1S9OjRQAWMsfQHFcav34Yrbb3aFweXLjs -iT9BJOMR4W/nyXvKAnMt/6vHKfO6kbxCtDFstH5qZAKbSceWX1Y6UaGimHXCnTYi -tlUMRNWlf6fFLdYBrRCh+MpLs5tSLc6NAYaQXTe3dJrjTRyzkxzYxeE/Y6Mii8KR -gF3Fu5OwkJ39jKdWZf17i/LUofgQHzW4ymuDMWcrqX1kZXPjD6WN8c8NmNCGvlsT -n1V6jPGb8tORIn8+CX+mCyJcxLpbG3ke90DIPnMol7WJ+3xV7J9peJqp0fY4jkmF -I96EUhY1HTZcy4SnhiPwKb8NDpdqwFx1qwytf7eM+65Cf+rj9Nh6ShVOjIfOT9gh -zEp0W0SFTU7p5af9ULnONCJABvRB8Gneosc6iwVclgHhTJcUzILRqNjcrJQu1j1v -oK9Ls+VANww4zEOqx8g+T/P4pHmGTIYTDErzyDmBw8aFD7fDl+kPUtanqC1oTvnJ -qZvoJ3JJ9Z2edW7Ulc1+BhnB8Cfs/jEJQHCngciUjW8yLUcVKdmFKkd9cajhoeQz -bJp6/t9dRUVXo2ulZzvdN93TWV66rTxHQAI4OBZKqbQLYm9iQGJvYi5jb22JARwE -EAECAAYFAmGTOVkACgkQSL3lExF3kQq7swf+Ndhd9iogkofT9ihMuMksoSDituN+ -7hZY5zCj0UzCS8o2vHU+XJCRCpRlOc7gxl+44S60YmwqKtTjT5eqXCXrqa1XTyZz -xYpRfRjwnS6coQbdREQUvIgKapHII+b5gmnNhVX8niO11KyUHc29RWRiLFvMMcYO -urG06WshDewpqrBdq0MYBSSWO7myQLR5xEW6ld6CKkU0153LHgVdlGVIzrLM7sRo -NoHsidPbBIYv+aQxSVHxdKpFEpCHi9vckLSew+8LG5sDA/X3G4l9P3c1KusXP248 -hfOiWo/4tMCN8XJpe0L+99ubcnHjQR7C8htFB4DnIA8KhMBSDdF/Vgp97g== -=8+cN ------END PGP PRIVATE KEY BLOCK-----" - -ECPRIVKEY="-----BEGIN EC PRIVATE KEY----- -MHcCAQEEIIGhcmCI5F7BPMH4r3pWCpQdAsveErdU5DjvVQerErJuoAoGCCqGSM49 -AwEHoUQDQgAE+9E3Qe+h25ofmz3Uo2T004Dfy49iX06MMbxf9rsGmLkOPrS0KYDl -1QMfFuSbrtf8wTWNT9HNxrW/Foz39mDhHw== ------END EC PRIVATE KEY-----" - -ED25519PRIVKEY="-----BEGIN PRIVATE KEY----- -MC4CAQAwBQYDK2VwBCIEIALEbo1EFnWFqBK/wC+hhypG/8hXEerwdNetAoFoFVdv ------END PRIVATE KEY-----" - -#Test importing valid RSA PEM -./../cosign import-key-pair --key <(echo "$RSAPRIVKEY") - -#Test importing an invalid RSA PEM -#Expected output: invalid pem block -./../cosign import-key-pair --key <(echo "$INVALID_RSAPRVKEY1") -./../cosign import-key-pair --key <(echo "$INVALID_RSAPRVKEY2") - -#Test importing valid EC PEM -./../cosign import-key-pair --key <(echo "$ECPRIVKEY") - -#Test importing an Ed25519 key generated using OpenSSL 1.1 -#Expected output: parsing error -./../cosign import-key-pair --key <(echo "$ED25519PRIVKEY") - -#Test signing container with imported keypair: -./../cosign sign --key import-cosign.key dlorenc/demo From b2f2056418432aee7a78b494a4ae597c46048ac2 Mon Sep 17 00:00:00 2001 From: Ivan Wallis Date: Sat, 4 Dec 2021 16:42:51 -0800 Subject: [PATCH 08/14] lint updates Signed-off-by: Ivan Wallis --- pkg/cosign/keys.go | 1 - pkg/cosign/keys_test.go | 6 ------ 2 files changed, 7 deletions(-) diff --git a/pkg/cosign/keys.go b/pkg/cosign/keys.go index 4bd4c90d0e0..98f92f96a28 100644 --- a/pkg/cosign/keys.go +++ b/pkg/cosign/keys.go @@ -85,7 +85,6 @@ func ImportKeyPair(keyPath string, pf PassFunc) (*KeysBytes, error) { } return marshalKeyPair(Keys{pk, pk.Public()}, pf) } - } func marshalKeyPair(keypair Keys, pf PassFunc) (*KeysBytes, error) { diff --git a/pkg/cosign/keys_test.go b/pkg/cosign/keys_test.go index 4ffbe5b84a8..c3dbf8e0c40 100644 --- a/pkg/cosign/keys_test.go +++ b/pkg/cosign/keys_test.go @@ -135,7 +135,6 @@ func TestLoadECDSAPrivateKey(t *testing.T) { } func TestImportPrivateKey(t *testing.T) { - err := os.WriteFile("validrsa.key", []byte(validrsa), 0600) if err != nil { t.Fatal(err) @@ -143,7 +142,6 @@ func TestImportPrivateKey(t *testing.T) { // Test valid RSA private key if _, err = ImportKeyPair("validrsa.key", pass("hello")); err != nil { - t.Errorf("unexpected error importing key: %s", err) } os.Remove("validrsa.key") @@ -155,7 +153,6 @@ func TestImportPrivateKey(t *testing.T) { // Test invalid RSA private key if _, err = ImportKeyPair("invalidrsa.key", pass("hello")); err == nil { - t.Errorf("unexpected error importing key: %s", err) } os.Remove("invalidrsa.key") @@ -167,7 +164,6 @@ func TestImportPrivateKey(t *testing.T) { // Test invalid PGP private key if _, err = ImportKeyPair("invalidkey.key", pass("hello")); err == nil { - t.Errorf("unexpected error importing key: %s", err) } os.Remove("invalidkey.key") @@ -179,7 +175,6 @@ func TestImportPrivateKey(t *testing.T) { // Test valid EC private key if _, err = ImportKeyPair("validec.key", pass("hello")); err != nil { - t.Errorf("unexpected error importing key: %s", err) } os.Remove("validec.key") @@ -195,5 +190,4 @@ func TestImportPrivateKey(t *testing.T) { } os.Remove("ed25519.key") - } From 4f21d45e20ac2ec2913e4c52b5fb13e380ad6bed Mon Sep 17 00:00:00 2001 From: Ivan Wallis Date: Mon, 6 Dec 2021 10:03:07 -0800 Subject: [PATCH 09/14] importkeypair update Signed-off-by: Ivan Wallis --- pkg/cosign/keys.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pkg/cosign/keys.go b/pkg/cosign/keys.go index 98f92f96a28..d91c7869df1 100644 --- a/pkg/cosign/keys.go +++ b/pkg/cosign/keys.go @@ -71,20 +71,21 @@ func ImportKeyPair(keyPath string, pf PassFunc) (*KeysBytes, error) { return nil, errors.New("invalid pem block") } + var pk crypto.Signer + switch p.Type { case RSAPrivateKeyPemType: - pk, err := x509.ParsePKCS1PrivateKey(p.Bytes) + pk, err = x509.ParsePKCS1PrivateKey(p.Bytes) if err != nil { return nil, fmt.Errorf("parsing error") } - return marshalKeyPair(Keys{pk, pk.Public()}, pf) default: - pk, err := x509.ParseECPrivateKey(p.Bytes) + pk, err = x509.ParseECPrivateKey(p.Bytes) if err != nil { return nil, fmt.Errorf("parsing error") } - return marshalKeyPair(Keys{pk, pk.Public()}, pf) } + return marshalKeyPair(Keys{pk, pk.Public()}, pf) } func marshalKeyPair(keypair Keys, pf PassFunc) (*KeysBytes, error) { From 1e0f967e7fadb05595f93c5b732ee1df32824667 Mon Sep 17 00:00:00 2001 From: Ivan Wallis Date: Mon, 6 Dec 2021 10:26:25 -0800 Subject: [PATCH 10/14] TestImportPrivateKey update Signed-off-by: Ivan Wallis --- pkg/cosign/keys_test.go | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/pkg/cosign/keys_test.go b/pkg/cosign/keys_test.go index c3dbf8e0c40..1ff56642544 100644 --- a/pkg/cosign/keys_test.go +++ b/pkg/cosign/keys_test.go @@ -18,6 +18,7 @@ package cosign import ( "crypto/rand" "os" + "path/filepath" "testing" ) @@ -135,59 +136,60 @@ func TestLoadECDSAPrivateKey(t *testing.T) { } func TestImportPrivateKey(t *testing.T) { - err := os.WriteFile("validrsa.key", []byte(validrsa), 0600) + td := t.TempDir() + err := os.WriteFile(filepath.Join(td, "validrsa.key"), []byte(validrsa), 0600) if err != nil { t.Fatal(err) } // Test valid RSA private key - if _, err = ImportKeyPair("validrsa.key", pass("hello")); err != nil { + if _, err = ImportKeyPair(filepath.Join(td, "validrsa.key"), pass("hello")); err != nil { t.Errorf("unexpected error importing key: %s", err) } - os.Remove("validrsa.key") + os.Remove(filepath.Join(td, "validrsa.key")) - err = os.WriteFile("invalidrsa.key", []byte(invalidrsa), 0600) + err = os.WriteFile(filepath.Join(td, "invalidrsa.key"), []byte(invalidrsa), 0600) if err != nil { t.Fatal(err) } // Test invalid RSA private key - if _, err = ImportKeyPair("invalidrsa.key", pass("hello")); err == nil { + if _, err = ImportKeyPair(filepath.Join(td, "invalidrsa.key"), pass("hello")); err == nil { t.Errorf("unexpected error importing key: %s", err) } - os.Remove("invalidrsa.key") + os.Remove(filepath.Join(td, "invalidrsa.key")) - err = os.WriteFile("invalidkey.key", []byte(invalidkey), 0600) + err = os.WriteFile(filepath.Join(td, "invalidkey.key"), []byte(invalidkey), 0600) if err != nil { t.Fatal(err) } // Test invalid PGP private key - if _, err = ImportKeyPair("invalidkey.key", pass("hello")); err == nil { + if _, err = ImportKeyPair(filepath.Join(td, "invalidkey.key"), pass("hello")); err == nil { t.Errorf("unexpected error importing key: %s", err) } - os.Remove("invalidkey.key") + os.Remove(filepath.Join(td, "invalidkey.key")) - err = os.WriteFile("validec.key", []byte(validec), 0600) + err = os.WriteFile(filepath.Join(td, "validec.key"), []byte(validec), 0600) if err != nil { t.Fatal(err) } // Test valid EC private key - if _, err = ImportKeyPair("validec.key", pass("hello")); err != nil { + if _, err = ImportKeyPair(filepath.Join(td, "validec.key"), pass("hello")); err != nil { t.Errorf("unexpected error importing key: %s", err) } - os.Remove("validec.key") + os.Remove(filepath.Join(td, "validec.key")) - err = os.WriteFile("ed25519.key", []byte(ed25519key), 0600) + err = os.WriteFile(filepath.Join(td, "ed25519.key"), []byte(ed25519key), 0600) if err != nil { t.Fatal(err) } // Test invalid EC private key - if _, err = ImportKeyPair("ed25519.key", pass("hello")); err == nil { + if _, err = ImportKeyPair(filepath.Join(td, "ed25519.key"), pass("hello")); err == nil { t.Errorf("unexpected error importing key: %s", err) } - os.Remove("ed25519.key") + os.Remove(filepath.Join(td, "ed25519.key")) } From 86c3adaa37a4b9ee7f2d10957d0628ecf0b9f683 Mon Sep 17 00:00:00 2001 From: Ivan Wallis Date: Mon, 6 Dec 2021 16:25:58 -0800 Subject: [PATCH 11/14] TestImportPrivateKey updates Signed-off-by: Ivan Wallis --- pkg/cosign/keys.go | 2 +- pkg/cosign/keys_test.go | 97 +++++++++++++++++++---------------------- 2 files changed, 45 insertions(+), 54 deletions(-) diff --git a/pkg/cosign/keys.go b/pkg/cosign/keys.go index d91c7869df1..a4ad1903b6f 100644 --- a/pkg/cosign/keys.go +++ b/pkg/cosign/keys.go @@ -68,7 +68,7 @@ func ImportKeyPair(keyPath string, pf PassFunc) (*KeysBytes, error) { p, _ := pem.Decode(kb) if p == nil { - return nil, errors.New("invalid pem block") + return nil, fmt.Errorf("invalid pem block") } var pk crypto.Signer diff --git a/pkg/cosign/keys_test.go b/pkg/cosign/keys_test.go index 1ff56642544..9c7bc136411 100644 --- a/pkg/cosign/keys_test.go +++ b/pkg/cosign/keys_test.go @@ -17,9 +17,12 @@ package cosign import ( "crypto/rand" + "errors" "os" "path/filepath" "testing" + + "github.com/stretchr/testify/require" ) const validrsa = `-----BEGIN RSA PRIVATE KEY----- @@ -136,60 +139,48 @@ func TestLoadECDSAPrivateKey(t *testing.T) { } func TestImportPrivateKey(t *testing.T) { - td := t.TempDir() - err := os.WriteFile(filepath.Join(td, "validrsa.key"), []byte(validrsa), 0600) - if err != nil { - t.Fatal(err) - } - - // Test valid RSA private key - if _, err = ImportKeyPair(filepath.Join(td, "validrsa.key"), pass("hello")); err != nil { - t.Errorf("unexpected error importing key: %s", err) - } - os.Remove(filepath.Join(td, "validrsa.key")) - - err = os.WriteFile(filepath.Join(td, "invalidrsa.key"), []byte(invalidrsa), 0600) - if err != nil { - t.Fatal(err) - } - - // Test invalid RSA private key - if _, err = ImportKeyPair(filepath.Join(td, "invalidrsa.key"), pass("hello")); err == nil { - t.Errorf("unexpected error importing key: %s", err) - } - os.Remove(filepath.Join(td, "invalidrsa.key")) - - err = os.WriteFile(filepath.Join(td, "invalidkey.key"), []byte(invalidkey), 0600) - if err != nil { - t.Fatal(err) - } - - // Test invalid PGP private key - if _, err = ImportKeyPair(filepath.Join(td, "invalidkey.key"), pass("hello")); err == nil { - t.Errorf("unexpected error importing key: %s", err) - } - os.Remove(filepath.Join(td, "invalidkey.key")) - - err = os.WriteFile(filepath.Join(td, "validec.key"), []byte(validec), 0600) - if err != nil { - t.Fatal(err) - } - - // Test valid EC private key - if _, err = ImportKeyPair(filepath.Join(td, "validec.key"), pass("hello")); err != nil { - t.Errorf("unexpected error importing key: %s", err) - } - os.Remove(filepath.Join(td, "validec.key")) - - err = os.WriteFile(filepath.Join(td, "ed25519.key"), []byte(ed25519key), 0600) - if err != nil { - t.Fatal(err) + testCases := []struct { + fileName string + pemData string + expected error + }{ + { + fileName: "validrsa.key", + pemData: validrsa, + expected: nil, + }, + { + fileName: "invalidrsa.key", + pemData: invalidrsa, + expected: errors.New("parsing error"), + }, + { + fileName: "invalidkey.key", + pemData: invalidkey, + expected: errors.New("invalid pem block"), + }, + { + fileName: "validec.key", + pemData: validec, + expected: nil, + }, + { + fileName: "ed25519.key", + pemData: ed25519key, + expected: errors.New("parsing error"), + }, } + td := t.TempDir() - // Test invalid EC private key - if _, err = ImportKeyPair(filepath.Join(td, "ed25519.key"), pass("hello")); err == nil { - t.Errorf("unexpected error importing key: %s", err) + for _, tc := range testCases { + t.Run(tc.fileName, func(t *testing.T) { + f := filepath.Join(td, tc.fileName) + err := os.WriteFile(f, []byte(tc.pemData), 0600) + if err != nil { + t.Fatal(err) + } + _, err = ImportKeyPair(f, pass("hello")) + require.Equal(t, tc.expected, err) + }) } - - os.Remove(filepath.Join(td, "ed25519.key")) } From 2dfbb28846d89b6d433bf62db636c6fdcfc0e122 Mon Sep 17 00:00:00 2001 From: Ivan Wallis Date: Tue, 28 Dec 2021 10:53:37 -0800 Subject: [PATCH 12/14] linting fixes Signed-off-by: Ivan Wallis --- pkg/cosign/kubernetes/secret.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/cosign/kubernetes/secret.go b/pkg/cosign/kubernetes/secret.go index 963c7e3a30a..385846fed8e 100644 --- a/pkg/cosign/kubernetes/secret.go +++ b/pkg/cosign/kubernetes/secret.go @@ -102,7 +102,7 @@ func KeyPairSecret(ctx context.Context, k8sRef string, pf cosign.PassFunc) error // * cosign.key // * cosign.pub // * cosign.password -func secret(keys *cosign.KeysBytes, namespace, name string, data map[string][]byte) *v1.Secret { +func secret(keys *cosign.KeysBytes, namespace, name string, data map[string][]byte, immutable bool) *v1.Secret { if data == nil { data = map[string][]byte{} } From 660b3945f87df99b4644f95863f089f477092df7 Mon Sep 17 00:00:00 2001 From: Ivan Wallis Date: Tue, 28 Dec 2021 11:10:39 -0800 Subject: [PATCH 13/14] E2E fix Signed-off-by: Ivan Wallis --- test/e2e_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e_test.go b/test/e2e_test.go index 1613cf842e3..7a403c35700 100644 --- a/test/e2e_test.go +++ b/test/e2e_test.go @@ -188,7 +188,7 @@ func TestImportSignVerifyClean(t *testing.T) { // Now sign the image ko := sign.KeyOpts{KeyRef: privKeyPath, PassFunc: passFunc} - must(sign.SignCmd(ctx, ko, options.RegistryOptions{}, nil, []string{imgName}, "", true, "", false, false, ""), t) + must(sign.SignCmd(ctx, ko, options.RegistryOptions{}, nil, []string{imgName}, "", true, "", "", "", false, false, ""), t) // Now verify and download should work! must(verify(pubKeyPath, imgName, true, nil, ""), t) From a37d984c0153fc7cb30de2661e1b80840bb23a63 Mon Sep 17 00:00:00 2001 From: Ivan Wallis Date: Fri, 31 Dec 2021 12:56:30 -0800 Subject: [PATCH 14/14] conflict fix Signed-off-by: Ivan Wallis --- pkg/signature/keys.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/pkg/signature/keys.go b/pkg/signature/keys.go index be8a7ceac4f..2d071686896 100644 --- a/pkg/signature/keys.go +++ b/pkg/signature/keys.go @@ -18,6 +18,7 @@ import ( "context" "crypto" "crypto/x509" + "fmt" "os" "path/filepath" "strings" @@ -73,7 +74,6 @@ func loadKey(keyPath string, pf cosign.PassFunc) (signature.SignerVerifier, erro if err != nil { return nil, err } - return cosign.LoadPrivateKey(kb, pass) } @@ -141,12 +141,14 @@ func SignerVerifierFromKeyRef(ctx context.Context, keyRef string, pf cosign.Pass } return cosign.LoadPrivateKey([]byte(pk), []byte(pass)) - default: - if sv, err := kms.Get(ctx, keyRef, crypto.SHA256); err == nil { - return sv, nil - } } + sv, err := kms.Get(ctx, keyRef, crypto.SHA256) + if err == nil { + return sv, nil + } + + fmt.Fprintf(os.Stderr, "an error occurred: %v, will try to load key from disk...\n", err) return loadKey(keyRef, pf) }