mixnet

package
v0.0.0-...-9db400c Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 10, 2015 License: Apache-2.0 Imports: 15 Imported by: 0

README

Mixnet over CloudProxy

A mixnet router facilitates anonymous communications among a set of peers. Alice wants to send Msg to Bob; she encrypts, authenticates, and sends the message (Msg, Bob) to Molly, a mixnet router. Molly waits until she has n-1 more messages from n-1 other peers, then transmits the messages to their respective destinations simultaneously, thus anonymizing Alice among a set of n peers. Such a service is only useful if Molly can be trusted to not divulge the link (Alice, Bob). This document specifies a simple mixnet built on the CloudProxy platform that reduces this trust to the knowledge of a public key and trust in the owner of that key.

Security goals and threat model

There are three principals in our protocol: the sender, recipient, and the policy owner. Our goal is to design a protocol that provides anonymity for senders without requiring the recipient to execute the protocol. The policy owner controls the root policy private key that is used to attest to the instantiation of mixnet routers using the CloudProxy platform. CloudProxy exposes the code to the users, as well as the operating system in which it is running. To instantiate a mixnet router, a TPM coupled with the hardware platform generates a public key, which is attested to by the policy owner by signing it with the private policy key. When the machine boots, the OS is measured and generates a private/public key pair, which is attested to by the TPM; finally, the mixnet code itself is measured and generates a private/public key pair, which is attested to by the OS. Hence, trust in the mixnet routers to faithfully carry out the protocol is reduced to correct provisioning of the policy key.

