Exemplo n.º 1
0
            /// <summary>
            /// Is called when TLS handshake has completed.
            /// </summary>
            /// <param name="op">Asynchronous operation.</param>
            /// <exception cref="ArgumentNullException">Is raised when <b>op</b> is null reference.</exception>
            private void SwitchToSecureCompleted(SwitchToSecureAsyncOP op)
            {
                if(op == null){
                    throw new ArgumentNullException("op");
                }

                try{
                    if(op.Error != null){
                        m_pException = op.Error;
                        m_pSmtpClient.LogAddException("Exception: " + m_pException.Message,m_pException);
                    }
                    else{
                        // Log
                        m_pSmtpClient.LogAddText("TLS handshake completed sucessfully.");
                    }
                }
                catch(Exception x){
                    m_pException = x;
                    m_pSmtpClient.LogAddException("Exception: " + m_pException.Message,m_pException);
                }

                op.Dispose();

                SetState(AsyncOP_State.Completed);
            }
Exemplo n.º 2
0
        private void STARTTLS(string cmdTag,string cmdText)
        {
            /* RFC 3501 6.2.1. STARTTLS Command.
                Arguments:  none

                Responses:  no specific response for this command

                Result:     OK - starttls completed, begin TLS negotiation
                            BAD - command unknown or arguments invalid

                A [TLS] negotiation begins immediately after the CRLF at the end
                of the tagged OK response from the server.  Once a client issues a
                STARTTLS command, it MUST NOT issue further commands until a
                server response is seen and the [TLS] negotiation is complete.

                The server remains in the non-authenticated state, even if client
                credentials are supplied during the [TLS] negotiation.  This does
                not preclude an authentication mechanism such as EXTERNAL (defined
                in [SASL]) from using client identity determined by the [TLS]
                negotiation.

                Once [TLS] has been started, the client MUST discard cached
                information about server capabilities and SHOULD re-issue the
                CAPABILITY command.  This is necessary to protect against man-in-
                the-middle attacks which alter the capabilities list prior to
                STARTTLS.  The server MAY advertise different capabilities after
                STARTTLS.

                Example:    C: a001 CAPABILITY
                            S: * CAPABILITY IMAP4rev1 STARTTLS LOGINDISABLED
                            S: a001 OK CAPABILITY completed
                            C: a002 STARTTLS
                            S: a002 OK Begin TLS negotiation now
                            <TLS negotiation, further commands are under [TLS] layer>
                            C: a003 CAPABILITY
                            S: * CAPABILITY IMAP4rev1 AUTH=PLAIN
                            S: a003 OK CAPABILITY completed
                            C: a004 LOGIN joe password
                            S: a004 OK LOGIN completed
            */

            if(m_SessionRejected){
                m_pResponseSender.SendResponseAsync(new IMAP_r_ServerStatus(cmdTag,"NO","Bad sequence of commands: Session rejected."));

                return;
            }
            if(this.IsAuthenticated){
                m_pResponseSender.SendResponseAsync(new IMAP_r_ServerStatus(cmdTag,"NO","This ommand is only valid in not-authenticated state."));

                return;
            }
            if(this.IsSecureConnection){
                m_pResponseSender.SendResponseAsync(new IMAP_r_ServerStatus(cmdTag,"NO","Bad sequence of commands: Connection is already secure."));

                return;
            }
            if(this.Certificate == null){
                m_pResponseSender.SendResponseAsync(new IMAP_r_ServerStatus(cmdTag,"NO","TLS not available: Server has no SSL certificate."));

                return;
            }

            m_pResponseSender.SendResponseAsync(new IMAP_r_ServerStatus(cmdTag,"OK","Begin TLS negotiation now."));
            
            try{
                DateTime startTime = DateTime.Now;

                // Create delegate which is called when SwitchToSecureAsync has completed.
                Action<SwitchToSecureAsyncOP> switchSecureCompleted = delegate(SwitchToSecureAsyncOP e){
                    try{
                        // Operation failed.
                        if(e.Error != null){
                            LogAddException(e.Error);
                            Disconnect();
                        }
                        // Operation suceeded.
                        else{
                            // Log
                            LogAddText("SSL negotiation completed successfully in " + (DateTime.Now - startTime).TotalSeconds.ToString("f2") + " seconds.");

                            BeginReadCmd();
                        }
                    }
                    catch(Exception x){
                        LogAddException(x);
                        Disconnect();
                    }
                };

                SwitchToSecureAsyncOP op = new SwitchToSecureAsyncOP();
                op.CompletedAsync += delegate(object sender,EventArgs<TCP_ServerSession.SwitchToSecureAsyncOP> e){
                    switchSecureCompleted(op);
                };
                // Switch to secure completed synchronously.
                if(!SwitchToSecureAsync(op)){
                    switchSecureCompleted(op);
                }
            }
            catch(Exception x){
                LogAddException(x);
                Disconnect();
            }
        }
Exemplo n.º 3
0
            /// <summary>
            /// Is called when STARTTLS command response reading has completed.
            /// </summary>
            /// <param name="op">Asynchronous operation.</param>
            /// <exception cref="ArgumentNullException">Is raised when <b>op</b> is null reference.</exception>
            private void StartTlsReadResponseCompleted(ReadResponseAsyncOP op)
            {
                if(op == null){
                    throw new ArgumentNullException("op");
                }

                try{
                    if(op.Error != null){
                        m_pException = op.Error;
                    }
                    else{
                        // STARTTLS accepted.
                        if(op.ReplyLines[0].ReplyCode == 220){
                            /* RFC 3207 4.
                                The format for the STARTTLS command is:

                                STARTTLS

                                with no parameters.

                                After the client gives the STARTTLS command, the server responds with
                                one of the following reply codes:

                                220 Ready to start TLS
                                501 Syntax error (no parameters allowed)
                                454 TLS not available due to temporary reason
                            */

                            // Log
                            m_pSmtpClient.LogAddText("Starting TLS handshake.");

                            SwitchToSecureAsyncOP switchSecureOP = new SwitchToSecureAsyncOP(m_pCertCallback);
                            switchSecureOP.CompletedAsync += delegate(object s,EventArgs<SwitchToSecureAsyncOP> e){
                                SwitchToSecureCompleted(switchSecureOP);
                            };
                            if(!m_pSmtpClient.SwitchToSecureAsync(switchSecureOP)){
                                SwitchToSecureCompleted(switchSecureOP);
                            }                       
                        }
                        // STARTTLS failed.
                        else{
                            m_pException = new SMTP_ClientException(op.ReplyLines);
                        }
                    }
                }
                catch(Exception x){
                    m_pException = x;                    
                }

                op.Dispose();

                if(m_pException != null){
                    m_pSmtpClient.LogAddException("Exception: " + m_pException.Message,m_pException);
                    SetState(AsyncOP_State.Completed);
                }
            }
Exemplo n.º 4
0
        /// <summary>
        /// Starts switching connection to secure.
        /// </summary>
        /// <param name="op">Asynchronous operation.</param>
        /// <returns>Returns true if aynchronous operation is pending (The <see cref="SwitchToSecureAsyncOP.CompletedAsync"/> event is raised upon completion of the operation).
        /// Returns false if operation completed synchronously.</returns>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception>
        /// <exception cref="InvalidOperationException">Is raised when TCP client is not connected or connection is already secure.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>op</b> is null reference.</exception>
        protected bool SwitchToSecureAsync(SwitchToSecureAsyncOP op)
        {
            if(this.IsDisposed){
                throw new ObjectDisposedException(this.GetType().Name);
            }
            if(!this.IsConnected){
                throw new InvalidOperationException("You must connect first.");
            }
            if(this.IsSecureConnection){
                throw new InvalidOperationException("Connection is already secure.");
            }
            if(op == null){
                throw new ArgumentNullException("op");
            }
            if(op.State != AsyncOP_State.WaitingForStart){
                throw new ArgumentException("Invalid argument 'op' state, 'op' must be in 'AsyncOP_State.WaitingForStart' state.","op");
            }

            return op.Start(this);
        }
Exemplo n.º 5
0
        /// <summary>
        /// Starts switching connection to secure.
        /// </summary>
        /// <param name="op">Asynchronous operation.</param>
        /// <returns>Returns true if aynchronous operation is pending (The <see cref="SwitchToSecureAsyncOP.CompletedAsync"/> event is raised upon completion of the operation).
        /// Returns false if operation completed synchronously.</returns>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception>
        /// <exception cref="InvalidOperationException">Is raised when connection is already secure or when SSL certificate is not specified.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>op</b> is null reference.</exception>
        public bool SwitchToSecureAsync(SwitchToSecureAsyncOP op)
        {
            if(this.IsDisposed){
                throw new ObjectDisposedException(this.GetType().Name);
            }
            if(this.IsSecureConnection){
                throw new InvalidOperationException("Connection is already secure.");
            }            
            if(m_pCertificate == null){
                throw new InvalidOperationException("There is no certificate specified.");
            }
            if(op == null){
                throw new ArgumentNullException("op");
            }
            if(op.State != AsyncOP_State.WaitingForStart){
                throw new ArgumentException("Invalid argument 'op' state, 'op' must be in 'AsyncOP_State.WaitingForStart' state.","op");
            }

            return op.Start(this);
        }
Exemplo n.º 6
0
        /// <summary>
        /// Switches session to secure connection.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this method is accessed.</exception>
        /// <exception cref="InvalidOperationException">Is raised when connection is already secure or when SSL certificate is not specified.</exception>
        public void SwitchToSecure()
        {
            if(m_IsDisposed){
                throw new ObjectDisposedException("TCP_ServerSession");
            }
            if(m_IsSecure){
                throw new InvalidOperationException("Session is already SSL/TLS.");
            }
            if(m_pCertificate == null){
                throw new InvalidOperationException("There is no certificate specified.");
            }

            ManualResetEvent wait = new ManualResetEvent(false);
            using(SwitchToSecureAsyncOP op = new SwitchToSecureAsyncOP()){
                op.CompletedAsync += delegate(object s1,EventArgs<SwitchToSecureAsyncOP> e1){
                    wait.Set();
                };
                if(!this.SwitchToSecureAsync(op)){
                    wait.Set();
                }
                wait.WaitOne();
                wait.Close();

                if(op.Error != null){
                    throw op.Error;
                }
            }
        }
Exemplo n.º 7
0
        /// <summary>
        /// This method is called from TCP server when session should start processing incoming connection.
        /// </summary>
        internal void StartI()
        {
            if(m_IsSsl){
                // Log
                LogAddText("Starting SSL negotiation now.");

                DateTime startTime = DateTime.Now;

                // Create delegate which is called when SwitchToSecureAsync has completed.
                Action<SwitchToSecureAsyncOP> switchSecureCompleted = delegate(SwitchToSecureAsyncOP e){
                    try{
                        // Operation failed.
                        if(e.Error != null){
                            LogAddException(e.Error);
                            if(!this.IsDisposed){
                                Disconnect();
                            }
                        }
                        // Operation suceeded.
                        else{
                            // Log
                            LogAddText("SSL negotiation completed successfully in " + (DateTime.Now - startTime).TotalSeconds.ToString("f2") + " seconds.");

                            Start();
                        }
                    }
                    catch(Exception x){
                        LogAddException(x);
                        if(!this.IsDisposed){
                            Disconnect();
                        }
                    }
                };

                SwitchToSecureAsyncOP op = new SwitchToSecureAsyncOP();
                op.CompletedAsync += delegate(object sender,EventArgs<TCP_ServerSession.SwitchToSecureAsyncOP> e){
                    switchSecureCompleted(op);
                };
                // Switch to secure completed synchronously.
                if(!SwitchToSecureAsync(op)){
                    switchSecureCompleted(op);
                }
            }
            else{
                Start();
            }
        }
Exemplo n.º 8
0
            /// <summary>
            /// Is called when POP3 server STLS response reading has completed.
            /// </summary>
            /// <param name="op">Asynchronous operation.</param>
            private void StlsReadResponseCompleted(SmartStream.ReadLineAsyncOP op)
            {
                try{
                    // Operation failed.
                    if(op.Error != null){
                        m_pException = op.Error;
                        m_pPop3Client.LogAddException("Exception: " + op.Error.Message,op.Error);
                        SetState(AsyncOP_State.Completed);
                    }
                    // Operation succeeded.
                    else{
                        // Log
                        m_pPop3Client.LogAddRead(op.BytesInBuffer,op.LineUtf8);
                                            
                        // Server returned success response.
                        if(string.Equals(op.LineUtf8.Split(new char[]{' '},2)[0],"+OK",StringComparison.InvariantCultureIgnoreCase)){                        
                            // Log
                            m_pPop3Client.LogAddText("Starting TLS handshake.");

                            SwitchToSecureAsyncOP switchSecureOP = new SwitchToSecureAsyncOP(m_pCertCallback);
                            switchSecureOP.CompletedAsync += delegate(object s,EventArgs<SwitchToSecureAsyncOP> e){
                                SwitchToSecureCompleted(switchSecureOP);
                            };
                            if(!m_pPop3Client.SwitchToSecureAsync(switchSecureOP)){
                                SwitchToSecureCompleted(switchSecureOP);
                            }
                        }
                        // Server returned error response.
                        else{
                            m_pException = new POP3_ClientException(op.LineUtf8);
                            SetState(AsyncOP_State.Completed);
                        }
                    }
                }
                catch(Exception x){
                    m_pException = x;
                    m_pPop3Client.LogAddException("Exception: " + x.Message,x);
                    SetState(AsyncOP_State.Completed);
                }

                op.Dispose();
            }