Exemple #1
0
        public void OnData(byte[] data, int offset, int length) {
            _buffer.Write(data, offset, length);
            int expectedLength = SSHUtil.ReadInt32(_buffer.UnderlyingBuffer, 0);
            if(expectedLength + 4 <= _buffer.Length) {
                SSH2DataReader r = new SSH2DataReader(new DataFragment(_buffer.UnderlyingBuffer, 4, _buffer.Length-4));
                AgentForwadPacketType pt = (AgentForwadPacketType)r.ReadByte();
                //remaining len-1
                _buffer.SetOffset(0);

                switch(pt) {
                    case AgentForwadPacketType.SSH2_AGENTC_REQUEST_IDENTITIES:
                        SendKeyList();
                        break;
                    case AgentForwadPacketType.SSH2_AGENTC_SIGN_REQUEST:
                        SendSign(r);
                        break;
                    default:
                        //Debug.WriteLine("Unknown agent packet " + pt.ToString());
                        TransmitWriter(OpenWriter(AgentForwadPacketType.SSH_AGENT_FAILURE));
                        break;
                }
            }
        }
Exemple #2
0
        public void OnData(byte[] data, int offset, int length)
        {
            #if DUMP_PACKET
            Dump("SFTP: OnData", data, offset, length);
            #endif
            DataFragment dataFragment;
            if (_isDataIncomplete) {
                // append to buffer
                _dataBuffer.Write(data, offset, length);

                if (_dataTotal == 0) {  // not determined yet
                    if (_dataBuffer.Length < 4)
                        return;
                    _dataTotal = SSHUtil.ReadInt32(_dataBuffer.UnderlyingBuffer, 0);
                }

                if (_dataBuffer.Length < _dataTotal)
                    return;

                _isDataIncomplete = false;
                _dataTotal = 0;
                dataFragment = new DataFragment(_dataBuffer.UnderlyingBuffer, 0, (int)_dataBuffer.Length);
            }
            else {
                if (length < 4) {
                    _dataBuffer.Reset();
                    _dataBuffer.Write(data, offset, length);
                    _isDataIncomplete = true;
                    _dataTotal = 0; // determine later...
                    return;
                }

                int total = SSHUtil.ReadInt32(data, offset);
                if (length - 4 < total) {
                    _dataBuffer.Reset();
                    _dataBuffer.Write(data, offset, length);
                    _isDataIncomplete = true;
                    _dataTotal = total;
                    return;
                }
                dataFragment = new DataFragment(data, offset, length);
            }

            SSH2DataReader reader = new SSH2DataReader(dataFragment);
            int dataLength = reader.ReadInt32();
            if (dataLength >= 1) {
                SFTPPacketType packetType = (SFTPPacketType)reader.ReadByte();
                dataLength--;
                lock (ResponseNotifier) {
                    bool processed = false;
                    if (_responseHandler != null) {
                        try {
                            processed = _responseHandler(packetType, reader);
                        }
                        catch (Exception e) {
                            _responseHandlerException = e;
                            processed = true;
                        }
                    }
                    else {
                        processed = true;
                    }

                    if (processed) {
                        Monitor.PulseAll(_responseNotifier);
                    }
                }
            }
            // FIXME: invalid packet should be alerted
        }
 /// <summary>
 /// Reads a multiple precision integer.
 /// </summary>
 /// <returns>a multiple precision integer</returns>
 private BigInteger ReadBigIntWithBits(SSH2DataReader reader)
 {
     int bits = reader.ReadInt32();
     int bytes = (bits + 7) / 8;
     byte[] biData = reader.Read(bytes);
     return new BigInteger(biData);
 }
        /// <summary>
        /// Read PuTTY SSH2 private key parameters.
        /// </summary>
        /// <param name="passphrase">passphrase for decrypt the key file</param>
        /// <param name="keyPair">key pair</param>
        /// <param name="comment">comment or empty if it didn't exist</param>
        public void Load(string passphrase, out KeyPair keyPair, out string comment)
        {
            if (keyFile == null)
                throw new SSHException("A key file is not loaded yet");

            int version;
            string keyTypeName;
            KeyType keyType;
            string encryptionName;
            CipherAlgorithm? encryption;
            byte[] publicBlob;
            byte[] privateBlob;
            string privateMac;
            string privateHash;

            using (StreamReader sreader = GetStreamReader()) {
                //*** Read header and key type
                ReadHeaderLine(sreader, out version, out keyTypeName);

                if (keyTypeName == "ssh-rsa")
                    keyType = KeyType.RSA;
                else if (keyTypeName == "ssh-dss")
                    keyType = KeyType.DSA;
                else
                    throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (unexpected key type)");

                //*** Read encryption
                ReadItemLine(sreader, "Encryption", out encryptionName);

                if (encryptionName == "aes256-cbc")
                    encryption = CipherAlgorithm.AES256;
                else if (encryptionName == "none")
                    encryption = null;
                else
                    throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (unexpected encryption)");

                //*** Read comment
                ReadItemLine(sreader, "Comment", out comment);

                //*** Read public lines
                string publicLinesStr;
                ReadItemLine(sreader, "Public-Lines", out publicLinesStr);
                int publicLines;
                if (!Int32.TryParse(publicLinesStr, out publicLines) || publicLines < 0)
                    throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (invalid public lines)");

                ReadBlob(sreader, publicLines, out publicBlob);

                //*** Read private lines
                string privateLinesStr;
                ReadItemLine(sreader, "Private-Lines", out privateLinesStr);
                int privateLines;
                if (!Int32.TryParse(privateLinesStr, out privateLines) || privateLines < 0)
                    throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (invalid private lines)");

                ReadBlob(sreader, privateLines, out privateBlob);

                //*** Read private MAC
                ReadPrivateMACLine(sreader, version, out privateMac, out privateHash);
            }

            if (encryption.HasValue) {
                byte[] key = PuTTYPassphraseToKey(passphrase);
                byte[] iv = new byte[16];
                Cipher cipher = CipherFactory.CreateCipher(SSHProtocol.SSH2, encryption.Value, key, iv);
                if (privateBlob.Length % cipher.BlockSize != 0)
                    throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (invalid key data size)");
                cipher.Decrypt(privateBlob, 0, privateBlob.Length, privateBlob, 0);
            }

            bool verified = Verify(version, privateMac, privateHash,
                                passphrase, keyTypeName, encryptionName, comment, publicBlob, privateBlob);
            if (!verified) {
                if (encryption.HasValue)
                    throw new SSHException(Strings.GetString("WrongPassphrase"));
                else
                    throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (HMAC verification failed)");
            }

            if (keyType == KeyType.RSA) {
                SSH2DataReader reader = new SSH2DataReader(publicBlob);
                string magic = reader.ReadString();
                if (magic != "ssh-rsa")
                    throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (missing magic)");

                BigInteger e = reader.ReadMPInt();
                BigInteger n = reader.ReadMPInt();

                reader = new SSH2DataReader(privateBlob);
                BigInteger d = reader.ReadMPInt();
                BigInteger p = reader.ReadMPInt();
                BigInteger q = reader.ReadMPInt();
                BigInteger iqmp = reader.ReadMPInt();

                BigInteger u = p.ModInverse(q);

                keyPair = new RSAKeyPair(e, d, n, u, p, q);
            }
            else if (keyType == KeyType.DSA) {
                SSH2DataReader reader = new SSH2DataReader(publicBlob);
                string magic = reader.ReadString();
                if (magic != "ssh-dss")
                    throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (missing magic)");

                BigInteger p = reader.ReadMPInt();
                BigInteger q = reader.ReadMPInt();
                BigInteger g = reader.ReadMPInt();
                BigInteger y = reader.ReadMPInt();

                reader = new SSH2DataReader(privateBlob);
                BigInteger x = reader.ReadMPInt();

                keyPair = new DSAKeyPair(p, g, q, y, x);
            }
            else {
                throw new SSHException("Unknown file type. This should not happen.");
            }
        }
 private void EstablishSession(ISSHChannelEventReceiver receiver, PacketType pt, SSH2DataReader reader) {
     if(_negotiationStatus==NegotiationStatus.WaitingChannelConfirmation) {
         if(pt!=PacketType.SSH_MSG_CHANNEL_OPEN_CONFIRMATION) {
             if(pt!=PacketType.SSH_MSG_CHANNEL_OPEN_FAILURE)
                 receiver.OnChannelError(new SSHException("opening channel failed; packet type="+pt));
             else {
                 int remote_id = reader.ReadInt32();
                 int errcode = reader.ReadInt32();
                 string msg = Encoding.ASCII.GetString(reader.ReadString());
                 receiver.OnChannelError(new SSHException(msg));
             }
             Close();
         }
         else {
             _remoteID = reader.ReadInt32();
             _serverMaxPacketSize = reader.ReadInt32();
             _negotiationStatus = NegotiationStatus.Ready;
             receiver.OnChannelReady();
         }
     }
     else
         throw new SSHException("internal state error");
 }
        // sending "exec" service for SCP protocol.
        private void ExecCommand(ISSHChannelEventReceiver receiver, PacketType pt, SSH2DataReader reader) {
            if(_negotiationStatus==NegotiationStatus.WaitingChannelConfirmation) {
                if(pt!=PacketType.SSH_MSG_CHANNEL_OPEN_CONFIRMATION) {
                    if(pt!=PacketType.SSH_MSG_CHANNEL_OPEN_FAILURE)
                        receiver.OnChannelError(new SSHException("opening channel failed; packet type="+pt));
                    else {
                        int errcode = reader.ReadInt32();
                        string msg = Encoding.ASCII.GetString(reader.ReadString());
                        receiver.OnChannelError(new SSHException(msg));
                    }
                    Close();
                }
                else {
                    _remoteID = reader.ReadInt32();
                    _allowedDataSize = reader.ReadInt32();
                    _serverMaxPacketSize = reader.ReadInt32();

                    // exec command
                    SSH2DataWriter wr = new SSH2DataWriter();
                    SSHConnectionParameter param = _connection.Param;
                    wr.WritePacketType(PacketType.SSH_MSG_CHANNEL_REQUEST);
                    wr.Write(_remoteID);
                    wr.Write("exec");  // "exec"
                    wr.Write(false);   // want confirm is disabled. (*)
                    wr.Write(_command);

                    if (_connection.IsEventTracerAvailable)
                        _connection.TraceTransmissionEvent("exec command","cmd={0}", _command);
                    TransmitPayload(wr.ToByteArray());

                    //confirmation is omitted
                    receiver.OnChannelReady();
                    _negotiationStatus = NegotiationStatus.Ready; //goal!
                }
            }
            else if(_negotiationStatus==NegotiationStatus.WaitingExecCmdConfirmation) {
                if(pt!=PacketType.SSH_MSG_CHANNEL_DATA) {
                    receiver.OnChannelError(new SSHException("exec command failed"));
                    Close();
                }
                else {
                    receiver.OnChannelReady();
                    _negotiationStatus = NegotiationStatus.Ready; //goal!
                }
            }
            else
                throw new SSHException("internal state error");
        }
 private void ProcessChannelLocalData(ISSHChannelEventReceiver receiver, PacketType pt, SSH2DataReader re) {
     switch(pt) {
         case PacketType.SSH_MSG_CHANNEL_DATA: {
             int len = re.ReadInt32();
             receiver.OnData(re.Image, re.Offset, len);
         }
             break;
         case PacketType.SSH_MSG_CHANNEL_EXTENDED_DATA: {
             int t = re.ReadInt32();
             byte[] data = re.ReadString();
             receiver.OnExtendedData(t, data);
         }
             break;
         case PacketType.SSH_MSG_CHANNEL_REQUEST: {
             string request = Encoding.ASCII.GetString(re.ReadString());
             bool reply = re.ReadBool();
             if(request=="exit-status") {
                 int status = re.ReadInt32();
             }
             else if(reply) { //we reject unknown requests including keep-alive check
                 SSH2DataWriter wr = new SSH2DataWriter();
                 wr.WritePacketType(PacketType.SSH_MSG_CHANNEL_FAILURE);
                 wr.Write(_remoteID);
                 TransmitPayload(wr.ToByteArray());
             }
         }
             break;
         case PacketType.SSH_MSG_CHANNEL_EOF:
             receiver.OnChannelEOF();
             break;
         case PacketType.SSH_MSG_CHANNEL_CLOSE:
             _connection.ChannelCollection.UnregisterChannelEventReceiver(_localID);
             receiver.OnChannelClosed();
             break;
         case PacketType.SSH_MSG_CHANNEL_FAILURE:
             receiver.OnMiscPacket((byte)pt, re.Image, re.Offset, re.Rest);
             break;
         default:
             receiver.OnMiscPacket((byte)pt, re.Image, re.Offset, re.Rest);
             Debug.WriteLine("Unknown Packet "+pt);
             break;
     }			
 }
        internal void ProcessPacket(ISSHChannelEventReceiver receiver, PacketType pt, int data_length, SSH2DataReader re) {
            //NOTE: the offset of 're' is next to 'receipiant channel' field

            AdjustWindowSize(pt, data_length);

            //SSH_MSG_CHANNEL_WINDOW_ADJUST comes before the complete of channel establishment
            if(pt==PacketType.SSH_MSG_CHANNEL_WINDOW_ADJUST) {
                int w = re.ReadInt32();
                //some servers may not send SSH_MSG_CHANNEL_WINDOW_ADJUST. 
                //it is dangerous to wait this message in send procedure
                _allowedDataSize += w;
                if(_connection.IsEventTracerAvailable)
                    _connection.TraceReceptionEvent("SSH_MSG_CHANNEL_WINDOW_ADJUST", "adjusted to {0} by increasing {1}", _allowedDataSize, w);
                return;
            }

            if(_negotiationStatus!=NegotiationStatus.Ready) //when the negotiation is not completed
                ProgressChannelNegotiation(receiver, pt, re);
            else 
                ProcessChannelLocalData(receiver, pt, re);
        }
        private void ProcessKEXINIT(DataFragment packet) {
            SSH2DataReader re = null;
            do {
                _serverKEXINITPayload = packet.ToNewArray();
                re = new SSH2DataReader(_serverKEXINITPayload);
                byte[] head = re.Read(17); //Type and cookie
                PacketType pt = (PacketType)head[0];

                if(pt==PacketType.SSH_MSG_KEXINIT)
                    break; //successfully exit
                else if(pt==PacketType.SSH_MSG_IGNORE || pt==PacketType.SSH_MSG_DEBUG) { //continue
                    packet = _connection.ReceivePacket();
                }
                else
                    throw new SSHException(String.Format("Server response is not SSH_MSG_KEXINIT but {0}", head[0]));
            } while(true);

            Encoding enc = Encoding.ASCII;
            
            string kex = enc.GetString(re.ReadString());
            _cInfo._supportedKEXAlgorithms = kex;
            CheckAlgorithmSupport("keyexchange", kex, "diffie-hellman-group1-sha1");
            
            string host_key = enc.GetString(re.ReadString());
            _cInfo._supportedHostKeyAlgorithms = host_key;
            _cInfo._algorithmForHostKeyVerification = DecideHostKeyAlgorithm(host_key);
            
            string enc_cs = enc.GetString(re.ReadString());
            _cInfo._supportedCipherAlgorithms = enc_cs;
            _cInfo._algorithmForTransmittion = DecideCipherAlgorithm(enc_cs);
            
            string enc_sc = enc.GetString(re.ReadString());
            _cInfo._algorithmForReception = DecideCipherAlgorithm(enc_sc);

            string mac_cs = enc.GetString(re.ReadString());
            CheckAlgorithmSupport("mac", mac_cs, "hmac-sha1");
            
            string mac_sc = enc.GetString(re.ReadString());
            CheckAlgorithmSupport("mac", mac_sc, "hmac-sha1");
            
            string comp_cs = enc.GetString(re.ReadString());
            CheckAlgorithmSupport("compression", comp_cs, "none");
            string comp_sc = enc.GetString(re.ReadString());
            CheckAlgorithmSupport("compression", comp_sc, "none");
            
            string lang_cs = enc.GetString(re.ReadString());
            string lang_sc = enc.GetString(re.ReadString());
            bool flag = re.ReadBool();
            int reserved = re.ReadInt32();
            Debug.Assert(re.Rest==0);

            if(_connection.IsEventTracerAvailable) {
                StringBuilder bld = new StringBuilder();
                bld.Append("kex_algorithm=");                            bld.Append(kex);
                bld.Append("; server_host_key_algorithms=");             bld.Append(host_key);
                bld.Append("; encryption_algorithms_client_to_server="); bld.Append(enc_cs);
                bld.Append("; encryption_algorithms_server_to_client="); bld.Append(enc_sc);
                bld.Append("; mac_algorithms_client_to_server=");        bld.Append(mac_cs);
                bld.Append("; mac_algorithms_server_to_client=");        bld.Append(mac_sc);
                bld.Append("; comression_algorithms_client_to_server="); bld.Append(comp_cs);
                bld.Append("; comression_algorithms_server_to_client="); bld.Append(comp_sc);
                TraceReceptionNegotiation(PacketType.SSH_MSG_KEXINIT, bld.ToString());
            }

            if(flag) throw new SSHException("Algorithm negotiation failed"); 
        }
Exemple #10
0
 internal static DSAPublicKey ReadFrom(SSH2DataReader reader)
 {
     BigInteger p = reader.ReadMPInt();
     BigInteger q = reader.ReadMPInt();
     BigInteger g = reader.ReadMPInt();
     BigInteger y = reader.ReadMPInt();
     return new DSAPublicKey(p, g, q, y);
 }
        public static SSH2UserAuthKey FromByteArray(byte[] keydata, string passphrase)
        {
            SSH2DataReader re = new SSH2DataReader(keydata);
            int magic = re.ReadInt32();
            if (magic != MAGIC_VAL) throw new SSHException("key file is broken");
            int privateKeyLen = re.ReadInt32();
            string type = Encoding.ASCII.GetString(re.ReadString());

            string ciphername = Encoding.ASCII.GetString(re.ReadString());
            int bufLen = re.ReadInt32();
            if (ciphername != "none")
            {
                CipherAlgorithm algo = CipherFactory.SSH2NameToAlgorithm(ciphername);
                byte[] key = PassphraseToKey(passphrase, CipherFactory.GetKeySize(algo));
                Cipher c = CipherFactory.CreateCipher(SSHProtocol.SSH2, algo, key);
                byte[] tmp = new Byte[re.Image.Length - re.Offset];
                c.Decrypt(re.Image, re.Offset, re.Image.Length - re.Offset, tmp, 0);
                re = new SSH2DataReader(tmp);
            }

            int parmLen = re.ReadInt32();
            if (parmLen < 0 || parmLen > re.Rest)
                throw new SSHException(Strings.GetString("WrongPassphrase"));

            if (type.IndexOf("if-modn") != -1)
            {
                //mindterm mistaken this order of BigIntegers
                BigInteger e = re.ReadBigIntWithBits();
                BigInteger d = re.ReadBigIntWithBits();
                BigInteger n = re.ReadBigIntWithBits();
                BigInteger u = re.ReadBigIntWithBits();
                BigInteger p = re.ReadBigIntWithBits();
                BigInteger q = re.ReadBigIntWithBits();
                return new SSH2UserAuthKey(new RSAKeyPair(e, d, n, u, p, q));
            }
            else if (type.IndexOf("dl-modp") != -1)
            {
                if (re.ReadInt32() != 0) throw new SSHException("DSS Private Key File is broken");
                BigInteger p = re.ReadBigIntWithBits();
                BigInteger g = re.ReadBigIntWithBits();
                BigInteger q = re.ReadBigIntWithBits();
                BigInteger y = re.ReadBigIntWithBits();
                BigInteger x = re.ReadBigIntWithBits();
                return new SSH2UserAuthKey(new DSAKeyPair(p, g, q, y, x));
            }
            else
                throw new SSHException("unknown authentication method " + type);
        }
