From 4b4b72ced79840cacc75f23cf2829e3f4aa59f31 Mon Sep 17 00:00:00 2001 From: Drawaes Date: Wed, 2 Aug 2017 22:54:01 +0100 Subject: [PATCH 01/54] Added reference to AppSet/AppGet from openssl --- .../Unix/System.Security.Cryptography.Native/opensslshim.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h index 3e405b09da87..58cc2a7c1551 100644 --- a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +++ b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h @@ -68,11 +68,14 @@ int EC_POINT_set_affine_coordinates_GF2m(const EC_GROUP *group, EC_POINT *p, PER_FUNCTION_BLOCK(BIO_ctrl, true) \ PER_FUNCTION_BLOCK(BIO_ctrl_pending, true) \ PER_FUNCTION_BLOCK(BIO_free, true) \ + PER_FUNCTION_BLOCK(BIO_get_app_data) \ PER_FUNCTION_BLOCK(BIO_gets, true) \ PER_FUNCTION_BLOCK(BIO_new, true) \ PER_FUNCTION_BLOCK(BIO_new_file, true) \ PER_FUNCTION_BLOCK(BIO_read, true) \ PER_FUNCTION_BLOCK(BIO_s_mem, true) \ + PER_FUNCTION_BLOCK(BIO_set_app_data) \ + PER_FUNCTION_BLOCK(BIO_set_flags) \ PER_FUNCTION_BLOCK(BIO_write, true) \ PER_FUNCTION_BLOCK(BN_bin2bn, true) \ PER_FUNCTION_BLOCK(BN_bn2bin, true) \ @@ -359,11 +362,14 @@ FOR_ALL_OPENSSL_FUNCTIONS #define BIO_ctrl BIO_ctrl_ptr #define BIO_ctrl_pending BIO_ctrl_pending_ptr #define BIO_free BIO_free_ptr +#define BIO_get_app_data BIO_get_app_data_ptr #define BIO_gets BIO_gets_ptr #define BIO_new BIO_new_ptr #define BIO_new_file BIO_new_file_ptr #define BIO_read BIO_read_ptr #define BIO_s_mem BIO_s_mem_ptr +#define BIO_set_app_data BIO_set_app_data_ptr +#define BIO_set_flags BIO_set_flags_ptr #define BIO_write BIO_write_ptr #define BN_bin2bn BN_bin2bn_ptr #define BN_bn2bin BN_bn2bin_ptr From 4079b92a6176e21d5e4cc904bdee7ecfb425717e Mon Sep 17 00:00:00 2001 From: Drawaes Date: Wed, 2 Aug 2017 23:00:08 +0100 Subject: [PATCH 02/54] Added Bio methods to the openssl native shim --- .../pal_bio.cpp | 20 +++++++++++++++++++ .../pal_bio.h | 19 ++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp b/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp index b4009d5c402e..96495a3e2527 100644 --- a/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp +++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp @@ -6,6 +6,11 @@ #include +extern "C" BIO* CryptoNative_CreateCustomBio(BIO_METHOD* bioMethod) +{ + return BIO_new(bioMethod); +} + extern "C" BIO* CryptoNative_CreateMemoryBio() { return BIO_new(BIO_s_mem()); @@ -52,3 +57,18 @@ extern "C" int32_t CryptoNative_BioCtrlPending(BIO* bio) assert(result <= INT32_MAX); return static_cast(result); } + +extern "C" void CryptoNative_BioSetAppData(BIO* bio, void* data) +{ + BIO_set_app_data(bio, data); +} + +extern "C" void* CryptoNative_BioGetAppData(BIO* bio) +{ + return BIO_get_app_data(bio); +} + +extern "C" void CryptoNative_BioSetFlags(BIO* bio, int32_t flags) +{ + BIO_set_flags(bio, flags); +} diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.h b/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.h index 6897dc14030b..6c8215d989f1 100644 --- a/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.h +++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.h @@ -5,6 +5,11 @@ #include "pal_types.h" #include "opensslshim.h" +/* +Creates a custom BIO instance. +*/ +extern "C" BIO* CryptoNative_CreateCustomBio(BIO_METHOD* bioMethod); + /* Creates a new memory-backed BIO instance. */ @@ -54,3 +59,17 @@ Shims the BIO_ctrl_pending method. Returns the number of pending characters in the BIOs read and write buffers. */ extern "C" int32_t CryptoNative_BioCtrlPending(BIO* bio); +/* +Adds app data to the extension slot of the bio +*/ +extern "C" void CryptoNative_BioSetAppData(BIO* bio, void* data); + +/* +Gets app data from the extension slot of the bio +*/ +extern "C" void* CryptoNative_BioGetAppData(BIO* bio); + +/* +Shims the Set flags for the custom bio +*/ +extern "C" void CryptoNative_BioSetFlags(BIO* bio, int32_t flags); From 1fa274a523c1e6a1cf417e197b83e8832bcb39ff Mon Sep 17 00:00:00 2001 From: Drawaes Date: Wed, 2 Aug 2017 23:35:32 +0100 Subject: [PATCH 03/54] Add basic custom bio interop code, write and read still needed --- .../Interop.BIO.cs | 39 +++++++++++++++++++ .../src/System.Net.Http.csproj | 3 ++ .../src/System.Net.Security.csproj | 5 ++- 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.cs index ffa82ef001f8..2d4224369c03 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.cs @@ -35,5 +35,44 @@ internal static partial class Crypto [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_BioCtrlPending")] internal static extern int BioCtrlPending(SafeBioHandle bio); + + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_CreateCustomBio")] + internal static extern SafeBioHandle CreateCustomBio(IntPtr bioMethodStruct); + + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_BioSetAppData")] + internal static extern void BioSetAppData(SafeBioHandle bio, IntPtr data); + + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_BioGetAppData")] + internal static extern IntPtr BioGetAppData(IntPtr bio); + + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_BioSetFlags")] + internal static extern IntPtr BioSetFlags(IntPtr bio, BIO_FLAGS flags); + + [Flags] + internal enum BIO_FLAGS + { + BIO_FLAGS_READ = 0x01, + BIO_FLAGS_WRITE = 0x02, + BIO_FLAGS_IO_SPECIAL = 0x04, + BIO_FLAGS_RWS = (BIO_FLAGS_READ | BIO_FLAGS_WRITE | BIO_FLAGS_IO_SPECIAL), + BIO_FLAGS_SHOULD_RETRY = 0x08, + } + + internal enum BIO_CTRL + { + BIO_CTRL_RESET = 1,/* opt - rewind/zero etc */ + BIO_CTRL_EOF = 2,/* opt - are we at the eof */ + BIO_CTRL_INFO = 3,/* opt - extra tit-bits */ + BIO_CTRL_SET = 4,/* man - set the 'IO' type */ + BIO_CTRL_GET = 5,/* man - get the 'IO' type */ + BIO_CTRL_PUSH = 6,/* opt - internal, used to signify change */ + BIO_CTRL_POP = 7,/* opt - internal, used to signify change */ + BIO_CTRL_GET_CLOSE = 8,/* man - set the 'close' on free */ + BIO_CTRL_SET_CLOSE = 9,/* man - set the 'close' on free */ + BIO_CTRL_PENDING = 10,/* opt - is their more data buffered */ + BIO_CTRL_FLUSH = 11,/* opt - 'flush' buffered output */ + BIO_CTRL_DUP = 12,/* man - extra stuff for 'duped' BIO */ + BIO_CTRL_WPENDING = 13,/* opt - number of bytes still to write */ + } } } diff --git a/src/System.Net.Http/src/System.Net.Http.csproj b/src/System.Net.Http/src/System.Net.Http.csproj index 252c82030211..89d4fa22011e 100644 --- a/src/System.Net.Http/src/System.Net.Http.csproj +++ b/src/System.Net.Http/src/System.Net.Http.csproj @@ -314,6 +314,9 @@ Common\Interop\Unix\System.Security.Cryptography.Native\Interop.BIO.cs + + Common\Interop\Unix\System.Security.Cryptography.Native\Interop.BIO.Custom.cs + Common\Interop\Unix\System.Security.Cryptography.Native\Interop.ERR.cs diff --git a/src/System.Net.Security/src/System.Net.Security.csproj b/src/System.Net.Security/src/System.Net.Security.csproj index b901f525744b..bb0ff4181d81 100644 --- a/src/System.Net.Security/src/System.Net.Security.csproj +++ b/src/System.Net.Security/src/System.Net.Security.csproj @@ -273,6 +273,9 @@ Common\Interop\Unix\System.Security.Cryptography.Native\Interop.BIO.cs + + Common\Interop\Unix\System.Security.Cryptography.Native\Interop.BIO.Custom.cs + Common\Interop\Unix\System.Security.Cryptography.Native\Interop.ERR.cs @@ -411,4 +414,4 @@ - \ No newline at end of file + From d5fc98335b98c9bfd97a23caed31db809c13eb37 Mon Sep 17 00:00:00 2001 From: Drawaes Date: Wed, 2 Aug 2017 23:44:22 +0100 Subject: [PATCH 04/54] Added BIO.Custom file Added the SslReadBuffer --- .../Interop.BIO.Custom.cs | 151 ++++++++++++++++++ .../Interop.Ssl.cs | 55 ++++++- 2 files changed, 204 insertions(+), 2 deletions(-) create mode 100644 src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs new file mode 100644 index 000000000000..fb8a3966be73 --- /dev/null +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs @@ -0,0 +1,151 @@ +using System; +using System.Runtime.InteropServices; +using Microsoft.Win32.SafeHandles; +using System.Diagnostics; + +internal static partial class Interop +{ + internal static class CustomBio + { + private static IntPtr _customBioMethodStructure; + private static CreateDelegate _createDelegate; + private static DestroyDelegate _destroyDelegate; + private unsafe static ControlDelegate _controlDelegate; + private unsafe static ReadDelegate _readDelegate; + private unsafe static WriteDelegate _writeDelegate; + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private unsafe delegate int CreateDelegate(bio_st* bio); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private unsafe delegate int ReadDelegate(IntPtr bio, void* buf, int size); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private unsafe delegate int WriteDelegate(IntPtr bio, void* buf, int num); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private unsafe delegate long ControlDelegate(IntPtr bio, BIO_CTRL cmd, long num, void* ptr); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate int DestroyDelegate(IntPtr bio); + + static CustomBio() + { + CustomBio.Initialize(); + } + + internal unsafe static void Initialize() + { + _createDelegate = Create; + _controlDelegate = Control; + _destroyDelegate = Destroy; + _writeDelegate = Write; + _readDelegate = Read; + + var name = Marshal.StringToHGlobalAnsi("Managed Bio"); + var bioStruct = new bio_method_st() + { + create = _createDelegate, + name = name, + type = BIO_TYPE.BIO_TYPE_SOURCE_SINK, + destroy = _destroyDelegate, + ctrl = _controlDelegate, + bread = _readDelegate, + bwrite = _writeDelegate, + }; + + var memory = Marshal.AllocHGlobal(Marshal.SizeOf()); + Marshal.StructureToPtr(bioStruct, memory, true); + _customBioMethodStructure = memory; + } + + internal static GCHandle BioGetGCHandle(IntPtr bio) + { + var ptr = Crypto.BioGetAppData(bio); + if (ptr == IntPtr.Zero) + { + return default(GCHandle); + } + var handle = GCHandle.FromIntPtr(ptr); + return handle; + } + + internal static void BioSetGCHandle(SafeBioHandle bio, GCHandle handle) + { + var ptr = GCHandle.ToIntPtr(handle); + Crypto.BioSetAppData(bio, ptr); + } + + internal static SafeBioHandle CreateCustomBio() + { + var bio = Crypto.CreateCustomBio(_customBioMethodStructure); + return bio; + } + + private unsafe static int Create(bio_st* bio) + { + bio[0].init = 1; + return 1; + } + + private static int Destroy(IntPtr bio) => 1; + + private static unsafe int Write(IntPtr bio, void* input, int size) + { + var handle = BioGetGCHandle(bio); + Debug.Assert(handle.IsAllocated); + if (!handle.IsAllocated) + { + return -1; + } + throw new NotImplementedException(); + } + + private static unsafe int Read(IntPtr bio, void* output, int size) + { + var handle = BioGetGCHandle(bio); + Debug.Assert(handle.IsAllocated); + if (!handle.IsAllocated) + { + return -1; + } + throw new NotImplementedException(); + } + + [Flags] + private enum BIO_TYPE + { + BIO_TYPE_SOURCE_SINK = 0x0400, + } + + [StructLayout(LayoutKind.Sequential)] + private unsafe struct bio_st + { + public void* method; + public void* callback; + public void* cb_arg; + public int init; + public int shutdown; + public int flags; + public int retry_reason; + public int num; + public void* ptr; + } + + [StructLayout(LayoutKind.Sequential)] + private unsafe struct bio_method_st + { + public BIO_TYPE type; + public IntPtr name; + public WriteDelegate bwrite; // int (* bwrite) (BIO*, const char*, int); + public ReadDelegate bread; // int (* bread) (BIO*, char*, int); + public IntPtr bputs; // int (* bputs) (BIO*, const char*); + public IntPtr bgets; // int (* bgets) (BIO*, char*, int); + public ControlDelegate ctrl; // long (* ctrl) (BIO*, int, long, void*); + public CreateDelegate create; // int (* create) (BIO*); + public DestroyDelegate destroy; // int (* destroy) (BIO*); + public IntPtr callback_ctrl; // long (* callback_ctrl) (BIO*, int, bio_info_cb*); + } + + } +} diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs index c468e1a34ad0..049139b65683 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs @@ -156,12 +156,12 @@ internal enum SslErrorCode SSL_ERROR_WANT_WRITE = 3, SSL_ERROR_SYSCALL = 5, SSL_ERROR_ZERO_RETURN = 6, - + // NOTE: this SslErrorCode value doesn't exist in OpenSSL, but // we use it to distinguish when a renegotiation is pending. // Choosing an arbitrarily large value that shouldn't conflict // with any actual OpenSSL error codes - SSL_ERROR_RENEGOTIATE = 29304 + SSL_ERROR_RENEGOTIATE = 29304 } } } @@ -296,5 +296,56 @@ internal SafeSslHandle(IntPtr validSslPointer, bool ownsHandle) : base(IntPtr.Ze { handle = validSslPointer; } + + internal class ReadBioBuffer : IDisposable + { + private SafeBioHandle _bioHandle; + private GCHandle _handle; + + internal ReadBioBuffer(SafeBioHandle bioHandle) + { + _bioHandle = bioHandle; + _handle = GCHandle.Alloc(this, GCHandleType.Normal); + Interop.CustomBio.BioSetGCHandle(BioHandle, _handle); + } + + public int BytesAvailable { get; set; } + public byte[] ByteArray { get; private set; } + public int Offset { get; set; } + + public void SetBio(byte[] buffer, int offset, int length) + { + ByteArray = buffer; + Offset = offset; + BytesAvailable = length; + } + + public void ResetBio() + { + ByteArray = null; + Offset = 0; + BytesAvailable = 0; + } + + //Bio is already released by the ssl object + private void Dispose(bool isDisposing) + { + if (_handle.IsAllocated) + { + _handle.Free(); + } + } + + internal void Dispose() + { + Dispose(false); + GC.SuppressFinalize(this); + } + + ~ReadBioBuffer() + { + Dispose(false); + } + } } } From 7bbcc3d4f1fbabb7131f38bb1334e4c79298e421 Mon Sep 17 00:00:00 2001 From: Drawaes Date: Wed, 2 Aug 2017 23:50:41 +0100 Subject: [PATCH 05/54] Added Write Buffer and changed disposable to be public to match interface --- .../Interop.Ssl.cs | 74 ++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs index 049139b65683..222a8400baf0 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs @@ -336,7 +336,7 @@ private void Dispose(bool isDisposing) } } - internal void Dispose() + public void Dispose() { Dispose(false); GC.SuppressFinalize(this); @@ -347,5 +347,77 @@ internal void Dispose() Dispose(false); } } + + internal class WriteBioBuffer :IDisposable + { + private SafeBioHandle _bioHandle; + private GCHandle _handle; + + internal WriteBioBuffer(SafeBioHandle bioHandle) + { + _bioHandle = bioHandle; + _handle = GCHandle.Alloc(this, GCHandleType.Normal); + Interop.CustomBio.BioSetGCHandle(BioHandle, _handle); + } + + public int FreeSpace { get; set; } + public byte[] ByteArray { get; private set; } + public int StartOfFreeSpace { get; set; } + public int TotalBytes { get; set; } + + public void SetBio(byte[] buffer, int offset, int length) + { + ByteArray = buffer; + StartOfFreeSpace = offset; + TotalBytes = 0; + FreeSpace = length; + } + + public void ResetBio() + { + ByteArray = null; + StartOfFreeSpace = 0; + TotalBytes = 0; + FreeSpace = 0; + } + + public void CheckSpaceOrIncrease(int sizeWanted) + { + if (ByteArray == null) + { + ByteArray = new byte[sizeWanted]; + FreeSpace = sizeWanted; + TotalBytes = 0; + StartOfFreeSpace = 0; + } + else if (FreeSpace < sizeWanted) + { + var newArray = new byte[ByteArray.Length + (sizeWanted - StartOfFreeSpace)]; + FreeSpace = sizeWanted; + Array.Copy(ByteArray, newArray, ByteArray.Length); + ByteArray = newArray; + } + } + + //Bio is already released by the ssl object + private void Dispose(bool isDisposing) + { + if (_handle.IsAllocated) + { + _handle.Free(); + } + } + + public void Dispose() + { + Dispose(false); + GC.SuppressFinalize(this); + } + + ~WriteBioBuffer() + { + Dispose(false); + } + } } } From dd8fae2383672db4b4d7b7e7d0aec597e23d8551 Mon Sep 17 00:00:00 2001 From: Drawaes Date: Thu, 3 Aug 2017 00:05:02 +0100 Subject: [PATCH 06/54] Added the custom bio into the main code line for SslStream --- .../Interop.OpenSsl.cs | 171 +++++++++--------- .../Interop.Ssl.cs | 31 +--- 2 files changed, 99 insertions(+), 103 deletions(-) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs index 5ac8a42b5977..3665a85a447b 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs @@ -135,50 +135,45 @@ internal static bool DoSslHandshake(SafeSslHandle context, byte[] recvBuf, int r { sendBuf = null; sendCount = 0; - if ((recvBuf != null) && (recvCount > 0)) - { - BioWrite(context.InputBio, recvBuf, recvOffset, recvCount); - } - int retVal = Ssl.SslDoHandshake(context); + context.InputBio.SetBio(recvBuf, recvOffset, recvCount); + context.OutputBio.SetBio(null, 0, 0); - if (retVal != 1) + try { - Exception innerError; - Ssl.SslErrorCode error = GetSslError(context, retVal, out innerError); + int retVal = Ssl.SslDoHandshake(context); - if ((retVal != -1) || (error != Ssl.SslErrorCode.SSL_ERROR_WANT_READ)) + if (retVal != 1) { - throw new SslException(SR.Format(SR.net_ssl_handshake_failed_error, error), innerError); - } - } + Exception innerError; + Ssl.SslErrorCode error = GetSslError(context, retVal, out innerError); - sendCount = Crypto.BioCtrlPending(context.OutputBio); + if ((retVal != -1) || (error != Ssl.SslErrorCode.SSL_ERROR_WANT_READ)) + { + throw new SslException(SR.Format(SR.net_ssl_handshake_failed_error, error), innerError); + } + } - if (sendCount > 0) - { - sendBuf = new byte[sendCount]; + sendCount = Crypto.BioCtrlPending(context.OutputBio); - try + if (context.OutputBio.ByteArray != null) { - sendCount = BioRead(context.OutputBio, sendBuf, sendCount); + sendBuf = context.OutputBio.ByteArray; + sendCount = context.OutputBio.TotalBytes; } - finally + + bool stateOk = Ssl.IsSslStateOK(context); + if (stateOk) { - if (sendCount <= 0) - { - sendBuf = null; - sendCount = 0; - } + context.MarkHandshakeCompleted(); } + return stateOk; } - - bool stateOk = Ssl.IsSslStateOK(context); - if (stateOk) + finally { - context.MarkHandshakeCompleted(); + context.InputBio.ResetBio(); + context.OutputBio.ResetBio(); } - return stateOk; } internal static int Encrypt(SafeSslHandle context, byte[] input, int offset, int count, ref byte[] output, out Ssl.SslErrorCode errorCode) @@ -190,56 +185,65 @@ internal static int Encrypt(SafeSslHandle context, byte[] input, int offset, int Debug.Assert(input.Length - offset >= count); errorCode = Ssl.SslErrorCode.SSL_ERROR_NONE; + context.OutputBio.SetBio(output, 0, output?.Length ?? 0); - int retVal; - unsafe + try { - fixed (byte* fixedBuffer = input) + int retVal; + unsafe { - retVal = Ssl.SslWrite(context, fixedBuffer + offset, count); + fixed (byte* fixedBuffer = input) + { + retVal = Ssl.SslWrite(context, fixedBuffer + offset, count); + } } - } - if (retVal != count) - { - Exception innerError; - errorCode = GetSslError(context, retVal, out innerError); - retVal = 0; + if (retVal != count) + { + Exception innerError; + errorCode = GetSslError(context, retVal, out innerError); + retVal = 0; + + switch (errorCode) + { + // indicate end-of-file + case Ssl.SslErrorCode.SSL_ERROR_ZERO_RETURN: + case Ssl.SslErrorCode.SSL_ERROR_WANT_READ: + break; - switch (errorCode) + default: + throw new SslException(SR.Format(SR.net_ssl_encrypt_failed, errorCode), innerError); + } + } + else { - // indicate end-of-file - case Ssl.SslErrorCode.SSL_ERROR_ZERO_RETURN: - case Ssl.SslErrorCode.SSL_ERROR_WANT_READ: - break; + int capacityNeeded = Crypto.BioCtrlPending(context.OutputBio); + + if (output == null || output.Length < capacityNeeded) + { + output = new byte[capacityNeeded]; + } - default: - throw new SslException(SR.Format(SR.net_ssl_encrypt_failed, errorCode), innerError); + retVal = BioRead(context.OutputBio, output, capacityNeeded); } + output = context.OutputBio.ByteArray; + return context.OutputBio.TotalBytes; } - else + finally { - int capacityNeeded = Crypto.BioCtrlPending(context.OutputBio); - - if (output == null || output.Length < capacityNeeded) - { - output = new byte[capacityNeeded]; - } - - retVal = BioRead(context.OutputBio, output, capacityNeeded); + context.OutputBio.ResetBio(); } - - return retVal; } internal static int Decrypt(SafeSslHandle context, byte[] outBuffer, int offset, int count, out Ssl.SslErrorCode errorCode) { errorCode = Ssl.SslErrorCode.SSL_ERROR_NONE; - int retVal = BioWrite(context.InputBio, outBuffer, offset, count); + context.InputBio.SetBio(outBuffer, offset, count); - if (retVal == count) + try { + int retVal; unsafe { fixed (byte* fixedBuffer = outBuffer) @@ -252,33 +256,38 @@ internal static int Decrypt(SafeSslHandle context, byte[] outBuffer, int offset, { count = retVal; } - } - if (retVal != count) - { - Exception innerError; - errorCode = GetSslError(context, retVal, out innerError); - retVal = 0; - switch (errorCode) + if (retVal != count) { - // indicate end-of-file - case Ssl.SslErrorCode.SSL_ERROR_ZERO_RETURN: - break; - - case Ssl.SslErrorCode.SSL_ERROR_WANT_READ: - // update error code to renegotiate if renegotiate is pending, otherwise make it SSL_ERROR_WANT_READ - errorCode = Ssl.IsSslRenegotiatePending(context) ? - Ssl.SslErrorCode.SSL_ERROR_RENEGOTIATE : - Ssl.SslErrorCode.SSL_ERROR_WANT_READ; - break; - - default: - throw new SslException(SR.Format(SR.net_ssl_decrypt_failed, errorCode), innerError); + Exception innerError; + errorCode = GetSslError(context, retVal, out innerError); + retVal = 0; + + switch (errorCode) + { + // indicate end-of-file + case Ssl.SslErrorCode.SSL_ERROR_ZERO_RETURN: + break; + + case Ssl.SslErrorCode.SSL_ERROR_WANT_READ: + // update error code to renegotiate if renegotiate is pending, otherwise make it SSL_ERROR_WANT_READ + errorCode = Ssl.IsSslRenegotiatePending(context) ? + Ssl.SslErrorCode.SSL_ERROR_RENEGOTIATE : + Ssl.SslErrorCode.SSL_ERROR_WANT_READ; + break; + + default: + throw new SslException(SR.Format(SR.net_ssl_decrypt_failed, errorCode), innerError); + } } - } - return retVal; + return retVal; + } + finally + { + context.InputBio.ResetBio(); + } } internal static SafeX509Handle GetPeerCertificate(SafeSslHandle context) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs index 222a8400baf0..ae2c2b8e3738 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs @@ -170,8 +170,8 @@ namespace Microsoft.Win32.SafeHandles { internal sealed class SafeSslHandle : SafeHandle { - private SafeBioHandle _readBio; - private SafeBioHandle _writeBio; + private ReadBioBuffer _readBio; + private WriteBioBuffer _writeBio; private bool _isServer; private bool _handshakeCompleted = false; @@ -180,22 +180,9 @@ public bool IsServer get { return _isServer; } } - public SafeBioHandle InputBio - { - get - { - return _readBio; - } - } - - public SafeBioHandle OutputBio - { - get - { - return _writeBio; - } - } - + public ReadBioBuffer InputBio => _readBio; + public WriteBioBuffer OutputBio => _writeBio; + internal void MarkHandshakeCompleted() { _handshakeCompleted = true; @@ -203,8 +190,8 @@ internal void MarkHandshakeCompleted() public static SafeSslHandle Create(SafeSslContextHandle context, bool isServer) { - SafeBioHandle readBio = Interop.Crypto.CreateMemoryBio(); - SafeBioHandle writeBio = Interop.Crypto.CreateMemoryBio(); + SafeBioHandle readBio = Interop.CustomBio.CreateCustomBio(); + SafeBioHandle writeBio = Interop.CustomBio.CreateCustomBio(); SafeSslHandle handle = Interop.Ssl.SslCreate(context); if (readBio.IsInvalid || writeBio.IsInvalid || handle.IsInvalid) { @@ -220,8 +207,8 @@ public static SafeSslHandle Create(SafeSslContextHandle context, bool isServer) { readBio.TransferOwnershipToParent(handle); writeBio.TransferOwnershipToParent(handle); - handle._readBio = readBio; - handle._writeBio = writeBio; + handle._readBio = new ReadBioBuffer(readBio); + handle._writeBio = new WriteBioBuffer(writeBio); Interop.Ssl.SslSetBio(handle, readBio, writeBio); } catch (Exception exc) From 7c51afe6131f8b109a8c8172e651e2d154030657 Mon Sep 17 00:00:00 2001 From: Drawaes Date: Thu, 3 Aug 2017 00:07:10 +0100 Subject: [PATCH 07/54] Add the BIO Control method --- .../Interop.BIO.Custom.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs index fb8a3966be73..ae9bdeb8402a 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs @@ -24,7 +24,7 @@ internal static class CustomBio private unsafe delegate int WriteDelegate(IntPtr bio, void* buf, int num); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private unsafe delegate long ControlDelegate(IntPtr bio, BIO_CTRL cmd, long num, void* ptr); + private unsafe delegate long ControlDelegate(IntPtr bio, Crypto.BIO_CTRL cmd, long num, void* ptr); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate int DestroyDelegate(IntPtr bio); @@ -90,6 +90,18 @@ private unsafe static int Create(bio_st* bio) private static int Destroy(IntPtr bio) => 1; + private static unsafe long Control(IntPtr bio, Crypto.BIO_CTRL cmd, long param, void* ptr) + { + switch (cmd) + { + case Crypto.BIO_CTRL.BIO_CTRL_FLUSH: + case Crypto.BIO_CTRL.BIO_CTRL_POP: + case Crypto.BIO_CTRL.BIO_CTRL_PUSH: + return 1; + } + return 0; + } + private static unsafe int Write(IntPtr bio, void* input, int size) { var handle = BioGetGCHandle(bio); From 7080b6900033bcfa85e5796c950100a5b487e419 Mon Sep 17 00:00:00 2001 From: Drawaes Date: Thu, 3 Aug 2017 00:18:45 +0100 Subject: [PATCH 08/54] Removed pending reference from DoHandshake --- .../Interop.OpenSsl.cs | 13 ------------- .../Interop.Ssl.cs | 4 ++-- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs index 3665a85a447b..11b01ceaa5ef 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs @@ -154,8 +154,6 @@ internal static bool DoSslHandshake(SafeSslHandle context, byte[] recvBuf, int r } } - sendCount = Crypto.BioCtrlPending(context.OutputBio); - if (context.OutputBio.ByteArray != null) { sendBuf = context.OutputBio.ByteArray; @@ -215,18 +213,7 @@ internal static int Encrypt(SafeSslHandle context, byte[] input, int offset, int throw new SslException(SR.Format(SR.net_ssl_encrypt_failed, errorCode), innerError); } } - else - { - int capacityNeeded = Crypto.BioCtrlPending(context.OutputBio); - - if (output == null || output.Length < capacityNeeded) - { - output = new byte[capacityNeeded]; - } - retVal = BioRead(context.OutputBio, output, capacityNeeded); - } - output = context.OutputBio.ByteArray; return context.OutputBio.TotalBytes; } finally diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs index ae2c2b8e3738..01cf6b914047 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs @@ -293,7 +293,7 @@ internal ReadBioBuffer(SafeBioHandle bioHandle) { _bioHandle = bioHandle; _handle = GCHandle.Alloc(this, GCHandleType.Normal); - Interop.CustomBio.BioSetGCHandle(BioHandle, _handle); + Interop.CustomBio.BioSetGCHandle(_bioHandle, _handle); } public int BytesAvailable { get; set; } @@ -344,7 +344,7 @@ internal WriteBioBuffer(SafeBioHandle bioHandle) { _bioHandle = bioHandle; _handle = GCHandle.Alloc(this, GCHandleType.Normal); - Interop.CustomBio.BioSetGCHandle(BioHandle, _handle); + Interop.CustomBio.BioSetGCHandle(_bioHandle, _handle); } public int FreeSpace { get; set; } From 860bba103b9f538527f7198f899a821ebe3d856c Mon Sep 17 00:00:00 2001 From: Drawaes Date: Thu, 3 Aug 2017 00:27:24 +0100 Subject: [PATCH 09/54] Added custom bio read code --- .../Interop.BIO.Custom.cs | 26 ++++++++++++++++++- .../Interop.BIO.cs | 1 + 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs index ae9bdeb8402a..4b8ccf7106db 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs @@ -121,7 +121,31 @@ private static unsafe int Read(IntPtr bio, void* output, int size) { return -1; } - throw new NotImplementedException(); + var buffer = handle.Target as SafeSslHandle.ReadBioBuffer; + + if (buffer == null) + { + Crypto.BioSetFlags(bio, Crypto.BIO_FLAGS.NONE); + return -1; + } + if (buffer.BytesAvailable == 0) + { + Crypto.BioSetFlags(bio, Crypto.BIO_FLAGS.BIO_FLAGS_READ | Crypto.BIO_FLAGS.BIO_FLAGS_SHOULD_RETRY); + return -1; + } + fixed (byte* bPtr = buffer.ByteArray) + { + var offsetPtr = bPtr + buffer.Offset; + var bytesToCopy = Math.Min(size, buffer.BytesAvailable); + Buffer.MemoryCopy(offsetPtr, output, size, bytesToCopy); + buffer.BytesAvailable -= bytesToCopy; + buffer.Offset += bytesToCopy; + if (bytesToCopy < size) + { + Crypto.BioSetFlags(bio, Crypto.BIO_FLAGS.BIO_FLAGS_READ | Crypto.BIO_FLAGS.BIO_FLAGS_SHOULD_RETRY); + } + return bytesToCopy; + } } [Flags] diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.cs index 2d4224369c03..ccd039b5f6ab 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.cs @@ -51,6 +51,7 @@ internal static partial class Crypto [Flags] internal enum BIO_FLAGS { + BIO_FLAGS_NONE = 0x0, BIO_FLAGS_READ = 0x01, BIO_FLAGS_WRITE = 0x02, BIO_FLAGS_IO_SPECIAL = 0x04, From 6b19a38601883c85f4c901f39ba96746326b9e71 Mon Sep 17 00:00:00 2001 From: Drawaes Date: Thu, 3 Aug 2017 00:29:44 +0100 Subject: [PATCH 10/54] changed read flags --- .../System.Security.Cryptography.Native/Interop.BIO.Custom.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs index 4b8ccf7106db..41dd37b32c46 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs @@ -125,7 +125,7 @@ private static unsafe int Read(IntPtr bio, void* output, int size) if (buffer == null) { - Crypto.BioSetFlags(bio, Crypto.BIO_FLAGS.NONE); + Crypto.BioSetFlags(bio, Crypto.BIO_FLAGS.BIO_FLAGS_NONE); return -1; } if (buffer.BytesAvailable == 0) From 7f7f47ac719a558cb1823c6a3e591028db096620 Mon Sep 17 00:00:00 2001 From: Drawaes Date: Thu, 3 Aug 2017 00:33:48 +0100 Subject: [PATCH 11/54] Added write method --- .../Interop.BIO.Custom.cs | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs index 41dd37b32c46..2fd00ddba2dd 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs @@ -110,7 +110,25 @@ private static unsafe int Write(IntPtr bio, void* input, int size) { return -1; } - throw new NotImplementedException(); + + var buffer = handle.Target as SafeSslHandle.WriteBioBuffer; + + if (buffer == null) + { + Crypto.BioSetFlags(bio, Crypto.BIO_FLAGS.BIO_FLAGS_NONE); + return -1; + } + + buffer.CheckSpaceOrIncrease(size); + fixed (byte* bPtr = buffer.ByteArray) + { + var offsetPtr = bPtr + buffer.StartOfFreeSpace; + Buffer.MemoryCopy(input, offsetPtr, buffer.FreeSpace, size); + buffer.StartOfFreeSpace += size; + buffer.FreeSpace -= size; + buffer.TotalBytes += size; + return size; + } } private static unsafe int Read(IntPtr bio, void* output, int size) From 0be51acbc6f0333080c2c227a60c684aa81633f9 Mon Sep 17 00:00:00 2001 From: Drawaes Date: Thu, 3 Aug 2017 00:36:08 +0100 Subject: [PATCH 12/54] fixed indexing on resize --- .../Interop.BIO.Custom.cs | 2 +- .../Unix/System.Security.Cryptography.Native/Interop.Ssl.cs | 2 +- .../tests/FunctionalTests/SslStreamStreamToStreamTest.cs | 5 ++++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs index 2fd00ddba2dd..33a74caa349b 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs @@ -146,7 +146,7 @@ private static unsafe int Read(IntPtr bio, void* output, int size) Crypto.BioSetFlags(bio, Crypto.BIO_FLAGS.BIO_FLAGS_NONE); return -1; } - if (buffer.BytesAvailable == 0) + if (buffer.ByteArray == null || buffer.BytesAvailable == 0) { Crypto.BioSetFlags(bio, Crypto.BIO_FLAGS.BIO_FLAGS_READ | Crypto.BIO_FLAGS.BIO_FLAGS_SHOULD_RETRY); return -1; diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs index 01cf6b914047..3d40ee869f45 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs @@ -379,7 +379,7 @@ public void CheckSpaceOrIncrease(int sizeWanted) } else if (FreeSpace < sizeWanted) { - var newArray = new byte[ByteArray.Length + (sizeWanted - StartOfFreeSpace)]; + var newArray = new byte[ByteArray.Length + (sizeWanted - FreeSpace)]; FreeSpace = sizeWanted; Array.Copy(ByteArray, newArray, ByteArray.Length); ByteArray = newArray; diff --git a/src/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs b/src/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs index a0277c5bfa56..5408f25b24c4 100644 --- a/src/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs +++ b/src/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs @@ -11,6 +11,8 @@ using System.Threading.Tasks; using Xunit; +using Xunit.Abstractions; +using Xunit.NetCore.Extensions; namespace System.Net.Security.Tests { @@ -139,8 +141,9 @@ public void SslStream_StreamToStream_Successive_ClientWrite_WithZeroBytes_Succes } [Theory] + [Trait(XunitConstants.Category, "SingleTest")] [InlineData(false)] - [InlineData(true)] + //[InlineData(true)] public void SslStream_StreamToStream_LargeWrites_Sync_Success(bool randomizedData) { VirtualNetwork network = new VirtualNetwork(); From 4694662e8e3f02acbb50b7107c07e6633aba60f2 Mon Sep 17 00:00:00 2001 From: Drawaes Date: Thu, 3 Aug 2017 10:41:39 +0100 Subject: [PATCH 13/54] updated the output ref on encrypt --- .../Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs index 11b01ceaa5ef..11a69ad6f1f8 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs @@ -213,7 +213,7 @@ internal static int Encrypt(SafeSslHandle context, byte[] input, int offset, int throw new SslException(SR.Format(SR.net_ssl_encrypt_failed, errorCode), innerError); } } - + output = context.OutputBio.ByteArray; return context.OutputBio.TotalBytes; } finally From 5f4e2bf6cc5b05ecad2e68770c51bbe5449bdc47 Mon Sep 17 00:00:00 2001 From: Drawaes Date: Thu, 3 Aug 2017 21:05:54 +0100 Subject: [PATCH 14/54] Added short circuit for the dohandshake to return the shutdown alert --- .../Interop.OpenSsl.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs index 11a69ad6f1f8..6eb816c3555d 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs @@ -136,6 +136,14 @@ internal static bool DoSslHandshake(SafeSslHandle context, byte[] recvBuf, int r sendBuf = null; sendCount = 0; + if (recvBuf == null && context.OutputBio.TotalBytes > 0) + { + sendBuf = context.OutputBio.ByteArray; + sendCount = context.OutputBio.TotalBytes; + context.OutputBio.ResetBio(); + return false; + } + context.InputBio.SetBio(recvBuf, recvOffset, recvCount); context.OutputBio.SetBio(null, 0, 0); From 293ea41beeb9504c2ce2afbe03229e8502227e1d Mon Sep 17 00:00:00 2001 From: Drawaes Date: Sat, 5 Aug 2017 15:14:58 +0100 Subject: [PATCH 15/54] Simplify the write bio --- .../Interop.OpenSsl.cs | 164 ++++++++---------- .../Interop.Ssl.cs | 25 +-- .../System/Net/Security/SslStreamPal.Unix.cs | 4 + 3 files changed, 83 insertions(+), 110 deletions(-) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs index 6eb816c3555d..7daca5b7f335 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs @@ -139,47 +139,38 @@ internal static bool DoSslHandshake(SafeSslHandle context, byte[] recvBuf, int r if (recvBuf == null && context.OutputBio.TotalBytes > 0) { sendBuf = context.OutputBio.ByteArray; - sendCount = context.OutputBio.TotalBytes; - context.OutputBio.ResetBio(); + sendCount = context.OutputBio.TakeBytes(); return false; } context.InputBio.SetBio(recvBuf, recvOffset, recvCount); - context.OutputBio.SetBio(null, 0, 0); + context.OutputBio.SetBio(null); - try - { - int retVal = Ssl.SslDoHandshake(context); - - if (retVal != 1) - { - Exception innerError; - Ssl.SslErrorCode error = GetSslError(context, retVal, out innerError); + int retVal = Ssl.SslDoHandshake(context); - if ((retVal != -1) || (error != Ssl.SslErrorCode.SSL_ERROR_WANT_READ)) - { - throw new SslException(SR.Format(SR.net_ssl_handshake_failed_error, error), innerError); - } - } + if (retVal != 1) + { + Exception innerError; + Ssl.SslErrorCode error = GetSslError(context, retVal, out innerError); - if (context.OutputBio.ByteArray != null) + if ((retVal != -1) || (error != Ssl.SslErrorCode.SSL_ERROR_WANT_READ)) { - sendBuf = context.OutputBio.ByteArray; - sendCount = context.OutputBio.TotalBytes; + throw new SslException(SR.Format(SR.net_ssl_handshake_failed_error, error), innerError); } + } - bool stateOk = Ssl.IsSslStateOK(context); - if (stateOk) - { - context.MarkHandshakeCompleted(); - } - return stateOk; + if (context.OutputBio.ByteArray != null) + { + sendBuf = context.OutputBio.ByteArray; + sendCount = context.OutputBio.TakeBytes(); } - finally + + bool stateOk = Ssl.IsSslStateOK(context); + if (stateOk) { - context.InputBio.ResetBio(); - context.OutputBio.ResetBio(); + context.MarkHandshakeCompleted(); } + return stateOk; } internal static int Encrypt(SafeSslHandle context, byte[] input, int offset, int count, ref byte[] output, out Ssl.SslErrorCode errorCode) @@ -191,43 +182,35 @@ internal static int Encrypt(SafeSslHandle context, byte[] input, int offset, int Debug.Assert(input.Length - offset >= count); errorCode = Ssl.SslErrorCode.SSL_ERROR_NONE; - context.OutputBio.SetBio(output, 0, output?.Length ?? 0); + context.OutputBio.SetBio(output); - try + int retVal; + unsafe { - int retVal; - unsafe + fixed (byte* fixedBuffer = input) { - fixed (byte* fixedBuffer = input) - { - retVal = Ssl.SslWrite(context, fixedBuffer + offset, count); - } + retVal = Ssl.SslWrite(context, fixedBuffer + offset, count); } + } - if (retVal != count) - { - Exception innerError; - errorCode = GetSslError(context, retVal, out innerError); - retVal = 0; + if (retVal != count) + { + Exception innerError; + errorCode = GetSslError(context, retVal, out innerError); + retVal = 0; - switch (errorCode) - { - // indicate end-of-file - case Ssl.SslErrorCode.SSL_ERROR_ZERO_RETURN: - case Ssl.SslErrorCode.SSL_ERROR_WANT_READ: - break; + switch (errorCode) + { + // indicate end-of-file + case Ssl.SslErrorCode.SSL_ERROR_ZERO_RETURN: + case Ssl.SslErrorCode.SSL_ERROR_WANT_READ: + break; - default: - throw new SslException(SR.Format(SR.net_ssl_encrypt_failed, errorCode), innerError); - } + default: + throw new SslException(SR.Format(SR.net_ssl_encrypt_failed, errorCode), innerError); } - output = context.OutputBio.ByteArray; - return context.OutputBio.TotalBytes; - } - finally - { - context.OutputBio.ResetBio(); } + return context.OutputBio.TakeBytes(); } internal static int Decrypt(SafeSslHandle context, byte[] outBuffer, int offset, int count, out Ssl.SslErrorCode errorCode) @@ -236,53 +219,46 @@ internal static int Decrypt(SafeSslHandle context, byte[] outBuffer, int offset, context.InputBio.SetBio(outBuffer, offset, count); - try + int retVal; + unsafe { - int retVal; - unsafe + fixed (byte* fixedBuffer = outBuffer) { - fixed (byte* fixedBuffer = outBuffer) - { - retVal = Ssl.SslRead(context, fixedBuffer + offset, outBuffer.Length); - } + retVal = Ssl.SslRead(context, fixedBuffer + offset, outBuffer.Length); } + } - if (retVal > 0) - { - count = retVal; - } + if (retVal > 0) + { + count = retVal; + } - if (retVal != count) - { - Exception innerError; - errorCode = GetSslError(context, retVal, out innerError); - retVal = 0; + if (retVal != count) + { + Exception innerError; + errorCode = GetSslError(context, retVal, out innerError); + retVal = 0; - switch (errorCode) - { - // indicate end-of-file - case Ssl.SslErrorCode.SSL_ERROR_ZERO_RETURN: - break; - - case Ssl.SslErrorCode.SSL_ERROR_WANT_READ: - // update error code to renegotiate if renegotiate is pending, otherwise make it SSL_ERROR_WANT_READ - errorCode = Ssl.IsSslRenegotiatePending(context) ? - Ssl.SslErrorCode.SSL_ERROR_RENEGOTIATE : - Ssl.SslErrorCode.SSL_ERROR_WANT_READ; - break; - - default: - throw new SslException(SR.Format(SR.net_ssl_decrypt_failed, errorCode), innerError); - } + switch (errorCode) + { + // indicate end-of-file + case Ssl.SslErrorCode.SSL_ERROR_ZERO_RETURN: + break; + + case Ssl.SslErrorCode.SSL_ERROR_WANT_READ: + // update error code to renegotiate if renegotiate is pending, otherwise make it SSL_ERROR_WANT_READ + errorCode = Ssl.IsSslRenegotiatePending(context) ? + Ssl.SslErrorCode.SSL_ERROR_RENEGOTIATE : + Ssl.SslErrorCode.SSL_ERROR_WANT_READ; + break; + + default: + throw new SslException(SR.Format(SR.net_ssl_decrypt_failed, errorCode), innerError); } - - return retVal; - } - finally - { - context.InputBio.ResetBio(); } + + return retVal; } internal static SafeX509Handle GetPeerCertificate(SafeSslHandle context) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs index 3d40ee869f45..d6c9e63b56b0 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs @@ -306,14 +306,7 @@ public void SetBio(byte[] buffer, int offset, int length) Offset = offset; BytesAvailable = length; } - - public void ResetBio() - { - ByteArray = null; - Offset = 0; - BytesAvailable = 0; - } - + //Bio is already released by the ssl object private void Dispose(bool isDisposing) { @@ -352,22 +345,22 @@ internal WriteBioBuffer(SafeBioHandle bioHandle) public int StartOfFreeSpace { get; set; } public int TotalBytes { get; set; } - public void SetBio(byte[] buffer, int offset, int length) + public void SetBio(byte[] buffer) { ByteArray = buffer; - StartOfFreeSpace = offset; + StartOfFreeSpace = 0; TotalBytes = 0; - FreeSpace = length; + FreeSpace = buffer?.Length ?? 0; } - public void ResetBio() + public int TakeBytes() { - ByteArray = null; - StartOfFreeSpace = 0; + var bytes = TotalBytes; TotalBytes = 0; - FreeSpace = 0; + ByteArray = null; + return bytes == 0 ? -1 : bytes; } - + public void CheckSpaceOrIncrease(int sizeWanted) { if (ByteArray == null) diff --git a/src/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs b/src/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs index a0a4d65781a1..130e2b7dfa5c 100644 --- a/src/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs +++ b/src/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs @@ -150,6 +150,10 @@ private static SecurityStatusPal EncryptDecryptHelper(SafeDeleteContext security if (encrypt) { + if(output == null || output.Length < (size + 32 + 5)) + { + output = new byte[size + 32 + 5]; + } resultSize = Interop.OpenSsl.Encrypt(scHandle, input, offset, size, ref output, out errorCode); } else From d83a0910621cbefc1ea1c903c7365640a0226200 Mon Sep 17 00:00:00 2001 From: Drawaes Date: Sat, 5 Aug 2017 17:31:47 +0100 Subject: [PATCH 16/54] Changed the write to use a span --- .../Interop.BIO.Custom.cs | 23 ++------- .../Interop.OpenSsl.cs | 15 ++---- .../Interop.Ssl.cs | 49 +++++++++---------- 3 files changed, 30 insertions(+), 57 deletions(-) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs index 33a74caa349b..2de3d2ccb28a 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs @@ -105,30 +105,13 @@ private static unsafe long Control(IntPtr bio, Crypto.BIO_CTRL cmd, long param, private static unsafe int Write(IntPtr bio, void* input, int size) { var handle = BioGetGCHandle(bio); - Debug.Assert(handle.IsAllocated); - if (!handle.IsAllocated) - { - return -1; - } - - var buffer = handle.Target as SafeSslHandle.WriteBioBuffer; - if (buffer == null) + if (handle.IsAllocated && handle.Target is SafeSslHandle.WriteBioBuffer buffer) { - Crypto.BioSetFlags(bio, Crypto.BIO_FLAGS.BIO_FLAGS_NONE); - return -1; + return buffer.Write(new Span(input, size)); } - buffer.CheckSpaceOrIncrease(size); - fixed (byte* bPtr = buffer.ByteArray) - { - var offsetPtr = bPtr + buffer.StartOfFreeSpace; - Buffer.MemoryCopy(input, offsetPtr, buffer.FreeSpace, size); - buffer.StartOfFreeSpace += size; - buffer.FreeSpace -= size; - buffer.TotalBytes += size; - return size; - } + return -1; } private static unsafe int Read(IntPtr bio, void* output, int size) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs index 7daca5b7f335..c5d980e06cbd 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs @@ -136,10 +136,9 @@ internal static bool DoSslHandshake(SafeSslHandle context, byte[] recvBuf, int r sendBuf = null; sendCount = 0; - if (recvBuf == null && context.OutputBio.TotalBytes > 0) + sendCount = context.OutputBio.TakeBytes(out sendBuf); + if (recvBuf == null && sendCount > 0) { - sendBuf = context.OutputBio.ByteArray; - sendCount = context.OutputBio.TakeBytes(); return false; } @@ -159,12 +158,8 @@ internal static bool DoSslHandshake(SafeSslHandle context, byte[] recvBuf, int r } } - if (context.OutputBio.ByteArray != null) - { - sendBuf = context.OutputBio.ByteArray; - sendCount = context.OutputBio.TakeBytes(); - } - + sendCount = context.OutputBio.TakeBytes(out sendBuf); + bool stateOk = Ssl.IsSslStateOK(context); if (stateOk) { @@ -210,7 +205,7 @@ internal static int Encrypt(SafeSslHandle context, byte[] input, int offset, int throw new SslException(SR.Format(SR.net_ssl_encrypt_failed, errorCode), innerError); } } - return context.OutputBio.TakeBytes(); + return context.OutputBio.TakeBytes(out output); } internal static int Decrypt(SafeSslHandle context, byte[] outBuffer, int offset, int count, out Ssl.SslErrorCode errorCode) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs index d6c9e63b56b0..c0639aaa03fc 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs @@ -4,6 +4,7 @@ using System; using System.Diagnostics; +using System.Runtime; using System.Runtime.InteropServices; using System.Security.Cryptography.X509Certificates; using Microsoft.Win32.SafeHandles; @@ -332,6 +333,8 @@ internal class WriteBioBuffer :IDisposable { private SafeBioHandle _bioHandle; private GCHandle _handle; + private byte[] _byteArray; + private int _bytesWritten; internal WriteBioBuffer(SafeBioHandle bioHandle) { @@ -339,46 +342,38 @@ internal WriteBioBuffer(SafeBioHandle bioHandle) _handle = GCHandle.Alloc(this, GCHandleType.Normal); Interop.CustomBio.BioSetGCHandle(_bioHandle, _handle); } - - public int FreeSpace { get; set; } - public byte[] ByteArray { get; private set; } - public int StartOfFreeSpace { get; set; } - public int TotalBytes { get; set; } - + public void SetBio(byte[] buffer) { - ByteArray = buffer; - StartOfFreeSpace = 0; - TotalBytes = 0; - FreeSpace = buffer?.Length ?? 0; + _byteArray = buffer; + _bytesWritten = 0; } - public int TakeBytes() + public int TakeBytes(out byte[] output) { - var bytes = TotalBytes; - TotalBytes = 0; - ByteArray = null; - return bytes == 0 ? -1 : bytes; + var bytes = _bytesWritten; + output = _byteArray; + _bytesWritten = 0; + _byteArray = null; + return bytes; } - public void CheckSpaceOrIncrease(int sizeWanted) + public int Write(Span input) { - if (ByteArray == null) + if(_byteArray == null) { - ByteArray = new byte[sizeWanted]; - FreeSpace = sizeWanted; - TotalBytes = 0; - StartOfFreeSpace = 0; + _byteArray = new byte[input.Length]; } - else if (FreeSpace < sizeWanted) + else if (_byteArray.Length - _bytesWritten < intput.Length) { - var newArray = new byte[ByteArray.Length + (sizeWanted - FreeSpace)]; - FreeSpace = sizeWanted; - Array.Copy(ByteArray, newArray, ByteArray.Length); - ByteArray = newArray; + var oldSpan = new Span(_byteArray); + _byteArray = new byte[input.Length + _bytesWritten]; + oldSpan.CopyTo(_byteArray); } + input.CopyTo(_byteArray, _bytesWritten); + return input.Length; } - + //Bio is already released by the ssl object private void Dispose(bool isDisposing) { From 05b412b9070afc1a07b342ece7c35c1a0ecf0394 Mon Sep 17 00:00:00 2001 From: Drawaes Date: Sat, 5 Aug 2017 17:37:36 +0100 Subject: [PATCH 17/54] Typo, intput --- .../Unix/System.Security.Cryptography.Native/Interop.Ssl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs index c0639aaa03fc..e47b97a49fbc 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs @@ -364,7 +364,7 @@ public int Write(Span input) { _byteArray = new byte[input.Length]; } - else if (_byteArray.Length - _bytesWritten < intput.Length) + else if (_byteArray.Length - _bytesWritten < input.Length) { var oldSpan = new Span(_byteArray); _byteArray = new byte[input.Length + _bytesWritten]; From 56a7e4373433756c6f9082f8bb7e11d95f1f4a40 Mon Sep 17 00:00:00 2001 From: Drawaes Date: Sat, 5 Aug 2017 17:45:06 +0100 Subject: [PATCH 18/54] Fix span copyto --- .../Unix/System.Security.Cryptography.Native/Interop.Ssl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs index e47b97a49fbc..d279dcfdde68 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs @@ -370,7 +370,7 @@ public int Write(Span input) _byteArray = new byte[input.Length + _bytesWritten]; oldSpan.CopyTo(_byteArray); } - input.CopyTo(_byteArray, _bytesWritten); + input.CopyTo(new Span(_byteArray, _bytesWritten)); return input.Length; } From e6dd27ede118fae201eb8676595148cc06b6c6a1 Mon Sep 17 00:00:00 2001 From: Drawaes Date: Sat, 5 Aug 2017 17:57:10 +0100 Subject: [PATCH 19/54] Added length update --- .../Unix/System.Security.Cryptography.Native/Interop.Ssl.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs index d279dcfdde68..1f0043fc9d55 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs @@ -371,6 +371,7 @@ public int Write(Span input) oldSpan.CopyTo(_byteArray); } input.CopyTo(new Span(_byteArray, _bytesWritten)); + _bytesWritten += input.Length; return input.Length; } From 93e0ad997b2ede24a430e91a0ca5bd139191e5ca Mon Sep 17 00:00:00 2001 From: Drawaes Date: Sat, 5 Aug 2017 18:07:48 +0100 Subject: [PATCH 20/54] Change the pinnable write buffer pool size and the max message size to the upper limit of TLS --- .../src/System/Net/Security/SslStreamInternal.cs | 2 +- .../src/System/Net/Security/SslStreamPal.Unix.cs | 4 ---- .../src/System/Net/Security/StreamSizes.Unix.cs | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs b/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs index 7b11fb88f6ce..b5921ce68a9c 100644 --- a/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs +++ b/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs @@ -23,7 +23,7 @@ internal class SslStreamInternal private const int PinnableReadBufferSize = 4096 * 4 + 32; // We read in 16K chunks + headers. private static PinnableBufferCache s_PinnableReadBufferCache = new PinnableBufferCache("System.Net.SslStream", PinnableReadBufferSize); - private const int PinnableWriteBufferSize = 4096 + 1024; // We write in 4K chunks + encryption overhead. + private const int PinnableWriteBufferSize = 1024 * 16 + 5 + 32; // We write in 4K chunks + encryption overhead. private static PinnableBufferCache s_PinnableWriteBufferCache = new PinnableBufferCache("System.Net.SslStream", PinnableWriteBufferSize); private SslState _sslState; diff --git a/src/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs b/src/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs index 130e2b7dfa5c..a0a4d65781a1 100644 --- a/src/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs +++ b/src/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs @@ -150,10 +150,6 @@ private static SecurityStatusPal EncryptDecryptHelper(SafeDeleteContext security if (encrypt) { - if(output == null || output.Length < (size + 32 + 5)) - { - output = new byte[size + 32 + 5]; - } resultSize = Interop.OpenSsl.Encrypt(scHandle, input, offset, size, ref output, out errorCode); } else diff --git a/src/System.Net.Security/src/System/Net/Security/StreamSizes.Unix.cs b/src/System.Net.Security/src/System/Net/Security/StreamSizes.Unix.cs index 58025fa76032..b014a6d7c2d2 100644 --- a/src/System.Net.Security/src/System/Net/Security/StreamSizes.Unix.cs +++ b/src/System.Net.Security/src/System/Net/Security/StreamSizes.Unix.cs @@ -24,7 +24,7 @@ public StreamSizes() { Header = 0; Trailer = 0; - MaximumMessage = 32 * 1024; + MaximumMessage = 16 * 1024; } } } From 7904f68f072ac5a32b6aadf068150addc7ebbff6 Mon Sep 17 00:00:00 2001 From: Drawaes Date: Sat, 5 Aug 2017 18:33:39 +0100 Subject: [PATCH 21/54] Remove some flag settings --- .../Interop.BIO.Custom.cs | 6 ------ .../Unix/System.Security.Cryptography.Native/Interop.BIO.cs | 2 +- .../Unix/System.Security.Cryptography.Native/Interop.Ssl.cs | 1 + 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs index 2de3d2ccb28a..e758aa3ba7ec 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs @@ -126,12 +126,10 @@ private static unsafe int Read(IntPtr bio, void* output, int size) if (buffer == null) { - Crypto.BioSetFlags(bio, Crypto.BIO_FLAGS.BIO_FLAGS_NONE); return -1; } if (buffer.ByteArray == null || buffer.BytesAvailable == 0) { - Crypto.BioSetFlags(bio, Crypto.BIO_FLAGS.BIO_FLAGS_READ | Crypto.BIO_FLAGS.BIO_FLAGS_SHOULD_RETRY); return -1; } fixed (byte* bPtr = buffer.ByteArray) @@ -141,10 +139,6 @@ private static unsafe int Read(IntPtr bio, void* output, int size) Buffer.MemoryCopy(offsetPtr, output, size, bytesToCopy); buffer.BytesAvailable -= bytesToCopy; buffer.Offset += bytesToCopy; - if (bytesToCopy < size) - { - Crypto.BioSetFlags(bio, Crypto.BIO_FLAGS.BIO_FLAGS_READ | Crypto.BIO_FLAGS.BIO_FLAGS_SHOULD_RETRY); - } return bytesToCopy; } } diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.cs index ccd039b5f6ab..0f08ca084b76 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.cs @@ -46,7 +46,7 @@ internal static partial class Crypto internal static extern IntPtr BioGetAppData(IntPtr bio); [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_BioSetFlags")] - internal static extern IntPtr BioSetFlags(IntPtr bio, BIO_FLAGS flags); + internal static extern IntPtr BioSetFlags(SafeBioHandle bio, BIO_FLAGS flags); [Flags] internal enum BIO_FLAGS diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs index 1f0043fc9d55..1234beecb372 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs @@ -295,6 +295,7 @@ internal ReadBioBuffer(SafeBioHandle bioHandle) _bioHandle = bioHandle; _handle = GCHandle.Alloc(this, GCHandleType.Normal); Interop.CustomBio.BioSetGCHandle(_bioHandle, _handle); + Interop.Crypto.BioSetFlags(bioHandle, Interop.Crypto.BIO_FLAGS.BIO_FLAGS_READ | Interop.Crypto.BIO_FLAGS.BIO_FLAGS_SHOULD_RETRY); } public int BytesAvailable { get; set; } From bebfc150b489c83fd134ffdb07fdea62e0abbe4e Mon Sep 17 00:00:00 2001 From: Drawaes Date: Sat, 5 Aug 2017 18:57:45 +0100 Subject: [PATCH 22/54] Simplify the read bio --- .../Interop.BIO.Custom.cs | 25 +++---------------- .../Interop.Ssl.cs | 24 ++++++++++++------ 2 files changed, 20 insertions(+), 29 deletions(-) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs index e758aa3ba7ec..603729d01fbb 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs @@ -117,30 +117,11 @@ private static unsafe int Write(IntPtr bio, void* input, int size) private static unsafe int Read(IntPtr bio, void* output, int size) { var handle = BioGetGCHandle(bio); - Debug.Assert(handle.IsAllocated); - if (!handle.IsAllocated) + if (handle.IsAllocated && handle.Target is SafeSslHandle.ReadBioBuffer buffer) { - return -1; - } - var buffer = handle.Target as SafeSslHandle.ReadBioBuffer; - - if (buffer == null) - { - return -1; - } - if (buffer.ByteArray == null || buffer.BytesAvailable == 0) - { - return -1; - } - fixed (byte* bPtr = buffer.ByteArray) - { - var offsetPtr = bPtr + buffer.Offset; - var bytesToCopy = Math.Min(size, buffer.BytesAvailable); - Buffer.MemoryCopy(offsetPtr, output, size, bytesToCopy); - buffer.BytesAvailable -= bytesToCopy; - buffer.Offset += bytesToCopy; - return bytesToCopy; + return buffer.Read(new Span(output, size)); } + return -1; } [Flags] diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs index 1234beecb372..bb7a6f03df13 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs @@ -289,6 +289,9 @@ internal class ReadBioBuffer : IDisposable { private SafeBioHandle _bioHandle; private GCHandle _handle; + private int _bytesAvailable; + private byte[] _byteArray; + private int _offset; internal ReadBioBuffer(SafeBioHandle bioHandle) { @@ -298,15 +301,22 @@ internal ReadBioBuffer(SafeBioHandle bioHandle) Interop.Crypto.BioSetFlags(bioHandle, Interop.Crypto.BIO_FLAGS.BIO_FLAGS_READ | Interop.Crypto.BIO_FLAGS.BIO_FLAGS_SHOULD_RETRY); } - public int BytesAvailable { get; set; } - public byte[] ByteArray { get; private set; } - public int Offset { get; set; } - public void SetBio(byte[] buffer, int offset, int length) { - ByteArray = buffer; - Offset = offset; - BytesAvailable = length; + _byteArray = buffer; + _offset = offset; + _bytesAvailable = length; + } + + public int Read(Span output) + { + var bytesToCopy = Math.Min(output.Length, _bytesAvailable); + if (bytesToCopy == 0) return -1; + var span = new Span(_byteArray, _offset, bytesToCopy); + span.CopyTo(output); + _offset += bytesToCopy; + _bytesAvailable -= bytesToCopy; + return bytesToCopy; } //Bio is already released by the ssl object From 6033a15ef74fcb9f1adb51cbd94e523179f9beae Mon Sep 17 00:00:00 2001 From: Drawaes Date: Sun, 6 Aug 2017 11:30:08 +0100 Subject: [PATCH 23/54] Changed the write path to allow for multiple writes to the output buffer --- .../Interop.OpenSsl.cs | 12 ++++++-- .../Interop.Ssl.cs | 30 +++++++++++-------- .../Interop.SslCtxOptions.cs | 3 ++ .../opensslshim.h | 2 ++ .../pal_ssl.cpp | 5 ++++ .../pal_ssl.h | 5 ++++ .../System.Net.Security.sln | 19 +++++++----- .../src/System/Net/Security/SecureChannel.cs | 25 +++++++++------- .../System/Net/Security/SslStreamInternal.cs | 6 +++- .../System/Net/Security/SslStreamPal.Unix.cs | 2 ++ 10 files changed, 74 insertions(+), 35 deletions(-) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs index c5d980e06cbd..37f463eb2071 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs @@ -73,6 +73,10 @@ internal static SafeSslHandle AllocateSslContext(SslProtocols protocols, SafeX50 // https://www.openssl.org/docs/manmaster/ssl/SSL_shutdown.html Ssl.SslCtxSetQuietShutdown(innerContext); + // This allows the write buffer to move during a multi call write, this stops us having to pin it + // across multiple calls where there is an async output to the innerstream inbetween + Ssl.SslCtxSetAcceptMovingWriteBuffer(innerContext); + if (!Ssl.SetEncryptionPolicy(innerContext, policy)) { throw new PlatformNotSupportedException(SR.Format(SR.net_ssl_encryptionpolicy_notsupported, policy)); @@ -143,7 +147,7 @@ internal static bool DoSslHandshake(SafeSslHandle context, byte[] recvBuf, int r } context.InputBio.SetBio(recvBuf, recvOffset, recvCount); - context.OutputBio.SetBio(null); + context.OutputBio.SetBio(null, true); int retVal = Ssl.SslDoHandshake(context); @@ -177,7 +181,7 @@ internal static int Encrypt(SafeSslHandle context, byte[] input, int offset, int Debug.Assert(input.Length - offset >= count); errorCode = Ssl.SslErrorCode.SSL_ERROR_NONE; - context.OutputBio.SetBio(output); + context.OutputBio.SetBio(output, false); int retVal; unsafe @@ -200,7 +204,9 @@ internal static int Encrypt(SafeSslHandle context, byte[] input, int offset, int case Ssl.SslErrorCode.SSL_ERROR_ZERO_RETURN: case Ssl.SslErrorCode.SSL_ERROR_WANT_READ: break; - + //indicates we need to write the out buffer and write again + case Ssl.SslErrorCode.SSL_ERROR_WANT_WRITE: + break; default: throw new SslException(SR.Format(SR.net_ssl_encrypt_failed, errorCode), innerError); } diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs index bb7a6f03df13..d50776839e73 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs @@ -346,6 +346,7 @@ internal class WriteBioBuffer :IDisposable private GCHandle _handle; private byte[] _byteArray; private int _bytesWritten; + private bool _isHandshake; internal WriteBioBuffer(SafeBioHandle bioHandle) { @@ -354,10 +355,11 @@ internal WriteBioBuffer(SafeBioHandle bioHandle) Interop.CustomBio.BioSetGCHandle(_bioHandle, _handle); } - public void SetBio(byte[] buffer) + public void SetBio(byte[] buffer, bool isHandshake) { _byteArray = buffer; _bytesWritten = 0; + _isHandshake = isHandshake; } public int TakeBytes(out byte[] output) @@ -371,19 +373,23 @@ public int TakeBytes(out byte[] output) public int Write(Span input) { - if(_byteArray == null) + if (_isHandshake) { - _byteArray = new byte[input.Length]; + if (_byteArray == null) + { + _byteArray = new byte[input.Length]; + } + else if (_byteArray.Length - _bytesWritten < input.Length) + { + var oldSpan = new Span(_byteArray); + _byteArray = new byte[input.Length + _bytesWritten]; + oldSpan.CopyTo(_byteArray); + } } - else if (_byteArray.Length - _bytesWritten < input.Length) - { - var oldSpan = new Span(_byteArray); - _byteArray = new byte[input.Length + _bytesWritten]; - oldSpan.CopyTo(_byteArray); - } - input.CopyTo(new Span(_byteArray, _bytesWritten)); - _bytesWritten += input.Length; - return input.Length; + var bytesToWrite = Math.Min(input.Length, input.Length - _bytesWritten); + input.Slice(0, bytesToWrite).CopyTo(new Span(_byteArray, _bytesWritten)); + _bytesWritten += bytesToWrite; + return bytesToWrite; } //Bio is already released by the ssl object diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.SslCtxOptions.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.SslCtxOptions.cs index 3ab95d491ed1..29951bc69d33 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.SslCtxOptions.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.SslCtxOptions.cs @@ -35,5 +35,8 @@ internal static partial class Ssl [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslCtxSetClientCAList")] internal static extern void SslCtxSetClientCAList(SafeSslContextHandle ctx, SafeX509NameStackHandle x509NameStackPtr); + + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslCtxSetAcceptMovingWriteBuffer")] + internal static extern void SslCtxSetAcceptMovingWriteBuffer(SafeSslContextHandle ctx); } } diff --git a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h index 58cc2a7c1551..39abdc35bd17 100644 --- a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +++ b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h @@ -255,6 +255,7 @@ int EC_POINT_set_affine_coordinates_GF2m(const EC_GROUP *group, EC_POINT *p, PER_FUNCTION_BLOCK(SSL_CTX_free, true) \ PER_FUNCTION_BLOCK(SSL_CTX_new, true) \ PER_FUNCTION_BLOCK(SSL_CTX_set_cert_verify_callback, true) \ + PER_FUNCTION_BLOCK(SSL_CTX_set_mode, true) \ PER_FUNCTION_BLOCK(SSL_CTX_set_cipher_list, true) \ PER_FUNCTION_BLOCK(SSL_CTX_set_client_CA_list, true) \ PER_FUNCTION_BLOCK(SSL_CTX_set_client_cert_cb, true) \ @@ -548,6 +549,7 @@ FOR_ALL_OPENSSL_FUNCTIONS #define SSL_CTX_ctrl SSL_CTX_ctrl_ptr #define SSL_CTX_free SSL_CTX_free_ptr #define SSL_CTX_new SSL_CTX_new_ptr +#define SSL_CTX_set_mode SSL_CTX_set_mode_ptr #define SSL_CTX_set_cert_verify_callback SSL_CTX_set_cert_verify_callback_ptr #define SSL_CTX_set_cipher_list SSL_CTX_set_cipher_list_ptr #define SSL_CTX_set_client_CA_list SSL_CTX_set_client_CA_list_ptr diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_ssl.cpp b/src/Native/Unix/System.Security.Cryptography.Native/pal_ssl.cpp index fda1f4da9537..45cd1b19443b 100644 --- a/src/Native/Unix/System.Security.Cryptography.Native/pal_ssl.cpp +++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_ssl.cpp @@ -41,6 +41,11 @@ extern "C" SSL_CTX* CryptoNative_SslCtxCreate(SSL_METHOD* method) return ctx; } +extern "C" void CryptoNative_SslCtxSetAcceptMovingWriteBuffer(SSL_CTX* ctx) +{ + SSL_CTX_set_mode(ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); +} + extern "C" void CryptoNative_SetProtocolOptions(SSL_CTX* ctx, SslProtocols protocols) { // protocols may be 0, meaning system default, in which case let OpenSSL do what OpenSSL wants. diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_ssl.h b/src/Native/Unix/System.Security.Cryptography.Native/pal_ssl.h index 4fd7fb59c051..c69adde07d44 100644 --- a/src/Native/Unix/System.Security.Cryptography.Native/pal_ssl.h +++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_ssl.h @@ -177,6 +177,11 @@ Always succeeds. */ extern "C" void CryptoNative_SslCtxDestroy(SSL_CTX* ctx); +/* +Shims the SSL_ctx_change_mode with the flag SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER +*/ +extern "C" void CryptoNative_SslCtxSetAcceptMovingWriteBuffer(SSL_CTX* ctx); + /* Shims the SSL_set_connect_state method. */ diff --git a/src/System.Net.Security/System.Net.Security.sln b/src/System.Net.Security/System.Net.Security.sln index 7661a942233e..d94c6e4cdac7 100644 --- a/src/System.Net.Security/System.Net.Security.sln +++ b/src/System.Net.Security/System.Net.Security.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 +# Visual Studio 15 +VisualStudioVersion = 15.0.26711.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Net.Security.Tests", "tests\FunctionalTests\System.Net.Security.Tests.csproj", "{A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}" ProjectSection(ProjectDependencies) = postProject @@ -31,16 +31,16 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.Debug|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Debug|Any CPU - {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.Debug|Any CPU.Build.0 = netcoreapp-Windows_NT-Debug|Any CPU + {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.Debug|Any CPU.ActiveCfg = netcoreapp-Unix-Debug|Any CPU + {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.Debug|Any CPU.Build.0 = netcoreapp-Unix-Debug|Any CPU {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|Any CPU {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.Release|Any CPU.Build.0 = netcoreapp-Windows_NT-Release|Any CPU - {0D174EA9-9E61-4519-8D31-7BD2331A1982}.Debug|Any CPU.ActiveCfg = netstandard-Windows_NT-Debug|Any CPU - {0D174EA9-9E61-4519-8D31-7BD2331A1982}.Debug|Any CPU.Build.0 = netstandard-Windows_NT-Debug|Any CPU + {0D174EA9-9E61-4519-8D31-7BD2331A1982}.Debug|Any CPU.ActiveCfg = netstandard-Unix-Debug|Any CPU + {0D174EA9-9E61-4519-8D31-7BD2331A1982}.Debug|Any CPU.Build.0 = netstandard-Unix-Debug|Any CPU {0D174EA9-9E61-4519-8D31-7BD2331A1982}.Release|Any CPU.ActiveCfg = netstandard-Windows_NT-Release|Any CPU {0D174EA9-9E61-4519-8D31-7BD2331A1982}.Release|Any CPU.Build.0 = netstandard-Windows_NT-Release|Any CPU - {89F37791-6254-4D60-AB96-ACD3CCA0E771}.Debug|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Debug|Any CPU - {89F37791-6254-4D60-AB96-ACD3CCA0E771}.Debug|Any CPU.Build.0 = netcoreapp-Windows_NT-Debug|Any CPU + {89F37791-6254-4D60-AB96-ACD3CCA0E771}.Debug|Any CPU.ActiveCfg = netcoreapp-Unix-Debug|Any CPU + {89F37791-6254-4D60-AB96-ACD3CCA0E771}.Debug|Any CPU.Build.0 = netcoreapp-Unix-Debug|Any CPU {89F37791-6254-4D60-AB96-ACD3CCA0E771}.Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|Any CPU {89F37791-6254-4D60-AB96-ACD3CCA0E771}.Release|Any CPU.Build.0 = netcoreapp-Windows_NT-Release|Any CPU {A7488FC0-9A8F-4EF9-BC3E-C5EBA47E13F8}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU @@ -57,4 +57,7 @@ Global {89F37791-6254-4D60-AB96-ACD3CCA0E771} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} {A7488FC0-9A8F-4EF9-BC3E-C5EBA47E13F8} = {2E666815-2EDB-464B-9DF6-380BF4789AD4} EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {1798D82D-8D02-431F-A7C8-56D76A267DF6} + EndGlobalSection EndGlobal diff --git a/src/System.Net.Security/src/System/Net/Security/SecureChannel.cs b/src/System.Net.Security/src/System/Net/Security/SecureChannel.cs index f623b2fdbf55..e6617e6fa8ef 100644 --- a/src/System.Net.Security/src/System/Net/Security/SecureChannel.cs +++ b/src/System.Net.Security/src/System/Net/Security/SecureChannel.cs @@ -905,8 +905,6 @@ internal SecurityStatusPal Encrypt(byte[] buffer, int offset, int size, ref byte NetEventSource.DumpBuffer(this, buffer, 0, Math.Min(buffer.Length, 128)); } - byte[] writeBuffer = output; - try { if (offset < 0 || offset > (buffer == null ? 0 : buffer.Length)) @@ -934,19 +932,24 @@ internal SecurityStatusPal Encrypt(byte[] buffer, int offset, int size, ref byte size, _headerSize, _trailerSize, - ref writeBuffer, + ref output, out resultSize); - if (secStatus.ErrorCode != SecurityStatusPalErrorCode.OK) - { - if (NetEventSource.IsEnabled) NetEventSource.Exit(this, $"ERROR {secStatus}"); - } - else + if (NetEventSource.IsEnabled) { - output = writeBuffer; - if (NetEventSource.IsEnabled) NetEventSource.Exit(this, $"OK data size:{resultSize}"); + switch (secStatus.ErrorCode) + { + case SecurityStatusPalErrorCode.OK: + NetEventSource.Exit($"OK data size:{resultSize}"); + break; + case SecurityStatusPalErrorCode.ContinueNeeded: + NetEventSource.Exit(this, $"OK but more writes needed data size:{ resultSize}"); + break; + default: + NetEventSource.Exit(this, $"ERROR {secStatus}"); + break; + } } - return secStatus; } diff --git a/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs b/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs index b5921ce68a9c..dfdd563c476d 100644 --- a/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs +++ b/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs @@ -417,7 +417,11 @@ private void StartWriting(byte[] buffer, int offset, int count, AsyncProtocolReq int chunkBytes = Math.Min(count, _sslState.MaxDataSize); int encryptedBytes; SecurityStatusPal status = _sslState.EncryptData(buffer, offset, chunkBytes, ref outBuffer, out encryptedBytes); - if (status.ErrorCode != SecurityStatusPalErrorCode.OK) + if(status.ErrorCode != SecurityStatusPalErrorCode.ContinueNeeded) + { + chunkBytes = 0; + } + else if (status.ErrorCode != SecurityStatusPalErrorCode.OK) { // Re-handshake status is not supported. ProtocolToken message = new ProtocolToken(null, status); diff --git a/src/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs b/src/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs index a0a4d65781a1..bf9cabbc19d7 100644 --- a/src/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs +++ b/src/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs @@ -167,6 +167,8 @@ private static SecurityStatusPal EncryptDecryptHelper(SafeDeleteContext security case Interop.Ssl.SslErrorCode.SSL_ERROR_NONE: case Interop.Ssl.SslErrorCode.SSL_ERROR_WANT_READ: return new SecurityStatusPal(SecurityStatusPalErrorCode.OK); + case Interop.Ssl.SslErrorCode.SSL_ERROR_WANT_WRITE: + return new SecurityStatusPal(SecurityStatusPalErrorCode.ContinueNeeded); default: return new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, new Interop.OpenSsl.SslException((int)errorCode)); } From f4c0005528f28677e1e116a4ccf0dea3e4d3479f Mon Sep 17 00:00:00 2001 From: Drawaes Date: Sun, 6 Aug 2017 11:54:41 +0100 Subject: [PATCH 24/54] Resetting the pinned buffers to the original size --- .../src/System/Net/Security/SslStreamInternal.cs | 2 +- .../src/System/Net/Security/StreamSizes.Unix.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs b/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs index dfdd563c476d..42d446d0e0b4 100644 --- a/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs +++ b/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs @@ -23,7 +23,7 @@ internal class SslStreamInternal private const int PinnableReadBufferSize = 4096 * 4 + 32; // We read in 16K chunks + headers. private static PinnableBufferCache s_PinnableReadBufferCache = new PinnableBufferCache("System.Net.SslStream", PinnableReadBufferSize); - private const int PinnableWriteBufferSize = 1024 * 16 + 5 + 32; // We write in 4K chunks + encryption overhead. + private const int PinnableWriteBufferSize = 4096 + 1024; // We write in 4K chunks + encryption overhead. private static PinnableBufferCache s_PinnableWriteBufferCache = new PinnableBufferCache("System.Net.SslStream", PinnableWriteBufferSize); private SslState _sslState; diff --git a/src/System.Net.Security/src/System/Net/Security/StreamSizes.Unix.cs b/src/System.Net.Security/src/System/Net/Security/StreamSizes.Unix.cs index b014a6d7c2d2..58025fa76032 100644 --- a/src/System.Net.Security/src/System/Net/Security/StreamSizes.Unix.cs +++ b/src/System.Net.Security/src/System/Net/Security/StreamSizes.Unix.cs @@ -24,7 +24,7 @@ public StreamSizes() { Header = 0; Trailer = 0; - MaximumMessage = 16 * 1024; + MaximumMessage = 32 * 1024; } } } From b4d2301dc15c413c9a9807e8f1f09ad0d2fcd4f4 Mon Sep 17 00:00:00 2001 From: bench Date: Sun, 6 Aug 2017 20:38:21 +0100 Subject: [PATCH 25/54] Changed pinnable buffers on write to use one for the write then return it --- .../Interop.BIO.Custom.cs | 0 .../Interop.BIO.cs | 0 .../Interop.OpenSsl.cs | 0 .../Interop.Ssl.cs | 20 ++-- .../src/System.Net.Security.csproj | 0 .../src/System/Net/Security/SecureChannel.cs | 15 ++- .../System/Net/Security/SslStreamInternal.cs | 101 +++++++----------- .../System/Net/Security/SslStreamPal.Unix.cs | 0 .../System/Net/Security/StreamSizes.Unix.cs | 0 9 files changed, 59 insertions(+), 77 deletions(-) mode change 100644 => 100755 src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs mode change 100644 => 100755 src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.cs mode change 100644 => 100755 src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs mode change 100644 => 100755 src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs mode change 100644 => 100755 src/System.Net.Security/src/System.Net.Security.csproj mode change 100644 => 100755 src/System.Net.Security/src/System/Net/Security/SecureChannel.cs mode change 100644 => 100755 src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs mode change 100644 => 100755 src/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs mode change 100644 => 100755 src/System.Net.Security/src/System/Net/Security/StreamSizes.Unix.cs diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs old mode 100644 new mode 100755 diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.cs old mode 100644 new mode 100755 diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs old mode 100644 new mode 100755 diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs old mode 100644 new mode 100755 index d50776839e73..00b32fbde745 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs @@ -183,7 +183,7 @@ public bool IsServer public ReadBioBuffer InputBio => _readBio; public WriteBioBuffer OutputBio => _writeBio; - + internal void MarkHandshakeCompleted() { _handshakeCompleted = true; @@ -318,7 +318,7 @@ public int Read(Span output) _bytesAvailable -= bytesToCopy; return bytesToCopy; } - + //Bio is already released by the ssl object private void Dispose(bool isDisposing) { @@ -340,7 +340,7 @@ public void Dispose() } } - internal class WriteBioBuffer :IDisposable + internal class WriteBioBuffer : IDisposable { private SafeBioHandle _bioHandle; private GCHandle _handle; @@ -354,7 +354,7 @@ internal WriteBioBuffer(SafeBioHandle bioHandle) _handle = GCHandle.Alloc(this, GCHandleType.Normal); Interop.CustomBio.BioSetGCHandle(_bioHandle, _handle); } - + public void SetBio(byte[] buffer, bool isHandshake) { _byteArray = buffer; @@ -370,7 +370,7 @@ public int TakeBytes(out byte[] output) _byteArray = null; return bytes; } - + public int Write(Span input) { if (_isHandshake) @@ -378,6 +378,7 @@ public int Write(Span input) if (_byteArray == null) { _byteArray = new byte[input.Length]; + _bytesWritten = 0; } else if (_byteArray.Length - _bytesWritten < input.Length) { @@ -386,12 +387,17 @@ public int Write(Span input) oldSpan.CopyTo(_byteArray); } } - var bytesToWrite = Math.Min(input.Length, input.Length - _bytesWritten); + var bytesToWrite = Math.Min(input.Length, _byteArray.Length - _bytesWritten); + if (bytesToWrite < 1) + { + Interop.Crypto.BioSetFlags(_bioHandle, Interop.Crypto.BIO_FLAGS.BIO_FLAGS_WRITE); + return -1; + } input.Slice(0, bytesToWrite).CopyTo(new Span(_byteArray, _bytesWritten)); _bytesWritten += bytesToWrite; return bytesToWrite; } - + //Bio is already released by the ssl object private void Dispose(bool isDisposing) { diff --git a/src/System.Net.Security/src/System.Net.Security.csproj b/src/System.Net.Security/src/System.Net.Security.csproj old mode 100644 new mode 100755 diff --git a/src/System.Net.Security/src/System/Net/Security/SecureChannel.cs b/src/System.Net.Security/src/System/Net/Security/SecureChannel.cs old mode 100644 new mode 100755 index e6617e6fa8ef..15a5f9ecb13a --- a/src/System.Net.Security/src/System/Net/Security/SecureChannel.cs +++ b/src/System.Net.Security/src/System/Net/Security/SecureChannel.cs @@ -83,7 +83,7 @@ internal SecureChannel(string hostname, bool serverMode, SslProtocols sslProtoco _certSelectionDelegate = certSelectionDelegate; _refreshCredentialNeeded = true; _encryptionPolicy = encryptionPolicy; - + if (NetEventSource.IsEnabled) NetEventSource.Exit(this); } @@ -845,7 +845,7 @@ private SecurityStatusPal GenerateToken(byte[] input, int offset, int count, ref } output = outgoingSecurity.token; - + return status; } @@ -934,16 +934,15 @@ internal SecurityStatusPal Encrypt(byte[] buffer, int offset, int size, ref byte _trailerSize, ref output, out resultSize); - if (NetEventSource.IsEnabled) { switch (secStatus.ErrorCode) { case SecurityStatusPalErrorCode.OK: - NetEventSource.Exit($"OK data size:{resultSize}"); + NetEventSource.Exit(this, $"OK data size:{resultSize}"); break; case SecurityStatusPalErrorCode.ContinueNeeded: - NetEventSource.Exit(this, $"OK but more writes needed data size:{ resultSize}"); + NetEventSource.Exit(this, $"OK but more writes needed data size:{resultSize}"); break; default: NetEventSource.Exit(this, $"ERROR {secStatus}"); @@ -1154,7 +1153,7 @@ private ProtocolToken GenerateAlertToken() return token; } - + private static TlsAlertMessage GetAlertMessageFromChain(X509Chain chain) { foreach (X509ChainStatus chainStatus in chain.ChainStatus) @@ -1172,7 +1171,7 @@ private static TlsAlertMessage GetAlertMessageFromChain(X509Chain chain) } if ((chainStatus.Status & - (X509ChainStatusFlags.Revoked | X509ChainStatusFlags.OfflineRevocation )) != 0) + (X509ChainStatusFlags.Revoked | X509ChainStatusFlags.OfflineRevocation)) != 0) { return TlsAlertMessage.CertificateRevoked; } @@ -1186,7 +1185,7 @@ private static TlsAlertMessage GetAlertMessageFromChain(X509Chain chain) if ((chainStatus.Status & X509ChainStatusFlags.CtlNotValidForUsage) != 0) { - return TlsAlertMessage.UnsupportedCert; + return TlsAlertMessage.UnsupportedCert; } if ((chainStatus.Status & diff --git a/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs b/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs old mode 100644 new mode 100755 index 42d446d0e0b4..129d9d7e1788 --- a/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs +++ b/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs @@ -31,14 +31,12 @@ internal class SslStreamInternal private int _nestedRead; private AsyncProtocolRequest _readProtocolRequest; // cached, reusable AsyncProtocolRequest used for read operations private AsyncProtocolRequest _writeProtocolRequest; // cached, reusable AsyncProtocolRequest used for write operations + private Action _freeBufferAction; // Never updated directly, special properties are used. This is the read buffer. private byte[] _internalBuffer; private bool _internalBufferFromPinnableCache; - private byte[] _pinnableOutputBuffer; // Used for writes when we can do it. - private byte[] _pinnableOutputBufferInUse; // Remembers what UNENCRYPTED buffer is using _PinnableOutputBuffer. - private int _internalOffset; private int _internalBufferCount; @@ -51,11 +49,11 @@ internal SslStreamInternal(SslState sslState) { PinnableBufferCacheEventSource.Log.DebugMessage1("CTOR: In System.Net._SslStream.SslStream", this.GetHashCode()); } - _sslState = sslState; _decryptedBytesOffset = 0; _decryptedBytesCount = 0; + _freeBufferAction = (_, buffer) => FreeBuffer((byte[])buffer); } // If we have a read buffer from the pinnable cache, return it. @@ -81,15 +79,6 @@ private void FreeReadBuffer() FreeReadBuffer(); } - if (_pinnableOutputBuffer != null) - { - if (PinnableBufferCacheEventSource.Log.IsEnabled()) - { - PinnableBufferCacheEventSource.Log.DebugMessage2("DTOR: In System.Net._SslStream.~SslStream Freeing Write Buffer", this.GetHashCode(), PinnableBufferCacheEventSource.AddressOfByteArray(_pinnableOutputBuffer)); - } - - s_PinnableWriteBufferCache.FreeBuffer(_pinnableOutputBuffer); - } } internal int ReadByte() @@ -325,7 +314,7 @@ private AsyncProtocolRequest GetOrCreateProtocolRequest(ref AsyncProtocolRequest // private void ProcessWrite(byte[] buffer, int offset, int count, LazyAsyncResult asyncResult) { - _sslState.CheckThrow(authSuccessCheck:true, shutdownCheck:true); + _sslState.CheckThrow(authSuccessCheck: true, shutdownCheck: true); ValidateParameters(buffer, offset, count); if (Interlocked.Exchange(ref _nestedWrite, 1) == 1) @@ -373,31 +362,8 @@ private void StartWriting(byte[] buffer, int offset, int count, AsyncProtocolReq // We loop to this method from the callback. // If the last chunk was just completed from async callback (count < 0), we complete user request. - if (count >= 0 ) + if (count >= 0) { - byte[] outBuffer = null; - if (_pinnableOutputBufferInUse == null) - { - if (_pinnableOutputBuffer == null) - { - _pinnableOutputBuffer = s_PinnableWriteBufferCache.AllocateBuffer(); - } - - _pinnableOutputBufferInUse = buffer; - outBuffer = _pinnableOutputBuffer; - if (PinnableBufferCacheEventSource.Log.IsEnabled()) - { - PinnableBufferCacheEventSource.Log.DebugMessage3("In System.Net._SslStream.StartWriting Trying Pinnable", this.GetHashCode(), count, PinnableBufferCacheEventSource.AddressOfByteArray(outBuffer)); - } - } - else - { - if (PinnableBufferCacheEventSource.Log.IsEnabled()) - { - PinnableBufferCacheEventSource.Log.DebugMessage2("In System.Net._SslStream.StartWriting BufferInUse", this.GetHashCode(), count); - } - } - do { if (count == 0 && !SslStreamPal.CanEncryptEmptyMessage) @@ -416,29 +382,39 @@ private void StartWriting(byte[] buffer, int offset, int count, AsyncProtocolReq int chunkBytes = Math.Min(count, _sslState.MaxDataSize); int encryptedBytes; - SecurityStatusPal status = _sslState.EncryptData(buffer, offset, chunkBytes, ref outBuffer, out encryptedBytes); - if(status.ErrorCode != SecurityStatusPalErrorCode.ContinueNeeded) + byte[] outBuffer = s_PinnableWriteBufferCache.AllocateBuffer(); + if (PinnableBufferCacheEventSource.Log.IsEnabled()) { - chunkBytes = 0; + PinnableBufferCacheEventSource.Log.DebugMessage3("In System.Net._SslStream.StartWriting Using Pinnable", this.GetHashCode(), count, PinnableBufferCacheEventSource.AddressOfByteArray(outBuffer)); } - else if (status.ErrorCode != SecurityStatusPalErrorCode.OK) + try { - // Re-handshake status is not supported. - ProtocolToken message = new ProtocolToken(null, status); - throw new IOException(SR.net_io_encrypt, message.GetException()); - } + SecurityStatusPal status = _sslState.EncryptData(buffer, offset, chunkBytes, ref outBuffer, out encryptedBytes); - if (PinnableBufferCacheEventSource.Log.IsEnabled()) + if (status.ErrorCode == SecurityStatusPalErrorCode.ContinueNeeded) + { + chunkBytes = 0; + } + else if (status.ErrorCode != SecurityStatusPalErrorCode.OK) + { + // Re-handshake status is not supported. + ProtocolToken message = new ProtocolToken(null, status); + throw new IOException(SR.net_io_encrypt, message.GetException()); + } + } + catch { - PinnableBufferCacheEventSource.Log.DebugMessage3("In System.Net._SslStream.StartWriting Got Encrypted Buffer", - this.GetHashCode(), encryptedBytes, PinnableBufferCacheEventSource.AddressOfByteArray(outBuffer)); + FreeBuffer(outBuffer); + throw; } + if (asyncRequest != null) { // Prepare for the next request. asyncRequest.SetNextRequest(buffer, offset + chunkBytes, count - chunkBytes, s_resumeAsyncWriteCallback); - Task t = _sslState.InnerStream.WriteAsync(outBuffer, 0, encryptedBytes); + Task t = _sslState.InnerStream.WriteAsync(outBuffer, 0, encryptedBytes) + .ContinueWith(_freeBufferAction, outBuffer); if (t.IsCompleted) { t.GetAwaiter().GetResult(); @@ -456,6 +432,7 @@ private void StartWriting(byte[] buffer, int offset, int count, AsyncProtocolReq else { _sslState.InnerStream.Write(outBuffer, 0, encryptedBytes); + FreeBuffer(outBuffer); } offset += chunkBytes; @@ -467,18 +444,18 @@ private void StartWriting(byte[] buffer, int offset, int count, AsyncProtocolReq } while (count != 0); } - if (asyncRequest != null) + if (asyncRequest != null) { asyncRequest.CompleteUser(); } + } - if (buffer == _pinnableOutputBufferInUse) + private void FreeBuffer(byte[] buffer) + { + s_PinnableWriteBufferCache.FreeBuffer(buffer); + if (PinnableBufferCacheEventSource.Log.IsEnabled()) { - _pinnableOutputBufferInUse = null; - if (PinnableBufferCacheEventSource.Log.IsEnabled()) - { - PinnableBufferCacheEventSource.Log.DebugMessage1("In System.Net._SslStream.StartWriting Freeing buffer.", this.GetHashCode()); - } + PinnableBufferCacheEventSource.Log.DebugMessage1("In System.Net._SslStream.StartWriting Freeing buffer.", this.GetHashCode()); } } @@ -656,7 +633,7 @@ private int ProcessRead(byte[] buffer, int offset, int count, BufferAsyncResult if (Interlocked.Exchange(ref _nestedRead, 1) == 1) { - throw new NotSupportedException(SR.Format(SR.net_io_invalidnestedcall, (asyncResult!=null? "BeginRead":"Read"), "read")); + throw new NotSupportedException(SR.Format(SR.net_io_invalidnestedcall, (asyncResult != null ? "BeginRead" : "Read"), "read")); } // If this is an async operation, get the AsyncProtocolRequest to use. @@ -670,9 +647,9 @@ private int ProcessRead(byte[] buffer, int offset, int count, BufferAsyncResult if (_decryptedBytesCount != 0) { int copyBytes = CopyDecryptedData(buffer, offset, count); - + asyncRequest?.CompleteUser(copyBytes); - + return copyBytes; } @@ -747,7 +724,7 @@ private int StartFrameHeader(byte[] buffer, int offset, int count, AsyncProtocol Debug.Assert(asyncRequest != null); return 0; } - + return StartFrameBody(readBytes, buffer, offset, count, asyncRequest); } @@ -776,7 +753,7 @@ private int StartFrameBody(int readBytes, byte[] buffer, int offset, int count, } Debug.Assert(readBytes == 0 || readBytes == SecureChannel.ReadHeaderSize + payloadBytes); - + return ProcessFrameBody(readBytes, buffer, offset, count, asyncRequest); } diff --git a/src/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs b/src/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs old mode 100644 new mode 100755 diff --git a/src/System.Net.Security/src/System/Net/Security/StreamSizes.Unix.cs b/src/System.Net.Security/src/System/Net/Security/StreamSizes.Unix.cs old mode 100644 new mode 100755 From f4dbc39b58fca8897ef9c8bb66e168612c2f25e0 Mon Sep 17 00:00:00 2001 From: Drawaes Date: Sun, 6 Aug 2017 21:42:02 +0100 Subject: [PATCH 26/54] Reset Sln Changes before PR Revert test trait changes --- .../System.Net.Security.sln | 19 ++++++++----------- .../SslStreamStreamToStreamTest.cs | 5 +---- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/System.Net.Security/System.Net.Security.sln b/src/System.Net.Security/System.Net.Security.sln index d94c6e4cdac7..7661a942233e 100644 --- a/src/System.Net.Security/System.Net.Security.sln +++ b/src/System.Net.Security/System.Net.Security.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26711.1 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Net.Security.Tests", "tests\FunctionalTests\System.Net.Security.Tests.csproj", "{A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}" ProjectSection(ProjectDependencies) = postProject @@ -31,16 +31,16 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.Debug|Any CPU.ActiveCfg = netcoreapp-Unix-Debug|Any CPU - {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.Debug|Any CPU.Build.0 = netcoreapp-Unix-Debug|Any CPU + {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.Debug|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Debug|Any CPU + {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.Debug|Any CPU.Build.0 = netcoreapp-Windows_NT-Debug|Any CPU {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|Any CPU {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.Release|Any CPU.Build.0 = netcoreapp-Windows_NT-Release|Any CPU - {0D174EA9-9E61-4519-8D31-7BD2331A1982}.Debug|Any CPU.ActiveCfg = netstandard-Unix-Debug|Any CPU - {0D174EA9-9E61-4519-8D31-7BD2331A1982}.Debug|Any CPU.Build.0 = netstandard-Unix-Debug|Any CPU + {0D174EA9-9E61-4519-8D31-7BD2331A1982}.Debug|Any CPU.ActiveCfg = netstandard-Windows_NT-Debug|Any CPU + {0D174EA9-9E61-4519-8D31-7BD2331A1982}.Debug|Any CPU.Build.0 = netstandard-Windows_NT-Debug|Any CPU {0D174EA9-9E61-4519-8D31-7BD2331A1982}.Release|Any CPU.ActiveCfg = netstandard-Windows_NT-Release|Any CPU {0D174EA9-9E61-4519-8D31-7BD2331A1982}.Release|Any CPU.Build.0 = netstandard-Windows_NT-Release|Any CPU - {89F37791-6254-4D60-AB96-ACD3CCA0E771}.Debug|Any CPU.ActiveCfg = netcoreapp-Unix-Debug|Any CPU - {89F37791-6254-4D60-AB96-ACD3CCA0E771}.Debug|Any CPU.Build.0 = netcoreapp-Unix-Debug|Any CPU + {89F37791-6254-4D60-AB96-ACD3CCA0E771}.Debug|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Debug|Any CPU + {89F37791-6254-4D60-AB96-ACD3CCA0E771}.Debug|Any CPU.Build.0 = netcoreapp-Windows_NT-Debug|Any CPU {89F37791-6254-4D60-AB96-ACD3CCA0E771}.Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|Any CPU {89F37791-6254-4D60-AB96-ACD3CCA0E771}.Release|Any CPU.Build.0 = netcoreapp-Windows_NT-Release|Any CPU {A7488FC0-9A8F-4EF9-BC3E-C5EBA47E13F8}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU @@ -57,7 +57,4 @@ Global {89F37791-6254-4D60-AB96-ACD3CCA0E771} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} {A7488FC0-9A8F-4EF9-BC3E-C5EBA47E13F8} = {2E666815-2EDB-464B-9DF6-380BF4789AD4} EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {1798D82D-8D02-431F-A7C8-56D76A267DF6} - EndGlobalSection EndGlobal diff --git a/src/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs b/src/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs index 5408f25b24c4..a0277c5bfa56 100644 --- a/src/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs +++ b/src/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs @@ -11,8 +11,6 @@ using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; -using Xunit.NetCore.Extensions; namespace System.Net.Security.Tests { @@ -141,9 +139,8 @@ public void SslStream_StreamToStream_Successive_ClientWrite_WithZeroBytes_Succes } [Theory] - [Trait(XunitConstants.Category, "SingleTest")] [InlineData(false)] - //[InlineData(true)] + [InlineData(true)] public void SslStream_StreamToStream_LargeWrites_Sync_Success(bool randomizedData) { VirtualNetwork network = new VirtualNetwork(); From 0e78e711466f987b3065a0efe91c645f08455428 Mon Sep 17 00:00:00 2001 From: Drawaes Date: Sun, 6 Aug 2017 23:42:56 +0100 Subject: [PATCH 27/54] Added the true flag to the new methods --- .../Unix/System.Security.Cryptography.Native/opensslshim.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h index 39abdc35bd17..782d3eb76052 100644 --- a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +++ b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h @@ -68,14 +68,14 @@ int EC_POINT_set_affine_coordinates_GF2m(const EC_GROUP *group, EC_POINT *p, PER_FUNCTION_BLOCK(BIO_ctrl, true) \ PER_FUNCTION_BLOCK(BIO_ctrl_pending, true) \ PER_FUNCTION_BLOCK(BIO_free, true) \ - PER_FUNCTION_BLOCK(BIO_get_app_data) \ + PER_FUNCTION_BLOCK(BIO_get_app_data, true) \ PER_FUNCTION_BLOCK(BIO_gets, true) \ PER_FUNCTION_BLOCK(BIO_new, true) \ PER_FUNCTION_BLOCK(BIO_new_file, true) \ PER_FUNCTION_BLOCK(BIO_read, true) \ PER_FUNCTION_BLOCK(BIO_s_mem, true) \ - PER_FUNCTION_BLOCK(BIO_set_app_data) \ - PER_FUNCTION_BLOCK(BIO_set_flags) \ + PER_FUNCTION_BLOCK(BIO_set_app_data, true) \ + PER_FUNCTION_BLOCK(BIO_set_flags, true) \ PER_FUNCTION_BLOCK(BIO_write, true) \ PER_FUNCTION_BLOCK(BN_bin2bn, true) \ PER_FUNCTION_BLOCK(BN_bn2bin, true) \ From 3014c47a40738863c94ec31d3b3260b3f619967b Mon Sep 17 00:00:00 2001 From: Drawaes Date: Sun, 6 Aug 2017 23:53:24 +0100 Subject: [PATCH 28/54] Change from Macros that aren't in older OpenSSL to the underlying functions --- .../System.Security.Cryptography.Native/opensslshim.h | 10 ++++------ .../System.Security.Cryptography.Native/pal_bio.cpp | 4 ++-- .../System.Security.Cryptography.Native/pal_ssl.cpp | 2 +- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h index 782d3eb76052..1258d00b2860 100644 --- a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +++ b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h @@ -68,13 +68,13 @@ int EC_POINT_set_affine_coordinates_GF2m(const EC_GROUP *group, EC_POINT *p, PER_FUNCTION_BLOCK(BIO_ctrl, true) \ PER_FUNCTION_BLOCK(BIO_ctrl_pending, true) \ PER_FUNCTION_BLOCK(BIO_free, true) \ - PER_FUNCTION_BLOCK(BIO_get_app_data, true) \ + PER_FUNCTION_BLOCK(BIO_get_ex_data, true) \ PER_FUNCTION_BLOCK(BIO_gets, true) \ PER_FUNCTION_BLOCK(BIO_new, true) \ PER_FUNCTION_BLOCK(BIO_new_file, true) \ PER_FUNCTION_BLOCK(BIO_read, true) \ PER_FUNCTION_BLOCK(BIO_s_mem, true) \ - PER_FUNCTION_BLOCK(BIO_set_app_data, true) \ + PER_FUNCTION_BLOCK(BIO_set_ex_data, true) \ PER_FUNCTION_BLOCK(BIO_set_flags, true) \ PER_FUNCTION_BLOCK(BIO_write, true) \ PER_FUNCTION_BLOCK(BN_bin2bn, true) \ @@ -255,7 +255,6 @@ int EC_POINT_set_affine_coordinates_GF2m(const EC_GROUP *group, EC_POINT *p, PER_FUNCTION_BLOCK(SSL_CTX_free, true) \ PER_FUNCTION_BLOCK(SSL_CTX_new, true) \ PER_FUNCTION_BLOCK(SSL_CTX_set_cert_verify_callback, true) \ - PER_FUNCTION_BLOCK(SSL_CTX_set_mode, true) \ PER_FUNCTION_BLOCK(SSL_CTX_set_cipher_list, true) \ PER_FUNCTION_BLOCK(SSL_CTX_set_client_CA_list, true) \ PER_FUNCTION_BLOCK(SSL_CTX_set_client_cert_cb, true) \ @@ -363,13 +362,13 @@ FOR_ALL_OPENSSL_FUNCTIONS #define BIO_ctrl BIO_ctrl_ptr #define BIO_ctrl_pending BIO_ctrl_pending_ptr #define BIO_free BIO_free_ptr -#define BIO_get_app_data BIO_get_app_data_ptr +#define BIO_get_ex_data BIO_get_ex_data_ptr #define BIO_gets BIO_gets_ptr #define BIO_new BIO_new_ptr #define BIO_new_file BIO_new_file_ptr #define BIO_read BIO_read_ptr #define BIO_s_mem BIO_s_mem_ptr -#define BIO_set_app_data BIO_set_app_data_ptr +#define BIO_set_ex_data BIO_set_ex_data_ptr #define BIO_set_flags BIO_set_flags_ptr #define BIO_write BIO_write_ptr #define BN_bin2bn BN_bin2bn_ptr @@ -549,7 +548,6 @@ FOR_ALL_OPENSSL_FUNCTIONS #define SSL_CTX_ctrl SSL_CTX_ctrl_ptr #define SSL_CTX_free SSL_CTX_free_ptr #define SSL_CTX_new SSL_CTX_new_ptr -#define SSL_CTX_set_mode SSL_CTX_set_mode_ptr #define SSL_CTX_set_cert_verify_callback SSL_CTX_set_cert_verify_callback_ptr #define SSL_CTX_set_cipher_list SSL_CTX_set_cipher_list_ptr #define SSL_CTX_set_client_CA_list SSL_CTX_set_client_CA_list_ptr diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp b/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp index 96495a3e2527..187a5d475aa3 100644 --- a/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp +++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp @@ -60,12 +60,12 @@ extern "C" int32_t CryptoNative_BioCtrlPending(BIO* bio) extern "C" void CryptoNative_BioSetAppData(BIO* bio, void* data) { - BIO_set_app_data(bio, data); + BIO_set_ex_data(bio, 0, data); } extern "C" void* CryptoNative_BioGetAppData(BIO* bio) { - return BIO_get_app_data(bio); + return BIO_get_ex_data(bio, 0); } extern "C" void CryptoNative_BioSetFlags(BIO* bio, int32_t flags) diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_ssl.cpp b/src/Native/Unix/System.Security.Cryptography.Native/pal_ssl.cpp index 45cd1b19443b..dc65f0a86c0f 100644 --- a/src/Native/Unix/System.Security.Cryptography.Native/pal_ssl.cpp +++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_ssl.cpp @@ -43,7 +43,7 @@ extern "C" SSL_CTX* CryptoNative_SslCtxCreate(SSL_METHOD* method) extern "C" void CryptoNative_SslCtxSetAcceptMovingWriteBuffer(SSL_CTX* ctx) { - SSL_CTX_set_mode(ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + SSL_CTX_ctrl(ctx, SSL_CTRL_MODE, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER, nullptr); } extern "C" void CryptoNative_SetProtocolOptions(SSL_CTX* ctx, SslProtocols protocols) From a47874ff67e9d3188bb4941c784999004d1a8445 Mon Sep 17 00:00:00 2001 From: Drawaes Date: Tue, 8 Aug 2017 00:31:08 +0100 Subject: [PATCH 29/54] Removed var voliations in files edited (there was one in an loop i didn't edit but was updated anyway) --- .../Interop.BIO.Custom.cs | 46 +++++++++---------- .../Interop.OpenSsl.cs | 11 ++--- .../System.Net.Security.sln | 19 ++++---- 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs index 603729d01fbb..6b17568170dd 100755 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs @@ -7,12 +7,12 @@ internal static partial class Interop { internal static class CustomBio { - private static IntPtr _customBioMethodStructure; - private static CreateDelegate _createDelegate; - private static DestroyDelegate _destroyDelegate; - private unsafe static ControlDelegate _controlDelegate; - private unsafe static ReadDelegate _readDelegate; - private unsafe static WriteDelegate _writeDelegate; + private static IntPtr s_customBioMethodStructure; + private static CreateDelegate s_createDelegate; + private static DestroyDelegate s_destroyDelegate; + private unsafe static ControlDelegate s_controlDelegate; + private unsafe static ReadDelegate s_readDelegate; + private unsafe static WriteDelegate s_writeDelegate; [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private unsafe delegate int CreateDelegate(bio_st* bio); @@ -36,32 +36,32 @@ static CustomBio() internal unsafe static void Initialize() { - _createDelegate = Create; - _controlDelegate = Control; - _destroyDelegate = Destroy; - _writeDelegate = Write; - _readDelegate = Read; + s_createDelegate = Create; + s_controlDelegate = Control; + s_destroyDelegate = Destroy; + s_writeDelegate = Write; + s_readDelegate = Read; - var name = Marshal.StringToHGlobalAnsi("Managed Bio"); + IntPtr name = Marshal.StringToHGlobalAnsi("Managed Bio"); var bioStruct = new bio_method_st() { - create = _createDelegate, + create = s_createDelegate, name = name, type = BIO_TYPE.BIO_TYPE_SOURCE_SINK, - destroy = _destroyDelegate, - ctrl = _controlDelegate, - bread = _readDelegate, - bwrite = _writeDelegate, + destroy = s_destroyDelegate, + ctrl = s_controlDelegate, + bread = s_readDelegate, + bwrite = s_writeDelegate, }; - var memory = Marshal.AllocHGlobal(Marshal.SizeOf()); + IntPtr memory = Marshal.AllocHGlobal(Marshal.SizeOf()); Marshal.StructureToPtr(bioStruct, memory, true); - _customBioMethodStructure = memory; + s_customBioMethodStructure = memory; } internal static GCHandle BioGetGCHandle(IntPtr bio) { - var ptr = Crypto.BioGetAppData(bio); + IntPtr ptr = Crypto.BioGetAppData(bio); if (ptr == IntPtr.Zero) { return default(GCHandle); @@ -78,7 +78,7 @@ internal static void BioSetGCHandle(SafeBioHandle bio, GCHandle handle) internal static SafeBioHandle CreateCustomBio() { - var bio = Crypto.CreateCustomBio(_customBioMethodStructure); + SafeBioHandle bio = Crypto.CreateCustomBio(s_customBioMethodStructure); return bio; } @@ -104,7 +104,7 @@ private static unsafe long Control(IntPtr bio, Crypto.BIO_CTRL cmd, long param, private static unsafe int Write(IntPtr bio, void* input, int size) { - var handle = BioGetGCHandle(bio); + GCHandle handle = BioGetGCHandle(bio); if (handle.IsAllocated && handle.Target is SafeSslHandle.WriteBioBuffer buffer) { @@ -116,7 +116,7 @@ private static unsafe int Write(IntPtr bio, void* input, int size) private static unsafe int Read(IntPtr bio, void* output, int size) { - var handle = BioGetGCHandle(bio); + GCHandle handle = BioGetGCHandle(bio); if (handle.IsAllocated && handle.Target is SafeSslHandle.ReadBioBuffer buffer) { return buffer.Read(new Span(output, size)); diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs index 37f463eb2071..a818ce4a919e 100755 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs @@ -153,8 +153,7 @@ internal static bool DoSslHandshake(SafeSslHandle context, byte[] recvBuf, int r if (retVal != 1) { - Exception innerError; - Ssl.SslErrorCode error = GetSslError(context, retVal, out innerError); + Ssl.SslErrorCode error = GetSslError(context, retVal, out Exception innerError); if ((retVal != -1) || (error != Ssl.SslErrorCode.SSL_ERROR_WANT_READ)) { @@ -194,8 +193,7 @@ internal static int Encrypt(SafeSslHandle context, byte[] input, int offset, int if (retVal != count) { - Exception innerError; - errorCode = GetSslError(context, retVal, out innerError); + errorCode = GetSslError(context, retVal, out Exception innerError); retVal = 0; switch (errorCode) @@ -237,8 +235,7 @@ internal static int Decrypt(SafeSslHandle context, byte[] outBuffer, int offset, if (retVal != count) { - Exception innerError; - errorCode = GetSslError(context, retVal, out innerError); + errorCode = GetSslError(context, retVal, out Exception innerError); retVal = 0; switch (errorCode) @@ -326,7 +323,7 @@ private static void AddX509Names(SafeX509NameStackHandle nameStack, StoreLocatio { store.Open(OpenFlags.ReadOnly); - foreach (var certificate in store.Certificates) + foreach (X509Certificate2 certificate in store.Certificates) { //Check if issuer name is already present //Avoiding duplicate names diff --git a/src/System.Net.Security/System.Net.Security.sln b/src/System.Net.Security/System.Net.Security.sln index 7661a942233e..1740ede2152d 100644 --- a/src/System.Net.Security/System.Net.Security.sln +++ b/src/System.Net.Security/System.Net.Security.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 +# Visual Studio 15 +VisualStudioVersion = 15.0.26711.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Net.Security.Tests", "tests\FunctionalTests\System.Net.Security.Tests.csproj", "{A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}" ProjectSection(ProjectDependencies) = postProject @@ -31,16 +31,16 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.Debug|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Debug|Any CPU - {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.Debug|Any CPU.Build.0 = netcoreapp-Windows_NT-Debug|Any CPU + {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.Debug|Any CPU.ActiveCfg = netcoreapp-Unix-Debug|Any CPU + {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.Debug|Any CPU.Build.0 = netcoreapp-Unix-Debug|Any CPU {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|Any CPU {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.Release|Any CPU.Build.0 = netcoreapp-Windows_NT-Release|Any CPU - {0D174EA9-9E61-4519-8D31-7BD2331A1982}.Debug|Any CPU.ActiveCfg = netstandard-Windows_NT-Debug|Any CPU - {0D174EA9-9E61-4519-8D31-7BD2331A1982}.Debug|Any CPU.Build.0 = netstandard-Windows_NT-Debug|Any CPU + {0D174EA9-9E61-4519-8D31-7BD2331A1982}.Debug|Any CPU.ActiveCfg = netstandard-Unix-Debug|Any CPU + {0D174EA9-9E61-4519-8D31-7BD2331A1982}.Debug|Any CPU.Build.0 = netstandard-Unix-Debug|Any CPU {0D174EA9-9E61-4519-8D31-7BD2331A1982}.Release|Any CPU.ActiveCfg = netstandard-Windows_NT-Release|Any CPU {0D174EA9-9E61-4519-8D31-7BD2331A1982}.Release|Any CPU.Build.0 = netstandard-Windows_NT-Release|Any CPU - {89F37791-6254-4D60-AB96-ACD3CCA0E771}.Debug|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Debug|Any CPU - {89F37791-6254-4D60-AB96-ACD3CCA0E771}.Debug|Any CPU.Build.0 = netcoreapp-Windows_NT-Debug|Any CPU + {89F37791-6254-4D60-AB96-ACD3CCA0E771}.Debug|Any CPU.ActiveCfg = netcoreapp-Unix-Debug|Any CPU + {89F37791-6254-4D60-AB96-ACD3CCA0E771}.Debug|Any CPU.Build.0 = netcoreapp-Unix-Debug|Any CPU {89F37791-6254-4D60-AB96-ACD3CCA0E771}.Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|Any CPU {89F37791-6254-4D60-AB96-ACD3CCA0E771}.Release|Any CPU.Build.0 = netcoreapp-Windows_NT-Release|Any CPU {A7488FC0-9A8F-4EF9-BC3E-C5EBA47E13F8}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU @@ -57,4 +57,7 @@ Global {89F37791-6254-4D60-AB96-ACD3CCA0E771} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} {A7488FC0-9A8F-4EF9-BC3E-C5EBA47E13F8} = {2E666815-2EDB-464B-9DF6-380BF4789AD4} EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {E4326E62-D794-49A8-AE7D-85903688E655} + EndGlobalSection EndGlobal From fb87ba4b8bbbca53a04e10257d1c0ed9308f3328 Mon Sep 17 00:00:00 2001 From: Drawaes Date: Tue, 8 Aug 2017 00:33:56 +0100 Subject: [PATCH 30/54] Added named parameters to increase readability --- .../System.Security.Cryptography.Native/Interop.OpenSsl.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs index a818ce4a919e..33f8d4bc1a33 100755 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs @@ -147,7 +147,7 @@ internal static bool DoSslHandshake(SafeSslHandle context, byte[] recvBuf, int r } context.InputBio.SetBio(recvBuf, recvOffset, recvCount); - context.OutputBio.SetBio(null, true); + context.OutputBio.SetBio(buffer: null, isHandshake: true); int retVal = Ssl.SslDoHandshake(context); @@ -162,7 +162,7 @@ internal static bool DoSslHandshake(SafeSslHandle context, byte[] recvBuf, int r } sendCount = context.OutputBio.TakeBytes(out sendBuf); - + bool stateOk = Ssl.IsSslStateOK(context); if (stateOk) { @@ -180,7 +180,7 @@ internal static int Encrypt(SafeSslHandle context, byte[] input, int offset, int Debug.Assert(input.Length - offset >= count); errorCode = Ssl.SslErrorCode.SSL_ERROR_NONE; - context.OutputBio.SetBio(output, false); + context.OutputBio.SetBio(output, isHandshake: false); int retVal; unsafe From dcbed7ec380d9a66d4e4a7a92d53e5d39fc6e03e Mon Sep 17 00:00:00 2001 From: Drawaes Date: Tue, 8 Aug 2017 01:01:10 +0100 Subject: [PATCH 31/54] Removed raw set flags methods and provided shim methods for the two functions needed --- .../Interop.BIO.cs | 18 +++++------------- .../Interop.Ssl.cs | 7 ++++--- .../pal_bio.cpp | 15 +++++++++++++-- .../pal_bio.h | 9 +++++++-- 4 files changed, 29 insertions(+), 20 deletions(-) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.cs index 0f08ca084b76..55b27908532a 100755 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.cs @@ -45,20 +45,12 @@ internal static partial class Crypto [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_BioGetAppData")] internal static extern IntPtr BioGetAppData(IntPtr bio); - [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_BioSetFlags")] - internal static extern IntPtr BioSetFlags(SafeBioHandle bio, BIO_FLAGS flags); - - [Flags] - internal enum BIO_FLAGS - { - BIO_FLAGS_NONE = 0x0, - BIO_FLAGS_READ = 0x01, - BIO_FLAGS_WRITE = 0x02, - BIO_FLAGS_IO_SPECIAL = 0x04, - BIO_FLAGS_RWS = (BIO_FLAGS_READ | BIO_FLAGS_WRITE | BIO_FLAGS_IO_SPECIAL), - BIO_FLAGS_SHOULD_RETRY = 0x08, - } + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_BioSetWriteFlag")] + internal static extern void BioSetWriteFlag(SafeBioHandle bio); + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_BioSetShoudRetryReadFlag")] + internal static extern void BioSetShoudRetryReadFlag(SafeBioHandle bio); + internal enum BIO_CTRL { BIO_CTRL_RESET = 1,/* opt - rewind/zero etc */ diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs index 00b32fbde745..d0080606829c 100755 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs @@ -298,7 +298,7 @@ internal ReadBioBuffer(SafeBioHandle bioHandle) _bioHandle = bioHandle; _handle = GCHandle.Alloc(this, GCHandleType.Normal); Interop.CustomBio.BioSetGCHandle(_bioHandle, _handle); - Interop.Crypto.BioSetFlags(bioHandle, Interop.Crypto.BIO_FLAGS.BIO_FLAGS_READ | Interop.Crypto.BIO_FLAGS.BIO_FLAGS_SHOULD_RETRY); + Interop.Crypto.BioSetShoudRetryReadFlag(bioHandle); } public void SetBio(byte[] buffer, int offset, int length) @@ -311,7 +311,8 @@ public void SetBio(byte[] buffer, int offset, int length) public int Read(Span output) { var bytesToCopy = Math.Min(output.Length, _bytesAvailable); - if (bytesToCopy == 0) return -1; + if (bytesToCopy == 0) + return -1; var span = new Span(_byteArray, _offset, bytesToCopy); span.CopyTo(output); _offset += bytesToCopy; @@ -390,7 +391,7 @@ public int Write(Span input) var bytesToWrite = Math.Min(input.Length, _byteArray.Length - _bytesWritten); if (bytesToWrite < 1) { - Interop.Crypto.BioSetFlags(_bioHandle, Interop.Crypto.BIO_FLAGS.BIO_FLAGS_WRITE); + Interop.Crypto.BioSetWriteFlag(_bioHandle); return -1; } input.Slice(0, bytesToWrite).CopyTo(new Span(_byteArray, _bytesWritten)); diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp b/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp index 187a5d475aa3..7b467aa8f3a7 100644 --- a/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp +++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp @@ -68,7 +68,18 @@ extern "C" void* CryptoNative_BioGetAppData(BIO* bio) return BIO_get_ex_data(bio, 0); } -extern "C" void CryptoNative_BioSetFlags(BIO* bio, int32_t flags) +/* +Set write flag for the custom bio +*/ +extern "C" void CryptoNative_BioSetWriteFlag(BIO* bio) { - BIO_set_flags(bio, flags); + BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY | BIO_FLAGS_READ); } + +/* +Set the read and should retry flag for the custom bio +*/ +extern "C" void CryptoNative_BioSetShoudRetryReadFlag(BIO* bio) +{ + BIO_set_flags(bio, BIO_FLAGS_WRITE); +} \ No newline at end of file diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.h b/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.h index 6c8215d989f1..816c1a542c03 100644 --- a/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.h +++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.h @@ -70,6 +70,11 @@ Gets app data from the extension slot of the bio extern "C" void* CryptoNative_BioGetAppData(BIO* bio); /* -Shims the Set flags for the custom bio +Set write flag for the custom bio */ -extern "C" void CryptoNative_BioSetFlags(BIO* bio, int32_t flags); +extern "C" void CryptoNative_BioSetWriteFlag(BIO* bio); + +/* +Set the read and should retry flag for the custom bio +*/ +extern "C" void CryptoNative_BioSetShoudRetryReadFlag(BIO* bio); From 3ec53c69cf37855956f21a7a3a567a874dd1ee8d Mon Sep 17 00:00:00 2001 From: Drawaes Date: Tue, 8 Aug 2017 02:55:31 +0100 Subject: [PATCH 32/54] React to shim changes in the managed layer --- .../Interop.BIO.Custom.cs | 100 +----------------- .../Interop.BIO.cs | 19 +--- 2 files changed, 6 insertions(+), 113 deletions(-) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs index 6b17568170dd..28c6f6525951 100755 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs @@ -7,15 +7,11 @@ internal static partial class Interop { internal static class CustomBio { - private static IntPtr s_customBioMethodStructure; - private static CreateDelegate s_createDelegate; - private static DestroyDelegate s_destroyDelegate; - private unsafe static ControlDelegate s_controlDelegate; private unsafe static ReadDelegate s_readDelegate; private unsafe static WriteDelegate s_writeDelegate; - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private unsafe delegate int CreateDelegate(bio_st* bio); + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_InitCustomBioMethod")] + private static extern void InitCustomBioMethod(WriteDelegate bwrite, ReadDelegate bread); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private unsafe delegate int ReadDelegate(IntPtr bio, void* buf, int size); @@ -23,40 +19,14 @@ internal static class CustomBio [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private unsafe delegate int WriteDelegate(IntPtr bio, void* buf, int num); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private unsafe delegate long ControlDelegate(IntPtr bio, Crypto.BIO_CTRL cmd, long num, void* ptr); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int DestroyDelegate(IntPtr bio); - - static CustomBio() - { - CustomBio.Initialize(); - } + static CustomBio() => Initialize(); internal unsafe static void Initialize() { - s_createDelegate = Create; - s_controlDelegate = Control; - s_destroyDelegate = Destroy; s_writeDelegate = Write; s_readDelegate = Read; - IntPtr name = Marshal.StringToHGlobalAnsi("Managed Bio"); - var bioStruct = new bio_method_st() - { - create = s_createDelegate, - name = name, - type = BIO_TYPE.BIO_TYPE_SOURCE_SINK, - destroy = s_destroyDelegate, - ctrl = s_controlDelegate, - bread = s_readDelegate, - bwrite = s_writeDelegate, - }; - - IntPtr memory = Marshal.AllocHGlobal(Marshal.SizeOf()); - Marshal.StructureToPtr(bioStruct, memory, true); - s_customBioMethodStructure = memory; + InitCustomBioMethod(s_writeDelegate, s_readDelegate); } internal static GCHandle BioGetGCHandle(IntPtr bio) @@ -76,31 +46,7 @@ internal static void BioSetGCHandle(SafeBioHandle bio, GCHandle handle) Crypto.BioSetAppData(bio, ptr); } - internal static SafeBioHandle CreateCustomBio() - { - SafeBioHandle bio = Crypto.CreateCustomBio(s_customBioMethodStructure); - return bio; - } - - private unsafe static int Create(bio_st* bio) - { - bio[0].init = 1; - return 1; - } - - private static int Destroy(IntPtr bio) => 1; - - private static unsafe long Control(IntPtr bio, Crypto.BIO_CTRL cmd, long param, void* ptr) - { - switch (cmd) - { - case Crypto.BIO_CTRL.BIO_CTRL_FLUSH: - case Crypto.BIO_CTRL.BIO_CTRL_POP: - case Crypto.BIO_CTRL.BIO_CTRL_PUSH: - return 1; - } - return 0; - } + internal static SafeBioHandle CreateCustomBio() => Crypto.CreateCustomBio(); private static unsafe int Write(IntPtr bio, void* input, int size) { @@ -123,41 +69,5 @@ private static unsafe int Read(IntPtr bio, void* output, int size) } return -1; } - - [Flags] - private enum BIO_TYPE - { - BIO_TYPE_SOURCE_SINK = 0x0400, - } - - [StructLayout(LayoutKind.Sequential)] - private unsafe struct bio_st - { - public void* method; - public void* callback; - public void* cb_arg; - public int init; - public int shutdown; - public int flags; - public int retry_reason; - public int num; - public void* ptr; - } - - [StructLayout(LayoutKind.Sequential)] - private unsafe struct bio_method_st - { - public BIO_TYPE type; - public IntPtr name; - public WriteDelegate bwrite; // int (* bwrite) (BIO*, const char*, int); - public ReadDelegate bread; // int (* bread) (BIO*, char*, int); - public IntPtr bputs; // int (* bputs) (BIO*, const char*); - public IntPtr bgets; // int (* bgets) (BIO*, char*, int); - public ControlDelegate ctrl; // long (* ctrl) (BIO*, int, long, void*); - public CreateDelegate create; // int (* create) (BIO*); - public DestroyDelegate destroy; // int (* destroy) (BIO*); - public IntPtr callback_ctrl; // long (* callback_ctrl) (BIO*, int, bio_info_cb*); - } - } } diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.cs index 55b27908532a..b9225e66aefa 100755 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.cs @@ -37,7 +37,7 @@ internal static partial class Crypto internal static extern int BioCtrlPending(SafeBioHandle bio); [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_CreateCustomBio")] - internal static extern SafeBioHandle CreateCustomBio(IntPtr bioMethodStruct); + internal static extern SafeBioHandle CreateCustomBio(); [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_BioSetAppData")] internal static extern void BioSetAppData(SafeBioHandle bio, IntPtr data); @@ -50,22 +50,5 @@ internal static partial class Crypto [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_BioSetShoudRetryReadFlag")] internal static extern void BioSetShoudRetryReadFlag(SafeBioHandle bio); - - internal enum BIO_CTRL - { - BIO_CTRL_RESET = 1,/* opt - rewind/zero etc */ - BIO_CTRL_EOF = 2,/* opt - are we at the eof */ - BIO_CTRL_INFO = 3,/* opt - extra tit-bits */ - BIO_CTRL_SET = 4,/* man - set the 'IO' type */ - BIO_CTRL_GET = 5,/* man - get the 'IO' type */ - BIO_CTRL_PUSH = 6,/* opt - internal, used to signify change */ - BIO_CTRL_POP = 7,/* opt - internal, used to signify change */ - BIO_CTRL_GET_CLOSE = 8,/* man - set the 'close' on free */ - BIO_CTRL_SET_CLOSE = 9,/* man - set the 'close' on free */ - BIO_CTRL_PENDING = 10,/* opt - is their more data buffered */ - BIO_CTRL_FLUSH = 11,/* opt - 'flush' buffered output */ - BIO_CTRL_DUP = 12,/* man - extra stuff for 'duped' BIO */ - BIO_CTRL_WPENDING = 13,/* opt - number of bytes still to write */ - } } } From 3c1d3bdf05429c523b9b2a9e89d51bc6075272de Mon Sep 17 00:00:00 2001 From: Drawaes Date: Tue, 8 Aug 2017 02:55:31 +0100 Subject: [PATCH 33/54] React to shim changes in the managed layer --- .../pal_bio.cpp | 56 +++++++++++++++++-- .../pal_bio.h | 8 ++- 2 files changed, 57 insertions(+), 7 deletions(-) mode change 100644 => 100755 src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp mode change 100644 => 100755 src/Native/Unix/System.Security.Cryptography.Native/pal_bio.h diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp b/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp old mode 100644 new mode 100755 index 7b467aa8f3a7..74c542a12979 --- a/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp +++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp @@ -6,11 +6,6 @@ #include -extern "C" BIO* CryptoNative_CreateCustomBio(BIO_METHOD* bioMethod) -{ - return BIO_new(bioMethod); -} - extern "C" BIO* CryptoNative_CreateMemoryBio() { return BIO_new(BIO_s_mem()); @@ -82,4 +77,53 @@ Set the read and should retry flag for the custom bio extern "C" void CryptoNative_BioSetShoudRetryReadFlag(BIO* bio) { BIO_set_flags(bio, BIO_FLAGS_WRITE); -} \ No newline at end of file +} + +static long ControlCallback(BIO* bio, int cmd, long param, void* ptr) +{ + (void)bio, (void)param, (void)ptr; // deliberately unused parameters + switch (cmd) + { + case BIO_CTRL_FLUSH: + case BIO_CTRL_POP: + case BIO_CTRL_PUSH: + return 1; + } + return 0; +} + +static int DestroyCallback(BIO* bio) +{ + (void)bio; // deliberately unused parameter + return -1; +} + +static int CreateCallback(BIO* bio) +{ + bio->init = 1; + return 1; +} + +static BIO_METHOD sslStreamCustomBio = { + BIO_TYPE_SOURCE_SINK, + "SslStreamCustomBio", + nullptr, + nullptr, + nullptr, + nullptr, + ControlCallback, + CreateCallback, + DestroyCallback, + nullptr, +}; + +extern "C" void CryptoNative_InitCustomBioMethod(BWriteCallback bwrite, BReadCallback bread) +{ + sslStreamCustomBio.bwrite = bwrite; + sslStreamCustomBio.bread = bread; +} + +extern "C" BIO* CryptoNative_CreateCustomBio() +{ + return BIO_new(&sslStreamCustomBio); +} diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.h b/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.h old mode 100644 new mode 100755 index 816c1a542c03..352655f22674 --- a/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.h +++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.h @@ -5,10 +5,13 @@ #include "pal_types.h" #include "opensslshim.h" +typedef int32_t (*BWriteCallback)(BIO* b, const char* buf, int32_t len); +typedef int32_t (*BReadCallback)(BIO* b, char* buf, int32_t len); + /* Creates a custom BIO instance. */ -extern "C" BIO* CryptoNative_CreateCustomBio(BIO_METHOD* bioMethod); +extern "C" BIO* CryptoNative_CreateCustomBio(); /* Creates a new memory-backed BIO instance. @@ -78,3 +81,6 @@ extern "C" void CryptoNative_BioSetWriteFlag(BIO* bio); Set the read and should retry flag for the custom bio */ extern "C" void CryptoNative_BioSetShoudRetryReadFlag(BIO* bio); + +extern "C" void CryptoNative_InitCustomBioMethod(BWriteCallback bwrite, BReadCallback bread); + From f6dcc55ae8da93bf73589da75cb5af954941fb08 Mon Sep 17 00:00:00 2001 From: bench Date: Tue, 8 Aug 2017 14:41:35 +0100 Subject: [PATCH 34/54] Fix the flags change to be the correct direction --- .../Unix/System.Security.Cryptography.Native/pal_bio.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp b/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp index 74c542a12979..e4e0654440f0 100755 --- a/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp +++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp @@ -68,7 +68,7 @@ Set write flag for the custom bio */ extern "C" void CryptoNative_BioSetWriteFlag(BIO* bio) { - BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY | BIO_FLAGS_READ); + BIO_set_flags(bio, BIO_FLAGS_WRITE); } /* @@ -76,7 +76,7 @@ Set the read and should retry flag for the custom bio */ extern "C" void CryptoNative_BioSetShoudRetryReadFlag(BIO* bio) { - BIO_set_flags(bio, BIO_FLAGS_WRITE); + BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY | BIO_FLAGS_READ); } static long ControlCallback(BIO* bio, int cmd, long param, void* ptr) From 0a27d81a9b78929423c5c784df5773a12dc0d8e6 Mon Sep 17 00:00:00 2001 From: bench Date: Tue, 8 Aug 2017 23:53:07 +0100 Subject: [PATCH 35/54] Cleaned up spacing and formatting and the interop code --- .../Interop.BIO.Custom.cs | 19 +++++++++++++----- .../Interop.BIO.cs | 5 +---- .../pal_bio.cpp | 2 +- .../pal_bio.h | 20 +++++++++++-------- 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs index 28c6f6525951..58158850f523 100755 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs @@ -19,6 +19,9 @@ internal static class CustomBio [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private unsafe delegate int WriteDelegate(IntPtr bio, void* buf, int num); + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_CreateCustomBio")] + internal static extern SafeBioHandle CreateCustomBio(); + static CustomBio() => Initialize(); internal unsafe static void Initialize() @@ -42,12 +45,18 @@ internal static GCHandle BioGetGCHandle(IntPtr bio) internal static void BioSetGCHandle(SafeBioHandle bio, GCHandle handle) { - var ptr = GCHandle.ToIntPtr(handle); - Crypto.BioSetAppData(bio, ptr); + IntPtr pointer; + if (handle.IsAllocated) + { + pointer = GCHandle.ToIntPtr(handle); + } + else + { + pointer = IntPtr.Zero; + } + Crypto.BioSetAppData(bio, pointer); } - internal static SafeBioHandle CreateCustomBio() => Crypto.CreateCustomBio(); - private static unsafe int Write(IntPtr bio, void* input, int size) { GCHandle handle = BioGetGCHandle(bio); @@ -56,13 +65,13 @@ private static unsafe int Write(IntPtr bio, void* input, int size) { return buffer.Write(new Span(input, size)); } - return -1; } private static unsafe int Read(IntPtr bio, void* output, int size) { GCHandle handle = BioGetGCHandle(bio); + if (handle.IsAllocated && handle.Target is SafeSslHandle.ReadBioBuffer buffer) { return buffer.Read(new Span(output, size)); diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.cs index b9225e66aefa..267be4cb6ec1 100755 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.cs @@ -35,10 +35,7 @@ internal static partial class Crypto [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_BioCtrlPending")] internal static extern int BioCtrlPending(SafeBioHandle bio); - - [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_CreateCustomBio")] - internal static extern SafeBioHandle CreateCustomBio(); - + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_BioSetAppData")] internal static extern void BioSetAppData(SafeBioHandle bio, IntPtr data); diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp b/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp index e4e0654440f0..aed0260809d0 100755 --- a/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp +++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp @@ -117,7 +117,7 @@ static BIO_METHOD sslStreamCustomBio = { nullptr, }; -extern "C" void CryptoNative_InitCustomBioMethod(BWriteCallback bwrite, BReadCallback bread) +extern "C" void CryptoNative_InitCustomBioMethod(BioWriteCallback bwrite, BioReadCallback bread) { sslStreamCustomBio.bwrite = bwrite; sslStreamCustomBio.bread = bread; diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.h b/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.h index 352655f22674..04feda3bb921 100755 --- a/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.h +++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.h @@ -5,13 +5,8 @@ #include "pal_types.h" #include "opensslshim.h" -typedef int32_t (*BWriteCallback)(BIO* b, const char* buf, int32_t len); -typedef int32_t (*BReadCallback)(BIO* b, char* buf, int32_t len); - -/* -Creates a custom BIO instance. -*/ -extern "C" BIO* CryptoNative_CreateCustomBio(); +typedef int32_t (*BioWriteCallback)(BIO* b, const char* buf, int32_t len); +typedef int32_t (*BioReadCallback)(BIO* b, char* buf, int32_t len); /* Creates a new memory-backed BIO instance. @@ -82,5 +77,14 @@ Set the read and should retry flag for the custom bio */ extern "C" void CryptoNative_BioSetShoudRetryReadFlag(BIO* bio); -extern "C" void CryptoNative_InitCustomBioMethod(BWriteCallback bwrite, BReadCallback bread); +/* +Creates a custom BIO instance. +*/ +extern "C" BIO* CryptoNative_CreateCustomBio(); + +/* +Sets the managed callbacks that are used by the custom bio +for reads and writes +*/ +extern "C" void CryptoNative_InitCustomBioMethod(BioWriteCallback bwrite, BioReadCallback bread); From bc4699365451695e7f9c018956cc2449d0b9ac5c Mon Sep 17 00:00:00 2001 From: bench Date: Wed, 9 Aug 2017 23:22:42 +0100 Subject: [PATCH 36/54] Reacting to Review Added Comments about -1/0 return from read Added Comments about different path in write for handshakes Added more spacing after {} nit var Made callback in native code and get data call there Renamed from CustomBio to ManagedSslBio Renamed SetBio to SetData Added Assert on the Read Bio to ensure all previous data used Moved interop into the Crypto class Moved the Bio class into the Crypto class as a child class Fixed Dispose call to be true instead of false Moved null pointer test in callback to shim Removed Shim methods no longer needed Added GetBytes overload that doesn't return the buffer to make logic clearer for encrypt --- .../Interop.BIO.Custom.cs | 82 ------------------- .../Interop.BIO.cs | 16 +++- .../Interop.ManagedSslBio.cs | 66 +++++++++++++++ .../Interop.OpenSsl.cs | 12 +-- .../Interop.Ssl.cs | 40 ++++++--- .../pal_bio.cpp | 60 +++++++++----- .../pal_bio.h | 18 ++-- .../src/System.Net.Http.csproj | 4 +- .../ref/System.Net.Security.csproj | 0 .../src/System.Net.Security.csproj | 4 +- .../src/System/Net/Security/SecureChannel.cs | 1 + .../System/Net/Security/SslStreamInternal.cs | 4 + .../System/Net/Security/SslStreamPal.Unix.cs | 1 + .../System/Net/Security/StreamSizes.Unix.cs | 0 14 files changed, 173 insertions(+), 135 deletions(-) delete mode 100755 src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs mode change 100755 => 100644 src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.cs create mode 100644 src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.ManagedSslBio.cs mode change 100755 => 100644 src/Native/Unix/System.Security.Cryptography.Native/pal_bio.h mode change 100644 => 100755 src/System.Net.Http/src/System.Net.Http.csproj mode change 100644 => 100755 src/System.Net.Security/ref/System.Net.Security.csproj mode change 100755 => 100644 src/System.Net.Security/src/System/Net/Security/SecureChannel.cs mode change 100755 => 100644 src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs mode change 100755 => 100644 src/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs mode change 100755 => 100644 src/System.Net.Security/src/System/Net/Security/StreamSizes.Unix.cs diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs deleted file mode 100755 index 58158850f523..000000000000 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.Custom.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using Microsoft.Win32.SafeHandles; -using System.Diagnostics; - -internal static partial class Interop -{ - internal static class CustomBio - { - private unsafe static ReadDelegate s_readDelegate; - private unsafe static WriteDelegate s_writeDelegate; - - [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_InitCustomBioMethod")] - private static extern void InitCustomBioMethod(WriteDelegate bwrite, ReadDelegate bread); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private unsafe delegate int ReadDelegate(IntPtr bio, void* buf, int size); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private unsafe delegate int WriteDelegate(IntPtr bio, void* buf, int num); - - [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_CreateCustomBio")] - internal static extern SafeBioHandle CreateCustomBio(); - - static CustomBio() => Initialize(); - - internal unsafe static void Initialize() - { - s_writeDelegate = Write; - s_readDelegate = Read; - - InitCustomBioMethod(s_writeDelegate, s_readDelegate); - } - - internal static GCHandle BioGetGCHandle(IntPtr bio) - { - IntPtr ptr = Crypto.BioGetAppData(bio); - if (ptr == IntPtr.Zero) - { - return default(GCHandle); - } - var handle = GCHandle.FromIntPtr(ptr); - return handle; - } - - internal static void BioSetGCHandle(SafeBioHandle bio, GCHandle handle) - { - IntPtr pointer; - if (handle.IsAllocated) - { - pointer = GCHandle.ToIntPtr(handle); - } - else - { - pointer = IntPtr.Zero; - } - Crypto.BioSetAppData(bio, pointer); - } - - private static unsafe int Write(IntPtr bio, void* input, int size) - { - GCHandle handle = BioGetGCHandle(bio); - - if (handle.IsAllocated && handle.Target is SafeSslHandle.WriteBioBuffer buffer) - { - return buffer.Write(new Span(input, size)); - } - return -1; - } - - private static unsafe int Read(IntPtr bio, void* output, int size) - { - GCHandle handle = BioGetGCHandle(bio); - - if (handle.IsAllocated && handle.Target is SafeSslHandle.ReadBioBuffer buffer) - { - return buffer.Read(new Span(output, size)); - } - return -1; - } - } -} diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.cs old mode 100755 new mode 100644 index 267be4cb6ec1..194cecbbb0c7 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.BIO.cs @@ -39,13 +39,23 @@ internal static partial class Crypto [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_BioSetAppData")] internal static extern void BioSetAppData(SafeBioHandle bio, IntPtr data); - [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_BioGetAppData")] - internal static extern IntPtr BioGetAppData(IntPtr bio); - [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_BioSetWriteFlag")] internal static extern void BioSetWriteFlag(SafeBioHandle bio); [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_BioSetShoudRetryReadFlag")] internal static extern void BioSetShoudRetryReadFlag(SafeBioHandle bio); + + //These need to be here and private to ensure the static constructor is run to init the bio on the class + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_CreateManagedSslBio")] + private static extern SafeBioHandle CreateManagedSslBio(); + + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_InitManagedSslBioMethod")] + private static extern void InitManagedSslBioMethod(WriteDelegate bwrite, ReadDelegate bread); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private unsafe delegate int ReadDelegate(IntPtr bio, void* buf, int size, IntPtr data); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private unsafe delegate int WriteDelegate(IntPtr bio, void* buf, int num, IntPtr data); } } diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.ManagedSslBio.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.ManagedSslBio.cs new file mode 100644 index 000000000000..7dc8df187f5b --- /dev/null +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.ManagedSslBio.cs @@ -0,0 +1,66 @@ +using System; +using System.Runtime.InteropServices; +using Microsoft.Win32.SafeHandles; +using System.Diagnostics; + +internal static partial class Interop +{ + internal static partial class Crypto + { + internal static class ManagedSslBio + { + private unsafe static ReadDelegate s_readDelegate; + private unsafe static WriteDelegate s_writeDelegate; + + static ManagedSslBio() => Initialize(); + + internal static SafeBioHandle CreateManagedSslBio() => Crypto.CreateManagedSslBio(); + + private unsafe static void Initialize() + { + s_writeDelegate = Write; + s_readDelegate = Read; + Crypto.InitManagedSslBioMethod(s_writeDelegate, s_readDelegate); + } + + internal static void BioSetGCHandle(SafeBioHandle bio, GCHandle handle) + { + IntPtr pointer; + if (handle.IsAllocated) + { + pointer = GCHandle.ToIntPtr(handle); + } + else + { + pointer = IntPtr.Zero; + } + + Crypto.BioSetAppData(bio, pointer); + } + + private static unsafe int Write(IntPtr bio, void* input, int size, IntPtr data) + { + GCHandle handle = GCHandle.FromIntPtr(data); + + if (handle.IsAllocated && handle.Target is SafeSslHandle.WriteBioBuffer buffer) + { + return buffer.Write(new Span(input, size)); + } + + return -1; + } + + private static unsafe int Read(IntPtr bio, void* output, int size, IntPtr data) + { + GCHandle handle = GCHandle.FromIntPtr(data); + + if (handle.IsAllocated && handle.Target is SafeSslHandle.ReadBioBuffer buffer) + { + return buffer.Read(new Span(output, size)); + } + + return -1; + } + } + } +} diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs index 33f8d4bc1a33..bb32011cf1f4 100755 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs @@ -146,8 +146,8 @@ internal static bool DoSslHandshake(SafeSslHandle context, byte[] recvBuf, int r return false; } - context.InputBio.SetBio(recvBuf, recvOffset, recvCount); - context.OutputBio.SetBio(buffer: null, isHandshake: true); + context.InputBio.SetData(recvBuf, recvOffset, recvCount); + context.OutputBio.SetData(buffer: null, isHandshake: true); int retVal = Ssl.SslDoHandshake(context); @@ -168,6 +168,7 @@ internal static bool DoSslHandshake(SafeSslHandle context, byte[] recvBuf, int r { context.MarkHandshakeCompleted(); } + return stateOk; } @@ -180,7 +181,7 @@ internal static int Encrypt(SafeSslHandle context, byte[] input, int offset, int Debug.Assert(input.Length - offset >= count); errorCode = Ssl.SslErrorCode.SSL_ERROR_NONE; - context.OutputBio.SetBio(output, isHandshake: false); + context.OutputBio.SetData(output, isHandshake: false); int retVal; unsafe @@ -209,14 +210,15 @@ internal static int Encrypt(SafeSslHandle context, byte[] input, int offset, int throw new SslException(SR.Format(SR.net_ssl_encrypt_failed, errorCode), innerError); } } - return context.OutputBio.TakeBytes(out output); + + return context.OutputBio.TakeBytes(); } internal static int Decrypt(SafeSslHandle context, byte[] outBuffer, int offset, int count, out Ssl.SslErrorCode errorCode) { errorCode = Ssl.SslErrorCode.SSL_ERROR_NONE; - context.InputBio.SetBio(outBuffer, offset, count); + context.InputBio.SetData(outBuffer, offset, count); int retVal; unsafe diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs index d0080606829c..5887dc5629c9 100755 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs @@ -191,8 +191,8 @@ internal void MarkHandshakeCompleted() public static SafeSslHandle Create(SafeSslContextHandle context, bool isServer) { - SafeBioHandle readBio = Interop.CustomBio.CreateCustomBio(); - SafeBioHandle writeBio = Interop.CustomBio.CreateCustomBio(); + SafeBioHandle readBio = Interop.Crypto.ManagedSslBio.CreateManagedSslBio(); + SafeBioHandle writeBio = Interop.Crypto.ManagedSslBio.CreateManagedSslBio(); SafeSslHandle handle = Interop.Ssl.SslCreate(context); if (readBio.IsInvalid || writeBio.IsInvalid || handle.IsInvalid) { @@ -297,12 +297,14 @@ internal ReadBioBuffer(SafeBioHandle bioHandle) { _bioHandle = bioHandle; _handle = GCHandle.Alloc(this, GCHandleType.Normal); - Interop.CustomBio.BioSetGCHandle(_bioHandle, _handle); + Interop.Crypto.ManagedSslBio.BioSetGCHandle(_bioHandle, _handle); Interop.Crypto.BioSetShoudRetryReadFlag(bioHandle); } - public void SetBio(byte[] buffer, int offset, int length) + public void SetData(byte[] buffer, int offset, int length) { + Debug.Assert(_bytesAvailable == 0); + _byteArray = buffer; _offset = offset; _bytesAvailable = length; @@ -312,7 +314,10 @@ public int Read(Span output) { var bytesToCopy = Math.Min(output.Length, _bytesAvailable); if (bytesToCopy == 0) + { return -1; + } + var span = new Span(_byteArray, _offset, bytesToCopy); span.CopyTo(output); _offset += bytesToCopy; @@ -331,7 +336,7 @@ private void Dispose(bool isDisposing) public void Dispose() { - Dispose(false); + Dispose(true); GC.SuppressFinalize(this); } @@ -353,10 +358,10 @@ internal WriteBioBuffer(SafeBioHandle bioHandle) { _bioHandle = bioHandle; _handle = GCHandle.Alloc(this, GCHandleType.Normal); - Interop.CustomBio.BioSetGCHandle(_bioHandle, _handle); + Interop.Crypto.ManagedSslBio.BioSetGCHandle(_bioHandle, _handle); } - public void SetBio(byte[] buffer, bool isHandshake) + public void SetData(byte[] buffer, bool isHandshake) { _byteArray = buffer; _bytesWritten = 0; @@ -365,8 +370,13 @@ public void SetBio(byte[] buffer, bool isHandshake) public int TakeBytes(out byte[] output) { - var bytes = _bytesWritten; output = _byteArray; + return TakeBytes(); + } + + public int TakeBytes() + { + var bytes = _bytesWritten; _bytesWritten = 0; _byteArray = null; return bytes; @@ -374,6 +384,11 @@ public int TakeBytes(out byte[] output) public int Write(Span input) { + //Only for the handshake do we dynamically allocate + //buffers for normal encrypt operations we use a fixed + //size buffer handed to us and loop to do all the needed + //writes. This should be changed for the handshake as well + //but will require more securechannel/sslstatus changes if (_isHandshake) { if (_byteArray == null) @@ -381,6 +396,7 @@ public int Write(Span input) _byteArray = new byte[input.Length]; _bytesWritten = 0; } + else if (_byteArray.Length - _bytesWritten < input.Length) { var oldSpan = new Span(_byteArray); @@ -388,12 +404,16 @@ public int Write(Span input) oldSpan.CopyTo(_byteArray); } } - var bytesToWrite = Math.Min(input.Length, _byteArray.Length - _bytesWritten); + + int bytesToWrite = Math.Min(input.Length, _byteArray.Length - _bytesWritten); if (bytesToWrite < 1) { + //We need to return -1 to indicate that it is an async method and + //and the write should retry later rather and a zero indicating EOF Interop.Crypto.BioSetWriteFlag(_bioHandle); return -1; } + input.Slice(0, bytesToWrite).CopyTo(new Span(_byteArray, _bytesWritten)); _bytesWritten += bytesToWrite; return bytesToWrite; @@ -410,7 +430,7 @@ private void Dispose(bool isDisposing) public void Dispose() { - Dispose(false); + Dispose(true); GC.SuppressFinalize(this); } diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp b/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp index aed0260809d0..3471e32d037f 100755 --- a/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp +++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp @@ -58,27 +58,27 @@ extern "C" void CryptoNative_BioSetAppData(BIO* bio, void* data) BIO_set_ex_data(bio, 0, data); } -extern "C" void* CryptoNative_BioGetAppData(BIO* bio) -{ - return BIO_get_ex_data(bio, 0); -} - -/* -Set write flag for the custom bio -*/ extern "C" void CryptoNative_BioSetWriteFlag(BIO* bio) { BIO_set_flags(bio, BIO_FLAGS_WRITE); } -/* -Set the read and should retry flag for the custom bio -*/ extern "C" void CryptoNative_BioSetShoudRetryReadFlag(BIO* bio) { BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY | BIO_FLAGS_READ); } +typedef struct ReadWriteMethodStruct +{ + BioWriteCallback write; + BioReadCallback read; +} ReadWriteMethodStruct; + +static ReadWriteMethodStruct managedMethods = { + nullptr, + nullptr +}; + static long ControlCallback(BIO* bio, int cmd, long param, void* ptr) { (void)bio, (void)param, (void)ptr; // deliberately unused parameters @@ -104,11 +104,31 @@ static int CreateCallback(BIO* bio) return 1; } -static BIO_METHOD sslStreamCustomBio = { +static int WriteCallback(BIO* b, const char* buf, int32_t len) +{ + void* ptr = BIO_get_ex_data(b, 0); + if(ptr == nullptr) + { + return -1; + } + return managedMethods.write(b, buf, len, ptr); +} + +static int ReadCallback(BIO* b, char* buf, int32_t len) +{ + void* ptr = BIO_get_ex_data(b, 0); + if(ptr == nullptr) + { + return -1; + } + return managedMethods.read(b, buf, len, ptr); +} + +static BIO_METHOD managedSslBio = { BIO_TYPE_SOURCE_SINK, - "SslStreamCustomBio", - nullptr, - nullptr, + "Managed Ssl Bio", + WriteCallback, + ReadCallback, nullptr, nullptr, ControlCallback, @@ -117,13 +137,13 @@ static BIO_METHOD sslStreamCustomBio = { nullptr, }; -extern "C" void CryptoNative_InitCustomBioMethod(BioWriteCallback bwrite, BioReadCallback bread) +extern "C" void CryptoNative_InitManagedSslBioMethod(BioWriteCallback bwrite, BioReadCallback bread) { - sslStreamCustomBio.bwrite = bwrite; - sslStreamCustomBio.bread = bread; + managedMethods.write = bwrite; + managedMethods.read = bread; } -extern "C" BIO* CryptoNative_CreateCustomBio() +extern "C" BIO* CryptoNative_CreateManagedSslBio() { - return BIO_new(&sslStreamCustomBio); + return BIO_new(&managedSslBio); } diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.h b/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.h old mode 100755 new mode 100644 index 04feda3bb921..ce77cd11edba --- a/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.h +++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.h @@ -5,8 +5,8 @@ #include "pal_types.h" #include "opensslshim.h" -typedef int32_t (*BioWriteCallback)(BIO* b, const char* buf, int32_t len); -typedef int32_t (*BioReadCallback)(BIO* b, char* buf, int32_t len); +typedef int32_t (*BioWriteCallback)(BIO* b, const char* buf, int32_t len, void* appData); +typedef int32_t (*BioReadCallback)(BIO* b, char* buf, int32_t len, void* appData); /* Creates a new memory-backed BIO instance. @@ -57,16 +57,12 @@ Shims the BIO_ctrl_pending method. Returns the number of pending characters in the BIOs read and write buffers. */ extern "C" int32_t CryptoNative_BioCtrlPending(BIO* bio); + /* Adds app data to the extension slot of the bio */ extern "C" void CryptoNative_BioSetAppData(BIO* bio, void* data); -/* -Gets app data from the extension slot of the bio -*/ -extern "C" void* CryptoNative_BioGetAppData(BIO* bio); - /* Set write flag for the custom bio */ @@ -78,13 +74,13 @@ Set the read and should retry flag for the custom bio extern "C" void CryptoNative_BioSetShoudRetryReadFlag(BIO* bio); /* -Creates a custom BIO instance. +Creates a ManagedSslBio instance. */ -extern "C" BIO* CryptoNative_CreateCustomBio(); +extern "C" BIO* CryptoNative_CreateManagedSslBio(); /* -Sets the managed callbacks that are used by the custom bio +Sets the managed callbacks that are used by the ManagedSslBio for reads and writes */ -extern "C" void CryptoNative_InitCustomBioMethod(BioWriteCallback bwrite, BioReadCallback bread); +extern "C" void CryptoNative_InitManagedSslBioMethod(BioWriteCallback bwrite, BioReadCallback bread); diff --git a/src/System.Net.Http/src/System.Net.Http.csproj b/src/System.Net.Http/src/System.Net.Http.csproj old mode 100644 new mode 100755 index 89d4fa22011e..23fe7bbf349e --- a/src/System.Net.Http/src/System.Net.Http.csproj +++ b/src/System.Net.Http/src/System.Net.Http.csproj @@ -314,8 +314,8 @@ Common\Interop\Unix\System.Security.Cryptography.Native\Interop.BIO.cs - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.BIO.Custom.cs + + Common\Interop\Unix\System.Security.Cryptography.Native\Interop.ManagedSslBio.cs Common\Interop\Unix\System.Security.Cryptography.Native\Interop.ERR.cs diff --git a/src/System.Net.Security/ref/System.Net.Security.csproj b/src/System.Net.Security/ref/System.Net.Security.csproj old mode 100644 new mode 100755 diff --git a/src/System.Net.Security/src/System.Net.Security.csproj b/src/System.Net.Security/src/System.Net.Security.csproj index bb0ff4181d81..0b32e6f54067 100755 --- a/src/System.Net.Security/src/System.Net.Security.csproj +++ b/src/System.Net.Security/src/System.Net.Security.csproj @@ -273,8 +273,8 @@ Common\Interop\Unix\System.Security.Cryptography.Native\Interop.BIO.cs - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.BIO.Custom.cs + + Common\Interop\Unix\System.Security.Cryptography.Native\Interop.ManagedSslBio.cs Common\Interop\Unix\System.Security.Cryptography.Native\Interop.ERR.cs diff --git a/src/System.Net.Security/src/System/Net/Security/SecureChannel.cs b/src/System.Net.Security/src/System/Net/Security/SecureChannel.cs old mode 100755 new mode 100644 index 15a5f9ecb13a..a72829e6b46e --- a/src/System.Net.Security/src/System/Net/Security/SecureChannel.cs +++ b/src/System.Net.Security/src/System/Net/Security/SecureChannel.cs @@ -949,6 +949,7 @@ internal SecurityStatusPal Encrypt(byte[] buffer, int offset, int size, ref byte break; } } + return secStatus; } diff --git a/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs b/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs old mode 100755 new mode 100644 index 129d9d7e1788..7e84e48cdb31 --- a/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs +++ b/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs @@ -387,6 +387,7 @@ private void StartWriting(byte[] buffer, int offset, int count, AsyncProtocolReq { PinnableBufferCacheEventSource.Log.DebugMessage3("In System.Net._SslStream.StartWriting Using Pinnable", this.GetHashCode(), count, PinnableBufferCacheEventSource.AddressOfByteArray(outBuffer)); } + try { SecurityStatusPal status = _sslState.EncryptData(buffer, offset, chunkBytes, ref outBuffer, out encryptedBytes); @@ -401,6 +402,7 @@ private void StartWriting(byte[] buffer, int offset, int count, AsyncProtocolReq ProtocolToken message = new ProtocolToken(null, status); throw new IOException(SR.net_io_encrypt, message.GetException()); } + } catch { @@ -428,6 +430,7 @@ private void StartWriting(byte[] buffer, int offset, int count, AsyncProtocolReq } TaskToApm.End(ar); } + } else { @@ -442,6 +445,7 @@ private void StartWriting(byte[] buffer, int offset, int count, AsyncProtocolReq _sslState.FinishWrite(); } while (count != 0); + } if (asyncRequest != null) diff --git a/src/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs b/src/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs old mode 100755 new mode 100644 index bf9cabbc19d7..ad53e0ad87ad --- a/src/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs +++ b/src/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs @@ -67,6 +67,7 @@ public static SecurityStatusPal DecryptMessage(SafeDeleteContext securityContext { count = resultSize; } + return retVal; } diff --git a/src/System.Net.Security/src/System/Net/Security/StreamSizes.Unix.cs b/src/System.Net.Security/src/System/Net/Security/StreamSizes.Unix.cs old mode 100755 new mode 100644 From 5ba0c75f82648ea914b840af824eb1677f67a019 Mon Sep 17 00:00:00 2001 From: bench Date: Wed, 9 Aug 2017 23:31:56 +0100 Subject: [PATCH 37/54] Fixing file bit mode to remove execute caused by windows file copy --- src/System.Net.Http/src/System.Net.Http.csproj | 0 src/System.Net.Security/ref/System.Net.Security.csproj | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 src/System.Net.Http/src/System.Net.Http.csproj mode change 100755 => 100644 src/System.Net.Security/ref/System.Net.Security.csproj diff --git a/src/System.Net.Http/src/System.Net.Http.csproj b/src/System.Net.Http/src/System.Net.Http.csproj old mode 100755 new mode 100644 diff --git a/src/System.Net.Security/ref/System.Net.Security.csproj b/src/System.Net.Security/ref/System.Net.Security.csproj old mode 100755 new mode 100644 From a049480d2a642596d28dc8966b2ab59a3a612cda Mon Sep 17 00:00:00 2001 From: bench Date: Wed, 9 Aug 2017 23:42:17 +0100 Subject: [PATCH 38/54] More bit mode changes --- .../Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs | 0 .../Unix/System.Security.Cryptography.Native/Interop.Ssl.cs | 0 src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp | 0 src/System.Net.Security/src/System.Net.Security.csproj | 0 4 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs mode change 100755 => 100644 src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs mode change 100755 => 100644 src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp mode change 100755 => 100644 src/System.Net.Security/src/System.Net.Security.csproj diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs old mode 100755 new mode 100644 diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs old mode 100755 new mode 100644 diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp b/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp old mode 100755 new mode 100644 diff --git a/src/System.Net.Security/src/System.Net.Security.csproj b/src/System.Net.Security/src/System.Net.Security.csproj old mode 100755 new mode 100644 From fc6f32791827ff5e368011993cf58a1e83343179 Mon Sep 17 00:00:00 2001 From: Drawaes Date: Fri, 18 Aug 2017 17:04:42 +0100 Subject: [PATCH 39/54] Fix style using clang-format and moved statics and typedefs to the top --- .../pal_bio.cpp | 133 +++++++++--------- 1 file changed, 65 insertions(+), 68 deletions(-) diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp b/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp index 3471e32d037f..4311694f3061 100644 --- a/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp +++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_bio.cpp @@ -6,78 +6,13 @@ #include -extern "C" BIO* CryptoNative_CreateMemoryBio() -{ - return BIO_new(BIO_s_mem()); -} - -extern "C" BIO* CryptoNative_BioNewFile(const char* filename, const char* mode) -{ - return BIO_new_file(filename, mode); -} - -extern "C" int32_t CryptoNative_BioDestroy(BIO* a) -{ - return BIO_free(a); -} - -extern "C" int32_t CryptoNative_BioGets(BIO* b, char* buf, int32_t size) -{ - return BIO_gets(b, buf, size); -} - -extern "C" int32_t CryptoNative_BioRead(BIO* b, void* buf, int32_t len) -{ - return BIO_read(b, buf, len); -} - -extern "C" int32_t CryptoNative_BioWrite(BIO* b, const void* buf, int32_t len) -{ - return BIO_write(b, buf, len); -} - -extern "C" int32_t CryptoNative_GetMemoryBioSize(BIO* bio) -{ - long ret = BIO_get_mem_data(bio, nullptr); - - // BIO_get_mem_data returns the memory size, which will always be - // an int32. - assert(ret <= INT32_MAX); - return static_cast(ret); -} - -extern "C" int32_t CryptoNative_BioCtrlPending(BIO* bio) -{ - size_t result = BIO_ctrl_pending(bio); - assert(result <= INT32_MAX); - return static_cast(result); -} - -extern "C" void CryptoNative_BioSetAppData(BIO* bio, void* data) -{ - BIO_set_ex_data(bio, 0, data); -} - -extern "C" void CryptoNative_BioSetWriteFlag(BIO* bio) -{ - BIO_set_flags(bio, BIO_FLAGS_WRITE); -} - -extern "C" void CryptoNative_BioSetShoudRetryReadFlag(BIO* bio) -{ - BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY | BIO_FLAGS_READ); -} - typedef struct ReadWriteMethodStruct { BioWriteCallback write; BioReadCallback read; } ReadWriteMethodStruct; -static ReadWriteMethodStruct managedMethods = { - nullptr, - nullptr -}; +static ReadWriteMethodStruct managedMethods = {nullptr, nullptr}; static long ControlCallback(BIO* bio, int cmd, long param, void* ptr) { @@ -107,7 +42,7 @@ static int CreateCallback(BIO* bio) static int WriteCallback(BIO* b, const char* buf, int32_t len) { void* ptr = BIO_get_ex_data(b, 0); - if(ptr == nullptr) + if (ptr == nullptr) { return -1; } @@ -117,7 +52,7 @@ static int WriteCallback(BIO* b, const char* buf, int32_t len) static int ReadCallback(BIO* b, char* buf, int32_t len) { void* ptr = BIO_get_ex_data(b, 0); - if(ptr == nullptr) + if (ptr == nullptr) { return -1; } @@ -137,6 +72,68 @@ static BIO_METHOD managedSslBio = { nullptr, }; +extern "C" BIO* CryptoNative_CreateMemoryBio() +{ + return BIO_new(BIO_s_mem()); +} + +extern "C" BIO* CryptoNative_BioNewFile(const char* filename, const char* mode) +{ + return BIO_new_file(filename, mode); +} + +extern "C" int32_t CryptoNative_BioDestroy(BIO* a) +{ + return BIO_free(a); +} + +extern "C" int32_t CryptoNative_BioGets(BIO* b, char* buf, int32_t size) +{ + return BIO_gets(b, buf, size); +} + +extern "C" int32_t CryptoNative_BioRead(BIO* b, void* buf, int32_t len) +{ + return BIO_read(b, buf, len); +} + +extern "C" int32_t CryptoNative_BioWrite(BIO* b, const void* buf, int32_t len) +{ + return BIO_write(b, buf, len); +} + +extern "C" int32_t CryptoNative_GetMemoryBioSize(BIO* bio) +{ + long ret = BIO_get_mem_data(bio, nullptr); + + // BIO_get_mem_data returns the memory size, which will always be + // an int32. + assert(ret <= INT32_MAX); + return static_cast(ret); +} + +extern "C" int32_t CryptoNative_BioCtrlPending(BIO* bio) +{ + size_t result = BIO_ctrl_pending(bio); + assert(result <= INT32_MAX); + return static_cast(result); +} + +extern "C" void CryptoNative_BioSetAppData(BIO* bio, void* data) +{ + BIO_set_ex_data(bio, 0, data); +} + +extern "C" void CryptoNative_BioSetWriteFlag(BIO* bio) +{ + BIO_set_flags(bio, BIO_FLAGS_WRITE); +} + +extern "C" void CryptoNative_BioSetShoudRetryReadFlag(BIO* bio) +{ + BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY | BIO_FLAGS_READ); +} + extern "C" void CryptoNative_InitManagedSslBioMethod(BioWriteCallback bwrite, BioReadCallback bread) { managedMethods.write = bwrite; From 8fd60cca3915b5af4e0f284c6603755a4e1d6377 Mon Sep 17 00:00:00 2001 From: bench Date: Fri, 18 Aug 2017 17:23:49 +0100 Subject: [PATCH 40/54] Reacting to review changes --- .../Interop.OpenSsl.cs | 15 ++++++++----- .../Interop.Ssl.cs | 22 ++++++++++--------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs index bb32011cf1f4..bc71fab6029a 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs @@ -97,7 +97,7 @@ internal static SafeSslHandle AllocateSslContext(SslProtocols protocols, SafeX50 Ssl.SslCtxSetVerify(innerContext, s_verifyClientCertificate); - //update the client CA list + // update the client CA list UpdateCAListFromRootStore(innerContext); } @@ -203,7 +203,7 @@ internal static int Encrypt(SafeSslHandle context, byte[] input, int offset, int case Ssl.SslErrorCode.SSL_ERROR_ZERO_RETURN: case Ssl.SslErrorCode.SSL_ERROR_WANT_READ: break; - //indicates we need to write the out buffer and write again + // indicates we need to write the out buffer and write again case Ssl.SslErrorCode.SSL_ERROR_WANT_WRITE: break; default: @@ -216,6 +216,9 @@ internal static int Encrypt(SafeSslHandle context, byte[] input, int offset, int internal static int Decrypt(SafeSslHandle context, byte[] outBuffer, int offset, int count, out Ssl.SslErrorCode errorCode) { + Debug.Assert(offset >= 0); + Debug.Assert(offset <= outBuffer.Length); + errorCode = Ssl.SslErrorCode.SSL_ERROR_NONE; context.InputBio.SetData(outBuffer, offset, count); @@ -225,7 +228,7 @@ internal static int Decrypt(SafeSslHandle context, byte[] outBuffer, int offset, { fixed (byte* fixedBuffer = outBuffer) { - retVal = Ssl.SslRead(context, fixedBuffer + offset, outBuffer.Length); + retVal = Ssl.SslRead(context, fixedBuffer + offset, outBuffer.Length - offset); } } @@ -327,8 +330,8 @@ private static void AddX509Names(SafeX509NameStackHandle nameStack, StoreLocatio foreach (X509Certificate2 certificate in store.Certificates) { - //Check if issuer name is already present - //Avoiding duplicate names + // Check if issuer name is already present + // Avoiding duplicate names if (!issuerNameHashSet.Add(certificate.Issuer)) { continue; @@ -438,7 +441,7 @@ private static void SetSslCertificate(SafeSslContextHandle contextPtr, SafeX509H throw CreateSslException(SR.net_ssl_use_private_key_failed); } - //check private key + // check private key retVal = Ssl.SslCtxCheckPrivateKey(contextPtr); if (1 != retVal) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs index 5887dc5629c9..1b6f909b6c03 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs @@ -312,7 +312,7 @@ public void SetData(byte[] buffer, int offset, int length) public int Read(Span output) { - var bytesToCopy = Math.Min(output.Length, _bytesAvailable); + int bytesToCopy = Math.Min(output.Length, _bytesAvailable); if (bytesToCopy == 0) { return -1; @@ -325,7 +325,7 @@ public int Read(Span output) return bytesToCopy; } - //Bio is already released by the ssl object + // Bio is already released by the ssl object private void Dispose(bool isDisposing) { if (_handle.IsAllocated) @@ -363,6 +363,8 @@ internal WriteBioBuffer(SafeBioHandle bioHandle) public void SetData(byte[] buffer, bool isHandshake) { + Debug.Assert(_byteArray == null); + _byteArray = buffer; _bytesWritten = 0; _isHandshake = isHandshake; @@ -384,11 +386,11 @@ public int TakeBytes() public int Write(Span input) { - //Only for the handshake do we dynamically allocate - //buffers for normal encrypt operations we use a fixed - //size buffer handed to us and loop to do all the needed - //writes. This should be changed for the handshake as well - //but will require more securechannel/sslstatus changes + // Only for the handshake do we dynamically allocate + // buffers for normal encrypt operations we use a fixed + // size buffer handed to us and loop to do all the needed + // writes. This should be changed for the handshake as well + // but will require more securechannel/sslstatus changes if (_isHandshake) { if (_byteArray == null) @@ -408,8 +410,8 @@ public int Write(Span input) int bytesToWrite = Math.Min(input.Length, _byteArray.Length - _bytesWritten); if (bytesToWrite < 1) { - //We need to return -1 to indicate that it is an async method and - //and the write should retry later rather and a zero indicating EOF + // We need to return -1 to indicate that it is an async method and + // and the write should retry later rather and a zero indicating EOF Interop.Crypto.BioSetWriteFlag(_bioHandle); return -1; } @@ -419,7 +421,7 @@ public int Write(Span input) return bytesToWrite; } - //Bio is already released by the ssl object + // Bio is already released by the ssl object private void Dispose(bool isDisposing) { if (_handle.IsAllocated) From f51c9e8f49f54229dec990a51f6ba12273a92860 Mon Sep 17 00:00:00 2001 From: bench Date: Fri, 18 Aug 2017 18:00:38 +0100 Subject: [PATCH 41/54] Changed Take Bytes --- .../Interop.OpenSsl.cs | 4 +++- .../System.Security.Cryptography.Native/Interop.Ssl.cs | 10 ++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs index bc71fab6029a..cfc3f4f12c07 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs @@ -211,7 +211,9 @@ internal static int Encrypt(SafeSslHandle context, byte[] input, int offset, int } } - return context.OutputBio.TakeBytes(); + var bytesWritten = context.OutputBio.BytesWritten; + context.OutputBio.Reset(); + return bytesWritten; } internal static int Decrypt(SafeSslHandle context, byte[] outBuffer, int offset, int count, out Ssl.SslErrorCode errorCode) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs index 1b6f909b6c03..a0850d1c9f01 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs @@ -361,6 +361,8 @@ internal WriteBioBuffer(SafeBioHandle bioHandle) Interop.Crypto.ManagedSslBio.BioSetGCHandle(_bioHandle, _handle); } + public int BytesWritten => _bytesWritten; + public void SetData(byte[] buffer, bool isHandshake) { Debug.Assert(_byteArray == null); @@ -373,15 +375,15 @@ public void SetData(byte[] buffer, bool isHandshake) public int TakeBytes(out byte[] output) { output = _byteArray; - return TakeBytes(); + var bytes = _bytesWritten; + Reset(); + return bytes; } - public int TakeBytes() + public void Reset() { - var bytes = _bytesWritten; _bytesWritten = 0; _byteArray = null; - return bytes; } public int Write(Span input) From 03da084c05e9ce8c84732c88dd3af7e53a3f2275 Mon Sep 17 00:00:00 2001 From: bench Date: Fri, 18 Aug 2017 18:15:56 +0100 Subject: [PATCH 42/54] nit var --- .../Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs index cfc3f4f12c07..8916ed8596bd 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs @@ -211,7 +211,7 @@ internal static int Encrypt(SafeSslHandle context, byte[] input, int offset, int } } - var bytesWritten = context.OutputBio.BytesWritten; + int bytesWritten = context.OutputBio.BytesWritten; context.OutputBio.Reset(); return bytesWritten; } From 172a1de13a32599f854f114913e568d0c6747998 Mon Sep 17 00:00:00 2001 From: bench Date: Fri, 18 Aug 2017 18:19:58 +0100 Subject: [PATCH 43/54] nit sln changes --- .../System.Net.Security.sln | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/System.Net.Security/System.Net.Security.sln b/src/System.Net.Security/System.Net.Security.sln index 1740ede2152d..88a324c58b9d 100644 --- a/src/System.Net.Security/System.Net.Security.sln +++ b/src/System.Net.Security/System.Net.Security.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26711.1 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Net.Security.Tests", "tests\FunctionalTests\System.Net.Security.Tests.csproj", "{A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}" ProjectSection(ProjectDependencies) = postProject @@ -31,16 +31,16 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.Debug|Any CPU.ActiveCfg = netcoreapp-Unix-Debug|Any CPU - {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.Debug|Any CPU.Build.0 = netcoreapp-Unix-Debug|Any CPU + {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.Debug|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Debug|Any CPU + {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.Debug|Any CPU.Build.0 = netcoreapp-Windows_NT-Debug|Any CPU {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|Any CPU {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.Release|Any CPU.Build.0 = netcoreapp-Windows_NT-Release|Any CPU - {0D174EA9-9E61-4519-8D31-7BD2331A1982}.Debug|Any CPU.ActiveCfg = netstandard-Unix-Debug|Any CPU - {0D174EA9-9E61-4519-8D31-7BD2331A1982}.Debug|Any CPU.Build.0 = netstandard-Unix-Debug|Any CPU + {0D174EA9-9E61-4519-8D31-7BD2331A1982}.Debug|Any CPU.ActiveCfg = netstandard-Windows_NT-Debug|Any CPU + {0D174EA9-9E61-4519-8D31-7BD2331A1982}.Debug|Any CPU.Build.0 = netstandard-Windows_NT-Debug|Any CPU {0D174EA9-9E61-4519-8D31-7BD2331A1982}.Release|Any CPU.ActiveCfg = netstandard-Windows_NT-Release|Any CPU {0D174EA9-9E61-4519-8D31-7BD2331A1982}.Release|Any CPU.Build.0 = netstandard-Windows_NT-Release|Any CPU - {89F37791-6254-4D60-AB96-ACD3CCA0E771}.Debug|Any CPU.ActiveCfg = netcoreapp-Unix-Debug|Any CPU - {89F37791-6254-4D60-AB96-ACD3CCA0E771}.Debug|Any CPU.Build.0 = netcoreapp-Unix-Debug|Any CPU + {89F37791-6254-4D60-AB96-ACD3CCA0E771}.Debug|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Debug|Any CPU + {89F37791-6254-4D60-AB96-ACD3CCA0E771}.Debug|Any CPU.Build.0 = netcoreapp-Windows_NT-Debug|Any CPU {89F37791-6254-4D60-AB96-ACD3CCA0E771}.Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|Any CPU {89F37791-6254-4D60-AB96-ACD3CCA0E771}.Release|Any CPU.Build.0 = netcoreapp-Windows_NT-Release|Any CPU {A7488FC0-9A8F-4EF9-BC3E-C5EBA47E13F8}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU @@ -57,7 +57,4 @@ Global {89F37791-6254-4D60-AB96-ACD3CCA0E771} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} {A7488FC0-9A8F-4EF9-BC3E-C5EBA47E13F8} = {2E666815-2EDB-464B-9DF6-380BF4789AD4} EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {E4326E62-D794-49A8-AE7D-85903688E655} - EndGlobalSection -EndGlobal +EndGlobal \ No newline at end of file From 8249c156ae40b355a7db0ce29e46441102151280 Mon Sep 17 00:00:00 2001 From: bench Date: Fri, 18 Aug 2017 19:10:21 +0100 Subject: [PATCH 44/54] removed initialize for static constructor, nit readonly --- .../Interop.ManagedSslBio.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.ManagedSslBio.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.ManagedSslBio.cs index 7dc8df187f5b..7b88fba9a078 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.ManagedSslBio.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.ManagedSslBio.cs @@ -9,14 +9,12 @@ internal static partial class Crypto { internal static class ManagedSslBio { - private unsafe static ReadDelegate s_readDelegate; - private unsafe static WriteDelegate s_writeDelegate; - - static ManagedSslBio() => Initialize(); + private unsafe readonly static ReadDelegate s_readDelegate; + private unsafe readonly static WriteDelegate s_writeDelegate; internal static SafeBioHandle CreateManagedSslBio() => Crypto.CreateManagedSslBio(); - private unsafe static void Initialize() + unsafe static ManagedSslBio() { s_writeDelegate = Write; s_readDelegate = Read; From 5e97bf7d61dfbef3d5baa940a22ac2c70ed48c66 Mon Sep 17 00:00:00 2001 From: bench Date: Fri, 18 Aug 2017 19:10:21 +0100 Subject: [PATCH 45/54] removed initialize for static constructor, nit readonly --- src/System.Net.Security/System.Net.Security.sln | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/System.Net.Security/System.Net.Security.sln b/src/System.Net.Security/System.Net.Security.sln index 88a324c58b9d..234b3b226483 100644 --- a/src/System.Net.Security/System.Net.Security.sln +++ b/src/System.Net.Security/System.Net.Security.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 +# Visual Studio 15 +VisualStudioVersion = 15.0.26730.3 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Net.Security.Tests", "tests\FunctionalTests\System.Net.Security.Tests.csproj", "{A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}" ProjectSection(ProjectDependencies) = postProject @@ -57,4 +57,7 @@ Global {89F37791-6254-4D60-AB96-ACD3CCA0E771} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} {A7488FC0-9A8F-4EF9-BC3E-C5EBA47E13F8} = {2E666815-2EDB-464B-9DF6-380BF4789AD4} EndGlobalSection -EndGlobal \ No newline at end of file + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {21E9B22F-61C2-4AAF-A44C-CF37265A7AC5} + EndGlobalSection +EndGlobal From f8e86a6687e976852089e5a4607c16a3fa8a308d Mon Sep 17 00:00:00 2001 From: bench Date: Fri, 18 Aug 2017 19:20:12 +0100 Subject: [PATCH 46/54] Changed if to be more concise --- .../Interop.ManagedSslBio.cs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.ManagedSslBio.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.ManagedSslBio.cs index 7b88fba9a078..2a52852eb792 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.ManagedSslBio.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.ManagedSslBio.cs @@ -23,16 +23,7 @@ unsafe static ManagedSslBio() internal static void BioSetGCHandle(SafeBioHandle bio, GCHandle handle) { - IntPtr pointer; - if (handle.IsAllocated) - { - pointer = GCHandle.ToIntPtr(handle); - } - else - { - pointer = IntPtr.Zero; - } - + IntPtr pointer = handle.IsAllocated ? GCHandle.ToIntPtr(handle) : IntPtr.Zero; Crypto.BioSetAppData(bio, pointer); } From 9a800a311cb905796c6b5db1a7fc301bb1a67517 Mon Sep 17 00:00:00 2001 From: Drawaes Date: Fri, 18 Aug 2017 19:44:08 +0100 Subject: [PATCH 47/54] Removed finalizers, added assert removed usless is allocated test. added "." in comment --- .../Interop.ManagedSslBio.cs | 8 +++-- .../Interop.Ssl.cs | 35 ++++--------------- 2 files changed, 11 insertions(+), 32 deletions(-) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.ManagedSslBio.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.ManagedSslBio.cs index 2a52852eb792..011f402b6c2d 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.ManagedSslBio.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.ManagedSslBio.cs @@ -13,7 +13,7 @@ internal static class ManagedSslBio private unsafe readonly static WriteDelegate s_writeDelegate; internal static SafeBioHandle CreateManagedSslBio() => Crypto.CreateManagedSslBio(); - + unsafe static ManagedSslBio() { s_writeDelegate = Write; @@ -30,8 +30,9 @@ internal static void BioSetGCHandle(SafeBioHandle bio, GCHandle handle) private static unsafe int Write(IntPtr bio, void* input, int size, IntPtr data) { GCHandle handle = GCHandle.FromIntPtr(data); + Debug.Assert(handle.IsAllocated); - if (handle.IsAllocated && handle.Target is SafeSslHandle.WriteBioBuffer buffer) + if (handle.Target is SafeSslHandle.WriteBioBuffer buffer) { return buffer.Write(new Span(input, size)); } @@ -42,8 +43,9 @@ private static unsafe int Write(IntPtr bio, void* input, int size, IntPtr data) private static unsafe int Read(IntPtr bio, void* output, int size, IntPtr data) { GCHandle handle = GCHandle.FromIntPtr(data); + Debug.Assert(handle.IsAllocated); - if (handle.IsAllocated && handle.Target is SafeSslHandle.ReadBioBuffer buffer) + if (handle.Target is SafeSslHandle.ReadBioBuffer buffer) { return buffer.Read(new Span(output, size)); } diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs index a0850d1c9f01..212e0e92ba4e 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs @@ -287,7 +287,7 @@ internal SafeSslHandle(IntPtr validSslPointer, bool ownsHandle) : base(IntPtr.Ze internal class ReadBioBuffer : IDisposable { - private SafeBioHandle _bioHandle; + private readonly SafeBioHandle _bioHandle; private GCHandle _handle; private int _bytesAvailable; private byte[] _byteArray; @@ -326,29 +326,18 @@ public int Read(Span output) } // Bio is already released by the ssl object - private void Dispose(bool isDisposing) + public void Dispose() { if (_handle.IsAllocated) { _handle.Free(); } } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - ~ReadBioBuffer() - { - Dispose(false); - } } internal class WriteBioBuffer : IDisposable { - private SafeBioHandle _bioHandle; + private readonly SafeBioHandle _bioHandle; private GCHandle _handle; private byte[] _byteArray; private int _bytesWritten; @@ -375,7 +364,7 @@ public void SetData(byte[] buffer, bool isHandshake) public int TakeBytes(out byte[] output) { output = _byteArray; - var bytes = _bytesWritten; + int bytes = _bytesWritten; Reset(); return bytes; } @@ -389,7 +378,7 @@ public void Reset() public int Write(Span input) { // Only for the handshake do we dynamically allocate - // buffers for normal encrypt operations we use a fixed + // buffers. For normal encrypt operations we use a fixed // size buffer handed to us and loop to do all the needed // writes. This should be changed for the handshake as well // but will require more securechannel/sslstatus changes @@ -408,7 +397,6 @@ public int Write(Span input) oldSpan.CopyTo(_byteArray); } } - int bytesToWrite = Math.Min(input.Length, _byteArray.Length - _bytesWritten); if (bytesToWrite < 1) { @@ -424,24 +412,13 @@ public int Write(Span input) } // Bio is already released by the ssl object - private void Dispose(bool isDisposing) + public void Dispose() { if (_handle.IsAllocated) { _handle.Free(); } } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - ~WriteBioBuffer() - { - Dispose(false); - } } } } From 90eb0f71aef01cd94a750f4680ae7eee1f8b5b4a Mon Sep 17 00:00:00 2001 From: Drawaes Date: Fri, 18 Aug 2017 19:50:40 +0100 Subject: [PATCH 48/54] wrong space removed --- .../Unix/System.Security.Cryptography.Native/Interop.Ssl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs index 212e0e92ba4e..de7121b9800f 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs @@ -389,7 +389,6 @@ public int Write(Span input) _byteArray = new byte[input.Length]; _bytesWritten = 0; } - else if (_byteArray.Length - _bytesWritten < input.Length) { var oldSpan = new Span(_byteArray); @@ -397,6 +396,7 @@ public int Write(Span input) oldSpan.CopyTo(_byteArray); } } + int bytesToWrite = Math.Min(input.Length, _byteArray.Length - _bytesWritten); if (bytesToWrite < 1) { From 3f35c6875165df2528c15e285358016890920404 Mon Sep 17 00:00:00 2001 From: Drawaes Date: Fri, 18 Aug 2017 21:03:11 +0100 Subject: [PATCH 49/54] Changed span to bye[], changed continuation to run sync and to propagate errors --- .../Interop.Ssl.cs | 3 +- .../System/Net/Security/SslStreamInternal.cs | 30 ++++++++++++------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs index de7121b9800f..f55dc2a89f78 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs @@ -391,8 +391,9 @@ public int Write(Span input) } else if (_byteArray.Length - _bytesWritten < input.Length) { - var oldSpan = new Span(_byteArray); + byte[] oldArray = _byteArray; _byteArray = new byte[input.Length + _bytesWritten]; + Buffer.BlockCopy(oldArray, 0, _byteArray, 0, _bytesWritten); oldSpan.CopyTo(_byteArray); } } diff --git a/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs b/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs index 7e84e48cdb31..f899d1940a87 100644 --- a/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs +++ b/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs @@ -53,7 +53,11 @@ internal SslStreamInternal(SslState sslState) _decryptedBytesOffset = 0; _decryptedBytesCount = 0; - _freeBufferAction = (_, buffer) => FreeBuffer((byte[])buffer); + _freeBufferAction = (task, buffer) => + { + FreeBuffer((byte[])buffer); + task.GetAwaiter().GetResult(); // propagate any exception + }; } // If we have a read buffer from the pinnable cache, return it. @@ -415,14 +419,15 @@ private void StartWriting(byte[] buffer, int offset, int count, AsyncProtocolReq { // Prepare for the next request. asyncRequest.SetNextRequest(buffer, offset + chunkBytes, count - chunkBytes, s_resumeAsyncWriteCallback); - Task t = _sslState.InnerStream.WriteAsync(outBuffer, 0, encryptedBytes) - .ContinueWith(_freeBufferAction, outBuffer); + Task t = _sslState.InnerStream.WriteAsync(outBuffer, 0, encryptedBytes); if (t.IsCompleted) { + FreeBuffer(outBuffer); t.GetAwaiter().GetResult(); } else { + t = t.ContinueWith(_freeBufferAction, outBuffer, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); IAsyncResult ar = TaskToApm.Begin(t, s_writeCallback, asyncRequest); if (!ar.CompletedSynchronously) { @@ -434,8 +439,14 @@ private void StartWriting(byte[] buffer, int offset, int count, AsyncProtocolReq } else { - _sslState.InnerStream.Write(outBuffer, 0, encryptedBytes); - FreeBuffer(outBuffer); + try + { + _sslState.InnerStream.Write(outBuffer, 0, encryptedBytes); + } + finally + { + FreeBuffer(outBuffer); + } } offset += chunkBytes; @@ -447,11 +458,7 @@ private void StartWriting(byte[] buffer, int offset, int count, AsyncProtocolReq } while (count != 0); } - - if (asyncRequest != null) - { - asyncRequest.CompleteUser(); - } + asyncRequest?.CompleteUser(); } private void FreeBuffer(byte[] buffer) @@ -814,7 +821,8 @@ private int ProcessFrameBody(int readBytes, byte[] buffer, int offset, int count private int ProcessReadErrorCode(SecurityStatusPal status, AsyncProtocolRequest asyncRequest, byte[] extraBuffer) { ProtocolToken message = new ProtocolToken(null, status); - if (NetEventSource.IsEnabled) NetEventSource.Info(null, $"***Processing an error Status = {message.Status}"); + if (NetEventSource.IsEnabled) + NetEventSource.Info(null, $"***Processing an error Status = {message.Status}"); if (message.Renegotiate) { From 155e8e923254e41d39bcac1fac8ace96877b6e21 Mon Sep 17 00:00:00 2001 From: Drawaes Date: Fri, 18 Aug 2017 21:17:59 +0100 Subject: [PATCH 50/54] Fixed compile error --- .../Unix/System.Security.Cryptography.Native/Interop.Ssl.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs index f55dc2a89f78..05c7f0e69e86 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs @@ -394,7 +394,6 @@ public int Write(Span input) byte[] oldArray = _byteArray; _byteArray = new byte[input.Length + _bytesWritten]; Buffer.BlockCopy(oldArray, 0, _byteArray, 0, _bytesWritten); - oldSpan.CopyTo(_byteArray); } } From e3f1577911170bf828830779c72c01ad1c5107a9 Mon Sep 17 00:00:00 2001 From: bench Date: Sat, 19 Aug 2017 02:50:36 +0100 Subject: [PATCH 51/54] Reverted Continutation --- .../src/System/Net/Security/SslStreamInternal.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) mode change 100644 => 100755 src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs diff --git a/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs b/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs old mode 100644 new mode 100755 index f899d1940a87..a75d1b9016e8 --- a/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs +++ b/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs @@ -419,15 +419,13 @@ private void StartWriting(byte[] buffer, int offset, int count, AsyncProtocolReq { // Prepare for the next request. asyncRequest.SetNextRequest(buffer, offset + chunkBytes, count - chunkBytes, s_resumeAsyncWriteCallback); - Task t = _sslState.InnerStream.WriteAsync(outBuffer, 0, encryptedBytes); + Task t = _sslState.InnerStream.WriteAsync(outBuffer, 0, encryptedBytes).ContinueWith(_freeBufferAction, outBuffer); if (t.IsCompleted) { - FreeBuffer(outBuffer); t.GetAwaiter().GetResult(); } else { - t = t.ContinueWith(_freeBufferAction, outBuffer, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); IAsyncResult ar = TaskToApm.Begin(t, s_writeCallback, asyncRequest); if (!ar.CompletedSynchronously) { From c67a9e2cf74d68d4485eefc92b042fd444a36484 Mon Sep 17 00:00:00 2001 From: bench Date: Sun, 20 Aug 2017 18:48:36 +0100 Subject: [PATCH 52/54] Fixed bug around write being triggered during decrypt. Now correctly returns -1 instead of throw for a null buffer --- .../Unix/System.Security.Cryptography.Native/Interop.Ssl.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) mode change 100644 => 100755 src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs old mode 100644 new mode 100755 index 05c7f0e69e86..89658e82d896 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs @@ -396,8 +396,7 @@ public int Write(Span input) Buffer.BlockCopy(oldArray, 0, _byteArray, 0, _bytesWritten); } } - - int bytesToWrite = Math.Min(input.Length, _byteArray.Length - _bytesWritten); + int bytesToWrite = Math.Min(input.Length, _byteArray?.Length ?? 0 - _bytesWritten); if (bytesToWrite < 1) { // We need to return -1 to indicate that it is an async method and From a1ea5b5b2d8174dcc9512ad1b57fca3abf953c00 Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Sun, 20 Aug 2017 21:00:36 +0100 Subject: [PATCH 53/54] PinnableBufferCache -> ArrayPool --- .../src/System.Net.Security.csproj | 2 +- .../System/Net/Security/SslStreamInternal.cs | 65 +- .../src/System/PinnableBufferCache.cs | 589 ------------------ 3 files changed, 21 insertions(+), 635 deletions(-) delete mode 100644 src/System.Net.Security/src/System/PinnableBufferCache.cs diff --git a/src/System.Net.Security/src/System.Net.Security.csproj b/src/System.Net.Security/src/System.Net.Security.csproj index 0b32e6f54067..40e180d13c4d 100644 --- a/src/System.Net.Security/src/System.Net.Security.csproj +++ b/src/System.Net.Security/src/System.Net.Security.csproj @@ -18,7 +18,6 @@ - @@ -389,6 +388,7 @@ + diff --git a/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs b/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs index a75d1b9016e8..cf71e4cf5f47 100755 --- a/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs +++ b/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Buffers; using System.Diagnostics; using System.IO; using System.Runtime.ExceptionServices; @@ -21,17 +22,21 @@ internal class SslStreamInternal private static readonly AsyncProtocolCallback s_readHeaderCallback = new AsyncProtocolCallback(ReadHeaderCallback); private static readonly AsyncProtocolCallback s_readFrameCallback = new AsyncProtocolCallback(ReadFrameCallback); - private const int PinnableReadBufferSize = 4096 * 4 + 32; // We read in 16K chunks + headers. - private static PinnableBufferCache s_PinnableReadBufferCache = new PinnableBufferCache("System.Net.SslStream", PinnableReadBufferSize); - private const int PinnableWriteBufferSize = 4096 + 1024; // We write in 4K chunks + encryption overhead. - private static PinnableBufferCache s_PinnableWriteBufferCache = new PinnableBufferCache("System.Net.SslStream", PinnableWriteBufferSize); + private const int ReadBufferSize = 4096 * 4 + 32; // We read in 16K chunks + headers. + private const int WriteBufferSize = 4096 + 1024; // We write in 4K chunks + encryption overhead. + + private static readonly ArrayPool BufferCache = ArrayPool.Shared; private SslState _sslState; private int _nestedWrite; private int _nestedRead; private AsyncProtocolRequest _readProtocolRequest; // cached, reusable AsyncProtocolRequest used for read operations private AsyncProtocolRequest _writeProtocolRequest; // cached, reusable AsyncProtocolRequest used for write operations - private Action _freeBufferAction; + private static Action s_freeBufferAction = (task, buffer) => + { + FreeBuffer((byte[])buffer); + task.GetAwaiter().GetResult(); // propagate any exception + }; // Never updated directly, special properties are used. This is the read buffer. private byte[] _internalBuffer; @@ -45,19 +50,10 @@ internal class SslStreamInternal internal SslStreamInternal(SslState sslState) { - if (PinnableBufferCacheEventSource.Log.IsEnabled()) - { - PinnableBufferCacheEventSource.Log.DebugMessage1("CTOR: In System.Net._SslStream.SslStream", this.GetHashCode()); - } _sslState = sslState; _decryptedBytesOffset = 0; _decryptedBytesCount = 0; - _freeBufferAction = (task, buffer) => - { - FreeBuffer((byte[])buffer); - task.GetAwaiter().GetResult(); // propagate any exception - }; } // If we have a read buffer from the pinnable cache, return it. @@ -65,7 +61,7 @@ private void FreeReadBuffer() { if (_internalBufferFromPinnableCache) { - s_PinnableReadBufferCache.FreeBuffer(_internalBuffer); + BufferCache.Return(_internalBuffer); _internalBufferFromPinnableCache = false; } @@ -76,11 +72,6 @@ private void FreeReadBuffer() { if (_internalBufferFromPinnableCache) { - if (PinnableBufferCacheEventSource.Log.IsEnabled()) - { - PinnableBufferCacheEventSource.Log.DebugMessage2("DTOR: In System.Net._SslStream.~SslStream Freeing Read Buffer", this.GetHashCode(), PinnableBufferCacheEventSource.AddressOfByteArray(_internalBuffer)); - } - FreeReadBuffer(); } } @@ -224,23 +215,13 @@ private void EnsureInternalBufferSize(int newSize) bool wasPinnable = _internalBufferFromPinnableCache; byte[] saved = _internalBuffer; - if (newSize <= PinnableReadBufferSize) + if (newSize <= ReadBufferSize) { - if (PinnableBufferCacheEventSource.Log.IsEnabled()) - { - PinnableBufferCacheEventSource.Log.DebugMessage2("In System.Net._SslStream.EnsureInternalBufferSize IS pinnable", this.GetHashCode(), newSize); - } - _internalBufferFromPinnableCache = true; - _internalBuffer = s_PinnableReadBufferCache.AllocateBuffer(); + _internalBuffer = BufferCache.Rent(ReadBufferSize); } else { - if (PinnableBufferCacheEventSource.Log.IsEnabled()) - { - PinnableBufferCacheEventSource.Log.DebugMessage2("In System.Net._SslStream.EnsureInternalBufferSize NOT pinnable", this.GetHashCode(), newSize); - } - _internalBufferFromPinnableCache = false; _internalBuffer = new byte[newSize]; } @@ -252,7 +233,7 @@ private void EnsureInternalBufferSize(int newSize) if (wasPinnable) { - s_PinnableReadBufferCache.FreeBuffer(saved); + BufferCache.Return(saved); } } else if (_internalOffset > 0 && _internalBufferCount > 0) @@ -386,11 +367,7 @@ private void StartWriting(byte[] buffer, int offset, int count, AsyncProtocolReq int chunkBytes = Math.Min(count, _sslState.MaxDataSize); int encryptedBytes; - byte[] outBuffer = s_PinnableWriteBufferCache.AllocateBuffer(); - if (PinnableBufferCacheEventSource.Log.IsEnabled()) - { - PinnableBufferCacheEventSource.Log.DebugMessage3("In System.Net._SslStream.StartWriting Using Pinnable", this.GetHashCode(), count, PinnableBufferCacheEventSource.AddressOfByteArray(outBuffer)); - } + byte[] outBuffer = BufferCache.Rent(WriteBufferSize); try { @@ -419,13 +396,15 @@ private void StartWriting(byte[] buffer, int offset, int count, AsyncProtocolReq { // Prepare for the next request. asyncRequest.SetNextRequest(buffer, offset + chunkBytes, count - chunkBytes, s_resumeAsyncWriteCallback); - Task t = _sslState.InnerStream.WriteAsync(outBuffer, 0, encryptedBytes).ContinueWith(_freeBufferAction, outBuffer); + Task t = _sslState.InnerStream.WriteAsync(outBuffer, 0, encryptedBytes); if (t.IsCompleted) { + FreeBuffer(outBuffer); t.GetAwaiter().GetResult(); } else { + t = t.ContinueWith(s_freeBufferAction, outBuffer, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); IAsyncResult ar = TaskToApm.Begin(t, s_writeCallback, asyncRequest); if (!ar.CompletedSynchronously) { @@ -459,13 +438,9 @@ private void StartWriting(byte[] buffer, int offset, int count, AsyncProtocolReq asyncRequest?.CompleteUser(); } - private void FreeBuffer(byte[] buffer) + private static void FreeBuffer(byte[] buffer) { - s_PinnableWriteBufferCache.FreeBuffer(buffer); - if (PinnableBufferCacheEventSource.Log.IsEnabled()) - { - PinnableBufferCacheEventSource.Log.DebugMessage1("In System.Net._SslStream.StartWriting Freeing buffer.", this.GetHashCode()); - } + BufferCache.Return(buffer); } // Fill the buffer up to the minimum specified size (or more, if possible). diff --git a/src/System.Net.Security/src/System/PinnableBufferCache.cs b/src/System.Net.Security/src/System/PinnableBufferCache.cs deleted file mode 100644 index 7e5889335045..000000000000 --- a/src/System.Net.Security/src/System/PinnableBufferCache.cs +++ /dev/null @@ -1,589 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Diagnostics.Tracing; -using System.Runtime.InteropServices; -using System.Threading; - -namespace System -{ - internal sealed class PinnableBufferCache - { - /// - /// Create a new cache for pinned byte[] buffers. - /// - /// A name used in diagnostic messages - /// The size of byte[] buffers in the cache (they are all the same size) - public PinnableBufferCache(string cacheName, int numberOfElements) : this(cacheName, () => new byte[numberOfElements]) { } - - /// - /// Get a buffer from the buffer manager. If no buffers exist, allocate a new one. - /// - public byte[] AllocateBuffer() { return (byte[])Allocate(); } - - /// - /// Return a buffer back to the buffer manager. - /// - public void FreeBuffer(byte[] buffer) { Free(buffer); } - - /// - /// Create a PinnableBufferCache that works on any object (it is intended for OverlappedData) - /// - internal PinnableBufferCache(string cacheName, Func factory) - { - _notGen2 = new List(DefaultNumberOfBuffers); - _factory = factory; - - PinnableBufferCacheEventSource.Log.Create(cacheName); - _cacheName = cacheName; - } - - /// - /// Get a object from the buffer manager. If no buffers exist, allocate a new one. - /// - [System.Security.SecuritySafeCritical] - internal object Allocate() - { - // Fast path, get it from our Gen2 aged _freeList. - object returnBuffer; - if (!_freeList.TryPop(out returnBuffer)) - { - Restock(out returnBuffer); - } - - // Computing free count is expensive enough that we don't want to compute it unless logging is on. - if (PinnableBufferCacheEventSource.Log.IsEnabled()) - { - int numAllocCalls = Interlocked.Increment(ref _numAllocCalls); - if (numAllocCalls >= 1024) - { - lock (this) - { - int previousNumAllocCalls = Interlocked.Exchange(ref _numAllocCalls, 0); - if (previousNumAllocCalls >= 1024) - { - int nonGen2Count = 0; - foreach (object o in _freeList) - { - if (GC.GetGeneration(o) < GC.MaxGeneration) - { - nonGen2Count++; - } - } - - PinnableBufferCacheEventSource.Log.WalkFreeListResult(_cacheName, _freeList.Count, nonGen2Count); - } - } - } - - PinnableBufferCacheEventSource.Log.AllocateBuffer(_cacheName, PinnableBufferCacheEventSource.AddressOf(returnBuffer), returnBuffer.GetHashCode(), GC.GetGeneration(returnBuffer), _freeList.Count); - } - return returnBuffer; - } - - /// - /// Return a buffer back to the buffer manager. - /// - [System.Security.SecuritySafeCritical] - internal void Free(object buffer) - { - if (PinnableBufferCacheEventSource.Log.IsEnabled()) - { - PinnableBufferCacheEventSource.Log.FreeBuffer(_cacheName, PinnableBufferCacheEventSource.AddressOf(buffer), buffer.GetHashCode(), _freeList.Count); - } - - - // After we've done 3 gen1 GCs, assume that all buffers have aged into gen2 on the free path. - if ((_gen1CountAtLastRestock + 3) > GC.CollectionCount(GC.MaxGeneration - 1)) - { - lock (this) - { - if (GC.GetGeneration(buffer) < GC.MaxGeneration) - { - // The buffer is not aged, so put it in the non-aged free list. - _moreThanFreeListNeeded = true; - PinnableBufferCacheEventSource.Log.FreeBufferStillTooYoung(_cacheName, _notGen2.Count); - _notGen2.Add(buffer); - _gen1CountAtLastRestock = GC.CollectionCount(GC.MaxGeneration - 1); - return; - } - } - } - - // If we discovered that it is indeed Gen2, great, put it in the Gen2 list. - _freeList.Push(buffer); - } - - #region Private - - /// - /// Called when we don't have any buffers in our free list to give out. - /// - /// - [System.Security.SecuritySafeCritical] - private void Restock(out object returnBuffer) - { - lock (this) - { - // Try again after getting the lock as another thread could have just filled the free list. If we don't check - // then we unnecessarily grab a new set of buffers because we think we are out. - if (_freeList.TryPop(out returnBuffer)) - { - return; - } - - // Lazy init, Ask that TrimFreeListIfNeeded be called on every Gen 2 GC. - if (_restockSize == 0) - { - Gen2GcCallback.Register(Gen2GcCallbackFunc, this); - } - - // Indicate to the trimming policy that the free list is insufficient. - _moreThanFreeListNeeded = true; - PinnableBufferCacheEventSource.Log.AllocateBufferFreeListEmpty(_cacheName, _notGen2.Count); - - // Get more buffers if needed. - if (_notGen2.Count == 0) - { - CreateNewBuffers(); - } - - // We have no buffers in the aged freelist, so get one from the newer list. Try to pick the best one. - int idx = _notGen2.Count - 1; - if (GC.GetGeneration(_notGen2[idx]) < GC.MaxGeneration && GC.GetGeneration(_notGen2[0]) == GC.MaxGeneration) - { - idx = 0; - } - - returnBuffer = _notGen2[idx]; - _notGen2.RemoveAt(idx); - - // Remember any sub-optimal buffer so we don't put it on the free list when it gets freed. - if (PinnableBufferCacheEventSource.Log.IsEnabled() && GC.GetGeneration(returnBuffer) < GC.MaxGeneration) - { - PinnableBufferCacheEventSource.Log.AllocateBufferFromNotGen2(_cacheName, _notGen2.Count); - } - - // If we have a Gen1 collection, then everything on _notGen2 should have aged. Move them to the _freeList. - if (!AgePendingBuffers()) - { - // Before we could age at set of buffers, we have handed out half of them. - // This implies we should be proactive about allocating more (since we will trim them if we over-allocate). - if (_notGen2.Count == _restockSize / 2) - { - PinnableBufferCacheEventSource.Log.DebugMessage("Proactively adding more buffers to aging pool"); - CreateNewBuffers(); - } - } - } - } - - /// - /// See if we can promote the buffers to the free list. Returns true if successful. - /// - [System.Security.SecuritySafeCritical] - private bool AgePendingBuffers() - { - if (_gen1CountAtLastRestock < GC.CollectionCount(GC.MaxGeneration - 1)) - { - // Allocate a temp list of buffers that are not actually in gen2, and swap it in once - // we're done scanning all buffers. - int promotedCount = 0; - List notInGen2 = new List(); - PinnableBufferCacheEventSource.Log.AllocateBufferAged(_cacheName, _notGen2.Count); - for (int i = 0; i < _notGen2.Count; i++) - { - // We actually check every object to ensure that we aren't putting non-aged buffers into the free list. - object currentBuffer = _notGen2[i]; - if (GC.GetGeneration(currentBuffer) >= GC.MaxGeneration) - { - _freeList.Push(currentBuffer); - promotedCount++; - } - else - { - notInGen2.Add(currentBuffer); - } - } - PinnableBufferCacheEventSource.Log.AgePendingBuffersResults(_cacheName, promotedCount, notInGen2.Count); - _notGen2 = notInGen2; - - return true; - } - return false; - } - - /// - /// Generates some buffers to age into Gen2. - /// - private void CreateNewBuffers() - { - // We choose a very modest number of buffers initially because for the client case. This is often enough. - if (_restockSize == 0) - { - _restockSize = 4; - } - else if (_restockSize < DefaultNumberOfBuffers) - { - _restockSize = DefaultNumberOfBuffers; - } - else if (_restockSize < 256) - { - _restockSize = _restockSize * 2; // Grow quickly at small sizes - } - else if (_restockSize < 4096) - { - _restockSize = _restockSize * 3 / 2; // Less aggressively at large ones - } - else - { - _restockSize = 4096; // Cap how aggressive we are - } - - // Ensure we hit our minimums - if (_minBufferCount > _buffersUnderManagement) - _restockSize = Math.Max(_restockSize, _minBufferCount - _buffersUnderManagement); - - PinnableBufferCacheEventSource.Log.AllocateBufferCreatingNewBuffers(_cacheName, _buffersUnderManagement, _restockSize); - for (int i = 0; i < _restockSize; i++) - { - // Make a new buffer. - object newBuffer = _factory(); - - // Create space between the objects. We do this because otherwise it forms a single plug (group of objects) - // and the GC pins the entire plug making them NOT move to Gen1 and Gen2. by putting space between them - // we ensure that object get a chance to move independently (even if some are pinned). - var dummyObject = new object(); - _notGen2.Add(newBuffer); - } - _buffersUnderManagement += _restockSize; - _gen1CountAtLastRestock = GC.CollectionCount(GC.MaxGeneration - 1); - } - - /// - /// This is the static function that is called from the gen2 GC callback. - /// The input object is the cache itself. - /// NOTE: The reason that we make this function static and take the cache as a parameter is that - /// otherwise, we root the cache to the Gen2GcCallback object, and leak the cache even when - /// the application no longer needs it. - /// - [System.Security.SecuritySafeCritical] - private static bool Gen2GcCallbackFunc(object targetObj) - { - return ((PinnableBufferCache)(targetObj)).TrimFreeListIfNeeded(); - } - - /// - /// This is called on every gen2 GC to see if we need to trim the free list. - /// NOTE: DO NOT CALL THIS DIRECTLY FROM THE GEN2GCCALLBACK. INSTEAD CALL IT VIA A STATIC FUNCTION (SEE ABOVE). - /// If you register a non-static function as a callback, then this object will be leaked. - /// - [System.Security.SecuritySafeCritical] - private bool TrimFreeListIfNeeded() - { - int curMSec = Environment.TickCount; - int deltaMSec = curMSec - _msecNoUseBeyondFreeListSinceThisTime; - PinnableBufferCacheEventSource.Log.TrimCheck(_cacheName, _buffersUnderManagement, _moreThanFreeListNeeded, deltaMSec); - - // If we needed more than just the set of aged buffers since the last time we were called, - // we obviously should not be trimming any memory, so do nothing except reset the flag - if (_moreThanFreeListNeeded) - { - _moreThanFreeListNeeded = false; - _trimmingExperimentInProgress = false; - _msecNoUseBeyondFreeListSinceThisTime = curMSec; - return true; - } - - // We require a minimum amount of clock time to pass (10 seconds) before we trim. Ideally this time - // is larger than the typical buffer hold time. - if (0 <= deltaMSec && deltaMSec < 10000) - { - return true; - } - - // If we got here we have spend the last few second without needing to lengthen the free list. Thus - // we have 'enough' buffers, but maybe we have too many. - // See if we can trim - lock (this) - { - // Hit a race, try again later. - if (_moreThanFreeListNeeded) - { - _moreThanFreeListNeeded = false; - _trimmingExperimentInProgress = false; - _msecNoUseBeyondFreeListSinceThisTime = curMSec; - return true; - } - - var freeCount = _freeList.Count; // This is expensive to fetch, do it once. - - // If there is something in _notGen2 it was not used for the last few seconds, it is trim-able. - if (_notGen2.Count > 0) - { - // If we are not performing an experiment and we have stuff that is waiting to go into the - // free list but has not made it there, it could be because the 'slow path' of restocking - // has not happened, so force this (which should flush the list) and start over. - if (!_trimmingExperimentInProgress) - { - PinnableBufferCacheEventSource.Log.TrimFlush(_cacheName, _buffersUnderManagement, freeCount, _notGen2.Count); - AgePendingBuffers(); - _trimmingExperimentInProgress = true; - return true; - } - - PinnableBufferCacheEventSource.Log.TrimFree(_cacheName, _buffersUnderManagement, freeCount, _notGen2.Count); - _buffersUnderManagement -= _notGen2.Count; - - // Possibly revise the restocking down. We don't want to grow aggressively if we are trimming. - var newRestockSize = _buffersUnderManagement / 4; - if (newRestockSize < _restockSize) - { - _restockSize = Math.Max(newRestockSize, DefaultNumberOfBuffers); - } - - _notGen2.Clear(); - _trimmingExperimentInProgress = false; - return true; - } - - // Set up an experiment where we use 25% less buffers in our free list. We put them in - // _notGen2, and if they are needed they will be put back in the free list again. - var trimSize = freeCount / 4 + 1; - - // We are OK with a 15% overhead, do nothing in that case. - if (freeCount * 15 <= _buffersUnderManagement || _buffersUnderManagement - trimSize <= _minBufferCount) - { - PinnableBufferCacheEventSource.Log.TrimFreeSizeOK(_cacheName, _buffersUnderManagement, freeCount); - return true; - } - - // Move buffers from the free list back to the non-aged list. If we don't use them by next time, then we'll consider trimming them. - PinnableBufferCacheEventSource.Log.TrimExperiment(_cacheName, _buffersUnderManagement, freeCount, trimSize); - object buffer; - for (int i = 0; i < trimSize; i++) - { - if (_freeList.TryPop(out buffer)) - { - _notGen2.Add(buffer); - } - } - _msecNoUseBeyondFreeListSinceThisTime = curMSec; - _trimmingExperimentInProgress = true; - } - - // Indicate that we want to be called back on the next Gen 2 GC. - return true; - } - - private const int DefaultNumberOfBuffers = 16; - private string _cacheName; - private Func _factory; - - /// - /// Contains 'good' buffers to reuse. They are guaranteed to be Gen 2 ENFORCED! - /// - private ConcurrentStack _freeList = new ConcurrentStack(); - /// - /// Contains buffers that are not gen 2 and thus we do not wish to give out unless we have to. - /// To implement trimming we sometimes put aged buffers in here as a place to 'park' them - /// before true deletion. - /// - private List _notGen2; - /// - /// What was the gen 1 count the last time re restocked? If it is now greater, then - /// we know that all objects are in Gen 2 so we don't have to check. Should be updated - /// every time something gets added to the _notGen2 list. - /// - private int _gen1CountAtLastRestock; - - /// - /// Used to ensure we have a minimum time between trimmings. - /// - private int _msecNoUseBeyondFreeListSinceThisTime; - /// - /// To trim, we remove things from the free list (which is Gen 2) and see if we 'hit bottom' - /// This flag indicates that we hit bottom (we really needed a bigger free list). - /// - private bool _moreThanFreeListNeeded; - /// - /// The total number of buffers that this cache has ever allocated. - /// Used in trimming heuristics. - /// - private int _buffersUnderManagement; - /// - /// The number of buffers we added the last time we restocked. - /// - private int _restockSize; - /// - /// Did we put some buffers into _notGen2 to see if we can trim? - /// - private bool _trimmingExperimentInProgress; - /// - /// A forced minimum number of buffers. - /// - private int _minBufferCount = 0; - /// - /// The number of calls to Allocate. - /// - private int _numAllocCalls; - #endregion - } - - /// - /// Schedules a callback roughly every gen 2 GC (you may see a Gen 0 an Gen 1 but only once) - /// (We can fix this by capturing the Gen 2 count at startup and testing, but I mostly don't care) - /// - internal sealed class Gen2GcCallback //: CriticalFinalizerObject - { - [System.Security.SecuritySafeCritical] - public Gen2GcCallback() - : base() - { - } - - /// - /// Schedule 'callback' to be called in the next GC. If the callback returns true it is - /// rescheduled for the next Gen 2 GC. Otherwise the callbacks stop. - /// - /// NOTE: This callback will be kept alive until either the callback function returns false, - /// or the target object dies. - /// - public static void Register(Func callback, object targetObj) - { - // Create a unreachable object that remembers the callback function and target object. - Gen2GcCallback gcCallback = new Gen2GcCallback(); - gcCallback.Setup(callback, targetObj); - } - - #region Private - - private Func _callback; - private GCHandle _weakTargetObj; - - [System.Security.SecuritySafeCritical] - private void Setup(Func callback, object targetObj) - { - _callback = callback; - _weakTargetObj = GCHandle.Alloc(targetObj, GCHandleType.Weak); - } - - [System.Security.SecuritySafeCritical] - ~Gen2GcCallback() - { - // Check to see if the target object is still alive. - object targetObj = _weakTargetObj.Target; - if (targetObj == null) - { - // The target object is dead, so this callback object is no longer needed. - _weakTargetObj.Free(); - return; - } - - // Execute the callback method. - try - { - if (!_callback(targetObj)) - { - // If the callback returns false, this callback object is no longer needed. - return; - } - } - catch - { - // Ensure that we still get a chance to resurrect this object, even if the callback throws an exception. - } - - // Resurrect ourselves by re-registering for finalization. - if (!Environment.HasShutdownStarted) - { - GC.ReRegisterForFinalize(this); - } - } - #endregion - } - - /// - /// PinnableBufferCacheEventSource is a private eventSource that we are using to - /// debug and monitor the effectiveness of PinnableBufferCache - /// - - // The following EventSource Name must be unique per DLL: - [EventSource(Name = "Microsoft-DotNETRuntime-PinnableBufferCache-Networking")] - internal sealed class PinnableBufferCacheEventSource : EventSource - { - public static readonly PinnableBufferCacheEventSource Log = new PinnableBufferCacheEventSource(); - - [Event(1, Level = EventLevel.Verbose)] - public void DebugMessage(string message) { if (IsEnabled()) WriteEvent(1, message); } - [Event(2, Level = EventLevel.Verbose)] - public void DebugMessage1(string message, long value) { if (IsEnabled()) WriteEvent(2, message, value); } - [Event(3, Level = EventLevel.Verbose)] - public void DebugMessage2(string message, long value1, long value2) { if (IsEnabled()) WriteEvent(3, message, value1, value2); } - [Event(18, Level = EventLevel.Verbose)] - public void DebugMessage3(string message, long value1, long value2, long value3) { if (IsEnabled()) WriteEvent(18, message, value1, value2, value3); } - - [Event(4)] - public void Create(string cacheName) { if (IsEnabled()) WriteEvent(4, cacheName); } - - [Event(5, Level = EventLevel.Verbose)] - public void AllocateBuffer(string cacheName, ulong objectId, int objectHash, int objectGen, int freeCountAfter) { if (IsEnabled()) WriteEvent(5, cacheName, objectId, objectHash, objectGen, freeCountAfter); } - [Event(6)] - public void AllocateBufferFromNotGen2(string cacheName, int notGen2CountAfter) { if (IsEnabled()) WriteEvent(6, cacheName, notGen2CountAfter); } - [Event(7)] - public void AllocateBufferCreatingNewBuffers(string cacheName, int totalBuffsBefore, int objectCount) { if (IsEnabled()) WriteEvent(7, cacheName, totalBuffsBefore, objectCount); } - [Event(8)] - public void AllocateBufferAged(string cacheName, int agedCount) { if (IsEnabled()) WriteEvent(8, cacheName, agedCount); } - [Event(9)] - public void AllocateBufferFreeListEmpty(string cacheName, int notGen2CountBefore) { if (IsEnabled()) WriteEvent(9, cacheName, notGen2CountBefore); } - - [Event(10, Level = EventLevel.Verbose)] - public void FreeBuffer(string cacheName, ulong objectId, int objectHash, int freeCountBefore) { if (IsEnabled()) WriteEvent(10, cacheName, objectId, objectHash, freeCountBefore); } - [Event(11)] - public void FreeBufferStillTooYoung(string cacheName, int notGen2CountBefore) { if (IsEnabled()) WriteEvent(11, cacheName, notGen2CountBefore); } - - [Event(13)] - public void TrimCheck(string cacheName, int totalBuffs, bool neededMoreThanFreeList, int deltaMSec) { if (IsEnabled()) WriteEvent(13, cacheName, totalBuffs, neededMoreThanFreeList, deltaMSec); } - [Event(14)] - public void TrimFree(string cacheName, int totalBuffs, int freeListCount, int toBeFreed) { if (IsEnabled()) WriteEvent(14, cacheName, totalBuffs, freeListCount, toBeFreed); } - [Event(15)] - public void TrimExperiment(string cacheName, int totalBuffs, int freeListCount, int numTrimTrial) { if (IsEnabled()) WriteEvent(15, cacheName, totalBuffs, freeListCount, numTrimTrial); } - [Event(16)] - public void TrimFreeSizeOK(string cacheName, int totalBuffs, int freeListCount) { if (IsEnabled()) WriteEvent(16, cacheName, totalBuffs, freeListCount); } - [Event(17)] - public void TrimFlush(string cacheName, int totalBuffs, int freeListCount, int notGen2CountBefore) { if (IsEnabled()) WriteEvent(17, cacheName, totalBuffs, freeListCount, notGen2CountBefore); } - [Event(20)] - public void AgePendingBuffersResults(string cacheName, int promotedToFreeListCount, int heldBackCount) { if (IsEnabled()) WriteEvent(20, cacheName, promotedToFreeListCount, heldBackCount); } - [Event(21)] - public void WalkFreeListResult(string cacheName, int freeListCount, int gen0BuffersInFreeList) { if (IsEnabled()) WriteEvent(21, cacheName, freeListCount, gen0BuffersInFreeList); } - - - internal static ulong AddressOf(object obj) - { - var asByteArray = obj as byte[]; - if (asByteArray != null) - { - return (ulong)AddressOfByteArray(asByteArray); - } - - return 0; - } - - [System.Security.SecuritySafeCritical] - internal static unsafe long AddressOfByteArray(byte[] array) - { - if (array == null) - { - return 0; - } - - fixed (byte* ptr = array) - { - return (long)(ptr - 2 * sizeof(void*)); - } - } - } -} From 4a1734bc746d425f171b2f30afa8dbfa40ba4bd5 Mon Sep 17 00:00:00 2001 From: bench Date: Sun, 20 Aug 2017 23:45:22 +0100 Subject: [PATCH 54/54] Fixed issue with the maxsize calculation and removed pinnable tests --- .../Interop.Ssl.cs | 10 ++++++- .../System.Net.Security.Unit.Tests.csproj | 9 ++----- .../System/PinnableBufferCacheTest.cs | 27 ------------------- 3 files changed, 11 insertions(+), 35 deletions(-) mode change 100644 => 100755 src/System.Net.Security/tests/UnitTests/System.Net.Security.Unit.Tests.csproj delete mode 100644 src/System.Net.Security/tests/UnitTests/System/PinnableBufferCacheTest.cs diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs index 89658e82d896..b611d9a319fb 100755 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs @@ -396,7 +396,15 @@ public int Write(Span input) Buffer.BlockCopy(oldArray, 0, _byteArray, 0, _bytesWritten); } } - int bytesToWrite = Math.Min(input.Length, _byteArray?.Length ?? 0 - _bytesWritten); + int bytesToWrite; + if (_byteArray == null) + { + bytesToWrite = -1; + } + else + { + bytesToWrite = Math.Min(input.Length, _byteArray.Length - _bytesWritten); + } if (bytesToWrite < 1) { // We need to return -1 to indicate that it is an async method and diff --git a/src/System.Net.Security/tests/UnitTests/System.Net.Security.Unit.Tests.csproj b/src/System.Net.Security/tests/UnitTests/System.Net.Security.Unit.Tests.csproj old mode 100644 new mode 100755 index fd8c1b14f280..87d1947635b0 --- a/src/System.Net.Security/tests/UnitTests/System.Net.Security.Unit.Tests.csproj +++ b/src/System.Net.Security/tests/UnitTests/System.Net.Security.Unit.Tests.csproj @@ -1,4 +1,4 @@ - + @@ -16,11 +16,9 @@ - - @@ -33,9 +31,6 @@ - - ProductionCode\System\PinnableBufferCache.cs - ProductionCode\System\Net\Security\SslStream.cs @@ -63,4 +58,4 @@ - + \ No newline at end of file diff --git a/src/System.Net.Security/tests/UnitTests/System/PinnableBufferCacheTest.cs b/src/System.Net.Security/tests/UnitTests/System/PinnableBufferCacheTest.cs deleted file mode 100644 index 2d6bc2306211..000000000000 --- a/src/System.Net.Security/tests/UnitTests/System/PinnableBufferCacheTest.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Xunit; - -namespace System.Net.Security.Tests -{ - public class PinnableBufferCacheTest - { - [Fact] - public void PinnableBufferCache_AllocateBuffer_Ok() - { - string cacheName = "Test"; - int numberOfElements = 5; - PinnableBufferCache p = new PinnableBufferCache(cacheName, numberOfElements); - - byte[] a = p.AllocateBuffer(); - - Assert.Equal(numberOfElements, a.Length); - foreach (byte t in a) - { - Assert.Equal(0, t); - } - } - } -}