private DTLSRecord CreateRecord(Session session, IHandshakeMessage handshakeMessage, ushort messageSequence)
        {
            int        size   = handshakeMessage.CalculateSize(session.Version);
            DTLSRecord record = new DTLSRecord();

            record.RecordType     = TRecordType.Handshake;
            record.Epoch          = session.Epoch;
            record.SequenceNumber = session.NextSequenceNumber();
            record.Fragment       = new byte[HandshakeRecord.RECORD_OVERHEAD + size];
            if (session.Version != null)
            {
                record.Version = session.Version;
            }
            HandshakeRecord handshakeRecord = new HandshakeRecord();

            handshakeRecord.MessageType    = handshakeMessage.MessageType;
            handshakeRecord.MessageSeq     = messageSequence;
            handshakeRecord.Length         = (uint)size;
            handshakeRecord.FragmentLength = (uint)size;
            using (MemoryStream stream = new MemoryStream(record.Fragment))
            {
                handshakeRecord.Serialise(stream);
                handshakeMessage.Serialise(stream, session.Version);
            }
            if (handshakeMessage.MessageType != THandshakeType.HelloVerifyRequest)
            {
                session.Handshake.UpdateHandshakeHash(record.Fragment);
            }
            if (session.Cipher != null)
            {
                long sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber;
                record.Fragment = session.Cipher.EncodePlaintext(sequenceNumber, (byte)TRecordType.Handshake, record.Fragment, 0, record.Fragment.Length);
            }
            return(record);
        }
Exemple #2
0
        private void SendHandshakeMessage(IHandshakeMessage handshakeMessage, bool encrypt)
        {
            int size           = handshakeMessage.CalculateSize(_Version);
            int maxPayloadSize = _MaxPacketSize - DTLSRecord.RECORD_OVERHEAD + HandshakeRecord.RECORD_OVERHEAD;

            if (size > maxPayloadSize)
            {
            }
            else
            {
                DTLSRecord record = new DTLSRecord
                {
                    RecordType     = TRecordType.Handshake,
                    Epoch          = _Epoch,
                    SequenceNumber = NextSequenceNumber(),
                    Fragment       = new byte[HandshakeRecord.RECORD_OVERHEAD + size]
                };
                if (_Version != null)
                {
                    record.Version = _Version;
                }
                HandshakeRecord handshakeRecord = new HandshakeRecord
                {
                    MessageType = handshakeMessage.MessageType,
                    MessageSeq  = _MessageSequence
                };
                _MessageSequence++;
                handshakeRecord.Length         = (uint)size;
                handshakeRecord.FragmentLength = (uint)size;
                using (MemoryStream stream = new MemoryStream(record.Fragment))
                {
                    handshakeRecord.Serialise(stream);
                    handshakeMessage.Serialise(stream, _Version);
                }
                if (handshakeMessage.MessageType != THandshakeType.HelloVerifyRequest)
                {
                    _HandshakeInfo.UpdateHandshakeHash(record.Fragment);
                }
                int responseSize = DTLSRecord.RECORD_OVERHEAD + HandshakeRecord.RECORD_OVERHEAD + size;
                if ((_Cipher != null) && encrypt)
                {
                    long sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber;
                    record.Fragment = _Cipher.EncodePlaintext(sequenceNumber, (byte)TRecordType.Handshake, record.Fragment, 0, record.Fragment.Length);
                    responseSize    = DTLSRecord.RECORD_OVERHEAD + record.Fragment.Length;
                }
                byte[] response = new byte[responseSize];
                using (MemoryStream stream = new MemoryStream(response))
                {
                    record.Serialise(stream);
                }
                SocketAsyncEventArgs parameters = new SocketAsyncEventArgs()
                {
                    RemoteEndPoint = _ServerEndPoint
                };
                parameters.SetBuffer(response, 0, responseSize);
                _Socket.SendToAsync(parameters);
            }
        }
        private void SendResponse(Session session, IHandshakeMessage handshakeMessage, ushort messageSequence)
        {
            int size           = handshakeMessage.CalculateSize(session.Version);
            int maxPayloadSize = _MaxPacketSize - DTLSRecord.RECORD_OVERHEAD + HandshakeRecord.RECORD_OVERHEAD;

            if (size > maxPayloadSize)
            {
            }
            else
            {
                DTLSRecord record = new DTLSRecord();
                record.RecordType     = TRecordType.Handshake;
                record.Epoch          = session.Epoch;
                record.SequenceNumber = session.NextSequenceNumber();
                record.Fragment       = new byte[HandshakeRecord.RECORD_OVERHEAD + size];
                if (session.Version != null)
                {
                    record.Version = session.Version;
                }
                HandshakeRecord handshakeRecord = new HandshakeRecord();
                handshakeRecord.MessageType    = handshakeMessage.MessageType;
                handshakeRecord.MessageSeq     = messageSequence;
                handshakeRecord.Length         = (uint)size;
                handshakeRecord.FragmentLength = (uint)size;
                using (MemoryStream stream = new MemoryStream(record.Fragment))
                {
                    handshakeRecord.Serialise(stream);
                    handshakeMessage.Serialise(stream, session.Version);
                }
                if (handshakeMessage.MessageType != THandshakeType.HelloVerifyRequest)
                {
                    session.Handshake.UpdateHandshakeHash(record.Fragment);
                }
                int responseSize = DTLSRecord.RECORD_OVERHEAD + HandshakeRecord.RECORD_OVERHEAD + size;
                if (session.Cipher != null)
                {
                    long sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber;
                    record.Fragment = session.Cipher.EncodePlaintext(sequenceNumber, (byte)TRecordType.Handshake, record.Fragment, 0, record.Fragment.Length);
                    responseSize    = DTLSRecord.RECORD_OVERHEAD + record.Fragment.Length;
                }
                byte[] response = new byte[responseSize];
                using (MemoryStream stream = new MemoryStream(response))
                {
                    record.Serialise(stream);
                }
                SocketAsyncEventArgs parameters = new SocketAsyncEventArgs()
                {
                    RemoteEndPoint = session.RemoteEndPoint
                };
                parameters.SetBuffer(response, 0, responseSize);
                _Socket.SendToAsync(parameters);
            }
        }
        private DTLSRecord CreateRecord(Session session, IHandshakeMessage handshakeMessage, ushort messageSequence)
        {
            if (session == null)
            {
                throw new ArgumentNullException(nameof(session));
            }

            if (handshakeMessage == null)
            {
                throw new ArgumentNullException(nameof(handshakeMessage));
            }

            var size   = handshakeMessage.CalculateSize(session.Version);
            var record = new DTLSRecord
            {
                RecordType     = TRecordType.Handshake,
                Epoch          = session.Epoch,
                SequenceNumber = session.NextSequenceNumber(),
                Fragment       = new byte[HandshakeRecord.RECORD_OVERHEAD + size]
            };

            if (session.Version != null)
            {
                record.Version = session.Version;
            }

            var handshakeRecord = new HandshakeRecord
            {
                MessageType    = handshakeMessage.MessageType,
                MessageSeq     = messageSequence,
                Length         = (uint)size,
                FragmentLength = (uint)size
            };

            using (var stream = new MemoryStream(record.Fragment))
            {
                handshakeRecord.Serialise(stream);
                handshakeMessage.Serialise(stream, session.Version);
            }

            if (handshakeMessage.MessageType != THandshakeType.HelloVerifyRequest)
            {
                session.Handshake.UpdateHandshakeHash(record.Fragment);
            }

            if (session.Cipher != null)
            {
                var sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber;
                record.Fragment = session.Cipher.EncodePlaintext(sequenceNumber, (byte)TRecordType.Handshake, record.Fragment, 0, record.Fragment.Length);
            }

            return(record);
        }