Exemple #12
0
        internal static ECDSAPublicKey ReadFrom(SSH2DataReader reader) {
            string curveName = reader.ReadString();
            byte[] q = reader.ReadByteString();

            EllipticCurve curve = EllipticCurve.FindByName(curveName);
            if (curve == null) {
                throw new SSHException(Strings.GetString("UnsupportedEllipticCurve") + " : " + curveName);
            }

            ECPoint p;
            if (!ECPoint.Parse(q, curve, out p)) {
                throw new SSHException(Strings.GetString("InvalidECPublicKey"));
            }

            return new ECDSAPublicKey(curve, p);
        }
Exemple #13
0
        public void Verify(byte[] data, byte[] expected) {
            SSH2DataReader reader = new SSH2DataReader(data);
            BigInteger r = reader.ReadMPInt();
            BigInteger s = reader.ReadMPInt();
            if (r == 0 || r >= _curve.Order || s == 0 || s >= _curve.Order) {
                goto Fail;
            }

            if (!IsValid()) {
                goto Fail;
            }

            BigInteger order = _curve.Order;

            byte[] hash = HashForSigning(expected, _curve);
            BigInteger e = new BigInteger(hash);

            BigInteger.ModulusRing nring = new BigInteger.ModulusRing(order);

            try {
                BigInteger sInv = s.ModInverse(order);
                BigInteger u1 = nring.Multiply(e, sInv);
                BigInteger u2 = nring.Multiply(r, sInv);

                ECPoint p1 = _curve.PointMul(u1, _curve.BasePoint, true);
                ECPoint p2 = _curve.PointMul(u2, Point, true);
                if (p1 == null || p2 == null) {
                    goto Fail;
                }
                ECPoint R = _curve.PointAdd(p1, p2, true);
                if (R == null) {
                    goto Fail;
                }

                BigInteger v = R.X % order;

                if (v != r) {
                    goto Fail;
                }
            }
            catch (Exception) {
                goto Fail;
            }

            return;

        Fail:
            throw new VerifyException("Failed to verify");
        }
