Skip to content
Snippets Groups Projects
Commit 20875a63 authored by Sydney Anne Erickson's avatar Sydney Anne Erickson :chipmunk:
Browse files

Merge branch 'revertRearrangements' into 'release'

Revert register.go

See merge request !288
parents ea2cb870 6d587dc2
No related branches found
No related tags found
No related merge requests found
...@@ -9,6 +9,7 @@ package api ...@@ -9,6 +9,7 @@ package api
import ( import (
"bufio" "bufio"
"crypto" "crypto"
"crypto/rand"
gorsa "crypto/rsa" gorsa "crypto/rsa"
"crypto/sha256" "crypto/sha256"
"encoding/base64" "encoding/base64"
...@@ -23,8 +24,11 @@ import ( ...@@ -23,8 +24,11 @@ import (
"gitlab.com/elixxir/client/parse" "gitlab.com/elixxir/client/parse"
"gitlab.com/elixxir/client/rekey" "gitlab.com/elixxir/client/rekey"
"gitlab.com/elixxir/client/user" "gitlab.com/elixxir/client/user"
"gitlab.com/elixxir/crypto/csprng"
"gitlab.com/elixxir/crypto/cyclic" "gitlab.com/elixxir/crypto/cyclic"
"gitlab.com/elixxir/crypto/hash"
"gitlab.com/elixxir/crypto/large" "gitlab.com/elixxir/crypto/large"
"gitlab.com/elixxir/crypto/registration"
"gitlab.com/elixxir/crypto/signature/rsa" "gitlab.com/elixxir/crypto/signature/rsa"
"gitlab.com/elixxir/crypto/tls" "gitlab.com/elixxir/crypto/tls"
"gitlab.com/elixxir/primitives/circuit" "gitlab.com/elixxir/primitives/circuit"
...@@ -33,6 +37,7 @@ import ( ...@@ -33,6 +37,7 @@ import (
"gitlab.com/elixxir/primitives/switchboard" "gitlab.com/elixxir/primitives/switchboard"
goio "io" goio "io"
"strings" "strings"
"sync"
"time" "time"
) )
...@@ -447,6 +452,331 @@ type SearchCallback interface { ...@@ -447,6 +452,331 @@ type SearchCallback interface {
Callback(userID, pubKey []byte, err error) Callback(userID, pubKey []byte, err error)
} }
const SaltSize = 256
// RegisterWithPermissioning registers user with permissioning and returns the
// User ID. Returns an error if registration fails.
func (cl *Client) RegisterWithPermissioning(preCan bool, registrationCode, nick, email,
password string, privateKeyRSA *rsa.PrivateKey) (*id.User, error) {
if !preCan && cl.commManager.GetConnectionStatus() != io.Online {
return nil, errors.New("Cannot register when disconnected from the network")
}
var err error
var u *user.User
var UID *id.User
cl.opStatus(globals.REG_KEYGEN)
largeIntBits := 16
cmixGrp := cyclic.NewGroup(
large.NewIntFromString(cl.ndf.CMIX.Prime, largeIntBits),
large.NewIntFromString(cl.ndf.CMIX.Generator, largeIntBits))
e2eGrp := cyclic.NewGroup(
large.NewIntFromString(cl.ndf.E2E.Prime, largeIntBits),
large.NewIntFromString(cl.ndf.E2E.Generator, largeIntBits))
// Make CMIX keys array
nk := make(map[id.Node]user.NodeKeys)
// GENERATE CLIENT RSA KEYS
if privateKeyRSA == nil {
privateKeyRSA, err = rsa.GenerateKey(rand.Reader, rsa.DefaultRSABitLen)
if err != nil {
return nil, err
}
}
publicKeyRSA := privateKeyRSA.GetPublic()
cmixPrivKeyDHByte, err := csprng.GenerateInGroup(cmixGrp.GetPBytes(), 256, csprng.NewSystemRNG())
if err != nil {
return nil, errors.Errorf("Could not generate cmix DH private key: %s", err.Error())
}
cmixPrivateKeyDH := cmixGrp.NewIntFromBytes(cmixPrivKeyDHByte)
cmixPublicKeyDH := cmixGrp.ExpG(cmixPrivateKeyDH, cmixGrp.NewMaxInt())
e2ePrivKeyDHByte, err := csprng.GenerateInGroup(cmixGrp.GetPBytes(), 256, csprng.NewSystemRNG())
if err != nil {
return nil, errors.Errorf("Could not generate e2e DH private key: %s", err.Error())
}
e2ePrivateKeyDH := e2eGrp.NewIntFromBytes(e2ePrivKeyDHByte)
e2ePublicKeyDH := e2eGrp.ExpG(e2ePrivateKeyDH, e2eGrp.NewMaxInt())
// Initialized response from Registration Server
regValidationSignature := make([]byte, 0)
var salt []byte
// Handle precanned registration
if preCan {
cl.opStatus(globals.REG_PRECAN)
globals.Log.INFO.Printf("Registering precanned user...")
u, UID, nk, err = cl.precannedRegister(registrationCode, nick, nk)
if err != nil {
errMsg := errors.Errorf("Unable to complete precanned registration: %+v", err)
return id.ZeroID, errMsg
}
} else {
cl.opStatus(globals.REG_UID_GEN)
globals.Log.INFO.Printf("Registering dynamic user...")
// Generate salt for UserID
salt = make([]byte, SaltSize)
_, err = csprng.NewSystemRNG().Read(salt)
if err != nil {
errMsg := errors.Errorf("Register: Unable to generate salt! %s", err)
return id.ZeroID, errMsg
}
// Generate UserID by hashing salt and public key
UID = registration.GenUserID(publicKeyRSA, salt)
// If Registration Server is specified, contact it
// Only if registrationCode is set
globals.Log.INFO.Println("Register: Contacting registration server")
if cl.ndf.Registration.Address != "" && registrationCode != "" {
cl.opStatus(globals.REG_PERM)
regValidationSignature, err = cl.sendRegistrationMessage(registrationCode, publicKeyRSA)
if err != nil {
err = errors.Errorf("Register: Unable to send registration message: %+v", err)
return id.ZeroID, err
}
}
globals.Log.INFO.Println("Register: successfully passed Registration message")
var actualNick string
if nick != "" {
actualNick = nick
} else {
actualNick = base64.StdEncoding.EncodeToString(UID[:])
}
u = user.Users.NewUser(UID, actualNick)
user.Users.UpsertUser(u)
}
cl.opStatus(globals.REG_SECURE_STORE)
u.Email = email
// Create the user session
newSession := user.NewSession(cl.storage, u, nk, publicKeyRSA,
privateKeyRSA, cmixPublicKeyDH, cmixPrivateKeyDH, e2ePublicKeyDH,
e2ePrivateKeyDH, salt, cmixGrp, e2eGrp, password, regValidationSignature)
cl.opStatus(globals.REG_SAVE)
//set the registration state
err = newSession.SetRegState(user.PermissioningComplete)
if err != nil {
return id.ZeroID, errors.Wrap(err, "Permissioning Registration "+
"Failed")
}
// Store the user session
errStore := newSession.StoreSession()
if errStore != nil {
errMsg := errors.Errorf(
"Permissioning Register: could not register due to failed session save"+
": %s", errStore.Error())
return id.ZeroID, errMsg
}
cl.session = newSession
return UID, nil
}
// RegisterWithUDB uses the account's email to register with the UDB for
// User discovery. Must be called after Register and Connect.
// It will fail if the user has already registered with UDB
func (cl *Client) RegisterWithUDB(timeout time.Duration) error {
regState := cl.GetSession().GetRegState()
if regState != user.PermissioningComplete {
return errors.New("Cannot register with UDB when registration " +
"state is not PermissioningComplete")
}
status := cl.commManager.GetConnectionStatus()
if status == io.Connecting || status == io.Offline {
return errors.New("ERROR: could not RegisterWithUDB - connection is either offline or connecting")
}
email := cl.session.GetCurrentUser().Email
var err error
if email != "" {
globals.Log.INFO.Printf("Registering user as %s with UDB", email)
valueType := "EMAIL"
publicKeyBytes := cl.session.GetE2EDHPublicKey().Bytes()
err = bots.Register(valueType, email, publicKeyBytes, cl.opStatus, timeout)
if err == nil {
globals.Log.INFO.Printf("Registered with UDB!")
} else {
globals.Log.WARN.Printf("Could not register with UDB: %s", err)
}
} else {
globals.Log.INFO.Printf("Not registering with UDB because no " +
"email found")
}
if err != nil {
return errors.Wrap(err, "Could not register with UDB")
}
//set the registration state
err = cl.session.SetRegState(user.UDBComplete)
if err != nil {
return errors.Wrap(err, "UDB Registration Failed")
}
errStore := cl.session.StoreSession()
// FIXME If we have an error here, the session that gets created
// doesn't get immolated. Immolation should happen in a deferred
// call instead.
if errStore != nil {
errMsg := errors.Errorf(
"UDB Register: could not register due to failed session save"+
": %s", errStore.Error())
return errMsg
}
return nil
}
func (cl *Client) RegisterWithNodes() error {
session := cl.GetSession()
//Load Cmix keys & group
cmixDHPrivKey := session.GetCMIXDHPrivateKey()
cmixDHPubKey := session.GetCMIXDHPublicKey()
cmixGrp := session.GetCmixGroup()
//Load the rsa keys
rsaPubKey := session.GetRSAPublicKey()
rsaPrivKey := session.GetRSAPrivateKey()
//Load the user ID
UID := session.GetCurrentUser().User
//Load the registration signature
regSignature := session.GetRegistrationValidationSignature()
var wg sync.WaitGroup
errChan := make(chan error, len(cl.ndf.Gateways))
//Get the registered node keys
registeredNodes := session.GetNodes()
salt := session.GetSalt()
// This variable keeps track of whether there were new registrations
// required, thus requiring the state file to be saved again
newRegistrations := false
for i := range cl.ndf.Gateways {
localI := i
nodeID := *id.NewNodeFromBytes(cl.ndf.Nodes[i].ID)
//Register with node if the node has not been registered with already
if _, ok := registeredNodes[nodeID]; !ok {
wg.Add(1)
newRegistrations = true
go func() {
cl.registerWithNode(localI, salt, regSignature, UID, rsaPubKey, rsaPrivKey,
cmixDHPubKey, cmixDHPrivKey, cmixGrp, errChan)
wg.Done()
}()
}
}
wg.Wait()
//See if the registration returned errors at all
var errs error
for len(errChan) > 0 {
err := <-errChan
if errs != nil {
errs = errors.Wrap(errs, err.Error())
} else {
errs = err
}
}
//If an error every occurred, return with error
if errs != nil {
cl.opStatus(globals.REG_FAIL)
return errs
}
// Store the user session if there were changes during node registration
if newRegistrations {
errStore := session.StoreSession()
if errStore != nil {
err := errors.Errorf(
"Register: could not register due to failed session save"+
": %s", errStore.Error())
return err
}
}
return nil
}
//registerWithNode registers a user. It serves as a helper for Register
func (cl *Client) registerWithNode(index int, salt, registrationValidationSignature []byte, UID *id.User,
publicKeyRSA *rsa.PublicKey, privateKeyRSA *rsa.PrivateKey,
cmixPublicKeyDH, cmixPrivateKeyDH *cyclic.Int,
cmixGrp *cyclic.Group, errorChan chan error) {
gatewayID := id.NewNodeFromBytes(cl.ndf.Nodes[index].ID).NewGateway()
// Initialise blake2b hash for transmission keys and sha256 for reception
// keys
transmissionHash, _ := hash.NewCMixHash()
receptionHash := sha256.New()
// Request nonce message from gateway
globals.Log.INFO.Printf("Register: Requesting nonce from gateway %v/%v",
index+1, len(cl.ndf.Gateways))
nonce, dhPub, err := cl.requestNonce(salt, registrationValidationSignature, cmixPublicKeyDH,
publicKeyRSA, privateKeyRSA, gatewayID)
if err != nil {
errMsg := errors.Errorf("Register: Failed requesting nonce from gateway: %+v", err)
errorChan <- errMsg
}
// Load server DH pubkey
serverPubDH := cmixGrp.NewIntFromBytes(dhPub)
// Confirm received nonce
globals.Log.INFO.Println("Register: Confirming received nonce")
err = cl.confirmNonce(UID.Bytes(), nonce, privateKeyRSA, gatewayID)
if err != nil {
errMsg := errors.Errorf("Register: Unable to confirm nonce: %v", err)
errorChan <- errMsg
}
nodeID := cl.topology.GetNodeAtIndex(index)
key := user.NodeKeys{
TransmissionKey: registration.GenerateBaseKey(cmixGrp,
serverPubDH, cmixPrivateKeyDH, transmissionHash),
ReceptionKey: registration.GenerateBaseKey(cmixGrp, serverPubDH,
cmixPrivateKeyDH, receptionHash),
}
cl.session.PushNodeKey(nodeID, key)
}
// UDB Search API // UDB Search API
// Pass a callback function to extract results // Pass a callback function to extract results
func (cl *Client) SearchForUser(emailAddress string, func (cl *Client) SearchForUser(emailAddress string,
......
////////////////////////////////////////////////////////////////////////////////
// Copyright © 2019 Privategrity Corporation /
// /
// All rights reserved. /
////////////////////////////////////////////////////////////////////////////////
package api
import (
"crypto/rand"
"crypto/sha256"
"encoding/base64"
"github.com/pkg/errors"
"gitlab.com/elixxir/client/bots"
"gitlab.com/elixxir/client/globals"
"gitlab.com/elixxir/client/io"
"gitlab.com/elixxir/client/user"
"gitlab.com/elixxir/crypto/csprng"
"gitlab.com/elixxir/crypto/cyclic"
"gitlab.com/elixxir/crypto/hash"
"gitlab.com/elixxir/crypto/large"
"gitlab.com/elixxir/crypto/registration"
"gitlab.com/elixxir/crypto/signature/rsa"
"gitlab.com/elixxir/primitives/id"
"sync"
"time"
)
const SaltSize = 256
// RegisterWithPermissioning registers user with permissioning and returns the
// User ID. Returns an error if registration fails.
func (cl *Client) RegisterWithPermissioning(preCan bool, registrationCode, nick, email,
password string, privateKeyRSA *rsa.PrivateKey) (*id.User, error) {
if !preCan && cl.commManager.GetConnectionStatus() != io.Online {
return nil, errors.New("Cannot register when disconnected from the network")
}
var err error
var u *user.User
var UID *id.User
cl.opStatus(globals.REG_KEYGEN)
largeIntBits := 16
cmixGrp := cyclic.NewGroup(
large.NewIntFromString(cl.ndf.CMIX.Prime, largeIntBits),
large.NewIntFromString(cl.ndf.CMIX.Generator, largeIntBits))
e2eGrp := cyclic.NewGroup(
large.NewIntFromString(cl.ndf.E2E.Prime, largeIntBits),
large.NewIntFromString(cl.ndf.E2E.Generator, largeIntBits))
// Make CMIX keys array
nk := make(map[id.Node]user.NodeKeys)
// GENERATE CLIENT RSA KEYS
if privateKeyRSA == nil {
privateKeyRSA, err = rsa.GenerateKey(rand.Reader, rsa.DefaultRSABitLen)
if err != nil {
return nil, err
}
}
publicKeyRSA := privateKeyRSA.GetPublic()
cmixPrivKeyDHByte, err := csprng.GenerateInGroup(cmixGrp.GetPBytes(), 256, csprng.NewSystemRNG())
if err != nil {
return nil, errors.Errorf("Could not generate cmix DH private key: %s", err.Error())
}
cmixPrivateKeyDH := cmixGrp.NewIntFromBytes(cmixPrivKeyDHByte)
cmixPublicKeyDH := cmixGrp.ExpG(cmixPrivateKeyDH, cmixGrp.NewMaxInt())
e2ePrivKeyDHByte, err := csprng.GenerateInGroup(cmixGrp.GetPBytes(), 256, csprng.NewSystemRNG())
if err != nil {
return nil, errors.Errorf("Could not generate e2e DH private key: %s", err.Error())
}
e2ePrivateKeyDH := e2eGrp.NewIntFromBytes(e2ePrivKeyDHByte)
e2ePublicKeyDH := e2eGrp.ExpG(e2ePrivateKeyDH, e2eGrp.NewMaxInt())
// Initialized response from Registration Server
regValidationSignature := make([]byte, 0)
var salt []byte
// Handle precanned registration
if preCan {
cl.opStatus(globals.REG_PRECAN)
globals.Log.INFO.Printf("Registering precanned user...")
u, UID, nk, err = cl.precannedRegister(registrationCode, nick, nk)
if err != nil {
errMsg := errors.Errorf("Unable to complete precanned registration: %+v", err)
return id.ZeroID, errMsg
}
} else {
cl.opStatus(globals.REG_UID_GEN)
globals.Log.INFO.Printf("Registering dynamic user...")
// Generate salt for UserID
salt = make([]byte, SaltSize)
_, err = csprng.NewSystemRNG().Read(salt)
if err != nil {
errMsg := errors.Errorf("Register: Unable to generate salt! %s", err)
return id.ZeroID, errMsg
}
// Generate UserID by hashing salt and public key
UID = registration.GenUserID(publicKeyRSA, salt)
// If Registration Server is specified, contact it
// Only if registrationCode is set
globals.Log.INFO.Println("Register: Contacting registration server")
if cl.ndf.Registration.Address != "" && registrationCode != "" {
cl.opStatus(globals.REG_PERM)
regValidationSignature, err = cl.sendRegistrationMessage(registrationCode, publicKeyRSA)
if err != nil {
err = errors.Errorf("Register: Unable to send registration message: %+v", err)
return id.ZeroID, err
}
}
globals.Log.INFO.Println("Register: successfully passed Registration message")
var actualNick string
if nick != "" {
actualNick = nick
} else {
actualNick = base64.StdEncoding.EncodeToString(UID[:])
}
u = user.Users.NewUser(UID, actualNick)
user.Users.UpsertUser(u)
}
cl.opStatus(globals.REG_SECURE_STORE)
u.Email = email
// Create the user session
newSession := user.NewSession(cl.storage, u, nk, publicKeyRSA,
privateKeyRSA, cmixPublicKeyDH, cmixPrivateKeyDH, e2ePublicKeyDH,
e2ePrivateKeyDH, salt, cmixGrp, e2eGrp, password, regValidationSignature)
cl.opStatus(globals.REG_SAVE)
//set the registration state
err = newSession.SetRegState(user.PermissioningComplete)
if err != nil {
return id.ZeroID, errors.Wrap(err, "Permissioning Registration "+
"Failed")
}
// Store the user session
errStore := newSession.StoreSession()
if errStore != nil {
errMsg := errors.Errorf(
"Permissioning Register: could not register due to failed session save"+
": %s", errStore.Error())
return id.ZeroID, errMsg
}
cl.session = newSession
return UID, nil
}
// RegisterWithUDB uses the account's email to register with the UDB for
// User discovery. Must be called after Register and Connect.
// It will fail if the user has already registered with UDB
func (cl *Client) RegisterWithUDB(timeout time.Duration) error {
regState := cl.GetSession().GetRegState()
if regState != user.PermissioningComplete {
return errors.New("Cannot register with UDB when registration " +
"state is not PermissioningComplete")
}
status := cl.commManager.GetConnectionStatus()
if status == io.Connecting || status == io.Offline {
return errors.New("ERROR: could not RegisterWithUDB - connection is either offline or connecting")
}
email := cl.session.GetCurrentUser().Email
var err error
if email != "" {
globals.Log.INFO.Printf("Registering user as %s with UDB", email)
valueType := "EMAIL"
publicKeyBytes := cl.session.GetE2EDHPublicKey().Bytes()
err = bots.Register(valueType, email, publicKeyBytes, cl.opStatus, timeout)
if err == nil {
globals.Log.INFO.Printf("Registered with UDB!")
} else {
globals.Log.WARN.Printf("Could not register with UDB: %s", err)
}
} else {
globals.Log.INFO.Printf("Not registering with UDB because no " +
"email found")
}
if err != nil {
return errors.Wrap(err, "Could not register with UDB")
}
//set the registration state
err = cl.session.SetRegState(user.UDBComplete)
if err != nil {
return errors.Wrap(err, "UDB Registration Failed")
}
errStore := cl.session.StoreSession()
// FIXME If we have an error here, the session that gets created
// doesn't get immolated. Immolation should happen in a deferred
// call instead.
if errStore != nil {
errMsg := errors.Errorf(
"UDB Register: could not register due to failed session save"+
": %s", errStore.Error())
return errMsg
}
return nil
}
func (cl *Client) RegisterWithNodes() error {
session := cl.GetSession()
//Load Cmix keys & group
cmixDHPrivKey := session.GetCMIXDHPrivateKey()
cmixDHPubKey := session.GetCMIXDHPublicKey()
cmixGrp := session.GetCmixGroup()
//Load the rsa keys
rsaPubKey := session.GetRSAPublicKey()
rsaPrivKey := session.GetRSAPrivateKey()
//Load the user ID
UID := session.GetCurrentUser().User
//Load the registration signature
regSignature := session.GetRegistrationValidationSignature()
var wg sync.WaitGroup
errChan := make(chan error, len(cl.ndf.Gateways))
//Get the registered node keys
registeredNodes := session.GetNodes()
salt := session.GetSalt()
// This variable keeps track of whether there were new registrations
// required, thus requiring the state file to be saved again
newRegistrations := false
for i := range cl.ndf.Gateways {
localI := i
nodeID := *id.NewNodeFromBytes(cl.ndf.Nodes[i].ID)
//Register with node if the node has not been registered with already
if _, ok := registeredNodes[nodeID]; !ok {
wg.Add(1)
newRegistrations = true
go func() {
cl.registerWithNode(localI, salt, regSignature, UID, rsaPubKey, rsaPrivKey,
cmixDHPubKey, cmixDHPrivKey, cmixGrp, errChan)
wg.Done()
}()
}
}
wg.Wait()
//See if the registration returned errors at all
var errs error
for len(errChan) > 0 {
err := <-errChan
if errs != nil {
errs = errors.Wrap(errs, err.Error())
} else {
errs = err
}
}
//If an error every occurred, return with error
if errs != nil {
cl.opStatus(globals.REG_FAIL)
return errs
}
// Store the user session if there were changes during node registration
if newRegistrations {
errStore := session.StoreSession()
if errStore != nil {
err := errors.Errorf(
"Register: could not register due to failed session save"+
": %s", errStore.Error())
return err
}
}
return nil
}
//registerWithNode registers a user. It serves as a helper for Register
func (cl *Client) registerWithNode(index int, salt, registrationValidationSignature []byte, UID *id.User,
publicKeyRSA *rsa.PublicKey, privateKeyRSA *rsa.PrivateKey,
cmixPublicKeyDH, cmixPrivateKeyDH *cyclic.Int,
cmixGrp *cyclic.Group, errorChan chan error) {
gatewayID := id.NewNodeFromBytes(cl.ndf.Nodes[index].ID).NewGateway()
// Initialise blake2b hash for transmission keys and sha256 for reception
// keys
transmissionHash, _ := hash.NewCMixHash()
receptionHash := sha256.New()
// Request nonce message from gateway
globals.Log.INFO.Printf("Register: Requesting nonce from gateway %v/%v",
index+1, len(cl.ndf.Gateways))
nonce, dhPub, err := cl.requestNonce(salt, registrationValidationSignature, cmixPublicKeyDH,
publicKeyRSA, privateKeyRSA, gatewayID)
if err != nil {
errMsg := errors.Errorf("Register: Failed requesting nonce from gateway: %+v", err)
errorChan <- errMsg
}
// Load server DH pubkey
serverPubDH := cmixGrp.NewIntFromBytes(dhPub)
// Confirm received nonce
globals.Log.INFO.Println("Register: Confirming received nonce")
err = cl.confirmNonce(UID.Bytes(), nonce, privateKeyRSA, gatewayID)
if err != nil {
errMsg := errors.Errorf("Register: Unable to confirm nonce: %v", err)
errorChan <- errMsg
}
nodeID := cl.topology.GetNodeAtIndex(index)
key := user.NodeKeys{
TransmissionKey: registration.GenerateBaseKey(cmixGrp,
serverPubDH, cmixPrivateKeyDH, transmissionHash),
ReceptionKey: registration.GenerateBaseKey(cmixGrp, serverPubDH,
cmixPrivateKeyDH, receptionHash),
}
cl.session.PushNodeKey(nodeID, key)
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment