Imported Upstream version 5.0.0.42

Former-commit-id: fd56571888259555122d8a0f58c68838229cea2b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2017-04-10 11:41:01 +00:00
parent 1190d13a04
commit 6bdd276d05
19939 changed files with 3099680 additions and 93811 deletions

View File

@@ -0,0 +1,40 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.23107.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common.Tests", "tests\Common.Tests.csproj", "{C72FD34C-539A-4447-9796-62A229571199}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
FreeBSD_Debug|Any CPU = FreeBSD_Debug|Any CPU
FreeBSD_Release|Any CPU = FreeBSD_Release|Any CPU
Linux_Debug|Any CPU = Linux_Debug|Any CPU
Linux_Release|Any CPU = Linux_Release|Any CPU
OSX_Debug|Any CPU = OSX_Debug|Any CPU
OSX_Release|Any CPU = OSX_Release|Any CPU
Windows_Debug|Any CPU = Windows_Debug|Any CPU
Windows_Release|Any CPU = Windows_Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C72FD34C-539A-4447-9796-62A229571199}.FreeBSD_Debug|Any CPU.ActiveCfg = FreeBSD_Debug|Any CPU
{C72FD34C-539A-4447-9796-62A229571199}.FreeBSD_Debug|Any CPU.Build.0 = FreeBSD_Debug|Any CPU
{C72FD34C-539A-4447-9796-62A229571199}.FreeBSD_Release|Any CPU.ActiveCfg = FreeBSD_Release|Any CPU
{C72FD34C-539A-4447-9796-62A229571199}.FreeBSD_Release|Any CPU.Build.0 = FreeBSD_Release|Any CPU
{C72FD34C-539A-4447-9796-62A229571199}.Linux_Debug|Any CPU.ActiveCfg = Linux_Debug|Any CPU
{C72FD34C-539A-4447-9796-62A229571199}.Linux_Debug|Any CPU.Build.0 = Linux_Debug|Any CPU
{C72FD34C-539A-4447-9796-62A229571199}.Linux_Release|Any CPU.ActiveCfg = Linux_Release|Any CPU
{C72FD34C-539A-4447-9796-62A229571199}.Linux_Release|Any CPU.Build.0 = Linux_Release|Any CPU
{C72FD34C-539A-4447-9796-62A229571199}.OSX_Debug|Any CPU.ActiveCfg = OSX_Debug|Any CPU
{C72FD34C-539A-4447-9796-62A229571199}.OSX_Debug|Any CPU.Build.0 = OSX_Debug|Any CPU
{C72FD34C-539A-4447-9796-62A229571199}.OSX_Release|Any CPU.ActiveCfg = OSX_Release|Any CPU
{C72FD34C-539A-4447-9796-62A229571199}.OSX_Release|Any CPU.Build.0 = OSX_Release|Any CPU
{C72FD34C-539A-4447-9796-62A229571199}.Windows_Debug|Any CPU.ActiveCfg = Windows_Debug|Any CPU
{C72FD34C-539A-4447-9796-62A229571199}.Windows_Debug|Any CPU.Build.0 = Windows_Debug|Any CPU
{C72FD34C-539A-4447-9796-62A229571199}.Windows_Release|Any CPU.ActiveCfg = Windows_Release|Any CPU
{C72FD34C-539A-4447-9796-62A229571199}.Windows_Release|Any CPU.Build.0 = Windows_Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,28 @@
{
"dependencies": {
"Microsoft.DotNet.xunit.performance.analysis": "1.0.0-alpha-build0040",
"Microsoft.DotNet.xunit.performance.analysis.cli": "1.0.0-alpha-build0040",
"Microsoft.DotNet.xunit.performance.runner.cli": "1.0.0-alpha-build0040",
"Microsoft.DotNet.xunit.performance.runner.Windows": "1.0.0-alpha-build0040"
},
"frameworks": {
"netstandard1.3": {}
},
"supports": {
"coreFx.Test.netcoreapp1.0": {
"netcoreapp1.0": [
"win7-x86",
"win7-x64",
"osx.10.10-x64",
"centos.7-x64",
"debian.8-x64",
"rhel.7-x64",
"ubuntu.14.04-x64",
"ubuntu.16.04-x64",
"fedora.23-x64",
"linux-x64",
"opensuse.13.2-x64"
]
}
}
}

View File

@@ -0,0 +1,57 @@
// 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;
using System.Diagnostics;
using System.Security.Cryptography;
namespace Internal.Cryptography
{
//
// Represents a symmetric reusable cipher encryptor or decryptor. Underlying technology may be CNG or OpenSSL or anything else.
// The key, IV, chaining mode, blocksize and direction of encryption are all locked in when the BasicSymmetricCipher is instantiated.
//
// - Performs no padding. Padding is done by a higher-level layer.
//
// - Transform and TransformFinal only accept blocks whose sizes are a multiple of the crypto algorithms block size.
//
// - Transform() can do in-place encryption/decryption (input and output referencing the same array.)
//
// - TransformFinal() resets the object for reuse.
//
internal abstract class BasicSymmetricCipher : IDisposable
{
protected BasicSymmetricCipher(byte[] iv, int blockSizeInBytes)
{
IV = iv;
BlockSizeInBytes = blockSizeInBytes;
}
public abstract int Transform(byte[] input, int inputOffset, int count, byte[] output, int outputOffset);
public abstract byte[] TransformFinal(byte[] input, int inputOffset, int count);
public int BlockSizeInBytes { get; private set; }
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (IV != null)
{
Array.Clear(IV, 0, IV.Length);
IV = null;
}
}
}
protected byte[] IV { get; private set; }
}
}

View File

