Exemple #1
0
        /// <summary>
        /// Processes StartConversationRequest message from client.
        /// <para>Initiates a conversation with the client provided that there is a common version of the protocol supported by both sides.</para>
        /// </summary>
        /// <param name="Client">Client that sent the request.</param>
        /// <param name="RequestMessage">Full request message.</param>
        /// <returns>Response message to be sent to the client.</returns>
        public ProxProtocolMessage ProcessMessageStartConversationRequest(IncomingClient Client, ProxProtocolMessage RequestMessage)
        {
            log.Trace("()");

            ProxProtocolMessage res = null;

            if (!CheckSessionConditions(Client, RequestMessage, null, ClientConversationStatus.NoConversation, out res))
            {
                log.Trace("(-):*.Response.Status={0}", res.Response.Status);
                return(res);
            }


            ProxMessageBuilder       messageBuilder           = Client.MessageBuilder;
            StartConversationRequest startConversationRequest = RequestMessage.Request.ConversationRequest.Start;

            byte[] clientChallenge = startConversationRequest.ClientChallenge.ToByteArray();
            byte[] pubKey          = startConversationRequest.PublicKey.ToByteArray();

            if (clientChallenge.Length == ProxMessageBuilder.ChallengeDataSize)
            {
                if ((0 < pubKey.Length) && (pubKey.Length <= ProtocolHelper.MaxPublicKeyLengthBytes))
                {
                    SemVer version;
                    if (GetCommonSupportedVersion(startConversationRequest.SupportedVersions, out version))
                    {
                        Client.PublicKey  = pubKey;
                        Client.IdentityId = Crypto.Sha256(Client.PublicKey);

                        if (clientList.AddNetworkPeerWithIdentity(Client))
                        {
                            Client.MessageBuilder.SetProtocolVersion(version);

                            byte[] challenge = new byte[ProxMessageBuilder.ChallengeDataSize];
                            Crypto.Rng.GetBytes(challenge);
                            Client.AuthenticationChallenge = challenge;
                            Client.ConversationStatus      = ClientConversationStatus.ConversationStarted;

                            log.Debug("Client {0} conversation status updated to {1}, selected version is '{2}', client public key set to '{3}', client identity ID set to '{4}', challenge set to '{5}'.",
                                      Client.RemoteEndPoint, Client.ConversationStatus, version, Client.PublicKey.ToHex(), Client.IdentityId.ToHex(), Client.AuthenticationChallenge.ToHex());

                            res = messageBuilder.CreateStartConversationResponse(RequestMessage, version, Config.Configuration.Keys.PublicKey, Client.AuthenticationChallenge, clientChallenge);
                        }
                        else
                        {
                            res = messageBuilder.CreateErrorInternalResponse(RequestMessage);
                        }
                    }
                    else
                    {
                        log.Warn("Client and server are incompatible in protocol versions.");
                        res = messageBuilder.CreateErrorUnsupportedResponse(RequestMessage);
                    }
                }
                else
                {
                    log.Warn("Client send public key of invalid length of {0} bytes.", pubKey.Length);
                    res = messageBuilder.CreateErrorInvalidValueResponse(RequestMessage, "publicKey");
                }
            }
            else
            {
                log.Warn("Client send clientChallenge, which is {0} bytes long, but it should be {1} bytes long.", clientChallenge.Length, ProxMessageBuilder.ChallengeDataSize);
                res = messageBuilder.CreateErrorInvalidValueResponse(RequestMessage, "clientChallenge");
            }

            log.Trace("(-):*.Response.Status={0}", res.Response.Status);
            return(res);
        }