mirror of
				https://source.quilibrium.com/quilibrium/ceremonyclient.git
				synced 2025-11-04 03:07:28 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			234 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			234 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// 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)
 |