Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

p2p: disable encryption handshake, enable log events #352

Merged
merged 6 commits into from
Feb 19, 2015
Merged
Show file tree
Hide file tree
Changes from all 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
3 changes: 2 additions & 1 deletion cmd/mist/assets/qml/main.qml
Original file line number Diff line number Diff line change
Expand Up @@ -927,7 +927,8 @@ ApplicationWindow {
model: peerModel
TableViewColumn{width: 180; role: "addr" ; title: "Remote Address" }
TableViewColumn{width: 280; role: "nodeID" ; title: "Node ID" }
TableViewColumn{width: 180; role: "caps" ; title: "Capabilities" }
TableViewColumn{width: 100; role: "name" ; title: "Name" }
TableViewColumn{width: 40; role: "caps" ; title: "Capabilities" }
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion cmd/mist/gui.go
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ NumGC: %d
))
}

type qmlpeer struct{ Addr, NodeID, Caps string }
type qmlpeer struct{ Addr, NodeID, Name, Caps string }

type peersByID []*qmlpeer

Expand All @@ -481,6 +481,7 @@ func (gui *Gui) setPeerInfo() {
qpeers[i] = &qmlpeer{
NodeID: p.ID().String(),
Addr: p.RemoteAddr().String(),
Name: p.Name(),
Caps: fmt.Sprint(p.Caps()),
}
}
Expand Down
20 changes: 10 additions & 10 deletions logger/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,16 @@ func (l *P2PConnected) EventName() string {
return "p2p.connected"
}

type P2PDisconnected struct {
NumConnections int `json:"num_connections"`
RemoteId string `json:"remote_id"`
LogEvent
}

func (l *P2PDisconnected) EventName() string {
return "p2p.disconnected"
}