Exemple #14
0
        internal static EDDSAPublicKey ReadFrom(PublicKeyAlgorithm algorithm, SSH2DataReader reader)
        {
            EdwardsCurve curve = EdwardsCurve.FindByAlgorithm(algorithm);
            if (curve == null) {
                throw new SSHException(Strings.GetString("UnsupportedEllipticCurve"));
            }

            byte[] q = reader.ReadByteString();
            return new EDDSAPublicKey(curve, q);
        }
        /// <summary>
        /// Process packet about this channel.
        /// </summary>
        /// <param name="packetType">a packet type (message number)</param>
        /// <param name="packetFragment">a packet image except message number and recipient channel.</param>
        public void ProcessPacket(SSH2PacketType packetType, DataFragment packetFragment)
        {
            if (_state == State.Closed) {
                return; // ignore
            }

            DataFragment dataFragmentArg;
            uint dataTypeCodeArg;

            lock (_stateSync) {
                switch (_state) {
                    case State.InitiatedByServer:
                        break;
                    case State.InitiatedByClient:
                        if (packetType == SSH2PacketType.SSH_MSG_CHANNEL_OPEN_CONFIRMATION) {
                            SSH2DataReader reader = new SSH2DataReader(packetFragment);
                            RemoteChannel = reader.ReadUInt32();
                            _serverWindowSizeLeft = reader.ReadUInt32();
                            _serverMaxPacketSize = reader.ReadUInt32();

                            _state = State.Established;
                            Monitor.PulseAll(_stateSync);   // notifies state change
                            dataFragmentArg = reader.GetRemainingDataView();
                            goto OnEstablished; // do it out of the lock block
                        }
                        if (packetType == SSH2PacketType.SSH_MSG_CHANNEL_OPEN_FAILURE) {
                            SSH2DataReader reader = new SSH2DataReader(packetFragment);
                            uint reasonCode = reader.ReadUInt32();
                            string description = reader.ReadUTF8String();
                            string lang = reader.ReadString();
                            goto RequestFailed; // do it out of the lock block
                        }
                        break;
                    case State.Closing:
                        if (packetType == SSH2PacketType.SSH_MSG_CHANNEL_CLOSE) {
                            goto SetStateClosedByClient;    // do it out of the lock block
                        }
                        break;
                    case State.Established:
                    case State.Ready:
                        if (ProcessPacketSub(packetType, packetFragment) == SubPacketProcessResult.Consumed) {
                            return;
                        }
                        switch (packetType) {
                            case SSH2PacketType.SSH_MSG_CHANNEL_DATA: {
                                    SSH2DataReader reader = new SSH2DataReader(packetFragment);
                                    int len = reader.ReadInt32();
                                    dataFragmentArg = reader.GetRemainingDataView(len);
                                    AdjustWindowSize(len);
                                }
                                goto OnData;    // do it out of the lock block
                            case SSH2PacketType.SSH_MSG_CHANNEL_EXTENDED_DATA: {
                                    SSH2DataReader reader = new SSH2DataReader(packetFragment);
                                    dataTypeCodeArg = reader.ReadUInt32();
                                    int len = reader.ReadInt32();
                                    dataFragmentArg = reader.GetRemainingDataView(len);
                                    AdjustWindowSize(len);
                                }
                                goto OnExtendedData;    // do it out of the lock block
                            case SSH2PacketType.SSH_MSG_CHANNEL_REQUEST: {
                                    SSH2DataReader reader = new SSH2DataReader(packetFragment);
                                    string request = reader.ReadString();
                                    bool wantReply = reader.ReadBool();
                                    if (wantReply) { //we reject unknown requests including keep-alive check
                                        Transmit(
                                            0,
                                            new SSH2Packet(SSH2PacketType.SSH_MSG_CHANNEL_FAILURE)
                                                .WriteUInt32(RemoteChannel)
                                        );
                                    }
                                }
                                break;
                            case SSH2PacketType.SSH_MSG_CHANNEL_EOF:
                                goto OnEOF; // do it out of the lock block
                            case SSH2PacketType.SSH_MSG_CHANNEL_CLOSE:
                                Transmit(
                                    0,
                                    new SSH2Packet(SSH2PacketType.SSH_MSG_CHANNEL_CLOSE)
                                        .WriteUInt32(RemoteChannel)
                                );
                                goto SetStateClosedByServer;    // do it out of the lock block
                            case SSH2PacketType.SSH_MSG_CHANNEL_WINDOW_ADJUST: {
                                    SSH2DataReader reader = new SSH2DataReader(packetFragment);
                                    uint bytesToAdd = reader.ReadUInt32();
                                    // some servers may not send SSH_MSG_CHANNEL_WINDOW_ADJUST.
                                    // it is dangerous to wait this message in send procedure
                                    _serverWindowSizeLeft += bytesToAdd;
                                }
                                goto OnWindowAdjust;
                            case SSH2PacketType.SSH_MSG_CHANNEL_SUCCESS:
                            case SSH2PacketType.SSH_MSG_CHANNEL_FAILURE: {
                                    _channelRequestResult.TrySet(packetType == SSH2PacketType.SSH_MSG_CHANNEL_SUCCESS, 1000);
                                }
                                break;
                            default:
                                goto OnUnhandledPacket;
                        }
                        break;  // case State.Ready
                }
            }

            return;

            OnEstablished:
            _protocolEventManager.Trace(
                "CH[{0}] remoteCH={1} remoteWindowSize={2} remoteMaxPacketSize={3}",
                LocalChannel, RemoteChannel, _serverWindowSizeLeft, _serverMaxPacketSize);
            _handler.OnEstablished(dataFragmentArg);
            OnChannelEstablished();
            return;

            RequestFailed:
            _protocolEventManager.Trace("CH[{0}] request failed", LocalChannel);
            RequestFailed();
            return;

            SetStateClosedByClient:
            _protocolEventManager.Trace("CH[{0}] closed completely", LocalChannel);
            SetStateClosed(false);
            return;

            SetStateClosedByServer:
            _protocolEventManager.Trace("CH[{0}] closed by server", LocalChannel);
            SetStateClosed(true);
            return;

            OnData:
            _handler.OnData(dataFragmentArg);
            return;

            OnExtendedData:
            _handler.OnExtendedData(dataTypeCodeArg, dataFragmentArg);
            return;

            OnEOF:
            _protocolEventManager.Trace("CH[{0}] caught EOF", LocalChannel);
            _handler.OnEOF();
            return;

            OnWindowAdjust:
            _protocolEventManager.Trace(
                "CH[{0}] adjusted remote window size to {1}",
                LocalChannel, _serverWindowSizeLeft);
            return;

            OnUnhandledPacket:
            _handler.OnUnhandledPacket((byte)packetType, packetFragment);
            return;
        }
        //synchronous reception
        internal DataFragment ReceivePacket() {
            while(true) {
                DataFragment data = _packetReceiver.WaitResponse();

                PacketType pt = (PacketType)data.ByteAt(0); //sneak

                //filter unnecessary packet
                if(pt==PacketType.SSH_MSG_IGNORE) {
                    SSH2DataReader r = new SSH2DataReader(data);
                    r.ReadPacketType(); //skip
                    byte[] msg = r.ReadString();
                    if(_eventReceiver!=null) _eventReceiver.OnIgnoreMessage(msg);
                    TraceReceptionEvent(pt, msg);
                }
                else if(pt==PacketType.SSH_MSG_DEBUG) {
                    SSH2DataReader r = new SSH2DataReader(data);
                    r.ReadPacketType(); //skip
                    bool f = r.ReadBool();
                    byte[] msg = r.ReadString();
                    if(_eventReceiver!=null) _eventReceiver.OnDebugMessage(f, msg);
                    TraceReceptionEvent(pt, msg);
                }
                else {
                    return data;
                }
            }
        }
        private bool ProcessPacket(DataFragment packet) {
            if(_readerForProcessPacket==null)
                _readerForProcessPacket = new SSH2DataReader(packet);
            else
                _readerForProcessPacket.Recycle(packet); //avoid 'new'

            SSH2DataReader r = _readerForProcessPacket; //rename for frequently use
            PacketType pt = r.ReadPacketType();
            
            if(pt==PacketType.SSH_MSG_DISCONNECT) {
                int errorcode = r.ReadInt32();
                _eventReceiver.OnConnectionClosed();
                return false;
            }
            else if(_waitingForPortForwardingResponse) {
                if(pt!=PacketType.SSH_MSG_REQUEST_SUCCESS)
                    _eventReceiver.OnUnknownMessage((byte)pt, r.Image);
                _waitingForPortForwardingResponse = false;
                return true;
            }
            else if(pt==PacketType.SSH_MSG_CHANNEL_OPEN) {
                string method = Encoding.ASCII.GetString(r.ReadString());
                if(method=="forwarded-tcpip")
                    ProcessPortforwardingRequest(_eventReceiver, r);
                else if(method.StartsWith("auth-agent")) //in most cases, method is "*****@*****.**"
                    ProcessAgentForwardRequest(_eventReceiver, r);
                else {
                    SSH2DataWriter wr = new SSH2DataWriter();
                    wr.WritePacketType(PacketType.SSH_MSG_CHANNEL_OPEN_FAILURE);
                    wr.Write(r.ReadInt32());
                    wr.Write(0);
                    wr.Write("unknown method");
                    wr.Write(""); //lang tag
                    TraceReceptionEvent("SSH_MSG_CHANNEL_OPEN rejected", "method={0}", method);
                }
                return true;
            }
            else if(pt>=PacketType.SSH_MSG_CHANNEL_OPEN_CONFIRMATION && pt<=PacketType.SSH_MSG_CHANNEL_FAILURE) {
                int local_channel = r.ReadInt32();
                ChannelCollection.Entry e = this.ChannelCollection.FindChannelEntry(local_channel);
                if(e!=null) 
                    ((SSH2Channel)e.Channel).ProcessPacket(e.Receiver, pt, 5+r.Rest, r);
                else
                    Debug.WriteLine("unexpected channel pt="+pt+" local_channel="+local_channel.ToString());
                return true;
            }
            else if(pt==PacketType.SSH_MSG_IGNORE) {
                _eventReceiver.OnIgnoreMessage(r.ReadString());
                return true;
            }
            else if(_asyncKeyExchanger!=null) {
                _asyncKeyExchanger.AsyncProcessPacket(packet);
                return true;
            }
            else if(pt==PacketType.SSH_MSG_KEXINIT) {
                //Debug.WriteLine("Host sent KEXINIT");
                _asyncKeyExchanger = new KeyExchanger(this, _sessionID);
                _asyncKeyExchanger.AsyncProcessPacket(packet);
                return true;
            }
            else {
                _eventReceiver.OnUnknownMessage((byte)pt, r.Image);
                return false;
            }
        }
        private bool ProcessKEXDHREPLY(DataFragment packet) {
            //Round2 receives response
            SSH2DataReader re = null;
            PacketType h;
            do {
                re = new SSH2DataReader(packet);
                h = re.ReadPacketType();
                if(h==PacketType.SSH_MSG_KEXDH_REPLY)
                    break; //successfully exit
                else if(h==PacketType.SSH_MSG_IGNORE || h==PacketType.SSH_MSG_DEBUG) { //continue
                    packet = _connection.ReceivePacket();
                }
                else
                    throw new SSHException(String.Format("KeyExchange response is not KEXDH_REPLY but {0}", h));
            } while(true);

            byte[] key_and_cert = re.ReadString();
            BigInteger f = re.ReadMPInt();
            byte[] signature = re.ReadString();
            Debug.Assert(re.Rest==0);

            //Round3 calc hash H
            SSH2DataWriter wr = new SSH2DataWriter();
            _k = f.modPow(_x, DH_PRIME);
            wr = new SSH2DataWriter();
            wr.Write(_cInfo._clientVersionString);
            wr.Write(_cInfo._serverVersionString);
            wr.WriteAsString(_clientKEXINITPayload);
            wr.WriteAsString(_serverKEXINITPayload);
            wr.WriteAsString(key_and_cert);
            wr.Write(_e);
            wr.Write(f);
            wr.Write(_k);
            _hash = new SHA1CryptoServiceProvider().ComputeHash(wr.ToByteArray());

            _connection.TraceReceptionEvent(h, "verifying host key");
            if(!VerifyHostKey(key_and_cert, signature, _hash)) return false;

            //Debug.WriteLine("hash="+DebugUtil.DumpByteArray(hash));
            if(_sessionID==null) _sessionID = _hash;
            return true;
        }
 //Progress the state of this channel establishment negotiation
 private void ProgressChannelNegotiation(ISSHChannelEventReceiver receiver, PacketType pt, SSH2DataReader re) {
     if(_type==ChannelType.Shell)
         OpenShellOrSubsystem(receiver, pt, re, "shell");
     else if(_type==ChannelType.ForwardedLocalToRemote)
         ReceivePortForwardingResponse(receiver, pt, re);
     else if(_type==ChannelType.Session)
         EstablishSession(receiver, pt, re);
     else if(_type==ChannelType.ExecCommand)  // for SCP
         ExecCommand(receiver, pt, re);
     else if(_type==ChannelType.Subsystem)
         OpenShellOrSubsystem(receiver, pt, re, "subsystem");
 }
        private bool VerifyHostKey(byte[] K_S, byte[] signature, byte[] hash) {
            SSH2DataReader re1 = new SSH2DataReader(K_S);
            string algorithm = Encoding.ASCII.GetString(re1.ReadString());
            if(algorithm!=SSH2Util.PublicKeyAlgorithmName(_cInfo._algorithmForHostKeyVerification))
                throw new SSHException("Protocol Error: Host Key Algorithm Mismatch");

            SSH2DataReader re2 = new SSH2DataReader(signature);
            algorithm = Encoding.ASCII.GetString(re2.ReadString());
            if(algorithm!=SSH2Util.PublicKeyAlgorithmName(_cInfo._algorithmForHostKeyVerification))
                throw new SSHException("Protocol Error: Host Key Algorithm Mismatch");
            byte[] sigbody = re2.ReadString();
            Debug.Assert(re2.Rest==0);

            if(_cInfo._algorithmForHostKeyVerification==PublicKeyAlgorithm.RSA)
                VerifyHostKeyByRSA(re1, sigbody, hash);
            else if(_cInfo._algorithmForHostKeyVerification==PublicKeyAlgorithm.DSA)
                VerifyHostKeyByDSS(re1, sigbody, hash);
            else
                throw new SSHException("Bad host key algorithm "+_cInfo._algorithmForHostKeyVerification);

            //ask the client whether he accepts the host key
            if(!_startedByHost && _param.KeyCheck!=null && !_param.KeyCheck(_cInfo))
                return false;
            else
                return true;
        }
        private void OpenShellOrSubsystem(ISSHChannelEventReceiver receiver, PacketType pt, SSH2DataReader reader, string scheme) {
            if(_negotiationStatus==NegotiationStatus.WaitingChannelConfirmation) {
                if(pt!=PacketType.SSH_MSG_CHANNEL_OPEN_CONFIRMATION) {
                    if(pt!=PacketType.SSH_MSG_CHANNEL_OPEN_FAILURE)
                        receiver.OnChannelError(new SSHException("opening channel failed; packet type="+pt));
                    else {
                        int errcode = reader.ReadInt32();
                        string msg = Encoding.ASCII.GetString(reader.ReadString());
                        receiver.OnChannelError(new SSHException(msg));
                    }
                    Close();
                }
                else {
                    _remoteID = reader.ReadInt32();
                    _allowedDataSize = reader.ReadInt32();
                    _serverMaxPacketSize = reader.ReadInt32();

                    //open pty
                    SSH2DataWriter wr = new SSH2DataWriter();
                    SSHConnectionParameter param = _connection.Param;
                    wr.WritePacketType(PacketType.SSH_MSG_CHANNEL_REQUEST);
                    wr.Write(_remoteID);
                    wr.Write("pty-req");
                    wr.Write(true);
                    wr.Write(param.TerminalName);
                    wr.Write(param.TerminalWidth);
                    wr.Write(param.TerminalHeight);
                    wr.Write(param.TerminalPixelWidth);
                    wr.Write(param.TerminalPixelHeight);
                    wr.WriteAsString(new byte[0]);
                    if(_connection.IsEventTracerAvailable)
                        _connection.TraceTransmissionEvent(PacketType.SSH_MSG_CHANNEL_REQUEST, "pty-req", "terminal={0} width={1} height={2}", param.TerminalName, param.TerminalWidth, param.TerminalHeight);
                    TransmitPayload(wr.ToByteArray());

                    _negotiationStatus = NegotiationStatus.WaitingPtyReqConfirmation;
                }
            }
            else if(_negotiationStatus==NegotiationStatus.WaitingPtyReqConfirmation) {
                if(pt!=PacketType.SSH_MSG_CHANNEL_SUCCESS) {
                    receiver.OnChannelError(new SSHException("opening pty failed"));
                    Close();
                }
                else {
                    //agent request (optional)
                    if(_connection.Param.AgentForward!=null) {
                        SSH2DataWriter wr = new SSH2DataWriter();
                        wr.WritePacketType(PacketType.SSH_MSG_CHANNEL_REQUEST);
                        wr.Write(_remoteID);
                        wr.Write("*****@*****.**");
                        wr.Write(true);
                        _connection.TraceTransmissionEvent(PacketType.SSH_MSG_CHANNEL_REQUEST, "auth-agent-req", "");
                        TransmitPayload(wr.ToByteArray());
                        _negotiationStatus = NegotiationStatus.WaitingAuthAgentReqConfirmation;
                    }
                    else {
                        OpenScheme(scheme);
                        _negotiationStatus = NegotiationStatus.WaitingShellConfirmation;
                    }
                }
            }
            else if(_negotiationStatus==NegotiationStatus.WaitingAuthAgentReqConfirmation) {
                if(pt!=PacketType.SSH_MSG_CHANNEL_SUCCESS && pt!=PacketType.SSH_MSG_CHANNEL_FAILURE) {
                    receiver.OnChannelError(new SSHException("auth-agent-req error"));
                    Close();
                }
                else { //auth-agent-req is optional
                    _connection.SetAgentForwardConfirmed(pt==PacketType.SSH_MSG_CHANNEL_SUCCESS);
                    _connection.TraceReceptionEvent(pt, "auth-agent-req");

                    OpenScheme(scheme);
                    _negotiationStatus = NegotiationStatus.WaitingShellConfirmation;
                }
            }
            else if(_negotiationStatus==NegotiationStatus.WaitingShellConfirmation) {
                if(pt!=PacketType.SSH_MSG_CHANNEL_SUCCESS) {
                    receiver.OnChannelError(new SSHException("Opening shell failed: packet type="+pt.ToString()));
                    Close();
                }
                else {
                    receiver.OnChannelReady();
                    _negotiationStatus = NegotiationStatus.Ready; //goal!
                }
            }
        }
        private void VerifyHostKeyByRSA(SSH2DataReader pubkey, byte[] sigbody, byte[] hash) {
            BigInteger exp = pubkey.ReadMPInt();
            BigInteger mod = pubkey.ReadMPInt();
            Debug.Assert(pubkey.Rest==0);

            RSAPublicKey pk = new RSAPublicKey(exp, mod);
            pk.VerifyWithSHA1(sigbody, new SHA1CryptoServiceProvider().ComputeHash(hash));
            _cInfo._hostkey = pk;
        }
        private void ServiceRequest(string servicename) {
            SSH2DataWriter wr = OpenTransmissionPacket();
            wr.WritePacketType(PacketType.SSH_MSG_SERVICE_REQUEST);
            wr.Write(servicename);
            TraceTransmissionEvent("SSH_MSG_SERVICE_REQUEST", servicename);
            TransmitPacket(wr);

            DataFragment response = ReceivePacket();
            SSH2DataReader re = new SSH2DataReader(response);
            PacketType t = re.ReadPacketType();
            if(t!=PacketType.SSH_MSG_SERVICE_ACCEPT) {
                TraceReceptionEvent(t.ToString(), "service request failed");
                throw new SSHException("service establishment failed "+t);
            }

            string s = Encoding.ASCII.GetString(re.ReadString());
            if(servicename!=s)
                throw new SSHException("protocol error");
        }
        private void VerifyHostKeyByDSS(SSH2DataReader pubkey, byte[] sigbody, byte[] hash) {
            BigInteger p = pubkey.ReadMPInt();
            BigInteger q = pubkey.ReadMPInt();
            BigInteger g = pubkey.ReadMPInt();
            BigInteger y = pubkey.ReadMPInt();
            Debug.Assert(pubkey.Rest==0);

            DSAPublicKey pk = new DSAPublicKey(p,g,q,y);
            pk.Verify(sigbody, new SHA1CryptoServiceProvider().ComputeHash(hash));
            _cInfo._hostkey = pk;
        }
