示例#1
0
 void SendMailCallback(IAsyncResult result)
 {
     GlobalLog.Enter("SmtpClient#" + ValidationHelper.HashString(this) + "::SendMailCallback");
     try {
         writer = transport.EndSendMail(result);
         // If some recipients failed but not others, send the e-mail anyways, but then return the
         // "Non-fatal" exception reporting the failures.  The sync code path does it this way.
         // Fatal exceptions would have thrown above at transport.EndSendMail(...)
         SendMailAsyncResult sendResult = (SendMailAsyncResult)result;
         // Save these and throw them later in SendMessageCallback, after the message has sent.
         failedRecipientException = sendResult.GetFailedRecipientException();
     }
     catch (Exception e)
     {
         Complete(e, result);
         GlobalLog.Leave("SmtpClient#" + ValidationHelper.HashString(this) + "::SendMailCallback");
         return;
     }
     try {
         if (cancelled)
         {
             Complete(null, result);
         }
         else
         {
             message.BeginSend(writer, DeliveryMethod != SmtpDeliveryMethod.Network,
                               ServerSupportsEai, new AsyncCallback(SendMessageCallback), result.AsyncState);
         }
     }
     catch (Exception e) {
         Complete(e, result);
     }
     GlobalLog.Leave("SmtpClient#" + ValidationHelper.HashString(this) + "::SendMailCallback");
 }
示例#2
0
        internal static IPEndPoint GetRemoteEndPoint(byte[] memoryBlob, IntPtr originalAddress)
        {
            GlobalLog.Enter("HttpApi::GetRemoteEndPoint()");

            SocketAddress v4address = new SocketAddress(AddressFamily.InterNetwork, SocketAddress.IPv4AddressSize);
            SocketAddress v6address = new SocketAddress(AddressFamily.InterNetworkV6, SocketAddress.IPv6AddressSize);

            fixed(byte *pMemoryBlob = memoryBlob)
            {
                HTTP_REQUEST *request = (HTTP_REQUEST *)pMemoryBlob;
                IntPtr        address = request->Address.pRemoteAddress != null ? (IntPtr)(pMemoryBlob - (byte *)originalAddress + (byte *)request->Address.pRemoteAddress) : IntPtr.Zero;

                CopyOutAddress(address, ref v4address, ref v6address);
            }

            IPEndPoint endpoint = null;

            if (v4address != null)
            {
                endpoint = IPEndPoint.Any.Create(v4address) as IPEndPoint;
            }
            else if (v6address != null)
            {
                endpoint = IPEndPoint.IPv6Any.Create(v6address) as IPEndPoint;
            }

            GlobalLog.Leave("HttpApi::GetRemoteEndPoint()");
            return(endpoint);
        }
示例#3
0
        internal IAsyncResult BeginGetConnection(ContextAwareResult outerResult, AsyncCallback callback, object state, string host, int port)
        {
            if (GlobalLog.IsEnabled)
            {
                GlobalLog.Enter("SmtpTransport#" + LoggingHash.HashString(this) + "::BeginConnect");
            }
            IAsyncResult result = null;

            try
            {
                _connection         = new SmtpConnection(this, _client, _credentials, _authenticationModules);
                _connection.Timeout = _timeout;
                if (MailEventSource.Log.IsEnabled())
                {
                    MailEventSource.Log.Associate(this, _connection);
                }
                if (EnableSsl)
                {
                    _connection.EnableSsl          = true;
                    _connection.ClientCertificates = ClientCertificates;
                }

                result = _connection.BeginGetConnection(outerResult, callback, state, host, port);
            }
            catch (Exception innerException)
            {
                throw new SmtpException(SR.MailHostNotFound, innerException);
            }

            if (GlobalLog.IsEnabled)
            {
                GlobalLog.Leave("SmtpTransport#" + LoggingHash.HashString(this) + "::BeginConnect Sync Completion");
            }
            return(result);
        }
示例#4
0
        internal SecureChannel(string hostname, bool serverMode, SslProtocols sslProtocols, X509Certificate serverCertificate, X509CertificateCollection clientCertificates, bool remoteCertRequired, bool checkCertName,
                               bool checkCertRevocationStatus, EncryptionPolicy encryptionPolicy, LocalCertSelectionCallback certSelectionDelegate)
        {
            GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::.ctor", "hostname:" + hostname + " #clientCertificates=" + ((clientCertificates == null) ? "0" : clientCertificates.Count.ToString(NumberFormatInfo.InvariantInfo)));
            if (Logging.On)
            {
                Logging.PrintInfo(Logging.Web, this, ".ctor", "hostname=" + hostname + ", #clientCertificates=" + ((clientCertificates == null) ? "0" : clientCertificates.Count.ToString(NumberFormatInfo.InvariantInfo)) + ", encryptionPolicy=" + encryptionPolicy);
            }

            SslStreamPal.VerifyPackageInfo();

            _destination = hostname;

            GlobalLog.Assert(hostname != null, "SecureChannel#{0}::.ctor()|hostname == null", Logging.HashString(this));
            _hostName   = hostname;
            _serverMode = serverMode;

            _sslProtocols = sslProtocols;

            _serverCertificate       = serverCertificate;
            _clientCertificates      = clientCertificates;
            _remoteCertRequired      = remoteCertRequired;
            _securityContext         = null;
            _checkCertRevocation     = checkCertRevocationStatus;
            _checkCertName           = checkCertName;
            _certSelectionDelegate   = certSelectionDelegate;
            _refreshCredentialNeeded = true;
            _encryptionPolicy        = encryptionPolicy;
            GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::.ctor");
        }
        internal IAsyncResult BeginGetConnection(ServicePoint servicePoint, ContextAwareResult outerResult, AsyncCallback callback, object state)
        {
            GlobalLog.Enter("SmtpTransport#" + ValidationHelper.HashString(this) + "::BeginConnect");
            IAsyncResult result = null;

            try{
                UpdateServicePoint(servicePoint);
                connection         = new SmtpConnection(this, client, credentials, authenticationModules);
                connection.Timeout = timeout;
                if (Logging.On)
                {
                    Logging.Associate(Logging.Web, this, connection);
                }
                if (EnableSsl)
                {
                    connection.EnableSsl          = true;
                    connection.ClientCertificates = ClientCertificates;
                }

                result = connection.BeginGetConnection(servicePoint, outerResult, callback, state);
            }
            catch (Exception innerException) {
                throw new SmtpException(SR.GetString(SR.MailHostNotFound), innerException);
            }
            GlobalLog.Leave("SmtpTransport#" + ValidationHelper.HashString(this) + "::BeginConnect [....] Completion");
            return(result);
        }
示例#6
0
        /*++
         *  ProcessHandshakeSuccess -
         *     Called on successful completion of Handshake -
         *     used to set header/trailer sizes for encryption use
         *
         *  Fills in the information about established protocol
         * --*/
        internal void ProcessHandshakeSuccess()
        {
            GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::ProcessHandshakeSuccess");

            StreamSizes streamSizes;

            SslStreamPal.QueryContextStreamSizes(_securityContext, out streamSizes);

            if (streamSizes != null)
            {
                try
                {
                    _headerSize  = streamSizes.header;
                    _trailerSize = streamSizes.trailer;
                    _maxDataSize = checked (streamSizes.maximumMessage - (_headerSize + _trailerSize));
                }
                catch (Exception e)
                {
                    if (!ExceptionCheck.IsFatal(e))
                    {
                        GlobalLog.Assert(false, "SecureChannel#" + Logging.HashString(this) + "::ProcessHandshakeSuccess", "StreamSizes out of range.");
                    }

                    throw;
                }
            }

            SslStreamPal.QueryContextConnectionInfo(_securityContext, out _connectionInfo);
            GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::ProcessHandshakeSuccess");
        }
