veyron2/security: Remove PrivateKey accessor from PrivateID interface.
We imagine that private keys are stored in secure storage - like a TPM
or some other simpler factotum service like an ssh-agent. Not keeping
the private keys in memory of the process makes attacks to reveal the
private key significantly harder.
This change modifies the interface so that only a "Sign" method
is exposed. Subsequent changes that introduce the TPM/ssh-agent etc.
will provide identity implementations that do not store the private key
in memory at all but defer to the TPM/agent for signatures.
Change-Id: I1a02694a819177d934590b66854e4ad0253772e0
diff --git a/runtimes/google/ipc/stream/vc/auth.go b/runtimes/google/ipc/stream/vc/auth.go
index 6afec46..0378b31 100644
--- a/runtimes/google/ipc/stream/vc/auth.go
+++ b/runtimes/google/ipc/stream/vc/auth.go
@@ -3,7 +3,6 @@
import (
"bytes"
"crypto/ecdsa"
- "crypto/rand"
"errors"
"fmt"
"io"
@@ -85,17 +84,16 @@
defer eid.Release()
// Sign the channel ID
- r, s, err := ecdsa.Sign(rand.Reader, id.PrivateKey(), chid.Contents)
+ signature, err := id.Sign(chid.Contents)
if err != nil {
return err
}
- // Encrypt the signature
- er, err := enc.Encrypt(iobuf.NewSlice(r.Bytes()))
+ er, err := enc.Encrypt(iobuf.NewSlice(signature.R.Bytes()))
if err != nil {
return err
}
defer er.Release()
- es, err := enc.Encrypt(iobuf.NewSlice(s.Bytes()))
+ es, err := enc.Encrypt(iobuf.NewSlice(signature.S.Bytes()))
if err != nil {
return err
}
diff --git a/runtimes/google/security/caveat/public_key_caveat.go b/runtimes/google/security/caveat/public_key_caveat.go
index be80c12..f142359 100644
--- a/runtimes/google/security/caveat/public_key_caveat.go
+++ b/runtimes/google/security/caveat/public_key_caveat.go
@@ -131,15 +131,13 @@
return wire.DecodeThirdPartyCaveats(d.Caveats)
}
-// sign uses the provided private key to sign the contents of the discharge. The private
-// key typically belongs to the principal that minted the discharge.
-func (d *publicKeyDischarge) sign(key *ecdsa.PrivateKey) error {
- r, s, err := ecdsa.Sign(rand.Reader, key, d.contentHash())
+// sign uses the provided identity to sign the contents of the discharge.
+func (d *publicKeyDischarge) sign(discharger security.PrivateID) error {
+ signature, err := discharger.Sign(d.contentHash())
if err != nil {
return err
}
- d.Signature.R = r.Bytes()
- d.Signature.S = s.Bytes()
+ d.Signature.Set(signature)
return nil
}
@@ -185,7 +183,7 @@
// the discharge includes the provided service caveats along with a universal
// expiry caveat for the provided duration. The discharge also includes a
// signature over its contents obtained from the provided private key.
-func NewPublicKeyDischarge(caveat security.ThirdPartyCaveat, ctx security.Context, dischargingKey *ecdsa.PrivateKey, duration time.Duration, caveats []security.ServiceCaveat) (security.ThirdPartyDischarge, error) {
+func NewPublicKeyDischarge(discharger security.PrivateID, caveat security.ThirdPartyCaveat, ctx security.Context, duration time.Duration, caveats []security.ServiceCaveat) (security.ThirdPartyDischarge, error) {
cav, ok := caveat.(*publicKeyCaveat)
if !ok {
return nil, fmt.Errorf("cannot mint discharges for %T", caveat)
@@ -198,23 +196,22 @@
if err := mintingCaveat.Validate(ctx); err != nil {
return nil, fmt.Errorf("failed to validate DischargeMintingCaveat: %s", err)
}
-
- discharge := &publicKeyDischarge{ThirdPartyCaveatID: caveat.ID()}
-
now := time.Now()
expiryCaveat := &vcaveat.Expiry{IssueTime: now, ExpiryTime: now.Add(duration)}
caveats = append(caveats, security.UniversalCaveat(expiryCaveat))
-
encodedCaveats, err := wire.EncodeCaveats(caveats)
if err != nil {
+ return nil, fmt.Errorf("failed to encode caveats in discharge: %v", err)
+ }
+ discharge := &publicKeyDischarge{
+ ThirdPartyCaveatID: caveat.ID(),
+ Caveats: encodedCaveats,
+ }
+ // TODO(ashankar,ataly): Should discharger necessarily be the same as ctx.LocalID()?
+ // If so, need the PrivateID object corresponding to ctx.LocalID.
+ if err := discharge.sign(discharger); err != nil {
return nil, err
}
- discharge.Caveats = encodedCaveats
-
- if err := discharge.sign(dischargingKey); err != nil {
- return nil, err
- }
-
return discharge, nil
}
diff --git a/runtimes/google/security/identity_chain.go b/runtimes/google/security/identity_chain.go
index 52f2147..ca6ca3d 100644
--- a/runtimes/google/security/identity_chain.go
+++ b/runtimes/google/security/identity_chain.go
@@ -120,11 +120,12 @@
privateKey *ecdsa.PrivateKey
}
-// PublicID returns the PublicID associated with the PrivateID.
func (id *chainPrivateID) PublicID() security.PublicID { return id.publicID }
-// PrivateKey returns the private key associated with the PrivateID.
-func (id *chainPrivateID) PrivateKey() *ecdsa.PrivateKey { return id.privateKey }
+func (id *chainPrivateID) Sign(message []byte) (signature security.Signature, err error) {
+ signature.R, signature.S, err = ecdsa.Sign(rand.Reader, id.privateKey, message)
+ return
+}
func (id *chainPrivateID) String() string { return fmt.Sprintf("PrivateID:%v", id.publicID) }
@@ -210,7 +211,7 @@
}
func (id *chainPrivateID) MintDischarge(cav security.ThirdPartyCaveat, ctx security.Context, duration time.Duration, dischargeCaveats []security.ServiceCaveat) (security.ThirdPartyDischarge, error) {
- return icaveat.NewPublicKeyDischarge(cav, ctx, id.privateKey, duration, dischargeCaveats)
+ return icaveat.NewPublicKeyDischarge(id, cav, ctx, duration, dischargeCaveats)
}
// newChainPrivateID returns a new PrivateID containing a freshly generated
diff --git a/runtimes/google/security/identity_set.go b/runtimes/google/security/identity_set.go
index 85bdbad..0b2bd89 100644
--- a/runtimes/google/security/identity_set.go
+++ b/runtimes/google/security/identity_set.go
@@ -146,8 +146,9 @@
case 1:
return ids[0], nil
default:
+ pub := ids[0].PublicID().PublicKey()
for i := 1; i < len(ids); i++ {
- if !reflect.DeepEqual(ids[0].PrivateKey(), ids[i].PrivateKey()) {
+ if !reflect.DeepEqual(pub, ids[i].PublicID().PublicKey()) {
return nil, errMismatchedKeys
}
}
@@ -164,7 +165,7 @@
return &set
}
-func (s setPrivateID) PrivateKey() *ecdsa.PrivateKey { return s[0].PrivateKey() }
+func (s setPrivateID) Sign(message []byte) (security.Signature, error) { return s[0].Sign(message) }
func (s setPrivateID) Bless(blessee security.PublicID, blessingName string, duration time.Duration, caveats []security.ServiceCaveat) (security.PublicID, error) {
pubs := make([]security.PublicID, len(s))
@@ -178,15 +179,12 @@
}
func (s setPrivateID) Derive(pub security.PublicID) (security.PrivateID, error) {
- if !reflect.DeepEqual(pub.PublicKey(), &s.PrivateKey().PublicKey) {
- return nil, errDeriveMismatch
- }
- var err error
switch p := pub.(type) {
case *chainPublicID:
return s[0].Derive(p)
case *setPublicID:
privs := make([]security.PrivateID, len(*p))
+ var err error
for ix, ip := range *p {
if privs[ix], err = s.Derive(ip); err != nil {
return nil, fmt.Errorf("Derive failed for %d of %d id in set", ix, len(*p))
diff --git a/runtimes/google/security/identity_test.go b/runtimes/google/security/identity_test.go
index 1d772ad..55ebf89 100644
--- a/runtimes/google/security/identity_test.go
+++ b/runtimes/google/security/identity_test.go
@@ -705,7 +705,7 @@
for _, d := range testdata {
derivedID, err := d.priv.Derive(d.pub)
if reflect.TypeOf(derivedID) != d.typ {
- t.Errorf("%T=%q.Derive(%T=%q) yielded %T, want %v", d.priv, d.priv, d.pub, d.pub, derivedID, d.typ)
+ t.Errorf("%T=%q.Derive(%T=%q) yielded (%T, %v), want %v", d.priv, d.priv, d.pub, d.pub, derivedID, err, d.typ)
continue
}
if err != nil {
@@ -716,9 +716,6 @@
if !reflect.DeepEqual(derivedID.PublicID(), d.pub) {
t.Errorf("%q.Derive(%q) returned: %q. PublicID mismatch", d.priv, d.pub, derivedID)
}
- if !reflect.DeepEqual(derivedID.PrivateKey(), d.priv.PrivateKey()) {
- t.Errorf("%q.Derive(%q) returned: %q. PrivateKey mismatch", d.priv, d.pub, derivedID)
- }
if _, err := roundTrip(derivedID.PublicID()); err != nil {
t.Errorf("roundTrip(%q=%q.Derive(%q)) failed: %v", derivedID, d.priv, d.pub, err)
}
diff --git a/tools/identity/main.go b/tools/identity/main.go
index 0ef0771..d440ffd 100644
--- a/tools/identity/main.go
+++ b/tools/identity/main.go
@@ -80,12 +80,11 @@
if len(*interpret) > 0 {
id := load(*interpret)
- fmt.Println("Name : ", id.PublicID())
- fmt.Printf("Go Type: %T\n", id)
- fmt.Println("Key : <Cannot print the elliptic curve>")
- fmt.Println(" X: ", id.PrivateKey().X)
- fmt.Println(" Y: ", id.PrivateKey().Y)
- fmt.Println(" D: ", id.PrivateKey().D)
+ fmt.Println("Name : ", id.PublicID())
+ fmt.Printf("Go Type : %T\n", id)
+ fmt.Println("PublicKey: <Cannot print the elliptic curve>")
+ fmt.Println(" X: ", id.PublicID().PublicKey().X)
+ fmt.Println(" Y: ", id.PublicID().PublicKey().Y)
fmt.Println("Any caveats in the identity are not printed")
}
}