diff --git a/pkg/transport-discovery/client/client_test.go b/pkg/transport-discovery/client/client_test.go index f9f6cd0753..88a1bae454 100644 --- a/pkg/transport-discovery/client/client_test.go +++ b/pkg/transport-discovery/client/client_test.go @@ -146,7 +146,8 @@ func TestRegisterTransportResponses(t *testing.T) { } func TestRegisterTransports(t *testing.T) { - sEntry := &transport.SignedEntry{Entry: newTestEntry(), Signatures: [2]cipher.Sig{}} + // Signatures does not matter in this test + sEntry := &transport.SignedEntry{Entry: newTestEntry()} srv := httptest.NewServer(authHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, "/transports/", r.URL.String()) diff --git a/pkg/transport/discovery_test.go b/pkg/transport/discovery_test.go index 51e1795f47..e4139b18ed 100644 --- a/pkg/transport/discovery_test.go +++ b/pkg/transport/discovery_test.go @@ -10,9 +10,10 @@ import ( func ExampleNewDiscoveryMock() { dc := NewDiscoveryMock() pk1, _ := cipher.GenerateKeyPair() - pk2, sk2 := cipher.GenerateKeyPair() + pk2, _ := cipher.GenerateKeyPair() entry := &Entry{Type: "mock", EdgesKeys: SortPubKeys(pk1, pk2)} - sEntry := &SignedEntry{Entry: entry, Signatures: [2]cipher.Sig{entry.Signature(sk2)}} + + sEntry := &SignedEntry{Entry: entry} if Ok := dc.RegisterTransports(context.TODO(), sEntry); Ok == nil { fmt.Println("RegisterTransport success") diff --git a/pkg/transport/entry.go b/pkg/transport/entry.go index 4937327aab..3a63ce28e4 100644 --- a/pkg/transport/entry.go +++ b/pkg/transport/entry.go @@ -95,6 +95,32 @@ type SignedEntry struct { Registered int64 `json:"registered,omitempty"` } +func (se *SignedEntry) Index(pk cipher.PubKey) byte { + if pk == se.Entry.Edges()[1] { + return 1 + } + return 0 +} + +// SetSignature sets Signature for a given PubKey in correct position +func (se *SignedEntry) SetSignature(pk cipher.PubKey, secKey cipher.SecKey) { + idx := se.Index(pk) + se.Signatures[idx] = se.Entry.Signature(secKey) +} + +// GetSignature gets Signature for a given PubKey from correct position +func (se *SignedEntry) GetSignature(pk cipher.PubKey) cipher.Sig { + idx := se.Index(pk) + return se.Signatures[idx] +} + +// NewSignedEntry creates a SignedEntry with first signature +func NewSignedEntry(entry *Entry, pk cipher.PubKey, secKey cipher.SecKey) *SignedEntry { + se := &SignedEntry{Entry: entry} + se.SetSignature(pk, secKey) + return se +} + // Status represents the current state of a Transport from the perspective // from a Transport's single edge. Each Transport will have two perspectives; // one from each of it's edges. diff --git a/pkg/transport/entry_test.go b/pkg/transport/entry_test.go index 5d61be46cc..1de0f7467f 100644 --- a/pkg/transport/entry_test.go +++ b/pkg/transport/entry_test.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/google/uuid" + "github.com/skycoin/skywire/pkg/cipher" ) @@ -79,3 +80,50 @@ func ExampleEntry_SetEdges() { // entryAB.ID != uuid.UUID{} // entryAB.ID == entryBA.ID } + +func ExampleSignedEntry_SetSignature() { + pkA, skA := cipher.GenerateKeyPair() + pkB, skB := cipher.GenerateKeyPair() + + entry := NewEntry(pkA, pkB, "mock", true) + sEntry := &SignedEntry{Entry: entry} + + if sEntry.Signatures[0].Null() && sEntry.Signatures[1].Null() { + fmt.Println("No signatures set") + } + + sEntry.SetSignature(pkA, skA) + if (!sEntry.Signatures[0].Null() && sEntry.Signatures[1].Null()) || + (!sEntry.Signatures[1].Null() && sEntry.Signatures[0].Null()) { + fmt.Println("One signature set") + } + + sEntry.SetSignature(pkB, skB) + if !sEntry.Signatures[0].Null() && !sEntry.Signatures[1].Null() { + fmt.Println("Both signatures set") + } + + // Output: No signatures set + // One signature set + // Both signatures set +} + +func ExampleSignedEntry_GetSignature() { + pkA, skA := cipher.GenerateKeyPair() + pkB, skB := cipher.GenerateKeyPair() + + entry := NewEntry(pkA, pkB, "mock", true) + sEntry := &SignedEntry{Entry: entry} + sEntry.SetSignature(pkA, skA) + sEntry.SetSignature(pkB, skB) + + if sEntry.GetSignature(pkA) == sEntry.Signatures[sEntry.Index(pkA)] { + fmt.Println("SignatureA got") + } + if sEntry.GetSignature(pkB) == sEntry.Signatures[sEntry.Index(pkB)] { + fmt.Println("SignatureB got") + } + + // Output: SignatureA got + // SignatureB got +} diff --git a/pkg/transport/handshake.go b/pkg/transport/handshake.go index bd43c623db..640e401936 100644 --- a/pkg/transport/handshake.go +++ b/pkg/transport/handshake.go @@ -44,7 +44,9 @@ func settlementInitiatorHandshake(id uuid.UUID, public bool) settlementHandshake entry.ID = GetTransportUUID(entry.Edges()[0], entry.Edges()[1], entry.Type) } - sEntry := &SignedEntry{Entry: entry, Signatures: [2]cipher.Sig{entry.Signature(tm.config.SecKey)}} + // sEntry := &SignedEntry{Entry: entry, Signatures: [2]cipher.Sig{entry.Signature(tm.config.SecKey)}} + + sEntry := NewSignedEntry(entry, tm.config.PubKey, tm.config.SecKey) if err := json.NewEncoder(tr).Encode(sEntry); err != nil { return nil, fmt.Errorf("write: %s", err) } @@ -53,7 +55,8 @@ func settlementInitiatorHandshake(id uuid.UUID, public bool) settlementHandshake return nil, fmt.Errorf("read: %s", err) } - if err := verifySig(sEntry, 1, tm.Remote(tr.Edges())); err != nil { + // Verifying remote signature + if err := verifySig(sEntry, tm.Remote(tr.Edges())); err != nil { return nil, err } @@ -71,11 +74,14 @@ func settlementResponderHandshake(tm *Manager, tr Transport) (*Entry, error) { return nil, fmt.Errorf("read: %s", err) } + // it must be tm.Local() ? if err := validateEntry(sEntry, tr, tm.Remote(tr.Edges())); err != nil { return nil, err } - sEntry.Signatures[1] = sEntry.Entry.Signature(tm.config.SecKey) + // Write second signature + // sEntry.Signatures[1] = sEntry.Entry.Signature(tm.config.SecKey) + sEntry.SetSignature(tm.Local(), tm.config.SecKey) newEntry := tm.walkEntries(func(e *Entry) bool { return *e == *sEntry.Entry }) == nil @@ -113,13 +119,14 @@ func validateEntry(sEntry *SignedEntry, tr Transport, rpk cipher.PubKey) error { return errors.New("invalid entry edges") } - if sEntry.Signatures[0].Null() { + // Weak check here + if sEntry.Signatures[0].Null() && sEntry.Signatures[1].Null() { return errors.New("invalid entry signature") } - return verifySig(sEntry, 0, rpk) + return verifySig(sEntry, rpk) } -func verifySig(sEntry *SignedEntry, idx int, pk cipher.PubKey) error { - return cipher.VerifyPubKeySignedPayload(pk, sEntry.Signatures[idx], sEntry.Entry.ToBinary()) +func verifySig(sEntry *SignedEntry, pk cipher.PubKey) error { + return cipher.VerifyPubKeySignedPayload(pk, sEntry.GetSignature(pk), sEntry.Entry.ToBinary()) } diff --git a/pkg/transport/handshake_test.go b/pkg/transport/handshake_test.go index fcdb6bff26..64f5ff8460 100644 --- a/pkg/transport/handshake_test.go +++ b/pkg/transport/handshake_test.go @@ -90,14 +90,23 @@ func ExampleNewHsMock() { } func Example_validateEntry() { - pk1, _ := cipher.GenerateKeyPair() + pk1, sk1 := cipher.GenerateKeyPair() pk2, _ := cipher.GenerateKeyPair() pk3, _ := cipher.GenerateKeyPair() tr := NewMockTransport(nil, pk1, pk2) - entry := Entry{Type: "mock", EdgesKeys: SortPubKeys(pk2, pk3)} - if err := validateEntry(&SignedEntry{Entry: &entry}, tr, pk1); err != nil { - fmt.Printf(err.Error()) + entryInvalidEdges := &SignedEntry{ + Entry: &Entry{Type: "mock", + EdgesKeys: SortPubKeys(pk2, pk3), + }} + if err := validateEntry(entryInvalidEdges, tr, pk1); err != nil { + fmt.Println(err.Error()) + } + + entry := NewEntry(pk1, pk2, "mock", true) + sEntry := NewSignedEntry(entry, pk1, sk1) + if Ok := validateEntry(sEntry, tr, pk1); Ok != nil { + fmt.Printf(Ok.Error()) } // Output: invalid entry edges @@ -131,7 +140,12 @@ func TestValidateEntry(t *testing.T) { "invalid entry signature", }, { - &SignedEntry{Entry: entry, Signatures: [2]cipher.Sig{entry.Signature(sk1)}}, + func() *SignedEntry { + sEntry := &SignedEntry{Entry: entry, Signatures: [2]cipher.Sig{}} + sEntry.SetSignature(pk1, sk2) + sEntry.SetSignature(pk2, sk1) + return sEntry + }(), "Recovered pubkey does not match pubkey", }, } @@ -144,8 +158,11 @@ func TestValidateEntry(t *testing.T) { }) } - sEntry := &SignedEntry{Entry: entry, Signatures: [2]cipher.Sig{entry.Signature(sk2)}} - require.NoError(t, validateEntry(sEntry, tr, pk2)) + sEntry := &SignedEntry{Entry: entry, Signatures: [2]cipher.Sig{}} + sEntry.SetSignature(pk1, sk1) + sEntry.SetSignature(pk2, sk2) + + require.NoError(t, validateEntry(sEntry, tr, pk1)) } func TestSettlementHandshake(t *testing.T) { diff --git a/pkg/transport/manager.go b/pkg/transport/manager.go index fefb482838..3314b34711 100644 --- a/pkg/transport/manager.go +++ b/pkg/transport/manager.go @@ -235,6 +235,11 @@ func SortPubKeys(keyA, keyB cipher.PubKey) [2]cipher.PubKey { return [2]cipher.PubKey{keyA, keyB} } +// SortEdges sorts edges so that list-significant comes firs +func SortEdges(edges [2]cipher.PubKey) [2]cipher.PubKey { + return SortPubKeys(edges[0], edges[1]) +} + // CreateTransport begins to attempt to establish transports to the given 'remote' node. func (tm *Manager) CreateTransport(ctx context.Context, remote cipher.PubKey, tpType string, public bool) (*ManagedTransport, error) { return tm.createTransport(ctx, remote, tpType, GetTransportUUID(tm.config.PubKey, remote, tpType), public) diff --git a/pkg/transport/mock.go b/pkg/transport/mock.go index dc80a09353..a76dfbc838 100644 --- a/pkg/transport/mock.go +++ b/pkg/transport/mock.go @@ -117,7 +117,7 @@ func (m *MockTransport) Close() error { // Edges returns edges of MockTransport func (m *MockTransport) Edges() [2]cipher.PubKey { - return m.edges + return SortEdges(m.edges) } // // Local returns the local static public key