diff --git a/client/client.go b/client/client.go index 47b1c13..9995eab 100644 --- a/client/client.go +++ b/client/client.go @@ -254,7 +254,7 @@ func (c *RemoteServer) Decrypt(req core.DecryptRequest) (*core.ResponseData, err } -// Decrypt issues an decrypt request to the remote server +// DecryptSign issues an decrypt-sign request to the remote server func (c *RemoteServer) DecryptSign(req core.DecryptSignRequest) (*core.ResponseData, error) { reqBytes, err := json.Marshal(req) if err != nil { diff --git a/cmd/ro/roagent/roagent.go b/cmd/ro/roagent/roagent.go index 50ab1ef..05558e0 100644 --- a/cmd/ro/roagent/roagent.go +++ b/cmd/ro/roagent/roagent.go @@ -1,3 +1,5 @@ +// Package roagent provides ROAgent, which implements the SSH agent interface, +// forwarding sign requests to a Red October server package roagent import ( @@ -5,7 +7,6 @@ import ( "crypto/rand" "encoding/json" "errors" - "fmt" "io" "log" @@ -43,7 +44,6 @@ func (signer ROSigner) Sign(rand io.Reader, msg []byte) (signature *ssh.Signatur log.Fatal("response status error:", resp.Status) return nil, errors.New("response status error") } - fmt.Println("Response Status:", resp.Status) var respMsg core.DecryptSignWithDelegates err = json.Unmarshal(resp.Response, &respMsg) @@ -51,12 +51,7 @@ func (signer ROSigner) Sign(rand io.Reader, msg []byte) (signature *ssh.Signatur return nil, err } - var respSignature ssh.Signature - err = json.Unmarshal(resp.Response, &respSignature) - if err != nil { - return nil, err - } - + respSignature := ssh.Signature{Format: respMsg.SignatureFormat, Blob: respMsg.Signature} return &respSignature, nil } @@ -64,6 +59,8 @@ type ROAgent struct { signer ROSigner } +// NewROAgent creates a new SSH agent which forwards signature requests to the +// provided remote server func NewROAgent(server *client.RemoteServer, pubKey ssh.PublicKey, encryptedPrivKey []byte, user, pswd string) agent.Agent { return &ROAgent{ ROSigner{ @@ -76,21 +73,22 @@ func NewROAgent(server *client.RemoteServer, pubKey ssh.PublicKey, encryptedPriv } } +// RemoveAll has no effect for the ROAgent func (r *ROAgent) RemoveAll() error { return nil } -// Remove removes all identities with the given public key. +// Remove has no effect for the ROAgent func (r *ROAgent) Remove(key ssh.PublicKey) error { return nil } -// Lock locks the agent. Sign and Remove will fail, and List will empty an empty list. +// Lock has no effect for the ROAgent func (r *ROAgent) Lock(passphrase []byte) error { return nil } -// Unlock undoes the effect of Lock +// Unlock has no effect for the ROAgent func (r *ROAgent) Unlock(passphrase []byte) error { return nil } @@ -101,14 +99,12 @@ func (r *ROAgent) List() ([]*agent.Key, error) { { Format: r.signer.PublicKey().Type(), Blob: r.signer.PublicKey().Marshal(), - Comment: "", + Comment: "Red October encrypted SSH key", }, }, nil } -// Insert adds a private key to the ROAgent. If a certificate -// is given, that certificate is added as public key. Note that -// any constraints given are ignored. +// Add has no effect for the ROAgent func (r *ROAgent) Add(key agent.AddedKey) error { return nil } diff --git a/cryptor/cryptor.go b/cryptor/cryptor.go index cb88ccf..7223801 100644 --- a/cryptor/cryptor.go +++ b/cryptor/cryptor.go @@ -61,21 +61,21 @@ func New(records *passvault.Records, cache *keycache.Cache, config *config.Confi // both, then he can decrypt it alone). If a predicate is present, it must be // satisfied to decrypt. type AccessStructure struct { - Minimum int - Names []string + Minimum int + Names []string LeftNames []string RightNames []string - Predicate string + Predicate string } // Implements msp.UserDatabase type UserDatabase struct { - names *[]string + names *[]string - records *passvault.Records - cache *keycache.Cache + records *passvault.Records + cache *keycache.Cache user string labels []string @@ -129,6 +129,9 @@ type EncryptedData struct { Version int VaultId int `json:",omitempty"` Labels []string `json:",omitempty"` + // Usages list the endpoints which may use this data + // If empty, only decryption in permitted + Usages []string `json:",omitempty"` Predicate string `json:",omitempty"` KeySet []MultiWrappedKey `json:",omitempty"` KeySetRSA map[string]SingleWrappedKey `json:",omitempty"` @@ -146,8 +149,8 @@ type pair struct { type mwkSlice []MultiWrappedKey type swkSlice []pair -func (s mwkSlice) Len() int { return len(s) } -func (s mwkSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s mwkSlice) Len() int { return len(s) } +func (s mwkSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func (s mwkSlice) Less(i, j int) bool { // Alphabetic order var shorter = i if len(s[i].Name) > len(s[j].Name) { @@ -184,8 +187,9 @@ func (encrypted *EncryptedData) computeHmac(key []byte) []byte { } sort.Sort(&swks) - // sort the labels + // sort the labels and usages sort.Strings(encrypted.Labels) + sort.Strings(encrypted.Usages) // start hashing mac.Write([]byte(strconv.Itoa(encrypted.Version))) @@ -210,8 +214,13 @@ func (encrypted *EncryptedData) computeHmac(key []byte) []byte { mac.Write(encrypted.Data) // hash the labels - for index := range encrypted.Labels { - mac.Write([]byte(encrypted.Labels[index])) + for _, label := range encrypted.Labels { + mac.Write([]byte(label)) + } + + // hash the usages + for _, usage := range encrypted.Usages { + mac.Write([]byte(usage)) } return mac.Sum(nil) @@ -493,7 +502,7 @@ func (encrypted *EncryptedData) unwrapKey(cache *keycache.Cache, user string) (u // Encrypt encrypts data with the keys associated with names. This // requires a minimum of min keys to decrypt. NOTE: as currently // implemented, the maximum value for min is 2. -func (c *Cryptor) Encrypt(in []byte, labels []string, access AccessStructure) (resp []byte, err error) { +func (c *Cryptor) Encrypt(in []byte, labels []string, usages []string, access AccessStructure) (resp []byte, err error) { var encrypted EncryptedData encrypted.Version = DEFAULT_VERSION if encrypted.VaultId, err = c.records.GetVaultID(); err != nil { @@ -530,6 +539,7 @@ func (c *Cryptor) Encrypt(in []byte, labels []string, access AccessStructure) (r encrypted.Data = encryptedFile encrypted.Labels = labels + encrypted.Usages = usages hmacKey, err := c.records.GetHMACKey() if err != nil { @@ -542,18 +552,18 @@ func (c *Cryptor) Encrypt(in []byte, labels []string, access AccessStructure) (r } // Decrypt decrypts a file using the keys in the key cache. -func (c *Cryptor) Decrypt(in []byte, user string) (resp []byte, labels, names []string, secure bool, err error) { +func (c *Cryptor) Decrypt(in []byte, user string) (resp []byte, labels, names []string, usages []string, secure bool, err error) { return c.decrypt(c.cache, in, user) } -func (c *Cryptor) decrypt(cache *keycache.Cache, in []byte, user string) (resp []byte, labels, names []string, secure bool, err error) { +func (c *Cryptor) decrypt(cache *keycache.Cache, in []byte, user string) (resp []byte, labels, names []string, usages []string, secure bool, err error) { // unwrap encrypted file var encrypted EncryptedData if err = json.Unmarshal(in, &encrypted); err != nil { return } if encrypted.Version != DEFAULT_VERSION && encrypted.Version != -1 { - return nil, nil, nil, secure, errors.New("Unknown version") + return nil, nil, nil, nil, secure, errors.New("Unknown version") } secure = encrypted.Version == -1 @@ -573,7 +583,7 @@ func (c *Cryptor) decrypt(cache *keycache.Cache, in []byte, user string) (resp [ return } if encrypted.VaultId != vaultId { - return nil, nil, nil, secure, errors.New("Wrong vault") + return nil, nil, nil, nil, secure, errors.New("Wrong vault") } // compute HMAC @@ -602,6 +612,7 @@ func (c *Cryptor) decrypt(cache *keycache.Cache, in []byte, user string) (resp [ resp, err = padding.RemovePadding(clearData) labels = encrypted.Labels + usages = encrypted.Usages return } @@ -726,7 +737,7 @@ func (c *Cryptor) store() error { Predicate: c.persist.Policy(), } - cache, err = c.Encrypt(cache, persist.Labels, access) + cache, err = c.Encrypt(cache, persist.Labels, persist.Usages, access) if err != nil { return err } @@ -764,7 +775,7 @@ func (c *Cryptor) Restore(name, password string, uses int, slot, durationString // just means there aren't enough delegations yet; the // sentinal value ErrRestoreDelegations is returned to // indicate this. However, the error - cache, _, names, _, err := c.decrypt(c.persist.Cache(), c.persist.Blob(), name) + cache, _, _, names, _, err := c.decrypt(c.persist.Cache(), c.persist.Blob(), name) if err != nil { if err == msp.ErrNotEnoughShares { return ErrRestoreDelegations diff --git a/cryptor/cryptor_test.go b/cryptor/cryptor_test.go index 53e2ee4..41eac79 100644 --- a/cryptor/cryptor_test.go +++ b/cryptor/cryptor_test.go @@ -111,7 +111,7 @@ func TestDuplicates(t *testing.T) { RightNames: right, } - resp, err := c.Encrypt([]byte("Hello World!"), []string{}, ac) + resp, err := c.Encrypt([]byte("Hello World!"), []string{}, []string{}, ac) if err != nil { t.Fatalf("Error: %s", err) }