From 387defa9fd0ae9f0035edd11760a61b93cc32b98 Mon Sep 17 00:00:00 2001 From: josh <josh@elixxir.io> Date: Wed, 29 Sep 2021 10:25:32 -0700 Subject: [PATCH] Implement new registration method --- api/mnemonic.go | 1 - go.mod | 4 +- go.sum | 4 + network/node/register.go | 206 ++++++++++++++++++++++++++++++++++----- 4 files changed, 189 insertions(+), 26 deletions(-) diff --git a/api/mnemonic.go b/api/mnemonic.go index 0ab1f2303..b885e912c 100644 --- a/api/mnemonic.go +++ b/api/mnemonic.go @@ -94,4 +94,3 @@ func LoadSecretWithMnemonic(mnemonic, path string) (secret []byte, err error) { return secret, nil } - diff --git a/go.mod b/go.mod index f1c1cf6bb..5b4e6e09c 100644 --- a/go.mod +++ b/go.mod @@ -17,8 +17,8 @@ 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.20210927221600-65a291f4e6a6 - gitlab.com/elixxir/crypto v0.0.7-0.20210920180151-6c9b84bae372 + gitlab.com/elixxir/comms v0.0.4-0.20210928204243-bcc6ba732877 + gitlab.com/elixxir/crypto v0.0.7-0.20210928232606-4f7feb90bee7 gitlab.com/elixxir/ekv v0.1.5 gitlab.com/elixxir/primitives v0.0.3-0.20210920180121-b85bca5212f4 gitlab.com/xx_network/comms v0.0.4-0.20210921011654-3b73a40ed3d6 diff --git a/go.sum b/go.sum index 39a2dd563..367f13987 100644 --- a/go.sum +++ b/go.sum @@ -261,10 +261,14 @@ gitlab.com/elixxir/comms v0.0.4-0.20210924220856-4864c21fe316 h1:PLGmuuaG5R1suI2 gitlab.com/elixxir/comms v0.0.4-0.20210924220856-4864c21fe316/go.mod h1:h41+FHc9zlQGveEao3aw8VSfzyOPecEhhUIadUsW1C8= gitlab.com/elixxir/comms v0.0.4-0.20210927221600-65a291f4e6a6 h1:draTda/SDnop2oCRfyWvu6hqC8G4i7BrVzfwZ7tDZls= gitlab.com/elixxir/comms v0.0.4-0.20210927221600-65a291f4e6a6/go.mod h1:h41+FHc9zlQGveEao3aw8VSfzyOPecEhhUIadUsW1C8= +gitlab.com/elixxir/comms v0.0.4-0.20210928204243-bcc6ba732877 h1:MpDU05tua291M8NH9FbxCzqmuyRsO2raOHtDQtJviao= +gitlab.com/elixxir/comms v0.0.4-0.20210928204243-bcc6ba732877/go.mod h1:h41+FHc9zlQGveEao3aw8VSfzyOPecEhhUIadUsW1C8= gitlab.com/elixxir/crypto v0.0.0-20200804182833-984246dea2c4/go.mod h1:ucm9SFKJo+K0N2GwRRpaNr+tKXMIOVWzmyUD0SbOu2c= gitlab.com/elixxir/crypto v0.0.3/go.mod h1:ZNgBOblhYToR4m8tj4cMvJ9UsJAUKq+p0gCp07WQmhA= gitlab.com/elixxir/crypto v0.0.7-0.20210920180151-6c9b84bae372 h1:W5Ax+cwqOOcsVegaMLvsFJ/Cs24a4Wyhp5UHFwvMQxo= gitlab.com/elixxir/crypto v0.0.7-0.20210920180151-6c9b84bae372/go.mod h1:9ipko6RwRCaF2H01PtCzGCjzWVex8/ZH2/vOK1qjjw4= +gitlab.com/elixxir/crypto v0.0.7-0.20210928232606-4f7feb90bee7 h1:03GKd/SLKnxeVSXdgX/QAzPtvdYcY5C/Fvt/lhTOlWk= +gitlab.com/elixxir/crypto v0.0.7-0.20210928232606-4f7feb90bee7/go.mod h1:9ipko6RwRCaF2H01PtCzGCjzWVex8/ZH2/vOK1qjjw4= gitlab.com/elixxir/ekv v0.1.5 h1:R8M1PA5zRU1HVnTyrtwybdABh7gUJSCvt1JZwUSeTzk= gitlab.com/elixxir/ekv v0.1.5/go.mod h1:e6WPUt97taFZe5PFLPb1Dupk7tqmDCTQu1kkstqJvw4= gitlab.com/elixxir/primitives v0.0.0-20200731184040-494269b53b4d/go.mod h1:OQgUZq7SjnE0b+8+iIAT2eqQF+2IFHn73tOo+aV11mg= diff --git a/network/node/register.go b/network/node/register.go index e295c967e..7fcd941b4 100644 --- a/network/node/register.go +++ b/network/node/register.go @@ -27,8 +27,10 @@ import ( "gitlab.com/elixxir/crypto/registration" "gitlab.com/xx_network/comms/connect" "gitlab.com/xx_network/comms/messages" + "gitlab.com/xx_network/crypto/chacha" "gitlab.com/xx_network/crypto/csprng" "gitlab.com/xx_network/crypto/signature/rsa" + "gitlab.com/xx_network/crypto/tls" "gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/netTime" "strconv" @@ -38,8 +40,14 @@ import ( type RegisterNodeCommsInterface interface { SendRequestClientKeyMessage(host *connect.Host, message *pb.SignedClientKeyRequest) (*pb.SignedKeyResponse, error) + + // ---------------------- Start of deprecated fields ----------- // + // TODO: Remove once RequestClientKey is properly tested + SendRequestNonceMessage(host *connect.Host, message *pb.NonceRequest) (*pb.Nonce, error) SendConfirmNonceMessage(host *connect.Host, message *pb.RequestRegistrationConfirmation) (*pb.RegistrationConfirmation, error) + // ---------------------- End of deprecated fields ----------- // + } func StartRegistration(sender *gateway.Sender, session *storage.Session, rngGen *fastRNG.StreamGenerator, comms RegisterNodeCommsInterface, @@ -124,32 +132,73 @@ func registerWithNode(sender *gateway.Sender, comms RegisterNodeCommsInterface, transmissionKey = store.GetGroup().NewIntFromBytes(h.Sum(nil)) jww.INFO.Printf("transmissionKey: %v", transmissionKey.Bytes()) } else { - // Initialise blake2b hash for transmission keys and reception - // keys - transmissionHash, _ := hash.NewCMixHash() - - nonce, dhPub, err := requestKey(sender, comms, gatewayID, regSig, + // Request key from server + signedKeyResponse, err := requestKey(sender, comms, gatewayID, regSig, registrationTimestampNano, uci, store, rng, stop) if err != nil { + // TODO: remove old codepath when new registration path is properly tested + jww.WARN.Printf("Databaseless registration failed, attempting soon "+ + "to be deprecated code path. Error: %v", err) + transmissionKey, err = registerDepreciated(sender, comms, regSig, + registrationTimestampNano, uci, store, rng, stop, gatewayID, nodeID) return errors.Errorf("Failed to request nonce: %+v", err) } - // Load server DH pubkey - serverPubDH := store.GetGroup().NewIntFromBytes(dhPub) + // Hash the response + opts := rsa.NewDefaultOptions() + h := opts.Hash.New() + h.Write(signedKeyResponse.KeyResponse) + hashedResponse := h.Sum(nil) + + // Load node certificate + nodeCert, err := tls.LoadCertificate(ngw.Node.TlsCertificate) + if err != nil { + return errors.WithMessagef(err, "Unable to load node's certificate") + } + + // Extract public key + nodePubKey, err := tls.ExtractPublicKey(nodeCert) + if err != nil { + return errors.WithMessagef(err, "Unable to load node's public key") + } - // Confirm received nonce - // fixme: need? I think this can be removed. I which case remove from comms as well - jww.INFO.Printf("Register: Confirming received nonce from node %s", nodeID.String()) - err = confirmNonce(sender, comms, uci.GetTransmissionID().Bytes(), - nonce, uci.GetTransmissionRSA(), gatewayID, stop) + // Verify the response signature + err = rsa.Verify(nodePubKey, opts.Hash, hashedResponse, + signedKeyResponse.KeyResponseSignedByNode.Signature, opts) + if err != nil { + return errors.WithMessagef(err, "Could not verify node's signature") + } + + // Unmarshal the response + keyResponse := &pb.ClientKeyResponse{} + err = proto.Unmarshal(signedKeyResponse.KeyResponse, keyResponse) + if err != nil { + return errors.WithMessagef(err, "Failed to unmarshal client key response") + } + + // Construct the session key + clientDhPub := store.GetDHPublicKey().Bytes() + h.Reset() + h.Write(keyResponse.NodeDHPubKey) + h.Write(clientDhPub) + sessionKey := h.Sum(nil) + + // Verify the HMAC + h.Reset() + if !registration.VerifyClientHMAC(sessionKey, keyResponse.EncryptedClientKey, + h, keyResponse.EncryptedClientKeyHMAC) { + return errors.WithMessagef(err, "Failed to verify client HMAC") + } + // Decrypt the client key + clientKey, err := chacha.Decrypt(sessionKey, keyResponse.EncryptedClientKey) if err != nil { - errMsg := fmt.Sprintf("Register: Unable to confirm nonce: %v", err) - return errors.New(errMsg) + return errors.WithMessagef(err, "Failed to decrypt client key") } - transmissionKey = registration.GenerateBaseKey(store.GetGroup(), - serverPubDH, store.GetDHPrivateKey(), transmissionHash) + + // Construct the transmission key from the client key + transmissionKey = store.GetGroup().NewIntFromBytes(clientKey) } store.Add(nodeID, transmissionKey) @@ -161,7 +210,7 @@ func registerWithNode(sender *gateway.Sender, comms RegisterNodeCommsInterface, func requestKey(sender *gateway.Sender, comms RegisterNodeCommsInterface, gwId *id.ID, regSig []byte, registrationTimestampNano int64, uci *user.CryptographicIdentity, - store *cmix.Store, rng csprng.Source, stop *stoppable.Single) (keyResponse, clientGatewayKey []byte, err error) { + store *cmix.Store, rng csprng.Source, stop *stoppable.Single) (keyResponse *pb.SignedKeyResponse, err error) { dhPub := store.GetDHPublicKey().Bytes() @@ -170,14 +219,14 @@ func requestKey(sender *gateway.Sender, comms RegisterNodeCommsInterface, gwId * ClientTransmissionConfirmation: &pb.SignedRegistrationConfirmation{ RegistrarSignature: &messages.RSASignature{Signature: regSig}, }, - ClientDHPubKey: dhPub, + ClientDHPubKey: dhPub, RegistrationTimestamp: registrationTimestampNano, - RequestTimestamp: netTime.Now().UnixNano(), + RequestTimestamp: netTime.Now().UnixNano(), } serializedMessage, err := proto.Marshal(keyRequest) if err != nil { - return nil, nil, err + return nil, err } opts := rsa.NewDefaultOptions() @@ -190,7 +239,7 @@ func requestKey(sender *gateway.Sender, comms RegisterNodeCommsInterface, gwId * clientSig, err := rsa.Sign(rng, uci.GetTransmissionRSA(), opts.Hash, data, opts) if err != nil { - return nil, nil, err + return nil, err } // Request nonce message from gateway @@ -212,22 +261,131 @@ func requestKey(sender *gateway.Sender, comms RegisterNodeCommsInterface, gwId * return nonceResponse, nil }, stop) + if err != nil { + return nil, err + } + + response := result.(*pb.SignedKeyResponse) + if response.Error != "" { + return nil, errors.New(response.Error) + } + + // Use Client keypair to sign Server nonce + return response, nil +} + +// ---------------------- Start of deprecated fields ----------- // + +// registerDepreciated is a DEPRECATED codepath that registers a user via +// the request/confirmNonce codepath. This is left for backward compatibility +// and will be removed. +// TODO: Remove this once RequestClientKey is properly tested +func registerDepreciated(sender *gateway.Sender, comms RegisterNodeCommsInterface, + regSig []byte, registrationTimestampNano int64, uci *user.CryptographicIdentity, + store *cmix.Store, rng csprng.Source, stop *stoppable.Single, + gatewayID, nodeID *id.ID) (*cyclic.Int, error) { + + jww.WARN.Printf("DEPRECATED: Registering using soon to be deprecated code path") + + transmissionHash, _ := hash.NewCMixHash() + + // Register nonce + nonce, dhPub, err := requestNonce(sender, comms, gatewayID, regSig, + registrationTimestampNano, uci, store, rng, stop) + if err != nil { + return nil, err + } + + // Load server DH pubkey + serverPubDH := store.GetGroup().NewIntFromBytes(dhPub) + + // Confirm received nonce + jww.INFO.Printf("Register: Confirming received nonce from node %s", nodeID.String()) + err = confirmNonce(sender, comms, uci.GetTransmissionID().Bytes(), + nonce, uci.GetTransmissionRSA(), gatewayID, stop) + + if err != nil { + errMsg := fmt.Sprintf("Register: Unable to confirm nonce: %v", err) + return nil, errors.New(errMsg) + } + transmissionKey := registration.GenerateBaseKey(store.GetGroup(), + serverPubDH, store.GetDHPrivateKey(), transmissionHash) + + return transmissionKey, err +} + +// WARNING DEPRECATED: requestNonce will soon be deprecated and removed. This will only +// be used for testing with backwards compatibility. +// TODO: Remove this once RequestClientKey is properly tested +func requestNonce(sender *gateway.Sender, comms RegisterNodeCommsInterface, gwId *id.ID, + regSig []byte, registrationTimestampNano int64, uci *user.CryptographicIdentity, + store *cmix.Store, rng csprng.Source, stop *stoppable.Single) ([]byte, []byte, error) { + + jww.WARN.Printf("DEPRECATED: Registering with a soon to be deprecated function") + + dhPub := store.GetDHPublicKey().Bytes() + opts := rsa.NewDefaultOptions() + opts.Hash = hash.CMixHash + h, _ := hash.NewCMixHash() + h.Write(dhPub) + data := h.Sum(nil) + + // Sign DH pubkey + clientSig, err := rsa.Sign(rng, uci.GetTransmissionRSA(), opts.Hash, + data, opts) + if err != nil { + return nil, nil, err + } + + // Request nonce message from gateway + jww.INFO.Printf("Register: Requesting nonce from gateway %v", gwId.String()) + + result, err := sender.SendToAny(func(host *connect.Host) (interface{}, error) { + nonceResponse, err := comms.SendRequestNonceMessage(host, + &pb.NonceRequest{ + Salt: uci.GetTransmissionSalt(), + ClientRSAPubKey: string(rsa.CreatePublicKeyPem(uci.GetTransmissionRSA().GetPublic())), + ClientSignedByServer: &messages.RSASignature{ + Signature: regSig, + }, + ClientDHPubKey: dhPub, + RequestSignature: &messages.RSASignature{ + Signature: clientSig, + }, + Target: gwId.Marshal(), + // Timestamp in which user has registered with registration + TimeStamp: registrationTimestampNano, + }) + if err != nil { + return nil, errors.WithMessage(err, "Register: Failed requesting nonce from gateway") + } + if nonceResponse.Error != "" { + return nil, errors.WithMessage(err, "requestNonce: nonceResponse error") + } + return nonceResponse, nil + }, stop) + if err != nil { return nil, nil, err } - nonceResponse := result.(*pb.SignedKeyResponse) + nonceResponse := result.(*pb.Nonce) // Use Client keypair to sign Server nonce - return nonceResponse.KeyResponse, nonceResponse.ClientGatewayKey, nil + return nonceResponse.Nonce, nonceResponse.DHPubKey, nil } +// WARNING DEPRECATED: confirmNonce will soon be deprecated and removed. This will only +// be used for testing with backwards compatibility. // confirmNonce is a helper for the Register function // It signs a nonce and sends it for confirmation // Returns nil if successful, error otherwise +// TODO: Remove this once RequestClientKey is properly tested func confirmNonce(sender *gateway.Sender, comms RegisterNodeCommsInterface, UID, nonce []byte, privateKeyRSA *rsa.PrivateKey, gwID *id.ID, stop *stoppable.Single) error { + jww.WARN.Printf("DEPRECATED: ConfirmNonce is a soon to be deprecated function") + opts := rsa.NewDefaultOptions() opts.Hash = hash.CMixHash h, _ := hash.NewCMixHash() @@ -270,3 +428,5 @@ func confirmNonce(sender *gateway.Sender, comms RegisterNodeCommsInterface, UID, return err } + +// ---------------------- End of deprecated fields ----------- // -- GitLab