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)); } }