Thanks to visit codestin.com
Credit goes to github.com

Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
4b4b72c
Added reference to AppSet/AppGet from openssl
Drawaes Aug 2, 2017
4079b92
Added Bio methods to the openssl native shim
Drawaes Aug 2, 2017
1fa274a
Add basic custom bio interop code, write and read still needed
Drawaes Aug 2, 2017
d5fc983
Added BIO.Custom file
Drawaes Aug 2, 2017
7bbcc3d
Added Write Buffer and changed disposable to be public to match inter…
Drawaes Aug 2, 2017
dd8fae2
Added the custom bio into the main code line for SslStream
Drawaes Aug 2, 2017
7c51afe
Add the BIO Control method
Drawaes Aug 2, 2017
7080b69
Removed pending reference from DoHandshake
Drawaes Aug 2, 2017
860bba1
Added custom bio read code
Drawaes Aug 2, 2017
6b19a38
changed read flags
Drawaes Aug 2, 2017
7f7f47a
Added write method
Drawaes Aug 2, 2017
0be51ac
fixed indexing on resize
Drawaes Aug 2, 2017
4694662
updated the output ref on encrypt
Drawaes Aug 3, 2017
5f4e2bf
Added short circuit for the dohandshake to return the shutdown alert
Drawaes Aug 3, 2017
293ea41
Simplify the write bio
Drawaes Aug 5, 2017
d83a091
Changed the write to use a span
Drawaes Aug 5, 2017
05b412b
Typo, intput
Drawaes Aug 5, 2017
56a7e43
Fix span copyto
Drawaes Aug 5, 2017
e6dd27e
Added length update
Drawaes Aug 5, 2017
93e0ad9
Change the pinnable write buffer pool size and the max message size t…
Drawaes Aug 5, 2017
7904f68
Remove some flag settings
Drawaes Aug 5, 2017
bebfc15
Simplify the read bio
Drawaes Aug 5, 2017
6033a15
Changed the write path to allow for multiple writes to the output buffer
Drawaes Aug 6, 2017
f4c0005
Resetting the pinned buffers to the original size
Drawaes Aug 6, 2017
b4d2301
Changed pinnable buffers on write to use one for the write then retur…
Drawaes Aug 6, 2017
f4dbc39
Reset Sln Changes before PR
Drawaes Aug 6, 2017
0e78e71
Added the true flag to the new methods
Drawaes Aug 6, 2017
3014c47
Change from Macros that aren't in older OpenSSL to the underlying fun…
Drawaes Aug 6, 2017
a47874f
Removed var voliations in files edited (there was one in an loop i di…
Drawaes Aug 7, 2017
fb87ba4
Added named parameters to increase readability
Drawaes Aug 7, 2017
dcbed7e
Removed raw set flags methods and provided shim methods for the two f…
Drawaes Aug 8, 2017
3ec53c6
React to shim changes in the managed layer
Drawaes Aug 8, 2017
3c1d3bd
React to shim changes in the managed layer
Drawaes Aug 8, 2017
f6dcc55
Fix the flags change to be the correct direction
Drawaes Aug 8, 2017
0a27d81
Cleaned up spacing and formatting and the interop code
Drawaes Aug 8, 2017
bc46993
Reacting to Review
Drawaes Aug 9, 2017
5ba0c75
Fixing file bit mode to remove execute caused by windows file copy
Drawaes Aug 9, 2017
a049480
More bit mode changes
Drawaes Aug 9, 2017
fc6f327
Fix style using clang-format and moved statics and typedefs to the top
Drawaes Aug 18, 2017
8fd60cc
Reacting to review changes
Drawaes Aug 18, 2017
f51c9e8
Changed Take Bytes
Drawaes Aug 18, 2017
03da084
nit var
Drawaes Aug 18, 2017
172a1de
nit sln changes
Drawaes Aug 18, 2017
8249c15
removed initialize for static constructor, nit readonly
Drawaes Aug 18, 2017
5e97bf7
removed initialize for static constructor, nit readonly
Drawaes Aug 18, 2017
f8e86a6
Changed if to be more concise
Drawaes Aug 18, 2017
9a800a3
Removed finalizers, added assert removed usless is allocated test. ad…
Drawaes Aug 18, 2017
90eb0f7
wrong space removed
Drawaes Aug 18, 2017
3f35c68
Changed span to bye[], changed continuation to run sync and to propag…
Drawaes Aug 18, 2017
155e8e9
Fixed compile error
Drawaes Aug 18, 2017
e3f1577
Reverted Continutation
Drawaes Aug 19, 2017
c67a9e2
Fixed bug around write being triggered during decrypt. Now correctly …
Drawaes Aug 20, 2017
a1ea5b5
PinnableBufferCache -> ArrayPool
benaadams Aug 20, 2017
354a992
Merge pull request #3 from benaadams/arraypool
Drawaes Aug 20, 2017
4a1734b
Fixed issue with the maxsize calculation and removed pinnable tests
Drawaes Aug 20, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,27 @@ internal static partial class Crypto

[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_BioCtrlPending")]
internal static extern int BioCtrlPending(SafeBioHandle bio);

[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_BioSetAppData")]
internal static extern void BioSetAppData(SafeBioHandle bio, IntPtr data);

[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);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
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 readonly static ReadDelegate s_readDelegate;
private unsafe readonly static WriteDelegate s_writeDelegate;

internal static SafeBioHandle CreateManagedSslBio() => Crypto.CreateManagedSslBio();

unsafe static ManagedSslBio()
{
s_writeDelegate = Write;
s_readDelegate = Read;
Crypto.InitManagedSslBioMethod(s_writeDelegate, s_readDelegate);
}

internal static void BioSetGCHandle(SafeBioHandle bio, GCHandle handle)
{
IntPtr pointer = handle.IsAllocated ? GCHandle.ToIntPtr(handle) : IntPtr.Zero;
Crypto.BioSetAppData(bio, pointer);
}

private static unsafe int Write(IntPtr bio, void* input, int size, IntPtr data)
{
GCHandle handle = GCHandle.FromIntPtr(data);
Debug.Assert(handle.IsAllocated);

if (handle.Target is SafeSslHandle.WriteBioBuffer buffer)
{
return buffer.Write(new Span<byte>(input, size));
}

return -1;
}

private static unsafe int Read(IntPtr bio, void* output, int size, IntPtr data)
{
GCHandle handle = GCHandle.FromIntPtr(data);
Debug.Assert(handle.IsAllocated);

if (handle.Target is SafeSslHandle.ReadBioBuffer buffer)
{
return buffer.Read(new Span<byte>(output, size));
}

return -1;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we know this to be always safe? What guarantees does OpenSSL need on the stability of the memory, and what guarantees can we meet with regard to GC compaction?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OpenSsl requires that the memory is the same (as in the content) but that the pointer itself can move. The length must also be the same. So I feel this is fine.

Make it possible to retry SSL_write() with changed buffer location (the buffer contents must stay the same). This is not the default to avoid the misconception that non-blocking SSL_write() behaves like non-blocking write().

Its really only in place to stop silly mistakes, in this case we know we won't change the content (unless the user is silly enough to modify the input array that is in a method and not returned and modify it else where in another thread). Now it is possible for a user to do this, but then you end up with the same situation as the user doing this while you are mid writing or copying the data anyway.

I do have an idea of how I can possibly remove this, but its not an easy change due to the APM model of the SslInternalStream, the large number of callback chaining in there makes state a tough call.


if (!Ssl.SetEncryptionPolicy(innerContext, policy))
{
throw new PlatformNotSupportedException(SR.Format(SR.net_ssl_encryptionpolicy_notsupported, policy));
Expand All @@ -93,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);
}

Expand Down Expand Up @@ -135,49 +139,36 @@ internal static bool DoSslHandshake(SafeSslHandle context, byte[] recvBuf, int r
{
sendBuf = null;
sendCount = 0;
if ((recvBuf != null) && (recvCount > 0))

sendCount = context.OutputBio.TakeBytes(out sendBuf);
if (recvBuf == null && sendCount > 0)
{
BioWrite(context.InputBio, recvBuf, recvOffset, recvCount);
return false;
}

context.InputBio.SetData(recvBuf, recvOffset, recvCount);
context.OutputBio.SetData(buffer: null, isHandshake: true);

int retVal = Ssl.SslDoHandshake(context);

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))
{
throw new SslException(SR.Format(SR.net_ssl_handshake_failed_error, error), innerError);
}
}

sendCount = Crypto.BioCtrlPending(context.OutputBio);

if (sendCount > 0)
{
sendBuf = new byte[sendCount];

try
{
sendCount = BioRead(context.OutputBio, sendBuf, sendCount);
}
finally
{
if (sendCount <= 0)
{
sendBuf = null;
sendCount = 0;
}
}
}
sendCount = context.OutputBio.TakeBytes(out sendBuf);

bool stateOk = Ssl.IsSslStateOK(context);
if (stateOk)
{
context.MarkHandshakeCompleted();
}

return stateOk;
}

Expand All @@ -190,6 +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.SetData(output, isHandshake: false);

int retVal;
unsafe
Expand All @@ -202,8 +194,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)
Expand All @@ -212,52 +203,46 @@ 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);
}
}
else
{
int capacityNeeded = Crypto.BioCtrlPending(context.OutputBio);

if (output == null || output.Length < capacityNeeded)
{
output = new byte[capacityNeeded];
}

retVal = BioRead(context.OutputBio, output, capacityNeeded);
}

return retVal;
int 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)
{
Debug.Assert(offset >= 0);
Debug.Assert(offset <= outBuffer.Length);

errorCode = Ssl.SslErrorCode.SSL_ERROR_NONE;

int retVal = BioWrite(context.InputBio, outBuffer, offset, count);
context.InputBio.SetData(outBuffer, offset, count);

if (retVal == count)
int retVal;
unsafe
{
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 - offset);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need to take count into account here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No this is our buffer we own internally, we can always use the entire thing. The count is the number of encrypted bytes currently in the same buffer for decrypting. This is the pattern for how it works pre the PR.

}
}

if (retVal > 0)
{
count = retVal;
}
if (retVal > 0)
{
count = retVal;
}


if (retVal != count)
{
Exception innerError;
errorCode = GetSslError(context, retVal, out innerError);
errorCode = GetSslError(context, retVal, out Exception innerError);
retVal = 0;

switch (errorCode)
Expand Down Expand Up @@ -345,10 +330,10 @@ 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
// Check if issuer name is already present
// Avoiding duplicate names
if (!issuerNameHashSet.Add(certificate.Issuer))
{
continue;
Expand Down Expand Up @@ -458,7 +443,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)
Expand Down
Loading