You've already forked linux-packaging-mono
Imported Upstream version 5.16.0.100
Former-commit-id: 38faa55fb9669e35e7d8448b15c25dc447f25767
This commit is contained in:
parent
0a9828183b
commit
7d7f676260
@@ -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.
|
||||
*/
|
||||
|
@@ -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; }
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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) {
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user