public void Append(DataFragment data) { Append(data.Data, data.Offset, data.Length); }
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, GetDiffieHellmanPrime(_cInfo._kexAlgorithm)); wr = new SSH2DataWriter(); wr.WriteString(_cInfo._clientVersionString); wr.WriteString(_cInfo._serverVersionString); wr.WriteAsString(_clientKEXINITPayload); wr.WriteAsString(_serverKEXINITPayload); wr.WriteAsString(key_and_cert); wr.WriteBigInteger(_e); wr.WriteBigInteger(f); wr.WriteBigInteger(_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; }
protected override void OnDataInLock(DataFragment data) { try { //the specification claims the version string ends with CRLF, however some servers send LF only if (data.Length <= 2 || data.Data[data.Offset + data.Length - 1] != 0x0A) throw new SSHException(Strings.GetString("NotSSHServer")); //Debug.WriteLine(String.Format("receiveServerVersion len={0}",len)); //this Trim() is necessary for computing hash in the host key authentication stage string sv = Encoding.ASCII.GetString(data.Data, data.Offset, data.Length).Trim(); //check compatibility int a = sv.IndexOf('-'); if (a == -1) ThrowUnexpectedFormatException(sv); int b = sv.IndexOf('-', a + 1); if (b == -1) ThrowUnexpectedFormatException(sv); int comma = sv.IndexOf('.', a, b - a); if (comma == -1) ThrowUnexpectedFormatException(sv); int major = Int32.Parse(sv.Substring(a + 1, comma - a - 1)); int minor = Int32.Parse(sv.Substring(comma + 1, b - comma - 1)); if (_param.Protocol == SSHProtocol.SSH1) { if (major != 1) ThrowVersionMismatchException(sv, SSHProtocol.SSH1); } else { if (major >= 3 || major <= 0 || (major == 1 && minor != 99)) ThrowVersionMismatchException(sv, SSHProtocol.SSH2); } _serverVersion = sv; this.SetSuccessfulResult(data); } catch (Exception ex) { this.SetFailureResult(ex); } }
internal PlainSocket(Socket s, IDataHandler h) : base(h) { _socket = s; Debug.Assert(_socket.Connected); _socketStatus = SocketStatus.Ready; _data = new DataFragment(0x1000); _callback = new AsyncCallback(RepeatCallback); }
public void OnData(DataFragment data) { lock (_socket) { OnDataInLock(data); } }
//Set the response protected void SetSuccessfulResult(DataFragment data) { _results.Enqueue(data.Isolate()); _event.Set(); }
public SSH2MsgNewKeys(DataFragment data, Handler onDequeued) : base(data.Data, data.Offset, data.Length) { _onDequeued = onDequeued; }
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.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 >= 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 if (pt == PacketType.SSH_MSG_GLOBAL_REQUEST) { SSH2DataWriter wr = new SSH2DataWriter(); wr.WritePacketType(PacketType.SSH_MSG_REQUEST_SUCCESS); wr.WriteBool(true); TransmitRawPayload(wr.ToByteArray()); return true; } else { _eventReceiver.OnUnknownMessage((byte)pt, r.Image); return false; } }
private void Init(DataFragment data) { _data = data.Data; _offset = data.Offset; _limit = _offset + data.Length; }
public void OnData(DataFragment data) { _connection.AsyncReceivePacket(data); }
public void Recycle(DataFragment data) { Init(data); }
public SSHDataReader(DataFragment data) { Init(data); }
public virtual DataFragment Isolate() { int newcapacity = RoundUp(_length); byte[] t = new byte[newcapacity]; Buffer.BlockCopy(_data, _offset, t, 0, _length); DataFragment f = new DataFragment(t, 0, _length); return f; }
private void ProcessNEWKEYS(DataFragment packet) { //confirms new key if (packet.Length != 1 || packet.ByteAt(0) != (byte)PacketType.SSH_MSG_NEWKEYS) { Monitor.Exit(_connection); throw new SSHException("SSH_MSG_NEWKEYS failed"); } _connection.RefreshKeys(_sessionID, _tc, _rc, _tm, _rm); Monitor.Exit(_connection); TraceReceptionNegotiation(PacketType.SSH_MSG_NEWKEYS, "the keys are refreshed"); _status = Status.FINISHED; }
public SSH2PacketBuilder(IDataHandler handler) : base(handler) { _buffer = new DataFragment(0x1000); _packet = new DataFragment(_buffer.Capacity); _sequence = 0; _cipher = null; _mac = null; _head = null; }
internal void AsyncReceivePacket(DataFragment packet) { try { ProcessPacket(packet); } catch (Exception ex) { _eventReceiver.OnError(ex); } }
public override void OnData(DataFragment data) { lock (_cipherSync) { try { if (!_keyError) { // key error detection if (_pending && DateTime.UtcNow > _keyErrorDetectionTimeout) { _keyError = true; // disable accepting data any more return; } _buffer.Append(data); if (!_pending) { ProcessBuffer(); } } } catch (Exception ex) { OnError(ex); } } }
public abstract void OnData(DataFragment data);
private bool IsMsgNewKeys(DataFragment packet) { return packet.Length >= 1 && packet.ByteAt(0) == (byte)PacketType.SSH_MSG_NEWKEYS; }
protected abstract void OnDataInLock(DataFragment data);
public SSH2TransmissionPacket() { _writer = new SSH2DataWriter(); _dataFragment = new DataFragment(null, 0, 0); _isOpen = false; }
//Send request and wait response public DataFragment SendAndWaitResponse(DataFragment data) { //this lock is important lock (_socket) { Debug.Assert(_results.Count == 0); _event.Reset(); if (data.Length > 0) _socket.Write(data.Data, data.Offset, data.Length); } _event.WaitOne(); Debug.Assert(_results.Count > 0); return Dequeue(); }
public void AsyncProcessPacket(DataFragment packet) { Mode m = Mode.Asynchronized; switch (_status) { case Status.INITIAL: _startedByHost = true; ProcessKEXINIT(packet); SendKEXINIT(m); SendKEXDHINIT(m); break; case Status.WAIT_KEXINIT: ProcessKEXINIT(packet); SendKEXDHINIT(m); break; case Status.WAIT_KEXDH_REPLY: ProcessKEXDHREPLY(packet); SendNEWKEYS(m); break; case Status.WAIT_NEWKEYS: ProcessNEWKEYS(packet); Debug.Assert(_status == Status.FINISHED); break; } }
protected override void OnDataInLock(DataFragment data) { this.SetSuccessfulResult(data); }
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; _cInfo._kexAlgorithm = DecideKexAlgorithm(kex); 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 (_fragment == null) _fragment = new DataFragment(data, offset, length); else _fragment.Init(data, offset, length); _handler.OnData(_fragment); }
public void Write(DataFragment data) { Write(data.Data, data.Offset, data.Length); }