示例#7
0
        public void SendAsyncCancel()
        {
            if (disposed)
            {
                throw new ObjectDisposedException(this.GetType().FullName);
            }
            if (Logging.On)
            {
                Logging.Enter(Logging.Web, this, "SendAsyncCancel", null);
            }
            GlobalLog.Enter("SmtpClient#" + ValidationHelper.HashString(this) + "::SendAsyncCancel");
            try {
                if (!InCall || cancelled)
                {
                    return;
                }

                cancelled = true;
                Abort();
            } finally {
                if (Logging.On)
                {
                    Logging.Exit(Logging.Web, this, "SendAsyncCancel", null);
                }
                GlobalLog.Leave("SmtpClient#" + ValidationHelper.HashString(this) + "::SendAsyncCancel");
            }
        }
示例#8
0
        private void ConnectCallback(IAsyncResult result)
        {
            if (GlobalLog.IsEnabled)
            {
                GlobalLog.Enter("SmtpClient#" + LoggingHash.HashString(this) + "::ConnectCallback");
            }
            try
            {
                _transport.EndGetConnection(result);
                if (_cancelled)
                {
                    Complete(null, result);
                }
                else
                {
                    // Detected durring Begin/EndGetConnection, restrictable using DeliveryFormat
                    bool allowUnicode = IsUnicodeSupported();
                    ValidateUnicodeRequirement(_message, _recipients, allowUnicode);
                    _transport.BeginSendMail(_message.Sender ?? _message.From, _recipients,
                                             _message.BuildDeliveryStatusNotificationString(), allowUnicode,
                                             new AsyncCallback(SendMailCallback), result.AsyncState);
                }
            }
            catch (Exception e)
            {
                Complete(e, result);
            }

            if (GlobalLog.IsEnabled)
            {
                GlobalLog.Leave("SmtpClient#" + LoggingHash.HashString(this) + "::ConnectCallback");
            }
        }
示例#9
0
        // Server API

        internal static WebHeaderCollection GetHeaders(byte[] memoryBlob, IntPtr originalAddress)
        {
            GlobalLog.Enter("HttpApi::GetHeaders()");

            // Return value.
            WebHeaderCollection headerCollection = new WebHeaderCollection(WebHeaderCollectionType.HttpListenerRequest);

            fixed(byte *pMemoryBlob = memoryBlob)
            {
                HTTP_REQUEST *request = (HTTP_REQUEST *)pMemoryBlob;
                long          fixup   = pMemoryBlob - (byte *)originalAddress;
                int           index;

                // unknown headers
                if (request->Headers.UnknownHeaderCount != 0)
                {
                    HTTP_UNKNOWN_HEADER *pUnknownHeader = (HTTP_UNKNOWN_HEADER *)(fixup + (byte *)request->Headers.pUnknownHeaders);
                    for (index = 0; index < request->Headers.UnknownHeaderCount; index++)
                    {
                        // For unknown headers, when header value is empty, RawValueLength will be 0 and
                        // pRawValue will be null.
                        if (pUnknownHeader->pName != null && pUnknownHeader->NameLength > 0)
                        {
                            string headerName = new string(pUnknownHeader->pName + fixup, 0, pUnknownHeader->NameLength);
                            string headerValue;
                            if (pUnknownHeader->pRawValue != null && pUnknownHeader->RawValueLength > 0)
                            {
                                headerValue = new string(pUnknownHeader->pRawValue + fixup, 0, pUnknownHeader->RawValueLength);
                            }
                            else
                            {
                                headerValue = string.Empty;
                            }
                            headerCollection.AddInternal(headerName, headerValue);
                        }
                        pUnknownHeader++;
                    }
                }

                // known headers
                HTTP_KNOWN_HEADER *pKnownHeader = &request->Headers.KnownHeaders;

                for (index = 0; index < HttpHeaderRequestMaximum; index++)
                {
                    // For known headers, when header value is empty, RawValueLength will be 0 and
                    // pRawValue will point to empty string ("\0")
                    if (pKnownHeader->pRawValue != null)
                    {
                        string headerValue = new string(pKnownHeader->pRawValue + fixup, 0, pKnownHeader->RawValueLength);
                        headerCollection.AddInternal(HTTP_REQUEST_HEADER_ID.ToString(index), headerValue);
                    }
                    pKnownHeader++;
                }
            }

            GlobalLog.Leave("HttpApi::GetHeaders()");
            return(headerCollection);
        }
示例#10
0
        /*++
         *  Encrypt - Encrypts our bytes before we send them over the wire
         *
         *  PERF: make more efficient, this does an extra copy when the offset
         *  is non-zero.
         *
         *  Input:
         *      buffer - bytes for sending
         *      offset -
         *      size   -
         *      output - Encrypted bytes
         * --*/
        internal SecurityStatusPal Encrypt(byte[] buffer, int offset, int size, ref byte[] output, out int resultSize)
        {
            GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::Encrypt");
            GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::Encrypt() - offset: " + offset.ToString() + " size: " + size.ToString() + " buffersize: " + buffer.Length.ToString());
            GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::Encrypt() buffer:");
            GlobalLog.Dump(buffer, Math.Min(buffer.Length, 128));

            byte[] writeBuffer;
            try
            {
                if (offset < 0 || offset > (buffer == null ? 0 : buffer.Length))
                {
                    throw new ArgumentOutOfRangeException("offset");
                }

                if (size < 0 || size > (buffer == null ? 0 : buffer.Length - offset))
                {
                    throw new ArgumentOutOfRangeException("size");
                }

                resultSize = 0;

                int bufferSizeNeeded = checked (size + _headerSize + _trailerSize);
                if (output != null && bufferSizeNeeded <= output.Length)
                {
                    writeBuffer = output;
                }
                else
                {
                    writeBuffer = new byte[bufferSizeNeeded];
                }

                Buffer.BlockCopy(buffer, offset, writeBuffer, _headerSize, size);
            }
            catch (Exception e)
            {
                if (!ExceptionCheck.IsFatal(e))
                {
                    GlobalLog.Assert(false, "SecureChannel#" + Logging.HashString(this) + "::Encrypt", "Arguments out of range.");
                }

                throw;
            }

            SecurityStatusPal secStatus = SslStreamPal.EncryptMessage(_securityContext, writeBuffer, size, _headerSize, _trailerSize, out resultSize);

            if (secStatus != SecurityStatusPal.OK)
            {
                GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::Encrypt ERROR", secStatus.ToString());
            }
            else
            {
                output = writeBuffer;
                GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::Encrypt OK", "data size:" + resultSize.ToString());
            }

            return(secStatus);
        }
