Пример #1
0
        /// <summary>
        /// Process a global message.
        /// </summary>
        /// <param name="packet"></param>
        /// <returns></returns>
        protected internal override bool ProcessGlobalMessage(SSHPacket packet)
        {
            // We need to filter for any messages that require a response from the
            // connection protocol such as channel open or global requests. These
            // are not handled anywhere else within this implementation because
            // doing so would require a thread to wait.

            try
            {
                switch (packet.MessageID)
                {
                case SSH_MSG_CHANNEL_OPEN:
                {
#if DEBUG
                    System.Diagnostics.Trace.WriteLine("Received SSH_MSG_CHANNEL_OPEN");
#endif
                    //		  Attempt to open the channel
                    System.String type         = packet.ReadString();
                    int           remoteid     = (int)packet.ReadUINT32();
                    int           remotewindow = (int)packet.ReadUINT32();
                    int           remotepacket = (int)packet.ReadUINT32();
                    byte[]        requestdata  = packet.Available > 0 ? new byte[packet.Available] : null;
                    if (requestdata != null)
                    {
                        packet.ReadBytes(requestdata);
                    }

                    ProcessChannelOpenRequest(type, remoteid, remotewindow, remotepacket, requestdata);
                    return(true);
                }

                case SSH_MSG_GLOBAL_REQUEST:
                {
#if DEBUG
                    System.Diagnostics.Trace.WriteLine("Received SSH_MSG_GLOBAL_REQUEST");
#endif

                    // Attempt to process the global request
                    System.String requestname = packet.ReadString();
                    bool          wantreply   = packet.ReadBool();
                    byte[]        requestdata = new byte[packet.Available];
                    packet.ReadBytes(requestdata);

                    // Process the request
                    ProcessGlobalRequest(requestname, wantreply, requestdata);
                    return(true);
                }

                default:
                    return(false);
                }
            }
            catch (System.IO.IOException ex)
            {
                throw new SSHException(ex.Message, SSHException.INTERNAL_ERROR);
            }
        }
Пример #2
0
        internal bool ProcessMessage(SSHPacket packet)
        {
            try
            {
                switch (packet.MessageID)
                {
                case SSH_MSG_USERAUTH_FAILURE:
                {
                    String auths = packet.ReadString();

                    throw new SSH2AuthenticationResult(
                              packet.ReadBool()
                                                        ? AuthenticationResult.FURTHER_AUTHENTICATION_REQUIRED
                                                        : AuthenticationResult.FAILED,
                              auths);
                }

                case SSH_MSG_USERAUTH_SUCCESS:
                {
                    connection.Start();
                    throw new SSH2AuthenticationResult(AuthenticationResult.COMPLETE, "");
                }

                case SSH_MSG_USERAUTH_BANNER:
                {
                    if (((SSH2Context)transport.Context).Banner != null)
                    {
                        ((SSH2Context)transport.Context).Banner.DisplayBanner(packet.ReadString());
                    }
                    return(true);
                }

                default:
                    return(false);
                }
            }
            catch (IOException ex)
            {
                throw new SSHException(ex.Message,
                                       SSHException.INTERNAL_ERROR);
            }
        }
Пример #3
0
        internal void PerformKeyExchange(SSHPacket packet)
        {
            lock (kexlock)
            {
                if (localkex == null)
                {
                    SendKeyExchangeInit();
                }

                SSH2Context context = (SSH2Context)client.Context;

                currentState = TransportProtocolState.PERFORMING_KEYEXCHANGE;

                remotekex = packet.Payload;

                // Ignore the cookie
                packet.Skip(16);

                String remoteKeyExchanges = packet.ReadString();
                String remotePublicKeys   = packet.ReadString();
                String remoteCiphersCS    = packet.ReadString();
                String remoteCiphersSC    = packet.ReadString();
                String remoteHMacCS       = packet.ReadString();
                String remoteHMacSC       = packet.ReadString();


                String cipherCS = SelectNegotiatedComponent(context.SupportedCiphers.List(
                                                                context.PreferredCipherCS), remoteCiphersCS);

                String cipherSC = SelectNegotiatedComponent(context.SupportedCiphers.List(
                                                                context.PreferredCipherSC), remoteCiphersSC);

                Cipher encryption = (Cipher)context.SupportedCiphers.GetInstance(cipherCS);

                Cipher decryption = (Cipher)context.SupportedCiphers.GetInstance(cipherSC);

                String macCS = SelectNegotiatedComponent(context.SupportedMACs.List(
                                                             context.PreferredMacCS), remoteHMacCS);

                String macSC = SelectNegotiatedComponent(context.SupportedMACs.List(
                                                             context.PreferredMacSC), remoteHMacSC);

                SSH2Hmac outgoingMac = (SSH2Hmac)context.SupportedMACs.GetInstance(macCS);

                SSH2Hmac incomingMac = (SSH2Hmac)context.SupportedMACs.GetInstance(macSC);

                // Ignore compression and languages as were not interested in that atm

                // Create a Key Exchange instance
                String kex = SelectNegotiatedComponent(context.SupportedKeyExchanges.List(
                                                           context.PreferredKeyExchange), remoteKeyExchanges);

                String publickey = SelectNegotiatedComponent(context.SupportedPublicKeys.List(
                                                                 context.PreferredPublicKey), remotePublicKeys);

#if DEBUG
                // Output the local settings
                System.Diagnostics.Trace.WriteLine("Local Key exchange settings follow:");
                System.Diagnostics.Trace.WriteLine("Key exchange: " + context.SupportedKeyExchanges.List(
                                                       context.PreferredKeyExchange));
                System.Diagnostics.Trace.WriteLine("Public keys : " + context.SupportedPublicKeys.List(
                                                       context.PreferredPublicKey));
                System.Diagnostics.Trace.WriteLine("Ciphers client->server: " + context.SupportedCiphers.List(
                                                       context.PreferredCipherCS));
                System.Diagnostics.Trace.WriteLine("Ciphers server->client: " + context.SupportedCiphers.List(
                                                       context.PreferredCipherSC));
                System.Diagnostics.Trace.WriteLine("HMAC client->server: " + context.SupportedMACs.List(
                                                       context.PreferredMacCS));
                System.Diagnostics.Trace.WriteLine("HMAC server->client: " + context.SupportedMACs.List(
                                                       context.PreferredMacSC));

                // Output the remote settings
                System.Diagnostics.Trace.WriteLine("Remote Key exchange settings follow:");
                System.Diagnostics.Trace.WriteLine("Key exchange: " + remoteKeyExchanges);
                System.Diagnostics.Trace.WriteLine("Public keys : " + remotePublicKeys);
                System.Diagnostics.Trace.WriteLine("Ciphers client->server: " + remoteCiphersCS);
                System.Diagnostics.Trace.WriteLine("Ciphers server->client: " + remoteCiphersSC);
                System.Diagnostics.Trace.WriteLine("HMAC client->server: " + remoteHMacCS);
                System.Diagnostics.Trace.WriteLine("HMAC server->client: " + remoteHMacSC);

                // Output the selected settigns
                System.Diagnostics.Trace.WriteLine("Selected kex exchange: " + kex);
                System.Diagnostics.Trace.WriteLine("Selected public key: " + publickey);
                System.Diagnostics.Trace.WriteLine("Selected cipher client->server: " + cipherCS);
                System.Diagnostics.Trace.WriteLine("Selected cipher server->client: " + cipherSC);
                System.Diagnostics.Trace.WriteLine("Selected HMAC client->server: " + macCS);
                System.Diagnostics.Trace.WriteLine("Selected HMAC server->client: " + macSC);
#endif
                keyexchange = (SSH2KeyExchange)context.SupportedKeyExchanges.GetInstance(kex);

                keyexchange.Init(this);

                // Perform the key exchange
                keyexchange.PerformClientExchange(client.LocalIdentification,
                                                  client.RemoteIdentification,
                                                  localkex,
                                                  remotekex);

                SSHPublicKey hostkey = (SSHPublicKey)context.SupportedPublicKeys.GetInstance(publickey);

                hostkey.Init(keyexchange.HostKey, 0, keyexchange.HostKey.Length);

                if (context.KnownHosts != null)
                {
                    if (!context.KnownHosts.VerifyHost(transport.Hostname, hostkey))
                    {
                        Disconnect("Host key not accepted", DisconnectionReason.HOST_KEY_NOT_VERIFIABLE);
                        throw new SSHException("The host key was not accepted",
                                               SSHException.CANCELLED_CONNECTION);
                    }
                }

                if (!hostkey.VerifySignature(keyexchange.Signature,
                                             keyexchange.ExchangeHash))
                {
                    Disconnect("The host key signature is invalid",
                               DisconnectionReason.HOST_KEY_NOT_VERIFIABLE);
                    throw new SSHException("The host key signature is invalid",
                                           SSHException.PROTOCOL_VIOLATION);
                }

                if (sessionIdentifier == null)
                {
                    sessionIdentifier = keyexchange.ExchangeHash;
                }

                packet = GetSSHPacket(true);
                packet.WriteByte(SSH_MSG_NEWKEYS);
#if DEBUG
                System.Diagnostics.Trace.WriteLine("Sending SSH_MSG_NEWKEYS");
#endif
                SendMessage(packet);


                encryption.Init(Cipher.ENCRYPT_MODE,
                                MakeSSHKey('A'),
                                MakeSSHKey('C'));

                outgoingCipherLength = encryption.BlockSize;

                outgoingMac.Init(MakeSSHKey('E'));
                outgoingMacLength = outgoingMac.MacLength;

                this.encryption  = encryption;
                this.outgoingMac = outgoingMac;

                do
                {
                    packet = ReadMessage();

                    // Process the transport protocol message, must only be
                    // SSH_MSH_INGORE, SSH_MSG_DEBUG, SSH_MSG_DISCONNECT or SSH_MSG_NEWKEYS
                    if (!ProcessMessage(packet))
                    {
                        Disconnect("Invalid message received during key exchange",
                                   DisconnectionReason.PROTOCOL_ERROR);
                        throw new SSHException(
                                  "Invalid message received during key exchange",
                                  SSHException.PROTOCOL_VIOLATION);
                    }
                }while(packet.MessageID != SSH_MSG_NEWKEYS);

                // Put the incoming components into use
                decryption.Init(Cipher.DECRYPT_MODE,
                                MakeSSHKey('B'),
                                MakeSSHKey('D'));
                incomingCipherLength = decryption.BlockSize;

                incomingMac.Init(MakeSSHKey('F'));
                incomingMacLength = incomingMac.MacLength;

                this.decryption  = decryption;
                this.incomingMac = incomingMac;
                //this.incomingCompression = incomingCompression;

                currentState = TransportProtocolState.CONNECTED;

                FireStateChange(TransportProtocolState.CONNECTED);

                lock (kexqueue)
                {
#if DEBUG
                    System.Diagnostics.Trace.WriteLine("Sending queued messages");
#endif
                    for (System.Collections.IEnumerator e = kexqueue.GetEnumerator(); e.MoveNext();)
                    {
                        SendMessage((SSHPacket)e.Current);
                    }

                    kexqueue.Clear();
                }

                // Clean up and reset any parameters
                localkex  = null;
                remotekex = null;
            }
        }
Пример #4
0
        internal bool ProcessMessage(SSHPacket packet)
        {
            try
            {
                if (packet.Length < 1)
                {
                    Disconnect("Invalid message received", DisconnectionReason.PROTOCOL_ERROR);
                    throw new SSHException("Invalid transport protocol message", SSHException.INTERNAL_ERROR);
                }

                switch (packet.MessageID)
                {
                case SSH_MSG_DISCONNECT:
                {
                    packet.ReadInt();
#if DEBUG
                    System.Diagnostics.Trace.WriteLine("Received SSH_MSG_DISCONNECT: " + packet.ReadString());
#endif
                    InternalDisconnect();
                    throw new SSHException(packet.ReadString(), SSHException.REMOTE_HOST_DISCONNECTED);
                }

                case SSH_MSG_IGNORE:
                {
#if DEBUG
                    System.Diagnostics.Trace.WriteLine("Received SSH_MSG_IGNORE");
#endif
                    return(true);
                }

                case SSH_MSG_DEBUG:
                {
#if DEBUG
                    System.Diagnostics.Trace.WriteLine("Received SSH_MSG_DEBUG");
                    packet.Skip(1);
                    System.Diagnostics.Trace.WriteLine(packet.ReadString());
#endif
                    return(true);
                }

                case SSH_MSG_NEWKEYS:
                {
                    // This lightweight implemention ignores these messages
#if DEBUG
                    System.Diagnostics.Trace.WriteLine("Received SSH_MSG_NEWKEYS");
#endif
                    return(true);
                }

                case SSH_MSG_KEX_INIT:
                {
#if DEBUG
                    System.Diagnostics.Trace.WriteLine("Received SSH_MSG_KEX_INIT");
#endif
                    if (remotekex != null)
                    {
                        Disconnect("Key exchange already in progress!",
                                   DisconnectionReason.PROTOCOL_ERROR);
                        throw new SSHException("Key exchange already in progress!", SSHException.PROTOCOL_VIOLATION);
                    }

                    PerformKeyExchange(packet);

                    return(true);
                }

                default:
                {
                    // Not a transport protocol message
                    return(false);
                }
                }
            }
            catch (System.IO.IOException ex1)
            {
                throw new SSHException(ex1.Message, SSHException.INTERNAL_ERROR);
            }
        }
