Skip to content
Snippets Groups Projects
Commit c8e5235d authored by Josh Brooks's avatar Josh Brooks
Browse files

Improve documentation & organization of auth package

parent 3cf2e785
No related branches found
No related tags found
2 merge requests!510Release,!207WIP: Client Restructure
...@@ -51,97 +51,98 @@ func (s *state) confirm(partner contact.Contact, serviceTag string) ( ...@@ -51,97 +51,98 @@ func (s *state) confirm(partner contact.Contact, serviceTag string) (
var sentRound id.Round var sentRound id.Round
//run the handler //run the handler
err := s.store.HandleReceivedRequest(partner.ID, func(rr *store.ReceivedRequest) error { err := s.store.HandleReceivedRequest(partner.ID,
// verify the passed contact matches what is stored func(rr *store.ReceivedRequest) error {
if rr.GetContact().DhPubKey.Cmp(partner.DhPubKey) != 0 { // verify the passed contact matches what is stored
return errors.New("pending Auth Request has different " + if rr.GetContact().DhPubKey.Cmp(partner.DhPubKey) != 0 {
"pubkey than stored") return errors.New("pending Auth Request has different " +
} "pubkey than stored")
}
/*cryptographic generation*/
/*cryptographic generation*/
// generate ownership proof
ownership := cAuth.MakeOwnershipProof(s.e2e.GetHistoricalDHPrivkey(), // generate ownership proof
partner.DhPubKey, s.e2e.GetGroup()) ownership := cAuth.MakeOwnershipProof(s.e2e.GetHistoricalDHPrivkey(),
partner.DhPubKey, s.e2e.GetGroup())
rng := s.rng.GetStream()
rng := s.rng.GetStream()
// generate new keypair
dhPriv, dhPub := genDHKeys(s.e2e.GetGroup(), rng) // generate new keypair
sidhVariant := util.GetCompatibleSIDHVariant( dhPriv, dhPub := genDHKeys(s.e2e.GetGroup(), rng)
rr.GetTheirSidHPubKeyA().Variant()) sidhVariant := util.GetCompatibleSIDHVariant(
sidhPriv, sidhPub := util.GenerateSIDHKeyPair(sidhVariant, rng) rr.GetTheirSidHPubKeyA().Variant())
sidhPriv, sidhPub := util.GenerateSIDHKeyPair(sidhVariant, rng)
rng.Close()
rng.Close()
/*construct message*/
// we build the payload before we save because it is technically fallible /*construct message*/
// which can get into a bricked state if it fails // we build the payload before we save because it is technically
baseFmt := newBaseFormat(s.net.GetMaxMessageLength(), // fallible which can get into a bricked state if it fails
s.e2e.GetGroup().GetP().ByteLen()) baseFmt := newBaseFormat(s.net.GetMaxMessageLength(),
ecrFmt := newEcrFormat(baseFmt.GetEcrPayloadLen()) s.e2e.GetGroup().GetP().ByteLen())
ecrFmt := newEcrFormat(baseFmt.GetEcrPayloadLen())
// setup the encrypted payload
ecrFmt.SetOwnership(ownership) // setup the encrypted payload
ecrFmt.SetSidHPubKey(sidhPub) ecrFmt.SetOwnership(ownership)
// confirmation has no custom payload ecrFmt.SetSidHPubKey(sidhPub)
// confirmation has no custom payload
// encrypt the payload
ecrPayload, mac := cAuth.Encrypt(dhPriv, partner.DhPubKey, // encrypt the payload
ecrFmt.data, s.e2e.GetGroup()) ecrPayload, mac := cAuth.Encrypt(dhPriv, partner.DhPubKey,
ecrFmt.data, s.e2e.GetGroup())
// get the fingerprint from the old ownership proof
fp := cAuth.MakeOwnershipProofFP(rr.GetContact().OwnershipProof) // get the fingerprint from the old ownership proof
fp := cAuth.MakeOwnershipProofFP(rr.GetContact().OwnershipProof)
// final construction
baseFmt.SetEcrPayload(ecrPayload) // final construction
baseFmt.SetPubKey(dhPub) baseFmt.SetEcrPayload(ecrPayload)
baseFmt.SetPubKey(dhPub)
jww.TRACE.Printf("SendConfirm PARTNERPUBKEY: %v",
partner.DhPubKey.TextVerbose(16, 0)) jww.TRACE.Printf("SendConfirm PARTNERPUBKEY: %v",
jww.TRACE.Printf("SendConfirm MYPUBKEY: %v", dhPub.TextVerbose(16, 0)) partner.DhPubKey.TextVerbose(16, 0))
jww.TRACE.Printf("SendConfirm MYPUBKEY: %v", dhPub.TextVerbose(16, 0))
jww.TRACE.Printf("SendConfirm ECRPAYLOAD: %v", baseFmt.GetEcrPayload())
jww.TRACE.Printf("SendConfirm MAC: %v", mac) jww.TRACE.Printf("SendConfirm ECRPAYLOAD: %v", baseFmt.GetEcrPayload())
jww.TRACE.Printf("SendConfirm MAC: %v", mac)
// warning: channel can get into a bricked state if the first save occurs and
// the second does not or the two occur and the storage into critical // warning: channel can get into a bricked state if the first save
// messages does not occur // occurs and the second does not or the two occur and the storage
// into critical messages does not occur
// create local relationship
p := session.GetDefaultParams() // create local relationship
_, err := s.e2e.AddPartner(partner.ID, partner.DhPubKey, dhPriv, p := session.GetDefaultParams()
rr.GetTheirSidHPubKeyA(), sidhPriv, p, p) _, err := s.e2e.AddPartner(partner.ID, partner.DhPubKey, dhPriv,
if err != nil { rr.GetTheirSidHPubKeyA(), sidhPriv, p, p)
em := fmt.Sprintf("Failed to create channel with partner (%s) "+ if err != nil {
"on confirmation, this is likley a replay: %s", em := fmt.Sprintf("Failed to create channel with partner (%s) "+
partner.ID, err.Error()) "on confirmation, this is likley a replay: %s",
jww.WARN.Print(em) partner.ID, err.Error())
s.event.Report(10, "Auth", "SendConfirmError", em) jww.WARN.Print(em)
} s.event.Report(10, "Auth", "SendConfirmError", em)
}
s.backupTrigger("confirmed authenticated channel")
s.backupTrigger("confirmed authenticated channel")
jww.INFO.Printf("Confirming Auth from %s to %s, msgDigest: %s",
partner.ID, s.e2e.GetReceptionID(), jww.INFO.Printf("Confirming Auth from %s to %s, msgDigest: %s",
format.DigestContents(baseFmt.Marshal())) partner.ID, s.e2e.GetReceptionID(),
format.DigestContents(baseFmt.Marshal()))
//service used for notification only
//service used for notification only
/*send message*/
if err = s.store.StoreConfirmation(partner.ID, baseFmt.Marshal(), /*send message*/
mac, fp); err == nil { if err = s.store.StoreConfirmation(partner.ID, baseFmt.Marshal(),
jww.WARN.Printf("Failed to store confirmation for replay "+ mac, fp); err == nil {
"for relationship between %s and %s, cannot be replayed: %+v", jww.WARN.Printf("Failed to store confirmation for replay "+
partner.ID, s.e2e.GetReceptionID(), err) "for relationship between %s and %s, cannot be replayed: %+v",
} partner.ID, s.e2e.GetReceptionID(), err)
}
//send confirmation
sentRound, err = sendAuthConfirm(s.net, partner.ID, fp, //send confirmation
baseFmt.Marshal(), mac, s.event, serviceTag) sentRound, err = sendAuthConfirm(s.net, partner.ID, fp,
baseFmt.Marshal(), mac, s.event, serviceTag)
return err
}) return err
})
return sentRound, err return sentRound, err
} }
......
package auth package auth
import ( import (
"github.com/cloudflare/circl/dh/sidh"
"gitlab.com/elixxir/client/cmix"
"gitlab.com/elixxir/client/cmix/identity"
"gitlab.com/elixxir/client/cmix/identity/receptionID"
"gitlab.com/elixxir/client/cmix/message"
"gitlab.com/elixxir/client/cmix/rounds"
"gitlab.com/elixxir/client/e2e" "gitlab.com/elixxir/client/e2e"
"gitlab.com/elixxir/client/e2e/ratchet/partner"
"gitlab.com/elixxir/client/e2e/ratchet/partner/session"
"gitlab.com/elixxir/crypto/contact" "gitlab.com/elixxir/crypto/contact"
"gitlab.com/elixxir/crypto/cyclic"
"gitlab.com/elixxir/primitives/fact" "gitlab.com/elixxir/primitives/fact"
"gitlab.com/elixxir/primitives/format"
"gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/id"
"gitlab.com/xx_network/primitives/id/ephemeral"
) )
type State interface { type State interface {
...@@ -84,3 +95,47 @@ type State interface { ...@@ -84,3 +95,47 @@ type State interface {
// VerifyOwnership checks if the received ownership proof is valid // VerifyOwnership checks if the received ownership proof is valid
VerifyOwnership(received, verified contact.Contact, e2e e2e.Handler) bool VerifyOwnership(received, verified contact.Contact, e2e e2e.Handler) bool
} }
// Callbacks is the interface for auth callback methods.
type Callbacks interface {
Request(partner contact.Contact, receptionID receptionID.EphemeralIdentity,
round rounds.Round)
Confirm(partner contact.Contact, receptionID receptionID.EphemeralIdentity,
round rounds.Round)
Reset(partner contact.Contact, receptionID receptionID.EphemeralIdentity,
round rounds.Round)
}
// cmixClient is a sub-interface of cmix.Client with
// methods relevant to this package.
type cmixClient interface {
IsHealthy() bool
GetMaxMessageLength() int
AddService(clientID *id.ID, newService message.Service,
response message.Processor)
DeleteService(clientID *id.ID, toDelete message.Service,
processor message.Processor)
GetIdentity(get *id.ID) (identity.TrackedID, error)
AddFingerprint(identity *id.ID, fingerprint format.Fingerprint,
mp message.Processor) error
DeleteFingerprint(identity *id.ID, fingerprint format.Fingerprint)
Send(recipient *id.ID, fingerprint format.Fingerprint,
service message.Service, payload, mac []byte, cmixParams cmix.CMIXParams) (
id.Round, ephemeral.Id, error)
}
// e2eHandler is a sub-interface of e2e.Handler containing
// methods relevant to this package.
type e2eHandler interface {
GetHistoricalDHPubkey() *cyclic.Int
GetHistoricalDHPrivkey() *cyclic.Int
GetGroup() *cyclic.Group
AddPartner(partnerID *id.ID,
partnerPubKey, myPrivKey *cyclic.Int,
partnerSIDHPubKey *sidh.PublicKey,
mySIDHPrivKey *sidh.PrivateKey, sendParams,
receiveParams session.Params) (partner.Manager, error)
GetPartner(partnerID *id.ID) (partner.Manager, error)
DeletePartner(partnerId *id.ID) error
GetReceptionID() *id.ID
}
...@@ -10,27 +10,19 @@ package auth ...@@ -10,27 +10,19 @@ package auth
import ( import (
"encoding/base64" "encoding/base64"
"github.com/cloudflare/circl/dh/sidh"
"github.com/pkg/errors" "github.com/pkg/errors"
"gitlab.com/elixxir/client/auth/store" "gitlab.com/elixxir/client/auth/store"
"gitlab.com/elixxir/client/cmix" "gitlab.com/elixxir/client/cmix"
"gitlab.com/elixxir/client/cmix/identity"
"gitlab.com/elixxir/client/cmix/identity/receptionID" "gitlab.com/elixxir/client/cmix/identity/receptionID"
"gitlab.com/elixxir/client/cmix/message" "gitlab.com/elixxir/client/cmix/message"
"gitlab.com/elixxir/client/cmix/rounds"
"gitlab.com/elixxir/client/e2e" "gitlab.com/elixxir/client/e2e"
"gitlab.com/elixxir/client/e2e/ratchet/partner"
"gitlab.com/elixxir/client/e2e/ratchet/partner/session"
"gitlab.com/elixxir/client/event" "gitlab.com/elixxir/client/event"
"gitlab.com/elixxir/client/storage/versioned" "gitlab.com/elixxir/client/storage/versioned"
"gitlab.com/elixxir/crypto/contact"
"gitlab.com/elixxir/crypto/cyclic"
"gitlab.com/elixxir/crypto/fastRNG" "gitlab.com/elixxir/crypto/fastRNG"
"gitlab.com/elixxir/primitives/format"
"gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/id"
"gitlab.com/xx_network/primitives/id/ephemeral"
) )
// state is an implementation of the State interface.
type state struct { type state struct {
callbacks Callbacks callbacks Callbacks
...@@ -46,45 +38,6 @@ type state struct { ...@@ -46,45 +38,6 @@ type state struct {
backupTrigger func(reason string) backupTrigger func(reason string)
} }
type cmixClient interface {
IsHealthy() bool
GetMaxMessageLength() int
AddService(clientID *id.ID, newService message.Service,
response message.Processor)
DeleteService(clientID *id.ID, toDelete message.Service,
processor message.Processor)
GetIdentity(get *id.ID) (identity.TrackedID, error)
AddFingerprint(identity *id.ID, fingerprint format.Fingerprint,
mp message.Processor) error
DeleteFingerprint(identity *id.ID, fingerprint format.Fingerprint)
Send(recipient *id.ID, fingerprint format.Fingerprint,
service message.Service, payload, mac []byte, cmixParams cmix.CMIXParams) (
id.Round, ephemeral.Id, error)
}
type e2eHandler interface {
GetHistoricalDHPubkey() *cyclic.Int
GetHistoricalDHPrivkey() *cyclic.Int
GetGroup() *cyclic.Group
AddPartner(partnerID *id.ID,
partnerPubKey, myPrivKey *cyclic.Int,
partnerSIDHPubKey *sidh.PublicKey,
mySIDHPrivKey *sidh.PrivateKey, sendParams,
receiveParams session.Params) (partner.Manager, error)
GetPartner(partnerID *id.ID) (partner.Manager, error)
DeletePartner(partnerId *id.ID) error
GetReceptionID() *id.ID
}
type Callbacks interface {
Request(partner contact.Contact, receptionID receptionID.EphemeralIdentity,
round rounds.Round)
Confirm(partner contact.Contact, receptionID receptionID.EphemeralIdentity,
round rounds.Round)
Reset(partner contact.Contact, receptionID receptionID.EphemeralIdentity,
round rounds.Round)
}
// NewState loads the auth state or creates new auth state if one cannot be // NewState loads the auth state or creates new auth state if one cannot be
// found. // found.
// Bases its reception identity and keys off of what is found in e2e. // Bases its reception identity and keys off of what is found in e2e.
...@@ -92,8 +45,8 @@ type Callbacks interface { ...@@ -92,8 +45,8 @@ type Callbacks interface {
// Parameters: // Parameters:
// The params object passed in determines the services that will be used // The params object passed in determines the services that will be used
// to pick up requests and signal notifications. These are unique to an // to pick up requests and signal notifications. These are unique to an
// identity, so multiple auth states with the same service tags with different // identity, so multiple auth states with the same service tags with
// identities can run simultaneously. // different identities can run simultaneously.
// Default parameters can be retrieved via GetDefaultParameters() // Default parameters can be retrieved via GetDefaultParameters()
// Temporary: // Temporary:
// In some cases, for example client <-> server communications, connections // In some cases, for example client <-> server communications, connections
...@@ -108,10 +61,9 @@ func NewState(kv *versioned.KV, net cmix.Client, e2e e2e.Handler, ...@@ -108,10 +61,9 @@ func NewState(kv *versioned.KV, net cmix.Client, e2e e2e.Handler,
kv, net, e2e, rng, event, params, callbacks, backupTrigger) kv, net, e2e, rng, event, params, callbacks, backupTrigger)
} }
// NewStateLegacy loads the auth state or creates new auth state if one cannot be // NewStateLegacy loads the auth state or creates new auth state if one cannot
// found. // be found. Bases its reception identity and keys off of what is found in e2e.
// Bases its reception identity and keys off of what is found in e2e. // Does not modify the kv prefix for backwards compatibility.
// Does not modify the kv prefix for backwards compatibility
// Otherwise, acts the same as NewState // Otherwise, acts the same as NewState
func NewStateLegacy(kv *versioned.KV, net cmix.Client, e2e e2e.Handler, func NewStateLegacy(kv *versioned.KV, net cmix.Client, e2e e2e.Handler,
rng *fastRNG.StreamGenerator, event event.Reporter, params Param, rng *fastRNG.StreamGenerator, event event.Reporter, params Param,
...@@ -152,13 +104,14 @@ func NewStateLegacy(kv *versioned.KV, net cmix.Client, e2e e2e.Handler, ...@@ -152,13 +104,14 @@ func NewStateLegacy(kv *versioned.KV, net cmix.Client, e2e e2e.Handler,
return s, nil return s, nil
} }
// CallAllReceivedRequests will iterate through all pending contact requests and replay // CallAllReceivedRequests will iterate through all pending contact requests
// them on the callbacks. // and replay them on the callbacks.
func (s *state) CallAllReceivedRequests() { func (s *state) CallAllReceivedRequests() {
rrList := s.store.GetAllReceivedRequests() rrList := s.store.GetAllReceivedRequests()
for i := range rrList { for i := range rrList {
rr := rrList[i] rr := rrList[i]
eph := receptionID.BuildIdentityFromRound(rr.GetContact().ID, rr.GetRound()) eph := receptionID.BuildIdentityFromRound(rr.GetContact().ID,
rr.GetRound())
s.callbacks.Request(rr.GetContact(), eph, rr.GetRound()) s.callbacks.Request(rr.GetContact(), eph, rr.GetRound())
} }
} }
......
package store package store
// SentRequestHandler allows the lower fevel to assign and remove services // SentRequestHandler allows the lower level to assign and remove services
type SentRequestHandler interface { type SentRequestHandler interface {
Add(sr *SentRequest) Add(sr *SentRequest)
Delete(sr *SentRequest) Delete(sr *SentRequest)
......
///////////////////////////////////////////////////////////////////////////////
// Copyright © 2020 xx network SEZC //
// //
// Use of this source code is governed by a license that can be found in the //
// LICENSE file //
///////////////////////////////////////////////////////////////////////////////
package e2e
import (
"gitlab.com/elixxir/client/catalog"
"gitlab.com/elixxir/client/e2e/parse"
"gitlab.com/elixxir/client/e2e/ratchet"
"gitlab.com/elixxir/client/e2e/receive"
"gitlab.com/elixxir/client/e2e/rekey"
"gitlab.com/elixxir/client/storage/versioned"
dh "gitlab.com/elixxir/crypto/diffieHellman"
"gitlab.com/elixxir/crypto/fastRNG"
"gitlab.com/elixxir/ekv"
"gitlab.com/xx_network/crypto/csprng"
"gitlab.com/xx_network/primitives/id"
"testing"
)
func TestManager_SendUnsafe(t *testing.T) {
streamGen := fastRNG.NewStreamGenerator(12, 1024, csprng.NewSystemRNG)
rng := streamGen.GetStream()
defer rng.Close()
netHandler := newMockCmixHandler()
// Generate new E2E manager
myKv := versioned.NewKV(ekv.MakeMemstore())
myID := id.NewIdFromString("myID", id.User, t)
myNet := newMockCmix(myID, netHandler, t)
m1 := &manager{
Switchboard: receive.New(),
partitioner: parse.NewPartitioner(myKv, myNet.GetMaxMessageLength()),
net: myNet,
myID: myID,
events: mockEventsManager{},
grp: myNet.GetInstance().GetE2EGroup(),
rekeyParams: rekey.GetDefaultParams(),
}
myPrivKey := dh.GeneratePrivateKey(
dh.DefaultPrivateKeyLength, m1.grp, rng)
err := ratchet.New(myKv, myID, myPrivKey, m1.grp)
if err != nil {
t.Errorf("Failed to generate new ratchet: %+v", err)
}
myFpGen := &fpGenerator{m1}
myServices := newMockServices()
m1.Ratchet, err = ratchet.Load(
myKv, myID, m1.grp, myFpGen, myServices, streamGen)
// Generate new E2E manager
partnerKv := versioned.NewKV(ekv.MakeMemstore())
partnerID := id.NewIdFromString("partnerID", id.User, t)
partnerNet := newMockCmix(partnerID, netHandler, t)
m2 := &manager{
Switchboard: receive.New(),
partitioner: parse.NewPartitioner(partnerKv, partnerNet.GetMaxMessageLength()),
net: partnerNet,
myID: partnerID,
events: mockEventsManager{},
grp: partnerNet.GetInstance().GetE2EGroup(),
rekeyParams: rekey.GetDefaultParams(),
}
receiveChan := make(chan receive.Message, 10)
m2.Switchboard.RegisterListener(partnerID, catalog.NoType, &mockListener{receiveChan})
partnerPrivKey := dh.GeneratePrivateKey(
dh.DefaultPrivateKeyLength, m2.grp, rng)
err = ratchet.New(partnerKv, partnerID, partnerPrivKey, m2.grp)
if err != nil {
t.Errorf("Failed to generate new ratchet: %+v", err)
}
partnerFpGen := &fpGenerator{m2}
partnerServices := newMockServices()
m1.Ratchet, err = ratchet.Load(
partnerKv, partnerID, m2.grp, partnerFpGen, partnerServices, streamGen)
// Generate partner identity and add partner
partnerPubKey, partnerSidhPubKey, mySidhPrivKey, sessionParams :=
genPartnerKeys(partnerPrivKey, m1.grp, rng, t)
_, err = m1.Ratchet.AddPartner(partnerID, partnerPubKey, myPrivKey,
partnerSidhPubKey, mySidhPrivKey, sessionParams, sessionParams)
if err != nil {
t.Errorf("Failed to add partner: %+v", err)
}
payload := []byte("My Payload")
p := GetDefaultParams()
_, _, err = m1.sendUnsafe(catalog.NoType, partnerID, payload, p)
if err != nil {
t.Fatalf("sendUnsafe error: %v", err)
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment