secure_conn.go 3.55 KB
Newer Older
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
1 2 3 4 5 6
package conn

import (
	"errors"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
7
	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95

	spipe "github.com/jbenet/go-ipfs/crypto/spipe"
	peer "github.com/jbenet/go-ipfs/peer"
)

// secureConn wraps another Conn object with an encrypted channel.
type secureConn struct {

	// the wrapped conn
	insecure Conn

	// secure pipe, wrapping insecure
	secure *spipe.SecurePipe

	ContextCloser
}

// newConn constructs a new connection
func newSecureConn(ctx context.Context, insecure Conn, peers peer.Peerstore) (Conn, error) {

	conn := &secureConn{
		insecure: insecure,
	}
	conn.ContextCloser = NewContextCloser(ctx, conn.close)

	log.Debug("newSecureConn: %v to %v", insecure.LocalPeer(), insecure.RemotePeer())
	// perform secure handshake before returning this connection.
	if err := conn.secureHandshake(peers); err != nil {
		conn.Close()
		return nil, err
	}
	log.Debug("newSecureConn: %v to %v handshake success!", insecure.LocalPeer(), insecure.RemotePeer())

	return conn, nil
}

// secureHandshake performs the spipe secure handshake.
func (c *secureConn) secureHandshake(peers peer.Peerstore) error {
	if c.secure != nil {
		return errors.New("Conn is already secured or being secured.")
	}

	// ok to panic here if this type assertion fails. Interface hack.
	// when we support wrapping other Conns, we'll need to change
	// spipe to do something else.
	insecureSC := c.insecure.(*singleConn)

	// setup a Duplex pipe for spipe
	insecureD := spipe.Duplex{
		In:  insecureSC.msgio.incoming.MsgChan,
		Out: insecureSC.msgio.outgoing.MsgChan,
	}

	// spipe performs the secure handshake, which takes multiple RTT
	sp, err := spipe.NewSecurePipe(c.Context(), 10, c.LocalPeer(), peers, insecureD)
	if err != nil {
		return err
	}

	// assign it into the conn object
	c.secure = sp

	// if we do not know RemotePeer, get it from secure chan (who identifies it)
	if insecureSC.remote == nil {
		insecureSC.remote = c.secure.RemotePeer()

	} else if insecureSC.remote != c.secure.RemotePeer() {
		// this panic is here because this would be an insidious programmer error
		// that we need to ensure we catch.
		// update: this actually might happen under normal operation-- should
		// perhaps return an error. TBD.

		log.Error("secureConn peer mismatch. %v != %v", insecureSC.remote, c.secure.RemotePeer())
		panic("secureConn peer mismatch. consructed incorrectly?")
	}

	return nil
}

// close is called by ContextCloser
func (c *secureConn) close() error {
	err := c.insecure.Close()
	if c.secure != nil { // may never have gotten here.
		err = c.secure.Close()
	}
	return err
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
96 97 98 99 100
// ID is an identifier unique to this connection.
func (c *secureConn) ID() string {
	return ID(c)
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
101 102 103 104
func (c *secureConn) String() string {
	return String(c, "secureConn")
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
105 106 107 108 109 110 111 112 113 114
// LocalMultiaddr is the Multiaddr on this side
func (c *secureConn) LocalMultiaddr() ma.Multiaddr {
	return c.insecure.LocalMultiaddr()
}

// RemoteMultiaddr is the Multiaddr on the remote side
func (c *secureConn) RemoteMultiaddr() ma.Multiaddr {
	return c.insecure.RemoteMultiaddr()
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
// LocalPeer is the Peer on this side
func (c *secureConn) LocalPeer() *peer.Peer {
	return c.insecure.LocalPeer()
}

// RemotePeer is the Peer on the remote side
func (c *secureConn) RemotePeer() *peer.Peer {
	return c.insecure.RemotePeer()
}

// In returns a readable message channel
func (c *secureConn) In() <-chan []byte {
	return c.secure.In
}

// Out returns a writable message channel
func (c *secureConn) Out() chan<- []byte {
	return c.secure.Out
}