Exemple #5
0
        private IEnumerable <byte[]> _GetBytes(IHandshakeMessage handshakeMessage, bool encrypt)
        {
            if (handshakeMessage == null)
            {
                throw new ArgumentNullException(nameof(handshakeMessage));
            }

            var size           = handshakeMessage.CalculateSize(this._Version);
            var maxPayloadSize = _MaxPacketSize - DTLSRecord.RECORD_OVERHEAD + HandshakeRecord.RECORD_OVERHEAD;

            if (size > maxPayloadSize)
            {
                var wholeMessage = new List <byte[]>();

                var record = new DTLSRecord
                {
                    RecordType = TRecordType.Handshake,
                    Epoch      = _Epoch,
                    Version    = this._Version
                };

                var handshakeRecord = new HandshakeRecord
                {
                    MessageType = handshakeMessage.MessageType,
                    MessageSeq  = _MessageSequence
                };

                if (!(handshakeMessage.MessageType == THandshakeType.HelloVerifyRequest ||
                      (handshakeMessage.MessageType == THandshakeType.ClientHello && (handshakeMessage as ClientHello).Cookie == null)))
                {
                    record.Fragment                = new byte[HandshakeRecord.RECORD_OVERHEAD + size];
                    handshakeRecord.Length         = (uint)size;
                    handshakeRecord.FragmentLength = (uint)size;
                    handshakeRecord.FragmentOffset = 0u;
                    using (var stream = new MemoryStream(record.Fragment))
                    {
                        handshakeRecord.Serialise(stream);
                        handshakeMessage.Serialise(stream, this._Version);
                    }

                    this._HandshakeInfo.UpdateHandshakeHash(record.Fragment);
                }

                var dataMessage = new byte[size];
                using (var stream = new MemoryStream(dataMessage))
                {
                    handshakeMessage.Serialise(stream, this._Version);
                }

                var dataMessageFragments = dataMessage.ChunkBySize(maxPayloadSize);
                handshakeRecord.FragmentOffset = 0U;
                dataMessageFragments.ForEach(x =>
                {
                    handshakeRecord.Length         = (uint)size;
                    handshakeRecord.FragmentLength = (uint)x.Count();
                    record.SequenceNumber          = this._NextSequenceNumber();

                    var baseMessage = new byte[HandshakeRecord.RECORD_OVERHEAD];
                    using (var stream = new MemoryStream(baseMessage))
                    {
                        handshakeRecord.Serialise(stream);
                    }

                    record.Fragment = baseMessage.Concat(x).ToArray();

                    var responseSize = DTLSRecord.RECORD_OVERHEAD + HandshakeRecord.RECORD_OVERHEAD + x.Count();
                    if ((this._Cipher != null) && encrypt)
                    {
                        var sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber;
                        record.Fragment    = this._Cipher.EncodePlaintext(sequenceNumber, (byte)TRecordType.Handshake, record.Fragment, 0, record.Fragment.Length);
                        responseSize       = DTLSRecord.RECORD_OVERHEAD + record.Fragment.Length;
                    }
                    var response = new byte[responseSize];
                    using (var stream = new MemoryStream(response))
                    {
                        record.Serialise(stream);
                    }

                    wholeMessage.Add(response);
                    handshakeRecord.FragmentOffset += (uint)x.Count();
                });

                this._MessageSequence++;
                return(wholeMessage);
            }
            else
            {
                var record = new DTLSRecord
                {
                    RecordType     = TRecordType.Handshake,
                    Epoch          = _Epoch,
                    SequenceNumber = this._NextSequenceNumber(),
                    Fragment       = new byte[HandshakeRecord.RECORD_OVERHEAD + size],
                    Version        = this._Version
                };

                var handshakeRecord = new HandshakeRecord
                {
                    MessageType = handshakeMessage.MessageType,
                    MessageSeq  = _MessageSequence
                };
                this._MessageSequence++;
                handshakeRecord.Length         = (uint)size;
                handshakeRecord.FragmentLength = (uint)size;
                using (var stream = new MemoryStream(record.Fragment))
                {
                    handshakeRecord.Serialise(stream);
                    handshakeMessage.Serialise(stream, this._Version);
                }

                if (!(handshakeMessage.MessageType == THandshakeType.HelloVerifyRequest ||
                      (handshakeMessage.MessageType == THandshakeType.ClientHello && (handshakeMessage as ClientHello).Cookie == null)))
                {
                    this._HandshakeInfo.UpdateHandshakeHash(record.Fragment);
                }

                var responseSize = DTLSRecord.RECORD_OVERHEAD + HandshakeRecord.RECORD_OVERHEAD + size;
                if ((this._Cipher != null) && encrypt)
                {
                    var sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber;
                    record.Fragment = this._Cipher.EncodePlaintext(sequenceNumber, (byte)TRecordType.Handshake, record.Fragment, 0, record.Fragment.Length);
                    responseSize    = DTLSRecord.RECORD_OVERHEAD + record.Fragment.Length;
                }

                var response = new byte[responseSize];
                using (var stream = new MemoryStream(response))
                {
                    record.Serialise(stream);
                }

                return(new List <byte[]>()
                {
                    response
                });
            }
        }
