2019-05-23 01:31:11 +08:00
|
|
|
// Package insecure provides an insecure, unencrypted implementation of the the SecureConn and SecureTransport interfaces.
|
|
|
|
//
|
|
|
|
// Recommended only for testing and other non-production usage.
|
|
|
|
package insecure
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2019-07-13 01:24:30 +08:00
|
|
|
"fmt"
|
|
|
|
"github.com/libp2p/go-libp2p-core/network"
|
2019-05-23 01:31:11 +08:00
|
|
|
"net"
|
|
|
|
|
|
|
|
"github.com/libp2p/go-libp2p-core/peer"
|
|
|
|
"github.com/libp2p/go-libp2p-core/sec"
|
|
|
|
|
2019-07-13 01:24:30 +08:00
|
|
|
ggio "github.com/gogo/protobuf/io"
|
2019-05-23 01:31:11 +08:00
|
|
|
ci "github.com/libp2p/go-libp2p-core/crypto"
|
2019-07-13 01:24:30 +08:00
|
|
|
pb "github.com/libp2p/go-libp2p-core/sec/insecure/pb"
|
2019-05-23 01:31:11 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
// ID is the multistream-select protocol ID that should be used when identifying
|
|
|
|
// this security transport.
|
2019-07-13 01:24:30 +08:00
|
|
|
const ID = "/plaintext/2.0.0"
|
2019-05-23 01:31:11 +08:00
|
|
|
|
|
|
|
// Transport is a no-op stream security transport. It provides no
|
2019-07-13 01:24:30 +08:00
|
|
|
// 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.
|
2019-05-23 01:31:11 +08:00
|
|
|
type Transport struct {
|
2019-07-13 01:24:30 +08:00
|
|
|
id peer.ID
|
|
|
|
key ci.PrivKey
|
2019-05-23 01:31:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// New constructs a new insecure transport.
|
2019-07-13 01:24:30 +08:00
|
|
|
func New(id peer.ID, key ci.PrivKey) *Transport {
|
2019-05-23 01:31:11 +08:00
|
|
|
return &Transport{
|
2019-07-13 01:24:30 +08:00
|
|
|
id: id,
|
|
|
|
key: key,
|
2019-05-23 01:31:11 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-13 01:24:30 +08:00
|
|
|
// LocalPeer returns the transport's local peer ID.
|
2019-05-23 01:31:11 +08:00
|
|
|
func (t *Transport) LocalPeer() peer.ID {
|
|
|
|
return t.id
|
|
|
|
}
|
|
|
|
|
2019-07-13 01:24:30 +08:00
|
|
|
// LocalPrivateKey returns the local private key.
|
|
|
|
// This key is used only for identity generation and provides no security.
|
2019-05-23 01:31:11 +08:00
|
|
|
func (t *Transport) LocalPrivateKey() ci.PrivKey {
|
2019-07-13 01:24:30 +08:00
|
|
|
return t.key
|
2019-05-23 01:31:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// SecureInbound *pretends to secure* an outbound connection to the given peer.
|
2019-07-13 01:24:30 +08:00
|
|
|
// 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.
|
2019-05-23 01:31:11 +08:00
|
|
|
func (t *Transport) SecureInbound(ctx context.Context, insecure net.Conn) (sec.SecureConn, error) {
|
2019-07-13 01:24:30 +08:00
|
|
|
conn := &Conn{
|
|
|
|
Conn: insecure,
|
|
|
|
local: t.id,
|
|
|
|
localPrivKey: t.key,
|
|
|
|
}
|
|
|
|
|
|
|
|
err := conn.runHandshakeSync(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return conn, nil
|
2019-05-23 01:31:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// SecureOutbound *pretends to secure* an outbound connection to the given peer.
|
2019-07-13 01:24:30 +08:00
|
|
|
// 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.
|
2019-05-23 01:31:11 +08:00
|
|
|
func (t *Transport) SecureOutbound(ctx context.Context, insecure net.Conn, p peer.ID) (sec.SecureConn, error) {
|
2019-07-13 01:24:30 +08:00
|
|
|
conn := &Conn{
|
|
|
|
Conn: insecure,
|
|
|
|
local: t.id,
|
|
|
|
localPrivKey: t.key,
|
|
|
|
}
|
|
|
|
|
|
|
|
err := conn.runHandshakeSync(ctx)
|
|
|
|
if 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
|
2019-05-23 01:31:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Conn is the connection type returned by the insecure transport.
|
|
|
|
type Conn struct {
|
|
|
|
net.Conn
|
2019-07-13 01:24:30 +08:00
|
|
|
|
2019-05-23 01:31:11 +08:00
|
|
|
local peer.ID
|
|
|
|
remote peer.ID
|
2019-07-13 01:24:30 +08:00
|
|
|
|
|
|
|
localPrivKey ci.PrivKey
|
|
|
|
remotePubKey ci.PubKey
|
|
|
|
}
|
|
|
|
|
|
|
|
func makeExchangeMessage(privkey ci.PrivKey) (*pb.Exchange, error) {
|
|
|
|
pubkey, err := ci.PublicKeyToProto(privkey.GetPublic())
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
id, err := peer.IDFromPrivateKey(privkey)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &pb.Exchange{
|
|
|
|
Id: []byte(id),
|
|
|
|
Pubkey: pubkey,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ic *Conn) runHandshakeSync(ctx context.Context) error {
|
|
|
|
reader := ggio.NewDelimitedReader(ic.Conn, network.MessageSizeMax)
|
|
|
|
writer := ggio.NewDelimitedWriter(ic.Conn)
|
|
|
|
|
|
|
|
// Generate an Exchange message
|
|
|
|
msg, err := makeExchangeMessage(ic.localPrivKey)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Send our Exchange and read theirs
|
|
|
|
err = writer.WriteMsg(msg)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
remoteMsg := new(pb.Exchange)
|
|
|
|
err = reader.ReadMsg(remoteMsg)
|
|
|
|
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.IDFromPublicKey(remotePubkey)
|
|
|
|
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
|
2019-05-23 01:31:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2019-07-13 01:24:30 +08:00
|
|
|
// 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.
|
2019-05-23 01:31:11 +08:00
|
|
|
func (ic *Conn) RemotePublicKey() ci.PubKey {
|
2019-07-13 01:24:30 +08:00
|
|
|
return ic.remotePubKey
|
2019-05-23 01:31:11 +08:00
|
|
|
}
|
|
|
|
|
2019-07-13 01:24:30 +08:00
|
|
|
// LocalPrivateKey returns the private key for the local peer.
|
2019-05-23 01:31:11 +08:00
|
|
|
func (ic *Conn) LocalPrivateKey() ci.PrivKey {
|
2019-07-13 01:24:30 +08:00
|
|
|
return ic.localPrivKey
|
2019-05-23 01:31:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
var _ sec.SecureTransport = (*Transport)(nil)
|
|
|
|
var _ sec.SecureConn = (*Conn)(nil)
|