blob: e3bbfbdfe4443df7b3a5569e24f69a797983c9e1 [file] [log] [blame]
// Package agent provides a client for communicating with an "Agent"
// process holding the private key for an identity.
package agent
import (
"fmt"
"net"
"os"
"veyron.io/veyron/veyron/lib/unixfd"
"veyron.io/veyron/veyron2/context"
"veyron.io/veyron/veyron2/ipc"
"veyron.io/veyron/veyron2/naming"
"veyron.io/veyron/veyron2/security"
"veyron.io/veyron/veyron2/security/wire"
)
// FdVarName is the name of the environment variable containing
// the file descriptor for talking to the agent.
const FdVarName = "VEYRON_AGENT_FD"
type client struct {
client ipc.Client
name string
ctx context.T
key security.PublicKey
}
func (c *client) call(name string, result interface{}, args ...interface{}) (err error) {
var call ipc.Call
if call, err = c.client.StartCall(c.ctx, c.name, name, args); err == nil {
if ierr := call.Finish(result, &err); ierr != nil {
err = ierr
}
}
return
}
// NewAgentSigner returns a Signer using the PrivateKey held in a remote agent process.
// 'fd' is the socket for connecting to the agent, typically obtained from
// os.GetEnv(agent.FdVarName).
// 'ctx' should not have a deadline, and should never be cancelled.
func NewAgentSigner(c ipc.Client, fd int, ctx context.T) (security.Signer, error) {
conn, err := net.FileConn(os.NewFile(uintptr(fd), "agent_client"))
if err != nil {
return nil, err
}
// This is just an arbitrary 1 byte string. The value is ignored.
data := make([]byte, 1)
addr, err := unixfd.SendConnection(conn.(*net.UnixConn), data)
if err != nil {
return nil, err
}
agent := &client{c, naming.JoinAddressName(naming.FormatEndpoint(addr.Network(), addr.String()), ""), ctx, nil}
if err := agent.fetchPublicKey(); err != nil {
return nil, err
}
return agent, nil
}
func (c *client) fetchPublicKey() (err error) {
var key wire.PublicKey
if err = c.call("PublicKey", &key); err != nil {
return
}
c.key, err = key.Decode()
return
}
func (c *client) PublicKey() security.PublicKey {
return c.key
}
func (c *client) Sign(purpose, message []byte) (sig security.Signature, err error) {
if purpose != nil {
err = fmt.Errorf("purpose not supported")
return
}
err = c.call("Sign", &sig, message)
return
}