diff --git a/auth/cmix.go b/auth/cmix.go deleted file mode 100644 index 0f76dd7efc1f757613c0cd43897afb851f4bd93a..0000000000000000000000000000000000000000 --- a/auth/cmix.go +++ /dev/null @@ -1,62 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// Copyright © 2020 xx network SEZC // -// // -// Use of this source code is governed by a license that can be found in the // -// LICENSE file // -/////////////////////////////////////////////////////////////////////////////// - -// cmix.go cMix functions for the auth module - -package auth - -import ( - "fmt" - - "github.com/pkg/errors" - jww "github.com/spf13/jwalterweatherman" - "gitlab.com/elixxir/client/interfaces" - "gitlab.com/elixxir/client/interfaces/params" - "gitlab.com/elixxir/client/interfaces/preimage" - "gitlab.com/elixxir/primitives/format" - "gitlab.com/xx_network/primitives/id" -) - -// getMixPayloadSize calculates the payload size of a cMix Message based on the -// total message size. -// TODO: Maybe move this to primitives and export it? -// FIXME: This can only vary per cMix network target, and it could be scoped -// to a Client instance. -func getMixPayloadSize(primeSize int) int { - return 2*primeSize - format.AssociatedDataSize - 1 -} - -// sendAuthRequest is a helper to send the cMix Message after the request -// is created. -func sendAuthRequest(recipient *id.ID, contents, mac []byte, primeSize int, - fingerprint format.Fingerprint, net interfaces.NetworkManager, - cMixParams params.CMIX) (id.Round, error) { - cmixMsg := format.NewMessage(primeSize) - cmixMsg.SetKeyFP(fingerprint) - cmixMsg.SetMac(mac) - cmixMsg.SetContents(contents) - - jww.INFO.Printf("Requesting Auth with %s, msgDigest: %s", - recipient, cmixMsg.Digest()) - - cMixParams.IdentityPreimage = preimage.GenerateRequest(recipient) - cMixParams.DebugTag = "auth.Request" - round, _, err := net.SendCMIX(cmixMsg, recipient, cMixParams) - if err != nil { - // if the send fails just set it to failed, it will - // but automatically retried - return 0, errors.WithMessagef(err, "Auth Request with %s "+ - "(msgDigest: %s) failed to transmit: %+v", recipient, - cmixMsg.Digest(), err) - } - - em := fmt.Sprintf("Auth Request with %s (msgDigest: %s) sent"+ - " on round %d", recipient, cmixMsg.Digest(), round) - jww.INFO.Print(em) - net.GetEventManager().Report(1, "Auth", "RequestSent", em) - return round, nil -} diff --git a/auth/manager.go b/auth/manager.go index a2ba826141ccbcf3a25bbae0c1df00afbda42d79..121df9259867dbe42c27227a8a08d300fa27b0ef 100644 --- a/auth/manager.go +++ b/auth/manager.go @@ -8,10 +8,15 @@ package auth import ( + "gitlab.com/elixxir/client/auth/store" + "gitlab.com/elixxir/client/e2e" + "gitlab.com/elixxir/client/event" "gitlab.com/elixxir/client/interfaces" "gitlab.com/elixxir/client/interfaces/message" + "gitlab.com/elixxir/client/network" "gitlab.com/elixxir/client/storage" "gitlab.com/elixxir/client/switchboard" + "gitlab.com/elixxir/crypto/cyclic" "gitlab.com/elixxir/crypto/fastRNG" "gitlab.com/xx_network/primitives/id" ) @@ -21,12 +26,13 @@ type Manager struct { confirmCallbacks *callbackMap resetCallbacks *callbackMap - rawMessages chan message.Receive + net network.Manager + e2e e2e.Handler + rng *fastRNG.StreamGenerator - storage *storage.Session - net interfaces.NetworkManager - rng *fastRNG.StreamGenerator - backupTrigger interfaces.TriggerBackup + store *store.Store + grp *cyclic.Group + event event.Manager replayRequests bool } diff --git a/auth/request.go b/auth/request.go index e3d987e577698225806423ccb1f26a8897711966..e0707e9a10fd038e1c5fcdc8f0d6215994777eca 100644 --- a/auth/request.go +++ b/auth/request.go @@ -8,9 +8,14 @@ package auth import ( + "fmt" auth2 "gitlab.com/elixxir/client/auth/store" "gitlab.com/elixxir/client/catalog" e2e2 "gitlab.com/elixxir/client/e2e/ratchet" + "gitlab.com/elixxir/client/network" + "gitlab.com/elixxir/client/network/message" + "gitlab.com/elixxir/primitives/format" + "gitlab.com/xx_network/crypto/signature/rsa" "io" "strings" @@ -32,156 +37,101 @@ import ( const terminator = ";" -func RequestAuth(partner, me contact.Contact, rng io.Reader, - storage *storage.Session, net interfaces.NetworkManager) (id.Round, error) { +func (m *Manager) RequestAuth(partner, me contact.Contact, + originDHPrivKey *cyclic.Int, temporary bool) (id.Round, error) { // check that an authenticated channel does not already exist - if _, err := storage.E2e().GetPartner(partner.ID); err == nil || + if _, err := m.e2e.GetPartner(partner.ID, me.ID); err == nil || !strings.Contains(err.Error(), e2e2.NoPartnerErrorStr) { return 0, errors.Errorf("Authenticated channel already " + "established with partner") } - return requestAuth(partner, me, rng, false, storage, net) -} - -func ResetSession(partner, me contact.Contact, rng io.Reader, - storage *storage.Session, net interfaces.NetworkManager) (id.Round, error) { - - // Delete authenticated channel if it exists. - if err := storage.E2e().DeletePartner(partner.ID); err != nil { - jww.WARN.Printf("Unable to delete partner when "+ - "resetting session: %+v", err) - } else { - // Delete any stored sent/received requests - storage.Auth().Delete(partner.ID) - } - - rqType, _, _, err := storage.Auth().GetRequest(partner.ID) - if err == nil && rqType == auth2.Sent { - return 0, errors.New("Cannot reset a session after " + - "sending request, caller must resend request instead") - } - - // Try to initiate a clean session request - return requestAuth(partner, me, rng, true, storage, net) + return m.requestAuth(partner, me, originDHPrivKey, temporary) } // requestAuth internal helper -func requestAuth(partner, me contact.Contact, rng io.Reader, reset bool, - storage *storage.Session, net interfaces.NetworkManager) (id.Round, error) { - - /*edge checks generation*/ - // check that the request is being sent from the proper ID - if !me.ID.Cmp(storage.GetUser().ReceptionID) { - return 0, errors.Errorf("Authenticated channel request " + - "can only be sent from user's identity") - } - - //denote if this is a resend of an old request - resend := false - - //lookup if an ongoing request is occurring - rqType, sr, _, err := storage.Auth().GetRequest(partner.ID) - if err != nil && !strings.Contains(err.Error(), auth2.NoRequest) { - return 0, errors.WithMessage(err, - "Cannot send a request after receiving unknown error "+ - "on requesting contact status") - } else if err == nil { - switch rqType { - case auth2.Receive: - // TODO: We've already received a request, so send a - // confirmation instead? - return 0, errors.Errorf("Cannot send a request after " + - "receiving a request") - case auth2.Sent: - resend = true - default: - return 0, errors.Errorf("Cannot send a request after "+ - "a stored request with unknown rqType: %d", - rqType) - } - } - - /*cryptographic generation*/ - var dhPriv, dhPub *cyclic.Int - var sidhPriv *sidh.PrivateKey - var sidhPub *sidh.PublicKey - - // NOTE: E2E group is the group used for DH key exchange, not cMix - dhGrp := storage.E2e().GetGroup() - // origin DH Priv key is the DH Key corresponding to the public key - // registered with user discovery - originDHPrivKey := storage.E2e().GetDHPrivateKey() - - // If we are resending (valid sent request), reuse those keys - if resend { - dhPriv = sr.GetMyPrivKey() - dhPub = sr.GetMyPubKey() - sidhPriv = sr.GetMySIDHPrivKey() - sidhPub = sr.GetMySIDHPubKey() - - } else { - dhPriv, dhPub = genDHKeys(dhGrp, rng) - sidhPriv, sidhPub = util.GenerateSIDHKeyPair( - sidh.KeyVariantSidhA, rng) - } - - jww.TRACE.Printf("RequestAuth MYPUBKEY: %v", dhPub.Bytes()) - jww.TRACE.Printf("RequestAuth THEIRPUBKEY: %v", - partner.DhPubKey.Bytes()) +func (m *Manager) requestAuth(partner, me contact.Contact, + originDHPrivKey *cyclic.Int, temporary bool) (id.Round, error) { - cMixPrimeSize := storage.Cmix().GetGroup().GetP().ByteLen() - cMixPayloadSize := getMixPayloadSize(cMixPrimeSize) + //do key generation + rng := m.rng.GetStream() + defer rng.Close() - sender := storage.GetUser().ReceptionID + dhPriv, dhPub := genDHKeys(m.grp, rng) + sidhPriv, sidhPub := util.GenerateSIDHKeyPair( + sidh.KeyVariantSidhA, rng) - //generate ownership proof ownership := cAuth.MakeOwnershipProof(originDHPrivKey, partner.DhPubKey, - dhGrp) + m.grp) confirmFp := cAuth.MakeOwnershipProofFP(ownership) - // cMix fingerprint so the recipient can recognize this is a - // request message. + // Add the sent request and use the return to build the send. This will + // replace the send with an old one if one was in process, wasting the key + // generation above. This is considered a reasonable loss due to the increase + // in code simplicity of this approach + sr, err := m.store.AddSent(partner.ID, me.ID, partner.DhPubKey, dhPriv, dhPub, + sidhPriv, sidhPub, confirmFp, temporary) + if err != nil { + if sr == nil { + return 0, err + } else { + jww.INFO.Printf("Resending request to %s from %s because "+ + "one was already sent", partner.ID, me) + } + } + + // cMix fingerprint. Used in old versions by the recipient can recognize + // this is a request message. Unchanged for backwards compatability + // (the SIH is used now) requestfp := cAuth.MakeRequestFingerprint(partner.DhPubKey) // My fact data so we can display in the interface. msgPayload := []byte(me.Facts.Stringify() + terminator) // Create the request packet. - request, mac, err := createRequestAuth(sender, msgPayload, ownership, + request, mac, err := createRequestAuth(partner.ID, msgPayload, ownership, dhPriv, dhPub, partner.DhPubKey, sidhPub, - dhGrp, cMixPayloadSize) + m.grp, m.net.GetMaxMessageLength()) if err != nil { return 0, err } contents := request.Marshal() - storage.GetEdge().Add(edge.Preimage{ - Data: preimage.Generate(confirmFp[:], catalog.Confirm), - Type: catalog.Confirm, - Source: partner.ID[:], - }, me.ID) + //todo-register correct service + m.net.AddService(me.ID, message.Service{ + Identifier: confirmFp[:], + Tag: catalog.Confirm, + Metadata: partner.ID[:], + }, nil) jww.TRACE.Printf("RequestAuth ECRPAYLOAD: %v", request.GetEcrPayload()) jww.TRACE.Printf("RequestAuth MAC: %v", mac) - /*store state*/ - //fixme: channel is bricked if the first store succedes but the second - // fails - //store the in progress auth if this is not a resend. - if !resend { - err = storage.Auth().AddSent(partner.ID, partner.DhPubKey, - dhPriv, dhPub, sidhPriv, sidhPub, confirmFp) - if err != nil { - return 0, errors.Errorf( - "Failed to store auth request: %s", err) - } + jww.INFO.Printf("Requesting Auth with %s, msgDigest: %s", + partner.ID, format.DigestContents(contents)) + + p := network.GetDefaultCMIXParams() + p.DebugTag = "auth.Request" + s := message.Service{ + Identifier: partner.ID.Marshal(), + Tag: catalog.Default, + Metadata: nil, } + round, _, err := m.net.SendCMIX(partner.ID, requestfp, s, contents, mac, p) + if err != nil { + // if the send fails just set it to failed, it will + // but automatically retried + return 0, errors.WithMessagef(err, "Auth Request with %s "+ + "(msgDigest: %s) failed to transmit: %+v", partner.ID, + format.DigestContents(contents), err) + } + + em := fmt.Sprintf("Auth Request with %s (msgDigest: %s) sent"+ + " on round %d", partner.ID, format.DigestContents(contents), round) + jww.INFO.Print(em) + m.event.Report(1, "Auth", "RequestSent", em) + return round, nil - cMixParams := params.GetDefaultCMIX() - rndID, err := sendAuthRequest(partner.ID, contents, mac, cMixPrimeSize, - requestfp, net, cMixParams) - return rndID, err } // genDHKeys is a short helper to generate a Diffie-Helman Keypair diff --git a/auth/reset.go b/auth/reset.go new file mode 100644 index 0000000000000000000000000000000000000000..2a28016164b72f03816cbb6cdeba25686b6a1d8e --- /dev/null +++ b/auth/reset.go @@ -0,0 +1,32 @@ +package auth + +import ( + jww "github.com/spf13/jwalterweatherman" + auth2 "gitlab.com/elixxir/client/auth/store" + "gitlab.com/elixxir/client/interfaces" + "gitlab.com/elixxir/client/storage" + "gitlab.com/elixxir/crypto/contact" + "gitlab.com/xx_network/primitives/id" + "io" +) + +func (m *Manager) ResetSession(partner, me contact.Contact, rng io.Reader) (id.Round, error) { + + // Delete authenticated channel if it exists. + if err := storage.E2e().DeletePartner(partner.ID); err != nil { + jww.WARN.Printf("Unable to delete partner when "+ + "resetting session: %+v", err) + } else { + // Delete any stored sent/received requests + storage.Auth().Delete(partner.ID) + } + + rqType, _, _, err := storage.Auth().GetRequest(partner.ID) + if err == nil && rqType == auth2.Sent { + return 0, errors.New("Cannot reset a session after " + + "sending request, caller must resend request instead") + } + + // Try to initiate a clean session request + return requestAuth(partner, me, rng, true, storage, net) +} diff --git a/auth/store/confirmation.go b/auth/store/confirmation.go index 6bd37b62dada4e1e5d3b6ebed7e1aa85700d283b..a321c354c5258f7e0613fd4d4cf67429672b9a88 100644 --- a/auth/store/confirmation.go +++ b/auth/store/confirmation.go @@ -56,6 +56,6 @@ func (s *Store) deleteConfirmation(partner *id.ID, fingerprint []byte) error { // makeConfirmationKey generates the key used to load and store confirmations // for the partner and fingerprint. func makeConfirmationKey(partner *id.ID, fingerprint []byte) string { - return confirmationKeyPrefix + partner.String() + "/" + - base64.StdEncoding.EncodeToString(fingerprint) + return confirmationKeyPrefix + base64.StdEncoding.EncodeToString( + partner.Marshal()) + "/" + base64.StdEncoding.EncodeToString(fingerprint) } diff --git a/auth/store/previousNegotiations.go b/auth/store/previousNegotiations.go index db49a7b25c7e8223299eff7b93d943d6a9dd92fe..7344318e822757578ed01d603709912c47851499 100644 --- a/auth/store/previousNegotiations.go +++ b/auth/store/previousNegotiations.go @@ -5,13 +5,6 @@ // LICENSE file // //////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -// Copyright © 2020 xx network SEZC // -// // -// Use of this source code is governed by a license that can be found in the // -// LICENSE file // -//////////////////////////////////////////////////////////////////////////////// - package store import ( @@ -52,10 +45,10 @@ func (s *Store) AddIfNew(partner, myID *id.ID, negotiationFingerprint []byte) ( aid := makeAuthIdentity(partner, myID) _, exists := s.previousNegotiations[aid] if !exists { - s.previousNegotiations[aid] = struct{}{} + s.previousNegotiations[aid] = true // Save fingerprint to storage - err := s.saveNegotiationFingerprints(partner, myID, negotiationFingerprint) + err := saveNegotiationFingerprints(partner, myID, s.kv, negotiationFingerprint) if err != nil { jww.FATAL.Panicf("Failed to save negotiation sentByFingerprints for "+ "partner %s: %+v", partner, err) @@ -75,7 +68,7 @@ func (s *Store) AddIfNew(partner, myID *id.ID, negotiationFingerprint []byte) ( } // get the fingerprint list from storage - fingerprints, err := s.loadNegotiationFingerprints(partner, myID) + fingerprints, err := loadNegotiationFingerprints(partner, myID, s.kv, myID.Cmp(s.defaultID)) if err != nil { jww.FATAL.Panicf("Failed to load negotiation sentByFingerprints for "+ "partner %s: %+v", partner, err) @@ -97,7 +90,7 @@ func (s *Store) AddIfNew(partner, myID *id.ID, negotiationFingerprint []byte) ( // If the partner does exist and the fingerprint does not exist, then add // the fingerprint to the list as latest fingerprints = append(fingerprints, negotiationFingerprint) - err = s.saveNegotiationFingerprints(partner, myID, fingerprints...) + err = saveNegotiationFingerprints(partner, myID, s.kv, fingerprints...) if err != nil { jww.FATAL.Panicf("Failed to save negotiation sentByFingerprints for "+ "partner %s: %+v", partner, err) @@ -109,48 +102,6 @@ func (s *Store) AddIfNew(partner, myID *id.ID, negotiationFingerprint []byte) ( return } -// deletePreviousNegotiationPartner removes the partner, its sentByFingerprints, and -// its confirmations from memory and storage. -func (s *Store) deletePreviousNegotiationPartner(partner, myID *id.ID) error { - - aid := makeAuthIdentity(partner, myID) - - // Do nothing if the partner does not exist - if _, exists := s.previousNegotiations[aid]; !exists { - return nil - } - - // Delete partner from memory - delete(s.previousNegotiations, aid) - - // Delete partner from storage and return an error - err := s.savePreviousNegotiations() - if err != nil { - return err - } - - // Check if sentByFingerprints exist - fingerprints, err := s.loadNegotiationFingerprints(partner, myID) - - // If sentByFingerprints exist for this partner, delete them from storage and any - // accompanying confirmations - if err == nil { - // Delete the fingerprint list from storage but do not return the error - // until after attempting to delete the confirmations - err = s.kv.Delete(makeNegotiationFingerprintsKey(partner, myID), - currentNegotiationFingerprintsVersion) - - // Delete all confirmations from storage - for _, fp := range fingerprints { - // Ignore the error since confirmations rarely exist - _ = s.deleteConfirmation(partner, fp) - } - } - - // Return any error from loading or deleting sentByFingerprints - return err -} - // savePreviousNegotiations saves the list of previousNegotiations partners to // storage. func (s *Store) savePreviousNegotiations() error { @@ -165,7 +116,7 @@ func (s *Store) savePreviousNegotiations() error { // newOrLoadPreviousNegotiations loads the list of previousNegotiations partners // from storage. -func (s *Store) newOrLoadPreviousNegotiations() (map[authIdentity]struct{}, error) { +func (s *Store) newOrLoadPreviousNegotiations() (map[authIdentity]bool, error) { obj, err := s.kv.Get(negotiationPartnersKey, negotiationPartnersVersion) if err != nil { @@ -175,7 +126,7 @@ func (s *Store) newOrLoadPreviousNegotiations() (map[authIdentity]struct{}, erro if err != nil { if strings.Contains(err.Error(), "object not found") || strings.Contains(err.Error(), "no such file or directory") { - return make(map[authIdentity]struct{}), nil + return make(map[authIdentity]bool), nil } else { return nil, err } @@ -190,7 +141,7 @@ func (s *Store) newOrLoadPreviousNegotiations() (map[authIdentity]struct{}, erro } // marshalPreviousNegotiations marshals the list of partners into a byte slice. -func marshalPreviousNegotiations(partners map[authIdentity]struct{}) []byte { +func marshalPreviousNegotiations(partners map[authIdentity]bool) []byte { toMarshal := make([]authIdentity, 0, len(partners)) for aid := range partners { @@ -207,7 +158,7 @@ func marshalPreviousNegotiations(partners map[authIdentity]struct{}) []byte { // unmarshalPreviousNegotiations unmarshalls the marshalled json into a //// list of partner IDs. -func unmarshalPreviousNegotiations(b []byte) (map[authIdentity]struct{}, +func unmarshalPreviousNegotiations(b []byte) (map[authIdentity]bool, error) { unmarshal := make([]authIdentity, 0) @@ -215,10 +166,10 @@ func unmarshalPreviousNegotiations(b []byte) (map[authIdentity]struct{}, return nil, err } - partners := make(map[authIdentity]struct{}) + partners := make(map[authIdentity]bool) for _, aid := range unmarshal { - partners[aid] = struct{}{} + partners[aid] = true } return partners, nil @@ -226,11 +177,11 @@ func unmarshalPreviousNegotiations(b []byte) (map[authIdentity]struct{}, // unmarshalOldPreviousNegotiations unmarshalls the marshalled json into a // list of partner IDs. -func unmarshalOldPreviousNegotiations(buf []byte, defaultID *id.ID) map[authIdentity]struct{} { +func unmarshalOldPreviousNegotiations(buf []byte, defaultID *id.ID) map[authIdentity]bool { buff := bytes.NewBuffer(buf) numberOfPartners := binary.LittleEndian.Uint64(buff.Next(8)) - partners := make(map[authIdentity]struct{}, numberOfPartners) + partners := make(map[authIdentity]bool, numberOfPartners) for i := uint64(0); i < numberOfPartners; i++ { partner, err := id.Unmarshal(buff.Next(id.ArrIDLen)) @@ -239,7 +190,7 @@ func unmarshalOldPreviousNegotiations(buf []byte, defaultID *id.ID) map[authIden "Failed to unmarshal negotiation partner ID: %+v", err) } - partners[makeAuthIdentity(partner, defaultID)] = struct{}{} + partners[makeAuthIdentity(partner, defaultID)] = false } return partners @@ -247,8 +198,8 @@ func unmarshalOldPreviousNegotiations(buf []byte, defaultID *id.ID) map[authIden // saveNegotiationFingerprints saves the list of sentByFingerprints for the given // partner to storage. -func (s *Store) saveNegotiationFingerprints( - partner, myID *id.ID, fingerprints ...[]byte) error { +func saveNegotiationFingerprints( + partner, myID *id.ID, kv *versioned.KV, fingerprints ...[]byte) error { obj := &versioned.Object{ Version: currentNegotiationFingerprintsVersion, @@ -256,23 +207,23 @@ func (s *Store) saveNegotiationFingerprints( Data: marshalNegotiationFingerprints(fingerprints...), } - return s.kv.Set(makeNegotiationFingerprintsKey(partner, myID), + return kv.Set(makeNegotiationFingerprintsKey(partner, myID), currentNegotiationFingerprintsVersion, obj) } // loadNegotiationFingerprints loads the list of sentByFingerprints for the given // partner from storage. -func (s *Store) loadNegotiationFingerprints(partner, myID *id.ID) ([][]byte, error) { - obj, err := s.kv.Get(makeNegotiationFingerprintsKey(partner, myID), +func loadNegotiationFingerprints(partner, myID *id.ID, kv *versioned.KV, possibleOld bool) ([][]byte, error) { + obj, err := kv.Get(makeNegotiationFingerprintsKey(partner, myID), currentNegotiationFingerprintsVersion) if err != nil { - if myID.Cmp(s.defaultID) { - obj, err = s.kv.Get(makeOldNegotiationFingerprintsKey(partner), + if possibleOld { + obj, err = kv.Get(makeOldNegotiationFingerprintsKey(partner), currentNegotiationFingerprintsVersion) if err != nil { return nil, err } - if err = s.kv.Set(makeNegotiationFingerprintsKey(partner, myID), + if err = kv.Set(makeNegotiationFingerprintsKey(partner, myID), currentNegotiationFingerprintsVersion, obj); err != nil { return nil, err } diff --git a/auth/store/receivedRequest.go b/auth/store/receivedRequest.go index 2dd7153d930bd8251f082ad297df9689b7fa938c..701fad374c26a515ec0a17a78954e0072bbdc0f9 100644 --- a/auth/store/receivedRequest.go +++ b/auth/store/receivedRequest.go @@ -128,3 +128,7 @@ func (rr *ReceivedRequest) delete() { func (rr *ReceivedRequest) getType() RequestType { return Receive } + +func (rr *ReceivedRequest) isTemporary() bool { + return rr.kv.IsMemStore() +} diff --git a/auth/store/sentRequest.go b/auth/store/sentRequest.go index 02721bdd251ca1503f71041e420c5c6447ddfa47..674c3b0552af4fe3a102d26c33ae7a43ba456c96 100644 --- a/auth/store/sentRequest.go +++ b/auth/store/sentRequest.go @@ -279,3 +279,7 @@ func (sr *SentRequest) getAuthID() authIdentity { func (sr *SentRequest) getType() RequestType { return Sent } + +func (sr *SentRequest) isTemporary() bool { + return sr.kv.IsMemStore() +} diff --git a/auth/store/sentRequestHandler.go b/auth/store/sentRequestHandler.go index d6d4b77a2df617804ee3ddbf99b2a186025d1e63..1f22c53a2647819d82aa609d3b7b38f2a5be045c 100644 --- a/auth/store/sentRequestHandler.go +++ b/auth/store/sentRequestHandler.go @@ -1,5 +1,6 @@ package store +// SentRequestHandler allows the lower fevel to assign and remove services type SentRequestHandler interface { Add(sr *SentRequest) Delete(sr *SentRequest) diff --git a/auth/store/store.go b/auth/store/store.go index 03438e9705be05c7a62983dbb94bdb0d95d19800..8b9a9c37941cc3d620c8e85835374db74ebc5eb5 100644 --- a/auth/store/store.go +++ b/auth/store/store.go @@ -30,11 +30,12 @@ const requestMapVersion = 0 type Store struct { kv *versioned.KV + memKV *versioned.KV grp *cyclic.Group receivedByID map[authIdentity]*ReceivedRequest sentByID map[authIdentity]*SentRequest - previousNegotiations map[authIdentity]struct{} + previousNegotiations map[authIdentity]bool defaultID *id.ID @@ -52,7 +53,7 @@ func NewStore(kv *versioned.KV, grp *cyclic.Group, srh SentRequestHandler) error grp: grp, receivedByID: make(map[authIdentity]*ReceivedRequest), sentByID: make(map[authIdentity]*SentRequest), - previousNegotiations: make(map[authIdentity]struct{}), + previousNegotiations: make(map[authIdentity]bool), srh: srh, } @@ -75,7 +76,7 @@ func LoadStore(kv *versioned.KV, defaultID *id.ID, grp *cyclic.Group, srh SentRe grp: grp, receivedByID: make(map[authIdentity]*ReceivedRequest), sentByID: make(map[authIdentity]*SentRequest), - previousNegotiations: make(map[authIdentity]struct{}), + previousNegotiations: make(map[authIdentity]bool), defaultID: defaultID, srh: srh, } @@ -151,22 +152,26 @@ func LoadStore(kv *versioned.KV, defaultID *id.ID, grp *cyclic.Group, srh SentRe func (s *Store) save() error { requestIDList := make([]requestDisk, 0, len(s.receivedByID)+len(s.sentByID)) - for _, r := range s.receivedByID { - rDisk := requestDisk{ - T: uint(r.getType()), - ID: r.partner.ID.Marshal(), - MyID: r.myID.Marshal(), + for _, rr := range s.receivedByID { + if !rr.isTemporary() { + rDisk := requestDisk{ + T: uint(rr.getType()), + ID: rr.partner.ID.Marshal(), + MyID: rr.myID.Marshal(), + } + requestIDList = append(requestIDList, rDisk) } - requestIDList = append(requestIDList, rDisk) } - for _, r := range s.sentByID { - rDisk := requestDisk{ - T: uint(r.getType()), - ID: r.partner.Marshal(), - MyID: r.myID.Marshal(), + for _, sr := range s.sentByID { + if !sr.isTemporary() { + rDisk := requestDisk{ + T: uint(sr.getType()), + ID: sr.partner.Marshal(), + MyID: sr.myID.Marshal(), + } + requestIDList = append(requestIDList, rDisk) } - requestIDList = append(requestIDList, rDisk) } data, err := json.Marshal(&requestIDList) @@ -190,13 +195,13 @@ func (s *Store) AddSent(partner, myID *id.ID, partnerHistoricalPubKey, myPrivKey aid := makeAuthIdentity(partner, myID) - if _, ok := s.sentByID[aid]; ok { - return nil, errors.Errorf("Cannot make new sentRequest for partner "+ - "%s, one already exists", partner) + if sentRq, ok := s.sentByID[aid]; ok { + return sentRq, errors.Errorf("Cannot make new sentRequest for partner "+ + "%s, a sent request already exists", partner) } if _, ok := s.receivedByID[aid]; ok { return nil, errors.Errorf("Cannot make new sentRequest for partner "+ - "%s, one already exists", partner) + "%s, a received reqyest already exists", partner) } sr, err := newSentRequest(s.kv, partner, myID, partnerHistoricalPubKey, myPrivKey, @@ -208,11 +213,16 @@ func (s *Store) AddSent(partner, myID *id.ID, partnerHistoricalPubKey, myPrivKey s.sentByID[sr.getAuthID()] = sr s.srh.Add(sr) + if err = s.save(); err != nil { + jww.FATAL.Panicf("Failed to save Sent Request Map after adding "+ + "partner %s to %s", partner, myID) + } return sr, nil } -func (s *Store) AddReceived(myID *id.ID, c contact.Contact, key *sidh.PublicKey) error { +func (s *Store) AddReceived(myID *id.ID, c contact.Contact, key *sidh.PublicKey, + temporary bool) error { s.mux.Lock() defer s.mux.Unlock() jww.DEBUG.Printf("AddReceived new contact: %s with %s", c.ID, myID) @@ -228,12 +238,19 @@ func (s *Store) AddReceived(myID *id.ID, c contact.Contact, key *sidh.PublicKey) "%s, one already exists", c.ID) } - r := newReceivedRequest(s.kv, myID, c, key) + kv := s.kv + if temporary { + kv = s.memKV + } + + r := newReceivedRequest(kv, myID, c, key) s.receivedByID[r.aid] = r - if err := s.save(); err != nil { - jww.FATAL.Panicf("Failed to save Sent Request Map after adding "+ - "partner %s", c.ID) + if !temporary { + if err := s.save(); err != nil { + jww.FATAL.Panicf("Failed to save Sent Request Map after adding "+ + "partner %s to %s", c.ID, myID) + } } return nil @@ -346,21 +363,3 @@ func (s *Store) GetReceivedRequest(partner, myID *id.ID) (contact.Contact, error return r.partner, nil } - -// Done is one of two calls after using a request. This one is to be used when -// the use is unsuccessful. It will allow any thread waiting on access to -// continue using the structure. -// It does not return an error because an error is not handleable. -func (s *Store) Done(rr *ReceivedRequest) { - s.mux.RLock() - r, ok := s.receivedByID[rr.aid] - s.mux.RUnlock() - - r.mux.Unlock() - - if !ok { - jww.ERROR.Panicf("Request cannot be finished, not "+ - "found: %s, %s", rr.partner, rr.myID) - return - } -} diff --git a/catalog/messageTypes.go b/catalog/messageTypes.go index a5fc5c9b442417b7e6d642267bf3ed70ca53b06c..969e6c703d1f56ab5db32bcbebfed0acf0d74c42 100644 --- a/catalog/messageTypes.go +++ b/catalog/messageTypes.go @@ -16,11 +16,20 @@ const ( /*End to End Rekey message types*/ - // KeyExchangeTrigger - Trigger a rekey, this message is used locally in client only + // KeyExchangeTrigger - Trigger a rekey, this message is used locally in + // client only KeyExchangeTrigger = 30 - // KeyExchangeConfirm - Rekey confirmation message. Sent by partner to confirm completion of a rekey + // KeyExchangeConfirm - Rekey confirmation message. Sent by partner to + //confirm completion of a rekey KeyExchangeConfirm = 31 + // KeyExchangeTriggerEphemeral - Trigger a rekey, this message is used + //locally in client only. For ephemeral only e2e instances. + KeyExchangeTriggerEphemeral = 32 + // KeyExchangeConfirmEphemeral - Rekey confirmation message. Sent by partner + // to confirm completion of a rekey. For ephemeral only e2e instances. + KeyExchangeConfirmEphemeral = 33 + /* Group chat message types */ // GroupCreationRequest - A group chat request message sent to all members in a group. diff --git a/e2e/interface.go b/e2e/interface.go index c2d00e3e24b9da5eb253f02198b1c5ff21ca7414..b830945ac1416f9d647d423497d3d720bdc165d7 100644 --- a/e2e/interface.go +++ b/e2e/interface.go @@ -101,7 +101,7 @@ type Handler interface { AddPartner(myID *id.ID, partnerID *id.ID, partnerPubKey, myPrivKey *cyclic.Int, partnerSIDHPubKey *sidh.PublicKey, mySIDHPrivKey *sidh.PrivateKey, sendParams, - receiveParams session.Params, temporary bool) (*partner.Manager, error) + receiveParams session.Params) (*partner.Manager, error) // GetPartner returns the partner per its ID, if it exists // myID is your ID in the relationship, if left blank, it will diff --git a/e2e/manager.go b/e2e/manager.go index 1a35f15746b91088579b90936eec88c65cbc6d14..f850add4b1be9a075e6ec8118ee69ff3aeb52f4d 100644 --- a/e2e/manager.go +++ b/e2e/manager.go @@ -28,12 +28,15 @@ type manager struct { events event.Manager grp *cyclic.Group crit *critical + rekeyParams rekey.Params } // Init Creates stores. After calling, use load // Passes a default ID and public key which is used for relationship with // partners when no default ID is selected -func Init(kv *versioned.KV, myDefaultID *id.ID, privKey *cyclic.Int, grp *cyclic.Group) error { +func Init(kv *versioned.KV, myDefaultID *id.ID, privKey *cyclic.Int, + grp *cyclic.Group, rekeyParams rekey.Params) error { + //store rekey params here return ratchet.New(kv, myDefaultID, privKey, grp) } @@ -61,6 +64,8 @@ func Load(kv *versioned.KV, net network.Manager, myDefaultID *id.ID, return nil, err } + //load rekey params here + //attach critical messages m.crit = newCritical(kv, net.AddHealthCallback, net.GetInstance().GetRoundEvents(), m.SendE2E) diff --git a/e2e/ratchet/ratchet.go b/e2e/ratchet/ratchet.go index 0c1bb6591fe5e2c69f7b2c90f46152052f103a96..695af6272ee25811d9e97f92877aef423ed93cc8 100644 --- a/e2e/ratchet/ratchet.go +++ b/e2e/ratchet/ratchet.go @@ -48,8 +48,7 @@ type Ratchet struct { sInteface Services servicesmux sync.RWMutex - kv *versioned.KV - memKv *versioned.KV + kv *versioned.KV } // New creates a new store for the passed user id and private key. @@ -98,7 +97,7 @@ func New(kv *versioned.KV, myID *id.ID, privKey *cyclic.Int, func (r *Ratchet) AddPartner(myID *id.ID, partnerID *id.ID, partnerPubKey, myPrivKey *cyclic.Int, partnerSIDHPubKey *sidh.PublicKey, mySIDHPrivKey *sidh.PrivateKey, sendParams, - receiveParams session.Params, temporary bool) (*partner.Manager, error) { + receiveParams session.Params) (*partner.Manager, error) { r.mux.Lock() defer r.mux.Unlock() @@ -117,14 +116,7 @@ func (r *Ratchet) AddPartner(myID *id.ID, partnerID *id.ID, if _, ok := r.managers[mid]; ok { return nil, errors.New("Cannot overwrite existing partner") } - - //pass a memory kv if it is supposed to be temporary - kv := r.kv - if temporary { - kv = r.memKv - } - - m := partner.NewManager(kv, r.defaultID, partnerID, myPrivKey, partnerPubKey, + m := partner.NewManager(r.kv, r.defaultID, partnerID, myPrivKey, partnerPubKey, mySIDHPrivKey, partnerSIDHPubKey, sendParams, receiveParams, r.cyHandler, r.grp, r.rng) diff --git a/e2e/ratchet/storage.go b/e2e/ratchet/storage.go index 0afc09c2a4a557d7fd39dd02f666a959567cc485..1b53cb99ea1f51b1bb106a8bb62d74ca11bc41eb 100644 --- a/e2e/ratchet/storage.go +++ b/e2e/ratchet/storage.go @@ -11,7 +11,6 @@ import ( "gitlab.com/elixxir/client/storage/versioned" "gitlab.com/elixxir/crypto/cyclic" "gitlab.com/elixxir/crypto/fastRNG" - "gitlab.com/elixxir/ekv" "gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/netTime" ) @@ -33,8 +32,7 @@ func Load(kv *versioned.KV, myID *id.ID, grp *cyclic.Group, defaultID: myID, - kv: kv, - memKv: versioned.NewKV(make(ekv.Memstore)), + kv: kv, cyHandler: cyHandler, grp: grp, @@ -97,11 +95,9 @@ func (r *Ratchet) marshal() ([]byte, error) { contacts := make([]partner.ManagerIdentity, len(r.managers)) index := 0 - for rid, m := range r.managers { - if !m.IsTemporary() { - contacts[index] = rid - index++ - } + for rid, _ := range r.managers { + contacts[index] = rid + index++ } return json.Marshal(&contacts) diff --git a/e2e/rekey/confirm_test.go b/e2e/rekey/confirm_test.go index 8da1485ab2447e9d1feee0c2db0d1039049fbe62..3cfbfb57d27355d59d5f82b7dc59a8d0920c89c3 100644 --- a/e2e/rekey/confirm_test.go +++ b/e2e/rekey/confirm_test.go @@ -69,7 +69,7 @@ func TestHandleConfirm(t *testing.T) { // Add bob as a partner sendParams := session.GetDefaultParams() receiveParams := session.GetDefaultParams() - _, err = r.AddPartner(myID, bobID, bobPubKey, alicePrivKey, bobSIDHPubKey, aliceSIDHPrivKey, sendParams, receiveParams, false) + _, err = r.AddPartner(myID, bobID, bobPubKey, alicePrivKey, bobSIDHPubKey, aliceSIDHPrivKey, sendParams, receiveParams) if err != nil { t.Errorf("Failed to add partner to ratchet: %+v", err) } diff --git a/e2e/rekey/exchange.go b/e2e/rekey/exchange.go index c5e111e5c8cc9f500aea1ef7f1a2b6544919f5b3..2bfd86e89bea4ea607fd2394b8b8e6d8dd91ee36 100644 --- a/e2e/rekey/exchange.go +++ b/e2e/rekey/exchange.go @@ -19,10 +19,6 @@ import ( "time" ) -const keyExchangeTriggerName = "KeyExchangeTrigger" -const keyExchangeConfirmName = "KeyExchangeConfirm" -const keyExchangeMulti = "KeyExchange" - type E2eSender func(mt catalog.MessageType, recipient *id.ID, payload []byte, cmixParams network.CMIXParams) ( []id.Round, e2e.MessageID, time.Time, error) @@ -32,11 +28,11 @@ func Start(switchboard *receive.Switchboard, ratchet *ratchet.Ratchet, // register the rekey trigger thread triggerCh := make(chan receive.Message, 100) - triggerID := switchboard.RegisterChannel(keyExchangeTriggerName, - &id.ID{}, catalog.KeyExchangeTrigger, triggerCh) + triggerID := switchboard.RegisterChannel(params.TriggerName, + &id.ID{}, params.Trigger, triggerCh) // create the trigger stoppable - triggerStop := stoppable.NewSingle(keyExchangeTriggerName) + triggerStop := stoppable.NewSingle(params.TriggerName) cleanupTrigger := func() { switchboard.Unregister(triggerID) @@ -48,11 +44,11 @@ func Start(switchboard *receive.Switchboard, ratchet *ratchet.Ratchet, //register the rekey confirm thread confirmCh := make(chan receive.Message, 100) - confirmID := switchboard.RegisterChannel(keyExchangeConfirmName, - &id.ID{}, catalog.KeyExchangeConfirm, confirmCh) + confirmID := switchboard.RegisterChannel(params.ConfirmName, + &id.ID{}, params.Confirm, confirmCh) // register the confirm stoppable - confirmStop := stoppable.NewSingle(keyExchangeConfirmName) + confirmStop := stoppable.NewSingle(params.ConfirmName) cleanupConfirm := func() { switchboard.Unregister(confirmID) } @@ -61,7 +57,7 @@ func Start(switchboard *receive.Switchboard, ratchet *ratchet.Ratchet, go startConfirm(ratchet, confirmCh, confirmStop, cleanupConfirm) //bundle the stoppables and return - exchangeStop := stoppable.NewMulti(keyExchangeMulti) + exchangeStop := stoppable.NewMulti(params.StoppableName) exchangeStop.Add(triggerStop) exchangeStop.Add(confirmStop) return exchangeStop, nil diff --git a/e2e/rekey/params.go b/e2e/rekey/params.go index 3579c44716ec967b1f29ceb9960ea1e4291b9aeb..0611e67e84b4875bae35f29855fbddc0e007fe83 100644 --- a/e2e/rekey/params.go +++ b/e2e/rekey/params.go @@ -1,13 +1,44 @@ package rekey -import "time" +import ( + "gitlab.com/elixxir/client/catalog" + "time" +) + +const keyExchangeTriggerName = "KeyExchangeTrigger" +const keyExchangeConfirmName = "KeyExchangeConfirm" +const keyExchangeMulti = "KeyExchange" + +const keyExchangeTriggerEphemeralName = "KeyExchangeTriggerEphemeral" +const keyExchangeConfirmEphemeralName = "KeyExchangeConfirmEphemeral" +const keyExchangeEphemeralMulti = "KeyExchangeEphemeral" type Params struct { - RoundTimeout time.Duration + RoundTimeout time.Duration + TriggerName string + Trigger catalog.MessageType + ConfirmName string + Confirm catalog.MessageType + StoppableName string } func GetDefaultParams() Params { return Params{ - RoundTimeout: time.Minute, + RoundTimeout: time.Minute, + TriggerName: keyExchangeTriggerName, + Trigger: catalog.KeyExchangeTrigger, + ConfirmName: keyExchangeConfirmName, + Confirm: catalog.KeyExchangeConfirm, + StoppableName: keyExchangeMulti, } } + +func GetDefaultEphemeralParams() Params { + p := GetDefaultParams() + p.TriggerName = keyExchangeTriggerEphemeralName + p.Trigger = catalog.KeyExchangeTriggerEphemeral + p.ConfirmName = keyExchangeConfirmEphemeralName + p.Confirm = catalog.KeyExchangeConfirmEphemeral + p.StoppableName = keyExchangeEphemeralMulti + return p +} diff --git a/e2e/rekey/rekey.go b/e2e/rekey/rekey.go index b25764b6100a0e865053fc75fef6c30ec84cf395..801e5538ea23c472bb6cd00284844ad6c5437653 100644 --- a/e2e/rekey/rekey.go +++ b/e2e/rekey/rekey.go @@ -94,7 +94,7 @@ func trigger(instance *commsNetwork.Instance, grp *cyclic.Group, sendE2E E2eSend } func negotiate(instance *commsNetwork.Instance, grp *cyclic.Group, sendE2E E2eSender, - sess *session.Session, sendTimeout time.Duration) error { + param Params, sess *session.Session, sendTimeout time.Duration) error { //generate public key pubKey := diffieHellman.GeneratePublicKey(sess.GetMyPrivKey(), grp) @@ -123,7 +123,7 @@ func negotiate(instance *commsNetwork.Instance, grp *cyclic.Group, sendE2E E2eSe params := network.GetDefaultCMIXParams() params.DebugTag = "kx.Request" - rounds, msgID, _, err := sendE2E(catalog.KeyExchangeTrigger, sess.GetPartner(), + rounds, msgID, _, err := sendE2E(param.Trigger, sess.GetPartner(), payload, params) // If the send fails, returns the error so it can be handled. The caller // should ensure the calling session is in a state where the Rekey will diff --git a/e2e/rekey/trigger.go b/e2e/rekey/trigger.go index 8d37e0e2f8f4f7b2764a91b4b1e0c0adf46ff7ce..4eb03ca19dbd15ee79fb2ac2c1c78c63f12a254b 100644 --- a/e2e/rekey/trigger.go +++ b/e2e/rekey/trigger.go @@ -13,7 +13,6 @@ import ( "github.com/golang/protobuf/proto" "github.com/pkg/errors" jww "github.com/spf13/jwalterweatherman" - "gitlab.com/elixxir/client/catalog" "gitlab.com/elixxir/client/e2e/ratchet" "gitlab.com/elixxir/client/e2e/ratchet/partner/session" "gitlab.com/elixxir/client/e2e/receive" @@ -120,7 +119,7 @@ func handleTrigger(ratchet *ratchet.Ratchet, sender E2eSender, params := network.GetDefaultCMIXParams() params.Critical = true //ignore results, the passed sender interface makes it a critical message - _, _, _, _ = sender(catalog.KeyExchangeConfirm, request.Sender, payload, + _, _, _, _ = sender(param.Confirm, request.Sender, payload, params) return nil