Imported Upstream version 5.16.0.100

Former-commit-id: 38faa55fb9669e35e7d8448b15c25dc447f25767
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2018-08-07 15:19:03 +00:00
parent 0a9828183b
commit 7d7f676260
4419 changed files with 170950 additions and 90273 deletions

View File

@@ -138,20 +138,6 @@ namespace Mono.Security.Interface
get { return supportsTrustAnchors; }
}
/*
* Internal API, intended to be used by MonoTlsProvider implementations.
*/
internal static ICertificateValidator2 GetInternalValidator (MonoTlsSettings settings, MonoTlsProvider provider)
{
return (ICertificateValidator2)NoReflectionHelper.GetInternalValidator (provider, settings);
}
[Obsolete ("Use GetInternalValidator")]
internal static ICertificateValidator2 GetDefaultValidator (MonoTlsSettings settings, MonoTlsProvider provider)
{
return GetInternalValidator (settings, provider);
}
/*
* Use this overloaded version in user code.
*/

View File

@@ -0,0 +1,77 @@
//
// IMonoAuthenticationOptions.cs
//
// Author:
// Martin Baulig <mabaul@microsoft.com>
//
// Copyright (c) 2018 Xamarin Inc. (http://www.xamarin.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Security.Principal;
using System.Security.Cryptography;
namespace Mono.Security.Interface
{
delegate X509Certificate MonoServerCertificateSelectionCallback (object sender, string hostName);
interface IMonoAuthenticationOptions
{
bool AllowRenegotiation {
get; set;
}
RemoteCertificateValidationCallback RemoteCertificateValidationCallback { get; set; }
SslProtocols EnabledSslProtocols {
get; set;
}
EncryptionPolicy EncryptionPolicy {
get; set;
}
X509RevocationMode CertificateRevocationCheckMode {
get; set;
}
}
interface IMonoSslClientAuthenticationOptions : IMonoAuthenticationOptions
{
LocalCertificateSelectionCallback LocalCertificateSelectionCallback { get; set; }
string TargetHost { get; set; }
X509CertificateCollection ClientCertificates { get; set; }
}
interface IMonoSslServerAuthenticationOptions : IMonoAuthenticationOptions
{
bool ClientCertificateRequired { get; set; }
MonoServerCertificateSelectionCallback ServerCertificateSelectionCallback { get; set; }
X509Certificate ServerCertificate { get; set; }
}
}

View File

@@ -44,30 +44,42 @@ namespace Mono.Security.Interface
void AuthenticateAsClient (string targetHost);
void AuthenticateAsClient (string targetHost, X509CertificateCollection clientCertificates, bool checkCertificateRevocation);
void AuthenticateAsClient (string targetHost, X509CertificateCollection clientCertificates, SSA.SslProtocols enabledSslProtocols, bool checkCertificateRevocation);
IAsyncResult BeginAuthenticateAsClient (string targetHost, AsyncCallback asyncCallback, object asyncState);
IAsyncResult BeginAuthenticateAsClient (string targetHost, X509CertificateCollection clientCertificates, bool checkCertificateRevocation, AsyncCallback asyncCallback, object asyncState);
IAsyncResult BeginAuthenticateAsClient (string targetHost, X509CertificateCollection clientCertificates, SSA.SslProtocols enabledSslProtocols, bool checkCertificateRevocation, AsyncCallback asyncCallback, object asyncState);
void EndAuthenticateAsClient (IAsyncResult asyncResult);
void AuthenticateAsServer (X509Certificate serverCertificate);
void AuthenticateAsServer (X509Certificate serverCertificate, bool clientCertificateRequired, bool checkCertificateRevocation);
void AuthenticateAsServer (X509Certificate serverCertificate, bool clientCertificateRequired, SSA.SslProtocols enabledSslProtocols, bool checkCertificateRevocation);
IAsyncResult BeginAuthenticateAsServer (X509Certificate serverCertificate, AsyncCallback asyncCallback, object asyncState);
IAsyncResult BeginAuthenticateAsServer (X509Certificate serverCertificate, bool clientCertificateRequired, bool checkCertificateRevocation, AsyncCallback asyncCallback, object asyncState);
IAsyncResult BeginAuthenticateAsServer (X509Certificate serverCertificate, bool clientCertificateRequired, SSA.SslProtocols enabledSslProtocols, bool checkCertificateRevocation, AsyncCallback asyncCallback, object asyncState);
void EndAuthenticateAsServer (IAsyncResult asyncResult);
Task AuthenticateAsClientAsync (string targetHost);
Task AuthenticateAsClientAsync (string targetHost, X509CertificateCollection clientCertificates, bool checkCertificateRevocation);
Task AuthenticateAsClientAsync (string targetHost, X509CertificateCollection clientCertificates, SSA.SslProtocols enabledSslProtocols, bool checkCertificateRevocation);
Task AuthenticateAsServerAsync (X509Certificate serverCertificate);
Task AuthenticateAsServerAsync (X509Certificate serverCertificate, bool clientCertificateRequired, bool checkCertificateRevocation);
Task AuthenticateAsServerAsync (X509Certificate serverCertificate, bool clientCertificateRequired, SSA.SslProtocols enabledSslProtocols, bool checkCertificateRevocation);
int Read (byte[] buffer, int offset, int count);
@@ -196,6 +208,19 @@ namespace Mono.Security.Interface
MonoTlsConnectionInfo GetConnectionInfo ();
bool CanRenegotiate {
get;
}
Task RenegotiateAsync (CancellationToken cancellationToken);
}
interface IMonoSslStream2 : IMonoSslStream
{
Task AuthenticateAsClientAsync (IMonoSslClientAuthenticationOptions sslClientAuthenticationOptions, CancellationToken cancellationToken);
Task AuthenticateAsServerAsync (IMonoSslServerAuthenticationOptions sslServerAuthenticationOptions, CancellationToken cancellationToken);
}
}

View File

@@ -178,8 +178,14 @@ namespace Mono.Security.Interface
*
* Negative version numbers are reserved for martin work branches.
*
* Version History:
*
* - 1: everything up until May 2018
* - 2: the new ServicePointScheduler changes have landed
* - 3: full support for Client Certificates
*
*/
internal const int InternalVersion = 1;
internal const int InternalVersion = 3;
#endregion
}

View File

