public IAsyncResult BeginClientHandshake(string targetHost, AsyncCallback asyncCallback, Object asyncState) { lock (_handshakeLock) { if (_isHandshaking) { throw new InvalidOperationException("Handshake already in progress"); } if (_isAuthenticated) { throw new InvalidOperationException("Renegotiation not supported"); } _recordHandler = new RecordHandler(_securityParameters.MinimumVersion, true); _handshakeSession = new ClientHandshakeSession(_securityParameters); _isHandshaking = true; } AsyncHandshakeResult asyncHandshakeResult = new AsyncHandshakeResult(asyncCallback, asyncState); ProcessSendHandshakePacket(asyncHandshakeResult); return(asyncHandshakeResult); }
public IAsyncResult BeginServerHandshake(X509Certificate serverCertificate, AsyncCallback asyncCallback, Object asyncState) { lock (_handshakeLock) { if (_isHandshaking) { throw new InvalidOperationException("Handshake already in progress"); } if (_isAuthenticated) { throw new InvalidOperationException("Renegotiation not supported"); } _recordHandler = new RecordHandler(_securityParameters.MinimumVersion, false); _handshakeSession = new ServerHandshakeSession(_securityParameters); _isHandshaking = true; } AsyncHandshakeResult asyncHandshakeResult = new AsyncHandshakeResult(asyncCallback, asyncState); _recordStream.BeginReceive(new AsyncCallback(ReceiveHandshakeCallback), asyncHandshakeResult); return(asyncHandshakeResult); }
private void SendHandshakeCallback(IAsyncResult asyncResult) { AsyncHandshakeResult asyncHandshakeResult = (AsyncHandshakeResult)asyncResult.AsyncState; try { _recordStream.EndSend(asyncResult); lock (_handshakeLock) { if (_isAuthenticated && !_isHandshaking) { // Mark send result as complete asyncHandshakeResult.SetComplete(); return; } } // Handshake not finished yet, continue performing ProcessSendHandshakePacket(asyncHandshakeResult); } catch (AlertException ae) { ProcessSendFatalAlert(new Alert(ae.AlertDescription, _handshakeSession.NegotiatedVersion)); asyncHandshakeResult.SetComplete(new Exception("Connection closed because of local alert", ae)); } catch (IOException) { asyncHandshakeResult.SetComplete(new EndOfStreamException("Connection closed unexpectedly")); } catch (Exception e) { ProcessSendFatalAlert(new Alert(AlertDescription.InternalError, _handshakeSession.NegotiatedVersion)); asyncHandshakeResult.SetComplete(new Exception("Connection closed because of local error", e)); } }
private void ProcessSendHandshakePacket(AsyncHandshakeResult asyncHandshakeResult) { HandshakeMessage[] messages = _handshakeSession.GetOutputMessages(); Record[] records = _handshakePacketizer.ProcessHandshakeMessages(_handshakeSession.NegotiatedVersion, messages, _recordStream.MaximumFragmentLength); if (records.Length > 0) { // Encrypt the handshake records for (int i = 0; i < records.Length; i++) { _recordHandler.ProcessOutputRecord(records[i]); } _recordStream.BeginSend(records, new AsyncCallback(SendHandshakeCallback), asyncHandshakeResult); } else { if (_handshakeSession.State == HandshakeState.Finished) { // Handshake finished, mark result as complete asyncHandshakeResult.SetComplete(); } else if (_handshakeSession.State == HandshakeState.SendChangeCipherSpec) { ProcessSendChangeCipherSpec(asyncHandshakeResult); } else { // Handshake not finished, receive the next handshake packet _recordStream.BeginReceive(new AsyncCallback(ReceiveHandshakeCallback), asyncHandshakeResult); } } }
private void ProcessHandshakeRecord(Record record, AsyncHandshakeResult asyncHandshakeResult) { // Process each handshake message included in this record fragment separately HandshakeMessage[] msgs = _handshakePacketizer.ProcessHandshakeRecord(_handshakeSession.NegotiatedVersion, record); for (int i = 0; i < msgs.Length; i++) { _handshakeSession.ProcessMessage(msgs[i]); } // Continue processing handshake by attempting to send packets ProcessSendHandshakePacket(asyncHandshakeResult); }
private void ProcessChangeCipherSpecRecord(Record record, AsyncHandshakeResult asyncHandshakeResult) { if (record.Fragment.Length != 1 || record.Fragment[0] != 0x01) { throw new AlertException(AlertDescription.IllegalParameter, "Received an invalid ChangeCipherSpec record"); } // NOTE: keep this before recordHandler.ChangeLocalState since it may generate masterSecret _handshakeSession.RemoteChangeCipherSpec(); // Change cipher suite in record handler and handle it in handshake session _recordHandler.SetCipherSuite(_handshakeSession.CipherSuite, _handshakeSession.ConnectionState); _recordHandler.ChangeRemoteState(); // Read the finished message after changing cipher spec _recordStream.BeginReceive(new AsyncCallback(ReceiveHandshakeCallback), asyncHandshakeResult); }
private void EndHandshake(IAsyncResult asyncResult) { AsyncHandshakeResult asyncHandshakeResult = (AsyncHandshakeResult)asyncResult; if (!asyncHandshakeResult.IsCompleted) { asyncHandshakeResult.AsyncWaitHandle.WaitOne(); } lock (_handshakeLock) { _isHandshaking = false; if (asyncHandshakeResult.CompletedWithException) { throw asyncHandshakeResult.AsyncException; } _isAuthenticated = true; } }
private void ProcessSendChangeCipherSpec(AsyncHandshakeResult asyncHandshakeResult) { // Create the change cipher spec protocol packet // NOTE: this has to be before recordHandler.ChangeLocalState since it uses the old state Record record = new Record(RecordType.ChangeCipherSpec, _handshakeSession.NegotiatedVersion, new byte[] { 0x01 }); _recordHandler.ProcessOutputRecord(record); // NOTE: keep this before recordHandler.ChangeLocalState since it may generate masterSecret _handshakeSession.LocalChangeCipherSpec(); // Change cipher suite in record handler and handle it in handshake session _recordHandler.SetCipherSuite(_handshakeSession.CipherSuite, _handshakeSession.ConnectionState); _recordHandler.ChangeLocalState(); // Send the change cipher spec protocol packet _recordStream.BeginSend(new Record[] { record }, new AsyncCallback(SendHandshakeCallback), asyncHandshakeResult); }
public IAsyncResult BeginClientHandshake(string targetHost, AsyncCallback asyncCallback, Object asyncState) { lock (_handshakeLock) { if (_isHandshaking) { throw new InvalidOperationException("Handshake already in progress"); } if (_isAuthenticated) { throw new InvalidOperationException("Renegotiation not supported"); } _recordHandler = new RecordHandler(_securityParameters.MinimumVersion, true); _handshakeSession = new ClientHandshakeSession(_securityParameters); _isHandshaking = true; } AsyncHandshakeResult asyncHandshakeResult = new AsyncHandshakeResult(asyncCallback, asyncState); ProcessSendHandshakePacket(asyncHandshakeResult); return asyncHandshakeResult; }
private void ProcessSendHandshakePacket(AsyncHandshakeResult asyncHandshakeResult) { HandshakeMessage[] messages = _handshakeSession.GetOutputMessages(); Record[] records = _handshakePacketizer.ProcessHandshakeMessages(_handshakeSession.NegotiatedVersion, messages, _recordStream.MaximumFragmentLength); if (records.Length > 0) { // Encrypt the handshake records for (int i=0; i<records.Length; i++) { _recordHandler.ProcessOutputRecord(records[i]); } _recordStream.BeginSend(records, new AsyncCallback(SendHandshakeCallback), asyncHandshakeResult); } else { if (_handshakeSession.State == HandshakeState.Finished) { // Handshake finished, mark result as complete asyncHandshakeResult.SetComplete(); } else if (_handshakeSession.State == HandshakeState.SendChangeCipherSpec) { ProcessSendChangeCipherSpec(asyncHandshakeResult); } else { // Handshake not finished, receive the next handshake packet _recordStream.BeginReceive(new AsyncCallback(ReceiveHandshakeCallback), asyncHandshakeResult); } } }
private void ProcessHandshakeRecord(Record record, AsyncHandshakeResult asyncHandshakeResult) { // Process each handshake message included in this record fragment separately HandshakeMessage[] msgs = _handshakePacketizer.ProcessHandshakeRecord(_handshakeSession.NegotiatedVersion, record); for (int i=0; i<msgs.Length; i++) { _handshakeSession.ProcessMessage(msgs[i]); } // Continue processing handshake by attempting to send packets ProcessSendHandshakePacket(asyncHandshakeResult); }
public IAsyncResult BeginServerHandshake(X509Certificate serverCertificate, AsyncCallback asyncCallback, Object asyncState) { lock (_handshakeLock) { if (_isHandshaking) { throw new InvalidOperationException("Handshake already in progress"); } if (_isAuthenticated) { throw new InvalidOperationException("Renegotiation not supported"); } _recordHandler = new RecordHandler(_securityParameters.MinimumVersion, false); _handshakeSession = new ServerHandshakeSession(_securityParameters); _isHandshaking = true; } AsyncHandshakeResult asyncHandshakeResult = new AsyncHandshakeResult(asyncCallback, asyncState); _recordStream.BeginReceive(new AsyncCallback(ReceiveHandshakeCallback), asyncHandshakeResult); return asyncHandshakeResult; }
private void ReceiveHandshakeCallback(IAsyncResult asyncResult) { AsyncHandshakeResult asyncHandshakeResult = (AsyncHandshakeResult)asyncResult.AsyncState; try { Record[] records = _recordStream.EndReceive(asyncResult); for (int i = 0; i < records.Length; i++) { Record record = records[i]; if (!_recordHandler.ProcessInputRecord(record)) { // Ignore records from invalid epoch continue; } lock (_handshakeLock) { if (!_isAuthenticated && record.Type == RecordType.Data) { // Refuse data packets before authentication throw new AlertException(AlertDescription.UnexpectedMessage, "Data packet received before handshake"); } if (!_isHandshaking && (record.Type == RecordType.ChangeCipherSpec || record.Type == RecordType.Handshake)) { // Refuse ChangeCipherSpec and Handshake packets if not handshaking // TODO: Should handle HelloRequest if renegotiation is supported throw new AlertException(AlertDescription.UnexpectedMessage, "Handshake packet received outside handshake"); } if (_isHandshaking && record.Type == RecordType.Data) { // Queue data packets during new handshake to avoid sync problems // TODO: Should handle the data correctly if renegotiation is supported throw new AlertException(AlertDescription.UnexpectedMessage, "Received a data packet during handshake"); } } switch (record.Type) { case RecordType.ChangeCipherSpec: ProcessChangeCipherSpecRecord(record, asyncHandshakeResult); break; case RecordType.Alert: ProcessAlertRecord(record, asyncHandshakeResult); break; case RecordType.Handshake: ProcessHandshakeRecord(record, asyncHandshakeResult); break; case RecordType.Data: // TODO: Implement this properly if renegotiation is supported break; default: ProcessUnknownRecord(record, asyncHandshakeResult); break; } } } catch (AlertException ae) { ProcessSendFatalAlert(new Alert(ae.AlertDescription, _handshakeSession.NegotiatedVersion)); asyncHandshakeResult.SetComplete(new Exception("Connection closed because of local alert", ae)); } catch (IOException) { asyncHandshakeResult.SetComplete(new EndOfStreamException("Connection closed unexpectedly")); } catch (Exception e) { ProcessSendFatalAlert(new Alert(AlertDescription.InternalError, _handshakeSession.NegotiatedVersion)); asyncHandshakeResult.SetComplete(new Exception("Connection closed because of local error", e)); } }