blob: 723067a3d9c98621d25e216045c9dd11ee9ded90 [file] [log] [blame]
package caveat
import (
"bytes"
"crypto/ecdsa"
"crypto/rand"
"crypto/sha256"
"encoding/binary"
"time"
"veyron/runtimes/google/security/wire"
"veyron/security/caveat"
"veyron2/security"
)
// NewPublicKeyCaveat returns a new third-party caveat from the provided restriction,
// third-party identity, and third-party location.
func NewPublicKeyCaveat(restriction string, thirdParty security.PublicID, location string) (security.ThirdPartyCaveat, error) {
nonce := make([]uint8, nonceLength)
_, err := rand.Read(nonce)
if err != nil {
return nil, err
}
var validationKey wire.PublicKey
if err := validationKey.Encode(thirdParty.PublicKey()); err != nil {
return nil, err
}
return &PublicKeyCaveat{
RandNonce: nonce,
Restriction: restriction,
ValidationKey: validationKey,
ThirdPartyLocation: location,
}, nil
}
// NewPublicKeyDischarge returns a new discharge for the provided PublicKeyCaveat.
// The CaveatID of the discharge is the same as the ID of the caveat, and
// 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(cav *PublicKeyCaveat, dischargingKey *ecdsa.PrivateKey, duration time.Duration, caveats []security.ServiceCaveat) (security.ThirdPartyDischarge, error) {
discharge := &PublicKeyDischarge{
RandNonce: cav.RandNonce,
Restriction: cav.Restriction,
}
now := time.Now()
expiryCaveat := &caveat.Expiry{IssueTime: now, ExpiryTime: now.Add(duration)}
caveats = append(caveats, security.UniversalCaveat(expiryCaveat))
encodedCaveats, err := wire.EncodeCaveats(caveats)
if err != nil {
return nil, err
}
discharge.Caveats = encodedCaveats
if err := discharge.sign(dischargingKey); err != nil {
return nil, err
}
return discharge, nil
}
// 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())
if err != nil {
return err
}
d.Signature.R = r.Bytes()
d.Signature.S = s.Bytes()
return nil
}
func (d *PublicKeyDischarge) contentHash() []byte {
h := sha256.New()
tmp := make([]byte, binary.MaxVarintLen64)
wire.WriteBytes(h, tmp, d.RandNonce)
wire.WriteString(h, tmp, d.Restriction)
for _, cav := range d.Caveats {
wire.WriteString(h, tmp, string(cav.Service))
wire.WriteBytes(h, tmp, cav.Bytes)
}
return h.Sum(nil)
}
// id serializes the provided byte slice and SHA-256 hash of the provided string.
func id(b []uint8, str string) string {
var buf bytes.Buffer
buf.Write(b)
h := sha256.New()
tmp := make([]byte, binary.MaxVarintLen64)
wire.WriteString(h, tmp, str)
buf.Write(h.Sum(nil))
return buf.String()
}