// This method is guaranteed to be called only once. If called with a non-zero userToken, the context is not flowed. protected override void Complete(IntPtr userToken) { if (GlobalLog.IsEnabled) { GlobalLog.Print("ContextAwareResult#" + LoggingHash.HashString(this) + "::Complete() _Context(set):" + (_context != null).ToString() + " userToken:" + userToken.ToString()); } // If no flowing, just complete regularly. if ((_flags & StateFlags.PostBlockStarted) == 0) { base.Complete(userToken); return; } // At this point, IsCompleted is set and CompletedSynchronously is fixed. If it's synchronous, then we want to hold // the completion for the CaptureOrComplete() call to avoid the context flow. If not, we know CaptureOrComplete() has completed. if (CompletedSynchronously) { return; } ExecutionContext context = _context; // If the context is being abandoned or wasn't captured (SuppressFlow, null AsyncCallback), just // complete regularly, as long as CaptureOrComplete() has finished. // if (userToken != IntPtr.Zero || context == null) { base.Complete(userToken); return; } ExecutionContext.Run(context, s => ((ContextAwareResult)s).CompleteCallback(), this); }
internal virtual void Abort(Exception e) { if (GlobalLog.IsEnabled) { GlobalLog.Print("CommandStream" + LoggingHash.HashString(this) + "::Abort() - closing control Stream"); } lock (this) { if (_aborted) { return; } _aborted = true; } try { base.Close(0); } finally { if (e != null) { InvokeRequestCallback(e); } else { InvokeRequestCallback(null); } } }
public static SecurityStatusPal EncryptMessage(SafeDeleteContext securityContext, byte[] writeBuffer, int size, int headerSize, int trailerSize, out int resultSize) { // Encryption using SCHANNEL requires 4 buffers: header, payload, trailer, empty. SecurityBuffer[] securityBuffer = new SecurityBuffer[4]; securityBuffer[0] = new SecurityBuffer(writeBuffer, 0, headerSize, SecurityBufferType.Header); securityBuffer[1] = new SecurityBuffer(writeBuffer, headerSize, size, SecurityBufferType.Data); securityBuffer[2] = new SecurityBuffer(writeBuffer, headerSize + size, trailerSize, SecurityBufferType.Trailer); securityBuffer[3] = new SecurityBuffer(null, SecurityBufferType.Empty); int errorCode = SSPIWrapper.EncryptMessage(GlobalSSPI.SSPISecureChannel, securityContext, securityBuffer, 0); if (errorCode != 0) { if (GlobalLog.IsEnabled) { GlobalLog.Print("SslStreamPal.Windows: SecureChannel#" + LoggingHash.HashString(securityContext) + "::Encrypt ERROR" + errorCode.ToString("x")); } resultSize = 0; } else { // The full buffer may not be used. resultSize = securityBuffer[0].size + securityBuffer[1].size + securityBuffer[2].size; } return(GetSecurityStatusPalFromWin32Int(errorCode)); }
internal SafeDeleteContext GetContext(out SecurityStatusPal status) { status = new SecurityStatusPal(SecurityStatusPalErrorCode.OK); if (!(IsCompleted && IsValidContext)) { if (GlobalLog.IsEnabled) { GlobalLog.AssertFormat("NTAuthentication#{0}::GetContextToken|Should be called only when completed with success, currently is not!", LoggingHash.HashString(this)); } Debug.Fail("NTAuthentication#" + LoggingHash.HashString(this) + "::GetContextToken |Should be called only when completed with success, currently is not!"); } if (!IsServer) { if (GlobalLog.IsEnabled) { GlobalLog.AssertFormat("NTAuthentication#{0}::GetContextToken|The method must not be called by the client side!", LoggingHash.HashString(this)); } Debug.Fail("NTAuthentication#" + LoggingHash.HashString(this) + "::GetContextToken |The method must not be called by the client side!"); } if (!IsValidContext) { status = new SecurityStatusPal(SecurityStatusPalErrorCode.InvalidHandle); return(null); } return(_securityContext); }
public static SafeFreeContextBufferChannelBinding QueryContextChannelBinding(SSPIInterface secModule, SafeDeleteContext securityContext, Interop.SspiCli.ContextAttribute contextAttribute) { if (GlobalLog.IsEnabled) { GlobalLog.Enter("QueryContextChannelBinding", contextAttribute.ToString()); } SafeFreeContextBufferChannelBinding result; int errorCode = secModule.QueryContextChannelBinding(securityContext, contextAttribute, out result); if (errorCode != 0) { if (GlobalLog.IsEnabled) { GlobalLog.Leave("QueryContextChannelBinding", "ERROR = " + ErrorDescription(errorCode)); } return(null); } if (GlobalLog.IsEnabled) { GlobalLog.Leave("QueryContextChannelBinding", LoggingHash.HashString(result)); } return(result); }
private object _event; // Lazy allocated event to be returned in the IAsyncResult for the client to wait on. internal LazyAsyncResult(object myObject, object myState, AsyncCallback myCallBack) { _asyncObject = myObject; _asyncState = myState; _asyncCallback = myCallBack; _result = DBNull.Value; GlobalLog.Print("LazyAsyncResult#" + LoggingHash.HashString(this) + "::.ctor()"); }
public static 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. try { int bufferSizeNeeded = checked (size + headerSize + trailerSize); if (output == null || output.Length < bufferSizeNeeded) { output = new byte[bufferSizeNeeded]; } } catch (Exception e) { if (!ExceptionCheck.IsFatal(e)) { 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; } byte[] writeBuffer = output; // Copy the input into the output buffer to prepare for SCHANNEL's expectations Buffer.BlockCopy(input, offset, writeBuffer, headerSize, size); // Encryption using SCHANNEL requires 4 buffers: header, payload, trailer, empty. SecurityBuffer[] securityBuffer = new SecurityBuffer[4]; securityBuffer[0] = new SecurityBuffer(writeBuffer, 0, headerSize, SecurityBufferType.Header); securityBuffer[1] = new SecurityBuffer(writeBuffer, headerSize, size, SecurityBufferType.Data); securityBuffer[2] = new SecurityBuffer(writeBuffer, headerSize + size, trailerSize, SecurityBufferType.Trailer); securityBuffer[3] = new SecurityBuffer(null, SecurityBufferType.Empty); int errorCode = SSPIWrapper.EncryptMessage(GlobalSSPI.SSPISecureChannel, securityContext, securityBuffer, 0); if (errorCode != 0) { if (GlobalLog.IsEnabled) { GlobalLog.Print("SslStreamPal.Windows: SecureChannel#" + LoggingHash.HashString(securityContext) + "::Encrypt ERROR" + errorCode.ToString("x")); } resultSize = 0; } else { // The full buffer may not be used. resultSize = securityBuffer[0].size + securityBuffer[1].size + securityBuffer[2].size; } return(SecurityStatusAdapterPal.GetSecurityStatusPalFromNativeInt(errorCode)); }
// // 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 (GlobalLog.IsEnabled && pIL2->cbSize <= 0) { GlobalLog.Assert("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); }
private void CompleteCallback() { if (GlobalLog.IsEnabled) { GlobalLog.Print("ContextAwareResult#" + LoggingHash.HashString(this) + "::CompleteCallback() Context set, calling callback."); } base.Complete(IntPtr.Zero); }
// NOTE: THIS METHOD MUST NOT BE CALLED DIRECTLY. // // This method does the callback's job and is guaranteed to be called exactly once. // A derived overriding method must call the base class somewhere or the completion is lost. protected virtual void Complete(IntPtr userToken) { bool offloaded = false; ThreadContext threadContext = CurrentThreadContext; try { bool globalLogEnabled = GlobalLog.IsEnabled; ++threadContext._nestedIOCount; if (_asyncCallback != null) { if (globalLogEnabled) { GlobalLog.Print("LazyAsyncResult#" + LoggingHash.HashString(this) + "::Complete() invoking callback"); } if (threadContext._nestedIOCount >= ForceAsyncCount) { if (globalLogEnabled) { GlobalLog.Print("LazyAsyncResult::Complete *** OFFLOADED the user callback ***"); } Task.Factory.StartNew( s => WorkerThreadComplete(s), this, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); offloaded = true; } else { _asyncCallback(this); } } else if (globalLogEnabled) { GlobalLog.Print("LazyAsyncResult#" + LoggingHash.HashString(this) + "::Complete() no callback to invoke"); } } finally { --threadContext._nestedIOCount; // Never call this method unless interlocked _intCompleted check has succeeded (like in this case). if (!offloaded) { Cleanup(); } } }
protected override void Cleanup() { base.Cleanup(); if (GlobalLog.IsEnabled) { GlobalLog.Print("ContextAwareResult#" + LoggingHash.HashString(this) + "::Cleanup()"); } CleanupInternal(); }
private int DecryptNtlm(byte[] payload, int offset, int count, out int newOffset, uint expectedSeqNumber) { // For the most part the arguments are verified in Encrypt(). if (count < 16) { if (GlobalLog.IsEnabled) { GlobalLog.Assert("NTAuthentication#" + LoggingHash.HashString(this) + "::DecryptNtlm", "Argument 'count' out of range."); } Debug.Fail("NTAuthentication#" + LoggingHash.HashString(this) + "::DecryptNtlm", "Argument 'count' out of range."); throw new ArgumentOutOfRangeException(nameof(count)); } var securityBuffer = new SecurityBuffer[2]; securityBuffer[0] = new SecurityBuffer(payload, offset, 16, SecurityBufferType.Token); securityBuffer[1] = new SecurityBuffer(payload, offset + 16, count - 16, SecurityBufferType.Data); int errorCode; SecurityBufferType realDataType = SecurityBufferType.Data; if (IsConfidentialityFlag) { errorCode = SSPIWrapper.DecryptMessage(GlobalSSPI.SSPIAuth, _securityContext, securityBuffer, expectedSeqNumber); } else { realDataType |= SecurityBufferType.ReadOnlyFlag; securityBuffer[1].type = realDataType; errorCode = SSPIWrapper.VerifySignature(GlobalSSPI.SSPIAuth, _securityContext, securityBuffer, expectedSeqNumber); } if (errorCode != 0) { if (GlobalLog.IsEnabled) { GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(this) + "::Decrypt() throw Error = " + errorCode.ToString("x", NumberFormatInfo.InvariantInfo)); } throw new Win32Exception(errorCode); } if (securityBuffer[1].type != realDataType) { throw new InternalException(); } newOffset = securityBuffer[1].offset; return(securityBuffer[1].size); }
protected override void Cleanup() { base.Cleanup(); GlobalLog.Print("ContextAwareResult#" + LoggingHash.HashString(this) + "::Cleanup()"); #if !NetNative if (_windowsIdentity != null) { _windowsIdentity.Dispose(); _windowsIdentity = null; } #endif }
protected override void Dispose(bool disposing) { if (GlobalLog.IsEnabled) { GlobalLog.Print("CommandStream" + LoggingHash.HashString(this) + "::Close()"); } InvokeRequestCallback(null); // Do not call base.Dispose(bool), which would close the web request. // This stream effectively should be a wrapper around a web // request that does not own the web request. }
// // Extracts a remote certificate upon request. // internal static X509Certificate2 GetRemoteCertificate(SafeDeleteContext securityContext, out X509Certificate2Collection remoteCertificateCollection) { remoteCertificateCollection = null; if (securityContext == null) { return(null); } if (GlobalLog.IsEnabled) { GlobalLog.Enter("CertificateValidationPal.Windows SecureChannel#" + LoggingHash.HashString(securityContext) + "::GetRemoteCertificate()"); } X509Certificate2 result = null; SafeFreeCertContext remoteContext = null; try { remoteContext = SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPISecureChannel, securityContext, Interop.SspiCli.ContextAttribute.RemoteCertificate) as SafeFreeCertContext; if (remoteContext != null && !remoteContext.IsInvalid) { result = new X509Certificate2(remoteContext.DangerousGetHandle()); } } finally { if (remoteContext != null && !remoteContext.IsInvalid) { remoteCertificateCollection = UnmanagedCertificateContext.GetRemoteCertificatesFromStoreContext(remoteContext); remoteContext.Dispose(); } } if (SecurityEventSource.Log.IsEnabled()) { SecurityEventSource.Log.RemoteCertificate(result == null ? "null" : result.ToString(true)); } if (GlobalLog.IsEnabled) { GlobalLog.Leave("CertificateValidationPal.Windows SecureChannel#" + LoggingHash.HashString(securityContext) + "::GetRemoteCertificate()", (result == null ? "null" : result.Subject)); } return(result); }
// 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) { if (GlobalLog.IsEnabled) { GlobalLog.AssertFormat("ContextAwareResult#{0}::StartPostingAsyncOp|Called on completed result.", LoggingHash.HashString(this)); } Debug.Fail("ContextAwareResult#" + LoggingHash.HashString(this) + "::StartPostingAsyncOp |Called on completed result."); } DebugProtectState(true); _lock = lockCapture ? new object() : null; _flags |= StateFlags.PostBlockStarted; return(_lock); }
// A method for completing the IO with a result and invoking the user's callback. // Used by derived classes to pass context into an overridden Complete(). Useful // for determining the 'winning' thread in case several may simultaneously call // the equivalent of InvokeCallback(). protected void ProtectedInvokeCallback(object result, IntPtr userToken) { if (GlobalLog.IsEnabled) { GlobalLog.Print("LazyAsyncResult#" + LoggingHash.HashString(this) + "::ProtectedInvokeCallback() result = " + (result is Exception ? ((Exception)result).Message : result == null ? "<null>" : result.ToString()) + ", userToken:" + userToken.ToString()); } // Critical to disallow DBNull here - it could result in a stuck spinlock in WaitForCompletion. if (result == DBNull.Value) { throw new ArgumentNullException("result"); } #if DEBUG // Always safe to ask for the state now. _protectState = false; #endif if ((_intCompleted & ~HighBit) == 0 && (Interlocked.Increment(ref _intCompleted) & ~HighBit) == 1) { // DBNull.Value is used to guarantee that the first caller wins, // even if the result was set to null. if (_result == DBNull.Value) { _result = result; } ManualResetEvent asyncEvent = (ManualResetEvent)_event; if (asyncEvent != null) { try { asyncEvent.Set(); } catch (ObjectDisposedException) { // Simply ignore this exception - There is apparently a rare race condition // where the event is disposed before the completion method is called. } } Complete(userToken); } }
internal FtpDataStream(NetworkStream networkStream, FtpWebRequest request, TriState writeOnly) { if (GlobalLog.IsEnabled) { GlobalLog.Print("FtpDataStream#" + LoggingHash.HashString(this) + "::FtpDataStream"); } _readable = true; _writeable = true; if (writeOnly == TriState.True) { _readable = false; } else if (writeOnly == TriState.False) { _writeable = false; } _networkStream = networkStream; _request = request; }
// Allows creating a pre-completed result with less interlockeds. Beware! Constructor calls the callback. // If a derived class ever uses this and overloads Cleanup, this may need to change. internal LazyAsyncResult(object myObject, object myState, AsyncCallback myCallBack, object result) { GlobalLog.Assert(result != DBNull.Value, "LazyAsyncResult#{0}::.ctor()|Result can't be set to DBNull - it's a special internal value.", LoggingHash.HashString(this)); _asyncObject = myObject; _asyncState = myState; _asyncCallback = myCallBack; _result = result; _intCompleted = 1; if (_asyncCallback != null) { GlobalLog.Print("LazyAsyncResult#" + LoggingHash.HashString(this) + "::Complete() invoking callback"); _asyncCallback(this); } else { GlobalLog.Print("LazyAsyncResult#" + LoggingHash.HashString(this) + "::Complete() no callback to invoke"); } GlobalLog.Print("LazyAsyncResult#" + LoggingHash.HashString(this) + "::.ctor() (pre-completed)"); }
internal FtpWebResponse(Stream responseStream, long contentLength, Uri responseUri, FtpStatusCode statusCode, string statusLine, DateTime lastModified, string bannerMessage, string welcomeMessage, string exitMessage) { if (GlobalLog.IsEnabled) { GlobalLog.Print("FtpWebResponse#" + LoggingHash.HashString(this) + "::.ctor(" + contentLength.ToString() + "," + statusLine + ")"); } _responseStream = responseStream; if (responseStream == null && contentLength < 0) { contentLength = 0; } _contentLength = contentLength; _responseUri = responseUri; _statusCode = statusCode; _statusLine = statusLine; _lastModified = lastModified; _bannerMessage = bannerMessage; _welcomeMessage = welcomeMessage; _exitMessage = exitMessage; }
private void Initialize(bool isServer, string package, NetworkCredential credential, string spn, ContextFlagsPal requestedContextFlags, ChannelBinding channelBinding) { if (GlobalLog.IsEnabled) { GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(this) + "::.ctor() package:" + LoggingHash.ObjectToString(package) + " spn:" + LoggingHash.ObjectToString(spn) + " flags :" + requestedContextFlags.ToString()); } _tokenSize = NegotiateStreamPal.QueryMaxTokenSize(package); _isServer = isServer; _spn = spn; _securityContext = null; _requestedContextFlags = requestedContextFlags; _package = package; _channelBinding = channelBinding; if (GlobalLog.IsEnabled) { GlobalLog.Print("Peer SPN-> '" + _spn + "'"); } // // Check if we're using DefaultCredentials. // Debug.Assert(CredentialCache.DefaultCredentials == CredentialCache.DefaultNetworkCredentials); if (credential == CredentialCache.DefaultCredentials) { if (GlobalLog.IsEnabled) { GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(this) + "::.ctor(): using DefaultCredentials"); } _credentialsHandle = NegotiateStreamPal.AcquireDefaultCredential(package, _isServer); } else { _credentialsHandle = NegotiateStreamPal.AcquireCredentialsHandle(package, _isServer, credential); } }
// This will return a client token when conducted authentication on server side. // This token can be used for impersonation. We use it to create a WindowsIdentity and hand it out to the server app. internal SecurityContextTokenHandle GetContextToken(out Interop.SecurityStatus status) { if (!(IsCompleted && IsValidContext)) { if (GlobalLog.IsEnabled) { GlobalLog.AssertFormat("NTAuthentication#{0}::GetContextToken|Should be called only when completed with success, currently is not!", LoggingHash.HashString(this)); } Debug.Fail("NTAuthentication#" + LoggingHash.HashString(this) + "::GetContextToken |Should be called only when completed with success, currently is not!"); } if (!IsServer) { if (GlobalLog.IsEnabled) { GlobalLog.AssertFormat("NTAuthentication#{0}::GetContextToken|The method must not be called by the client side!", LoggingHash.HashString(this)); } Debug.Fail("NTAuthentication#" + LoggingHash.HashString(this) + "::GetContextToken |The method must not be called by the client side!"); } if (!IsValidContext) { throw new Win32Exception((int)Interop.SecurityStatus.InvalidHandle); } SecurityContextTokenHandle token = null; status = (Interop.SecurityStatus)SSPIWrapper.QuerySecurityContextToken( GlobalSSPI.SSPIAuth, _securityContext, out token); return(token); }
internal CookieCollection CookieCutter(Uri uri, string headerName, string setCookieHeader, bool isThrow) { if (GlobalLog.IsEnabled) { GlobalLog.Print("CookieContainer#" + LoggingHash.HashString(this) + "::CookieCutter() uri:" + uri + " headerName:" + headerName + " setCookieHeader:" + setCookieHeader + " isThrow:" + isThrow); } CookieCollection cookies = new CookieCollection(); CookieVariant variant = CookieVariant.Unknown; if (headerName == null) { variant = CookieVariant.Default; } else { for (int i = 0; i < s_headerInfo.Length; ++i) { if ((String.Compare(headerName, s_headerInfo[i].Name, StringComparison.OrdinalIgnoreCase) == 0)) { variant = s_headerInfo[i].Variant; } } } bool isLocalDomain = IsLocalDomain(uri.Host); try { CookieParser parser = new CookieParser(setCookieHeader); do { Cookie cookie = parser.Get(); if (GlobalLog.IsEnabled) { GlobalLog.Print("CookieContainer#" + LoggingHash.HashString(this) + "::CookieCutter() CookieParser returned cookie:" + LoggingHash.ObjectToString(cookie)); } if (cookie == null) { break; } // Parser marks invalid cookies this way if (String.IsNullOrEmpty(cookie.Name)) { if (isThrow) { throw new CookieException(SR.net_cookie_format); } // Otherwise, ignore (reject) cookie continue; } // This will set the default values from the response URI // AND will check for cookie validity if (!cookie.VerifySetDefaults(variant, uri, isLocalDomain, _fqdnMyDomain, true, isThrow)) { continue; } // If many same cookies arrive we collapse them into just one, hence setting // parameter isStrict = true below cookies.InternalAdd(cookie, true); } while (true); } catch (OutOfMemoryException) { throw; } catch (Exception e) { if (isThrow) { throw new CookieException(SR.Format(SR.net_cookie_parse_header, uri.AbsoluteUri), e); } } foreach (Cookie c in cookies) { Add(c, isThrow); } return(cookies); }
// // Extracts a remote certificate upon request. // internal static X509Certificate2 GetRemoteCertificate(SafeDeleteContext securityContext, out X509Certificate2Collection remoteCertificateStore) { remoteCertificateStore = null; bool gotReference = false; if (securityContext == null) { return(null); } GlobalLog.Enter("CertificateValidationPal.Unix SecureChannel#" + LoggingHash.HashString(securityContext) + "::GetRemoteCertificate()"); X509Certificate2 result = null; SafeFreeCertContext remoteContext = null; try { int errorCode = QueryContextRemoteCertificate(securityContext, out remoteContext); if (remoteContext != null && !remoteContext.IsInvalid) { remoteContext.DangerousAddRef(ref gotReference); result = new X509Certificate2(remoteContext.DangerousGetHandle()); } remoteCertificateStore = new X509Certificate2Collection(); using (SafeSharedX509StackHandle chainStack = Interop.OpenSsl.GetPeerCertificateChain(securityContext.SslContext)) { if (!chainStack.IsInvalid) { int count = Interop.Crypto.GetX509StackFieldCount(chainStack); for (int i = 0; i < count; i++) { IntPtr certPtr = Interop.Crypto.GetX509StackField(chainStack, i); if (certPtr != IntPtr.Zero) { // X509Certificate2(IntPtr) calls X509_dup, so the reference is appropriately tracked. X509Certificate2 chainCert = new X509Certificate2(certPtr); remoteCertificateStore.Add(chainCert); } } } } } finally { if (gotReference) { remoteContext.DangerousRelease(); } if (remoteContext != null) { remoteContext.Dispose(); } } if (SecurityEventSource.Log.IsEnabled()) { SecurityEventSource.Log.RemoteCertificate(result == null ? "null" : result.ToString(true)); } GlobalLog.Leave("CertificateValidationPal.Unix SecureChannel#" + LoggingHash.HashString(securityContext) + "::GetRemoteCertificate()", (result == null ? "null" : result.Subject)); return(result); }
// Accepts an incoming binary security blob and returns an outgoing binary security blob. internal byte[] GetOutgoingBlob(byte[] incomingBlob, bool throwOnError, out SecurityStatusPal statusCode) { if (GlobalLog.IsEnabled) { GlobalLog.Enter("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob", ((incomingBlob == null) ? "0" : incomingBlob.Length.ToString(NumberFormatInfo.InvariantInfo)) + " bytes"); } var list = new List <SecurityBuffer>(2); if (incomingBlob != null) { list.Add(new SecurityBuffer(incomingBlob, SecurityBufferType.Token)); } if (_channelBinding != null) { list.Add(new SecurityBuffer(_channelBinding)); } SecurityBuffer[] inSecurityBufferArray = null; if (list.Count > 0) { inSecurityBufferArray = list.ToArray(); } var outSecurityBuffer = new SecurityBuffer(_tokenSize, SecurityBufferType.Token); bool firstTime = _securityContext == null; try { if (!_isServer) { // client session statusCode = NegotiateStreamPal.InitializeSecurityContext( _credentialsHandle, ref _securityContext, _spn, _requestedContextFlags, inSecurityBufferArray, outSecurityBuffer, ref _contextFlags); if (GlobalLog.IsEnabled) { GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob() SSPIWrapper.InitializeSecurityContext() returns statusCode:0x" + ((int)statusCode.ErrorCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); } if (statusCode.ErrorCode == SecurityStatusPalErrorCode.CompleteNeeded) { var inSecurityBuffers = new SecurityBuffer[1]; inSecurityBuffers[0] = outSecurityBuffer; statusCode = NegotiateStreamPal.CompleteAuthToken(ref _securityContext, inSecurityBuffers); if (GlobalLog.IsEnabled) { GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingDigestBlob() SSPIWrapper.CompleteAuthToken() returns statusCode:0x" + ((int)statusCode.ErrorCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); } outSecurityBuffer.token = null; } } else { // Server session. statusCode = NegotiateStreamPal.AcceptSecurityContext( _credentialsHandle, ref _securityContext, _requestedContextFlags, inSecurityBufferArray, outSecurityBuffer, ref _contextFlags); if (GlobalLog.IsEnabled) { GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob() SSPIWrapper.AcceptSecurityContext() returns statusCode:0x" + ((int)statusCode.ErrorCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); } } } finally { // // Assuming the ISC or ASC has referenced the credential on the first successful call, // we want to decrement the effective ref count by "disposing" it. // The real dispose will happen when the security context is closed. // Note if the first call was not successful the handle is physically destroyed here. // if (firstTime && _credentialsHandle != null) { _credentialsHandle.Dispose(); } } if (NegoState.IsError(statusCode)) { CloseContext(); _isCompleted = true; if (throwOnError) { Exception exception = NegotiateStreamPal.CreateExceptionFromError(statusCode); if (GlobalLog.IsEnabled) { GlobalLog.Leave("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob", "Win32Exception:" + exception); } throw exception; } if (GlobalLog.IsEnabled) { GlobalLog.Leave("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob", "null statusCode:0x" + ((int)statusCode.ErrorCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); } return(null); } else if (firstTime && _credentialsHandle != null) { // Cache until it is pushed out by newly incoming handles. SSPIHandleCache.CacheCredential(_credentialsHandle); } // The return value will tell us correctly if the handshake is over or not if (statusCode.ErrorCode == SecurityStatusPalErrorCode.OK) { // Success. _isCompleted = true; } else if (GlobalLog.IsEnabled) { // We need to continue. GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob() need continue statusCode:[0x" + ((int)statusCode.ErrorCode).ToString("x8", NumberFormatInfo.InvariantInfo) + "] (" + statusCode.ToString() + ") m_SecurityContext#" + LoggingHash.HashString(_securityContext) + "::Handle:" + LoggingHash.ObjectToString(_securityContext) + "]"); } if (GlobalLog.IsEnabled) { GlobalLog.Leave("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob", "IsCompleted:" + IsCompleted.ToString()); } return(outSecurityBuffer.token); }
// 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) { if (GlobalLog.IsEnabled) { GlobalLog.AssertFormat("ContextAwareResult#{0}::CaptureOrComplete|Called without calling StartPostingAsyncOp.", LoggingHash.HashString(this)); } Debug.Fail("ContextAwareResult#" + LoggingHash.HashString(this) + "::CaptureOrComplete |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 (GlobalLog.IsEnabled) { GlobalLog.Print("ContextAwareResult#" + LoggingHash.HashString(this) + "::CaptureOrComplete() 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 (GlobalLog.IsEnabled) { GlobalLog.Print("ContextAwareResult#" + LoggingHash.HashString(this) + "::CaptureOrComplete() starting capture"); } if (cachedContext == null) { cachedContext = ExecutionContext.Capture(); } if (cachedContext != null) { if (!returnContext) { _context = cachedContext; cachedContext = null; } else { _context = cachedContext; } } if (GlobalLog.IsEnabled) { GlobalLog.Print("ContextAwareResult#" + LoggingHash.HashString(this) + "::CaptureOrComplete() _Context:" + LoggingHash.HashString(_context)); } } else { // Otherwise we have to have completed synchronously, or not needed the context. if (GlobalLog.IsEnabled) { GlobalLog.Print("ContextAwareResult#" + LoggingHash.HashString(this) + "::CaptureOrComplete() skipping capture"); } cachedContext = null; if (AsyncCallback != null && !CompletedSynchronously) { if (GlobalLog.IsEnabled) { GlobalLog.AssertFormat("ContextAwareResult#{0}::CaptureOrComplete|Didn't capture context, but didn't complete synchronously!", LoggingHash.HashString(this)); } Debug.Fail("ContextAwareResult#" + LoggingHash.HashString(this) + "::CaptureOrComplete |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 (GlobalLog.IsEnabled) { GlobalLog.Print("ContextAwareResult#" + LoggingHash.HashString(this) + "::CaptureOrComplete() completing synchronously"); } base.Complete(IntPtr.Zero); return(true); } return(false); }
internal int Encrypt(byte[] buffer, int offset, int count, ref byte[] output, uint sequenceNumber) { SecSizes sizes = Sizes; try { int maxCount = checked (Int32.MaxValue - 4 - sizes.BlockSize - sizes.SecurityTrailer); if (count > maxCount || count < 0) { throw new ArgumentOutOfRangeException("count", SR.Format(SR.net_io_out_range, maxCount)); } } catch (Exception e) { if (!ExceptionCheck.IsFatal(e) && GlobalLog.IsEnabled) { GlobalLog.Assert("NTAuthentication#" + LoggingHash.HashString(this) + "::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 (IsConfidentialityFlag) { 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) { GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(this) + "::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); }
// Accepts an incoming binary security blob and returns an outgoing binary security blob. internal byte[] GetOutgoingBlob(byte[] incomingBlob, bool throwOnError, out Interop.SecurityStatus statusCode) { GlobalLog.Enter("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob", ((incomingBlob == null) ? "0" : incomingBlob.Length.ToString(NumberFormatInfo.InvariantInfo)) + " bytes"); var list = new List <SecurityBuffer>(2); if (incomingBlob != null) { list.Add(new SecurityBuffer(incomingBlob, SecurityBufferType.Token)); } if (_channelBinding != null) { list.Add(new SecurityBuffer(_channelBinding)); } SecurityBuffer[] inSecurityBufferArray = null; if (list.Count > 0) { inSecurityBufferArray = list.ToArray(); } var outSecurityBuffer = new SecurityBuffer(_tokenSize, SecurityBufferType.Token); bool firstTime = _securityContext == null; try { if (!_isServer) { // client session statusCode = (Interop.SecurityStatus)SSPIWrapper.InitializeSecurityContext( GlobalSSPI.SSPIAuth, _credentialsHandle, ref _securityContext, _spn, _requestedContextFlags, Interop.SspiCli.Endianness.Network, inSecurityBufferArray, outSecurityBuffer, ref _contextFlags); GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob() SSPIWrapper.InitializeSecurityContext() returns statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); if (statusCode == Interop.SecurityStatus.CompleteNeeded) { var inSecurityBuffers = new SecurityBuffer[1]; inSecurityBuffers[0] = outSecurityBuffer; statusCode = (Interop.SecurityStatus)SSPIWrapper.CompleteAuthToken( GlobalSSPI.SSPIAuth, ref _securityContext, inSecurityBuffers); GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingDigestBlob() SSPIWrapper.CompleteAuthToken() returns statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); outSecurityBuffer.token = null; } } else { // Server session. statusCode = (Interop.SecurityStatus)SSPIWrapper.AcceptSecurityContext( GlobalSSPI.SSPIAuth, _credentialsHandle, ref _securityContext, _requestedContextFlags, Interop.SspiCli.Endianness.Network, inSecurityBufferArray, outSecurityBuffer, ref _contextFlags); GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob() SSPIWrapper.AcceptSecurityContext() returns statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); } } finally { // // Assuming the ISC or ASC has referenced the credential on the first successful call, // we want to decrement the effective ref count by "disposing" it. // The real dispose will happen when the security context is closed. // Note if the first call was not successful the handle is physically destroyed here. // if (firstTime && _credentialsHandle != null) { _credentialsHandle.Dispose(); } } if (((int)statusCode & unchecked ((int)0x80000000)) != 0) { CloseContext(); _isCompleted = true; if (throwOnError) { var exception = new Win32Exception((int)statusCode); GlobalLog.Leave("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob", "Win32Exception:" + exception); throw exception; } GlobalLog.Leave("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob", "null statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); return(null); } else if (firstTime && _credentialsHandle != null) { // Cache until it is pushed out by newly incoming handles. SSPIHandleCache.CacheCredential(_credentialsHandle); } // The return value from SSPI will tell us correctly if the // handshake is over or not: http://msdn.microsoft.com/library/psdk/secspi/sspiref_67p0.htm // we also have to consider the case in which SSPI formed a new context, in this case we're done as well. if (statusCode == Interop.SecurityStatus.OK) { // Success. if ((statusCode == Interop.SecurityStatus.OK) && GlobalLog.IsEnabled) { GlobalLog.AssertFormat("NTAuthentication#{0}::GetOutgoingBlob()|statusCode:[0x{1:x8}] ({2}) m_SecurityContext#{3}::Handle:[{4}] [STATUS != OK]", LoggingHash.HashString(this), (int)statusCode, statusCode, LoggingHash.HashString(_securityContext), LoggingHash.ObjectToString(_securityContext)); } _isCompleted = true; } else { // We need to continue. GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob() need continue statusCode:[0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + "] (" + statusCode.ToString() + ") m_SecurityContext#" + LoggingHash.HashString(_securityContext) + "::Handle:" + LoggingHash.ObjectToString(_securityContext) + "]"); } GlobalLog.Leave("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob", "IsCompleted:" + IsCompleted.ToString()); return(outSecurityBuffer.token); }
private void Initialize(bool isServer, string package, NetworkCredential credential, string spn, Interop.SspiCli.ContextFlags requestedContextFlags, ChannelBinding channelBinding) { GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(this) + "::.ctor() package:" + LoggingHash.ObjectToString(package) + " spn:" + LoggingHash.ObjectToString(spn) + " flags :" + requestedContextFlags.ToString()); _tokenSize = SSPIWrapper.GetVerifyPackageInfo(GlobalSSPI.SSPIAuth, package, true).MaxToken; _isServer = isServer; _spn = spn; _securityContext = null; _requestedContextFlags = requestedContextFlags; _package = package; _channelBinding = channelBinding; GlobalLog.Print("Peer SPN-> '" + _spn + "'"); // // Check if we're using DefaultCredentials. // Debug.Assert(CredentialCache.DefaultCredentials == CredentialCache.DefaultNetworkCredentials); if (credential == CredentialCache.DefaultCredentials) { GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(this) + "::.ctor(): using DefaultCredentials"); _credentialsHandle = SSPIWrapper.AcquireDefaultCredential( GlobalSSPI.SSPIAuth, package, (_isServer ? Interop.SspiCli.CredentialUse.Inbound : Interop.SspiCli.CredentialUse.Outbound)); } else { unsafe { SafeSspiAuthDataHandle authData = null; try { Interop.SecurityStatus result = Interop.SspiCli.SspiEncodeStringsAsAuthIdentity( credential.UserName, credential.Domain, credential.Password, out authData); if (result != Interop.SecurityStatus.OK) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.PrintError( NetEventSource.ComponentType.Security, SR.Format( SR.net_log_operation_failed_with_error, "SspiEncodeStringsAsAuthIdentity()", String.Format(CultureInfo.CurrentCulture, "0x{0:X}", (int)result))); } throw new Win32Exception((int)result); } _credentialsHandle = SSPIWrapper.AcquireCredentialsHandle(GlobalSSPI.SSPIAuth, package, (_isServer ? Interop.SspiCli.CredentialUse.Inbound : Interop.SspiCli.CredentialUse.Outbound), ref authData); } finally { if (authData != null) { authData.Dispose(); } } } } }
private object WaitForCompletion(bool snap) { ManualResetEvent waitHandle = null; bool createdByMe = false; bool complete = snap ? IsCompleted : InternalPeekCompleted; if (!complete) { // Not done yet, so wait: waitHandle = (ManualResetEvent)_event; if (waitHandle == null) { createdByMe = LazilyCreateEvent(out waitHandle); } } if (waitHandle != null) { try { if (GlobalLog.IsEnabled) { GlobalLog.Print("LazyAsyncResult#" + LoggingHash.HashString(this) + "::InternalWaitForCompletion() Waiting for completion _event#" + LoggingHash.HashString(waitHandle)); } waitHandle.WaitOne(Timeout.Infinite); } catch (ObjectDisposedException) { // This can occur if this method is called from two different threads. // This possibility is the trade-off for not locking. } finally { // We also want to dispose the event although we can't unless we did wait on it here. if (createdByMe && !_userEvent) { // Does _userEvent need to be volatile (or _event set via Interlocked) in order // to avoid giving a user a disposed event? ManualResetEvent oldEvent = (ManualResetEvent)_event; _event = null; if (!_userEvent) { oldEvent.Dispose(); } } } } // A race condition exists because InvokeCallback sets _intCompleted before _result (so that _result // can benefit from the synchronization of _intCompleted). That means you can get here before _result got // set (although rarely - once every eight hours of stress). Handle that case with a spin-lock. SpinWait sw = new SpinWait(); while (_result == DBNull.Value) { sw.SpinOnce(); } if (GlobalLog.IsEnabled) { GlobalLog.Print("LazyAsyncResult#" + LoggingHash.HashString(this) + "::InternalWaitForCompletion() done: " + (_result is Exception ? ((Exception)_result).Message : _result == null ? "<null>" : _result.ToString())); } return(_result); }