internal SecureChannel(string hostname, bool serverMode, SslProtocols sslProtocols, X509Certificate serverCertificate, X509CertificateCollection clientCertificates, bool remoteCertRequired, bool checkCertName, bool checkCertRevocationStatus, EncryptionPolicy encryptionPolicy, LocalCertSelectionCallback certSelectionDelegate) { GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::.ctor", "hostname:" + hostname + " #clientCertificates=" + ((clientCertificates == null) ? "0" : clientCertificates.Count.ToString(NumberFormatInfo.InvariantInfo))); if (Logging.On) { Logging.PrintInfo(Logging.Web, this, ".ctor", "hostname=" + hostname + ", #clientCertificates=" + ((clientCertificates == null) ? "0" : clientCertificates.Count.ToString(NumberFormatInfo.InvariantInfo)) + ", encryptionPolicy=" + encryptionPolicy); } SSPIWrapper.VerifyPackageInfo(GlobalSSPI.SSPISecureChannel); _destination = hostname; GlobalLog.Assert(hostname != null, "SecureChannel#{0}::.ctor()|hostname == null", Logging.HashString(this)); _hostName = hostname; _serverMode = serverMode; _sslProtocols = sslProtocols; _serverCertificate = serverCertificate; _clientCertificates = clientCertificates; _remoteCertRequired = remoteCertRequired; _securityContext = null; _checkCertRevocation = checkCertRevocationStatus; _checkCertName = checkCertName; _certSelectionDelegate = certSelectionDelegate; _refreshCredentialNeeded = true; _encryptionPolicy = encryptionPolicy; GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::.ctor"); }
internal SecureChannel(string hostname, bool serverMode, SslProtocols sslProtocols, X509Certificate serverCertificate, X509CertificateCollection clientCertificates, bool remoteCertRequired, bool checkCertName, bool checkCertRevocationStatus, EncryptionPolicy encryptionPolicy, LocalCertSelectionCallback certSelectionDelegate) { if (NetEventSource.IsEnabled) { NetEventSource.Enter(this, hostname, clientCertificates); NetEventSource.Log.SecureChannelCtor(this, hostname, clientCertificates, encryptionPolicy); } SslStreamPal.VerifyPackageInfo(); _destination = hostname; if (hostname == null) { NetEventSource.Fail(this, "hostname == null"); } _hostName = hostname; _serverMode = serverMode; _sslProtocols = sslProtocols; _serverCertificate = serverCertificate; _clientCertificates = clientCertificates; _remoteCertRequired = remoteCertRequired; _securityContext = null; _checkCertRevocation = checkCertRevocationStatus; _checkCertName = checkCertName; _certSelectionDelegate = certSelectionDelegate; _refreshCredentialNeeded = true; _encryptionPolicy = encryptionPolicy; if (NetEventSource.IsEnabled) NetEventSource.Exit(this); }
internal static SecurityStatusPal CompleteAuthToken( ref SafeDeleteContext securityContext, SecurityBuffer[] inSecurityBufferArray) { Interop.SECURITY_STATUS winStatus = (Interop.SECURITY_STATUS)SSPIWrapper.CompleteAuthToken( GlobalSSPI.SSPIAuth, ref securityContext, inSecurityBufferArray); return SecurityStatusAdapterPal.GetSecurityStatusPalFromInterop(winStatus); }
public static SecurityStatusPal DecryptMessage(SafeDeleteContext securityContext, byte[] buffer, ref int offset, ref int count) { int resultSize; SecurityStatusPal retVal = EncryptDecryptHelper(securityContext, buffer, offset, count, false, ref buffer, out resultSize); if (retVal.ErrorCode == SecurityStatusPalErrorCode.OK || retVal.ErrorCode == SecurityStatusPalErrorCode.Renegotiate) { count = resultSize; } return retVal; }
public static SecurityStatusPal AcceptSecurityContext(ref SafeFreeCredentials credentialsHandle, ref SafeDeleteContext context, SecurityBuffer inputBuffer, SecurityBuffer outputBuffer, bool remoteCertRequired) { Interop.SspiCli.ContextFlags unusedAttributes = default(Interop.SspiCli.ContextFlags); int errorCode = SSPIWrapper.AcceptSecurityContext( GlobalSSPI.SSPISecureChannel, ref credentialsHandle, ref context, ServerRequiredFlags | (remoteCertRequired ? Interop.SspiCli.ContextFlags.MutualAuth : Interop.SspiCli.ContextFlags.Zero), Interop.SspiCli.Endianness.SECURITY_NATIVE_DREP, inputBuffer, outputBuffer, ref unusedAttributes); return SecurityStatusAdapterPal.GetSecurityStatusPalFromNativeInt(errorCode); }
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.SECURITY_NATIVE_DREP, inputBuffers, outputBuffer, ref unusedAttributes); return SecurityStatusAdapterPal.GetSecurityStatusPalFromNativeInt(errorCode); }
internal SecureChannel(string hostname, bool serverMode, SslProtocols sslProtocols, X509Certificate serverCertificate, X509CertificateCollection clientCertificates, bool remoteCertRequired, bool checkCertName, bool checkCertRevocationStatus, EncryptionPolicy encryptionPolicy, LocalCertSelectionCallback certSelectionDelegate) { if (GlobalLog.IsEnabled) { GlobalLog.Enter("SecureChannel#" + LoggingHash.HashString(this) + "::.ctor", "hostname:" + hostname + " #clientCertificates=" + ((clientCertificates == null) ? "0" : clientCertificates.Count.ToString(NumberFormatInfo.InvariantInfo))); } if (SecurityEventSource.Log.IsEnabled()) { SecurityEventSource.SecureChannelCtor(this, hostname, clientCertificates, encryptionPolicy); } SslStreamPal.VerifyPackageInfo(); _destination = hostname; if (hostname == null) { if (GlobalLog.IsEnabled) { GlobalLog.AssertFormat("SecureChannel#{0}::.ctor()|hostname == null", LoggingHash.HashString(this)); } Debug.Fail("SecureChannel#" + LoggingHash.HashString(this) + "::.ctor()|hostname == null"); } _hostName = hostname; _serverMode = serverMode; _sslProtocols = sslProtocols; _serverCertificate = serverCertificate; _clientCertificates = clientCertificates; _remoteCertRequired = remoteCertRequired; _securityContext = null; _checkCertRevocation = checkCertRevocationStatus; _checkCertName = checkCertName; _certSelectionDelegate = certSelectionDelegate; _refreshCredentialNeeded = true; _encryptionPolicy = encryptionPolicy; if (GlobalLog.IsEnabled) { GlobalLog.Leave("SecureChannel#" + LoggingHash.HashString(this) + "::.ctor"); } }
private unsafe static int QueryContextAttributes_SECURITY( SafeDeleteContext phContext, Interop.Secur32.ContextAttribute contextAttribute, byte* buffer, SafeHandle refHandle) { int status = (int)Interop.SecurityStatus.InvalidHandle; try { bool ignore = false; phContext.DangerousAddRef(ref ignore); status = Interop.Secur32.QueryContextAttributesW(ref phContext._handle, contextAttribute, buffer); } finally { phContext.DangerousRelease(); } if (status == 0 && refHandle != null) { if (refHandle is SafeFreeContextBuffer) { ((SafeFreeContextBuffer)refHandle).Set(*(IntPtr*)buffer); } else { ((SafeFreeCertContext)refHandle).Set(*(IntPtr*)buffer); } } if (status != 0 && refHandle != null) { refHandle.SetHandleAsInvalid(); } return status; }
internal static SecurityStatusPal InitializeSecurityContext( SafeFreeCredentials credentialsHandle, ref SafeDeleteContext securityContext, string spn, ContextFlagsPal requestedContextFlags, SecurityBuffer[] inSecurityBufferArray, SecurityBuffer outSecurityBuffer, ref ContextFlagsPal contextFlags) { Interop.SspiCli.ContextFlags outContextFlags = Interop.SspiCli.ContextFlags.Zero; Interop.SECURITY_STATUS winStatus = (Interop.SECURITY_STATUS)SSPIWrapper.InitializeSecurityContext( GlobalSSPI.SSPIAuth, credentialsHandle, ref securityContext, spn, ContextFlagsAdapterPal.GetInteropFromContextFlagsPal(requestedContextFlags), Interop.SspiCli.Endianness.SECURITY_NETWORK_DREP, inSecurityBufferArray, outSecurityBuffer, ref outContextFlags); contextFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop(outContextFlags); return SecurityStatusAdapterPal.GetSecurityStatusPalFromInterop(winStatus); }
// // After PInvoke call the method will fix the refHandle.handle with the returned value. // The caller is responsible for creating a correct SafeHandle template or null can be passed if no handle is returned. // // This method switches between three non-interruptible helper methods. (This method can't be both non-interruptible and // reference imports from all three DLLs - doing so would cause all three DLLs to try to be bound to.) // public unsafe static int QueryContextAttributes(SafeDeleteContext phContext, Interop.Secur32.ContextAttribute contextAttribute, byte *buffer, SafeHandle refHandle) { return(QueryContextAttributes_SECURITY(phContext, contextAttribute, buffer, refHandle)); }
internal static int Decrypt( SafeDeleteContext securityContext, byte[] buffer, int offset, int count, bool isConfidential, bool isNtlm, out int newOffset, uint sequenceNumber) { if (offset < 0 || offset > (buffer == null ? 0 : buffer.Length)) { if (GlobalLog.IsEnabled) { GlobalLog.Assert("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::Decrypt", "Argument 'offset' out of range."); } Debug.Fail("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::Decrypt", "Argument 'offset' out of range."); throw new ArgumentOutOfRangeException(nameof(offset)); } if (count < 0 || count > (buffer == null ? 0 : buffer.Length - offset)) { if (GlobalLog.IsEnabled) { GlobalLog.Assert("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::Decrypt", "Argument 'count' out of range."); } Debug.Fail("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::Decrypt", "Argument 'count' out of range."); throw new ArgumentOutOfRangeException(nameof(count)); } if (isNtlm) { return DecryptNtlm(securityContext, buffer, offset, count, isConfidential, out newOffset, sequenceNumber); } // // Kerberos and up // var securityBuffer = new SecurityBuffer[2]; securityBuffer[0] = new SecurityBuffer(buffer, offset, count, SecurityBufferType.Stream); securityBuffer[1] = new SecurityBuffer(0, SecurityBufferType.Data); int errorCode; if (isConfidential) { errorCode = SSPIWrapper.DecryptMessage(GlobalSSPI.SSPIAuth, securityContext, securityBuffer, sequenceNumber); } else { errorCode = SSPIWrapper.VerifySignature(GlobalSSPI.SSPIAuth, securityContext, securityBuffer, sequenceNumber); } if (errorCode != 0) { if (GlobalLog.IsEnabled) { GlobalLog.Print("NTAuthentication#"+ "::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 static string QueryContextAssociatedName(SafeDeleteContext securityContext) { throw new PlatformNotSupportedException(SR.net_nego_server_not_supported); }
public static void QueryContextConnectionInfo( SafeDeleteContext securityContext, out SslConnectionInfo connectionInfo) { connectionInfo = new SslConnectionInfo(((SafeDeleteSslContext)securityContext).SslContext); }
// // After PInvoke call the method will fix the refHandle.handle with the returned value. // The caller is responsible for creating a correct SafeHandle template or null can be passed if no handle is returned. // // This method switches between three non-interruptible helper methods. (This method can't be both non-interruptible and // reference imports from all three DLLs - doing so would cause all three DLLs to try to be bound to.) // public unsafe static int QueryContextAttributes(SafeDeleteContext phContext, Interop.Secur32.ContextAttribute contextAttribute, byte* buffer, SafeHandle refHandle) { return QueryContextAttributes_SECURITY(phContext, contextAttribute, buffer, refHandle); }
// // After PInvoke call the method will fix the handleTemplate.handle with the returned value. // The caller is responsible for creating a correct SafeFreeContextBuffer_XXX flavour or null can be passed if no handle is returned. // private static unsafe int MustRunAcceptSecurityContext_SECURITY( ref SafeFreeCredentials inCredentials, void *inContextPtr, Interop.Secur32.SecurityBufferDescriptor inputBuffer, Interop.Secur32.ContextFlags inFlags, Interop.Secur32.Endianness endianness, SafeDeleteContext outContext, Interop.Secur32.SecurityBufferDescriptor outputBuffer, ref Interop.Secur32.ContextFlags outFlags, SafeFreeContextBuffer handleTemplate) { int errorCode = (int)Interop.SecurityStatus.InvalidHandle; // Run the body of this method as a non-interruptible block. try { bool ignore = false; inCredentials.DangerousAddRef(ref ignore); outContext.DangerousAddRef(ref ignore); Interop.Secur32.SSPIHandle credentialHandle = inCredentials._handle; long timeStamp; errorCode = Interop.Secur32.AcceptSecurityContext( ref credentialHandle, inContextPtr, inputBuffer, inFlags, endianness, ref outContext._handle, outputBuffer, ref outFlags, out timeStamp); } finally { // // When a credential handle is first associated with the context we keep credential // ref count bumped up to ensure ordered finalization. // If the credential handle has been changed we de-ref the old one and associate the // context with the new cred handle but only if the call was successful. if (outContext._EffectiveCredential != inCredentials && (errorCode & 0x80000000) == 0) { // Disassociate the previous credential handle. if (outContext._EffectiveCredential != null) { outContext._EffectiveCredential.DangerousRelease(); } outContext._EffectiveCredential = inCredentials; } else { inCredentials.DangerousRelease(); } outContext.DangerousRelease(); } // The idea is that SSPI has allocated a block and filled up outUnmanagedBuffer+8 slot with the pointer. if (handleTemplate != null) { //ATTN: on 64 BIT that is still +8 cause of 2* c++ unsigned long == 8 bytes. handleTemplate.Set(((Interop.Secur32.SecurityBufferStruct *)outputBuffer.UnmanagedPointer)->token); if (handleTemplate.IsInvalid) { handleTemplate.SetHandleAsInvalid(); } } if (inContextPtr == null && (errorCode & 0x80000000) != 0) { // An error on the first call, need to set the out handle to invalid value. outContext._handle.SetToInvalid(); } return(errorCode); }
public static SecurityStatusPal InitializeSecurityContext(SafeFreeCredentials credentialsHandle, ref SafeDeleteContext context, string targetName, SecurityBuffer[] inputBuffers, SecurityBuffer outputBuffer, SslAuthenticationOptions sslAuthenticationOptions) { 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.SECURITY_NATIVE_DREP, inputBuffers, outputBuffer, ref unusedAttributes); return(SecurityStatusAdapterPal.GetSecurityStatusPalFromNativeInt(errorCode)); }
public unsafe static int QueryContextChannelBinding(SafeDeleteContext phContext, Interop.Secur32.ContextAttribute contextAttribute, Bindings* buffer, SafeFreeContextBufferChannelBinding refHandle) { return QueryContextChannelBinding_SECURITY(phContext, contextAttribute, buffer, refHandle); }
public static unsafe SafeFreeContextBufferChannelBinding QueryContextChannelBinding(SafeDeleteContext securityContext, ChannelBindingKind attribute) { return(SSPIWrapper.QueryContextChannelBinding(GlobalSSPI.SSPISecureChannel, securityContext, (Interop.SspiCli.ContextAttribute)attribute)); }
public static SecurityStatusPal AcceptSecurityContext(ref SafeFreeCredentials credentialsHandle, ref SafeDeleteContext context, SecurityBuffer[] inputBuffers, SecurityBuffer outputBuffer, SslAuthenticationOptions sslAuthenticationOptions) { Interop.SspiCli.ContextFlags unusedAttributes = default(Interop.SspiCli.ContextFlags); int errorCode = SSPIWrapper.AcceptSecurityContext( GlobalSSPI.SSPISecureChannel, credentialsHandle, ref context, ServerRequiredFlags | (sslAuthenticationOptions.RemoteCertRequired ? Interop.SspiCli.ContextFlags.MutualAuth : Interop.SspiCli.ContextFlags.Zero), Interop.SspiCli.Endianness.SECURITY_NATIVE_DREP, inputBuffers, outputBuffer, ref unusedAttributes); return(SecurityStatusAdapterPal.GetSecurityStatusPalFromNativeInt(errorCode)); }
public static SecurityStatusPal ApplyShutdownToken(ref SafeFreeCredentials credentialsHandle, SafeDeleteContext securityContext) { int shutdownToken = Interop.SChannel.SCHANNEL_SHUTDOWN; var bufferDesc = new SecurityBuffer[1]; var buffer = BitConverter.GetBytes(shutdownToken); bufferDesc[0] = new SecurityBuffer(buffer, SecurityBufferType.SECBUFFER_TOKEN); var errorCode = (Interop.SECURITY_STATUS)SSPIWrapper.ApplyControlToken( GlobalSSPI.SSPISecureChannel, ref securityContext, bufferDesc); return(SecurityStatusAdapterPal.GetSecurityStatusPalFromInterop(errorCode, attachException: true)); }
public static SecurityStatusPal ApplyAlertToken(ref SafeFreeCredentials credentialsHandle, SafeDeleteContext securityContext, TlsAlertType alertType, TlsAlertMessage alertMessage) { Interop.SChannel.SCHANNEL_ALERT_TOKEN alertToken; alertToken.dwTokenType = Interop.SChannel.SCHANNEL_ALERT; alertToken.dwAlertType = (uint)alertType; alertToken.dwAlertNumber = (uint)alertMessage; var bufferDesc = new SecurityBuffer[1]; int alertTokenByteSize = Marshal.SizeOf <Interop.SChannel.SCHANNEL_ALERT_TOKEN>(); IntPtr p = Marshal.AllocHGlobal(alertTokenByteSize); try { var buffer = new byte[alertTokenByteSize]; Marshal.StructureToPtr <Interop.SChannel.SCHANNEL_ALERT_TOKEN>(alertToken, p, false); Marshal.Copy(p, buffer, 0, alertTokenByteSize); bufferDesc[0] = new SecurityBuffer(buffer, SecurityBufferType.SECBUFFER_TOKEN); var errorCode = (Interop.SECURITY_STATUS)SSPIWrapper.ApplyControlToken( GlobalSSPI.SSPISecureChannel, ref securityContext, bufferDesc); return(SecurityStatusAdapterPal.GetSecurityStatusPalFromInterop(errorCode, attachException: true)); } finally { Marshal.FreeHGlobal(p); } }
public static unsafe SecurityStatusPal EncryptMessage(SafeDeleteContext securityContext, ReadOnlyMemory <byte> input, int headerSize, int trailerSize, ref byte[] output, out int resultSize) { // Ensure that there is sufficient space for the message output. int bufferSizeNeeded; try { bufferSizeNeeded = checked (input.Length + headerSize + trailerSize); } catch { NetEventSource.Fail(securityContext, "Arguments out of range"); throw; } if (output == null || output.Length < bufferSizeNeeded) { output = new byte[bufferSizeNeeded]; } // Copy the input into the output buffer to prepare for SCHANNEL's expectations input.Span.CopyTo(new Span <byte>(output, headerSize, input.Length)); const int NumSecBuffers = 4; // header + data + trailer + empty var unmanagedBuffer = stackalloc Interop.SspiCli.SecBuffer[NumSecBuffers]; var sdcInOut = new Interop.SspiCli.SecBufferDesc(NumSecBuffers); sdcInOut.pBuffers = unmanagedBuffer; fixed(byte *outputPtr = output) { Interop.SspiCli.SecBuffer *headerSecBuffer = &unmanagedBuffer[0]; headerSecBuffer->BufferType = SecurityBufferType.SECBUFFER_STREAM_HEADER; headerSecBuffer->pvBuffer = (IntPtr)outputPtr; headerSecBuffer->cbBuffer = headerSize; Interop.SspiCli.SecBuffer *dataSecBuffer = &unmanagedBuffer[1]; dataSecBuffer->BufferType = SecurityBufferType.SECBUFFER_DATA; dataSecBuffer->pvBuffer = (IntPtr)(outputPtr + headerSize); dataSecBuffer->cbBuffer = input.Length; Interop.SspiCli.SecBuffer *trailerSecBuffer = &unmanagedBuffer[2]; trailerSecBuffer->BufferType = SecurityBufferType.SECBUFFER_STREAM_TRAILER; trailerSecBuffer->pvBuffer = (IntPtr)(outputPtr + headerSize + input.Length); trailerSecBuffer->cbBuffer = trailerSize; Interop.SspiCli.SecBuffer *emptySecBuffer = &unmanagedBuffer[3]; emptySecBuffer->BufferType = SecurityBufferType.SECBUFFER_EMPTY; emptySecBuffer->cbBuffer = 0; emptySecBuffer->pvBuffer = IntPtr.Zero; int errorCode = GlobalSSPI.SSPISecureChannel.EncryptMessage(securityContext, ref sdcInOut, 0); if (errorCode != 0) { if (NetEventSource.IsEnabled) { NetEventSource.Info(securityContext, $"Encrypt ERROR {errorCode:X}"); } resultSize = 0; return(SecurityStatusAdapterPal.GetSecurityStatusPalFromNativeInt(errorCode)); } Debug.Assert(headerSecBuffer->cbBuffer >= 0 && dataSecBuffer->cbBuffer >= 0 && trailerSecBuffer->cbBuffer >= 0); Debug.Assert(checked (headerSecBuffer->cbBuffer + dataSecBuffer->cbBuffer + trailerSecBuffer->cbBuffer) <= output.Length); resultSize = checked (headerSecBuffer->cbBuffer + dataSecBuffer->cbBuffer + trailerSecBuffer->cbBuffer); return(new SecurityStatusPal(SecurityStatusPalErrorCode.OK)); } }
internal static string QueryContextAssociatedName(SafeDeleteContext securityContext) { return SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPIAuth, securityContext, Interop.SspiCli.ContextAttribute.Names) as string; }
private static unsafe int MustRunAcceptSecurityContext_SECURITY( ref SafeFreeCredentials inCredentials, bool isContextAbsent, Interop.SspiCli.SecBufferDesc *inputBuffer, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, SafeDeleteContext outContext, ref Interop.SspiCli.SecBufferDesc outputBuffer, ref Interop.SspiCli.ContextFlags outFlags, SafeFreeContextBuffer?handleTemplate) { int errorCode = (int)Interop.SECURITY_STATUS.InvalidHandle; // Run the body of this method as a non-interruptible block. try { bool ignore = false; inCredentials.DangerousAddRef(ref ignore); outContext.DangerousAddRef(ref ignore); Interop.SspiCli.CredHandle credentialHandle = inCredentials._handle; long timeStamp; // Now that "outContext" (or "refContext" by the caller) references an actual handle (and cannot // be closed until it is released below), point "inContextPtr" to its embedded handle (or // null if the embedded handle has not yet been initialized). Interop.SspiCli.CredHandle contextHandle = outContext._handle; void *inContextPtr = contextHandle.IsZero ? null : &contextHandle; // The "isContextAbsent" supplied by the caller is generally correct but was computed without proper // synchronization. Rewrite the indicator now that the final "inContext" is known, update if necessary. isContextAbsent = (inContextPtr == null); errorCode = Interop.SspiCli.AcceptSecurityContext( ref credentialHandle, inContextPtr, inputBuffer, inFlags, endianness, ref outContext._handle, ref outputBuffer, ref outFlags, out timeStamp); } finally { // // When a credential handle is first associated with the context we keep credential // ref count bumped up to ensure ordered finalization. // If the credential handle has been changed we de-ref the old one and associate the // context with the new cred handle but only if the call was successful. if (outContext._EffectiveCredential != inCredentials && (errorCode & 0x80000000) == 0) { // Disassociate the previous credential handle. outContext._EffectiveCredential?.DangerousRelease(); outContext._EffectiveCredential = inCredentials; } else { inCredentials.DangerousRelease(); } outContext.DangerousRelease(); } // The idea is that SSPI has allocated a block and filled up outUnmanagedBuffer+8 slot with the pointer. if (handleTemplate != null) { //ATTN: on 64 BIT that is still +8 cause of 2* c++ unsigned long == 8 bytes. handleTemplate.Set(((Interop.SspiCli.SecBuffer *)outputBuffer.pBuffers)->pvBuffer); if (handleTemplate.IsInvalid) { handleTemplate.SetHandleAsInvalid(); } } if (isContextAbsent && (errorCode & 0x80000000) != 0) { // An error on the first call, need to set the out handle to invalid value. outContext._handle.SetToInvalid(); } return(errorCode); }
internal static string QueryContextClientSpecifiedSpn(SafeDeleteContext securityContext) { return SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPIAuth, securityContext, Interop.SspiCli.ContextAttribute.ClientSpecifiedSpn) as string; }
public static void QueryContextStreamSizes( SafeDeleteContext securityContext, out StreamSizes streamSizes) { streamSizes = s_streamSizes; }
public static int SetContextAttributes( SafeDeleteContext phContext, Interop.Secur32.ContextAttribute contextAttribute, byte[] buffer) { return SetContextAttributes_SECURITY(phContext, contextAttribute, buffer); }
internal unsafe static int CompleteAuthToken( ref SafeDeleteContext refContext, SecurityBuffer[] inSecBuffers) { GlobalLog.Enter("SafeDeleteContext::CompleteAuthToken"); GlobalLog.Print(" refContext = " + Logging.ObjectToString(refContext)); #if TRACE_VERBOSE GlobalLog.Print(" inSecBuffers[] = length:" + inSecBuffers.Length); #endif GlobalLog.Assert(inSecBuffers != null, "SafeDeleteContext::CompleteAuthToken()|inSecBuffers == null"); var inSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(inSecBuffers.Length); int errorCode = (int)Interop.SecurityStatus.InvalidHandle; // These are pinned user byte arrays passed along with SecurityBuffers. GCHandle[] pinnedInBytes = null; var inUnmanagedBuffer = new Interop.Secur32.SecurityBufferStruct[inSecurityBufferDescriptor.Count]; fixed(void *inUnmanagedBufferPtr = inUnmanagedBuffer) { // Fix Descriptor pointer that points to unmanaged SecurityBuffers. inSecurityBufferDescriptor.UnmanagedPointer = inUnmanagedBufferPtr; pinnedInBytes = new GCHandle[inSecurityBufferDescriptor.Count]; SecurityBuffer securityBuffer; for (int index = 0; index < inSecurityBufferDescriptor.Count; ++index) { securityBuffer = inSecBuffers[index]; if (securityBuffer != null) { inUnmanagedBuffer[index].count = securityBuffer.size; inUnmanagedBuffer[index].type = securityBuffer.type; // Use the unmanaged token if it's not null; otherwise use the managed buffer. if (securityBuffer.unmanagedToken != null) { inUnmanagedBuffer[index].token = securityBuffer.unmanagedToken.DangerousGetHandle(); } else if (securityBuffer.token == null || securityBuffer.token.Length == 0) { inUnmanagedBuffer[index].token = IntPtr.Zero; } else { pinnedInBytes[index] = GCHandle.Alloc(securityBuffer.token, GCHandleType.Pinned); inUnmanagedBuffer[index].token = Marshal.UnsafeAddrOfPinnedArrayElement(securityBuffer.token, securityBuffer.offset); } #if TRACE_VERBOSE GlobalLog.Print("SecBuffer: cbBuffer:" + securityBuffer.size + " BufferType:" + securityBuffer.type); #endif } } Interop.Secur32.SSPIHandle contextHandle = new Interop.Secur32.SSPIHandle(); if (refContext != null) { contextHandle = refContext._handle; } try { if (refContext == null || refContext.IsInvalid) { refContext = new SafeDeleteContext_SECURITY(); } try { bool ignore = false; refContext.DangerousAddRef(ref ignore); errorCode = Interop.Secur32.CompleteAuthToken(contextHandle.IsZero ? null : &contextHandle, inSecurityBufferDescriptor); } finally { refContext.DangerousRelease(); } } finally { if (pinnedInBytes != null) { for (int index = 0; index < pinnedInBytes.Length; index++) { if (pinnedInBytes[index].IsAllocated) { pinnedInBytes[index].Free(); } } } } } GlobalLog.Leave("SafeDeleteContext::CompleteAuthToken() unmanaged CompleteAuthToken()", "errorCode:0x" + errorCode.ToString("x8") + " refContext:" + Logging.ObjectToString(refContext)); return(errorCode); }
public static SecurityStatusPal InitializeSecurityContext(ref SafeFreeCredentials credentialsHandle, ref SafeDeleteContext context, string targetName, ArraySegment <byte> input, ref byte[] outputBuffer, SslAuthenticationOptions sslAuthenticationOptions) { Interop.SspiCli.ContextFlags unusedAttributes = default; ThreeSecurityBuffers threeSecurityBuffers = default; SecurityBuffer? incomingSecurity = input.Array != null ? new SecurityBuffer(input.Array, input.Offset, input.Count, SecurityBufferType.SECBUFFER_TOKEN) : (SecurityBuffer?)null; Span <SecurityBuffer> inputBuffers = MemoryMarshal.CreateSpan(ref threeSecurityBuffers._item0, 3); GetIncomingSecurityBuffers(sslAuthenticationOptions, in incomingSecurity, ref inputBuffers); var resultBuffer = new SecurityBuffer(outputBuffer, SecurityBufferType.SECBUFFER_TOKEN); int errorCode = SSPIWrapper.InitializeSecurityContext( GlobalSSPI.SSPISecureChannel, ref credentialsHandle, ref context, targetName, RequiredFlags | Interop.SspiCli.ContextFlags.InitManualCredValidation, Interop.SspiCli.Endianness.SECURITY_NATIVE_DREP, inputBuffers, ref resultBuffer, ref unusedAttributes); outputBuffer = resultBuffer.token; return(SecurityStatusAdapterPal.GetSecurityStatusPalFromNativeInt(errorCode)); }
//------------------------------------------------------------------- internal unsafe static int AcceptSecurityContext( ref SafeFreeCredentials inCredentials, ref SafeDeleteContext refContext, Interop.Secur32.ContextFlags inFlags, Interop.Secur32.Endianness endianness, SecurityBuffer inSecBuffer, SecurityBuffer[] inSecBuffers, SecurityBuffer outSecBuffer, ref Interop.Secur32.ContextFlags outFlags) { #if TRACE_VERBOSE GlobalLog.Enter("SafeDeleteContext::AcceptSecurityContex"); GlobalLog.Print(" credential = " + inCredentials.ToString()); GlobalLog.Print(" refContext = " + Logging.ObjectToString(refContext)); GlobalLog.Print(" inFlags = " + inFlags); if (inSecBuffers == null) { GlobalLog.Print(" inSecBuffers = (null)"); } else { GlobalLog.Print(" inSecBuffers[] = length:" + inSecBuffers.Length); } #endif GlobalLog.Assert(outSecBuffer != null, "SafeDeleteContext::AcceptSecurityContext()|outSecBuffer != null"); GlobalLog.Assert(inSecBuffer == null || inSecBuffers == null, "SafeDeleteContext::AcceptSecurityContext()|inSecBuffer == null || inSecBuffers == null"); if (inCredentials == null) { throw new ArgumentNullException("inCredentials"); } Interop.Secur32.SecurityBufferDescriptor inSecurityBufferDescriptor = null; if (inSecBuffer != null) { inSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(1); } else if (inSecBuffers != null) { inSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(inSecBuffers.Length); } Interop.Secur32.SecurityBufferDescriptor outSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(1); // Actually, this is returned in outFlags. bool isSspiAllocated = (inFlags & Interop.Secur32.ContextFlags.AllocateMemory) != 0 ? true : false; int errorCode = -1; Interop.Secur32.SSPIHandle contextHandle = new Interop.Secur32.SSPIHandle(); if (refContext != null) { contextHandle = refContext._handle; } // These are pinned user byte arrays passed along with SecurityBuffers. GCHandle[] pinnedInBytes = null; GCHandle pinnedOutBytes = new GCHandle(); // Optional output buffer that may need to be freed. SafeFreeContextBuffer outFreeContextBuffer = null; try { pinnedOutBytes = GCHandle.Alloc(outSecBuffer.token, GCHandleType.Pinned); var inUnmanagedBuffer = new Interop.Secur32.SecurityBufferStruct[inSecurityBufferDescriptor == null ? 1 : inSecurityBufferDescriptor.Count]; fixed(void *inUnmanagedBufferPtr = inUnmanagedBuffer) { if (inSecurityBufferDescriptor != null) { // Fix Descriptor pointer that points to unmanaged SecurityBuffers. inSecurityBufferDescriptor.UnmanagedPointer = inUnmanagedBufferPtr; pinnedInBytes = new GCHandle[inSecurityBufferDescriptor.Count]; SecurityBuffer securityBuffer; for (int index = 0; index < inSecurityBufferDescriptor.Count; ++index) { securityBuffer = inSecBuffer != null ? inSecBuffer : inSecBuffers[index]; if (securityBuffer != null) { // Copy the SecurityBuffer content into unmanaged place holder. inUnmanagedBuffer[index].count = securityBuffer.size; inUnmanagedBuffer[index].type = securityBuffer.type; // Use the unmanaged token if it's not null; otherwise use the managed buffer. if (securityBuffer.unmanagedToken != null) { inUnmanagedBuffer[index].token = securityBuffer.unmanagedToken.DangerousGetHandle(); } else if (securityBuffer.token == null || securityBuffer.token.Length == 0) { inUnmanagedBuffer[index].token = IntPtr.Zero; } else { pinnedInBytes[index] = GCHandle.Alloc(securityBuffer.token, GCHandleType.Pinned); inUnmanagedBuffer[index].token = Marshal.UnsafeAddrOfPinnedArrayElement(securityBuffer.token, securityBuffer.offset); } #if TRACE_VERBOSE GlobalLog.Print("SecBuffer: cbBuffer:" + securityBuffer.size + " BufferType:" + securityBuffer.type); #endif } } } var outUnmanagedBuffer = new Interop.Secur32.SecurityBufferStruct[1]; fixed(void *outUnmanagedBufferPtr = outUnmanagedBuffer) { // Fix Descriptor pointer that points to unmanaged SecurityBuffers. outSecurityBufferDescriptor.UnmanagedPointer = outUnmanagedBufferPtr; // Copy the SecurityBuffer content into unmanaged place holder. outUnmanagedBuffer[0].count = outSecBuffer.size; outUnmanagedBuffer[0].type = outSecBuffer.type; if (outSecBuffer.token == null || outSecBuffer.token.Length == 0) { outUnmanagedBuffer[0].token = IntPtr.Zero; } else { outUnmanagedBuffer[0].token = Marshal.UnsafeAddrOfPinnedArrayElement(outSecBuffer.token, outSecBuffer.offset); } if (isSspiAllocated) { outFreeContextBuffer = SafeFreeContextBuffer.CreateEmptyHandle(); } if (refContext == null || refContext.IsInvalid) { refContext = new SafeDeleteContext_SECURITY(); } errorCode = MustRunAcceptSecurityContext_SECURITY( ref inCredentials, contextHandle.IsZero ? null : &contextHandle, inSecurityBufferDescriptor, inFlags, endianness, refContext, outSecurityBufferDescriptor, ref outFlags, outFreeContextBuffer); GlobalLog.Print("SafeDeleteContext:AcceptSecurityContext Marshalling OUT buffer"); // Get unmanaged buffer with index 0 as the only one passed into PInvoke. outSecBuffer.size = outUnmanagedBuffer[0].count; outSecBuffer.type = outUnmanagedBuffer[0].type; if (outSecBuffer.size > 0) { outSecBuffer.token = new byte[outSecBuffer.size]; Marshal.Copy(outUnmanagedBuffer[0].token, outSecBuffer.token, 0, outSecBuffer.size); } else { outSecBuffer.token = null; } } } } finally { if (pinnedInBytes != null) { for (int index = 0; index < pinnedInBytes.Length; index++) { if (pinnedInBytes[index].IsAllocated) { pinnedInBytes[index].Free(); } } } if (pinnedOutBytes.IsAllocated) { pinnedOutBytes.Free(); } if (outFreeContextBuffer != null) { outFreeContextBuffer.Dispose(); } } GlobalLog.Leave("SafeDeleteContext::AcceptSecurityContex() unmanaged AcceptSecurityContex()", "errorCode:0x" + errorCode.ToString("x8") + " refContext:" + Logging.ObjectToString(refContext)); return(errorCode); }
public unsafe static int QueryContextChannelBinding(SafeDeleteContext phContext, Interop.Secur32.ContextAttribute contextAttribute, Bindings *buffer, SafeFreeContextBufferChannelBinding refHandle) { return(QueryContextChannelBinding_SECURITY(phContext, contextAttribute, buffer, refHandle)); }
internal unsafe static int ApplyControlToken( ref SafeDeleteContext refContext, SecurityBuffer[] inSecBuffers) { if (NetEventSource.IsEnabled) { NetEventSource.Enter(null); NetEventSource.Info(null, $" refContext = {refContext}"); NetEventSource.Info(null, $" inSecBuffers[] = length:{inSecBuffers.Length}"); } if (inSecBuffers == null) { NetEventSource.Fail(null, "inSecBuffers == null"); } var inSecurityBufferDescriptor = new Interop.SspiCli.SecBufferDesc(inSecBuffers.Length); int errorCode = (int)Interop.SECURITY_STATUS.InvalidHandle; // These are pinned user byte arrays passed along with SecurityBuffers. GCHandle[] pinnedInBytes = null; var inUnmanagedBuffer = new Interop.SspiCli.SecBuffer[inSecurityBufferDescriptor.cBuffers]; fixed (void* inUnmanagedBufferPtr = inUnmanagedBuffer) { // Fix Descriptor pointer that points to unmanaged SecurityBuffers. inSecurityBufferDescriptor.pBuffers = inUnmanagedBufferPtr; pinnedInBytes = new GCHandle[inSecurityBufferDescriptor.cBuffers]; SecurityBuffer securityBuffer; for (int index = 0; index < inSecurityBufferDescriptor.cBuffers; ++index) { securityBuffer = inSecBuffers[index]; if (securityBuffer != null) { inUnmanagedBuffer[index].cbBuffer = securityBuffer.size; inUnmanagedBuffer[index].BufferType = securityBuffer.type; // Use the unmanaged token if it's not null; otherwise use the managed buffer. if (securityBuffer.unmanagedToken != null) { inUnmanagedBuffer[index].pvBuffer = securityBuffer.unmanagedToken.DangerousGetHandle(); } else if (securityBuffer.token == null || securityBuffer.token.Length == 0) { inUnmanagedBuffer[index].pvBuffer = IntPtr.Zero; } else { pinnedInBytes[index] = GCHandle.Alloc(securityBuffer.token, GCHandleType.Pinned); inUnmanagedBuffer[index].pvBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(securityBuffer.token, securityBuffer.offset); } #if TRACE_VERBOSE if (NetEventSource.IsEnabled) NetEventSource.Info(null, $"SecBuffer: cbBuffer:{securityBuffer.size} BufferType:{securityBuffer.type}"); #endif } } // TODO: (#3114): Optimizations to remove the unnecesary allocation of a CredHandle, remove the AddRef // if refContext was previously null, refactor the code to unify CompleteAuthToken and ApplyControlToken. Interop.SspiCli.CredHandle contextHandle = new Interop.SspiCli.CredHandle(); if (refContext != null) { contextHandle = refContext._handle; } try { if (refContext == null || refContext.IsInvalid) { refContext = new SafeDeleteContext_SECURITY(); } try { bool ignore = false; refContext.DangerousAddRef(ref ignore); errorCode = Interop.SspiCli.ApplyControlToken(contextHandle.IsZero ? null : &contextHandle, ref inSecurityBufferDescriptor); } finally { refContext.DangerousRelease(); } } finally { if (pinnedInBytes != null) { for (int index = 0; index < pinnedInBytes.Length; index++) { if (pinnedInBytes[index].IsAllocated) { pinnedInBytes[index].Free(); } } } } } if (NetEventSource.IsEnabled) NetEventSource.Exit(null, $"unmanaged ApplyControlToken() errorCode:0x{errorCode:x8} refContext: {refContext}"); return errorCode; }
//------------------------------------------------------------------- internal unsafe static int AcceptSecurityContext( ref SafeFreeCredentials inCredentials, ref SafeDeleteContext refContext, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, SecurityBuffer inSecBuffer, SecurityBuffer[] inSecBuffers, SecurityBuffer outSecBuffer, ref Interop.SspiCli.ContextFlags outFlags) { #if TRACE_VERBOSE if (NetEventSource.IsEnabled) { NetEventSource.Enter(null, $"credential={inCredentials}, refContext={refContext}, inFlags={inFlags}"); if (inSecBuffers == null) { NetEventSource.Info(null, "inSecBuffers = (null)"); } else { NetEventSource.Info(null, $"inSecBuffers[] = (inSecBuffers)"); } } #endif if (outSecBuffer == null) { NetEventSource.Fail(null, "outSecBuffer != null"); } if (inSecBuffer != null && inSecBuffers != null) { NetEventSource.Fail(null, "inSecBuffer == null || inSecBuffers == null"); } if (inCredentials == null) { throw new ArgumentNullException(nameof(inCredentials)); } Interop.SspiCli.SecBufferDesc inSecurityBufferDescriptor = default(Interop.SspiCli.SecBufferDesc); bool haveInSecurityBufferDescriptor = false; if (inSecBuffer != null) { inSecurityBufferDescriptor = new Interop.SspiCli.SecBufferDesc(1); haveInSecurityBufferDescriptor = true; } else if (inSecBuffers != null) { inSecurityBufferDescriptor = new Interop.SspiCli.SecBufferDesc(inSecBuffers.Length); haveInSecurityBufferDescriptor = true; } Interop.SspiCli.SecBufferDesc outSecurityBufferDescriptor = new Interop.SspiCli.SecBufferDesc(1); // Actually, this is returned in outFlags. bool isSspiAllocated = (inFlags & Interop.SspiCli.ContextFlags.AllocateMemory) != 0 ? true : false; int errorCode = -1; Interop.SspiCli.CredHandle contextHandle = new Interop.SspiCli.CredHandle(); if (refContext != null) { contextHandle = refContext._handle; } // These are pinned user byte arrays passed along with SecurityBuffers. GCHandle[] pinnedInBytes = null; GCHandle pinnedOutBytes = new GCHandle(); // Optional output buffer that may need to be freed. SafeFreeContextBuffer outFreeContextBuffer = null; try { pinnedOutBytes = GCHandle.Alloc(outSecBuffer.token, GCHandleType.Pinned); var inUnmanagedBuffer = new Interop.SspiCli.SecBuffer[haveInSecurityBufferDescriptor ? inSecurityBufferDescriptor.cBuffers : 1]; fixed (void* inUnmanagedBufferPtr = inUnmanagedBuffer) { if (haveInSecurityBufferDescriptor) { // Fix Descriptor pointer that points to unmanaged SecurityBuffers. inSecurityBufferDescriptor.pBuffers = inUnmanagedBufferPtr; pinnedInBytes = new GCHandle[inSecurityBufferDescriptor.cBuffers]; SecurityBuffer securityBuffer; for (int index = 0; index < inSecurityBufferDescriptor.cBuffers; ++index) { securityBuffer = inSecBuffer != null ? inSecBuffer : inSecBuffers[index]; if (securityBuffer != null) { // Copy the SecurityBuffer content into unmanaged place holder. inUnmanagedBuffer[index].cbBuffer = securityBuffer.size; inUnmanagedBuffer[index].BufferType = securityBuffer.type; // Use the unmanaged token if it's not null; otherwise use the managed buffer. if (securityBuffer.unmanagedToken != null) { inUnmanagedBuffer[index].pvBuffer = securityBuffer.unmanagedToken.DangerousGetHandle(); } else if (securityBuffer.token == null || securityBuffer.token.Length == 0) { inUnmanagedBuffer[index].pvBuffer = IntPtr.Zero; } else { pinnedInBytes[index] = GCHandle.Alloc(securityBuffer.token, GCHandleType.Pinned); inUnmanagedBuffer[index].pvBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(securityBuffer.token, securityBuffer.offset); } #if TRACE_VERBOSE if (NetEventSource.IsEnabled) NetEventSource.Info(null, $"SecBuffer: cbBuffer:{securityBuffer.size} BufferType:{securityBuffer.type}"); #endif } } } var outUnmanagedBuffer = new Interop.SspiCli.SecBuffer[1]; fixed (void* outUnmanagedBufferPtr = outUnmanagedBuffer) { // Fix Descriptor pointer that points to unmanaged SecurityBuffers. outSecurityBufferDescriptor.pBuffers = outUnmanagedBufferPtr; // Copy the SecurityBuffer content into unmanaged place holder. outUnmanagedBuffer[0].cbBuffer = outSecBuffer.size; outUnmanagedBuffer[0].BufferType = outSecBuffer.type; if (outSecBuffer.token == null || outSecBuffer.token.Length == 0) { outUnmanagedBuffer[0].pvBuffer = IntPtr.Zero; } else { outUnmanagedBuffer[0].pvBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(outSecBuffer.token, outSecBuffer.offset); } if (isSspiAllocated) { outFreeContextBuffer = SafeFreeContextBuffer.CreateEmptyHandle(); } if (refContext == null || refContext.IsInvalid) { refContext = new SafeDeleteContext_SECURITY(); } errorCode = MustRunAcceptSecurityContext_SECURITY( ref inCredentials, contextHandle.IsZero ? null : &contextHandle, haveInSecurityBufferDescriptor ? &inSecurityBufferDescriptor : null, inFlags, endianness, refContext, ref outSecurityBufferDescriptor, ref outFlags, outFreeContextBuffer); if (NetEventSource.IsEnabled) NetEventSource.Info(null, "Marshaling OUT buffer"); // Get unmanaged buffer with index 0 as the only one passed into PInvoke. outSecBuffer.size = outUnmanagedBuffer[0].cbBuffer; outSecBuffer.type = outUnmanagedBuffer[0].BufferType; if (outSecBuffer.size > 0) { outSecBuffer.token = new byte[outSecBuffer.size]; Marshal.Copy(outUnmanagedBuffer[0].pvBuffer, outSecBuffer.token, 0, outSecBuffer.size); } else { outSecBuffer.token = null; } } } } finally { if (pinnedInBytes != null) { for (int index = 0; index < pinnedInBytes.Length; index++) { if (pinnedInBytes[index].IsAllocated) { pinnedInBytes[index].Free(); } } } if (pinnedOutBytes.IsAllocated) { pinnedOutBytes.Free(); } if (outFreeContextBuffer != null) { outFreeContextBuffer.Dispose(); } } if (NetEventSource.IsEnabled) NetEventSource.Exit(null, $"errorCode:0x{errorCode:x8}, refContext:{refContext}"); return errorCode; }
private static int DecryptNtlm( SafeDeleteContext securityContext, byte[] buffer, int offset, int count, bool isConfidential, out int newOffset, uint sequenceNumber) { const int ntlmSignatureLength = 16; // For the most part the arguments are verified in Decrypt(). if (count < ntlmSignatureLength) { NetEventSource.Fail(null, "Argument 'count' out of range."); throw new ArgumentOutOfRangeException(nameof(count)); } var securityBuffer = new SecurityBuffer[2]; securityBuffer[0] = new SecurityBuffer(buffer, offset, ntlmSignatureLength, SecurityBufferType.SECBUFFER_TOKEN); securityBuffer[1] = new SecurityBuffer(buffer, offset + ntlmSignatureLength, count - ntlmSignatureLength, SecurityBufferType.SECBUFFER_DATA); int errorCode; SecurityBufferType realDataType = SecurityBufferType.SECBUFFER_DATA; if (isConfidential) { errorCode = SSPIWrapper.DecryptMessage(GlobalSSPI.SSPIAuth, securityContext, securityBuffer, sequenceNumber); } else { realDataType |= SecurityBufferType.SECBUFFER_READONLY; securityBuffer[1].type = realDataType; errorCode = SSPIWrapper.VerifySignature(GlobalSSPI.SSPIAuth, securityContext, securityBuffer, sequenceNumber); } if (errorCode != 0) { Exception e = new Win32Exception(errorCode); if (NetEventSource.IsEnabled) NetEventSource.Error(null, e); throw new Win32Exception(errorCode); } if (securityBuffer[1].type != realDataType) { throw new InternalException(); } newOffset = securityBuffer[1].offset; return securityBuffer[1].size; }
public static unsafe 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. int bufferSizeNeeded; try { bufferSizeNeeded = checked (size + headerSize + trailerSize); } catch { 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; } if (output == null || output.Length < bufferSizeNeeded) { output = new byte[bufferSizeNeeded]; } // Copy the input into the output buffer to prepare for SCHANNEL's expectations Buffer.BlockCopy(input, offset, output, headerSize, size); const int NumSecBuffers = 4; // header + data + trailer + empty var unmanagedBuffer = stackalloc Interop.SspiCli.SecBuffer[NumSecBuffers]; var sdcInOut = new Interop.SspiCli.SecBufferDesc(NumSecBuffers); sdcInOut.pBuffers = unmanagedBuffer; fixed(byte *outputPtr = output) { Interop.SspiCli.SecBuffer *headerSecBuffer = &unmanagedBuffer[0]; headerSecBuffer->BufferType = SecurityBufferType.SECBUFFER_STREAM_HEADER; headerSecBuffer->pvBuffer = (IntPtr)outputPtr; headerSecBuffer->cbBuffer = headerSize; Interop.SspiCli.SecBuffer *dataSecBuffer = &unmanagedBuffer[1]; dataSecBuffer->BufferType = SecurityBufferType.SECBUFFER_DATA; dataSecBuffer->pvBuffer = (IntPtr)(outputPtr + headerSize); dataSecBuffer->cbBuffer = size; Interop.SspiCli.SecBuffer *trailerSecBuffer = &unmanagedBuffer[2]; trailerSecBuffer->BufferType = SecurityBufferType.SECBUFFER_STREAM_TRAILER; trailerSecBuffer->pvBuffer = (IntPtr)(outputPtr + headerSize + size); trailerSecBuffer->cbBuffer = trailerSize; Interop.SspiCli.SecBuffer *emptySecBuffer = &unmanagedBuffer[3]; emptySecBuffer->BufferType = SecurityBufferType.SECBUFFER_EMPTY; emptySecBuffer->cbBuffer = 0; emptySecBuffer->pvBuffer = IntPtr.Zero; int errorCode = GlobalSSPI.SSPISecureChannel.EncryptMessage(securityContext, sdcInOut, 0); if (errorCode != 0) { if (GlobalLog.IsEnabled) { GlobalLog.Print("SslStreamPal.Windows: SecureChannel#" + LoggingHash.HashString(securityContext) + "::Encrypt ERROR" + errorCode.ToString("x")); } resultSize = 0; return(SecurityStatusAdapterPal.GetSecurityStatusPalFromNativeInt(errorCode)); } Debug.Assert(headerSecBuffer->cbBuffer >= 0 && dataSecBuffer->cbBuffer >= 0 && trailerSecBuffer->cbBuffer >= 0); Debug.Assert(checked (headerSecBuffer->cbBuffer + dataSecBuffer->cbBuffer + trailerSecBuffer->cbBuffer) <= output.Length); resultSize = checked (headerSecBuffer->cbBuffer + dataSecBuffer->cbBuffer + trailerSecBuffer->cbBuffer); return(new SecurityStatusPal(SecurityStatusPalErrorCode.OK)); } }
internal static SecurityStatusPal AcceptSecurityContext( SafeFreeCredentials credentialsHandle, ref SafeDeleteContext securityContext, ContextFlagsPal requestedContextFlags, SecurityBuffer[] inSecurityBufferArray, SecurityBuffer outSecurityBuffer, ref ContextFlagsPal contextFlags) { Interop.SspiCli.ContextFlags outContextFlags = Interop.SspiCli.ContextFlags.Zero; Interop.SecurityStatus winStatus = (Interop.SecurityStatus)SSPIWrapper.AcceptSecurityContext( GlobalSSPI.SSPIAuth, credentialsHandle, ref securityContext, ContextFlagsAdapterPal.GetInteropFromContextFlagsPal(requestedContextFlags), Interop.SspiCli.Endianness.Network, inSecurityBufferArray, outSecurityBuffer, ref outContextFlags); contextFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop(outContextFlags); return SecurityStatusAdapterPal.GetSecurityStatusPalFromInterop(winStatus); }
internal static int Decrypt( SafeDeleteContext securityContext, byte[] buffer, int offset, int count, bool isConfidential, bool isNtlm, out int newOffset, uint sequenceNumber) { if (offset < 0 || offset > (buffer == null ? 0 : buffer.Length)) { NetEventSource.Fail(null, "Argument 'offset' out of range."); throw new ArgumentOutOfRangeException(nameof(offset)); } if (count < 0 || count > (buffer == null ? 0 : buffer.Length - offset)) { NetEventSource.Fail(null, "Argument 'count' out of range."); throw new ArgumentOutOfRangeException(nameof(count)); } if (isNtlm) { return(DecryptNtlm(securityContext, buffer, offset, count, isConfidential, out newOffset, sequenceNumber)); } // // Kerberos and up // TwoSecurityBuffers buffers = default; var securityBuffer = MemoryMarshal.CreateSpan(ref buffers._item0, 2); securityBuffer[0] = new SecurityBuffer(buffer, offset, count, SecurityBufferType.SECBUFFER_STREAM); securityBuffer[1] = new SecurityBuffer(0, SecurityBufferType.SECBUFFER_DATA); int errorCode; if (isConfidential) { errorCode = SSPIWrapper.DecryptMessage(GlobalSSPI.SSPIAuth, securityContext, securityBuffer, sequenceNumber); } else { errorCode = SSPIWrapper.VerifySignature(GlobalSSPI.SSPIAuth, securityContext, securityBuffer, sequenceNumber); } if (errorCode != 0) { Exception e = new Win32Exception(errorCode); if (NetEventSource.IsEnabled) { NetEventSource.Error(null, e); } throw e; } if (securityBuffer[1].type != SecurityBufferType.SECBUFFER_DATA) { throw new InternalException(securityBuffer[1].type); } newOffset = securityBuffer[1].offset; return(securityBuffer[1].size); }
public static int SetContextAttributes( SafeDeleteContext phContext, Interop.Secur32.ContextAttribute contextAttribute, byte[] buffer) { return(SetContextAttributes_SECURITY(phContext, contextAttribute, buffer)); }
// // After PInvoke call the method will fix the handleTemplate.handle with the returned value. // The caller is responsible for creating a correct SafeFreeContextBuffer_XXX flavor or null can be passed if no handle is returned. // private static unsafe int MustRunInitializeSecurityContext_SECURITY( ref SafeFreeCredentials inCredentials, void* inContextPtr, byte* targetName, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, Interop.SspiCli.SecBufferDesc* inputBuffer, SafeDeleteContext outContext, ref Interop.SspiCli.SecBufferDesc outputBuffer, ref Interop.SspiCli.ContextFlags attributes, SafeFreeContextBuffer handleTemplate) { int errorCode = (int)Interop.SECURITY_STATUS.InvalidHandle; try { bool ignore = false; inCredentials.DangerousAddRef(ref ignore); outContext.DangerousAddRef(ref ignore); Interop.SspiCli.CredHandle credentialHandle = inCredentials._handle; long timeStamp; errorCode = Interop.SspiCli.InitializeSecurityContextW( ref credentialHandle, inContextPtr, targetName, inFlags, 0, endianness, inputBuffer, 0, ref outContext._handle, ref outputBuffer, ref attributes, out timeStamp); } finally { // // When a credential handle is first associated with the context we keep credential // ref count bumped up to ensure ordered finalization. // If the credential handle has been changed we de-ref the old one and associate the // context with the new cred handle but only if the call was successful. if (outContext._EffectiveCredential != inCredentials && (errorCode & 0x80000000) == 0) { // Disassociate the previous credential handle if (outContext._EffectiveCredential != null) { outContext._EffectiveCredential.DangerousRelease(); } outContext._EffectiveCredential = inCredentials; } else { inCredentials.DangerousRelease(); } outContext.DangerousRelease(); } // The idea is that SSPI has allocated a block and filled up outUnmanagedBuffer+8 slot with the pointer. if (handleTemplate != null) { //ATTN: on 64 BIT that is still +8 cause of 2* c++ unsigned long == 8 bytes handleTemplate.Set(((Interop.SspiCli.SecBuffer*)outputBuffer.pBuffers)->pvBuffer); if (handleTemplate.IsInvalid) { handleTemplate.SetHandleAsInvalid(); } } if (inContextPtr == null && (errorCode & 0x80000000) != 0) { // an error on the first call, need to set the out handle to invalid value outContext._handle.SetToInvalid(); } return errorCode; }
internal static int Encrypt( SafeDeleteContext securityContext, byte[] buffer, int offset, int count, bool isConfidential, bool isNtlm, ref byte[] output, uint sequenceNumber) { SecPkgContext_Sizes sizes = default; bool success = SSPIWrapper.QueryBlittableContextAttributes(GlobalSSPI.SSPIAuth, securityContext, Interop.SspiCli.ContextAttribute.SECPKG_ATTR_SIZES, ref sizes); Debug.Assert(success); try { int maxCount = checked (int.MaxValue - 4 - sizes.cbBlockSize - sizes.cbSecurityTrailer); if (count > maxCount || count < 0) { throw new ArgumentOutOfRangeException(nameof(count), SR.Format(SR.net_io_out_range, maxCount)); } } catch (Exception e) when(!ExceptionCheck.IsFatal(e)) { NetEventSource.Fail(null, "Arguments out of range."); throw; } int resultSize = count + sizes.cbSecurityTrailer + sizes.cbBlockSize; 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.cbSecurityTrailer, count); // Prepare buffers TOKEN(signature), DATA and Padding. ThreeSecurityBuffers buffers = default; var securityBuffer = MemoryMarshal.CreateSpan(ref buffers._item0, 3); securityBuffer[0] = new SecurityBuffer(output, 4, sizes.cbSecurityTrailer, SecurityBufferType.SECBUFFER_TOKEN); securityBuffer[1] = new SecurityBuffer(output, 4 + sizes.cbSecurityTrailer, count, SecurityBufferType.SECBUFFER_DATA); securityBuffer[2] = new SecurityBuffer(output, 4 + sizes.cbSecurityTrailer + count, sizes.cbBlockSize, SecurityBufferType.SECBUFFER_PADDING); int errorCode; if (isConfidential) { errorCode = SSPIWrapper.EncryptMessage(GlobalSSPI.SSPIAuth, securityContext, securityBuffer, sequenceNumber); } else { if (isNtlm) { securityBuffer[1].type |= SecurityBufferType.SECBUFFER_READONLY; } errorCode = SSPIWrapper.MakeSignature(GlobalSSPI.SSPIAuth, securityContext, securityBuffer, 0); } if (errorCode != 0) { Exception e = new Win32Exception(errorCode); if (NetEventSource.IsEnabled) { NetEventSource.Error(null, e); } throw e; } // Compacting the result. resultSize = securityBuffer[0].size; bool forceCopy = false; if (resultSize != sizes.cbSecurityTrailer) { 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.cbSecurityTrailer))) { 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); }
internal static int Decrypt( SafeDeleteContext securityContext, byte[] buffer, int offset, int count, bool isConfidential, bool isNtlm, out int newOffset, uint sequenceNumber) { if (offset < 0 || offset > (buffer == null ? 0 : buffer.Length)) { NetEventSource.Fail(null, "Argument 'offset' out of range."); throw new ArgumentOutOfRangeException(nameof(offset)); } if (count < 0 || count > (buffer == null ? 0 : buffer.Length - offset)) { NetEventSource.Fail(null, "Argument 'count' out of range."); throw new ArgumentOutOfRangeException(nameof(count)); } if (isNtlm) { return DecryptNtlm(securityContext, buffer, offset, count, isConfidential, out newOffset, sequenceNumber); } // // Kerberos and up // var securityBuffer = new SecurityBuffer[2]; securityBuffer[0] = new SecurityBuffer(buffer, offset, count, SecurityBufferType.SECBUFFER_STREAM); securityBuffer[1] = new SecurityBuffer(0, SecurityBufferType.SECBUFFER_DATA); int errorCode; if (isConfidential) { errorCode = SSPIWrapper.DecryptMessage(GlobalSSPI.SSPIAuth, securityContext, securityBuffer, sequenceNumber); } else { errorCode = SSPIWrapper.VerifySignature(GlobalSSPI.SSPIAuth, securityContext, securityBuffer, sequenceNumber); } if (errorCode != 0) { Exception e = new Win32Exception(errorCode); if (NetEventSource.IsEnabled) NetEventSource.Error(null, e); throw e; } if (securityBuffer[1].type != SecurityBufferType.SECBUFFER_DATA) { throw new InternalException(); } newOffset = securityBuffer[1].offset; return securityBuffer[1].size; }
internal static int Encrypt( SafeDeleteContext securityContext, byte[] buffer, int offset, int count, bool isConfidential, bool isNtlm, ref byte[] output, uint sequenceNumber) { SecPkgContext_Sizes sizes = SSPIWrapper.QueryContextAttributes( GlobalSSPI.SSPIAuth, securityContext, Interop.SspiCli.ContextAttribute.SECPKG_ATTR_SIZES ) as SecPkgContext_Sizes; try { int maxCount = checked (Int32.MaxValue - 4 - sizes.cbBlockSize - sizes.cbSecurityTrailer); if (count > maxCount || count < 0) { throw new ArgumentOutOfRangeException(nameof(count), SR.Format(SR.net_io_out_range, maxCount)); } } catch (Exception e) { if (!ExceptionCheck.IsFatal(e)) { if (GlobalLog.IsEnabled) { GlobalLog.Assert("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::Encrypt", "Arguments out of range."); } Debug.Fail("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::Encrypt", "Arguments out of range."); } throw; } int resultSize = count + sizes.cbSecurityTrailer + sizes.cbBlockSize; 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.cbSecurityTrailer, count); // Prepare buffers TOKEN(signature), DATA and Padding. var securityBuffer = new SecurityBuffer[3]; securityBuffer[0] = new SecurityBuffer(output, 4, sizes.cbSecurityTrailer, SecurityBufferType.SECBUFFER_TOKEN); securityBuffer[1] = new SecurityBuffer(output, 4 + sizes.cbSecurityTrailer, count, SecurityBufferType.SECBUFFER_DATA); securityBuffer[2] = new SecurityBuffer(output, 4 + sizes.cbSecurityTrailer + count, sizes.cbBlockSize, SecurityBufferType.SECBUFFER_PADDING); int errorCode; if (isConfidential) { errorCode = SSPIWrapper.EncryptMessage(GlobalSSPI.SSPIAuth, securityContext, securityBuffer, sequenceNumber); } else { if (isNtlm) { securityBuffer[1].type |= SecurityBufferType.SECBUFFER_READONLY; } errorCode = SSPIWrapper.MakeSignature(GlobalSSPI.SSPIAuth, securityContext, securityBuffer, 0); } if (errorCode != 0) { if (GlobalLog.IsEnabled) { GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::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.cbSecurityTrailer) { 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.cbSecurityTrailer))) { 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); }
internal static int Encrypt( SafeDeleteContext securityContext, byte[] buffer, int offset, int count, bool isConfidential, bool isNtlm, ref byte[] output, uint sequenceNumber) { SecPkgContext_Sizes sizes = SSPIWrapper.QueryContextAttributes( GlobalSSPI.SSPIAuth, securityContext, Interop.SspiCli.ContextAttribute.SECPKG_ATTR_SIZES ) as SecPkgContext_Sizes; try { int maxCount = checked(Int32.MaxValue - 4 - sizes.cbBlockSize - sizes.cbSecurityTrailer); if (count > maxCount || count < 0) { throw new ArgumentOutOfRangeException(nameof(count), SR.Format(SR.net_io_out_range, maxCount)); } } catch (Exception e) when (!ExceptionCheck.IsFatal(e)) { NetEventSource.Fail(null, "Arguments out of range."); throw; } int resultSize = count + sizes.cbSecurityTrailer + sizes.cbBlockSize; 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.cbSecurityTrailer, count); // Prepare buffers TOKEN(signature), DATA and Padding. var securityBuffer = new SecurityBuffer[3]; securityBuffer[0] = new SecurityBuffer(output, 4, sizes.cbSecurityTrailer, SecurityBufferType.SECBUFFER_TOKEN); securityBuffer[1] = new SecurityBuffer(output, 4 + sizes.cbSecurityTrailer, count, SecurityBufferType.SECBUFFER_DATA); securityBuffer[2] = new SecurityBuffer(output, 4 + sizes.cbSecurityTrailer + count, sizes.cbBlockSize, SecurityBufferType.SECBUFFER_PADDING); int errorCode; if (isConfidential) { errorCode = SSPIWrapper.EncryptMessage(GlobalSSPI.SSPIAuth, securityContext, securityBuffer, sequenceNumber); } else { if (isNtlm) { securityBuffer[1].type |= SecurityBufferType.SECBUFFER_READONLY; } errorCode = SSPIWrapper.MakeSignature(GlobalSSPI.SSPIAuth, securityContext, securityBuffer, 0); } if (errorCode != 0) { Exception e = new Win32Exception(errorCode); if (NetEventSource.IsEnabled) NetEventSource.Error(null, e); throw e; } // Compacting the result. resultSize = securityBuffer[0].size; bool forceCopy = false; if (resultSize != sizes.cbSecurityTrailer) { 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.cbSecurityTrailer))) { 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; }
internal static int Decrypt( SafeDeleteContext securityContext, byte[] buffer, int offset, int count, bool isConfidential, bool isNtlm, out int newOffset, uint sequenceNumber) { if (offset < 0 || offset > (buffer == null ? 0 : buffer.Length)) { if (GlobalLog.IsEnabled) { GlobalLog.Assert("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::Decrypt", "Argument 'offset' out of range."); } Debug.Fail("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::Decrypt", "Argument 'offset' out of range."); throw new ArgumentOutOfRangeException(nameof(offset)); } if (count < 0 || count > (buffer == null ? 0 : buffer.Length - offset)) { if (GlobalLog.IsEnabled) { GlobalLog.Assert("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::Decrypt", "Argument 'count' out of range."); } Debug.Fail("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::Decrypt", "Argument 'count' out of range."); throw new ArgumentOutOfRangeException(nameof(count)); } if (isNtlm) { return(DecryptNtlm(securityContext, buffer, offset, count, isConfidential, out newOffset, sequenceNumber)); } // // Kerberos and up // var securityBuffer = new SecurityBuffer[2]; securityBuffer[0] = new SecurityBuffer(buffer, offset, count, SecurityBufferType.SECBUFFER_STREAM); securityBuffer[1] = new SecurityBuffer(0, SecurityBufferType.SECBUFFER_DATA); int errorCode; if (isConfidential) { errorCode = SSPIWrapper.DecryptMessage(GlobalSSPI.SSPIAuth, securityContext, securityBuffer, sequenceNumber); } else { errorCode = SSPIWrapper.VerifySignature(GlobalSSPI.SSPIAuth, securityContext, securityBuffer, sequenceNumber); } if (errorCode != 0) { if (GlobalLog.IsEnabled) { GlobalLog.Print("NTAuthentication#" + "::Decrypt() throw Error = " + errorCode.ToString("x", NumberFormatInfo.InvariantInfo)); } throw new Win32Exception(errorCode); } if (securityBuffer[1].type != SecurityBufferType.SECBUFFER_DATA) { throw new InternalException(); } newOffset = securityBuffer[1].offset; return(securityBuffer[1].size); }
internal static int Encrypt( SafeDeleteContext securityContext, byte[] buffer, int offset, int count, bool isConfidential, bool isNtlm, ref byte[] output, uint sequenceNumber) { SecSizes sizes = SSPIWrapper.QueryContextAttributes( GlobalSSPI.SSPIAuth, securityContext, Interop.SspiCli.ContextAttribute.Sizes ) as SecSizes; try { int maxCount = checked(Int32.MaxValue - 4 - sizes.BlockSize - sizes.SecurityTrailer); if (count > maxCount || count < 0) { throw new ArgumentOutOfRangeException(nameof(count), SR.Format(SR.net_io_out_range, maxCount)); } } catch (Exception e) { if (!ExceptionCheck.IsFatal(e)) { if (GlobalLog.IsEnabled) { GlobalLog.Assert("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::Encrypt", "Arguments out of range."); } Debug.Fail("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::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 (isConfidential) { 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(securityContext) + "::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; }
internal static string QueryContextAssociatedName(SafeDeleteContext securityContext) { return(SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPIAuth, securityContext, Interop.SspiCli.ContextAttribute.SECPKG_ATTR_NAMES) as string); }
private static int DecryptNtlm( SafeDeleteContext securityContext, byte[] buffer, int offset, int count, bool isConfidential, out int newOffset, uint sequenceNumber) { const int ntlmSignatureLength = 16; // For the most part the arguments are verified in Decrypt(). if (count < ntlmSignatureLength) { if (GlobalLog.IsEnabled) { GlobalLog.Assert("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::DecryptNtlm", "Argument 'count' out of range."); } Debug.Fail("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::DecryptNtlm", "Argument 'count' out of range."); throw new ArgumentOutOfRangeException(nameof(count)); } var securityBuffer = new SecurityBuffer[2]; securityBuffer[0] = new SecurityBuffer(buffer, offset, ntlmSignatureLength, SecurityBufferType.Token); securityBuffer[1] = new SecurityBuffer(buffer, offset + ntlmSignatureLength, count - ntlmSignatureLength, SecurityBufferType.Data); int errorCode; SecurityBufferType realDataType = SecurityBufferType.Data; if (isConfidential) { errorCode = SSPIWrapper.DecryptMessage(GlobalSSPI.SSPIAuth, securityContext, securityBuffer, sequenceNumber); } else { realDataType |= SecurityBufferType.ReadOnlyFlag; securityBuffer[1].type = realDataType; errorCode = SSPIWrapper.VerifySignature(GlobalSSPI.SSPIAuth, securityContext, securityBuffer, sequenceNumber); } if (errorCode != 0) { if (GlobalLog.IsEnabled) { GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::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; }
internal static string QueryContextAuthenticationPackage(SafeDeleteContext securityContext) { var negotiationInfoClass = SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPIAuth, securityContext, Interop.SspiCli.ContextAttribute.SECPKG_ATTR_NEGOTIATION_INFO) as NegotiationInfoClass; return(negotiationInfoClass?.AuthenticationPackage); }
internal static string QueryContextAuthenticationPackage(SafeDeleteContext securityContext) { var negotiationInfoClass = SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPIAuth, securityContext, Interop.SspiCli.ContextAttribute.NegotiationInfo) as NegotiationInfoClass; return negotiationInfoClass?.AuthenticationPackage; }
internal static string QueryContextClientSpecifiedSpn(SafeDeleteContext securityContext) { return(SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPIAuth, securityContext, Interop.SspiCli.ContextAttribute.SECPKG_ATTR_CLIENT_SPECIFIED_TARGET) as string); }
internal unsafe static int CompleteAuthToken( ref SafeDeleteContext refContext, SecurityBuffer[] inSecBuffers) { GlobalLog.Enter("SafeDeleteContext::CompleteAuthToken"); GlobalLog.Print(" refContext = " + Logging.ObjectToString(refContext)); #if TRACE_VERBOSE GlobalLog.Print(" inSecBuffers[] = length:" + inSecBuffers.Length); #endif GlobalLog.Assert(inSecBuffers != null, "SafeDeleteContext::CompleteAuthToken()|inSecBuffers == null"); var inSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(inSecBuffers.Length); int errorCode = (int)Interop.SecurityStatus.InvalidHandle; // These are pinned user byte arrays passed along with SecurityBuffers. GCHandle[] pinnedInBytes = null; var inUnmanagedBuffer = new Interop.Secur32.SecurityBufferStruct[inSecurityBufferDescriptor.Count]; fixed (void* inUnmanagedBufferPtr = inUnmanagedBuffer) { // Fix Descriptor pointer that points to unmanaged SecurityBuffers. inSecurityBufferDescriptor.UnmanagedPointer = inUnmanagedBufferPtr; pinnedInBytes = new GCHandle[inSecurityBufferDescriptor.Count]; SecurityBuffer securityBuffer; for (int index = 0; index < inSecurityBufferDescriptor.Count; ++index) { securityBuffer = inSecBuffers[index]; if (securityBuffer != null) { inUnmanagedBuffer[index].count = securityBuffer.size; inUnmanagedBuffer[index].type = securityBuffer.type; // Use the unmanaged token if it's not null; otherwise use the managed buffer. if (securityBuffer.unmanagedToken != null) { inUnmanagedBuffer[index].token = securityBuffer.unmanagedToken.DangerousGetHandle(); } else if (securityBuffer.token == null || securityBuffer.token.Length == 0) { inUnmanagedBuffer[index].token = IntPtr.Zero; } else { pinnedInBytes[index] = GCHandle.Alloc(securityBuffer.token, GCHandleType.Pinned); inUnmanagedBuffer[index].token = Marshal.UnsafeAddrOfPinnedArrayElement(securityBuffer.token, securityBuffer.offset); } #if TRACE_VERBOSE GlobalLog.Print("SecBuffer: cbBuffer:" + securityBuffer.size + " BufferType:" + securityBuffer.type); #endif } } Interop.Secur32.SSPIHandle contextHandle = new Interop.Secur32.SSPIHandle(); if (refContext != null) { contextHandle = refContext._handle; } try { if (refContext == null || refContext.IsInvalid) { refContext = new SafeDeleteContext_SECURITY(); } try { bool ignore = false; refContext.DangerousAddRef(ref ignore); errorCode = Interop.Secur32.CompleteAuthToken(contextHandle.IsZero ? null : &contextHandle, inSecurityBufferDescriptor); } finally { refContext.DangerousRelease(); } } finally { if (pinnedInBytes != null) { for (int index = 0; index < pinnedInBytes.Length; index++) { if (pinnedInBytes[index].IsAllocated) { pinnedInBytes[index].Free(); } } } } } GlobalLog.Leave("SafeDeleteContext::CompleteAuthToken() unmanaged CompleteAuthToken()", "errorCode:0x" + errorCode.ToString("x8") + " refContext:" + Logging.ObjectToString(refContext)); return errorCode; }
private static SecurityStatusPal EstablishSecurityContext( SafeFreeNegoCredentials credential, ref SafeDeleteContext context, string targetName, ContextFlagsPal inFlags, SecurityBuffer inputBuffer, SecurityBuffer outputBuffer, ref ContextFlagsPal outFlags) { bool isNtlmOnly = credential.IsNtlmOnly; if (context == null) { // Empty target name causes the failure on Linux, hence passing a non-empty string context = isNtlmOnly ? new SafeDeleteNegoContext(credential, credential.UserName) : new SafeDeleteNegoContext(credential, targetName); } SafeDeleteNegoContext negoContext = (SafeDeleteNegoContext)context; try { Interop.NetSecurityNative.GssFlags inputFlags = ContextFlagsAdapterPal.GetInteropFromContextFlagsPal(inFlags, isServer: false); uint outputFlags; int isNtlmUsed; SafeGssContextHandle contextHandle = negoContext.GssContext; bool done = GssInitSecurityContext( ref contextHandle, credential.GssCredential, isNtlmOnly, negoContext.TargetName, inputFlags, inputBuffer?.token, out outputBuffer.token, out outputFlags, out isNtlmUsed); Debug.Assert(outputBuffer.token != null, "Unexpected null buffer returned by GssApi"); outputBuffer.size = outputBuffer.token.Length; outputBuffer.offset = 0; outFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop((Interop.NetSecurityNative.GssFlags)outputFlags, isServer: false); Debug.Assert(negoContext.GssContext == null || contextHandle == negoContext.GssContext); // Save the inner context handle for further calls to NetSecurity Debug.Assert(negoContext.GssContext == null || contextHandle == negoContext.GssContext); if (null == negoContext.GssContext) { negoContext.SetGssContext(contextHandle); } // Populate protocol used for authentication if (done) { negoContext.SetAuthenticationPackage(Convert.ToBoolean(isNtlmUsed)); } SecurityStatusPalErrorCode errorCode = done ? (negoContext.IsNtlmUsed && outputBuffer.size > 0 ? SecurityStatusPalErrorCode.OK : SecurityStatusPalErrorCode.CompleteNeeded) : SecurityStatusPalErrorCode.ContinueNeeded; return(new SecurityStatusPal(errorCode)); } catch (Exception ex) { if (NetEventSource.IsEnabled) { NetEventSource.Error(null, ex); } return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, ex)); } }
private unsafe static int QueryContextChannelBinding_SECURITY(SafeDeleteContext phContext, Interop.Secur32.ContextAttribute contextAttribute, Bindings* buffer, SafeFreeContextBufferChannelBinding refHandle) { int status = (int)Interop.SecurityStatus.InvalidHandle; // SCHANNEL only supports SECPKG_ATTR_ENDPOINT_BINDINGS and SECPKG_ATTR_UNIQUE_BINDINGS which // map to our enum ChannelBindingKind.Endpoint and ChannelBindingKind.Unique. if (contextAttribute != Interop.Secur32.ContextAttribute.EndpointBindings && contextAttribute != Interop.Secur32.ContextAttribute.UniqueBindings) { return status; } try { bool ignore = false; phContext.DangerousAddRef(ref ignore); status = Interop.Secur32.QueryContextAttributesW(ref phContext._handle, contextAttribute, buffer); } finally { phContext.DangerousRelease(); } if (status == 0 && refHandle != null) { refHandle.Set((*buffer).pBindings); refHandle._size = (*buffer).BindingsLength; } if (status != 0 && refHandle != null) { refHandle.SetHandleAsInvalid(); } return status; }
internal static string QueryContextClientSpecifiedSpn(SafeDeleteContext securityContext) { throw new PlatformNotSupportedException(SR.net_nego_server_not_supported); }
private static int SetContextAttributes_SECURITY( SafeDeleteContext phContext, Interop.Secur32.ContextAttribute contextAttribute, byte[] buffer) { try { bool ignore = false; phContext.DangerousAddRef(ref ignore); return Interop.Secur32.SetContextAttributesW(ref phContext._handle, contextAttribute, buffer, buffer.Length); } finally { phContext.DangerousRelease(); } }
internal static SecurityStatusPal CompleteAuthToken( ref SafeDeleteContext securityContext, SecurityBuffer[] inSecurityBufferArray) { return(new SecurityStatusPal(SecurityStatusPalErrorCode.OK)); }
//------------------------------------------------------------------- internal unsafe static int AcceptSecurityContext( ref SafeFreeCredentials inCredentials, ref SafeDeleteContext refContext, Interop.Secur32.ContextFlags inFlags, Interop.Secur32.Endianness endianness, SecurityBuffer inSecBuffer, SecurityBuffer[] inSecBuffers, SecurityBuffer outSecBuffer, ref Interop.Secur32.ContextFlags outFlags) { #if TRACE_VERBOSE GlobalLog.Enter("SafeDeleteContext::AcceptSecurityContex"); GlobalLog.Print(" credential = " + inCredentials.ToString()); GlobalLog.Print(" refContext = " + Logging.ObjectToString(refContext)); GlobalLog.Print(" inFlags = " + inFlags); if (inSecBuffers == null) { GlobalLog.Print(" inSecBuffers = (null)"); } else { GlobalLog.Print(" inSecBuffers[] = length:" + inSecBuffers.Length); } #endif GlobalLog.Assert(outSecBuffer != null, "SafeDeleteContext::AcceptSecurityContext()|outSecBuffer != null"); GlobalLog.Assert(inSecBuffer == null || inSecBuffers == null, "SafeDeleteContext::AcceptSecurityContext()|inSecBuffer == null || inSecBuffers == null"); if (inCredentials == null) { throw new ArgumentNullException("inCredentials"); } Interop.Secur32.SecurityBufferDescriptor inSecurityBufferDescriptor = null; if (inSecBuffer != null) { inSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(1); } else if (inSecBuffers != null) { inSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(inSecBuffers.Length); } Interop.Secur32.SecurityBufferDescriptor outSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(1); // Actually, this is returned in outFlags. bool isSspiAllocated = (inFlags & Interop.Secur32.ContextFlags.AllocateMemory) != 0 ? true : false; int errorCode = -1; Interop.Secur32.SSPIHandle contextHandle = new Interop.Secur32.SSPIHandle(); if (refContext != null) { contextHandle = refContext._handle; } // These are pinned user byte arrays passed along with SecurityBuffers. GCHandle[] pinnedInBytes = null; GCHandle pinnedOutBytes = new GCHandle(); // Optional output buffer that may need to be freed. SafeFreeContextBuffer outFreeContextBuffer = null; try { pinnedOutBytes = GCHandle.Alloc(outSecBuffer.token, GCHandleType.Pinned); var inUnmanagedBuffer = new Interop.Secur32.SecurityBufferStruct[inSecurityBufferDescriptor == null ? 1 : inSecurityBufferDescriptor.Count]; fixed (void* inUnmanagedBufferPtr = inUnmanagedBuffer) { if (inSecurityBufferDescriptor != null) { // Fix Descriptor pointer that points to unmanaged SecurityBuffers. inSecurityBufferDescriptor.UnmanagedPointer = inUnmanagedBufferPtr; pinnedInBytes = new GCHandle[inSecurityBufferDescriptor.Count]; SecurityBuffer securityBuffer; for (int index = 0; index < inSecurityBufferDescriptor.Count; ++index) { securityBuffer = inSecBuffer != null ? inSecBuffer : inSecBuffers[index]; if (securityBuffer != null) { // Copy the SecurityBuffer content into unmanaged place holder. inUnmanagedBuffer[index].count = securityBuffer.size; inUnmanagedBuffer[index].type = securityBuffer.type; // Use the unmanaged token if it's not null; otherwise use the managed buffer. if (securityBuffer.unmanagedToken != null) { inUnmanagedBuffer[index].token = securityBuffer.unmanagedToken.DangerousGetHandle(); } else if (securityBuffer.token == null || securityBuffer.token.Length == 0) { inUnmanagedBuffer[index].token = IntPtr.Zero; } else { pinnedInBytes[index] = GCHandle.Alloc(securityBuffer.token, GCHandleType.Pinned); inUnmanagedBuffer[index].token = Marshal.UnsafeAddrOfPinnedArrayElement(securityBuffer.token, securityBuffer.offset); } #if TRACE_VERBOSE GlobalLog.Print("SecBuffer: cbBuffer:" + securityBuffer.size + " BufferType:" + securityBuffer.type); #endif } } } var outUnmanagedBuffer = new Interop.Secur32.SecurityBufferStruct[1]; fixed (void* outUnmanagedBufferPtr = outUnmanagedBuffer) { // Fix Descriptor pointer that points to unmanaged SecurityBuffers. outSecurityBufferDescriptor.UnmanagedPointer = outUnmanagedBufferPtr; // Copy the SecurityBuffer content into unmanaged place holder. outUnmanagedBuffer[0].count = outSecBuffer.size; outUnmanagedBuffer[0].type = outSecBuffer.type; if (outSecBuffer.token == null || outSecBuffer.token.Length == 0) { outUnmanagedBuffer[0].token = IntPtr.Zero; } else { outUnmanagedBuffer[0].token = Marshal.UnsafeAddrOfPinnedArrayElement(outSecBuffer.token, outSecBuffer.offset); } if (isSspiAllocated) { outFreeContextBuffer = SafeFreeContextBuffer.CreateEmptyHandle(); } if (refContext == null || refContext.IsInvalid) { refContext = new SafeDeleteContext_SECURITY(); } errorCode = MustRunAcceptSecurityContext_SECURITY( ref inCredentials, contextHandle.IsZero ? null : &contextHandle, inSecurityBufferDescriptor, inFlags, endianness, refContext, outSecurityBufferDescriptor, ref outFlags, outFreeContextBuffer); GlobalLog.Print("SafeDeleteContext:AcceptSecurityContext Marshalling OUT buffer"); // Get unmanaged buffer with index 0 as the only one passed into PInvoke. outSecBuffer.size = outUnmanagedBuffer[0].count; outSecBuffer.type = outUnmanagedBuffer[0].type; if (outSecBuffer.size > 0) { outSecBuffer.token = new byte[outSecBuffer.size]; Marshal.Copy(outUnmanagedBuffer[0].token, outSecBuffer.token, 0, outSecBuffer.size); } else { outSecBuffer.token = null; } } } } finally { if (pinnedInBytes != null) { for (int index = 0; index < pinnedInBytes.Length; index++) { if (pinnedInBytes[index].IsAllocated) { pinnedInBytes[index].Free(); } } } if (pinnedOutBytes.IsAllocated) { pinnedOutBytes.Free(); } if (outFreeContextBuffer != null) { outFreeContextBuffer.Dispose(); } } GlobalLog.Leave("SafeDeleteContext::AcceptSecurityContex() unmanaged AcceptSecurityContex()", "errorCode:0x" + errorCode.ToString("x8") + " refContext:" + Logging.ObjectToString(refContext)); return errorCode; }
internal static string QueryContextAuthenticationPackage(SafeDeleteContext securityContext) { SafeDeleteNegoContext negoContext = (SafeDeleteNegoContext)securityContext; return(negoContext.IsNtlmUsed ? NegotiationInfoClass.NTLM : NegotiationInfoClass.Kerberos); }
// // After PInvoke call the method will fix the handleTemplate.handle with the returned value. // The caller is responsible for creating a correct SafeFreeContextBuffer_XXX flavour or null can be passed if no handle is returned. // private static unsafe int MustRunAcceptSecurityContext_SECURITY( ref SafeFreeCredentials inCredentials, void* inContextPtr, Interop.Secur32.SecurityBufferDescriptor inputBuffer, Interop.Secur32.ContextFlags inFlags, Interop.Secur32.Endianness endianness, SafeDeleteContext outContext, Interop.Secur32.SecurityBufferDescriptor outputBuffer, ref Interop.Secur32.ContextFlags outFlags, SafeFreeContextBuffer handleTemplate) { int errorCode = (int)Interop.SecurityStatus.InvalidHandle; // Run the body of this method as a non-interruptible block. try { bool ignore = false; inCredentials.DangerousAddRef(ref ignore); outContext.DangerousAddRef(ref ignore); Interop.Secur32.SSPIHandle credentialHandle = inCredentials._handle; long timeStamp; errorCode = Interop.Secur32.AcceptSecurityContext( ref credentialHandle, inContextPtr, inputBuffer, inFlags, endianness, ref outContext._handle, outputBuffer, ref outFlags, out timeStamp); } finally { // // When a credential handle is first associated with the context we keep credential // ref count bumped up to ensure ordered finalization. // If the credential handle has been changed we de-ref the old one and associate the // context with the new cred handle but only if the call was successful. if (outContext._EffectiveCredential != inCredentials && (errorCode & 0x80000000) == 0) { // Disassociate the previous credential handle. if (outContext._EffectiveCredential != null) { outContext._EffectiveCredential.DangerousRelease(); } outContext._EffectiveCredential = inCredentials; } else { inCredentials.DangerousRelease(); } outContext.DangerousRelease(); } // The idea is that SSPI has allocated a block and filled up outUnmanagedBuffer+8 slot with the pointer. if (handleTemplate != null) { //ATTN: on 64 BIT that is still +8 cause of 2* c++ unsigned long == 8 bytes. handleTemplate.Set(((Interop.Secur32.SecurityBufferStruct*)outputBuffer.UnmanagedPointer)->token); if (handleTemplate.IsInvalid) { handleTemplate.SetHandleAsInvalid(); } } if (inContextPtr == null && (errorCode & 0x80000000) != 0) { // An error on the first call, need to set the out handle to invalid value. outContext._handle.SetToInvalid(); } return errorCode; }
public static SecurityStatusPal EncryptMessage( SafeDeleteContext securityContext, ReadOnlyMemory <byte> input, int headerSize, int trailerSize, ref byte[] output, out int resultSize) { resultSize = 0; Debug.Assert(input.Length > 0, $"{nameof(input.Length)} > 0 since {nameof(CanEncryptEmptyMessage)} is false"); try { SafeDeleteSslContext sslContext = (SafeDeleteSslContext)securityContext; SafeSslHandle sslHandle = sslContext.SslContext; unsafe { MemoryHandle memHandle = input.Retain(pin: true); try { PAL_TlsIo status; lock (sslHandle) { status = Interop.AppleCrypto.SslWrite( sslHandle, (byte *)memHandle.Pointer, input.Length, out int written); } if (status < 0) { return(new SecurityStatusPal( SecurityStatusPalErrorCode.InternalError, Interop.AppleCrypto.CreateExceptionForOSStatus((int)status))); } if (sslContext.BytesReadyForConnection <= output?.Length) { resultSize = sslContext.ReadPendingWrites(output, 0, output.Length); } else { output = sslContext.ReadPendingWrites(); resultSize = output.Length; } switch (status) { case PAL_TlsIo.Success: return(new SecurityStatusPal(SecurityStatusPalErrorCode.OK)); case PAL_TlsIo.WouldBlock: return(new SecurityStatusPal(SecurityStatusPalErrorCode.ContinueNeeded)); default: Debug.Fail($"Unknown status value: {status}"); return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError)); } } finally { memHandle.Dispose(); } } } catch (Exception e) { return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, e)); } }