diff --git a/auth/manager.go b/auth/manager.go index 121df9259867dbe42c27227a8a08d300fa27b0ef..2d817ec301fe4a24f26a41e3b5384ddb43bc3661 100644 --- a/auth/manager.go +++ b/auth/manager.go @@ -34,9 +34,17 @@ type Manager struct { grp *cyclic.Group event event.Manager + registeredIDs map[id.ID]keypair + replayRequests bool } +type keypair struct { + privkey *cyclic.Int + //generated from pubkey on instantiation + pubkey *cyclic.Int +} + func NewManager(sw interfaces.Switchboard, storage *storage.Session, net interfaces.NetworkManager, rng *fastRNG.StreamGenerator, backupTrigger interfaces.TriggerBackup, replayRequests bool) *Manager { diff --git a/auth/receivedRequest.go b/auth/receivedRequest.go new file mode 100644 index 0000000000000000000000000000000000000000..bb92273031b13c3ef26655e1d7fb21e9d51080a2 --- /dev/null +++ b/auth/receivedRequest.go @@ -0,0 +1,109 @@ +package auth + +import ( + "encoding/base64" + "fmt" + "github.com/cloudflare/circl/dh/sidh" + "github.com/pkg/errors" + jww "github.com/spf13/jwalterweatherman" + "gitlab.com/elixxir/client/network/historical" + "gitlab.com/elixxir/client/network/identity/receptionID" + cAuth "gitlab.com/elixxir/crypto/e2e/auth" + "gitlab.com/elixxir/primitives/fact" + "gitlab.com/elixxir/primitives/format" + "gitlab.com/xx_network/primitives/id" +) + +type receivedRequestService struct { + m *Manager +} + +func (rrs *receivedRequestService) Process(message format.Message, + receptionID receptionID.EphemeralIdentity, round historical.Round) { + + //decode the outer format + baseFmt, partnerPubKey, err := handleBaseFormat( + message, rrs.m.grp) + if err != nil { + jww.WARN.Printf("Failed to handle auth request: %s", err) + return + } + + //lookup the keypair + kp := rrs.m.registeredIDs[*receptionID.Source] + + jww.TRACE.Printf("processing requests: \n\t MYPUBKEY: %s "+ + "\n\t PARTNERPUBKEY: %s \n\t ECRPAYLOAD: %s \n\t MAC: %s", + kp.pubkey.TextVerbose(16, 0), + partnerPubKey.TextVerbose(16, 0), + base64.StdEncoding.EncodeToString(baseFmt.data), + base64.StdEncoding.EncodeToString(message.GetMac())) + + //Attempt to decrypt the payload + success, payload := cAuth.Decrypt(kp.privkey, partnerPubKey, + baseFmt.GetEcrPayload(), message.GetMac(), rrs.m.grp) + + if !success { + jww.WARN.Printf("Received auth request of %s failed its mac "+ + "check", receptionID.Source) + return + } + + //extract data from the decrypted payload + partnerID, partnerSIDHPubKey, facts, err := processDecryptedMessage(payload) + if err != nil { + jww.WARN.Printf("Failed to decode the auth request: %+v", err) + return + } + + em := fmt.Sprintf("Received AuthRequest from %s,"+ + " msgDigest: %s", partnerID, format.DigestContents(message.GetContents())) + jww.INFO.Print(em) + rrs.m.event.Report(1, "Auth", "RequestReceived", em) + + // check the uniqueness of the request. Requests can be duplicated, so we must + // verify this is is not a duplicate, and drop if it is + fp := cAuth.CreateNegotiationFingerprint(partnerPubKey, + partnerSIDHPubKey) + newFP, latest := rrs.m.store.CheckIfNegotiationIsNew(partnerID, + receptionID.Source, fp) + +} + +func processDecryptedMessage(b []byte) (*id.ID, *sidh.PublicKey, fact.FactList, + error) { + //decode the ecr format + ecrFmt, err := unmarshalEcrFormat(b) + if err != nil { + return nil, nil, nil, errors.WithMessage(err, "Failed to "+ + "unmarshal auth request's encrypted payload") + } + + partnerSIDHPubKey, err := ecrFmt.GetSidhPubKey() + if err != nil { + return nil, nil, nil, errors.WithMessage(err, "Could not "+ + "unmarshal partner SIDH Pubkey") + } + + //decode the request format + requestFmt, err := newRequestFormat(ecrFmt) + if err != nil { + return nil, nil, nil, errors.WithMessage(err, "Failed to "+ + "unmarshal auth request's internal payload") + } + + partnerID, err := requestFmt.GetID() + if err != nil { + return nil, nil, nil, errors.WithMessage(err, "Failed to "+ + "unmarshal auth request's sender ID") + } + + facts, _, err := fact.UnstringifyFactList( + string(requestFmt.msgPayload)) + if err != nil { + return nil, nil, nil, errors.WithMessage(err, "Failed to "+ + "unmarshal auth request's facts") + } + + return partnerID, partnerSIDHPubKey, facts, nil +} diff --git a/auth/request.go b/auth/request.go index e0707e9a10fd038e1c5fcdc8f0d6215994777eca..daaa3f071e334a08aa3ab8545000f6dcb089a93d 100644 --- a/auth/request.go +++ b/auth/request.go @@ -38,7 +38,7 @@ import ( const terminator = ";" func (m *Manager) RequestAuth(partner, me contact.Contact, - originDHPrivKey *cyclic.Int, temporary bool) (id.Round, error) { + originDHPrivKey *cyclic.Int) (id.Round, error) { // check that an authenticated channel does not already exist if _, err := m.e2e.GetPartner(partner.ID, me.ID); err == nil || !strings.Contains(err.Error(), e2e2.NoPartnerErrorStr) { @@ -46,12 +46,12 @@ func (m *Manager) RequestAuth(partner, me contact.Contact, "established with partner") } - return m.requestAuth(partner, me, originDHPrivKey, temporary) + return m.requestAuth(partner, me, originDHPrivKey) } // requestAuth internal helper func (m *Manager) requestAuth(partner, me contact.Contact, - originDHPrivKey *cyclic.Int, temporary bool) (id.Round, error) { + originDHPrivKey *cyclic.Int) (id.Round, error) { //do key generation rng := m.rng.GetStream() @@ -70,7 +70,7 @@ func (m *Manager) requestAuth(partner, me contact.Contact, // 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) + sidhPriv, sidhPub, confirmFp) if err != nil { if sr == nil { return 0, err diff --git a/auth/store/previousNegotiations.go b/auth/store/previousNegotiations.go index 7344318e822757578ed01d603709912c47851499..80db8cab9fe42d37116af2c4a35311e1484dfc95 100644 --- a/auth/store/previousNegotiations.go +++ b/auth/store/previousNegotiations.go @@ -27,16 +27,16 @@ const ( currentNegotiationFingerprintsVersion = 0 ) -// AddIfNew adds a new negotiation fingerprint if it is new. +// CheckIfNegotiationIsNew adds a new negotiation fingerprint if it is new. // If the partner does not exist, it will add it and the new fingerprint and -// return newFingerprint = true, latest = true. +// return newFingerprint = true. // If the partner exists and the fingerprint does not exist, add it adds it as // the latest fingerprint and returns newFingerprint = true, latest = true // If the partner exists and the fingerprint exists, return // newFingerprint = false, latest = false or latest = true if it is the last one // in the list. -func (s *Store) AddIfNew(partner, myID *id.ID, negotiationFingerprint []byte) ( - newFingerprint, latest bool) { +func (s *Store) CheckIfNegotiationIsNew(partner, myID *id.ID, negotiationFingerprint []byte) ( + newFingerprint bool, position uint) { s.mux.Lock() defer s.mux.Unlock() diff --git a/auth/store/previousNegotiations_test.go b/auth/store/previousNegotiations_test.go index b227fb5c501ac1cf8825e4ce2328d5211421ec16..01c04ae40e9bef96567a31b7c5b57899a2b19445 100644 --- a/auth/store/previousNegotiations_test.go +++ b/auth/store/previousNegotiations_test.go @@ -23,7 +23,7 @@ import ( "testing" ) -// Tests the four possible cases of Store.AddIfNew: +// Tests the four possible cases of Store.CheckIfNegotationIsNew: // 1. If the partner does not exist, add partner with the new fingerprint. // Returns newFingerprint = true, latest = true. // 2. If the partner exists and the fingerprint does not, add the fingerprint. @@ -141,7 +141,7 @@ func TestStore_AddIfNew(t *testing.T) { } } - newFingerprint, latest := s.AddIfNew(tt.partner, tt.fp) + newFingerprint, latest := s.CheckIfNegotationIsNew(tt.partner, tt.fp) if newFingerprint != tt.newFingerprint { t.Errorf("Unexpected value for newFingerprint."+ diff --git a/auth/store/store.go b/auth/store/store.go index 8b9a9c37941cc3d620c8e85835374db74ebc5eb5..eb4d5a610ecae9f46b66f2cdb03b483d27599eef 100644 --- a/auth/store/store.go +++ b/auth/store/store.go @@ -30,7 +30,6 @@ const requestMapVersion = 0 type Store struct { kv *versioned.KV - memKV *versioned.KV grp *cyclic.Group receivedByID map[authIdentity]*ReceivedRequest sentByID map[authIdentity]*SentRequest @@ -221,8 +220,7 @@ func (s *Store) AddSent(partner, myID *id.ID, partnerHistoricalPubKey, myPrivKey return sr, nil } -func (s *Store) AddReceived(myID *id.ID, c contact.Contact, key *sidh.PublicKey, - temporary bool) error { +func (s *Store) AddReceived(myID *id.ID, c contact.Contact, key *sidh.PublicKey) error { s.mux.Lock() defer s.mux.Unlock() jww.DEBUG.Printf("AddReceived new contact: %s with %s", c.ID, myID) @@ -237,20 +235,12 @@ func (s *Store) AddReceived(myID *id.ID, c contact.Contact, key *sidh.PublicKey, return errors.Errorf("Cannot add contact for partner "+ "%s, one already exists", c.ID) } - - kv := s.kv - if temporary { - kv = s.memKV - } - - r := newReceivedRequest(kv, myID, c, key) + r := newReceivedRequest(s.kv, myID, c, key) s.receivedByID[r.aid] = r - 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) - } + 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 diff --git a/auth/store/store_test.go b/auth/store/store_test.go index 20f09f27928df8eb620a4832b76cff2a054582b0..43a2dd69fc35c13975bc64ee377814b06887551e 100644 --- a/auth/store/store_test.go +++ b/auth/store/store_test.go @@ -88,7 +88,7 @@ func TestLoadStore(t *testing.T) { t.Fatalf("AddSent() produced an error: %+v", err) } - s.AddIfNew( + s.CheckIfNegotationIsNew( sr.partner, auth.CreateNegotiationFingerprint(privKeys[0], sidhPubKey)) // Attempt to load the store diff --git a/e2e/interface.go b/e2e/interface.go index b830945ac1416f9d647d423497d3d720bdc165d7..96496eda48a4e13722df818ff2599ddd66e38541 100644 --- a/e2e/interface.go +++ b/e2e/interface.go @@ -149,4 +149,18 @@ type Handler interface { // EnableUnsafeReception enables the reception of unsafe message by // registering bespoke services for reception. For debugging only! EnableUnsafeReception() + + /* === Utility ========================================================== */ + + // GetGroup returns the cyclic group used for end to end encruption + GetGroup() *cyclic.Group + + // GetDefaultHistoricalDHPubkey returns the default user's Historical DH Public Key + GetDefaultHistoricalDHPubkey() *cyclic.Int + + // GetDefaultHistoricalDHPrivkey returns the default user's Historical DH Private Key + GetDefaultHistoricalDHPrivkey() *cyclic.Int + + // GetDefaultID returns the default IDs + GetDefaultID() *id.ID } diff --git a/e2e/util.go b/e2e/util.go new file mode 100644 index 0000000000000000000000000000000000000000..8acd9cac3415a76f21fa4e7ca41f4dc9f10d06ed --- /dev/null +++ b/e2e/util.go @@ -0,0 +1,26 @@ +package e2e + +import ( + "gitlab.com/elixxir/crypto/cyclic" + "gitlab.com/xx_network/primitives/id" +) + +// GetGroup returns the cyclic group used for end to end encruption +func (m *manager) GetGroup() *cyclic.Group { + return m.grp +} + +// GetDefaultHistoricalDHPubkey returns the default user's Historical DH Public Key +func (m *manager) GetDefaultHistoricalDHPubkey() *cyclic.Int { + return m.Ratchet.GetDHPublicKey() +} + +// GetDefaultHistoricalDHPrivkey returns the default user's Historical DH Private Key +func (m *manager) GetDefaultHistoricalDHPrivkey() *cyclic.Int { + return m.Ratchet.GetDHPrivateKey() +} + +// GetDefaultID returns the default IDs +func (m *manager) GetDefaultID() *id.ID { + return m.myDefaultID +}