internal void PostPop(object newOwner) { GlobalLog.Assert(!IsEmancipated, "Pooled object not in pool."); GlobalLog.Assert(CanBePooled, "Pooled object is not poolable."); lock (this) { if (null == m_Owner) { m_Owner = new WeakReference(newOwner); } else { if (null != m_Owner.Target) { throw new InternalException(); // pooled connection already has an owner! } m_Owner.Target = newOwner; } m_PooledCount--; if (null != Pool) { if (0 != m_PooledCount) { throw new InternalException(); // popping object off stack with multiple pooledCount } } else { if (-1 != m_PooledCount) { throw new InternalException(); // popping object off stack with multiple pooledCount } } } }
private void ReadFrameCallback(IAsyncResult transportResult) { if (!(transportResult.AsyncState is WorkerAsyncResult)) { if (GlobalLog.IsEnabled) { GlobalLog.Assert("StreamFramer::ReadFrameCallback|The state expected to be WorkerAsyncResult, received:{0}.", transportResult.GetType().FullName); } Debug.Fail("StreamFramer::ReadFrameCallback|The state expected to be WorkerAsyncResult, received:" + transportResult.GetType().FullName + "."); } if (transportResult.CompletedSynchronously) { return; } WorkerAsyncResult workerResult = (WorkerAsyncResult)transportResult.AsyncState; try { ReadFrameComplete(transportResult); } catch (Exception e) { if (e is OutOfMemoryException) { throw; } if (!(e is IOException)) { e = new System.IO.IOException(SR.Format(SR.net_io_readfailure, e.Message), e); } workerResult.InvokeCallback(e); } }
internal virtual void ConnectionCallback(object owningObject, Exception e, Socket socket, IPAddress address) { GlobalLog.Assert(owningObject == Owner || Owner == null, "PooledStream::ConnectionCallback|Owner is not the same as expected."); object result = null; if (e != null) { m_Initalizing = false; result = e; } else { try { m_NetworkStream.InitNetworkStream(socket, FileAccess.ReadWrite); result = this; } catch (Exception ex) { if (NclUtilities.IsFatal(ex)) { throw; } result = ex; } catch { throw; } m_ServerAddress = address; m_Initalizing = false; m_JustConnected = true; } if (m_AsyncCallback != null) { m_AsyncCallback(owningObject, result); } m_AbortSocket = null; m_AbortSocket6 = null; }
private static bool IsRecoverableAutoProxyError(int errorCode) { GlobalLog.Assert(errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_INVALID_PARAMETER, "WinHttpGetProxyForUrl() call: Error code 'Invalid parameter' should not be returned."); // According to WinHttp the following states can be considered "recoverable", i.e. // we should continue trying WinHttpGetProxyForUrl() with the provided script-location // (if available). switch ((UnsafeNclNativeMethods.WinHttp.ErrorCodes)errorCode) { case UnsafeNclNativeMethods.WinHttp.ErrorCodes.AutoProxyServiceError: case UnsafeNclNativeMethods.WinHttp.ErrorCodes.AudodetectionFailed: case UnsafeNclNativeMethods.WinHttp.ErrorCodes.BadAutoProxyScript: case UnsafeNclNativeMethods.WinHttp.ErrorCodes.LoginFailure: case UnsafeNclNativeMethods.WinHttp.ErrorCodes.OperationCancelled: case UnsafeNclNativeMethods.WinHttp.ErrorCodes.Timeout: case UnsafeNclNativeMethods.WinHttp.ErrorCodes.UnableToDownloadScript: case UnsafeNclNativeMethods.WinHttp.ErrorCodes.UnrecognizedScheme: return(true); } return(false); }
// // // private bool CheckCompletionBeforeNextRead(int bytes) { if (bytes == 0) { // 0 bytes was requested or EOF in the beginning of a frame, the caller should decide whether it's OK if (_TotalRead == 0) { _Request.CompleteRequest(0); return(true); } // EOF in the middle of a frame, bummer! throw new IOException(SR.GetString(SR.net_io_eof)); } GlobalLog.Assert(_TotalRead + bytes <= _Request.Count, "FixedSizeReader::CheckCompletion()|State got out of range. Total:{0} Count:{1}", _TotalRead + bytes, _Request.Count); if ((_TotalRead += bytes) == _Request.Count) { _Request.CompleteRequest(_Request.Count); return(true); } return(false); }
internal unsafe SslConnectionInfo(byte[] nativeBuffer) { fixed(void *voidPtr = nativeBuffer) { try { // TODO (Issue #3114): replace with Marshal.PtrToStructure. IntPtr unmanagedAddress = new IntPtr(voidPtr); Protocol = Marshal.ReadInt32(unmanagedAddress); DataCipherAlg = Marshal.ReadInt32(unmanagedAddress, 4); DataKeySize = Marshal.ReadInt32(unmanagedAddress, 8); DataHashAlg = Marshal.ReadInt32(unmanagedAddress, 12); DataHashKeySize = Marshal.ReadInt32(unmanagedAddress, 16); KeyExchangeAlg = Marshal.ReadInt32(unmanagedAddress, 20); KeyExchKeySize = Marshal.ReadInt32(unmanagedAddress, 24); } catch (OverflowException) { GlobalLog.Assert(false, "SslConnectionInfo::.ctor", "Negative size."); throw; } } }
/// <summary> /// <para>Retrieves a pooled stream from the pool proper /// this work by first attemting to find something in the pool on the New stack /// and then trying the Old stack if something is not there availble </para> /// </summary> private PooledStream GetFromPool(object owningObject) { PooledStream res = null; GlobalLog.Enter("ConnectionPool#" + ValidationHelper.HashString(this) + "::GetFromPool"); res = (PooledStream)m_StackNew.Pop(); if (null == res) { res = (PooledStream)m_StackOld.Pop(); } // Shouldn't be null, we could assert here. GlobalLog.Assert(res != null, "GetFromPool called with nothing in the pool!"); if (null != res) { res.PostPop(owningObject); GlobalLog.Print("GetFromGeneralPool pooledStream#" + ValidationHelper.HashString(res)); } GlobalLog.Leave("ConnectionPool#" + ValidationHelper.HashString(this) + "::GetFromPool", ValidationHelper.HashString(res)); return(res); }
protected bool Activate(object owningObject, bool async, GeneralAsyncDelegate asyncCallback) { GlobalLog.Assert(owningObject == Owner || Owner == null, "PooledStream::Activate|Owner is not the same as expected."); try { if (m_Initalizing) { IPAddress address = null; m_AsyncCallback = asyncCallback; Socket socket = ServicePoint.GetConnection(this, owningObject, async, out address, ref m_AbortSocket, ref m_AbortSocket6); if (socket != null) { if (Logging.On) { Logging.PrintInfo(Logging.Web, this, SR.GetString(SR.net_log_socket_connected, socket.LocalEndPoint, socket.RemoteEndPoint)); } m_NetworkStream.InitNetworkStream(socket, FileAccess.ReadWrite); m_ServerAddress = address; m_Initalizing = false; m_JustConnected = true; m_AbortSocket = null; m_AbortSocket6 = null; return(true); } return(false); } else if (async && asyncCallback != null) { asyncCallback(owningObject, this); } return(true); } catch { m_Initalizing = false; throw; } }
private static void ReadCallback(IAsyncResult transportResult) { if (GlobalLog.IsEnabled && !(transportResult.AsyncState is FixedSizeReader)) { GlobalLog.Assert("ReadCallback|State type is wrong, expected FixedSizeReader."); } if (transportResult.CompletedSynchronously) { return; } FixedSizeReader reader = (FixedSizeReader)transportResult.AsyncState; AsyncProtocolRequest request = reader._request; // Async completion. try { int bytes = reader._transportAPM.EndRead(transportResult); if (reader.CheckCompletionBeforeNextRead(bytes)) { return; } reader.StartReading(); } catch (Exception e) { if (request.IsUserCompleted) { throw; } request.CompleteWithError(e); } }
private static X509Store EnsureStoreOpened(ref X509Store storeField, StoreLocation storeLocation) { X509Store store = Volatile.Read(ref storeField); if (store == null) { lock (s_lockObject) { store = Volatile.Read(ref storeField); if (store == null) { try { store = new X509Store(StoreName.My, storeLocation); store.Open(OpenFlags.ReadOnly); Volatile.Write(ref storeField, store); GlobalLog.Print( "CertModule::EnsureStoreOpened() storeLocation:" + storeLocation + " returned store:" + store.GetHashCode().ToString("x")); } catch (CryptographicException e) { GlobalLog.Assert( "CertModule::EnsureStoreOpened()", "Failed to open cert store, location:" + storeLocation + " exception:" + e); throw; } } } } return(store); }
internal void CloseAsIs() { RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { #if DEBUG // If this throws it could be very bad. try { #endif InnerSafeCloseSocket innerSocket = m_InnerSocket == null ? null : Interlocked.Exchange <InnerSafeCloseSocket>(ref m_InnerSocket, null); Close(); if (innerSocket != null) { // Wait until it's safe. while (!m_Released) { Thread.SpinWait(1); } // Now free it with blocking. innerSocket.BlockingRelease(); } #if DEBUG } catch (Exception exception) { if (!NclUtilities.IsFatal(exception)) { GlobalLog.Assert("SafeCloseSocket::CloseAsIs(handle:" + handle.ToString("x") + ")", exception.Message); } throw; } #endif } }
public Authorization Authenticate(string challenge, WebRequest webRequest, ICredentials credentials) { GlobalLog.Print("BasicClient::Authenticate(): " + challenge); GlobalLog.Assert(credentials != null, "BasicClient::Authenticate()|credentials == null"); #if !FEATURE_PAL if (credentials == null || credentials is SystemNetworkCredential) { #else if (credentials == null) { #endif // !FEATURE_PAL return(null); } HttpWebRequest httpWebRequest = webRequest as HttpWebRequest; GlobalLog.Assert(httpWebRequest != null, "BasicClient::Authenticate()|httpWebRequest == null"); if (httpWebRequest == null || httpWebRequest.ChallengedUri == null) { // // there has been no challenge: // 1) the request never went on the wire // 2) somebody other than us is calling into AuthenticationManager // return(null); } int index = AuthenticationManager.FindSubstringNotInQuotes(challenge, Signature); if (index < 0) { return(null); } return(Lookup(httpWebRequest, credentials)); }
private void BeginWriteCallback(IAsyncResult transportResult) { GlobalLog.Assert(transportResult.AsyncState is WorkerAsyncResult, "StreamFramer::BeginWriteCallback|The state expected to be WorkerAsyncResult, received:{0}.", transportResult.AsyncState.GetType().FullName); if (transportResult.CompletedSynchronously) { return; } WorkerAsyncResult workerResult = (WorkerAsyncResult)transportResult.AsyncState; try { BeginWriteComplete(transportResult); } catch (Exception e) { if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) { throw; } workerResult.InvokeCallback(e); } }
internal unsafe SecSizes(byte[] memory) { fixed(void *voidPtr = memory) { IntPtr unmanagedAddress = new IntPtr(voidPtr); try { // TODO (Issue #3114): replace with Marshal.PtrToStructure. MaxToken = (int)checked ((uint)Marshal.ReadInt32(unmanagedAddress)); MaxSignature = (int)checked ((uint)Marshal.ReadInt32(unmanagedAddress, 4)); BlockSize = (int)checked ((uint)Marshal.ReadInt32(unmanagedAddress, 8)); SecurityTrailer = (int)checked ((uint)Marshal.ReadInt32(unmanagedAddress, 12)); } catch (OverflowException) { if (GlobalLog.IsEnabled) { GlobalLog.Assert("SecSizes::.ctor", "Negative size."); } throw; } } }
/// <summary> /// <para>Creates new timers. This method is thread-safe.</para> /// </summary> internal override Timer CreateTimer(Callback callback, object context) { TimerNode timer = new TimerNode(callback, context, Duration, m_Timers); // Add this on the tail. (Actually, one before the tail - m_Timers is the sentinel tail.) bool needProd = false; lock (m_Timers) { GlobalLog.Assert(m_Timers.Prev.Next == m_Timers, "TimerThread#{0}::CreateTimer()|m_Tail corruption.", Thread.CurrentThread.ManagedThreadId.ToString()); // If this is the first timer in the list, we need to create a queue handle and prod the timer thread. if (m_Timers.Next == m_Timers) { if (m_ThisHandle == IntPtr.Zero) { m_ThisHandle = (IntPtr)GCHandle.Alloc(this); } needProd = true; } timer.Next = m_Timers; timer.Prev = m_Timers.Prev; m_Timers.Prev.Next = timer; m_Timers.Prev = timer; } // If, after we add the new tail, there is a chance that the tail is the next // node to be processed, we need to wake up the timer thread. if (needProd) { TimerThread.Prod(); } return(timer); }
/// <summary> /// <para>Retrieves a pooled stream from the pool proper /// this work by first attemting to find something in the pool on the New stack /// and then trying the Old stack if something is not there availble </para> /// </summary> private PooledStream GetFromPool(object owningObject) { PooledStream res = null; GlobalLog.Enter("ConnectionPool#" + ValidationHelper.HashString(this) + "::GetFromPool"); res = (PooledStream)m_StackNew.Pop(); if (null == res) { res = (PooledStream)m_StackOld.Pop(); } // The semaphore guaranteed that a connection was available so if res is // null it means that this contract has been violated somewhere GlobalLog.Assert(res != null, "GetFromPool called with nothing in the pool!"); if (null != res) { res.PostPop(owningObject); GlobalLog.Print("GetFromGeneralPool pooledStream#" + ValidationHelper.HashString(res)); } GlobalLog.Leave("ConnectionPool#" + ValidationHelper.HashString(this) + "::GetFromPool", ValidationHelper.HashString(res)); return(res); }
/*++ * * ResponseStream - Return the response stream. * * This property returns the response stream for this response. The * response stream will do de-chunking, etc. as needed. * * Input: Nothing. Property is readonly. * * Returns: Response stream for response. * * --*/ /// <devdoc> /// <para>Gets the stream used for reading the body of the response from the /// server.</para> /// </devdoc> public override Stream GetResponseStream() { if (Logging.On) { Logging.Enter(Logging.Web, this, "GetResponseStream", ""); } CheckDisposed(); if (Logging.On) { Logging.PrintInfo(Logging.Web, "ContentLength=" + m_ContentLength); } Stream result; if (m_IsWebSocketResponse && m_StatusCode == HttpStatusCode.SwitchingProtocols) // HTTP 101 { if (this.m_WebSocketConnectionStream == null) { ConnectStream connectStream = m_ConnectStream as ConnectStream; GlobalLog.Assert(connectStream != null, "HttpWebResponse.m_ConnectStream should always be a ConnectStream in WebSocket cases."); GlobalLog.Assert(connectStream.Connection != null, "HttpWebResponse.m_ConnectStream.Connection should never be null in WebSocket cases."); this.m_WebSocketConnectionStream = new WebSocketConnectionStream(connectStream, this.ConnectionGroupName); } result = this.m_WebSocketConnectionStream; } else { result = m_ConnectStream; } if (Logging.On) { Logging.Exit(Logging.Web, this, "GetResponseStream", result); } return(result); }
// // NextRecord - called typically in Callback // to indicate that we need more bytes from the wire // to be decrypted. It is called either by a worker // thread or by the Read directly, it reads one chunk // of data, and attempts to decrypt. As soon as it has // the chunk of unencrypted data, it returns it in // m_ArrivingData and m_ExistingAmount contains, // the amount data that was decrypted. // // ASSUMES: we have an empty buffer of unencrypted bytes // RETURNS: upon error, by either leaving this buffer empty (0), // with an Exception set on this object, or on success, // by updating the global state (m_ArrivingData) // with unencrypted bytes // // WARNING: Can Throw! // private void NextRecord(byte[] buffer, int length) { byte[] packet = null; GlobalLog.Assert( (m_ExistingAmount == 0), "m_ExistingAmount != 0", "Has assumed internal SSL buffer would be empty"); // // This LOOP below will keep going until (EITHER): // 1) we have ONE succesful chunk of unencrypted data // 2) we have an error either from a renegotiate handhake (OR) Read (OR) Decrypt // do { packet = ReadFullRecord(buffer, length); if (packet == null) { return; } lock (this) { SecureChannel chkSecureChannel = SecureChannel; if (chkSecureChannel == null) { return; } int errorCode = chkSecureChannel.Decrypt(packet, ref m_ArrivingData); if (errorCode == (int)SecurityStatus.OK) { // SUCCESS - we have our decrypted Bytes GlobalLog.Print("TlsStream::NextRecord called (success) Decrypt[" + (m_ArrivingData != null ? (Encoding.ASCII.GetString(m_ArrivingData, 0, Math.Min(m_ArrivingData.Length, 512))) : "null") + "]"); break; } else { // ERROR - examine what kind ProtocolToken message = new ProtocolToken(packet, errorCode); GlobalLog.Print("TlsStream:: Decrypt errorCode = " + errorCode.ToString()); if (message.Renegotiate) { // HANDSHAKE - do a handshake between us and server InnerException = Handshake(message); if (InnerException != null) { return; // failure } // CONTINUE - Read On! we pick up from where // we were before the handshake and try to get // one block of unencrypted bytes, the earlier block // of data was control information for the handshake. // We need to read in the new header. if (ForceRead(buffer, 0, length) < length) { InnerException = new IOException(SR.GetString(SR.net_io_readfailure)); return; //failure } } else if (message.CloseConnection) { // CLOSE - server ordered us to shut down Close(); // close down the socket return; } else { // EXCEPTION - throw later on InnerException = message.GetException(); return; } } } // continue here in the case where we had a handshake, and needed // to reget new Data } while (true); // m_ExistingAmount was 0 on entry! if (m_ArrivingData == null) { return; } m_ExistingAmount = m_ArrivingData.Length; return; }
// If abortState becomes non-zero, the attempt to find a service point has been aborted. internal static ServicePoint FindServicePoint(Uri address, IWebProxy proxy, out ProxyChain chain, ref HttpAbortDelegate abortDelegate, ref int abortState) { if (address == null) { throw new ArgumentNullException("address"); } GlobalLog.Enter("ServicePointManager::FindServicePoint() address:" + address.ToString()); bool isProxyServicePoint = false; chain = null; // // find proxy info, and then switch on proxy // Uri proxyAddress = null; if (proxy != null && !address.IsLoopback) { IAutoWebProxy autoProxy = proxy as IAutoWebProxy; if (autoProxy != null) { chain = autoProxy.GetProxies(address); // Set up our ability to abort this MoveNext call. Note that the current implementations of ProxyChain will only // take time on the first call, so this is the only place we do this. If a new ProxyChain takes time in later // calls, this logic should be copied to other places MoveNext is called. GlobalLog.Assert(abortDelegate == null, "ServicePointManager::FindServicePoint()|AbortDelegate already set."); abortDelegate = chain.HttpAbortDelegate; try { Thread.MemoryBarrier(); if (abortState != 0) { Exception exception = new WebException(NetRes.GetWebStatusString(WebExceptionStatus.RequestCanceled), WebExceptionStatus.RequestCanceled); GlobalLog.LeaveException("ServicePointManager::FindServicePoint() Request aborted before proxy lookup.", exception); throw exception; } if (!chain.Enumerator.MoveNext()) { GlobalLog.Assert("ServicePointManager::FindServicePoint()|GetProxies() returned zero proxies."); /* * Exception exception = new WebException(NetRes.GetWebStatusString(WebExceptionStatus.RequestProhibitedByProxy), WebExceptionStatus.RequestProhibitedByProxy); * GlobalLog.LeaveException("ServicePointManager::FindServicePoint() Proxy prevented request.", exception); * throw exception; */ } proxyAddress = chain.Enumerator.Current; } finally { abortDelegate = null; } } else if (!proxy.IsBypassed(address)) { // use proxy support // rework address proxyAddress = proxy.GetProxy(address); } // null means DIRECT if (proxyAddress != null) { address = proxyAddress; isProxyServicePoint = true; } } ServicePoint servicePoint = FindServicePointHelper(address, isProxyServicePoint); GlobalLog.Leave("ServicePointManager::FindServicePoint() servicePoint#" + ValidationHelper.HashString(servicePoint)); return(servicePoint); }
internal InternalException() { GlobalLog.Assert("InternalException thrown."); }
internal SslStreamContext(SslStream sslStream) { GlobalLog.Assert(sslStream != null, "SslStreamContext..ctor(): Not expecting a null sslStream!"); this.sslStream = sslStream; }
private unsafe SecurityStatus EncryptDecryptHelper(OP op, SafeDeleteContext context, SecurityBuffer[] input, uint sequenceNumber) { Interop.Secur32.SecurityBufferDescriptor sdcInOut = new Interop.Secur32.SecurityBufferDescriptor(input.Length); var unmanagedBuffer = new Interop.Secur32.SecurityBufferStruct[input.Length]; fixed(Interop.Secur32.SecurityBufferStruct *unmanagedBufferPtr = unmanagedBuffer) { sdcInOut.UnmanagedPointer = unmanagedBufferPtr; GCHandle[] pinnedBuffers = new GCHandle[input.Length]; byte[][] buffers = new byte[input.Length][]; try { for (int i = 0; i < input.Length; i++) { SecurityBuffer iBuffer = input[i]; unmanagedBuffer[i].count = iBuffer.size; unmanagedBuffer[i].type = iBuffer.type; if (iBuffer.token == null || iBuffer.token.Length == 0) { unmanagedBuffer[i].token = IntPtr.Zero; } else { pinnedBuffers[i] = GCHandle.Alloc(iBuffer.token, GCHandleType.Pinned); unmanagedBuffer[i].token = Marshal.UnsafeAddrOfPinnedArrayElement(iBuffer.token, iBuffer.offset); buffers[i] = iBuffer.token; } } // The result is written in the input Buffer passed as type=BufferType.Data. int errorCode; switch (op) { case OP.Encrypt: errorCode = EncryptMessage(context, sdcInOut, sequenceNumber); break; case OP.Decrypt: errorCode = DecryptMessage(context, sdcInOut, sequenceNumber); break; default: throw NotImplemented.ByDesignWithMessage(SR.net_MethodNotImplementedException); } // Marshalling back returned sizes / data. for (int i = 0; i < input.Length; i++) { SecurityBuffer iBuffer = input[i]; iBuffer.size = unmanagedBuffer[i].count; iBuffer.type = unmanagedBuffer[i].type; if (iBuffer.size == 0) { iBuffer.offset = 0; iBuffer.token = null; } else { checked { // Find the buffer this is inside of. Usually they all point inside buffer 0. int j; for (j = 0; j < input.Length; j++) { if (buffers[j] == null) { continue; } byte *bufferAddress = (byte *)Marshal.UnsafeAddrOfPinnedArrayElement(buffers[j], 0); if ((byte *)unmanagedBuffer[i].token >= bufferAddress && (byte *)unmanagedBuffer[i].token + iBuffer.size <= bufferAddress + buffers[j].Length) { iBuffer.offset = (int)((byte *)unmanagedBuffer[i].token - bufferAddress); iBuffer.token = buffers[j]; break; } } if (j >= input.Length) { GlobalLog.Assert("SSPIWrapper::EncryptDecryptHelper", "Output buffer out of range."); iBuffer.size = 0; iBuffer.offset = 0; iBuffer.token = null; } } } // Backup validate the new sizes. GlobalLog.Assert(iBuffer.offset >= 0 && iBuffer.offset <= (iBuffer.token == null ? 0 : iBuffer.token.Length), "SSPIWrapper::EncryptDecryptHelper|'offset' out of range. [{0}]", iBuffer.offset); GlobalLog.Assert(iBuffer.size >= 0 && iBuffer.size <= (iBuffer.token == null ? 0 : iBuffer.token.Length - iBuffer.offset), "SSPIWrapper::EncryptDecryptHelper|'size' out of range. [{0}]", iBuffer.size); } if (errorCode != 0 && Logging.On) { if (errorCode == 0x90321) { Logging.PrintError(Logging.Web, SR.Format(SR.net_log_operation_returned_something, op, "SEC_I_RENEGOTIATE")); } else { Logging.PrintError(Logging.Web, SR.Format(SR.net_log_operation_failed_with_error, op, String.Format(CultureInfo.CurrentCulture, "0X{0:X}", errorCode))); } } return(MapToSecurityStatus((Interop.SecurityStatus)errorCode)); } finally { for (int i = 0; i < pinnedBuffers.Length; ++i) { if (pinnedBuffers[i].IsAllocated) { pinnedBuffers[i].Free(); } } } } }
// private void StartWakeupPendingIO(object nullState) { // state must be is null here GlobalLog.Assert(nullState == null, "TlsStream::StartWakeupPendingIO|Expected null state but got {0}.", nullState == null ? "null" : (nullState.GetType().FullName)); WakeupPendingIO(null); }
internal bool ProcessAuthentication(LazyAsyncResult result) { bool doHandshake = false; bool isSyncCall = result == null; lock (m_PendingIO) { // do we have handshake as already done before we grabbed a lock? if (m_Worker.IsAuthenticated) { return(false); } if (m_PendingIO.Count == 0) { doHandshake = true; } if (isSyncCall) { // we will wait on this guy in this method for the handshake to complete result = new LazyAsyncResult(this, null, null); } m_PendingIO.Add(result); } try { if (doHandshake) { bool success = true; LazyAsyncResult handshakeResult = null; try { m_Worker.ValidateCreateContext(false, m_DestinationHost, m_SslProtocols, null, m_ClientCertificates, true, m_CheckCertificateRevocationList, ServicePointManager.CheckCertificateName); if (!isSyncCall) { // wrap a user async IO/Handshake request into auth request handshakeResult = new LazyAsyncResult(m_Worker, null, new AsyncCallback(WakeupPendingIO)); #if DEBUG result._DebugAsyncChain = handshakeResult; #endif } // // TlsStream is used by classes that manually control ExecutionContext, so set it here if we need to. // if (_ExecutionContext != null) { ExecutionContext.Run(_ExecutionContext.CreateCopy(), new ContextCallback(CallProcessAuthentication), handshakeResult); } else { m_Worker.ProcessAuthentication(handshakeResult); } } catch { success = false; throw; } finally { if (isSyncCall || !success) { lock (m_PendingIO) { if (m_PendingIO.Count > 1) { // It was a real sync handshake (now completed) and another IO came in. // It's now waiting on us so resume. ThreadPool.QueueUserWorkItem(new WaitCallback(StartWakeupPendingIO), null); } else { m_PendingIO.Clear(); } } } } } else if (isSyncCall) { GlobalLog.Assert(result != null, "TlsStream::ProcessAuthentication() this is a Sync call and it did not started the handshake hence null result must be wrapped into LazyAsyncResult"); Exception e = result.InternalWaitForCompletion() as Exception; if (e != null) { throw e; } } } catch { if (m_Worker.IsCertValidationFailed) { m_ExceptionStatus = WebExceptionStatus.TrustFailure; } else if (m_Worker.LastSecurityStatus != SecurityStatus.OK) { m_ExceptionStatus = WebExceptionStatus.SecureChannelFailure; } else { m_ExceptionStatus = WebExceptionStatus.ReceiveFailure; } throw; } // Here in the async case a user IO has been queued (and may be already completed) // For sync case it does not matter since the caller will resume IO upon return return(true); }
// // Security: We temporarily reset thread token to open the cert store under process account. // internal override X509Store EnsureStoreOpened(bool isMachineStore) { X509Store store = isMachineStore ? s_myMachineCertStoreEx : s_myCertStoreEx; if (store == null) { lock (s_syncObject) { store = isMachineStore ? s_myMachineCertStoreEx : s_myCertStoreEx; if (store == null) { // NOTE: that if this call fails we won't keep track and the next time we enter we will try to open the store again. StoreLocation storeLocation = isMachineStore ? StoreLocation.LocalMachine : StoreLocation.CurrentUser; store = new X509Store(StoreName.My, storeLocation); try { // For app-compat We want to ensure the store is opened under the **process** account. try { WindowsIdentity.RunImpersonated(SafeAccessTokenHandle.InvalidHandle, () => { store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly); GlobalLog.Print("SecureChannel::EnsureStoreOpened() storeLocation:" + storeLocation + " returned store:" + store.GetHashCode().ToString("x")); }); } catch { throw; } if (isMachineStore) { s_myMachineCertStoreEx = store; } else { s_myCertStoreEx = store; } return(store); } catch (Exception exception) { if (exception is CryptographicException || exception is SecurityException) { GlobalLog.Assert("SecureChannel::EnsureStoreOpened()", "Failed to open cert store, location:" + storeLocation + " exception:" + exception); return(null); } if (Logging.On) { Logging.PrintError(Logging.Web, SR.Format(SR.net_log_open_store_failed, storeLocation, exception)); } throw; } } } } return(store); }
// // ReadFullRecord - reads a block of bytes, // attemps to ascertain, how much to read, by // assuming block encoding of the byte stream. // // This can be dangerous as these things // tend to change from protocol to protocol // // WARNING: Can throw! // public byte[] ReadFullRecord(byte[] buffer, int length) { // after shutdown/Close throw an exception if (m_ShutDown > 0) { throw new ObjectDisposedException(this.GetType().FullName); } SecureChannel chkSecureChannel = SecureChannel; if (chkSecureChannel == null) { return(null); } int headerSize = chkSecureChannel.HeaderSize; byte[] header = new byte[headerSize]; int read = length; if (buffer != null) { GlobalLog.Assert(length <= headerSize, "length > headerSize", ""); Buffer.BlockCopy(buffer, 0, header, 0, Math.Min(length, headerSize)); } if (length < headerSize) { GlobalLog.Print("RecordLayer::ReadFullRecord Reading " + headerSize + " byte header from the stream"); read += ForceRead(header, length, headerSize - length); } GlobalLog.Dump(header); if (read != headerSize) { GlobalLog.Print("RecordLayer::ReadFullRecord returning null"); return(null); } // if we can't verify, just return what we can find if (!verifyRecordFormat(header)) { return(header); } // WARNING this line, I find worrisome, because it // can differ on new protocols int payloadSize = (0x100 * header[3]) + header[4]; byte[] record = new byte[payloadSize + headerSize]; Buffer.BlockCopy(header, 0, record, 0, headerSize); int received = ForceRead(record, headerSize, payloadSize); GlobalLog.Dump(record); if (received < payloadSize) { GlobalLog.Print("RecordLayer::ReadFullRecord returning null"); return(null); } return(record); }
// // Handshake - the Handshake is perhaps the most important part of the SSL process, // this is a Handshake protocol between server & client, where we send a // a HELLO message / server responds, we respond back, and after a few round trips, // we have an SSL connection with the server. But this process may be repeated, // if a higher level of security is required for by the server, therefore, // this function may be called several times in the life of the connection. // // returns an Exception on error, containing the error code of the failure // private Exception Handshake(ProtocolToken message) { // // With some SSPI APIs, the SSPI wrapper may throw // uncaught Win32Exceptions, so we need to add // this try - catch here. // try { int round = 0; byte[] incoming = null; // will be null == message on connection creation/otherwise should be // renegotation if (message == null) { GlobalLog.Assert( (SecureChannel == null), "had assembed a null SecureChannel at this point", "SecureChannel != null"); m_SecureChannel = new SecureChannel(m_DestinationHost, m_ClientCertificates); } else { incoming = message.Payload; } do { GlobalLog.Print("Handshake::Round #" + round); // // this code runs in the constructor, hence there's no // way SecureChannel can become null // message = SecureChannel.NextMessage(incoming); #if TRAVE GlobalLog.Print("Handshake::generating TLS message(Status:" + SecureChannel.MapSecurityStatus((uint)message.Status) + " Done:" + message.Done.ToString() + ")"); #endif if (message.Failed) { break; } if (message.Payload != null) { GlobalLog.Print("Handshake::Outgoing message size: " + message.Payload.Length); GlobalLog.Dump(message.Payload); base.Write(message.Payload, 0, message.Payload.Length); } else { GlobalLog.Print("Handshake::No message necessary."); } if (message.Done) { break; } // // ReadFullRecord attempts to parse read data // from the byte stream, this can be dangerous as its not // always sure about protocols, at this point // incoming = ReadFullRecord(null, 0); if (incoming == null) { // // Handshake failed // GlobalLog.Print("Handshake::ReadFullRecord is null, Handshake failed"); GlobalLog.Assert( (!message.Done), "attempted bad return / must always fail", "message.Done"); return(message.GetException()); } GlobalLog.Print("Handshake::Incoming message size: " + incoming.Length); round++; } while (!message.Done); if (message.Done) { SecureChannel.ProcessHandshakeSuccess(); GlobalLog.Print("Handshake::Handshake completed successfully."); } else { // SEC_I_CONTINUE_NEEDED #if TRAVE GlobalLog.Print("Handshake::FAILED Handshake, last error: " + SecureChannel.MapSecurityStatus((uint)message.Status)); #endif } return(message.GetException()); } catch (Exception exception) { return(exception); } }
// // Used only by client SSL code, never returns null. // internal static string[] GetRequestCertificateAuthorities(SafeDeleteContext securityContext) { Interop.SspiCli.IssuerListInfoEx issuerList = (Interop.SspiCli.IssuerListInfoEx)SSPIWrapper.QueryContextAttributes( GlobalSSPI.SSPISecureChannel, securityContext, Interop.SspiCli.ContextAttribute.IssuerListInfoEx); string[] issuers = Array.Empty <string>(); try { if (issuerList.cIssuers > 0) { unsafe { uint count = issuerList.cIssuers; issuers = new string[issuerList.cIssuers]; Interop.SspiCli._CERT_CHAIN_ELEMENT *pIL = (Interop.SspiCli._CERT_CHAIN_ELEMENT *)issuerList.aIssuers.DangerousGetHandle(); for (int i = 0; i < count; ++i) { Interop.SspiCli._CERT_CHAIN_ELEMENT *pIL2 = pIL + i; if (pIL2->cbSize <= 0) { if (GlobalLog.IsEnabled) { GlobalLog.Assert("SecureChannel::GetIssuers()", "Interop.SspiCli._CERT_CHAIN_ELEMENT size is not positive: " + pIL2->cbSize.ToString()); } Debug.Fail("SecureChannel::GetIssuers()", "Interop.SspiCli._CERT_CHAIN_ELEMENT size is not positive: " + pIL2->cbSize.ToString()); } if (pIL2->cbSize > 0) { uint size = pIL2->cbSize; byte * ptr = (byte *)(pIL2->pCertContext); byte[] x = new byte[size]; for (int j = 0; j < size; j++) { x[j] = *(ptr + j); } X500DistinguishedName x500DistinguishedName = new X500DistinguishedName(x); issuers[i] = x500DistinguishedName.Name; if (GlobalLog.IsEnabled) { GlobalLog.Print("SecureChannel#" + LoggingHash.HashString(securityContext) + "::GetIssuers() IssuerListEx[" + i + "]:" + issuers[i]); } } } } } } finally { if (issuerList.aIssuers != null) { issuerList.aIssuers.Dispose(); } } return(issuers); }
//Caution, this will return ipv6 addresses if the OS supports it. This shouldn't be called by the public apis. internal static IPHostEntry InternalResolveFast(string hostName, int timeout, out bool timedOut) { GlobalLog.Assert(hostName != null, "hostName == null"); GlobalLog.Print("Dns.InternalResolveFase: " + hostName); // // the differences between this method and the previous InternalResolve() are: // // 1) we don't throw any exceptions // 2) we don't do a reverse lookup for address strings, we just use them // // IPv6 Changes: It is not practical to embed the code for GetAddrInfo here, instead // we call it and catch any exceptions. // // Timeout: Supports a timeout by offloading work to another thread if necessary. // // We can't abort a DNS lookup so if we think might need to, run it on another thread. // According to MSDN the max time is 17 seconds. Use 18 and say 20. // Also: MSDN describes how one lookup can result in a string of queries. It's unclear whether // those would be run in series, extending the possible time this will take, or whether it will always // give up after 17 seconds. For now assume that 17 seconds is the absolute max. bool mightTimeOut = 18000 >= (uint)timeout && timeout != Timeout.Infinite; timedOut = false; if (hostName.Length > 0 && hostName.Length <= MaxHostName) { // IP Address? IPAddress address; if (TryParseAsIP(hostName, out address)) { IPHostEntry ipHostEntry = new IPHostEntry(); ipHostEntry.HostName = address.ToString(); ipHostEntry.Aliases = new string[0]; ipHostEntry.AddressList = new IPAddress[] { address }; GlobalLog.Print("Dns::InternalResolveFast() returned address:" + address.ToString()); return(ipHostEntry); } // Looks like a hostname (or failed address parsing) if (Socket.OSSupportsIPv6) { try { // we will no longer offload to a thread, due to the consequence of having a threadpool thread //block on another threadpool thread. In addition, even w/ the DNS server functioning, we run // the risk of having too many of these queued up, causing requests to fail w/ an unable to resolve //exception. //I'm leaving the code commented out to possibly reuse in our async case. // if (!mightTimeOut) // { return(GetAddrInfo(hostName)); // } /* else * { * AsyncDnsContext dnsContext = new AsyncDnsContext(hostName); * dnsContext.Offload(new WaitCallback(OffloadedGetAddrInfo)); * return (IPHostEntry) dnsContext.Wait(timeout, out timedOut); * } */ } catch (Exception e) { GlobalLog.Print("Dns::InternalResolveFast() GetAddrInfo() threw: " + e.Message); } } else { // // we duplicate the code in GetHostByName() to avoid // having to catch the thrown exception // IntPtr nativePointer; //if (!mightTimeOut) //{ nativePointer = UnsafeNclNativeMethods.OSSOCK.gethostbyname(hostName); //} /* * else * { * AsyncDnsContext dnsContext = new AsyncDnsContext(hostName); * dnsContext.Offload(new WaitCallback(OffloadedGetHostByName)); * object result = dnsContext.Wait(timeout, out timedOut); * nativePointer = result == null ? IntPtr.Zero : (IntPtr) result; * } */ if (nativePointer != IntPtr.Zero) { GlobalLog.Print("Dns::InternalResolveFast() gethostbyname() returned nativePointer:" + nativePointer.ToString()); return(NativeToHostEntry(nativePointer)); } } } GlobalLog.Print("Dns::InternalResolveFast() returning null"); if (Logging.On) { Logging.Exit(Logging.Sockets, "DNS", "InternalResolveFast", null); } return(null); }
// // Security: We temporarily reset thread token to open the cert store under process account. // internal static X509Store EnsureStoreOpened(bool isMachineStore) { X509Store store = isMachineStore ? s_myMachineCertStoreEx : s_myCertStoreEx; // TODO #3862 Investigate if this can be switched to either the static or Lazy<T> patterns. if (Volatile.Read(ref store) == null) { lock (s_syncObject) { store = isMachineStore ? s_myMachineCertStoreEx : s_myCertStoreEx; if (Volatile.Read(ref store) == null) { // NOTE: that if this call fails we won't keep track and the next time we enter we will try to open the store again. StoreLocation storeLocation = isMachineStore ? StoreLocation.LocalMachine : StoreLocation.CurrentUser; store = new X509Store(StoreName.My, storeLocation); try { // For app-compat We want to ensure the store is opened under the **process** account. try { WindowsIdentity.RunImpersonated(SafeAccessTokenHandle.InvalidHandle, () => { store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly); if (GlobalLog.IsEnabled) { GlobalLog.Print("SecureChannel::EnsureStoreOpened() storeLocation:" + storeLocation + " returned store:" + store.GetHashCode().ToString("x")); } }); } catch { throw; } if (isMachineStore) { s_myMachineCertStoreEx = store; } else { s_myCertStoreEx = store; } return(store); } catch (Exception exception) { if (exception is CryptographicException || exception is SecurityException) { if (GlobalLog.IsEnabled) { GlobalLog.Assert("SecureChannel::EnsureStoreOpened()", "Failed to open cert store, location:" + storeLocation + " exception:" + exception); } Debug.Fail("SecureChannel::EnsureStoreOpened()", "Failed to open cert store, location:" + storeLocation + " exception:" + exception); return(null); } if (NetEventSource.Log.IsEnabled()) { NetEventSource.PrintError(NetEventSource.ComponentType.Security, SR.Format(SR.net_log_open_store_failed, storeLocation, exception)); } throw; } } } } return(store); }