@@ -0,0 +1,122 @@
// 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;
using System.Diagnostics;
using System.Security.Cryptography;
using Internal.NativeCrypto;
namespace Internal.Cryptography
{
internal sealed class BasicSymmetricCipherBCrypt : BasicSymmetricCipher
{
private readonly bool _encrypting;
private SafeKeyHandle _hKey;
private byte[] _currentIv; // CNG mutates this with the updated IV for the next stage on each Encrypt/Decrypt call.
// The base IV holds a copy of the original IV for Reset(), until it is cleared by Dispose().
public BasicSymmetricCipherBCrypt(SafeAlgorithmHandle algorithm, CipherMode cipherMode, int blockSizeInBytes, byte[] key, bool ownsParentHandle, byte[] iv, bool encrypting)
: base(cipherMode.GetCipherIv(iv), blockSizeInBytes)
{
Debug.Assert(algorithm != null);
_encrypting = encrypting;
if (IV != null)
{
_currentIv = new byte[IV.Length];
}
_hKey = algorithm.BCryptImportKey(key);
if (ownsParentHandle)
{
_hKey.SetParentHandle(algorithm);
}
Reset();
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
SafeKeyHandle hKey = _hKey;
_hKey = null;
if (hKey != null)
{
hKey.Dispose();
}
byte[] currentIv = _currentIv;
_currentIv = null;
if (currentIv != null)
{
Array.Clear(currentIv, 0, currentIv.Length);
}
}
base.Dispose(disposing);
}
public override int Transform(byte[] input, int inputOffset, int count, byte[] output, int outputOffset)
{
Debug.Assert(input != null);
Debug.Assert(inputOffset >= 0);
Debug.Assert(count > 0);
Debug.Assert((count % BlockSizeInBytes) == 0);
Debug.Assert(input.Length - inputOffset >= count);
Debug.Assert(output != null);
Debug.Assert(outputOffset >= 0);
Debug.Assert(output.Length - outputOffset >= count);
int numBytesWritten;
if (_encrypting)
{
numBytesWritten = _hKey.BCryptEncrypt(input, inputOffset, count, _currentIv, output, outputOffset, output.Length - outputOffset);
}
else
{
numBytesWritten = _hKey.BCryptDecrypt(input, inputOffset, count, _currentIv, output, outputOffset, output.Length - outputOffset);
}
if (numBytesWritten != count)
{
// CNG gives us no way to tell BCryptDecrypt() that we're decrypting the final block, nor is it performing any
// padding /depadding for us. So there's no excuse for a provider to hold back output for "future calls." Though
// this isn't technically our problem to detect, we might as well detect it now for easier diagnosis.
throw new CryptographicException(SR.Cryptography_UnexpectedTransformTruncation);
}
return numBytesWritten;
}
public override byte[] TransformFinal(byte[] input, int inputOffset, int count)
{
Debug.Assert(input != null);
Debug.Assert(inputOffset >= 0);
Debug.Assert(count >= 0);
Debug.Assert((count % BlockSizeInBytes) == 0);
Debug.Assert(input.Length - inputOffset >= count);
byte[] output = new byte[count];
if (count != 0)
{
int numBytesWritten = Transform(input, inputOffset, count, output, 0);
Debug.Assert(numBytesWritten == count); // Our implementation of Transform() guarantees this. See comment above.
}
Reset();
return output;
}
private void Reset()
{
if (IV != null)
{
Buffer.BlockCopy(IV, 0, _currentIv, 0, IV.Length);
}
}
}
}

View File

@@ -0,0 +1,50 @@
// 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;
using System.Diagnostics;
using System.IO;
using System.Security.Cryptography;
namespace Internal.Cryptography
{
internal static partial class CngCommon
{
public static byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm)
{
// The classes that call us are sealed and their base class has checked this already.
Debug.Assert(data != null);
Debug.Assert(offset >= 0 && offset <= data.Length);
Debug.Assert(count >= 0 && count <= data.Length);
Debug.Assert(!string.IsNullOrEmpty(hashAlgorithm.Name));
using (HashProviderCng hashProvider = new HashProviderCng(hashAlgorithm.Name, null))
{
hashProvider.AppendHashData(data, offset, count);
byte[] hash = hashProvider.FinalizeHashAndReset();
return hash;
}
}
public static byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm)
{
// The classes that call us are sealed and their base class has checked this already.
Debug.Assert(data != null);
Debug.Assert(!string.IsNullOrEmpty(hashAlgorithm.Name));
using (HashProviderCng hashProvider = new HashProviderCng(hashAlgorithm.Name, null))
{
// Default the buffer size to 4K.
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = data.Read(buffer, 0, buffer.Length)) > 0)
{
hashProvider.AppendHashData(buffer, 0, bytesRead);
}
byte[] hash = hashProvider.FinalizeHashAndReset();
return hash;
}
}
}
}

View File

@@ -0,0 +1,45 @@
// 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;
using System.Diagnostics;
using System.Security.Cryptography;
using Microsoft.Win32.SafeHandles;
using ErrorCode = Interop.NCrypt.ErrorCode;
using AsymmetricPaddingMode = Interop.NCrypt.AsymmetricPaddingMode;
namespace Internal.Cryptography
{
internal static partial class CngCommon
{
public static unsafe byte[] SignHash(this SafeNCryptKeyHandle keyHandle, byte[] hash, AsymmetricPaddingMode paddingMode, void* pPaddingInfo, int estimatedSize)
{
#if DEBUG
estimatedSize = 2; // Make sure the NTE_BUFFER_TOO_SMALL scenario gets exercised.
#endif
byte[] signature = new byte[estimatedSize];
int numBytesNeeded;
ErrorCode errorCode = Interop.NCrypt.NCryptSignHash(keyHandle, pPaddingInfo, hash, hash.Length, signature, signature.Length, out numBytesNeeded, paddingMode);
if (errorCode == ErrorCode.NTE_BUFFER_TOO_SMALL)
{
signature = new byte[numBytesNeeded];
errorCode = Interop.NCrypt.NCryptSignHash(keyHandle, pPaddingInfo, hash, hash.Length, signature, signature.Length, out numBytesNeeded, paddingMode);
}
if (errorCode != ErrorCode.ERROR_SUCCESS)
throw errorCode.ToCryptographicException();
Array.Resize(ref signature, numBytesNeeded);
return signature;
}
public static unsafe bool VerifyHash(this SafeNCryptKeyHandle keyHandle, byte[] hash, byte[] signature, AsymmetricPaddingMode paddingMode, void* pPaddingInfo)
{
ErrorCode errorCode = Interop.NCrypt.NCryptVerifySignature(keyHandle, pPaddingInfo, hash, hash.Length, signature, signature.Length, paddingMode);
bool verified = (errorCode == ErrorCode.ERROR_SUCCESS); // For consistency with other AsymmetricAlgorithm-derived classes, return "false" for any error code rather than making the caller catch an exception.
return verified;
}
}
}

View File

@@ -0,0 +1,56 @@
// 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;
using System.Diagnostics;
namespace Internal.Cryptography
{
//
// This abstract class represents a reusable hash object and can wrap a CNG or WinRT hash object.
//
internal abstract class HashProvider : IDisposable
{
// Adds new data to be hashed. This can be called repeatedly in order to hash data from noncontiguous sources.
public void AppendHashData(byte[] data, int offset, int count)
{
// AppendHashData can be called via exposed APIs (e.g. a type that derives from
// HMACSHA1 and calls HashCore) and could be passed bad data from there. It could
// also receive a bad count from HashAlgorithm reading from a Stream that returns
// an invalid number of bytes read. Since our implementations of AppendHashDataCore
// end up using unsafe code, we want to be sure the arguments are valid.
if (data == null)
throw new ArgumentNullException(nameof(data), SR.ArgumentNull_Buffer);
if (offset < 0)
throw new ArgumentOutOfRangeException(nameof(offset), SR.ArgumentOutOfRange_NeedNonNegNum);
if (count < 0)
throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum);
if (data.Length - offset < count)
throw new ArgumentException(SR.Argument_InvalidOffLen);
AppendHashDataCore(data, offset, count);
}
// Adds new data to be hashed. This can be called repeatedly in order to hash data from noncontiguous sources.
// Argument validation is handled by AppendHashData.
public abstract void AppendHashDataCore(byte[] data, int offset, int count);
// Compute the hash based on the appended data and resets the HashProvider for more hashing.
public abstract byte[] FinalizeHashAndReset();
// Returns the length of the byte array returned by FinalizeHashAndReset.
public abstract int HashSizeInBytes { get; }
// Releases any native resources and keys used by the HashProvider.
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
// Releases any native resources and keys used by the HashProvider.
public abstract void Dispose(bool disposing);
}
}

View File

@@ -0,0 +1,152 @@
// 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;
using System.Diagnostics;
using System.Security.Cryptography;
using Microsoft.Win32.SafeHandles;
using NTSTATUS = Interop.BCrypt.NTSTATUS;
using BCryptOpenAlgorithmProviderFlags = Interop.BCrypt.BCryptOpenAlgorithmProviderFlags;
using BCryptCreateHashFlags = Interop.BCrypt.BCryptCreateHashFlags;
namespace Internal.Cryptography
{
//
// Provides hash services via the native provider (CNG).
//
internal sealed class HashProviderCng : HashProvider
{
//
// - "hashAlgId" must be a name recognized by BCryptOpenAlgorithmProvider(). Examples: MD5, SHA1, SHA256.
//
// - "key" activates MAC hashing if present. If null, this HashProvider performs a regular old hash.
//
public HashProviderCng(string hashAlgId, byte[] key)
{
BCryptOpenAlgorithmProviderFlags dwFlags = BCryptOpenAlgorithmProviderFlags.None;
if (key != null)
{
_key = key.CloneByteArray();
dwFlags |= BCryptOpenAlgorithmProviderFlags.BCRYPT_ALG_HANDLE_HMAC_FLAG;
}
_hAlgorithm = Interop.BCrypt.BCryptAlgorithmCache.GetCachedBCryptAlgorithmHandle(hashAlgId, dwFlags);
// Win7 won't set hHash, Win8+ will; and both will set _hHash.
// So keep hHash trapped in this scope to prevent (mis-)use of it.
{
SafeBCryptHashHandle hHash = null;
NTSTATUS ntStatus = Interop.BCrypt.BCryptCreateHash(_hAlgorithm, out hHash, IntPtr.Zero, 0, key, key == null ? 0 : key.Length, BCryptCreateHashFlags.BCRYPT_HASH_REUSABLE_FLAG);
if (ntStatus == NTSTATUS.STATUS_INVALID_PARAMETER)
{
// If we got here, we're running on a downlevel OS (pre-Win8) that doesn't support reusable CNG hash objects. Fall back to creating a
// new HASH object each time.
ResetHashObject();
}
else if (ntStatus != NTSTATUS.STATUS_SUCCESS)
{
throw Interop.BCrypt.CreateCryptographicException(ntStatus);
}
else
{
_hHash = hHash;
_reusable = true;
}
}
unsafe
{
int cbSizeOfHashSize;
int hashSize;
NTSTATUS ntStatus = Interop.BCrypt.BCryptGetProperty(_hHash, Interop.BCrypt.BCryptPropertyStrings.BCRYPT_HASH_LENGTH, &hashSize, sizeof(int), out cbSizeOfHashSize, 0);
if (ntStatus != NTSTATUS.STATUS_SUCCESS)
throw Interop.BCrypt.CreateCryptographicException(ntStatus);
_hashSize = hashSize;
}
return;
}
public sealed override void AppendHashDataCore(byte[] data, int offset, int count)
{
unsafe
{
fixed (byte* pRgb = data)
{
NTSTATUS ntStatus = Interop.BCrypt.BCryptHashData(_hHash, pRgb + offset, count, 0);
if (ntStatus != NTSTATUS.STATUS_SUCCESS)
throw Interop.BCrypt.CreateCryptographicException(ntStatus);
}
}
}
public sealed override byte[] FinalizeHashAndReset()
{
byte[] hash = new byte[_hashSize];
NTSTATUS ntStatus = Interop.BCrypt.BCryptFinishHash(_hHash, hash, hash.Length, 0);
if (ntStatus != NTSTATUS.STATUS_SUCCESS)
throw Interop.BCrypt.CreateCryptographicException(ntStatus);
ResetHashObject();
return hash;
}
public sealed override void Dispose(bool disposing)
{
if (disposing)
{
DestroyHash();
if (_key != null)
{
byte[] key = _key;
_key = null;
Array.Clear(key, 0, key.Length);
}
}
}
public sealed override int HashSizeInBytes
{
get
{
return _hashSize;
}
}
private void ResetHashObject()
{
if (_reusable)
return;
DestroyHash();
SafeBCryptHashHandle hHash;
NTSTATUS ntStatus = Interop.BCrypt.BCryptCreateHash(_hAlgorithm, out hHash, IntPtr.Zero, 0, _key, _key == null ? 0 : _key.Length, BCryptCreateHashFlags.None);
if (ntStatus != NTSTATUS.STATUS_SUCCESS)
throw Interop.BCrypt.CreateCryptographicException(ntStatus);
_hHash = hHash;
}
private void DestroyHash()
{
SafeBCryptHashHandle hHash = _hHash;
_hHash = null;
if (hHash != null)
{
hHash.Dispose();
}
// Not disposing of _hAlgorithm as we got this from a cache. So it's not ours to Dispose().
}
private readonly SafeBCryptAlgorithmHandle _hAlgorithm;
private SafeBCryptHashHandle _hHash;
private byte[] _key;
private readonly bool _reusable;
private readonly int _hashSize;
}
}

View File

