diff options
| author | Samuele Pedroni <pedronis@lucediurna.net> | 2021-06-10 13:43:54 +0200 |
|---|---|---|
| committer | Samuele Pedroni <pedronis@lucediurna.net> | 2021-07-08 11:39:47 +0200 |
| commit | d9a4499dbfedd806cf3f94edbb48437a6b41d2e5 (patch) | |
| tree | f62f7ed098e45e631ee7f9ed20ae110fe2ec7c9d | |
| parent | abe8e48bb4e5d28fcdc2f3d05dd4b2f7f40bca5f (diff) | |
c/snap,asserts: create/delete-key external keypair manager interaction
at least initially we don't support using snap commands to create/delete keys under an external keypair manager, organize things such that though we can produce appropriate error messages and we can implement supporting this later if required
| -rw-r--r-- | asserts/extkeypairmgr.go | 20 | ||||
| -rw-r--r-- | asserts/extkeypairmgr_test.go | 19 | ||||
| -rw-r--r-- | cmd/snap/cmd_create_key.go | 22 | ||||
| -rw-r--r-- | cmd/snap/cmd_delete_key.go | 13 | ||||
| -rw-r--r-- | cmd/snap/cmd_delete_key_test.go | 11 | ||||
| -rw-r--r-- | cmd/snap/export_test.go | 1 | ||||
| -rw-r--r-- | cmd/snap/keymgr.go | 50 | ||||
| -rw-r--r-- | cmd/snap/keymgr_test.go | 29 |
8 files changed, 137 insertions, 28 deletions
diff --git a/asserts/extkeypairmgr.go b/asserts/extkeypairmgr.go index 0a945a8f8d..011da0cbd7 100644 --- a/asserts/extkeypairmgr.go +++ b/asserts/extkeypairmgr.go @@ -190,8 +190,26 @@ func (em *ExternalKeypairManager) GetByName(keyName string) (PrivateKey, error) return em.privateKey(cachedKey), nil } +// ExternalUnsupportedOpError represents the error situation of operations +// that are not supported/mediated via ExternalKeypairManager. +type ExternalUnsupportedOpError struct { + msg string +} + +func (euoe *ExternalUnsupportedOpError) Error() string { + return euoe.msg +} + func (em *ExternalKeypairManager) Put(privKey PrivateKey) error { - return fmt.Errorf("cannot import private key into external keypair manager") + return &ExternalUnsupportedOpError{"cannot import private key into external keypair manager"} +} + +func (em *ExternalKeypairManager) Delete(keyName string) error { + return &ExternalUnsupportedOpError{"no support to delete external keypair manager keys"} +} + +func (em *ExternalKeypairManager) Generate(keyName string) error { + return &ExternalUnsupportedOpError{"no support to mediate generating an external keypair manager key"} } func (em *ExternalKeypairManager) loadAllKeys() ([]string, error) { diff --git a/asserts/extkeypairmgr_test.go b/asserts/extkeypairmgr_test.go index c33180fa2a..c8e734b50f 100644 --- a/asserts/extkeypairmgr_test.go +++ b/asserts/extkeypairmgr_test.go @@ -299,3 +299,22 @@ func (s *extKeypairMgrSuite) TestListError(c *C) { _, err = kmgr.List() c.Check(err, ErrorMatches, `cannot get all external keypair manager key names:.*exit status 1.*`) } + +func (s *extKeypairMgrSuite) TestDeleteUnsupported(c *C) { + kmgr, err := asserts.NewExternalKeypairManager("keymgr") + c.Assert(err, IsNil) + + err = kmgr.Delete("key") + c.Check(err, ErrorMatches, `no support to delete external keypair manager keys`) + c.Check(err, FitsTypeOf, &asserts.ExternalUnsupportedOpError{}) + +} + +func (s *extKeypairMgrSuite) TestGenerateUnsupported(c *C) { + kmgr, err := asserts.NewExternalKeypairManager("keymgr") + c.Assert(err, IsNil) + + err = kmgr.Generate("key") + c.Check(err, ErrorMatches, `no support to mediate generating an external keypair manager key`) + c.Check(err, FitsTypeOf, &asserts.ExternalUnsupportedOpError{}) +} diff --git a/cmd/snap/cmd_create_key.go b/cmd/snap/cmd_create_key.go index fda20d9815..8288a7d71f 100644 --- a/cmd/snap/cmd_create_key.go +++ b/cmd/snap/cmd_create_key.go @@ -20,11 +20,9 @@ package main import ( - "errors" "fmt" "github.com/jessevdk/go-flags" - "golang.org/x/crypto/ssh/terminal" "github.com/snapcore/snapd/asserts" "github.com/snapcore/snapd/i18n" @@ -68,25 +66,9 @@ func (x *cmdCreateKey) Execute(args []string) error { return fmt.Errorf(i18n.G("key name %q is not valid; only ASCII letters, digits, and hyphens are allowed"), keyName) } - fmt.Fprint(Stdout, i18n.G("Passphrase: ")) - passphrase, err := terminal.ReadPassword(0) - fmt.Fprint(Stdout, "\n") + keypairMgr, err := getKeypairManager() if err != nil { return err } - fmt.Fprint(Stdout, i18n.G("Confirm passphrase: ")) - confirmPassphrase, err := terminal.ReadPassword(0) - fmt.Fprint(Stdout, "\n") - if err != nil { - return err - } - if string(passphrase) != string(confirmPassphrase) { - return errors.New("passphrases do not match") - } - if err != nil { - return err - } - - manager := asserts.NewGPGKeypairManager() - return manager.Generate(string(passphrase), keyName) + return generateKey(keypairMgr, keyName) } diff --git a/cmd/snap/cmd_delete_key.go b/cmd/snap/cmd_delete_key.go index e8dfb71e1b..517f6b936c 100644 --- a/cmd/snap/cmd_delete_key.go +++ b/cmd/snap/cmd_delete_key.go @@ -20,6 +20,8 @@ package main import ( + "fmt" + "github.com/jessevdk/go-flags" "github.com/snapcore/snapd/asserts" @@ -56,6 +58,13 @@ func (x *cmdDeleteKey) Execute(args []string) error { return ErrExtraArgs } - manager := asserts.NewGPGKeypairManager() - return manager.Delete(string(x.Positional.KeyName)) + keypairMgr, err := getKeypairManager() + if err != nil { + return err + } + err = keypairMgr.Delete(string(x.Positional.KeyName)) + if _, ok := err.(*asserts.ExternalUnsupportedOpError); ok { + return fmt.Errorf(i18n.G("cannot delete external keypair manager key via snap command, use the appropriate external procedure")) + } + return err } diff --git a/cmd/snap/cmd_delete_key_test.go b/cmd/snap/cmd_delete_key_test.go index 1f7dfdcdce..e0f4a369bc 100644 --- a/cmd/snap/cmd_delete_key_test.go +++ b/cmd/snap/cmd_delete_key_test.go @@ -62,3 +62,14 @@ func (s *SnapKeysSuite) TestDeleteKey(c *C) { c.Check(obtainedResponse, DeepEquals, expectedResponse) c.Check(s.Stderr(), Equals, "") } + +func (s *SnapKeysSuite) TestDeleteKeyExternalUnsupported(c *C) { + _, restore := mockNopExtKeyMgr(c) + defer restore() + + _, err := snap.Parser(snap.Client()).ParseArgs([]string{"delete-key", "key"}) + c.Assert(err, NotNil) + c.Check(err.Error(), Equals, "cannot delete external keypair manager key via snap command, use the appropriate external procedure") + c.Check(s.Stdout(), Equals, "") + c.Check(s.Stderr(), Equals, "") +} diff --git a/cmd/snap/export_test.go b/cmd/snap/export_test.go index 6dbc430e91..1831838c8c 100644 --- a/cmd/snap/export_test.go +++ b/cmd/snap/export_test.go @@ -93,6 +93,7 @@ var ( IsStopping = isStopping GetKeypairManager = getKeypairManager + GenerateKey = generateKey ) func HiddenCmd(descr string, completeHidden bool) *cmdInfo { diff --git a/cmd/snap/keymgr.go b/cmd/snap/keymgr.go index 6a3c613a02..9d502bef68 100644 --- a/cmd/snap/keymgr.go +++ b/cmd/snap/keymgr.go @@ -20,9 +20,12 @@ package main import ( + "errors" "fmt" "os" + "golang.org/x/crypto/ssh/terminal" + "github.com/snapcore/snapd/asserts" "github.com/snapcore/snapd/i18n" ) @@ -33,6 +36,7 @@ type KeypairManager interface { GetByName(keyNname string) (asserts.PrivateKey, error) Export(keyName string) ([]byte, error) List() ([]asserts.ExternalKeyInfo, error) + Delete(keyName string) error } func getKeypairManager() (KeypairManager, error) { @@ -47,3 +51,49 @@ func getKeypairManager() (KeypairManager, error) { keypairMgr := asserts.NewGPGKeypairManager() return keypairMgr, nil } + +type takingPassKeyGen interface { + Generate(passphrase string, keyName string) error +} + +type ownSecuringKeyGen interface { + Generate(keyName string) error +} + +func generateKey(keypairMgr KeypairManager, keyName string) error { + switch keyGen := keypairMgr.(type) { + case takingPassKeyGen: + return takePassGenKey(keyGen, keyName) + case ownSecuringKeyGen: + err := keyGen.Generate(keyName) + if _, ok := err.(*asserts.ExternalUnsupportedOpError); ok { + return fmt.Errorf(i18n.G("cannot generate external keypair manager key via snap command, use the appropriate external procedure to create a 4096-bit RSA key under the name/label %q"), keyName) + } + return err + default: + return fmt.Errorf("internal error: unsupported keypair manager %T", keypairMgr) + } +} + +func takePassGenKey(keyGen takingPassKeyGen, keyName string) error { + fmt.Fprint(Stdout, i18n.G("Passphrase: ")) + passphrase, err := terminal.ReadPassword(0) + fmt.Fprint(Stdout, "\n") + if err != nil { + return err + } + fmt.Fprint(Stdout, i18n.G("Confirm passphrase: ")) + confirmPassphrase, err := terminal.ReadPassword(0) + fmt.Fprint(Stdout, "\n") + if err != nil { + return err + } + if string(passphrase) != string(confirmPassphrase) { + return errors.New(i18n.G("passphrases do not match")) + } + if err != nil { + return err + } + + return keyGen.Generate(string(passphrase), keyName) +} diff --git a/cmd/snap/keymgr_test.go b/cmd/snap/keymgr_test.go index 5b4759e1a3..2c5fbba0d3 100644 --- a/cmd/snap/keymgr_test.go +++ b/cmd/snap/keymgr_test.go @@ -39,18 +39,26 @@ func (keymgrSuite) TestGPGKeypairManager(c *check.C) { c.Check(keypairMgr, check.FitsTypeOf, &asserts.GPGKeypairManager{}) } -func (keymgrSuite) TestExternalKeypairManager(c *check.C) { +func mockNopExtKeyMgr(c *check.C) (pgm *testutil.MockCmd, restore func()) { os.Setenv("SNAPD_EXT_KEYMGR", "keymgr") - defer os.Unsetenv("SNAPD_EXT_KEYMGR") - - pgm := testutil.MockCommand(c, "keymgr", ` + pgm = testutil.MockCommand(c, "keymgr", ` if [ "$1" == "features" ]; then echo '{"signing":["RSA-PKCS"] , "public-keys":["DER"]}' exit 0 fi exit 1 `) - defer pgm.Restore() + r := func() { + pgm.Restore() + os.Unsetenv("SNAPD_EXT_KEYMGR") + } + + return pgm, r +} + +func (keymgrSuite) TestExternalKeypairManager(c *check.C) { + pgm, restore := mockNopExtKeyMgr(c) + defer restore() keypairMgr, err := snap.GetKeypairManager() c.Check(err, check.IsNil) @@ -70,3 +78,14 @@ exit 1 _, err := snap.GetKeypairManager() c.Check(err, check.ErrorMatches, `cannot setup external keypair manager: external keypair manager "keymgr" \[features\] failed: exit status 1.*`) } + +func (keymgrSuite) TestExternalKeypairManagerGenerateKey(c *check.C) { + _, restore := mockNopExtKeyMgr(c) + defer restore() + + keypairMgr, err := snap.GetKeypairManager() + c.Check(err, check.IsNil) + + err = snap.GenerateKey(keypairMgr, "key") + c.Check(err, check.ErrorMatches, `cannot generate external keypair manager key via snap command, use the appropriate external procedure to create a 4096-bit RSA key under the name/label "key"`) +} |