type EthMinerNewBlock struct {
BlockHash string `json:"block_hash"`
BlockNumber int `json:"block_number"`
Expand Down Expand Up @@ -117,16 +127,6 @@ func (l *EthTxReceived) EventName() string {
// return "p2p.handshaked"
// }

// type P2PDisconnected struct {
// NumConnections int `json:"num_connections"`
// RemoteId string `json:"remote_id"`
// LogEvent
// }

// func (l *P2PDisconnected) EventName() string {
// return "p2p.disconnected"
// }

// type P2PDisconnecting struct {
// Reason string `json:"reason"`
// RemoteId string `json:"remote_id"`
Expand Down
137 changes: 104 additions & 33 deletions p2p/crypto.go → p2p/handshake.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
package p2p

import (
// "binary"
"crypto/ecdsa"
"crypto/rand"
"errors"
"fmt"
"io"
"net"

"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/ecies"
"github.com/ethereum/go-ethereum/crypto/secp256k1"
ethlogger "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/rlp"
)

var clogger = ethlogger.NewLogger("CRYPTOID")

const (
sskLen = 16 // ecies.MaxSharedKeyLength(pubKey) / 2
sigLen = 65 // elliptic S256
Expand All @@ -30,26 +29,76 @@ const (
rHSLen = authRespLen + eciesBytes // size of the final ECIES payload sent as receiver's handshake
)

type hexkey []byte
type conn struct {
*frameRW
*protoHandshake
}

func (self hexkey) String() string {
return fmt.Sprintf("(%d) %x", len(self), []byte(self))
func newConn(fd net.Conn, hs *protoHandshake) *conn {
return &conn{newFrameRW(fd, msgWriteTimeout), hs}
}

func encHandshake(conn io.ReadWriter, prv *ecdsa.PrivateKey, dial *discover.Node) (
remoteID discover.NodeID,
sessionToken []byte,
err error,
) {
// encHandshake represents information about the remote end
// of a connection that is negotiated during the encryption handshake.
type encHandshake struct {
ID discover.NodeID
IngressMAC []byte
EgressMAC []byte
Token []byte
}

// protoHandshake is the RLP structure of the protocol handshake.
type protoHandshake struct {
Version uint64
Name string
Caps []Cap
ListenPort uint64
ID discover.NodeID
}

// setupConn starts a protocol session on the given connection.
// It runs the encryption handshake and the protocol handshake.
// If dial is non-nil, the connection the local node is the initiator.
func setupConn(fd net.Conn, prv *ecdsa.PrivateKey, our *protoHandshake, dial *discover.Node) (*conn, error) {
if dial == nil {
var remotePubkey []byte
sessionToken, remotePubkey, err = inboundEncHandshake(conn, prv, nil)
copy(remoteID[:], remotePubkey)
return setupInboundConn(fd, prv, our)
} else {
remoteID = dial.ID
sessionToken, err = outboundEncHandshake(conn, prv, remoteID[:], nil)
return setupOutboundConn(fd, prv, our, dial)
}
}

func setupInboundConn(fd net.Conn, prv *ecdsa.PrivateKey, our *protoHandshake) (*conn, error) {
// var remotePubkey []byte
// sessionToken, remotePubkey, err = inboundEncHandshake(fd, prv, nil)
// copy(remoteID[:], remotePubkey)

rw := newFrameRW(fd, msgWriteTimeout)
rhs, err := readProtocolHandshake(rw, our)
if err != nil {
return nil, err
}
if err := writeProtocolHandshake(rw, our); err != nil {
return nil, fmt.Errorf("protocol write error: %v", err)
}
return &conn{rw, rhs}, nil
}

func setupOutboundConn(fd net.Conn, prv *ecdsa.PrivateKey, our *protoHandshake, dial *discover.Node) (*conn, error) {
// remoteID = dial.ID
// sessionToken, err = outboundEncHandshake(fd, prv, remoteID[:], nil)

rw := newFrameRW(fd, msgWriteTimeout)
if err := writeProtocolHandshake(rw, our); err != nil {
return nil, fmt.Errorf("protocol write error: %v", err)
}
return remoteID, sessionToken, err
rhs, err := readProtocolHandshake(rw, our)
if err != nil {
return nil, fmt.Errorf("protocol handshake read error: %v", err)
}
if rhs.ID != dial.ID {
return nil, errors.New("dialed node id mismatch")
}
return &conn{rw, rhs}, nil
}

// outboundEncHandshake negotiates a session token on conn.
Expand All @@ -66,18 +115,9 @@ func outboundEncHandshake(conn io.ReadWriter, prvKey *ecdsa.PrivateKey, remotePu
if err != nil {
return nil, err
}
if sessionToken != nil {
clogger.Debugf("session-token: %v", hexkey(sessionToken))
}

clogger.Debugf("initiator-nonce: %v", hexkey(initNonce))
clogger.Debugf("initiator-random-private-key: %v", hexkey(crypto.FromECDSA(randomPrivKey)))
randomPublicKeyS, _ := exportPublicKey(&randomPrivKey.PublicKey)
clogger.Debugf("initiator-random-public-key: %v", hexkey(randomPublicKeyS))
if _, err = conn.Write(auth); err != nil {
return nil, err
}
clogger.Debugf("initiator handshake: %v", hexkey(auth))

response := make([]byte, rHSLen)
if _, err = io.ReadFull(conn, response); err != nil {
Expand All @@ -88,9 +128,6 @@ func outboundEncHandshake(conn io.ReadWriter, prvKey *ecdsa.PrivateKey, remotePu
return nil, err
}

clogger.Debugf("receiver-nonce: %v", hexkey(recNonce))
remoteRandomPubKeyS, _ := exportPublicKey(remoteRandomPubKey)
clogger.Debugf("receiver-random-public-key: %v", hexkey(remoteRandomPubKeyS))
return newSession(initNonce, recNonce, randomPrivKey, remoteRandomPubKey)
}

Expand Down Expand Up @@ -221,12 +258,9 @@ func inboundEncHandshake(conn io.ReadWriter, prvKey *ecdsa.PrivateKey, sessionTo
if err != nil {
return nil, nil, err
}
clogger.Debugf("receiver-nonce: %v", hexkey(recNonce))
clogger.Debugf("receiver-random-priv-key: %v", hexkey(crypto.FromECDSA(randomPrivKey)))
if _, err = conn.Write(response); err != nil {
return nil, nil, err
}
clogger.Debugf("receiver handshake:\n%v", hexkey(response))
token, err = newSession(initNonce, recNonce, randomPrivKey, remoteRandomPubKey)
return token, remotePubKey, err
}
Expand Down Expand Up @@ -361,3 +395,40 @@ func xor(one, other []byte) (xor []byte) {
}
return xor
}

func writeProtocolHandshake(w MsgWriter, our *protoHandshake) error {
return EncodeMsg(w, handshakeMsg, our.Version, our.Name, our.Caps, our.ListenPort, our.ID[:])
}

func readProtocolHandshake(r MsgReader, our *protoHandshake) (*protoHandshake, error) {
// read and handle remote handshake
msg, err := r.ReadMsg()
if err != nil {
return nil, err
}
if msg.Code == discMsg {
// disconnect before protocol handshake is valid according to the
// spec and we send it ourself if Server.addPeer fails.
var reason DiscReason
rlp.Decode(msg.Payload, &reason)
return nil, discRequestedError(reason)
}
if msg.Code != handshakeMsg {
return nil, fmt.Errorf("expected handshake, got %x", msg.Code)
}
if msg.Size > baseProtocolMaxMsgSize {
return nil, fmt.Errorf("message too big (%d > %d)", msg.Size, baseProtocolMaxMsgSize)
}
var hs protoHandshake
if err := msg.Decode(&hs); err != nil {
return nil, err
}
// validate handshake info
if hs.Version != our.Version {
return nil, newPeerError(errP2PVersionMismatch, "required version %d, received %d\n", baseProtocolVersion, hs.Version)
}
if (hs.ID == discover.NodeID{}) {
return nil, newPeerError(errPubkeyInvalid, "missing")
}
return &hs, nil
}
63 changes: 60 additions & 3 deletions p2p/crypto_test.go → p2p/handshake_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import (
"crypto/ecdsa"
"crypto/rand"
"net"
"reflect"
"testing"

"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/ecies"
"github.com/ethereum/go-ethereum/p2p/discover"
)

func TestPublicKeyEncoding(t *testing.T) {
Expand Down Expand Up @@ -91,14 +93,14 @@ func testCryptoHandshake(prv0, prv1 *ecdsa.PrivateKey, sessionToken []byte, t *t
if err != nil {
t.Errorf("%v", err)
}
t.Logf("-> %v", hexkey(auth))
// t.Logf("-> %v", hexkey(auth))

// receiver reads auth and responds with response
response, remoteRecNonce, remoteInitNonce, _, remoteRandomPrivKey, remoteInitRandomPubKey, err := authResp(auth, sessionToken, prv1)
if err != nil {
t.Errorf("%v", err)
}
t.Logf("<- %v\n", hexkey(response))
// t.Logf("<- %v\n", hexkey(response))

// initiator reads receiver's response and the key exchange completes
recNonce, remoteRandomPubKey, _, err := completeHandshake(response, prv0)
Expand Down Expand Up @@ -132,7 +134,7 @@ func testCryptoHandshake(prv0, prv1 *ecdsa.PrivateKey, sessionToken []byte, t *t
}
}

func TestHandshake(t *testing.T) {
func TestEncHandshake(t *testing.T) {
defer testlog(t).detach()

prv0, _ := crypto.GenerateKey()
Expand Down Expand Up @@ -165,3 +167,58 @@ func TestHandshake(t *testing.T) {
t.Error("session token mismatch")
}
}

func TestSetupConn(t *testing.T) {
prv0, _ := crypto.GenerateKey()
prv1, _ := crypto.GenerateKey()
node0 := &discover.Node{
ID: discover.PubkeyID(&prv0.PublicKey),
IP: net.IP{1, 2, 3, 4},
TCPPort: 33,
}
node1 := &discover.Node{
ID: discover.PubkeyID(&prv1.PublicKey),
IP: net.IP{5, 6, 7, 8},
TCPPort: 44,
}
hs0 := &protoHandshake{
Version: baseProtocolVersion,
ID: node0.ID,
Caps: []Cap{{"a", 0}, {"b", 2}},
}
hs1 := &protoHandshake{
Version: baseProtocolVersion,
ID: node1.ID,
Caps: []Cap{{"c", 1}, {"d", 3}},
}
fd0, fd1 := net.Pipe()

done := make(chan struct{})
go func() {
defer close(done)
conn0, err := setupConn(fd0, prv0, hs0, node1)
if err != nil {
t.Errorf("outbound side error: %v", err)
return
}
if conn0.ID != node1.ID {
t.Errorf("outbound conn id mismatch: got %v, want %v", conn0.ID, node1.ID)
}
if !reflect.DeepEqual(conn0.Caps, hs1.Caps) {
t.Errorf("outbound caps mismatch: got %v, want %v", conn0.Caps, hs1.Caps)
}
}()

conn1, err := setupConn(fd1, prv1, hs1, nil)
if err != nil {
t.Fatalf("inbound side error: %v", err)
}
if conn1.ID != node0.ID {
t.Errorf("inbound conn id mismatch: got %v, want %v", conn1.ID, node0.ID)
}
if !reflect.DeepEqual(conn1.Caps, hs0.Caps) {
t.Errorf("inbound caps mismatch: got %v, want %v", conn1.Caps, hs0.Caps)
}

<-done
}
2 changes: 1 addition & 1 deletion p2p/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ func (rw *frameRW) ReadMsg() (msg Msg, err error) {
return msg, err
}
if !bytes.HasPrefix(start, magicToken) {
return msg, fmt.Errorf("bad magic token %x", start[:4], magicToken)
return msg, fmt.Errorf("bad magic token %x", start[:4])
}
size := binary.BigEndian.Uint32(start[4:])

Expand Down
Loading