bool ProcessHandshakeMessage(TlsBuffer incoming, out SecurityStatus status) { var handshakeType = (HandshakeType)incoming.ReadByte(); #if DEBUG_FULL if (EnableDebugging) { DebugHelper.WriteLine(">>>> Processing Handshake record ({0})", handshakeType); DebugHelper.WriteRemaining("HANDSHAKE", incoming); } #endif // Read message length int length = incoming.ReadInt24(); if (incoming.Remaining < length) { cachedFragment = new TlsBuffer(length + 4); cachedFragment.Position = incoming.Remaining + 4; Buffer.BlockCopy(incoming.Buffer, incoming.Position - 4, cachedFragment.Buffer, 0, cachedFragment.Position); incoming.Dispose(); status = SecurityStatus.ContinueNeeded; return(false); } var buffer = incoming.ReadBuffer(length); return(negotiationHandler.ProcessHandshakeMessage(handshakeType, buffer, out status)); }
SecurityStatus _DecryptMessage(ref TlsBuffer incoming) { // Try to read the Record Content Type var contentType = (ContentType)incoming.ReadByte(); #if DEBUG_FULL if (EnableDebugging) { DebugHelper.WriteLine("DecryptMessage: {0}", contentType); } #endif ReadStandardBuffer(contentType, ref incoming); if (contentType == ContentType.Alert) { var level = (AlertLevel)incoming.ReadByte(); var description = (AlertDescription)incoming.ReadByte(); if (level == AlertLevel.Warning && description == AlertDescription.CloseNotify) { ReceivedCloseNotify = true; return(SecurityStatus.ContextExpired); } DebugHelper.WriteLine("ALERT: {0} {1}", level, description); throw new TlsException(level, description); } else if (contentType == ContentType.ApplicationData) { return(SecurityStatus.OK); } else if (contentType != ContentType.Handshake) { throw new TlsException(AlertDescription.UnexpectedMessage, "Unknown content type {0}", contentType); } try { SecurityStatus status; var finished = ProcessHandshakeMessage(incoming, out status); DebugHelper.WriteLine("RENEGOTIATION REQUEST: {0} {1}", finished, status); return(status); } finally { incoming.Dispose(); incoming = null; } }
SecurityStatus ProcessAlert(TlsBuffer buffer) { bool decrypted = false; if ((session.Read != null && session.Read.Cipher != null) || (buffer.Remaining != 2)) { decrypted = ReadStandardBuffer(ContentType.Alert, ref buffer); } if (buffer.Remaining != 2) { throw new TlsException(AlertDescription.IlegalParameter, "Invalid Alert message size"); } var level = (AlertLevel)buffer.ReadByte(); var description = (AlertDescription)buffer.ReadByte(); if (decrypted) { buffer.Dispose(); } if (level == AlertLevel.Warning) { if (description == AlertDescription.CloseNotify) { ReceivedCloseNotify = true; if (eventSink != null) { eventSink.ReceivedCloseNotify(); } return(SecurityStatus.ContextExpired); } DebugHelper.WriteLine("Received alert: {0}", description); return(SecurityStatus.ContinueNeeded); } else { throw new TlsException(description); } }
SecurityStatus _GenerateNextToken(TlsBuffer incoming, TlsMultiBuffer outgoing) { #if DEBUG_FULL if (EnableDebugging) { DebugHelper.WriteLine("GenerateNextToken: {0}", negotiationHandler); if (incoming != null) { DebugHelper.WriteRemaining(" incoming", incoming); } } #endif if (incoming == null) { negotiationHandler = negotiationHandler.GenerateReply(outgoing); return(SecurityStatus.ContinueNeeded); } var contentType = (ContentType)incoming.ReadByte(); #if DEBUG_FULL if (EnableDebugging) { DebugHelper.WriteLine(" received message type {0}", contentType); } #endif if (skipToOffset >= 0 && contentType != ContentType.Handshake) { throw new TlsException(AlertDescription.InternalError); } if (contentType == ContentType.Alert) { return(ProcessAlert(incoming)); } bool decrypted = false; if (cachedFragment != null) { if (contentType != ContentType.Handshake) { throw new TlsException(AlertDescription.DecodeError); } decrypted = ReadStandardBuffer(ContentType.Handshake, ref incoming); cachedFragment.Write(incoming.Buffer, incoming.Position, incoming.Position + incoming.Remaining); if (cachedFragment.Remaining > 0) { return(SecurityStatus.ContinueNeeded); } incoming.Dispose(); incoming = cachedFragment; cachedFragment = null; incoming.Position = 0; } else { decrypted = ReadStandardBuffer(contentType, ref incoming); } if (Session.Read != null && Session.Read.Cipher != null && !decrypted) { throw new TlsException(AlertDescription.DecryptError, "Expected encrypted message."); } try { if (contentType == ContentType.ChangeCipherSpec) { return(negotiationHandler.ProcessMessage(new TlsChangeCipherSpec())); } else if (contentType == ContentType.ApplicationData) { if (session.Read == null || session.Read.Cipher == null || !session.SecureRenegotiation) { throw new TlsException(AlertDescription.DecodeError); } // FIXME throw new NotImplementedException(); } else if (contentType != ContentType.Handshake) { throw new TlsException(AlertDescription.UnexpectedMessage); } if (skipToOffset >= 0) { incoming.Position = skipToOffset; skipToOffset = -1; } SecurityStatus result; bool finished; while (true) { var startOffset = incoming.Position; finished = ProcessHandshakeMessage(incoming, out result); if (result == SecurityStatus.CredentialsNeeded) { // Caller will call us again with the same input. skipToOffset = startOffset; if (decrypted) { Session.Read.ReadSequenceNumber--; } return(result); } if (incoming.Remaining == 0) { break; } if (finished || result != SecurityStatus.ContinueNeeded) { throw new TlsException(AlertDescription.UnexpectedMessage); } } if (finished) { negotiationHandler = negotiationHandler.GenerateReply(outgoing); } return(result); } finally { if (decrypted) { incoming.Dispose(); } } }