public static object QueryContextAttributes(SSPIInterface secModule, SafeDeleteContext securityContext, Interop.SspiCli.ContextAttribute contextAttribute, out int errorCode) { if (GlobalLog.IsEnabled) { GlobalLog.Enter("QueryContextAttributes", contextAttribute.ToString()); } int nativeBlockSize = IntPtr.Size; Type handleType = null; switch (contextAttribute) { case Interop.SspiCli.ContextAttribute.Sizes: nativeBlockSize = SecSizes.SizeOf; break; case Interop.SspiCli.ContextAttribute.StreamSizes: nativeBlockSize = StreamSizes.SizeOf; break; case Interop.SspiCli.ContextAttribute.Names: handleType = typeof(SafeFreeContextBuffer); break; case Interop.SspiCli.ContextAttribute.PackageInfo: handleType = typeof(SafeFreeContextBuffer); break; case Interop.SspiCli.ContextAttribute.NegotiationInfo: handleType = typeof(SafeFreeContextBuffer); nativeBlockSize = Marshal.SizeOf <NegotiationInfo>(); break; case Interop.SspiCli.ContextAttribute.ClientSpecifiedSpn: handleType = typeof(SafeFreeContextBuffer); break; case Interop.SspiCli.ContextAttribute.RemoteCertificate: handleType = typeof(SafeFreeCertContext); break; case Interop.SspiCli.ContextAttribute.LocalCertificate: handleType = typeof(SafeFreeCertContext); break; case Interop.SspiCli.ContextAttribute.IssuerListInfoEx: nativeBlockSize = Marshal.SizeOf <Interop.SspiCli.IssuerListInfoEx>(); handleType = typeof(SafeFreeContextBuffer); break; case Interop.SspiCli.ContextAttribute.ConnectionInfo: nativeBlockSize = Marshal.SizeOf <SslConnectionInfo>(); break; default: throw new ArgumentException(SR.Format(SR.net_invalid_enum, "ContextAttribute"), "contextAttribute"); } SafeHandle sspiHandle = null; object attribute = null; try { var nativeBuffer = new byte[nativeBlockSize]; errorCode = secModule.QueryContextAttributes(securityContext, contextAttribute, nativeBuffer, handleType, out sspiHandle); if (errorCode != 0) { if (GlobalLog.IsEnabled) { GlobalLog.Leave("Win32:QueryContextAttributes", "ERROR = " + ErrorDescription(errorCode)); } return(null); } switch (contextAttribute) { case Interop.SspiCli.ContextAttribute.Sizes: attribute = new SecSizes(nativeBuffer); break; case Interop.SspiCli.ContextAttribute.StreamSizes: attribute = new StreamSizes(nativeBuffer); break; case Interop.SspiCli.ContextAttribute.Names: attribute = Marshal.PtrToStringUni(sspiHandle.DangerousGetHandle()); break; case Interop.SspiCli.ContextAttribute.PackageInfo: attribute = new SecurityPackageInfoClass(sspiHandle, 0); break; case Interop.SspiCli.ContextAttribute.NegotiationInfo: unsafe { fixed(void *ptr = nativeBuffer) { attribute = new NegotiationInfoClass(sspiHandle, Marshal.ReadInt32(new IntPtr(ptr), NegotiationInfo.NegotiationStateOffest)); } } break; case Interop.SspiCli.ContextAttribute.ClientSpecifiedSpn: attribute = Marshal.PtrToStringUni(sspiHandle.DangerousGetHandle()); break; case Interop.SspiCli.ContextAttribute.LocalCertificate: // Fall-through to RemoteCertificate is intentional. case Interop.SspiCli.ContextAttribute.RemoteCertificate: attribute = sspiHandle; sspiHandle = null; break; case Interop.SspiCli.ContextAttribute.IssuerListInfoEx: attribute = new Interop.SspiCli.IssuerListInfoEx(sspiHandle, nativeBuffer); sspiHandle = null; break; case Interop.SspiCli.ContextAttribute.ConnectionInfo: attribute = new SslConnectionInfo(nativeBuffer); break; default: // Will return null. break; } } finally { if (sspiHandle != null) { sspiHandle.Dispose(); } } if (GlobalLog.IsEnabled) { GlobalLog.Leave("QueryContextAttributes", LoggingHash.ObjectToString(attribute)); } return(attribute); }
public override string ToString() { return("[" + UriPrefixLength.ToString(NumberFormatInfo.InvariantInfo) + "]:" + LoggingHash.ObjectToString(UriPrefix) + ":" + LoggingHash.ObjectToString(AuthenticationType)); }
// // 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); } bool globalLogEnabled = GlobalLog.IsEnabled; if (globalLogEnabled) { 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)); } if (globalLogEnabled) { GlobalLog.Leave("CertificateValidationPal.Unix SecureChannel#" + LoggingHash.HashString(securityContext) + "::GetRemoteCertificate()", (result == null ? "null" : result.Subject)); } return(result); }
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); }
internal int Decrypt(byte[] payload, int offset, int count, out int newOffset, uint expectedSeqNumber) { if (offset < 0 || offset > (payload == null ? 0 : payload.Length)) { if (GlobalLog.IsEnabled) { GlobalLog.Assert("NTAuthentication#" + LoggingHash.HashString(this) + "::Decrypt", "Argument 'offset' out of range."); } Debug.Fail("NTAuthentication#" + LoggingHash.HashString(this) + "::Decrypt", "Argument 'offset' out of range."); throw new ArgumentOutOfRangeException("offset"); } if (count < 0 || count > (payload == null ? 0 : payload.Length - offset)) { if (GlobalLog.IsEnabled) { GlobalLog.Assert("NTAuthentication#" + LoggingHash.HashString(this) + "::Decrypt", "Argument 'count' out of range."); } Debug.Fail("NTAuthentication#" + LoggingHash.HashString(this) + "::Decrypt", "Argument 'count' out of range."); throw new ArgumentOutOfRangeException("count"); } if (IsNTLM) { return(DecryptNtlm(payload, offset, count, out newOffset, expectedSeqNumber)); } // // Kerberos and up // var securityBuffer = new SecurityBuffer[2]; securityBuffer[0] = new SecurityBuffer(payload, offset, count, SecurityBufferType.Stream); securityBuffer[1] = new SecurityBuffer(0, SecurityBufferType.Data); int errorCode; if (IsConfidentialityFlag) { errorCode = SSPIWrapper.DecryptMessage(GlobalSSPI.SSPIAuth, _securityContext, securityBuffer, expectedSeqNumber); } else { 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 != SecurityBufferType.Data) { throw new InternalException(); } newOffset = securityBuffer[1].offset; return(securityBuffer[1].size); }
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)) { if (GlobalLog.IsEnabled) { GlobalLog.Assert("NTAuthentication#" + LoggingHash.HashString(this) + "::Encrypt", "Arguments out of range."); } Debug.Fail("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) { if (GlobalLog.IsEnabled) { 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) { 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 = (Interop.SecurityStatus)SSPIWrapper.InitializeSecurityContext( GlobalSSPI.SSPIAuth, _credentialsHandle, ref _securityContext, _spn, _requestedContextFlags, Interop.SspiCli.Endianness.Network, inSecurityBufferArray, outSecurityBuffer, ref _contextFlags); if (GlobalLog.IsEnabled) { 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); if (GlobalLog.IsEnabled) { 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); if (GlobalLog.IsEnabled) { 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); 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).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) { if (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)); } Debug.Fail("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob()|statusCode:[0x" + ((int)statusCode).ToString("x8") + "] (" + statusCode + ") m_SecurityContext#" + LoggingHash.HashString(_securityContext) + "::Handle:[" + LoggingHash.ObjectToString(_securityContext) + "] [STATUS != OK]"); } _isCompleted = true; } else if (GlobalLog.IsEnabled) { // 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) + "]"); } if (GlobalLog.IsEnabled) { GlobalLog.Leave("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob", "IsCompleted:" + IsCompleted.ToString()); } return(outSecurityBuffer.token); }
// 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); }
private void Initialize(bool isServer, string package, NetworkCredential credential, string spn, Interop.SspiCli.ContextFlags 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 = SSPIWrapper.GetVerifyPackageInfo(GlobalSSPI.SSPIAuth, package, true).MaxToken; _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 = 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(); } } } } }