Skip to content
This repository has been archived by the owner on Sep 6, 2022. It is now read-only.

update insecure transport to plaintext/2.0.0 #37

Merged
merged 10 commits into from
Jul 12, 2019
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 20 additions & 6 deletions crypto/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,29 +276,43 @@ func UnmarshalPublicKey(data []byte) (PubKey, error) {
if err != nil {
return nil, err
}
return PublicKeyFromProto(*pmes)
}

um, ok := PubKeyUnmarshallers[pmes.GetType()]
func PublicKeyFromProto(keyMessage pb.PublicKey) (PubKey, error) {
um, ok := PubKeyUnmarshallers[keyMessage.GetType()]
if !ok {
return nil, ErrBadKeyType
}

return um(pmes.GetData())
return um(keyMessage.GetData())
}

// MarshalPublicKey converts a public key object into a protobuf serialized
// public key
func MarshalPublicKey(k PubKey) ([]byte, error) {
pbmes := new(pb.PublicKey)
pbmes.Type = k.Type()
data, err := k.Raw()
pbmes, err := PublicKeyToProto(k)
if err != nil {
return nil, err
}
pbmes.Data = data

return proto.Marshal(pbmes)
}

// PublicKeyToProto converts a public key object into an unserialized protobuf
// PublicKey message.
func PublicKeyToProto(k PubKey) (*pb.PublicKey, error) {
data, err := k.Raw()
if err != nil {
return nil, err
}

pbmes := new(pb.PublicKey)
pbmes.Type = k.Type()
pbmes.Data = data
return pbmes, nil
}

