Пример #1
0
        public void AddIdentity(string identity, byte[] key)
        {
            PSKIdentity pskIdentity = new PSKIdentity()
            {
                Identity = Encoding.UTF8.GetBytes(identity), Key = key
            };

            _Identities.Add(pskIdentity.Identity, pskIdentity);
        }
Пример #2
0
        public void AddIdentity(byte[] identity, byte[] key)
        {
            PSKIdentity pskIdentity = new PSKIdentity()
            {
                Identity = identity, Key = key
            };

            _Identities.Add(pskIdentity.Identity, pskIdentity);
        }
Пример #3
0
        internal PSKIdentity GetRandom()
        {
            PSKIdentity result = null;

            if (_Identities.Count > 0)
            {
                Random random = new Random();
                int    index  = random.Next(_Identities.Count);
                int    count  = 0;
                foreach (byte[] identity in _Identities.Keys)
                {
                    if (count == index)
                    {
                        _Identities.TryGetValue(identity, out result);
                        break;
                    }
                    count++;
                }
            }
            return(result);
        }
Пример #4
0
        private void ProcessHandshake(DTLSRecord record)
        {
            byte[] data;
            if (_EncyptedServerEpoch.HasValue && (_EncyptedServerEpoch.Value == record.Epoch))
            {
                int count = 0;
                while ((_Cipher == null) && (count < 500))
                {
                    System.Threading.Thread.Sleep(10);
                    count++;
                }

                if (_Cipher == null)
                {
                    throw new Exception();
                }


                if (_Cipher != null)
                {
                    long sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber;
                    data = _Cipher.DecodeCiphertext(sequenceNumber, (byte)TRecordType.Handshake, record.Fragment, 0, record.Fragment.Length);
                }
                else
                {
                    data = record.Fragment;
                }
            }
            else
            {
                data = record.Fragment;
            }

            using (MemoryStream stream = new MemoryStream(data))
            {
                HandshakeRecord handshakeRecord = HandshakeRecord.Deserialise(stream);
                if (handshakeRecord != null)
                {
#if DEBUG
                    Console.WriteLine(handshakeRecord.MessageType.ToString());
#endif
                    switch (handshakeRecord.MessageType)
                    {
                    case THandshakeType.HelloRequest:
                        break;

                    case THandshakeType.ClientHello:
                        break;

                    case THandshakeType.ServerHello:
                        ServerHello serverHello = ServerHello.Deserialise(stream);
                        if (serverHello != null)
                        {
                            _ServerEpoch = record.Epoch;
                            _HandshakeInfo.UpdateHandshakeHash(data);
                            _HandshakeInfo.CipherSuite  = (TCipherSuite)serverHello.CipherSuite;
                            _HandshakeInfo.ServerRandom = serverHello.Random;
                            Version version = SupportedVersion;
                            if (serverHello.ServerVersion < version)
                            {
                                version = serverHello.ServerVersion;
                            }
                            _Version = version;
                        }
                        break;

                    case THandshakeType.HelloVerifyRequest:
                        HelloVerifyRequest helloVerifyRequest = HelloVerifyRequest.Deserialise(stream);
                        if (helloVerifyRequest != null)
                        {
                            _Version = helloVerifyRequest.ServerVersion;
                            SendHello(helloVerifyRequest.Cookie);
                        }
                        break;

                    case THandshakeType.Certificate:
                        _HandshakeInfo.UpdateHandshakeHash(data);
                        break;

                    case THandshakeType.ServerKeyExchange:
                        _HandshakeInfo.UpdateHandshakeHash(data);
                        TKeyExchangeAlgorithm keyExchangeAlgorithm = CipherSuites.GetKeyExchangeAlgorithm(_HandshakeInfo.CipherSuite);
                        byte[]       preMasterSecret = null;
                        IKeyExchange keyExchange     = null;
                        if (keyExchangeAlgorithm == TKeyExchangeAlgorithm.ECDHE_ECDSA)
                        {
                            ECDHEServerKeyExchange serverKeyExchange = ECDHEServerKeyExchange.Deserialise(stream, _Version);
                            ECDHEKeyExchange       keyExchangeECDHE  = new ECDHEKeyExchange
                            {
                                CipherSuite          = _HandshakeInfo.CipherSuite,
                                Curve                = serverKeyExchange.EllipticCurve,
                                KeyExchangeAlgorithm = keyExchangeAlgorithm,
                                ClientRandom         = _HandshakeInfo.ClientRandom,
                                ServerRandom         = _HandshakeInfo.ServerRandom
                            };
                            keyExchangeECDHE.GenerateEphemeralKey();
                            ECDHEClientKeyExchange clientKeyExchange = new ECDHEClientKeyExchange(keyExchangeECDHE.PublicKey);
                            _ClientKeyExchange = clientKeyExchange;
                            preMasterSecret    = keyExchangeECDHE.GetPreMasterSecret(serverKeyExchange.PublicKeyBytes);
                            keyExchange        = keyExchangeECDHE;
                        }
                        else if (keyExchangeAlgorithm == TKeyExchangeAlgorithm.ECDHE_PSK)
                        {
                            ECDHEPSKServerKeyExchange serverKeyExchange = ECDHEPSKServerKeyExchange.Deserialise(stream, _Version);
                            ECDHEKeyExchange          keyExchangeECDHE  = new ECDHEKeyExchange
                            {
                                CipherSuite          = _HandshakeInfo.CipherSuite,
                                Curve                = serverKeyExchange.EllipticCurve,
                                KeyExchangeAlgorithm = keyExchangeAlgorithm,
                                ClientRandom         = _HandshakeInfo.ClientRandom,
                                ServerRandom         = _HandshakeInfo.ServerRandom
                            };
                            keyExchangeECDHE.GenerateEphemeralKey();
                            ECDHEPSKClientKeyExchange clientKeyExchange = new ECDHEPSKClientKeyExchange(keyExchangeECDHE.PublicKey);
                            if (serverKeyExchange.PSKIdentityHint != null)
                            {
                                byte[] key = _PSKIdentities.GetKey(serverKeyExchange.PSKIdentityHint);
                                if (key != null)
                                {
                                    _PSKIdentity = new PSKIdentity()
                                    {
                                        Identity = serverKeyExchange.PSKIdentityHint, Key = key
                                    }
                                }
                                ;
                            }
                            if (_PSKIdentity == null)
                            {
                                _PSKIdentity = _PSKIdentities.GetRandom();
                            }
                            clientKeyExchange.PSKIdentity = _PSKIdentity.Identity;
                            _ClientKeyExchange            = clientKeyExchange;
                            byte[] otherSecret = keyExchangeECDHE.GetPreMasterSecret(serverKeyExchange.PublicKeyBytes);
                            preMasterSecret = TLSUtils.GetPSKPreMasterSecret(otherSecret, _PSKIdentity.Key);
                            keyExchange     = keyExchangeECDHE;
                        }
                        else if (keyExchangeAlgorithm == TKeyExchangeAlgorithm.PSK)
                        {
                            PSKServerKeyExchange serverKeyExchange = PSKServerKeyExchange.Deserialise(stream, _Version);
                            PSKClientKeyExchange clientKeyExchange = new PSKClientKeyExchange();
                            if (serverKeyExchange.PSKIdentityHint != null)
                            {
                                byte[] key = _PSKIdentities.GetKey(serverKeyExchange.PSKIdentityHint);
                                if (key != null)
                                {
                                    _PSKIdentity = new PSKIdentity()
                                    {
                                        Identity = serverKeyExchange.PSKIdentityHint, Key = key
                                    }
                                }
                                ;
                            }
                            if (_PSKIdentity == null)
                            {
                                _PSKIdentity = _PSKIdentities.GetRandom();
                            }
                            byte[] otherSecret = new byte[_PSKIdentity.Key.Length];
                            clientKeyExchange.PSKIdentity = _PSKIdentity.Identity;
                            _ClientKeyExchange            = clientKeyExchange;
                            preMasterSecret = TLSUtils.GetPSKPreMasterSecret(otherSecret, _PSKIdentity.Key);
                        }
                        _Cipher = TLSUtils.AssignCipher(preMasterSecret, true, _Version, _HandshakeInfo);

                        break;

                    case THandshakeType.CertificateRequest:
                        _HandshakeInfo.UpdateHandshakeHash(data);
                        _SendCertificate = true;
                        break;

                    case THandshakeType.ServerHelloDone:
                        _HandshakeInfo.UpdateHandshakeHash(data);
                        if (_Cipher == null)
                        {
                            keyExchangeAlgorithm = CipherSuites.GetKeyExchangeAlgorithm(_HandshakeInfo.CipherSuite);
                            if (keyExchangeAlgorithm == TKeyExchangeAlgorithm.PSK)
                            {
                                PSKClientKeyExchange clientKeyExchange = new PSKClientKeyExchange();
                                _PSKIdentity = _PSKIdentities.GetRandom();
                                byte[] otherSecret = new byte[_PSKIdentity.Key.Length];
                                clientKeyExchange.PSKIdentity = _PSKIdentity.Identity;
                                _ClientKeyExchange            = clientKeyExchange;
                                preMasterSecret = TLSUtils.GetPSKPreMasterSecret(otherSecret, _PSKIdentity.Key);
                                _Cipher         = TLSUtils.AssignCipher(preMasterSecret, true, _Version, _HandshakeInfo);
                            }
                        }

                        if (_SendCertificate)
                        {
                            SendHandshakeMessage(_Certificate, false);
                        }
                        SendHandshakeMessage(_ClientKeyExchange, false);
                        if (_SendCertificate)
                        {
                            CertificateVerify certificateVerify = new CertificateVerify();
                            byte[]            signatureHash     = _HandshakeInfo.GetHash();
                            certificateVerify.SignatureHashAlgorithm = new SignatureHashAlgorithm()
                            {
                                Signature = TSignatureAlgorithm.ECDSA, Hash = THashAlgorithm.SHA256
                            };
                            certificateVerify.Signature = TLSUtils.Sign(_PrivateKey, true, _Version, _HandshakeInfo, certificateVerify.SignatureHashAlgorithm, signatureHash);
                            SendHandshakeMessage(certificateVerify, false);
                        }
                        SendChangeCipherSpec();
                        byte[]   handshakeHash = _HandshakeInfo.GetHash();
                        Finished finished      = new Finished
                        {
                            VerifyData = TLSUtils.GetVerifyData(_Version, _HandshakeInfo, true, true, handshakeHash)
                        };
                        SendHandshakeMessage(finished, true);
#if DEBUG
                        Console.Write($"Handshake Hash: {TLSUtils.WriteToString(handshakeHash)}");
                        Console.Write($"Sent Verify: {TLSUtils.WriteToString(finished.VerifyData)}");
#endif
                        break;

                    case THandshakeType.CertificateVerify:
                        break;

                    case THandshakeType.ClientKeyExchange:
                        break;

                    case THandshakeType.Finished:
                        Finished serverFinished = Finished.Deserialise(stream);
                        handshakeHash = _HandshakeInfo.GetHash();
                        byte[] calculatedVerifyData = TLSUtils.GetVerifyData(_Version, _HandshakeInfo, true, false, handshakeHash);
#if DEBUG
                        Console.Write("$Recieved Verify: {TLSUtils.WriteToString(serverFinished.VerifyData)}");
                        Console.Write($"Calc Verify: {TLSUtils.WriteToString(calculatedVerifyData)}");
#endif
                        if (TLSUtils.ByteArrayCompare(serverFinished.VerifyData, calculatedVerifyData))
                        {
#if DEBUG
                            Console.WriteLine("Handshake Complete");
#endif
                            _Connected.Set();
                        }
                        break;

                    default:
                        break;
                    }
                }
            }
        }
