Skip to content
Snippets Groups Projects
Commit 188a4059 authored by Jake Taylor's avatar Jake Taylor :lips:
Browse files

Merge branch 'release' into 'master'

Release

See merge request !117
parents 7ee97274 65019043
No related branches found
No related tags found
1 merge request!117Release
......@@ -81,7 +81,7 @@ bindings-ios:
tags:
- ios
script:
- go get -u golang.org/x/mobile/cmd/gomobile@76c259c465ba39f84de7e2751a666612ddca556b
- go get -u golang.org/x/mobile/cmd/gomobile
- gomobile init
- gomobile bind -target ios gitlab.com/elixxir/client/bindings
- ls
......
......@@ -140,17 +140,19 @@ Full usage of client can be found with `client --help`:
```
$ ./client --help
Runs a client for cMix anonymous communication platform
Usage:
client [flags]
client [command]
Available Commands:
fileTransfer Send and receive file for cMix client
generate Generates version and dependency information for the Elixxir binary
getndf Download the network definition file from the network and print it.
group Group commands for cMix client
help Help about any command
init Initialize a user ID but do not connect to the network
proto Load client with a proto client JSON file.
single Send and respond to single-use messages.
ud Register for and search users using the xx network user discovery service.
version Print the version and dependency information for the Elixxir binary
......@@ -164,6 +166,7 @@ Flags:
--e2eMaxKeys uint Max keys used before blocking until a rekey completes (default 800)
--e2eMinKeys uint Minimum number of keys used before requesting rekey (default 500)
--e2eNumReKeys uint Number of rekeys reserved for rekey operations (default 16)
--e2eRekeyThreshold float64 Number between 0 an 1. Percent of keys used before a rekey is started
--forceHistoricalRounds Force all rounds to be sent to historical round retrieval
--forceMessagePickupRetry Enable a mechanism which forces a 50% chance of no message pickup, instead triggering the message pickup retry mechanism
-h, --help help for client
......@@ -173,8 +176,8 @@ Flags:
-n, --ndf string Path to the network definition JSON file (default "ndf.json")
-p, --password string Password to the session file
--profile-cpu string Enable cpu profiling to this file
--protoUserOut string Path to which a normally constructed client will write proto user JSON file (default "protoUser.json")
--protoUserPath string Path to proto user JSON file containing cryptographic primitives the client will load (default "protoUser.json")
--protoUserOut string Path to which a normally constructed client will write proto user JSON file
--protoUserPath string Path to proto user JSON file containing cryptographic primitives the client will load
--receiveCount uint How many messages we should wait for before quitting (default 1)
--regcode string Identity code (optional)
--send-auth-request Send an auth request to the specified destination and waitfor confirmation
......@@ -186,9 +189,9 @@ Flags:
--unsafe Send raw, unsafe messages without e2e encryption.
--unsafe-channel-creation Turns off the user identity authenticated channel check, automatically approving authenticated channels
--verboseRoundTracking Verbose round tracking, keeps track and prints all rounds the client was aware of while running. Defaults to false if not set.
--verify-sends Ensure successful message sending by checking for round completion
--waitTimeout uint The number of seconds to wait for messages to arrive (default 15)
-w, --writeContact string Write contact information, if any, to this file, defaults to stdout (default "-")
file
Use "client [command] --help" for more information about a command.
```
......
......@@ -8,15 +8,19 @@
package api
import (
"encoding/binary"
"github.com/cloudflare/circl/dh/sidh"
"github.com/pkg/errors"
jww "github.com/spf13/jwalterweatherman"
"gitlab.com/elixxir/client/auth"
"gitlab.com/elixxir/client/interfaces"
"gitlab.com/elixxir/client/interfaces/preimage"
"gitlab.com/elixxir/client/storage/edge"
util "gitlab.com/elixxir/client/storage/utility"
"gitlab.com/elixxir/crypto/contact"
"gitlab.com/elixxir/primitives/fact"
"gitlab.com/xx_network/primitives/id"
"math/rand"
)
// RequestAuthenticatedChannel sends a request to another party to establish an
......@@ -36,7 +40,7 @@ func (c *Client) RequestAuthenticatedChannel(recipient, me contact.Contact,
"creation when the network is not healthy")
}
return auth.RequestAuth(recipient, me, message, c.rng.GetStream(),
return auth.RequestAuth(recipient, me, c.rng.GetStream(),
c.storage, c.network)
}
......@@ -96,10 +100,31 @@ func (c *Client) MakePrecannedAuthenticatedChannel(precannedID uint) (contact.Co
precan := c.MakePrecannedContact(precannedID)
myID := binary.BigEndian.Uint64(c.GetUser().GetContact().ID[:])
// Pick a variant based on if their ID is bigger than mine.
myVariant := sidh.KeyVariantSidhA
theirVariant := sidh.KeyVariant(sidh.KeyVariantSidhB)
if myID > uint64(precannedID) {
myVariant = sidh.KeyVariantSidhB
theirVariant = sidh.KeyVariantSidhA
}
prng1 := rand.New(rand.NewSource(int64(precannedID)))
theirSIDHPrivKey := util.NewSIDHPrivateKey(theirVariant)
theirSIDHPubKey := util.NewSIDHPublicKey(theirVariant)
theirSIDHPrivKey.Generate(prng1)
theirSIDHPrivKey.GeneratePublicKey(theirSIDHPubKey)
prng2 := rand.New(rand.NewSource(int64(myID)))
mySIDHPrivKey := util.NewSIDHPrivateKey(myVariant)
mySIDHPubKey := util.NewSIDHPublicKey(myVariant)
mySIDHPrivKey.Generate(prng2)
mySIDHPrivKey.GeneratePublicKey(mySIDHPubKey)
// add the precanned user as a e2e contact
sesParam := c.parameters.E2EParams
err := c.storage.E2e().AddPartner(precan.ID, precan.DhPubKey,
c.storage.E2e().GetDHPrivateKey(), sesParam, sesParam)
c.storage.E2e().GetDHPrivateKey(), theirSIDHPubKey,
mySIDHPrivKey, sesParam, sesParam)
// check garbled messages in case any messages arrived before creating
// the channel
......@@ -119,10 +144,17 @@ func (c *Client) MakePrecannedAuthenticatedChannel(precannedID uint) (contact.Co
Source: precan.ID[:],
}, me)
//rekey
//slient (rekey)
c.storage.GetEdge().Add(edge.Preimage{
Data: sessionPartner.GetSilentPreimage(),
Type: preimage.Silent,
Source: precan.ID[:],
}, me)
// File transfer end
c.storage.GetEdge().Add(edge.Preimage{
Data: sessionPartner.GetRekeyPreimage(),
Type: preimage.Rekey,
Data: sessionPartner.GetFileTransferPreimage(),
Type: preimage.EndFT,
Source: precan.ID[:],
}, me)
......
......@@ -330,7 +330,6 @@ func LoginWithNewBaseNDF_UNSAFE(storageDir string, password []byte,
//Open the client
c, err := OpenClient(storageDir, password, parameters)
if err != nil {
return nil, err
}
......@@ -374,6 +373,63 @@ func LoginWithNewBaseNDF_UNSAFE(storageDir string, password []byte,
return c, nil
}
// LoginWithProtoClient creates a client object with a protoclient JSON containing the
// cryptographic primitives. This is designed for some specific deployment
//// procedures and is generally unsafe.
func LoginWithProtoClient(storageDir string, password []byte, protoClientJSON []byte,
newBaseNdf string, parameters params.Network) (*Client, error) {
jww.INFO.Printf("LoginWithProtoClient()")
// Parse the NDF
def, err := parseNDF(newBaseNdf)
if err != nil {
return nil, err
}
//Open the client
err = NewProtoClient_Unsafe(newBaseNdf, storageDir, password, protoClientJSON)
if err != nil {
return nil, err
}
//Open the client
c, err := OpenClient(storageDir, password, parameters)
if err != nil {
return nil, err
}
//initialize comms
err = c.initComms()
if err != nil {
return nil, err
}
//store the updated base NDF
c.storage.SetNDF(def)
err = c.initPermissioning(def)
if err != nil {
return nil, err
}
// Initialize network and link it to context
c.network, err = network.NewManager(c.storage, c.switchboard, c.rng,
c.events, c.comms, parameters, def)
if err != nil {
return nil, err
}
// initialize the auth tracker
c.auth = auth.NewManager(c.switchboard, c.storage, c.network)
err = c.registerFollower()
if err != nil {
return nil, err
}
return c, nil
}
func (c *Client) initComms() error {
var err error
......@@ -500,7 +556,7 @@ func (c *Client) GetErrorsChannel() <-chan interfaces.ClientError {
// Handles both auth confirm and requests
func (c *Client) StartNetworkFollower(timeout time.Duration) error {
u := c.GetUser()
jww.INFO.Printf("StartNetworkFollower() \n\tTransmisstionID: %s "+
jww.INFO.Printf("StartNetworkFollower() \n\tTransmissionID: %s "+
"\n\tReceptionID: %s", u.TransmissionID, u.ReceptionID)
return c.followerServices.start(timeout)
......@@ -526,6 +582,12 @@ func (c *Client) NetworkFollowerStatus() Status {
return c.followerServices.status()
}
// HasRunningProcessies checks if any background threads are running
// and returns true if one or more are
func (c *Client) HasRunningProcessies() bool {
return !c.followerServices.stoppable.IsStopped()
}
// Returns the health tracker for registration and polling
func (c *Client) GetHealth() interfaces.HealthTracker {
jww.INFO.Printf("GetHealth()")
......@@ -579,10 +641,17 @@ func (c *Client) GetNetworkInterface() interfaces.NetworkManager {
return c.network
}
// GetRateLimitParams retrieves the rate limiting parameters.
func (c *Client) GetRateLimitParams() (uint32, uint32, int64) {
rateLimitParams := c.storage.GetBucketParams().Get()
return rateLimitParams.Capacity, rateLimitParams.LeakedTokens,
rateLimitParams.LeakDuration.Nanoseconds()
}
// GetNodeRegistrationStatus gets the current state of node registration. It
// returns the the total number of nodes in the NDF and the number of those
// which are currently registers with. An error is returned if the network is
// not healthy.
// returns the total number of nodes in the NDF and the number of those which
// are currently registers with. An error is returned if the network is not
// healthy.
func (c *Client) GetNodeRegistrationStatus() (int, int, error) {
// Return an error if the network is not healthy
if !c.GetHealth().IsHealthy() {
......@@ -625,7 +694,8 @@ func (c *Client) DeleteContact(partnerId *id.ID) error {
"they could not be found", partnerId)
}
e2ePreimage := partner.GetE2EPreimage()
rekeyPreimage := partner.GetRekeyPreimage()
rekeyPreimage := partner.GetSilentPreimage()
fileTransferPreimage := partner.GetFileTransferPreimage()
//delete the partner
if err = c.storage.E2e().DeletePartner(partnerId); err != nil {
......@@ -643,13 +713,22 @@ func (c *Client) DeleteContact(partnerId *id.ID) error {
if err = c.storage.GetEdge().Remove(edge.Preimage{
Data: rekeyPreimage,
Type: preimage.Rekey,
Type: preimage.Silent,
Source: partnerId[:],
}, c.storage.GetUser().ReceptionID); err != nil {
jww.WARN.Printf("Failed delete the preimage for rekey "+
"from %s on contact deletion: %+v", partnerId, err)
}
if err = c.storage.GetEdge().Remove(edge.Preimage{
Data: fileTransferPreimage,
Type: preimage.EndFT,
Source: partnerId[:],
}, c.storage.GetUser().ReceptionID); err != nil {
jww.WARN.Printf("Failed delete the preimage for file transfer "+
"from %s on contact deletion: %+v", partnerId, err)
}
if err = c.storage.Auth().Delete(partnerId); err != nil {
return err
}
......@@ -773,7 +852,7 @@ func checkVersionAndSetupStorage(def *ndf.NetworkDefinition,
// Create Storage
passwordStr := string(password)
storageSess, err := storage.New(storageDir, passwordStr, protoUser,
currentVersion, cmixGrp, e2eGrp, rngStreamGen)
currentVersion, cmixGrp, e2eGrp, rngStreamGen, def.RateLimits)
if err != nil {
return nil, err
}
......
///////////////////////////////////////////////////////////////////////////////
// Copyright © 2020 xx network SEZC //
// //
// Use of this source code is governed by a license that can be found in the //
// LICENSE file //
///////////////////////////////////////////////////////////////////////////////
package api
import (
"encoding/base64"
"github.com/pkg/errors"
pb "gitlab.com/elixxir/comms/mixmessages"
"gitlab.com/xx_network/comms/signature"
"gitlab.com/xx_network/crypto/tls"
"google.golang.org/protobuf/proto"
"io/ioutil"
"net/http"
)
// DownloadAndVerifySignedNdfWithUrl retrieves the NDF from a specified URL.
// The NDF is processed into a protobuf containing a signature which
// is verified using the cert string passed in. The NDF is returned as marshaled
// byte data which may be used to start a client.
func DownloadAndVerifySignedNdfWithUrl(url, cert string) ([]byte, error) {
// Build a request for the file
resp, err := http.Get(url)
if err != nil {
return nil, errors.WithMessagef(err, "Failed to retrieve "+
"NDF from %s", url)
}
defer resp.Body.Close()
// Download contents of the file
signedNdfEncoded, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, errors.WithMessage(err, "Failed to read signed "+
"NDF response request")
}
// Process the download NDF and return the marshaled NDF
return processAndVerifySignedNdf(signedNdfEncoded, cert)
}
// processAndVerifySignedNdf is a helper function which parses the downloaded NDF
// into a protobuf containing a signature. The signature is verified using the
// passed in cert. Upon successful parsing and verification, the NDF is
// returned as byte data.
func processAndVerifySignedNdf(signedNdfEncoded []byte, cert string) ([]byte, error) {
// Base64 decode the signed NDF
signedNdfMarshaled, err := base64.StdEncoding.DecodeString(
string(signedNdfEncoded))
if err != nil {
return nil, errors.WithMessage(err, "Failed to decode signed NDF")
}
// Unmarshal the signed NDF
signedNdfMsg := &pb.NDF{}
err = proto.Unmarshal(signedNdfMarshaled, signedNdfMsg)
if err != nil {
return nil, errors.WithMessage(err, "Failed to unmarshal "+
"signed NDF into protobuf")
}
// Load the certificate from it's PEM contents
schedulingCert, err := tls.LoadCertificate(cert)
if err != nil {
return nil, errors.WithMessagef(err, "Failed to parse scheduling cert (%s)", cert)
}
// Extract the public key from the cert
schedulingPubKey, err := tls.ExtractPublicKey(schedulingCert)
if err != nil {
return nil, errors.WithMessage(err, "Failed to extract public key from cert")
}
// Verify signed NDF message
err = signature.VerifyRsa(signedNdfMsg, schedulingPubKey)
if err != nil {
return nil, errors.WithMessage(err, "Failed to verify signed NDF message")
}
return signedNdfMsg.Ndf, nil
}
......@@ -93,6 +93,13 @@ func (c *Client) getRoundResults(roundList []id.Round, timeout time.Duration,
oldestRound := networkInstance.GetOldestRoundID()
// Set a lower timeout so there is room for retries,
// while ensuring it does not go too low and cause too many timeouts
roundEventTimeout := 5 * time.Second
if timeout < roundEventTimeout {
roundEventTimeout = timeout
}
// Parse and adjudicate every round
for _, rnd := range roundList {
// Every round is timed out by default, until proven to have finished
......@@ -109,20 +116,20 @@ func (c *Client) getRoundResults(roundList []id.Round, timeout time.Duration,
} else {
// If in progress, add a channel monitoring its state
roundEvents.AddRoundEventChan(rnd, sendResults,
timeout-time.Millisecond, states.COMPLETED, states.FAILED)
roundEventTimeout, states.COMPLETED, states.FAILED)
numResults++
}
} else {
// Update oldest round (buffer may have updated externally)
// Update the oldest round (buffer may have updated externally)
if rnd < oldestRound {
// If round is older that oldest round in our buffer
// Add it to the historical round request (performed later)
historicalRequest.Rounds = append(historicalRequest.Rounds, uint64(rnd))
numResults++
} else {
// Otherwise, monitor it's progress
// Otherwise, monitor its progress
roundEvents.AddRoundEventChan(rnd, sendResults,
timeout-time.Millisecond, states.COMPLETED, states.FAILED)
roundEventTimeout, states.COMPLETED, states.FAILED)
numResults++
}
}
......@@ -151,13 +158,19 @@ func (c *Client) getRoundResults(roundList []id.Round, timeout time.Duration,
roundCallback(false, true, roundsResults)
return
case roundReport := <-sendResults:
numResults--
// Skip if the round is nil (unknown from historical rounds)
// they default to timed out, so correct behavior is preserved
if roundReport.RoundInfo == nil || roundReport.TimedOut {
if roundReport.RoundInfo == nil {
allRoundsSucceeded = false
numResults--
} else if roundReport.TimedOut {
// Generate a message to track the timed out round
timeoutRequest := &pb.HistoricalRounds{
Rounds: []uint64{roundReport.RoundInfo.ID},
}
// Request that round's information, feeding back into sendResults
jww.DEBUG.Printf("Sending HistoricalRounds retry for Round %d", roundReport.RoundInfo.ID)
go c.getHistoricalRounds(timeoutRequest, sendResults, commsInterface)
} else {
// If available, denote the result
roundId := id.Round(roundReport.RoundInfo.ID)
......@@ -166,8 +179,8 @@ func (c *Client) getRoundResults(roundList []id.Round, timeout time.Duration,
} else {
roundsResults[roundId] = Failed
allRoundsSucceeded = false
}
numResults--
}
}
}
......@@ -177,7 +190,7 @@ func (c *Client) getRoundResults(roundList []id.Round, timeout time.Duration,
}
// Helper function which asynchronously pings a random gateway until
// it gets information on it's requested historical rounds
// it gets information on its requested historical rounds
func (c *Client) getHistoricalRounds(msg *pb.HistoricalRounds,
sendResults chan ds.EventReturn, comms historicalRoundsComm) {
......
......@@ -56,7 +56,7 @@ func (c *Client) SendCMIX(msg format.Message, recipientID *id.ID,
// SendManyCMIX sends many "raw" CMIX message payloads to each of the
// provided recipients. Used for group chat functionality. Returns the
// round ID of the round the payload was sent or an error if it fails.
func (c *Client) SendManyCMIX(messages map[id.ID]format.Message,
func (c *Client) SendManyCMIX(messages []message.TargetedCmixMessage,
params params.CMIX) (id.Round, []ephemeral.Id, error) {
return c.network.SendManyCMIX(messages, params)
}
......
////////////////////////////////////////////////////////////////////////////////
// Copyright © 2021 Privategrity Corporation /
// /
// All rights reserved. /
////////////////////////////////////////////////////////////////////////////////
// Provides various utility functions for access over the bindings
package api
import (
"bytes"
"github.com/nfnt/resize"
"github.com/pkg/errors"
"image/jpeg"
"math"
)
const (
// Maximum input image size (in bytes)
maxSize int64 = 12000000
// Desired number of pixels in output image
desiredSize = 307200
)
// CompressJpeg takes a JPEG image in byte format
// and compresses it based on desired output size
func CompressJpeg(imgBytes []byte) ([]byte, error) {
// Convert bytes to a reader
imgBuf := bytes.NewReader(imgBytes)
// Ensure the size of the image is under the limit
if imgSize := imgBuf.Size(); imgSize > maxSize {
return nil, errors.Errorf("Image is too large: %d/%d", imgSize, maxSize)
}
// Decode the image information
imgInfo, err := jpeg.DecodeConfig(imgBuf)
if err != nil {
return nil, errors.Errorf("Unable to decode image config: %+v", err)
}
// If the dimensions of the image are below desiredSize, no compression is required
if imgInfo.Width*imgInfo.Height < desiredSize {
return imgBytes, nil
}
// Reset the buffer to the beginning to begin decoding the image
_, err = imgBuf.Seek(0, 0)
if err != nil {
return nil, errors.Errorf("Unable to reset image buffer: %+v", err)
}
// Decode image into image.Image object
img, err := jpeg.Decode(imgBuf)
if err != nil {
return nil, errors.Errorf("Unable to decode image: %+v", err)
}
// Determine the new width of the image based on desiredSize
newWidth := uint(math.Sqrt(float64(desiredSize) * (float64(imgInfo.Width) / float64(imgInfo.Height))))
// Resize the image based on newWidth while preserving aspect ratio
newImg := resize.Resize(newWidth, 0, img, resize.Bicubic)
// Encode the new image to a buffer
newImgBuf := new(bytes.Buffer)
err = jpeg.Encode(newImgBuf, newImg, nil)
if err != nil {
return nil, errors.Errorf("Unable to encode image: %+v", err)
}
// Return the compressed image in byte form
return newImgBuf.Bytes(), nil
}
......@@ -100,16 +100,13 @@ func (t *testNetworkManagerGeneric) Follow(report interfaces.ClientErrorReport)
func (t *testNetworkManagerGeneric) CheckGarbledMessages() {
return
}
func (t *testNetworkManagerGeneric) GetVerboseRounds() string {
return ""
}
func (t *testNetworkManagerGeneric) SendE2E(message.Send, params.E2E, *stoppable.Single) (
[]id.Round, cE2e.MessageID, time.Time, error) {
rounds := []id.Round{id.Round(0), id.Round(1), id.Round(2)}
return rounds, cE2e.MessageID{}, time.Time{}, nil
}
func (t *testNetworkManagerGeneric) SendUnsafe(m message.Send, p params.Unsafe) ([]id.Round, error) {
return nil, nil
......@@ -117,7 +114,7 @@ func (t *testNetworkManagerGeneric) SendUnsafe(m message.Send, p params.Unsafe)
func (t *testNetworkManagerGeneric) SendCMIX(message format.Message, rid *id.ID, p params.CMIX) (id.Round, ephemeral.Id, error) {
return id.Round(0), ephemeral.Id{}, nil
}
func (t *testNetworkManagerGeneric) SendManyCMIX(messages map[id.ID]format.Message, p params.CMIX) (id.Round, []ephemeral.Id, error) {
func (t *testNetworkManagerGeneric) SendManyCMIX(messages []message.TargetedCmixMessage, p params.CMIX) (id.Round, []ephemeral.Id, error) {
return 0, []ephemeral.Id{}, nil
}
func (t *testNetworkManagerGeneric) GetInstance() *network.Instance {
......
This diff is collapsed.
// Code generated by go generate; DO NOT EDIT.
// This file was generated by robots at
// 2021-11-11 13:19:35.619263 -0600 CST m=+0.049820030
// 2022-01-04 12:45:01.875155 -0600 CST m=+0.041061278
package api
const GITVERSION = `e595b772 Merge branch 'hotfix/stale-registration' into 'release'`
const SEMVER = "3.2.0"
const GITVERSION = `1144194c Merge branch 'dev' into 'release'`
const SEMVER = "4.0.0"
const DEPENDENCIES = `module gitlab.com/elixxir/client
go 1.13
require (
github.com/cloudflare/circl v1.0.1-0.20211008185751-59b49bc148ce
github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3
github.com/golang/protobuf v1.5.2
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 // indirect
github.com/magiconair/properties v1.8.4 // indirect
github.com/mitchellh/mapstructure v1.4.0 // indirect
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
github.com/pelletier/go-toml v1.8.1 // indirect
github.com/pkg/errors v0.9.1
github.com/smartystreets/assertions v1.0.1 // indirect
......@@ -24,17 +26,17 @@ require (
github.com/spf13/jwalterweatherman v1.1.0
github.com/spf13/viper v1.7.1
gitlab.com/elixxir/bloomfilter v0.0.0-20200930191214-10e9ac31b228
gitlab.com/elixxir/comms v0.0.4-0.20211101174956-590ba1b47887
gitlab.com/elixxir/crypto v0.0.7-0.20211022013957-3a7899285c4c
gitlab.com/elixxir/comms v0.0.4-0.20220104174855-044783c5c1e6
gitlab.com/elixxir/crypto v0.0.7-0.20220104174238-dbd761b30553
gitlab.com/elixxir/ekv v0.1.5
gitlab.com/elixxir/primitives v0.0.3-0.20211102233208-a716d5c670b6
gitlab.com/xx_network/comms v0.0.4-0.20211014163953-e774276b83ae
gitlab.com/xx_network/crypto v0.0.5-0.20211014163843-57b345890686
gitlab.com/xx_network/primitives v0.0.4-0.20211014163031-53405cf191fb
gitlab.com/elixxir/primitives v0.0.3-0.20220104173924-275cb9d7834f
gitlab.com/xx_network/comms v0.0.4-0.20211227194445-c099754b3cda
gitlab.com/xx_network/crypto v0.0.5-0.20211227194420-f311e8920467
gitlab.com/xx_network/primitives v0.0.4-0.20211222205802-03e9d7d835b0
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519
golang.org/x/net v0.0.0-20210525063256-abc453219eb5
google.golang.org/genproto v0.0.0-20210105202744-fe13368bc0e1 // indirect
google.golang.org/grpc v1.38.0
google.golang.org/grpc v1.42.0
google.golang.org/protobuf v1.27.1
gopkg.in/ini.v1 v1.62.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
......
......@@ -9,6 +9,7 @@ package auth
import (
"fmt"
"github.com/cloudflare/circl/dh/sidh"
"github.com/pkg/errors"
jww "github.com/spf13/jwalterweatherman"
"gitlab.com/elixxir/client/interfaces"
......@@ -21,8 +22,10 @@ import (
"gitlab.com/elixxir/crypto/cyclic"
"gitlab.com/elixxir/crypto/diffieHellman"
cAuth "gitlab.com/elixxir/crypto/e2e/auth"
"gitlab.com/elixxir/crypto/fastRNG"
"gitlab.com/elixxir/primitives/fact"
"gitlab.com/elixxir/primitives/format"
"gitlab.com/xx_network/crypto/csprng"
"strings"
)
......@@ -47,7 +50,13 @@ func (m *Manager) StartProcesses() (stoppable.Stoppable, error) {
func (m *Manager) processAuthMessage(msg message.Receive) {
authStore := m.storage.Auth()
//lookup the message, check if it is an auth request
cmixMsg := format.Unmarshal(msg.Payload)
cmixMsg, err := format.Unmarshal(msg.Payload)
if err != nil {
jww.WARN.Printf("Invalid message when unmarshalling: %s",
err.Error())
// Ignore this message
return
}
fp := cmixMsg.GetKeyFP()
jww.INFO.Printf("RAW AUTH FP: %v", fp)
// this takes the request lock if it is a specific fp, all
......@@ -82,7 +91,8 @@ func (m *Manager) processAuthMessage(msg message.Receive) {
func (m *Manager) handleRequest(cmixMsg format.Message,
myHistoricalPrivKey *cyclic.Int, grp *cyclic.Group) {
//decode the outer format
baseFmt, partnerPubKey, err := handleBaseFormat(cmixMsg, grp)
baseFmt, partnerPubKey, err := handleBaseFormat(
cmixMsg, grp)
if err != nil {
jww.WARN.Printf("Failed to handle auth request: %s", err)
return
......@@ -94,12 +104,11 @@ func (m *Manager) handleRequest(cmixMsg format.Message,
jww.TRACE.Printf("handleRequest PARTNERPUBKEY: %v", partnerPubKey.Bytes())
//decrypt the message
jww.TRACE.Printf("handleRequest SALT: %v", baseFmt.GetSalt())
jww.TRACE.Printf("handleRequest ECRPAYLOAD: %v", baseFmt.GetEcrPayload())
jww.TRACE.Printf("handleRequest MAC: %v", cmixMsg.GetMac())
success, payload := cAuth.Decrypt(myHistoricalPrivKey,
partnerPubKey, baseFmt.GetSalt(), baseFmt.GetEcrPayload(),
partnerPubKey, baseFmt.GetEcrPayload(),
cmixMsg.GetMac(), grp)
if !success {
......@@ -115,6 +124,11 @@ func (m *Manager) handleRequest(cmixMsg format.Message,
"request's encrypted payload: %s", err)
return
}
partnerSIDHPubKey, err := ecrFmt.GetSidhPubKey()
if err != nil {
jww.WARN.Printf("Could not unmarshal partner SIDH Pubkey: %s",
err)
}
//decode the request format
requestFmt, err := newRequestFormat(ecrFmt)
......@@ -176,23 +190,73 @@ func (m *Manager) handleRequest(cmixMsg format.Message,
jww.INFO.Printf("Received AuthRequest from %s,"+
" msgDigest: %s which has been requested, auto-confirming",
partnerID, cmixMsg.Digest())
// do the confirmation
if err := m.doConfirm(sr2, grp, partnerPubKey, m.storage.E2e().GetDHPrivateKey(),
sr2.GetPartnerHistoricalPubKey(), ecrFmt.GetOwnership()); err != nil {
em := fmt.Sprintf("Auto Confirmation with %s failed: %s",
partnerID, err)
// Verify this request is legit
ownership := ecrFmt.GetOwnership()
if !cAuth.VerifyOwnershipProof(
myHistoricalPrivKey, partnerPubKey, grp,
ownership) {
jww.WARN.Printf("Invalid ownership proof from %s received, discarding msdDigest: %s",
partnerID, cmixMsg.Digest())
}
// Check if I need to resend by comparing the
// SIDH Keys
mySIDH := sr2.GetMySIDHPubKey()
theirSIDH := partnerSIDHPubKey
myBytes := make([]byte, mySIDH.Size())
theirBytes := make([]byte, theirSIDH.Size())
mySIDH.Export(myBytes)
theirSIDH.Export(theirBytes)
for i := 0; i < len(myBytes); i++ {
if myBytes[i] > theirBytes[i] {
// OK, this side is dropping
// the request
// Do we need to delete
// something here?
// No, because we will
// now wait to receive
// confirmation.
return
} else if myBytes[i] < theirBytes[i] {
break
}
}
// If I do, delete my request on disk
_, _, partnerContact, _ := m.storage.Auth().GetRequest(partnerID)
m.storage.Auth().Delete(partnerID)
// add a confirmation to disk
if err = m.storage.Auth().AddReceived(partnerContact,
partnerSIDHPubKey); err != nil {
em := fmt.Sprintf("failed to store contact Auth "+
"Request: %s", err)
jww.WARN.Print(em)
events.Report(10, "Auth",
"RequestError", em)
events.Report(10, "Auth", "RequestError", em)
}
//exit
// Call ConfirmRequestAuth to send confirmation
rngGen := fastRNG.NewStreamGenerator(1, 1,
csprng.NewSystemRNG)
rng := rngGen.GetStream()
rndNum, err := ConfirmRequestAuth(partnerContact,
rng, m.storage, m.net)
if err != nil {
jww.ERROR.Printf("Could not ConfirmRequestAuth: %+v",
err)
return
}
jww.INFO.Printf("ConfirmRequestAuth to %s on round %d",
partnerID, rndNum)
return
}
}
}
//process the inner payload
facts, msg, err := fact.UnstringifyFactList(
facts, _, err := fact.UnstringifyFactList(
string(requestFmt.msgPayload))
if err != nil {
em := fmt.Sprintf("failed to parse facts and message "+
......@@ -202,7 +266,7 @@ func (m *Manager) handleRequest(cmixMsg format.Message,
return
}
//create the contact
//create the contact, note that no facts are sent in the payload
c := contact.Contact{
ID: partnerID,
DhPubKey: partnerPubKey,
......@@ -213,7 +277,7 @@ func (m *Manager) handleRequest(cmixMsg format.Message,
// fixme: the client will never be notified of the channel creation if a
// crash occurs after the store but before the conclusion of the callback
//create the auth storage
if err = m.storage.Auth().AddReceived(c); err != nil {
if err = m.storage.Auth().AddReceived(c, partnerSIDHPubKey); err != nil {
em := fmt.Sprintf("failed to store contact Auth "+
"Request: %s", err)
jww.WARN.Print(em)
......@@ -226,7 +290,7 @@ func (m *Manager) handleRequest(cmixMsg format.Message,
cbList := m.requestCallbacks.Get(c.ID)
for _, cb := range cbList {
rcb := cb.(interfaces.RequestCallback)
go rcb(c, msg)
go rcb(c, "")
}
return
}
......@@ -246,7 +310,8 @@ func (m *Manager) handleConfirm(cmixMsg format.Message, sr *auth.SentRequest,
}
// extract the message
baseFmt, partnerPubKey, err := handleBaseFormat(cmixMsg, grp)
baseFmt, partnerPubKey, err := handleBaseFormat(
cmixMsg, grp)
if err != nil {
em := fmt.Sprintf("Failed to handle auth confirm: %s", err)
jww.WARN.Print(em)
......@@ -259,11 +324,10 @@ func (m *Manager) handleConfirm(cmixMsg format.Message, sr *auth.SentRequest,
jww.TRACE.Printf("handleConfirm SRMYPUBKEY: %v", sr.GetMyPubKey().Bytes())
// decrypt the payload
jww.TRACE.Printf("handleConfirm SALT: %v", baseFmt.GetSalt())
jww.TRACE.Printf("handleConfirm ECRPAYLOAD: %v", baseFmt.GetEcrPayload())
jww.TRACE.Printf("handleConfirm MAC: %v", cmixMsg.GetMac())
success, payload := cAuth.Decrypt(sr.GetMyPrivKey(),
partnerPubKey, baseFmt.GetSalt(), baseFmt.GetEcrPayload(),
partnerPubKey, baseFmt.GetEcrPayload(),
cmixMsg.GetMac(), grp)
if !success {
......@@ -285,9 +349,23 @@ func (m *Manager) handleConfirm(cmixMsg format.Message, sr *auth.SentRequest,
return
}
partnerSIDHPubKey, err := ecrFmt.GetSidhPubKey()
if err != nil {
em := fmt.Sprintf("Could not get auth conf SIDH Pubkey: %s",
err)
jww.WARN.Print(em)
events.Report(10, "Auth", "ConfirmError", em)
m.storage.Auth().Done(sr.GetPartner())
return
}
jww.TRACE.Printf("handleConfirm PARTNERSIDHPUBKEY: %v",
partnerSIDHPubKey)
// finalize the confirmation
if err := m.doConfirm(sr, grp, partnerPubKey, sr.GetMyPrivKey(),
sr.GetPartnerHistoricalPubKey(), ecrFmt.GetOwnership()); err != nil {
sr.GetPartnerHistoricalPubKey(),
ecrFmt.GetOwnership(),
partnerSIDHPubKey); err != nil {
em := fmt.Sprintf("Confirmation failed: %s", err)
jww.WARN.Print(em)
events.Report(10, "Auth", "ConfirmError", em)
......@@ -297,7 +375,8 @@ func (m *Manager) handleConfirm(cmixMsg format.Message, sr *auth.SentRequest,
}
func (m *Manager) doConfirm(sr *auth.SentRequest, grp *cyclic.Group,
partnerPubKey, myPrivateKeyOwnershipProof, partnerPubKeyOwnershipProof *cyclic.Int, ownershipProof []byte) error {
partnerPubKey, myPrivateKeyOwnershipProof, partnerPubKeyOwnershipProof *cyclic.Int,
ownershipProof []byte, partnerSIDHPubKey *sidh.PublicKey) error {
// verify the message came from the intended recipient
if !cAuth.VerifyOwnershipProof(myPrivateKeyOwnershipProof,
partnerPubKeyOwnershipProof, grp, ownershipProof) {
......@@ -309,7 +388,8 @@ func (m *Manager) doConfirm(sr *auth.SentRequest, grp *cyclic.Group,
// the second does not
p := m.storage.E2e().GetE2ESessionParams()
if err := m.storage.E2e().AddPartner(sr.GetPartner(),
partnerPubKey, sr.GetMyPrivKey(), p, p); err != nil {
partnerPubKey, sr.GetMyPrivKey(), partnerSIDHPubKey,
sr.GetMySIDHPrivKey(), p, p); err != nil {
return errors.Errorf("Failed to create channel with partner (%s) "+
"after confirmation: %+v",
sr.GetPartner(), err)
......@@ -340,10 +420,17 @@ func (m *Manager) doConfirm(sr *auth.SentRequest, grp *cyclic.Group,
Source: sr.GetPartner()[:],
}, me)
//rekey
//silent (rekey)
m.storage.GetEdge().Add(edge.Preimage{
Data: sessionPartner.GetRekeyPreimage(),
Type: preimage.Rekey,
Data: sessionPartner.GetSilentPreimage(),
Type: preimage.Silent,
Source: sr.GetPartner()[:],
}, me)
// File transfer end
m.storage.GetEdge().Add(edge.Preimage{
Data: sessionPartner.GetFileTransferPreimage(),
Type: preimage.EndFT,
Source: sr.GetPartner()[:],
}, me)
......@@ -397,5 +484,6 @@ func handleBaseFormat(cmixMsg format.Message, grp *cyclic.Group) (baseFormat,
"auth confirmation public key is not in the e2e cyclic group")
}
partnerPubKey := grp.NewIntFromBytes(baseFmt.pubkey)
return baseFmt, partnerPubKey, nil
}
......@@ -16,6 +16,7 @@ import (
"gitlab.com/elixxir/client/interfaces/preimage"
"gitlab.com/elixxir/client/storage"
"gitlab.com/elixxir/client/storage/edge"
util "gitlab.com/elixxir/client/storage/utility"
"gitlab.com/elixxir/crypto/contact"
"gitlab.com/elixxir/crypto/diffieHellman"
cAuth "gitlab.com/elixxir/crypto/e2e/auth"
......@@ -36,11 +37,13 @@ func ConfirmRequestAuth(partner contact.Contact, rng io.Reader,
}
// check if the partner has an auth in progress
// this takes the lock, from this point forward any errors need to release
// the lock
storedContact, err := storage.Auth().GetReceivedRequest(partner.ID)
// this takes the lock, from this point forward any errors need to
// release the lock
storedContact, theirSidhKey, err := storage.Auth().GetReceivedRequest(
partner.ID)
if err != nil {
return 0, errors.Errorf("failed to find a pending Auth Request: %s",
return 0, errors.Errorf(
"failed to find a pending Auth Request: %s",
err)
}
defer storage.Auth().Done(partner.ID)
......@@ -48,8 +51,8 @@ func ConfirmRequestAuth(partner contact.Contact, rng io.Reader,
// verify the passed contact matches what is stored
if storedContact.DhPubKey.Cmp(partner.DhPubKey) != 0 {
storage.Auth().Done(partner.ID)
return 0, errors.WithMessage(err, "Pending Auth Request has different "+
"pubkey than stored")
return 0, errors.WithMessage(err,
"Pending Auth Request has different pubkey than stored")
}
grp := storage.E2e().GetGroup()
......@@ -64,13 +67,11 @@ func ConfirmRequestAuth(partner contact.Contact, rng io.Reader,
newPrivKey := diffieHellman.GeneratePrivateKey(256, grp, rng)
newPubKey := diffieHellman.GeneratePublicKey(newPrivKey, grp)
//generate salt
salt := make([]byte, saltSize)
_, err = rng.Read(salt)
if err != nil {
return 0, errors.Wrap(err, "Failed to generate salt for "+
"confirmation")
}
sidhVariant := util.GetCompatibleSIDHVariant(theirSidhKey.Variant())
newSIDHPrivKey := util.NewSIDHPrivateKey(sidhVariant)
newSIDHPubKey := util.NewSIDHPublicKey(sidhVariant)
newSIDHPrivKey.Generate(rng)
newSIDHPrivKey.GeneratePublicKey(newSIDHPubKey)
/*construct message*/
// we build the payload before we save because it is technically fallible
......@@ -81,11 +82,12 @@ func ConfirmRequestAuth(partner contact.Contact, rng io.Reader,
// setup the encrypted payload
ecrFmt.SetOwnership(ownership)
ecrFmt.SetSidHPubKey(newSIDHPubKey)
// confirmation has no custom payload
//encrypt the payload
ecrPayload, mac := cAuth.Encrypt(newPrivKey, partner.DhPubKey,
salt, ecrFmt.data, grp)
ecrFmt.data, grp)
//get the fingerprint from the old ownership proof
fp := cAuth.MakeOwnershipProofFP(storedContact.OwnershipProof)
......@@ -93,7 +95,6 @@ func ConfirmRequestAuth(partner contact.Contact, rng io.Reader,
//final construction
baseFmt.SetEcrPayload(ecrPayload)
baseFmt.SetSalt(salt)
baseFmt.SetPubKey(newPubKey)
cmixMsg.SetKeyFP(fp)
......@@ -108,7 +109,8 @@ func ConfirmRequestAuth(partner contact.Contact, rng io.Reader,
//create local relationship
p := storage.E2e().GetE2ESessionParams()
if err := storage.E2e().AddPartner(partner.ID, partner.DhPubKey, newPrivKey,
if err := storage.E2e().AddPartner(partner.ID, partner.DhPubKey,
newPrivKey, theirSidhKey, newSIDHPrivKey,
p, p); err != nil {
em := fmt.Sprintf("Failed to create channel with partner (%s) "+
"on confirmation, this is likley a replay: %s",
......@@ -131,10 +133,17 @@ func ConfirmRequestAuth(partner contact.Contact, rng io.Reader,
Source: partner.ID[:],
}, me)
//rekey
//slient (rekey)
storage.GetEdge().Add(edge.Preimage{
Data: sessionPartner.GetSilentPreimage(),
Type: preimage.Silent,
Source: partner.ID[:],
}, me)
// File transfer end
storage.GetEdge().Add(edge.Preimage{
Data: sessionPartner.GetRekeyPreimage(),
Type: preimage.Rekey,
Data: sessionPartner.GetFileTransferPreimage(),
Type: preimage.EndFT,
Source: partner.ID[:],
}, me)
......
......@@ -8,29 +8,33 @@
package auth
import (
"github.com/cloudflare/circl/dh/sidh"
"github.com/pkg/errors"
jww "github.com/spf13/jwalterweatherman"
sidhinterface "gitlab.com/elixxir/client/interfaces/sidh"
util "gitlab.com/elixxir/client/storage/utility"
"gitlab.com/elixxir/crypto/cyclic"
"gitlab.com/xx_network/primitives/id"
)
//Basic Format//////////////////////////////////////////////////////////////////
const saltSize = 32
type baseFormat struct {
data []byte
pubkey []byte
salt []byte
ecrPayload []byte
}
func newBaseFormat(payloadSize, pubkeySize int) baseFormat {
if payloadSize < pubkeySize+saltSize {
jww.FATAL.Panicf("Size of baseFormat is too small, must be big " +
"enough to contain public key and salt")
total := pubkeySize + sidhinterface.PubKeyByteSize + 1
if payloadSize < total {
jww.FATAL.Panicf("Size of baseFormat is too small (%d), must be big "+
"enough to contain public key (%d) and sidh key (%d)"+
"which totals to %d", payloadSize, pubkeySize,
sidhinterface.PubKeyByteSize+1, total)
}
jww.INFO.Printf("Empty Space RequestAuth: %d", payloadSize-total)
f := buildBaseFormat(make([]byte, payloadSize), pubkeySize)
return f
......@@ -41,14 +45,17 @@ func buildBaseFormat(data []byte, pubkeySize int) baseFormat {
data: data,
}
f.pubkey = f.data[:pubkeySize]
f.salt = f.data[pubkeySize : pubkeySize+saltSize]
f.ecrPayload = f.data[pubkeySize+saltSize:]
start := 0
end := pubkeySize
f.pubkey = f.data[:end]
start = end
f.ecrPayload = f.data[start:]
return f
}
func unmarshalBaseFormat(b []byte, pubkeySize int) (baseFormat, error) {
if len(b) < pubkeySize+saltSize {
if len(b) < pubkeySize {
return baseFormat{}, errors.New("Received baseFormat too small")
}
......@@ -68,18 +75,7 @@ func (f baseFormat) SetPubKey(pubKey *cyclic.Int) {
copy(f.pubkey, pubKeyBytes)
}
func (f baseFormat) GetSalt() []byte {
return f.salt
}
func (f baseFormat) SetSalt(salt []byte) {
if len(salt) != saltSize {
jww.FATAL.Panicf("Salt incorrect size")
}
copy(f.salt, salt)
}
// GetEcrPayload is the data that is encrypted
func (f baseFormat) GetEcrPayload() []byte {
return f.ecrPayload
}
......@@ -103,11 +99,12 @@ const ownershipSize = 32
type ecrFormat struct {
data []byte
ownership []byte
sidHpubkey []byte
payload []byte
}
func newEcrFormat(size int) ecrFormat {
if size < ownershipSize {
if size < (ownershipSize + sidhinterface.PubKeyByteSize + 1) {
jww.FATAL.Panicf("Size too small to hold")
}
......@@ -122,8 +119,16 @@ func buildEcrFormat(data []byte) ecrFormat {
data: data,
}
f.ownership = f.data[:ownershipSize]
f.payload = f.data[ownershipSize:]
start := 0
end := ownershipSize
f.ownership = f.data[start:end]
start = end
end = start + sidhinterface.PubKeyByteSize + 1
f.sidHpubkey = f.data[start:end]
start = end
f.payload = f.data[start:]
return f
}
......@@ -151,6 +156,18 @@ func (f ecrFormat) SetOwnership(ownership []byte) {
copy(f.ownership, ownership)
}
func (f ecrFormat) SetSidHPubKey(pubKey *sidh.PublicKey) {
f.sidHpubkey[0] = byte(pubKey.Variant())
pubKey.Export(f.sidHpubkey[1:])
}
func (f ecrFormat) GetSidhPubKey() (*sidh.PublicKey, error) {
variant := sidh.KeyVariant(f.sidHpubkey[0])
pubKey := util.NewSIDHPublicKey(variant)
err := pubKey.Import(f.sidHpubkey[1:])
return pubKey, err
}
func (f ecrFormat) GetPayload() []byte {
return f.payload
}
......
......@@ -9,6 +9,7 @@ package auth
import (
"bytes"
sidhinterface "gitlab.com/elixxir/client/interfaces/sidh"
"gitlab.com/xx_network/primitives/id"
"math/rand"
"reflect"
......@@ -19,7 +20,7 @@ import (
func TestNewBaseFormat(t *testing.T) {
// Construct message
pubKeySize := 256
payloadSize := saltSize + pubKeySize
payloadSize := pubKeySize + sidhinterface.PubKeyByteSize + 1
baseMsg := newBaseFormat(payloadSize, pubKeySize)
// Check that the base format was constructed properly
......@@ -30,14 +31,7 @@ func TestNewBaseFormat(t *testing.T) {
"\n\tReceived: %v", make([]byte, pubKeySize), baseMsg.pubkey)
}
if !bytes.Equal(baseMsg.salt, make([]byte, saltSize)) {
t.Errorf("NewBaseFormat error: "+
"Unexpected salt field in base format."+
"\n\tExpected: %v"+
"\n\tReceived: %v", make([]byte, saltSize), baseMsg.salt)
}
expectedEcrPayloadSize := payloadSize - (pubKeySize + saltSize)
expectedEcrPayloadSize := payloadSize - (pubKeySize)
if !bytes.Equal(baseMsg.ecrPayload, make([]byte, expectedEcrPayloadSize)) {
t.Errorf("NewBaseFormat error: "+
"Unexpected payload field in base format."+
......@@ -45,7 +39,7 @@ func TestNewBaseFormat(t *testing.T) {
"\n\tReceived: %v", make([]byte, expectedEcrPayloadSize), baseMsg.ecrPayload)
}
// Error case, where payload size is less than the public key plus salt
// Error case, where payload size is less than the public key
defer func() {
if r := recover(); r == nil {
t.Error("newBaseFormat() did not panic when the size of " +
......@@ -62,7 +56,7 @@ func TestNewBaseFormat(t *testing.T) {
func TestBaseFormat_SetGetPubKey(t *testing.T) {
// Construct message
pubKeySize := 256
payloadSize := saltSize + pubKeySize
payloadSize := pubKeySize + sidhinterface.PubKeyByteSize + 1
baseMsg := newBaseFormat(payloadSize, pubKeySize)
// Test setter
......@@ -86,50 +80,15 @@ func TestBaseFormat_SetGetPubKey(t *testing.T) {
}
// Set/Get salt tests
func TestBaseFormat_SetGetSalt(t *testing.T) {
// Construct message
pubKeySize := 256
payloadSize := saltSize + pubKeySize
baseMsg := newBaseFormat(payloadSize, pubKeySize)
// Test setter
salt := newSalt("salt")
baseMsg.SetSalt(salt)
if !bytes.Equal(salt, baseMsg.salt) {
t.Errorf("SetSalt() error: "+
"Salt field does not have expected value."+
"\n\tExpected: %v\n\tReceived: %v", salt, baseMsg.salt)
}
// Test getter
receivedSalt := baseMsg.GetSalt()
if !bytes.Equal(salt, receivedSalt) {
t.Errorf("GetSalt() error: "+
"Salt retrieved does not have expected value."+
"\n\tExpected: %v\n\tReceived: %v", salt, receivedSalt)
}
// Test setter error path: Setting salt of incorrect size
defer func() {
if r := recover(); r == nil {
t.Error("SetSalt() did not panic when the size of " +
"the salt is smaller than the required salt size.")
}
}()
baseMsg.SetSalt([]byte("salt"))
}
// Set/Get EcrPayload tests
func TestBaseFormat_SetGetEcrPayload(t *testing.T) {
// Construct message
pubKeySize := 256
payloadSize := (saltSize + pubKeySize) * 2
payloadSize := (pubKeySize + sidhinterface.PubKeyByteSize) * 2
baseMsg := newBaseFormat(payloadSize, pubKeySize)
// Test setter
ecrPayloadSize := payloadSize - (pubKeySize + saltSize)
ecrPayloadSize := payloadSize - (pubKeySize)
ecrPayload := newPayload(ecrPayloadSize, "ecrPayload")
baseMsg.SetEcrPayload(ecrPayload)
if !bytes.Equal(ecrPayload, baseMsg.ecrPayload) {
......@@ -162,13 +121,11 @@ func TestBaseFormat_SetGetEcrPayload(t *testing.T) {
func TestBaseFormat_MarshalUnmarshal(t *testing.T) {
// Construct a fully populated message
pubKeySize := 256
payloadSize := (saltSize + pubKeySize) * 2
payloadSize := (pubKeySize + sidhinterface.PubKeyByteSize) * 2
baseMsg := newBaseFormat(payloadSize, pubKeySize)
ecrPayloadSize := payloadSize - (pubKeySize + saltSize)
ecrPayloadSize := payloadSize - (pubKeySize)
ecrPayload := newPayload(ecrPayloadSize, "ecrPayload")
baseMsg.SetEcrPayload(ecrPayload)
salt := newSalt("salt")
baseMsg.SetSalt(salt)
grp := getGroup()
pubKey := grp.NewInt(25)
baseMsg.SetPubKey(pubKey)
......@@ -206,7 +163,7 @@ func TestBaseFormat_MarshalUnmarshal(t *testing.T) {
// Tests newEcrFormat
func TestNewEcrFormat(t *testing.T) {
// Construct message
payloadSize := ownershipSize * 2
payloadSize := ownershipSize*2 + sidhinterface.PubKeyByteSize + 1
ecrMsg := newEcrFormat(payloadSize)
// Check that the ecrFormat was constructed properly
......@@ -217,14 +174,15 @@ func TestNewEcrFormat(t *testing.T) {
"\n\tReceived: %v", make([]byte, payloadSize), ecrMsg.ownership)
}
if !bytes.Equal(ecrMsg.payload, make([]byte, payloadSize-ownershipSize)) {
if !bytes.Equal(ecrMsg.payload, make([]byte,
payloadSize-ownershipSize-sidhinterface.PubKeyByteSize-1)) {
t.Errorf("newEcrFormat error: "+
"Unexpected ownership field in ecrFormat."+
"\n\tExpected: %v"+
"\n\tReceived: %v", make([]byte, payloadSize-ownershipSize), ecrMsg.payload)
}
// Error case, where payload size is less than the public key plus salt
// Error case, where payload size is less than the public key
defer func() {
if r := recover(); r == nil {
t.Error("newEcrFormat() did not panic when the size of " +
......@@ -240,7 +198,7 @@ func TestNewEcrFormat(t *testing.T) {
// Set/Get ownership tests
func TestEcrFormat_SetGetOwnership(t *testing.T) {
// Construct message
payloadSize := ownershipSize * 2
payloadSize := ownershipSize*2 + sidhinterface.PubKeyByteSize + 1
ecrMsg := newEcrFormat(payloadSize)
// Test setter
......@@ -276,11 +234,13 @@ func TestEcrFormat_SetGetOwnership(t *testing.T) {
// Set/Get payload tests
func TestEcrFormat_SetGetPayload(t *testing.T) {
// Construct message
payloadSize := ownershipSize * 2
payloadSize := ownershipSize*2 + sidhinterface.PubKeyByteSize + 1
ecrMsg := newEcrFormat(payloadSize)
// Test set
expectedPayload := newPayload(payloadSize-ownershipSize, "ownership")
expectedPayload := newPayload(
payloadSize-ownershipSize-sidhinterface.PubKeyByteSize-1,
"ownership")
ecrMsg.SetPayload(expectedPayload)
if !bytes.Equal(expectedPayload, ecrMsg.payload) {
......@@ -312,9 +272,11 @@ func TestEcrFormat_SetGetPayload(t *testing.T) {
// Marshal/ unmarshal tests
func TestEcrFormat_MarshalUnmarshal(t *testing.T) {
// Construct message
payloadSize := ownershipSize * 2
payloadSize := ownershipSize*2 + sidhinterface.PubKeyByteSize + 1
ecrMsg := newEcrFormat(payloadSize)
expectedPayload := newPayload(payloadSize-ownershipSize, "ownership")
expectedPayload := newPayload(
payloadSize-ownershipSize-sidhinterface.PubKeyByteSize-1,
"ownership")
ecrMsg.SetPayload(expectedPayload)
ownership := newOwnership("owner")
ecrMsg.SetOwnership(ownership)
......@@ -352,7 +314,7 @@ func TestEcrFormat_MarshalUnmarshal(t *testing.T) {
// Tests newRequestFormat
func TestNewRequestFormat(t *testing.T) {
// Construct message
payloadSize := id.ArrIDLen*2 - 1
payloadSize := id.ArrIDLen*2 - 1 + sidhinterface.PubKeyByteSize + 1
ecrMsg := newEcrFormat(payloadSize)
expectedPayload := newPayload(id.ArrIDLen, "ownership")
ecrMsg.SetPayload(expectedPayload)
......@@ -370,14 +332,16 @@ func TestNewRequestFormat(t *testing.T) {
"\n\tReceived: %v", make([]byte, id.ArrIDLen), reqMsg.id)
}
if !bytes.Equal(reqMsg.msgPayload, make([]byte, 0)) {
t.Errorf("newRequestFormat() error: "+
"Unexpected msgPayload field in requestFormat."+
"\n\tExpected: %v"+
"\n\tReceived: %v", make([]byte, 0), reqMsg.msgPayload)
}
// FIXME: Commented out for now.. it's not clear why this was necessary
// if !bytes.Equal(reqMsg.GetPayload(), make([]byte, 0,
// sidhinterface.PubKeyByteSize)) {
// t.Errorf("newRequestFormat() error: "+
// "Unexpected msgPayload field in requestFormat."+
// "\n\tExpected: %v"+
// "\n\tReceived: %v", make([]byte, 0), reqMsg.GetPayload())
// }
payloadSize = ownershipSize * 2
payloadSize = ownershipSize*2 + sidhinterface.PubKeyByteSize + 1
ecrMsg = newEcrFormat(payloadSize)
reqMsg, err = newRequestFormat(ecrMsg)
if err == nil {
......@@ -391,7 +355,7 @@ func TestNewRequestFormat(t *testing.T) {
// Unit test for Get/SetID
func TestRequestFormat_SetGetID(t *testing.T) {
// Construct message
payloadSize := id.ArrIDLen*2 - 1
payloadSize := id.ArrIDLen*2 - 1 + sidhinterface.PubKeyByteSize + 1
ecrMsg := newEcrFormat(payloadSize)
expectedPayload := newPayload(id.ArrIDLen, "ownership")
ecrMsg.SetPayload(expectedPayload)
......@@ -408,7 +372,7 @@ func TestRequestFormat_SetGetID(t *testing.T) {
if !bytes.Equal(reqMsg.id, expectedId.Bytes()) {
t.Errorf("SetID() error: "+
"Id field does not have expected value."+
"\n\tExpected: %v\n\tReceived: %v", expectedId, reqMsg.msgPayload)
"\n\tExpected: %v\n\tReceived: %v", expectedId, reqMsg.GetPayload())
}
// Test GetID
......@@ -432,7 +396,7 @@ func TestRequestFormat_SetGetID(t *testing.T) {
// Unit test for Get/SetMsgPayload
func TestRequestFormat_SetGetMsgPayload(t *testing.T) {
// Construct message
payloadSize := id.ArrIDLen*3 - 1
payloadSize := id.ArrIDLen*3 - 1 + sidhinterface.PubKeyByteSize + 1
ecrMsg := newEcrFormat(payloadSize)
expectedPayload := newPayload(id.ArrIDLen*2, "ownership")
ecrMsg.SetPayload(expectedPayload)
......@@ -443,16 +407,17 @@ func TestRequestFormat_SetGetMsgPayload(t *testing.T) {
}
// Test SetMsgPayload
msgPayload := newPayload(id.ArrIDLen, "msgPayload")
reqMsg.SetMsgPayload(msgPayload)
if !bytes.Equal(reqMsg.msgPayload, msgPayload) {
msgPayload := newPayload(id.ArrIDLen*2,
"msgPayload")
reqMsg.SetPayload(msgPayload)
if !bytes.Equal(reqMsg.GetPayload(), msgPayload) {
t.Errorf("SetMsgPayload() error: "+
"MsgPayload has unexpected value: "+
"\n\tExpected: %v\n\tReceived: %v", msgPayload, reqMsg.msgPayload)
"\n\tExpected: %v\n\tReceived: %v", msgPayload, reqMsg.GetPayload())
}
// Test GetMsgPayload
retrievedMsgPayload := reqMsg.GetMsgPayload()
retrievedMsgPayload := reqMsg.GetPayload()
if !bytes.Equal(retrievedMsgPayload, msgPayload) {
t.Errorf("GetMsgPayload() error: "+
"MsgPayload has unexpected value: "+
......@@ -468,5 +433,5 @@ func TestRequestFormat_SetGetMsgPayload(t *testing.T) {
}
}()
expectedPayload = append(expectedPayload, expectedPayload...)
reqMsg.SetMsgPayload(expectedPayload)
reqMsg.SetPayload(expectedPayload)
}
......@@ -9,6 +9,7 @@ package auth
import (
"fmt"
"github.com/cloudflare/circl/dh/sidh"
"github.com/pkg/errors"
jww "github.com/spf13/jwalterweatherman"
"gitlab.com/elixxir/client/interfaces"
......@@ -18,6 +19,7 @@ import (
"gitlab.com/elixxir/client/storage/auth"
"gitlab.com/elixxir/client/storage/e2e"
"gitlab.com/elixxir/client/storage/edge"
util "gitlab.com/elixxir/client/storage/utility"
"gitlab.com/elixxir/crypto/contact"
"gitlab.com/elixxir/crypto/cyclic"
"gitlab.com/elixxir/crypto/diffieHellman"
......@@ -30,7 +32,7 @@ import (
const terminator = ";"
func RequestAuth(partner, me contact.Contact, message string, rng io.Reader,
func RequestAuth(partner, me contact.Contact, rng io.Reader,
storage *storage.Session, net interfaces.NetworkManager) (id.Round, error) {
/*edge checks generation*/
......@@ -47,11 +49,6 @@ func RequestAuth(partner, me contact.Contact, message string, rng io.Reader,
"can only be sent from user's identity")
}
// check that the message is properly formed
if strings.Contains(message, terminator) {
return 0, errors.Errorf("Message cannot contain '%s'", terminator)
}
//denote if this is a resend of an old request
resend := false
......@@ -87,35 +84,42 @@ func RequestAuth(partner, me contact.Contact, message string, rng io.Reader,
//check the payload fits
facts := me.Facts.Stringify()
msgPayload := facts + message + terminator
msgPayload := facts + terminator
msgPayloadBytes := []byte(msgPayload)
if len(msgPayloadBytes) > requestFmt.MsgPayloadLen() {
return 0, errors.Errorf("Combined message longer than space "+
"available in payload; available: %v, length: %v",
requestFmt.MsgPayloadLen(), len(msgPayloadBytes))
}
/*cryptographic generation*/
//generate salt
salt := make([]byte, saltSize)
_, err = rng.Read(salt)
if err != nil {
return 0, errors.Wrap(err, "Failed to generate salt")
}
var newPrivKey, newPubKey *cyclic.Int
var sidHPrivKeyA *sidh.PrivateKey
var sidHPubKeyA *sidh.PublicKey
// in this case we have an ongoing request so we can resend the extant
// request
if resend {
newPrivKey = sr.GetMyPrivKey()
newPubKey = sr.GetMyPubKey()
sidHPrivKeyA = sr.GetMySIDHPrivKey()
sidHPubKeyA = sr.GetMySIDHPubKey()
//in this case it is a new request and we must generate new keys
} else {
//generate new keypair
newPrivKey = diffieHellman.GeneratePrivateKey(256, grp, rng)
newPubKey = diffieHellman.GeneratePublicKey(newPrivKey, grp)
sidHPrivKeyA = util.NewSIDHPrivateKey(sidh.KeyVariantSidhA)
sidHPubKeyA = util.NewSIDHPublicKey(sidh.KeyVariantSidhA)
if err = sidHPrivKeyA.Generate(rng); err != nil {
return 0, errors.WithMessagef(err, "RequestAuth: "+
"could not generate SIDH private key")
}
sidHPrivKeyA.GeneratePublicKey(sidHPubKeyA)
}
if len(msgPayloadBytes) > requestFmt.MsgPayloadLen() {
return 0, errors.Errorf("Combined message longer than space "+
"available in payload; available: %v, length: %v",
requestFmt.MsgPayloadLen(), len(msgPayloadBytes))
}
//generate ownership proof
......@@ -129,14 +133,14 @@ func RequestAuth(partner, me contact.Contact, message string, rng io.Reader,
requestFmt.SetID(storage.GetUser().ReceptionID)
requestFmt.SetMsgPayload(msgPayloadBytes)
ecrFmt.SetOwnership(ownership)
ecrFmt.SetSidHPubKey(sidHPubKeyA)
ecrPayload, mac := cAuth.Encrypt(newPrivKey, partner.DhPubKey,
salt, ecrFmt.data, grp)
ecrFmt.data, grp)
confirmFp := cAuth.MakeOwnershipProofFP(ownership)
requestfp := cAuth.MakeRequestFingerprint(partner.DhPubKey)
/*construct message*/
baseFmt.SetEcrPayload(ecrPayload)
baseFmt.SetSalt(salt)
baseFmt.SetPubKey(newPubKey)
cmixMsg.SetKeyFP(requestfp)
......@@ -149,7 +153,6 @@ func RequestAuth(partner, me contact.Contact, message string, rng io.Reader,
Source: partner.ID[:],
}, me.ID)
jww.TRACE.Printf("RequestAuth SALT: %v", salt)
jww.TRACE.Printf("RequestAuth ECRPAYLOAD: %v", baseFmt.GetEcrPayload())
jww.TRACE.Printf("RequestAuth MAC: %v", mac)
......@@ -158,7 +161,7 @@ func RequestAuth(partner, me contact.Contact, message string, rng io.Reader,
//store the in progress auth
if !resend {
err = storage.Auth().AddSent(partner.ID, partner.DhPubKey, newPrivKey,
newPubKey, confirmFp)
newPubKey, sidHPrivKeyA, sidHPubKeyA, confirmFp)
if err != nil {
return 0, errors.Errorf("Failed to store auth request: %s", err)
}
......
......@@ -31,12 +31,6 @@ func randID(rng *rand.Rand, t id.Type) *id.ID {
return newID
}
func newSalt(s string) []byte {
salt := make([]byte, saltSize)
copy(salt[:], s)
return salt
}
func newPayload(size int, s string) []byte {
b := make([]byte, size)
copy(b[:], s)
......
......@@ -65,7 +65,7 @@ func (c *Client) RegisterAuthCallbacks(request AuthRequestCallback,
requestFunc := func(requestor contact.Contact, message string) {
requestorBind := &Contact{c: &requestor}
request.Callback(requestorBind, message)
request.Callback(requestorBind)
}
confirmFunc := func(partner contact.Contact) {
......
......@@ -51,7 +51,7 @@ type MessageDeliveryCallback interface {
// AuthRequestCallback notifies the register whenever they receive an auth
// request
type AuthRequestCallback interface {
Callback(requestor *Contact, message string)
Callback(requestor *Contact)
}
// AuthConfirmCallback notifies the register whenever they receive an auth
......
......@@ -23,6 +23,7 @@ import (
"gitlab.com/xx_network/primitives/id"
"gitlab.com/xx_network/primitives/netTime"
"google.golang.org/grpc/grpclog"
"runtime/pprof"
"strings"
"sync"
"time"
......@@ -264,6 +265,15 @@ func (c *Client) WaitForNetwork(timeoutMS int) bool {
func (c *Client) NetworkFollowerStatus() int {
return int(c.api.NetworkFollowerStatus())
}
// HasRunningProcessies checks if any background threads are running.
// returns true if none are running. This is meant to be
// used when NetworkFollowerStatus() returns Stopping.
// Due to the handling of comms on iOS, where the OS can
// block indefiently, it may not enter the stopped
// state apropreatly. This can be used instead.
func (c *Client) HasRunningProcessies() bool {
return c.api.HasRunningProcessies()
}
// returns true if the network is read to be in a healthy state where
// messages can be sent
......@@ -485,6 +495,11 @@ func (c *Client) GetPreferredBins(countryCode string) (string, error) {
return buff.String(), nil
}
// GetRateLimitParams retrieves the rate limiting parameters.
func (c *Client) GetRateLimitParams() (uint32, uint32, int64) {
return c.api.GetRateLimitParams()
}
/*
// SearchWithHandler is a non-blocking search that also registers
// a callback interface for user disovery events.
......@@ -523,3 +538,13 @@ func (c *Client) getSingle() (*single.Manager, error) {
return c.single, nil
}
// DumpStack returns a string with the stack trace of every running thread.
func DumpStack() (string, error) {
buf := new(bytes.Buffer)
err := pprof.Lookup("goroutine").WriteTo(buf, 2)
if err != nil {
return "", err
}
return buf.String(), nil
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment