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)); } TwoSecurityBuffers buffers = default; var securityBuffer = MemoryMarshal.CreateSpan(ref buffers._item0, 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(securityBuffer[1].type); } newOffset = securityBuffer[1].offset; return(securityBuffer[1].size); }
internal static SecurityStatusPal InitializeSecurityContext( ref SafeFreeCredentials credentialsHandle, ref SafeDeleteContext securityContext, string spn, ContextFlagsPal requestedContextFlags, byte[] incomingBlob, ChannelBinding channelBinding, ref byte[] resultBlob, ref ContextFlagsPal contextFlags) { #if netstandard Span <SecurityBuffer> inSecurityBufferSpan = new SecurityBuffer[2]; #else TwoSecurityBuffers twoSecurityBuffers = default; Span <SecurityBuffer> inSecurityBufferSpan = MemoryMarshal.CreateSpan(ref twoSecurityBuffers._item0, 2); #endif int inSecurityBufferSpanLength = 0; if (incomingBlob != null && channelBinding != null) { inSecurityBufferSpan[0] = new SecurityBuffer(incomingBlob, SecurityBufferType.SECBUFFER_TOKEN); inSecurityBufferSpan[1] = new SecurityBuffer(channelBinding); inSecurityBufferSpanLength = 2; } else if (incomingBlob != null) { inSecurityBufferSpan[0] = new SecurityBuffer(incomingBlob, SecurityBufferType.SECBUFFER_TOKEN); inSecurityBufferSpanLength = 1; } else if (channelBinding != null) { inSecurityBufferSpan[0] = new SecurityBuffer(channelBinding); inSecurityBufferSpanLength = 1; } inSecurityBufferSpan = inSecurityBufferSpan.Slice(0, inSecurityBufferSpanLength); var outSecurityBuffer = new SecurityBuffer(resultBlob, SecurityBufferType.SECBUFFER_TOKEN); Interop.SspiCli.ContextFlags outContextFlags = Interop.SspiCli.ContextFlags.Zero; // There is only one SafeDeleteContext type on Windows which is SafeDeleteSslContext so this cast is safe. SafeDeleteSslContext sslContext = (SafeDeleteSslContext)securityContext; Interop.SECURITY_STATUS winStatus = (Interop.SECURITY_STATUS)SSPIWrapper.InitializeSecurityContext( GlobalSSPI.SSPIAuth, ref credentialsHandle, ref sslContext, spn, ContextFlagsAdapterPal.GetInteropFromContextFlagsPal(requestedContextFlags), Interop.SspiCli.Endianness.SECURITY_NETWORK_DREP, inSecurityBufferSpan, ref outSecurityBuffer, ref outContextFlags); securityContext = sslContext; resultBlob = outSecurityBuffer.token; contextFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop(outContextFlags); return(SecurityStatusAdapterPal.GetSecurityStatusPalFromInterop(winStatus)); }
internal static int VerifySignature(SafeDeleteContext securityContext, byte[] buffer, int offset, int count) { // validate offset within length if (offset < 0 || offset > (buffer == null ? 0 : buffer.Length)) { NetEventSource.Info("Argument 'offset' out of range."); throw new ArgumentOutOfRangeException(nameof(offset)); } // validate count within offset and end of buffer if (count < 0 || count > (buffer == null ? 0 : buffer.Length - offset)) { NetEventSource.Info("Argument 'count' out of range."); throw new ArgumentOutOfRangeException(nameof(count)); } // setup security buffers for ssp call // one points at signed data // two will receive payload if signature is valid #if NETSTANDARD2_0 Span <SecurityBuffer> securityBuffer = new SecurityBuffer[2]; #else TwoSecurityBuffers stackBuffer = default; Span <SecurityBuffer> securityBuffer = MemoryMarshal.CreateSpan(ref stackBuffer._item0, 2); #endif securityBuffer[0] = new SecurityBuffer(buffer, offset, count, SecurityBufferType.SECBUFFER_STREAM); securityBuffer[1] = new SecurityBuffer(0, SecurityBufferType.SECBUFFER_DATA); // call SSP function int errorCode = SSPIWrapper.VerifySignature( GlobalSSPI.SSPIAuth, securityContext, securityBuffer, 0); // throw if error if (errorCode != 0) { NetEventSource.Info($"VerifySignature threw error: {errorCode.ToString("x", NumberFormatInfo.InvariantInfo)}"); throw new Win32Exception(errorCode); } // not sure why this is here - retained from Encrypt code above if (securityBuffer[1].type != SecurityBufferType.SECBUFFER_DATA) { throw new InternalException(securityBuffer[1].type); } // return validated payload size return(securityBuffer[1].size); }
internal static int MakeSignature(SafeDeleteContext securityContext, byte[] buffer, int offset, int count, [AllowNull] ref byte[] output) { SecPkgContext_Sizes sizes = default; bool success = SSPIWrapper.QueryBlittableContextAttributes(GlobalSSPI.SSPIAuth, securityContext, Interop.SspiCli.ContextAttribute.SECPKG_ATTR_SIZES, ref sizes); Debug.Assert(success); // alloc new output buffer if not supplied or too small int resultSize = count + sizes.cbMaxSignature; if (output == null || output.Length < resultSize) { output = new byte[resultSize]; } // make a copy of user data for in-place encryption Buffer.BlockCopy(buffer, offset, output, sizes.cbMaxSignature, count); // setup security buffers for ssp call #if NETSTANDARD2_0 Span <SecurityBuffer> securityBuffer = new SecurityBuffer[2]; #else TwoSecurityBuffers stackBuffer = default; Span <SecurityBuffer> securityBuffer = MemoryMarshal.CreateSpan(ref stackBuffer._item0, 2); #endif securityBuffer[0] = new SecurityBuffer(output, 0, sizes.cbMaxSignature, SecurityBufferType.SECBUFFER_TOKEN); securityBuffer[1] = new SecurityBuffer(output, sizes.cbMaxSignature, count, SecurityBufferType.SECBUFFER_DATA); // call SSP Function int errorCode = SSPIWrapper.MakeSignature(GlobalSSPI.SSPIAuth, securityContext, securityBuffer, 0); // throw if error if (errorCode != 0) { NetEventSource.Info($"MakeSignature threw error: {errorCode.ToString("x", NumberFormatInfo.InvariantInfo)}"); throw new Win32Exception(errorCode); } // return signed size return(securityBuffer[0].size + securityBuffer[1].size); }
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); }