// If ContextCopy or Identity will be used, the return value should be locked until FinishPostingAsyncOp() is called // or the operation has been aborted (e.g. by BeginXxx throwing). Otherwise, this can be called with false to prevent the lock // object from being created. internal object StartPostingAsyncOp(bool lockCapture) { if (InternalPeekCompleted) { NetEventSource.Fail(this, "Called on completed result."); } DebugProtectState(true); _lock = lockCapture ? new object() : null; _flags |= StateFlags.PostBlockStarted; return(_lock); }
public AsyncProtocolRequest(LazyAsyncResult userAsyncResult, CancellationToken cancellationToken) { if (userAsyncResult == null) { NetEventSource.Fail(this, "userAsyncResult == null"); } if (userAsyncResult.InternalPeekCompleted) { NetEventSource.Fail(this, "userAsyncResult is already completed."); } UserAsyncResult = userAsyncResult; CancellationToken = cancellationToken; }
private string GetClientSpecifiedSpn() { if (!(IsValidContext && IsCompleted)) { NetEventSource.Fail(this, "Trying to get the client SPN before handshaking is done!"); } string spn = NegotiateStreamPal.QueryContextClientSpecifiedSpn(_securityContext); if (NetEventSource.IsEnabled) { NetEventSource.Info(this, $"The client specified SPN is [{spn}]"); } return(spn); }
internal static void ThreadContract(ThreadKinds kind, ThreadKinds allowedSources, string errorMsg) { if ((kind & ThreadKinds.SourceMask) != ThreadKinds.Unknown || (allowedSources & ThreadKinds.SourceMask) != allowedSources) { throw new InternalException(); } if (NetEventSource.IsEnabled) { ThreadKinds threadKind = CurrentThreadKind; if ((threadKind & allowedSources) != 0) { NetEventSource.Fail(null, $"Thread Contract Violation.|Expected source:({allowedSources}) Actual source:({threadKind & ThreadKinds.SourceMask})"); } if ((threadKind & kind) == kind) { NetEventSource.Fail(null, $"Thread Contract Violation.|Expected kind:({kind}) Actual kind:({threadKind & ~ThreadKinds.SourceMask})"); } } }
// // Used only by client SSL code, never returns null. // internal static string[] GetRequestCertificateAuthorities(SafeDeleteContext securityContext) { Interop.SspiCli.SecPkgContext_IssuerListInfoEx issuerList = default; bool success = SSPIWrapper.QueryContextAttributes_SECPKG_ATTR_ISSUER_LIST_EX(GlobalSSPI.SSPISecureChannel, securityContext, ref issuerList, out SafeHandle sspiHandle); string[] issuers = Array.Empty <string>(); try { if (success && issuerList.cIssuers > 0) { unsafe { issuers = new string[issuerList.cIssuers]; var elements = new Span <Interop.SspiCli.CERT_CHAIN_ELEMENT>((void *)sspiHandle.DangerousGetHandle(), issuers.Length); for (int i = 0; i < elements.Length; ++i) { if (elements[i].cbSize <= 0) { NetEventSource.Fail(securityContext, $"Interop.SspiCli._CERT_CHAIN_ELEMENT size is not positive: {elements[i].cbSize}"); } if (elements[i].cbSize > 0) { byte[] x = new Span <byte>((byte *)elements[i].pCertContext, checked ((int)elements[i].cbSize)).ToArray(); var x500DistinguishedName = new X500DistinguishedName(x); issuers[i] = x500DistinguishedName.Name; if (NetEventSource.IsEnabled) { NetEventSource.Info(securityContext, "IssuerListEx[{issuers[i]}]"); } } } } } } finally { sspiHandle?.Dispose(); } return(issuers); }
internal SafeDeleteContext GetContext(out SecurityStatusPal status) { status = new SecurityStatusPal(SecurityStatusPalErrorCode.OK); if (!(IsCompleted && IsValidContext)) { NetEventSource.Fail(this, "Should be called only when completed with success, currently is not!"); } if (!IsServer) { NetEventSource.Fail(this, "The method must not be called by the client side!"); } if (!IsValidContext) { status = new SecurityStatusPal(SecurityStatusPalErrorCode.InvalidHandle); return(null); } return(_securityContext); }
internal unsafe SecPkgContext_Sizes(byte[] memory) { fixed(void *voidPtr = memory) { IntPtr unmanagedAddress = new IntPtr(voidPtr); try { // TODO (Issue #3114): replace with Marshal.PtrToStructure. cbMaxToken = (int)checked ((uint)Marshal.ReadInt32(unmanagedAddress)); cbMaxSignature = (int)checked ((uint)Marshal.ReadInt32(unmanagedAddress, 4)); cbBlockSize = (int)checked ((uint)Marshal.ReadInt32(unmanagedAddress, 8)); cbSecurityTrailer = (int)checked ((uint)Marshal.ReadInt32(unmanagedAddress, 12)); } catch (OverflowException) { NetEventSource.Fail(this, "Negative size."); throw; } } }
private static X509Store EnsureStoreOpened(ref X509Store storeField, StoreLocation storeLocation) { return(LazyInitializer.EnsureInitialized(ref storeField, ref s_lockObject, () => { try { X509Store store = new X509Store(StoreName.My, storeLocation); store.Open(OpenFlags.ReadOnly); if (NetEventSource.IsEnabled) { NetEventSource.Info(null, $"storeLocation: {storeLocation} returned store {store}"); } return store; } catch (CryptographicException e) { NetEventSource.Fail(null, $"Failed to open cert store, location: {storeLocation} exception {e}"); 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, _timers); // Add this on the tail. (Actually, one before the tail - _timers is the sentinel tail.) bool needProd = false; lock (_timers) { if (!(_timers.Prev.Next == _timers)) { NetEventSource.Fail(this, $"Tail corruption."); } // If this is the first timer in the list, we need to create a queue handle and prod the timer thread. if (_timers.Next == _timers) { if (_thisHandle == IntPtr.Zero) { _thisHandle = (IntPtr)GCHandle.Alloc(this); } needProd = true; } timer.Next = _timers; timer.Prev = _timers.Prev; _timers.Prev.Next = timer; _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); }
internal static void SetThreadSource(ThreadKinds source) { if ((source & ThreadKinds.SourceMask) != source || source == ThreadKinds.Unknown) { throw new ArgumentException("Must specify the thread source.", nameof(source)); } if (ThreadKindStack.Count == 0) { ThreadKindStack.Push(source); return; } if (ThreadKindStack.Count > 1) { if (NetEventSource.IsEnabled) { NetEventSource.Error(null, "SetThreadSource must be called at the base of the stack, or the stack has been corrupted."); } while (ThreadKindStack.Count > 1) { ThreadKindStack.Pop(); } } if (ThreadKindStack.Peek() != source) { if (NetEventSource.IsEnabled) { NetEventSource.Error(null, "The stack has been corrupted."); } ThreadKinds last = ThreadKindStack.Pop() & ThreadKinds.SourceMask; if (last != source && last != ThreadKinds.Other && NetEventSource.IsEnabled) { NetEventSource.Fail(null, $"Thread source changed.|Was:({last}) Now:({source})"); } ThreadKindStack.Push(source); } }
public void Reset(LazyAsyncResult userAsyncResult) { if (userAsyncResult == null) { NetEventSource.Fail(this, "userAsyncResult == null"); } if (userAsyncResult.InternalPeekCompleted) { NetEventSource.Fail(this, "userAsyncResult is already completed."); } UserAsyncResult = userAsyncResult; _callback = null; _completionStatus = 0; Result = 0; AsyncState = null; Buffer = null; Offset = 0; Count = 0; #if DEBUG _debugAsyncChain = 0; #endif }
internal unsafe SecPkgContext_ConnectionInfo(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) { NetEventSource.Fail(this, "Negative size"); throw; } } }
private static void ReadCallback(IAsyncResult transportResult) { if (!(transportResult.AsyncState is FixedSizeReader)) { NetEventSource.Fail(null, "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._transport.EndRead(transportResult); if (reader.CheckCompletionBeforeNextRead(bytes)) { return; } reader.StartReading(); } catch (Exception e) { if (request.IsUserCompleted) { throw; } request.CompleteUserWithError(e); } }
public unsafe int DecryptMessage(SafeDeleteContext context, ref Interop.SspiCli.SecBufferDesc inputOutput, uint sequenceNumber) { int status = (int)Interop.SECURITY_STATUS.InvalidHandle; uint qop = 0; try { bool ignore = false; context.DangerousAddRef(ref ignore); status = Interop.SspiCli.DecryptMessage(ref context._handle, ref inputOutput, sequenceNumber, &qop); } finally { context.DangerousRelease(); } if (status == 0 && qop == Interop.SspiCli.SECQOP_WRAP_NO_ENCRYPT) { NetEventSource.Fail(this, $"Expected qop = 0, returned value = {qop}"); throw new InvalidOperationException(SR.net_auth_message_not_encrypted); } return(status); }
private PipelineInstruction QueueOrCreateDataConection(PipelineEntry entry, ResponseDescription response, bool timeout, ref Stream stream, out bool isSocketReady) { isSocketReady = false; if (_dataHandshakeStarted) { isSocketReady = true; return(PipelineInstruction.Pause); //if we already started then this is re-entering into the callback where we proceed with the stream } _dataHandshakeStarted = true; // Handle passive responses by parsing the port and later doing a Connect(...) bool isPassive = false; int port = -1; if (entry.Command == "PASV\r\n" || entry.Command == "EPSV\r\n") { if (!response.PositiveCompletion) { _abortReason = SR.Format(SR.net_ftp_server_failed_passive, response.Status); return(PipelineInstruction.Abort); } if (entry.Command == "PASV\r\n") { port = GetPortV4(response.StatusDescription); } else { port = GetPortV6(response.StatusDescription); } isPassive = true; } if (isPassive) { if (port == -1) { NetEventSource.Fail(this, "'port' not set."); } try { _dataSocket = CreateFtpDataSocket((FtpWebRequest)_request, Socket); } catch (ObjectDisposedException) { throw ExceptionHelper.RequestAbortedException; } IPEndPoint localEndPoint = new IPEndPoint(((IPEndPoint)Socket.LocalEndPoint).Address, 0); _dataSocket.Bind(localEndPoint); _passiveEndPoint = new IPEndPoint(ServerAddress, port); } PipelineInstruction result; if (_passiveEndPoint != null) { IPEndPoint passiveEndPoint = _passiveEndPoint; _passiveEndPoint = null; if (NetEventSource.IsEnabled) { NetEventSource.Info(this, "starting Connect()"); } if (_isAsync) { _dataSocket.BeginConnect(passiveEndPoint, s_connectCallbackDelegate, this); result = PipelineInstruction.Pause; } else { _dataSocket.Connect(passiveEndPoint); result = PipelineInstruction.Advance; // for passive mode we end up going to the next command } } else { if (NetEventSource.IsEnabled) { NetEventSource.Info(this, "starting Accept()"); } if (_isAsync) { _dataSocket.BeginAccept(s_acceptCallbackDelegate, this); result = PipelineInstruction.Pause; } else { Socket listenSocket = _dataSocket; try { _dataSocket = _dataSocket.Accept(); if (!ServerAddress.Equals(((IPEndPoint)_dataSocket.RemoteEndPoint).Address)) { _dataSocket.Close(); throw new WebException(SR.net_ftp_active_address_different, WebExceptionStatus.ProtocolError); } isSocketReady = true; // for active mode we end up creating a stream before advancing the pipeline result = PipelineInstruction.Pause; } finally { listenSocket.Close(); } } } return(result); }
private static unsafe int EncryptDecryptHelper(OP op, SSPIInterface secModule, SafeDeleteContext context, SecurityBuffer[] input, uint sequenceNumber) { Interop.SspiCli.SecBufferDesc sdcInOut = new Interop.SspiCli.SecBufferDesc(input.Length); var unmanagedBuffer = new Interop.SspiCli.SecBuffer[input.Length]; fixed(Interop.SspiCli.SecBuffer *unmanagedBufferPtr = unmanagedBuffer) { sdcInOut.pBuffers = 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].cbBuffer = iBuffer.size; unmanagedBuffer[i].BufferType = iBuffer.type; if (iBuffer.token == null || iBuffer.token.Length == 0) { unmanagedBuffer[i].pvBuffer = IntPtr.Zero; } else { pinnedBuffers[i] = GCHandle.Alloc(iBuffer.token, GCHandleType.Pinned); unmanagedBuffer[i].pvBuffer = 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 = secModule.EncryptMessage(context, ref sdcInOut, sequenceNumber); break; case OP.Decrypt: errorCode = secModule.DecryptMessage(context, ref sdcInOut, sequenceNumber); break; case OP.MakeSignature: errorCode = secModule.MakeSignature(context, ref sdcInOut, sequenceNumber); break; case OP.VerifySignature: errorCode = secModule.VerifySignature(context, ref sdcInOut, sequenceNumber); break; default: NetEventSource.Fail(null, $"Unknown OP: {op}"); throw NotImplemented.ByDesignWithMessage(Strings.net_MethodNotImplementedException); } // Marshalling back returned sizes / data. for (int i = 0; i < input.Length; i++) { SecurityBuffer iBuffer = input[i]; iBuffer.size = unmanagedBuffer[i].cbBuffer; iBuffer.type = unmanagedBuffer[i].BufferType; 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].pvBuffer >= bufferAddress && (byte *)unmanagedBuffer[i].pvBuffer + iBuffer.size <= bufferAddress + buffers[j].Length) { iBuffer.offset = (int)((byte *)unmanagedBuffer[i].pvBuffer - bufferAddress); iBuffer.token = buffers[j]; break; } } if (j >= input.Length) { NetEventSource.Fail(null, "Output buffer out of range."); iBuffer.size = 0; iBuffer.offset = 0; iBuffer.token = null; } } } // Backup validate the new sizes. if (iBuffer.offset < 0 || iBuffer.offset > (iBuffer.token == null ? 0 : iBuffer.token.Length)) { NetEventSource.Fail(null, $"'offset' out of range. [{iBuffer.offset}]"); } if (iBuffer.size < 0 || iBuffer.size > (iBuffer.token == null ? 0 : iBuffer.token.Length - iBuffer.offset)) { NetEventSource.Fail(null, $"'size' out of range. [{iBuffer.size}]"); } } if (NetEventSource.IsEnabled && errorCode != 0) { if (errorCode == Interop.SspiCli.SEC_I_RENEGOTIATE) { NetEventSource.Error(null, System.StringsHelper.Format(Strings.event_OperationReturnedSomething, op, "SEC_I_RENEGOTIATE")); } else { NetEventSource.Error(null, System.StringsHelper.Format(Strings.net_log_operation_failed_with_error, op, $"0x{0:X}")); } } return(errorCode); } finally { for (int i = 0; i < pinnedBuffers.Length; ++i) { if (pinnedBuffers[i].IsAllocated) { pinnedBuffers[i].Free(); } } } } }
// This must be called right before returning the result to the user. It might call the callback itself, // to avoid flowing context. Even if the operation completes before this call, the callback won't have been // called. // // Returns whether the operation completed sync or not. private bool CaptureOrComplete(ref ExecutionContext cachedContext, bool returnContext) { if ((_flags & StateFlags.PostBlockStarted) == 0) { NetEventSource.Fail(this, "Called without calling StartPostingAsyncOp."); } // See if we're going to need to capture the context. bool capturingContext = AsyncCallback != null || (_flags & StateFlags.CaptureContext) != 0; // Peek if we've already completed, but don't fix CompletedSynchronously yet // Capture the identity if requested, unless we're going to capture the context anyway, unless // capturing the context won't be sufficient. if ((_flags & StateFlags.CaptureIdentity) != 0 && !InternalPeekCompleted && (!capturingContext)) { if (NetEventSource.IsEnabled) NetEventSource.Info(this, "starting identity capture"); SafeCaptureIdentity(); } // No need to flow if there's no callback, unless it's been specifically requested. // Note that Capture() can return null, for example if SuppressFlow() is in effect. if (capturingContext && !InternalPeekCompleted) { if (NetEventSource.IsEnabled) NetEventSource.Info(this, "starting capture"); if (cachedContext == null) { cachedContext = ExecutionContext.Capture(); } if (cachedContext != null) { if (!returnContext) { _context = cachedContext; cachedContext = null; } else { _context = cachedContext; } } if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"_context:{_context}"); } else { // Otherwise we have to have completed synchronously, or not needed the context. if (NetEventSource.IsEnabled) NetEventSource.Info(this, "Skipping capture"); cachedContext = null; if (AsyncCallback != null && !CompletedSynchronously) { NetEventSource.Fail(this, "Didn't capture context, but didn't complete synchronously!"); } } // Now we want to see for sure what to do. We might have just captured the context for no reason. // This has to be the first time the state has been queried "for real" (apart from InvokeCallback) // to guarantee synchronization with Complete() (otherwise, Complete() could try to call the // callback without the context having been gotten). DebugProtectState(false); if (CompletedSynchronously) { if (NetEventSource.IsEnabled) NetEventSource.Info(this, "Completing synchronously"); base.Complete(IntPtr.Zero); return true; } return false; }
// IO COMPLETION CALLBACK // // This callback is responsible for getting the complete protocol frame. // 1. it reads the header. // 2. it determines the frame size. // 3. loops while not all frame received or an error. // private void ReadFrameComplete(IAsyncResult transportResult) { do { if (!(transportResult.AsyncState is WorkerAsyncResult)) { NetEventSource.Fail(this, $"The state expected to be WorkerAsyncResult, received {transportResult}."); } WorkerAsyncResult workerResult = (WorkerAsyncResult)transportResult.AsyncState; int bytesRead = TaskToApm.End <int>(transportResult); workerResult.Offset += bytesRead; if (!(workerResult.Offset <= workerResult.End)) { NetEventSource.Fail(this, $"WRONG: offset - end = {workerResult.Offset - workerResult.End}"); } if (bytesRead <= 0) { // (by design) This indicates the stream has receives EOF // If we are in the middle of a Frame - fail, otherwise - produce EOF object result = null; if (!workerResult.HeaderDone && workerResult.Offset == 0) { result = (object)-1; } else { result = new System.IO.IOException(SR.net_frame_read_io); } workerResult.InvokeCallback(result); return; } if (workerResult.Offset >= workerResult.End) { if (!workerResult.HeaderDone) { workerResult.HeaderDone = true; // This indicates the header has been read successfully _curReadHeader.CopyFrom(workerResult.Buffer, 0, _readVerifier); int payloadSize = _curReadHeader.PayloadSize; if (payloadSize < 0) { // Let's call user callback and he call us back and we will throw workerResult.InvokeCallback(new System.IO.IOException(SR.Format(SR.net_frame_read_size))); } if (payloadSize == 0) { // report empty frame (NOT eof!) to the caller, he might be interested in workerResult.InvokeCallback(0); return; } if (payloadSize > _curReadHeader.MaxMessageSize) { throw new InvalidOperationException(SR.Format(SR.net_frame_size, _curReadHeader.MaxMessageSize.ToString(NumberFormatInfo.InvariantInfo), payloadSize.ToString(NumberFormatInfo.InvariantInfo))); } // Start reading the remaining frame data (note header does not count). byte[] frame = new byte[payloadSize]; // Save the ref of the data block workerResult.Buffer = frame; workerResult.End = frame.Length; workerResult.Offset = 0; // Transport.ReadAsync below will pickup those changes. } else { workerResult.HeaderDone = false; // Reset for optional object reuse. workerResult.InvokeCallback(workerResult.End); return; } } // This means we need more data to complete the data block. transportResult = TaskToApm.Begin(_transport.ReadAsync(workerResult.Buffer, workerResult.Offset, workerResult.End - workerResult.Offset), _readFrameCallback, workerResult); } while (transportResult.CompletedSynchronously); }
// // 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 (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); if (NetEventSource.IsEnabled) { NetEventSource.Info(null, $"storeLocation {storeLocation} returned store: {store}"); } }); } catch { throw; } if (isMachineStore) { s_myMachineCertStoreEx = store; } else { s_myCertStoreEx = store; } return(store); } catch (Exception exception) { if (exception is CryptographicException || exception is SecurityException) { NetEventSource.Fail(null, $"Failed to open cert store, location: {storeLocation} exception: {exception}"); return(null); } if (NetEventSource.IsEnabled) { NetEventSource.Error(null, SR.Format(SR.net_log_open_store_failed, storeLocation, exception)); } throw; } } } } return(store); }
internal static X509Store EnsureStoreOpened(bool isMachineStore) { X509Store store = isMachineStore ? s_myMachineCertStoreEx : s_myCertStoreEx; if (store == null) { StoreLocation storeLocation = isMachineStore ? StoreLocation.LocalMachine : StoreLocation.CurrentUser; // On Windows and OSX CheckSupportsStore is not defined, so the call is eliminated and the // if should be folded out. // // On Unix it will prevent the lock from being held and released over and over for the LocalMachine store. bool supportsStore = true; CheckSupportsStore(storeLocation, ref supportsStore); if (!supportsStore) { return(null); } lock (s_syncObject) { store = isMachineStore ? s_myMachineCertStoreEx : s_myCertStoreEx; if (store == null) { try { // 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. store = OpenStore(storeLocation); if (NetEventSource.IsEnabled) { NetEventSource.Info(null, $"storeLocation: {storeLocation} returned store {store}"); } if (isMachineStore) { s_myMachineCertStoreEx = store; } else { s_myCertStoreEx = store; } } catch (Exception exception) { if (exception is CryptographicException || exception is SecurityException) { NetEventSource.Fail(null, $"Failed to open cert store, location: {storeLocation} exception: {exception}"); return(null); } if (NetEventSource.IsEnabled) { NetEventSource.Error(null, SR.Format(SR.net_log_open_store_failed, storeLocation, exception)); } throw; } } } } return(store); }