forked from libp2p/go-libp2p
-
Notifications
You must be signed in to change notification settings - Fork 0
/
insecure.go
233 lines (193 loc) · 6.45 KB
/
insecure.go
1
2
3
4
5
6
7
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
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
// Package insecure provides an insecure, unencrypted implementation of the SecureConn and SecureTransport interfaces.
//
// Recommended only for testing and other non-production usage.
package insecure
import (
"context"
"fmt"
"io"
"net"
ci "github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/core/protocol"
"github.com/libp2p/go-libp2p/core/sec"
"github.com/libp2p/go-libp2p/core/sec/insecure/pb"
"github.com/libp2p/go-msgio"
"google.golang.org/protobuf/proto"
)
//go:generate protoc --proto_path=$PWD:$PWD/../../.. --go_out=. --go_opt=Mpb/plaintext.proto=./pb pb/plaintext.proto
// ID is the multistream-select protocol ID that should be used when identifying
// this security transport.
const ID = "/plaintext/2.0.0"
// Transport is a no-op stream security transport. It provides no
// security and simply mocks the security methods. Identity methods
// return the local peer's ID and private key, and whatever the remote
// peer presents as their ID and public key.
// No authentication of the remote identity is performed.
type Transport struct {
id peer.ID
key ci.PrivKey
protocolID protocol.ID
}
var _ sec.SecureTransport = &Transport{}
// NewWithIdentity constructs a new insecure transport. The public key is sent to
// remote peers. No security is provided.
func NewWithIdentity(protocolID protocol.ID, id peer.ID, key ci.PrivKey) *Transport {
return &Transport{
protocolID: protocolID,
id: id,
key: key,
}
}
// LocalPeer returns the transport's local peer ID.
func (t *Transport) LocalPeer() peer.ID {
return t.id
}
// SecureInbound *pretends to secure* an inbound connection to the given peer.
// It sends the local peer's ID and public key, and receives the same from the remote peer.
// No validation is performed as to the authenticity or ownership of the provided public key,
// and the key exchange provides no security.
//
// SecureInbound may fail if the remote peer sends an ID and public key that are inconsistent
// with each other, or if a network error occurs during the ID exchange.
func (t *Transport) SecureInbound(_ context.Context, insecure net.Conn, p peer.ID) (sec.SecureConn, error) {
conn := &Conn{
Conn: insecure,
local: t.id,
localPubKey: t.key.GetPublic(),
}
if err := conn.runHandshakeSync(); err != nil {
return nil, err
}
if p != "" && p != conn.remote {
return nil, fmt.Errorf("remote peer sent unexpected peer ID. expected=%s received=%s", p, conn.remote)
}
return conn, nil
}
// SecureOutbound *pretends to secure* an outbound connection to the given peer.
// It sends the local peer's ID and public key, and receives the same from the remote peer.
// No validation is performed as to the authenticity or ownership of the provided public key,
// and the key exchange provides no security.
//
// SecureOutbound may fail if the remote peer sends an ID and public key that are inconsistent
// with each other, or if the ID sent by the remote peer does not match the one dialed. It may
// also fail if a network error occurs during the ID exchange.
func (t *Transport) SecureOutbound(_ context.Context, insecure net.Conn, p peer.ID) (sec.SecureConn, error) {
conn := &Conn{
Conn: insecure,
local: t.id,
localPubKey: t.key.GetPublic(),
}
if err := conn.runHandshakeSync(); err != nil {
return nil, err
}
if p != conn.remote {
return nil, fmt.Errorf("remote peer sent unexpected peer ID. expected=%s received=%s",
p, conn.remote)
}
return conn, nil
}
func (t *Transport) ID() protocol.ID { return t.protocolID }
// Conn is the connection type returned by the insecure transport.
type Conn struct {
net.Conn
local, remote peer.ID
localPubKey, remotePubKey ci.PubKey
}
func makeExchangeMessage(pubkey ci.PubKey) (*pb.Exchange, error) {
keyMsg, err := ci.PublicKeyToProto(pubkey)
if err != nil {
return nil, err
}
id, err := peer.IDFromPublicKey(pubkey)
if err != nil {
return nil, err
}
return &pb.Exchange{
Id: []byte(id),
Pubkey: keyMsg,
}, nil
}
func (ic *Conn) runHandshakeSync() error {
// If we were initialized without keys, behave as in plaintext/1.0.0 (do nothing)
if ic.localPubKey == nil {
return nil
}
// Generate an Exchange message
msg, err := makeExchangeMessage(ic.localPubKey)
if err != nil {
return err
}
// Send our Exchange and read theirs
remoteMsg, err := readWriteMsg(ic.Conn, msg)
if err != nil {
return err
}
// Pull remote ID and public key from message
remotePubkey, err := ci.PublicKeyFromProto(remoteMsg.Pubkey)
if err != nil {
return err
}
remoteID, err := peer.IDFromBytes(remoteMsg.Id)
if err != nil {
return err
}
// Validate that ID matches public key
if !remoteID.MatchesPublicKey(remotePubkey) {
calculatedID, _ := peer.IDFromPublicKey(remotePubkey)
return fmt.Errorf("remote peer id does not match public key. id=%s calculated_id=%s",
remoteID, calculatedID)
}
// Add remote ID and key to conn state
ic.remotePubKey = remotePubkey
ic.remote = remoteID
return nil
}
// read and write a message at the same time.
func readWriteMsg(rw io.ReadWriter, out *pb.Exchange) (*pb.Exchange, error) {
const maxMessageSize = 1 << 16
outBytes, err := proto.Marshal(out)
if err != nil {
return nil, err
}
wresult := make(chan error)
go func() {
w := msgio.NewVarintWriter(rw)
wresult <- w.WriteMsg(outBytes)
}()
r := msgio.NewVarintReaderSize(rw, maxMessageSize)
b, err1 := r.ReadMsg()
// Always wait for the read to finish.
err2 := <-wresult
if err1 != nil {
return nil, err1
}
if err2 != nil {
r.ReleaseMsg(b)
return nil, err2
}
inMsg := new(pb.Exchange)
err = proto.Unmarshal(b, inMsg)
return inMsg, err
}
// LocalPeer returns the local peer ID.
func (ic *Conn) LocalPeer() peer.ID {
return ic.local
}
// RemotePeer returns the remote peer ID if we initiated the dial. Otherwise, it
// returns "" (because this connection isn't actually secure).
func (ic *Conn) RemotePeer() peer.ID {
return ic.remote
}
// RemotePublicKey returns whatever public key was given by the remote peer.
// Note that no verification of ownership is done, as this connection is not secure.
func (ic *Conn) RemotePublicKey() ci.PubKey {
return ic.remotePubKey
}
// ConnState returns the security connection's state information.
func (ic *Conn) ConnState() network.ConnectionState {
return network.ConnectionState{}
}
var _ sec.SecureTransport = (*Transport)(nil)
var _ sec.SecureConn = (*Conn)(nil)