@@ -0,0 +1,153 @@
// 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;
using System.Diagnostics;
using System.IO;
using System.Security.Cryptography;
namespace Internal.Cryptography
{
//
// Common infrastructure for AsymmetricAlgorithm-derived classes that layer on OpenSSL.
//
internal static class OpenSslAsymmetricAlgorithmCore
{
public static byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm)
{
// The classes that call us are sealed and their base class has checked this already.
Debug.Assert(data != null);
Debug.Assert(count >= 0 && count <= data.Length);
Debug.Assert(offset >= 0 && offset <= data.Length - count);
Debug.Assert(!string.IsNullOrEmpty(hashAlgorithm.Name));
using (HashAlgorithm hasher = GetHashAlgorithm(hashAlgorithm))
{
return hasher.ComputeHash(data, offset, count);
}
}
public static byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm)
{
// The classes that call us are sealed and their base class has checked this already.
Debug.Assert(data != null);
Debug.Assert(!string.IsNullOrEmpty(hashAlgorithm.Name));
using (HashAlgorithm hasher = GetHashAlgorithm(hashAlgorithm))
{
return hasher.ComputeHash(data);
}
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA5351", Justification = "MD5 is used when the user asks for it.")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA5350", Justification = "SHA1 is used when the user asks for it.")]
private static HashAlgorithm GetHashAlgorithm(HashAlgorithmName hashAlgorithmName)
{
HashAlgorithm hasher;
if (hashAlgorithmName == HashAlgorithmName.MD5)
{
hasher = MD5.Create();
}
else if (hashAlgorithmName == HashAlgorithmName.SHA1)
{
hasher = SHA1.Create();
}
else if (hashAlgorithmName == HashAlgorithmName.SHA256)
{
hasher = SHA256.Create();
}
else if (hashAlgorithmName == HashAlgorithmName.SHA384)
{
hasher = SHA384.Create();
}
else if (hashAlgorithmName == HashAlgorithmName.SHA512)
{
hasher = SHA512.Create();
}
else
{
throw new CryptographicException(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithmName.Name);
}
return hasher;
}
/// <summary>
/// Convert Ieee1363 format of (r, s) to Der format
/// </summary>
public static byte[] ConvertIeee1363ToDer(byte[] input)
{
Debug.Assert(input != null);
Debug.Assert(input.Length % 2 == 0);
Debug.Assert(input.Length > 1);
// Input is (r, s), each of them exactly half of the array.
// Output is the DER encoded value of CONSTRUCTEDSEQUENCE(INTEGER(r), INTEGER(s)).
int halfLength = input.Length / 2;
byte[][] rEncoded = DerEncoder.SegmentedEncodeUnsignedInteger(input, 0, halfLength);
byte[][] sEncoded = DerEncoder.SegmentedEncodeUnsignedInteger(input, halfLength, halfLength);
return DerEncoder.ConstructSequence(rEncoded, sEncoded);
}
/// <summary>
/// Convert Der format of (r, s) to Ieee1363 format
/// </summary>
public static byte[] ConvertDerToIeee1363(byte[] input, int inputOffset, int inputCount, int fieldSizeBits)
{
int size = BitsToBytes(fieldSizeBits);
try
{
DerSequenceReader reader = new DerSequenceReader(input, inputOffset, inputCount);
byte[] rDer = reader.ReadIntegerBytes();
byte[] sDer = reader.ReadIntegerBytes();
byte[] response = new byte[2 * size];
CopySignatureField(rDer, response, 0, size);
CopySignatureField(sDer, response, size, size);
return response;
}
catch (InvalidOperationException e)
{
throw new CryptographicException(SR.Arg_CryptographyException, e);
}
}
public static int BitsToBytes(int bitLength)
{
int byteLength = (bitLength + 7) / 8;
return byteLength;
}
private static void CopySignatureField(byte[] signatureField, byte[] response, int offset, int fieldLength)
{
if (signatureField.Length > fieldLength)
{
// The only way this should be true is if the value required a zero-byte-pad.
Debug.Assert(signatureField.Length == fieldLength + 1, "signatureField.Length == fieldLength + 1");
Debug.Assert(signatureField[0] == 0, "signatureField[0] == 0");
Debug.Assert(signatureField[1] > 0x7F, "signatureField[1] > 0x7F");
Buffer.BlockCopy(signatureField, 1, response, offset, fieldLength);
}
else if (signatureField.Length == fieldLength)
{
Buffer.BlockCopy(signatureField, 0, response, offset, fieldLength);
}
else
{
// If the field is too short then it needs to be prepended
// with zeroes in the response. Since the array was already
// zeroed out, just figure out where we need to start copying.
int writeOffset = fieldLength - signatureField.Length;
Buffer.BlockCopy(signatureField, 0, response, offset + writeOffset, signatureField.Length);
}
}
}
}

View File

