diff --git a/connections/authenticated/authenticated.go b/connections/authenticated/authenticated.go index c9c7a52ca963a805efc275bc3c0104694464f142..66e15ecae95d61724a382315285a2a893899421f 100644 --- a/connections/authenticated/authenticated.go +++ b/connections/authenticated/authenticated.go @@ -13,11 +13,13 @@ import ( "gitlab.com/elixxir/client/catalog" "gitlab.com/elixxir/client/cmix" "gitlab.com/elixxir/client/connections/connect" + clientE2e "gitlab.com/elixxir/client/e2e" "gitlab.com/elixxir/crypto/contact" "gitlab.com/elixxir/crypto/cyclic" "gitlab.com/elixxir/crypto/fastRNG" "gitlab.com/xx_network/crypto/signature/rsa" "gitlab.com/xx_network/primitives/id" + "gitlab.com/xx_network/primitives/netTime" "sync" "time" ) @@ -39,27 +41,74 @@ type Connection interface { // new authenticated.Connection objects as they are established. type ConnectionCallback func(connection Connection) -// ConnectWithAuthentication is called by the client, ie the initiator -// of establishing a connection. This will establish a connect.Connection with -// the server and then authenticate their identity to the server. +// ConnectWithAuthentication is called by the client, ie the one establishing +// connection with the server. Once a connect.Connection has been established +// with the server and then authenticate their identity to the server. func ConnectWithAuthentication(recipient contact.Contact, myId *id.ID, - salt []byte, rsaPrivkey *rsa.PrivateKey, dhPrivKey *cyclic.Int, + salt []byte, myRsaPrivKey *rsa.PrivateKey, myDhPrivKey *cyclic.Int, rng *fastRNG.StreamGenerator, grp *cyclic.Group, net cmix.Client, p connect.Params) (Connection, error) { - conn, err := connect.Connect(recipient, myId, dhPrivKey, rng, grp, net, p) + conn, err := connect.Connect(recipient, myId, myDhPrivKey, rng, grp, net, p) if err != nil { return nil, errors.WithMessagef(err, "Failed to establish connection "+ "with recipient %s", recipient.ID) } - // Build the callback for the connection being established + + // Construct message + payload, err := makeClientAuthRequest(conn.GetPartner(), rng, myRsaPrivKey, salt) + if err != nil { + errClose := conn.Close() + if errClose != nil { + return nil, errors.Errorf( + "failed to close connection with %s after error %v: %+v", + recipient.ID, err, errClose) + } + return nil, errors.WithMessagef(err, "failed to construct client "+ + "authentication message") + } + + // Send message to user + e2eParams := clientE2e.GetDefaultParams() + rids, _, _, err := conn.SendE2E(catalog.ConnectionAuthenticationRequest, + payload, e2eParams) + if err != nil { + errClose := conn.Close() + if errClose != nil { + return nil, errors.Errorf( + "failed to close connection with %s after error %v: %+v", + recipient.ID, err, errClose) + } + return nil, errors.WithMessagef(err, "failed to construct client "+ + "authentication message") + } + + // Record since we first successfully sen the message + timeStart := netTime.Now() + authConnChan := make(chan Connection, 1) - cb := ConnectionCallback(func(authConn Connection) { - authConnChan <- authConn - }) - go initiateClientAuthentication(cb, conn, net, rng, rsaPrivkey, salt, p) + // Determine that the message is properly sent by tracking the success + // of the round(s) + roundCb := cmix.RoundEventCallback(func(allRoundsSucceeded, + timedOut bool, rounds map[id.Round]cmix.RoundResult) { + if allRoundsSucceeded { + // If rounds succeeded, assume recipient has successfully + // confirmed the authentication. Pass the connection + // along via the callback + authConn := buildAuthenticatedConnection(conn) + authConn.setAuthenticated() + authConnChan <- authConn + } + }) + remainingTime := e2eParams.Timeout - netTime.Since(timeStart) + err = net.GetRoundResults(remainingTime, + roundCb, rids...) + if err != nil { + return nil, errors.Errorf("could not track rounds for successful " + + "identity confirmation message delivery") + } // Block waiting for auth to confirm it timeouts jww.DEBUG.Printf("Connection waiting for authenticated "+ "connection with %s to be established...", recipient.ID.String()) @@ -80,41 +129,27 @@ func ConnectWithAuthentication(recipient contact.Contact, myId *id.ID, } -// StartAuthenticatedConnectionServer is called by the receiver of an +// StartServer is called by the receiver of an // authenticated connection request. Calling this will indicate that they // will handle authenticated requests and verify the client's attempt to // authenticate themselves. An established authenticated.Connection will // be passed via the callback. -func StartAuthenticatedConnectionServer(cb ConnectionCallback, +func StartServer(cb ConnectionCallback, myId *id.ID, privKey *cyclic.Int, rng *fastRNG.StreamGenerator, grp *cyclic.Group, net cmix.Client, p connect.Params) error { // Register the waiter for a connection establishment - connChan := make(chan connect.Connection, 1) connCb := connect.Callback(func(connection connect.Connection) { - connChan <- connection - }) - err := connect.RegisterConnectionCallback(connCb, myId, privKey, rng, grp, net, p) - if err != nil { - return err - } - - // Wait for a connection to be established - timer := time.NewTimer(p.Timeout) - defer timer.Stop() - select { - case conn := <-connChan: // Upon establishing a connection, register a listener for the // client's identity proof. If a identity authentication - // message is received and validated, an authenticated connection will be - // passed along via the callback - conn.RegisterListener(catalog.ConnectionAuthenticationRequest, - getServer(cb, conn)) - return nil - case <-timer.C: - return errors.New("Timed out trying to establish a connection") - } + // message is received and validated, an authenticated connection will + // be passed along via the callback + connection.RegisterListener(catalog.ConnectionAuthenticationRequest, + handleAuthConfirmation(cb, connection)) + }) + return connect.StartServer(connCb, myId, privKey, rng, grp, + net, p) } // handler provides an implementation for the authenticated.Connection diff --git a/connections/authenticated/client.go b/connections/authenticated/client.go index 5a8913baba01d4269281e9b5124aa68da5a1008e..fd66428318df2d12e6484ec41a13d1ab27c3ebe5 100644 --- a/connections/authenticated/client.go +++ b/connections/authenticated/client.go @@ -2,34 +2,21 @@ package authenticated import ( "github.com/golang/protobuf/proto" - jww "github.com/spf13/jwalterweatherman" - "gitlab.com/elixxir/client/catalog" - "gitlab.com/elixxir/client/cmix" - "gitlab.com/elixxir/client/connections/connect" - clientE2e "gitlab.com/elixxir/client/e2e" + "github.com/pkg/errors" + "gitlab.com/elixxir/client/e2e/ratchet/partner" "gitlab.com/elixxir/crypto/fastRNG" "gitlab.com/xx_network/crypto/signature/rsa" - "gitlab.com/xx_network/primitives/id" ) -// initiateClientAuthentication is a helper function which will handle the -// establishment of an authenticated.Connection. This will have the -// client send an identity authentication message to the server. Upon -// successful sending of the message (determined by the result of the round(s)) -// an authenticated.Connection is assumed to be established and passed along -// via the callback. -func initiateClientAuthentication(authCb ConnectionCallback, - conn connect.Connection, net cmix.Client, - rng *fastRNG.StreamGenerator, rsaPrivKey *rsa.PrivateKey, salt []byte, - connParams connect.Params) { - - // After confirmation, get the new partner - newPartner := conn.GetPartner() +// makeClientAuthRequest is a helper function which constructs a marshalled +// IdentityAuthentication message. +func makeClientAuthRequest(newPartner partner.Manager, + rng *fastRNG.StreamGenerator, rsaPrivKey *rsa.PrivateKey, + salt []byte) ([]byte, error) { // The connection fingerprint (hashed) represents a shared nonce // between these two partners connectionFp := newPartner.ConnectionFingerprint().Bytes() - opts := rsa.NewDefaultOptions() h := opts.Hash.New() h.Write(connectionFp) @@ -41,10 +28,7 @@ func initiateClientAuthentication(authCb ConnectionCallback, signature, err := rsa.Sign(stream, rsaPrivKey, opts.Hash, nonce, opts) if err != nil { - jww.ERROR.Printf("Unable to build connection with "+ - "partner %s: %+v", newPartner.PartnerId(), err) - // Send a nil connection to avoid hold-ups down the line - authCb(nil) + return nil, errors.Errorf("failed to sign nonce: %+v", err) } // Construct message @@ -56,48 +40,10 @@ func initiateClientAuthentication(authCb ConnectionCallback, } payload, err := proto.Marshal(iar) if err != nil { - jww.ERROR.Printf("Unable to build connection with "+ - "partner %s: %+v", newPartner.PartnerId(), err) - // Send a nil connection to avoid hold-ups down the line - authCb(nil) - } - - // Send message to user - rids, _, _, err := conn.SendE2E(catalog.ConnectionAuthenticationRequest, - payload, clientE2e.GetDefaultParams()) - if err != nil { - jww.ERROR.Printf("Unable to build connection with "+ - "partner %s: %+v", newPartner.PartnerId(), err) - // Send a nil connection to avoid hold-ups down the line - authCb(nil) - } - // Determine that the message is properly sent by tracking the success - // of the round(s) - roundCb := cmix.RoundEventCallback(func(allRoundsSucceeded, - timedOut bool, rounds map[id.Round]cmix.RoundResult) { - if allRoundsSucceeded { - // If rounds succeeded, assume recipient has successfully - // confirmed the authentication. Pass the connection - // along via the callback - authConn := buildAuthenticatedConnection(conn) - authConn.setAuthenticated() - authCb(authConn) - } else { - jww.ERROR.Printf("Unable to build connection with "+ - "partner %s: %+v", newPartner.PartnerId(), err) - // Send a nil connection to avoid hold-ups down the line - authCb(nil) - } - }) - - err = net.GetRoundResults(connParams.Timeout, - roundCb, rids...) - if err != nil { - jww.ERROR.Printf("Unable to build connection with "+ - "partner %s: %+v", newPartner.PartnerId(), err) - // Send a nil connection to avoid hold-ups down the line - authCb(nil) + return nil, errors.Errorf("failed to marshal identity request "+ + "message: %+v", err) } + return payload, nil } diff --git a/connections/authenticated/server.go b/connections/authenticated/server.go index d3708ec98a4f2d926df347e30a3f46e2e02a2194..0ae4b1ae38aba7cfb353199aae26e57e6fbcd06d 100644 --- a/connections/authenticated/server.go +++ b/connections/authenticated/server.go @@ -1,3 +1,10 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright © 2020 xx network SEZC // +// // +// Use of this source code is governed by a license that can be found in the // +// LICENSE file // +/////////////////////////////////////////////////////////////////////////////// + package authenticated import ( @@ -30,8 +37,9 @@ type serverListener struct { conn connect.Connection } -// getServer returns a serverListener object. -func getServer(cb ConnectionCallback, connection connect.Connection) server { +// handleAuthConfirmation returns a serverListener object. +func handleAuthConfirmation(cb ConnectionCallback, + connection connect.Connection) server { return serverListener{ connectionCallback: cb, conn: connection,