Exemple #25
0
 internal static RSAPublicKey ReadFrom(SSH2DataReader reader)
 {
     BigInteger exp = reader.ReadMPInt();
     BigInteger mod = reader.ReadMPInt();
     return new RSAPublicKey(exp, mod);
 }
 private AuthenticationResult ProcessAuthenticationResponse() {
     do {
         SSH2DataReader response = new SSH2DataReader(ReceivePacket());
         PacketType h = response.ReadPacketType();
         if(h==PacketType.SSH_MSG_USERAUTH_FAILURE) {
             string msg = Encoding.ASCII.GetString(response.ReadString());
             TraceReceptionEvent(h, "user authentication failed:" + msg);
             return AuthenticationResult.Failure;
         }
         else if(h==PacketType.SSH_MSG_USERAUTH_BANNER) {
             TraceReceptionEvent(h, "");
         }
         else if(h==PacketType.SSH_MSG_USERAUTH_SUCCESS) {
             TraceReceptionEvent(h, "user authentication succeeded");
             _packetBuilder.InnerHandler = new CallbackSSH2PacketHandler(this);
             return AuthenticationResult.Success; //successfully exit
         }
         else if(h==PacketType.SSH_MSG_USERAUTH_INFO_REQUEST) {
             string name = Encoding.ASCII.GetString(response.ReadString());
             string inst = Encoding.ASCII.GetString(response.ReadString());
             string lang = Encoding.ASCII.GetString(response.ReadString());
             int num = response.ReadInt32();
             string[] prompts = new string[num];
             for(int i=0; i<num; i++) {
                 prompts[i] = Encoding.ASCII.GetString(response.ReadString());
                 bool echo = response.ReadBool();
             }
             _eventReceiver.OnAuthenticationPrompt(prompts);
             _requiredResponseCount = num;
             return AuthenticationResult.Prompt;
         }
         else
             throw new SSHException("protocol error: unexpected packet type "+h);
     } while(true);
 }
        /*
         * Format style note
         *  ---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----
         *  Comment: *******
         *  <base64-encoded body>
         *  ---- END SSH2 ENCRYPTED PRIVATE KEY ----
         * 
         *  body = MAGIC_VAL || body-length || type(string) || encryption-algorithm-name(string) || encrypted-body(string)
         *  encrypted-body = array of BigInteger(algorithm-specific)
         */