We consider a global passive adversary who observes all communications between senders and mixnet routers, mixnet routers and other mixnet routers, and mixnet routers and recipients. The adversary may also send messages on channels it observes. Since the service is anonymous, the adversary is allowed to control any number of senders or recipients. The effect is that the state of that peer is exposed, including any and all cryptographic keys. We assume that the policy key was correctly provisioned; if the code implements the protocol correctly and is properly isolated during its execution, we claim this precludes the possibility of exposing a router’s state. (This is a strong claim offered here without proof. CloudProxy provides assurance that the expected program is running; assuming the code does not contain any bugs that allow it to be comprimised, a formal treatment of our protocol should reduce the adversary's control of the routers to standard cryptographic assumptions: in particular, CDH on elliptic curves, as well as the integrity and confidentiality of the cipher suite underyling TLS.)

The intended property of communications over the mixnet is unlinkability in the sense of [1]. Consider a set of senders S where |S| = n and a set of recipients T. Each sender chooses one recipient as well as a message to send so that M : S → T is an onto mapping. The messages are transmitted to their respective recipients over the mixnet; the adversary succeeds if it outputs (s, t) such that M(s) = t, unless it controls both s and t. We say that communication over the mixnet is unlinkable if for any adversary the probability of success is less than 1/n plus some negligible value.

Alternative definition: as above, except the adversary chooses the messages to be sent. This change may make it easier to analyze the unlinkability of a particular protocol. However, this would require the recipients to participate in the protocol, since messages exiting the mixnet must be encrypted.

For a protocol to achieve security in this sense, the messages must all have the same length; of course, this is not always reasonable in practice. Mixnets address this by splitting messages into fixed-length cells. Senders split messages into cells (zero-padding the last cell as needed) and send them to the first router where they are added to a queue. At each round the router waits until there are m cells in the queue from m distinct senders and transmits these simultaneously to achieve anonymity.

Extending the definition of unlinkability to a mixnet that divides messages into cells and transmits at rounds is challenging: the presence of variable-length messages exposes traffic patterns to the adversary. One way to mitigate this problem is to zero-pad all messages to the length of the longest message. This achieves a property called unobservability [1] which is too expensive for our purposes.

Another appraoch is to weaken the security model to one in which the adversary may only observe a fraction of the network at any one time; relaying messages over circuits of routers may make it more difficult to perform traffic analysis. This is the case for the design of the Tor onion-routing protocol [2]. We will consider extending our protocol to a network of routers to achieve security in this model. This approach may have the added benifit of reducing latency of messages traversing the mixnet.

Design

We designed the mixnet to proxy client/server protocols. There are two main components of the protocol: the proxy (mixnet_proxy) accepts arbitrary TCP connections from a client and relays messages over the mixnet to the server; the router (mixnet_router) accepts connections from a proxy and performs the mixnet operations. The proxy and router perform a one-way authenticated TLS handshake to exchange a key for wrapping (encrypting and authenticating) messages sent between them. Messages sent between proxies and routers (or routers and routers) are fixed length cells.

The protocol for a single proxy and router is as follows. To send a message to a server, the client sends the message to the proxy which divides the message into cells and sends them to the router. The router waits until it has received all the cells, then assembles them into the original message. Once the router has queued messages from enough senders, it transmits the message to the server. It then waits for a reply from the server, divides the reply into cells, and queues the cells to be transmitted back to the proxy. The proxy waits until it has received all the reply cells, assembles them into the complete message, and sends it back to the client.

The router maintains two data structures: the sendQueue for sender to recipient traffic, and the replyQueue for recipient to sender traffic. They are functionally equivalent (see queue.go); they receive cells from proxies (or other routers) and replies from recipients, and they send cells to proxies (or other routers) and messages to recipients. The batchSize specifies how many messages/cells are waiting in the queue from distinct peers before transmitting them. When its time to transmit, a connection to the destination is established (if it hasn't been established already) and the messages are sent in a random order.

A cell is either a chunk of a message or a directive. A directive contains instructions for a router or proxy and are implemented as protocol buffers (mixnet.proto):

  • ERROR: something went wrong.
  • CREATE: the proxy instructs the router to create a circuit over the mixnet to a destination address. The response is either ERROR or CREATED.
  • CREATED: the router informs the proxy that the circuit was created.
  • DESTROY: the proxy instructs the router to destroy the circuit.

Note that when a circuit is created, all that happens is the router is informed of the destination server. The connection is established when the router is ready to dequeue; otherwise, the TCP handshake would allow the adversary to correlate the wrapped CREATE directive with the TCP handshake.

The router (router.go) is a Tao-delegated program and will only run when launched in a Tao environment. The proxy (proxy.go) is not launched in the Tao and is expected to run locally on the client's machine. It is assumed that the client has a copy of the root public policy key. When the proxy dials the router, the router attests to its identity, and the attestation is verified by the proxy using the policy key; if verification fails, the proxy exits. Both the proxy and router communicate with the TaoCA to obtain a copy of the policy.

The proxy implements SOCKS [3], a widely a widely used protocol that allows a server to proxy client internet traffic. (See socks.go.) Our proxy only partially implements the server role; see SocksListener.Accept() for details. For example, it only allows the client to specify IPv4 addresses, which excludes DNS-based host names.

Our implementation so far only allows a mixnet with a single router; router-to-router communication and construction/destruction of multi-hop circuits still need to be implemented. Notice that our design makes no attempt to preserve the confidentiality or integrity of cells on the routers; as a result, every router a message traverses would learn its intended destination, as well as the contents of the message. This problem is addressed in Tor using onion-routing, a technique that ensures each router knows only the previous and next hops in the circuit. Doing this in a way that preserves forward secrecy makes the circuit construction expensive, since the proxy needs to exchange a key with each hop successively. Since the client can be assured of the identity of the routers via the root of trust, and trusting the code is secure, we could construct the circuit in one pass.

References

[1] Andreas Pfitzman, 2010. A terminology for talking about privacy by data minimization: Anonymity, Unlinkability, Undetectability, Unobservability, Pseudonymity, and Identity Management. https://dud.inf.tu-dresden.de/literatur/Anon_Terminology_v0.34.pdf

[2] Tor specification. https://svn.torproject.org/svn/projects/design-paper/tor-design.pdf

[3] SOCKS Protocol Version 5. http://tools.ietf.org/html/rfc1928

Documentation

Overview

Package mixnet is a generated protocol buffer package.

It is generated from these files:

mixnet.proto

It has these top-level messages:

Directive

Index

Constants

View Source
const (

	// CellBytes specifies the length of a cell.
	CellBytes = 1 << 10

	// MaxMsgBytes specifies the maximum length of a message.
	MaxMsgBytes = 1 << 16
)
View Source
const (
	SocksVersion            = 0x05
	SocksMethodNoAuth       = 0x00
	SocksNoAcceptableMethod = 0xff
	SocksCmdConnect         = 0x01
	SocksAtypIPv4           = 0x01
	SocksRepSuccess         = 0x00
	SocksRepFailure         = 0x01
	SocksRepUnsupported     = 0x07
)

Codes used in the RFC standard of SOCKS version 5.

Variables

View Source
var DirectiveType_name = map[int32]string{
	0: "ERROR",
	1: "CREATE",
	2: "CREATED",
	3: "DESTROY",
}
View Source
var DirectiveType_value = map[string]int32{
	"ERROR":   0,
	"CREATE":  1,
	"CREATED": 2,
	"DESTROY": 3,
}

Functions

func SocksListen

func SocksListen(network, addr string) (net.Listener, error)

SocksListen binds an address to a socket and returns a SocksListener for serving SOCKS clients.

Types

type Conn

type Conn struct {
	net.Conn
	// contains filtered or unexported fields
}

Conn implements the net.Conn interface. The read and write operations are overloaded to check that only cells are sent between entities in the mixnet protocol.

func (*Conn) GetID

func (c *Conn) GetID() uint64

GetID returns the connection's serial ID.

func (*Conn) Read

func (c *Conn) Read(msg []byte) (n int, err error)

Read a cell from the channel. If len(msg) != CellBytes, return an error.

func (*Conn) Write

func (c *Conn) Write(msg []byte) (n int, err error)

Write a cell to the channel. If the len(cell) != CellBytes, return an error.

type Directive

type Directive struct {
	Type *DirectiveType `protobuf:"varint,1,req,name=type,enum=mixnet.DirectiveType" json:"type,omitempty"`
	// CREATE, a sequence of addresses (e.g. "192.168.1.1:7007")
	// comprising the circuit to be constructed over the mixnet. Each address
	// corresponds to a mixnet router except the last, which is the service the
	// proxy would like to contact.
	Addrs []string `protobuf:"bytes,2,rep,name=addrs" json:"addrs,omitempty"`
	// ERROR or FATAL, an error message.
	Error            *string `protobuf:"bytes,3,opt,name=error" json:"error,omitempty"`
	XXX_unrecognized []byte  `json:"-"`
}

func (*Directive) GetAddrs

func (m *Directive) GetAddrs() []string

func (*Directive) GetError

func (m *Directive) GetError() string

func (*Directive) GetType

func (m *Directive) GetType() DirectiveType

func (*Directive) ProtoMessage

func (*Directive) ProtoMessage()

func (*Directive) Reset

func (m *Directive) Reset()

func (*Directive) String

func (m *Directive) String() string

type DirectiveType

type DirectiveType int32
const (
	DirectiveType_ERROR   DirectiveType = 0
	DirectiveType_CREATE  DirectiveType = 1
	DirectiveType_CREATED DirectiveType = 2
	DirectiveType_DESTROY DirectiveType = 3
)

func (DirectiveType) Enum

func (x DirectiveType) Enum() *DirectiveType

func (DirectiveType) String

func (x DirectiveType) String() string

func (*DirectiveType) UnmarshalJSON

func (x *DirectiveType) UnmarshalJSON(data []byte) error

type ProxyContext

type ProxyContext struct {
	// contains filtered or unexported fields
}

ProxyContext stores the runtime environment for a mixnet proxy. A mixnet proxy connects to a mixnet router on behalf of a client's application.

func NewProxyContext

func NewProxyContext(path, network, addr string, timeout time.Duration) (p *ProxyContext, err error)

NewProxyContext loads a domain from a local configuration.

func (*ProxyContext) Accept

func (p *ProxyContext) Accept() (net.Conn, error)

Accept waits for clients running the SOCKS5 protocol.

func (*ProxyContext) Close

func (p *ProxyContext) Close()

Close unbinds the proxy server socket.

func (*ProxyContext) CreateCircuit

func (p *ProxyContext) CreateCircuit(addrs ...string) (*Conn, error)

CreateCircuit connects anonymously to a remote Tao-delegated mixnet router specified by addrs[0]. It directs the router to construct a circuit to a particular destination over the mixnet specified by addrs[len(addrs)-1].

func (*ProxyContext) DestroyCircuit

func (p *ProxyContext) DestroyCircuit(c *Conn) error

DestroyCircuit directs the router to close the connection to the destination and destroy the circuit then closes the connection. TODO(cjpatton) in order to support multi-hop circuits, this code will need to wait for a DESTROYED directive from the first hop.

func (*ProxyContext) DialRouter

func (p *ProxyContext) DialRouter(network, addr string) (*Conn, error)

DialRouter connects anonymously to a remote Tao-delegated mixnet router.

func (*ProxyContext) HandleClient

func (p *ProxyContext) HandleClient(c net.Conn, d *Conn) error

HandleClient relays a message read from client connection c to mixnet connection d and relay reply.

func (*ProxyContext) ReceiveDirective

func (p *ProxyContext) ReceiveDirective(c *Conn, d *Directive) (int, error)

ReceiveDirective awaits a reply from the peer and returns the directive received, e.g. in response to RouterContext.HandleProxy(). If the directive type is ERROR, return an error.

func (*ProxyContext) ReceiveMessage

func (p *ProxyContext) ReceiveMessage(c *Conn) ([]byte, error)

ReceiveMessage reads message cells from the router and assembles them into a messsage.

func (*ProxyContext) SendDirective

func (p *ProxyContext) SendDirective(c *Conn, d *Directive) (int, error)

SendDirective serializes and pads a directive to the length of a cell and sends it to the peer. A directive is signaled to the receiver by the first byte of the cell. The next few bytes encode the length of of the serialized protocol buffer. If the buffer doesn't fit in a cell, then throw an error.

func (*ProxyContext) SendMessage

func (p *ProxyContext) SendMessage(c *Conn, msg []byte) error

SendMessage divides a message into cells and sends each cell over the network connection. A message is signaled to the receiver by the first byte of the first cell. The next few bytes encode the total number of bytes in the message.

func (*ProxyContext) ServeClient

func (p *ProxyContext) ServeClient(c net.Conn, addrs ...string) error

ServeClient creates a circuit over the mixnet and relays messages to a destination (specified by addrs[len(addrs)-1]) on behalf of the client. Read a message from the client, send it over the mixnet, wait for a reply, and forward it the client. Once an EOF is encountered (or some other error occurs), destroy the circuit.

type Queue

type Queue struct {
	// contains filtered or unexported fields
}

The Queue structure maps a serial identifier corresponding to a sender (in the router context) to a destination. It also maintains a message buffer for each sender. Once there messages ready on enough buffers, a batch of messages are transmitted simultaneously.

func NewQueue

func NewQueue(network string, batchSize int, timeout time.Duration) (sq *Queue)

NewQueue creates a new Queue structure.

func (*Queue) Close

func (sq *Queue) Close(id uint64)

Close creates a queueable object that closes the connection and deletes all associated resources.

func (*Queue) DoQueue

func (sq *Queue) DoQueue(kill <-chan bool)

DoQueue adds messages to a queue and transmits messages in batches. It also provides an interface for receiving messages from a server. Typically a message is a cell, but when the calling router is an exit point, the message length is arbitrary. A batch is transmitted when there are messages on batchSize distinct sender channels.

func (*Queue) DoQueueErrorHandler

func (sq *Queue) DoQueueErrorHandler(queue *Queue, kill <-chan bool)

DoQueueErrorHandler handles errors produced by DoQueue by enqueing onto queue a directive containing the error message.

func (*Queue) DoQueueErrorHandlerLog

func (sq *Queue) DoQueueErrorHandlerLog(name string, kill <-chan bool)

DoQueueErrorHandlerLog logs errors that occur on this queue.

func (*Queue) Enqueue

func (sq *Queue) Enqueue(q *Queueable)

Enqueue inserts a queueable object into the queue. Note that this is generally unsafe to use concurrently because it doesn't make a copy of the data.

func (*Queue) EnqueueMsg

func (sq *Queue) EnqueueMsg(id uint64, msg []byte)

EnqueueMsg copies a byte slice into a queueable object and adds it to the queue.

func (*Queue) EnqueueMsgReply

func (sq *Queue) EnqueueMsgReply(id uint64, msg []byte, reply chan []byte)

EnqueueMsgReply creates a queueable object with a message and a reply channel and adds it to the queue.

func (*Queue) EnqueueReply

func (sq *Queue) EnqueueReply(id uint64, reply chan []byte)

EnqueueReply creates a queuable object with a reply channel and adds it to the queue.

func (*Queue) SetAddr

func (sq *Queue) SetAddr(id uint64, addr string)

SetAddr copies an address into a queuable object and adds it to the queue. This sets the next-hop address for the id.

func (*Queue) SetConn

func (sq *Queue) SetConn(id uint64, c net.Conn)

SetConn creates a queueable object with a net.Conn interface and adds it to the queue. This allows us to reuse an already created channel for replying.

type Queueable

type Queueable struct {
	// contains filtered or unexported fields
}

The Queueable object is passed through a channel and mutates the state of the Queue in some manner; for example, it can set the destination adddress or connection of a sender, add a message or request for reply to the queue, or destroy any resources associated with the connection.

type RouterContext

type RouterContext struct {
	// contains filtered or unexported fields
}

RouterContext stores the runtime environment for a Tao-delegated router.

func NewRouterContext

func NewRouterContext(path, network, addr string, batchSize int, timeout time.Duration,
	x509Identity *pkix.Name, t tao.Tao) (hp *RouterContext, err error)

NewRouterContext generates new keys, loads a local domain configuration from path and binds an anonymous listener socket to addr on network network. A delegation is requested from the Tao t which is nominally the parent of this hosted program.

func (*RouterContext) AcceptProxy

func (hp *RouterContext) AcceptProxy() (*Conn, error)

AcceptProxy Waits for connectons from proxies.

func (*RouterContext) Close

func (hp *RouterContext) Close()

Close releases any resources held by the hosted program.

func (*RouterContext) HandleProxy

func (hp *RouterContext) HandleProxy(c *Conn) error

HandleProxy reads a directive or a message from a proxy.

func (*RouterContext) SendError

func (hp *RouterContext) SendError(c *Conn, err error) error

SendError sends an error message to a client.

type SocksConn

type SocksConn struct {
	net.Conn
	// contains filtered or unexported fields
}

SocksConn implements the net.Conn interface and contains a destination network and address for the proxy.

func (*SocksConn) DestinationAddr

func (c *SocksConn) DestinationAddr() string

DestinationAddr returns the destination address negotiated in the SOCKS protocol.

type SocksListener

type SocksListener struct {
	net.Listener
	// contains filtered or unexported fields
}

SocksListener implements the net.Listener interface as a SOCKS server. This program partially implements the server role in version 5 of the SOCKS protocol specified in RFC 1928. In particular, it only supports TCP clients with no authentication who request CONNECT to IPv4 addresses; neither BIND nor UDP ASSOCIATE are supported.

func (*SocksListener) Accept

func (l *SocksListener) Accept() (net.Conn, error)

Accept exposes the SOCKS5 protocol to connecting client. Return the connection and the requested destination address.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL