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

Peerstore Fix #128

Merged
merged 11 commits into from
Sep 27, 2014
Merged
2 changes: 1 addition & 1 deletion core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func NewIpfsNode(cfg *config.Config, online bool) (*IpfsNode, error) {
return nil, err
}

net, err = inet.NewIpfsNetwork(context.TODO(), local, &mux.ProtocolMap{
net, err = inet.NewIpfsNetwork(context.TODO(), local, peerstore, &mux.ProtocolMap{
mux.ProtocolID_Routing: dhtService,
mux.ProtocolID_Exchange: exchangeService,
})
Expand Down
11 changes: 9 additions & 2 deletions core/core_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ import (
)

func TestInitialization(t *testing.T) {
id := &config.Identity{
id := config.Identity{
PeerID: "QmNgdzLieYi8tgfo2WfTUzNVH5hQK9oAYGVf6dxN12NrHt",
Address: "/ip4/127.0.0.1/tcp/8000",
PrivKey: "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",
Copy link
Member

Choose a reason for hiding this comment

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

such a large string!

}

Expand All @@ -19,6 +18,10 @@ func TestInitialization(t *testing.T) {
Datastore: config.Datastore{
Type: "memory",
},
Addresses: config.Addresses{
Swarm: "/ip4/0.0.0.0/tcp/4001",
API: "/ip4/127.0.0.1/tcp/8000",
},
},

&config.Config{
Expand All @@ -27,6 +30,10 @@ func TestInitialization(t *testing.T) {
Type: "leveldb",
Path: ".testdb",
},
Addresses: config.Addresses{
Swarm: "/ip4/0.0.0.0/tcp/4001",
API: "/ip4/127.0.0.1/tcp/8000",
},
},
}

Expand Down
29 changes: 23 additions & 6 deletions crypto/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,17 @@ const (
RSA = iota
)

type Key interface {
// Bytes returns a serialized, storeable representation of this key
Bytes() ([]byte, error)

// Equals checks whether two PubKeys are the same
Equals(Key) bool
}

type PrivKey interface {
Key

// Cryptographically sign the given bytes
Sign([]byte) ([]byte, error)

Expand All @@ -32,17 +42,13 @@ type PrivKey interface {

// Generate a secret string of bytes
GenSecret() []byte

// Bytes returns a serialized, storeable representation of this key
Bytes() ([]byte, error)
}

type PubKey interface {
Key

// Verify that 'sig' is the signed hash of 'data'
Verify(data []byte, sig []byte) (bool, error)

// Bytes returns a serialized, storeable representation of this key
Bytes() ([]byte, error)
}

// Given a public key, generates the shared key.
Expand Down Expand Up @@ -229,3 +235,14 @@ func UnmarshalPrivateKey(data []byte) (PrivKey, error) {
return nil, ErrBadKeyType
}
}

// KeyEqual checks whether two
func KeyEqual(k1, k2 Key) bool {
if k1 == k2 {
return true
}

b1, err1 := k1.Bytes()
b2, err2 := k2.Bytes()
return bytes.Equal(b1, b2) && err1 == err2
}
42 changes: 41 additions & 1 deletion crypto/key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ package crypto
import "testing"

func TestRsaKeys(t *testing.T) {
sk, _, err := GenerateKeyPair(RSA, 512)
sk, pk, err := GenerateKeyPair(RSA, 512)
if err != nil {
t.Fatal(err)
}
testKeySignature(t, sk)
testKeyEncoding(t, sk)
testKeyEquals(t, sk)
testKeyEquals(t, pk)
}

func testKeySignature(t *testing.T, sk PrivKey) {
Expand Down Expand Up @@ -52,3 +54,41 @@ func testKeyEncoding(t *testing.T, sk PrivKey) {
t.Fatal(err)
}
}

func testKeyEquals(t *testing.T, k Key) {
kb, err := k.Bytes()
if err != nil {
t.Fatal(err)
}

if !KeyEqual(k, k) {
t.Fatal("Key not equal to itself.")
}

if !KeyEqual(k, testkey(kb)) {
t.Fatal("Key not equal to key with same bytes.")
}

sk, pk, err := GenerateKeyPair(RSA, 512)
if err != nil {
t.Fatal(err)
}

if KeyEqual(k, sk) {
t.Fatal("Keys should not equal.")
}

if KeyEqual(k, pk) {
t.Fatal("Keys should not equal.")
}
}

type testkey []byte

func (pk testkey) Bytes() ([]byte, error) {
return pk, nil
}

func (pk testkey) Equals(k Key) bool {
return KeyEqual(pk, k)
}
10 changes: 10 additions & 0 deletions crypto/rsa.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ func (pk *RsaPublicKey) Bytes() ([]byte, error) {
return proto.Marshal(pbmes)
}

// Equals checks whether this key is equal to another
func (pk *RsaPublicKey) Equals(k Key) bool {
return KeyEqual(pk, k)
}

func (sk *RsaPrivateKey) GenSecret() []byte {
buf := make([]byte, 16)
rand.Read(buf)
Expand All @@ -65,6 +70,11 @@ func (sk *RsaPrivateKey) Bytes() ([]byte, error) {
return proto.Marshal(pbmes)
}

// Equals checks whether this key is equal to another
func (sk *RsaPrivateKey) Equals(k Key) bool {
return KeyEqual(sk, k)
}

func UnmarshalRsaPrivateKey(b []byte) (*RsaPrivateKey, error) {
sk, err := x509.ParsePKCS1PrivateKey(b)
if err != nil {
Expand Down
64 changes: 54 additions & 10 deletions crypto/spipe/handshake.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,23 +90,18 @@ func (s *SecurePipe) handshake() error {
return err
}

s.remote.PubKey, err = ci.UnmarshalPublicKey(proposeResp.GetPubkey())
// get remote identity
remotePubKey, err := ci.UnmarshalPublicKey(proposeResp.GetPubkey())
if err != nil {
return err
}

remoteID, err := IDFromPubKey(s.remote.PubKey)
// get or construct peer
s.remote, err = getOrConstructPeer(s.peers, remotePubKey)
if err != nil {
return err
}

if s.remote.ID != nil && !remoteID.Equal(s.remote.ID) {
e := "Expected pubkey does not match sent pubkey: %v - %v"
return fmt.Errorf(e, s.remote.ID.Pretty(), remoteID.Pretty())
} else if s.remote.ID == nil {
s.remote.ID = remoteID
}
// u.POut("Remote Peer Identified as %s\n", s.remote.ID.Pretty())
u.DOut("[%s] Remote Peer Identified as %s\n", s.local.ID.Pretty(), s.remote.ID.Pretty())

exchange, err := selectBest(SupportedExchanges, proposeResp.GetExchanges())
if err != nil {
Expand Down Expand Up @@ -340,3 +335,52 @@ func selectBest(myPrefs, theirPrefs string) (string, error) {

return "", errors.New("No algorithms in common!")
}

// getOrConstructPeer attempts to fetch a peer from a peerstore.
// if succeeds, verify ID and PubKey match.
// else, construct it.
func getOrConstructPeer(peers peer.Peerstore, rpk ci.PubKey) (*peer.Peer, error) {

rid, err := IDFromPubKey(rpk)
if err != nil {
return nil, err
}

npeer, err := peers.Get(rid)
if err != nil || npeer == nil {
if err != peer.ErrNotFound {
return nil, err // unexpected error happened.
}

// dont have peer, so construct it + add it to peerstore.
npeer = &peer.Peer{ID: rid, PubKey: rpk}
if err := peers.Put(npeer); err != nil {
return nil, err
}

// done, return the newly constructed peer.
return npeer, nil
}

// did have it locally.

// let's verify ID
if !npeer.ID.Equal(rid) {
e := "Expected peer.ID does not match sent pubkey's hash: %v - %v"
Copy link
Member

Choose a reason for hiding this comment

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

Would be an interesting scenario that this could fail in..

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, I added that test case because I could be Dialing to a peer1 and then i receive back peer2's pubkey, and thus am like wat!? (note that if this is an incoming connection, peer is ErrNotFound above, and returns beforehand. Did prompt me to find a bug though (if peers.Get returns nil, nil, we'd panic).

return nil, fmt.Errorf(e, npeer.ID.Pretty(), rid.Pretty())
}

if npeer.PubKey == nil {
// didn't have a pubkey, just set it.
npeer.PubKey = rpk
return npeer, nil
}

// did have pubkey, let's verify it's really the same.
// this shouldn't ever happen, given we hashed, etc, but it could mean
// expected code (or protocol) invariants violated.
if !npeer.PubKey.Equals(rpk) {
return nil, fmt.Errorf("WARNING: PubKey mismatch: %v", npeer.ID.Pretty())
}
return npeer, nil
}
19 changes: 15 additions & 4 deletions crypto/spipe/pipe.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type SecurePipe struct {

local *peer.Peer
remote *peer.Peer
peers peer.Peerstore

params params

Expand All @@ -32,16 +33,16 @@ type params struct {
}

// NewSecurePipe constructs a pipe with channels of a given buffer size.
func NewSecurePipe(ctx context.Context, bufsize int, local,
remote *peer.Peer) (*SecurePipe, error) {
func NewSecurePipe(ctx context.Context, bufsize int, local *peer.Peer,
peers peer.Peerstore) (*SecurePipe, error) {

sp := &SecurePipe{
Duplex: Duplex{
In: make(chan []byte, bufsize),
Out: make(chan []byte, bufsize),
},
local: local,
remote: remote,
local: local,
peers: peers,
}
return sp, nil
}
Expand All @@ -63,6 +64,16 @@ func (s *SecurePipe) Wrap(ctx context.Context, insecure Duplex) error {
return nil
}

// LocalPeer retrieves the local peer.
func (s *SecurePipe) LocalPeer() *peer.Peer {
return s.local
}

// RemotePeer retrieves the local peer.
func (s *SecurePipe) RemotePeer() *peer.Peer {
return s.remote
}

// Close closes the secure pipe
func (s *SecurePipe) Close() error {
if s.cancel == nil {
Expand Down
11 changes: 9 additions & 2 deletions daemon/daemon_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,8 @@ func TestInitializeDaemonListener(t *testing.T) {
privKey := base64.StdEncoding.EncodeToString(prbytes)
pID := ident.Pretty()

id := &config.Identity{
id := config.Identity{
PeerID: pID,
Address: "/ip4/127.0.0.1/tcp/8000",
PrivKey: privKey,
}

Expand All @@ -38,6 +37,10 @@ func TestInitializeDaemonListener(t *testing.T) {
Datastore: config.Datastore{
Type: "memory",
},
Addresses: config.Addresses{
Swarm: "/ip4/0.0.0.0/tcp/4001",
API: "/ip4/127.0.0.1/tcp/8000",
},
},

&config.Config{
Expand All @@ -46,6 +49,10 @@ func TestInitializeDaemonListener(t *testing.T) {
Type: "leveldb",
Path: ".testdb",
},
Addresses: config.Addresses{
Swarm: "/ip4/0.0.0.0/tcp/4001",
API: "/ip4/127.0.0.1/tcp/8000",
},
},
}

Expand Down
17 changes: 6 additions & 11 deletions net/conn/conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,6 @@ func NewConn(peer *peer.Peer, addr *ma.Multiaddr, nconn net.Conn) (*Conn, error)
return conn, nil
}

// NewNetConn constructs a new connection with given net.Conn
func NewNetConn(nconn net.Conn) (*Conn, error) {

addr, err := ma.FromNetAddr(nconn.RemoteAddr())
if err != nil {
return nil, err
}

return NewConn(new(peer.Peer), addr, nconn)
}

// Dial connects to a particular peer, over a given network
// Example: Dial("udp", peer)
func Dial(network string, peer *peer.Peer) (*Conn, error) {
Expand Down Expand Up @@ -112,3 +101,9 @@ func (c *Conn) Close() error {
c.Closed <- true
return err
}

// NetConnMultiaddr returns the net.Conn's address, recast as a multiaddr.
// (consider moving this directly into the multiaddr package)
func NetConnMultiaddr(nconn net.Conn) (*ma.Multiaddr, error) {
return ma.FromNetAddr(nconn.RemoteAddr())
}
Loading