veyron.io/veyron/veyron/security: create principal from signer.
Add methods that create in-memory and persistent principals from an
existing signer.
We need this functionality as in Android we store the private key inside
a hardware token and pass a signer into Go.
Change-Id: I5575ec92533ded5dae22219ba39e9a8195b8ee4f
diff --git a/security/principal.go b/security/principal.go
index c92430d..a351f00 100644
--- a/security/principal.go
+++ b/security/principal.go
@@ -23,6 +23,27 @@
return security.CreatePrincipal(security.NewInMemoryECDSASigner(priv), newInMemoryBlessingStore(pub), newInMemoryBlessingRoots())
}
+// NewPrincipalFromSigner creates a principal using the provided signer, storing its
+// BlessingRoots and BlessingStore in memory.
+func NewPrincipalFromSigner(signer security.Signer) (security.Principal, error) {
+ return security.CreatePrincipal(signer, newInMemoryBlessingStore(signer.PublicKey()), newInMemoryBlessingRoots())
+}
+
+// NewPersistentPrincipalForSigner creates a new principal using the provided Signer and a
+// partial state (i.e., BlessingRoots, BlessingStore) that is read from the provided directory 'dir'.
+// Changes to the partial state are persisted and commited to the same directory; the provided
+// signer isn't persisted: the caller is expected to persist it separately or use the
+// {Load,Create}PersistentPrincipal() methods instead.
+//
+// If the directory does not contain any partial state, new partial state instances are created
+// and subsequently commited to 'dir'. If the directory does not exist, it is created.
+func NewPersistentPrincipalFromSigner(signer security.Signer, dir string) (security.Principal, error) {
+ if err := mkDir(dir); err != nil {
+ return nil, err
+ }
+ return newPersistentPrincipalFromSigner(signer, dir)
+}
+
// LoadPersistentPrincipal reads state for a principal (private key, BlessingRoots, BlessingStore)
// from the provided directory 'dir' and commits all state changes to the same directory.
// If private key file does not exist then an error 'err' is returned such that os.IsNotExist(err) is true.
@@ -33,27 +54,49 @@
if err != nil {
return nil, err
}
- return newPersistentPrincipalFromKey(key, dir)
+ 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) (principal security.Principal, err error) {
- if finfo, err := os.Stat(dir); err == nil {
- if !finfo.IsDir() {
- return nil, fmt.Errorf("%q is not a directory", dir)
- }
- } else if err := os.MkdirAll(dir, 0700); err != nil {
- return nil, fmt.Errorf("failed to create %q: %v", dir, err)
+func CreatePersistentPrincipal(dir string, passphrase []byte) (security.Principal, 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)
}
- p, err := newPersistentPrincipalFromKey(key, dir)
- return p, err
+ return newPersistentPrincipalFromSigner(security.NewInMemoryECDSASigner(key), dir)
+}
+
+func newPersistentPrincipalFromSigner(signer security.Signer, dir string) (security.Principal, error) {
+ serializationSigner, err := security.CreatePrincipal(signer, nil, nil)
+ if err != nil {
+ return nil, fmt.Errorf("failed to create serialization.Signer: %v", err)
+ }
+ roots, err := newPersistingBlessingRoots(dir, serializationSigner)
+ if err != nil {
+ return nil, fmt.Errorf("failed to load BlessingRoots from %q: %v", dir, err)
+ }
+ store, err := newPersistingBlessingStore(dir, serializationSigner)
+ if err != nil {
+ return nil, fmt.Errorf("failed to load BlessingStore from %q: %v", dir, err)
+ }
+ return security.CreatePrincipal(signer, store, roots)
+}
+
+func mkDir(dir string) error {
+ if finfo, err := os.Stat(dir); err == nil {
+ if !finfo.IsDir() {
+ return fmt.Errorf("%q is not a directory", dir)
+ }
+ } else if err := os.MkdirAll(dir, 0700); err != nil {
+ return fmt.Errorf("failed to create %q: %v", dir, err)
+ }
+ return nil
}
func loadKeyFromDir(dir string, passphrase []byte) (*ecdsa.PrivateKey, error) {
@@ -70,22 +113,6 @@
return key.(*ecdsa.PrivateKey), nil
}
-func newPersistentPrincipalFromKey(key *ecdsa.PrivateKey, dir string) (security.Principal, error) {
- signer, err := security.CreatePrincipal(security.NewInMemoryECDSASigner(key), nil, nil)
- if err != nil {
- return nil, fmt.Errorf("failed to create serialization.Signer: %v", err)
- }
- roots, err := newPersistingBlessingRoots(dir, signer)
- if err != nil {
- return nil, fmt.Errorf("failed to load BlessingRoots from %q: %v", dir, err)
- }
- store, err := newPersistingBlessingStore(dir, signer)
- if err != nil {
- return nil, fmt.Errorf("failed to load BlessingStore from %q: %v", dir, err)
- }
- return security.CreatePrincipal(security.NewInMemoryECDSASigner(key), store, roots)
-}
-
// newKey generates an ECDSA (public, private) key pair.
func newKey() (security.PublicKey, *ecdsa.PrivateKey, error) {
priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)