Пример #5
0
        private async Task _ProcessHandshakeAsync(DTLSRecord record)
        {
            if (record == null)
            {
                throw new ArgumentNullException(nameof(record));
            }

            var data = record.Fragment;

            if (this._EncyptedServerEpoch == record.Epoch)
            {
                var count = 0;
                while ((this._Cipher == null) && (count < 500))
                {
                    await Task.Delay(10).ConfigureAwait(false);

                    count++;
                }

                if (this._Cipher == null)
                {
                    throw new Exception("Need Cipher for Encrypted Session");
                }

                var sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber;
                data = this._Cipher.DecodeCiphertext(sequenceNumber, (byte)TRecordType.Handshake, record.Fragment, 0, record.Fragment.Length);
            }

            using (var tempStream = new MemoryStream(data))
            {
                var handshakeRec = HandshakeRecord.Deserialise(tempStream);
                if (handshakeRec.Length > (handshakeRec.FragmentLength + handshakeRec.FragmentOffset))
                {
                    this._IsFragment = true;
                    this._FragmentedRecordList.Add(data);
                    return;
                }
                else if (this._IsFragment)
                {
                    this._FragmentedRecordList.Add(data);
                    data = new byte[0];
                    foreach (var rec in this._FragmentedRecordList)
                    {
                        data = data.Concat(rec.Skip(HandshakeRecord.RECORD_OVERHEAD)).ToArray();
                    }

                    var tempHandshakeRec = new HandshakeRecord()
                    {
                        Length         = handshakeRec.Length,
                        MessageSeq     = handshakeRec.MessageSeq,
                        MessageType    = handshakeRec.MessageType,
                        FragmentLength = handshakeRec.Length,
                        FragmentOffset = 0
                    };

                    var tempHandshakeBytes = new byte[HandshakeRecord.RECORD_OVERHEAD];
                    using (var updateStream = new MemoryStream(tempHandshakeBytes))
                    {
                        tempHandshakeRec.Serialise(updateStream);
                    }

                    data = tempHandshakeBytes.Concat(data).ToArray();
                }
            }

            using (var stream = new MemoryStream(data))
            {
                var handshakeRecord = HandshakeRecord.Deserialise(stream);
                switch (handshakeRecord.MessageType)
                {
                case THandshakeType.HelloRequest:
                {
                    break;
                }

                case THandshakeType.ClientHello:
                {
                    break;
                }

                case THandshakeType.ServerHello:
                {
                    var serverHello = ServerHello.Deserialise(stream);
                    this._HandshakeInfo.UpdateHandshakeHash(data);
                    this._ServerEpoch = record.Epoch;
                    this._HandshakeInfo.CipherSuite  = (TCipherSuite)serverHello.CipherSuite;
                    this._HandshakeInfo.ServerRandom = serverHello.Random;
                    this._Version = serverHello.ServerVersion <= this._Version ? serverHello.ServerVersion : _SupportedVersion;
                    break;
                }

                case THandshakeType.HelloVerifyRequest:
                {
                    var helloVerifyRequest = HelloVerifyRequest.Deserialise(stream);
                    this._Version = helloVerifyRequest.ServerVersion;
                    await this._SendHelloAsync(helloVerifyRequest.Cookie).ConfigureAwait(false);

                    break;
                }

                case THandshakeType.Certificate:
                {
                    var cert = Certificate.Deserialise(stream, TCertificateType.X509);
                    this._HandshakeInfo.UpdateHandshakeHash(data);
                    this.ServerCertificate = cert.Cert;
                    break;
                }

                case THandshakeType.ServerKeyExchange:
                {
                    this._HandshakeInfo.UpdateHandshakeHash(data);
                    var          keyExchangeAlgorithm = CipherSuites.GetKeyExchangeAlgorithm(this._HandshakeInfo.CipherSuite);
                    byte[]       preMasterSecret      = null;
                    IKeyExchange keyExchange          = null;
                    if (keyExchangeAlgorithm == TKeyExchangeAlgorithm.ECDHE_ECDSA)
                    {
                        var serverKeyExchange = ECDHEServerKeyExchange.Deserialise(stream, this._Version);
                        var keyExchangeECDHE  = new ECDHEKeyExchange
                        {
                            CipherSuite          = this._HandshakeInfo.CipherSuite,
                            Curve                = serverKeyExchange.EllipticCurve,
                            KeyExchangeAlgorithm = keyExchangeAlgorithm,
                            ClientRandom         = this._HandshakeInfo.ClientRandom,
                            ServerRandom         = this._HandshakeInfo.ServerRandom
                        };
                        keyExchangeECDHE.GenerateEphemeralKey();
                        var clientKeyExchange = new ECDHEClientKeyExchange(keyExchangeECDHE.PublicKey);
                        this._ClientKeyExchange = clientKeyExchange;
                        preMasterSecret         = keyExchangeECDHE.GetPreMasterSecret(serverKeyExchange.PublicKeyBytes);
                        keyExchange             = keyExchangeECDHE;
                    }
                    else if (keyExchangeAlgorithm == TKeyExchangeAlgorithm.ECDHE_PSK)
                    {
                        var serverKeyExchange = ECDHEPSKServerKeyExchange.Deserialise(stream);
                        var keyExchangeECDHE  = new ECDHEKeyExchange
                        {
                            CipherSuite          = this._HandshakeInfo.CipherSuite,
                            Curve                = serverKeyExchange.EllipticCurve,
                            KeyExchangeAlgorithm = keyExchangeAlgorithm,
                            ClientRandom         = this._HandshakeInfo.ClientRandom,
                            ServerRandom         = this._HandshakeInfo.ServerRandom
                        };
                        keyExchangeECDHE.GenerateEphemeralKey();
                        var clientKeyExchange = new ECDHEPSKClientKeyExchange(keyExchangeECDHE.PublicKey);
                        if (serverKeyExchange.PSKIdentityHint != null)
                        {
                            var key = this.PSKIdentities.GetKey(serverKeyExchange.PSKIdentityHint);
                            if (key != null)
                            {
                                this._PSKIdentity = new PSKIdentity()
                                {
                                    Identity = serverKeyExchange.PSKIdentityHint, Key = key
                                };
                            }
                        }
                        if (this._PSKIdentity == null)
                        {
                            this._PSKIdentity = this.PSKIdentities.GetRandom();
                        }

                        clientKeyExchange.PSKIdentity = this._PSKIdentity.Identity;
                        this._ClientKeyExchange       = clientKeyExchange;
                        var otherSecret = keyExchangeECDHE.GetPreMasterSecret(serverKeyExchange.PublicKeyBytes);
                        preMasterSecret = TLSUtils.GetPSKPreMasterSecret(otherSecret, this._PSKIdentity.Key);
                        keyExchange     = keyExchangeECDHE;
                    }
                    else if (keyExchangeAlgorithm == TKeyExchangeAlgorithm.PSK)
                    {
                        var serverKeyExchange = PSKServerKeyExchange.Deserialise(stream);
                        var clientKeyExchange = new PSKClientKeyExchange();
                        if (serverKeyExchange.PSKIdentityHint != null)
                        {
                            var key = this.PSKIdentities.GetKey(serverKeyExchange.PSKIdentityHint);
                            if (key != null)
                            {
                                this._PSKIdentity = new PSKIdentity()
                                {
                                    Identity = serverKeyExchange.PSKIdentityHint, Key = key
                                };
                            }
                        }
                        if (this._PSKIdentity == null)
                        {
                            this._PSKIdentity = this.PSKIdentities.GetRandom();
                        }

                        var otherSecret = new byte[this._PSKIdentity.Key.Length];
                        clientKeyExchange.PSKIdentity = this._PSKIdentity.Identity;
                        this._ClientKeyExchange       = clientKeyExchange;
                        preMasterSecret = TLSUtils.GetPSKPreMasterSecret(otherSecret, this._PSKIdentity.Key);
                    }
                    this._Cipher = TLSUtils.AssignCipher(preMasterSecret, true, this._Version, this._HandshakeInfo);
                    break;
                }

                case THandshakeType.CertificateRequest:
                {
                    this._HandshakeInfo.UpdateHandshakeHash(data);
                    this._SendCertificate = true;
                    break;
                }

                case THandshakeType.ServerHelloDone:
                {
                    this._HandshakeInfo.UpdateHandshakeHash(data);
                    var keyExchangeAlgorithm = CipherSuites.GetKeyExchangeAlgorithm(this._HandshakeInfo.CipherSuite);
                    if (this._Cipher == null)
                    {
                        if (keyExchangeAlgorithm == TKeyExchangeAlgorithm.PSK)
                        {
                            var clientKeyExchange = new PSKClientKeyExchange();
                            this._PSKIdentity = this.PSKIdentities.GetRandom();
                            var otherSecret = new byte[this._PSKIdentity.Key.Length];
                            clientKeyExchange.PSKIdentity = this._PSKIdentity.Identity;
                            this._ClientKeyExchange       = clientKeyExchange;
                            var preMasterSecret = TLSUtils.GetPSKPreMasterSecret(otherSecret, this._PSKIdentity.Key);
                            this._Cipher = TLSUtils.AssignCipher(preMasterSecret, true, this._Version, this._HandshakeInfo);
                        }
                        else if (keyExchangeAlgorithm == TKeyExchangeAlgorithm.RSA)
                        {
                            var clientKeyExchange = new RSAClientKeyExchange();
                            this._ClientKeyExchange = clientKeyExchange;
                            var PreMasterSecret = TLSUtils.GetRsaPreMasterSecret(this._Version);
                            clientKeyExchange.PremasterSecret = TLSUtils.GetEncryptedRsaPreMasterSecret(this.ServerCertificate, PreMasterSecret);
                            this._Cipher = TLSUtils.AssignCipher(PreMasterSecret, true, this._Version, this._HandshakeInfo);
                        }
                        else
                        {
                            throw new NotImplementedException($"Key Exchange Algorithm {keyExchangeAlgorithm} Not Implemented");
                        }
                    }

                    if (this._SendCertificate)
                    {
                        await this._SendHandshakeMessageAsync(this._Certificate, false).ConfigureAwait(false);
                    }

                    await this._SendHandshakeMessageAsync(this._ClientKeyExchange, false).ConfigureAwait(false);

                    if (this._SendCertificate)
                    {
                        var signatureHashAlgorithm = new SignatureHashAlgorithm()
                        {
                            Signature = TSignatureAlgorithm.ECDSA, Hash = THashAlgorithm.SHA256
                        };
                        if (keyExchangeAlgorithm == TKeyExchangeAlgorithm.RSA)
                        {
                            signatureHashAlgorithm = new SignatureHashAlgorithm()
                            {
                                Signature = TSignatureAlgorithm.RSA, Hash = THashAlgorithm.SHA1
                            };
                        }

                        var certVerify = new CertificateVerify
                        {
                            SignatureHashAlgorithm = signatureHashAlgorithm,
                            Signature = TLSUtils.Sign(this._PrivateKey, this._PrivateKeyRsa, true, this._Version, this._HandshakeInfo, signatureHashAlgorithm, this._HandshakeInfo.GetHash(this._Version))
                        };

                        await this._SendHandshakeMessageAsync(certVerify, false).ConfigureAwait(false);
                    }

                    await this._SendChangeCipherSpecAsync().ConfigureAwait(false);

                    var handshakeHash = this._HandshakeInfo.GetHash(this._Version);
                    var finished      = new Finished
                    {
                        VerifyData = TLSUtils.GetVerifyData(this._Version, this._HandshakeInfo, true, true, handshakeHash)
                    };

                    await this._SendHandshakeMessageAsync(finished, true).ConfigureAwait(false);

                    break;
                }

                case THandshakeType.NewSessionTicket:
                {
                    this._HandshakeInfo.UpdateHandshakeHash(data);
                    break;
                }

                case THandshakeType.CertificateVerify:
                {
                    break;
                }

                case THandshakeType.ClientKeyExchange:
                {
                    break;
                }

                case THandshakeType.Finished:
                {
                    var serverFinished       = Finished.Deserialise(stream);
                    var handshakeHash        = this._HandshakeInfo.GetHash(this._Version);
                    var calculatedVerifyData = TLSUtils.GetVerifyData(this._Version, this._HandshakeInfo, true, false, handshakeHash);
                    if (serverFinished.VerifyData.SequenceEqual(calculatedVerifyData))
                    {
                        this._ConnectionComplete = true;
                    }
                    break;
                }

                default:
                {
                    break;
                }
                }
            }

            this._IsFragment = false;
            this._FragmentedRecordList.RemoveAll(x => true);
        }