示例#11
0
        internal static uint GetChunks(byte[] memoryBlob, IntPtr originalAddress, ref int dataChunkIndex, ref uint dataChunkOffset, byte[] buffer, int offset, int size)
        {
            GlobalLog.Enter("HttpApi::GetChunks() memoryBlob:" + ValidationHelper.ToString(memoryBlob));

            // Return value.
            uint dataRead = 0;

            fixed(byte *pMemoryBlob = memoryBlob)
            {
                HTTP_REQUEST *request = (HTTP_REQUEST *)pMemoryBlob;
                long          fixup   = pMemoryBlob - (byte *)originalAddress;

                if (request->EntityChunkCount > 0 && dataChunkIndex < request->EntityChunkCount && dataChunkIndex != -1)
                {
                    HTTP_DATA_CHUNK *pDataChunk = (HTTP_DATA_CHUNK *)(fixup + (byte *)&request->pEntityChunks[dataChunkIndex]);

                    fixed(byte *pReadBuffer = buffer)
                    {
                        byte *pTo = &pReadBuffer[offset];

                        while (dataChunkIndex < request->EntityChunkCount && dataRead < size)
                        {
                            if (dataChunkOffset >= pDataChunk->BufferLength)
                            {
                                dataChunkOffset = 0;
                                dataChunkIndex++;
                                pDataChunk++;
                            }
                            else
                            {
                                byte *pFrom = pDataChunk->pBuffer + dataChunkOffset + fixup;

                                uint bytesToRead = pDataChunk->BufferLength - (uint)dataChunkOffset;
                                if (bytesToRead > (uint)size)
                                {
                                    bytesToRead = (uint)size;
                                }
                                for (uint i = 0; i < bytesToRead; i++)
                                {
                                    *(pTo++) = *(pFrom++);
                                }
                                dataRead        += bytesToRead;
                                dataChunkOffset += bytesToRead;
                            }
                        }
                    }
                }
                //we're finished.
                if (dataChunkIndex == request->EntityChunkCount)
                {
                    dataChunkIndex = -1;
                }
            }

            GlobalLog.Leave("HttpApi::GetChunks()");
            return(dataRead);
        }
示例#12
0
        private void Complete(Exception exception, IAsyncResult result)
        {
            ContextAwareResult operationCompletedResult = (ContextAwareResult)result.AsyncState;

            if (GlobalLog.IsEnabled)
            {
                GlobalLog.Enter("SmtpClient#" + LoggingHash.HashString(this) + "::Complete");
            }
            try
            {
                if (_cancelled)
                {
                    //any exceptions were probably caused by cancellation, clear it.
                    exception = null;
                    Abort();
                }
                // An individual failed recipient exception is benign, only abort here if ALL the recipients failed.
                else if (exception != null && (!(exception is SmtpFailedRecipientException) || ((SmtpFailedRecipientException)exception).fatal))
                {
                    if (GlobalLog.IsEnabled)
                    {
                        GlobalLog.Print("SmtpClient#" + LoggingHash.HashString(this) + "::Complete Exception: " + exception.ToString());
                    }
                    Abort();

                    if (!(exception is SmtpException))
                    {
                        exception = new SmtpException(SR.SmtpSendMailFailure, exception);
                    }
                }
                else
                {
                    if (_writer != null)
                    {
                        try
                        {
                            _writer.Close();
                        }
                        // Close may result in a DataStopCommand and the server may return error codes at this time.
                        catch (SmtpException se)
                        {
                            exception = se;
                        }
                    }
                    _transport.ReleaseConnection();
                }
            }
            finally
            {
                operationCompletedResult.InvokeCallback(exception);
            }

            if (GlobalLog.IsEnabled)
            {
                GlobalLog.Leave("SmtpClient#" + LoggingHash.HashString(this) + "::Complete");
            }
        }
 internal void EndGetConnection(IAsyncResult result)
 {
     GlobalLog.Enter("SmtpTransport#" + ValidationHelper.HashString(this) + "::EndGetConnection");
     try {
         connection.EndGetConnection(result);
     }
     finally {
         GlobalLog.Leave("SmtpTransport#" + ValidationHelper.HashString(this) + "::EndConnect");
     }
 }
示例#14
0
            private static void ConnectionCreatedCallback(object request, object state)
            {
                GlobalLog.Enter("ConnectAndHandshakeAsyncResult#" + ValidationHelper.HashString(request) + "::ConnectionCreatedCallback");
                ConnectAndHandshakeAsyncResult ConnectAndHandshakeAsyncResult = (ConnectAndHandshakeAsyncResult)request;

                if (state is Exception)
                {
                    ConnectAndHandshakeAsyncResult.InvokeCallback((Exception)state);
                    return;
                }
                SmtpPooledStream pooledStream = (SmtpPooledStream)(PooledStream)state;


                try
                {
                    while (pooledStream.creds != null && pooledStream.creds != ConnectAndHandshakeAsyncResult.connection.credentials)
                    {
                        GlobalLog.Print("ConnectAndHandshakeAsyncResult#" + ValidationHelper.HashString(request) + "::Connect pooledStream has wrong creds " + ValidationHelper.HashString(pooledStream));
                        ConnectAndHandshakeAsyncResult.connection.connectionPool.PutConnection(pooledStream,
                                                                                               pooledStream.Owner, ConnectAndHandshakeAsyncResult.connection.Timeout, false);
                        pooledStream = (SmtpPooledStream)ConnectAndHandshakeAsyncResult.connection.connectionPool.GetConnection((object)ConnectAndHandshakeAsyncResult, ConnectAndHandshakeAsyncResult.m_ConnectionCreatedCallback, ConnectAndHandshakeAsyncResult.connection.Timeout);
                        if (pooledStream == null)
                        {
                            GlobalLog.Leave("ConnectAndHandshakeAsyncResult#" + ValidationHelper.HashString(request) + "::Connect returning asynchronously");
                            return;
                        }
                    }
                    if (Logging.On)
                    {
                        Logging.Associate(Logging.Web, ConnectAndHandshakeAsyncResult.connection, pooledStream);
                    }
                    pooledStream.Owner = ConnectAndHandshakeAsyncResult.connection; //needs to be updated for gc reasons
                    pooledStream.creds = ConnectAndHandshakeAsyncResult.connection.credentials;


                    lock (ConnectAndHandshakeAsyncResult.connection) {
                        //if we were cancelled while getting the connection, we should close and return
                        if (ConnectAndHandshakeAsyncResult.connection.isClosed)
                        {
                            ConnectAndHandshakeAsyncResult.connection.connectionPool.PutConnection(pooledStream, pooledStream.Owner, ConnectAndHandshakeAsyncResult.connection.Timeout, false);
                            GlobalLog.Print("ConnectAndHandshakeAsyncResult#" + ValidationHelper.HashString(request) + "::ConnectionCreatedCallback Connect was aborted " + ValidationHelper.HashString(pooledStream));
                            ConnectAndHandshakeAsyncResult.InvokeCallback(null);
                            return;
                        }
                        ConnectAndHandshakeAsyncResult.connection.pooledStream = pooledStream;
                    }

                    ConnectAndHandshakeAsyncResult.Handshake();
                }
                catch (Exception e)
                {
                    ConnectAndHandshakeAsyncResult.InvokeCallback(e);
                }
                GlobalLog.Leave("ConnectAndHandshakeAsyncResult#" + ValidationHelper.HashString(request) + "::ConnectionCreatedCallback pooledStream#" + ValidationHelper.HashString(pooledStream));
            }
示例#15
0
 void SendMessageCallback(IAsyncResult result)
 {
     GlobalLog.Enter("SmtpClient#" + ValidationHelper.HashString(this) + "::SendMessageCallback");
     try {
         message.EndSend(result);
         // If some recipients failed but not others, throw AFTER sending the message.
         Complete(failedRecipientException, result);
     }
     catch (Exception e) {
         Complete(e, result);
     }
     GlobalLog.Leave("SmtpClient#" + ValidationHelper.HashString(this) + "::SendMessageCallback");
 }
示例#16
0
        internal ChannelBinding GetChannelBinding(ChannelBindingKind kind)
        {
            GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::GetChannelBindingToken", kind.ToString());

            ChannelBinding result = null;

            if (_securityContext != null)
            {
                result = SslStreamPal.QueryContextChannelBinding(_securityContext, kind);
            }

            GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::GetChannelBindingToken", Logging.HashString(result));
            return(result);
        }
示例#17
0
        private unsafe static string GetVerb(HTTP_REQUEST *request, long fixup)
        {
            GlobalLog.Enter("HttpApi::GetVerb()");
            string verb = null;

            if ((int)request->Verb > (int)HTTP_VERB.HttpVerbUnknown && (int)request->Verb < (int)HTTP_VERB.HttpVerbMaximum)
            {
                verb = HttpVerbs[(int)request->Verb];
            }
            else if (request->Verb == HTTP_VERB.HttpVerbUnknown && request->pUnknownVerb != null)
            {
                verb = new string(request->pUnknownVerb + fixup, 0, request->UnknownVerbLength);
            }

            GlobalLog.Leave("HttpApi::GetVerb() return:" + ValidationHelper.ToString(verb));
            return(verb);
        }
示例#18
0
        //
        internal ProtocolToken NextMessage(byte[] incoming, int offset, int count)
        {
            GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::NextMessage");
            byte[]            nextmsg   = null;
            SecurityStatusPal errorCode = GenerateToken(incoming, offset, count, ref nextmsg);

            if (!_serverMode && errorCode == SecurityStatusPal.CredentialsNeeded)
            {
                GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::NextMessage() returned SecurityStatusPal.CredentialsNeeded");
                SetRefreshCredentialNeeded();
                errorCode = GenerateToken(incoming, offset, count, ref nextmsg);
            }

            ProtocolToken token = new ProtocolToken(nextmsg, errorCode);

            GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::NextMessage", token.ToString());
            return(token);
        }
示例#19
0
 internal void EndGetConnection(IAsyncResult result)
 {
     if (GlobalLog.IsEnabled)
     {
         GlobalLog.Enter("SmtpTransport#" + LoggingHash.HashString(this) + "::EndGetConnection");
     }
     try
     {
         _connection.EndGetConnection(result);
     }
     finally
     {
         if (GlobalLog.IsEnabled)
         {
             GlobalLog.Leave("SmtpTransport#" + LoggingHash.HashString(this) + "::EndConnect");
         }
     }
 }
示例#20
0
        private static string GetKnownHeader(HTTP_REQUEST *request, long fixup, int headerIndex)
        {
            GlobalLog.Enter("HttpApi::GetKnownHeader()");
            string header = null;

            HTTP_KNOWN_HEADER *pKnownHeader = (&request->Headers.KnownHeaders) + headerIndex;

            GlobalLog.Print("HttpApi::GetKnownHeader() pKnownHeader:0x" + ((IntPtr)pKnownHeader).ToString("x"));
            GlobalLog.Print("HttpApi::GetKnownHeader() pRawValue:0x" + ((IntPtr)pKnownHeader->pRawValue).ToString("x") + " RawValueLength:" + pKnownHeader->RawValueLength.ToString());
            // For known headers, when header value is empty, RawValueLength will be 0 and
            // pRawValue will point to empty string ("\0")
            if (pKnownHeader->pRawValue != null)
            {
                header = new string(pKnownHeader->pRawValue + fixup, 0, pKnownHeader->RawValueLength);
            }

            GlobalLog.Leave("HttpApi::GetKnownHeader() return:" + ValidationHelper.ToString(header));
            return(header);
        }
示例#21
0
            private static void ConnectionCreatedCallback(object request, object state)
            {
                if (GlobalLog.IsEnabled)
                {
                    GlobalLog.Enter("ConnectAndHandshakeAsyncResult#" + LoggingHash.HashString(request) + "::ConnectionCreatedCallback");
                }
                ConnectAndHandshakeAsyncResult ConnectAndHandshakeAsyncResult = (ConnectAndHandshakeAsyncResult)request;

                if (state is Exception)
                {
                    ConnectAndHandshakeAsyncResult.InvokeCallback((Exception)state);
                    return;
                }

                try
                {
                    lock (ConnectAndHandshakeAsyncResult._connection)
                    {
                        //if we were cancelled while getting the connection, we should close and return
                        if (ConnectAndHandshakeAsyncResult._connection._isClosed)
                        {
                            ConnectAndHandshakeAsyncResult._connection.ReleaseConnection();
                            if (GlobalLog.IsEnabled)
                            {
                                GlobalLog.Print("ConnectAndHandshakeAsyncResult#" + LoggingHash.HashString(request) + "::ConnectionCreatedCallback Connect was aborted ");
                            }
                            ConnectAndHandshakeAsyncResult.InvokeCallback(null);
                            return;
                        }
                    }

                    ConnectAndHandshakeAsyncResult.Handshake();
                }
                catch (Exception e)
                {
                    ConnectAndHandshakeAsyncResult.InvokeCallback(e);
                }

                if (GlobalLog.IsEnabled)
                {
                    GlobalLog.Leave("ConnectAndHandshakeAsyncResult#" + LoggingHash.HashString(request) + "::ConnectionCreatedCallback");
                }
            }
示例#22
0
            internal void GetConnection(bool synchronous)
            {
                GlobalLog.Enter("ConnectAndHandshakeAsyncResult#" + ValidationHelper.HashString(this) + "::Connect: [....]=" + (synchronous ? "true" : "false"));
                if (connection.isConnected)
                {
                    throw new InvalidOperationException(SR.GetString(SR.SmtpAlreadyConnected));
                }


                SmtpPooledStream pooledStream = (SmtpPooledStream)connection.connectionPool.GetConnection((object)this, (synchronous ? null : m_ConnectionCreatedCallback), connection.Timeout);

                GlobalLog.Print("ConnectAndHandshakeAsyncResult#" + ValidationHelper.HashString(this) + "::Connect returned" + ValidationHelper.HashString(this));

                if (pooledStream != null)
                {
                    try
                    {
                        while (pooledStream.creds != null && pooledStream.creds != connection.credentials)
                        {
                            GlobalLog.Print("ConnectAndHandshakeAsyncResult#" + ValidationHelper.HashString(this) + "::Connect pooledStream has wrong creds " + ValidationHelper.HashString(pooledStream));
                            connection.connectionPool.PutConnection(pooledStream, pooledStream.Owner, connection.Timeout, false);
                            pooledStream = (SmtpPooledStream)connection.connectionPool.GetConnection((object)this, (synchronous ? null : m_ConnectionCreatedCallback), connection.Timeout);
                            if (pooledStream == null)
                            {
                                GlobalLog.Leave("ConnectAndHandshakeAsyncResult#" + ValidationHelper.HashString(this) + "::Connect returning asynchronously");
                                return;
                            }
                        }
                        pooledStream.creds = connection.credentials;
                        pooledStream.Owner = this.connection; //needs to be updated for gc reasons

                        lock (connection) {
                            connection.pooledStream = pooledStream;
                        }
                        Handshake();
                    }
                    catch (Exception e)
                    {
                        InvokeCallback(e);
                    }
                }
                GlobalLog.Leave("ConnectAndHandshakeAsyncResult#" + ValidationHelper.HashString(this) + "::Connect pooledStream#" + ValidationHelper.HashString(pooledStream));
            }
示例#23
0
        internal static HTTP_VERB GetKnownVerb(byte[] memoryBlob, IntPtr originalAddress)
        {
            GlobalLog.Enter("HttpApi::GetKnownVerb()");

            // Return value.
            HTTP_VERB verb = HTTP_VERB.HttpVerbUnknown;

            fixed(byte *pMemoryBlob = memoryBlob)
            {
                HTTP_REQUEST *request = (HTTP_REQUEST *)pMemoryBlob;

                if ((int)request->Verb > (int)HTTP_VERB.HttpVerbUnparsed && (int)request->Verb < (int)HTTP_VERB.HttpVerbMaximum)
                {
                    verb = request->Verb;
                }
            }

            GlobalLog.Leave("HttpApi::GetKnownVerb()");
            return(verb);
        }
示例#24
0
 private void SendMessageCallback(IAsyncResult result)
 {
     if (GlobalLog.IsEnabled)
     {
         GlobalLog.Enter("SmtpClient#" + LoggingHash.HashString(this) + "::SendMessageCallback");
     }
     try
     {
         _message.EndSend(result);
         // If some recipients failed but not others, throw AFTER sending the message.
         Complete(_failedRecipientException, result);
     }
     catch (Exception e)
     {
         Complete(e, result);
     }
     if (GlobalLog.IsEnabled)
     {
         GlobalLog.Leave("SmtpClient#" + LoggingHash.HashString(this) + "::SendMessageCallback");
     }
 }
示例#25
0
        public void SendAsyncCancel()
        {
            if (_disposed)
            {
                throw new ObjectDisposedException(GetType().FullName);
            }
            if (NetEventSource.Log.IsEnabled())
            {
                NetEventSource.Enter(NetEventSource.ComponentType.Web, this, "SendAsyncCancel", null);
            }

            if (GlobalLog.IsEnabled)
            {
                GlobalLog.Enter("SmtpClient#" + LoggingHash.HashString(this) + "::SendAsyncCancel");
            }

            try
            {
                if (!InCall || _cancelled)
                {
                    return;
                }

                _cancelled = true;
                Abort();
            }
            finally
            {
                if (NetEventSource.Log.IsEnabled())
                {
                    NetEventSource.Exit(NetEventSource.ComponentType.Web, this, "SendAsyncCancel", null);
                }
                if (GlobalLog.IsEnabled)
                {
                    GlobalLog.Leave("SmtpClient#" + LoggingHash.HashString(this) + "::SendAsyncCancel");
                }
            }
        }
示例#26
0
        /*++
         *  GenerateToken - Called after each successive state
         *  in the Client - Server handshake.  This function
         *  generates a set of bytes that will be sent next to
         *  the server.  The server responds, each response,
         *  is pass then into this function, again, and the cycle
         *  repeats until successful connection, or failure.
         *
         *  Input:
         *      input  - bytes from the wire
         *      output - ref to byte [], what we will send to the
         *          server in response
         *  Return:
         *      errorCode - an SSPI error code
         * --*/
        private SecurityStatusPal GenerateToken(byte[] input, int offset, int count, ref byte[] output)
        {
#if TRACE_VERBOSE
            GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::GenerateToken, _refreshCredentialNeeded = " + _refreshCredentialNeeded);
#endif

            if (offset < 0 || offset > (input == null ? 0 : input.Length))
            {
                GlobalLog.Assert(false, "SecureChannel#" + Logging.HashString(this) + "::GenerateToken", "Argument 'offset' out of range.");
                throw new ArgumentOutOfRangeException("offset");
            }

            if (count < 0 || count > (input == null ? 0 : input.Length - offset))
            {
                GlobalLog.Assert(false, "SecureChannel#" + Logging.HashString(this) + "::GenerateToken", "Argument 'count' out of range.");
                throw new ArgumentOutOfRangeException("count");
            }

            SecurityBuffer   incomingSecurity        = null;
            SecurityBuffer[] incomingSecurityBuffers = null;

            if (input != null)
            {
                incomingSecurity        = new SecurityBuffer(input, offset, count, SecurityBufferType.Token);
                incomingSecurityBuffers = new SecurityBuffer[]
                {
                    incomingSecurity,
                    new SecurityBuffer(null, 0, 0, SecurityBufferType.Empty)
                };
            }

            SecurityBuffer outgoingSecurity = new SecurityBuffer(null, SecurityBufferType.Token);

            SecurityStatusPal errorCode = 0;

            bool   cachedCreds = false;
            byte[] thumbPrint  = null;

            //
            // Looping through ASC or ISC with potentially cached credential that could have been
            // already disposed from a different thread before ISC or ASC dir increment a cred ref count.
            //
            try
            {
                do
                {
                    thumbPrint = null;
                    if (_refreshCredentialNeeded)
                    {
                        cachedCreds = _serverMode
                                        ? AcquireServerCredentials(ref thumbPrint)
                                        : AcquireClientCredentials(ref thumbPrint);
                    }

                    if (_serverMode)
                    {
                        errorCode = SslStreamPal.AcceptSecurityContext(
                            ref _credentialsHandle,
                            ref _securityContext,
                            incomingSecurity,
                            outgoingSecurity,
                            _remoteCertRequired);
                    }
                    else
                    {
                        if (incomingSecurity == null)
                        {
                            errorCode = SslStreamPal.InitializeSecurityContext(
                                ref _credentialsHandle,
                                ref _securityContext,
                                _destination,
                                incomingSecurity,
                                outgoingSecurity);
                        }
                        else
                        {
                            errorCode = SslStreamPal.InitializeSecurityContext(
                                _credentialsHandle,
                                ref _securityContext,
                                _destination,
                                incomingSecurityBuffers,
                                outgoingSecurity);
                        }
                    }
                } while (cachedCreds && _credentialsHandle == null);
            }
            finally
            {
                if (_refreshCredentialNeeded)
                {
                    _refreshCredentialNeeded = false;

                    //
                    // Assuming the ISC or ASC has referenced the credential,
                    // we want to call dispose so to decrement the effective ref count.
                    //
                    if (_credentialsHandle != null)
                    {
                        _credentialsHandle.Dispose();
                    }

                    //
                    // This call may bump up the credential reference count further.
                    // Note that thumbPrint is retrieved from a safe cert object that was possible cloned from the user passed cert.
                    //
                    if (!cachedCreds && _securityContext != null && !_securityContext.IsInvalid && _credentialsHandle != null && !_credentialsHandle.IsInvalid)
                    {
                        SslSessionsCache.CacheCredential(_credentialsHandle, thumbPrint, _sslProtocols, _serverMode, _encryptionPolicy);
                    }
                }
            }

            output = outgoingSecurity.token;

#if TRACE_VERBOSE
            GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::GenerateToken()", Interop.MapSecurityStatus((uint)errorCode));
#endif
            return((SecurityStatusPal)errorCode);
        }
示例#27
0
        /*++
         *  VerifyRemoteCertificate - Validates the content of a Remote Certificate
         *
         *  checkCRL if true, checks the certificate revocation list for validity.
         *  checkCertName, if true checks the CN field of the certificate
         * --*/

        //This method validates a remote certificate.
        //SECURITY: The scenario is allowed in semitrust StorePermission is asserted for Chain.Build
        //          A user callback has unique signature so it is safe to call it under permission assert.
        //
        internal bool VerifyRemoteCertificate(RemoteCertValidationCallback remoteCertValidationCallback)
        {
            GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::VerifyRemoteCertificate");
            SslPolicyErrors sslPolicyErrors = SslPolicyErrors.None;

            // We don't catch exceptions in this method, so it's safe for "accepted" be initialized with true.
            bool             success             = false;
            X509Chain        chain               = null;
            X509Certificate2 remoteCertificateEx = null;

            try
            {
                X509Certificate2Collection remoteCertificateStore;
                remoteCertificateEx           = CertificateValidationPal.GetRemoteCertificate(_securityContext, out remoteCertificateStore);
                _isRemoteCertificateAvailable = remoteCertificateEx != null;

                if (remoteCertificateEx == null)
                {
                    GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::VerifyRemoteCertificate (no remote cert)", (!_remoteCertRequired).ToString());
                    sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNotAvailable;
                }
                else
                {
                    chain = new X509Chain();
                    chain.ChainPolicy.RevocationMode = _checkCertRevocation ? X509RevocationMode.Online : X509RevocationMode.NoCheck;
                    chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot;
                    if (remoteCertificateStore != null)
                    {
                        chain.ChainPolicy.ExtraStore.AddRange(remoteCertificateStore);
                    }

                    sslPolicyErrors |= CertificateValidationPal.VerifyCertificateProperties(
                        chain,
                        remoteCertificateEx,
                        _checkCertName,
                        _serverMode,
                        _hostName);
                }

                if (remoteCertValidationCallback != null)
                {
                    success = remoteCertValidationCallback(_hostName, remoteCertificateEx, chain, sslPolicyErrors);
                }
                else
                {
                    if (sslPolicyErrors == SslPolicyErrors.RemoteCertificateNotAvailable && !_remoteCertRequired)
                    {
                        success = true;
                    }
                    else
                    {
                        success = (sslPolicyErrors == SslPolicyErrors.None);
                    }
                }

                if (Logging.On)
                {
                    if (sslPolicyErrors != SslPolicyErrors.None)
                    {
                        Logging.PrintInfo(Logging.Web, this, SR.net_log_remote_cert_has_errors);
                        if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateNotAvailable) != 0)
                        {
                            Logging.PrintInfo(Logging.Web, this, "\t" + SR.net_log_remote_cert_not_available);
                        }

                        if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateNameMismatch) != 0)
                        {
                            Logging.PrintInfo(Logging.Web, this, "\t" + SR.net_log_remote_cert_name_mismatch);
                        }

                        if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateChainErrors) != 0)
                        {
                            foreach (X509ChainStatus chainStatus in chain.ChainStatus)
                            {
                                Logging.PrintInfo(Logging.Web, this, "\t" + chainStatus.StatusInformation);
                            }
                        }
                    }
                    if (success)
                    {
                        if (remoteCertValidationCallback != null)
                        {
                            Logging.PrintInfo(Logging.Web, this, SR.net_log_remote_cert_user_declared_valid);
                        }
                        else
                        {
                            Logging.PrintInfo(Logging.Web, this, SR.net_log_remote_cert_has_no_errors);
                        }
                    }
                    else
                    {
                        if (remoteCertValidationCallback != null)
                        {
                            Logging.PrintInfo(Logging.Web, this, SR.net_log_remote_cert_user_declared_invalid);
                        }
                    }
                }
                GlobalLog.Print("Cert Validation, remote cert = " + (remoteCertificateEx == null ? "<null>" : remoteCertificateEx.ToString(true)));
            }
            finally
            {
                // At least on Win2k server the chain is found to have dependencies on the original cert context.
                // So it should be closed first.
                if (chain != null)
                {
                    chain.Dispose();
                }

                if (remoteCertificateEx != null)
                {
                    remoteCertificateEx.Dispose();
                }
            }
            GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::VerifyRemoteCertificate", success.ToString());
            return(success);
        }
示例#28
0
        /*++
         *  AcquireCredentials - Attempts to find Client Credential
         *  Information, that can be sent to the server.  In our case,
         *  this is only Client Certificates, that we have Credential Info.
         *
         *  How it works:
         *      case 0: Cert Selection delegate is present
         *              Always use its result as the client cert answer.
         *              Try to use cached credential handle whenever feasible.
         *              Do not use cached anonymous creds if the delegate has returned null
         *              and the collection is not empty (allow responding with the cert later).
         *
         *      case 1: Certs collection is empty
         *              Always use the same statically acquired anonymous SSL Credential
         *
         *      case 2: Before our Connection with the Server
         *              If we have a cached credential handle keyed by first X509Certificate
         **content** in the passed collection, then we use that cached
         *              credential and hoping to restart a session.
         *
         *              Otherwise create a new anonymous (allow responding with the cert later).
         *
         *      case 3: After our Connection with the Server (i.e. during handshake or re-handshake)
         *              The server has requested that we send it a Certificate then
         *              we Enumerate a list of server sent Issuers trying to match against
         *              our list of Certificates, the first match is sent to the server.
         *
         *              Once we got a cert we again try to match cached credential handle if possible.
         *              This will not restart a session but helps minimizing the number of handles we create.
         *
         *      In the case of an error getting a Certificate or checking its private Key we fall back
         *      to the behavior of having no certs, case 1.
         *
         *  Returns: True if cached creds were used, false otherwise.
         *
         * --*/

        private bool AcquireClientCredentials(ref byte[] thumbPrint)
        {
            GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials");

            // Acquire possible Client Certificate information and set it on the handle.
            X509Certificate clientCertificate = null;            // This is a candidate that can come from the user callback or be guessed when targeting a session restart.
            ArrayList       filteredCerts     = new ArrayList(); // This is an intermediate client certs collection that try to use if no selectedCert is available yet.

            string[] issuers = null;                             // This is a list of issuers sent by the server, only valid is we do know what the server cert is.

            bool sessionRestartAttempt = false;                  // If true and no cached creds we will use anonymous creds.

            if (_certSelectionDelegate != null)
            {
                issuers = GetRequestCertificateAuthorities();

                GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials() calling CertificateSelectionCallback");

                X509Certificate2 remoteCert = null;
                try
                {
                    X509Certificate2Collection dummyCollection;
                    remoteCert        = CertificateValidationPal.GetRemoteCertificate(_securityContext, out dummyCollection);
                    clientCertificate = _certSelectionDelegate(_hostName, ClientCertificates, remoteCert, issuers);
                }
                finally
                {
                    if (remoteCert != null)
                    {
                        remoteCert.Dispose();
                    }
                }


                if (clientCertificate != null)
                {
                    if (_credentialsHandle == null)
                    {
                        sessionRestartAttempt = true;
                    }

                    filteredCerts.Add(clientCertificate);
                    if (Logging.On)
                    {
                        Logging.PrintInfo(Logging.Web, this, SR.net_log_got_certificate_from_delegate);
                    }
                }
                else
                {
                    if (ClientCertificates.Count == 0)
                    {
                        if (Logging.On)
                        {
                            Logging.PrintInfo(Logging.Web, this, SR.net_log_no_delegate_and_have_no_client_cert);
                        }

                        sessionRestartAttempt = true;
                    }
                    else
                    {
                        if (Logging.On)
                        {
                            Logging.PrintInfo(Logging.Web, this, SR.net_log_no_delegate_but_have_client_cert);
                        }
                    }
                }
            }
            else if (_credentialsHandle == null && _clientCertificates != null && _clientCertificates.Count > 0)
            {
                // This is where we attempt to restart a session by picking the FIRST cert from the collection.
                // Otherwise it is either server sending a client cert request or the session is renegotiated.
                clientCertificate     = ClientCertificates[0];
                sessionRestartAttempt = true;
                if (clientCertificate != null)
                {
                    filteredCerts.Add(clientCertificate);
                }

                if (Logging.On)
                {
                    Logging.PrintInfo(Logging.Web, this, SR.Format(SR.net_log_attempting_restart_using_cert, (clientCertificate == null ? "null" : clientCertificate.ToString(true))));
                }
            }
            else if (_clientCertificates != null && _clientCertificates.Count > 0)
            {
                //
                // This should be a server request for the client cert sent over currently anonymous sessions.
                //
                issuers = GetRequestCertificateAuthorities();

                if (Logging.On)
                {
                    if (issuers == null || issuers.Length == 0)
                    {
                        Logging.PrintInfo(Logging.Web, this, SR.net_log_no_issuers_try_all_certs);
                    }
                    else
                    {
                        Logging.PrintInfo(Logging.Web, this, SR.Format(SR.net_log_server_issuers_look_for_matching_certs, issuers.Length));
                    }
                }

                for (int i = 0; i < _clientCertificates.Count; ++i)
                {
                    //
                    // Make sure we add only if the cert matches one of the issuers.
                    // If no issuers were sent and then try all client certs starting with the first one.
                    //
                    if (issuers != null && issuers.Length != 0)
                    {
                        X509Certificate2 certificateEx = null;
                        X509Chain        chain         = null;
                        try
                        {
                            certificateEx = MakeEx(_clientCertificates[i]);
                            if (certificateEx == null)
                            {
                                continue;
                            }

                            GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials() root cert:" + certificateEx.Issuer);
                            chain = new X509Chain();

                            chain.ChainPolicy.RevocationMode    = X509RevocationMode.NoCheck;
                            chain.ChainPolicy.VerificationFlags = X509VerificationFlags.IgnoreInvalidName;
                            chain.Build(certificateEx);
                            bool found = false;

                            //
                            // We ignore any errors happened with chain.
                            //
                            if (chain.ChainElements.Count > 0)
                            {
                                for (int ii = 0; ii < chain.ChainElements.Count; ++ii)
                                {
                                    string issuer = chain.ChainElements[ii].Certificate.Issuer;
                                    found = Array.IndexOf(issuers, issuer) != -1;
                                    if (found)
                                    {
                                        GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials() matched:" + issuer);
                                        break;
                                    }
                                    GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials() no match:" + issuer);
                                }
                            }

                            if (!found)
                            {
                                continue;
                            }
                        }
                        finally
                        {
                            if (chain != null)
                            {
                                chain.Dispose();
                            }

                            if (certificateEx != null && (object)certificateEx != (object)_clientCertificates[i])
                            {
                                certificateEx.Dispose();
                            }
                        }
                    }

                    if (Logging.On)
                    {
                        Logging.PrintInfo(Logging.Web, this, SR.Format(SR.net_log_selected_cert, _clientCertificates[i].ToString(true)));
                    }

                    filteredCerts.Add(_clientCertificates[i]);
                }
            }

            bool             cachedCred   = false;     // This is a return result from this method.
            X509Certificate2 selectedCert = null;      // This is a final selected cert (ensured that it does have private key with it).

            clientCertificate = null;

            if (Logging.On)
            {
                Logging.PrintInfo(Logging.Web, this, SR.Format(SR.net_log_n_certs_after_filtering, filteredCerts.Count));
                if (filteredCerts.Count != 0)
                {
                    Logging.PrintInfo(Logging.Web, this, SR.net_log_finding_matching_certs);
                }
            }

            //
            // ATTN: When the client cert was returned by the user callback OR it was guessed AND it has no private key,
            //       THEN anonymous (no client cert) credential will be used.
            //
            // SECURITY: Accessing X509 cert Credential is disabled for semitrust.
            // We no longer need to demand for unmanaged code permissions.
            // EnsurePrivateKey should do the right demand for us.
            for (int i = 0; i < filteredCerts.Count; ++i)
            {
                clientCertificate = filteredCerts[i] as X509Certificate;
                if ((selectedCert = EnsurePrivateKey(clientCertificate)) != null)
                {
                    break;
                }

                clientCertificate = null;
                selectedCert      = null;
            }

            GlobalLog.Assert(((object)clientCertificate == (object)selectedCert) || clientCertificate.Equals(selectedCert), "AcquireClientCredentials()|'selectedCert' does not match 'clientCertificate'.");

            GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials() Selected Cert = " + (selectedCert == null ? "null" : selectedCert.Subject));
            try
            {
                // Try to locate cached creds first.
                //
                // SECURITY: selectedCert ref if not null is a safe object that does not depend on possible **user** inherited X509Certificate type.
                //
                byte[] guessedThumbPrint = selectedCert == null ? null : selectedCert.GetCertHash();
                SafeFreeCredentials cachedCredentialHandle = SslSessionsCache.TryCachedCredential(guessedThumbPrint, _sslProtocols, _serverMode, _encryptionPolicy);

                // We can probably do some optimization here. If the selectedCert is returned by the delegate
                // we can always go ahead and use the certificate to create our credential
                // (instead of going anonymous as we do here).
                if (sessionRestartAttempt && cachedCredentialHandle == null && selectedCert != null)
                {
                    GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials() Reset to anonymous session.");

                    // IIS does not renegotiate a restarted session if client cert is needed.
                    // So we don't want to reuse **anonymous** cached credential for a new SSL connection if the client has passed some certificate.
                    // The following block happens if client did specify a certificate but no cached creds were found in the cache.
                    // Since we don't restart a session the server side can still challenge for a client cert.
                    if ((object)clientCertificate != (object)selectedCert)
                    {
                        selectedCert.Dispose();
                    }

                    guessedThumbPrint = null;
                    selectedCert      = null;
                    clientCertificate = null;
                }

                if (cachedCredentialHandle != null)
                {
                    if (Logging.On)
                    {
                        Logging.PrintInfo(Logging.Web, SR.net_log_using_cached_credential);
                    }

                    _credentialsHandle         = cachedCredentialHandle;
                    _selectedClientCertificate = clientCertificate;
                    cachedCred = true;
                }
                else
                {
                    _credentialsHandle = SslStreamPal.AcquireCredentialsHandle(selectedCert, _sslProtocols, _encryptionPolicy, _serverMode);

                    thumbPrint = guessedThumbPrint; // Delay until here in case something above threw.
                    _selectedClientCertificate = clientCertificate;
                }
            }
            finally
            {
                // An extra cert could have been created, dispose it now.
                if (selectedCert != null && (object)clientCertificate != (object)selectedCert)
                {
                    selectedCert.Dispose();
                }
            }

            GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials, cachedCreds = " + cachedCred.ToString(), Logging.ObjectToString(_credentialsHandle));
            return(cachedCred);
        }
示例#29
0
        //
        // Acquire Server Side Certificate information and set it on the class.
        //
        private bool AcquireServerCredentials(ref byte[] thumbPrint)
        {
            GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::AcquireServerCredentials");

            X509Certificate localCertificate = null;
            bool            cachedCred       = false;

            if (_certSelectionDelegate != null)
            {
                X509CertificateCollection tempCollection = new X509CertificateCollection();
                tempCollection.Add(_serverCertificate);
                localCertificate = _certSelectionDelegate(string.Empty, tempCollection, null, Array.Empty <string>());
                GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireServerCredentials() Use delegate selected Cert");
            }
            else
            {
                localCertificate = _serverCertificate;
            }

            if (localCertificate == null)
            {
                throw new NotSupportedException(SR.net_ssl_io_no_server_cert);
            }

            // SECURITY: Accessing X509 cert Credential is disabled for semitrust.
            // We no longer need to demand for unmanaged code permissions.
            // EnsurePrivateKey should do the right demand for us.
            X509Certificate2 selectedCert = EnsurePrivateKey(localCertificate);

            if (selectedCert == null)
            {
                throw new NotSupportedException(SR.net_ssl_io_no_server_cert);
            }

            GlobalLog.Assert(localCertificate.Equals(selectedCert), "AcquireServerCredentials()|'selectedCert' does not match 'localCertificate'.");

            //
            // Note selectedCert is a safe ref possibly cloned from the user passed Cert object
            //
            byte[] guessedThumbPrint = selectedCert.GetCertHash();
            try
            {
                SafeFreeCredentials cachedCredentialHandle = SslSessionsCache.TryCachedCredential(guessedThumbPrint, _sslProtocols, _serverMode, _encryptionPolicy);

                if (cachedCredentialHandle != null)
                {
                    _credentialsHandle = cachedCredentialHandle;
                    _serverCertificate = localCertificate;
                    cachedCred         = true;
                }
                else
                {
                    _credentialsHandle = SslStreamPal.AcquireCredentialsHandle(selectedCert, _sslProtocols, _encryptionPolicy, _serverMode);
                    thumbPrint         = guessedThumbPrint;
                    _serverCertificate = localCertificate;
                }
            }
            finally
            {
                // An extra cert could have been created, dispose it now.
                if ((object)localCertificate != (object)selectedCert)
                {
                    selectedCert.Dispose();
                }
            }

            GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::AcquireServerCredentials, cachedCreds = " + cachedCred.ToString(), Logging.ObjectToString(_credentialsHandle));
            return(cachedCred);
        }
示例#30
0
        public void SendAsync(MailMessage message, object userToken)
        {
            if (_disposed)
            {
                throw new ObjectDisposedException(GetType().FullName);
            }

            if (NetEventSource.Log.IsEnabled())
            {
                NetEventSource.Enter(NetEventSource.ComponentType.Web, this, "SendAsync", "DeliveryMethod=" + DeliveryMethod.ToString());
            }

            if (GlobalLog.IsEnabled)
            {
                GlobalLog.Enter("SmtpClient#" + LoggingHash.HashString(this) + "::SendAsync Transport#" + LoggingHash.HashString(_transport));
            }

            try
            {
                if (InCall)
                {
                    throw new InvalidOperationException(SR.net_inasync);
                }

                if (message == null)
                {
                    throw new ArgumentNullException(nameof(message));
                }

                if (DeliveryMethod == SmtpDeliveryMethod.Network)
                {
                    CheckHostAndPort();
                }

                _recipients = new MailAddressCollection();

                if (message.From == null)
                {
                    throw new InvalidOperationException(SR.SmtpFromRequired);
                }

                if (message.To != null)
                {
                    foreach (MailAddress address in message.To)
                    {
                        _recipients.Add(address);
                    }
                }
                if (message.Bcc != null)
                {
                    foreach (MailAddress address in message.Bcc)
                    {
                        _recipients.Add(address);
                    }
                }
                if (message.CC != null)
                {
                    foreach (MailAddress address in message.CC)
                    {
                        _recipients.Add(address);
                    }
                }

                if (_recipients.Count == 0)
                {
                    throw new InvalidOperationException(SR.SmtpRecipientRequired);
                }

                try
                {
                    InCall     = true;
                    _cancelled = false;
                    _message   = message;
                    string pickupDirectory = PickupDirectoryLocation;

                    CredentialCache cache;
                    // Skip token capturing if no credentials are used or they don't include a default one.
                    // Also do capture the token if ICredential is not of CredentialCache type so we don't know what the exact credential response will be.
                    _transport.IdentityRequired = Credentials != null && (ReferenceEquals(Credentials, CredentialCache.DefaultNetworkCredentials) || (cache = Credentials as CredentialCache) == null);

                    _asyncOp = AsyncOperationManager.CreateOperation(userToken);
                    switch (DeliveryMethod)
                    {
                    case SmtpDeliveryMethod.PickupDirectoryFromIis:
                        throw new NotSupportedException(SR.SmtpGetIisPickupDirectoryNotSupported);

                    case SmtpDeliveryMethod.SpecifiedPickupDirectory:
                    {
                        if (EnableSsl)
                        {
                            throw new SmtpException(SR.SmtpPickupDirectoryDoesnotSupportSsl);
                        }

                        _writer = GetFileMailWriter(pickupDirectory);
                        bool allowUnicode = IsUnicodeSupported();
                        ValidateUnicodeRequirement(message, _recipients, allowUnicode);
                        message.Send(_writer, true, allowUnicode);

                        if (_writer != null)
                        {
                            _writer.Close();
                        }

                        _transport.ReleaseConnection();
                        AsyncCompletedEventArgs eventArgs = new AsyncCompletedEventArgs(null, false, _asyncOp.UserSuppliedState);
                        InCall = false;
                        _asyncOp.PostOperationCompleted(_onSendCompletedDelegate, eventArgs);
                        break;
                    }

                    case SmtpDeliveryMethod.Network:
                    default:
                        _operationCompletedResult = new ContextAwareResult(_transport.IdentityRequired, true, null, this, s_contextSafeCompleteCallback);
                        lock (_operationCompletedResult.StartPostingAsyncOp())
                        {
                            if (GlobalLog.IsEnabled)
                            {
                                GlobalLog.Print("SmtpClient#" + LoggingHash.HashString(this) + "::SendAsync calling BeginConnect.  Transport#" + LoggingHash.HashString(_transport));
                            }

                            _transport.BeginGetConnection(_operationCompletedResult, ConnectCallback, _operationCompletedResult, Host, Port);
                            _operationCompletedResult.FinishPostingAsyncOp();
                        }
                        break;
                    }
                }
                catch (Exception e)
                {
                    InCall = false;

                    if (NetEventSource.Log.IsEnabled())
                    {
                        NetEventSource.Exception(NetEventSource.ComponentType.Web, this, "Send", e);
                    }

                    if (e is SmtpFailedRecipientException && !((SmtpFailedRecipientException)e).fatal)
                    {
                        throw;
                    }

                    Abort();
                    if (_timedOut)
                    {
                        throw new SmtpException(SR.net_timeout);
                    }

                    if (e is SecurityException ||
                        e is AuthenticationException ||
                        e is SmtpException)
                    {
                        throw;
                    }

                    throw new SmtpException(SR.SmtpSendMailFailure, e);
                }
            }
            finally
            {
                if (NetEventSource.Log.IsEnabled())
                {
                    NetEventSource.Exit(NetEventSource.ComponentType.Web, this, "SendAsync", null);
                }

                if (GlobalLog.IsEnabled)
                {
                    GlobalLog.Leave("SmtpClient#" + LoggingHash.HashString(this) + "::SendAsync");
                }
            }
        }