internal static int Decrypt( SafeDeleteContext securityContext, byte[] buffer, int offset, int count, bool isConfidential, bool isNtlm, out int newOffset, uint sequenceNumber) { if (offset < 0 || offset > (buffer == null ? 0 : buffer.Length)) { if (GlobalLog.IsEnabled) { GlobalLog.Assert("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::Decrypt", "Argument 'offset' out of range."); } Debug.Fail("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::Decrypt", "Argument 'offset' out of range."); throw new ArgumentOutOfRangeException(nameof(offset)); } if (count < 0 || count > (buffer == null ? 0 : buffer.Length - offset)) { if (GlobalLog.IsEnabled) { GlobalLog.Assert("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::Decrypt", "Argument 'count' out of range."); } Debug.Fail("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::Decrypt", "Argument 'count' out of range."); throw new ArgumentOutOfRangeException(nameof(count)); } if (isNtlm) { return(DecryptNtlm(securityContext, buffer, offset, count, isConfidential, out newOffset, sequenceNumber)); } // // Kerberos and up // var securityBuffer = new SecurityBuffer[2]; securityBuffer[0] = new SecurityBuffer(buffer, offset, count, SecurityBufferType.Stream); securityBuffer[1] = new SecurityBuffer(0, SecurityBufferType.Data); int errorCode; if (isConfidential) { errorCode = SSPIWrapper.DecryptMessage(GlobalSSPI.SSPIAuth, securityContext, securityBuffer, sequenceNumber); } else { errorCode = SSPIWrapper.VerifySignature(GlobalSSPI.SSPIAuth, securityContext, securityBuffer, sequenceNumber); } if (errorCode != 0) { if (GlobalLog.IsEnabled) { GlobalLog.Print("NTAuthentication#" + "::Decrypt() throw Error = " + errorCode.ToString("x", NumberFormatInfo.InvariantInfo)); } throw new Win32Exception(errorCode); } if (securityBuffer[1].type != SecurityBufferType.Data) { throw new InternalException(); } newOffset = securityBuffer[1].offset; return(securityBuffer[1].size); }
public void LogRemainingOperations() { Interlocked.MemoryBarrier(); GlobalLog.Print("InnerSafeCloseSocket: Releasing with pending operations: " + _refCount); }
/*++ * 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 = CertWrapper.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); } // Don't call chain.Build here in the common code, because the Windows version // is potentially going to check for GetLastWin32Error, and that call needs to be // guaranteed to be right after the call to chain.Build. sslPolicyErrors |= CertWrapper.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); }
/// <include file='doc\NetworkStream.uex' path='docs/doc[@for="NetworkStream.Close"]/*' /> /// <devdoc> /// <para> /// Closes the stream, and then closes the underlying socket. /// </para> /// </devdoc> public override void Close() { GlobalLog.Print("NetworkStream::Close()"); ((IDisposable)this).Dispose(); }
// // The app is calling this method after starting an SSL handshake. // // ATTN: The thumbPrint must be from inspected and possibly cloned user Cert object or we get a security hole in SslCredKey ctor. // internal static void CacheCredential(SafeFreeCredentials creds, byte[] thumbPrint, SslProtocols sslProtocols, bool isServer, EncryptionPolicy encryptionPolicy) { GlobalLog.Assert(creds != null, "CacheCredential|creds == null"); if (creds.IsInvalid) { GlobalLog.Print("CacheCredential() Refused to cache an Invalid Handle = " + creds.ToString() + ", Current Cache Count = " + s_CachedCreds.Count); return; } object key = new SslCredKey(thumbPrint, (int)sslProtocols, isServer, encryptionPolicy); SafeCredentialReference cached = s_CachedCreds[key] as SafeCredentialReference; if (cached == null || cached.IsClosed || cached.Target.IsInvalid) { lock (s_CachedCreds) { cached = s_CachedCreds[key] as SafeCredentialReference; if (cached == null || cached.IsClosed) { cached = SafeCredentialReference.CreateReference(creds); if (cached == null) { // Means the handle got closed in between, return it back and let caller deal with the issue. return; } s_CachedCreds[key] = cached; GlobalLog.Print("CacheCredential() Caching New Handle = " + creds.ToString() + ", Current Cache Count = " + s_CachedCreds.Count); // // A simplest way of preventing infinite cache grows. // // Security relief (DoS): // A number of active creds is never greater than a number of _outstanding_ // security sessions, i.e. SSL connections. // So we will try to shrink cache to the number of active creds once in a while. // // We won't shrink cache in the case when NO new handles are coming to it. // if ((s_CachedCreds.Count % CheckExpiredModulo) == 0) { DictionaryEntry[] toRemoveAttempt = new DictionaryEntry[s_CachedCreds.Count]; s_CachedCreds.CopyTo(toRemoveAttempt, 0); for (int i = 0; i < toRemoveAttempt.Length; ++i) { cached = toRemoveAttempt[i].Value as SafeCredentialReference; if (cached != null) { creds = cached.Target; cached.Dispose(); if (!creds.IsClosed && !creds.IsInvalid && (cached = SafeCredentialReference.CreateReference(creds)) != null) { s_CachedCreds[toRemoveAttempt[i].Key] = cached; } else { s_CachedCreds.Remove(toRemoveAttempt[i].Key); } } } GlobalLog.Print("Scavenged cache, New Cache Count = " + s_CachedCreds.Count); } } else { GlobalLog.Print("CacheCredential() (locked retry) Found already cached Handle = " + cached.Target.ToString()); } } } else { GlobalLog.Print("CacheCredential() Ignoring incoming handle = " + creds.ToString() + " since found already cached Handle = " + cached.Target.ToString()); } }
/*++ * 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#" + LoggingHash.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#" + LoggingHash.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 (SecurityEventSource.Log.IsEnabled()) { if (sslPolicyErrors != SslPolicyErrors.None) { SecurityEventSource.Log.RemoteCertificateError(LoggingHash.HashInt(this), SR.net_log_remote_cert_has_errors); if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateNotAvailable) != 0) { SecurityEventSource.Log.RemoteCertificateError(LoggingHash.HashInt(this), SR.net_log_remote_cert_not_available); } if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateNameMismatch) != 0) { SecurityEventSource.Log.RemoteCertificateError(LoggingHash.HashInt(this), SR.net_log_remote_cert_name_mismatch); } if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateChainErrors) != 0) { string chainStatusString = "ChainStatus: "; foreach (X509ChainStatus chainStatus in chain.ChainStatus) { chainStatusString += "\t" + chainStatus.StatusInformation; } SecurityEventSource.Log.RemoteCertificateError(LoggingHash.HashInt(this), chainStatusString); } } if (success) { if (remoteCertValidationCallback != null) { SecurityEventSource.Log.RemoteCertDeclaredValid(LoggingHash.HashInt(this)); } else { SecurityEventSource.Log.RemoteCertHasNoErrors(LoggingHash.HashInt(this)); } } else { if (remoteCertValidationCallback != null) { SecurityEventSource.Log.RemoteCertUserDeclaredInvalid(LoggingHash.HashInt(this)); } } } 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#" + LoggingHash.HashString(this) + "::VerifyRemoteCertificate", success.ToString()); return(success); }
// // Acquire Server Side Certificate information and set it on the class. // private bool AcquireServerCredentials(ref byte[] thumbPrint) { GlobalLog.Enter("SecureChannel#" + LoggingHash.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#" + LoggingHash.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#" + LoggingHash.HashString(this) + "::AcquireServerCredentials, cachedCreds = " + cachedCred.ToString(), LoggingHash.ObjectToString(_credentialsHandle)); return(cachedCred); }
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"); } } }
//UEUE /// <include file='doc\UDPClient.uex' path='docs/doc[@for="UdpClient.Close"]/*' /> public void Close() { GlobalLog.Print("UdpClient::Close()"); this.FreeResources(); GC.SuppressFinalize(this); }
// This method will be called by us when the IO completes synchronously and // by the ThreadPool when the IO completes asynchronously. (only called on WinNT) internal override object PostCompletion(int numBytes) { SocketError errorCode = (SocketError)ErrorCode; Internals.SocketAddress remoteSocketAddress = null; if (errorCode == SocketError.Success) { _localBytesTransferred = numBytes; if (SocketsEventSource.Log.IsEnabled()) { LogBuffer((long)numBytes); } // get the endpoint remoteSocketAddress = IPEndPointExtensions.Serialize(_listenSocket._rightEndPoint); IntPtr localAddr; int localAddrLength; IntPtr remoteAddr; // set the socket context try { _listenSocket.GetAcceptExSockaddrs( Marshal.UnsafeAddrOfPinnedArrayElement(_buffer, 0), _buffer.Length - (_addressBufferLength * 2), _addressBufferLength, _addressBufferLength, out localAddr, out localAddrLength, out remoteAddr, out remoteSocketAddress.InternalSize); Marshal.Copy(remoteAddr, remoteSocketAddress.Buffer, 0, remoteSocketAddress.Size); IntPtr handle = _listenSocket.SafeHandle.DangerousGetHandle(); errorCode = Interop.Winsock.setsockopt( _acceptSocket.SafeHandle, SocketOptionLevel.Socket, SocketOptionName.UpdateAcceptContext, ref handle, Marshal.SizeOf(handle)); if (errorCode == SocketError.SocketError) { errorCode = (SocketError)Marshal.GetLastWin32Error(); } if (GlobalLog.IsEnabled) { GlobalLog.Print("AcceptOverlappedAsyncResult#" + LoggingHash.HashString(this) + "::PostCallback() setsockopt handle:" + handle.ToString() + " AcceptSocket:" + LoggingHash.HashString(_acceptSocket) + " itsHandle:" + _acceptSocket.SafeHandle.DangerousGetHandle().ToString() + " returns:" + errorCode.ToString()); } } catch (ObjectDisposedException) { errorCode = SocketError.OperationAborted; } ErrorCode = (int)errorCode; } if (errorCode != SocketError.Success) { return(null); } return(_listenSocket.UpdateAcceptSocket(_acceptSocket, _listenSocket._rightEndPoint.Create(remoteSocketAddress))); }
// // This is the static internal callback that will be called when // the IO we issued for the user to winsock has completed, either // synchronously (Signaled=false) or asynchronously (Signaled=true) // when this function gets called it must: // 1) update the AsyncResult object with the results of the completed IO // 2) signal events that the user might be waiting on // 3) cal the callback function that the user might have specified // internal static void ConnectCallback(object stateObject, bool Signaled) { ConnectAsyncResult asyncResult = stateObject as ConnectAsyncResult; Socket socket = asyncResult.AsyncObject as Socket; GlobalLog.Enter("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback", "Signaled:" + Signaled.ToString()); GlobalLog.Assert(!asyncResult.IsCompleted, "Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback() asyncResult.IsCompleted", ""); // // we now need to get the status of the async completion, we had an easy implementation // that uses GetSocketOption(), but VadimE suggested not to use this 'cause it may be // buggy on some platforms, so we use WSAEnumNetworkEvents() instead: // // The best way to do this is to call WSAEnumNetworkEvents and use the error code iError // array corresponding to FD_CONNECT. getsockopt (SO_ERROR) may return NO_ERROR under // stress even in case of error at least on Winnt4.0 (I don't remember whether I fixed // it on Win2000 or WinXP). // // // get async completion // /* * int errorCode = (int)socket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Error); * GlobalLog.Print("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback() GetSocketOption() returns errorCode:" + errorCode.ToString()); */ NetworkEvents networkEvents = new NetworkEvents(); networkEvents.Events = AsyncEventBits.FdConnect; AutoResetEvent chkAsyncEvent = socket.m_AsyncEvent; int errorCode = SocketErrors.WSAENOTSOCK; if (chkAsyncEvent != null) { errorCode = UnsafeNclNativeMethods.OSSOCK.WSAEnumNetworkEvents( socket.m_Handle, chkAsyncEvent.Handle, ref networkEvents); if (errorCode != SocketErrors.Success) { errorCode = Marshal.GetLastWin32Error(); GlobalLog.Print("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback() WSAEnumNetworkEvents() failed with errorCode:" + errorCode.ToString()); } else { errorCode = networkEvents.ErrorCodes[(int)AsyncEventBitsPos.FdConnectBit]; GlobalLog.Print("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback() ErrorCodes(FdConnect) got errorCode:" + errorCode.ToString()); } } try { // // cancel async event // socket.SetAsyncEventSelect(AsyncEventBits.FdNone); // // go back to blocking mode // socket.InternalSetBlocking(true); } catch (Exception exception) { GlobalLog.Print("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback() caught exception::" + exception.Message); asyncResult.Result = exception; } // // if the native non-blocking call failed we'll throw a SocketException in EndConnect() // if (errorCode != SocketErrors.Success) { // // just save the error code, the SocketException will be thrown in EndConnect() // asyncResult.ErrorCode = errorCode; } else { // // the Socket is connected, update our state and performance counter // socket.SetToConnected(); } // // call the user's callback now, if there is one. // asyncResult.InvokeCallback(false); GlobalLog.Leave("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback", errorCode.ToString()); }
// // This method will be called by us when the IO completes synchronously and // by the ThreadPool when the IO completes asynchronously. (only called on WinNT) // internal override object PostCompletion(int numBytes) { SocketError errorCode = (SocketError)ErrorCode; SocketAddress remoteSocketAddress = null; if (errorCode == SocketError.Success) { m_LocalBytesTransferred = numBytes; if (Logging.On) { LogBuffer((long)numBytes); } //get the endpoint remoteSocketAddress = m_ListenSocket.m_RightEndPoint.Serialize(); IntPtr localAddr; int localAddrLength; IntPtr remoteAddr; //set the socket context try { m_ListenSocket.GetAcceptExSockaddrs( Marshal.UnsafeAddrOfPinnedArrayElement(m_Buffer, 0), m_Buffer.Length - (m_AddressBufferLength * 2), m_AddressBufferLength, m_AddressBufferLength, out localAddr, out localAddrLength, out remoteAddr, out remoteSocketAddress.m_Size ); Marshal.Copy(remoteAddr, remoteSocketAddress.m_Buffer, 0, remoteSocketAddress.m_Size); IntPtr handle = m_ListenSocket.SafeHandle.DangerousGetHandle(); errorCode = UnsafeNclNativeMethods.OSSOCK.setsockopt( m_AcceptSocket.SafeHandle, SocketOptionLevel.Socket, SocketOptionName.UpdateAcceptContext, ref handle, Marshal.SizeOf(handle)); if (errorCode == SocketError.SocketError) { errorCode = (SocketError)Marshal.GetLastWin32Error(); } GlobalLog.Print("AcceptOverlappedAsyncResult#" + ValidationHelper.HashString(this) + "::PostCallback() setsockopt handle:" + handle.ToString() + " AcceptSocket:" + ValidationHelper.HashString(m_AcceptSocket) + " itsHandle:" + m_AcceptSocket.SafeHandle.DangerousGetHandle().ToString() + " returns:" + errorCode.ToString()); } catch (ObjectDisposedException) { errorCode = SocketError.OperationAborted; } ErrorCode = (int)errorCode; } if (errorCode == SocketError.Success) { return(m_ListenSocket.UpdateAcceptSocket(m_AcceptSocket, m_ListenSocket.m_RightEndPoint.Create(remoteSocketAddress), false)); } else { return(null); } }
// // This is the static internal callback that will be called when // the IO we issued for the user to winsock has completed, either // synchronously (Signaled=false) or asynchronously (Signaled=true) // when this function gets called it must: // 1) update the AsyncResult object with the results of the completed IO // 2) signal events that the user might be waiting on // 3) cal the callback function that the user might have specified // internal static void ConnectCallback(object stateObject, bool Signaled) { ConnectAsyncResult asyncResult = stateObject as ConnectAsyncResult; Socket socket = asyncResult.AsyncObject as Socket; GlobalLog.Enter("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback", "Signaled:" + Signaled.ToString()); GlobalLog.Assert(!asyncResult.IsCompleted, "Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback() asyncResult.IsCompleted", ""); // // // get async completion // /* * int errorCode = (int)socket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Error); * GlobalLog.Print("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback() GetSocketOption() returns errorCode:" + errorCode.ToString()); */ NetworkEvents networkEvents = new NetworkEvents(); networkEvents.Events = AsyncEventBits.FdConnect; AutoResetEvent chkAsyncEvent = socket.m_AsyncEvent; int errorCode = SocketErrors.WSAENOTSOCK; if (chkAsyncEvent != null) { errorCode = UnsafeNclNativeMethods.OSSOCK.WSAEnumNetworkEvents( socket.m_Handle, chkAsyncEvent.Handle, ref networkEvents); if (errorCode != SocketErrors.Success) { errorCode = Marshal.GetLastWin32Error(); GlobalLog.Print("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback() WSAEnumNetworkEvents() failed with errorCode:" + errorCode.ToString()); } else { errorCode = networkEvents.ErrorCodes[(int)AsyncEventBitsPos.FdConnectBit]; GlobalLog.Print("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback() ErrorCodes(FdConnect) got errorCode:" + errorCode.ToString()); } } try { // // cancel async event // socket.SetAsyncEventSelect(AsyncEventBits.FdNone); // // go back to blocking mode // socket.InternalSetBlocking(true); } catch (Exception exception) { GlobalLog.Print("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback() caught exception::" + exception.Message); asyncResult.Result = exception; } // // if the native non-blocking call failed we'll throw a SocketException in EndConnect() // if (errorCode != SocketErrors.Success) { // // just save the error code, the SocketException will be thrown in EndConnect() // asyncResult.ErrorCode = errorCode; } else { // // the Socket is connected, update our state and performance counter // socket.SetToConnected(); } // // call the user's callback now, if there is one. // asyncResult.InvokeCallback(false); GlobalLog.Leave("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback", errorCode.ToString()); }
protected SafeNativeOverlapped() : this(IntPtr.Zero) { GlobalLog.Print("SafeNativeOverlapped#" + LoggingHash.HashString(this) + "::ctor(null)"); }
internal unsafe static int CompleteAuthToken( ref SafeDeleteContext refContext, SecurityBuffer[] inSecBuffers) { GlobalLog.Enter("SafeDeleteContext::CompleteAuthToken"); GlobalLog.Print(" refContext = " + LoggingHash.ObjectToString(refContext)); #if TRACE_VERBOSE GlobalLog.Print(" inSecBuffers[] = length:" + inSecBuffers.Length); #endif GlobalLog.Assert(inSecBuffers != null, "SafeDeleteContext::CompleteAuthToken()|inSecBuffers == null"); var inSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(inSecBuffers.Length); int errorCode = (int)Interop.SecurityStatus.InvalidHandle; // These are pinned user byte arrays passed along with SecurityBuffers. GCHandle[] pinnedInBytes = null; var inUnmanagedBuffer = new Interop.Secur32.SecurityBufferStruct[inSecurityBufferDescriptor.Count]; fixed(void *inUnmanagedBufferPtr = inUnmanagedBuffer) { // Fix Descriptor pointer that points to unmanaged SecurityBuffers. inSecurityBufferDescriptor.UnmanagedPointer = inUnmanagedBufferPtr; pinnedInBytes = new GCHandle[inSecurityBufferDescriptor.Count]; SecurityBuffer securityBuffer; for (int index = 0; index < inSecurityBufferDescriptor.Count; ++index) { securityBuffer = inSecBuffers[index]; if (securityBuffer != null) { inUnmanagedBuffer[index].count = securityBuffer.size; inUnmanagedBuffer[index].type = securityBuffer.type; // Use the unmanaged token if it's not null; otherwise use the managed buffer. if (securityBuffer.unmanagedToken != null) { inUnmanagedBuffer[index].token = securityBuffer.unmanagedToken.DangerousGetHandle(); } else if (securityBuffer.token == null || securityBuffer.token.Length == 0) { inUnmanagedBuffer[index].token = IntPtr.Zero; } else { pinnedInBytes[index] = GCHandle.Alloc(securityBuffer.token, GCHandleType.Pinned); inUnmanagedBuffer[index].token = Marshal.UnsafeAddrOfPinnedArrayElement(securityBuffer.token, securityBuffer.offset); } #if TRACE_VERBOSE GlobalLog.Print("SecBuffer: cbBuffer:" + securityBuffer.size + " BufferType:" + securityBuffer.type); #endif } } Interop.Secur32.SSPIHandle contextHandle = new Interop.Secur32.SSPIHandle(); if (refContext != null) { contextHandle = refContext._handle; } try { if (refContext == null || refContext.IsInvalid) { refContext = new SafeDeleteContext_SECURITY(); } try { bool ignore = false; refContext.DangerousAddRef(ref ignore); errorCode = Interop.Secur32.CompleteAuthToken(contextHandle.IsZero ? null : &contextHandle, inSecurityBufferDescriptor); } finally { refContext.DangerousRelease(); } } finally { if (pinnedInBytes != null) { for (int index = 0; index < pinnedInBytes.Length; index++) { if (pinnedInBytes[index].IsAllocated) { pinnedInBytes[index].Free(); } } } } } GlobalLog.Leave("SafeDeleteContext::CompleteAuthToken() unmanaged CompleteAuthToken()", "errorCode:0x" + errorCode.ToString("x8") + " refContext:" + LoggingHash.ObjectToString(refContext)); return(errorCode); }
public void SendAsync(MailMessage message, object userToken) { if (disposed) { throw new ObjectDisposedException(this.GetType().FullName); } if (Logging.On) { Logging.Enter(Logging.Web, this, "SendAsync", "DeliveryMethod=" + DeliveryMethod.ToString()); } GlobalLog.Enter("SmtpClient#" + ValidationHelper.HashString(this) + "::SendAsync Transport#" + ValidationHelper.HashString(transport)); try { if (InCall) { throw new InvalidOperationException(SR.GetString(SR.net_inasync)); } if (message == null) { throw new ArgumentNullException("message"); } if (DeliveryMethod == SmtpDeliveryMethod.Network) { CheckHostAndPort(); } recipients = new MailAddressCollection(); if (message.From == null) { throw new InvalidOperationException(SR.GetString(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.GetString(SR.SmtpRecipientRequired)); } try { InCall = true; cancelled = false; this.message = message; string pickupDirectory = PickupDirectoryLocation; #if !FEATURE_PAL 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 && (Credentials is SystemNetworkCredential || (cache = Credentials as CredentialCache) == null || cache.IsDefaultInCache); #endif // !FEATURE_PAL asyncOp = AsyncOperationManager.CreateOperation(userToken); switch (DeliveryMethod) { #if !FEATURE_PAL case SmtpDeliveryMethod.PickupDirectoryFromIis: pickupDirectory = IisPickupDirectory.GetPickupDirectory(); goto case SmtpDeliveryMethod.SpecifiedPickupDirectory; #endif // !FEATURE_PAL case SmtpDeliveryMethod.SpecifiedPickupDirectory: { if (EnableSsl) { throw new SmtpException(SR.GetString(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, _ContextSafeCompleteCallback); lock (operationCompletedResult.StartPostingAsyncOp()) { GlobalLog.Print("SmtpClient#" + ValidationHelper.HashString(this) + "::SendAsync calling BeginConnect. Transport#" + ValidationHelper.HashString(transport)); transport.BeginGetConnection(ServicePoint, operationCompletedResult, ConnectCallback, operationCompletedResult); operationCompletedResult.FinishPostingAsyncOp(); } break; } } catch (Exception e) { InCall = false; if (Logging.On) { Logging.Exception(Logging.Web, this, "Send", e); } if (e is SmtpFailedRecipientException && !((SmtpFailedRecipientException)e).fatal) { throw; } Abort(); if (timedOut) { throw new SmtpException(SR.GetString(SR.net_timeout)); } if (e is SecurityException || e is AuthenticationException || e is SmtpException) { throw; } throw new SmtpException(SR.GetString(SR.SmtpSendMailFailure), e); } } finally { if (Logging.On) { Logging.Exit(Logging.Web, this, "SendAsync", null); } GlobalLog.Leave("SmtpClient#" + ValidationHelper.HashString(this) + "::SendAsync"); } }
//------------------------------------------------------------------- internal unsafe static int AcceptSecurityContext( ref SafeFreeCredentials inCredentials, ref SafeDeleteContext refContext, Interop.Secur32.ContextFlags inFlags, Interop.Secur32.Endianness endianness, SecurityBuffer inSecBuffer, SecurityBuffer[] inSecBuffers, SecurityBuffer outSecBuffer, ref Interop.Secur32.ContextFlags outFlags) { #if TRACE_VERBOSE GlobalLog.Enter("SafeDeleteContext::AcceptSecurityContex"); GlobalLog.Print(" credential = " + inCredentials.ToString()); GlobalLog.Print(" refContext = " + LoggingHash.ObjectToString(refContext)); GlobalLog.Print(" inFlags = " + inFlags); if (inSecBuffers == null) { GlobalLog.Print(" inSecBuffers = (null)"); } else { GlobalLog.Print(" inSecBuffers[] = length:" + inSecBuffers.Length); } #endif GlobalLog.Assert(outSecBuffer != null, "SafeDeleteContext::AcceptSecurityContext()|outSecBuffer != null"); GlobalLog.Assert(inSecBuffer == null || inSecBuffers == null, "SafeDeleteContext::AcceptSecurityContext()|inSecBuffer == null || inSecBuffers == null"); if (inCredentials == null) { throw new ArgumentNullException("inCredentials"); } Interop.Secur32.SecurityBufferDescriptor inSecurityBufferDescriptor = null; if (inSecBuffer != null) { inSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(1); } else if (inSecBuffers != null) { inSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(inSecBuffers.Length); } Interop.Secur32.SecurityBufferDescriptor outSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(1); // Actually, this is returned in outFlags. bool isSspiAllocated = (inFlags & Interop.Secur32.ContextFlags.AllocateMemory) != 0 ? true : false; int errorCode = -1; Interop.Secur32.SSPIHandle contextHandle = new Interop.Secur32.SSPIHandle(); if (refContext != null) { contextHandle = refContext._handle; } // These are pinned user byte arrays passed along with SecurityBuffers. GCHandle[] pinnedInBytes = null; GCHandle pinnedOutBytes = new GCHandle(); // Optional output buffer that may need to be freed. SafeFreeContextBuffer outFreeContextBuffer = null; try { pinnedOutBytes = GCHandle.Alloc(outSecBuffer.token, GCHandleType.Pinned); var inUnmanagedBuffer = new Interop.Secur32.SecurityBufferStruct[inSecurityBufferDescriptor == null ? 1 : inSecurityBufferDescriptor.Count]; fixed(void *inUnmanagedBufferPtr = inUnmanagedBuffer) { if (inSecurityBufferDescriptor != null) { // Fix Descriptor pointer that points to unmanaged SecurityBuffers. inSecurityBufferDescriptor.UnmanagedPointer = inUnmanagedBufferPtr; pinnedInBytes = new GCHandle[inSecurityBufferDescriptor.Count]; SecurityBuffer securityBuffer; for (int index = 0; index < inSecurityBufferDescriptor.Count; ++index) { securityBuffer = inSecBuffer != null ? inSecBuffer : inSecBuffers[index]; if (securityBuffer != null) { // Copy the SecurityBuffer content into unmanaged place holder. inUnmanagedBuffer[index].count = securityBuffer.size; inUnmanagedBuffer[index].type = securityBuffer.type; // Use the unmanaged token if it's not null; otherwise use the managed buffer. if (securityBuffer.unmanagedToken != null) { inUnmanagedBuffer[index].token = securityBuffer.unmanagedToken.DangerousGetHandle(); } else if (securityBuffer.token == null || securityBuffer.token.Length == 0) { inUnmanagedBuffer[index].token = IntPtr.Zero; } else { pinnedInBytes[index] = GCHandle.Alloc(securityBuffer.token, GCHandleType.Pinned); inUnmanagedBuffer[index].token = Marshal.UnsafeAddrOfPinnedArrayElement(securityBuffer.token, securityBuffer.offset); } #if TRACE_VERBOSE GlobalLog.Print("SecBuffer: cbBuffer:" + securityBuffer.size + " BufferType:" + securityBuffer.type); #endif } } } var outUnmanagedBuffer = new Interop.Secur32.SecurityBufferStruct[1]; fixed(void *outUnmanagedBufferPtr = outUnmanagedBuffer) { // Fix Descriptor pointer that points to unmanaged SecurityBuffers. outSecurityBufferDescriptor.UnmanagedPointer = outUnmanagedBufferPtr; // Copy the SecurityBuffer content into unmanaged place holder. outUnmanagedBuffer[0].count = outSecBuffer.size; outUnmanagedBuffer[0].type = outSecBuffer.type; if (outSecBuffer.token == null || outSecBuffer.token.Length == 0) { outUnmanagedBuffer[0].token = IntPtr.Zero; } else { outUnmanagedBuffer[0].token = Marshal.UnsafeAddrOfPinnedArrayElement(outSecBuffer.token, outSecBuffer.offset); } if (isSspiAllocated) { outFreeContextBuffer = SafeFreeContextBuffer.CreateEmptyHandle(); } if (refContext == null || refContext.IsInvalid) { refContext = new SafeDeleteContext_SECURITY(); } errorCode = MustRunAcceptSecurityContext_SECURITY( ref inCredentials, contextHandle.IsZero ? null : &contextHandle, inSecurityBufferDescriptor, inFlags, endianness, refContext, outSecurityBufferDescriptor, ref outFlags, outFreeContextBuffer); GlobalLog.Print("SafeDeleteContext:AcceptSecurityContext Marshalling OUT buffer"); // Get unmanaged buffer with index 0 as the only one passed into PInvoke. outSecBuffer.size = outUnmanagedBuffer[0].count; outSecBuffer.type = outUnmanagedBuffer[0].type; if (outSecBuffer.size > 0) { outSecBuffer.token = new byte[outSecBuffer.size]; Marshal.Copy(outUnmanagedBuffer[0].token, outSecBuffer.token, 0, outSecBuffer.size); } else { outSecBuffer.token = null; } } } } finally { if (pinnedInBytes != null) { for (int index = 0; index < pinnedInBytes.Length; index++) { if (pinnedInBytes[index].IsAllocated) { pinnedInBytes[index].Free(); } } } if (pinnedOutBytes.IsAllocated) { pinnedOutBytes.Free(); } if (outFreeContextBuffer != null) { outFreeContextBuffer.Dispose(); } } GlobalLog.Leave("SafeDeleteContext::AcceptSecurityContex() unmanaged AcceptSecurityContex()", "errorCode:0x" + errorCode.ToString("x8") + " refContext:" + LoggingHash.ObjectToString(refContext)); return(errorCode); }
private static SecurityStatusPal EstablishSecurityContext( SafeFreeNegoCredentials credential, ref SafeDeleteContext context, string targetName, ContextFlagsPal inFlags, SecurityBuffer inputBuffer, SecurityBuffer outputBuffer, ref ContextFlagsPal outFlags) { bool isNtlmOnly = credential.IsNtlmOnly; if (context == null) { // Empty target name causes the failure on Linux, hence passing a non-empty string context = isNtlmOnly ? new SafeDeleteNegoContext(credential, credential.UserName) : new SafeDeleteNegoContext(credential, targetName); } SafeDeleteNegoContext negoContext = (SafeDeleteNegoContext)context; try { Interop.NetSecurityNative.GssFlags inputFlags = ContextFlagsAdapterPal.GetInteropFromContextFlagsPal(inFlags); uint outputFlags; int isNtlmUsed; SafeGssContextHandle contextHandle = negoContext.GssContext; bool done = Interop.GssApi.EstablishSecurityContext( ref contextHandle, credential.GssCredential, isNtlmOnly, negoContext.TargetName, inputFlags, inputBuffer?.token, out outputBuffer.token, out outputFlags, out isNtlmUsed); Debug.Assert(outputBuffer.token != null, "Unexpected null buffer returned by GssApi"); outputBuffer.size = outputBuffer.token.Length; outputBuffer.offset = 0; outFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop((Interop.NetSecurityNative.GssFlags)outputFlags); // Save the inner context handle for further calls to NetSecurity Debug.Assert(negoContext.GssContext == null || contextHandle == negoContext.GssContext); if (null == negoContext.GssContext) { negoContext.SetGssContext(contextHandle); } // Populate protocol used for authentication if (done) { negoContext.SetAuthenticationPackage(Convert.ToBoolean(isNtlmUsed)); } SecurityStatusPalErrorCode errorCode = done ? (negoContext.IsNtlmUsed && outputBuffer.size > 0 ? SecurityStatusPalErrorCode.OK : SecurityStatusPalErrorCode.CompleteNeeded) : SecurityStatusPalErrorCode.ContinueNeeded; return(new SecurityStatusPal(errorCode)); } catch (Exception ex) { if (GlobalLog.IsEnabled) { GlobalLog.Print("Exception Caught. - " + ex); } return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, ex)); } }
/*++ * 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#" + LoggingHash.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#" + LoggingHash.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 (SecurityEventSource.Log.IsEnabled()) { SecurityEventSource.Log.CertificateFromDelegate(LoggingHash.HashInt(this)); } } else { if (ClientCertificates.Count == 0) { if (SecurityEventSource.Log.IsEnabled()) { SecurityEventSource.Log.NoDelegateNoClientCert(LoggingHash.HashInt(this)); } sessionRestartAttempt = true; } else { if (SecurityEventSource.Log.IsEnabled()) { SecurityEventSource.Log.NoDelegateButClientCert(LoggingHash.HashInt(this)); } } } } 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 (SecurityEventSource.Log.IsEnabled()) { SecurityEventSource.Log.AttemptingRestartUsingCert(clientCertificate == null ? "null" : clientCertificate.ToString(true), LoggingHash.HashInt(this)); } } 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 (SecurityEventSource.Log.IsEnabled()) { if (issuers == null || issuers.Length == 0) { SecurityEventSource.Log.NoIssuersTryAllCerts(LoggingHash.HashInt(this)); } else { SecurityEventSource.Log.LookForMatchingCerts(issuers.Length, LoggingHash.HashInt(this)); } } 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#" + LoggingHash.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#" + LoggingHash.HashString(this) + "::AcquireClientCredentials() matched:" + issuer); break; } GlobalLog.Print("SecureChannel#" + LoggingHash.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 (SecurityEventSource.Log.IsEnabled()) { SecurityEventSource.Log.SelectedCert(_clientCertificates[i].ToString(true), LoggingHash.HashInt(this)); } 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 (SecurityEventSource.Log.IsEnabled()) { SecurityEventSource.Log.CertsAfterFiltering(filteredCerts.Count, LoggingHash.HashInt(this)); if (filteredCerts.Count != 0) { SecurityEventSource.Log.FindingMatchingCerts(LoggingHash.HashInt(this)); } } // // 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#" + LoggingHash.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#" + LoggingHash.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 (SecurityEventSource.Log.IsEnabled()) { SecurityEventSource.Log.UsingCachedCredential(LoggingHash.HashInt(this)); } _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#" + LoggingHash.HashString(this) + "::AcquireClientCredentials, cachedCreds = " + cachedCred.ToString(), LoggingHash.ObjectToString(_credentialsHandle)); return(cachedCred); }
/// <devdoc> /// <para> /// Creates a new instance of the <see cref='System.Net.Sockets.SocketException'/> class with the default error code. /// </para> /// </devdoc> public SocketException() : base(Marshal.GetLastWin32Error()) { GlobalLog.Print("SocketException::.ctor() " + NativeErrorCode.ToString() + ":" + Message); }
private unsafe SocketError InnerReleaseHandle() { int errorCode; // If _blockable was set in BlockingRelease, it's safe to block here, which means // we can honor the linger options set on the socket. It also means closesocket() might return WSAEWOULDBLOCK, in which // case we need to do some recovery. if (_blockable) { if (GlobalLog.IsEnabled) { GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") Following 'blockable' branch."); } errorCode = Interop.Sys.Close(handle); if (errorCode == -1) { errorCode = (int)Interop.Sys.GetLastError(); } if (GlobalLog.IsEnabled) { GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") close()#1:" + errorCode.ToString()); } #if DEBUG _closeSocketHandle = handle; _closeSocketResult = SocketPal.GetSocketErrorForErrorCode((Interop.Error)errorCode); #endif // If it's not EWOULDBLOCK, there's no more recourse - we either succeeded or failed. if (errorCode != (int)Interop.Error.EWOULDBLOCK) { return(SocketPal.GetSocketErrorForErrorCode((Interop.Error)errorCode)); } // The socket must be non-blocking with a linger timeout set. // We have to set the socket to blocking. errorCode = Interop.Sys.Fcntl.DangerousSetIsNonBlocking(handle, 0); if (errorCode == 0) { // The socket successfully made blocking; retry the close(). errorCode = Interop.Sys.Close(handle); if (GlobalLog.IsEnabled) { GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") close()#2:" + errorCode.ToString()); } #if DEBUG _closeSocketHandle = handle; _closeSocketResult = SocketPal.GetSocketErrorForErrorCode((Interop.Error)errorCode); #endif return(SocketPal.GetSocketErrorForErrorCode((Interop.Error)errorCode)); } // The socket could not be made blocking; fall through to the regular abortive close. } // By default or if CloseAsIs() path failed, set linger timeout to zero to get an abortive close (RST). var linger = new Interop.Sys.LingerOption { OnOff = 1, Seconds = 0 }; errorCode = (int)Interop.Sys.DangerousSetLingerOption((int)handle, &linger); #if DEBUG _closeSocketLinger = SocketPal.GetSocketErrorForErrorCode((Interop.Error)errorCode); #endif if (GlobalLog.IsEnabled) { GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") setsockopt():" + errorCode.ToString()); } if (errorCode != 0 && errorCode != (int)Interop.Error.EINVAL && errorCode != (int)Interop.Error.ENOPROTOOPT) { // Too dangerous to try closesocket() - it might block! return(SocketPal.GetSocketErrorForErrorCode((Interop.Error)errorCode)); } errorCode = Interop.Sys.Close(handle); #if DEBUG _closeSocketHandle = handle; _closeSocketResult = SocketPal.GetSocketErrorForErrorCode((Interop.Error)errorCode); #endif if (GlobalLog.IsEnabled) { GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") close#3():" + (errorCode == -1 ? (int)Interop.Sys.GetLastError() : errorCode).ToString()); } return(SocketPal.GetSocketErrorForErrorCode((Interop.Error)errorCode)); }
/// <devdoc> /// <para> /// Creates a new instance of the <see cref='System.Net.Sockets.SocketException'/> class with the specified error code. /// </para> /// </devdoc> public SocketException(int errorCode) : base(errorCode) { GlobalLog.Print("SocketException::.ctor(int) " + NativeErrorCode.ToString() + ":" + Message); }
GetChunkSize(IReadChunkBytes Source, out int chunkSize) { int BytesRead; int Size; int Current; GlobalLog.Enter("GetChunkSize"); Size = 0; // // Loop while we have data. If we run out of data and exit the loop // at the bottom, then we've run out of data and haven't found the // length. Current = Source.NextByte; BytesRead = 0; if (Current == 10 || Current == 13) { GlobalLog.Print(" Got Char: " + Current.ToString()); BytesRead++; Current = Source.NextByte; } while (Current != -1) { // Get the next byte, and decode it. if (Current >= '0' && Current <= '9') { // Normalize it to 0 based. Current -= '0'; } else { // If we're here, this might be a hex digit. // If it is, normalize it to 10 based. if (Current >= 'a' && Current <= 'f') { Current -= 'a'; } else { if (Current >= 'A' && Current <= 'F') { Current -= 'A'; } else { // Done with the decoding. If we haven't actually // decoded a digit yet, we'll end up returning // 0, which will signal the error. // Push back the byte we read and didn't use. Source.NextByte = Current; chunkSize = Size; // Return how many bytes we took. GlobalLog.Print("*Size* = " + Size.ToString()); GlobalLog.Leave("GetChunkSize", BytesRead); return(BytesRead); } } // If we get here we've had an A-F digit, add 10 // to it to normalize it. Current += 10; } // Update the size and our state. Size *= 16; Size += Current; BytesRead++; Current = Source.NextByte; } chunkSize = Size; GlobalLog.Print("*Size* = " + Size.ToString()); GlobalLog.Leave("GetChunkSize", -1); return(-1); }
protected SocketException(SerializationInfo serializationInfo, StreamingContext streamingContext) : base(serializationInfo, streamingContext) { GlobalLog.Print("SocketException::.ctor(serialized) " + NativeErrorCode.ToString() + ":" + Message); }
private SocketError InnerReleaseHandle() { SocketError errorCode; // If _blockable was set in BlockingRelease, it's safe to block here, which means // we can honor the linger options set on the socket. It also means closesocket() might return WSAEWOULDBLOCK, in which // case we need to do some recovery. if (_blockable) { if (GlobalLog.IsEnabled) { GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") Following 'blockable' branch."); } errorCode = Interop.Winsock.closesocket(handle); #if DEBUG _closeSocketHandle = handle; _closeSocketResult = errorCode; #endif if (errorCode == SocketError.SocketError) { errorCode = (SocketError)Marshal.GetLastWin32Error(); } if (GlobalLog.IsEnabled) { GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") closesocket()#1:" + errorCode.ToString()); } // If it's not WSAEWOULDBLOCK, there's no more recourse - we either succeeded or failed. if (errorCode != SocketError.WouldBlock) { return(errorCode); } // The socket must be non-blocking with a linger timeout set. // We have to set the socket to blocking. int nonBlockCmd = 0; errorCode = Interop.Winsock.ioctlsocket( handle, Interop.Winsock.IoctlSocketConstants.FIONBIO, ref nonBlockCmd); if (errorCode == SocketError.SocketError) { errorCode = (SocketError)Marshal.GetLastWin32Error(); } if (GlobalLog.IsEnabled) { GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") ioctlsocket()#1:" + errorCode.ToString()); } // This can fail if there's a pending WSAEventSelect. Try canceling it. if (errorCode == SocketError.InvalidArgument) { errorCode = Interop.Winsock.WSAEventSelect( handle, IntPtr.Zero, Interop.Winsock.AsyncEventBits.FdNone); if (GlobalLog.IsEnabled) { GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") WSAEventSelect():" + (errorCode == SocketError.SocketError ? (SocketError)Marshal.GetLastWin32Error() : errorCode).ToString()); } // Now retry the ioctl. errorCode = Interop.Winsock.ioctlsocket( handle, Interop.Winsock.IoctlSocketConstants.FIONBIO, ref nonBlockCmd); if (GlobalLog.IsEnabled) { GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") ioctlsocket#2():" + (errorCode == SocketError.SocketError ? (SocketError)Marshal.GetLastWin32Error() : errorCode).ToString()); } } // If that succeeded, try again. if (errorCode == SocketError.Success) { errorCode = Interop.Winsock.closesocket(handle); #if DEBUG _closeSocketHandle = handle; _closeSocketResult = errorCode; #endif if (errorCode == SocketError.SocketError) { errorCode = (SocketError)Marshal.GetLastWin32Error(); } if (GlobalLog.IsEnabled) { GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") closesocket#2():" + errorCode.ToString()); } // If it's not WSAEWOULDBLOCK, there's no more recourse - we either succeeded or failed. if (errorCode != SocketError.WouldBlock) { return(errorCode); } } // It failed. Fall through to the regular abortive close. } // By default or if CloseAsIs() path failed, set linger timeout to zero to get an abortive close (RST). Interop.Winsock.Linger lingerStruct; lingerStruct.OnOff = 1; lingerStruct.Time = 0; errorCode = Interop.Winsock.setsockopt( handle, SocketOptionLevel.Socket, SocketOptionName.Linger, ref lingerStruct, 4); #if DEBUG _closeSocketLinger = errorCode; #endif if (errorCode == SocketError.SocketError) { errorCode = (SocketError)Marshal.GetLastWin32Error(); } if (GlobalLog.IsEnabled) { GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") setsockopt():" + errorCode.ToString()); } if (errorCode != SocketError.Success && errorCode != SocketError.InvalidArgument && errorCode != SocketError.ProtocolOption) { // Too dangerous to try closesocket() - it might block! return(errorCode); } errorCode = Interop.Winsock.closesocket(handle); #if DEBUG _closeSocketHandle = handle; _closeSocketResult = errorCode; #endif if (GlobalLog.IsEnabled) { GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") closesocket#3():" + (errorCode == SocketError.SocketError ? (SocketError)Marshal.GetLastWin32Error() : errorCode).ToString()); } return(errorCode); }
internal static int Encrypt( SafeDeleteContext securityContext, byte[] buffer, int offset, int count, bool isConfidential, bool isNtlm, ref byte[] output, uint sequenceNumber) { SecSizes sizes = SSPIWrapper.QueryContextAttributes( GlobalSSPI.SSPIAuth, securityContext, Interop.SspiCli.ContextAttribute.Sizes ) as SecSizes; try { int maxCount = checked (Int32.MaxValue - 4 - sizes.BlockSize - sizes.SecurityTrailer); if (count > maxCount || count < 0) { throw new ArgumentOutOfRangeException(nameof(count), SR.Format(SR.net_io_out_range, maxCount)); } } catch (Exception e) { if (!ExceptionCheck.IsFatal(e)) { if (GlobalLog.IsEnabled) { GlobalLog.Assert("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::Encrypt", "Arguments out of range."); } Debug.Fail("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::Encrypt", "Arguments out of range."); } throw; } int resultSize = count + sizes.SecurityTrailer + sizes.BlockSize; if (output == null || output.Length < resultSize + 4) { output = new byte[resultSize + 4]; } // Make a copy of user data for in-place encryption. Buffer.BlockCopy(buffer, offset, output, 4 + sizes.SecurityTrailer, count); // Prepare buffers TOKEN(signature), DATA and Padding. var securityBuffer = new SecurityBuffer[3]; securityBuffer[0] = new SecurityBuffer(output, 4, sizes.SecurityTrailer, SecurityBufferType.Token); securityBuffer[1] = new SecurityBuffer(output, 4 + sizes.SecurityTrailer, count, SecurityBufferType.Data); securityBuffer[2] = new SecurityBuffer(output, 4 + sizes.SecurityTrailer + count, sizes.BlockSize, SecurityBufferType.Padding); int errorCode; if (isConfidential) { errorCode = SSPIWrapper.EncryptMessage(GlobalSSPI.SSPIAuth, securityContext, securityBuffer, sequenceNumber); } else { if (isNtlm) { securityBuffer[1].type |= SecurityBufferType.ReadOnlyFlag; } errorCode = SSPIWrapper.MakeSignature(GlobalSSPI.SSPIAuth, securityContext, securityBuffer, 0); } if (errorCode != 0) { if (GlobalLog.IsEnabled) { GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::Encrypt() throw Error = " + errorCode.ToString("x", NumberFormatInfo.InvariantInfo)); } throw new Win32Exception(errorCode); } // Compacting the result. resultSize = securityBuffer[0].size; bool forceCopy = false; if (resultSize != sizes.SecurityTrailer) { forceCopy = true; Buffer.BlockCopy(output, securityBuffer[1].offset, output, 4 + resultSize, securityBuffer[1].size); } resultSize += securityBuffer[1].size; if (securityBuffer[2].size != 0 && (forceCopy || resultSize != (count + sizes.SecurityTrailer))) { Buffer.BlockCopy(output, securityBuffer[2].offset, output, 4 + resultSize, securityBuffer[2].size); } resultSize += securityBuffer[2].size; unchecked { output[0] = (byte)((resultSize) & 0xFF); output[1] = (byte)(((resultSize) >> 8) & 0xFF); output[2] = (byte)(((resultSize) >> 16) & 0xFF); output[3] = (byte)(((resultSize) >> 24) & 0xFF); } return(resultSize + 4); }
private unsafe static void CompletionPortCallback(uint errorCode, uint numBytes, NativeOverlapped *nativeOverlapped) { #if DEBUG GlobalLog.SetThreadSource(ThreadKinds.CompletionPort); using (GlobalLog.SetThreadKind(ThreadKinds.System)) { #endif BaseOverlappedAsyncResult asyncResult = (BaseOverlappedAsyncResult)ThreadPoolBoundHandle.GetNativeOverlappedState(nativeOverlapped); object returnObject = null; if (asyncResult.InternalPeekCompleted) { if (GlobalLog.IsEnabled) { GlobalLog.AssertFormat("BaseOverlappedAsyncResult#{0}::CompletionPortCallback()|asyncResult.IsCompleted", LoggingHash.HashString(asyncResult)); } Debug.Fail("BaseOverlappedAsyncResult#" + LoggingHash.HashString(asyncResult) + "::CompletionPortCallback()|asyncResult.IsCompleted"); } if (GlobalLog.IsEnabled) { GlobalLog.Print( "BaseOverlappedAsyncResult#" + LoggingHash.HashString(asyncResult) + "::CompletionPortCallback" + " errorCode:" + errorCode.ToString() + " numBytes:" + numBytes.ToString() + " pOverlapped:" + ((int)nativeOverlapped).ToString()); } // Complete the IO and invoke the user's callback. SocketError socketError = (SocketError)errorCode; if (socketError != SocketError.Success && socketError != SocketError.OperationAborted) { // There are cases where passed errorCode does not reflect the details of the underlined socket error. // "So as of today, the key is the difference between WSAECONNRESET and ConnectionAborted, // .e.g remote party or network causing the connection reset or something on the local host (e.g. closesocket // or receiving data after shutdown (SD_RECV)). With Winsock/TCP stack rewrite in longhorn, there may // be other differences as well." Socket socket = asyncResult.AsyncObject as Socket; if (socket == null) { socketError = SocketError.NotSocket; } else if (socket.CleanedUp) { socketError = SocketError.OperationAborted; } else { try { // The async IO completed with a failure. // Here we need to call WSAGetOverlappedResult() just so Marshal.GetLastWin32Error() will return the correct error. SocketFlags ignore; bool success = Interop.Winsock.WSAGetOverlappedResult( socket.SafeHandle, asyncResult.NativeOverlapped, out numBytes, false, out ignore); if (!success) { socketError = (SocketError)Marshal.GetLastWin32Error(); if (socketError == 0) { if (GlobalLog.IsEnabled) { GlobalLog.AssertFormat("BaseOverlappedAsyncResult#{0}::CompletionPortCallback()|socketError:0 numBytes:{1}", LoggingHash.HashString(asyncResult), numBytes); } Debug.Fail("BaseOverlappedAsyncResult#" + LoggingHash.HashString(asyncResult) + "::CompletionPortCallback()|socketError:0 numBytes:" + numBytes); } } if (success) { if (GlobalLog.IsEnabled) { GlobalLog.AssertFormat("BaseOverlappedAsyncResult#{0}::CompletionPortCallback()|Unexpectedly succeeded. errorCode:{1} numBytes:{2}", LoggingHash.HashString(asyncResult), errorCode, numBytes); } Debug.Fail("BaseOverlappedAsyncResult#" + LoggingHash.HashString(asyncResult) + "::CompletionPortCallback()|Unexpectedly succeeded. errorCode:" + errorCode + " numBytes: " + numBytes); } } catch (ObjectDisposedException) { // CleanedUp check above does not always work since this code is subject to race conditions socketError = SocketError.OperationAborted; } } } asyncResult.ErrorCode = (int)socketError; returnObject = asyncResult.PostCompletion((int)numBytes); asyncResult.ReleaseUnmanagedStructures(); asyncResult.InvokeCallback(returnObject); #if DEBUG } #endif }
public static unsafe SecurityStatusPal EncryptMessage(SafeDeleteContext securityContext, byte[] input, int offset, int size, int headerSize, int trailerSize, ref byte[] output, out int resultSize) { // Ensure that there is sufficient space for the message output. int bufferSizeNeeded; try { bufferSizeNeeded = checked (size + headerSize + trailerSize); } catch { if (GlobalLog.IsEnabled) { GlobalLog.Assert("SslStreamPal.Windows: SecureChannel#" + LoggingHash.HashString(securityContext) + "::Encrypt", "Arguments out of range."); } Debug.Fail("SslStreamPal.Windows: SecureChannel#" + LoggingHash.HashString(securityContext) + "::Encrypt", "Arguments out of range."); throw; } if (output == null || output.Length < bufferSizeNeeded) { output = new byte[bufferSizeNeeded]; } // Copy the input into the output buffer to prepare for SCHANNEL's expectations Buffer.BlockCopy(input, offset, output, headerSize, size); const int NumSecBuffers = 4; // header + data + trailer + empty var unmanagedBuffer = stackalloc Interop.SspiCli.SecBuffer[NumSecBuffers]; var sdcInOut = new Interop.SspiCli.SecBufferDesc(NumSecBuffers); sdcInOut.pBuffers = unmanagedBuffer; fixed(byte *outputPtr = output) { Interop.SspiCli.SecBuffer *headerSecBuffer = &unmanagedBuffer[0]; headerSecBuffer->BufferType = SecurityBufferType.SECBUFFER_STREAM_HEADER; headerSecBuffer->pvBuffer = (IntPtr)outputPtr; headerSecBuffer->cbBuffer = headerSize; Interop.SspiCli.SecBuffer *dataSecBuffer = &unmanagedBuffer[1]; dataSecBuffer->BufferType = SecurityBufferType.SECBUFFER_DATA; dataSecBuffer->pvBuffer = (IntPtr)(outputPtr + headerSize); dataSecBuffer->cbBuffer = size; Interop.SspiCli.SecBuffer *trailerSecBuffer = &unmanagedBuffer[2]; trailerSecBuffer->BufferType = SecurityBufferType.SECBUFFER_STREAM_TRAILER; trailerSecBuffer->pvBuffer = (IntPtr)(outputPtr + headerSize + size); trailerSecBuffer->cbBuffer = trailerSize; Interop.SspiCli.SecBuffer *emptySecBuffer = &unmanagedBuffer[3]; emptySecBuffer->BufferType = SecurityBufferType.SECBUFFER_EMPTY; emptySecBuffer->cbBuffer = 0; emptySecBuffer->pvBuffer = IntPtr.Zero; int errorCode = GlobalSSPI.SSPISecureChannel.EncryptMessage(securityContext, sdcInOut, 0); if (errorCode != 0) { if (GlobalLog.IsEnabled) { GlobalLog.Print("SslStreamPal.Windows: SecureChannel#" + LoggingHash.HashString(securityContext) + "::Encrypt ERROR" + errorCode.ToString("x")); } resultSize = 0; return(SecurityStatusAdapterPal.GetSecurityStatusPalFromNativeInt(errorCode)); } Debug.Assert(headerSecBuffer->cbBuffer >= 0 && dataSecBuffer->cbBuffer >= 0 && trailerSecBuffer->cbBuffer >= 0); Debug.Assert(checked (headerSecBuffer->cbBuffer + dataSecBuffer->cbBuffer + trailerSecBuffer->cbBuffer) <= output.Length); resultSize = checked (headerSecBuffer->cbBuffer + dataSecBuffer->cbBuffer + trailerSecBuffer->cbBuffer); return(new SecurityStatusPal(SecurityStatusPalErrorCode.OK)); } }