Exemple #1
0
        public static void SetDh(HandshakeState state, byte[] ephemeral)
        {
            var flags = BindingFlags.Instance | BindingFlags.NonPublic;
            var setDh = state.GetType().GetMethod("SetDh", flags);

            setDh.Invoke(state, new object[] { new FixedKeyDh(ephemeral) });
        }
        protected HandshakeSession(SecurityParameters securityParameters, ILogger logger)
        {
            this.logger = logger;

            _pluginManager = new CipherSuitePluginManager(this.logger);
            _state = HandshakeState.Initial;

            _minVersion = securityParameters.MinimumVersion;
            _maxVersion = securityParameters.MaximumVersion;
            _supportedCipherSuites = securityParameters.CipherSuiteIDs.ToArray();
            _supportedCompressions = securityParameters.CompressionIDs.ToArray();

            _availableCertificates = new List<X509CertificateCollection>(securityParameters.AvailableCertificates);
            _availablePrivateKeys = new List<CertificatePrivateKey>(securityParameters.AvailablePrivateKeys);

            _clientCertificates = new X509CertificateCollection();
            _serverCertificates = new X509CertificateCollection();

            // Initialize the default ClientHello version, to
            // be as compatible as possible based on maxVersion
            _version = _minVersion;

            
            _cipherSuite = new CipherSuite(_version);
        }
Exemple #3
0
        protected HandshakeSession(SecurityParameters securityParameters)
        {
            string path      = System.Reflection.Assembly.GetAssembly(typeof(HandshakeSession)).Location;
            string directory = Path.GetDirectoryName(path);

            _pluginManager = new CipherSuitePluginManager(directory);
            _state         = HandshakeState.Initial;

            _minVersion            = securityParameters.MinimumVersion;
            _maxVersion            = securityParameters.MaximumVersion;
            _supportedCipherSuites = securityParameters.CipherSuiteIDs.ToArray();
            _supportedCompressions = securityParameters.CompressionIDs.ToArray();

            _availableCertificates = new List <X509CertificateCollection>(securityParameters.AvailableCertificates);
            _availablePrivateKeys  = new List <CertificatePrivateKey>(securityParameters.AvailablePrivateKeys);

            _clientCertificates = new X509CertificateCollection();
            _serverCertificates = new X509CertificateCollection();

            // Initialize the default ClientHello version, to
            // be as compatible as possible based on maxVersion
            if (_maxVersion == ProtocolVersion.SSL3_0)
            {
                _version = ProtocolVersion.SSL3_0;
            }
            else if (_maxVersion.IsUsingDatagrams)
            {
                _version = ProtocolVersion.DTLS1_0;
            }
            else
            {
                _version = ProtocolVersion.TLS1_0;
            }
            _cipherSuite = new CipherSuite(_version);
        }
Exemple #4
0
        private static async Task Server(HandshakeState handshakeState)
        {
            var buffer = new byte[Protocol.MaxMessageLength];

            // Receive the first handshake message from the client.
            var received = await clientToServer.Receive();

            handshakeState.ReadMessage(received, buffer);

            // Send the second handshake message to the client.
            var(bytesWritten, _, transport) = handshakeState.WriteMessage(null, buffer);
            await serverToClient.Send(Slice(buffer, bytesWritten));

            // Handshake complete, switch to transport mode.
            using (transport)
            {
                for (;;)
                {
                    // Receive the message from the client.
                    var request = await clientToServer.Receive();

                    var bytesRead = transport.ReadMessage(request, buffer);

                    // Echo the message back to the client.
                    bytesWritten = transport.WriteMessage(Slice(buffer, bytesRead), buffer);
                    await serverToClient.Send(Slice(buffer, bytesWritten));
                }
            }
        }
Exemple #5
0
        private static async Task Client(HandshakeState state)
        {
            var buffer = new byte[Protocol.MaxMessageLength];

            // Send the first handshake message to the server.
            var(bytesWritten, _, _) = state.WriteMessage(null, buffer);
            await clientToServer.Send(Slice(buffer, bytesWritten));

            // Receive the second handshake message from the server.
            var received = await serverToClient.Receive();

            var(_, _, transport) = state.ReadMessage(received, buffer);

            // Handshake complete, switch to transport mode.
            using (transport)
            {
                foreach (var message in messages)
                {
                    Memory <byte> request = Encoding.UTF8.GetBytes(message);

                    // Send the message to the server.
                    bytesWritten = transport.WriteMessage(request.Span, buffer);
                    await clientToServer.Send(Slice(buffer, bytesWritten));

                    // Receive the response and print it to the standard output.
                    var response = await serverToClient.Receive();

                    var bytesRead = transport.ReadMessage(response, buffer);

                    Console.WriteLine(Encoding.UTF8.GetString(Slice(buffer, bytesRead)));
                }
            }
        }
Exemple #6
0
 /// <summary>
 /// Sent to backend
 /// </summary>
 public Handshake(string host, int port, HandshakeState state)
 {
     Version = MinecraftServer.BackendVersion;
     Host = host;
     Port = port;
     State = state;
     Prepare();
 }
Exemple #7
0
 /// <summary>
 /// Sent to backend
 /// </summary>
 public Handshake(string host, int port, HandshakeState state)
 {
     Version = MinecraftServer.BackendVersion;
     Host    = host;
     Port    = port;
     State   = state;
     Prepare();
 }
Exemple #8
0
 protected override void Parse(EndianBinaryReader r)
 {
     Version = (ProtocolVersion)ReadVarInt(r);
     Host = ReadString8(r);
     Port = r.ReadUInt16();
     State = (HandshakeState)ReadVarInt(r);
     
     DebugGotAll(r);
 }
Exemple #9
0
        protected override void Parse(EndianBinaryReader r)
        {
            Version = (ProtocolVersion)ReadVarInt(r);
            Host    = ReadString8(r);
            Port    = r.ReadUInt16();
            State   = (HandshakeState)ReadVarInt(r);

            DebugGotAll(r);
        }
Exemple #10
0
 /// <summary>
 /// Renegotiate session keys - calls SSL_renegotiate
 /// </summary>
 public void Renegotiate()
 {
     if (ssl != null)
     {
         // Call the SSL_renegotiate to reset the SSL object state
         // to start handshake
         Native.ExpectSuccess(Native.SSL_renegotiate(ssl.Handle));
         handShakeState = HandshakeState.Renegotiate;
     }
 }
Exemple #11
0
 public virtual void Clear()
 {
     compressionMethod = SecurityCompressionType.None;
     serverSettings    = new TlsServerSettings();
     clientSettings    = new TlsClientSettings();
     handshakeMessages = new TlsStream();
     sessionId         = null;
     handshakeState    = HandshakeState.None;
     ClearKeyInfo();
 }
Exemple #12
0
 public virtual void Clear()
 {
     this.compressionMethod = SecurityCompressionType.None;
     this.serverSettings    = new TlsServerSettings();
     this.clientSettings    = new TlsClientSettings();
     this.handshakeMessages = new TlsStream();
     this.sessionId         = (byte[])null;
     this.handshakeState    = HandshakeState.None;
     this.ClearKeyInfo();
 }
 public Context(SecurityProtocolType securityProtocolType)
 {
     this.SecurityProtocol  = securityProtocolType;
     this.compressionMethod = SecurityCompressionType.None;
     this.serverSettings    = new TlsServerSettings();
     this.clientSettings    = new TlsClientSettings();
     this.handshakeMessages = new TlsStream();
     this.sessionId         = null;
     this.handshakeState    = HandshakeState.None;
     this.random            = RandomNumberGenerator.Create();
 }
        public unsafe NoiseProtocol(bool initiator, byte *sk, PskRef psk, byte[] publicKey = default,
                                    string id = default, TextWriter @out = default)
        {
            _initiator = initiator;
            _id        = id ?? "[NOISE]";
            _out       = @out;
            var psks = new List <PskRef> {
                psk
            };

            _state    = Protocol.Create(initiator, default, sk, (int)Crypto.EncryptionKeyBytes, publicKey, psks);
        public void Connect(VpnChannel channel)
        {
            string serverPort = "8000";
            string secret     = "test";
            string parameters = null;

            _datagramSocket = new DatagramSocket();
            channel.AssociateTransport(_datagramSocket, null);
            _datagramSocket.MessageReceived += (s, e) =>
            {
                DataReader dataReader = e.GetDataReader();
                if (dataReader.UnconsumedBufferLength > 0 && dataReader.ReadByte() == 0)
                {
                    parameters      = dataReader.ReadString(dataReader.UnconsumedBufferLength);
                    _handshakeState = HandshakeState.Received;
                }
            };
            var         serverHostName = channel.Configuration.ServerHostNameList[0];
            XmlDocument xmlDocument    = new XmlDocument();

            xmlDocument.LoadXml(channel.Configuration.CustomField);
            var firstChild = xmlDocument.FirstChild;

            if (firstChild.Name.Equals("ToyVpnConfig"))
            {
                foreach (XmlNode childNode in firstChild.ChildNodes)
                {
                    if (childNode.Name.Equals("ServerPort"))
                    {
                        serverPort = childNode.InnerText;
                    }
                    else if (childNode.Name.Equals("Secret"))
                    {
                        secret = childNode.InnerText;
                    }
                }
            }
            _datagramSocket.ConnectAsync(serverHostName, serverPort).AsTask().GetAwaiter().GetResult();
            _handshakeState = HandshakeState.Waiting;
            HandShake(_datagramSocket, secret).AsTask().GetAwaiter().GetResult();
            if (_handshakeState == HandshakeState.Received)
            {
                ConfigureAndConnect(channel, parameters);
            }
            else
            {
                channel.Stop();
            }
        }
        private IAsyncResult BeginHandshake(InternalAsyncResult readwriteAsyncResult)
        {
            if (disposed)
            {
                return(null);
            }
            //!!
            // Move the handshake state to the next state
            //if (handShakeState == HandshakeState.Renegotiate)
            //{
            //    handShakeState = HandshakeState.RenegotiateInProcess;
            //}
            //else
            if (handShakeState != HandshakeState.Renegotiate)
            {
                handShakeState = HandshakeState.InProcess;
            }

            // Wrap the read/write InternalAsyncResult in the Handshake InternalAsyncResult instance
            var handshakeAsyncResult = new InternalAsyncResult(
                AsyncHandshakeComplete,
                readwriteAsyncResult,
                null,
                0,
                0,
                readwriteAsyncResult.IsWriteOperation,
                readwriteAsyncResult.ContinueAfterHandshake);

            if (ProcessHandshake())
            {
                handShakeState = HandshakeState.Complete;
                handshakeAsyncResult.SetComplete();
            }
            else
            {
                //!! if (readwriteAsyncResult.IsWriteOperation)
                if (write_bio.BytesPending > 0)
                {
                    handshakeAsyncResult.IsWriteOperation = true;
                    BeginWrite(new byte[0], 0, 0, AsyncHandshakeCallback, handshakeAsyncResult);
                }
                else
                {
                    handshakeAsyncResult.IsWriteOperation = false;
                    BeginRead(new byte[0], 0, 0, AsyncHandshakeCallback, handshakeAsyncResult);
                }
            }
            return(handshakeAsyncResult);
        }
Exemple #17
0
        protected HandshakeSession(SecurityParameters securityParameters)
        {
            _pluginManager = new CipherSuitePluginManager();
            _state         = HandshakeState.Initial;

            _minVersion            = securityParameters.MinimumVersion;
            _maxVersion            = securityParameters.MaximumVersion;
            _supportedCipherSuites = securityParameters.CipherSuiteIDs.ToArray();
            _supportedCompressions = securityParameters.CompressionIDs.ToArray();

            _availableCertificates = new List <X509CertificateCollection>(securityParameters.AvailableCertificates);
            _availablePrivateKeys  = new List <CertificatePrivateKey>(securityParameters.AvailablePrivateKeys);

            _clientCertificates = new X509CertificateCollection();
            _serverCertificates = new X509CertificateCollection();

            // Initialize the default ClientHello version, to
            // be as compatible as possible based on maxVersion
            _version = _minVersion;


            _cipherSuite = new CipherSuite(_version);
        }
Exemple #18
0
        private void Reinitialize(Protocol protocol, ProtocolConfig config, State state)
        {
            bool fallback = state == State.Switch && (protocol.Modifiers & PatternModifiers.Fallback) != 0;

            if (fallback && handshakeState == null)
            {
                throw new InvalidOperationException("Cannot perform the fallback handshake on an uninitialized server.");
            }

            if (protocol.HandshakePattern.Patterns.Count() == 1)
            {
                throw new NotSupportedException("One-way patterns are not yet supported.");
            }

            if (transport != null)
            {
                throw new InvalidOperationException($"Cannot change protocol after the handshake has been completed.");
            }

            if (this.state != State.Initial)
            {
                throw new InvalidOperationException($"Cannot change protocol more than once.");
            }

            this.protocol = protocol;
            this.config   = config;
            this.state    = state;
            this.fallback = fallback;

            if (!fallback && handshakeState != null)
            {
                handshakeState.Dispose();
                handshakeState = null;
            }

            isNextMessageEncrypted = IsInitialMessageEncrypted(protocol);
        }
Exemple #19
0
        /// <summary>
        /// Apply the first authorization step
        /// </summary>
        /// <returns></returns>
        protected override Task ApplyResponseChallengeAsync()
        {
            // only act on unauthorized responses
            if (Response.StatusCode == 401 && Response.Headers.ContainsKey("WWW-Authenticate") == false)
            {
                var challenge = Helper.LookupChallenge(Options.AuthenticationType, Options.AuthenticationMode);

                // this migth be our chance to request NTLM authentication!
                if (challenge != null)
                {
                    var authProperties = challenge.Properties;

                    if (string.IsNullOrEmpty(authProperties.RedirectUri))
                    {
                        throw new ArgumentException("The authentication challenge's redirect URI can't be empty!");
                    }

                    // get a fairly "unique" string to use in the redirection URL
                    var protectedProperties = Options.StateDataFormat.Protect(authProperties);
                    var stateHash           = CalculateMD5Hash(protectedProperties);

                    // create a new handshake state
                    var state = new HandshakeState()
                    {
                        AuthenticationProperties = authProperties
                    };

                    // and store it in the state cache
                    Options.LoginStateCache.Add(stateHash, state);

                    // redirect to trigger trigger NTLM authentication
                    Response.Redirect(WebUtilities.AddQueryString(Options.CallbackPath.Value, "state", stateHash));
                }
            }

            return(Task.Delay(0));
        }
Exemple #20
0
        private void InitializeHandshakeState()
        {
            if (fallback)
            {
                Debug.Assert(protocol != null);

                var config = new ProtocolConfig(
                    this.config.Initiator,
                    CalculatePrologue(),
                    this.config.LocalStatic,
                    this.config.RemoteStatic,
                    this.config.PreSharedKeys
                    );

                handshakeState.Fallback(protocol, config);
                fallback = false;
            }
            else if (handshakeState == null)
            {
                if (protocol == null)
                {
                    string error = $"Cannot perform the handshake before calling either {nameof(Accept)}, {nameof(Switch)}, or {nameof(Retry)}.";
                    throw new InvalidOperationException(error);
                }

                handshakeState = protocol.Create(
                    config.Initiator,
                    CalculatePrologue(),
                    config.LocalStatic,
                    config.RemoteStatic,
                    config.PreSharedKeys
                    );

                initializer?.Invoke(handshakeState);
            }
        }
Exemple #21
0
        /// <summary>
        /// Asynchronously reads the handshake message from the input stream.
        /// </summary>
        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
        /// <returns>
        /// A task that represents the asynchronous read operation.
        /// The result of the task contains the decrypted message body.
        /// </returns>
        /// <exception cref="ObjectDisposedException">
        /// Thrown if either the current instance, or the input stream has already been disposed.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// Thrown if the call to this method was unexpected in the current state of this object.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// Thrown if the decrypted message body length was invalid.
        /// </exception>
        /// <exception cref="System.Security.Cryptography.CryptographicException">
        /// Thrown if the decryption of the message has failed.
        /// </exception>
        /// <exception cref="IOException">Thrown if an I/O error occurs.</exception>
        /// <exception cref="NotSupportedException">Thrown if the stream does not support reading.</exception>
        /// <remarks>
        /// This method can also throw all exceptions that <see cref="Protocol.Create(ProtocolConfig)"/>
        /// and <see cref="HandshakeState.Fallback(Protocol, ProtocolConfig)"/> methods can throw.
        /// See <see cref="Protocol"/> and <see cref="HandshakeState"/> documentation for more details.
        /// </remarks>
        public async Task <byte[]> ReadHandshakeMessageAsync(CancellationToken cancellationToken = default)
        {
            ThrowIfDisposed();

            if (this.transport != null)
            {
                throw new InvalidOperationException($"Cannot call {nameof(ReadHandshakeMessageAsync)} after the handshake has been completed.");
            }

            InitializeHandshakeState();

            var noiseMessage = await ReadPacketAsync(stream, cancellationToken).ConfigureAwait(false);

            ProcessMessage(HandshakeOperation.ReadHandshakeMessage, noiseMessage, false);

            var plaintext = new byte[noiseMessage.Length];

            var(bytesRead, handshakeHash, transport) = handshakeState.ReadMessage(noiseMessage, plaintext);

            if (transport != null)
            {
                handshakeState.Dispose();
                handshakeState = null;

                this.handshakeHash = handshakeHash;
                this.transport     = transport;
            }

            if (isNextMessageEncrypted)
            {
                return(ReadPacket(plaintext.AsSpan(0, bytesRead)));
            }

            isNextMessageEncrypted = true;
            return(plaintext.AsSpan(0, bytesRead).ToArray());
        }
Exemple #22
0
        /// <summary>
        /// Disco peer initialization
        /// </summary>
        /// <param name="handshakeType">Noise handshake pattern</param>
        /// <param name="initiator">This party initiates connection</param>
        /// <param name="prologue">Prologue string, some data prior to handshake</param>
        /// <param name="s">local static key</param>
        /// <param name="e">local ephemeral key</param>
        /// <param name="rs">remote static key</param>
        /// <param name="re">remote ephemeral key</param>
        /// <returns>Initialized Disco handshake state</returns>
        public static HandshakeState InitializeDisco(
            NoiseHandshakeType handshakeType,
            bool initiator,
            byte[] prologue,
            KeyPair s,
            KeyPair e,
            KeyPair rs,
            KeyPair re)
        {
            var handshakePattern = HandshakePattern.GetPattern(handshakeType);

            var handshakeState = new HandshakeState
            {
                SymmetricState = new SymmetricState($"Noise_{handshakePattern.Name}_25519_STROBEv1.0.2"),
                Initiator      = initiator,
                ShouldWrite    = initiator
            };

            try
            {
                if (prologue != null)
                {
                    handshakeState.SymmetricState.MixHash(prologue);
                }

                if (s != null)
                {
                    handshakeState.S = s;
                }

                if (e != null)
                {
                    throw new NotSupportedException("disco: fallback patterns are not implemented");
                }

                if (rs != null)
                {
                    handshakeState.Rs = rs;
                }

                if (re != null)
                {
                    throw new NotSupportedException("disco: fallback patterns are not implemented");
                }

                //Calls MixHash() once for each public key listed in the pre-messages from handshake_pattern,
                //with the specified public key as input (see Section 7 for an explanation of pre-messages).
                //If both initiator and responder have pre-messages, the initiator's public keys are hashed first.

                // initiator pre-message pattern
                foreach (var token in handshakePattern.PreMessagePatterns[0])
                {
                    if (token == Tokens.TokenS)
                    {
                        if (initiator)
                        {
                            if (s == null)
                            {
                                throw new Exception("disco: the static key of the client should be set");
                            }

                            handshakeState.SymmetricState.MixHash(s.PublicKey);
                        }
                        else
                        {
                            if (rs == null)
                            {
                                throw new Exception("disco: the remote static key of the server should be set");
                            }

                            handshakeState.SymmetricState.MixHash(rs.PublicKey);
                        }
                    }
                    else
                    {
                        throw new Exception("disco: token of pre-message not supported");
                    }
                }

                // responder pre-message pattern
                foreach (var token in handshakePattern.PreMessagePatterns[1])
                {
                    if (token == Tokens.TokenS)
                    {
                        if (initiator)
                        {
                            if (rs == null)
                            {
                                throw new Exception("disco: the remote static key of the client should be set");
                            }

                            handshakeState.SymmetricState.MixHash(rs.PublicKey);
                        }
                        else
                        {
                            if (s == null)
                            {
                                throw new Exception("disco: the static key of the server should be set");
                            }

                            handshakeState.SymmetricState.MixHash(s.PublicKey);
                        }
                    }
                    else
                    {
                        throw new NotSupportedException("disco: token of pre - message not supported");
                    }
                }

                handshakeState.MessagePatterns = handshakePattern.MessagePatterns;
                return(handshakeState);
            }
            catch (Exception)
            {
                handshakeState.Dispose();
                throw;
            }
        }
		public virtual void Clear()
		{
			this.compressionMethod	= SecurityCompressionType.None;
			this.serverSettings		= new TlsServerSettings();
			this.clientSettings		= new TlsClientSettings();
			this.handshakeMessages	= new TlsStream();
			this.sessionId			= null;
			this.handshakeState		= HandshakeState.None;

			this.ClearKeyInfo();
		}
		public Context(SecurityProtocolType securityProtocolType)
		{
			this.SecurityProtocol	= securityProtocolType;
			this.compressionMethod	= SecurityCompressionType.None;
			this.serverSettings		= new TlsServerSettings();
			this.clientSettings		= new TlsClientSettings();
			this.handshakeMessages	= new TlsStream();
			this.sessionId			= null;
			this.handshakeState		= HandshakeState.None;
			this.random				= RandomNumberGenerator.Create();
		}
        protected HandshakeSession(SecurityParameters securityParameters)
        {
            string path = System.Reflection.Assembly.GetAssembly(typeof(HandshakeSession)).Location;
            string directory = Path.GetDirectoryName(path);

            _pluginManager = new CipherSuitePluginManager(directory);
            _state = HandshakeState.Initial;

            _minVersion = securityParameters.MinimumVersion;
            _maxVersion = securityParameters.MaximumVersion;
            _supportedCipherSuites = securityParameters.CipherSuiteIDs.ToArray();
            _supportedCompressions = securityParameters.CompressionIDs.ToArray();

            _availableCertificates = new List<X509CertificateCollection>(securityParameters.AvailableCertificates);
            _availablePrivateKeys = new List<CertificatePrivateKey>(securityParameters.AvailablePrivateKeys);

            _clientCertificates = new X509CertificateCollection();
            _serverCertificates = new X509CertificateCollection();

            // Initialize the default ClientHello version, to
            // be as compatible as possible based on maxVersion
            if (_maxVersion == ProtocolVersion.SSL3_0) {
                _version = ProtocolVersion.SSL3_0;
            } else if (_maxVersion.IsUsingDatagrams) {
                _version = ProtocolVersion.DTLS1_0;
            } else {
                _version = ProtocolVersion.TLS1_0;
            }
            _cipherSuite = new CipherSuite(_version);
        }
Exemple #26
0
        void handshakeSendHandler(IAsyncResult ar)
        {
            if (_closing || _disposed)
                return;
            
            try
            {
                _stream.EndWrite(ar);
            }
            catch (SocketException ex)
            {
                shutdown("Unable to resolve host(" + ex.Message +  ")");
                return;
            }

            HandshakeState state = new HandshakeState();

            _stream.BeginRead(state.data,
                              0,
                              state.data.Length,
                              new AsyncCallback(handshakeHandler),
                              state);
        }
Exemple #27
0
        /// <summary>
        /// Asynchronously writes the negotiation data and the handshake message to the input stream.
        /// </summary>
        /// <param name="negotiationData">The negotiation data.</param>
        /// <param name="messageBody">The message body to encrypt.</param>
        /// <param name="paddedLength">
        /// If this message has an encrypted payload and the length of the
        /// <paramref name="messageBody"/> is less than <paramref name="paddedLength"/>,
        /// <paramref name="messageBody"/> is padded to make its
        /// length equal to <paramref name="paddedLength"/>.
        /// </param>
        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
        /// <returns>A task that represents the asynchronous write operation.</returns>
        /// <exception cref="ObjectDisposedException">
        /// Thrown if either the current instance, or the output stream has already been disposed.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// Thrown if the call to this method was unexpected in the current state of this object.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// Thrown if either the negotiation data, or the Noise message was greater
        /// than <see cref="Protocol.MaxMessageLength"/> bytes in length.
        /// </exception>
        /// <exception cref="IOException">Thrown if an I/O error occurs.</exception>
        /// <exception cref="NotSupportedException">Thrown if the stream does not support reading.</exception>
        /// <remarks>
        /// This method can also throw all exceptions that <see cref="Protocol.Create(ProtocolConfig)"/>
        /// and <see cref="HandshakeState.Fallback(Protocol, ProtocolConfig)"/> methods can throw.
        /// See <see cref="Protocol"/> and <see cref="HandshakeState"/> documentation for more details.
        /// </remarks>
        public async Task WriteHandshakeMessageAsync(
            Memory <byte> negotiationData       = default,
            Memory <byte> messageBody           = default,
            ushort paddedLength                 = default,
            CancellationToken cancellationToken = default)
        {
            ThrowIfDisposed();

            if (this.transport != null)
            {
                throw new InvalidOperationException($"Cannot call {nameof(WriteHandshakeMessageAsync)} after the handshake has been completed.");
            }

            if (negotiationData.Length > Protocol.MaxMessageLength)
            {
                throw new ArgumentException($"Negotiation data must be less than or equal to {Protocol.MaxMessageLength} bytes in length.");
            }

            if (messageBody.Length > Protocol.MaxMessageLength)
            {
                throw new ArgumentException($"Handshake message must be less than or equal to {Protocol.MaxMessageLength} bytes in length.");
            }

            ProcessMessage(HandshakeOperation.WriteNegotiationData, negotiationData);
            InitializeHandshakeState();

            // negotiation_data_len (2 bytes)
            // negotiation_data
            // noise_message_len (2 bytes)
            // noise_message
            int negotiationLength = LenFieldSize + negotiationData.Length;
            int maxNoiseLength    = LenFieldSize + Protocol.MaxMessageLength;

            // Prevent the buffer from going to the LOH (it may be greater than 85000 bytes).
            var pool   = ArrayPool <byte> .Shared;
            var buffer = pool.Rent(negotiationLength + maxNoiseLength);

            try
            {
                Memory <byte> plaintext = messageBody;

                if (isNextMessageEncrypted)
                {
                    plaintext = new byte[LenFieldSize + Math.Max(messageBody.Length, paddedLength)];
                    WritePacket(messageBody.Span, plaintext.Span);
                }

                var ciphertext = buffer.AsMemory(negotiationLength + LenFieldSize);
                var(bytesWritten, handshakeHash, transport) = handshakeState.WriteMessage(plaintext.Span, ciphertext.Span);
                isNextMessageEncrypted = true;

                if (transport != null)
                {
                    handshakeState.Dispose();
                    handshakeState = null;

                    this.handshakeHash = handshakeHash;
                    this.transport     = transport;
                }

                WritePacket(negotiationData.Span, buffer);
                BinaryPrimitives.WriteUInt16BigEndian(buffer.AsSpan(negotiationLength), (ushort)bytesWritten);
                ProcessMessage(HandshakeOperation.WriteHandshakeMessage, ciphertext.Slice(0, bytesWritten));

                int noiseLength     = LenFieldSize + bytesWritten;
                int handshakeLength = negotiationLength + noiseLength;

                await stream.WriteAsync(buffer, 0, handshakeLength, cancellationToken).ConfigureAwait(false);
            }
            finally
            {
                pool.Return(buffer);
            }
        }
Exemple #28
0
        /// <summary>
        /// Perform handshake protocol if it has not been already run.
        /// </summary>
        /// <remarks>
        /// Most uses of this package need not call Handshake explicitly:
        /// the first Read or Write will call it automatically.
        /// </remarks>
        internal void HandShake()
        {
            // Locking the handshakeMutex
            this.handshakeMutex.WaitOne();

            HandshakeState handshakeState = null;

            try
            {
                Strobe c1;
                Strobe c2;
                byte[] receivedPayload = null;

                // did we already go through the handshake?
                if (this.handshakeComplite)
                {
                    return;
                }

                KeyPair remoteKeyPair = null;
                if (this.config.RemoteKey != null)
                {
                    if (this.config.RemoteKey.Length != Asymmetric.DhLen)
                    {
                        throw new Exception($"disco: the provided remote key is not {Asymmetric.DhLen}-byte");
                    }

                    remoteKeyPair = new KeyPair {
                        PublicKey = new byte[this.config.RemoteKey.Length]
                    };
                    Array.Copy(this.config.RemoteKey, remoteKeyPair.PublicKey, this.config.RemoteKey.Length);
                }

                handshakeState = DiscoHelper.InitializeDisco(
                    this.config.HandshakePattern,
                    this.isClient,
                    this.config.Prologue,
                    this.config.KeyPair,
                    null,
                    remoteKeyPair,
                    null);

                // pre-shared key
                handshakeState.Psk = this.config.PreSharedKey;

                do
                {
                    // start handshake
                    if (handshakeState.ShouldWrite)
                    {
                        // we're writing the next message pattern
                        // if it's the message pattern and we're sending a static key, we also send a proof
                        // TODO: is this the best way of sending a proof :/ ?
                        byte[] bufToWrite;

                        if (handshakeState.MessagePatterns.Length <= 2 && this.config.StaticPublicKeyProof != null)
                        {
                            (c1, c2) = handshakeState.WriteMessage(this.config.StaticPublicKeyProof, out bufToWrite);
                        }
                        else
                        {
                            (c1, c2) = handshakeState.WriteMessage(new byte[] { }, out bufToWrite);
                        }

                        // header (length)
                        var length = new[] { (byte)(bufToWrite.Length >> 8), (byte)(bufToWrite.Length % 256) };
                        // write
                        var dataToWrite = length.Concat(bufToWrite).ToArray();
                        this.connectionStream.Write(dataToWrite, 0, dataToWrite.Length);
                    }
                    else
                    {
                        var bufHeader = this.ReadFromUntil(this.connectionStream, 2);

                        var length = (bufHeader[0] << 8) | bufHeader[1];

                        if (length > Config.NoiseMessageLength)
                        {
                            throw new Exception("disco: Disco message received exceeds DiscoMessageLength");
                        }

                        var noiseMessage = this.ReadFromUntil(this.connectionStream, length);

                        (c1, c2) = handshakeState.ReadMessage(noiseMessage, out receivedPayload);
                    }
                }while (c1 == null);

                // Has the other peer been authenticated so far?
                if (!this.isRemoteAuthenticated && this.config.PublicKeyVerifier != null)
                {
                    byte isRemoteStaticKeySet = 0;
                    // test if remote static key is empty
                    foreach (var val in handshakeState.Rs.PublicKey)
                    {
                        isRemoteStaticKeySet |= val;
                    }

                    if (isRemoteStaticKeySet != 0)
                    {
                        // a remote static key has been received. Verify it
                        if (!this.config.PublicKeyVerifier(handshakeState.Rs.PublicKey, receivedPayload))
                        {
                            throw new Exception("disco: the received public key could not be authenticated");
                        }

                        this.isRemoteAuthenticated = true;
                        this.RemotePublicKey       = handshakeState.Rs.PublicKey;
                    }
                }

                // Processing the final handshake message returns two CipherState objects
                // the first for encrypting transport messages from initiator to responder
                // and the second for messages in the other direction.
                if (c2 != null)
                {
                    if (this.isClient)
                    {
                        (this.strobeOut, this.strobeIn) = (c1, c2);
                    }
                    else
                    {
                        (this.strobeOut, this.strobeIn) = (c2, c1);
                    }
                }
                else
                {
                    this.IsHalfDuplex = true;
                    this.strobeIn     = c1;
                    this.strobeOut    = c1;
                }

                // TODO: preserve c.hs.symmetricState.h
                // At that point the HandshakeState should be deleted except for the hash value h, which may be used for post-handshake channel binding (see Section 11.2).
                handshakeState.Dispose();

                // no errors :)
                this.handshakeComplite = true;
            }
            finally
            {
                handshakeState?.Dispose();
                this.handshakeMutex.ReleaseMutex();
            }
        }
        private void Handle(Action action, SocketError socketError, int bytesTransferred)
        {
            switch (m_state)
            {
            case State.Closed:
                switch (action)
                {
                case Action.Start:
                    if (m_options.RawSocket)
                    {
                        m_encoder = new RawEncoder(Config.OutBatchSize, m_session, m_options.Endian);
                        m_decoder = new RawDecoder(Config.InBatchSize, m_options.MaxMessageSize, m_session, m_options.Endian);

                        Activate();
                    }
                    else
                    {
                        m_state          = State.Handshaking;
                        m_handshakeState = HandshakeState.Closed;
                        HandleHandshake(action, socketError, bytesTransferred);
                    }

                    break;
                }
                break;

            case State.Handshaking:
                HandleHandshake(action, socketError, bytesTransferred);
                break;

            case State.Active:
                switch (action)
                {
                case Action.InCompleted:
                    m_insize = EndRead(socketError, bytesTransferred);

                    ProcessInput();
                    break;

                case Action.ActivateIn:

                    // if we stuck let's continue, other than that nothing to do
                    if (m_receivingState == ReceiveState.Stuck)
                    {
                        m_receivingState = ReceiveState.Active;
                        ProcessInput();
                    }
                    break;

                case Action.OutCompleted:
                    int bytesSent = EndWrite(socketError, bytesTransferred);

                    // IO error has occurred. We stop waiting for output events.
                    // The engine is not terminated until we detect input error;
                    // this is necessary to prevent losing incoming messages.
                    if (bytesSent == -1)
                    {
                        m_sendingState = SendState.Error;
                    }
                    else
                    {
                        m_outpos.AdvanceOffset(bytesSent);
                        m_outsize -= bytesSent;

                        BeginSending();
                    }
                    break;

                case Action.ActivateOut:
                    // if we idle we start sending, other than do nothing
                    if (m_sendingState == SendState.Idle)
                    {
                        m_sendingState = SendState.Active;
                        BeginSending();
                    }
                    break;

                default:
                    Debug.Assert(false);
                    break;
                }
                break;

            case State.Stalled:
                switch (action)
                {
                case Action.ActivateIn:
                    // There was an input error but the engine could not
                    // be terminated (due to the stalled decoder).
                    // Flush the pending message and terminate the engine now.
                    m_decoder.ProcessBuffer(m_inpos, 0);
                    Debug.Assert(!m_decoder.Stalled());
                    m_session.Flush();
                    Error();
                    break;

                case Action.ActivateOut:
                    break;
                }
                break;
            }
        }
 public HandshakeErrorEventArgs(HandshakeState state, string message)
     : base(message)
 {
     State = state;
 }
Exemple #31
0
        private void AsyncHandshakeCallback(IAsyncResult asyncResult)
        {
            // Get the handshake internal result instance
            InternalAsyncResult internalAsyncResult = (InternalAsyncResult)asyncResult.AsyncState;
            int bytesRead = 0;

            if (internalAsyncResult.IsWriteOperation)
            {
                EndWrite(asyncResult);
                // Check to see if the handshake is complete (this could have been
                // the last response packet from the server.  If so, we want to finalize
                // the async operation and call the HandshakeComplete callback
                if (handShakeState == HandshakeState.Complete)
                {
                    internalAsyncResult.SetComplete();
                    return;
                }
                // Check to see if we saved an exception from the last Handshake process call
                // the if the client gets an error code, it needs to send the alert, and then
                // throw the exception here.
                if (handshakeException != null)
                {
                    internalAsyncResult.SetComplete(handshakeException);
                    return;
                }
                // We wrote out the handshake data, now read to get the response
                internalAsyncResult.IsWriteOperation = false;
                BeginRead(new byte[0], 0, 0, new AsyncCallback(AsyncHandshakeCallback), internalAsyncResult);
            }
            else
            {
                try
                {
                    bytesRead = EndRead(asyncResult);
                    if (bytesRead > 0)
                    {
                        if (ProcessHandshake())
                        {
                            //inHandshakeLoop = false;
                            handShakeState = HandshakeState.Complete;
                            // We have completed the handshake, but need to send the
                            // last response packet.
                            if (write_bio.BytesPending > 0)
                            {
                                internalAsyncResult.IsWriteOperation = true;
                                BeginWrite(new byte[0], 0, 0, new AsyncCallback(AsyncHandshakeCallback), internalAsyncResult);
                            }
                            else
                            {
                                internalAsyncResult.SetComplete();
                                return;
                            }
                        }
                        else
                        {
                            // Not complete with the handshake yet, write the handshake packet out
                            internalAsyncResult.IsWriteOperation = true;
                            BeginWrite(new byte[0], 0, 0, new AsyncCallback(AsyncHandshakeCallback), internalAsyncResult);
                        }
                    }
                    else
                    {
                        // Read read 0 bytes, the remote socket has been closed, so complete the operation
                        internalAsyncResult.SetComplete(new IOException("The remote stream has been closed"));
                    }
                }
                catch (Exception ex)
                {
                    internalAsyncResult.SetComplete(ex);
                }
            }
        }
Exemple #32
0
		/// <summary>
		/// Renegotiate session keys - calls SSL_renegotiate
		/// </summary>
		public void Renegotiate()
		{
			if (ssl != null)
			{
				// Call the SSL_renegotiate to reset the SSL object state
				// to start handshake
				Native.ExpectSuccess(Native.SSL_renegotiate(ssl.Handle));
				handShakeState = HandshakeState.Renegotiate;
			}
		}
Exemple #33
0
		/*
		public abstract virtual bool ProcessRenegotiation();

		private IAsyncResult BeginRenegotiate(InternalAsyncResult readwriteAsyncResult)
		{
			Console.WriteLine("BeginRenegotiate");

			handShakeState = HandshakeState.Renegotiate;

			// Wrap the readwriteAsyncResult in the renegotiateAsyncResult
			InternalAsyncResult renegotiateAsyncResult = new InternalAsyncResult(new AsyncCallback(RenegotiateComplete), readwriteAsyncResult, null, 0, 0, readwriteAsyncResult.IsWriteOperation, readwriteAsyncResult.ContinueAfterHandshake);

			if (ProcessRenegotiation())
			{
				handShakeState = HandshakeState.Complete;
				renegotiateAsyncResult.SetComplete();
			}
			else
			{
				//!! if (readwriteAsyncResult.IsWriteOperation)
				if (write_bio.BytesPending > 0)
				{
					renegotiateAsyncResult.IsWriteOperation = true;
					BeginWrite(new byte[0], 0, 0, new AsyncCallback(RenegotiateCallback), renegotiateAsyncResult);
				}
				else
				{
					renegotiateAsyncResult.IsWriteOperation = false;
					BeginRead(new byte[0], 0, 0, new AsyncCallback(RenegotiateCallback), renegotiateAsyncResult);
				}
			}
			return renegotiateAsyncResult;
		}

		private void RenegotiateCallback(IAsyncResult asyncResult)
		{
			InternalAsyncResult renegotiateAsyncResult = asyncResult.AsyncState as InternalAsyncResult;
		}
		*/

		private IAsyncResult BeginHandshake(InternalAsyncResult readwriteAsyncResult)
		{
			//!!
			// Move the handshake state to the next state
			//if (handShakeState == HandshakeState.Renegotiate)
			//{
			//    handShakeState = HandshakeState.RenegotiateInProcess;
			//}
			//else
			if (handShakeState != HandshakeState.Renegotiate)
			{
				handShakeState = HandshakeState.InProcess;
			}

			// Wrap the read/write InternalAsyncResult in the Handshake InternalAsyncResult instance
			InternalAsyncResult handshakeAsyncResult = new InternalAsyncResult(new AsyncCallback(AsyncHandshakeComplete), readwriteAsyncResult, null, 0, 0, readwriteAsyncResult.IsWriteOperation, readwriteAsyncResult.ContinueAfterHandshake);

			if (ProcessHandshake())
			{
				//inHandshakeLoop = false;
				handShakeState = HandshakeState.Complete;
				handshakeAsyncResult.SetComplete();
			}
			else
			{
				//!! if (readwriteAsyncResult.IsWriteOperation)
				if (write_bio.BytesPending > 0)
				{
					handshakeAsyncResult.IsWriteOperation = true;
					BeginWrite(new byte[0], 0, 0, new AsyncCallback(AsyncHandshakeCallback), handshakeAsyncResult);
				}
				else
				{
					handshakeAsyncResult.IsWriteOperation = false;
					BeginRead(new byte[0], 0, 0, new AsyncCallback(AsyncHandshakeCallback), handshakeAsyncResult);
				}
			}
			return handshakeAsyncResult;
		}
Exemple #34
0
		private void AsyncHandshakeCallback(IAsyncResult asyncResult)
		{
			// Get the handshake internal result instance
			InternalAsyncResult internalAsyncResult = (InternalAsyncResult)asyncResult.AsyncState;
			int bytesRead = 0;

			if (internalAsyncResult.IsWriteOperation)
			{
				EndWrite(asyncResult);
				// Check to see if the handshake is complete (this could have been
				// the last response packet from the server.  If so, we want to finalize
				// the async operation and call the HandshakeComplete callback
				if (handShakeState == HandshakeState.Complete)
				{
					internalAsyncResult.SetComplete();
					return;
				}
				// Check to see if we saved an exception from the last Handshake process call
				// the if the client gets an error code, it needs to send the alert, and then
				// throw the exception here.
				if (handshakeException != null)
				{
					internalAsyncResult.SetComplete(handshakeException);
					return;
				}
				// We wrote out the handshake data, now read to get the response
				internalAsyncResult.IsWriteOperation = false;
				BeginRead(new byte[0], 0, 0, new AsyncCallback(AsyncHandshakeCallback), internalAsyncResult);
			}
			else
			{
				try
				{
					bytesRead = EndRead(asyncResult);
					if (bytesRead > 0)
					{
						if (ProcessHandshake())
						{
							//inHandshakeLoop = false;
							handShakeState = HandshakeState.Complete;
							// We have completed the handshake, but need to send the
							// last response packet.
							if (write_bio.BytesPending > 0)
							{
								internalAsyncResult.IsWriteOperation = true;
								BeginWrite(new byte[0], 0, 0, new AsyncCallback(AsyncHandshakeCallback), internalAsyncResult);
							}
							else
							{
								internalAsyncResult.SetComplete();
								return;
							}
						}
						else
						{
							// Not complete with the handshake yet, write the handshake packet out
							internalAsyncResult.IsWriteOperation = true;
							BeginWrite(new byte[0], 0, 0, new AsyncCallback(AsyncHandshakeCallback), internalAsyncResult);
						}
					}
					else
					{
						// Read read 0 bytes, the remote socket has been closed, so complete the operation
						internalAsyncResult.SetComplete(new IOException("The remote stream has been closed"));
					}
				}
				catch (Exception ex)
				{
					internalAsyncResult.SetComplete(ex);
				}
			}
		}
Exemple #35
0
        private void Handle(Action action, SocketError socketError, int bytesTransferred)
        {
            switch (m_state)
            {
                case State.Closed:
                    switch (action)
                    {
                        case Action.Start:
                            if (m_options.RawSocket)
                            {
                                m_encoder = new RawEncoder(Config.OutBatchSize, m_session, m_options.Endian);
                                m_decoder = new RawDecoder(Config.InBatchSize, m_options.MaxMessageSize, m_session, m_options.Endian);

                                Activate();
                            }
                            else
                            {
                                m_state = State.Handshaking;
                                m_handshakeState = HandshakeState.Closed;
                                HandleHandshake(action, socketError, bytesTransferred);
                            }

                            break;
                    }
                    break;
                case State.Handshaking:
                    HandleHandshake(action, socketError, bytesTransferred);
                    break;
                case State.Active:
                    switch (action)
                    {
                        case Action.InCompleted:
                            m_insize = EndRead(socketError, bytesTransferred);

                            ProcessInput();
                            break;
                        case Action.ActivateIn:

                            // if we stuck let's continue, other than that nothing to do
                            if (m_receivingState == ReceiveState.Stuck)
                            {
                                m_receivingState = ReceiveState.Active;
                                ProcessInput();
                            }
                            break;
                        case Action.OutCompleted:
                            int bytesSent = EndWrite(socketError, bytesTransferred);

                            //  IO error has occurred. We stop waiting for output events.
                            //  The engine is not terminated until we detect input error;
                            //  this is necessary to prevent losing incoming messages.
                            if (bytesSent == -1)
                            {
                                m_sendingState = SendState.Error;
                            }
                            else
                            {
                                m_outpos.AdvanceOffset(bytesSent);
                                m_outsize -= bytesSent;

                                BeginSending();
                            }
                            break;
                        case Action.ActivateOut:
                            // if we idle we start sending, other than do nothing
                            if (m_sendingState == SendState.Idle)
                            {
                                m_sendingState = SendState.Active;
                                BeginSending();
                            }
                            break;
                        default:
                            Debug.Assert(false);
                            break;
                    }
                    break;
                case State.Stalled:
                    switch (action)
                    {
                        case Action.ActivateIn:
                            //  There was an input error but the engine could not
                            //  be terminated (due to the stalled decoder).
                            //  Flush the pending message and terminate the engine now.
                            m_decoder.ProcessBuffer(m_inpos, 0);
                            Debug.Assert(!m_decoder.Stalled());
                            m_session.Flush();
                            Error();
                            break;
                        case Action.ActivateOut:
                            break;
                    }
                    break;
            }
        }
Exemple #36
0
        /// <summary>
        /// Authenticate the request
        /// </summary>
        /// <returns></returns>
        protected override async Task <AuthenticationTicket> AuthenticateCoreAsync()
        {
            // note: this is cheating for async...
            AuthenticationProperties properties = await Task.FromResult <AuthenticationProperties>(null);

            HandshakeState state = null;

            // retrieve the state Id
            var stateId = Request.Query["state"];


            if (stateId != null && this.Options.LoginStateCache.TryGet(stateId, out state))
            {
                // okay, we shall authenticate! For that we must
                // get the authorization header and extract the token
                var authorizationHeader = Request.Headers["Authorization"];

                byte[] token = null;
                if (!string.IsNullOrEmpty(authorizationHeader) && authorizationHeader.StartsWith("NTLM "))
                {
                    token = Convert.FromBase64String(authorizationHeader.Substring(5));
                }

                // First eight bytes are header containing NTLMSSP\0 signature
                // Next byte contains type of the message recieved.
                // No Token - it's the initial request. Add a authenticate header
                // Message Type 1 — is initial client's response to server's 401 Unauthorized error.
                // Message Type 2 — is the server's response to it. Contains random 8 bytes challenge.
                // Message Type 3 — is encrypted password hashes from client ready to server validation.
                if (token != null && token[8] == 1)
                {
                    // Message of type 1 was received
                    if (state.TryAcquireServerChallenge(ref token))
                    {
                        // send the type 2 message
                        var authorization = Convert.ToBase64String(token);
                        Response.Headers.Add("WWW-Authenticate", new[] { string.Concat("NTLM ", authorization) });
                        Response.StatusCode = 401;

                        // not sucessfull
                        return(new AuthenticationTicket(null, properties));
                    }
                }
                else if (token != null && token[8] == 3)
                {
                    // message of type 3 was received
                    if (state.IsClientResponseValid(token))
                    {
                        // Authorization successful
                        properties = state.AuthenticationProperties;

                        if (Options.Filter == null || Options.Filter.Invoke(state.WindowsIdentity, Request))
                        {
                            // If the name is something like DOMAIN\username then
                            // grab the name part (and what if it looks like username@domain?)
                            var    parts     = state.WindowsIdentity.Name.Split(new[] { '\\' }, 2);
                            string shortName = parts.Length == 1 ? parts[0] : parts[parts.Length - 1];

                            // we need to create a new identity using the sign in type that
                            // the cookie authentication is listening for
                            var identity = new ClaimsIdentity(Options.SignInAsAuthenticationType);

                            identity.AddClaims(new[]
                            {
                                new Claim(ClaimTypes.NameIdentifier, state.WindowsIdentity.User.Value, null, Options.AuthenticationType),
                                new Claim(ClaimTypes.Name, shortName),
                                new Claim(ClaimTypes.Sid, state.WindowsIdentity.User.Value),
                                new Claim(ClaimTypes.AuthenticationMethod, NtlmAuthenticationDefaults.AuthenticationType)
                            });

                            // We don't need that state anymore
                            Options.LoginStateCache.TryRemove(stateId);

                            // create the authentication ticket
                            return(new AuthenticationTicket(identity, properties));
                        }
                    }
                }

                // This code runs under following conditions:
                // - authentication failed (in either step: IsClientResponseValid() or TryAcquireServerChallenge())
                // - there's no token in the headers
                //
                // This means we've got to set the WWW-Authenticate header and return a 401
                Response.Headers.Add("WWW-Authenticate", new[] { "NTLM" });
                Response.StatusCode = 401;
            }

            return(new AuthenticationTicket(null, properties));
        }
Exemple #37
0
        private void HandleHandshake(Action action, SocketError socketError, int bytesTransferred)
        {
            int bytesSent;
            int bytesReceived;

            switch (m_handshakeState)
            {
                case HandshakeState.Closed:
                    switch (action)
                    {
                        case Action.Start:
                            //  Send the 'length' and 'flags' fields of the identity message.
                            //  The 'length' field is encoded in the long format.

                            m_greetingOutputBuffer[m_outsize++] = ((byte)0xff);
                            m_greetingOutputBuffer.PutLong(m_options.Endian, (long)m_options.IdentitySize + 1, 1);
                            m_outsize += 8;
                            m_greetingOutputBuffer[m_outsize++] = ((byte)0x7f);

                            m_outpos = new ByteArraySegment(m_greetingOutputBuffer);

                            m_handshakeState = HandshakeState.SendingGreeting;

                            BeginWrite(m_outpos, m_outsize);
                            break;
                        default:
                            Debug.Assert(false);
                            break;
                    }
                    break;
                case HandshakeState.SendingGreeting:
                    switch (action)
                    {
                        case Action.OutCompleted:
                            bytesSent = EndWrite(socketError, bytesTransferred);

                            if (bytesSent == -1)
                            {
                                Error();
                            }
                            else
                            {
                                m_outpos.AdvanceOffset(bytesSent);
                                m_outsize -= bytesSent;

                                if (m_outsize > 0)
                                {
                                    BeginWrite(m_outpos, m_outsize);
                                }
                                else
                                {
                                    m_greetingBytesRead = 0;

                                    var greetingSegment = new ByteArraySegment(m_greeting, m_greetingBytesRead);

                                    m_handshakeState = HandshakeState.ReceivingGreeting;

                                    BeginRead(greetingSegment, PreambleSize);
                                }
                            }
                            break;
                        case Action.ActivateIn:
                        case Action.ActivateOut:
                            // nothing to do
                            break;
                        default:
                            Debug.Assert(false);
                            break;
                    }
                    break;
                case HandshakeState.ReceivingGreeting:
                    switch (action)
                    {
                        case Action.InCompleted:
                            bytesReceived = EndRead(socketError, bytesTransferred);

                            if (bytesReceived == -1)
                            {
                                Error();
                            }
                            else
                            {
                                m_greetingBytesRead += bytesReceived;

                                // check if it is an unversion protocol
                                if (m_greeting[0] != 0xff || (m_greetingBytesRead == 10 && (m_greeting[9] & 0x01) == 0))
                                {
                                    m_encoder = new V1Encoder(Config.OutBatchSize, m_options.Endian);
                                    m_encoder.SetMsgSource(m_session);

                                    m_decoder = new V1Decoder(Config.InBatchSize, m_options.MaxMessageSize, m_options.Endian);
                                    m_decoder.SetMsgSink(m_session);

                                    //  We have already sent the message header.
                                    //  Since there is no way to tell the encoder to
                                    //  skip the message header, we simply throw that
                                    //  header data away.
                                    int headerSize = m_options.IdentitySize + 1 >= 255 ? 10 : 2;
                                    var tmp = new byte[10];
                                    var bufferp = new ByteArraySegment(tmp);

                                    int bufferSize = headerSize;

                                    m_encoder.GetData(ref bufferp, ref bufferSize);

                                    Debug.Assert(bufferSize == headerSize);

                                    //  Make sure the decoder sees the data we have already received.
                                    m_inpos = new ByteArraySegment(m_greeting);
                                    m_insize = m_greetingBytesRead;

                                    //  To allow for interoperability with peers that do not forward
                                    //  their subscriptions, we inject a phony subscription
                                    //  message into the incoming message stream. To put this
                                    //  message right after the identity message, we temporarily
                                    //  divert the message stream from session to ourselves.
                                    if (m_options.SocketType == ZmqSocketType.Pub || m_options.SocketType == ZmqSocketType.Xpub)
                                        m_decoder.SetMsgSink(this);

                                    ActivateOut();
                                }
                                else if (m_greetingBytesRead < 10)
                                {
                                    var greetingSegment = new ByteArraySegment(m_greeting, m_greetingBytesRead);
                                    BeginRead(greetingSegment, PreambleSize - m_greetingBytesRead);
                                }
                                else
                                {
                                    //  The peer is using versioned protocol.
                                    //  Send the rest of the greeting.
                                    m_outpos[m_outsize++] = 1; // Protocol version
                                    m_outpos[m_outsize++] = (byte)m_options.SocketType;

                                    m_handshakeState = HandshakeState.SendingRestOfGreeting;

                                    BeginWrite(m_outpos, m_outsize);
                                }
                            }
                            break;
                        case Action.ActivateIn:
                        case Action.ActivateOut:
                            // nothing to do
                            break;
                        default:
                            Debug.Assert(false);
                            break;
                    }
                    break;
                case HandshakeState.SendingRestOfGreeting:
                    switch (action)
                    {
                        case Action.OutCompleted:
                            bytesSent = EndWrite(socketError, bytesTransferred);

                            if (bytesSent == -1)
                            {
                                Error();
                            }
                            else
                            {
                                m_outpos.AdvanceOffset(bytesSent);
                                m_outsize -= bytesSent;

                                if (m_outsize > 0)
                                {
                                    BeginWrite(m_outpos, m_outsize);
                                }
                                else
                                {
                                    var greetingSegment = new ByteArraySegment(m_greeting, m_greetingBytesRead);

                                    m_handshakeState = HandshakeState.ReceivingRestOfGreeting;
                                    BeginRead(greetingSegment, GreetingSize - m_greetingBytesRead);
                                }
                            }
                            break;
                        case Action.ActivateIn:
                        case Action.ActivateOut:
                            // nothing to do
                            break;
                        default:
                            Debug.Assert(false);
                            break;
                    }
                    break;
                case HandshakeState.ReceivingRestOfGreeting:
                    switch (action)
                    {
                        case Action.InCompleted:
                            bytesReceived = EndRead(socketError, bytesTransferred);

                            if (bytesReceived == -1)
                            {
                                Error();
                            }
                            else
                            {
                                m_greetingBytesRead += bytesReceived;

                                if (m_greetingBytesRead < GreetingSize)
                                {
                                    var greetingSegment = new ByteArraySegment(m_greeting, m_greetingBytesRead);
                                    BeginRead(greetingSegment, GreetingSize);
                                }
                                else
                                {
                                    if (m_greeting[VersionPos] == 0)
                                    {
                                        //  ZMTP/1.0 framing.
                                        m_encoder = new V1Encoder(Config.OutBatchSize, m_options.Endian);
                                        m_encoder.SetMsgSource(m_session);

                                        m_decoder = new V1Decoder(Config.InBatchSize, m_options.MaxMessageSize, m_options.Endian);
                                        m_decoder.SetMsgSink(m_session);
                                    }
                                    else
                                    {
                                        //  v1 framing protocol.
                                        m_encoder = new V2Encoder(Config.OutBatchSize, m_session, m_options.Endian);
                                        m_decoder = new V2Decoder(Config.InBatchSize, m_options.MaxMessageSize, m_session, m_options.Endian);
                                    }

                                    // handshake is done
                                    Activate();
                                }
                            }
                            break;
                        case Action.ActivateIn:
                        case Action.ActivateOut:
                            // nothing to do
                            break;
                        default:
                            Debug.Assert(false);
                            break;
                    }
                    break;
                default:
                    Debug.Assert(false);
                    break;
            }
        }
        private void HandleHandshake(Action action, SocketError socketError, int bytesTransferred)
        {
            int bytesSent;
            int bytesReceived;

            switch (m_handshakeState)
            {
            case HandshakeState.Closed:
                switch (action)
                {
                case Action.Start:
                    // Send the 'length' and 'flags' fields of the identity message.
                    // The 'length' field is encoded in the long format.

                    m_greetingOutputBuffer[m_outsize++] = ((byte)0xff);
                    m_greetingOutputBuffer.PutLong(m_options.Endian, (long)m_options.IdentitySize + 1, 1);
                    m_outsize += 8;
                    m_greetingOutputBuffer[m_outsize++] = ((byte)0x7f);

                    m_outpos = new ByteArraySegment(m_greetingOutputBuffer);

                    m_handshakeState = HandshakeState.SendingGreeting;

                    BeginWrite(m_outpos, m_outsize);
                    break;

                default:
                    Debug.Assert(false);
                    break;
                }
                break;

            case HandshakeState.SendingGreeting:
                switch (action)
                {
                case Action.OutCompleted:
                    bytesSent = EndWrite(socketError, bytesTransferred);

                    if (bytesSent == -1)
                    {
                        Error();
                    }
                    else
                    {
                        m_outpos.AdvanceOffset(bytesSent);
                        m_outsize -= bytesSent;

                        if (m_outsize > 0)
                        {
                            BeginWrite(m_outpos, m_outsize);
                        }
                        else
                        {
                            m_greetingBytesRead = 0;

                            var greetingSegment = new ByteArraySegment(m_greeting, m_greetingBytesRead);

                            m_handshakeState = HandshakeState.ReceivingGreeting;

                            BeginRead(greetingSegment, PreambleSize);
                        }
                    }
                    break;

                case Action.ActivateIn:
                case Action.ActivateOut:
                    // nothing to do
                    break;

                default:
                    Debug.Assert(false);
                    break;
                }
                break;

            case HandshakeState.ReceivingGreeting:
                switch (action)
                {
                case Action.InCompleted:
                    bytesReceived = EndRead(socketError, bytesTransferred);

                    if (bytesReceived == -1)
                    {
                        Error();
                    }
                    else
                    {
                        m_greetingBytesRead += bytesReceived;

                        // check if it is an unversioned protocol
                        if (m_greeting[0] != 0xff || (m_greetingBytesRead == 10 && (m_greeting[9] & 0x01) == 0))
                        {
                            m_encoder = new V1Encoder(Config.OutBatchSize, m_options.Endian);
                            m_encoder.SetMsgSource(m_session);

                            m_decoder = new V1Decoder(Config.InBatchSize, m_options.MaxMessageSize, m_options.Endian);
                            m_decoder.SetMsgSink(m_session);

                            // We have already sent the message header.
                            // Since there is no way to tell the encoder to
                            // skip the message header, we simply throw that
                            // header data away.
                            int headerSize = m_options.IdentitySize + 1 >= 255 ? 10 : 2;
                            var tmp        = new byte[10];
                            var bufferp    = new ByteArraySegment(tmp);

                            int bufferSize = headerSize;

                            m_encoder.GetData(ref bufferp, ref bufferSize);

                            Debug.Assert(bufferSize == headerSize);

                            // Make sure the decoder sees the data we have already received.
                            m_inpos  = new ByteArraySegment(m_greeting);
                            m_insize = m_greetingBytesRead;

                            // To allow for interoperability with peers that do not forward
                            // their subscriptions, we inject a phony subscription
                            // message into the incoming message stream. To put this
                            // message right after the identity message, we temporarily
                            // divert the message stream from session to ourselves.
                            if (m_options.SocketType == ZmqSocketType.Pub || m_options.SocketType == ZmqSocketType.Xpub)
                            {
                                m_decoder.SetMsgSink(this);
                            }

                            // handshake is done
                            Activate();
                        }
                        else if (m_greetingBytesRead < 10)
                        {
                            var greetingSegment = new ByteArraySegment(m_greeting, m_greetingBytesRead);
                            BeginRead(greetingSegment, PreambleSize - m_greetingBytesRead);
                        }
                        else
                        {
                            // The peer is using versioned protocol.
                            // Send the rest of the greeting.
                            m_outpos[m_outsize++] = 1;         // Protocol version
                            m_outpos[m_outsize++] = (byte)m_options.SocketType;

                            m_handshakeState = HandshakeState.SendingRestOfGreeting;

                            BeginWrite(m_outpos, m_outsize);
                        }
                    }
                    break;

                case Action.ActivateIn:
                case Action.ActivateOut:
                    // nothing to do
                    break;

                default:
                    Debug.Assert(false);
                    break;
                }
                break;

            case HandshakeState.SendingRestOfGreeting:
                switch (action)
                {
                case Action.OutCompleted:
                    bytesSent = EndWrite(socketError, bytesTransferred);

                    if (bytesSent == -1)
                    {
                        Error();
                    }
                    else
                    {
                        m_outpos.AdvanceOffset(bytesSent);
                        m_outsize -= bytesSent;

                        if (m_outsize > 0)
                        {
                            BeginWrite(m_outpos, m_outsize);
                        }
                        else
                        {
                            var greetingSegment = new ByteArraySegment(m_greeting, m_greetingBytesRead);

                            m_handshakeState = HandshakeState.ReceivingRestOfGreeting;
                            BeginRead(greetingSegment, GreetingSize - m_greetingBytesRead);
                        }
                    }
                    break;

                case Action.ActivateIn:
                case Action.ActivateOut:
                    // nothing to do
                    break;

                default:
                    Debug.Assert(false);
                    break;
                }
                break;

            case HandshakeState.ReceivingRestOfGreeting:
                switch (action)
                {
                case Action.InCompleted:
                    bytesReceived = EndRead(socketError, bytesTransferred);

                    if (bytesReceived == -1)
                    {
                        Error();
                    }
                    else
                    {
                        m_greetingBytesRead += bytesReceived;

                        if (m_greetingBytesRead < GreetingSize)
                        {
                            var greetingSegment = new ByteArraySegment(m_greeting, m_greetingBytesRead);
                            BeginRead(greetingSegment, GreetingSize - m_greetingBytesRead);
                        }
                        else
                        {
                            if (m_greeting[VersionPos] == 0)
                            {
                                // ZMTP/1.0 framing.
                                m_encoder = new V1Encoder(Config.OutBatchSize, m_options.Endian);
                                m_encoder.SetMsgSource(m_session);

                                m_decoder = new V1Decoder(Config.InBatchSize, m_options.MaxMessageSize, m_options.Endian);
                                m_decoder.SetMsgSink(m_session);
                            }
                            else
                            {
                                // v1 framing protocol.
                                m_encoder = new V2Encoder(Config.OutBatchSize, m_session, m_options.Endian);
                                m_decoder = new V2Decoder(Config.InBatchSize, m_options.MaxMessageSize, m_session, m_options.Endian);
                            }

                            // handshake is done
                            Activate();
                        }
                    }
                    break;

                case Action.ActivateIn:
                case Action.ActivateOut:
                    // nothing to do
                    break;

                default:
                    Debug.Assert(false);
                    break;
                }
                break;

            default:
                Debug.Assert(false);
                break;
            }
        }
Exemple #39
0
 protected void OnHandshakeError(HandshakeState handshakeState, string errorMessage)
 {
     HandshakeError?.Invoke(this, new HandshakeErrorEventArgs(handshakeState, errorMessage));
 }