private async Task _SendHelloAsync(byte[] cookie) { var clientHello = new ClientHello { ClientVersion = this._Version, Random = this._HandshakeInfo.ClientRandom, Cookie = cookie }; var cipherSuites = new ushort[this.SupportedCipherSuites.Count]; var index = 0; foreach (var item in this.SupportedCipherSuites) { cipherSuites[index] = (ushort)item; index++; } clientHello.CipherSuites = cipherSuites; clientHello.CompressionMethods = new byte[1]; clientHello.CompressionMethods[0] = 0; clientHello.Extensions = new Extensions { new Extension() { ExtensionType = TExtensionType.SessionTicketTLS }, new Extension() { ExtensionType = TExtensionType.EncryptThenMAC }, new Extension() { ExtensionType = TExtensionType.ExtendedMasterSecret }, }; var ellipticCurvesExtension = new EllipticCurvesExtension(); for (var curve = 0; curve < (int)TEllipticCurve.secp521r1; curve++) { if (EllipticCurveFactory.SupportedCurve((TEllipticCurve)curve)) { ellipticCurvesExtension.SupportedCurves.Add((TEllipticCurve)curve); } } clientHello.Extensions.Add(new Extension(ellipticCurvesExtension)); var cllipticCurvePointFormatsExtension = new EllipticCurvePointFormatsExtension(); cllipticCurvePointFormatsExtension.SupportedPointFormats.Add(TEllipticCurvePointFormat.Uncompressed); clientHello.Extensions.Add(new Extension(cllipticCurvePointFormatsExtension)); var signatureAlgorithmsExtension = new SignatureAlgorithmsExtension(); signatureAlgorithmsExtension.SupportedAlgorithms.Add(new SignatureHashAlgorithm() { Hash = THashAlgorithm.SHA1, Signature = TSignatureAlgorithm.RSA }); clientHello.Extensions.Add(new Extension(signatureAlgorithmsExtension)); await this._SendHandshakeMessageAsync(clientHello, false, TimeSpan.FromSeconds(1)).ConfigureAwait(false); }
private void SendHello(byte[] cookie) { ClientHello clientHello = new ClientHello { ClientVersion = SupportedVersion, Random = _HandshakeInfo.ClientRandom, Cookie = cookie }; ushort[] cipherSuites = new ushort[_SupportedCipherSuites.Count]; int index = 0; foreach (TCipherSuite item in _SupportedCipherSuites) { cipherSuites[index] = (ushort)item; index++; } clientHello.CipherSuites = cipherSuites; clientHello.CompressionMethods = new byte[1]; clientHello.CompressionMethods[0] = 0; clientHello.Extensions = new Extensions(); clientHello.Extensions.Add(new Extension() { ExtensionType = TExtensionType.EncryptThenMAC }); clientHello.Extensions.Add(new Extension() { ExtensionType = TExtensionType.ExtendedMasterSecret }); EllipticCurvesExtension ellipticCurvesExtension = new EllipticCurvesExtension(); for (int curve = 0; curve < (int)TEllipticCurve.secp521r1; curve++) { if (EllipticCurveFactory.SupportedCurve((TEllipticCurve)curve)) { ellipticCurvesExtension.SupportedCurves.Add((TEllipticCurve)curve); } } clientHello.Extensions.Add(new Extension(ellipticCurvesExtension)); EllipticCurvePointFormatsExtension cllipticCurvePointFormatsExtension = new EllipticCurvePointFormatsExtension(); cllipticCurvePointFormatsExtension.SupportedPointFormats.Add(TEllipticCurvePointFormat.Uncompressed); clientHello.Extensions.Add(new Extension(cllipticCurvePointFormatsExtension)); SignatureAlgorithmsExtension signatureAlgorithmsExtension = new SignatureAlgorithmsExtension(); signatureAlgorithmsExtension.SupportedAlgorithms.Add(new SignatureHashAlgorithm() { Hash = THashAlgorithm.SHA256, Signature = TSignatureAlgorithm.ECDSA }); clientHello.Extensions.Add(new Extension(signatureAlgorithmsExtension)); _HandshakeInfo.InitaliseHandshakeHash(false); SendHandshakeMessage(clientHello, false); }
public static SignatureAlgorithmsExtension Deserialise(Stream stream) { SignatureAlgorithmsExtension result = new SignatureAlgorithmsExtension(); ushort length = NetworkByteOrderConverter.ToUInt16(stream); ushort supportedAlgorithmsLength = (ushort)(length / 2); if (supportedAlgorithmsLength > 0) { for (uint index = 0; index < supportedAlgorithmsLength; index++) { THashAlgorithm hash = (THashAlgorithm)stream.ReadByte(); TSignatureAlgorithm signature = (TSignatureAlgorithm)stream.ReadByte(); result.SupportedAlgorithms.Add(new SignatureHashAlgorithm() { Hash = hash, Signature = signature }); } } return result; }
public static Extension Deserialise(Stream stream, bool client) { if (stream == null) { throw new ArgumentNullException(nameof(stream)); } Extension result = null; if (stream.Position < stream.Length) { result = new Extension { ExtensionType = (TExtensionType)NetworkByteOrderConverter.ToUInt16(stream) }; var length = NetworkByteOrderConverter.ToUInt16(stream); if (length > 0) { if (result.ExtensionType == TExtensionType.EllipticCurves) { result.SpecificExtension = EllipticCurvesExtension.Deserialise(stream); } else if (result.ExtensionType == TExtensionType.ClientCertificateType) { result.SpecificExtension = ClientCertificateTypeExtension.Deserialise(stream, client); } else if (result.ExtensionType == TExtensionType.ServerCertificateType) { result.SpecificExtension = ServerCertificateTypeExtension.Deserialise(stream, client); } else if (result.ExtensionType == TExtensionType.SignatureAlgorithms) { result.SpecificExtension = SignatureAlgorithmsExtension.Deserialise(stream); } else { result.Data = new byte[length]; stream.Read(result.Data, 0, length); } } } return(result); }
public static SignatureAlgorithmsExtension Deserialise(Stream stream) { SignatureAlgorithmsExtension result = new SignatureAlgorithmsExtension(); ushort length = NetworkByteOrderConverter.ToUInt16(stream); ushort supportedAlgorithmsLength = (ushort)(length / 2); if (supportedAlgorithmsLength > 0) { for (uint index = 0; index < supportedAlgorithmsLength; index++) { THashAlgorithm hash = (THashAlgorithm)stream.ReadByte(); TSignatureAlgorithm signature = (TSignatureAlgorithm)stream.ReadByte(); result.SupportedAlgorithms.Add(new SignatureHashAlgorithm() { Hash = hash, Signature = signature }); } } return(result); }
public static Extension Deserialise(Stream stream, bool client) { Extension result = null; if (stream.Position < stream.Length) { result = new Extension(); result._ExtensionType = (TExtensionType)NetworkByteOrderConverter.ToUInt16(stream); ushort length = NetworkByteOrderConverter.ToUInt16(stream); if (length > 0) { if (result._ExtensionType == TExtensionType.EllipticCurves) { result._SpecifcExtension = EllipticCurvesExtension.Deserialise(stream); } else if (result._ExtensionType == TExtensionType.ClientCertificateType) { result._SpecifcExtension = ClientCertificateTypeExtension.Deserialise(stream, client); } else if (result._ExtensionType == TExtensionType.ServerCertificateType) { result._SpecifcExtension = ServerCertificateTypeExtension.Deserialise(stream, client); } else if (result._ExtensionType == TExtensionType.SignatureAlgorithms) { result._SpecifcExtension = SignatureAlgorithmsExtension.Deserialise(stream); } else { result._Data = new byte[length]; stream.Read(result._Data, 0, length); } } } return(result); }
public void ProcessHandshake(DTLSRecord record) { #if DEBUG Console.WriteLine($"> ProcessHandshake got {record}"); #endif SocketAddress address = record.RemoteEndPoint.Serialize(); Session session = Sessions.GetSession(address); byte[] data; if ((session != null) && session.IsEncypted(record)) { int count = 0; while ((session.Cipher == null) && (count < (HandshakeTimeout / HANDSHAKE_DWELL_TIME))) { System.Threading.Thread.Sleep(HANDSHAKE_DWELL_TIME); count++; } if (session.Cipher == null) { throw new Exception($"HandshakeTimeout: >{HandshakeTimeout}"); } if (session.Cipher != null) { long sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber; data = session.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: //HelloReq break; case THandshakeType.ClientHello: ClientHello clientHello = ClientHello.Deserialise(stream); if (clientHello != null) { byte[] cookie = clientHello.CalculateCookie(record.RemoteEndPoint, _HelloSecret); if (clientHello.Cookie == null) { Version version = clientHello.ClientVersion; if (ServerVersion < version) { version = ServerVersion; } if (session == null) { session = new Session { SessionID = Guid.NewGuid(), RemoteEndPoint = record.RemoteEndPoint, Version = version }; Sessions.AddSession(address, session); } else { session.Reset(); session.Version = version; } session.ClientEpoch = record.Epoch; session.ClientSequenceNumber = record.SequenceNumber; //session.Handshake.UpdateHandshakeHash(data); HelloVerifyRequest helloVerifyRequest = new HelloVerifyRequest { Cookie = cookie, ServerVersion = ServerVersion }; SendResponse(session, (IHandshakeMessage)helloVerifyRequest, 0); } else { if (session != null && session.Cipher != null && !session.IsEncypted(record)) { session.Reset(); } if (TLSUtils.ByteArrayCompare(clientHello.Cookie, cookie)) { Version version = clientHello.ClientVersion; if (ServerVersion < version) { version = ServerVersion; } if (clientHello.SessionID == null) { if (session == null) { session = new Session(); session.NextSequenceNumber(); session.SessionID = Guid.NewGuid(); session.RemoteEndPoint = record.RemoteEndPoint; Sessions.AddSession(address, session); } } else { Guid sessionID = Guid.Empty; if (clientHello.SessionID.Length >= 16) { byte[] receivedSessionID = new byte[16]; Buffer.BlockCopy(clientHello.SessionID, 0, receivedSessionID, 0, 16); sessionID = new Guid(receivedSessionID); } if (sessionID != Guid.Empty) { session = Sessions.GetSession(sessionID); } if (session == null) { //need to Find Session session = new Session { SessionID = Guid.NewGuid() }; session.NextSequenceNumber(); session.RemoteEndPoint = record.RemoteEndPoint; Sessions.AddSession(address, session); //session.Version = clientHello.ClientVersion; } } session.Version = version; session.Handshake.InitaliseHandshakeHash(version < DTLSRecord.Version1_2); session.Handshake.UpdateHandshakeHash(data); TCipherSuite cipherSuite = TCipherSuite.TLS_NULL_WITH_NULL_NULL; foreach (TCipherSuite item in clientHello.CipherSuites) { if (_SupportedCipherSuites.ContainsKey(item) && CipherSuites.SupportedVersion(item, session.Version) && CipherSuites.SuiteUsable(item, PrivateKey, _PSKIdentities, _ValidatePSK != null)) { cipherSuite = item; break; } } TKeyExchangeAlgorithm keyExchangeAlgorithm = CipherSuites.GetKeyExchangeAlgorithm(cipherSuite); ServerHello serverHello = new ServerHello(); byte[] clientSessionID = new byte[32]; byte[] temp = session.SessionID.ToByteArray(); Buffer.BlockCopy(temp, 0, clientSessionID, 0, 16); Buffer.BlockCopy(temp, 0, clientSessionID, 16, 16); serverHello.SessionID = clientSessionID; // session.SessionID.ToByteArray(); serverHello.Random = new RandomData(); serverHello.Random.Generate(); serverHello.CipherSuite = (ushort)cipherSuite; serverHello.ServerVersion = session.Version; THashAlgorithm hash = THashAlgorithm.SHA256; TEllipticCurve curve = TEllipticCurve.secp521r1; if (clientHello.Extensions != null) { foreach (Extension extension in clientHello.Extensions) { if (extension.SpecifcExtension is ClientCertificateTypeExtension) { ClientCertificateTypeExtension clientCertificateType = extension.SpecifcExtension as ClientCertificateTypeExtension; //TCertificateType certificateType = TCertificateType.Unknown; //foreach (TCertificateType item in clientCertificateType.CertificateTypes) //{ //} //serverHello.AddExtension(new ClientCertificateTypeExtension(certificateType)); } else if (extension.SpecifcExtension is EllipticCurvesExtension) { EllipticCurvesExtension ellipticCurves = extension.SpecifcExtension as EllipticCurvesExtension; foreach (TEllipticCurve item in ellipticCurves.SupportedCurves) { if (EllipticCurveFactory.SupportedCurve(item)) { curve = item; break; } } } else if (extension.SpecifcExtension is ServerCertificateTypeExtension) { //serverHello.AddExtension(); } else if (extension.SpecifcExtension is SignatureAlgorithmsExtension) { SignatureAlgorithmsExtension signatureAlgorithms = extension.SpecifcExtension as SignatureAlgorithmsExtension; foreach (SignatureHashAlgorithm item in signatureAlgorithms.SupportedAlgorithms) { if (item.Signature == TSignatureAlgorithm.ECDSA) { hash = item.Hash; break; } } } } } session.Handshake.CipherSuite = cipherSuite; session.Handshake.ClientRandom = clientHello.Random; session.Handshake.ServerRandom = serverHello.Random; if (keyExchangeAlgorithm == TKeyExchangeAlgorithm.ECDHE_ECDSA) { EllipticCurvePointFormatsExtension pointFormatsExtension = new EllipticCurvePointFormatsExtension(); pointFormatsExtension.SupportedPointFormats.Add(TEllipticCurvePointFormat.Uncompressed); serverHello.AddExtension(pointFormatsExtension); } session.Handshake.MessageSequence = 1; SendResponse(session, serverHello, session.Handshake.MessageSequence); session.Handshake.MessageSequence++; if (keyExchangeAlgorithm == TKeyExchangeAlgorithm.ECDHE_ECDSA) { if (Certificate != null) { SendResponse(session, Certificate, session.Handshake.MessageSequence); session.Handshake.MessageSequence++; } ECDHEKeyExchange keyExchange = new ECDHEKeyExchange { Curve = curve, KeyExchangeAlgorithm = keyExchangeAlgorithm, ClientRandom = clientHello.Random, ServerRandom = serverHello.Random }; keyExchange.GenerateEphemeralKey(); session.Handshake.KeyExchange = keyExchange; if (session.Version == DTLSRecord.DefaultVersion) { hash = THashAlgorithm.SHA1; } ECDHEServerKeyExchange serverKeyExchange = new ECDHEServerKeyExchange(keyExchange, hash, TSignatureAlgorithm.ECDSA, PrivateKey); SendResponse(session, serverKeyExchange, session.Handshake.MessageSequence); session.Handshake.MessageSequence++; if (_RequireClientCertificate) { CertificateRequest certificateRequest = new CertificateRequest(); certificateRequest.CertificateTypes.Add(TClientCertificateType.ECDSASign); certificateRequest.SupportedAlgorithms.Add(new SignatureHashAlgorithm() { Hash = THashAlgorithm.SHA256, Signature = TSignatureAlgorithm.ECDSA }); SendResponse(session, certificateRequest, session.Handshake.MessageSequence); session.Handshake.MessageSequence++; } } else if (keyExchangeAlgorithm == TKeyExchangeAlgorithm.ECDHE_PSK) { ECDHEKeyExchange keyExchange = new ECDHEKeyExchange { Curve = curve, KeyExchangeAlgorithm = keyExchangeAlgorithm, ClientRandom = clientHello.Random, ServerRandom = serverHello.Random }; keyExchange.GenerateEphemeralKey(); session.Handshake.KeyExchange = keyExchange; ECDHEPSKServerKeyExchange serverKeyExchange = new ECDHEPSKServerKeyExchange(keyExchange); SendResponse(session, serverKeyExchange, session.Handshake.MessageSequence); session.Handshake.MessageSequence++; } else if (keyExchangeAlgorithm == TKeyExchangeAlgorithm.PSK) { PSKKeyExchange keyExchange = new PSKKeyExchange { KeyExchangeAlgorithm = keyExchangeAlgorithm, ClientRandom = clientHello.Random, ServerRandom = serverHello.Random }; session.Handshake.KeyExchange = keyExchange; //Need to be able to hint identity?? for PSK if not hinting don't really need key exchange message //PSKServerKeyExchange serverKeyExchange = new PSKServerKeyExchange(); //SendResponse(session, serverKeyExchange, session.Handshake.MessageSequence); //session.Handshake.MessageSequence++; } SendResponse(session, new ServerHelloDone(), session.Handshake.MessageSequence); session.Handshake.MessageSequence++; } } } break; case THandshakeType.ServerHello: break; case THandshakeType.HelloVerifyRequest: break; case THandshakeType.Certificate: Certificate clientCertificate = Certificate.Deserialise(stream, TCertificateType.X509); if (clientCertificate.CertChain.Count > 0) { session.CertificateInfo = Certificates.GetCertificateInfo(clientCertificate.CertChain[0], TCertificateFormat.CER); } session.Handshake.UpdateHandshakeHash(data); break; case THandshakeType.ServerKeyExchange: break; case THandshakeType.CertificateRequest: break; case THandshakeType.ServerHelloDone: break; case THandshakeType.CertificateVerify: CertificateVerify certificateVerify = CertificateVerify.Deserialise(stream, session.Version); session.Handshake.UpdateHandshakeHash(data); break; case THandshakeType.ClientKeyExchange: if ((session == null) || (session.Handshake.KeyExchange == null)) { } else { session.Handshake.UpdateHandshakeHash(data); byte[] preMasterSecret = null; if (session.Handshake.KeyExchange.KeyExchangeAlgorithm == TKeyExchangeAlgorithm.ECDHE_ECDSA) { ECDHEClientKeyExchange clientKeyExchange = ECDHEClientKeyExchange.Deserialise(stream); if (clientKeyExchange != null) { ECDHEKeyExchange ecKeyExchange = session.Handshake.KeyExchange as ECDHEKeyExchange; preMasterSecret = ecKeyExchange.GetPreMasterSecret(clientKeyExchange.PublicKeyBytes); } } else if (session.Handshake.KeyExchange.KeyExchangeAlgorithm == TKeyExchangeAlgorithm.ECDHE_PSK) { ECDHEPSKClientKeyExchange clientKeyExchange = ECDHEPSKClientKeyExchange.Deserialise(stream); if (clientKeyExchange != null) { session.PSKIdentity = Encoding.UTF8.GetString(clientKeyExchange.PSKIdentity); byte[] psk = _PSKIdentities.GetKey(clientKeyExchange.PSKIdentity); if (psk == null) { psk = _ValidatePSK(clientKeyExchange.PSKIdentity); if (psk != null) { _PSKIdentities.AddIdentity(clientKeyExchange.PSKIdentity, psk); } } if (psk != null) { ECDHEKeyExchange ecKeyExchange = session.Handshake.KeyExchange as ECDHEKeyExchange; byte[] otherSecret = ecKeyExchange.GetPreMasterSecret(clientKeyExchange.PublicKeyBytes); preMasterSecret = TLSUtils.GetPSKPreMasterSecret(otherSecret, psk); } } } else if (session.Handshake.KeyExchange.KeyExchangeAlgorithm == TKeyExchangeAlgorithm.PSK) { PSKClientKeyExchange clientKeyExchange = PSKClientKeyExchange.Deserialise(stream); if (clientKeyExchange != null) { session.PSKIdentity = Encoding.UTF8.GetString(clientKeyExchange.PSKIdentity); byte[] psk = _PSKIdentities.GetKey(clientKeyExchange.PSKIdentity); if (psk == null) { psk = _ValidatePSK(clientKeyExchange.PSKIdentity); if (psk != null) { _PSKIdentities.AddIdentity(clientKeyExchange.PSKIdentity, psk); } } if (psk != null) { ECDHEKeyExchange ecKeyExchange = session.Handshake.KeyExchange as ECDHEKeyExchange; byte[] otherSecret = new byte[psk.Length]; preMasterSecret = TLSUtils.GetPSKPreMasterSecret(otherSecret, psk); } } } if (preMasterSecret != null) { //session.MasterSecret = TLSUtils.CalculateMasterSecret(preMasterSecret, session.KeyExchange); //TLSUtils.AssignCipher(session); session.Cipher = TLSUtils.AssignCipher(preMasterSecret, false, session.Version, session.Handshake); } else { Console.WriteLine($"preMasterSecret is null!"); } } break; case THandshakeType.Finished: Finished finished = Finished.Deserialise(stream); if (session != null) { byte[] handshakeHash = session.Handshake.GetHash(); byte[] calculatedVerifyData = TLSUtils.GetVerifyData(session.Version, session.Handshake, false, true, handshakeHash); #if DEBUG Console.Write($"Handshake Hash: {TLSUtils.WriteToString(handshakeHash)}"); Console.Write($"Sent Verify: {TLSUtils.WriteToString(finished.VerifyData)}"); Console.Write($"Calc Verify: {TLSUtils.WriteToString(calculatedVerifyData)}"); #endif if (TLSUtils.ByteArrayCompare(finished.VerifyData, calculatedVerifyData)) { SendChangeCipherSpec(session); session.Handshake.UpdateHandshakeHash(data); handshakeHash = session.Handshake.GetHash(); Finished serverFinished = new Finished { VerifyData = TLSUtils.GetVerifyData(session.Version, session.Handshake, false, false, handshakeHash) }; SendResponse(session, serverFinished, session.Handshake.MessageSequence); session.Handshake.MessageSequence++; } else { throw new Exception(); } } break; default: break; } } } }
private void SendHello(byte[] cookie) { ClientHello clientHello = new ClientHello(); clientHello.ClientVersion = SupportedVersion; clientHello.Random = _HandshakeInfo.ClientRandom; clientHello.Cookie = cookie; ushort[] cipherSuites = new ushort[_SupportedCipherSuites.Count]; int index = 0; foreach (TCipherSuite item in _SupportedCipherSuites) { cipherSuites[index] = (ushort)item; index++; } clientHello.CipherSuites = cipherSuites; clientHello.CompressionMethods = new byte[1]; clientHello.CompressionMethods[0] = 0; clientHello.Extensions = new Extensions(); clientHello.Extensions.Add(new Extension() { ExtensionType = TExtensionType.EncryptThenMAC}); clientHello.Extensions.Add(new Extension() { ExtensionType = TExtensionType.ExtendedMasterSecret }); EllipticCurvesExtension ellipticCurvesExtension = new EllipticCurvesExtension(); for (int curve = 0; curve < (int)TEllipticCurve.secp521r1; curve++) { if (EllipticCurveFactory.SupportedCurve((TEllipticCurve)curve)) { ellipticCurvesExtension.SupportedCurves.Add((TEllipticCurve)curve); } } clientHello.Extensions.Add(new Extension(ellipticCurvesExtension)); EllipticCurvePointFormatsExtension cllipticCurvePointFormatsExtension = new EllipticCurvePointFormatsExtension(); cllipticCurvePointFormatsExtension.SupportedPointFormats.Add(TEllipticCurvePointFormat.Uncompressed); clientHello.Extensions.Add(new Extension(cllipticCurvePointFormatsExtension)); SignatureAlgorithmsExtension signatureAlgorithmsExtension = new SignatureAlgorithmsExtension(); signatureAlgorithmsExtension.SupportedAlgorithms.Add(new SignatureHashAlgorithm() { Hash= THashAlgorithm.SHA256, Signature = TSignatureAlgorithm.ECDSA }); clientHello.Extensions.Add(new Extension(signatureAlgorithmsExtension)); _HandshakeInfo.InitaliseHandshakeHash(false); SendHandshakeMessage(clientHello, false); }