@@ -0,0 +1,242 @@
// 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;
using System.Diagnostics;
using System.Security.Cryptography;
namespace Internal.Cryptography
{
//
// A cross-platform ICryptoTransform implementation for decryption.
//
// - Implements the various padding algorithms (as we support padding algorithms that the underlying native apis don't.)
//
// - Parameterized by a BasicSymmetricCipher which encapsulates the algorithm, key, IV, chaining mode, direction of encryption
// and the underlying native apis implementing the encryption.
//
internal sealed class UniversalCryptoDecryptor : UniversalCryptoTransform
{
public UniversalCryptoDecryptor(PaddingMode paddingMode, BasicSymmetricCipher basicSymmetricCipher)
: base(paddingMode, basicSymmetricCipher)
{
}
protected sealed override int UncheckedTransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
//
// If we're decrypting, it's possible to be called with the last blocks of the data, and then
// have TransformFinalBlock called with an empty array. Since we don't know if this is the case,
// we won't decrypt the last block of the input until either TransformBlock or
// TransformFinalBlock is next called.
//
// We don't need to do this for PaddingMode.None because there is no padding to strip, and
// we also don't do this for PaddingMode.Zeros since there is no way for us to tell if the
// zeros at the end of a block are part of the plaintext or the padding.
//
int decryptedBytes = 0;
if (DepaddingRequired)
{
// If we have data saved from a previous call, decrypt that into the output first
if (_heldoverCipher != null)
{
int depadDecryptLength = BasicSymmetricCipher.Transform(_heldoverCipher, 0, _heldoverCipher.Length, outputBuffer, outputOffset);
outputOffset += depadDecryptLength;
decryptedBytes += depadDecryptLength;
}
else
{
_heldoverCipher = new byte[InputBlockSize];
}
// Postpone the last block to the next round.
Debug.Assert(inputCount >= _heldoverCipher.Length, "inputCount >= _heldoverCipher.Length");
int startOfLastBlock = inputOffset + inputCount - _heldoverCipher.Length;
Buffer.BlockCopy(inputBuffer, startOfLastBlock, _heldoverCipher, 0, _heldoverCipher.Length);
inputCount -= _heldoverCipher.Length;
Debug.Assert(inputCount % InputBlockSize == 0, "Did not remove whole blocks for depadding");
}
if (inputCount > 0)
{
decryptedBytes += BasicSymmetricCipher.Transform(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);
}
return decryptedBytes;
}
protected sealed override byte[] UncheckedTransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
{
// We can't complete decryption on a partial block
if (inputCount % InputBlockSize != 0)
throw new CryptographicException(SR.Cryptography_PartialBlock);
//
// If we have postponed cipher bits from the prior round, copy that into the decryption buffer followed by the input data.
// Otherwise the decryption buffer is just the input data.
//
byte[] ciphertext = null;
if (_heldoverCipher == null)
{
ciphertext = new byte[inputCount];
Buffer.BlockCopy(inputBuffer, inputOffset, ciphertext, 0, inputCount);
}
else
{
ciphertext = new byte[_heldoverCipher.Length + inputCount];
Buffer.BlockCopy(_heldoverCipher, 0, ciphertext, 0, _heldoverCipher.Length);
Buffer.BlockCopy(inputBuffer, inputOffset, ciphertext, _heldoverCipher.Length, inputCount);
}
// Decrypt the data, then strip the padding to get the final decrypted data. Note that even if the cipherText length is 0, we must
// invoke TransformFinal() so that the cipher object knows to reset for the next cipher operation.
byte[] decryptedBytes = BasicSymmetricCipher.TransformFinal(ciphertext, 0, ciphertext.Length);
byte[] outputData;
if (ciphertext.Length > 0)
{
outputData = DepadBlock(decryptedBytes, 0, decryptedBytes.Length);
}
else
{
outputData = Array.Empty<byte>();
}
Reset();
return outputData;
}
protected sealed override void Dispose(bool disposing)
{
if (disposing)
{
byte[] heldoverCipher = _heldoverCipher;
_heldoverCipher = null;
if (heldoverCipher != null)
{
Array.Clear(heldoverCipher, 0, heldoverCipher.Length);
}
}
base.Dispose(disposing);
}
private void Reset()
{
if (_heldoverCipher != null)
{
Array.Clear(_heldoverCipher, 0, _heldoverCipher.Length);
_heldoverCipher = null;
}
}
private bool DepaddingRequired
{
get
{
// Some padding modes encode sufficient information to allow for automatic depadding to happen.
switch (PaddingMode)
{
case PaddingMode.PKCS7:
case PaddingMode.ANSIX923:
case PaddingMode.ISO10126:
return true;
case PaddingMode.Zeros:
case PaddingMode.None:
return false;
default:
Debug.Fail($"Invalid padding mode {PaddingMode}.");
throw new CryptographicException(SR.Cryptography_InvalidPadding);
}
}
}
/// <summary>
/// Remove the padding from the last blocks being decrypted
/// </summary>
private byte[] DepadBlock(byte[] block, int offset, int count)
{
Debug.Assert(block != null && count >= block.Length - offset);
Debug.Assert(0 <= offset);
Debug.Assert(0 <= count);
int padBytes = 0;
// See PadBlock for a description of the padding modes.
switch (PaddingMode)
{
case PaddingMode.ANSIX923:
padBytes = block[offset + count - 1];
// Verify the amount of padding is reasonable
if (padBytes <= 0 || padBytes > InputBlockSize)
{
throw new CryptographicException(SR.Cryptography_InvalidPadding);
}
// Verify that all the padding bytes are 0s
for (int i = offset + count - padBytes; i < offset + count - 1; i++)
{
if (block[i] != 0)
{
throw new CryptographicException(SR.Cryptography_InvalidPadding);
}
}
break;
case PaddingMode.ISO10126:
padBytes = block[offset + count - 1];
// Verify the amount of padding is reasonable
if (padBytes <= 0 || padBytes > InputBlockSize)
{
throw new CryptographicException(SR.Cryptography_InvalidPadding);
}
// Since the padding consists of random bytes, we cannot verify the actual pad bytes themselves
break;
case PaddingMode.PKCS7:
padBytes = block[offset + count - 1];
// Verify the amount of padding is reasonable
if (padBytes <= 0 || padBytes > InputBlockSize)
throw new CryptographicException(SR.Cryptography_InvalidPadding);
// Verify all the padding bytes match the amount of padding
for (int i = offset + count - padBytes; i < offset + count; i++)
{
if (block[i] != padBytes)
throw new CryptographicException(SR.Cryptography_InvalidPadding);
}
break;
// We cannot remove Zeros padding because we don't know if the zeros at the end of the block
// belong to the padding or the plaintext itself.
case PaddingMode.Zeros:
case PaddingMode.None:
padBytes = 0;
break;
default:
throw new CryptographicException(SR.Cryptography_UnknownPaddingMode);
}
// Copy everything but the padding to the output
byte[] depadded = new byte[count - padBytes];
Buffer.BlockCopy(block, offset, depadded, 0, depadded.Length);
return depadded;
}
//
// For padding modes that support automatic depadding, TransformBlock() leaves the last block it is given undone since it has no way of knowing
// whether this is the final block that needs depadding. This block is held (in encrypted form) in _heldoverCipher. The next call to TransformBlock
// or TransformFinalBlock must include the decryption of _heldoverCipher in the results.
//
private byte[] _heldoverCipher;
}
}

View File

@@ -0,0 +1,115 @@
// 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;
using System.Diagnostics;
using System.Security.Cryptography;
namespace Internal.Cryptography
{
//
// A cross-platform ICryptoTransform implementation for encryption.
//
// - Implements the various padding algorithms (as we support padding algorithms that the underlying native apis don't.)
//
// - Parameterized by a BasicSymmetricCipher which encapsulates the algorithm, key, IV, chaining mode, direction of encryption
// and the underlying native apis implementing the encryption.
//
internal sealed class UniversalCryptoEncryptor : UniversalCryptoTransform
{
private static readonly RandomNumberGenerator s_randomNumberGenerator = RandomNumberGenerator.Create();
public UniversalCryptoEncryptor(PaddingMode paddingMode, BasicSymmetricCipher basicSymmetricCipher)
: base(paddingMode, basicSymmetricCipher)
{
}
protected sealed override int UncheckedTransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
return BasicSymmetricCipher.Transform(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);
}
protected sealed override byte[] UncheckedTransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
{
byte[] paddedBlock = PadBlock(inputBuffer, inputOffset, inputCount);
byte[] output = BasicSymmetricCipher.TransformFinal(paddedBlock, 0, paddedBlock.Length);
return output;
}
private byte[] PadBlock(byte[] block, int offset, int count)
{
byte[] result;
int padBytes = InputBlockSize - (count % InputBlockSize);
switch (PaddingMode)
{
case PaddingMode.None:
if (count % InputBlockSize != 0)
throw new CryptographicException(SR.Cryptography_PartialBlock);
result = new byte[count];
Buffer.BlockCopy(block, offset, result, 0, result.Length);
break;
// ANSI padding fills the blocks with zeros and adds the total number of padding bytes as
// the last pad byte, adding an extra block if the last block is complete.
//
// x 00 00 00 00 00 00 07
case PaddingMode.ANSIX923:
result = new byte[count + padBytes];
Buffer.BlockCopy(block, offset, result, 0, count);
result[result.Length - 1] = (byte)padBytes;
break;
// ISO padding fills the blocks up with random bytes and adds the total number of padding
// bytes as the last pad byte, adding an extra block if the last block is complete.
//
// xx rr rr rr rr rr rr 07
case PaddingMode.ISO10126:
result = new byte[count + padBytes];
Buffer.BlockCopy(block, offset, result, 0, count);
s_randomNumberGenerator.GetBytes(result, count + 1, padBytes - 1);
result[result.Length - 1] = (byte)padBytes;
break;
// PKCS padding fills the blocks up with bytes containing the total number of padding bytes
// used, adding an extra block if the last block is complete.
//
// xx xx 06 06 06 06 06 06
case PaddingMode.PKCS7:
result = new byte[count + padBytes];
Buffer.BlockCopy(block, offset, result, 0, count);
for (int i = count; i < result.Length; i++)
{
result[i] = (byte)padBytes;
}
break;
// Zeros padding fills the last partial block with zeros, and does not add a new block to
// the end if the last block is already complete.
//
// xx 00 00 00 00 00 00 00
case PaddingMode.Zeros:
if (padBytes == InputBlockSize)
{
padBytes = 0;
}
result = new byte[count + padBytes];
Buffer.BlockCopy(block, offset, result, 0, count);
break;
default:
throw new CryptographicException(SR.Cryptography_UnknownPaddingMode);
}
return result;
}
}
}

