private static X509Certificate2 GetRemoteCertificate( SafeDeleteContext securityContext, bool retrieveCollection, out X509Certificate2Collection remoteCertificateCollection) { remoteCertificateCollection = null; if (securityContext == null) { return(null); } if (NetEventSource.IsEnabled) { NetEventSource.Enter(securityContext); } X509Certificate2 result = null; SafeFreeCertContext remoteContext = null; try { remoteContext = SSPIWrapper.QueryContextAttributes_SECPKG_ATTR_REMOTE_CERT_CONTEXT(GlobalSSPI.SSPISecureChannel, securityContext); if (remoteContext != null && !remoteContext.IsInvalid) { result = new X509Certificate2(remoteContext.DangerousGetHandle()); } } finally { if (remoteContext != null && !remoteContext.IsInvalid) { if (retrieveCollection) { remoteCertificateCollection = UnmanagedCertificateContext.GetRemoteCertificatesFromStoreContext(remoteContext); } remoteContext.Dispose(); } } if (NetEventSource.IsEnabled) { NetEventSource.Log.RemoteCertificate(result); NetEventSource.Exit(null, result, securityContext); } return(result); }
public static SecurityStatusPal InitializeSecurityContext(SafeFreeCredentials credentialsHandle, ref SafeDeleteContext context, string targetName, SecurityBuffer[] inputBuffers, SecurityBuffer outputBuffer) { Interop.SspiCli.ContextFlags unusedAttributes = default(Interop.SspiCli.ContextFlags); int errorCode = SSPIWrapper.InitializeSecurityContext( GlobalSSPI.SSPISecureChannel, credentialsHandle, ref context, targetName, RequiredFlags | Interop.SspiCli.ContextFlags.InitManualCredValidation, Interop.SspiCli.Endianness.Native, inputBuffers, outputBuffer, ref unusedAttributes); return(GetSecurityStatusPalFromWin32Int(errorCode)); }
// // Security: we temporarily reset thread token to open the handle under process account. // private static SafeFreeCredentials AcquireCredentialsHandle(Interop.Secur32.CredentialUse credUsage, Interop.Secur32.SecureCredential secureCredential) { // First try without impersonation, if it fails, then try the process account. // I.E. We don't know which account the certificate context was created under. try { // // For app-compat we want to ensure the credential are accessed under >>process<< acount. // return(WindowsIdentity.RunImpersonated <SafeFreeCredentials>(SafeAccessTokenHandle.InvalidHandle, () => { return SSPIWrapper.AcquireCredentialsHandle(GlobalSSPI.SSPISecureChannel, SecurityPackage, credUsage, secureCredential); })); } catch { return(SSPIWrapper.AcquireCredentialsHandle(GlobalSSPI.SSPISecureChannel, SecurityPackage, credUsage, secureCredential)); } }
internal int MakeSignature(byte[] buffer, int offset, int count, ref byte[] output) { SecSizes sizes = this.Sizes; int num = count + sizes.MaxSignature; if ((output == null) || (output.Length < num)) { output = new byte[num]; } Buffer.BlockCopy(buffer, offset, output, sizes.MaxSignature, count); SecurityBuffer[] input = new SecurityBuffer[] { new SecurityBuffer(output, 0, sizes.MaxSignature, BufferType.Token), new SecurityBuffer(output, sizes.MaxSignature, count, BufferType.Data) }; int error = SSPIWrapper.MakeSignature(GlobalSSPI.SSPIAuth, this.m_SecurityContext, input, 0); if (error != 0) { throw new Win32Exception(error); } return(input[0].size + input[1].size); }
private string GetClientSpecifiedSpn() { if ((IsValidContext && IsCompleted)) { if (GlobalLog.IsEnabled) { GlobalLog.Assert("NTAuthentication: Trying to get the client SPN before handshaking is done!"); } Debug.Fail("NTAuthentication: Trying to get the client SPN before handshaking is done!"); } string spn = SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPIAuth, _securityContext, Interop.SspiCli.ContextAttribute.ClientSpecifiedSpn) as string; if (GlobalLog.IsEnabled) { GlobalLog.Print("NTAuthentication: The client specified SPN is [" + spn + "]"); } return(spn); }
// // 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); }
// // Extracts a remote certificate upon request. // internal override X509Certificate2 GetRemoteCertificate(SafeDeleteContext securityContext, out X509Certificate2Collection remoteCertificateStore) { remoteCertificateStore = null; if (securityContext == null) { return(null); } GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::RemoteCertificate{get;}"); X509Certificate2 result = null; SafeFreeCertContext remoteContext = null; try { int errorCode = SSPIWrapper.QueryContextRemoteCertificate(GlobalSSPI.SSPISecureChannel, securityContext, out remoteContext); if (remoteContext != null && !remoteContext.IsInvalid) { result = new X509Certificate2(remoteContext.DangerousGetHandle()); } } finally { if (remoteContext != null && !remoteContext.IsInvalid) { remoteCertificateStore = UnmanagedCertificateContext.GetRemoteCertificatesFromStoreContext(remoteContext); remoteContext.Dispose(); } } if (Logging.On) { Logging.PrintInfo(Logging.Web, SR.Format(SR.net_log_remote_certificate, (result == null ? "null" : result.ToString(true)))); } GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::RemoteCertificate{get;}", (result == null ? "null" : result.Subject)); return(result); }
// // Extracts a remote certificate upon request. // internal static X509Certificate2 GetRemoteCertificate(SafeDeleteContext securityContext, out X509Certificate2Collection remoteCertificateStore) { remoteCertificateStore = null; if (securityContext == null) { return(null); } GlobalLog.Enter("CertificateValidationPal.Windows SecureChannel#" + Logging.HashString(securityContext) + "::GetRemoteCertificate()"); X509Certificate2 result = null; SafeFreeCertContext remoteContext = null; try { remoteContext = SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPISecureChannel, securityContext, Interop.Secur32.ContextAttribute.RemoteCertificate) as SafeFreeCertContext; if (remoteContext != null && !remoteContext.IsInvalid) { result = new X509Certificate2(remoteContext.DangerousGetHandle()); } } finally { if (remoteContext != null && !remoteContext.IsInvalid) { remoteCertificateStore = UnmanagedCertificateContext.GetRemoteCertificatesFromStoreContext(remoteContext); remoteContext.Dispose(); } } if (Logging.On) { Logging.PrintInfo(Logging.Web, SR.Format(SR.net_log_remote_certificate, (result == null ? "null" : result.ToString(true)))); } GlobalLog.Leave("CertificateValidationPal.Windows SecureChannel#" + Logging.HashString(securityContext) + "::GetRemoteCertificate()", (result == null ? "null" : result.Subject)); return(result); }
// // Extracts a remote certificate upon request. // internal static X509Certificate2 GetRemoteCertificate(SafeDeleteContext securityContext, out X509Certificate2Collection remoteCertificateCollection) { remoteCertificateCollection = null; if (securityContext == null) { return(null); } 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)); } GlobalLog.Leave("CertificateValidationPal.Windows SecureChannel#" + LoggingHash.HashString(securityContext) + "::GetRemoteCertificate()", (result == null ? "null" : result.Subject)); return(result); }
internal int VerifySignature(byte[] buffer, int offset, int count) { if ((offset < 0) || (offset > ((buffer == null) ? 0 : buffer.Length))) { throw new ArgumentOutOfRangeException("offset"); } if ((count < 0) || (count > ((buffer == null) ? 0 : (buffer.Length - offset)))) { throw new ArgumentOutOfRangeException("count"); } SecurityBuffer[] input = new SecurityBuffer[] { new SecurityBuffer(buffer, offset, count, BufferType.Stream), new SecurityBuffer(0, BufferType.Data) }; int error = SSPIWrapper.VerifySignature(GlobalSSPI.SSPIAuth, this.m_SecurityContext, input, 0); if (error != 0) { throw new Win32Exception(error); } if (input[1].type != BufferType.Data) { throw new InternalException(); } return(input[1].size); }
private void Initialize(bool isServer, string package, NetworkCredential credential, string spn, ContextFlags requestedContextFlags, System.Security.Authentication.ExtendedProtection.ChannelBinding channelBinding) { this.m_TokenSize = SSPIWrapper.GetVerifyPackageInfo(GlobalSSPI.SSPIAuth, package, true).MaxToken; this.m_IsServer = isServer; this.m_Spn = spn; this.m_SecurityContext = null; this.m_RequestedContextFlags = requestedContextFlags; this.m_Package = package; this.m_ChannelBinding = channelBinding; if (credential is SystemNetworkCredential) { this.m_CredentialsHandle = SSPIWrapper.AcquireDefaultCredential(GlobalSSPI.SSPIAuth, package, this.m_IsServer ? CredentialUse.Inbound : CredentialUse.Outbound); this.m_UniqueUserId = "/S"; } else { string userName = credential.InternalGetUserName(); string domain = credential.InternalGetDomain(); AuthIdentity authdata = new AuthIdentity(userName, credential.InternalGetPassword(), ((package == "WDigest") && ((domain == null) || (domain.Length == 0))) ? null : domain); this.m_UniqueUserId = domain + "/" + userName + "/U"; this.m_CredentialsHandle = SSPIWrapper.AcquireCredentialsHandle(GlobalSSPI.SSPIAuth, package, this.m_IsServer ? CredentialUse.Inbound : CredentialUse.Outbound, ref authdata); } }
internal int Decrypt(byte[] payload, int offset, int count, out int newOffset, uint expectedSeqNumber) { int num; if ((offset < 0) || (offset > ((payload == null) ? 0 : payload.Length))) { throw new ArgumentOutOfRangeException("offset"); } if ((count < 0) || (count > ((payload == null) ? 0 : (payload.Length - offset)))) { throw new ArgumentOutOfRangeException("count"); } if (this.IsNTLM) { return(this.DecryptNtlm(payload, offset, count, out newOffset, expectedSeqNumber)); } SecurityBuffer[] input = new SecurityBuffer[] { new SecurityBuffer(payload, offset, count, BufferType.Stream), new SecurityBuffer(0, BufferType.Data) }; if (this.IsConfidentialityFlag) { num = SSPIWrapper.DecryptMessage(GlobalSSPI.SSPIAuth, this.m_SecurityContext, input, expectedSeqNumber); } else { num = SSPIWrapper.VerifySignature(GlobalSSPI.SSPIAuth, this.m_SecurityContext, input, expectedSeqNumber); } if (num != 0) { throw new Win32Exception(num); } if (input[1].type != BufferType.Data) { throw new InternalException(); } newOffset = input[1].offset; return(input[1].size); }
// 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 int Encrypt(byte[] buffer, int offset, int count, ref byte[] output, uint sequenceNumber) { int num3; SecSizes sizes = this.Sizes; try { int num = (0x7ffffffb - sizes.BlockSize) - sizes.SecurityTrailer; if ((count > num) || (count < 0)) { throw new ArgumentOutOfRangeException("count", SR.GetString("net_io_out_range", new object[] { num })); } } catch (Exception exception) { NclUtilities.IsFatal(exception); throw; } int size = (count + sizes.SecurityTrailer) + sizes.BlockSize; if ((output == null) || (output.Length < (size + 4))) { output = new byte[size + 4]; } Buffer.BlockCopy(buffer, offset, output, 4 + sizes.SecurityTrailer, count); SecurityBuffer[] input = new SecurityBuffer[] { new SecurityBuffer(output, 4, sizes.SecurityTrailer, BufferType.Token), new SecurityBuffer(output, 4 + sizes.SecurityTrailer, count, BufferType.Data), new SecurityBuffer(output, (4 + sizes.SecurityTrailer) + count, sizes.BlockSize, BufferType.Padding) }; if (this.IsConfidentialityFlag) { num3 = SSPIWrapper.EncryptMessage(GlobalSSPI.SSPIAuth, this.m_SecurityContext, input, sequenceNumber); } else { if (this.IsNTLM) { SecurityBuffer buffer1 = input[1]; buffer1.type |= BufferType.ReadOnlyFlag; } num3 = SSPIWrapper.MakeSignature(GlobalSSPI.SSPIAuth, this.m_SecurityContext, input, 0); } if (num3 != 0) { throw new Win32Exception(num3); } size = input[0].size; bool flag = false; if (size != sizes.SecurityTrailer) { flag = true; Buffer.BlockCopy(output, input[1].offset, output, 4 + size, input[1].size); } size += input[1].size; if ((input[2].size != 0) && (flag || (size != (count + sizes.SecurityTrailer)))) { Buffer.BlockCopy(output, input[2].offset, output, 4 + size, input[2].size); } size += input[2].size; output[0] = (byte)(size & 0xff); output[1] = (byte)((size >> 8) & 0xff); output[2] = (byte)((size >> 0x10) & 0xff); output[3] = (byte)((size >> 0x18) & 0xff); return(size + 4); }
// // Extracts a remote certificate upon request. // internal override X509Certificate2 GetRemoteCertificate(SafeDeleteContext securityContext, out X509Certificate2Collection remoteCertificateStore) { remoteCertificateStore = null; bool gotReference = false; if (securityContext == null) { return(null); } GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::RemoteCertificate{get;}"); X509Certificate2 result = null; SafeFreeCertContext remoteContext = null; try { int errorCode = SSPIWrapper.QueryContextRemoteCertificate(GlobalSSPI.SSPISecureChannel, 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 (Logging.On) { Logging.PrintInfo(Logging.Web, SR.Format(SR.net_log_remote_certificate, (result == null ? "null" : result.ToString(true)))); } GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::RemoteCertificate{get;}", (result == null ? "null" : result.Subject)); return(result); }
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(); } } } } }
internal byte[] GetOutgoingBlob(byte[] incomingBlob, bool throwOnError, out SecurityStatus statusCode) { List <SecurityBuffer> list = new List <SecurityBuffer>(2); if (incomingBlob != null) { list.Add(new SecurityBuffer(incomingBlob, BufferType.Token)); } if (this.m_ChannelBinding != null) { list.Add(new SecurityBuffer(this.m_ChannelBinding)); } SecurityBuffer[] inputBuffers = null; if (list.Count > 0) { inputBuffers = list.ToArray(); } SecurityBuffer outputBuffer = new SecurityBuffer(this.m_TokenSize, BufferType.Token); bool flag = this.m_SecurityContext == null; try { if (!this.m_IsServer) { statusCode = (SecurityStatus)SSPIWrapper.InitializeSecurityContext(GlobalSSPI.SSPIAuth, this.m_CredentialsHandle, ref this.m_SecurityContext, this.m_Spn, this.m_RequestedContextFlags, Endianness.Network, inputBuffers, outputBuffer, ref this.m_ContextFlags); if (statusCode == SecurityStatus.CompleteNeeded) { SecurityBuffer[] bufferArray2 = new SecurityBuffer[] { outputBuffer }; statusCode = (SecurityStatus)SSPIWrapper.CompleteAuthToken(GlobalSSPI.SSPIAuth, ref this.m_SecurityContext, bufferArray2); outputBuffer.token = null; } } else { statusCode = (SecurityStatus)SSPIWrapper.AcceptSecurityContext(GlobalSSPI.SSPIAuth, this.m_CredentialsHandle, ref this.m_SecurityContext, this.m_RequestedContextFlags, Endianness.Network, inputBuffers, outputBuffer, ref this.m_ContextFlags); } } finally { if (flag && (this.m_CredentialsHandle != null)) { this.m_CredentialsHandle.Close(); } } if ((statusCode & ((SecurityStatus)(-2147483648))) != SecurityStatus.OK) { this.CloseContext(); this.m_IsCompleted = true; if (throwOnError) { Win32Exception exception = new Win32Exception((int)statusCode); throw exception; } return(null); } if (flag && (this.m_CredentialsHandle != null)) { SSPIHandleCache.CacheCredential(this.m_CredentialsHandle); } if (statusCode == SecurityStatus.OK) { this.m_IsCompleted = true; } return(outputBuffer.token); }
// // Extracts a remote certificate upon request. // private static X509Certificate2?GetRemoteCertificate( SafeDeleteContext?securityContext, bool retrieveChainCertificates, ref X509Chain?chain, X509ChainPolicy?chainPolicy) { if (securityContext == null) { return(null); } X509Certificate2? result = null; SafeFreeCertContext?remoteContext = null; try { // SECPKG_ATTR_REMOTE_CERT_CONTEXT will not succeed before TLS handshake completes. Inside the handshake, // we need to use (more expensive) SECPKG_ATTR_REMOTE_CERT_CHAIN. That one may be unsupported on older // versions of windows. In that case, we have no option than to return null. // // We can use retrieveCollection to distinguish between in-handshake and after-handshake calls, because // the collection is retrieved for cert validation purposes after the handshake completes. if (retrieveChainCertificates) // handshake completed { SSPIWrapper.QueryContextAttributes_SECPKG_ATTR_REMOTE_CERT_CONTEXT(GlobalSSPI.SSPISecureChannel, securityContext, out remoteContext); } else // in handshake { SSPIWrapper.QueryContextAttributes_SECPKG_ATTR_REMOTE_CERT_CHAIN(GlobalSSPI.SSPISecureChannel, securityContext, out remoteContext); } if (remoteContext != null && !remoteContext.IsInvalid) { result = new X509Certificate2(remoteContext.DangerousGetHandle()); } } finally { if (remoteContext != null) { if (!remoteContext.IsInvalid) { if (retrieveChainCertificates) { chain ??= new X509Chain(); if (chainPolicy != null) { chain.ChainPolicy = chainPolicy; } UnmanagedCertificateContext.GetRemoteCertificatesFromStoreContext(remoteContext, chain.ChainPolicy.ExtraStore); } } remoteContext.Dispose(); } } if (NetEventSource.Log.IsEnabled()) { NetEventSource.Log.RemoteCertificate(result); } return(result); }
public unsafe static SafeFreeContextBufferChannelBinding QueryContextChannelBinding(SafeDeleteContext securityContext, ChannelBindingKind attribute) { return(SSPIWrapper.QueryContextChannelBinding(GlobalSSPI.SSPISecureChannel, securityContext, (Interop.SspiCli.ContextAttribute)attribute)); }
// // NTAuth::GetOutgoingBlob() // Created: 12-01-1999: L.M. // Description: // Accepts an incoming binary security blob and returns // an outgoing binary security blob // private byte[] GetOutgoingBlob(byte[] incomingBlob, out bool handshakeComplete) { GlobalLog.Enter("NTAuthentication::GetOutgoingBlob", ((incomingBlob == null) ? "0" : incomingBlob.Length.ToString()) + " bytes"); // default to true in case of failure handshakeComplete = true; if (m_SecurityContext.Handle != -1 && incomingBlob == null) { // we tried auth previously, now we got a null blob, we're done. this happens // with Kerberos & valid credentials on the domain but no ACLs on the resource // the handle for m_SecurityContext will be collected at GC time. GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob() null blob AND m_SecurityContext#" + ValidationHelper.HashString(m_SecurityContext) + "::Handle:[0x" + m_SecurityContext.Handle.ToString("x8") + "]"); m_SecurityContext.Close(); IsCompleted = true; return(null); } int requestedFlags = (int)ContextFlags.Delegate | (int)ContextFlags.MutualAuth | (int)ContextFlags.ReplayDetect | (int)ContextFlags.SequenceDetect | (int)ContextFlags.Confidentiality | (int)ContextFlags.Connection; SecurityBufferClass inSecurityBuffer = null; if (incomingBlob != null) { GlobalLog.Print("in blob = "); GlobalLog.Dump(incomingBlob); inSecurityBuffer = new SecurityBufferClass(incomingBlob, BufferType.Token); } SecurityBufferClass outSecurityBuffer = new SecurityBufferClass(m_TokenSize, BufferType.Token); int status; #if SERVER_SIDE_SSPI if (m_SecureSessionType == SecureSessionType.ClientSession) { #endif // // client session // requestedFlags |= (int)ContextFlags.ClientIntegrity; status = SSPIWrapper.InitializeSecurityContext( GlobalSSPI.SSPIAuth, m_CredentialsHandle.Handle, m_SecurityContext.Handle, m_RemotePeerId, requestedFlags, m_Endianness, inSecurityBuffer, ref m_SecurityContext.Handle, outSecurityBuffer, ref m_ContextFlags, ref m_SecurityContext.TimeStamp ); GlobalLog.Print("SSPIWrapper.InitializeSecurityContext() returns 0x" + string.Format("{0:x}", status)); #if SERVER_SIDE_SSPI } else { // // server session // requestedFlags |= (int)ContextFlags.ServerIntegrity; status = SSPIWrapper.AcceptSecurityContext( GlobalSSPI.SSPIAuth, m_CredentialsHandle.Handle, m_SecurityContext.Handle, requestedFlags, m_Endianness, inSecurityBuffer, ref m_SecurityContext.Handle, outSecurityBuffer, out m_ContextFlags, out m_SecurityContext.TimeStamp ); GlobalLog.Print("SSPIWrapper.AcceptSecurityContext() returns 0x" + string.Format("{0:x}", status)); } #endif // SERVER_SIDE_SSPI int errorCode = status & unchecked ((int)0x80000000); if (errorCode != 0) { throw new Win32Exception(status); } // // 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 (status != (int)SecurityStatus.OK && m_SecurityContext.Handle != -1) { // we need to continue GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob() need continue status:[0x" + status.ToString("x8") + "] m_SecurityContext#" + ValidationHelper.HashString(m_SecurityContext) + "::Handle:[0x" + m_SecurityContext.Handle.ToString("x8") + "]"); handshakeComplete = false; } else { // we're done, cleanup GlobalLog.Assert(status == (int)SecurityStatus.OK, "NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob() status:[0x" + status.ToString("x8") + "] m_SecurityContext#" + ValidationHelper.HashString(m_SecurityContext) + "::Handle:[0x" + m_SecurityContext.Handle.ToString("x8") + "]", "[STATUS != OK]"); m_SecurityContext.Close(); IsCompleted = true; } #if TRAVE if (handshakeComplete) { // // Kevin Damour says: // You should not query the securitycontext until you have actually formed one ( // with a success return form ISC). It is only a partially formed context and // no info is available to user applications (at least for digest). // SecurityPackageInfoClass securityPackageInfo = (SecurityPackageInfoClass)SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPIAuth, m_SecurityContext, ContextAttribute.PackageInfo); GlobalLog.Print("SecurityPackageInfoClass: using:[" + ((securityPackageInfo == null)?"null":securityPackageInfo.ToString()) + "]"); } #endif // #if TRAVE GlobalLog.Print("out token = " + m_TokenSize.ToString()); GlobalLog.Dump(outSecurityBuffer.token); GlobalLog.Leave("NTAuthentication::GetOutgoingBlob", "handshakeComplete:" + handshakeComplete.ToString()); return(outSecurityBuffer.token); }
internal string GetOutgoingDigestBlob(string incomingBlob, string requestMethod, string requestedUri, string realm, bool isClientPreAuth, bool throwOnError, out SecurityStatus statusCode) { SecurityBuffer[] inputBuffers = null; SecurityBuffer outputBuffer = new SecurityBuffer(this.m_TokenSize, isClientPreAuth ? BufferType.Parameters : BufferType.Token); bool flag = this.m_SecurityContext == null; try { if (!this.m_IsServer) { if (!isClientPreAuth) { if (incomingBlob != null) { List <SecurityBuffer> list = new List <SecurityBuffer>(5) { new SecurityBuffer(WebHeaderCollection.HeaderEncoding.GetBytes(incomingBlob), 2), new SecurityBuffer(WebHeaderCollection.HeaderEncoding.GetBytes(requestMethod), 3), new SecurityBuffer(null, 3), new SecurityBuffer(Encoding.Unicode.GetBytes(this.m_Spn), 0x10) }; if (this.m_ChannelBinding != null) { list.Add(new SecurityBuffer(this.m_ChannelBinding)); } inputBuffers = list.ToArray(); } statusCode = (SecurityStatus)SSPIWrapper.InitializeSecurityContext(GlobalSSPI.SSPIAuth, this.m_CredentialsHandle, ref this.m_SecurityContext, requestedUri, this.m_RequestedContextFlags, Endianness.Network, inputBuffers, outputBuffer, ref this.m_ContextFlags); } else { statusCode = SecurityStatus.OK; } } else { List <SecurityBuffer> list2 = new List <SecurityBuffer>(6) { (incomingBlob == null) ? new SecurityBuffer(0, BufferType.Token) : new SecurityBuffer(WebHeaderCollection.HeaderEncoding.GetBytes(incomingBlob), BufferType.Token), (requestMethod == null) ? new SecurityBuffer(0, BufferType.Parameters) : new SecurityBuffer(WebHeaderCollection.HeaderEncoding.GetBytes(requestMethod), BufferType.Parameters), (requestedUri == null) ? new SecurityBuffer(0, BufferType.Parameters) : new SecurityBuffer(WebHeaderCollection.HeaderEncoding.GetBytes(requestedUri), BufferType.Parameters), new SecurityBuffer(0, BufferType.Parameters), (realm == null) ? new SecurityBuffer(0, BufferType.Parameters) : new SecurityBuffer(Encoding.Unicode.GetBytes(realm), BufferType.Parameters) }; if (this.m_ChannelBinding != null) { list2.Add(new SecurityBuffer(this.m_ChannelBinding)); } inputBuffers = list2.ToArray(); statusCode = (SecurityStatus)SSPIWrapper.AcceptSecurityContext(GlobalSSPI.SSPIAuth, this.m_CredentialsHandle, ref this.m_SecurityContext, this.m_RequestedContextFlags, Endianness.Network, inputBuffers, outputBuffer, ref this.m_ContextFlags); if (statusCode == SecurityStatus.CompleteNeeded) { inputBuffers[4] = outputBuffer; statusCode = (SecurityStatus)SSPIWrapper.CompleteAuthToken(GlobalSSPI.SSPIAuth, ref this.m_SecurityContext, inputBuffers); outputBuffer.token = null; } } } finally { if (flag && (this.m_CredentialsHandle != null)) { this.m_CredentialsHandle.Close(); } } if ((statusCode & ((SecurityStatus)(-2147483648))) != SecurityStatus.OK) { this.CloseContext(); if (throwOnError) { Win32Exception exception = new Win32Exception((int)statusCode); throw exception; } return(null); } if (flag && (this.m_CredentialsHandle != null)) { SSPIHandleCache.CacheCredential(this.m_CredentialsHandle); } if (statusCode == SecurityStatus.OK) { this.m_IsCompleted = true; } byte[] token = outputBuffer.token; string str = null; if ((token != null) && (token.Length > 0)) { str = WebHeaderCollection.HeaderEncoding.GetString(token, 0, outputBuffer.size); } return(str); }
// // NTAuthentication::NTAuthentication() // Created: 12-01-1999: L.M. // Parameters: // package - security package to use (kerberos/ntlm/negotiate) // networkCredential - credentials we're using for authentication // remotePeerId - for a server session: // ignored (except when delegating, in which case this has the same rules as the client session.) // for a client session: // for kerberos: specifies the expected account under which the server // is supposed to be running (KDC). If the server runs under a // different account an exception is thrown during the blob // exchange. (this allows mutual authentication.) // One can specify a fully qualified account name (domain\userName) // or just a username, in which case the domain is assumed // to be the same as the client. // for ntlm: ignored // // Description: Initializes SSPI // public NTAuthentication(string package, NetworkCredential networkCredential, string remotePeerId, DelegationFix delegationFix) { GlobalLog.Print("NTAuthentication::.ctor() package:" + package); #if SERVER_SIDE_SSPI m_SecureSessionType = SecureSessionType.ClientSession; #endif m_RemotePeerId = remotePeerId; // only needed for Kerberos, it's the KDC m_Endianness = Endianness.Network; m_SecurityContext = new SecurityContext(GlobalSSPI.SSPIAuth); bool found = false; GlobalLog.Print("NTAuthentication::.ctor() searching for name: " + package); if (m_SupportedSecurityPackages != null) { for (int i = 0; i < m_SupportedSecurityPackages.Length; i++) { GlobalLog.Print("NTAuthentication::.ctor() supported name: " + m_SupportedSecurityPackages[i].Name); if (string.Compare(m_SupportedSecurityPackages[i].Name, package, true, CultureInfo.InvariantCulture) == 0) { GlobalLog.Print("NTAuthentication::.ctor(): found SecurityPackage(" + package + ")"); m_TokenSize = m_SupportedSecurityPackages[i].MaxToken; m_Capabilities = m_SupportedSecurityPackages[i].Capabilities; found = true; break; } } } if (!found) { GlobalLog.Print("NTAuthentication::.ctor(): initialization failed: SecurityPackage(" + package + ") NOT FOUND"); throw new WebException(SR.GetString(SR.net_securitypackagesupport), WebExceptionStatus.SecureChannelFailure); } // // In order to prevent a race condition where one request could // steal a connection from another request, before a handshake is // complete, we create a new Group for each authentication request. // if (package == NtlmClient.AuthType || package == NegotiateClient.AuthType) { m_UniqueUserId = (Interlocked.Increment(ref s_UniqueGroupId)).ToString(); } // // check if we're using DefaultCredentials // if (networkCredential is SystemNetworkCredential) { // // we're using DefaultCredentials // GlobalLog.Print("NTAuthentication::.ctor(): using DefaultCredentials"); m_UniqueUserId += "/S"; // save off for unique connection marking // DELEGATION: // The fix is implemented in cooperation with HttpWebRequest class // Remove from both places and change the constructor of NTAuthentication class // once the Common Language Runtime will start propagating the Thread token with their stack // compression stuff. // GlobalLog.Assert(delegationFix != null, "DelegationFix ==NULL -> request Credentials has been changed after the request submission!", ""); if (delegationFix != null) { delegationFix.SetToken(); } GlobalLog.Print("DELEGATION for peer-> '" + m_RemotePeerId + "', SetToken = " + delegationFix.Token.ToString()); try { m_CredentialsHandle = SSPIWrapper.AcquireCredentialsHandle( GlobalSSPI.SSPIAuth, package, CredentialUse.Outgoing); } finally { if (delegationFix != null) { delegationFix.RevertToken(); } GlobalLog.Print("DELEGATION for peer-> '" + m_RemotePeerId + "', UNSetToken = " + delegationFix.Token.ToString()); } return; } // // we're not using DefaultCredentials, we need a // AuthIdentity struct to contain credentials // SECREVIEW: // we'll save username/domain in temp strings, to avoid decrypting multiple times. // password is only used once // string username = networkCredential.UserName; string domain = networkCredential.Domain; m_UniqueUserId += domain + "/" + username + "/U"; // save off for unique connection marking AuthIdentity authIdentity = new AuthIdentity(username, networkCredential.Password, domain); GlobalLog.Print("NTAuthentication::.ctor(): using authIdentity:" + authIdentity.ToString()); m_CredentialsHandle = SSPIWrapper.AcquireCredentialsHandle( GlobalSSPI.SSPIAuth, package, CredentialUse.Outgoing, authIdentity ); }
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(nameof(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(nameof(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); }
// // 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); }
private string GetClientSpecifiedSpn() { return(SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPIAuth, this.m_SecurityContext, ContextAttribute.ClientSpecifiedSpn) as string); }
public static void VerifyPackageInfo() { SSPIWrapper.GetVerifyPackageInfo(GlobalSSPI.SSPISecureChannel, SecurityPackage, true); }
// // for Digest, the server will send us the blob immediately, so we need to make sure we // call InitializeSecurityContext() a first time with a null input buffer, otherwise // the next call will fail. do so here: // WDigest.dll requires us to pass in 3 security buffers here // 1) BufferType: SECBUFFER_TOKEN, Content: server's challenge (incoming) // 2) BufferType: SECBUFFER_PKG_PARAMS, Content: request's HTTP Method // 3) BufferType: SECBUFFER_PKG_PARAMS, Content: the HEntity (this would be the MD5 footprint of the request entity // body, we can pass in NULL as this is not required) // public string GetOutgoingDigestBlob(string incomingBlob, string requestMethod, out bool handshakeComplete) { GlobalLog.Enter("NTAuthentication::GetOutgoingDigestBlob", incomingBlob); // // first time call with null incoming buffer to initialize. // we should get back a 0x90312 and a null outgoingBlob. // byte[] decodedOutgoingBlob = GetOutgoingBlob(null, out handshakeComplete); GlobalLog.Assert(!handshakeComplete, "NTAuthentication::GetOutgoingDigestBlob() handshakeComplete==true", ""); GlobalLog.Assert(decodedOutgoingBlob == null, "NTAuthentication::GetOutgoingDigestBlob() decodedOutgoingBlob!=null", ""); // // second time call with 3 incoming buffers to select HTTP client. // we should get back a SecurityStatus.OK and a non null outgoingBlob. // byte[] decodedIncomingBlob = Encoding.Default.GetBytes(incomingBlob); byte[] decodedRequestMethod = Encoding.Default.GetBytes(requestMethod); int requestedFlags = (int)ContextFlags.Delegate | (int)ContextFlags.MutualAuth | (int)ContextFlags.ReplayDetect | (int)ContextFlags.SequenceDetect | // (int)ContextFlags.Confidentiality | // this would only work if the server provided a qop="auth-conf" directive // (int)ContextFlags.ClientIntegrity | // this would only work if the server provided a qop="auth-int" directive (int)ContextFlags.Connection; SecurityBufferClass[] inSecurityBuffers = new SecurityBufferClass[] { new SecurityBufferClass(decodedIncomingBlob, BufferType.Token), new SecurityBufferClass(decodedRequestMethod, BufferType.Parameters), new SecurityBufferClass(null, BufferType.Parameters), }; SecurityBufferClass[] outSecurityBuffers = new SecurityBufferClass[] { new SecurityBufferClass(m_TokenSize, BufferType.Token), }; SecurityContext newSecurityContext = new SecurityContext(GlobalSSPI.SSPIAuth); // // this call is still returning an error. fix together with Kevin Damour // int status = SSPIWrapper.InitializeSecurityContext( GlobalSSPI.SSPIAuth, m_CredentialsHandle.Handle, m_SecurityContext.Handle, m_RemotePeerId, // this must match the Uri in the HTTP status line for the current request requestedFlags, m_Endianness, inSecurityBuffers, ref newSecurityContext.Handle, outSecurityBuffers, ref m_ContextFlags, ref newSecurityContext.TimeStamp); GlobalLog.Print("NTAuthentication::GetOutgoingDigestBlob() SSPIWrapper.InitializeSecurityContext() returns 0x" + string.Format("{0:x}", status)); int errorCode = status & unchecked ((int)0x80000000); if (errorCode != 0) { throw new Win32Exception(status); } // // 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. // IsCompleted = (status == (int)SecurityStatus.OK) || (m_SecurityContext.Handle != -1 && m_SecurityContext.Handle != newSecurityContext.Handle); if (IsCompleted) { // ... if we're done, clean the handle up or the call to UpdateHandle() might leak it. SSPIWrapper.DeleteSecurityContext(m_SecurityContext.m_SecModule, m_SecurityContext.Handle); } handshakeComplete = IsCompleted; m_Authenticated = m_SecurityContext.Handle != -1; m_SecurityContext.UpdateHandle(newSecurityContext); #if TRAVE if (handshakeComplete) { // // Kevin Damour says: // You should not query the securitycontext until you have actually formed one ( // with a success return form ISC). It is only a partially formed context and // no info is available to user applications (at least for digest). // SecurityPackageInfoClass securityPackageInfo = (SecurityPackageInfoClass)SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPIAuth, m_SecurityContext, ContextAttribute.PackageInfo); GlobalLog.Print("SecurityPackageInfoClass: using:[" + ((securityPackageInfo == null)?"null":securityPackageInfo.ToString()) + "]"); } #endif // #if TRAVE GlobalLog.Assert(outSecurityBuffers.Length == 1, "NTAuthentication::GetOutgoingDigestBlob() outSecurityBuffers.Length==" + outSecurityBuffers.Length.ToString(), ""); GlobalLog.Print("out token = " + m_TokenSize.ToString() + " size = " + outSecurityBuffers[0].size.ToString()); GlobalLog.Dump(outSecurityBuffers[0].token); GlobalLog.Print("NTAuthentication::GetOutgoingDigestBlob() handshakeComplete:" + handshakeComplete.ToString()); decodedOutgoingBlob = outSecurityBuffers[0].token; string outgoingBlob = null; if (decodedOutgoingBlob != null && decodedOutgoingBlob.Length > 0) { // CONSIDER V.NEXT // review Encoding.Default.GetString usage here because it might // end up creating non ANSI characters in the string outgoingBlob = Encoding.Default.GetString(decodedOutgoingBlob, 0, outSecurityBuffers[0].size); } GlobalLog.Leave("NTAuthentication::GetOutgoingDigestBlob", outgoingBlob); return(outgoingBlob); }