interface.go 3 KB
Newer Older
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
1
2
3
4
5
6
// package secio handles establishing secure communication between two peers.
package secio

import (
	"io"

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
7
	ci "github.com/ipfs/go-libp2p/p2p/crypto"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
8

Jeromy's avatar
Jeromy committed
9
10
	msgio "github.com/jbenet/go-msgio"
	context "golang.org/x/net/context"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
11
	peer "github.com/ipfs/go-libp2p/p2p/peer"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
12
13
14
15
16
17
18
19
)

// SessionGenerator constructs secure communication sessions for a peer.
type SessionGenerator struct {
	LocalID    peer.ID
	PrivateKey ci.PrivKey
}

20
// NewSession takes an insecure io.ReadWriter, sets up a TLS-like
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
21
// handshake with the other side, and returns a secure session.
22
// The handshake isn't run until the connection is read or written to.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
23
24
// See the source for the protocol details and security implementation.
// The provided Context is only needed for the duration of this function.
25
26
func (sg *SessionGenerator) NewSession(ctx context.Context, insecure io.ReadWriteCloser) (Session, error) {
	return newSecureSession(ctx, sg.LocalID, sg.PrivateKey, insecure)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
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
}

type Session interface {
	// ReadWriter returns the encrypted communication channel
	ReadWriter() msgio.ReadWriteCloser

	// LocalPeer retrieves the local peer.
	LocalPeer() peer.ID

	// LocalPrivateKey retrieves the local private key
	LocalPrivateKey() ci.PrivKey

	// RemotePeer retrieves the remote peer.
	RemotePeer() peer.ID

	// RemotePublicKey retrieves the remote's public key
	// which was received during the handshake.
	RemotePublicKey() ci.PubKey

	// Close closes the secure session
	Close() error
}

// SecureReadWriter returns the encrypted communication channel
func (s *secureSession) ReadWriter() msgio.ReadWriteCloser {
52
53
54
	if err := s.Handshake(); err != nil {
		return &closedRW{err}
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
	return s.secure
}

// LocalPeer retrieves the local peer.
func (s *secureSession) LocalPeer() peer.ID {
	return s.localPeer
}

// LocalPrivateKey retrieves the local peer's PrivateKey
func (s *secureSession) LocalPrivateKey() ci.PrivKey {
	return s.localKey
}

// RemotePeer retrieves the remote peer.
func (s *secureSession) RemotePeer() peer.ID {
70
71
72
	if err := s.Handshake(); err != nil {
		return ""
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
73
74
75
76
77
	return s.remotePeer
}

// RemotePeer retrieves the remote peer.
func (s *secureSession) RemotePublicKey() ci.PubKey {
78
79
80
	if err := s.Handshake(); err != nil {
		return nil
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
81
82
83
84
85
	return s.remote.permanentPubKey
}

// Close closes the secure session
func (s *secureSession) Close() error {
86
87
88
89
90
91
	s.cancel()
	s.handshakeMu.Lock()
	defer s.handshakeMu.Unlock()
	if s.secure == nil {
		return s.insecure.Close() // hadn't secured yet.
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
92
93
	return s.secure.Close()
}
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126

// closedRW implements a stub msgio interface that's already
// closed and errored.
type closedRW struct {
	err error
}

func (c *closedRW) Read(buf []byte) (int, error) {
	return 0, c.err
}

func (c *closedRW) Write(buf []byte) (int, error) {
	return 0, c.err
}

func (c *closedRW) NextMsgLen() (int, error) {
	return 0, c.err
}

func (c *closedRW) ReadMsg() ([]byte, error) {
	return nil, c.err
}

func (c *closedRW) WriteMsg(buf []byte) error {
	return c.err
}

func (c *closedRW) Close() error {
	return c.err
}

func (c *closedRW) ReleaseMsg(m []byte) {
}