View File

@@ -0,0 +1,119 @@
// 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;
using System.Diagnostics;
using System.Security.Cryptography;
namespace Internal.Cryptography
{
//
// The common base class for the cross-platform CreateEncryptor()/CreateDecryptor() implementations.
//
// - Implements the various padding algorithms (as we support padding algorithms that the underlying native apis don't.)
//
// - Parameterized by a BasicSymmetricCipher which encapsulates the algorithm, key, IV, chaining mode, direction of encryption
// and the underlying native apis implementing the encryption.
//
internal abstract class UniversalCryptoTransform : ICryptoTransform
{
public static ICryptoTransform Create(PaddingMode paddingMode, BasicSymmetricCipher cipher, bool encrypting)
{
if (encrypting)
return new UniversalCryptoEncryptor(paddingMode, cipher);
else
return new UniversalCryptoDecryptor(paddingMode, cipher);
}
protected UniversalCryptoTransform(PaddingMode paddingMode, BasicSymmetricCipher basicSymmetricCipher)
{
PaddingMode = paddingMode;
BasicSymmetricCipher = basicSymmetricCipher;
}
public bool CanReuseTransform
{
get { return true; }
}
public bool CanTransformMultipleBlocks
{
get { return true; }
}
public int InputBlockSize
{
get { return BasicSymmetricCipher.BlockSizeInBytes; }
}
public int OutputBlockSize
{
get { return BasicSymmetricCipher.BlockSizeInBytes; }
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
if (inputBuffer == null)
throw new ArgumentNullException(nameof(inputBuffer));
if (inputOffset < 0)
throw new ArgumentOutOfRangeException(nameof(inputOffset));
if (inputOffset > inputBuffer.Length)
throw new ArgumentOutOfRangeException(nameof(inputOffset));
if (inputCount <= 0)
throw new ArgumentOutOfRangeException(nameof(inputCount));
if (inputCount % InputBlockSize != 0)
throw new ArgumentOutOfRangeException(nameof(inputCount), SR.Cryptography_MustTransformWholeBlock);
if (inputCount > inputBuffer.Length - inputOffset)
throw new ArgumentOutOfRangeException(nameof(inputCount), SR.Cryptography_TransformBeyondEndOfBuffer);
if (outputBuffer == null)
throw new ArgumentNullException(nameof(outputBuffer));
if (outputOffset > outputBuffer.Length)
throw new ArgumentOutOfRangeException(nameof(outputOffset));
if (inputCount > outputBuffer.Length - outputOffset)
throw new ArgumentOutOfRangeException(nameof(outputOffset), SR.Cryptography_TransformBeyondEndOfBuffer);
int numBytesWritten = UncheckedTransformBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);
Debug.Assert(numBytesWritten >= 0 && numBytesWritten <= inputCount);
return numBytesWritten;
}
public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
{
if (inputBuffer == null)
throw new ArgumentNullException(nameof(inputBuffer));
if (inputOffset < 0)
throw new ArgumentOutOfRangeException(nameof(inputOffset));
if (inputCount < 0)
throw new ArgumentOutOfRangeException(nameof(inputCount));
if (inputOffset > inputBuffer.Length)
throw new ArgumentOutOfRangeException(nameof(inputOffset));
if (inputCount > inputBuffer.Length - inputOffset)
throw new ArgumentOutOfRangeException(nameof(inputCount), SR.Cryptography_TransformBeyondEndOfBuffer);
byte[] output = UncheckedTransformFinalBlock(inputBuffer, inputOffset, inputCount);
return output;
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
BasicSymmetricCipher.Dispose();
}
}
protected abstract int UncheckedTransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset);
protected abstract byte[] UncheckedTransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount);
protected PaddingMode PaddingMode { get; private set; }
protected BasicSymmetricCipher BasicSymmetricCipher { get; private set; }
}
}

View File

@@ -0,0 +1,28 @@
// 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;
using System.Diagnostics;
using System.Security.Cryptography;
namespace Internal.Cryptography
{
internal static class CryptoThrowHelper
{
public static CryptographicException ToCryptographicException(this int hr)
{
string message = Interop.Kernel32.GetMessage(hr);
return new WindowsCryptographicException(hr, message);
}
private sealed class WindowsCryptographicException : CryptographicException
{
public WindowsCryptographicException(int hr, string message)
: base(message)
{
HResult = hr;
}
}
}
}

View File

@@ -0,0 +1,16 @@
// 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.Security.Cryptography;
namespace Internal.Cryptography
{
internal static class ErrorCodeHelper
{
public static CryptographicException ToCryptographicException(this Interop.NCrypt.ErrorCode errorCode)
{
return ((int)errorCode).ToCryptographicException();
}
}
}

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;
internal static partial class Interop
{
public static unsafe void CheckBounds(byte* buffer, int bufferSize, byte* offset, int accessSize)
{
var start = checked((int)(IntPtr)(offset - buffer));
var end = checked(start + accessSize);
if (start < 0 || end > bufferSize)
{
throw new IndexOutOfRangeException();
}
}
public static unsafe void CheckBounds(byte* buffer, int bufferSize, byte* offset)
{
CheckBounds(buffer, bufferSize, offset, sizeof(byte));
}
public static unsafe void CheckBounds(byte* buffer, int bufferSize, ushort* offset)
{
CheckBounds(buffer, bufferSize, (byte*)offset, sizeof(ushort));
}
public static unsafe void CheckBounds(byte* buffer, int bufferSize, uint* offset)
{
CheckBounds(buffer, bufferSize, (byte*)offset, sizeof(uint));
}
public static unsafe byte CheckedRead(byte* buffer, int bufferSize, byte* offset)
{
CheckBounds(buffer, bufferSize, offset);
return *offset;
}
public static unsafe ushort CheckedRead(byte* buffer, int bufferSize, ushort* offset)
{
CheckBounds(buffer, bufferSize, offset);
return *offset;
}
public static unsafe uint CheckedRead(byte* buffer, int bufferSize, uint* offset)
{
CheckBounds(buffer, bufferSize, offset);
return *offset;
}
public static unsafe void CheckedWrite(byte* buffer, int bufferSize, byte* offset, byte value)
{
CheckBounds(buffer, bufferSize, offset);
*offset = value;
}
public static unsafe void CheckedWrite(byte* buffer, int bufferSize, ushort* offset, ushort value)
{
CheckBounds(buffer, bufferSize, offset);
*offset = value;
}
public static unsafe void CheckedWrite(byte* buffer, int bufferSize, uint* offset, uint value)
{
CheckBounds(buffer, bufferSize, offset);
*offset = value;
}
}