Exemple #6
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);
        }
		private DTLSRecord CreateRecord(Session session, IHandshakeMessage handshakeMessage, ushort messageSequence)
		{
			int size = handshakeMessage.CalculateSize(session.Version);
			DTLSRecord record = new DTLSRecord();
			record.RecordType = TRecordType.Handshake;
			record.Epoch = session.Epoch;
			record.SequenceNumber = session.NextSequenceNumber();
			record.Fragment = new byte[HandshakeRecord.RECORD_OVERHEAD + size];
			if (session.Version != null)
				record.Version = session.Version;
			HandshakeRecord handshakeRecord = new HandshakeRecord();
			handshakeRecord.MessageType = handshakeMessage.MessageType;
			handshakeRecord.MessageSeq = messageSequence;
			handshakeRecord.Length = (uint)size;
			handshakeRecord.FragmentLength = (uint)size;
			using (MemoryStream stream = new MemoryStream(record.Fragment))
			{
				handshakeRecord.Serialise(stream);
				handshakeMessage.Serialise(stream, session.Version);
			}
			if (handshakeMessage.MessageType != THandshakeType.HelloVerifyRequest)
			{
				session.Handshake.UpdateHandshakeHash(record.Fragment);
			}
			if (session.Cipher != null)
			{
				long sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber;
				record.Fragment = session.Cipher.EncodePlaintext(sequenceNumber, (byte)TRecordType.Handshake, record.Fragment, 0, record.Fragment.Length);
			}
			return record;
		}
		private void SendResponse(Session session, IHandshakeMessage handshakeMessage, ushort messageSequence)
		{
			int size = handshakeMessage.CalculateSize(session.Version);
			int maxPayloadSize = _MaxPacketSize - DTLSRecord.RECORD_OVERHEAD + HandshakeRecord.RECORD_OVERHEAD;
			if (size > maxPayloadSize)
			{

			}
			else
			{
				
				DTLSRecord record = new DTLSRecord();
				record.RecordType = TRecordType.Handshake;
				record.Epoch = session.Epoch;
				record.SequenceNumber = session.NextSequenceNumber();
				record.Fragment = new byte[HandshakeRecord.RECORD_OVERHEAD + size];
				if (session.Version != null)
					record.Version = session.Version;
				HandshakeRecord handshakeRecord = new HandshakeRecord();
				handshakeRecord.MessageType = handshakeMessage.MessageType;
				handshakeRecord.MessageSeq = messageSequence;
				handshakeRecord.Length = (uint)size;
				handshakeRecord.FragmentLength = (uint)size;
				using (MemoryStream stream = new MemoryStream(record.Fragment))
				{
					handshakeRecord.Serialise(stream);
					handshakeMessage.Serialise(stream, session.Version);
				}
                if (handshakeMessage.MessageType != THandshakeType.HelloVerifyRequest)
                {
                    session.Handshake.UpdateHandshakeHash(record.Fragment);
                }
                int responseSize = DTLSRecord.RECORD_OVERHEAD + HandshakeRecord.RECORD_OVERHEAD + size;
                if (session.Cipher != null)
                {
                   long sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber;                   
                   record.Fragment = session.Cipher.EncodePlaintext(sequenceNumber, (byte)TRecordType.Handshake, record.Fragment, 0, record.Fragment.Length);
                   responseSize = DTLSRecord.RECORD_OVERHEAD + record.Fragment.Length;
                }
                byte[] response = new byte[responseSize];
				using (MemoryStream stream = new MemoryStream(response))
				{
					record.Serialise(stream);
				}
                SocketAsyncEventArgs parameters = new SocketAsyncEventArgs()
                {
                    RemoteEndPoint = session.RemoteEndPoint
                };
                parameters.SetBuffer(response, 0, responseSize);
                _Socket.SendToAsync(parameters);
			}


		}
        private void SendResponse(Session session, IHandshakeMessage handshakeMessage, ushort messageSequence)
        {
            if (session == null)
            {
                throw new ArgumentNullException(nameof(session));
            }

            if (handshakeMessage == null)
            {
                throw new ArgumentNullException(nameof(handshakeMessage));
            }

            var size           = handshakeMessage.CalculateSize(session.Version);
            var maxPayloadSize = this._MaxPacketSize - DTLSRecord.RECORD_OVERHEAD + HandshakeRecord.RECORD_OVERHEAD;

            if (size > maxPayloadSize)
            {
                //fragments
                return;
            }

            var record = new DTLSRecord
            {
                RecordType     = TRecordType.Handshake,
                Epoch          = session.Epoch,
                SequenceNumber = session.NextSequenceNumber(),
                Fragment       = new byte[HandshakeRecord.RECORD_OVERHEAD + size]
            };

            if (session.Version != null)
            {
                record.Version = session.Version;
            }

            var handshakeRecord = new HandshakeRecord
            {
                MessageType    = handshakeMessage.MessageType,
                MessageSeq     = messageSequence,
                Length         = (uint)size,
                FragmentLength = (uint)size
            };

            using (var stream = new MemoryStream(record.Fragment))
            {
                handshakeRecord.Serialise(stream);
                handshakeMessage.Serialise(stream, session.Version);
            }

            if (handshakeMessage.MessageType != THandshakeType.HelloVerifyRequest)
            {
                session.Handshake.UpdateHandshakeHash(record.Fragment);
            }

            var responseSize = DTLSRecord.RECORD_OVERHEAD + HandshakeRecord.RECORD_OVERHEAD + size;

            if (session.Cipher != null)
            {
                var sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber;
                record.Fragment = session.Cipher.EncodePlaintext(sequenceNumber, (byte)TRecordType.Handshake, record.Fragment, 0, record.Fragment.Length);
                responseSize    = DTLSRecord.RECORD_OVERHEAD + record.Fragment.Length;
            }

            var response = new byte[responseSize];

            using (var stream = new MemoryStream(response))
            {
                record.Serialise(stream);
            }
            var parameters = new SocketAsyncEventArgs()
            {
                RemoteEndPoint = session.RemoteEndPoint
            };

            parameters.SetBuffer(response, 0, responseSize);
            this._Socket.SendToAsync(parameters);
        }