Пример #5
0
        /// <summary>
        /// Opens a channel
        /// </summary>
        /// <param name="channel"></param>
        /// <param name="requestdata"></param>
        public void OpenChannel(SSH2Channel channel, byte[] requestdata)
        {
            lock (this)
            {
                try
                {
                    int channelid = AllocateChannel(channel);

                    if (channelid == -1)
                    {
                        throw new ChannelOpenException("Maximum number of channels exceeded",
                                                       ChannelOpenException.RESOURCE_SHORTAGE);
                    }

                    channel.Init(this, channelid);
                    SSHPacket packet = GetPacket();
                    packet.WriteByte(SSH_MSG_CHANNEL_OPEN);
                    packet.WriteString(channel.Name);
                    packet.WriteUINT32(channel.ChannelID);
                    packet.WriteUINT32(channel.WindowSize);
                    packet.WriteUINT32(channel.PacketSize);
                    if (requestdata != null)
                    {
                        packet.WriteBytes(requestdata);
                    }

#if DEBUG
                    System.Diagnostics.Trace.WriteLine("Sending SSH_MSG_CHANNEL_OPEN");
                    System.Diagnostics.Trace.WriteLine("Channelid=" + channel.ChannelID);
                    System.Diagnostics.Trace.WriteLine("Name=" + channel.Name);
#endif

                    transport.SendMessage(packet);

                    packet = channel.MessageStore.NextMessage(CHANNEL_OPEN_RESPONSE_MESSAGES);

#if DEBUG
                    System.Diagnostics.Trace.WriteLine("Received reply to SSH_MSG_CHANNEL_OPEN");
                    channel.LogMessage(packet);
#endif
                    if (packet.MessageID == SSH_MSG_CHANNEL_OPEN_FAILURE)
                    {
                        FreeChannel(channel);
                        int reason = (int)packet.ReadUINT32();
                        throw new ChannelOpenException(packet.ReadString(), reason);
                    }
                    else
                    {
                        int    remoteid     = (int)packet.ReadUINT32();
                        int    remotewindow = (int)packet.ReadUINT32();
                        int    remotepacket = (int)packet.ReadUINT32();
                        byte[] responsedata = new byte[packet.Available];
                        packet.ReadBytes(responsedata);

                        channel.Open(remoteid, remotewindow, remotepacket, responsedata);

                        return;
                    }
                }
                catch (System.IO.IOException ex)
                {
                    throw new SSHException(ex.Message, SSHException.INTERNAL_ERROR);
                }
            }
        }
Пример #6
0
        /// <summary>
        /// Start the authentication request.
        /// </summary>
        /// <param name="authentication">The authentication protocol instance.</param>
        /// <param name="serviceName">The name of the service to start upon a successful authentication.</param>
        public void Authenticate(AuthenticationProtocol authentication, String serviceName)
        {
            if (InteractivePrompt == null)
            {
                throw new SSHException("An interactive prompt event must be set!",
                                       SSHException.BAD_API_USAGE);
            }

            ByteBuffer baw = new ByteBuffer();

            baw.WriteString("");
            baw.WriteString("");

            authentication.SendRequest(username,
                                       serviceName,
                                       "keyboard-interactive",
                                       baw.ToByteArray());

            while (true)
            {
                SSHPacket msg = authentication.ReadMessage();
                if (msg.MessageID != SSH_MSG_USERAUTH_INFO_REQUEST)
                {
                    authentication.transport.Disconnect("Unexpected authentication message received!",
                                                        DisconnectionReason.PROTOCOL_ERROR);
                    throw new SSHException("Unexpected authentication message received!",
                                           SSHException.PROTOCOL_VIOLATION);
                }

                String name        = msg.ReadString();
                String instruction = msg.ReadString();
                String langtag     = msg.ReadString();

                int         num = (int)msg.ReadInt();
                String      prompt;
                bool        echo;
                KBIPrompt[] prompts = new KBIPrompt[num];
                for (int i = 0; i < num; i++)
                {
                    prompt     = msg.ReadString();
                    echo       = (msg.ReadBool());
                    prompts[i] = new KBIPrompt(prompt, echo);
                }

                if (InteractivePrompt(name, instruction, prompts))
                {
                    msg = authentication.transport.GetSSHPacket(true);
                    msg.WriteByte(SSH_MSG_USERAUTH_INFO_RESPONSE);
                    msg.WriteInt(prompts.Length);

                    for (int i = 0; i < prompts.Length; i++)
                    {
                        msg.WriteString(prompts[i].Response);
                    }

                    authentication.transport.SendMessage(msg);
                }
                else
                {
                    throw new SSHException("User cancelled during authentication",
                                           SSHException.USER_CANCELATION);
                }
            }
        }