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; } } }
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"); }
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); }
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); }
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"); }
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; }
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()); }