@@ -93,6 +93,17 @@ namespace Mono.Security.Interface
get; set;
}
/*
* Client Certificate Support.
*/
public string[] ClientCertificateIssuers {
get; set;
}
public bool DisallowUnauthenticatedCertificateRequest {
get; set;
}
/*
* If you set this here, then it will override 'ServicePointManager.SecurityProtocol'.
*/
@@ -181,6 +192,8 @@ namespace Mono.Security.Interface
EnabledCiphers = other.EnabledCiphers;
CertificateValidationTime = other.CertificateValidationTime;
SendCloseNotify = other.SendCloseNotify;
ClientCertificateIssuers = other.ClientCertificateIssuers;
DisallowUnauthenticatedCertificateRequest = other.DisallowUnauthenticatedCertificateRequest;
if (other.TrustAnchors != null)
TrustAnchors = new X509CertificateCollection (other.TrustAnchors);
if (other.CertificateSearchPaths != null) {

View File

@@ -142,6 +142,7 @@
./Mono.Security.Interface/CipherSuiteCode.cs
./Mono.Security.Interface/ExchangeAlgorithmType.cs
./Mono.Security.Interface/HashAlgorithmType.cs
./Mono.Security.Interface/IMonoAuthenticationOptions.cs
./Mono.Security.Interface/IMonoSslStream.cs
./Mono.Security.Interface/MonoTlsConnectionInfo.cs
./Mono.Security.Interface/MonoTlsProvider.cs

View File

@@ -278,132 +278,238 @@ namespace Mono.Security {
UInt32 p = BitConverterLE.ToUInt32 (headers, i * 40 + 20);
UInt32 s = BitConverterLE.ToUInt32 (headers, i * 40 + 12);
int l = (int) BitConverterLE.ToUInt32 (headers, i * 40 + 8);
if ((s <= r) && (r < s + l)) {
if ((s <= r) && (r < s + l))
return p + r - s;
}
}
return 0;
}
private static StrongNameSignature Error (string a)
{
//Console.WriteLine (a);
return null;
}
private static byte[] ReadMore (Stream stream, byte[] a, int newSize)
{
int oldSize = a.Length;
Array.Resize (ref a, newSize);
if (newSize <= oldSize)
return a;
int diff = newSize - oldSize;
return (stream.Read (a, oldSize, diff) == diff) ? a : null;
}
internal StrongNameSignature StrongHash (Stream stream, StrongNameOptions options)
{
StrongNameSignature info = new StrongNameSignature ();
HashAlgorithm hash = HashAlgorithm.Create (TokenAlgorithm);
CryptoStream cs = new CryptoStream (Stream.Null, hash, CryptoStreamMode.Write);
// MS-DOS Header - always 128 bytes
// Bing "msdn pecoff".
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680547(v=vs.85).aspx
// Very many of the magic constants and names, funny or otherwise, come from this.
// ref: Section 24.2.1, Partition II Metadata
byte[] mz = new byte [128];
stream.Read (mz, 0, 128);
if (BitConverterLE.ToUInt16 (mz, 0) != 0x5a4d)
return null;
UInt32 peHeader = BitConverterLE.ToUInt32 (mz, 60);
cs.Write (mz, 0, 128);
if (peHeader != 128) {
byte[] mzextra = new byte [peHeader - 128];
stream.Read (mzextra, 0, mzextra.Length);
cs.Write (mzextra, 0, mzextra.Length);
}
// PE File Header - always 248 bytes
// ref: Section 24.2.2, Partition II Metadata
byte[] pe = new byte [248];
stream.Read (pe, 0, 248);
if (BitConverterLE.ToUInt32 (pe, 0) != 0x4550)
return null;
if (BitConverterLE.ToUInt16 (pe, 4) != 0x14c)
return null;
// MUST zeroize both CheckSum and Security Directory
byte[] v = new byte [8];
Buffer.BlockCopy (v, 0, pe, 88, 4);
Buffer.BlockCopy (v, 0, pe, 152, 8);
cs.Write (pe, 0, 248);
UInt16 numSection = BitConverterLE.ToUInt16 (pe, 6);
int sectionLength = (numSection * 40);
byte[] sectionHeaders = new byte [sectionLength];
stream.Read (sectionHeaders, 0, sectionLength);
cs.Write (sectionHeaders, 0, sectionLength);
UInt32 cliHeaderRVA = BitConverterLE.ToUInt32 (pe, 232);
UInt32 cliHeaderPos = RVAtoPosition (cliHeaderRVA, numSection, sectionHeaders);
int cliHeaderSiz = (int) BitConverterLE.ToUInt32 (pe, 236);
// CLI Header
// ref: Section 24.3.3, Partition II Metadata
byte[] cli = new byte [cliHeaderSiz];
stream.Position = cliHeaderPos;
stream.Read (cli, 0, cliHeaderSiz);
UInt32 strongNameSignatureRVA = BitConverterLE.ToUInt32 (cli, 32);
info.SignaturePosition = RVAtoPosition (strongNameSignatureRVA, numSection, sectionHeaders);
info.SignatureLength = BitConverterLE.ToUInt32 (cli, 36);
// Read MS-DOS header.
UInt32 metadataRVA = BitConverterLE.ToUInt32 (cli, 8);
info.MetadataPosition = RVAtoPosition (metadataRVA, numSection, sectionHeaders);
info.MetadataLength = BitConverterLE.ToUInt32 (cli, 12);
const int mzSize = 64;
byte[] mz = new byte [mzSize];
if (options == StrongNameOptions.Metadata) {
cs.Close ();
hash.Initialize ();
byte[] metadata = new byte [info.MetadataLength];
stream.Position = info.MetadataPosition;
stream.Read (metadata, 0, metadata.Length);
info.Hash = hash.ComputeHash (metadata);
return info;
int peHeader = 0;
int mzRead = stream.Read (mz, 0, mzSize);
if (mzRead == mzSize && mz [0] == (byte)'M' && mz [1] == (byte)'Z') { // 0x5a4d
peHeader = BitConverterLE.ToInt32 (mz, 60);
if (peHeader < mzSize)
return Error ("peHeader_lt_64");
// Read MS-DOS stub.
mz = ReadMore (stream, mz, peHeader);
if (mz == null)
return Error ("read_mz2_failed");
} else if (mzRead >= 4 && mz [0] == (byte)'P' && mz [1] == (byte)'E' && mz [2] == 0 && mz [3] == 0) { // 0x4550
// MS-DOS header/stub can be omitted and just start with PE, though it is rare.
stream.Position = 0;
mz = new byte [0];
} else
return Error ("read_mz_or_mzsig_failed");
// PE File Header
// PE signature 4 bytes
// file header 20 bytes (really, at this point)
// optional header varies in size and its size is in the file header
// "optional" means "not in .obj files", but always in .dll/.exes
const int sizeOfPeSignature = 4;
const int sizeOfFileHeader = 20;
const int sizeOfOptionalHeaderMagic = 2;
const int offsetOfFileHeader = sizeOfPeSignature;
const int offsetOfOptionalHeader = sizeOfPeSignature + sizeOfFileHeader;
int sizeOfOptionalHeader = sizeOfOptionalHeaderMagic; // initial minimum
int minimumHeadersSize = offsetOfOptionalHeader + sizeOfOptionalHeader;
byte[] pe = new byte [minimumHeadersSize];
if (stream.Read (pe, 0, minimumHeadersSize) != minimumHeadersSize
|| pe [0] != (byte)'P' || pe [1] != (byte)'E' || pe [2] != 0 || pe [3] != 0) // 0x4550
return Error ("read_minimumHeadersSize_or_pesig_failed");
sizeOfOptionalHeader = BitConverterLE.ToUInt16 (pe, offsetOfFileHeader + 16);
if (sizeOfOptionalHeader < sizeOfOptionalHeaderMagic)
return Error ($"sizeOfOptionalHeader_lt_2 ${sizeOfOptionalHeader}");
int headersSize = offsetOfOptionalHeader + sizeOfOptionalHeader;
if (headersSize < offsetOfOptionalHeader) // check overflow
return Error ("headers_overflow");
// Read the rest of the NT headers (i.e. the rest of the optional header).
pe = ReadMore (stream, pe, headersSize);
if (pe == null)
return Error ("read_pe2_failed");
uint magic = BitConverterLE.ToUInt16 (pe, offsetOfOptionalHeader);
// Refer to PE32+ as PE64 for brevity.
// PE64 proposal that widened more fields was rejected.
// Between PE32 and PE32+:
// Some fields are the same size and offset. For example the entire
// MS-DOS header, FileHeader, and section headers, and some of the optional header.
// Some fields are PE32-only (BaseOfData).
// Some fields are constant size, some are pointer size.
// Relative virtual addresses and file offsets are always 4 bytes.
// Some fields offsets are offset by 4, 8, or 12, but mostly 0 or 16,
// and it so happens that the 4/8/12-offset fields are less interesting.
int pe64 = 0;
bool rom = false;
if (magic == 0x10B) {
// nothing
} else if (magic == 0x20B)
pe64 = 16;
else if (magic == 0x107)
rom = true;
else
return Error ("bad_magic_value");
uint numberOfRvaAndSizes = 0;
if (!rom) { // ROM images have no data directories or checksum.
if (sizeOfOptionalHeader >= offsetOfOptionalHeader + 92 + pe64 + 4)
numberOfRvaAndSizes = BitConverterLE.ToUInt32 (pe, offsetOfOptionalHeader + 92 + pe64);
// Clear CheckSum and Security Directory if present.
// CheckSum is located the same for PE32+, all data directories are not.
for (int i = 64; i < sizeOfOptionalHeader && i < 68; ++i)
pe [offsetOfOptionalHeader + i] = 0;
for (int i = 128 + pe64; i < sizeOfOptionalHeader && i < 128 + 8 + pe64; ++i)
pe [offsetOfOptionalHeader + i] = 0;
}
// now we hash every section EXCEPT the signature block
for (int i=0; i < numSection; i++) {
UInt32 start = BitConverterLE.ToUInt32 (sectionHeaders, i * 40 + 20);
int length = (int) BitConverterLE.ToUInt32 (sectionHeaders, i * 40 + 16);
byte[] section = new byte [length];
stream.Position = start;
stream.Read (section, 0, length);
if ((start <= info.SignaturePosition) && (info.SignaturePosition < start + length)) {
// hash before the signature
int before = (int)(info.SignaturePosition - start);
if (before > 0) {
cs.Write (section, 0, before);
}
// copy signature
info.Signature = new byte [info.SignatureLength];
Buffer.BlockCopy (section, before, info.Signature, 0, (int)info.SignatureLength);
Array.Reverse (info.Signature);
// hash after the signature
int s = (int)(before + info.SignatureLength);
int after = (int)(length - s);
if (after > 0) {
cs.Write (section, s, after);
// Read the section headers if present (an image can have no sections, just headers).
const int sizeOfSectionHeader = 40;
int numberOfSections = BitConverterLE.ToUInt16 (pe, offsetOfFileHeader + 2);
byte[] sectionHeaders = new byte [numberOfSections * sizeOfSectionHeader];
if (stream.Read (sectionHeaders, 0, sectionHeaders.Length) != sectionHeaders.Length)
return Error ("read_section_headers_failed");
// Read the CLR header if present.
uint SignaturePosition = 0;
uint SignatureLength = 0;
uint MetadataPosition = 0;
uint MetadataLength = 0;
if (15 < numberOfRvaAndSizes && sizeOfOptionalHeader >= 216 + pe64) {
uint cliHeaderRVA = BitConverterLE.ToUInt32 (pe, offsetOfOptionalHeader + 208 + pe64);
uint cliHeaderPos = RVAtoPosition (cliHeaderRVA, numberOfSections, sectionHeaders);
int cliHeaderSiz = BitConverterLE.ToInt32 (pe, offsetOfOptionalHeader + 208 + 4 + pe64);
// CLI Header
// ref: Section 24.3.3, Partition II Metadata
var cli = new byte [cliHeaderSiz];
stream.Position = cliHeaderPos;
if (stream.Read (cli, 0, cliHeaderSiz) != cliHeaderSiz)
return Error ("read_cli_header_failed");
uint strongNameSignatureRVA = BitConverterLE.ToUInt32 (cli, 32);
SignaturePosition = RVAtoPosition (strongNameSignatureRVA, numberOfSections, sectionHeaders);
SignatureLength = BitConverterLE.ToUInt32 (cli, 36);
uint metadataRVA = BitConverterLE.ToUInt32 (cli, 8);
MetadataPosition = RVAtoPosition (metadataRVA, numberOfSections, sectionHeaders);
MetadataLength = BitConverterLE.ToUInt32 (cli, 12);
}
StrongNameSignature info = new StrongNameSignature ();
info.SignaturePosition = SignaturePosition;
info.SignatureLength = SignatureLength;
info.MetadataPosition = MetadataPosition;
info.MetadataLength = MetadataLength;
using (HashAlgorithm hash = HashAlgorithm.Create (TokenAlgorithm)) {
if (options == StrongNameOptions.Metadata) {
hash.Initialize ();
byte[] metadata = new byte [MetadataLength];
stream.Position = MetadataPosition;
if (stream.Read (metadata, 0, (int)MetadataLength) != (int)MetadataLength)
return Error ("read_cli_metadata_failed");
info.Hash = hash.ComputeHash (metadata);
return info;
}
using (CryptoStream cs = new CryptoStream (Stream.Null, hash, CryptoStreamMode.Write)) {
cs.Write (mz, 0, mz.Length); // Hash MS-DOS header/stub despite that stub is not run.
cs.Write (pe, 0, pe.Length);
cs.Write (sectionHeaders, 0, sectionHeaders.Length);
// now we hash every section EXCEPT the signature block
for (int i=0; i < numberOfSections; i++) {
UInt32 start = BitConverterLE.ToUInt32 (sectionHeaders, i * sizeOfSectionHeader + 20);
int length = BitConverterLE.ToInt32 (sectionHeaders, i * sizeOfSectionHeader + 16);
byte[] section = new byte [length];
stream.Position = start;
if (stream.Read (section, 0, length) != length)
return Error ("read_section_failed");
// The signature is assumed not to straddle sections.
if ((start <= SignaturePosition) && (SignaturePosition < start + (uint)length)) {
// hash before the signature
int before = (int)(SignaturePosition - start);
if (before > 0)
cs.Write (section, 0, before);
// copy signature
info.Signature = new byte [SignatureLength];
Buffer.BlockCopy (section, before, info.Signature, 0, (int)SignatureLength);
Array.Reverse (info.Signature);
// hash after the signature
int s = (int)(before + SignatureLength);
int after = (int)(length - s);
if (after > 0)
cs.Write (section, s, after);
}
else
cs.Write (section, 0, length);
}
}
else
cs.Write (section, 0, length);
info.Hash = hash.Hash;
}
cs.Close ();
info.Hash = hash.Hash;
return info;
}
// return the same result as the undocumented and unmanaged GetHashFromAssemblyFile
public byte[] Hash (string fileName)
{
FileStream fs = File.OpenRead (fileName);
StrongNameSignature sn = StrongHash (fs, StrongNameOptions.Metadata);
fs.Close ();
return sn.Hash;
using (FileStream fs = File.OpenRead (fileName)) {
return StrongHash (fs, StrongNameOptions.Metadata).Hash;
}
}
public bool Sign (string fileName)
{
bool result = false;
StrongNameSignature sn;
using (FileStream fs = File.OpenRead (fileName)) {
sn = StrongHash (fs, StrongNameOptions.Signature);
fs.Close ();
}
if (sn.Hash == null)
return false;
@@ -422,28 +528,22 @@ namespace Mono.Security {
using (FileStream fs = File.OpenWrite (fileName)) {
fs.Position = sn.SignaturePosition;
fs.Write (signature, 0, signature.Length);
fs.Close ();
result = true;
}
return result;
return true;
}
public bool Verify (string fileName)
{
bool result = false;
using (FileStream fs = File.OpenRead (fileName)) {
result = Verify (fs);
fs.Close ();
return Verify (fs);
}
return result;
}
public bool Verify (Stream stream)
{
StrongNameSignature sn = StrongHash (stream, StrongNameOptions.Signature);
if (sn.Hash == null) {
if (sn.Hash == null)
return false;
}
try {
AssemblyHashAlgorithm algorithm = AssemblyHashAlgorithm.SHA1;
@@ -482,23 +582,20 @@ namespace Mono.Security {
return false;
byte[] publicKey = StrongNameManager.GetMappedPublicKey (an.GetPublicKeyToken ());
if ((publicKey == null) || (publicKey.Length < 12)) {
if (publicKey == null || publicKey.Length < 12) {
// no mapping
publicKey = an.GetPublicKey ();
if ((publicKey == null) || (publicKey.Length < 12))
if (publicKey == null || publicKey.Length < 12)
return false;
}
// Note: MustVerify is based on the original token (by design). Public key
// remapping won't affect if the assembly is verified or not.
if (!StrongNameManager.MustVerify (an)) {
if (!StrongNameManager.MustVerify (an))
return true;
}
RSA rsa = CryptoConvert.FromCapiPublicKeyBlob (publicKey, 12);
StrongName sn = new StrongName (rsa);
bool result = sn.Verify (assemblyName);
return result;
return new StrongName (rsa).Verify (assemblyName);
}
catch {
// no exception allowed