View File

@@ -0,0 +1,33 @@
// 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;
internal static partial class Interop
{
// /usr/include/linux/if.h
[Flags]
internal enum LinuxNetDeviceFlags
{
IFF_UP = 1 << 0, /* sysfs */
IFF_BROADCAST = 1 << 1, /* volatile */
IFF_DEBUG = 1 << 2, /* sysfs */
IFF_LOOPBACK = 1 << 3, /* volatile */
IFF_POINTOPOINT = 1 << 4, /* volatile */
IFF_NOTRAILERS = 1 << 5, /* sysfs */
IFF_RUNNING = 1 << 6, /* volatile */
IFF_NOARP = 1 << 7, /* sysfs */
IFF_PROMISC = 1 << 8, /* sysfs */
IFF_ALLMULTI = 1 << 9, /* sysfs */
IFF_MASTER = 1 << 10, /* volatile */
IFF_SLAVE = 1 << 11, /* volatile */
IFF_MULTICAST = 1 << 12, /* sysfs */
IFF_PORTSEL = 1 << 13, /* sysfs */
IFF_AUTOMEDIA = 1 << 14, /* sysfs */
IFF_DYNAMIC = 1 << 15, /* sysfs */
IFF_LOWER_UP = 1 << 16, /* volatile */
IFF_DORMANT = 1 << 17, /* volatile */
IFF_ECHO = 1 << 18, /* volatile */
}
}

View File

@@ -0,0 +1,26 @@
// 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.
internal static partial class Interop
{
/// <summary>
/// Represents a TCP state from the Linux kernel.
/// Taken from /include/net/tcp_states.h
/// </summary>
internal enum LinuxTcpState
{
TCP_ESTABLISHED = 1,
TCP_SYN_SENT,
TCP_SYN_RECV,
TCP_FIN_WAIT1,
TCP_FIN_WAIT2,
TCP_TIME_WAIT,
TCP_CLOSE,
TCP_CLOSE_WAIT,
TCP_LAST_ACK,
TCP_LISTEN,
TCP_CLOSING,
TCP_NEW_SYN_RECV,
}
}

View File

@@ -0,0 +1,63 @@
// 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;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
internal static partial class Interop
{
internal static partial class Sys
{
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_INotifyInit", SetLastError = true)]
internal static extern SafeFileHandle INotifyInit();
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_INotifyAddWatch", SetLastError = true)]
internal static extern int INotifyAddWatch(SafeFileHandle fd, string pathName, uint mask);
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_INotifyRemoveWatch", SetLastError = true)]
private static extern int INotifyRemoveWatch_private(SafeFileHandle fd, int wd);
internal static int INotifyRemoveWatch(SafeFileHandle fd, int wd)
{
int result = INotifyRemoveWatch_private(fd, wd);
if (result < 0)
{
Error hr = GetLastError();
if (hr == Error.EINVAL)
{
// This specific case means that there was a deleted event in the queue that was not processed
// so this call is expected to fail since the WatchDescriptor is no longer valid and was cleaned
// up automatically by the OS.
result = 0;
}
else
{
Debug.Fail("inotify_rm_watch failed with " + hr);
}
}
return result;
}
[Flags]
internal enum NotifyEvents
{
IN_ACCESS = 0x00000001,
IN_MODIFY = 0x00000002,
IN_ATTRIB = 0x00000004,
IN_MOVED_FROM = 0x00000040,
IN_MOVED_TO = 0x00000080,
IN_CREATE = 0x00000100,
IN_DELETE = 0x00000200,
IN_Q_OVERFLOW = 0x00004000,
IN_IGNORED = 0x00008000,
IN_ONLYDIR = 0x01000000,
IN_DONT_FOLLOW = 0x02000000,
IN_EXCL_UNLINK = 0x04000000,
IN_ISDIR = 0x40000000,
}
}
}

View File

@@ -0,0 +1,33 @@
// 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.Runtime.InteropServices;
using System;
internal static partial class Interop
{
internal static partial class Sys
{
public enum NetworkChangeKind
{
None = -1,
AddressAdded = 0,
AddressRemoved = 1,
LinkAdded = 2,
LinkRemoved = 3,
AvailabilityChanged = 4
}
public delegate void NetworkChangeEvent(int socket, NetworkChangeKind kind);
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_CreateNetworkChangeListenerSocket")]
public static extern Error CreateNetworkChangeListenerSocket(out int socket);
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_CloseNetworkChangeListenerSocket")]
public static extern Error CloseNetworkChangeListenerSocket(int socket);
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_ReadEvents")]
public static extern void ReadEvents(int socket, NetworkChangeEvent onNetworkChange);
}
}

View File