Пример #6
0
        private void ProcessHandshake(DTLSRecord record)
        {
            byte[] data;
            if (_EncyptedServerEpoch.HasValue && (_EncyptedServerEpoch.Value == record.Epoch))
            {

                int count = 0;
                while ((_Cipher == null) && (count < 500))
                {
                    System.Threading.Thread.Sleep(10);
                    count++;
                }

                if (_Cipher == null)
                    throw new Exception();


                if (_Cipher != null)
                {
                    long sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber;
                    data = _Cipher.DecodeCiphertext(sequenceNumber, (byte)TRecordType.Handshake, record.Fragment, 0, record.Fragment.Length);
                }
                else
                    data = record.Fragment;
            }
            else
                data = record.Fragment;

            using (MemoryStream stream = new MemoryStream(data))
            {
                HandshakeRecord handshakeRecord = HandshakeRecord.Deserialise(stream);
                if (handshakeRecord != null)
                {
#if DEBUG
                    Console.WriteLine(handshakeRecord.MessageType.ToString());
#endif
                    switch (handshakeRecord.MessageType)
                    {
                        case THandshakeType.HelloRequest:
                            break;
                        case THandshakeType.ClientHello:
                            break;
                        case THandshakeType.ServerHello:
                            ServerHello serverHello = ServerHello.Deserialise(stream);
                            if (serverHello != null)
                            {
                                _ServerEpoch = record.Epoch;
                                _HandshakeInfo.UpdateHandshakeHash(data);
                                _HandshakeInfo.CipherSuite = (TCipherSuite)serverHello.CipherSuite;
                                _HandshakeInfo.ServerRandom = serverHello.Random;
                                Version version = SupportedVersion;
                                if (serverHello.ServerVersion < version)
                                    version = serverHello.ServerVersion;
                                _Version = version;
                            }
                            break;
                        case THandshakeType.HelloVerifyRequest:
                            HelloVerifyRequest helloVerifyRequest = HelloVerifyRequest.Deserialise(stream);
                            if (helloVerifyRequest != null)
                            {
                                _Version = helloVerifyRequest.ServerVersion;
                                SendHello(helloVerifyRequest.Cookie);
                            }
                            break;
                        case THandshakeType.Certificate:
                            _HandshakeInfo.UpdateHandshakeHash(data);
                            break;
                        case THandshakeType.ServerKeyExchange:
                            _HandshakeInfo.UpdateHandshakeHash(data);
                            TKeyExchangeAlgorithm keyExchangeAlgorithm = CipherSuites.GetKeyExchangeAlgorithm(_HandshakeInfo.CipherSuite);
                            byte[] preMasterSecret = null;
                            IKeyExchange keyExchange = null;
                            if (keyExchangeAlgorithm == TKeyExchangeAlgorithm.ECDHE_ECDSA)
                            {
                                ECDHEServerKeyExchange serverKeyExchange = ECDHEServerKeyExchange.Deserialise(stream, _Version);
                                ECDHEKeyExchange keyExchangeECDHE = new ECDHEKeyExchange();
                                keyExchangeECDHE.CipherSuite = _HandshakeInfo.CipherSuite;
                                keyExchangeECDHE.Curve = serverKeyExchange.EllipticCurve;
                                keyExchangeECDHE.KeyExchangeAlgorithm = keyExchangeAlgorithm;
                                keyExchangeECDHE.ClientRandom = _HandshakeInfo.ClientRandom;
                                keyExchangeECDHE.ServerRandom = _HandshakeInfo.ServerRandom;
                                keyExchangeECDHE.GenerateEphemeralKey();
                                ECDHEClientKeyExchange clientKeyExchange = new ECDHEClientKeyExchange(keyExchangeECDHE.PublicKey);
                                _ClientKeyExchange = clientKeyExchange;
                                preMasterSecret = keyExchangeECDHE.GetPreMasterSecret(serverKeyExchange.PublicKeyBytes);
                                keyExchange = keyExchangeECDHE;
                            }
                            else if (keyExchangeAlgorithm == TKeyExchangeAlgorithm.ECDHE_PSK)
                            {
                                ECDHEPSKServerKeyExchange serverKeyExchange = ECDHEPSKServerKeyExchange.Deserialise(stream, _Version);
                                ECDHEKeyExchange keyExchangeECDHE = new ECDHEKeyExchange();
                                keyExchangeECDHE.CipherSuite = _HandshakeInfo.CipherSuite;
                                keyExchangeECDHE.Curve = serverKeyExchange.EllipticCurve;
                                keyExchangeECDHE.KeyExchangeAlgorithm = keyExchangeAlgorithm;
                                keyExchangeECDHE.ClientRandom = _HandshakeInfo.ClientRandom;
                                keyExchangeECDHE.ServerRandom = _HandshakeInfo.ServerRandom;
                                keyExchangeECDHE.GenerateEphemeralKey();
                                ECDHEPSKClientKeyExchange clientKeyExchange = new ECDHEPSKClientKeyExchange(keyExchangeECDHE.PublicKey);
                                if (serverKeyExchange.PSKIdentityHint != null)
                                {
                                    byte[] key = _PSKIdentities.GetKey(serverKeyExchange.PSKIdentityHint);
                                    if (key != null)
                                        _PSKIdentity = new PSKIdentity() { Identity = serverKeyExchange.PSKIdentityHint, Key = key };
                                }
                                if (_PSKIdentity == null)
                                    _PSKIdentity = _PSKIdentities.GetRandom();
                                clientKeyExchange.PSKIdentity = _PSKIdentity.Identity;
                                _ClientKeyExchange = clientKeyExchange;
                                byte[] otherSecret = keyExchangeECDHE.GetPreMasterSecret(serverKeyExchange.PublicKeyBytes);
                                preMasterSecret = TLSUtils.GetPSKPreMasterSecret(otherSecret, _PSKIdentity.Key);
                                keyExchange = keyExchangeECDHE;
                            }
                            else if (keyExchangeAlgorithm == TKeyExchangeAlgorithm.PSK)
                            {
                                PSKServerKeyExchange serverKeyExchange = PSKServerKeyExchange.Deserialise(stream, _Version);
                                PSKClientKeyExchange clientKeyExchange = new PSKClientKeyExchange();
                                if (serverKeyExchange.PSKIdentityHint != null)
                                {
                                    byte[] key = _PSKIdentities.GetKey(serverKeyExchange.PSKIdentityHint);
                                    if (key != null)
                                        _PSKIdentity = new PSKIdentity() { Identity = serverKeyExchange.PSKIdentityHint, Key = key };
                                }
                                if (_PSKIdentity == null)
                                    _PSKIdentity = _PSKIdentities.GetRandom();
                                byte[] otherSecret = new byte[_PSKIdentity.Key.Length];
                                clientKeyExchange.PSKIdentity = _PSKIdentity.Identity;
                                _ClientKeyExchange = clientKeyExchange;
                                preMasterSecret = TLSUtils.GetPSKPreMasterSecret(otherSecret, _PSKIdentity.Key);
                            }
                            _Cipher = TLSUtils.AssignCipher(preMasterSecret, true, _Version, _HandshakeInfo);

                            break;
                        case THandshakeType.CertificateRequest:
                            _HandshakeInfo.UpdateHandshakeHash(data);
                            _SendCertificate = true;
                            break;
                        case THandshakeType.ServerHelloDone:
                            _HandshakeInfo.UpdateHandshakeHash(data);
                            if (_Cipher == null)
                            {
                                keyExchangeAlgorithm = CipherSuites.GetKeyExchangeAlgorithm(_HandshakeInfo.CipherSuite);
                                if (keyExchangeAlgorithm == TKeyExchangeAlgorithm.PSK)
                                {
                                    PSKClientKeyExchange clientKeyExchange = new PSKClientKeyExchange();
                                    _PSKIdentity = _PSKIdentities.GetRandom();
                                    byte[] otherSecret = new byte[_PSKIdentity.Key.Length];
                                    clientKeyExchange.PSKIdentity = _PSKIdentity.Identity;
                                    _ClientKeyExchange = clientKeyExchange;
                                    preMasterSecret = TLSUtils.GetPSKPreMasterSecret(otherSecret, _PSKIdentity.Key);
                                    _Cipher = TLSUtils.AssignCipher(preMasterSecret, true, _Version, _HandshakeInfo);
                                }
                            }

                            if (_SendCertificate)
                            {
                                SendHandshakeMessage(_Certificate, false);
                            }
                            SendHandshakeMessage(_ClientKeyExchange, false);
                            if (_SendCertificate)
                            {
                                CertificateVerify certificateVerify = new CertificateVerify();
                                byte[] signatureHash = _HandshakeInfo.GetHash();
                                certificateVerify.SignatureHashAlgorithm = new SignatureHashAlgorithm() { Signature = TSignatureAlgorithm.ECDSA, Hash = THashAlgorithm.SHA256 };
                                certificateVerify.Signature = TLSUtils.Sign(_PrivateKey, true, _Version, _HandshakeInfo, certificateVerify.SignatureHashAlgorithm, signatureHash);
                                SendHandshakeMessage(certificateVerify, false);
                            }
                            SendChangeCipherSpec();
                            byte[] handshakeHash = _HandshakeInfo.GetHash();
                            Finished finished = new Finished();
                            finished.VerifyData = TLSUtils.GetVerifyData(_Version,_HandshakeInfo,true, true, handshakeHash);
                            SendHandshakeMessage(finished, true);
#if DEBUG
                            Console.Write("Handshake Hash:");
                            TLSUtils.WriteToConsole(handshakeHash);
                            Console.Write("Sent Verify:");
                            TLSUtils.WriteToConsole(finished.VerifyData);
#endif
                            break;
                        case THandshakeType.CertificateVerify:
                            break;
                        case THandshakeType.ClientKeyExchange:
                            break;
                        case THandshakeType.Finished:
                            Finished serverFinished = Finished.Deserialise(stream);
                            handshakeHash = _HandshakeInfo.GetHash();
                            byte[] calculatedVerifyData = TLSUtils.GetVerifyData(_Version,_HandshakeInfo, true, false, handshakeHash);
#if DEBUG
                            Console.Write("Recieved Verify:");
                            TLSUtils.WriteToConsole(serverFinished.VerifyData);
                            Console.Write("Calc Verify:");
                            TLSUtils.WriteToConsole(calculatedVerifyData);
#endif
                            if (TLSUtils.ByteArrayCompare(serverFinished.VerifyData, calculatedVerifyData))
                            {
#if DEBUG
                                Console.WriteLine("Handshake Complete");
#endif
                                _Connected.Set();
                            }
                            break;
                        default:
                            break;
                    }
                }
            }
        }