"veyron/tools/principal": Overwrite flag for create
At the moment, the create command on the principal tools
complains if it is provided with a directly that already
contains a principal object. This causes some inconvenience
in tests and tutorials.
This CL resolves the issues by adding a --overwrite flag to
the principal that overwrites any existing principal data in
the directory.
Change-Id: I08ed5abb89c4a2d74de42586846b49df73a6f0f4
diff --git a/security/principal.go b/security/principal.go
index a351f00..ab23b09 100644
--- a/security/principal.go
+++ b/security/principal.go
@@ -57,21 +57,49 @@
return newPersistentPrincipalFromSigner(security.NewInMemoryECDSASigner(key), dir)
}
-// CreatePersistentPrincipal creates a new principal (private key, BlessingRoots, BlessingStore) and commits all state changes to the provided directory.
-// The generated private key is serialized and saved encrypted if the 'passphrase' is non-nil, and unencrypted otherwise.
-// If the directory has any preexisting key, CreatePersistentPrincipal will return an error.
-// The specified directory may not exist, in which case it gets created by this function.
-func CreatePersistentPrincipal(dir string, passphrase []byte) (security.Principal, error) {
+// CreatePersistentPrincipal creates a new principal (private key, BlessingRoots,
+// BlessingStore) and commits all state changes to the provided directory.
+//
+// The generated private key is serialized and saved encrypted if the 'passphrase'
+// is non-nil, and unencrypted otherwise.
+//
+// If the directory has any preexisting principal data, CreatePersistentPrincipal
+// will return an error.
+//
+// The specified directory may not exist, in which case it gets created by this
+// function.
+func CreatePersistentPrincipal(dir string, passphrase []byte) (principal security.Principal, err error) {
if err := mkDir(dir); err != nil {
return nil, err
}
key, err := initKey(dir, nil)
if err != nil {
- return nil, fmt.Errorf("could not initialize private key from credentials directory %v: %v", dir, err)
+ return nil, fmt.Errorf("failed to initialize private key: %v", err)
}
return newPersistentPrincipalFromSigner(security.NewInMemoryECDSASigner(key), dir)
}
+// CreateOrOverwritePersistentPrincipal behaves like CreatePersistentPrincipal except that
+// if the provided directory holds any preexisting principal data then the data gets
+// overwritten. Any prexising private key, BlessingRoots and BlessingStore would get lost
+// as a result of calling this function.
+func CreateOrOverwritePersistentPrincipal(dir string, passphrase []byte) (principal security.Principal, err error) {
+ if err := removePersistentPrincipal(dir); err != nil {
+ return nil, err
+ }
+ return CreatePersistentPrincipal(dir, passphrase)
+}
+
+func removePersistentPrincipal(dir string) error {
+ files := []string{privateKeyFile, blessingRootsDataFile, blessingRootsSigFile, blessingStoreDataFile, blessingStoreSigFile}
+ for _, f := range files {
+ if err := os.Remove(path.Join(dir, f)); err != nil && !os.IsNotExist(err) {
+ return err
+ }
+ }
+ return nil
+}
+
func newPersistentPrincipalFromSigner(signer security.Signer, dir string) (security.Principal, error) {
serializationSigner, err := security.CreatePrincipal(signer, nil, nil)
if err != nil {
@@ -124,7 +152,6 @@
func initKey(dir string, passphrase []byte) (*ecdsa.PrivateKey, error) {
keyFile := path.Join(dir, privateKeyFile)
- // O_EXCL returns an error if file exists.
f, err := os.OpenFile(keyFile, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600)
if err != nil {
return nil, fmt.Errorf("failed to open %q for writing: %v", keyFile, err)
diff --git a/security/principal_test.go b/security/principal_test.go
index d2d18ce..467d37a 100644
--- a/security/principal_test.go
+++ b/security/principal_test.go
@@ -66,20 +66,25 @@
if err != nil {
t.Fatal(err)
}
+ p, err = CreatePersistentPrincipal(dir, passphrase)
+ if err == nil {
+ t.Error("CreatePersistentPrincipal passed unexpectedly")
+ }
+ p, err = CreateOrOverwritePersistentPrincipal(dir, passphrase)
+ if err != nil {
+ t.Errorf("CreateOrOverwritePersistentPrincipal failed unexpectedly: %v", err)
+ }
+
sig, err := p.Sign(message)
if err != nil {
t.Fatal(err)
}
- p2, err := CreatePersistentPrincipal(dir, passphrase)
- if err == nil {
- t.Errorf("p2 CreatePersistentPrincipal should have failed")
- }
- p2, err = LoadPersistentPrincipal(dir, passphrase)
+ p2, err := LoadPersistentPrincipal(dir, passphrase)
if err != nil {
t.Fatal(err)
}
- if !sig.Verify(p.PublicKey(), message) {
+ if !sig.Verify(p2.PublicKey(), message) {
t.Errorf("%s failed: p.PublicKey=%v, p2.PublicKey=%v", message, p.PublicKey(), p2.PublicKey())
}
}
diff --git a/tools/principal/main.go b/tools/principal/main.go
index ecfaf16..d2bebca 100644
--- a/tools/principal/main.go
+++ b/tools/principal/main.go
@@ -36,6 +36,9 @@
flagSeekBlessingsSetDefault bool
flagSeekBlessingsForPeer string
+ // Flag for the create command
+ flagCreateOverwrite bool
+
// Flags common to many commands
flagAddToRoots bool
@@ -357,10 +360,14 @@
Name: "create",
Short: "Create a new principal and persist it into a directory",
Long: `
- Creates a new principal with a single self-blessed blessing and writes it out
- to the provided directory. The same directory can be used to set the VEYRON_CREDENTIALS
- environment variables for other veyron applications.
- `,
+Creates a new principal with a single self-blessed blessing and writes it out
+to the provided directory. The same directory can be used to set the VEYRON_CREDENTIALS
+environment variables for other veyron applications.
+
+The operation fails if the directory already contains a principal. In this case
+the --overwrite flag can be provided to overwrite the existing principal data in
+the directory.
+`,
ArgsName: "<directory> <blessing>",
ArgsLong: `
<directory> is the directory to which the principal will be persisted.
@@ -372,7 +379,15 @@
}
dir, name := args[0], args[1]
// TODO(suharshs,ashankar,ataly): How should we make an ecrypted pk... or is that up to the agent?
- p, err := vsecurity.CreatePersistentPrincipal(dir, nil)
+ var (
+ p security.Principal
+ err error
+ )
+ if flagCreateOverwrite {
+ p, err = vsecurity.CreateOrOverwritePersistentPrincipal(dir, nil)
+ } else {
+ p, err = vsecurity.CreatePersistentPrincipal(dir, nil)
+ }
if err != nil {
return err
}
@@ -477,6 +492,7 @@
cmdSeekBlessings.Flags.BoolVar(&flagAddToRoots, "add_to_roots", true, "If true, the root certificate of the blessing will be added to the principal's set of recognized root certificates")
cmdStoreSet.Flags.BoolVar(&flagAddToRoots, "add_to_roots", true, "If true, the root certificate of the blessing will be added to the principal's set of recognized root certificates")
cmdStoreSetDefault.Flags.BoolVar(&flagAddToRoots, "add_to_roots", true, "If true, the root certificate of the blessing will be added to the principal's set of recognized root certificates")
+ cmdCreate.Flags.BoolVar(&flagCreateOverwrite, "overwrite", false, "If true, any existing principal data in the directory will be overwritten")
cmdStore := &cmdline.Command{
Name: "store",
diff --git a/tools/principal/test.sh b/tools/principal/test.sh
index 9d26963..c5afe4a 100755
--- a/tools/principal/test.sh
+++ b/tools/principal/test.sh
@@ -36,8 +36,9 @@
# Prevent any VEYRON_CREDENTIALS in the environment from interfering with this test.
unset VEYRON_CREDENTIALS
# Create two principals, one called "alice" one called "bob"
- ./principal create ./alice alice >/dev/null || shell_test::fail "line ${LINENO}: create failed"
+ ./principal create --overwrite=true ./alice alice >/dev/null || shell_test::fail "line ${LINENO}: create failed"
./principal create ./bob bob >/dev/null || shell_test::fail "line ${LINENO}: create failed"
+ ./principal create --overwrite=true ./bob bob >/dev/null || shell_test::fail "line ${LINENO}: create failed"
# Run dump, bless, blessself on alice
export VEYRON_CREDENTIALS=./alice
./principal blessself alicereborn >alice.blessself || shell_test::fail "line ${LINENO}: blessself failed"