#if !PODEROSA_KEYFORMAT
        public static SSH2UserAuthKey FromSECSHStyleStream(Stream strm, string passphrase) {
            StreamReader r = new StreamReader(strm, Encoding.ASCII);
            string l = r.ReadLine();
            if (l == null || l != "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----")
                throw new SSHException("Wrong key format");

            string comment = "";
            l = r.ReadLine();
            StringBuilder buf = new StringBuilder();
            while (l != "---- END SSH2 ENCRYPTED PRIVATE KEY ----") {
                if (l.IndexOf(':') == -1)
                    buf.Append(l);
                else if (l[l.Length - 1] == '\\')
                    buf.Append(l, 0, l.Length - 1);
                else if (l.StartsWith("Comment: "))
                    comment = l.Substring("Comment: ".Length);

                l = r.ReadLine();
                if (l == null)
                    throw new SSHException("Key is broken");
            }
            r.Close();

            byte[] keydata = Base64.Decode(Encoding.ASCII.GetBytes(buf.ToString()));
            //Debug.WriteLine(DebugUtil.DumpByteArray(keydata));


            SSH2DataReader re = new SSH2DataReader(keydata);
            int magic = re.ReadInt32();
            if (magic != MAGIC_VAL)
                throw new SSHException("key file is broken");
            int privateKeyLen = re.ReadInt32();
            string type = Encoding.ASCII.GetString(re.ReadString());

            string ciphername = Encoding.ASCII.GetString(re.ReadString());
            int bufLen = re.ReadInt32();
            if (ciphername != "none") {
                CipherAlgorithm algo = CipherFactory.SSH2NameToAlgorithm(ciphername);
                byte[] key = PassphraseToKey(passphrase, CipherFactory.GetKeySize(algo));
                Cipher c = CipherFactory.CreateCipher(SSHProtocol.SSH2, algo, key);
                byte[] tmp = new Byte[re.Image.Length - re.Offset];
                c.Decrypt(re.Image, re.Offset, re.Image.Length - re.Offset, tmp, 0);
                re = new SSH2DataReader(tmp);
            }

            int parmLen = re.ReadInt32();
            if (parmLen < 0 || parmLen > re.Rest)
                throw new SSHException(Strings.GetString("WrongPassphrase"));

            if (type.IndexOf("if-modn") != -1) {
                //mindterm mistaken this order of BigIntegers
                BigInteger e = re.ReadBigIntWithBits();
                BigInteger d = re.ReadBigIntWithBits();
                BigInteger n = re.ReadBigIntWithBits();
                BigInteger u = re.ReadBigIntWithBits();
                BigInteger p = re.ReadBigIntWithBits();
                BigInteger q = re.ReadBigIntWithBits();
                return new SSH2UserAuthKey(new RSAKeyPair(e, d, n, u, p, q), comment);
            }
            else if (type.IndexOf("dl-modp") != -1) {
                if (re.ReadInt32() != 0)
                    throw new SSHException("DSS Private Key File is broken");
                BigInteger p = re.ReadBigIntWithBits();
                BigInteger g = re.ReadBigIntWithBits();
                BigInteger q = re.ReadBigIntWithBits();
                BigInteger y = re.ReadBigIntWithBits();
                BigInteger x = re.ReadBigIntWithBits();
                return new SSH2UserAuthKey(new DSAKeyPair(p, g, q, y, x), comment);
            }
            else
                throw new SSHException("unknown authentication method " + type);

        }
        private void ProcessPortforwardingRequest(ISSHConnectionEventReceiver receiver, SSH2DataReader reader) {

            int remote_channel = reader.ReadInt32();
            int window_size = reader.ReadInt32(); //skip initial window size
            int servermaxpacketsize = reader.ReadInt32();
            string host = Encoding.ASCII.GetString(reader.ReadString());
            int port = reader.ReadInt32();
            string originator_ip = Encoding.ASCII.GetString(reader.ReadString());
            int originator_port = reader.ReadInt32();
            
            TraceReceptionEvent("port forwarding request", String.Format("host={0} port={1} originator-ip={2} originator-port={3}", host, port, originator_ip, originator_port));
            PortForwardingCheckResult r = receiver.CheckPortForwardingRequest(host,port,originator_ip,originator_port);
            SSH2DataWriter wr = new SSH2DataWriter();
            if(r.allowed) {
                //send OPEN_CONFIRMATION
                SSH2Channel channel = new SSH2Channel(this, ChannelType.ForwardedRemoteToLocal, this.ChannelCollection.RegisterChannelEventReceiver(null, r.channel).LocalID, remote_channel, servermaxpacketsize);
                wr.WritePacketType(PacketType.SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
                wr.Write(remote_channel);
                wr.Write(channel.LocalChannelID);
                wr.Write(_param.WindowSize); //initial window size
                wr.Write(_param.MaxPacketSize); //max packet size
                receiver.EstablishPortforwarding(r.channel, channel);
                TraceTransmissionEvent("port-forwarding request is confirmed", "host={0} port={1} originator-ip={2} originator-port={3}", host, port, originator_ip, originator_port);
            }
            else {
                wr.WritePacketType(PacketType.SSH_MSG_CHANNEL_OPEN_FAILURE);
                wr.Write(remote_channel);
                wr.Write(r.reason_code);
                wr.Write(r.reason_message);
                wr.Write(""); //lang tag
                TraceTransmissionEvent("port-forwarding request is rejected", "host={0} port={1} originator-ip={2} originator-port={3}", host, port, originator_ip, originator_port);
            }
            TransmitRawPayload(wr.ToByteArray());
        }
        /// <summary>
        /// Read SSH.com SSH2 private key parameters.
        /// </summary>
        /// <param name="passphrase">passphrase for decrypt the key file</param>
        /// <param name="keyPair">key pair</param>
        /// <param name="comment">comment or empty if it didn't exist</param>
        /// <exception cref="SSHException">failed to parse</exception>
        public void Load(string passphrase, out KeyPair keyPair, out string comment)
        {
            if (keyFile == null)
                throw new SSHException("A key file is not loaded yet");

            String base64Text;
            using (StreamReader sreader = GetStreamReader()) {
                string line = sreader.ReadLine();
                if (line == null || line != PrivateKeyFileHeader.SSH2_SSHCOM_HEADER)
                    throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (missing header)");

                StringBuilder buf = new StringBuilder();
                comment = String.Empty;
                while (true) {
                    line = sreader.ReadLine();
                    if (line == null)
                        throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (unexpected eof)");
                    if (line == PrivateKeyFileHeader.SSH2_SSHCOM_FOOTER)
                        break;
                    if (line.IndexOf(':') >= 0) {
                        if (line.StartsWith("Comment: "))
                            comment = line.Substring("Comment: ".Length);
                    }
                    else if (line[line.Length - 1] == '\\')
                        buf.Append(line, 0, line.Length - 1);
                    else
                        buf.Append(line);
                }
                base64Text = buf.ToString();
            }

            byte[] keydata = Base64.Decode(Encoding.ASCII.GetBytes(base64Text));
            //Debug.WriteLine(DebugUtil.DumpByteArray(keydata));

            SSH2DataReader reader = new SSH2DataReader(keydata);
            int magic = reader.ReadInt32();
            if (magic != MAGIC)
                throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (magic code unmatched)");
            int privateKeyLen = reader.ReadInt32();
            string type = reader.ReadString();

            string ciphername = reader.ReadString();
            int bufLen = reader.ReadInt32();
            if (ciphername != "none") {
                CipherAlgorithm algo = CipherFactory.SSH2NameToAlgorithm(ciphername);
                byte[] key = SSH2UserAuthKey.PassphraseToKey(passphrase, CipherFactory.GetKeySize(algo));
                Cipher c = CipherFactory.CreateCipher(SSHProtocol.SSH2, algo, key);
                byte[] tmp = new Byte[keydata.Length - reader.Offset];
                c.Decrypt(keydata, reader.Offset, keydata.Length - reader.Offset, tmp, 0);
                reader = new SSH2DataReader(tmp);
            }

            int parmLen = reader.ReadInt32();
            if (parmLen < 0 || parmLen > reader.RemainingDataLength)
                throw new SSHException(Strings.GetString("WrongPassphrase"));

            if (type.IndexOf("if-modn") != -1) {
                //mindterm mistaken this order of BigIntegers
                BigInteger e = ReadBigIntWithBits(reader);
                BigInteger d = ReadBigIntWithBits(reader);
                BigInteger n = ReadBigIntWithBits(reader);
                BigInteger u = ReadBigIntWithBits(reader);
                BigInteger p = ReadBigIntWithBits(reader);
                BigInteger q = ReadBigIntWithBits(reader);
                keyPair = new RSAKeyPair(e, d, n, u, p, q);
            }
            else if (type.IndexOf("dl-modp") != -1) {
                if (reader.ReadInt32() != 0)
                    throw new SSHException(Strings.GetString("UnsupportedPrivateKeyFormat")
                            + " (" + Strings.GetString("Reason_UnsupportedDSAKeyFormat") + ")");
                BigInteger p = ReadBigIntWithBits(reader);
                BigInteger g = ReadBigIntWithBits(reader);
                BigInteger q = ReadBigIntWithBits(reader);
                BigInteger y = ReadBigIntWithBits(reader);
                BigInteger x = ReadBigIntWithBits(reader);
                keyPair = new DSAKeyPair(p, g, q, y, x);
            }
            else
                throw new SSHException(Strings.GetString("UnsupportedAuthenticationMethod"));
        }
        private void ProcessAgentForwardRequest(ISSHConnectionEventReceiver receiver, SSH2DataReader reader) {
            int remote_channel = reader.ReadInt32();
            int window_size = reader.ReadInt32(); //skip initial window size
            int servermaxpacketsize = reader.ReadInt32();
            TraceReceptionEvent("agent forward request", "");

            SSH2DataWriter wr = new SSH2DataWriter();
            IAgentForward af = _param.AgentForward;
            if(_agentForwardConfirmed && af!=null && af.CanAcceptForwarding()) {
                //send OPEN_CONFIRMATION
                AgentForwardingChannel ch = new AgentForwardingChannel(af);
                SSH2Channel channel = new SSH2Channel(this, ChannelType.AgentForward, this.ChannelCollection.RegisterChannelEventReceiver(null, ch).LocalID, remote_channel, servermaxpacketsize);
                ch.SetChannel(channel);
                wr.WritePacketType(PacketType.SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
                wr.Write(remote_channel);
                wr.Write(channel.LocalChannelID);
                wr.Write(_param.WindowSize); //initial window size
                wr.Write(_param.MaxPacketSize); //max packet size
                TraceTransmissionEvent("granados confirmed agent-forwarding request", "");
            }
            else {
                wr.WritePacketType(PacketType.SSH_MSG_CHANNEL_OPEN_FAILURE);
                wr.Write(remote_channel);
                wr.Write(0);
                wr.Write("reject");
                wr.Write(""); //lang tag
                TraceTransmissionEvent("granados rejected agent-forwarding request", "");
            }
            TransmitRawPayload(wr.ToByteArray());
        }