// 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; } }
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 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()); }
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); }
/// <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); }
private void OpenShellOrSubsystem(ISSHChannelEventReceiver receiver, SSH2PacketType pt, SSH2DataReader reader, string scheme) { if (_negotiationStatus == NegotiationStatus.WaitingChannelConfirmation) { if (pt != SSH2PacketType.SSH_MSG_CHANNEL_OPEN_CONFIRMATION) { if (pt != SSH2PacketType.SSH_MSG_CHANNEL_OPEN_FAILURE) receiver.OnChannelError(new SSHException("opening channel failed; packet type=" + pt)); else { int errcode = reader.ReadInt32(); string msg = reader.ReadUTF8String(); receiver.OnChannelError(new SSHException(msg)); } // Close() shouldn't be called because remote channel number is not given yet. // We just remove an event receiver from the collection of channels. // FIXME: _negotiationStatus sould be set an error status ? _connection.ChannelCollection.UnregisterChannelEventReceiver(_localID); } else { _remoteID = reader.ReadInt32(); _allowedDataSize = reader.ReadUInt32(); _serverMaxPacketSize = reader.ReadInt32(); if (_type == ChannelType.Subsystem) { OpenScheme(scheme); _negotiationStatus = NegotiationStatus.WaitingSubsystemConfirmation; } else { //open pty SSHConnectionParameter param = _connection.Param; Transmit( 0, new SSH2Packet(SSH2PacketType.SSH_MSG_CHANNEL_REQUEST) .WriteInt32(_remoteID) .WriteString("pty-req") .WriteBool(true) .WriteString(param.TerminalName) .WriteInt32(param.TerminalWidth) .WriteInt32(param.TerminalHeight) .WriteInt32(param.TerminalPixelWidth) .WriteInt32(param.TerminalPixelHeight) .WriteAsString(new byte[0]) ); if (_connection.IsEventTracerAvailable) { _connection.TraceTransmissionEvent( SSH2PacketType.SSH_MSG_CHANNEL_REQUEST, "pty-req", "terminal={0} width={1} height={2}", param.TerminalName, param.TerminalWidth, param.TerminalHeight); } _negotiationStatus = NegotiationStatus.WaitingPtyReqConfirmation; } } } else if (_negotiationStatus == NegotiationStatus.WaitingPtyReqConfirmation) { if (pt != SSH2PacketType.SSH_MSG_CHANNEL_SUCCESS) { receiver.OnChannelError(new SSHException("opening pty failed")); Close(); } else { //agent request (optional) if (_connection.Param.AgentForward != null) { Transmit( 0, new SSH2Packet(SSH2PacketType.SSH_MSG_CHANNEL_REQUEST) .WriteInt32(_remoteID) .WriteString("*****@*****.**") .WriteBool(true) ); _connection.TraceTransmissionEvent(SSH2PacketType.SSH_MSG_CHANNEL_REQUEST, "auth-agent-req", ""); _negotiationStatus = NegotiationStatus.WaitingAuthAgentReqConfirmation; } else { OpenScheme(scheme); _negotiationStatus = NegotiationStatus.WaitingShellConfirmation; } } } else if (_negotiationStatus == NegotiationStatus.WaitingAuthAgentReqConfirmation) { if (pt != SSH2PacketType.SSH_MSG_CHANNEL_SUCCESS && pt != SSH2PacketType.SSH_MSG_CHANNEL_FAILURE) { receiver.OnChannelError(new SSHException("auth-agent-req error")); Close(); } else { //auth-agent-req is optional _connection.SetAgentForwardConfirmed(pt == SSH2PacketType.SSH_MSG_CHANNEL_SUCCESS); _connection.TraceReceptionEvent(pt, "auth-agent-req"); OpenScheme(scheme); _negotiationStatus = NegotiationStatus.WaitingShellConfirmation; } } else if (_negotiationStatus == NegotiationStatus.WaitingShellConfirmation) { if (pt != SSH2PacketType.SSH_MSG_CHANNEL_SUCCESS) { receiver.OnChannelError(new SSHException("Opening shell failed: packet type=" + pt.ToString())); Close(); } else { receiver.OnChannelReady(); _negotiationStatus = NegotiationStatus.Ready; //goal! } } else if (_negotiationStatus == NegotiationStatus.WaitingSubsystemConfirmation) { if (pt != SSH2PacketType.SSH_MSG_CHANNEL_SUCCESS) { receiver.OnChannelError(new SSHException("Opening subsystem failed: packet type=" + pt.ToString())); Close(); } else { receiver.OnChannelReady(); _negotiationStatus = NegotiationStatus.Ready; //goal! } } }
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); }
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"); }
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> /// 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; }
private bool ProcessPacket(DataFragment packet) { SSH2DataReader r = new SSH2DataReader(packet); SSH2PacketType pt = (SSH2PacketType) r.ReadByte(); if (pt == SSH2PacketType.SSH_MSG_DISCONNECT) { int errorcode = r.ReadInt32(); _eventReceiver.OnConnectionClosed(); return false; } else if (_waitingForPortForwardingResponse) { if (pt != SSH2PacketType.SSH_MSG_REQUEST_SUCCESS) _eventReceiver.OnUnknownMessage((byte)pt, packet.GetBytes()); _waitingForPortForwardingResponse = false; return true; } else if (pt == SSH2PacketType.SSH_MSG_CHANNEL_OPEN) { string method = 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.WriteByte((byte)SSH2PacketType.SSH_MSG_CHANNEL_OPEN_FAILURE); wr.WriteInt32(r.ReadInt32()); wr.WriteInt32(0); wr.WriteString("unknown method"); wr.WriteString(""); //lang tag TraceReceptionEvent("SSH_MSG_CHANNEL_OPEN rejected", "method={0}", method); } return true; } else if (pt >= SSH2PacketType.SSH_MSG_CHANNEL_OPEN_CONFIRMATION && pt <= SSH2PacketType.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, r); else Debug.WriteLine("unexpected channel pt=" + pt + " local_channel=" + local_channel.ToString()); return true; } else if (pt == SSH2PacketType.SSH_MSG_IGNORE) { _eventReceiver.OnIgnoreMessage(r.ReadByteString()); return true; } else if (_asyncKeyExchanger != null) { _asyncKeyExchanger.AsyncProcessPacket(packet); return true; } else if (pt == SSH2PacketType.SSH_MSG_KEXINIT) { //Debug.WriteLine("Host sent KEXINIT"); _asyncKeyExchanger = new KeyExchanger(this, _sessionID); _asyncKeyExchanger.AsyncProcessPacket(packet); return true; } else { _eventReceiver.OnUnknownMessage((byte)pt, packet.GetBytes()); return false; } }
private void ReceivePortForwardingResponse(ISSHChannelEventReceiver receiver, SSH2PacketType pt, SSH2DataReader reader) { if (_negotiationStatus == NegotiationStatus.WaitingChannelConfirmation) { if (pt != SSH2PacketType.SSH_MSG_CHANNEL_OPEN_CONFIRMATION) { if (pt != SSH2PacketType.SSH_MSG_CHANNEL_OPEN_FAILURE) receiver.OnChannelError(new SSHException("opening channel failed; packet type=" + pt)); else { int errcode = reader.ReadInt32(); string msg = reader.ReadUTF8String(); 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"); }
private void ProcessChannelLocalData(ISSHChannelEventReceiver receiver, SSH2PacketType pt, SSH2DataReader re) { switch (pt) { case SSH2PacketType.SSH_MSG_CHANNEL_DATA: { int len = re.ReadInt32(); DataFragment frag = re.GetRemainingDataView(len); receiver.OnData(frag.Data, frag.Offset, frag.Length); } break; case SSH2PacketType.SSH_MSG_CHANNEL_EXTENDED_DATA: { int t = re.ReadInt32(); byte[] data = re.ReadByteString(); receiver.OnExtendedData(t, data); } break; case SSH2PacketType.SSH_MSG_CHANNEL_REQUEST: { string request = 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 Transmit( 0, new SSH2Packet(SSH2PacketType.SSH_MSG_CHANNEL_FAILURE) .WriteInt32(_remoteID) ); } } break; case SSH2PacketType.SSH_MSG_CHANNEL_EOF: receiver.OnChannelEOF(); break; case SSH2PacketType.SSH_MSG_CHANNEL_CLOSE: _connection.ChannelCollection.UnregisterChannelEventReceiver(_localID); receiver.OnChannelClosed(); break; case SSH2PacketType.SSH_MSG_CHANNEL_FAILURE: { DataFragment frag = re.GetRemainingDataView(); receiver.OnMiscPacket((byte)pt, frag.Data, frag.Offset, frag.Length); } break; default: { DataFragment frag = re.GetRemainingDataView(); receiver.OnMiscPacket((byte)pt, frag.Data, frag.Offset, frag.Length); } Debug.WriteLine("Unknown Packet " + pt); break; } }
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"); }
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 ProcessKEXINIT(DataFragment packet) { SSH2DataReader re = null; do { _serverKEXINITPayload = packet.GetBytes(); re = new SSH2DataReader(_serverKEXINITPayload); byte[] head = re.Read(17); //Type and cookie SSH2PacketType pt = (SSH2PacketType)head[0]; if (pt == SSH2PacketType.SSH_MSG_KEXINIT) break; //successfully exit if (pt == SSH2PacketType.SSH_MSG_IGNORE || pt == SSH2PacketType.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); string kex = re.ReadString(); _cInfo.SupportedKEXAlgorithms = kex; _cInfo.KEXAlgorithm = DecideKexAlgorithm(kex); string host_key = re.ReadString(); _cInfo.SupportedHostKeyAlgorithms = host_key; _cInfo.HostKeyAlgorithm = DecideHostKeyAlgorithm(host_key); string enc_cs = re.ReadString(); _cInfo.SupportedEncryptionAlgorithmsClientToServer = enc_cs; _cInfo.OutgoingPacketCipher = DecideCipherAlgorithm(enc_cs); string enc_sc = re.ReadString(); _cInfo.SupportedEncryptionAlgorithmsServerToClient = enc_sc; _cInfo.IncomingPacketCipher = DecideCipherAlgorithm(enc_sc); string mac_cs = re.ReadString(); CheckAlgorithmSupport("mac", mac_cs, "hmac-sha1"); string mac_sc = re.ReadString(); CheckAlgorithmSupport("mac", mac_sc, "hmac-sha1"); string comp_cs = re.ReadString(); CheckAlgorithmSupport("compression", comp_cs, "none"); string comp_sc = re.ReadString(); CheckAlgorithmSupport("compression", comp_sc, "none"); string lang_cs = re.ReadString(); string lang_sc = re.ReadString(); bool flag = re.ReadBool(); int reserved = re.ReadInt32(); Debug.Assert(re.RemainingDataLength == 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(SSH2PacketType.SSH_MSG_KEXINIT, bld.ToString()); } if (flag) throw new SSHException("Algorithm negotiation failed"); }