@@ -0,0 +1,284 @@
// 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;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Text;
internal static partial class Interop
{
internal static partial class procfs
{
internal const string RootPath = "/proc/";
internal const string SelfExeFilePath = RootPath + "self/exe";
internal const string ProcUptimeFilePath = RootPath + "uptime";
private const string StatFileName = "/stat";
private const string MapsFileName = "/maps";
private const string FileDescriptorDirectoryName = "/fd/";
private const string TaskDirectoryName = "/task/";
internal struct ParsedStat
{
// Commented out fields are available in the stat data file but
// are currently not used. If/when needed, they can be uncommented,
// and the corresponding entry can be added back to StatParser, replacing
// the MoveNext() with the appropriate ParseNext* call and assignment.
internal int pid;
internal string comm;
internal char state;
//internal int ppid;
//internal int pgrp;
internal int session;
//internal int tty_nr;
//internal int tpgid;
//internal uint flags;
//internal ulong minflt;
//internal ulong cminflt;
//internal ulong majflt;
//internal ulong cmajflt;
internal ulong utime;
internal ulong stime;
//internal long cutime;
//internal long cstime;
//internal long priority;
internal long nice;
//internal long num_threads;
//internal long itrealvalue;
internal ulong starttime;
internal ulong vsize;
internal long rss;
internal ulong rsslim;
//internal ulong startcode;
//internal ulong endcode;
//internal ulong startstack;
//internal ulong kstkesp;
//internal ulong kstkeip;
//internal ulong signal;
//internal ulong blocked;
//internal ulong sigignore;
//internal ulong sigcatch;
//internal ulong wchan;
//internal ulong nswap;
//internal ulong cnswap;
//internal int exit_signal;
//internal int processor;
//internal uint rt_priority;
//internal uint policy;
//internal ulong delayacct_blkio_ticks;
//internal ulong guest_time;
//internal long cguest_time;
}
internal struct ParsedMapsModule
{
internal string FileName;
internal KeyValuePair<long, long> AddressRange;
}
internal static string GetStatFilePathForProcess(int pid)
{
return RootPath + pid.ToString(CultureInfo.InvariantCulture) + StatFileName;
}
internal static string GetMapsFilePathForProcess(int pid)
{
return RootPath + pid.ToString(CultureInfo.InvariantCulture) + MapsFileName;
}
internal static string GetTaskDirectoryPathForProcess(int pid)
{
return RootPath + pid.ToString(CultureInfo.InvariantCulture) + TaskDirectoryName;
}
internal static string GetFileDescriptorDirectoryPathForProcess(int pid)
{
return RootPath + pid.ToString(CultureInfo.InvariantCulture) + FileDescriptorDirectoryName;
}
internal static IEnumerable<ParsedMapsModule> ParseMapsModules(int pid)
{
try
{
return ParseMapsModulesCore(File.ReadLines(GetMapsFilePathForProcess(pid)));
}
catch (IOException) { }
catch (UnauthorizedAccessException) { }
return Array.Empty<ParsedMapsModule>();
}
private static IEnumerable<ParsedMapsModule> ParseMapsModulesCore(IEnumerable<string> lines)
{
Debug.Assert(lines != null);
// Parse each line from the maps file into a ParsedMapsModule result
foreach (string line in lines)
{
// Use a StringParser to avoid string.Split costs
var parser = new StringParser(line, separator: ' ', skipEmpty: true);
// Parse the address range
KeyValuePair<long, long> addressRange =
parser.ParseRaw(delegate (string s, ref int start, ref int end)
{
long startingAddress = 0, endingAddress = 0;
int pos = s.IndexOf('-', start, end - start);
if (pos > 0)
{
string startingString = s.Substring(start, pos);
if (long.TryParse(startingString, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out startingAddress))
{
string endingString = s.Substring(pos + 1, end - (pos + 1));
long.TryParse(endingString, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out endingAddress);
}
}
return new KeyValuePair<long, long>(startingAddress, endingAddress);
});
// Parse the permissions (we only care about entries with 'r' and 'x' set)
if (!parser.ParseRaw(delegate (string s, ref int start, ref int end)
{
bool sawRead = false, sawExec = false;
for (int i = start; i < end; i++)
{
if (s[i] == 'r')
sawRead = true;
else if (s[i] == 'x')
sawExec = true;
}
return sawRead & sawExec;
}))
{
continue;
}
// Skip past the offset, dev, and inode fields
parser.MoveNext();
parser.MoveNext();
parser.MoveNext();
// Parse the pathname
if (!parser.MoveNext())
{
continue;
}
string pathname = parser.ExtractCurrentToEnd();
// We only get here if a we have a non-empty pathname and
// the permissions included both readability and executability.
// Yield the result.
yield return new ParsedMapsModule { FileName = pathname, AddressRange = addressRange };
}
}
private static string GetStatFilePathForThread(int pid, int tid)
{
// Perf note: Calling GetTaskDirectoryPathForProcess will allocate a string,
// which we then use in another Concat call to produce another string. The straightforward alternative,
// though, since we have five input strings, is to use the string.Concat overload that takes a params array.
// This results in allocating not only the params array but also a defensive copy inside of Concat,
// which means allocating two five-element arrays. This two-string approach will result not only in fewer
// allocations, but also typically in less memory allocated, and it's a bit more maintainable.
return GetTaskDirectoryPathForProcess(pid) + tid.ToString(CultureInfo.InvariantCulture) + StatFileName;
}
internal static bool TryReadStatFile(int pid, out ParsedStat result, ReusableTextReader reusableReader)
{
bool b = TryParseStatFile(GetStatFilePathForProcess(pid), out result, reusableReader);
Debug.Assert(!b || result.pid == pid, "Expected process ID from stat file to match supplied pid");
return b;
}
internal static bool TryReadStatFile(int pid, int tid, out ParsedStat result, ReusableTextReader reusableReader)
{
bool b = TryParseStatFile(GetStatFilePathForThread(pid, tid), out result, reusableReader);
//
// This assert currently fails in the Windows Subsystem For Linux. See https://github.com/Microsoft/BashOnWindows/issues/967.
//
//Debug.Assert(!b || result.pid == tid, "Expected thread ID from stat file to match supplied tid");
return b;
}
internal static bool TryParseStatFile(string statFilePath, out ParsedStat result, ReusableTextReader reusableReader)
{
string statFileContents;
try
{
using (var source = new FileStream(statFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 1, useAsync: false))
{
statFileContents = reusableReader.ReadAllText(source);
}
}
catch (IOException)
{
// Between the time that we get an ID and the time that we try to read the associated stat
// file(s), the process could be gone.
result = default(ParsedStat);
return false;
}
var parser = new StringParser(statFileContents, ' ');
var results = default(ParsedStat);
results.pid = parser.ParseNextInt32();
results.comm = parser.MoveAndExtractNextInOuterParens();
results.state = parser.ParseNextChar();
parser.MoveNextOrFail(); // ppid
parser.MoveNextOrFail(); // pgrp
results.session = parser.ParseNextInt32();
parser.MoveNextOrFail(); // tty_nr
parser.MoveNextOrFail(); // tpgid
parser.MoveNextOrFail(); // flags
parser.MoveNextOrFail(); // majflt
parser.MoveNextOrFail(); // cmagflt
parser.MoveNextOrFail(); // minflt
parser.MoveNextOrFail(); // cminflt
results.utime = parser.ParseNextUInt64();
results.stime = parser.ParseNextUInt64();
parser.MoveNextOrFail(); // cutime
parser.MoveNextOrFail(); // cstime
parser.MoveNextOrFail(); // priority
results.nice = parser.ParseNextInt64();
parser.MoveNextOrFail(); // num_threads
parser.MoveNextOrFail(); // itrealvalue
results.starttime = parser.ParseNextUInt64();
results.vsize = parser.ParseNextUInt64();
results.rss = parser.ParseNextInt64();
results.rsslim = parser.ParseNextUInt64();
// The following lines are commented out as there's no need to parse through
// the rest of the entry (we've gotten all of the data we need). Should any
// of these fields be needed in the future, uncomment all of the lines up
// through and including the one that's needed. For now, these are being left
// commented to document what's available in the remainder of the entry.
//parser.MoveNextOrFail(); // startcode
//parser.MoveNextOrFail(); // endcode
//parser.MoveNextOrFail(); // startstack
//parser.MoveNextOrFail(); // kstkesp
//parser.MoveNextOrFail(); // kstkeip
//parser.MoveNextOrFail(); // signal
//parser.MoveNextOrFail(); // blocked
//parser.MoveNextOrFail(); // sigignore
//parser.MoveNextOrFail(); // sigcatch
//parser.MoveNextOrFail(); // wchan
//parser.MoveNextOrFail(); // nswap
//parser.MoveNextOrFail(); // cnswap
//parser.MoveNextOrFail(); // exit_signal
//parser.MoveNextOrFail(); // processor
//parser.MoveNextOrFail(); // rt_priority
//parser.MoveNextOrFail(); // policy
//parser.MoveNextOrFail(); // delayacct_blkio_ticks
//parser.MoveNextOrFail(); // guest_time
//parser.MoveNextOrFail(); // cguest_time
result = results;
return true;
}
}
}

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