Example #1
0
        internal static void HandleClientRPCRequest(ulong clientId, Stream stream, string channelName, SecuritySendFlags security)
        {
            using (PooledBitReader reader = PooledBitReader.Get(stream))
            {
                ulong  networkId   = reader.ReadUInt64Packed();
                ushort behaviourId = reader.ReadUInt16Packed();
                ulong  hash        = reader.ReadUInt64Packed();
                ulong  responseId  = reader.ReadUInt64Packed();

                if (SpawnManager.SpawnedObjects.ContainsKey(networkId))
                {
                    NetworkedBehaviour behaviour = SpawnManager.SpawnedObjects[networkId].GetBehaviourAtOrderIndex(behaviourId);
                    if (behaviour != null)
                    {
                        object result = behaviour.OnRemoteClientRPC(hash, clientId, stream);

                        using (PooledBitStream responseStream = PooledBitStream.Get())
                        {
                            using (PooledBitWriter responseWriter = PooledBitWriter.Get(responseStream))
                            {
                                responseWriter.WriteUInt64Packed(responseId);
                                responseWriter.WriteObjectPacked(result);
                            }

                            InternalMessageHandler.Send(clientId, MLAPIConstants.MLAPI_CLIENT_RPC_RESPONSE, channelName, responseStream, security, null);
                        }
                    }
                }
            }
        }
        // Runs on client
        internal static void HandleHailRequest(uint clientId, Stream stream, int channelId)
        {
            X509Certificate2 certificate = null;

            byte[] serverDiffieHellmanPublicPart = null;
            using (PooledBitReader reader = PooledBitReader.Get(stream))
            {
                if (netManager.NetworkConfig.EnableEncryption)
                {
                    // Read the certificate
                    if (netManager.NetworkConfig.SignKeyExchange)
                    {
                        // Allocation justification: This runs on client and only once, at initial connection
                        certificate = new X509Certificate2(reader.ReadByteArray());
                        if (CryptographyHelper.VerifyCertificate(certificate, netManager.ConnectedHostname))
                        {
                            // The certificate is not valid :(
                            // Man in the middle.
                            if (LogHelper.CurrentLogLevel <= LogLevel.Normal)
                            {
                                if (LogHelper.CurrentLogLevel <= LogLevel.Normal)
                                {
                                    LogHelper.LogWarning("Invalid certificate. Disconnecting");
                                }
                            }
                            netManager.StopClient();
                            return;
                        }
                        else
                        {
                            netManager.NetworkConfig.ServerX509Certificate = certificate;
                        }
                    }

                    // Read the ECDH
                    // Allocation justification: This runs on client and only once, at initial connection
                    serverDiffieHellmanPublicPart = reader.ReadByteArray();

                    // Verify the key exchange
                    if (netManager.NetworkConfig.SignKeyExchange)
                    {
                        byte[] serverDiffieHellmanPublicPartSignature = reader.ReadByteArray();

                        RSACryptoServiceProvider rsa = certificate.PublicKey.Key as RSACryptoServiceProvider;

                        if (rsa != null)
                        {
                            using (SHA256Managed sha = new SHA256Managed())
                            {
                                if (!rsa.VerifyData(serverDiffieHellmanPublicPart, sha, serverDiffieHellmanPublicPartSignature))
                                {
                                    if (LogHelper.CurrentLogLevel <= LogLevel.Normal)
                                    {
                                        if (LogHelper.CurrentLogLevel <= LogLevel.Normal)
                                        {
                                            LogHelper.LogWarning("Invalid signature. Disconnecting");
                                        }
                                    }
                                    netManager.StopClient();
                                    return;
                                }
                            }
                        }
                    }
                }
            }

            using (PooledBitStream outStream = PooledBitStream.Get())
            {
                using (PooledBitWriter writer = PooledBitWriter.Get(outStream))
                {
                    if (netManager.NetworkConfig.EnableEncryption)
                    {
                        // Create a ECDH key
                        EllipticDiffieHellman diffieHellman = new EllipticDiffieHellman(EllipticDiffieHellman.DEFAULT_CURVE, EllipticDiffieHellman.DEFAULT_GENERATOR, EllipticDiffieHellman.DEFAULT_ORDER);
                        netManager.clientAesKey = diffieHellman.GetSharedSecret(serverDiffieHellmanPublicPart);
                        byte[] diffieHellmanPublicKey = diffieHellman.GetPublicKey();
                        writer.WriteByteArray(diffieHellmanPublicKey);
                        if (netManager.NetworkConfig.SignKeyExchange)
                        {
                            RSACryptoServiceProvider rsa = certificate.PublicKey.Key as RSACryptoServiceProvider;

                            if (rsa != null)
                            {
                                using (SHA256CryptoServiceProvider sha = new SHA256CryptoServiceProvider())
                                {
                                    writer.WriteByteArray(rsa.Encrypt(sha.ComputeHash(diffieHellmanPublicKey), false));
                                }
                            }
                            else
                            {
                                throw new CryptographicException("[MLAPI] Only RSA certificates are supported. No valid RSA key was found");
                            }
                        }
                    }
                }
                // Send HailResponse
                InternalMessageHandler.Send(NetworkingManager.Singleton.ServerClientId, MLAPIConstants.MLAPI_CERTIFICATE_HAIL_RESPONSE, "MLAPI_INTERNAL", outStream, SecuritySendFlags.None, true);
            }
        }
        // Ran on server
        internal static void HandleHailResponse(uint clientId, Stream stream, int channelId)
        {
            if (!netManager.PendingClients.ContainsKey(clientId) || netManager.PendingClients[clientId].ConnectionState != PendingClient.State.PendingHail)
            {
                return;
            }
            if (!netManager.NetworkConfig.EnableEncryption)
            {
                return;
            }

            using (PooledBitReader reader = PooledBitReader.Get(stream))
            {
                if (NetworkingManager.Singleton.PendingClients[clientId].KeyExchange != null)
                {
                    byte[] diffieHellmanPublic = reader.ReadByteArray();
                    netManager.PendingClients[clientId].AesKey = netManager.PendingClients[clientId].KeyExchange.GetSharedSecret(diffieHellmanPublic);
                    if (netManager.NetworkConfig.SignKeyExchange)
                    {
                        byte[]                   diffieHellmanPublicSignature = reader.ReadByteArray();
                        X509Certificate2         certificate = netManager.NetworkConfig.ServerX509Certificate;
                        RSACryptoServiceProvider rsa         = certificate.PrivateKey as RSACryptoServiceProvider;

                        if (rsa != null)
                        {
                            using (SHA256Managed sha = new SHA256Managed())
                            {
                                byte[] clientHash = rsa.Decrypt(diffieHellmanPublicSignature, false);
                                byte[] serverHash = sha.ComputeHash(diffieHellmanPublic);
                                if (clientHash.Length != serverHash.Length)
                                {
                                    //Man in the middle.
                                    if (LogHelper.CurrentLogLevel <= LogLevel.Normal)
                                    {
                                        if (LogHelper.CurrentLogLevel <= LogLevel.Normal)
                                        {
                                            LogHelper.LogWarning("Signature length doesnt match for the key exchange public part. Disconnecting");
                                        }
                                    }
                                    netManager.DisconnectClient(clientId);
                                    return;
                                }
                                for (int i = 0; i < clientHash.Length; i++)
                                {
                                    if (clientHash[i] != serverHash[i])
                                    {
                                        //Man in the middle.
                                        if (LogHelper.CurrentLogLevel <= LogLevel.Normal)
                                        {
                                            if (LogHelper.CurrentLogLevel <= LogLevel.Normal)
                                            {
                                                LogHelper.LogWarning("Signature doesnt match for the key exchange public part. Disconnecting");
                                            }
                                        }
                                        netManager.DisconnectClient(clientId);
                                        return;
                                    }
                                }
                            }
                        }
                        else
                        {
                            throw new CryptographicException("[MLAPI] Only RSA certificates are supported. No valid RSA key was found");
                        }
                    }
                }
            }

            netManager.PendingClients[clientId].ConnectionState = PendingClient.State.PendingConnection;
            netManager.PendingClients[clientId].KeyExchange     = null; // Give to GC

            // Send greetings, they have passed all the handshakes
            using (PooledBitStream outStream = PooledBitStream.Get())
            {
                using (PooledBitWriter writer = PooledBitWriter.Get(outStream))
                {
                    writer.WriteInt64Packed(DateTime.Now.Ticks); // This serves no purpose.
                }
                InternalMessageHandler.Send(clientId, MLAPIConstants.MLAPI_GREETINGS, "MLAPI_INTERNAL", outStream, SecuritySendFlags.None, true);
            }
        }