protected virtual void SendCertificateMessage(Certificate certificate) { if (certificate == null) { certificate = Certificate.EmptyChain; } if (certificate.IsEmpty) { TlsContext context = Context; if (!context.IsServer) { ProtocolVersion serverVersion = Context.ServerVersion; if (serverVersion.IsSsl) { string errorMessage = serverVersion.ToString() + " client didn't provide credentials"; RaiseWarning(AlertDescription.no_certificate, errorMessage); return; } } } HandshakeMessage message = new HandshakeMessage(HandshakeType.certificate); certificate.Encode(message); message.WriteToRecordStream(this); }
public void Add (HandshakeMessage message, IBufferOffsetSize buffer) { if (message is TlsHelloRequest) throw new InvalidOperationException (); for (int i = 0; i < hashes.Length; i++) hashes [i].TransformBlock (buffer.Buffer, buffer.Offset, buffer.Size); }
public void Write(HandshakeMessage message) { var body = message.GetBytes(); var record = new Record(RecordType.Handshake, state.Version, body); state.UpdateHandshakeVerify(body, 0, body.Length); state.RecordWriter.WriteRecord(record); }
SecurityStatus EncodeHandshakeRecord (HandshakeMessage message, TlsMultiBuffer output) { var bytes = EncodeHandshakeRecord (message); output.Add (bytes); return message.Type == HandshakeType.Finished ? SecurityStatus.OK : SecurityStatus.ContinueNeeded; }
protected override void Handshake(HandshakeMessage message) { _context = _principal.Handshake(this, message); if (null != _context) { Trace.TraceInformation("Client Connection Handshake succeeded"); } else { Trace.TraceError("Client Connection Handshake failed - Close Connection"); TryClose(); } }
protected virtual void SendServerHelloMessage() { HandshakeMessage message = new HandshakeMessage(HandshakeType.server_hello); { ProtocolVersion server_version = mTlsServer.GetServerVersion(); if (!server_version.IsEqualOrEarlierVersionOf(Context.ClientVersion)) throw new TlsFatalAlert(AlertDescription.internal_error); mRecordStream.ReadVersion = server_version; mRecordStream.SetWriteVersion(server_version); mRecordStream.SetRestrictReadVersion(true); ContextAdmin.SetServerVersion(server_version); TlsUtilities.WriteVersion(server_version, message); } message.Write(this.mSecurityParameters.serverRandom); /* * The server may return an empty session_id to indicate that the session will not be cached * and therefore cannot be resumed. */ TlsUtilities.WriteOpaque8(TlsUtilities.EmptyBytes, message); int selectedCipherSuite = mTlsServer.GetSelectedCipherSuite(); if (!Arrays.Contains(mOfferedCipherSuites, selectedCipherSuite) || selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL || CipherSuite.IsScsv(selectedCipherSuite) || !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, Context.ServerVersion)) { throw new TlsFatalAlert(AlertDescription.internal_error); } mSecurityParameters.cipherSuite = selectedCipherSuite; byte selectedCompressionMethod = mTlsServer.GetSelectedCompressionMethod(); if (!Arrays.Contains(mOfferedCompressionMethods, selectedCompressionMethod)) { throw new TlsFatalAlert(AlertDescription.internal_error); } mSecurityParameters.compressionAlgorithm = selectedCompressionMethod; TlsUtilities.WriteUint16(selectedCipherSuite, message); TlsUtilities.WriteUint8(selectedCompressionMethod, message); this.mServerExtensions = mTlsServer.GetServerExtensions(); /* * RFC 5746 3.6. Server Behavior: Initial Handshake */ if (this.mSecureRenegotiation) { byte[] renegExtData = TlsUtilities.GetExtensionData(this.mServerExtensions, ExtensionType.renegotiation_info); bool noRenegExt = (null == renegExtData); if (noRenegExt) { /* * Note that Sending a "renegotiation_info" extension in response to a ClientHello * containing only the SCSV is an explicit exception to the prohibition in RFC 5246, * Section 7.4.1.4, on the server Sending unsolicited extensions and is only allowed * because the client is signaling its willingness to receive the extension via the * TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV. */ /* * If the secure_renegotiation flag is set to TRUE, the server MUST include an empty * "renegotiation_info" extension in the ServerHello message. */ this.mServerExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(mServerExtensions); this.mServerExtensions[ExtensionType.renegotiation_info] = CreateRenegotiationInfo(TlsUtilities.EmptyBytes); } } if (mSecurityParameters.extendedMasterSecret) { this.mServerExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(mServerExtensions); TlsExtensionsUtilities.AddExtendedMasterSecretExtension(mServerExtensions); } /* * TODO RFC 3546 2.3 If [...] the older session is resumed, then the server MUST ignore * extensions appearing in the client hello, and Send a server hello containing no * extensions. */ if (this.mServerExtensions != null) { this.mSecurityParameters.encryptThenMac = TlsExtensionsUtilities.HasEncryptThenMacExtension(mServerExtensions); this.mSecurityParameters.maxFragmentLength = ProcessMaxFragmentLengthExtension(mClientExtensions, mServerExtensions, AlertDescription.internal_error); this.mSecurityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(mServerExtensions); /* * TODO It's surprising that there's no provision to allow a 'fresh' CertificateStatus to be sent in * a session resumption handshake. */ this.mAllowCertificateStatus = !mResumedSession && TlsUtilities.HasExpectedEmptyExtensionData(mServerExtensions, ExtensionType.status_request, AlertDescription.internal_error); this.mExpectSessionTicket = !mResumedSession && TlsUtilities.HasExpectedEmptyExtensionData(mServerExtensions, ExtensionType.session_ticket, AlertDescription.internal_error); WriteExtensions(message, this.mServerExtensions); } mSecurityParameters.prfAlgorithm = GetPrfAlgorithm(Context, mSecurityParameters.CipherSuite); /* * RFC 5264 7.4.9. Any cipher suite which does not explicitly specify verify_data_length has * a verify_data_length equal to 12. This includes all existing cipher suites. */ mSecurityParameters.verifyDataLength = 12; ApplyMaxFragmentLengthExtension(); message.WriteToRecordStream(this); }
protected override void ProcessFinished(HandshakeMessage finished) { if (_state != HandshakeState.ReceivedChangeCipherSpec) { throw new AlertException(AlertDescription.UnexpectedMessage, "Finished message received at the wrong time"); } byte[] allMessages = _handshakeStream.ToArray(); byte[] handshakeMessages = new byte[allMessages.Length - finished.Encode().Length]; Buffer.BlockCopy(allMessages, 0, handshakeMessages, 0, handshakeMessages.Length); PseudoRandomFunction prf = _cipherSuite.PseudoRandomFunction; HashAlgorithm verifyHash = prf.CreateVerifyHashAlgorithm(_connectionState.MasterSecret); verifyHash.TransformBlock(handshakeMessages, 0, handshakeMessages.Length, handshakeMessages, 0); byte[] ourVerifyData; if (_version == ProtocolVersion.SSL3_0) { byte[] senderBytes = Encoding.ASCII.GetBytes("SRVR"); verifyHash.TransformFinalBlock(senderBytes, 0, senderBytes.Length); ourVerifyData = verifyHash.Hash; } else { verifyHash.TransformFinalBlock(new byte[0], 0, 0); byte[] hash = verifyHash.Hash; int length = _cipherSuite.PseudoRandomFunction.VerifyDataLength; ourVerifyData = _cipherSuite.PseudoRandomFunction.GetBytes(_connectionState.MasterSecret, "server finished", hash, length); } // Verify that the received data matches ours bool verifyOk = false; if (ourVerifyData.Length == finished.Data.Length) { verifyOk = true; for (int i = 0; i < ourVerifyData.Length; i++) { if (ourVerifyData[i] != finished.Data[i]) { verifyOk = false; } } } if (!verifyOk) { throw new AlertException(AlertDescription.DecryptError, "Finished packet contents incorrect"); } _connectionState.ServerVerifyData = ourVerifyData; // Cleanup the handshake stream used for verify hashes _handshakeStream = new MemoryStream(); // Everything done and handshake finished _state = HandshakeState.Finished; }
protected virtual void SendClientKeyExchangeMessage() { HandshakeMessage message = new HandshakeMessage(HandshakeType.client_key_exchange); this.mKeyExchange.GenerateClientKeyExchange(message); message.WriteToRecordStream(this); }
protected virtual void SendCertificateVerifyMessage(DigitallySigned certificateVerify) { HandshakeMessage message = new HandshakeMessage(HandshakeType.certificate_verify); certificateVerify.Encode(message); message.WriteToRecordStream(this); }
private void EndCheckEncryption(IAsyncResult result) { var id = (PeerId) result.AsyncState; try { byte[] initialData; EncryptorFactory.EndCheckEncryption(result, out initialData); if (initialData != null && initialData.Length == HandshakeMessage.HandshakeLength) { var message = new HandshakeMessage(); message.Decode(initialData, 0, initialData.Length); HandleHandshake(id, message); } else if (initialData.Length > 0) { throw new Exception("Argh. I can't handle this scenario. It also shouldn't happen. Ever."); } else { PeerIO.EnqueueReceiveHandshake(id.Connection, id.Decryptor, _handshakeReceivedCallback, id); } } catch { id.Connection.Dispose(); } }
public override HandshakeMessage GetMessage(HandshakeType type) { HandshakeMessage msg = this.createClientHandshakeMessage(type); return(msg); }
private void handleHandshake(PeerId id, HandshakeMessage message) { TorrentManager man = null; try { if (message.ProtocolString != VersionInfo.ProtocolStringV100) { throw new ProtocolException("Invalid protocol string in handshake"); } } catch (Exception ex) { Logger.Log(id.Connection, ex.Message); id.Connection.Dispose(); return; } ClientEngine.MainLoop.QueueWait((MainLoopTask) delegate { for (int i = 0; i < engine.Torrents.Count; i++) { if (message.infoHash == engine.Torrents[i].InfoHash) { man = engine.Torrents[i]; } } }); //FIXME: #warning FIXME: Don't stop the message loop until Dispose() and track all incoming connections if (man == null) // We're not hosting that torrent { Logger.Log(id.Connection, "ListenManager - Handshake requested nonexistant torrent"); id.Connection.Dispose(); return; } if (man.State == TorrentState.Stopped) { Logger.Log(id.Connection, "ListenManager - Handshake requested for torrent which is not running"); id.Connection.Dispose(); return; } if (!man.Mode.CanAcceptConnections) { Logger.Log(id.Connection, "ListenManager - Current mode does not support connections"); id.Connection.Dispose(); return; } id.Peer.PeerId = message.PeerId; id.TorrentManager = man; // If the handshake was parsed properly without encryption, then it definitely was not encrypted. If this is not allowed, abort if ((id.Encryptor is PlainTextEncryption && !Toolbox.HasEncryption(engine.Settings.AllowedEncryption, EncryptionTypes.PlainText)) && ClientEngine.SupportsEncryption) { Logger.Log(id.Connection, "ListenManager - Encryption is required but was not active"); id.Connection.Dispose(); return; } message.Handle(id); Logger.Log(id.Connection, "ListenManager - Handshake successful handled"); id.ClientApp = new Software(message.PeerId); message = new HandshakeMessage(id.TorrentManager.InfoHash, engine.PeerId, VersionInfo.ProtocolStringV100); var callback = engine.ConnectionManager.incomingConnectionAcceptedCallback; PeerIO.EnqueueSendMessage(id.Connection, id.Encryptor, message, id.TorrentManager.UploadLimiter, id.Monitor, id.TorrentManager.Monitor, callback, id); }
private void Handshake(EncryptionTypes encryptionA, EncryptionTypes encryptionB, bool addInitial) { bool doneA = false; bool doneB = false; HandshakeMessage m = new HandshakeMessage(rig.Torrent.InfoHash, "12345123451234512345", VersionInfo.ProtocolStringV100); byte[] handshake = m.Encode(); PeerAEncryption a = new PeerAEncryption(rig.Torrent.InfoHash, encryptionA); if (addInitial) { a.AddPayload(handshake); } PeerBEncryption b = new PeerBEncryption(new InfoHash[] { rig.Torrent.InfoHash }, encryptionB); IAsyncResult resultA = a.BeginHandshake(conn.Outgoing, null, null); IAsyncResult resultB = b.BeginHandshake(conn.Incoming, null, null); WaitHandle[] handles = new WaitHandle[] { resultA.AsyncWaitHandle, resultB.AsyncWaitHandle }; int count = 1000; while (!WaitHandle.WaitAll(handles, 5, true)) { if (!doneA && (doneA = resultA.IsCompleted)) { a.EndHandshake(resultA); } if (!doneB && (doneB = resultB.IsCompleted)) { b.EndHandshake(resultB); } if (count-- == 0) { Assert.Fail("Could not handshake"); } } if (!doneA) { a.EndHandshake(resultA); } if (!doneB) { b.EndHandshake(resultB); } HandshakeMessage d = new HandshakeMessage(); if (!addInitial) { a.Encrypt(handshake, 0, handshake.Length); b.Decrypt(handshake, 0, handshake.Length); d.Decode(handshake, 0, handshake.Length); } else { d.Decode(b.InitialData, 0, b.InitialData.Length); } Assert.AreEqual(m, d); if (encryptionA == EncryptionTypes.RC4Full || encryptionB == EncryptionTypes.RC4Full) { Assert.IsTrue(a.Encryptor is RC4); Assert.IsTrue(b.Encryptor is RC4); } else if (encryptionA == EncryptionTypes.RC4Header || encryptionB == EncryptionTypes.RC4Header) { Assert.IsTrue(a.Encryptor is RC4Header); Assert.IsTrue(b.Encryptor is RC4Header); } else if (encryptionA == EncryptionTypes.PlainText || encryptionB == EncryptionTypes.PlainText) { Assert.IsTrue(a.Encryptor is PlainTextEncryption); Assert.IsTrue(b.Encryptor is PlainTextEncryption); } }
protected virtual void SendServerHelloMessage() { HandshakeMessage message = new HandshakeMessage(HandshakeType.server_hello); { ProtocolVersion server_version = mTlsServer.GetServerVersion(); if (!server_version.IsEqualOrEarlierVersionOf(Context.ClientVersion)) { throw new TlsFatalAlert(AlertDescription.internal_error); } mRecordStream.ReadVersion = server_version; mRecordStream.SetWriteVersion(server_version); mRecordStream.SetRestrictReadVersion(true); ContextAdmin.SetServerVersion(server_version); TlsUtilities.WriteVersion(server_version, message); } message.Write(this.mSecurityParameters.serverRandom); /* * The server may return an empty session_id to indicate that the session will not be cached * and therefore cannot be resumed. */ TlsUtilities.WriteOpaque8(TlsUtilities.EmptyBytes, message); int selectedCipherSuite = mTlsServer.GetSelectedCipherSuite(); if (!Arrays.Contains(mOfferedCipherSuites, selectedCipherSuite) || selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL || CipherSuite.IsScsv(selectedCipherSuite) || !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, Context.ServerVersion)) { throw new TlsFatalAlert(AlertDescription.internal_error); } mSecurityParameters.cipherSuite = selectedCipherSuite; byte selectedCompressionMethod = mTlsServer.GetSelectedCompressionMethod(); if (!Arrays.Contains(mOfferedCompressionMethods, selectedCompressionMethod)) { throw new TlsFatalAlert(AlertDescription.internal_error); } mSecurityParameters.compressionAlgorithm = selectedCompressionMethod; TlsUtilities.WriteUint16(selectedCipherSuite, message); TlsUtilities.WriteUint8(selectedCompressionMethod, message); this.mServerExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(mTlsServer.GetServerExtensions()); /* * RFC 5746 3.6. Server Behavior: Initial Handshake */ if (this.mSecureRenegotiation) { byte[] renegExtData = TlsUtilities.GetExtensionData(this.mServerExtensions, ExtensionType.renegotiation_info); bool noRenegExt = (null == renegExtData); if (noRenegExt) { /* * Note that Sending a "renegotiation_info" extension in response to a ClientHello * containing only the SCSV is an explicit exception to the prohibition in RFC 5246, * Section 7.4.1.4, on the server Sending unsolicited extensions and is only allowed * because the client is signaling its willingness to receive the extension via the * TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV. */ /* * If the secure_renegotiation flag is set to TRUE, the server MUST include an empty * "renegotiation_info" extension in the ServerHello message. */ this.mServerExtensions[ExtensionType.renegotiation_info] = CreateRenegotiationInfo(TlsUtilities.EmptyBytes); } } if (TlsUtilities.IsSsl(mTlsServerContext)) { mSecurityParameters.extendedMasterSecret = false; } else if (mSecurityParameters.IsExtendedMasterSecret) { TlsExtensionsUtilities.AddExtendedMasterSecretExtension(mServerExtensions); } /* * TODO RFC 3546 2.3 If [...] the older session is resumed, then the server MUST ignore * extensions appearing in the client hello, and Send a server hello containing no * extensions. */ if (this.mServerExtensions.Count > 0) { this.mSecurityParameters.encryptThenMac = TlsExtensionsUtilities.HasEncryptThenMacExtension(mServerExtensions); this.mSecurityParameters.maxFragmentLength = ProcessMaxFragmentLengthExtension(mClientExtensions, mServerExtensions, AlertDescription.internal_error); this.mSecurityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(mServerExtensions); /* * TODO It's surprising that there's no provision to allow a 'fresh' CertificateStatus to be sent in * a session resumption handshake. */ this.mAllowCertificateStatus = !mResumedSession && TlsUtilities.HasExpectedEmptyExtensionData(mServerExtensions, ExtensionType.status_request, AlertDescription.internal_error); this.mExpectSessionTicket = !mResumedSession && TlsUtilities.HasExpectedEmptyExtensionData(mServerExtensions, ExtensionType.session_ticket, AlertDescription.internal_error); WriteExtensions(message, this.mServerExtensions); } mSecurityParameters.prfAlgorithm = GetPrfAlgorithm(Context, mSecurityParameters.CipherSuite); /* * RFC 5246 7.4.9. Any cipher suite which does not explicitly specify verify_data_length has * a verify_data_length equal to 12. This includes all existing cipher suites. */ mSecurityParameters.verifyDataLength = 12; ApplyMaxFragmentLengthExtension(); message.WriteToRecordStream(this); }
async Task Handshake(IList <EncryptionType> outgoingEncryption, IList <EncryptionType> incomingEncryption, bool appendInitialPayload) { var handshakeIn = new HandshakeMessage(InfoHash, IncomingId, VersionInfo.ProtocolStringV100); var handshakeOut = new HandshakeMessage(InfoHash, OutgoingId, VersionInfo.ProtocolStringV100); var incomingTask = EncryptorFactory.CheckIncomingConnectionAsync(Incoming, incomingEncryption, SKeys); var outgoingTask = EncryptorFactory.CheckOutgoingConnectionAsync(Outgoing, outgoingEncryption, InfoHash, appendInitialPayload ? handshakeOut : null); // If the handshake was not part of the initial payload, send it now. var outgoingCrypto = await outgoingTask; if (!appendInitialPayload) { await PeerIO.SendMessageAsync(Outgoing, outgoingCrypto.Encryptor, handshakeOut, null, null, null); } // Receive the handshake and make sure it decrypted correctly. var incomingCrypto = await incomingTask; Assert.AreEqual(OutgoingId, incomingCrypto.Handshake.PeerId, "#1a"); // Send the other handshake. await PeerIO.SendMessageAsync(Incoming, incomingCrypto.Encryptor, handshakeIn, null, null, null); // Receive the other handshake and make sure it decrypted ok on the other side. handshakeIn = await PeerIO.ReceiveHandshakeAsync(Outgoing, outgoingCrypto.Decryptor); Assert.AreEqual(IncomingId, handshakeIn.PeerId, "#1b"); if (outgoingEncryption[0] == EncryptionType.PlainText) { // If the outgoing encryption is plain text, then the whole thing is plain text Assert.IsInstanceOf <PlainTextEncryption> (incomingCrypto.Decryptor, "#2a"); Assert.IsInstanceOf <PlainTextEncryption> (outgoingCrypto.Decryptor, "#2b"); } else { EncryptionType expected; if (outgoingEncryption.Contains(EncryptionType.RC4Full) && outgoingEncryption.Contains(EncryptionType.RC4Header)) { // If the outgoing encryption supports both RC4Full and RC4Header, the final type is determined by // the priority associated with the 'Incoming' connection as it will decide between Header or Full if // the Outgoing connection asks for both. expected = EncryptionTypes.PreferredRC4(incomingEncryption).Value; } else { // Otherwise the outgoing encryption will specify a single RC4 type, so the incoming connection // will either accept it or close the connection. expected = EncryptionTypes.PreferredRC4(outgoingEncryption).Value; } if (expected == EncryptionType.RC4Full) { Assert.IsInstanceOf <RC4> (incomingCrypto.Decryptor, "#3a"); Assert.IsInstanceOf <RC4> (outgoingCrypto.Decryptor, "#3b"); } else if (expected == EncryptionType.RC4Header) { Assert.IsInstanceOf <RC4Header> (incomingCrypto.Decryptor, "#4a"); Assert.IsInstanceOf <RC4Header> (outgoingCrypto.Decryptor, "#4b"); } else { throw new NotSupportedException(); } } }
internal async void ProcessNewOutgoingConnection(TorrentManager manager, PeerId id) { // If we have too many open connections, close the connection if (OpenConnections > MaxOpenConnections) { CleanupSocket(manager, id); return; } id.ProcessingQueue = true; manager.Peers.ActivePeers.Add(id.Peer); manager.Peers.HandshakingPeers.Add(id); try { // Create a handshake message to send to the peer var handshake = new HandshakeMessage(manager.InfoHash, LocalPeerId, VersionInfo.ProtocolStringV100); var result = await EncryptorFactory.CheckOutgoingConnectionAsync(id.Connection, id.Peer.AllowedEncryption, Settings, manager.InfoHash, handshake); id.Decryptor = result.Decryptor; id.Encryptor = result.Encryptor; } catch { // If an exception is thrown it's because we tried to establish an encrypted connection and something went wrong id.Peer.AllowedEncryption &= ~(EncryptionTypes.RC4Full | EncryptionTypes.RC4Header); manager.RaiseConnectionAttemptFailed(new ConnectionAttemptFailedEventArgs(id.Peer, ConnectionFailureReason.EncryptionNegiotiationFailed, manager)); CleanupSocket(manager, id); // CleanupSocket will contain the peer only if AllowedEncryption is not set to None. If // the peer was re-added, then we should try to reconnect to it immediately to try an // unencrypted connection. if (manager.Peers.AvailablePeers.Remove(id.Peer)) { ConnectToPeer(manager, id.Peer); } return; } try { // Receive their handshake var handshake = await PeerIO.ReceiveHandshakeAsync(id.Connection, id.Decryptor); handshake.Handle(manager, id); } catch { // If we choose plaintext and it resulted in the connection being closed, remove it from the list. id.Peer.AllowedEncryption &= ~id.EncryptionType; manager.RaiseConnectionAttemptFailed(new ConnectionAttemptFailedEventArgs(id.Peer, ConnectionFailureReason.HandshakeFailed, manager)); CleanupSocket(manager, id); // CleanupSocket will contain the peer only if AllowedEncryption is not set to None. If // the peer was re-added, then we should try to reconnect to it immediately to try an // encrypted connection, assuming the previous connection was unencrypted and it failed. if (manager.Peers.AvailablePeers.Remove(id.Peer)) { ConnectToPeer(manager, id.Peer); } return; } try { manager.Peers.HandshakingPeers.Remove(id); manager.HandlePeerConnected(id); // If there are any pending messages, send them otherwise set the queue // processing as finished. if (id.QueueLength > 0) { ProcessQueue(manager, id); } else { id.ProcessingQueue = false; } ReceiveMessagesAsync(id.Connection, id.Decryptor, manager.DownloadLimiters, id.Monitor, manager, id); id.WhenConnected.Restart(); id.LastBlockReceived.Restart(); } catch { manager.RaiseConnectionAttemptFailed(new ConnectionAttemptFailedEventArgs(id.Peer, ConnectionFailureReason.Unknown, manager)); CleanupSocket(manager, id); return; } }
protected virtual void SendFinishedMessage() { byte[] verify_data = CreateVerifyData(Context.IsServer); HandshakeMessage message = new HandshakeMessage(HandshakeType.finished, verify_data.Length); message.Write(verify_data, 0, verify_data.Length); message.WriteToRecordStream(this); }
protected virtual HandshakeMessage CreateMessage(HandshakeType type, TlsBuffer incoming) { return(HandshakeMessage.ReadMessage(Context, type, incoming)); }
internal async void ProcessNewOutgoingConnection(TorrentManager manager, PeerId id) { // If we have too many open connections, close the connection if (OpenConnections > MaxOpenConnections) { CleanupSocket(manager, id); return; } manager.Peers.ActivePeers.Add(id.Peer); manager.Peers.ConnectedPeers.Add(id); Interlocked.Increment(ref openConnections); try { // Create a handshake message to send to the peer var handshake = new HandshakeMessage(manager.InfoHash, LocalPeerId, VersionInfo.ProtocolStringV100); var preferredEncryption = EncryptionTypes.GetPreferredEncryption(id.Peer.AllowedEncryption, Settings.AllowedEncryption); EncryptorFactory.EncryptorResult result = await EncryptorFactory.CheckOutgoingConnectionAsync(id.Connection, preferredEncryption, manager.InfoHash, handshake); id.Decryptor = result.Decryptor; id.Encryptor = result.Encryptor; } catch { // If an exception is thrown it's because we tried to establish an encrypted connection and something went wrong if (id.Peer.AllowedEncryption.Contains(EncryptionType.PlainText)) { id.Peer.AllowedEncryption = EncryptionTypes.PlainText; } else { id.Peer.AllowedEncryption = EncryptionTypes.None; } manager.RaiseConnectionAttemptFailed(new ConnectionAttemptFailedEventArgs(id.Peer, ConnectionFailureReason.EncryptionNegiotiationFailed, manager)); CleanupSocket(manager, id); // CleanupSocket will contain the peer only if AllowedEncryption is not set to None. If // the peer was re-added, then we should try to reconnect to it immediately to try an // unencrypted connection. if (manager.Peers.AvailablePeers.Remove(id.Peer)) { ConnectToPeer(manager, id.Peer); } return; } try { // Receive their handshake HandshakeMessage handshake = await PeerIO.ReceiveHandshakeAsync(id.Connection, id.Decryptor); manager.Mode.HandleMessage(id, handshake); } catch { // If we choose plaintext and it resulted in the connection being closed, remove it from the list. id.Peer.AllowedEncryption = EncryptionTypes.Remove(id.Peer.AllowedEncryption, id.EncryptionType); manager.RaiseConnectionAttemptFailed(new ConnectionAttemptFailedEventArgs(id.Peer, ConnectionFailureReason.HandshakeFailed, manager)); CleanupSocket(manager, id); // CleanupSocket will contain the peer only if AllowedEncryption is not set to None. If // the peer was re-added, then we should try to reconnect to it immediately to try an // encrypted connection, assuming the previous connection was unencrypted and it failed. if (manager.Peers.AvailablePeers.Remove(id.Peer)) { ConnectToPeer(manager, id.Peer); } return; } try { if (id.BitField.Length != manager.Bitfield.Length) { throw new TorrentException($"The peer's bitfield was of length {id.BitField.Length} but the TorrentManager's bitfield was of length {manager.Bitfield.Length}."); } manager.HandlePeerConnected(id); id.MessageQueue.SetReady(); TryProcessQueue(manager, id); ReceiveMessagesAsync(id.Connection, id.Decryptor, manager.DownloadLimiters, id.Monitor, manager, id); id.WhenConnected.Restart(); id.LastBlockReceived.Restart(); } catch { manager.RaiseConnectionAttemptFailed(new ConnectionAttemptFailedEventArgs(id.Peer, ConnectionFailureReason.Unknown, manager)); CleanupSocket(manager, id); return; } }
private void HandleHandshake(PeerId id, HandshakeMessage message) { TorrentManager man = null; try { if (message.ProtocolString != VersionInfo.ProtocolStringV100) throw new ProtocolException("Invalid protocol string in handshake"); } catch (Exception ex) { Logger.Log(id.Connection, ex.Message); id.Connection.Dispose(); return; } ClientEngine.MainLoop.QueueWait(() => { foreach (var torrentManager in _engine.Torrents.Where(tm => message.InfoHash == tm.InfoHash)) man = torrentManager; }); //FIXME: #warning FIXME: Don't stop the message loop until Dispose() and track all incoming connections if (man == null) // We're not hosting that torrent { Logger.Log(id.Connection, "ListenManager - Handshake requested nonexistant torrent"); id.Connection.Dispose(); return; } if (man.State == TorrentState.Stopped) { Logger.Log(id.Connection, "ListenManager - Handshake requested for torrent which is not running"); id.Connection.Dispose(); return; } if (!man.Mode.CanAcceptConnections) { Logger.Log(id.Connection, "ListenManager - Current mode does not support connections"); id.Connection.Dispose(); return; } id.Peer.PeerId = message.PeerId; id.TorrentManager = man; // If the handshake was parsed properly without encryption, then it definitely was not encrypted. If this is not allowed, abort if ((id.Encryptor is PlainTextEncryption && !Toolbox.HasEncryption(_engine.Settings.AllowedEncryption, EncryptionTypes.PlainText)) && ClientEngine.SupportsEncryption) { Logger.Log(id.Connection, "ListenManager - Encryption is required but was not active"); id.Connection.Dispose(); return; } message.Handle(id); Logger.Log(id.Connection, "ListenManager - Handshake successful handled"); id.ClientApp = new Software(message.PeerId); message = new HandshakeMessage(id.TorrentManager.InfoHash, _engine.PeerId, VersionInfo.ProtocolStringV100); var callback = _engine.ConnectionManager.IncomingConnectionAcceptedCallback; PeerIO.EnqueueSendMessage(id.Connection, id.Encryptor, message, id.TorrentManager.UploadLimiter, id.Monitor, id.TorrentManager.Monitor, callback, id); }
protected virtual void SendClientHelloMessage() { this.mRecordStream.SetWriteVersion(this.mTlsClient.ClientHelloRecordLayerVersion); ProtocolVersion client_version = this.mTlsClient.ClientVersion; if (client_version.IsDtls) { throw new TlsFatalAlert(AlertDescription.internal_error); } ContextAdmin.SetClientVersion(client_version); /* * TODO RFC 5077 3.4. When presenting a ticket, the client MAY generate and include a * Session ID in the TLS ClientHello. */ byte[] session_id = TlsUtilities.EmptyBytes; if (this.mTlsSession != null) { session_id = this.mTlsSession.SessionID; if (session_id == null || session_id.Length > 32) { session_id = TlsUtilities.EmptyBytes; } } bool fallback = this.mTlsClient.IsFallback; this.mOfferedCipherSuites = this.mTlsClient.GetCipherSuites(); this.mOfferedCompressionMethods = this.mTlsClient.GetCompressionMethods(); if (session_id.Length > 0 && this.mSessionParameters != null) { if (!Arrays.Contains(this.mOfferedCipherSuites, mSessionParameters.CipherSuite) || !Arrays.Contains(this.mOfferedCompressionMethods, mSessionParameters.CompressionAlgorithm)) { session_id = TlsUtilities.EmptyBytes; } } this.mClientExtensions = this.mTlsClient.GetClientExtensions(); HandshakeMessage message = new HandshakeMessage(HandshakeType.client_hello); TlsUtilities.WriteVersion(client_version, message); message.Write(this.mSecurityParameters.ClientRandom); TlsUtilities.WriteOpaque8(session_id, message); // Cipher Suites (and SCSV) { /* * RFC 5746 3.4. The client MUST include either an empty "renegotiation_info" extension, * or the TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling cipher suite value in the * ClientHello. Including both is NOT RECOMMENDED. */ byte[] renegExtData = TlsUtilities.GetExtensionData(mClientExtensions, ExtensionType.renegotiation_info); bool noRenegExt = (null == renegExtData); bool noRenegScsv = !Arrays.Contains(mOfferedCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV); if (noRenegExt && noRenegScsv) { // TODO Consider whether to default to a client extension instead // this.mClientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(this.mClientExtensions); // this.mClientExtensions[ExtensionType.renegotiation_info] = CreateRenegotiationInfo(TlsUtilities.EmptyBytes); this.mOfferedCipherSuites = Arrays.Append(mOfferedCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV); } /* * draft-ietf-tls-downgrade-scsv-00 4. If a client sends a ClientHello.client_version * containing a lower value than the latest (highest-valued) version supported by the * client, it SHOULD include the TLS_FALLBACK_SCSV cipher suite value in * ClientHello.cipher_suites. */ if (fallback && !Arrays.Contains(mOfferedCipherSuites, CipherSuite.TLS_FALLBACK_SCSV)) { this.mOfferedCipherSuites = Arrays.Append(mOfferedCipherSuites, CipherSuite.TLS_FALLBACK_SCSV); } TlsUtilities.WriteUint16ArrayWithUint16Length(mOfferedCipherSuites, message); } TlsUtilities.WriteUint8ArrayWithUint8Length(mOfferedCompressionMethods, message); if (mClientExtensions != null) { WriteExtensions(message, mClientExtensions); } message.WriteToRecordStream(this); }
protected virtual void SendClientHelloMessage() { this.mRecordStream.SetWriteVersion(this.mTlsClient.ClientHelloRecordLayerVersion); ProtocolVersion client_version = this.mTlsClient.ClientVersion; if (client_version.IsDtls) throw new TlsFatalAlert(AlertDescription.internal_error); ContextAdmin.SetClientVersion(client_version); /* * TODO RFC 5077 3.4. When presenting a ticket, the client MAY generate and include a * Session ID in the TLS ClientHello. */ byte[] session_id = TlsUtilities.EmptyBytes; if (this.mTlsSession != null) { session_id = this.mTlsSession.SessionID; if (session_id == null || session_id.Length > 32) { session_id = TlsUtilities.EmptyBytes; } } bool fallback = this.mTlsClient.IsFallback; this.mOfferedCipherSuites = this.mTlsClient.GetCipherSuites(); this.mOfferedCompressionMethods = this.mTlsClient.GetCompressionMethods(); if (session_id.Length > 0 && this.mSessionParameters != null) { if (!Arrays.Contains(this.mOfferedCipherSuites, mSessionParameters.CipherSuite) || !Arrays.Contains(this.mOfferedCompressionMethods, mSessionParameters.CompressionAlgorithm)) { session_id = TlsUtilities.EmptyBytes; } } this.mClientExtensions = this.mTlsClient.GetClientExtensions(); HandshakeMessage message = new HandshakeMessage(HandshakeType.client_hello); TlsUtilities.WriteVersion(client_version, message); message.Write(this.mSecurityParameters.ClientRandom); TlsUtilities.WriteOpaque8(session_id, message); // Cipher Suites (and SCSV) { /* * RFC 5746 3.4. The client MUST include either an empty "renegotiation_info" extension, * or the TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling cipher suite value in the * ClientHello. Including both is NOT RECOMMENDED. */ byte[] renegExtData = TlsUtilities.GetExtensionData(mClientExtensions, ExtensionType.renegotiation_info); bool noRenegExt = (null == renegExtData); bool noRenegScsv = !Arrays.Contains(mOfferedCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV); if (noRenegExt && noRenegScsv) { // TODO Consider whether to default to a client extension instead // this.mClientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(this.mClientExtensions); // this.mClientExtensions[ExtensionType.renegotiation_info] = CreateRenegotiationInfo(TlsUtilities.EmptyBytes); this.mOfferedCipherSuites = Arrays.Append(mOfferedCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV); } /* * draft-ietf-tls-downgrade-scsv-00 4. If a client sends a ClientHello.client_version * containing a lower value than the latest (highest-valued) version supported by the * client, it SHOULD include the TLS_FALLBACK_SCSV cipher suite value in * ClientHello.cipher_suites. */ if (fallback && !Arrays.Contains(mOfferedCipherSuites, CipherSuite.TLS_FALLBACK_SCSV)) { this.mOfferedCipherSuites = Arrays.Append(mOfferedCipherSuites, CipherSuite.TLS_FALLBACK_SCSV); } TlsUtilities.WriteUint16ArrayWithUint16Length(mOfferedCipherSuites, message); } TlsUtilities.WriteUint8ArrayWithUint8Length(mOfferedCompressionMethods, message); if (mClientExtensions != null) { WriteExtensions(message, mClientExtensions); } message.WriteToRecordStream(this); }
protected virtual void SendCertificateStatusMessage(CertificateStatus certificateStatus) { HandshakeMessage message = new HandshakeMessage(HandshakeType.certificate_status); certificateStatus.Encode(message); message.WriteToRecordStream(this); }
internal static async ReusableTask <EncryptorResult> CheckOutgoingConnectionAsync(IConnection2 connection, EncryptionTypes encryption, EngineSettings settings, InfoHash infoHash, HandshakeMessage handshake = null) { if (connection.IsIncoming) { throw new Exception("oops"); } using (var cts = new CancellationTokenSource(Timeout)) using (var registration = cts.Token.Register(connection.Dispose)) return(await DoCheckOutgoingConnectionAsync(connection, encryption, settings, infoHash, handshake)); }
protected override void ProcessServerHelloDone(HandshakeMessage serverHelloDone) { if (_state != HandshakeState.ReceivedCertificate && _state != HandshakeState.ReceivedServerKeyExchange && _state != HandshakeState.ReceivedCertificateRequest) { throw new AlertException(AlertDescription.UnexpectedMessage, "Server hello done received at the wrong time"); } bool clientCertificateSent = false; if (_clientCertificateRequested) { // Ask for correct certificate from the callback int certificateIndex = _certificateSelectionCallback(_availableCertificates.ToArray(), _serverCertificates); if (certificateIndex >= 0 && certificateIndex < _availableCertificates.Count) { _clientCertificates.AddRange(_availableCertificates[certificateIndex]); _selectedPrivateKey = _availablePrivateKeys[certificateIndex]; } // If certificate was selected, send it to server if (_clientCertificates.Count > 0) { HandshakeCertificate certificate = new HandshakeCertificate(_version); certificate.CertificateList.AddRange(_clientCertificates); OutputMessage(certificate); clientCertificateSent = true; } else { // TODO: In case of SSLv3 we should send warning alert instead? HandshakeCertificate certificate = new HandshakeCertificate(_version); OutputMessage(certificate); } } // Send client key exchange message byte[] clientKeys = null; if (_serverCertificates.Count > 0) { CertificatePublicKey publicKey = new CertificatePublicKey(_serverCertificates[0]); clientKeys = _cipherSuite.KeyExchangeAlgorithm.GetClientKeys(_version, _maxVersion, publicKey); } HandshakeMessage keyex = new HandshakeMessage(HandshakeMessageType.ClientKeyExchange, _version, clientKeys); OutputMessage(keyex); if (clientCertificateSent) { // Get all handshake messages byte[] handshakeMessages = _handshakeStream.ToArray(); // FIXME: Generate the signature of handshakeMessages with client cert signature // this breaks if client certificate signature is different type than negotiated byte[] signature = GenerateSignature(_selectedPrivateKey, handshakeMessages); // Create CertificateVerify message and send it to server HandshakeMessage verify = new HandshakeMessage(HandshakeMessageType.CertificateVerify, _version, signature); OutputMessage(verify); } // Generate the master secret from key exchange _connectionState.MasterSecret = GenerateMasterSecret(_version, _cipherSuite, _connectionState); // Wait for changecipherspec+finished _state = HandshakeState.SendChangeCipherSpec; }
protected virtual void SendCertificateRequestMessage(CertificateRequest certificateRequest) { HandshakeMessage message = new HandshakeMessage(HandshakeType.certificate_request); certificateRequest.Encode(message); message.WriteToRecordStream(this); }
static async ReusableTask <EncryptorResult> DoCheckOutgoingConnectionAsync(IConnection2 connection, EncryptionTypes encryption, EngineSettings settings, InfoHash infoHash, HandshakeMessage handshake) { var allowedEncryption = settings.AllowedEncryption & encryption; var supportsRC4Header = allowedEncryption.HasFlag(EncryptionTypes.RC4Header); var supportsRC4Full = allowedEncryption.HasFlag(EncryptionTypes.RC4Full); var supportsPlainText = allowedEncryption.HasFlag(EncryptionTypes.PlainText); if ((settings.PreferEncryption || !supportsPlainText) && (supportsRC4Header || supportsRC4Full)) { var encSocket = new PeerAEncryption(infoHash, allowedEncryption, handshake?.Encode()); await encSocket.HandshakeAsync(connection); if (encSocket.Decryptor is RC4Header && !supportsRC4Header) { throw new EncryptionException("Decryptor was RC4Header but that is not allowed"); } if (encSocket.Decryptor is RC4 && !supportsRC4Full) { throw new EncryptionException("Decryptor was RC4Full but that is not allowed"); } return(new EncryptorResult(encSocket.Decryptor, encSocket.Encryptor, null)); } else if (supportsPlainText) { if (handshake != null) { var length = handshake.ByteLength; var buffer = ClientEngine.BufferManager.GetBuffer(length); handshake.Encode(buffer, 0); try { await NetworkIO.SendAsync(connection, buffer, 0, length, null, null, null); } finally { ClientEngine.BufferManager.FreeBuffer(buffer); } } return(new EncryptorResult(PlainTextEncryption.Instance, PlainTextEncryption.Instance, null)); } connection.Dispose(); throw new EncryptionException("Invalid handshake received and no decryption works"); }
protected virtual void SendNewSessionTicketMessage(NewSessionTicket newSessionTicket) { if (newSessionTicket == null) throw new TlsFatalAlert(AlertDescription.internal_error); HandshakeMessage message = new HandshakeMessage(HandshakeType.session_ticket); newSessionTicket.Encode(message); message.WriteToRecordStream(this); }
public EncryptorResult(IEncryption decryptor, IEncryption encryptor, HandshakeMessage handshake) { Decryptor = decryptor; Encryptor = encryptor; Handshake = handshake; }
protected virtual void SendServerKeyExchangeMessage(byte[] serverKeyExchange) { HandshakeMessage message = new HandshakeMessage(HandshakeType.server_key_exchange, serverKeyExchange.Length); message.Write(serverKeyExchange); message.WriteToRecordStream(this); }
static async ReusableTask <EncryptorResult> DoCheckIncomingConnectionAsync(IConnection2 connection, EncryptionTypes encryption, EngineSettings settings, InfoHash[] sKeys) { var allowedEncryption = (settings?.AllowedEncryption ?? EncryptionTypes.All) & encryption; var supportsRC4Header = allowedEncryption.HasFlag(EncryptionTypes.RC4Header); var supportsRC4Full = allowedEncryption.HasFlag(EncryptionTypes.RC4Full); var supportsPlainText = allowedEncryption.HasFlag(EncryptionTypes.PlainText); // If the connection is incoming, receive the handshake before // trying to decide what encryption to use var buffer = ClientEngine.BufferManager.GetBuffer(HandshakeMessage.HandshakeLength); var message = new HandshakeMessage(); try { await NetworkIO.ReceiveAsync(connection, buffer, 0, HandshakeMessage.HandshakeLength, null, null, null).ConfigureAwait(false); message.Decode(buffer, 0, HandshakeMessage.HandshakeLength); if (message.ProtocolString == VersionInfo.ProtocolStringV100) { if (supportsPlainText) { return(new EncryptorResult(PlainTextEncryption.Instance, PlainTextEncryption.Instance, message)); } } else if (supportsRC4Header || supportsRC4Full) { // The data we just received was part of an encrypted handshake and was *not* the BitTorrent handshake var encSocket = new PeerBEncryption(sKeys, EncryptionTypes.All); await encSocket.HandshakeAsync(connection, buffer, 0, HandshakeMessage.HandshakeLength); if (encSocket.Decryptor is RC4Header && !supportsRC4Header) { throw new EncryptionException("Decryptor was RC4Header but that is not allowed"); } if (encSocket.Decryptor is RC4 && !supportsRC4Full) { throw new EncryptionException("Decryptor was RC4Full but that is not allowed"); } // As the connection was encrypted, the data we got from the initial Receive call will have // been consumed during the crypto handshake process. Now that the encrypted handshake has // been established, we should ensure we read the data again. var data = encSocket.InitialData?.Length > 0 ? encSocket.InitialData : null; if (data == null) { data = buffer; await NetworkIO.ReceiveAsync(connection, data, 0, HandshakeMessage.HandshakeLength, null, null, null); encSocket.Decryptor.Decrypt(data, 0, HandshakeMessage.HandshakeLength); } message.Decode(data, 0, HandshakeMessage.HandshakeLength); if (message.ProtocolString == VersionInfo.ProtocolStringV100) { return(new EncryptorResult(encSocket.Decryptor, encSocket.Encryptor, message)); } } } finally { ClientEngine.BufferManager.FreeBuffer(buffer); } connection.Dispose(); throw new EncryptionException("Invalid handshake received and no decryption works"); }
internal byte[] EncodeHandshakeRecord (HandshakeMessage message) { var buffer = message.EncodeMessage (); var encoded = EncodeRecord (ContentType.Handshake, buffer); if (message.Type != HandshakeType.HelloRequest) HandshakeParameters.HandshakeMessages.Add (message, buffer); #if DEBUG_FULL if (EnableDebugging) { DebugHelper.WriteLine ("EncodeHandshakeRecord: {0}", message.Type); DebugHelper.WriteLine ("Encoded", encoded); } #endif return encoded; }
protected override void Handshake(HandshakeMessage message) { _context = _handshaker(this, message); if (null != _context) { _connectPromise.TrySetResult(this); } else { _connectPromise.TrySetException(new ConnectorException( "Failed Application HandShake")); TryClose(); } }
protected virtual void HandleHandshakeMessage(PeerId id, HandshakeMessage message) { if (!message.ProtocolString.Equals(VersionInfo.ProtocolStringV100)) { Logger.Log(id.Connection, "HandShake.Handle - Invalid protocol in handshake: {0}", message.ProtocolString); throw new ProtocolException("Invalid protocol string"); } // If we got the peer as a "compact" peer, then the peerid will be empty. In this case // we just copy the one that is in the handshake. if (string.IsNullOrEmpty(id.Peer.PeerId)) id.Peer.PeerId = message.PeerId; // If the infohash doesn't match, dump the connection if (message.InfoHash != id.TorrentManager.InfoHash) { Logger.Log(id.Connection, "HandShake.Handle - Invalid infohash"); throw new TorrentException("Invalid infohash. Not tracking this torrent"); } // If the peer id's don't match, dump the connection. This is due to peers faking usually if (id.Peer.PeerId != message.PeerId) { Logger.Log(id.Connection, "HandShake.Handle - Invalid peerid"); throw new TorrentException("Supplied PeerID didn't match the one the tracker gave us"); } // Attempt to parse the application that the peer is using id.ClientApp = new Software(message.PeerId); id.SupportsFastPeer = message.SupportsFastPeer; id.SupportsLTMessages = message.SupportsExtendedMessaging; // If they support fast peers, create their list of allowed pieces that they can request off me if (id.SupportsFastPeer && id.TorrentManager != null && id.TorrentManager.HasMetadata) id.AmAllowedFastPieces = AllowedFastAlgorithm.Calculate(id.AddressBytes, id.TorrentManager.InfoHash, (uint) id.TorrentManager.Torrent.Pieces.Count); }
internal byte[] EncodeHandshakeRecord (HandshakeMessage message) { var buffer = message.EncodeMessage (); int fragmentSize = MAX_FRAGMENT_SIZE; #if INSTRUMENTATION if (message.Type == HandshakeType.ServerHello && HasInstrument (HandshakeInstrumentType.FragmentServerHello)) fragmentSize = 30; else if (HasInstrument (HandshakeInstrumentType.FragmentHandshakeMessages)) fragmentSize = 512; #endif var encoded = EncodeRecord_internal (ContentType.Handshake, buffer, fragmentSize); if (message.Type != HandshakeType.HelloRequest) HandshakeParameters.HandshakeMessages.Add (message, buffer); #if DEBUG_FULL if (EnableDebugging) { DebugHelper.WriteLine ("EncodeHandshakeRecord: {0}", message.Type); DebugHelper.WriteLine ("Encoded", encoded); } #endif return encoded; }
protected virtual void SendSupplementalDataMessage(IList supplementalData) { HandshakeMessage message = new HandshakeMessage(HandshakeType.supplemental_data); WriteSupplementalData(message, supplementalData); message.WriteToRecordStream(this); }
private void EndCheckEncryption(IAsyncResult result) { var id = (PeerId) result.AsyncState; try { byte[] initialData; EncryptorFactory.EndCheckEncryption(result, out initialData); if (initialData != null && initialData.Length > 0) throw new EncryptionException("unhandled initial data"); var e = _engine.Settings.AllowedEncryption; if (id.Encryptor is RC4 && !Toolbox.HasEncryption(e, EncryptionTypes.RC4Full) || id.Encryptor is RC4Header && !Toolbox.HasEncryption(e, EncryptionTypes.RC4Header) || id.Encryptor is PlainTextEncryption && !Toolbox.HasEncryption(e, EncryptionTypes.PlainText)) { CleanupSocket(id, id.Encryptor.GetType().Name + " encryption is not enabled"); } else { // Create a handshake message to send to the peer var handshake = new HandshakeMessage(id.TorrentManager.InfoHash, _engine.PeerId, VersionInfo.ProtocolStringV100); SendMessage(id, handshake, _handshakeSentCallback); } } catch { id.Peer.Encryption &= ~EncryptionTypes.RC4Full; id.Peer.Encryption &= ~EncryptionTypes.RC4Header; CleanupSocket(id, "Failed encryptor check"); } }