// UnmarshalPrivateKey converts a protobuf serialized private key into its
// representative object
func UnmarshalPrivateKey(data []byte) (PrivKey, error) {
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ require (
github.com/ipfs/go-cid v0.0.2
github.com/jbenet/goprocess v0.1.3
github.com/libp2p/go-flow-metrics v0.0.1
github.com/libp2p/go-msgio v0.0.4
github.com/minio/sha256-simd v0.1.0
github.com/mr-tron/base58 v1.1.2
github.com/multiformats/go-multiaddr v0.0.4
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,12 @@ github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23 h1:FOOIBWrEkLgmlgGfMuZT83xIwfPDxEI2OHu6xUmJMFE=
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
github.com/libp2p/go-buffer-pool v0.0.1 h1:9Rrn/H46cXjaA2HQ5Y8lyhOS1NhTkZ4yuEs2r3Eechg=
github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ=
github.com/libp2p/go-flow-metrics v0.0.1 h1:0gxuFd2GuK7IIP5pKljLwps6TvcuYgvG7Atqi3INF5s=
github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8=
github.com/libp2p/go-msgio v0.0.4 h1:agEFehY3zWJFUHK6SEMR7UYmk2z6kC3oeCM7ybLhguA=
github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g=
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=
github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16 h1:5W7KhL8HVF3XCFOweFD3BNESdnO8ewyYTFT2R+/b8FQ=
Expand Down
175 changes: 156 additions & 19 deletions sec/insecure/insecure.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,35 @@ package insecure

import (
"context"
"fmt"
"github.com/gogo/protobuf/proto"
"github.com/libp2p/go-msgio"
"net"

"github.com/libp2p/go-libp2p-core/peer"
"github.com/libp2p/go-libp2p-core/sec"

ci "github.com/libp2p/go-libp2p-core/crypto"
pb "github.com/libp2p/go-libp2p-core/sec/insecure/pb"
)

// ID is the multistream-select protocol ID that should be used when identifying
// this security transport.
const ID = "/plaintext/1.0.0"
const ID = "/plaintext/2.0.0"

// Transport is a no-op stream security transport. It provides no
// security and simply mocks the security and identity methods to
// return peer IDs known ahead of time.
type Transport struct {
id peer.ID
id peer.ID
key ci.PrivKey
}

// New constructs a new insecure transport.
func New(id peer.ID) *Transport {
func New(id peer.ID, key ci.PrivKey) *Transport {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This causes pretty severe API breakage.

  1. in the Transport option of the go-libp2p constructor.
  2. elsewhere (e.g. go-tcp-transport) where this constructor is used directly.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The private key is unnecessary here. The public key should do.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should deprecate the New function and make a WithIdentity() function that the public key, and returns a function of signature func(id peer.ID) *Transport that can then be used with the go-libp2p constructor.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding a new constructor function and deprecating the old is definitely the way to go 👍

I added the private key to avoid returning nil from LocalPrivateKey - if we don't care about that then we can just take the public key.

return &Transport{
id: id,
id: id,
key: key,
}
}

Expand All @@ -36,33 +42,163 @@ func (t *Transport) LocalPeer() peer.ID {
return t.id
}

// LocalPrivateKey returns nil. This transport is not secure.
// LocalPrivateKey returns the local private key.
// This key is used only for identity generation and provides no security.
func (t *Transport) LocalPrivateKey() ci.PrivKey {
return nil
return t.key
}

// SecureInbound *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.
//
// 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(ctx context.Context, insecure net.Conn) (sec.SecureConn, error) {
return &Conn{
Conn: insecure,
local: t.id,
}, nil
conn := &Conn{
Conn: insecure,
local: t.id,
localPrivKey: t.key,
}

err := conn.runHandshakeSync(ctx)
if err != nil {
return nil, err
}

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(ctx context.Context, insecure net.Conn, p peer.ID) (sec.SecureConn, error) {
return &Conn{
Conn: insecure,
local: t.id,
remote: p,
}, nil
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)
}

if !p.MatchesPublicKey(conn.remotePubKey) {
yusefnapora marked this conversation as resolved.
Show resolved Hide resolved
return nil, fmt.Errorf("remote public key does not match expected peer ID")
}

return conn, nil
}

// Conn is the connection type returned by the insecure transport.
type Conn struct {
net.Conn

local peer.ID
remote peer.ID

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 {
insecureM := msgio.NewReadWriter(ic.Conn)
yusefnapora marked this conversation as resolved.
Show resolved Hide resolved

// Generate an Exchange message
msg, err := makeExchangeMessage(ic.localPrivKey)
if err != nil {
return err
}

msgBytes, err := proto.Marshal(msg)
if err != nil {
return err
}

// Send our Exchange and read theirs
remoteExchangeBytes, err := readWriteMsg(insecureM, msgBytes)
if err != nil {
return err
}

remoteMsg := new(pb.Exchange)
err = proto.Unmarshal(remoteExchangeBytes, 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
}

// read and write a message at the same time.
func readWriteMsg(c msgio.ReadWriter, out []byte) ([]byte, error) {
yusefnapora marked this conversation as resolved.
Show resolved Hide resolved
wresult := make(chan error)
go func() {
yusefnapora marked this conversation as resolved.
Show resolved Hide resolved
wresult <- c.WriteMsg(out)
}()

msg, err1 := c.ReadMsg()

// Always wait for the read to finish.
err2 := <-wresult

if err1 != nil {
return nil, err1
}
if err2 != nil {
c.ReleaseMsg(msg)
return nil, err2
}
return msg, nil
}

// LocalPeer returns the local peer ID.
Expand All @@ -76,14 +212,15 @@ func (ic *Conn) RemotePeer() peer.ID {
return ic.remote
}

// RemotePublicKey returns nil. This connection is not secure
// 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 nil
return ic.remotePubKey
}

// LocalPrivateKey returns nil. This connection is not secure.
// LocalPrivateKey returns the private key for the local peer.
func (ic *Conn) LocalPrivateKey() ci.PrivKey {
return nil
return ic.localPrivKey
}

var _ sec.SecureTransport = (*Transport)(nil)
Expand Down
Loading