summaryrefslogtreecommitdiff
diff options
authorSamuele Pedroni <pedronis@lucediurna.net>2021-06-10 13:43:54 +0200
committerSamuele Pedroni <pedronis@lucediurna.net>2021-07-08 11:39:47 +0200
commitd9a4499dbfedd806cf3f94edbb48437a6b41d2e5 (patch)
treef62f7ed098e45e631ee7f9ed20ae110fe2ec7c9d
parentabe8e48bb4e5d28fcdc2f3d05dd4b2f7f40bca5f (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.go20
-rw-r--r--asserts/extkeypairmgr_test.go19
-rw-r--r--cmd/snap/cmd_create_key.go22
-rw-r--r--cmd/snap/cmd_delete_key.go13
-rw-r--r--cmd/snap/cmd_delete_key_test.go11
-rw-r--r--cmd/snap/export_test.go1
-rw-r--r--cmd/snap/keymgr.go50
-rw-r--r--cmd/snap/keymgr_test.go29
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"`)
+}