Imported Upstream version 5.10.0.69

Former-commit-id: fc39669a0b707dd3c063977486506b6793da2890
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2018-01-29 19:03:06 +00:00
parent d8f8abd549
commit e2950ec768
6283 changed files with 453847 additions and 91879 deletions

View File

@@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26923.0
# 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
@@ -35,10 +35,10 @@ Global
{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-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
{0D174EA9-9E61-4519-8D31-7BD2331A1982}.Debug|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Debug|Any CPU
{0D174EA9-9E61-4519-8D31-7BD2331A1982}.Debug|Any CPU.Build.0 = netcoreapp-Windows_NT-Debug|Any CPU
{0D174EA9-9E61-4519-8D31-7BD2331A1982}.Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|Any CPU
{0D174EA9-9E61-4519-8D31-7BD2331A1982}.Release|Any CPU.Build.0 = netcoreapp-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}.Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|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 = {72DFF69F-F9E9-4112-91E8-5FC8169B6F1F}
EndGlobalSection
EndGlobal

View File

@@ -5,6 +5,11 @@
// Changes to this file must follow the http://aka.ms/api-review process.
// ------------------------------------------------------------------------------
using System.Collections.Generic;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
namespace System.Net.Security
{
@@ -94,6 +99,48 @@ namespace System.Net.Security
EncryptAndSign = 2
}
public delegate bool RemoteCertificateValidationCallback(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate, System.Security.Cryptography.X509Certificates.X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors);
public class SslServerAuthenticationOptions
{
public bool AllowRenegotiation { get { throw null; } set { } }
public X509Certificate ServerCertificate { get { throw null; } set { } }
public bool ClientCertificateRequired { get { throw null; } set { } }
public SslProtocols EnabledSslProtocols { get { throw null; } set { } }
public X509RevocationMode CertificateRevocationCheckMode { get { throw null; } set { } }
public List<SslApplicationProtocol> ApplicationProtocols { get { throw null; } set { } }
public RemoteCertificateValidationCallback RemoteCertificateValidationCallback { get { throw null; } set { } }
public EncryptionPolicy EncryptionPolicy { get { throw null; } set { } }
}
public partial class SslClientAuthenticationOptions
{
public bool AllowRenegotiation { get { throw null; } set { } }
public string TargetHost { get { throw null; } set { } }
public X509CertificateCollection ClientCertificates { get { throw null; } set { } }
public LocalCertificateSelectionCallback LocalCertificateSelectionCallback { get { throw null; } set { } }
public SslProtocols EnabledSslProtocols { get { throw null; } set { } }
public X509RevocationMode CertificateRevocationCheckMode { get { throw null; } set { } }
public List<SslApplicationProtocol> ApplicationProtocols { get { throw null; } set { } }
public RemoteCertificateValidationCallback RemoteCertificateValidationCallback { get { throw null; } set { } }
public EncryptionPolicy EncryptionPolicy { get { throw null; } set { } }
}
public readonly partial struct SslApplicationProtocol : IEquatable<SslApplicationProtocol>
{
private readonly object _dummy;
public static readonly SslApplicationProtocol Http2;
public static readonly SslApplicationProtocol Http11;
public SslApplicationProtocol(byte[] protocol) { throw null; }
public SslApplicationProtocol(string protocol) { throw null; }
public ReadOnlyMemory<byte> Protocol { get { throw null; } }
public bool Equals(SslApplicationProtocol other) { throw null; }
public override bool Equals(object obj) { throw null; }
public override int GetHashCode() { throw null; }
public override string ToString() { throw null; }
public static bool operator ==(SslApplicationProtocol left, SslApplicationProtocol right) { throw null; }
public static bool operator !=(SslApplicationProtocol left, SslApplicationProtocol right) { throw null; }
}
public partial class SslStream : AuthenticatedStream
{
public SslStream(System.IO.Stream innerStream) : base(innerStream, false) { }
@@ -101,6 +148,7 @@ namespace System.Net.Security
public SslStream(System.IO.Stream innerStream, bool leaveInnerStreamOpen, System.Net.Security.RemoteCertificateValidationCallback userCertificateValidationCallback) : base(innerStream, leaveInnerStreamOpen) { }
public SslStream(System.IO.Stream innerStream, bool leaveInnerStreamOpen, System.Net.Security.RemoteCertificateValidationCallback userCertificateValidationCallback, System.Net.Security.LocalCertificateSelectionCallback userCertificateSelectionCallback) : base(innerStream, leaveInnerStreamOpen) { }
public SslStream(System.IO.Stream innerStream, bool leaveInnerStreamOpen, System.Net.Security.RemoteCertificateValidationCallback userCertificateValidationCallback, System.Net.Security.LocalCertificateSelectionCallback userCertificateSelectionCallback, System.Net.Security.EncryptionPolicy encryptionPolicy) : base(innerStream, leaveInnerStreamOpen) { }
public SslApplicationProtocol NegotiatedApplicationProtocol { get { throw null; } }
public override bool CanRead { get { throw null; } }
public override bool CanSeek { get { throw null; } }
public override bool CanTimeout { get { throw null; } }
@@ -134,9 +182,11 @@ namespace System.Net.Security
public virtual System.Threading.Tasks.Task AuthenticateAsClientAsync(string targetHost) { throw null; }
public virtual System.Threading.Tasks.Task AuthenticateAsClientAsync(string targetHost, System.Security.Cryptography.X509Certificates.X509CertificateCollection clientCertificates, System.Security.Authentication.SslProtocols enabledSslProtocols, bool checkCertificateRevocation) { throw null; }
public virtual System.Threading.Tasks.Task AuthenticateAsClientAsync(string targetHost, System.Security.Cryptography.X509Certificates.X509CertificateCollection clientCertificates, bool checkCertificateRevocation) { throw null; }
public Task AuthenticateAsClientAsync(SslClientAuthenticationOptions sslClientAuthenticationOptions, CancellationToken cancellationToken) { throw null; }
public virtual System.Threading.Tasks.Task AuthenticateAsServerAsync(System.Security.Cryptography.X509Certificates.X509Certificate serverCertificate) { throw null; }
public virtual System.Threading.Tasks.Task AuthenticateAsServerAsync(System.Security.Cryptography.X509Certificates.X509Certificate serverCertificate, bool clientCertificateRequired, System.Security.Authentication.SslProtocols enabledSslProtocols, bool checkCertificateRevocation) { throw null; }
public virtual System.Threading.Tasks.Task AuthenticateAsServerAsync(System.Security.Cryptography.X509Certificates.X509Certificate serverCertificate, bool clientCertificateRequired, bool checkCertificateRevocation) { throw null; }
public Task AuthenticateAsServerAsync(SslServerAuthenticationOptions sslClientAuthenticationOptions, CancellationToken cancellationToken) { throw null; }
public virtual System.IAsyncResult BeginAuthenticateAsClient(string targetHost, System.AsyncCallback asyncCallback, object asyncState) { throw null; }
public virtual System.IAsyncResult BeginAuthenticateAsClient(string targetHost, System.Security.Cryptography.X509Certificates.X509CertificateCollection clientCertificates, System.Security.Authentication.SslProtocols enabledSslProtocols, bool checkCertificateRevocation, System.AsyncCallback asyncCallback, object asyncState) { throw null; }
public virtual System.IAsyncResult BeginAuthenticateAsClient(string targetHost, System.Security.Cryptography.X509Certificates.X509CertificateCollection clientCertificates, bool checkCertificateRevocation, System.AsyncCallback asyncCallback, object asyncState) { throw null; }

View File

@@ -13,6 +13,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\System.Collections.NonGeneric\ref\System.Collections.NonGeneric.csproj" />
<ProjectReference Include="..\..\System.Collections\ref\System.Collections.csproj" />
<ProjectReference Include="..\..\System.IO\ref\System.IO.csproj" />
<ProjectReference Include="..\..\System.Net.Primitives\ref\System.Net.Primitives.csproj" />
<ProjectReference Include="..\..\System.Runtime\ref\System.Runtime.csproj" />
@@ -21,5 +22,8 @@
<ProjectReference Include="..\..\System.Security.Principal\ref\System.Security.Principal.csproj" />
<ProjectReference Include="..\..\System.Threading.Tasks\ref\System.Threading.Tasks.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Memory" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>

View File

@@ -1,5 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
@@ -70,9 +129,6 @@
<data name="net_MethodNotImplementedException" xml:space="preserve">
<value>This method is not implemented by this class.</value>
</data>
<data name="net_completed_result" xml:space="preserve">
<value>This operation cannot be performed on a completed asynchronous result object.</value>
</data>
<data name="net_io_readfailure" xml:space="preserve">
<value>Unable to read data from the transport connection: {0}.</value>
</data>
@@ -115,6 +171,9 @@
<data name="net_ssl_io_frame" xml:space="preserve">
<value>The handshake failed due to an unexpected packet format.</value>
</data>
<data name="net_ssl_io_renego" xml:space="preserve">
<value>The remote party requested renegotiation when AllowRenegotiation was set to false.</value>
</data>
<data name="net_ssl_io_cert_validation" xml:space="preserve">
<value>The remote certificate is invalid according to the validation procedure.</value>
</data>
@@ -295,9 +354,6 @@
<data name="net_ssl_encrypt_failed" xml:space="preserve">
<value>Encrypt failed with OpenSSL error - {0}.</value>
</data>
<data name="net_get_ssl_method_failed" xml:space="preserve">
<value>Failed to get SSL method '{0}'. Ensure the OpenSSL method exists on the current system.</value>
</data>
<data name="net_ssl_check_private_key_failed" xml:space="preserve">
<value>SSL certificate private key check failed with OpenSSL error - {0}.</value>
</data>
@@ -355,10 +411,25 @@
<data name="net_nego_not_supported_empty_target_with_defaultcreds" xml:space="preserve">
<value>Target name should be non empty if default credentials are passed.</value>
</data>
<data name="net_security_sslprotocol_contiguous">
<data name="net_security_sslprotocol_contiguous" xml:space="preserve">
<value>The requested combination of SslProtocols ({0}) is not valid for this platform because it skips intermediate versions.</value>
</data>
<data name="net_encryptionpolicy_notsupported" xml:space="preserve">
<value>The '{0}' encryption policy is not supported on this platform.</value>
</data>
<data name="net_alpn_config_failed" xml:space="preserve">
<value>ALPN configuration failed on this platform.</value>
</data>
<data name="net_alpn_failed" xml:space="preserve">
<value>No common application protocol exists between the client and the server. Application negotiation failed.</value>
</data>
<data name="net_ssl_app_protocols_invalid" xml:space="preserve">
<value>The application protocol list is invalid.</value>
</data>
<data name="net_ssl_app_protocol_invalid" xml:space="preserve">
<value>The application protocol value is invalid.</value>
</data>
<data name="net_conflicting_options" xml:space="preserve">
<value>The '{0}' option was already set in the SslStream constructor.</value>
</data>
</root>

View File

@@ -22,6 +22,10 @@
<Compile Include="System\Net\FixedSizeReader.cs" />
<Compile Include="System\Net\HelperAsyncResults.cs" />
<Compile Include="System\Net\Logging\NetEventSource.cs" />
<Compile Include="System\Net\Security\SslApplicationProtocol.cs" />
<Compile Include="System\Net\Security\SslAuthenticationOptions.cs" />
<Compile Include="System\Net\Security\SslClientAuthenticationOptions.cs" />
<Compile Include="System\Net\Security\SslServerAuthenticationOptions.cs" />
<Compile Include="System\Net\Security\SslStreamInternal.Adapters.cs" />
<Compile Include="System\Net\SslStreamContext.cs" />
<Compile Include="System\Net\Security\AuthenticatedStream.cs" />
@@ -161,6 +165,12 @@
<Compile Include="$(CommonPath)\Interop\Windows\SChannel\SecPkgContext_ConnectionInfo.cs">
<Link>Common\Interop\Windows\SChannel\SecPkgContext_ConnectionInfo.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Windows\SChannel\Interop.SecPkgContext_ApplicationProtocol.cs">
<Link>Common\Interop\Windows\SChannel\Interop.SecPkgContext_ApplicationProtocol.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Windows\SChannel\Interop.Sec_Application_Protocols.cs">
<Link>Common\Interop\Windows\SChannel\Interop.Sec_Application_Protocols.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Windows\SChannel\UnmanagedCertificateContext.cs">
<Link>Common\Interop\Windows\SChannel\UnmanagedCertificateContext.cs</Link>
</Compile>
@@ -396,6 +406,7 @@
<Reference Include="System.Collections.NonGeneric" />
<Reference Include="System.Diagnostics.Debug" />
<Reference Include="System.Diagnostics.Tracing" />
<Reference Include="System.Memory" />
<Reference Include="System.Net.Primitives" />
<Reference Include="System.Resources.ResourceManager" />
<Reference Include="System.Runtime" />
@@ -416,4 +427,4 @@
<Reference Include="System.Security.Cryptography.Primitives" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>
</Project>

View File

@@ -22,7 +22,7 @@ namespace System.Net
public SafeSslHandle SslContext => _sslContext;
public SafeDeleteSslContext(SafeFreeSslCredentials credential, bool isServer)
public SafeDeleteSslContext(SafeFreeSslCredentials credential, SslAuthenticationOptions sslAuthenticationOptions)
: base(credential)
{
Debug.Assert((null != credential) && !credential.IsInvalid, "Invalid credential used in SafeDeleteSslContext");
@@ -35,7 +35,7 @@ namespace System.Net
_writeCallback = WriteToConnection;
}
_sslContext = CreateSslContext(credential, isServer);
_sslContext = CreateSslContext(credential, sslAuthenticationOptions.IsServer);
int osStatus = Interop.AppleCrypto.SslSetIoCallbacks(
_sslContext,

View File

@@ -0,0 +1,140 @@
// 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.Text;
namespace System.Net.Security
{
public readonly struct SslApplicationProtocol : IEquatable<SslApplicationProtocol>
{
private readonly ReadOnlyMemory<byte> _readOnlyProtocol;
private static readonly Encoding s_utf8 = Encoding.GetEncoding(Encoding.UTF8.CodePage, EncoderFallback.ExceptionFallback, DecoderFallback.ExceptionFallback);
// Refer IANA on ApplicationProtocols: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids
// h2
public static readonly SslApplicationProtocol Http2 = new SslApplicationProtocol(new byte[] { 0x68, 0x32 }, false);
// http/1.1
public static readonly SslApplicationProtocol Http11 = new SslApplicationProtocol(new byte[] { 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31 }, false);
internal SslApplicationProtocol(byte[] protocol, bool copy)
{
if (protocol == null)
{
throw new ArgumentNullException(nameof(protocol));
}
// RFC 7301 states protocol size <= 255 bytes.
if (protocol.Length == 0 || protocol.Length > 255)
{
throw new ArgumentException(SR.net_ssl_app_protocol_invalid, nameof(protocol));
}
if (copy)
{
byte[] temp = new byte[protocol.Length];
Array.Copy(protocol, 0, temp, 0, protocol.Length);
_readOnlyProtocol = new ReadOnlyMemory<byte>(temp);
}
else
{
_readOnlyProtocol = new ReadOnlyMemory<byte>(protocol);
}
}
public SslApplicationProtocol(byte[] protocol) : this(protocol, true) { }
public SslApplicationProtocol(string protocol) : this(s_utf8.GetBytes(protocol), copy: false) { }
public ReadOnlyMemory<byte> Protocol
{
get => _readOnlyProtocol;
}
public bool Equals(SslApplicationProtocol other)
{
if (_readOnlyProtocol.Length != other._readOnlyProtocol.Length)
return false;
return (_readOnlyProtocol.IsEmpty && other._readOnlyProtocol.IsEmpty) ||
_readOnlyProtocol.Span.SequenceEqual(other._readOnlyProtocol.Span);
}
public override bool Equals(object obj)
{
if (obj is SslApplicationProtocol protocol)
{
return Equals(protocol);
}
return false;
}
public override int GetHashCode()
{
if (_readOnlyProtocol.Length == 0)
return 0;
int hash1 = 0;
ReadOnlySpan<byte> pSpan = _readOnlyProtocol.Span;
for (int i = 0; i < _readOnlyProtocol.Length; i++)
{
hash1 = ((hash1 << 5) + hash1) ^ pSpan[i];
}
return hash1;
}
public override string ToString()
{
try
{
if (_readOnlyProtocol.Length == 0)
{
return null;
}
return s_utf8.GetString(_readOnlyProtocol.Span);
}
catch
{
// In case of decoding errors, return the byte values as hex string.
int byteCharsLength = _readOnlyProtocol.Length * 5;
char[] byteChars = new char[byteCharsLength];
int index = 0;
ReadOnlySpan<byte> pSpan = _readOnlyProtocol.Span;
for (int i = 0; i < byteCharsLength; i += 5)
{
byte b = pSpan[index++];
byteChars[i] = '0';
byteChars[i + 1] = 'x';
byteChars[i + 2] = GetHexValue(Math.DivRem(b, 16, out int rem));
byteChars[i + 3] = GetHexValue(rem);
byteChars[i + 4] = ' ';
}
return new string(byteChars, 0, byteCharsLength - 1);
char GetHexValue(int i)
{
if (i < 10)
return (char)(i + '0');
return (char)(i - 10 + 'a');
}
}
}
public static bool operator ==(SslApplicationProtocol left, SslApplicationProtocol right)
{
return left.Equals(right);
}
public static bool operator !=(SslApplicationProtocol left, SslApplicationProtocol right)
{
return !(left == right);
}
}
}

View File

@@ -0,0 +1,71 @@
// 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.Generic;
using System.Runtime.InteropServices;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
namespace System.Net.Security
{
internal class SslAuthenticationOptions
{
internal SslAuthenticationOptions(SslClientAuthenticationOptions sslClientAuthenticationOptions)
{
// Common options.
AllowRenegotiation = sslClientAuthenticationOptions.AllowRenegotiation;
ApplicationProtocols = sslClientAuthenticationOptions.ApplicationProtocols;
CertValidationDelegate = sslClientAuthenticationOptions._certValidationDelegate;
CheckCertName = true;
EnabledSslProtocols = sslClientAuthenticationOptions.EnabledSslProtocols;
EncryptionPolicy = sslClientAuthenticationOptions.EncryptionPolicy;
IsServer = false;
RemoteCertRequired = true;
RemoteCertificateValidationCallback = sslClientAuthenticationOptions.RemoteCertificateValidationCallback;
TargetHost = sslClientAuthenticationOptions.TargetHost;
// Client specific options.
CertSelectionDelegate = sslClientAuthenticationOptions._certSelectionDelegate;
CertificateRevocationCheckMode = sslClientAuthenticationOptions.CertificateRevocationCheckMode;
ClientCertificates = sslClientAuthenticationOptions.ClientCertificates;
LocalCertificateSelectionCallback = sslClientAuthenticationOptions.LocalCertificateSelectionCallback;
}
internal SslAuthenticationOptions(SslServerAuthenticationOptions sslServerAuthenticationOptions)
{
// Common options.
AllowRenegotiation = sslServerAuthenticationOptions.AllowRenegotiation;
ApplicationProtocols = sslServerAuthenticationOptions.ApplicationProtocols;
CertValidationDelegate = sslServerAuthenticationOptions._certValidationDelegate;
CheckCertName = false;
EnabledSslProtocols = sslServerAuthenticationOptions.EnabledSslProtocols;
EncryptionPolicy = sslServerAuthenticationOptions.EncryptionPolicy;
IsServer = true;
RemoteCertRequired = sslServerAuthenticationOptions.ClientCertificateRequired;
RemoteCertificateValidationCallback = sslServerAuthenticationOptions.RemoteCertificateValidationCallback;
TargetHost = string.Empty;
// Server specific options.
CertificateRevocationCheckMode = sslServerAuthenticationOptions.CertificateRevocationCheckMode;
ServerCertificate = sslServerAuthenticationOptions.ServerCertificate;
}
internal bool AllowRenegotiation { get; set; }
internal string TargetHost { get; set; }
internal X509CertificateCollection ClientCertificates { get; set; }
internal List<SslApplicationProtocol> ApplicationProtocols { get; }
internal bool IsServer { get; set; }
internal RemoteCertificateValidationCallback RemoteCertificateValidationCallback { get; set; }
internal LocalCertificateSelectionCallback LocalCertificateSelectionCallback { get; set; }
internal X509Certificate ServerCertificate { get; set; }
internal SslProtocols EnabledSslProtocols { get; set; }
internal X509RevocationMode CertificateRevocationCheckMode { get; set; }
internal EncryptionPolicy EncryptionPolicy { get; set; }
internal bool RemoteCertRequired { get; set; }
internal bool CheckCertName { get; set; }
internal RemoteCertValidationCallback CertValidationDelegate { get; set; }
internal LocalCertSelectionCallback CertSelectionDelegate { get; set; }
}
}

View File

@@ -0,0 +1,73 @@
// 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.Generic;
using System.Runtime.InteropServices;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
namespace System.Net.Security
{
public class SslClientAuthenticationOptions
{
private EncryptionPolicy _encryptionPolicy = EncryptionPolicy.RequireEncryption;
private X509RevocationMode _checkCertificateRevocation = X509RevocationMode.NoCheck;
private SslProtocols _enabledSslProtocols = SecurityProtocol.SystemDefaultSecurityProtocols;
private bool _allowRenegotiation = true;
internal RemoteCertValidationCallback _certValidationDelegate;
internal LocalCertSelectionCallback _certSelectionDelegate;
public bool AllowRenegotiation
{
get => _allowRenegotiation;
set => _allowRenegotiation = value;
}
public LocalCertificateSelectionCallback LocalCertificateSelectionCallback { get; set; }
public RemoteCertificateValidationCallback RemoteCertificateValidationCallback { get; set; }
public List<SslApplicationProtocol> ApplicationProtocols { get; set; }
public string TargetHost { get; set; }
public X509CertificateCollection ClientCertificates { get; set; }
public X509RevocationMode CertificateRevocationCheckMode
{
get => _checkCertificateRevocation;
set
{
if (value != X509RevocationMode.NoCheck && value != X509RevocationMode.Offline && value != X509RevocationMode.Online)
{
throw new ArgumentException(SR.Format(SR.net_invalid_enum, nameof(X509RevocationMode)), nameof(value));
}
_checkCertificateRevocation = value;
}
}
public EncryptionPolicy EncryptionPolicy
{
get => _encryptionPolicy;
set
{
if (value != EncryptionPolicy.RequireEncryption && value != EncryptionPolicy.AllowNoEncryption && value != EncryptionPolicy.NoEncryption)
{
throw new ArgumentException(SR.Format(SR.net_invalid_enum, nameof(EncryptionPolicy)), nameof(value));
}
_encryptionPolicy = value;
}
}
public SslProtocols EnabledSslProtocols
{
get => _enabledSslProtocols;
set => _enabledSslProtocols = value;
}
}
}

View File

@@ -0,0 +1,69 @@
// 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.Generic;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
namespace System.Net.Security
{
public class SslServerAuthenticationOptions
{
private X509RevocationMode _checkCertificateRevocation = X509RevocationMode.NoCheck;
private SslProtocols _enabledSslProtocols = SecurityProtocol.SystemDefaultSecurityProtocols;
private EncryptionPolicy _encryptionPolicy = EncryptionPolicy.RequireEncryption;
private bool _allowRenegotiation = true;
internal RemoteCertValidationCallback _certValidationDelegate;
public bool AllowRenegotiation
{
get => _allowRenegotiation;
set => _allowRenegotiation = value;
}
public bool ClientCertificateRequired { get; set; }
public List<SslApplicationProtocol> ApplicationProtocols { get; set; }
public RemoteCertificateValidationCallback RemoteCertificateValidationCallback { get; set; }
public X509Certificate ServerCertificate { get; set; }
public SslProtocols EnabledSslProtocols
{
get => _enabledSslProtocols;
set => _enabledSslProtocols = value;
}
public X509RevocationMode CertificateRevocationCheckMode
{
get => _checkCertificateRevocation;
set
{
if (value != X509RevocationMode.NoCheck && value != X509RevocationMode.Offline && value != X509RevocationMode.Online)
{
throw new ArgumentException(SR.Format(SR.net_invalid_enum, nameof(X509RevocationMode)), nameof(value));
}
_checkCertificateRevocation = value;
}
}
public EncryptionPolicy EncryptionPolicy
{
get => _encryptionPolicy;
set
{
if (value != EncryptionPolicy.RequireEncryption && value != EncryptionPolicy.AllowNoEncryption && value != EncryptionPolicy.NoEncryption)
{
throw new ArgumentException(SR.Format(SR.net_invalid_enum, nameof(EncryptionPolicy)), nameof(value));
}
_encryptionPolicy = value;
}
}
}
}

View File

@@ -19,7 +19,7 @@ namespace System.Net.Security
//
// Uses certificate thumb-print comparison.
//
private struct SslCredKey : IEquatable<SslCredKey>
private readonly struct SslCredKey : IEquatable<SslCredKey>
{
private readonly byte[] _thumbPrint;
private readonly int _allowedProtocols;

View File

@@ -22,8 +22,7 @@ namespace System.Net.Security
private static AsyncProtocolCallback s_readFrameCallback = new AsyncProtocolCallback(ReadFrameCallback);
private static AsyncCallback s_writeCallback = new AsyncCallback(WriteCallback);
private RemoteCertValidationCallback _certValidationDelegate;
private LocalCertSelectionCallback _certSelectionDelegate;
internal SslAuthenticationOptions _sslAuthenticationOptions;
private Stream _innerStream;
@@ -33,7 +32,6 @@ namespace System.Net.Security
private SecureChannel _context;
private bool _handshakeCompleted;
private bool _certValidationFailed;
private bool _shutdown;
private SecurityStatusPal _securityStatus;
@@ -70,31 +68,17 @@ namespace System.Net.Security
private int _lockReadState;
private object _queuedReadStateRequest;
private readonly EncryptionPolicy _encryptionPolicy;
//
// The public Client and Server classes enforce the parameters rules before
// calling into this .ctor.
//
internal SslState(Stream innerStream, RemoteCertValidationCallback certValidationCallback, LocalCertSelectionCallback certSelectionCallback, EncryptionPolicy encryptionPolicy)
internal SslState(Stream innerStream)
{
_innerStream = innerStream;
_certValidationDelegate = certValidationCallback;
_certSelectionDelegate = certSelectionCallback;
_encryptionPolicy = encryptionPolicy;
}
internal void ValidateCreateContext(bool isServer, string targetHost, SslProtocols enabledSslProtocols, X509Certificate serverCertificate, X509CertificateCollection clientCertificates, bool remoteCertRequired, bool checkCertRevocationStatus)
internal void ValidateCreateContext(SslClientAuthenticationOptions sslClientAuthenticationOptions)
{
ValidateCreateContext(isServer, targetHost, enabledSslProtocols, serverCertificate, clientCertificates, remoteCertRequired,
checkCertRevocationStatus, !isServer);
}
internal void ValidateCreateContext(bool isServer, string targetHost, SslProtocols enabledSslProtocols, X509Certificate serverCertificate, X509CertificateCollection clientCertificates, bool remoteCertRequired, bool checkCertRevocationStatus, bool checkCertName)
{
//
// We don't support SSL alerts right now, hence any exception is fatal and cannot be retried.
//
if (_exception != null)
{
_exception.Throw();
@@ -105,31 +89,26 @@ namespace System.Net.Security
throw new InvalidOperationException(SR.net_auth_reauth);
}
if (Context != null && IsServer != isServer)
if (Context != null && IsServer)
{
throw new InvalidOperationException(SR.net_auth_client_server);
}
if (targetHost == null)
if (sslClientAuthenticationOptions.TargetHost == null)
{
throw new ArgumentNullException(nameof(targetHost));
throw new ArgumentNullException(nameof(sslClientAuthenticationOptions.TargetHost));
}
if (isServer && serverCertificate == null)
if (sslClientAuthenticationOptions.TargetHost.Length == 0)
{
throw new ArgumentNullException(nameof(serverCertificate));
}
if (targetHost.Length == 0)
{
targetHost = "?" + Interlocked.Increment(ref s_uniqueNameInteger).ToString(NumberFormatInfo.InvariantInfo);
sslClientAuthenticationOptions.TargetHost = "?" + Interlocked.Increment(ref s_uniqueNameInteger).ToString(NumberFormatInfo.InvariantInfo);
}
_exception = null;
try
{
_context = new SecureChannel(targetHost, isServer, enabledSslProtocols, serverCertificate, clientCertificates, remoteCertRequired,
checkCertName, checkCertRevocationStatus, _encryptionPolicy, _certSelectionDelegate);
_sslAuthenticationOptions = new SslAuthenticationOptions(sslClientAuthenticationOptions);
_context = new SecureChannel(_sslAuthenticationOptions);
}
catch (Win32Exception e)
{
@@ -137,6 +116,51 @@ namespace System.Net.Security
}
}
internal void ValidateCreateContext(SslServerAuthenticationOptions sslServerAuthenticationOptions)
{
if (_exception != null)
{
_exception.Throw();
}
if (Context != null && Context.IsValidContext)
{
throw new InvalidOperationException(SR.net_auth_reauth);
}
if (Context != null && !IsServer)
{
throw new InvalidOperationException(SR.net_auth_client_server);
}
if (sslServerAuthenticationOptions.ServerCertificate == null)
{
throw new ArgumentNullException(nameof(sslServerAuthenticationOptions.ServerCertificate));
}
_exception = null;
try
{
_sslAuthenticationOptions = new SslAuthenticationOptions(sslServerAuthenticationOptions);
_context = new SecureChannel(_sslAuthenticationOptions);
}
catch (Win32Exception e)
{
throw new AuthenticationException(SR.net_auth_SSPI, e);
}
}
internal SslApplicationProtocol NegotiatedApplicationProtocol
{
get
{
if (Context == null)
return default;
return Context.NegotiatedApplicationProtocol;
}
}
internal bool IsAuthenticated
{
get
@@ -172,14 +196,6 @@ namespace System.Net.Security
}
}
//
// SSL related properties
//
internal void SetCertValidationDelegate(RemoteCertValidationCallback certValidationCallback)
{
_certValidationDelegate = certValidationCallback;
}
//
// This will return selected local cert for both client/server streams
//
@@ -209,20 +225,7 @@ namespace System.Net.Security
{
get
{
return Context != null && Context.CheckCertRevocationStatus;
}
}
internal SecurityStatusPal LastSecurityStatus
{
get { return _securityStatus; }
}
internal bool IsCertValidationFailed
{
get
{
return _certValidationFailed;
return Context != null && Context.CheckCertRevocationStatus != X509RevocationMode.NoCheck;
}
}
@@ -390,14 +393,6 @@ namespace System.Net.Security
}
}
internal int HeaderSize
{
get
{
return Context.HeaderSize;
}
}
internal int MaxDataSize
{
get
@@ -526,14 +521,14 @@ namespace System.Net.Security
//
// Must be called under the lock in case concurrent handshake is going.
//
internal int CheckOldKeyDecryptedData(byte[] buffer, int offset, int count)
internal int CheckOldKeyDecryptedData(Memory<byte> buffer)
{
CheckThrow(true);
if (_queuedReadData != null)
{
// This is inefficient yet simple and should be a REALLY rare case.
int toCopy = Math.Min(_queuedReadCount, count);
Buffer.BlockCopy(_queuedReadData, 0, buffer, offset, toCopy);
int toCopy = Math.Min(_queuedReadCount, buffer.Length);
new Span<byte>(_queuedReadData, 0, toCopy).CopyTo(buffer.Span);
_queuedReadCount -= toCopy;
if (_queuedReadCount == 0)
{
@@ -580,14 +575,15 @@ namespace System.Net.Security
// Not aync so the connection is completed at this point.
if (lazyResult == null && NetEventSource.IsEnabled)
{
if (NetEventSource.IsEnabled) NetEventSource.Log.SspiSelectedCipherSuite(nameof(ProcessAuthentication),
SslProtocol,
CipherAlgorithm,
CipherStrength,
HashAlgorithm,
HashStrength,
KeyExchangeAlgorithm,
KeyExchangeStrength);
if (NetEventSource.IsEnabled)
NetEventSource.Log.SspiSelectedCipherSuite(nameof(ProcessAuthentication),
SslProtocol,
CipherAlgorithm,
CipherStrength,
HashAlgorithm,
HashStrength,
KeyExchangeAlgorithm,
KeyExchangeStrength);
}
}
catch (Exception)
@@ -714,14 +710,15 @@ namespace System.Net.Security
// Connection is completed at this point.
if (NetEventSource.IsEnabled)
{
if (NetEventSource.IsEnabled) NetEventSource.Log.SspiSelectedCipherSuite(nameof(EndProcessAuthentication),
SslProtocol,
CipherAlgorithm,
CipherStrength,
HashAlgorithm,
HashStrength,
KeyExchangeAlgorithm,
KeyExchangeStrength);
if (NetEventSource.IsEnabled)
NetEventSource.Log.SspiSelectedCipherSuite(nameof(EndProcessAuthentication),
SslProtocol,
CipherAlgorithm,
CipherStrength,
HashAlgorithm,
HashStrength,
KeyExchangeAlgorithm,
KeyExchangeStrength);
}
}
@@ -1014,23 +1011,24 @@ namespace System.Net.Security
//
private bool CompleteHandshake(ref ProtocolToken alertToken)
{
if (NetEventSource.IsEnabled) NetEventSource.Enter(this);
if (NetEventSource.IsEnabled)
NetEventSource.Enter(this);
Context.ProcessHandshakeSuccess();
if (!Context.VerifyRemoteCertificate(_certValidationDelegate, ref alertToken))
if (!Context.VerifyRemoteCertificate(_sslAuthenticationOptions.CertValidationDelegate, ref alertToken))
{
_handshakeCompleted = false;
_certValidationFailed = true;
if (NetEventSource.IsEnabled) NetEventSource.Exit(this, false);
if (NetEventSource.IsEnabled)
NetEventSource.Exit(this, false);
return false;
}
_certValidationFailed = false;
_handshakeCompleted = true;
if (NetEventSource.IsEnabled) NetEventSource.Exit(this, true);
if (NetEventSource.IsEnabled)
NetEventSource.Exit(this, true);
return true;
}
@@ -1088,7 +1086,8 @@ namespace System.Net.Security
private static void PartialFrameCallback(AsyncProtocolRequest asyncRequest)
{
if (NetEventSource.IsEnabled) NetEventSource.Enter(null);
if (NetEventSource.IsEnabled)
NetEventSource.Enter(null);
// Async ONLY completion.
SslState sslState = (SslState)asyncRequest.AsyncObject;
@@ -1112,7 +1111,8 @@ namespace System.Net.Security
//
private static void ReadFrameCallback(AsyncProtocolRequest asyncRequest)
{
if (NetEventSource.IsEnabled) NetEventSource.Enter(null);
if (NetEventSource.IsEnabled)
NetEventSource.Enter(null);
// Async ONLY completion.
SslState sslState = (SslState)asyncRequest.AsyncObject;
@@ -1183,43 +1183,28 @@ namespace System.Net.Security
}
_lockReadState = LockRead;
object obj = _queuedReadStateRequest;
if (obj == null)
{
// Other thread did not get under the lock yet.
return;
}
_queuedReadStateRequest = null;
if (obj is LazyAsyncResult)
{
((LazyAsyncResult)obj).InvokeCallback();
}
else
{
ThreadPool.QueueUserWorkItem(new WaitCallback(CompleteRequestWaitCallback), obj);
}
HandleQueuedCallback(ref _queuedReadStateRequest);
}
}
// Returns:
// -1 - proceed
// 0 - queued
// X - some bytes are ready, no need for IO
internal int CheckEnqueueRead(byte[] buffer, int offset, int count, AsyncProtocolRequest request)
internal int CheckEnqueueRead(Memory<byte> buffer)
{
int lockState = Interlocked.CompareExchange(ref _lockReadState, LockRead, LockNone);
if (lockState != LockHandshake)
{
// Proceed, no concurrent handshake is ongoing so no need for a lock.
return CheckOldKeyDecryptedData(buffer, offset, count);
return CheckOldKeyDecryptedData(buffer);
}
LazyAsyncResult lazyResult = null;
lock (this)
{
int result = CheckOldKeyDecryptedData(buffer, offset, count);
int result = CheckOldKeyDecryptedData(buffer);
if (result != -1)
{
return result;
@@ -1235,12 +1220,6 @@ namespace System.Net.Security
_lockReadState = LockPendingRead;
if (request != null)
{
// Request queued.
_queuedReadStateRequest = request;
return 0;
}
lazyResult = new LazyAsyncResult(null, null, /*must be */ null);
_queuedReadStateRequest = lazyResult;
}
@@ -1248,7 +1227,40 @@ namespace System.Net.Security
lazyResult.InternalWaitForCompletion();
lock (this)
{
return CheckOldKeyDecryptedData(buffer, offset, count);
return CheckOldKeyDecryptedData(buffer);
}
}
internal ValueTask<int> CheckEnqueueReadAsync(Memory<byte> buffer)
{
int lockState = Interlocked.CompareExchange(ref _lockReadState, LockRead, LockNone);
if (lockState != LockHandshake)
{
// Proceed, no concurrent handshake is ongoing so no need for a lock.
return new ValueTask<int>(CheckOldKeyDecryptedData(buffer));
}
lock (this)
{
int result = CheckOldKeyDecryptedData(buffer);
if (result != -1)
{
return new ValueTask<int>(result);
}
// Check again under lock.
if (_lockReadState != LockHandshake)
{
// The other thread has finished before we grabbed the lock.
_lockReadState = LockRead;
return new ValueTask<int>(-1);
}
_lockReadState = LockPendingRead;
TaskCompletionSource<int> taskCompletionSource = new TaskCompletionSource<int>(buffer, TaskCreationOptions.RunContinuationsAsynchronously);
_queuedReadStateRequest = taskCompletionSource;
return new ValueTask<int>(taskCompletionSource.Task);
}
}
@@ -1346,23 +1358,30 @@ namespace System.Net.Security
lock (this)
{
HandleWriteCallback();
HandleQueuedCallback(ref _queuedWriteStateRequest);
}
}
private void HandleWriteCallback()
private void HandleQueuedCallback(ref object queuedStateRequest)
{
object obj = _queuedWriteStateRequest;
_queuedWriteStateRequest = null;
object obj = queuedStateRequest;
if (obj == null)
{
return;
}
queuedStateRequest = null;
switch (obj)
{
case null:
break;
case LazyAsyncResult lazy:
lazy.InvokeCallback();
break;
case TaskCompletionSource<int> tsc:
tsc.SetResult(0);
case TaskCompletionSource<int> taskCompletionSource when taskCompletionSource.Task.AsyncState != null:
Memory<byte> array = (Memory<byte>)taskCompletionSource.Task.AsyncState;
taskCompletionSource.SetResult(CheckOldKeyDecryptedData(array));
break;
case TaskCompletionSource<int> taskCompletionSource:
taskCompletionSource.SetResult(0);
break;
default:
ThreadPool.QueueUserWorkItem(new WaitCallback(AsyncResumeHandshake), obj);
@@ -1427,7 +1446,7 @@ namespace System.Net.Security
}
_lockWriteState = LockWrite;
HandleWriteCallback();
HandleQueuedCallback(ref _queuedWriteStateRequest);
}
}
finally
@@ -1662,7 +1681,8 @@ namespace System.Net.Security
// This is called from SslStream class too.
internal int GetRemainingFrameSize(byte[] buffer, int offset, int dataSize)
{
if (NetEventSource.IsEnabled) NetEventSource.Enter(this, buffer, offset, dataSize);
if (NetEventSource.IsEnabled)
NetEventSource.Enter(this, buffer, offset, dataSize);
int payloadSize = -1;
switch (_Framing)
@@ -1702,7 +1722,8 @@ namespace System.Net.Security
break;
}
if (NetEventSource.IsEnabled) NetEventSource.Exit(this, payloadSize);
if (NetEventSource.IsEnabled)
NetEventSource.Exit(this, payloadSize);
return payloadSize;
}
@@ -1824,7 +1845,7 @@ namespace System.Net.Security
internal IAsyncResult BeginShutdown(AsyncCallback asyncCallback, object asyncState)
{
CheckThrow(authSuccessCheck:true, shutdownCheck:true);
CheckThrow(authSuccessCheck: true, shutdownCheck: true);
ProtocolToken message = Context.CreateShutdownToken();
return TaskToApm.Begin(InnerStream.WriteAsync(message.Payload, 0, message.Payload.Length), asyncCallback, asyncState);
@@ -1832,7 +1853,7 @@ namespace System.Net.Security
internal void EndShutdown(IAsyncResult result)
{
CheckThrow(authSuccessCheck: true, shutdownCheck:true);
CheckThrow(authSuccessCheck: true, shutdownCheck: true);
TaskToApm.End(result);
_shutdown = true;

View File

@@ -2,7 +2,9 @@
// 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.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.Authentication;
using System.Security.Authentication.ExtendedProtection;
using System.Security.Cryptography.X509Certificates;
@@ -36,10 +38,14 @@ namespace System.Net.Security
public class SslStream : AuthenticatedStream
{
private SslState _sslState;
private RemoteCertificateValidationCallback _userCertificateValidationCallback;
private LocalCertificateSelectionCallback _userCertificateSelectionCallback;
private object _remoteCertificateOrBytes;
internal RemoteCertificateValidationCallback _userCertificateValidationCallback;
internal LocalCertificateSelectionCallback _userCertificateSelectionCallback;
internal RemoteCertValidationCallback _certValidationDelegate;
internal LocalCertSelectionCallback _certSelectionDelegate;
internal EncryptionPolicy _encryptionPolicy;
public SslStream(Stream innerStream)
: this(innerStream, false, null, null)
{
@@ -72,9 +78,44 @@ namespace System.Net.Security
_userCertificateValidationCallback = userCertificateValidationCallback;
_userCertificateSelectionCallback = userCertificateSelectionCallback;
RemoteCertValidationCallback _userCertValidationCallbackWrapper = new RemoteCertValidationCallback(UserCertValidationCallbackWrapper);
LocalCertSelectionCallback _userCertSelectionCallbackWrapper = userCertificateSelectionCallback == null ? null : new LocalCertSelectionCallback(UserCertSelectionCallbackWrapper);
_sslState = new SslState(innerStream, _userCertValidationCallbackWrapper, _userCertSelectionCallbackWrapper, encryptionPolicy);
_encryptionPolicy = encryptionPolicy;
_certValidationDelegate = new RemoteCertValidationCallback(UserCertValidationCallbackWrapper);
_certSelectionDelegate = userCertificateSelectionCallback == null ? null : new LocalCertSelectionCallback(UserCertSelectionCallbackWrapper);
_sslState = new SslState(innerStream);
}
public SslApplicationProtocol NegotiatedApplicationProtocol
{
get
{
return _sslState.NegotiatedApplicationProtocol;
}
}
private void SetAndVerifyValidationCallback(RemoteCertificateValidationCallback callback)
{
if (_userCertificateValidationCallback == null)
{
_userCertificateValidationCallback = callback;
_certValidationDelegate = new RemoteCertValidationCallback(UserCertValidationCallbackWrapper);
}
else if (callback != null && _userCertificateValidationCallback != callback)
{
throw new InvalidOperationException(SR.Format(SR.net_conflicting_options, nameof(RemoteCertificateValidationCallback)));
}
}
private void SetAndVerifySelectionCallback(LocalCertificateSelectionCallback callback)
{
if (_userCertificateSelectionCallback == null)
{
_userCertificateSelectionCallback = callback;
_certSelectionDelegate = _userCertificateSelectionCallback == null ? null : new LocalCertSelectionCallback(UserCertSelectionCallbackWrapper);
}
else if (callback != null && _userCertificateSelectionCallback != callback)
{
throw new InvalidOperationException(SR.Format(SR.net_conflicting_options, nameof(LocalCertificateSelectionCallback)));
}
}
private bool UserCertValidationCallbackWrapper(string hostName, X509Certificate2 certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
@@ -119,8 +160,29 @@ namespace System.Net.Security
SslProtocols enabledSslProtocols, bool checkCertificateRevocation,
AsyncCallback asyncCallback, object asyncState)
{
SecurityProtocol.ThrowOnNotAllowed(enabledSslProtocols);
_sslState.ValidateCreateContext(false, targetHost, enabledSslProtocols, null, clientCertificates, true, checkCertificateRevocation);
SslClientAuthenticationOptions options = new SslClientAuthenticationOptions
{
TargetHost = targetHost,
ClientCertificates = clientCertificates,
EnabledSslProtocols = enabledSslProtocols,
CertificateRevocationCheckMode = checkCertificateRevocation ? X509RevocationMode.Online : X509RevocationMode.NoCheck,
EncryptionPolicy = _encryptionPolicy,
};
return BeginAuthenticateAsClient(options, CancellationToken.None, asyncCallback, asyncState);
}
internal virtual IAsyncResult BeginAuthenticateAsClient(SslClientAuthenticationOptions sslClientAuthenticationOptions, CancellationToken cancellationToken, AsyncCallback asyncCallback, object asyncState)
{
SecurityProtocol.ThrowOnNotAllowed(sslClientAuthenticationOptions.EnabledSslProtocols);
SetAndVerifyValidationCallback(sslClientAuthenticationOptions.RemoteCertificateValidationCallback);
SetAndVerifySelectionCallback(sslClientAuthenticationOptions.LocalCertificateSelectionCallback);
// Set the delegates on the options.
sslClientAuthenticationOptions._certValidationDelegate = _certValidationDelegate;
sslClientAuthenticationOptions._certSelectionDelegate = _certSelectionDelegate;
_sslState.ValidateCreateContext(sslClientAuthenticationOptions);
LazyAsyncResult result = new LazyAsyncResult(_sslState, asyncState, asyncCallback);
_sslState.ProcessAuthentication(result);
@@ -154,8 +216,28 @@ namespace System.Net.Security
AsyncCallback asyncCallback,
object asyncState)
{
SecurityProtocol.ThrowOnNotAllowed(enabledSslProtocols);
_sslState.ValidateCreateContext(true, string.Empty, enabledSslProtocols, serverCertificate, null, clientCertificateRequired, checkCertificateRevocation);
SslServerAuthenticationOptions options = new SslServerAuthenticationOptions
{
ServerCertificate = serverCertificate,
ClientCertificateRequired = clientCertificateRequired,
EnabledSslProtocols = enabledSslProtocols,
CertificateRevocationCheckMode = checkCertificateRevocation ? X509RevocationMode.Online : X509RevocationMode.NoCheck,
EncryptionPolicy = _encryptionPolicy,
};
return BeginAuthenticateAsServer(options, CancellationToken.None, asyncCallback, asyncState);
}
private IAsyncResult BeginAuthenticateAsServer(SslServerAuthenticationOptions sslServerAuthenticationOptions, CancellationToken cancellationToken, AsyncCallback asyncCallback, object asyncState)
{
SecurityProtocol.ThrowOnNotAllowed(sslServerAuthenticationOptions.EnabledSslProtocols);
SetAndVerifyValidationCallback(sslServerAuthenticationOptions.RemoteCertificateValidationCallback);
// Set the delegate on the options.
sslServerAuthenticationOptions._certValidationDelegate = _certValidationDelegate;
_sslState.ValidateCreateContext(sslServerAuthenticationOptions);
LazyAsyncResult result = new LazyAsyncResult(_sslState, asyncState, asyncCallback);
_sslState.ProcessAuthentication(result);
return result;
@@ -202,8 +284,29 @@ namespace System.Net.Security
public virtual void AuthenticateAsClient(string targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
{
SecurityProtocol.ThrowOnNotAllowed(enabledSslProtocols);
_sslState.ValidateCreateContext(false, targetHost, enabledSslProtocols, null, clientCertificates, true, checkCertificateRevocation);
SslClientAuthenticationOptions options = new SslClientAuthenticationOptions
{
TargetHost = targetHost,
ClientCertificates = clientCertificates,
EnabledSslProtocols = enabledSslProtocols,
CertificateRevocationCheckMode = checkCertificateRevocation ? X509RevocationMode.Online : X509RevocationMode.NoCheck,
EncryptionPolicy = _encryptionPolicy,
};
AuthenticateAsClient(options);
}
private void AuthenticateAsClient(SslClientAuthenticationOptions sslClientAuthenticationOptions)
{
SecurityProtocol.ThrowOnNotAllowed(sslClientAuthenticationOptions.EnabledSslProtocols);
SetAndVerifyValidationCallback(sslClientAuthenticationOptions.RemoteCertificateValidationCallback);
SetAndVerifySelectionCallback(sslClientAuthenticationOptions.LocalCertificateSelectionCallback);
// Set the delegates on the options.
sslClientAuthenticationOptions._certValidationDelegate = _certValidationDelegate;
sslClientAuthenticationOptions._certSelectionDelegate = _certSelectionDelegate;
_sslState.ValidateCreateContext(sslClientAuthenticationOptions);
_sslState.ProcessAuthentication(null);
}
@@ -219,8 +322,27 @@ namespace System.Net.Security
public virtual void AuthenticateAsServer(X509Certificate serverCertificate, bool clientCertificateRequired, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
{
SecurityProtocol.ThrowOnNotAllowed(enabledSslProtocols);
_sslState.ValidateCreateContext(true, string.Empty, enabledSslProtocols, serverCertificate, null, clientCertificateRequired, checkCertificateRevocation);
SslServerAuthenticationOptions options = new SslServerAuthenticationOptions
{
ServerCertificate = serverCertificate,
ClientCertificateRequired = clientCertificateRequired,
EnabledSslProtocols = enabledSslProtocols,
CertificateRevocationCheckMode = checkCertificateRevocation ? X509RevocationMode.Online : X509RevocationMode.NoCheck,
EncryptionPolicy = _encryptionPolicy,
};
AuthenticateAsServer(options);
}
private void AuthenticateAsServer(SslServerAuthenticationOptions sslServerAuthenticationOptions)
{
SecurityProtocol.ThrowOnNotAllowed(sslServerAuthenticationOptions.EnabledSslProtocols);
SetAndVerifyValidationCallback(sslServerAuthenticationOptions.RemoteCertificateValidationCallback);
// Set the delegate on the options.
sslServerAuthenticationOptions._certValidationDelegate = _certValidationDelegate;
_sslState.ValidateCreateContext(sslServerAuthenticationOptions);
_sslState.ProcessAuthentication(null);
}
#endregion
@@ -252,6 +374,15 @@ namespace System.Net.Security
this);
}
public Task AuthenticateAsClientAsync(SslClientAuthenticationOptions sslClientAuthenticationOptions, CancellationToken cancellationToken)
{
return Task.Factory.FromAsync(
(arg1, arg2, callback, state) => ((SslStream)state).BeginAuthenticateAsClient(arg1, arg2, callback, state),
iar => ((SslStream)iar.AsyncState).EndAuthenticateAsClient(iar),
sslClientAuthenticationOptions, cancellationToken,
this);
}
public virtual Task AuthenticateAsServerAsync(X509Certificate serverCertificate) =>
Task.Factory.FromAsync(
(arg1, callback, state) => ((SslStream)state).BeginAuthenticateAsServer(arg1, callback, state),
@@ -278,6 +409,15 @@ namespace System.Net.Security
this);
}
public Task AuthenticateAsServerAsync(SslServerAuthenticationOptions sslServerAuthenticationOptions, CancellationToken cancellationToken)
{
return Task.Factory.FromAsync(
(arg1, arg2, callback, state) => ((SslStream)state).BeginAuthenticateAsServer(arg1, arg2, callback, state),
iar => ((SslStream)iar.AsyncState).EndAuthenticateAsServer(iar),
sslServerAuthenticationOptions, cancellationToken,
this);
}
public virtual Task ShutdownAsync() =>
Task.Factory.FromAsync(
(callback, state) => ((SslStream)state).BeginShutdown(callback, state),
@@ -575,5 +715,15 @@ namespace System.Net.Security
{
return _sslState.SecureStream.WriteAsync(source, cancellationToken);
}
public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
return _sslState.SecureStream.ReadAsync(buffer, offset, count, cancellationToken);
}
public override ValueTask<int> ReadAsync(Memory<byte> destination, CancellationToken cancellationToken = default)
{
return _sslState.SecureStream.ReadAsync(destination, cancellationToken);
}
}
}

View File

@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// 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.Threading;
@@ -15,7 +15,40 @@ namespace System.Net.Security
Task WriteAsync(byte[] buffer, int offset, int count);
}
private struct SslWriteAsync : ISslWriteAdapter
private interface ISslReadAdapter
{
ValueTask<int> ReadAsync(byte[] buffer, int offset, int count);
ValueTask<int> LockAsync(Memory<byte> buffer);
}
private readonly struct SslReadAsync : ISslReadAdapter
{
private readonly SslState _sslState;
private readonly CancellationToken _cancellationToken;
public SslReadAsync(SslState sslState, CancellationToken cancellationToken)
{
_cancellationToken = cancellationToken;
_sslState = sslState;
}
public ValueTask<int> ReadAsync(byte[] buffer, int offset, int count) => _sslState.InnerStream.ReadAsync(new Memory<byte>(buffer, offset, count), _cancellationToken);
public ValueTask<int> LockAsync(Memory<byte> buffer) => _sslState.CheckEnqueueReadAsync(buffer);
}
private readonly struct SslReadSync : ISslReadAdapter
{
private readonly SslState _sslState;
public SslReadSync(SslState sslState) => _sslState = sslState;
public ValueTask<int> ReadAsync(byte[] buffer, int offset, int count) => new ValueTask<int>(_sslState.InnerStream.Read(buffer, offset, count));
public ValueTask<int> LockAsync(Memory<byte> buffer) => new ValueTask<int>(_sslState.CheckEnqueueRead(buffer));
}
private readonly struct SslWriteAsync : ISslWriteAdapter
{
private readonly SslState _sslState;
private readonly CancellationToken _cancellationToken;
@@ -31,7 +64,7 @@ namespace System.Net.Security
public Task WriteAsync(byte[] buffer, int offset, int count) => _sslState.InnerStream.WriteAsync(buffer, offset, count, _cancellationToken);
}
private struct SslWriteSync : ISslWriteAdapter
private readonly struct SslWriteSync : ISslWriteAdapter
{
private readonly SslState _sslState;

View File

@@ -37,11 +37,21 @@ namespace System.Net.Security
public static SecurityStatusPal AcceptSecurityContext(
ref SafeFreeCredentials credential,
ref SafeDeleteContext context,
SecurityBuffer inputBuffer,
SecurityBuffer[] inputBuffers,
SecurityBuffer outputBuffer,
bool remoteCertRequired)
SslAuthenticationOptions sslAuthenticationOptions)
{
return HandshakeInternal(credential, ref context, inputBuffer, outputBuffer, true, remoteCertRequired, null);
if (inputBuffers != null)
{
Debug.Assert(inputBuffers.Length == 2);
Debug.Assert(inputBuffers[1].token == null);
return HandshakeInternal(credential, ref context, inputBuffers[0], outputBuffer, sslAuthenticationOptions);
}
else
{
return HandshakeInternal(credential, ref context, inputBuffer: null, outputBuffer, sslAuthenticationOptions);
}
}
public static SecurityStatusPal InitializeSecurityContext(
@@ -49,9 +59,10 @@ namespace System.Net.Security
ref SafeDeleteContext context,
string targetName,
SecurityBuffer inputBuffer,
SecurityBuffer outputBuffer)
SecurityBuffer outputBuffer,
SslAuthenticationOptions sslAuthenticationOptions)
{
return HandshakeInternal(credential, ref context, inputBuffer, outputBuffer, false, false, targetName);
return HandshakeInternal(credential, ref context, inputBuffer, outputBuffer, sslAuthenticationOptions);
}
public static SecurityStatusPal InitializeSecurityContext(
@@ -59,11 +70,28 @@ namespace System.Net.Security
ref SafeDeleteContext context,
string targetName,
SecurityBuffer[] inputBuffers,
SecurityBuffer outputBuffer)
SecurityBuffer outputBuffer,
SslAuthenticationOptions sslAuthenticationOptions)
{
Debug.Assert(inputBuffers.Length == 2);
Debug.Assert(inputBuffers[1].token == null);
return HandshakeInternal(credential, ref context, inputBuffers[0], outputBuffer, false, false, targetName);
return HandshakeInternal(credential, ref context, inputBuffers[0], outputBuffer, sslAuthenticationOptions);
}
public static SecurityBuffer[] GetIncomingSecurityBuffers(SslAuthenticationOptions options, ref SecurityBuffer incomingSecurity)
{
SecurityBuffer[] incomingSecurityBuffers = null;
if (incomingSecurity != null)
{
incomingSecurityBuffers = new SecurityBuffer[]
{
incomingSecurity,
new SecurityBuffer(null, 0, 0, SecurityBufferType.SECBUFFER_EMPTY)
};
}
return incomingSecurityBuffers;
}
public static SafeFreeCredentials AcquireCredentialsHandle(
@@ -75,6 +103,12 @@ namespace System.Net.Security
return new SafeFreeSslCredentials(certificate, protocols, policy);
}
internal static byte[] GetNegotiatedApplicationProtocol(SafeDeleteContext context)
{
// OSX SecureTransport does not export APIs to support ALPN, no-op.
return null;
}
public static SecurityStatusPal EncryptMessage(
SafeDeleteContext securityContext,
ReadOnlyMemory<byte> input,
@@ -97,7 +131,16 @@ namespace System.Net.Security
MemoryHandle memHandle = input.Retain(pin: true);
try
{
PAL_TlsIo status = Interop.AppleCrypto.SslWrite(sslHandle, (byte*)memHandle.PinnedPointer, input.Length, out int written);
PAL_TlsIo status;
lock (sslHandle)
{
status = Interop.AppleCrypto.SslWrite(
sslHandle,
(byte*)memHandle.Pointer,
input.Length,
out int written);
}
if (status < 0)
{
@@ -157,7 +200,12 @@ namespace System.Net.Security
fixed (byte* offsetInput = &buffer[offset])
{
int written;
PAL_TlsIo status = Interop.AppleCrypto.SslRead(sslHandle, offsetInput, count, out written);
PAL_TlsIo status;
lock (sslHandle)
{
status = Interop.AppleCrypto.SslRead(sslHandle, offsetInput, count, out written);
}
if (status < 0)
{
@@ -226,9 +274,7 @@ namespace System.Net.Security
ref SafeDeleteContext context,
SecurityBuffer inputBuffer,
SecurityBuffer outputBuffer,
bool isServer,
bool remoteCertRequired,
string targetName)
SslAuthenticationOptions sslAuthenticationOptions)
{
Debug.Assert(!credential.IsInvalid);
@@ -238,18 +284,17 @@ namespace System.Net.Security
if ((null == context) || context.IsInvalid)
{
sslContext = new SafeDeleteSslContext(credential as SafeFreeSslCredentials, isServer);
sslContext = new SafeDeleteSslContext(credential as SafeFreeSslCredentials, sslAuthenticationOptions);
context = sslContext;
if (!string.IsNullOrEmpty(targetName))
if (!string.IsNullOrEmpty(sslAuthenticationOptions.TargetHost))
{
Debug.Assert(!isServer, "targetName should not be set for server-side handshakes");
Interop.AppleCrypto.SslSetTargetName(sslContext.SslContext, targetName);
Debug.Assert(!sslAuthenticationOptions.IsServer, "targetName should not be set for server-side handshakes");
Interop.AppleCrypto.SslSetTargetName(sslContext.SslContext, sslAuthenticationOptions.TargetHost);
}
if (remoteCertRequired)
if (sslAuthenticationOptions.IsServer && sslAuthenticationOptions.RemoteCertRequired)
{
Debug.Assert(isServer, "remoteCertRequired should not be set for client-side handshakes");
Interop.AppleCrypto.SslSetAcceptClientCert(sslContext.SslContext);
}
}
@@ -259,7 +304,13 @@ namespace System.Net.Security
sslContext.Write(inputBuffer.token, inputBuffer.offset, inputBuffer.size);
}
SecurityStatusPal status = PerformHandshake(sslContext.SslContext);
SafeSslHandle sslHandle = sslContext.SslContext;
SecurityStatusPal status;
lock (sslHandle)
{
status = PerformHandshake(sslHandle);
}
byte[] output = sslContext.ReadPendingWrites();
outputBuffer.offset = 0;
@@ -320,7 +371,13 @@ namespace System.Net.Security
SafeDeleteContext securityContext)
{
SafeDeleteSslContext sslContext = ((SafeDeleteSslContext)securityContext);
int osStatus = Interop.AppleCrypto.SslShutdown(sslContext.SslContext);
SafeSslHandle sslHandle = sslContext.SslContext;
int osStatus;
lock (sslHandle)
{
osStatus = Interop.AppleCrypto.SslShutdown(sslHandle);
}
if (osStatus == 0)
{

View File

@@ -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.Collections.Generic;
using System.Diagnostics;
using System.Net.Security;
using System.Runtime.InteropServices;
@@ -29,22 +30,49 @@ namespace System.Net.Security
}
public static SecurityStatusPal AcceptSecurityContext(ref SafeFreeCredentials credential, ref SafeDeleteContext context,
SecurityBuffer inputBuffer, SecurityBuffer outputBuffer, bool remoteCertRequired)
SecurityBuffer[] inputBuffers, SecurityBuffer outputBuffer, SslAuthenticationOptions sslAuthenticationOptions)
{
return HandshakeInternal(credential, ref context, inputBuffer, outputBuffer, true, remoteCertRequired);
if (inputBuffers != null)
{
Debug.Assert(inputBuffers.Length == 2);
Debug.Assert(inputBuffers[1].token == null);
return HandshakeInternal(credential, ref context, inputBuffers[0], outputBuffer, sslAuthenticationOptions);
}
else
{
return HandshakeInternal(credential, ref context, inputBuffer: null, outputBuffer, sslAuthenticationOptions);
}
}
public static SecurityStatusPal InitializeSecurityContext(ref SafeFreeCredentials credential, ref SafeDeleteContext context,
string targetName, SecurityBuffer inputBuffer, SecurityBuffer outputBuffer)
string targetName, SecurityBuffer inputBuffer, SecurityBuffer outputBuffer, SslAuthenticationOptions sslAuthenticationOptions)
{
return HandshakeInternal(credential, ref context, inputBuffer, outputBuffer, false, false);
return HandshakeInternal(credential, ref context, inputBuffer, outputBuffer, sslAuthenticationOptions);
}
public static SecurityStatusPal InitializeSecurityContext(SafeFreeCredentials credential, ref SafeDeleteContext context, string targetName, SecurityBuffer[] inputBuffers, SecurityBuffer outputBuffer)
public static SecurityStatusPal InitializeSecurityContext(SafeFreeCredentials credential, ref SafeDeleteContext context, string targetName, SecurityBuffer[] inputBuffers, SecurityBuffer outputBuffer, SslAuthenticationOptions sslAuthenticationOptions)
{
Debug.Assert(inputBuffers.Length == 2);
Debug.Assert(inputBuffers[1].token == null);
return HandshakeInternal(credential, ref context, inputBuffers[0], outputBuffer, false, false);
return HandshakeInternal(credential, ref context, inputBuffers[0], outputBuffer, sslAuthenticationOptions);
}
public static SecurityBuffer[] GetIncomingSecurityBuffers(SslAuthenticationOptions options, ref SecurityBuffer incomingSecurity)
{
SecurityBuffer[] incomingSecurityBuffers = null;
if (incomingSecurity != null)
{
incomingSecurityBuffers = new SecurityBuffer[]
{
incomingSecurity,
new SecurityBuffer(null, 0, 0, SecurityBufferType.SECBUFFER_EMPTY)
};
}
return incomingSecurityBuffers;
}
public static SafeFreeCredentials AcquireCredentialsHandle(X509Certificate certificate,
@@ -55,7 +83,7 @@ namespace System.Net.Security
public static SecurityStatusPal EncryptMessage(SafeDeleteContext securityContext, ReadOnlyMemory<byte> input, int headerSize, int trailerSize, ref byte[] output, out int resultSize)
{
return EncryptDecryptHelper(securityContext, input, offset:0, size: 0, encrypt: true, output: ref output, resultSize: out resultSize);
return EncryptDecryptHelper(securityContext, input, offset: 0, size: 0, encrypt: true, output: ref output, resultSize: out resultSize);
}
public static SecurityStatusPal DecryptMessage(SafeDeleteContext securityContext, byte[] buffer, ref int offset, ref int count)
@@ -102,8 +130,13 @@ namespace System.Net.Security
connectionInfo = new SslConnectionInfo(((SafeDeleteSslContext)securityContext).SslContext);
}
private static SecurityStatusPal HandshakeInternal(SafeFreeCredentials credential, ref SafeDeleteContext context,
SecurityBuffer inputBuffer, SecurityBuffer outputBuffer, bool isServer, bool remoteCertRequired)
public static byte[] ConvertAlpnProtocolListToByteArray(List<SslApplicationProtocol> applicationProtocols)
{
return Interop.Ssl.ConvertAlpnProtocolListToByteArray(applicationProtocols);
}
private static SecurityStatusPal HandshakeInternal(SafeFreeCredentials credential, ref SafeDeleteContext context, SecurityBuffer inputBuffer,
SecurityBuffer outputBuffer, SslAuthenticationOptions sslAuthenticationOptions)
{
Debug.Assert(!credential.IsInvalid);
@@ -111,7 +144,7 @@ namespace System.Net.Security
{
if ((null == context) || context.IsInvalid)
{
context = new SafeDeleteSslContext(credential as SafeFreeSslCredentials, isServer, remoteCertRequired);
context = new SafeDeleteSslContext(credential as SafeFreeSslCredentials, sslAuthenticationOptions);
}
byte[] output = null;
@@ -127,6 +160,16 @@ namespace System.Net.Security
done = Interop.OpenSsl.DoSslHandshake(((SafeDeleteSslContext)context).SslContext, inputBuffer.token, inputBuffer.offset, inputBuffer.size, out output, out outputSize);
}
// When the handshake is done, and the context is server, check if the alpnHandle target was set to null during ALPN.
// If it was, then that indiciates ALPN failed, send failure.
// We have this workaround, as openssl supports terminating handshake only from version 1.1.0,
// whereas ALPN is supported from version 1.0.2.
SafeSslHandle sslContext = ((SafeDeleteSslContext)context).SslContext;
if (done && sslAuthenticationOptions.IsServer && sslAuthenticationOptions.ApplicationProtocols != null && sslContext.AlpnHandle.IsAllocated && sslContext.AlpnHandle.Target == null)
{
return new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, Interop.OpenSsl.CreateSslException(SR.net_alpn_failed));
}
outputBuffer.size = outputSize;
outputBuffer.offset = 0;
outputBuffer.token = outputSize > 0 ? output : null;
@@ -139,6 +182,14 @@ namespace System.Net.Security
}
}
internal static byte[] GetNegotiatedApplicationProtocol(SafeDeleteContext context)
{
if (context == null)
return null;
return Interop.Ssl.SslGetAlpnSelected(((SafeDeleteSslContext)context).SslContext);
}
private static SecurityStatusPal EncryptDecryptHelper(SafeDeleteContext securityContext, ReadOnlyMemory<byte> input, int offset, int size, bool encrypt, ref byte[] output, out int resultSize)
{
resultSize = 0;

View File

@@ -2,15 +2,15 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.Win32.SafeHandles;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Net.Security;
using System.Runtime.InteropServices;
using System.Security.Authentication;
using System.Security.Authentication.ExtendedProtection;
using System.Security.Cryptography.X509Certificates;
using System.Security.Principal;
using Microsoft.Win32.SafeHandles;
namespace System.Net.Security
{
@@ -41,24 +41,29 @@ namespace System.Net.Security
SSPIWrapper.GetVerifyPackageInfo(GlobalSSPI.SSPISecureChannel, SecurityPackage, true);
}
public static SecurityStatusPal AcceptSecurityContext(ref SafeFreeCredentials credentialsHandle, ref SafeDeleteContext context, SecurityBuffer inputBuffer, SecurityBuffer outputBuffer, bool remoteCertRequired)
public static byte[] ConvertAlpnProtocolListToByteArray(List<SslApplicationProtocol> protocols)
{
return Interop.Sec_Application_Protocols.ToByteArray(protocols);
}
public static SecurityStatusPal AcceptSecurityContext(ref SafeFreeCredentials credentialsHandle, ref SafeDeleteContext context, SecurityBuffer[] inputBuffers, SecurityBuffer outputBuffer, SslAuthenticationOptions sslAuthenticationOptions)
{
Interop.SspiCli.ContextFlags unusedAttributes = default(Interop.SspiCli.ContextFlags);
int errorCode = SSPIWrapper.AcceptSecurityContext(
GlobalSSPI.SSPISecureChannel,
ref credentialsHandle,
credentialsHandle,
ref context,
ServerRequiredFlags | (remoteCertRequired ? Interop.SspiCli.ContextFlags.MutualAuth : Interop.SspiCli.ContextFlags.Zero),
ServerRequiredFlags | (sslAuthenticationOptions.RemoteCertRequired ? Interop.SspiCli.ContextFlags.MutualAuth : Interop.SspiCli.ContextFlags.Zero),
Interop.SspiCli.Endianness.SECURITY_NATIVE_DREP,
inputBuffer,
inputBuffers,
outputBuffer,
ref unusedAttributes);
return SecurityStatusAdapterPal.GetSecurityStatusPalFromNativeInt(errorCode);
}
public static SecurityStatusPal InitializeSecurityContext(ref SafeFreeCredentials credentialsHandle, ref SafeDeleteContext context, string targetName, SecurityBuffer inputBuffer, SecurityBuffer outputBuffer)
public static SecurityStatusPal InitializeSecurityContext(ref SafeFreeCredentials credentialsHandle, ref SafeDeleteContext context, string targetName, SecurityBuffer inputBuffer, SecurityBuffer outputBuffer, SslAuthenticationOptions sslAuthenticationOptions)
{
Interop.SspiCli.ContextFlags unusedAttributes = default(Interop.SspiCli.ContextFlags);
@@ -76,7 +81,7 @@ namespace System.Net.Security
return SecurityStatusAdapterPal.GetSecurityStatusPalFromNativeInt(errorCode);
}
public static SecurityStatusPal InitializeSecurityContext(SafeFreeCredentials credentialsHandle, ref SafeDeleteContext context, string targetName, SecurityBuffer[] inputBuffers, SecurityBuffer outputBuffer)
public static SecurityStatusPal InitializeSecurityContext(SafeFreeCredentials credentialsHandle, ref SafeDeleteContext context, string targetName, SecurityBuffer[] inputBuffers, SecurityBuffer outputBuffer, SslAuthenticationOptions sslAuthenticationOptions)
{
Interop.SspiCli.ContextFlags unusedAttributes = default(Interop.SspiCli.ContextFlags);
@@ -94,6 +99,45 @@ namespace System.Net.Security
return SecurityStatusAdapterPal.GetSecurityStatusPalFromNativeInt(errorCode);
}
public static SecurityBuffer[] GetIncomingSecurityBuffers(SslAuthenticationOptions options, ref SecurityBuffer incomingSecurity)
{
SecurityBuffer alpnBuffer = null;
SecurityBuffer[] incomingSecurityBuffers = null;
if (options.ApplicationProtocols != null && options.ApplicationProtocols.Count != 0)
{
byte[] alpnBytes = SslStreamPal.ConvertAlpnProtocolListToByteArray(options.ApplicationProtocols);
alpnBuffer = new SecurityBuffer(alpnBytes, 0, alpnBytes.Length, SecurityBufferType.SECBUFFER_APPLICATION_PROTOCOLS);
}
if (incomingSecurity != null)
{
if (alpnBuffer != null)
{
incomingSecurityBuffers = new SecurityBuffer[]
{
incomingSecurity,
new SecurityBuffer(null, 0, 0, SecurityBufferType.SECBUFFER_EMPTY),
alpnBuffer
};
}
else
{
incomingSecurityBuffers = new SecurityBuffer[]
{
incomingSecurity,
new SecurityBuffer(null, 0, 0, SecurityBufferType.SECBUFFER_EMPTY)
};
}
}
else if (alpnBuffer != null)
{
incomingSecurity = alpnBuffer;
}
return incomingSecurityBuffers;
}
public static SafeFreeCredentials AcquireCredentialsHandle(X509Certificate certificate, SslProtocols protocols, EncryptionPolicy policy, bool isServer)
{
int protocolFlags = GetProtocolFlagsFromSslProtocols(protocols, isServer);
@@ -103,9 +147,9 @@ namespace System.Net.Security
if (!isServer)
{
direction = Interop.SspiCli.CredentialUse.SECPKG_CRED_OUTBOUND;
flags =
Interop.SspiCli.SCHANNEL_CRED.Flags.SCH_CRED_MANUAL_CRED_VALIDATION |
Interop.SspiCli.SCHANNEL_CRED.Flags.SCH_CRED_NO_DEFAULT_CREDS |
flags =
Interop.SspiCli.SCHANNEL_CRED.Flags.SCH_CRED_MANUAL_CRED_VALIDATION |
Interop.SspiCli.SCHANNEL_CRED.Flags.SCH_CRED_NO_DEFAULT_CREDS |
Interop.SspiCli.SCHANNEL_CRED.Flags.SCH_SEND_AUX_RECORD;
// CoreFX: always opt-in SCH_USE_STRONG_CRYPTO except for SSL3.
@@ -131,6 +175,24 @@ namespace System.Net.Security
return AcquireCredentialsHandle(direction, secureCredential);
}
internal static byte[] GetNegotiatedApplicationProtocol(SafeDeleteContext context)
{
Interop.SecPkgContext_ApplicationProtocol alpnContext = SSPIWrapper.QueryContextAttributes(
GlobalSSPI.SSPISecureChannel,
context,
Interop.SspiCli.ContextAttribute.SECPKG_ATTR_APPLICATION_PROTOCOL) as Interop.SecPkgContext_ApplicationProtocol;
// Check if the context returned is alpn data, with successful negotiation.
if (alpnContext == null ||
alpnContext.ProtoNegoExt != Interop.ApplicationProtocolNegotiationExt.ALPN ||
alpnContext.ProtoNegoStatus != Interop.ApplicationProtocolNegotiationStatus.Success)
{
return null;
}
return alpnContext.Protocol;
}
public static unsafe SecurityStatusPal EncryptMessage(SafeDeleteContext securityContext, ReadOnlyMemory<byte> input, int headerSize, int trailerSize, ref byte[] output, out int resultSize)
{
// Ensure that there is sufficient space for the message output.
@@ -182,7 +244,8 @@ namespace System.Net.Security
if (errorCode != 0)
{
if (NetEventSource.IsEnabled) NetEventSource.Info(securityContext, $"Encrypt ERROR {errorCode:X}");
if (NetEventSource.IsEnabled)
NetEventSource.Info(securityContext, $"Encrypt ERROR {errorCode:X}");
resultSize = 0;
return SecurityStatusAdapterPal.GetSecurityStatusPalFromNativeInt(errorCode);
}
@@ -266,7 +329,7 @@ namespace System.Net.Security
ref securityContext,
bufferDesc);
return SecurityStatusAdapterPal.GetSecurityStatusPalFromInterop(errorCode, attachException:true);
return SecurityStatusAdapterPal.GetSecurityStatusPalFromInterop(errorCode, attachException: true);
}
finally
{
@@ -287,7 +350,7 @@ namespace System.Net.Security
ref securityContext,
bufferDesc);
return SecurityStatusAdapterPal.GetSecurityStatusPalFromInterop(errorCode, attachException:true);
return SecurityStatusAdapterPal.GetSecurityStatusPalFromInterop(errorCode, attachException: true);
}
public static unsafe SafeFreeContextBufferChannelBinding QueryContextChannelBinding(SafeDeleteContext securityContext, ChannelBindingKind attribute)
@@ -402,7 +465,7 @@ namespace System.Net.Security
return SSPIWrapper.AcquireCredentialsHandle(GlobalSSPI.SSPISecureChannel, SecurityPackage, credUsage, secureCredential);
});
}
catch(Exception ex)
catch (Exception ex)
{
Debug.Fail("AcquireCredentialsHandle failed.", ex.ToString());
return SSPIWrapper.AcquireCredentialsHandle(GlobalSSPI.SSPISecureChannel, SecurityPackage, credUsage, secureCredential);

View File

@@ -12,14 +12,19 @@ namespace System.Security.Authentication
/// remote party willingness of accepting that.
/// </summary>
[Serializable]
#if !MONO
[System.Runtime.CompilerServices.TypeForwardedFrom("System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
#endif
public class AuthenticationException : SystemException
{
public AuthenticationException() { }
public AuthenticationException(string message) : base(message) { }
public AuthenticationException(string message, Exception innerException) : base(message, innerException) { }
protected AuthenticationException(SerializationInfo serializationInfo, StreamingContext streamingContext) : base(serializationInfo, streamingContext)
{
throw new PlatformNotSupportedException();
}
}
@@ -31,14 +36,19 @@ namespace System.Security.Authentication
/// </para>
/// </summary>
[Serializable]
#if !MONO
[System.Runtime.CompilerServices.TypeForwardedFrom("System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
#endif
public class InvalidCredentialException : AuthenticationException
{
public InvalidCredentialException() { }
public InvalidCredentialException(string message) : base(message) { }
public InvalidCredentialException(string message, Exception innerException) : base(message, innerException) { }
protected InvalidCredentialException(SerializationInfo serializationInfo, StreamingContext streamingContext) : base(serializationInfo, streamingContext)
{
throw new PlatformNotSupportedException();
}
}
}

Some files were not shown because too many files have changed in this diff Show More