/// <summary>Removes from the connection table any outdated connection information.</summary> /// <remarks> /// When the table is sweeped, the table is locked to prevent it from being modified during the /// sweep which could cause exceptions to be thrown. The downside to this is that while the /// table is locked, incoming requests will be blocked! As such, either this should be rewritten /// or the frequency of the sleep should be limited. Idle checks could also be implemented to /// ensure that the process runs only when a long idle period has been observed. /// </remarks> private void SweepConnections(object sender, ElapsedEventArgs e) { // We lock it because we want all checks and deletions to be atomic. // If anyone tries to access the hashtable during the sweep, they'll // have to wait. lock (_connections.SyncRoot) { ArrayList toDelete = new ArrayList(_connections.Count); // Find all entries that need to be deleted foreach (DictionaryEntry entry in _connections) { ClientConnectionInfo cci = (ClientConnectionInfo)entry.Value; if (cci.LastUsed.AddSeconds(_connectionAgeLimit).CompareTo(DateTime.UtcNow) < 0) { toDelete.Add(entry.Key); ((IDisposable)cci).Dispose(); // Dispose of the connection System.Diagnostics.Debug.WriteLine("Removing connection: " + cci.TransactID); } } // Delete the out-of-date entries found above foreach (Object obj in toDelete) { _connections.Remove(obj); } toDelete = null; } }
/// <summary>Generates the output parameters necessary to send a new shared key to the client.</summary> /// <param name="transactID">The transaction ID for the client to whom we're communicating.</param> /// <param name="requestHeaders">Headers retrieved from the client.</param> /// <param name="responseMsg">Upon return, contains an empty message to be sent to the client.</param> /// <param name="responseHeaders">Upon return, contains the transport headers to be sent to the client.</param> /// <param name="responseStream">Upon return, contains an empty stream to be sent to the client.</param> /// <returns>Status of the server message processing (always returns Complete).</returns> /// <remarks>Caches the generated client information for later use.</remarks> private ServerProcessing MakeSharedKey( Guid transactID, ITransportHeaders requestHeaders, out IMessage responseMsg, out ITransportHeaders responseHeaders, out Stream responseStream) { // Generate a new shared key and iv (done as part of the constructor of the algorithm) SymmetricAlgorithm symmetricProvider = CryptoHelper.GetNewSymmetricProvider(_algorithm); // Add the transaction id and related information to the connections table. // We cache the entire provider object for use later on. ClientConnectionInfo cci = new ClientConnectionInfo(transactID, symmetricProvider); lock (_connections.SyncRoot) _connections[transactID.ToString()] = cci; // Encrypt the shared key with the sent RSA public key. We need to make sure // the client actually sent us one. RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(); string publicKey = (string)requestHeaders[CommonHeaders.PublicKey]; if (publicKey == null || publicKey == string.Empty) { throw new SecureRemotingException("No public key found with which to encrypt the shared key."); } rsaProvider.FromXmlString(publicKey); // load the public key byte [] encryptedKey = rsaProvider.Encrypt(symmetricProvider.Key, _oaep); byte [] encryptedIV = rsaProvider.Encrypt(symmetricProvider.IV, _oaep); // Setup the output headers and messages responseHeaders = new TransportHeaders(); responseHeaders[CommonHeaders.Transaction] = ((int)SecureTransaction.SendingSharedKey).ToString(); responseHeaders[CommonHeaders.SharedKey] = Convert.ToBase64String(encryptedKey); responseHeaders[CommonHeaders.SharedIV] = Convert.ToBase64String(encryptedIV); // There is no message to send back, but need to initialize them none-the-less. responseMsg = null; responseStream = new MemoryStream(); // We're done; don't forward this on to the next sink! Just return. return(ServerProcessing.Complete); }
/// <summary>Generates the output parameters necessary to send a new shared key to the client.</summary> /// <param name="transactID">The transaction ID for the client to whom we're communicating.</param> /// <param name="requestHeaders">Headers retrieved from the client.</param> /// <param name="responseMsg">Upon return, contains an empty message to be sent to the client.</param> /// <param name="responseHeaders">Upon return, contains the transport headers to be sent to the client.</param> /// <param name="responseStream">Upon return, contains an empty stream to be sent to the client.</param> /// <returns>Status of the server message processing (always returns Complete).</returns> /// <remarks>Caches the generated client information for later use.</remarks> private ServerProcessing MakeSharedKey( Guid transactID, ITransportHeaders requestHeaders, out IMessage responseMsg, out ITransportHeaders responseHeaders, out Stream responseStream) { // Generate a new shared key and iv (done as part of the constructor of the algorithm) SymmetricAlgorithm symmetricProvider = CryptoHelper.GetNewSymmetricProvider(_algorithm); // Add the transaction id and related information to the connections table. // We cache the entire provider object for use later on. ClientConnectionInfo cci = new ClientConnectionInfo(transactID, symmetricProvider); lock(_connections.SyncRoot) _connections[transactID.ToString()] = cci; // Encrypt the shared key with the sent RSA public key. We need to make sure // the client actually sent us one. RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(); string publicKey = (string)requestHeaders[CommonHeaders.PublicKey]; if (publicKey == null || publicKey == string.Empty) throw new SecureRemotingException("No public key found with which to encrypt the shared key."); rsaProvider.FromXmlString(publicKey); // load the public key byte [] encryptedKey = rsaProvider.Encrypt(symmetricProvider.Key, _oaep); byte [] encryptedIV = rsaProvider.Encrypt(symmetricProvider.IV, _oaep); // Setup the output headers and messages responseHeaders = new TransportHeaders(); responseHeaders[CommonHeaders.Transaction] = ((int)SecureTransaction.SendingSharedKey).ToString(); responseHeaders[CommonHeaders.SharedKey] = Convert.ToBase64String(encryptedKey); responseHeaders[CommonHeaders.SharedIV] = Convert.ToBase64String(encryptedIV); // There is no message to send back, but need to initialize them none-the-less. responseMsg = null; responseStream = new MemoryStream(); // We're done; don't forward this on to the next sink! Just return. return ServerProcessing.Complete; }