From c74b6f24070a11eb347a43d7ac6de3304a50e789 Mon Sep 17 00:00:00 2001 From: dotnet-bot Date: Fri, 4 Sep 2015 16:00:47 -0700 Subject: [PATCH] Porting System.Net.Security --- .../Windows/Crypt32/Interop.certificates.cs | 1 - .../Crypt32/Interop.certificates_types.cs | 23 +- .../src/Interop/Windows/Interop.Libraries.cs | 1 + .../Windows/SChannel/Interop.SchProtocols.cs | 2 - .../SChannel/Interop.SecurityStatus.cs | 356 +++ .../Interop/Windows/secur32/Interop.SSPI.cs | 515 ++++ .../CriticalHandleMinusOneIsInvalid.cs | 23 + .../CriticalHandleZeroOrMinusOneIsInvalid.cs | 23 + src/Common/src/System/IO/StreamAsyncHelper.cs | 208 ++ .../DebugCriticalHandleMinusOneIsInvalid.cs | 46 + ...ugCriticalHandleZeroOrMinusOneIsInvalid.cs | 46 + src/Common/src/System/Net/DebugSafeHandle.cs | 3 +- src/Common/src/System/Net/ExceptionCheck.cs | 13 + .../src/System/Net/Logging/GlobalLog.cs | 5 + src/Common/src/System/Net/Logging/Logging.cs | 57 + .../src/System/Net/Shims/ExecutionContext.cs | 1 + .../src/System/Net/_BufferOffsetSize.cs | 51 + .../src/System/Net/_ContextAwareResult.cs | 7 + src/Common/src/System/Net/_LazyAsyncResult.cs | 63 +- src/Common/src/System/SR.cs | 2 + .../System.Net/EventSourceTestLogging.cs | 40 + .../tests/System.Net/TaskAPMExtensions.cs | 88 + src/Common/tests/System.Net/TestLogging.cs | 33 + .../tests/System.Net/VerboseTestLogging.cs | 33 + .../System.Net.Security.sln | 104 + .../src/Resources/Strings.resx | 333 +++ .../src/Shims/X509CertificateExtensions.cs | 15 + .../src/System.Net.Security.csproj | 157 ++ .../SecureProtocols/AuthenticatedStream.cs | 84 + .../AuthenticationException.cs | 31 + .../System/Net/SecureProtocols/SslStream.cs | 464 ++++ .../Net/SecureProtocols/SslStreamContext.cs | 24 + .../Net/SecureProtocols/_FixedSizeReader.cs | 151 ++ .../SecureProtocols/_HelperAsyncResults.cs | 166 ++ .../_SecuritySafeHandles.Windows.cs | 1241 ++++++++++ .../System/Net/SecureProtocols/_SslState.cs | 1809 ++++++++++++++ .../System/Net/SecureProtocols/_SslStream.cs | 748 ++++++ .../System/Net/SecurityContextTokenHandle.cs | 35 + .../src/System/Net/_NativeSSPI.cs | 395 +++ .../src/System/Net/_SSPIWrapper.cs | 931 +++++++ .../src/System/Net/_SecureChannel.cs | 1614 ++++++++++++ .../src/System/Net/_SecurityBuffer.cs | 51 + .../src/System/Net/_SecurityBufferType.cs | 23 + .../src/System/Net/_SslSessionsCache.cs | 226 ++ .../src/System/PinnableBufferCache.cs | 589 +++++ .../ExtendedProtectionPolicy.cs | 150 ++ .../ExtendedProtection/PolicyEnforcement.cs | 12 + .../ExtendedProtection/ProtectionScenario.cs | 11 + .../ServiceNameCollection.cs | 206 ++ src/System.Net.Security/src/project.json | 10 + src/System.Net.Security/src/project.lock.json | 1842 ++++++++++++++ .../ClientAsyncAuthenticateTest.cs | 204 ++ .../ClientDefaultEncryptionTest.cs | 96 + .../tests/FunctionalTests/DummyTcpServer.cs | 319 +++ .../ParameterValidationTest.cs | 40 + .../ServerAllowNoEncryptionTest.cs | 99 + .../FunctionalTests/ServerNoEncryptionTest.cs | 101 + .../ServerRequireEncryptionTest.cs | 94 + .../FunctionalTests/SslStreamAPMExtensions.cs | 61 + .../SslStreamStreamToStreamTest.cs | 229 ++ .../FunctionalTests/StreamAPMExtensions.cs | 37 + .../System.Net.Security.Tests.csproj | 73 + .../System.Net.Security.Tests.nuget.props | 9 + .../FunctionalTests/TestConfiguration.cs | 35 + .../FunctionalTests/TransportContextTest.cs | 72 + .../tests/FunctionalTests/project.json | 13 + .../tests/FunctionalTests/project.lock.json | 2164 +++++++++++++++++ 67 files changed, 16665 insertions(+), 43 deletions(-) create mode 100644 src/Common/src/Interop/Windows/SChannel/Interop.SecurityStatus.cs create mode 100644 src/Common/src/Interop/Windows/secur32/Interop.SSPI.cs create mode 100644 src/Common/src/Microsoft/Win32/SafeHandles/CriticalHandleMinusOneIsInvalid.cs create mode 100644 src/Common/src/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs create mode 100644 src/Common/src/System/IO/StreamAsyncHelper.cs create mode 100644 src/Common/src/System/Net/DebugCriticalHandleMinusOneIsInvalid.cs create mode 100644 src/Common/src/System/Net/DebugCriticalHandleZeroOrMinusOneIsInvalid.cs create mode 100644 src/Common/src/System/Net/ExceptionCheck.cs create mode 100644 src/Common/src/System/Net/_BufferOffsetSize.cs create mode 100644 src/Common/tests/System.Net/EventSourceTestLogging.cs create mode 100644 src/Common/tests/System.Net/TaskAPMExtensions.cs create mode 100644 src/Common/tests/System.Net/TestLogging.cs create mode 100644 src/Common/tests/System.Net/VerboseTestLogging.cs create mode 100644 src/System.Net.Security/System.Net.Security.sln create mode 100644 src/System.Net.Security/src/Resources/Strings.resx create mode 100644 src/System.Net.Security/src/Shims/X509CertificateExtensions.cs create mode 100644 src/System.Net.Security/src/System.Net.Security.csproj create mode 100644 src/System.Net.Security/src/System/Net/SecureProtocols/AuthenticatedStream.cs create mode 100644 src/System.Net.Security/src/System/Net/SecureProtocols/AuthenticationException.cs create mode 100644 src/System.Net.Security/src/System/Net/SecureProtocols/SslStream.cs create mode 100644 src/System.Net.Security/src/System/Net/SecureProtocols/SslStreamContext.cs create mode 100644 src/System.Net.Security/src/System/Net/SecureProtocols/_FixedSizeReader.cs create mode 100644 src/System.Net.Security/src/System/Net/SecureProtocols/_HelperAsyncResults.cs create mode 100644 src/System.Net.Security/src/System/Net/SecureProtocols/_SecuritySafeHandles.Windows.cs create mode 100644 src/System.Net.Security/src/System/Net/SecureProtocols/_SslState.cs create mode 100644 src/System.Net.Security/src/System/Net/SecureProtocols/_SslStream.cs create mode 100644 src/System.Net.Security/src/System/Net/SecurityContextTokenHandle.cs create mode 100644 src/System.Net.Security/src/System/Net/_NativeSSPI.cs create mode 100644 src/System.Net.Security/src/System/Net/_SSPIWrapper.cs create mode 100644 src/System.Net.Security/src/System/Net/_SecureChannel.cs create mode 100644 src/System.Net.Security/src/System/Net/_SecurityBuffer.cs create mode 100644 src/System.Net.Security/src/System/Net/_SecurityBufferType.cs create mode 100644 src/System.Net.Security/src/System/Net/_SslSessionsCache.cs create mode 100644 src/System.Net.Security/src/System/PinnableBufferCache.cs create mode 100644 src/System.Net.Security/src/System/Security/Authentication/ExtendedProtection/ExtendedProtectionPolicy.cs create mode 100644 src/System.Net.Security/src/System/Security/Authentication/ExtendedProtection/PolicyEnforcement.cs create mode 100644 src/System.Net.Security/src/System/Security/Authentication/ExtendedProtection/ProtectionScenario.cs create mode 100644 src/System.Net.Security/src/System/Security/Authentication/ExtendedProtection/ServiceNameCollection.cs create mode 100644 src/System.Net.Security/src/project.json create mode 100644 src/System.Net.Security/src/project.lock.json create mode 100644 src/System.Net.Security/tests/FunctionalTests/ClientAsyncAuthenticateTest.cs create mode 100644 src/System.Net.Security/tests/FunctionalTests/ClientDefaultEncryptionTest.cs create mode 100644 src/System.Net.Security/tests/FunctionalTests/DummyTcpServer.cs create mode 100644 src/System.Net.Security/tests/FunctionalTests/ParameterValidationTest.cs create mode 100644 src/System.Net.Security/tests/FunctionalTests/ServerAllowNoEncryptionTest.cs create mode 100644 src/System.Net.Security/tests/FunctionalTests/ServerNoEncryptionTest.cs create mode 100644 src/System.Net.Security/tests/FunctionalTests/ServerRequireEncryptionTest.cs create mode 100644 src/System.Net.Security/tests/FunctionalTests/SslStreamAPMExtensions.cs create mode 100644 src/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs create mode 100644 src/System.Net.Security/tests/FunctionalTests/StreamAPMExtensions.cs create mode 100644 src/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj create mode 100644 src/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.nuget.props create mode 100644 src/System.Net.Security/tests/FunctionalTests/TestConfiguration.cs create mode 100644 src/System.Net.Security/tests/FunctionalTests/TransportContextTest.cs create mode 100644 src/System.Net.Security/tests/FunctionalTests/project.json create mode 100644 src/System.Net.Security/tests/FunctionalTests/project.lock.json diff --git a/src/Common/src/Interop/Windows/Crypt32/Interop.certificates.cs b/src/Common/src/Interop/Windows/Crypt32/Interop.certificates.cs index 28199da27373..53a3d1161df9 100644 --- a/src/Common/src/Interop/Windows/Crypt32/Interop.certificates.cs +++ b/src/Common/src/Interop/Windows/Crypt32/Interop.certificates.cs @@ -3,7 +3,6 @@ using System; using System.Runtime.InteropServices; -using System.Security.Cryptography.X509Certificates; using Microsoft.Win32.SafeHandles; diff --git a/src/Common/src/Interop/Windows/Crypt32/Interop.certificates_types.cs b/src/Common/src/Interop/Windows/Crypt32/Interop.certificates_types.cs index 7679a936197a..9accdec6b129 100644 --- a/src/Common/src/Interop/Windows/Crypt32/Interop.certificates_types.cs +++ b/src/Common/src/Interop/Windows/Crypt32/Interop.certificates_types.cs @@ -3,9 +3,6 @@ using System; using System.Runtime.InteropServices; -using System.Security.Cryptography.X509Certificates; - -using Microsoft.Win32.SafeHandles; internal static partial class Interop { @@ -16,12 +13,12 @@ internal static partial class AuthType internal const uint AUTHTYPE_CLIENT = 1; internal const uint AUTHTYPE_SERVER = 2; } - + internal static partial class CertChainPolicyIgnoreFlags { internal const uint CERT_CHAIN_POLICY_IGNORE_NOT_TIME_VALID_FLAG = 0x00000001; - internal const uint CERT_CHAIN_POLICY_IGNORE_CTL_NOT_TIME_VALID_FLAG = 0x00000002; - internal const uint CERT_CHAIN_POLICY_IGNORE_NOT_TIME_NESTED_FLAG = 0x00000004; + internal const uint CERT_CHAIN_POLICY_IGNORE_CTL_NOT_TIME_VALID_FLAG = 0x00000002; + internal const uint CERT_CHAIN_POLICY_IGNORE_NOT_TIME_NESTED_FLAG = 0x00000004; internal const uint CERT_CHAIN_POLICY_IGNORE_INVALID_BASIC_CONSTRAINTS_FLAG = 0x00000008; internal const uint CERT_CHAIN_POLICY_ALLOW_UNKNOWN_CA_FLAG = 0x00000010; internal const uint CERT_CHAIN_POLICY_IGNORE_WRONG_USAGE_FLAG = 0x00000020; @@ -34,8 +31,8 @@ internal static partial class CertChainPolicyIgnoreFlags internal const uint CERT_CHAIN_POLICY_IGNORE_ALL = CERT_CHAIN_POLICY_IGNORE_NOT_TIME_VALID_FLAG | - CERT_CHAIN_POLICY_IGNORE_CTL_NOT_TIME_VALID_FLAG | - CERT_CHAIN_POLICY_IGNORE_NOT_TIME_NESTED_FLAG | + CERT_CHAIN_POLICY_IGNORE_CTL_NOT_TIME_VALID_FLAG | + CERT_CHAIN_POLICY_IGNORE_NOT_TIME_NESTED_FLAG | CERT_CHAIN_POLICY_IGNORE_INVALID_BASIC_CONSTRAINTS_FLAG | CERT_CHAIN_POLICY_ALLOW_UNKNOWN_CA_FLAG | CERT_CHAIN_POLICY_IGNORE_WRONG_USAGE_FLAG | @@ -58,7 +55,7 @@ internal static partial class CertChainPolicy internal const int CERT_CHAIN_POLICY_MICROSOFT_ROOT = 7; internal const int CERT_CHAIN_POLICY_EV = 8; } - + internal static partial class CertChainPolicyErrors { // Base Policy errors (CERT_CHAIN_POLICY_BASE). @@ -74,7 +71,7 @@ internal static partial class CertChainPolicyErrors // Basic Constraints Policy errors (CERT_CHAIN_POLICY_BASIC_CONSTRAINTS). internal const uint TRUST_E_BASIC_CONSTRAINTS = 0x80096019; - + // Authenticode Policy errors (CERT_CHAIN_POLICY_AUTHENTICODE and CERT_CHAIN_POLICY_AUTHENTICODE_TS). internal const uint CERT_E_CRITICAL = 0x800B0105; internal const uint CERT_E_VALIDITYPERIODNESTING = 0x800B0102; @@ -83,12 +80,12 @@ internal static partial class CertChainPolicyErrors internal const uint CERT_E_PURPOSE = 0x800B0106; internal const uint CERT_E_REVOKED = 0x800B010C; internal const uint CERT_E_REVOCATION_FAILURE = 0x800B010E; - + // SSL Policy errors (CERT_CHAIN_POLICY_SSL). internal const uint CERT_E_CN_NO_MATCH = 0x800B010F; internal const uint CERT_E_ROLE = 0x800B0103; } - + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] internal struct CERT_CONTEXT { @@ -115,7 +112,7 @@ internal unsafe struct CERT_CHAIN_POLICY_PARA public uint dwFlags; public SSL_EXTRA_CERT_CHAIN_POLICY_PARA* pvExtraPolicyPara; } - + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] internal unsafe struct CERT_CHAIN_POLICY_STATUS { diff --git a/src/Common/src/Interop/Windows/Interop.Libraries.cs b/src/Common/src/Interop/Windows/Interop.Libraries.cs index d43e6d9321a5..e7edc67a40e7 100644 --- a/src/Common/src/Interop/Windows/Interop.Libraries.cs +++ b/src/Common/src/Interop/Windows/Interop.Libraries.cs @@ -41,6 +41,7 @@ internal static class Libraries internal const string Psapi_Obsolete = "api-ms-win-core-psapi-obsolete-l1-1-0.dll"; internal const string Registry_L1 = "api-ms-win-core-registry-l1-1-0.dll"; internal const string Registry_L2 = "api-ms-win-core-registry-l2-1-0.dll"; + internal const string Secur32 = "Secur32.dll"; internal const string SecurityBase = "api-ms-win-security-base-l1-1-0.dll"; internal const string SecurityCpwl = "api-ms-win-security-cpwl-l1-1-0.dll"; internal const string SecurityLsa = "api-ms-win-security-lsalookup-l2-1-0.dll"; diff --git a/src/Common/src/Interop/Windows/SChannel/Interop.SchProtocols.cs b/src/Common/src/Interop/Windows/SChannel/Interop.SchProtocols.cs index f7c0f78a64d4..c8856c3f2375 100644 --- a/src/Common/src/Interop/Windows/SChannel/Interop.SchProtocols.cs +++ b/src/Common/src/Interop/Windows/SChannel/Interop.SchProtocols.cs @@ -1,8 +1,6 @@ // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System; - internal static partial class Interop { internal static partial class SChannel diff --git a/src/Common/src/Interop/Windows/SChannel/Interop.SecurityStatus.cs b/src/Common/src/Interop/Windows/SChannel/Interop.SecurityStatus.cs new file mode 100644 index 000000000000..4091f9180160 --- /dev/null +++ b/src/Common/src/Interop/Windows/SChannel/Interop.SecurityStatus.cs @@ -0,0 +1,356 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +internal static partial class Interop +{ + internal enum SecurityStatus + { + // Success / Informational + OK = 0x00000000, + ContinueNeeded = unchecked((int)0x00090312), + CompleteNeeded = unchecked((int)0x00090313), + CompAndContinue = unchecked((int)0x00090314), + ContextExpired = unchecked((int)0x00090317), + CredentialsNeeded = unchecked((int)0x00090320), + Renegotiate = unchecked((int)0x00090321), + + // Errors + OutOfMemory = unchecked((int)0x80090300), + InvalidHandle = unchecked((int)0x80090301), + Unsupported = unchecked((int)0x80090302), + TargetUnknown = unchecked((int)0x80090303), + InternalError = unchecked((int)0x80090304), + PackageNotFound = unchecked((int)0x80090305), + NotOwner = unchecked((int)0x80090306), + CannotInstall = unchecked((int)0x80090307), + InvalidToken = unchecked((int)0x80090308), + CannotPack = unchecked((int)0x80090309), + QopNotSupported = unchecked((int)0x8009030A), + NoImpersonation = unchecked((int)0x8009030B), + LogonDenied = unchecked((int)0x8009030C), + UnknownCredentials = unchecked((int)0x8009030D), + NoCredentials = unchecked((int)0x8009030E), + MessageAltered = unchecked((int)0x8009030F), + OutOfSequence = unchecked((int)0x80090310), + NoAuthenticatingAuthority = unchecked((int)0x80090311), + IncompleteMessage = unchecked((int)0x80090318), + IncompleteCredentials = unchecked((int)0x80090320), + BufferNotEnough = unchecked((int)0x80090321), + WrongPrincipal = unchecked((int)0x80090322), + TimeSkew = unchecked((int)0x80090324), + UntrustedRoot = unchecked((int)0x80090325), + IllegalMessage = unchecked((int)0x80090326), + CertUnknown = unchecked((int)0x80090327), + CertExpired = unchecked((int)0x80090328), + AlgorithmMismatch = unchecked((int)0x80090331), + SecurityQosFailed = unchecked((int)0x80090332), + SmartcardLogonRequired = unchecked((int)0x8009033E), + UnsupportedPreauth = unchecked((int)0x80090343), + BadBinding = unchecked((int)0x80090346) + } + +#if TRACE_VERBOSE + internal static string MapSecurityStatus(uint statusCode) + { + switch (statusCode) + { + case 0: return "0"; + case 0x80090001: return "NTE_BAD_UID"; + case 0x80090002: return "NTE_BAD_HASH"; + case 0x80090003: return "NTE_BAD_KEY"; + case 0x80090004: return "NTE_BAD_LEN"; + case 0x80090005: return "NTE_BAD_DATA"; + case 0x80090006: return "NTE_BAD_SIGNATURE"; + case 0x80090007: return "NTE_BAD_VER"; + case 0x80090008: return "NTE_BAD_ALGID"; + case 0x80090009: return "NTE_BAD_FLAGS"; + case 0x8009000A: return "NTE_BAD_TYPE"; + case 0x8009000B: return "NTE_BAD_KEY_STATE"; + case 0x8009000C: return "NTE_BAD_HASH_STATE"; + case 0x8009000D: return "NTE_NO_KEY"; + case 0x8009000E: return "NTE_NO_MEMORY"; + case 0x8009000F: return "NTE_EXISTS"; + case 0x80090010: return "NTE_PERM"; + case 0x80090011: return "NTE_NOT_FOUND"; + case 0x80090012: return "NTE_DOUBLE_ENCRYPT"; + case 0x80090013: return "NTE_BAD_PROVIDER"; + case 0x80090014: return "NTE_BAD_PROV_TYPE"; + case 0x80090015: return "NTE_BAD_PUBLIC_KEY"; + case 0x80090016: return "NTE_BAD_KEYSET"; + case 0x80090017: return "NTE_PROV_TYPE_NOT_DEF"; + case 0x80090018: return "NTE_PROV_TYPE_ENTRY_BAD"; + case 0x80090019: return "NTE_KEYSET_NOT_DEF"; + case 0x8009001A: return "NTE_KEYSET_ENTRY_BAD"; + case 0x8009001B: return "NTE_PROV_TYPE_NO_MATCH"; + case 0x8009001C: return "NTE_SIGNATURE_FILE_BAD"; + case 0x8009001D: return "NTE_PROVIDER_DLL_FAIL"; + case 0x8009001E: return "NTE_PROV_DLL_NOT_FOUND"; + case 0x8009001F: return "NTE_BAD_KEYSET_PARAM"; + case 0x80090020: return "NTE_FAIL"; + case 0x80090021: return "NTE_SYS_ERR"; + case 0x80090022: return "NTE_SILENT_CONTEXT"; + case 0x80090023: return "NTE_TOKEN_KEYSET_STORAGE_FULL"; + case 0x80090024: return "NTE_TEMPORARY_PROFILE"; + case 0x80090025: return "NTE_FIXEDPARAMETER"; + case 0x80090300: return "SEC_E_INSUFFICIENT_MEMORY"; + case 0x80090301: return "SEC_E_INVALID_HANDLE"; + case 0x80090302: return "SEC_E_UNSUPPORTED_FUNCTION"; + case 0x80090303: return "SEC_E_TARGET_UNKNOWN"; + case 0x80090304: return "SEC_E_INTERNAL_ERROR"; + case 0x80090305: return "SEC_E_SECPKG_NOT_FOUND"; + case 0x80090306: return "SEC_E_NOT_OWNER"; + case 0x80090307: return "SEC_E_CANNOT_INSTALL"; + case 0x80090308: return "SEC_E_INVALID_TOKEN"; + case 0x80090309: return "SEC_E_CANNOT_PACK"; + case 0x8009030A: return "SEC_E_QOP_NOT_SUPPORTED"; + case 0x8009030B: return "SEC_E_NO_IMPERSONATION"; + case 0x8009030C: return "SEC_E_LOGON_DENIED"; + case 0x8009030D: return "SEC_E_UNKNOWN_CREDENTIALS"; + case 0x8009030E: return "SEC_E_NO_CREDENTIALS"; + case 0x8009030F: return "SEC_E_MESSAGE_ALTERED"; + case 0x80090310: return "SEC_E_OUT_OF_SEQUENCE"; + case 0x80090311: return "SEC_E_NO_AUTHENTICATING_AUTHORITY"; + case 0x00090312: return "SEC_I_CONTINUE_NEEDED"; + case 0x00090313: return "SEC_I_COMPLETE_NEEDED"; + case 0x00090314: return "SEC_I_COMPLETE_AND_CONTINUE"; + case 0x00090315: return "SEC_I_LOCAL_LOGON"; + case 0x80090316: return "SEC_E_BAD_PKGID"; + case 0x80090317: return "SEC_E_CONTEXT_EXPIRED"; + case 0x00090317: return "SEC_I_CONTEXT_EXPIRED"; + case 0x80090318: return "SEC_E_INCOMPLETE_MESSAGE"; + case 0x80090320: return "SEC_E_INCOMPLETE_CREDENTIALS"; + case 0x80090321: return "SEC_E_BUFFER_TOO_SMALL"; + case 0x00090320: return "SEC_I_INCOMPLETE_CREDENTIALS"; + case 0x00090321: return "SEC_I_RENEGOTIATE"; + case 0x80090322: return "SEC_E_WRONG_PRINCIPAL"; + case 0x00090323: return "SEC_I_NO_LSA_CONTEXT"; + case 0x80090324: return "SEC_E_TIME_SKEW"; + case 0x80090325: return "SEC_E_UNTRUSTED_ROOT"; + case 0x80090326: return "SEC_E_ILLEGAL_MESSAGE"; + case 0x80090327: return "SEC_E_CERT_UNKNOWN"; + case 0x80090328: return "SEC_E_CERT_EXPIRED"; + case 0x80090329: return "SEC_E_ENCRYPT_FAILURE"; + case 0x80090330: return "SEC_E_DECRYPT_FAILURE"; + case 0x80090331: return "SEC_E_ALGORITHM_MISMATCH"; + case 0x80090332: return "SEC_E_SECURITY_QOS_FAILED"; + case 0x80090333: return "SEC_E_UNFINISHED_CONTEXT_DELETED"; + case 0x80090334: return "SEC_E_NO_TGT_REPLY"; + case 0x80090335: return "SEC_E_NO_IP_ADDRESSES"; + case 0x80090336: return "SEC_E_WRONG_CREDENTIAL_HANDLE"; + case 0x80090337: return "SEC_E_CRYPTO_SYSTEM_INVALID"; + case 0x80090338: return "SEC_E_MAX_REFERRALS_EXCEEDED"; + case 0x80090339: return "SEC_E_MUST_BE_KDC"; + case 0x8009033A: return "SEC_E_STRONG_CRYPTO_NOT_SUPPORTED"; + case 0x8009033B: return "SEC_E_TOO_MANY_PRINCIPALS"; + case 0x8009033C: return "SEC_E_NO_PA_DATA"; + case 0x8009033D: return "SEC_E_PKINIT_NAME_MISMATCH"; + case 0x8009033E: return "SEC_E_SMARTCARD_LOGON_REQUIRED"; + case 0x8009033F: return "SEC_E_SHUTDOWN_IN_PROGRESS"; + case 0x80090340: return "SEC_E_KDC_INVALID_REQUEST"; + case 0x80090341: return "SEC_E_KDC_UNABLE_TO_REFER"; + case 0x80090342: return "SEC_E_KDC_UNKNOWN_ETYPE"; + case 0x80090343: return "SEC_E_UNSUPPORTED_PREAUTH"; + case 0x80090345: return "SEC_E_DELEGATION_REQUIRED"; + case 0x80090346: return "SEC_E_BAD_BINDINGS"; + case 0x80090347: return "SEC_E_MULTIPLE_ACCOUNTS"; + case 0x80090348: return "SEC_E_NO_KERB_KEY"; + case 0x80091001: return "CRYPT_E_MSG_ERROR"; + case 0x80091002: return "CRYPT_E_UNKNOWN_ALGO"; + case 0x80091003: return "CRYPT_E_OID_FORMAT"; + case 0x80091004: return "CRYPT_E_INVALID_MSG_TYPE"; + case 0x80091005: return "CRYPT_E_UNEXPECTED_ENCODING"; + case 0x80091006: return "CRYPT_E_AUTH_ATTR_MISSING"; + case 0x80091007: return "CRYPT_E_HASH_VALUE"; + case 0x80091008: return "CRYPT_E_INVALID_INDEX"; + case 0x80091009: return "CRYPT_E_ALREADY_DECRYPTED"; + case 0x8009100A: return "CRYPT_E_NOT_DECRYPTED"; + case 0x8009100B: return "CRYPT_E_RECIPIENT_NOT_FOUND"; + case 0x8009100C: return "CRYPT_E_CONTROL_TYPE"; + case 0x8009100D: return "CRYPT_E_ISSUER_SERIALNUMBER"; + case 0x8009100E: return "CRYPT_E_SIGNER_NOT_FOUND"; + case 0x8009100F: return "CRYPT_E_ATTRIBUTES_MISSING"; + case 0x80091010: return "CRYPT_E_STREAM_MSG_NOT_READY"; + case 0x80091011: return "CRYPT_E_STREAM_INSUFFICIENT_DATA"; + case 0x00091012: return "CRYPT_I_NEW_PROTECTION_REQUIRED"; + case 0x80092001: return "CRYPT_E_BAD_LEN"; + case 0x80092002: return "CRYPT_E_BAD_ENCODE"; + case 0x80092003: return "CRYPT_E_FILE_ERROR"; + case 0x80092004: return "CRYPT_E_NOT_FOUND"; + case 0x80092005: return "CRYPT_E_EXISTS"; + case 0x80092006: return "CRYPT_E_NO_PROVIDER"; + case 0x80092007: return "CRYPT_E_SELF_SIGNED"; + case 0x80092008: return "CRYPT_E_DELETED_PREV"; + case 0x80092009: return "CRYPT_E_NO_MATCH"; + case 0x8009200A: return "CRYPT_E_UNEXPECTED_MSG_TYPE"; + case 0x8009200B: return "CRYPT_E_NO_KEY_PROPERTY"; + case 0x8009200C: return "CRYPT_E_NO_DECRYPT_CERT"; + case 0x8009200D: return "CRYPT_E_BAD_MSG"; + case 0x8009200E: return "CRYPT_E_NO_SIGNER"; + case 0x8009200F: return "CRYPT_E_PENDING_CLOSE"; + case 0x80092010: return "CRYPT_E_REVOKED"; + case 0x80092011: return "CRYPT_E_NO_REVOCATION_DLL"; + case 0x80092012: return "CRYPT_E_NO_REVOCATION_CHECK"; + case 0x80092013: return "CRYPT_E_REVOCATION_OFFLINE"; + case 0x80092014: return "CRYPT_E_NOT_IN_REVOCATION_DATABASE"; + case 0x80092020: return "CRYPT_E_INVALID_NUMERIC_STRING"; + case 0x80092021: return "CRYPT_E_INVALID_PRINTABLE_STRING"; + case 0x80092022: return "CRYPT_E_INVALID_IA5_STRING"; + case 0x80092023: return "CRYPT_E_INVALID_X500_STRING"; + case 0x80092024: return "CRYPT_E_NOT_CHAR_STRING"; + case 0x80092025: return "CRYPT_E_FILERESIZED"; + case 0x80092026: return "CRYPT_E_SECURITY_SETTINGS"; + case 0x80092027: return "CRYPT_E_NO_VERIFY_USAGE_DLL"; + case 0x80092028: return "CRYPT_E_NO_VERIFY_USAGE_CHECK"; + case 0x80092029: return "CRYPT_E_VERIFY_USAGE_OFFLINE"; + case 0x8009202A: return "CRYPT_E_NOT_IN_CTL"; + case 0x8009202B: return "CRYPT_E_NO_TRUSTED_SIGNER"; + case 0x8009202C: return "CRYPT_E_MISSING_PUBKEY_PARA"; + case 0x80093000: return "CRYPT_E_OSS_ERROR"; + case 0x80093001: return "OSS_MORE_BUF"; + case 0x80093002: return "OSS_NEGATIVE_UINTEGER"; + case 0x80093003: return "OSS_PDU_RANGE"; + case 0x80093004: return "OSS_MORE_INPUT"; + case 0x80093005: return "OSS_DATA_ERROR"; + case 0x80093006: return "OSS_BAD_ARG"; + case 0x80093007: return "OSS_BAD_VERSION"; + case 0x80093008: return "OSS_OUT_MEMORY"; + case 0x80093009: return "OSS_PDU_MISMATCH"; + case 0x8009300A: return "OSS_LIMITED"; + case 0x8009300B: return "OSS_BAD_PTR"; + case 0x8009300C: return "OSS_BAD_TIME"; + case 0x8009300D: return "OSS_INDEFINITE_NOT_SUPPORTED"; + case 0x8009300E: return "OSS_MEM_ERROR"; + case 0x8009300F: return "OSS_BAD_TABLE"; + case 0x80093010: return "OSS_TOO_LONG"; + case 0x80093011: return "OSS_CONSTRAINT_VIOLATED"; + case 0x80093012: return "OSS_FATAL_ERROR"; + case 0x80093013: return "OSS_ACCESS_SERIALIZATION_ERROR"; + case 0x80093014: return "OSS_NULL_TBL"; + case 0x80093015: return "OSS_NULL_FCN"; + case 0x80093016: return "OSS_BAD_ENCRULES"; + case 0x80093017: return "OSS_UNAVAIL_ENCRULES"; + case 0x80093018: return "OSS_CANT_OPEN_TRACE_WINDOW"; + case 0x80093019: return "OSS_UNIMPLEMENTED"; + case 0x8009301A: return "OSS_OID_DLL_NOT_LINKED"; + case 0x8009301B: return "OSS_CANT_OPEN_TRACE_FILE"; + case 0x8009301C: return "OSS_TRACE_FILE_ALREADY_OPEN"; + case 0x8009301D: return "OSS_TABLE_MISMATCH"; + case 0x8009301E: return "OSS_TYPE_NOT_SUPPORTED"; + case 0x8009301F: return "OSS_REAL_DLL_NOT_LINKED"; + case 0x80093020: return "OSS_REAL_CODE_NOT_LINKED"; + case 0x80093021: return "OSS_OUT_OF_RANGE"; + case 0x80093022: return "OSS_COPIER_DLL_NOT_LINKED"; + case 0x80093023: return "OSS_CONSTRAINT_DLL_NOT_LINKED"; + case 0x80093024: return "OSS_COMPARATOR_DLL_NOT_LINKED"; + case 0x80093025: return "OSS_COMPARATOR_CODE_NOT_LINKED"; + case 0x80093026: return "OSS_MEM_MGR_DLL_NOT_LINKED"; + case 0x80093027: return "OSS_PDV_DLL_NOT_LINKED"; + case 0x80093028: return "OSS_PDV_CODE_NOT_LINKED"; + case 0x80093029: return "OSS_API_DLL_NOT_LINKED"; + case 0x8009302A: return "OSS_BERDER_DLL_NOT_LINKED"; + case 0x8009302B: return "OSS_PER_DLL_NOT_LINKED"; + case 0x8009302C: return "OSS_OPEN_TYPE_ERROR"; + case 0x8009302D: return "OSS_MUTEX_NOT_CREATED"; + case 0x8009302E: return "OSS_CANT_CLOSE_TRACE_FILE"; + case 0x80093100: return "CRYPT_E_ASN1_ERROR"; + case 0x80093101: return "CRYPT_E_ASN1_INTERNAL"; + case 0x80093102: return "CRYPT_E_ASN1_EOD"; + case 0x80093103: return "CRYPT_E_ASN1_CORRUPT"; + case 0x80093104: return "CRYPT_E_ASN1_LARGE"; + case 0x80093105: return "CRYPT_E_ASN1_CONSTRAINT"; + case 0x80093106: return "CRYPT_E_ASN1_MEMORY"; + case 0x80093107: return "CRYPT_E_ASN1_OVERFLOW"; + case 0x80093108: return "CRYPT_E_ASN1_BADPDU"; + case 0x80093109: return "CRYPT_E_ASN1_BADARGS"; + case 0x8009310A: return "CRYPT_E_ASN1_BADREAL"; + case 0x8009310B: return "CRYPT_E_ASN1_BADTAG"; + case 0x8009310C: return "CRYPT_E_ASN1_CHOICE"; + case 0x8009310D: return "CRYPT_E_ASN1_RULE"; + case 0x8009310E: return "CRYPT_E_ASN1_UTF8"; + case 0x80093133: return "CRYPT_E_ASN1_PDU_TYPE"; + case 0x80093134: return "CRYPT_E_ASN1_NYI"; + case 0x80093201: return "CRYPT_E_ASN1_EXTENDED"; + case 0x80093202: return "CRYPT_E_ASN1_NOEOD"; + case 0x80094001: return "CERTSRV_E_BAD_REQUESTSUBJECT"; + case 0x80094002: return "CERTSRV_E_NO_REQUEST"; + case 0x80094003: return "CERTSRV_E_BAD_REQUESTSTATUS"; + case 0x80094004: return "CERTSRV_E_PROPERTY_EMPTY"; + case 0x80094005: return "CERTSRV_E_INVALID_CA_CERTIFICATE"; + case 0x80094006: return "CERTSRV_E_SERVER_SUSPENDED"; + case 0x80094007: return "CERTSRV_E_ENCODING_LENGTH"; + case 0x80094008: return "CERTSRV_E_ROLECONFLICT"; + case 0x80094009: return "CERTSRV_E_RESTRICTEDOFFICER"; + case 0x8009400A: return "CERTSRV_E_KEY_ARCHIVAL_NOT_CONFIGURED"; + case 0x8009400B: return "CERTSRV_E_NO_VALID_KRA"; + case 0x8009400C: return "CERTSRV_E_BAD_REQUEST_KEY_ARCHIVAL"; + case 0x80094800: return "CERTSRV_E_UNSUPPORTED_CERT_TYPE"; + case 0x80094801: return "CERTSRV_E_NO_CERT_TYPE"; + case 0x80094802: return "CERTSRV_E_TEMPLATE_CONFLICT"; + case 0x80096001: return "TRUST_E_SYSTEM_ERROR"; + case 0x80096002: return "TRUST_E_NO_SIGNER_CERT"; + case 0x80096003: return "TRUST_E_COUNTER_SIGNER"; + case 0x80096004: return "TRUST_E_CERT_SIGNATURE"; + case 0x80096005: return "TRUST_E_TIME_STAMP"; + case 0x80096010: return "TRUST_E_BAD_DIGEST"; + case 0x80096019: return "TRUST_E_BASIC_CONSTRAINTS"; + case 0x8009601E: return "TRUST_E_FINANCIAL_CRITERIA"; + case 0x80097001: return "MSSIPOTF_E_OUTOFMEMRANGE"; + case 0x80097002: return "MSSIPOTF_E_CANTGETOBJECT"; + case 0x80097003: return "MSSIPOTF_E_NOHEADTABLE"; + case 0x80097004: return "MSSIPOTF_E_BAD_MAGICNUMBER"; + case 0x80097005: return "MSSIPOTF_E_BAD_OFFSET_TABLE"; + case 0x80097006: return "MSSIPOTF_E_TABLE_TAGORDER"; + case 0x80097007: return "MSSIPOTF_E_TABLE_LONGWORD"; + case 0x80097008: return "MSSIPOTF_E_BAD_FIRST_TABLE_PLACEMENT"; + case 0x80097009: return "MSSIPOTF_E_TABLES_OVERLAP"; + case 0x8009700A: return "MSSIPOTF_E_TABLE_PADBYTES"; + case 0x8009700B: return "MSSIPOTF_E_FILETOOSMALL"; + case 0x8009700C: return "MSSIPOTF_E_TABLE_CHECKSUM"; + case 0x8009700D: return "MSSIPOTF_E_FILE_CHECKSUM"; + case 0x80097010: return "MSSIPOTF_E_FAILED_POLICY"; + case 0x80097011: return "MSSIPOTF_E_FAILED_HINTS_CHECK"; + case 0x80097012: return "MSSIPOTF_E_NOT_OPENTYPE"; + case 0x80097013: return "MSSIPOTF_E_FILE"; + case 0x80097014: return "MSSIPOTF_E_CRYPT"; + case 0x80097015: return "MSSIPOTF_E_BADVERSION"; + case 0x80097016: return "MSSIPOTF_E_DSIG_STRUCTURE"; + case 0x80097017: return "MSSIPOTF_E_PCONST_CHECK"; + case 0x80097018: return "MSSIPOTF_E_STRUCTURE"; + case 0x800B0001: return "TRUST_E_PROVIDER_UNKNOWN"; + case 0x800B0002: return "TRUST_E_ACTION_UNKNOWN"; + case 0x800B0003: return "TRUST_E_SUBJECT_FORM_UNKNOWN"; + case 0x800B0004: return "TRUST_E_SUBJECT_NOT_TRUSTED"; + case 0x800B0005: return "DIGSIG_E_ENCODE"; + case 0x800B0006: return "DIGSIG_E_DECODE"; + case 0x800B0007: return "DIGSIG_E_EXTENSIBILITY"; + case 0x800B0008: return "DIGSIG_E_CRYPTO"; + case 0x800B0009: return "PERSIST_E_SIZEDEFINITE"; + case 0x800B000A: return "PERSIST_E_SIZEINDEFINITE"; + case 0x800B000B: return "PERSIST_E_NOTSELFSIZING"; + case 0x800B0100: return "TRUST_E_NOSIGNATURE"; + case 0x800B0101: return "CERT_E_EXPIRED"; + case 0x800B0102: return "CERT_E_VALIDITYPERIODNESTING"; + case 0x800B0103: return "CERT_E_ROLE"; + case 0x800B0104: return "CERT_E_PATHLENCONST"; + case 0x800B0105: return "CERT_E_CRITICAL"; + case 0x800B0106: return "CERT_E_PURPOSE"; + case 0x800B0107: return "CERT_E_ISSUERCHAINING"; + case 0x800B0108: return "CERT_E_MALFORMED"; + case 0x800B0109: return "CERT_E_UNTRUSTEDROOT"; + case 0x800B010A: return "CERT_E_CHAINING"; + case 0x800B010B: return "TRUST_E_FAIL"; + case 0x800B010C: return "CERT_E_REVOKED"; + case 0x800B010D: return "CERT_E_UNTRUSTEDTESTROOT"; + case 0x800B010E: return "CERT_E_REVOCATION_FAILURE"; + case 0x800B010F: return "CERT_E_CN_NO_MATCH"; + case 0x800B0110: return "CERT_E_WRONG_USAGE"; + case 0x800B0111: return "TRUST_E_EXPLICIT_DISTRUST"; + case 0x800B0112: return "CERT_E_UNTRUSTEDCA"; + case 0x800B0113: return "CERT_E_INVALID_POLICY"; + case 0x800B0114: return "CERT_E_INVALID_NAME"; + } + + return string.Format("0x{0:x} [{1}]", statusCode, statusCode); + } +#endif // TRACE_VERBOSE +} diff --git a/src/Common/src/Interop/Windows/secur32/Interop.SSPI.cs b/src/Common/src/Interop/Windows/secur32/Interop.SSPI.cs new file mode 100644 index 000000000000..7392b1a0e143 --- /dev/null +++ b/src/Common/src/Interop/Windows/secur32/Interop.SSPI.cs @@ -0,0 +1,515 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Net.Security; +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + internal static partial class Secur32 + { + // TODO (Issue #3114): Throughout the entire file: replace with OS names from and + internal const uint SECQOP_WRAP_NO_ENCRYPT = 0x80000001; + + internal const int SEC_I_RENEGOTIATE = 0x90321; + + internal const int SECPKG_NEGOTIATION_COMPLETE = 0; + internal const int SECPKG_NEGOTIATION_OPTIMISTIC = 1; + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct SSPIHandle + { + private IntPtr _handleHi; + private IntPtr _handleLo; + + public bool IsZero + { + get { return _handleHi == IntPtr.Zero && HandleLo1 == IntPtr.Zero; } + } + + public IntPtr HandleLo1 + { + get + { + return _handleLo; + } + + set + { + _handleLo = value; + } + } + + internal void SetToInvalid() + { + _handleHi = IntPtr.Zero; + HandleLo1 = IntPtr.Zero; + } + + public override string ToString() + { + { return _handleHi.ToString("x") + ":" + HandleLo1.ToString("x"); } + } + } + + internal enum ContextAttribute + { + Sizes = 0x00, + Names = 0x01, + Lifespan = 0x02, + DceInfo = 0x03, + StreamSizes = 0x04, + //KeyInfo = 0x05, must not be used, see ConnectionInfo instead + Authority = 0x06, + // SECPKG_ATTR_PROTO_INFO = 7, + // SECPKG_ATTR_PASSWORD_EXPIRY = 8, + // SECPKG_ATTR_SESSION_KEY = 9, + PackageInfo = 0x0A, + // SECPKG_ATTR_USER_FLAGS = 11, + NegotiationInfo = 0x0C, + // SECPKG_ATTR_NATIVE_NAMES = 13, + // SECPKG_ATTR_FLAGS = 14, + // SECPKG_ATTR_USE_VALIDATED = 15, + // SECPKG_ATTR_CREDENTIAL_NAME = 16, + // SECPKG_ATTR_TARGET_INFORMATION = 17, + // SECPKG_ATTR_ACCESS_TOKEN = 18, + // SECPKG_ATTR_TARGET = 19, + // SECPKG_ATTR_AUTHENTICATION_ID = 20, + UniqueBindings = 0x19, + EndpointBindings = 0x1A, + ClientSpecifiedSpn = 0x1B, // SECPKG_ATTR_CLIENT_SPECIFIED_TARGET = 27 + RemoteCertificate = 0x53, + LocalCertificate = 0x54, + RootStore = 0x55, + IssuerListInfoEx = 0x59, + ConnectionInfo = 0x5A, + // SECPKG_ATTR_EAP_KEY_BLOCK 0x5b // returns SecPkgContext_EapKeyBlock + // SECPKG_ATTR_MAPPED_CRED_ATTR 0x5c // returns SecPkgContext_MappedCredAttr + // SECPKG_ATTR_SESSION_INFO 0x5d // returns SecPkgContext_SessionInfo + // SECPKG_ATTR_APP_DATA 0x5e // sets/returns SecPkgContext_SessionAppData + // SECPKG_ATTR_REMOTE_CERTIFICATES 0x5F // returns SecPkgContext_Certificates + // SECPKG_ATTR_CLIENT_CERT_POLICY 0x60 // sets SecPkgCred_ClientCertCtlPolicy + // SECPKG_ATTR_CC_POLICY_RESULT 0x61 // returns SecPkgContext_ClientCertPolicyResult + // SECPKG_ATTR_USE_NCRYPT 0x62 // Sets the CRED_FLAG_USE_NCRYPT_PROVIDER FLAG on cred group + // SECPKG_ATTR_LOCAL_CERT_INFO 0x63 // returns SecPkgContext_CertInfo + // SECPKG_ATTR_CIPHER_INFO 0x64 // returns new CNG SecPkgContext_CipherInfo + // SECPKG_ATTR_EAP_PRF_INFO 0x65 // sets SecPkgContext_EapPrfInfo + // SECPKG_ATTR_SUPPORTED_SIGNATURES 0x66 // returns SecPkgContext_SupportedSignatures + // SECPKG_ATTR_REMOTE_CERT_CHAIN 0x67 // returns PCCERT_CONTEXT + UiInfo = 0x68, // sets SEcPkgContext_UiInfo + } + + // #define ISC_REQ_DELEGATE 0x00000001 + // #define ISC_REQ_MUTUAL_AUTH 0x00000002 + // #define ISC_REQ_REPLAY_DETECT 0x00000004 + // #define ISC_REQ_SEQUENCE_DETECT 0x00000008 + // #define ISC_REQ_CONFIDENTIALITY 0x00000010 + // #define ISC_REQ_USE_SESSION_KEY 0x00000020 + // #define ISC_REQ_PROMPT_FOR_CREDS 0x00000040 + // #define ISC_REQ_USE_SUPPLIED_CREDS 0x00000080 + // #define ISC_REQ_ALLOCATE_MEMORY 0x00000100 + // #define ISC_REQ_USE_DCE_STYLE 0x00000200 + // #define ISC_REQ_DATAGRAM 0x00000400 + // #define ISC_REQ_CONNECTION 0x00000800 + // #define ISC_REQ_CALL_LEVEL 0x00001000 + // #define ISC_REQ_FRAGMENT_SUPPLIED 0x00002000 + // #define ISC_REQ_EXTENDED_ERROR 0x00004000 + // #define ISC_REQ_STREAM 0x00008000 + // #define ISC_REQ_INTEGRITY 0x00010000 + // #define ISC_REQ_IDENTIFY 0x00020000 + // #define ISC_REQ_NULL_SESSION 0x00040000 + // #define ISC_REQ_MANUAL_CRED_VALIDATION 0x00080000 + // #define ISC_REQ_RESERVED1 0x00100000 + // #define ISC_REQ_FRAGMENT_TO_FIT 0x00200000 + // #define ISC_REQ_HTTP 0x10000000 + // Win7 SP1 + + // #define ISC_REQ_UNVERIFIED_TARGET_NAME 0x20000000 + + // #define ASC_REQ_DELEGATE 0x00000001 + // #define ASC_REQ_MUTUAL_AUTH 0x00000002 + // #define ASC_REQ_REPLAY_DETECT 0x00000004 + // #define ASC_REQ_SEQUENCE_DETECT 0x00000008 + // #define ASC_REQ_CONFIDENTIALITY 0x00000010 + // #define ASC_REQ_USE_SESSION_KEY 0x00000020 + // #define ASC_REQ_ALLOCATE_MEMORY 0x00000100 + // #define ASC_REQ_USE_DCE_STYLE 0x00000200 + // #define ASC_REQ_DATAGRAM 0x00000400 + // #define ASC_REQ_CONNECTION 0x00000800 + // #define ASC_REQ_CALL_LEVEL 0x00001000 + // #define ASC_REQ_EXTENDED_ERROR 0x00008000 + // #define ASC_REQ_STREAM 0x00010000 + // #define ASC_REQ_INTEGRITY 0x00020000 + // #define ASC_REQ_LICENSING 0x00040000 + // #define ASC_REQ_IDENTIFY 0x00080000 + // #define ASC_REQ_ALLOW_NULL_SESSION 0x00100000 + // #define ASC_REQ_ALLOW_NON_USER_LOGONS 0x00200000 + // #define ASC_REQ_ALLOW_CONTEXT_REPLAY 0x00400000 + // #define ASC_REQ_FRAGMENT_TO_FIT 0x00800000 + // #define ASC_REQ_FRAGMENT_SUPPLIED 0x00002000 + // #define ASC_REQ_NO_TOKEN 0x01000000 + // #define ASC_REQ_HTTP 0x10000000 + + [Flags] + internal enum ContextFlags + { + Zero = 0, + // The server in the transport application can + // build new security contexts impersonating the + // client that will be accepted by other servers + // as the client's contexts. + Delegate = 0x00000001, + // The communicating parties must authenticate + // their identities to each other. Without MutualAuth, + // the client authenticates its identity to the server. + // With MutualAuth, the server also must authenticate + // its identity to the client. + MutualAuth = 0x00000002, + // The security package detects replayed packets and + // notifies the caller if a packet has been replayed. + // The use of this flag implies all of the conditions + // specified by the Integrity flag. + ReplayDetect = 0x00000004, + // The context must be allowed to detect out-of-order + // delivery of packets later through the message support + // functions. Use of this flag implies all of the + // conditions specified by the Integrity flag. + SequenceDetect = 0x00000008, + // The context must protect data while in transit. + // Confidentiality is supported for NTLM with Microsoft + // Windows NT version 4.0, SP4 and later and with the + // Kerberos protocol in Microsoft Windows 2000 and later. + Confidentiality = 0x00000010, + UseSessionKey = 0x00000020, + AllocateMemory = 0x00000100, + + // Connection semantics must be used. + Connection = 0x00000800, + + // Client applications requiring extended error messages specify the + // ISC_REQ_EXTENDED_ERROR flag when calling the InitializeSecurityContext + // Server applications requiring extended error messages set + // the ASC_REQ_EXTENDED_ERROR flag when calling AcceptSecurityContext. + InitExtendedError = 0x00004000, + AcceptExtendedError = 0x00008000, + // A transport application requests stream semantics + // by setting the ISC_REQ_STREAM and ASC_REQ_STREAM + // flags in the calls to the InitializeSecurityContext + // and AcceptSecurityContext functions + InitStream = 0x00008000, + AcceptStream = 0x00010000, + // Buffer integrity can be verified; however, replayed + // and out-of-sequence messages will not be detected + InitIntegrity = 0x00010000, // ISC_REQ_INTEGRITY + AcceptIntegrity = 0x00020000, // ASC_REQ_INTEGRITY + + InitManualCredValidation = 0x00080000, // ISC_REQ_MANUAL_CRED_VALIDATION + InitUseSuppliedCreds = 0x00000080, // ISC_REQ_USE_SUPPLIED_CREDS + InitIdentify = 0x00020000, // ISC_REQ_IDENTIFY + AcceptIdentify = 0x00080000, // ASC_REQ_IDENTIFY + + ProxyBindings = 0x04000000, // ASC_REQ_PROXY_BINDINGS + AllowMissingBindings = 0x10000000, // ASC_REQ_ALLOW_MISSING_BINDINGS + + UnverifiedTargetName = 0x20000000, // ISC_REQ_UNVERIFIED_TARGET_NAME + } + + internal enum Endianness + { + Network = 0x00, + Native = 0x10, + } + + internal enum CredentialUse + { + Inbound = 0x1, + Outbound = 0x2, + Both = 0x3, + } + + [StructLayout(LayoutKind.Sequential)] + internal struct _CERT_CHAIN_ELEMENT + { + public uint cbSize; + public IntPtr pCertContext; + // Since this structure is allocated by unmanaged code, we can + // omit the fileds below since we don't need to access them + // CERT_TRUST_STATUS TrustStatus; + // IntPtr pRevocationInfo; + // IntPtr pIssuanceUsage; + // IntPtr pApplicationUsage; + } + + // SecPkgContext_IssuerListInfoEx + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct IssuerListInfoEx + { + public SafeHandle aIssuers; + public uint cIssuers; + + public unsafe IssuerListInfoEx(SafeHandle handle, byte[] nativeBuffer) + { + aIssuers = handle; + fixed (byte* voidPtr = nativeBuffer) + { + // TODO (Issue #3114): Properly marshal the struct instead of assuming no padding. + cIssuers = *((uint*)(voidPtr + IntPtr.Size)); + } + } + } + + [StructLayout(LayoutKind.Sequential)] + internal struct SecureCredential + { + /* + typedef struct _SCHANNEL_CRED + { + DWORD dwVersion; // always SCHANNEL_CRED_VERSION + DWORD cCreds; + PCCERT_CONTEXT *paCred; + HCERTSTORE hRootStore; + + DWORD cMappers; + struct _HMAPPER **aphMappers; + + DWORD cSupportedAlgs; + ALG_ID * palgSupportedAlgs; + + DWORD grbitEnabledProtocols; + DWORD dwMinimumCipherStrength; + DWORD dwMaximumCipherStrength; + DWORD dwSessionLifespan; + DWORD dwFlags; + DWORD reserved; + } SCHANNEL_CRED, *PSCHANNEL_CRED; + */ + + public const int CurrentVersion = 0x4; + + public int version; + public int cCreds; + + // ptr to an array of pointers + // There is a hack done with this field. AcquireCredentialsHandle requires an array of + // certificate handles; we only ever use one. In order to avoid pinning a one element array, + // we copy this value onto the stack, create a pointer on the stack to the copied value, + // and replace this field with the pointer, during the call to AcquireCredentialsHandle. + // Then we fix it up afterwards. Fine as long as all the SSPI credentials are not + // supposed to be threadsafe. + public IntPtr certContextArray; + + public IntPtr rootStore; // == always null, OTHERWISE NOT RELIABLE + public int cMappers; + public IntPtr phMappers; // == always null, OTHERWISE NOT RELIABLE + public int cSupportedAlgs; + public IntPtr palgSupportedAlgs; // == always null, OTHERWISE NOT RELIABLE + public int grbitEnabledProtocols; + public int dwMinimumCipherStrength; + public int dwMaximumCipherStrength; + public int dwSessionLifespan; + public SecureCredential.Flags dwFlags; + public int reserved; + + [Flags] + public enum Flags + { + Zero = 0, + NoSystemMapper = 0x02, + NoNameCheck = 0x04, + ValidateManual = 0x08, + NoDefaultCred = 0x10, + ValidateAuto = 0x20, + UseStrongCrypto = 0x00400000, + } + } // SecureCredential + + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct SecurityBufferStruct + { + public int count; + public SecurityBufferType type; + public IntPtr token; + + public static readonly int Size = sizeof(SecurityBufferStruct); + } + + [StructLayout(LayoutKind.Sequential)] + internal unsafe class SecurityBufferDescriptor + { + /* + typedef struct _SecBufferDesc { + ULONG ulVersion; + ULONG cBuffers; + PSecBuffer pBuffers; + } SecBufferDesc, * PSecBufferDesc; + */ + public readonly int Version; + public readonly int Count; + public void* UnmanagedPointer; + + public SecurityBufferDescriptor(int count) + { + Version = 0; + Count = count; + UnmanagedPointer = null; + } + } // SecurityBufferDescriptor + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + internal struct AuthIdentity + { + // see SEC_WINNT_AUTH_IDENTITY_W + internal string UserName; + internal int UserNameLength; + internal string Domain; + internal int DomainLength; + internal string Password; + internal int PasswordLength; + internal int Flags; + } + + [DllImport(Interop.Libraries.Secur32, ExactSpelling = true, SetLastError = true)] + internal static extern int EncryptMessage( + ref SSPIHandle contextHandle, + [In] uint qualityOfProtection, + [In, Out] SecurityBufferDescriptor inputOutput, + [In] uint sequenceNumber + ); + + [DllImport(Interop.Libraries.Secur32, ExactSpelling = true, SetLastError = true)] + internal static unsafe extern int DecryptMessage( + [In] ref SSPIHandle contextHandle, + [In, Out] SecurityBufferDescriptor inputOutput, + [In] uint sequenceNumber, + uint* qualityOfProtection + ); + + [DllImport(Interop.Libraries.Secur32, ExactSpelling = true, SetLastError = true)] + internal static extern int QuerySecurityContextToken( + ref SSPIHandle phContext, + [Out] out SecurityContextTokenHandle handle); + + [DllImport(Interop.Libraries.Secur32, ExactSpelling = true, SetLastError = true)] + internal static extern int FreeContextBuffer( + [In] IntPtr contextBuffer); + + [DllImport(Interop.Libraries.Secur32, ExactSpelling = true, SetLastError = true)] + internal static extern int FreeCredentialsHandle( + ref SSPIHandle handlePtr + ); + + [DllImport(Interop.Libraries.Secur32, ExactSpelling = true, SetLastError = true)] + internal static extern int DeleteSecurityContext( + ref SSPIHandle handlePtr + ); + + [DllImport(Interop.Libraries.Secur32, ExactSpelling = true, SetLastError = true)] + internal unsafe static extern int AcceptSecurityContext( + ref SSPIHandle credentialHandle, + [In] void* inContextPtr, + [In] SecurityBufferDescriptor inputBuffer, + [In] ContextFlags inFlags, + [In] Endianness endianness, + ref SSPIHandle outContextPtr, + [In, Out] SecurityBufferDescriptor outputBuffer, + [In, Out] ref ContextFlags attributes, + out long timeStamp + ); + + [DllImport(Interop.Libraries.Secur32, ExactSpelling = true, SetLastError = true)] + internal unsafe static extern int QueryContextAttributesW( + ref SSPIHandle contextHandle, + [In] ContextAttribute attribute, + [In] void* buffer); + + [DllImport(Interop.Libraries.Secur32, ExactSpelling = true, SetLastError = true)] + internal unsafe static extern int SetContextAttributesW( + ref SSPIHandle contextHandle, + [In] ContextAttribute attribute, + [In] byte[] buffer, + [In] int bufferSize); + + [DllImport(Interop.Libraries.Secur32, ExactSpelling = true, SetLastError = true)] + internal static extern int EnumerateSecurityPackagesW( + [Out] out int pkgnum, + [Out] out SafeFreeContextBuffer_SECURITY handle); + + [DllImport(Interop.Libraries.Secur32, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] + internal unsafe static extern int AcquireCredentialsHandleW( + [In] string principal, + [In] string moduleName, + [In] int usage, + [In] void* logonID, + [In] ref AuthIdentity authdata, + [In] void* keyCallback, + [In] void* keyArgument, + ref SSPIHandle handlePtr, + [Out] out long timeStamp + ); + + [DllImport(Interop.Libraries.Secur32, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] + internal unsafe static extern int AcquireCredentialsHandleW( + [In] string principal, + [In] string moduleName, + [In] int usage, + [In] void* logonID, + [In] IntPtr zero, + [In] void* keyCallback, + [In] void* keyArgument, + ref SSPIHandle handlePtr, + [Out] out long timeStamp + ); + + [DllImport(Interop.Libraries.Secur32, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] + internal unsafe static extern int AcquireCredentialsHandleW( + [In] string principal, + [In] string moduleName, + [In] int usage, + [In] void* logonID, + [In] SafeSspiAuthDataHandle authdata, + [In] void* keyCallback, + [In] void* keyArgument, + ref SSPIHandle handlePtr, + [Out] out long timeStamp + ); + + [DllImport(Interop.Libraries.Secur32, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] + internal unsafe static extern int AcquireCredentialsHandleW( + [In] string principal, + [In] string moduleName, + [In] int usage, + [In] void* logonID, + [In] ref SecureCredential authData, + [In] void* keyCallback, + [In] void* keyArgument, + ref SSPIHandle handlePtr, + [Out] out long timeStamp + ); + + [DllImport(Interop.Libraries.Secur32, ExactSpelling = true, SetLastError = true)] + internal unsafe static extern int InitializeSecurityContextW( + ref SSPIHandle credentialHandle, + [In] void* inContextPtr, + [In] byte* targetName, + [In] ContextFlags inFlags, + [In] int reservedI, + [In] Endianness endianness, + [In] SecurityBufferDescriptor inputBuffer, + [In] int reservedII, + ref SSPIHandle outContextPtr, + [In, Out] SecurityBufferDescriptor outputBuffer, + [In, Out] ref ContextFlags attributes, + out long timeStamp + ); + + [DllImport(Interop.Libraries.Secur32, ExactSpelling = true, SetLastError = true)] + internal unsafe static extern int CompleteAuthToken( + [In] void* inContextPtr, + [In, Out] SecurityBufferDescriptor inputBuffers + ); + + [DllImport(Interop.Libraries.Secur32, ExactSpelling = true, SetLastError = true)] + internal unsafe static extern SecurityStatus SspiFreeAuthIdentity( + [In] IntPtr authData); + } +} diff --git a/src/Common/src/Microsoft/Win32/SafeHandles/CriticalHandleMinusOneIsInvalid.cs b/src/Common/src/Microsoft/Win32/SafeHandles/CriticalHandleMinusOneIsInvalid.cs new file mode 100644 index 000000000000..bd7cdb726f17 --- /dev/null +++ b/src/Common/src/Microsoft/Win32/SafeHandles/CriticalHandleMinusOneIsInvalid.cs @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Runtime.InteropServices; + +namespace Microsoft.Win32.SafeHandles +{ + // Issue 2499: Replace ad-hoc definitions of SafeHandleZeroOrMinusOneIsInvalid with a single definition + // + // Other definitions of this type should be removed in favor of this definition. + internal abstract class CriticalHandleMinusOneIsInvalid : CriticalHandle + { + protected CriticalHandleMinusOneIsInvalid() : base(new IntPtr(-1)) + { + } + + public override bool IsInvalid + { + get { return handle == new IntPtr(-1); } + } + } +} diff --git a/src/Common/src/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs b/src/Common/src/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs new file mode 100644 index 000000000000..b77316bd8fd3 --- /dev/null +++ b/src/Common/src/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Runtime.InteropServices; + +namespace Microsoft.Win32.SafeHandles +{ + // Issue 2499: Replace ad-hoc definitions of SafeHandleZeroOrMinusOneIsInvalid with a single definition + // + // Other definitions of this type should be removed in favor of this definition. + internal abstract class CriticalHandleZeroOrMinusOneIsInvalid : CriticalHandle + { + protected CriticalHandleZeroOrMinusOneIsInvalid() : base(IntPtr.Zero) + { + } + + public override bool IsInvalid + { + get { return handle == new IntPtr(0) || handle == new IntPtr(-1); } + } + } +} diff --git a/src/Common/src/System/IO/StreamAsyncHelper.cs b/src/Common/src/System/IO/StreamAsyncHelper.cs new file mode 100644 index 000000000000..d42bd2573c86 --- /dev/null +++ b/src/Common/src/System/IO/StreamAsyncHelper.cs @@ -0,0 +1,208 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; +using System.Diagnostics.Contracts; +using System.Threading; +using System.Threading.Tasks; + +namespace System.IO +{ + /// Provides support for implementing asynchronous operations on Streams. + internal sealed class StreamAsyncHelper + { + private SemaphoreSlim _asyncActiveSemaphore; + private Task _activeReadWriteTask; + private readonly Stream _stream; + + internal StreamAsyncHelper(Stream stream) + { + Debug.Assert(stream != null); + _stream = stream; + } + + private SemaphoreSlim EnsureAsyncActiveSemaphoreInitialized() + { + // Lazily-initialize _asyncActiveSemaphore. As we're never accessing the SemaphoreSlim's + // WaitHandle, we don't need to worry about Disposing it. + return LazyInitializer.EnsureInitialized(ref _asyncActiveSemaphore, () => new SemaphoreSlim(1, 1)); + } + + internal IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) + { + if (!_stream.CanRead) + { + throw __Error.GetReadNotSupported(); + } + + return BeginReadWrite(true, buffer, offset, count, callback, state); + } + + internal IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, Object state) + { + if (!_stream.CanWrite) + { + throw __Error.GetWriteNotSupported(); + } + + return BeginReadWrite(false, buffer, offset, count, callback, state); + } + + private IAsyncResult BeginReadWrite(bool isRead, byte[] buffer, int offset, int count, AsyncCallback callback, object state) + { + // To avoid a race with a stream's position pointer & generating race + // conditions with internal buffer indexes in our own streams that + // don't natively support async IO operations when there are multiple + // async requests outstanding, we block the calling thread until + // the active one completes. + SemaphoreSlim sem = EnsureAsyncActiveSemaphoreInitialized(); + sem.Wait(); + Debug.Assert(_activeReadWriteTask == null); + + // Create the task to asynchronously run the read or write. Even though Task implements IAsyncResult, + // we wrap it in a special IAsyncResult object that stores all of the state for the operation + // and that we can pass around as a state parameter to all of our delegates. Even though this + // is an allocation, this allows us to avoid any closures or non-statically cached delegates + // for both the Task and its continuation, saving more allocations. + var asyncResult = new StreamReadWriteAsyncResult(_stream, buffer, offset, count, callback, state); + Task t; + if (isRead) + { + t = new Task(obj => + { + var ar = (StreamReadWriteAsyncResult)obj; + return ar._stream.Read(ar._buffer, ar._offset, ar._count); + }, asyncResult, CancellationToken.None, TaskCreationOptions.DenyChildAttach); + } + else + { + t = new Task(obj => + { + var ar = (StreamReadWriteAsyncResult)obj; + ar._stream.Write(ar._buffer, ar._offset, ar._count); + }, asyncResult, CancellationToken.None, TaskCreationOptions.DenyChildAttach); + } + + asyncResult._task = t; // this doesn't happen in the async result's ctor because the Task needs to reference the AR, and vice versa + + if (callback != null) + { + t.ContinueWith((_, obj) => + { + var ar = (StreamReadWriteAsyncResult)obj; + ar._callback(ar); + }, asyncResult, CancellationToken.None, TaskContinuationOptions.DenyChildAttach | TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); + } + + _activeReadWriteTask = t; + t.Start(TaskScheduler.Default); + + return asyncResult; + } + + internal int EndRead(IAsyncResult asyncResult) + { + if (asyncResult == null) + { + throw new ArgumentNullException("asyncResult"); + } + + Contract.Ensures(Contract.Result() >= 0); + Contract.EndContractBlock(); + + var ar = asyncResult as StreamReadWriteAsyncResult; + var task = _activeReadWriteTask; + + if (task == null || ar == null) + { + throw new ArgumentException(SR.InvalidOperation_WrongAsyncResultOrEndReadCalledMultiple); + } + else if (task != ar._task) + { + throw new InvalidOperationException(SR.InvalidOperation_WrongAsyncResultOrEndReadCalledMultiple); + } + + Task readTask = task as Task; + if (readTask == null) + { + throw new ArgumentException(SR.InvalidOperation_WrongAsyncResultOrEndReadCalledMultiple); + } + + try + { + return readTask.GetAwaiter().GetResult(); // block until completion, then get result / propagate any exception + } + finally + { + _activeReadWriteTask = null; + Debug.Assert(_asyncActiveSemaphore != null, "Must have been initialized in order to get here."); + _asyncActiveSemaphore.Release(); + } + } + + internal void EndWrite(IAsyncResult asyncResult) + { + if (asyncResult == null) + { + throw new ArgumentNullException("asyncResult"); + } + + Contract.EndContractBlock(); + + var ar = asyncResult as StreamReadWriteAsyncResult; + var writeTask = _activeReadWriteTask; + + if (writeTask == null || ar == null) + { + throw new ArgumentException(SR.InvalidOperation_WrongAsyncResultOrEndWriteCalledMultiple); + } + else if (writeTask != ar._task) + { + throw new InvalidOperationException(SR.InvalidOperation_WrongAsyncResultOrEndWriteCalledMultiple); + } + else if (writeTask is Task) + { + throw new ArgumentException(SR.InvalidOperation_WrongAsyncResultOrEndWriteCalledMultiple); + } + + try + { + writeTask.GetAwaiter().GetResult(); // block until completion, then propagate any exceptions + } + finally + { + _activeReadWriteTask = null; + Debug.Assert(_asyncActiveSemaphore != null, "Must have been initialized in order to get here."); + _asyncActiveSemaphore.Release(); + } + } + + private sealed class StreamReadWriteAsyncResult : IAsyncResult + { + internal readonly Stream _stream; + internal readonly byte[] _buffer; + internal readonly int _offset; + internal readonly int _count; + internal readonly AsyncCallback _callback; + internal readonly object _state; + + internal Task _task; + + internal StreamReadWriteAsyncResult(Stream stream, byte[] buffer, int offset, int count, AsyncCallback callback, object state) + { + _stream = stream; + _buffer = buffer; + _offset = offset; + _count = count; + _callback = callback; + _state = state; + } + + object IAsyncResult.AsyncState { get { return _state; } } // return caller-provided state, not that from the task + bool IAsyncResult.CompletedSynchronously { get { return false; } } // we always complete asynchronously + + bool IAsyncResult.IsCompleted { get { return _task.IsCompleted; } } + WaitHandle IAsyncResult.AsyncWaitHandle { get { return ((IAsyncResult)_task).AsyncWaitHandle; } } + } + } +} \ No newline at end of file diff --git a/src/Common/src/System/Net/DebugCriticalHandleMinusOneIsInvalid.cs b/src/Common/src/System/Net/DebugCriticalHandleMinusOneIsInvalid.cs new file mode 100644 index 000000000000..e111ae23fda6 --- /dev/null +++ b/src/Common/src/System/Net/DebugCriticalHandleMinusOneIsInvalid.cs @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Win32.SafeHandles; + +using System.Diagnostics.CodeAnalysis; +using System.Net.NetworkInformation; +using System.Net.Sockets; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Threading; + +namespace System.Net +{ +#if DEBUG + // + // This is a helper class for debugging GC-ed handles that we define. + // As a general rule normal code path should always destroy handles explicitly + // + internal abstract class DebugCriticalHandleMinusOneIsInvalid : CriticalHandleMinusOneIsInvalid + { + private string _trace; + + protected DebugCriticalHandleMinusOneIsInvalid() : base() + { + Trace(); + } + + private void Trace() + { + _trace = "WARNING! GC-ed >>" + this.GetType().FullName + "<< (should be excplicitly closed) \r\n"; + GlobalLog.Print("Creating SafeHandle, type = " + this.GetType().FullName); +#if TRACE_VERBOSE + string stacktrace = Environment.StackTrace; + _trace += stacktrace; +#endif //TRACE_VERBOSE + } + + ~DebugCriticalHandleMinusOneIsInvalid() + { + GlobalLog.SetThreadSource(ThreadKinds.Finalization); + GlobalLog.Print(_trace); + } + } +#endif // DEBUG +} diff --git a/src/Common/src/System/Net/DebugCriticalHandleZeroOrMinusOneIsInvalid.cs b/src/Common/src/System/Net/DebugCriticalHandleZeroOrMinusOneIsInvalid.cs new file mode 100644 index 000000000000..378a3cb5f98b --- /dev/null +++ b/src/Common/src/System/Net/DebugCriticalHandleZeroOrMinusOneIsInvalid.cs @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Win32.SafeHandles; + +using System.Diagnostics.CodeAnalysis; +using System.Net.NetworkInformation; +using System.Net.Sockets; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Threading; + +namespace System.Net +{ +#if DEBUG + // + // This is a helper class for debugging GC-ed handles that we define. + // As a general rule normal code path should always destroy handles explicitly + // + internal abstract class DebugCriticalHandleZeroOrMinusOneIsInvalid : CriticalHandleZeroOrMinusOneIsInvalid + { + private string _trace; + + protected DebugCriticalHandleZeroOrMinusOneIsInvalid() : base() + { + Trace(); + } + + private void Trace() + { + _trace = "WARNING! GC-ed >>" + this.GetType().FullName + "<< (should be excplicitly closed) \r\n"; + GlobalLog.Print("Creating SafeHandle, type = " + this.GetType().FullName); +#if TRACE_VERBOSE + string stacktrace = Environment.StackTrace; + _trace += stacktrace; +#endif //TRACE_VERBOSE + } + + ~DebugCriticalHandleZeroOrMinusOneIsInvalid() + { + GlobalLog.SetThreadSource(ThreadKinds.Finalization); + GlobalLog.Print(_trace); + } + } +#endif // DEBUG +} diff --git a/src/Common/src/System/Net/DebugSafeHandle.cs b/src/Common/src/System/Net/DebugSafeHandle.cs index dcf0cc4b12d7..c1965de7ed8a 100644 --- a/src/Common/src/System/Net/DebugSafeHandle.cs +++ b/src/Common/src/System/Net/DebugSafeHandle.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Microsoft.Win32.SafeHandles; + using System.Diagnostics.CodeAnalysis; using System.Net.NetworkInformation; using System.Net.Sockets; @@ -34,7 +35,7 @@ protected DebugSafeHandle(IntPtr invalidValue, bool ownsHandle) : base(ownsHandl private void Trace() { _trace = "WARNING! GC-ed >>" + this.GetType().FullName + "<< (should be excplicitly closed) \r\n"; -#if TRAVE +#if TRACE_VERBOSE string stacktrace = Environment.StackTrace; _trace += stacktrace; #endif diff --git a/src/Common/src/System/Net/ExceptionCheck.cs b/src/Common/src/System/Net/ExceptionCheck.cs new file mode 100644 index 000000000000..7716ed196c76 --- /dev/null +++ b/src/Common/src/System/Net/ExceptionCheck.cs @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Net +{ + internal static class ExceptionCheck + { + internal static bool IsFatal(Exception exception) + { + return exception != null && (exception is OutOfMemoryException); + } + } +} diff --git a/src/Common/src/System/Net/Logging/GlobalLog.cs b/src/Common/src/System/Net/Logging/GlobalLog.cs index 95fd6433230d..b6d98bcc0d7c 100644 --- a/src/Common/src/System/Net/Logging/GlobalLog.cs +++ b/src/Common/src/System/Net/Logging/GlobalLog.cs @@ -21,6 +21,7 @@ private static Stack ThreadKindStack { t_ThreadKindStack = new Stack(); } + return t_ThreadKindStack; } } @@ -239,21 +240,25 @@ public static void Dump(byte[] buffer, int offset, int length) EventSourceLogging.Log.WarningDumpArray("buffer is null"); return; } + if (offset >= buffer.Length) { EventSourceLogging.Log.WarningDumpArray("offset out of range"); return; } + if ((length < 0) || (length > buffer.Length - offset)) { EventSourceLogging.Log.WarningDumpArray("length out of range"); return; } + var bufferSegment = new byte[length]; for (int i = 0; i < length; i++) { bufferSegment[i] = buffer[offset + i]; } + EventSourceLogging.Log.DebugDumpArray(bufferSegment); } } diff --git a/src/Common/src/System/Net/Logging/Logging.cs b/src/Common/src/System/Net/Logging/Logging.cs index c6421261b9c5..740fcfd31136 100644 --- a/src/Common/src/System/Net/Logging/Logging.cs +++ b/src/Common/src/System/Net/Logging/Logging.cs @@ -52,6 +52,7 @@ private static object InternalSyncObject object o = new Object(); Interlocked.CompareExchange(ref s_InternalSyncObject, o, null); } + return s_InternalSyncObject; } } @@ -64,6 +65,7 @@ internal static bool On { InitializeLogging(); } + return s_LoggingEnabled; } } @@ -81,10 +83,12 @@ internal static TraceSource Web { InitializeLogging(); } + if (!s_LoggingEnabled) { return null; } + return s_WebTraceSource; } } @@ -97,10 +101,12 @@ internal static TraceSource Http { InitializeLogging(); } + if (!s_LoggingEnabled) { return null; } + return s_TraceSourceHttpName; } } @@ -113,10 +119,12 @@ internal static TraceSource HttpListener { InitializeLogging(); } + if (!s_LoggingEnabled) { return null; } + return s_HttpListenerTraceSource; } } @@ -129,10 +137,12 @@ internal static TraceSource Sockets { InitializeLogging(); } + if (!s_LoggingEnabled) { return null; } + return s_SocketsTraceSource; } } @@ -145,10 +155,12 @@ internal static TraceSource RequestCache { InitializeLogging(); } + if (!s_LoggingEnabled) { return null; } + return s_CacheTraceSource; } } @@ -161,10 +173,12 @@ internal static TraceSource WebSockets { InitializeLogging(); } + if (!s_LoggingEnabled) { return null; } + return s_WebSocketsTraceSource; } } @@ -212,6 +226,7 @@ private static void InitializeLogging() Close(); loggingEnabled = false; } + s_LoggingEnabled = loggingEnabled; s_LoggingInitialized = true; } @@ -224,22 +239,27 @@ private static void Close() { s_WebTraceSource.Close(); } + if (s_HttpListenerTraceSource != null) { s_HttpListenerTraceSource.Close(); } + if (s_SocketsTraceSource != null) { s_SocketsTraceSource.Close(); } + if (s_WebSocketsTraceSource != null) { s_WebSocketsTraceSource.Close(); } + if (s_CacheTraceSource != null) { s_CacheTraceSource.Close(); } + if (s_TraceSourceHttpName != null) { s_TraceSourceHttpName.Close(); @@ -253,14 +273,17 @@ private static bool ValidateSettings(TraceSource traceSource, TraceEventType tra { return false; } + if (!s_LoggingInitialized) { InitializeLogging(); } + if (traceSource == null || !traceSource.Switch.ShouldTrace(traceLevel)) { return false; } + return true; } @@ -304,6 +327,7 @@ internal static void Enter(TraceSource traceSource, object obj, string method, s { return; } + Enter(traceSource, GetObjectName(obj) + "#" + Logging.HashString(obj), method, param); } @@ -313,6 +337,7 @@ internal static void Enter(TraceSource traceSource, object obj, string method, o { return; } + Enter(traceSource, GetObjectName(obj) + "#" + Logging.HashString(obj), method, paramObject); } @@ -322,6 +347,7 @@ internal static void Enter(TraceSource traceSource, string obj, string method, s { return; } + Enter(traceSource, obj + "::" + method + "(" + param + ")"); } @@ -331,11 +357,13 @@ internal static void Enter(TraceSource traceSource, string obj, string method, o { return; } + string paramObjectValue = ""; if (paramObject != null) { paramObjectValue = GetObjectName(paramObject) + "#" + Logging.HashString(paramObject); } + Enter(traceSource, obj + "::" + method + "(" + paramObjectValue + ")"); } @@ -345,6 +373,7 @@ internal static void Enter(TraceSource traceSource, string method, string parame { return; } + Enter(traceSource, method + "(" + parameters + ")"); } @@ -364,11 +393,13 @@ internal static void Exit(TraceSource traceSource, object obj, string method, ob { return; } + string retValue = ""; if (retObject != null) { retValue = GetObjectName(retObject) + "#" + Logging.HashString(retObject); } + Exit(traceSource, obj, method, retValue); } @@ -378,11 +409,13 @@ internal static void Exit(TraceSource traceSource, string obj, string method, ob { return; } + string retValue = ""; if (retObject != null) { retValue = GetObjectName(retObject) + "#" + Logging.HashString(retObject); } + Exit(traceSource, obj, method, retValue); } @@ -392,6 +425,7 @@ internal static void Exit(TraceSource traceSource, object obj, string method, st { return; } + Exit(traceSource, GetObjectName(obj) + "#" + Logging.HashString(obj), method, retValue); } @@ -401,10 +435,12 @@ internal static void Exit(TraceSource traceSource, string obj, string method, st { return; } + if (!string.IsNullOrEmpty(retValue)) { retValue = "\t-> " + retValue; } + Exit(traceSource, obj + "::" + method + "() " + retValue); } @@ -414,6 +450,7 @@ internal static void Exit(TraceSource traceSource, string method, string paramet { return; } + Exit(traceSource, method + "() " + parameters); } @@ -423,6 +460,7 @@ internal static void Exit(TraceSource traceSource, string msg) { return; } + PrintLine(traceSource, TraceEventType.Verbose, 0, "Exiting " + msg); // Trace.CorrelationManager.StopLogicalOperation(); } @@ -439,6 +477,7 @@ internal static void Exception(TraceSource traceSource, object obj, string metho { infoLine += Environment.NewLine + e.StackTrace; } + PrintLine(traceSource, TraceEventType.Error, 0, infoLine); } @@ -448,6 +487,7 @@ internal static void PrintInfo(TraceSource traceSource, string msg) { return; } + PrintLine(traceSource, TraceEventType.Information, 0, msg); } @@ -457,6 +497,7 @@ internal static void PrintInfo(TraceSource traceSource, object obj, string msg) { return; } + PrintLine(traceSource, TraceEventType.Information, 0, GetObjectName(obj) + "#" + Logging.HashString(obj) + " - " + msg); @@ -468,6 +509,7 @@ internal static void PrintInfo(TraceSource traceSource, object obj, string metho { return; } + PrintLine(traceSource, TraceEventType.Information, 0, GetObjectName(obj) + "#" + Logging.HashString(obj) + "::" + method + "(" + param + ")"); @@ -479,6 +521,7 @@ internal static void PrintWarning(TraceSource traceSource, string msg) { return; } + PrintLine(traceSource, TraceEventType.Warning, 0, msg); } @@ -488,6 +531,7 @@ internal static void PrintWarning(TraceSource traceSource, object obj, string me { return; } + PrintLine(traceSource, TraceEventType.Warning, 0, GetObjectName(obj) + "#" + Logging.HashString(obj) + "::" + method + "() - " + msg); @@ -499,6 +543,7 @@ internal static void PrintError(TraceSource traceSource, string msg) { return; } + PrintLine(traceSource, TraceEventType.Error, 0, msg); } @@ -508,6 +553,7 @@ internal static void PrintError(TraceSource traceSource, object obj, string meth { return; } + PrintLine(traceSource, TraceEventType.Error, 0, GetObjectName(obj) + "#" + Logging.HashString(obj) + "::" + method + "() - " + msg); @@ -524,6 +570,7 @@ internal static void Dump(TraceSource traceSource, object obj, string method, In { return; } + byte[] buffer = new byte[length]; Marshal.Copy(bufferPtr, buffer, 0, length); Dump(traceSource, obj, method, buffer, 0, length); @@ -535,16 +582,19 @@ internal static void Dump(TraceSource traceSource, object obj, string method, by { return; } + if (buffer == null) { PrintLine(traceSource, TraceEventType.Verbose, 0, "(null)"); return; } + if (offset > buffer.Length) { PrintLine(traceSource, TraceEventType.Verbose, 0, "(offset out of range)"); return; } + PrintLine(traceSource, TraceEventType.Verbose, 0, "Data from " + GetObjectName(obj) + "#" + Logging.HashString(obj) + "::" + method); int maxDumpSize = GetMaxDumpSizeSetting(traceSource); if (length > maxDumpSize) @@ -552,10 +602,12 @@ internal static void Dump(TraceSource traceSource, object obj, string method, by PrintLine(traceSource, TraceEventType.Verbose, 0, "(printing " + maxDumpSize.ToString(NumberFormatInfo.InvariantInfo) + " out of " + length.ToString(NumberFormatInfo.InvariantInfo) + ")"); length = maxDumpSize; } + if ((length < 0) || (length > buffer.Length - offset)) { length = buffer.Length - offset; } + do { int n = Math.Min(length, 16); @@ -564,10 +616,12 @@ internal static void Dump(TraceSource traceSource, object obj, string method, by { disp += string.Format(CultureInfo.CurrentCulture, "{0:X2}", buffer[offset + i]) + ((i == 7) ? '-' : ' '); } + for (int i = n; i < 16; ++i) { disp += " "; } + disp += ": "; for (int i = 0; i < n; ++i) { @@ -575,6 +629,7 @@ internal static void Dump(TraceSource traceSource, object obj, string method, by ? '.' : (char)(buffer[offset + i]); } + PrintLine(traceSource, TraceEventType.Verbose, 0, disp); offset += n; length -= n; @@ -626,10 +681,12 @@ private static string ExceptionMessage(Exception exception) { return string.Empty; } + if (exception.InnerException == null) { return exception.Message; } + return exception.Message + " (" + ExceptionMessage(exception.InnerException) + ")"; } diff --git a/src/Common/src/System/Net/Shims/ExecutionContext.cs b/src/Common/src/System/Net/Shims/ExecutionContext.cs index 9da4e6e3aa6e..e6b567bb55ff 100644 --- a/src/Common/src/System/Net/Shims/ExecutionContext.cs +++ b/src/Common/src/System/Net/Shims/ExecutionContext.cs @@ -38,6 +38,7 @@ public static void RestoreFlow() { throw new InvalidOperationException(); } + s_threadEc.Value._isFlowSuppressed = false; } diff --git a/src/Common/src/System/Net/_BufferOffsetSize.cs b/src/Common/src/System/Net/_BufferOffsetSize.cs new file mode 100644 index 000000000000..adb78004f63f --- /dev/null +++ b/src/Common/src/System/Net/_BufferOffsetSize.cs @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Net +{ + // + // This class is used by the BeginMultipleSend() API + // to allow a user to send multiple buffers on a socket. + // + internal class BufferOffsetSize + { + internal byte[] Buffer; + internal int Offset; + internal int Size; + + internal BufferOffsetSize(byte[] buffer, int offset, int size, bool copyBuffer) + { + GlobalLog.Assert(buffer != null && buffer.Length >= size + offset, "BufferOffsetSize::.ctor|Illegal parameters."); + if (copyBuffer) + { + byte[] newBuffer = new byte[size]; + + System.Buffer.BlockCopy( + buffer, // src + offset, // src index + newBuffer, // dest + 0, // dest index + size); // total size to copy + + offset = 0; + buffer = newBuffer; + } + Buffer = buffer; + Offset = offset; + Size = size; + GlobalLog.Print("BufferOffsetSize#" + Logging.HashString(this) + "::.ctor() copyBuffer:" + copyBuffer.ToString() + " this:[" + ToString() + "]"); + } + + internal BufferOffsetSize(byte[] buffer, bool copyBuffer) + : this(buffer, 0, buffer.Length, copyBuffer) + { + } +#if TRACE_VERBOSE + public override string ToString() + { + return "BufferOffsetSize#" + Logging.HashString(this) + " Buffer#" + Logging.HashString(Buffer) + " Offset:" + Offset.ToString() + " Size:" + Size.ToString(); + } +#endif + + } // class BufferOffsetSize +} // namespace System.Net diff --git a/src/Common/src/System/Net/_ContextAwareResult.cs b/src/Common/src/System/Net/_ContextAwareResult.cs index 74092be003c5..64d3828a40ef 100644 --- a/src/Common/src/System/Net/_ContextAwareResult.cs +++ b/src/Common/src/System/Net/_ContextAwareResult.cs @@ -38,12 +38,16 @@ internal CallbackClosure(ExecutionContext context, AsyncCallback callback) internal bool IsCompatible(AsyncCallback callback) { if (callback == null || _savedCallback == null) + { return false; + } // Delegates handle this ok. AsyncCallback is sealed and immutable, so if this succeeds, we are safe to use // the passed-in instance. if (!object.Equals(_savedCallback, callback)) + { return false; + } return true; } @@ -253,6 +257,7 @@ internal bool FinishPostingAsyncOp() { return false; } + _Flags |= StateFlags.PostBlockFinished; ExecutionContext cachedContext = null; @@ -270,6 +275,7 @@ internal bool FinishPostingAsyncOp(ref CallbackClosure closure) { return false; } + _Flags |= StateFlags.PostBlockFinished; // Need a copy of this ref argument since it can be used in many of these calls simultaneously. @@ -351,6 +357,7 @@ private bool CaptureOrComplete(ref ExecutionContext cachedContext, bool returnCo { cachedContext = ExecutionContext.Capture(); } + if (cachedContext != null) { if (!returnContext) diff --git a/src/Common/src/System/Net/_LazyAsyncResult.cs b/src/Common/src/System/Net/_LazyAsyncResult.cs index ea5ec65e3612..d6f1291a20fe 100644 --- a/src/Common/src/System/Net/_LazyAsyncResult.cs +++ b/src/Common/src/System/Net/_LazyAsyncResult.cs @@ -12,8 +12,8 @@ namespace System.Net // that want to take advantage of lazy allocated event handles. internal class LazyAsyncResult : IAsyncResult { - private const int c_HighBit = unchecked((int)0x80000000); - private const int c_ForceAsyncCount = 50; + private const int HighBit = unchecked((int)0x80000000); + private const int ForceAsyncCount = 50; // This is to avoid user mistakes when they queue another async op from a callback the completes sync. [ThreadStatic] @@ -29,13 +29,14 @@ private static ThreadContext CurrentThreadContext threadContext = new ThreadContext(); s_ThreadContext = threadContext; } + return threadContext; } } private class ThreadContext { - internal int m_NestedIOCount; + internal int _nestedIOCount; } #if DEBUG @@ -150,11 +151,11 @@ public WaitHandle AsyncWaitHandle // The user has access to this object. Lock-in CompletedSynchronously. if (_intCompleted == 0) { - Interlocked.CompareExchange(ref _intCompleted, c_HighBit, 0); + Interlocked.CompareExchange(ref _intCompleted, HighBit, 0); } // Because InternalWaitForCompletion() tries to dispose this event, it's - // possible for m_Event to become null immediately after being set, but only if + // possible for _event to become null immediately after being set, but only if // IsCompleted has become true. Therefore it's possible for this property // to give different (set) events to different callers when IsCompleted is true. asyncEvent = (ManualResetEvent)_event; @@ -163,7 +164,7 @@ public WaitHandle AsyncWaitHandle LazilyCreateEvent(out asyncEvent); } - GlobalLog.Print("LazyAsyncResult#" + Logging.HashString(this) + "::get_AsyncWaitHandle() m_Event:" + Logging.HashString(_event)); + GlobalLog.Print("LazyAsyncResult#" + Logging.HashString(this) + "::get_AsyncWaitHandle() _event:" + Logging.HashString(_event)); return asyncEvent; } } @@ -187,7 +188,7 @@ private bool LazilyCreateEvent(out ManualResetEvent waitHandle) { waitHandle.Dispose(); waitHandle = (ManualResetEvent)_event; - // There's a chance here that m_Event became null. But the only way is if another thread completed + // There's a chance here that _event became null. But the only way is if another thread completed // in InternalWaitForCompletion and disposed it. If we're in InternalWaitForCompletion, we now know // IsCompleted is set, so we can avoid the wait when waitHandle comes back null. AsyncWaitHandle // will try again in this case. @@ -199,7 +200,10 @@ private bool LazilyCreateEvent(out ManualResetEvent waitHandle) // This should be very rare, but doing this will reduce the chance of deadlock. _event = null; if (waitHandle != null) + { waitHandle.Dispose(); + } + throw; } } @@ -232,8 +236,9 @@ public bool CompletedSynchronously int result = _intCompleted; if (result == 0) { - result = Interlocked.CompareExchange(ref _intCompleted, c_HighBit, 0); + result = Interlocked.CompareExchange(ref _intCompleted, HighBit, 0); } + GlobalLog.Print("LazyAsyncResult#" + Logging.HashString(this) + "::get_CompletedSynchronously() returns: " + ((result > 0) ? "true" : "false")); return result > 0; } @@ -259,9 +264,10 @@ public bool IsCompleted int result = _intCompleted; if (result == 0) { - result = Interlocked.CompareExchange(ref _intCompleted, c_HighBit, 0); + result = Interlocked.CompareExchange(ref _intCompleted, HighBit, 0); } - return (result & ~c_HighBit) != 0; + + return (result & ~HighBit) != 0; } } @@ -270,7 +276,7 @@ internal bool InternalPeekCompleted { get { - return (_intCompleted & ~c_HighBit) != 0; + return (_intCompleted & ~HighBit) != 0; } } @@ -342,12 +348,14 @@ protected void ProtectedInvokeCallback(object result, IntPtr userToken) _ProtectState = false; #endif - if ((_intCompleted & ~c_HighBit) == 0 && (Interlocked.Increment(ref _intCompleted) & ~c_HighBit) == 1) + if ((_intCompleted & ~HighBit) == 0 && (Interlocked.Increment(ref _intCompleted) & ~HighBit) == 1) { // DBNull.Value is used to guarantee that the first caller wins, // even if the result was set to null. if (_result == DBNull.Value) + { _result = result; + } ManualResetEvent asyncEvent = (ManualResetEvent)_event; if (asyncEvent != null) @@ -390,17 +398,17 @@ protected virtual void Complete(IntPtr userToken) ThreadContext threadContext = CurrentThreadContext; try { - ++threadContext.m_NestedIOCount; + ++threadContext._nestedIOCount; if (_asyncCallback != null) { GlobalLog.Print("LazyAsyncResult#" + Logging.HashString(this) + "::Complete() invoking callback"); - if (threadContext.m_NestedIOCount >= c_ForceAsyncCount) + if (threadContext._nestedIOCount >= ForceAsyncCount) { GlobalLog.Print("LazyAsyncResult::Complete *** OFFLOADED the user callback ***"); Task.Factory.StartNew( - s => WorkerThreadComplete(s), - null, + s => WorkerThreadComplete(s), + this, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); @@ -419,9 +427,9 @@ protected virtual void Complete(IntPtr userToken) } finally { - --threadContext.m_NestedIOCount; + --threadContext._nestedIOCount; - // Never call this method unless interlocked m_IntCompleted check has succeeded (like in this case) + // Never call this method unless interlocked _intCompleted check has succeeded (like in this case) if (!offloaded) { Cleanup(); @@ -430,15 +438,18 @@ protected virtual void Complete(IntPtr userToken) } // Only called in the above method - private void WorkerThreadComplete(object state) + private static void WorkerThreadComplete(object state) { + Debug.Assert(state is LazyAsyncResult); + LazyAsyncResult thisPtr = (LazyAsyncResult)state; + try { - _asyncCallback(this); + thisPtr._asyncCallback(thisPtr); } finally { - Cleanup(); + thisPtr.Cleanup(); } } @@ -473,7 +484,7 @@ private object WaitForCompletion(bool snap) { try { - GlobalLog.Print("LazyAsyncResult#" + Logging.HashString(this) + "::InternalWaitForCompletion() Waiting for completion m_Event#" + Logging.HashString(waitHandle)); + GlobalLog.Print("LazyAsyncResult#" + Logging.HashString(this) + "::InternalWaitForCompletion() Waiting for completion _event#" + Logging.HashString(waitHandle)); waitHandle.WaitOne(Timeout.Infinite); } catch (ObjectDisposedException) @@ -486,7 +497,7 @@ private object WaitForCompletion(bool snap) // We also want to dispose the event although we can't unless we did wait on it here. if (createdByMe && !_userEvent) { - // Does m_UserEvent need to be volatile (or m_Event set via Interlocked) in order + // Does _userEvent need to be volatile (or _event set via Interlocked) in order // to avoid giving a user a disposed event? ManualResetEvent oldEvent = (ManualResetEvent)_event; _event = null; @@ -498,8 +509,8 @@ private object WaitForCompletion(bool snap) } } - // A race condition exists because InvokeCallback sets m_IntCompleted before m_Result (so that m_Result - // can benefit from the synchronization of m_IntCompleted). That means you can get here before m_Result got + // A race condition exists because InvokeCallback sets _intCompleted before _result (so that _result + // can benefit from the synchronization of _intCompleted). That means you can get here before _result got // set (although rarely - once every eight hours of stress). Handle that case with a spin-lock. SpinWait sw = new SpinWait(); @@ -518,7 +529,7 @@ private object WaitForCompletion(bool snap) // It completes the result but doesn't do any of the notifications. internal void InternalCleanup() { - if ((_intCompleted & ~c_HighBit) == 0 && (Interlocked.Increment(ref _intCompleted) & ~c_HighBit) == 1) + if ((_intCompleted & ~HighBit) == 0 && (Interlocked.Increment(ref _intCompleted) & ~HighBit) == 1) { // Set no result so that just in case there are waiters, they don't hang in the spin lock. _result = null; diff --git a/src/Common/src/System/SR.cs b/src/Common/src/System/SR.cs index e3500270f60b..8650a0975b88 100644 --- a/src/Common/src/System/SR.cs +++ b/src/Common/src/System/SR.cs @@ -18,6 +18,7 @@ private static ResourceManager ResourceManager { SR.s_resourceManager = new ResourceManager(SR.ResourceType); } + return SR.s_resourceManager; } } @@ -85,6 +86,7 @@ internal static string Format(string resourceFormat, object p1, object p2, objec { return String.Join(", ", resourceFormat, p1, p2, p3); } + return String.Format(resourceFormat, p1, p2, p3); } } diff --git a/src/Common/tests/System.Net/EventSourceTestLogging.cs b/src/Common/tests/System.Net/EventSourceTestLogging.cs new file mode 100644 index 000000000000..3c4395105cb9 --- /dev/null +++ b/src/Common/tests/System.Net/EventSourceTestLogging.cs @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics.Tracing; + +namespace System.Net.Test.Common +{ + [EventSource(Name = "Microsoft-System-Net-TestLogging")] + internal class EventSourceTestLogging : EventSource + { + private static EventSourceTestLogging s_log = new EventSourceTestLogging(); + private EventSourceTestLogging() { } + + public static EventSourceTestLogging Log + { + get + { + return s_log; + } + } + + [Event(1, Keywords = Keywords.Default, Level = EventLevel.Informational)] + public void TestMessage(string message) + { + WriteEvent(1, message); + } + + [Event(2, Keywords = Keywords.Debug, Level = EventLevel.Verbose)] + public void TestVerboseMessage(string message) + { + WriteEvent(2, message); + } + + public static class Keywords + { + public const EventKeywords Default = (EventKeywords)0x0001; + public const EventKeywords Debug = (EventKeywords)0x0002; + } + } +} diff --git a/src/Common/tests/System.Net/TaskAPMExtensions.cs b/src/Common/tests/System.Net/TaskAPMExtensions.cs new file mode 100644 index 000000000000..43448ab1531b --- /dev/null +++ b/src/Common/tests/System.Net/TaskAPMExtensions.cs @@ -0,0 +1,88 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/// +/// Task APM helper based on http://blogs.msdn.com/b/pfxteam/archive/2011/06/27/10179452.aspx +/// + +// TODO: #3144 - Remove this class and rewrite tests to work directly with TPL. + +namespace System.Threading.Tasks +{ + public static class TaskAPMExtensions + { + public static Task ToApm(this Task task, AsyncCallback callback, object state) + { + if (task.AsyncState == state) + { + if (callback != null) + { + task.ContinueWith(delegate { callback(task); }, + CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Default); + } + return task; + } + + var tcs = new TaskCompletionSource(state); + task.ContinueWith(delegate + { + if (task.IsFaulted) + { + tcs.TrySetException(task.Exception.InnerExceptions); + } + else if (task.IsCanceled) + { + tcs.TrySetCanceled(); + } + else + { + tcs.TrySetResult(false); + } + + if (callback != null) + { + callback(tcs.Task); + } + }, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Default); + return tcs.Task; + } + + public static Task ToApm(this Task task, AsyncCallback callback, object state) + { + if (task.AsyncState == state) + { + if (callback != null) + { + task.ContinueWith(delegate { callback(task); }, + CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Default); + } + + return task; + } + + var tcs = new TaskCompletionSource(state); + task.ContinueWith(delegate + { + if (task.IsFaulted) + { + tcs.TrySetException(task.Exception.InnerExceptions); + } + else if (task.IsCanceled) + { + tcs.TrySetCanceled(); + } + else + { + tcs.TrySetResult(task.Result); + } + + if (callback != null) + { + callback(tcs.Task); + } + }, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Default); + + return tcs.Task; + } + } +} diff --git a/src/Common/tests/System.Net/TestLogging.cs b/src/Common/tests/System.Net/TestLogging.cs new file mode 100644 index 000000000000..ae18ce4f4642 --- /dev/null +++ b/src/Common/tests/System.Net/TestLogging.cs @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics.Tracing; +using System.Text; +using Xunit.Abstractions; + +namespace System.Net.Test.Common +{ + public class TestLogging : ITestOutputHelper + { + private static TestLogging s_instance = new TestLogging(); + + private TestLogging() + { + } + + public static TestLogging GetInstance() + { + return s_instance; + } + + public void WriteLine(string message) + { + EventSourceTestLogging.Log.TestMessage(message); + } + + public void WriteLine(string format, params object[] args) + { + EventSourceTestLogging.Log.TestMessage(string.Format(format, args)); + } + } +} diff --git a/src/Common/tests/System.Net/VerboseTestLogging.cs b/src/Common/tests/System.Net/VerboseTestLogging.cs new file mode 100644 index 000000000000..9838873b8267 --- /dev/null +++ b/src/Common/tests/System.Net/VerboseTestLogging.cs @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics.Tracing; +using System.Text; +using Xunit.Abstractions; + +namespace System.Net.Test.Common +{ + public class VerboseTestLogging : ITestOutputHelper + { + private static VerboseTestLogging s_instance = new VerboseTestLogging(); + + private VerboseTestLogging() + { + } + + public static VerboseTestLogging GetInstance() + { + return s_instance; + } + + public void WriteLine(string message) + { + EventSourceTestLogging.Log.TestVerboseMessage(message); + } + + public void WriteLine(string format, params object[] args) + { + EventSourceTestLogging.Log.TestVerboseMessage(string.Format(format, args)); + } + } +} diff --git a/src/System.Net.Security/System.Net.Security.sln b/src/System.Net.Security/System.Net.Security.sln new file mode 100644 index 000000000000..5069dbf44f82 --- /dev/null +++ b/src/System.Net.Security/System.Net.Security.sln @@ -0,0 +1,104 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.23107.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{E923EB8F-73DA-436E-B2AE-CF46C13FFB35}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{0A911515-B709-40A3-A1E7-0A75F8739DC1}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{3AF6EFA9-4406-459F-B04C-02F7A5270D38}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Net.Security", "ref\System.Net.Security.csproj", "{6C5EF6EC-A9F6-4257-B7CB-C855E7A2671F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Net.Security", "src\System.Net.Security.csproj", "{89F37791-6254-4D60-AB96-ACD3CCA0E771}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "FunctionalTests", "FunctionalTests", "{8A72677F-6CD2-45DE-9A2F-BCD9124DB910}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Net.Security.Tests", "tests\FunctionalTests\System.Net.Security.Tests.csproj", "{A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + 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 + Release|Any CPU = Release|Any CPU + Windows_Debug|Any CPU = Windows_Debug|Any CPU + Windows_Release|Any CPU = Windows_Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6C5EF6EC-A9F6-4257-B7CB-C855E7A2671F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6C5EF6EC-A9F6-4257-B7CB-C855E7A2671F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6C5EF6EC-A9F6-4257-B7CB-C855E7A2671F}.FreeBSD_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6C5EF6EC-A9F6-4257-B7CB-C855E7A2671F}.FreeBSD_Debug|Any CPU.Build.0 = Debug|Any CPU + {6C5EF6EC-A9F6-4257-B7CB-C855E7A2671F}.FreeBSD_Release|Any CPU.ActiveCfg = Debug|Any CPU + {6C5EF6EC-A9F6-4257-B7CB-C855E7A2671F}.FreeBSD_Release|Any CPU.Build.0 = Debug|Any CPU + {6C5EF6EC-A9F6-4257-B7CB-C855E7A2671F}.Linux_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6C5EF6EC-A9F6-4257-B7CB-C855E7A2671F}.Linux_Debug|Any CPU.Build.0 = Debug|Any CPU + {6C5EF6EC-A9F6-4257-B7CB-C855E7A2671F}.Linux_Release|Any CPU.ActiveCfg = Debug|Any CPU + {6C5EF6EC-A9F6-4257-B7CB-C855E7A2671F}.Linux_Release|Any CPU.Build.0 = Debug|Any CPU + {6C5EF6EC-A9F6-4257-B7CB-C855E7A2671F}.OSX_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6C5EF6EC-A9F6-4257-B7CB-C855E7A2671F}.OSX_Debug|Any CPU.Build.0 = Debug|Any CPU + {6C5EF6EC-A9F6-4257-B7CB-C855E7A2671F}.OSX_Release|Any CPU.ActiveCfg = Debug|Any CPU + {6C5EF6EC-A9F6-4257-B7CB-C855E7A2671F}.OSX_Release|Any CPU.Build.0 = Debug|Any CPU + {6C5EF6EC-A9F6-4257-B7CB-C855E7A2671F}.Release|Any CPU.ActiveCfg = Debug|Any CPU + {6C5EF6EC-A9F6-4257-B7CB-C855E7A2671F}.Release|Any CPU.Build.0 = Debug|Any CPU + {6C5EF6EC-A9F6-4257-B7CB-C855E7A2671F}.Windows_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6C5EF6EC-A9F6-4257-B7CB-C855E7A2671F}.Windows_Debug|Any CPU.Build.0 = Debug|Any CPU + {6C5EF6EC-A9F6-4257-B7CB-C855E7A2671F}.Windows_Release|Any CPU.ActiveCfg = Debug|Any CPU + {6C5EF6EC-A9F6-4257-B7CB-C855E7A2671F}.Windows_Release|Any CPU.Build.0 = Debug|Any CPU + {89F37791-6254-4D60-AB96-ACD3CCA0E771}.Debug|Any CPU.ActiveCfg = Windows_Debug|Any CPU + {89F37791-6254-4D60-AB96-ACD3CCA0E771}.Debug|Any CPU.Build.0 = Windows_Debug|Any CPU + {89F37791-6254-4D60-AB96-ACD3CCA0E771}.FreeBSD_Debug|Any CPU.ActiveCfg = FreeBSD_Debug|Any CPU + {89F37791-6254-4D60-AB96-ACD3CCA0E771}.FreeBSD_Debug|Any CPU.Build.0 = FreeBSD_Debug|Any CPU + {89F37791-6254-4D60-AB96-ACD3CCA0E771}.FreeBSD_Release|Any CPU.ActiveCfg = FreeBSD_Release|Any CPU + {89F37791-6254-4D60-AB96-ACD3CCA0E771}.FreeBSD_Release|Any CPU.Build.0 = FreeBSD_Release|Any CPU + {89F37791-6254-4D60-AB96-ACD3CCA0E771}.Linux_Debug|Any CPU.ActiveCfg = Linux_Debug|Any CPU + {89F37791-6254-4D60-AB96-ACD3CCA0E771}.Linux_Debug|Any CPU.Build.0 = Linux_Debug|Any CPU + {89F37791-6254-4D60-AB96-ACD3CCA0E771}.Linux_Release|Any CPU.ActiveCfg = Linux_Release|Any CPU + {89F37791-6254-4D60-AB96-ACD3CCA0E771}.Linux_Release|Any CPU.Build.0 = Linux_Release|Any CPU + {89F37791-6254-4D60-AB96-ACD3CCA0E771}.OSX_Debug|Any CPU.ActiveCfg = OSX_Debug|Any CPU + {89F37791-6254-4D60-AB96-ACD3CCA0E771}.OSX_Debug|Any CPU.Build.0 = OSX_Debug|Any CPU + {89F37791-6254-4D60-AB96-ACD3CCA0E771}.OSX_Release|Any CPU.ActiveCfg = OSX_Release|Any CPU + {89F37791-6254-4D60-AB96-ACD3CCA0E771}.OSX_Release|Any CPU.Build.0 = OSX_Release|Any CPU + {89F37791-6254-4D60-AB96-ACD3CCA0E771}.Release|Any CPU.ActiveCfg = Windows_Release|Any CPU + {89F37791-6254-4D60-AB96-ACD3CCA0E771}.Release|Any CPU.Build.0 = Windows_Release|Any CPU + {89F37791-6254-4D60-AB96-ACD3CCA0E771}.Windows_Debug|Any CPU.ActiveCfg = Windows_Debug|Any CPU + {89F37791-6254-4D60-AB96-ACD3CCA0E771}.Windows_Debug|Any CPU.Build.0 = Windows_Debug|Any CPU + {89F37791-6254-4D60-AB96-ACD3CCA0E771}.Windows_Release|Any CPU.ActiveCfg = Windows_Release|Any CPU + {89F37791-6254-4D60-AB96-ACD3CCA0E771}.Windows_Release|Any CPU.Build.0 = Windows_Release|Any CPU + {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.FreeBSD_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.FreeBSD_Debug|Any CPU.Build.0 = Debug|Any CPU + {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.FreeBSD_Release|Any CPU.ActiveCfg = Release|Any CPU + {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.FreeBSD_Release|Any CPU.Build.0 = Release|Any CPU + {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.Linux_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.Linux_Debug|Any CPU.Build.0 = Debug|Any CPU + {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.Linux_Release|Any CPU.ActiveCfg = Release|Any CPU + {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.Linux_Release|Any CPU.Build.0 = Release|Any CPU + {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.OSX_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.OSX_Debug|Any CPU.Build.0 = Debug|Any CPU + {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.OSX_Release|Any CPU.ActiveCfg = Release|Any CPU + {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.OSX_Release|Any CPU.Build.0 = Release|Any CPU + {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.Release|Any CPU.Build.0 = Release|Any CPU + {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.Windows_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.Windows_Debug|Any CPU.Build.0 = Debug|Any CPU + {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.Windows_Release|Any CPU.ActiveCfg = Release|Any CPU + {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}.Windows_Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {6C5EF6EC-A9F6-4257-B7CB-C855E7A2671F} = {E923EB8F-73DA-436E-B2AE-CF46C13FFB35} + {89F37791-6254-4D60-AB96-ACD3CCA0E771} = {0A911515-B709-40A3-A1E7-0A75F8739DC1} + {8A72677F-6CD2-45DE-9A2F-BCD9124DB910} = {3AF6EFA9-4406-459F-B04C-02F7A5270D38} + {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2} = {8A72677F-6CD2-45DE-9A2F-BCD9124DB910} + EndGlobalSection +EndGlobal diff --git a/src/System.Net.Security/src/Resources/Strings.resx b/src/System.Net.Security/src/Resources/Strings.resx new file mode 100644 index 000000000000..021dac118dce --- /dev/null +++ b/src/System.Net.Security/src/Resources/Strings.resx @@ -0,0 +1,333 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + This stream does not support seek operations. + + + The requested security package is not supported. + + + This method is not implemented by this class. + + + This operation cannot be performed on a completed asynchronous result object. + + + Unable to read data from the transport connection: {0}. + + + The connection was closed + + + The {0} method cannot be called when another {1} operation is pending. + + + {0} can only be called once for each asynchronous operation. + + + The stream has to be read/write. + + + Found a wrong header field {0} read : {1}, expected : {2}. + + + The encryption operation failed, see inner exception. + + + The decryption operation failed, see inner exception. + + + The read operation failed, see inner exception. + + + The write operation failed, see inner exception. + + + Received an unexpected EOF or 0 bytes from the transport stream. + + + The parameter: {0} is not valid. Use the object returned from corresponding Begin async call. + + + The handshake failed due to an unexpected packet format. + + + The remote certificate is invalid according to the validation procedure. + + + The server mode SSL must use a certificate with the associated private key. + + + This operation is not allowed on a security context that has already been authenticated. + + + This operation is only allowed using a successfully authenticated context. + + + Once authentication is attempted as the client or server, additional authentication attempts must use the same client or server role. + + + A call to SSPI failed, see inner exception. + + + Authentication failed because the remote party has closed the transport stream. + + + Re-authentication failed because the remote party continued to encrypt more than {0} bytes before answering re-authentication. + + + Protocol error: A received message contains a valid signature but it was not encrypted as required by the effective Protection Level. + + + Received an invalid authentication frame. The message size is limited to {0} bytes, attempted to read {1} bytes. + + + Received incomplete authentication message. Remote party has probably closed the connection. + + + Cannot determine the frame size or a corrupted frame was received. + + + The payload size is limited to {0}, attempted set it to {1}. + + + Sum of offset and count cannot be greater than the length of the buffer. + + + The specified value is not valid in the '{0}' enumeration. + + + Exception in {0}::{1} - {2}. + + + Enumerating security packages: + + + Security package '{0}' was not found. + + + {0}(In-Buffer length={1}, Out-Buffer length={2}, returned code={3}). + + + {0}(In-Buffers count={1}, Out-Buffer length={2}, returned code={3}). + + + {0}(Protocol={1}, Cipher={2} {3} bit strength, Hash={4} {5} bit strength, Key Exchange={6} {7} bit strength). + + + Remote certificate: {0}. + + + Locating the private key for the certificate: {0}. + + + Certificate is of type X509Certificate2 and contains the private key. + + + Found the certificate in the {0} store. + + + Cannot find the certificate in either the LocalMachine store or the CurrentUser store. + + + Opening Certificate store {0} failed, exception: {1}. + + + Got a certificate from the client delegate. + + + Client delegate did not provide a certificate; and there are not other user-provided certificates. Need to attempt a session restart. + + + Client delegate did not provide a certificate; but there are other user-provided certificates. + + + Attempting to restart the session using the user-provided certificate: {0}. + + + We have user-provided certificates. The server has not specified any issuers, so try all the certificates. + + + We have user-provided certificates. The server has specified {0} issuer(s). Looking for certificates that match any of the issuers. + + + Selected certificate: {0}. + + + Left with {0} client certificates to choose from. + + + Trying to find a matching certificate in the certificate store. + + + Using the cached credential handle. + + + Remote certificate was verified as valid by the user. + + + Remote certificate was verified as invalid by the user. + + + Remote certificate has no errors. + + + Remote certificate has errors: + + + The remote server did not provide a certificate. + + + Certificate name mismatch. + + + {0} returned {1}. + + + {0} failed with error {1}. + + + '{0}' is not a supported handle type. + + + To construct a policy with PolicyEnforcement.Never, the single-parameter constructor must be used. + + + The ServiceNameCollection must contain at least one service name. + + + A service name must not be null or empty. + + + Either the IAsyncResult object did not come from the corresponding async method on this type, or EndRead was called multiple times with the same IAsyncResult. + + + Either the IAsyncResult object did not come from the corresponding async method on this type, or EndWrite was called multiple times with the same IAsyncResult. + + + Cannot access a closed Stream. + + + Stream does not support reading. + + + Stream does not support writing. + + \ No newline at end of file diff --git a/src/System.Net.Security/src/Shims/X509CertificateExtensions.cs b/src/System.Net.Security/src/Shims/X509CertificateExtensions.cs new file mode 100644 index 000000000000..5896d7d1da06 --- /dev/null +++ b/src/System.Net.Security/src/Shims/X509CertificateExtensions.cs @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Security.Cryptography.X509Certificates +{ + internal static class X509StoreExtensions + { + // TODO (Issue #3114): remove this shim as soon as the implementation is available. + // Placeholder for the X509Store(IntPtr) ctor. + internal static X509Store CreateFromNativeHandle(IntPtr storeHandle) + { + return new X509Store(StoreName.My, StoreLocation.CurrentUser); + } + } +} diff --git a/src/System.Net.Security/src/System.Net.Security.csproj b/src/System.Net.Security/src/System.Net.Security.csproj new file mode 100644 index 000000000000..01cd2b76f128 --- /dev/null +++ b/src/System.Net.Security/src/System.Net.Security.csproj @@ -0,0 +1,157 @@ + + + + System.Net.Security + 4.0.0.0 + Library + {89F37791-6254-4D60-AB96-ACD3CCA0E771} + true + $(DefineConstants);FEATURE_CORECLR + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Common\System\Net\Shims\TraceSource.cs + + + Common\System\Net\Logging\Logging.cs + + + Common\System\Net\Logging\GlobalLog.cs + + + Common\System\Net\Logging\EventSourceLogging.cs + + + Common\System\Net\InternalException.cs + + + + + Common\System\Net\DebugSafeHandle.cs + + + Common\System\Net\DebugCriticalHandleMinusOneIsInvalid.cs + + + Common\System\Net\DebugCriticalHandleZeroOrMinusOneIsInvalid.cs + + + + + Common\System\Net\_BufferOffsetSize.cs + + + Common\System\Net\_ContextAwareResult.cs + + + Common\System\Net\ExceptionCheck.cs + + + Common\System\Net\IntPtrHelper.cs + + + + Common\System\Net\_LazyAsyncResult.cs + + + Common\System\Net\Shims\ExecutionContext.cs + + + Common\System\Net\Shims\DBNull.cs + + + + Common\System\Net\UriScheme.cs + + + + + Common\Microsoft\Win32\SafeHandles\CriticalHandleMinusOneIsInvalid.cs + + + Common\Microsoft\Win32\SafeHandles\CriticalHandleZeroOrMinusOneIsInvalid.cs + + + Common\System\NotImplemented.cs + + + Common\Microsoft\Win32\SafeHandles\SafeHandleZeroOrMinusOneIsInvalid.cs + + + Common\System\IO\StreamAsyncHelper.cs + + + Common\System\IO\__Error.cs + + + + + Interop\Windows\Interop.Libraries.cs + + + Interop\Windows\Crypt32\Interop.certificates.cs + + + Interop\Windows\Crypt32\Interop.certificates_types.cs + + + Interop\Windows\mincore\Interop.CloseHandle.cs + + + Interop\Windows\SChannel\Interop.SchProtocols.cs + + + Interop\Windows\SChannel\Interop.SecurityStatus.cs + + + Interop\Windows\secur32\Interop.SSPI.cs + + + + + + + + + + + + diff --git a/src/System.Net.Security/src/System/Net/SecureProtocols/AuthenticatedStream.cs b/src/System.Net.Security/src/System/Net/SecureProtocols/AuthenticatedStream.cs new file mode 100644 index 000000000000..2f8cb9525cb2 --- /dev/null +++ b/src/System.Net.Security/src/System/Net/SecureProtocols/AuthenticatedStream.cs @@ -0,0 +1,84 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.IO; + +namespace System.Net.Security +{ + // A public contract for a base abstract authenticated stream. + public abstract class AuthenticatedStream : Stream + { + private Stream _innerStream; + private bool _leaveStreamOpen; + + protected AuthenticatedStream(Stream innerStream, bool leaveInnerStreamOpen) + { + if (innerStream == null || innerStream == Stream.Null) + { + throw new ArgumentNullException("innerStream"); + } + + if (!innerStream.CanRead || !innerStream.CanWrite) + { + throw new ArgumentException(SR.net_io_must_be_rw_stream, "innerStream"); + } + + _innerStream = innerStream; + _leaveStreamOpen = leaveInnerStreamOpen; + } + + public bool LeaveInnerStreamOpen + { + get + { + return _leaveStreamOpen; + } + } + + protected Stream InnerStream + { + get + { + return _innerStream; + } + } + + protected override void Dispose(bool disposing) + { +#if DEBUG + using (GlobalLog.SetThreadKind(ThreadKinds.User)) + { +#endif + try + { + if (disposing) + { + if (_leaveStreamOpen) + { + _innerStream.Flush(); + } + else + { + _innerStream.Dispose(); + } + } + } + finally + { + base.Dispose(disposing); + } +#if DEBUG + } +#endif + } + + public abstract bool IsAuthenticated { get; } + public abstract bool IsMutuallyAuthenticated { get; } + public abstract bool IsEncrypted { get; } + public abstract bool IsSigned { get; } + public abstract bool IsServer { get; } + } +} + + + diff --git a/src/System.Net.Security/src/System/Net/SecureProtocols/AuthenticationException.cs b/src/System.Net.Security/src/System/Net/SecureProtocols/AuthenticationException.cs new file mode 100644 index 000000000000..caf3ca8d389f --- /dev/null +++ b/src/System.Net.Security/src/System/Net/SecureProtocols/AuthenticationException.cs @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Security.Authentication +{ + /// + /// This exception can be thrown from Authenticate() method of Ssl and Negotiate classes. + /// The authentication process can be retried with different parameters subject to + /// remote party willingness of accepting that. + /// + public class AuthenticationException : Exception + { + public AuthenticationException() { } + public AuthenticationException(string message) : base(message) { } + public AuthenticationException(string message, Exception innerException) : base(message, innerException) { } + } + + /// + /// + /// This exception can be thrown from Authenticate() method of Ssl and Negotiate classes. + /// The authentication is expected to fail prematurely if called using the same + /// underlined stream. + /// + /// + public class InvalidCredentialException : AuthenticationException + { + public InvalidCredentialException() { } + public InvalidCredentialException(string message) : base(message) { } + public InvalidCredentialException(string message, Exception innerException) : base(message, innerException) { } + } +} diff --git a/src/System.Net.Security/src/System/Net/SecureProtocols/SslStream.cs b/src/System.Net.Security/src/System/Net/SecureProtocols/SslStream.cs new file mode 100644 index 000000000000..6e1813f7d2a6 --- /dev/null +++ b/src/System.Net.Security/src/System/Net/SecureProtocols/SslStream.cs @@ -0,0 +1,464 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.IO; +using System.Security.Authentication; +using System.Security.Authentication.ExtendedProtection; +using System.Security.Cryptography.X509Certificates; +using System.Threading.Tasks; + +namespace System.Net.Security +{ + public enum EncryptionPolicy + { + // Prohibit null ciphers (current system defaults) + RequireEncryption = 0, + + // Add null ciphers to current system defaults + AllowNoEncryption, + + // Request null ciphers only + NoEncryption + } + + // A user delegate used to verify remote SSL certificate. + public delegate bool RemoteCertificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors); + + // A user delegate used to select local SSL certificate. + public delegate X509Certificate LocalCertificateSelectionCallback(object sender, string targetHost, X509CertificateCollection localCertificates, X509Certificate remoteCertificate, string[] acceptableIssuers); + + // Internal versions of the above delegates. + internal delegate bool RemoteCertValidationCallback(string host, X509Certificate2 certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors); + internal delegate X509Certificate LocalCertSelectionCallback(string targetHost, X509CertificateCollection localCertificates, X509Certificate2 remoteCertificate, string[] acceptableIssuers); + + public class SslStream : AuthenticatedStream + { + private const SslProtocols DefaultProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls; + + private SslState _sslState; + private RemoteCertificateValidationCallback _userCertificateValidationCallback; + private LocalCertificateSelectionCallback _userCertificateSelectionCallback; + private object _remoteCertificateOrBytes; + + public SslStream(Stream innerStream) + : this(innerStream, false, null, null) + { + } + + public SslStream(Stream innerStream, bool leaveInnerStreamOpen) + : this(innerStream, leaveInnerStreamOpen, null, null, EncryptionPolicy.RequireEncryption) + { + } + + public SslStream(Stream innerStream, bool leaveInnerStreamOpen, RemoteCertificateValidationCallback userCertificateValidationCallback) + : this(innerStream, leaveInnerStreamOpen, userCertificateValidationCallback, null, EncryptionPolicy.RequireEncryption) + { + } + + public SslStream(Stream innerStream, bool leaveInnerStreamOpen, RemoteCertificateValidationCallback userCertificateValidationCallback, + LocalCertificateSelectionCallback userCertificateSelectionCallback) + : this(innerStream, leaveInnerStreamOpen, userCertificateValidationCallback, userCertificateSelectionCallback, EncryptionPolicy.RequireEncryption) + { + } + + public SslStream(Stream innerStream, bool leaveInnerStreamOpen, RemoteCertificateValidationCallback userCertificateValidationCallback, + LocalCertificateSelectionCallback userCertificateSelectionCallback, EncryptionPolicy encryptionPolicy) + : base(innerStream, leaveInnerStreamOpen) + { + if (encryptionPolicy != EncryptionPolicy.RequireEncryption && encryptionPolicy != EncryptionPolicy.AllowNoEncryption && encryptionPolicy != EncryptionPolicy.NoEncryption) + { + throw new ArgumentException(SR.Format(SR.net_invalid_enum, "EncryptionPolicy"), "encryptionPolicy"); + } + + _userCertificateValidationCallback = userCertificateValidationCallback; + _userCertificateSelectionCallback = userCertificateSelectionCallback; + RemoteCertValidationCallback _userCertValidationCallbackWrapper = new RemoteCertValidationCallback(UserCertValidationCallbackWrapper); + LocalCertSelectionCallback _userCertSelectionCallbackWrapper = userCertificateSelectionCallback == null ? null : new LocalCertSelectionCallback(UserCertSelectionCallbackWrapper); + _sslState = new SslState(innerStream, _userCertValidationCallbackWrapper, _userCertSelectionCallbackWrapper, encryptionPolicy); + } + + private bool UserCertValidationCallbackWrapper(string hostName, X509Certificate2 certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) + { + _remoteCertificateOrBytes = certificate == null ? null : certificate.RawData; + if (_userCertificateValidationCallback == null) + { + if (!_sslState.RemoteCertRequired) + { + sslPolicyErrors &= ~SslPolicyErrors.RemoteCertificateNotAvailable; + } + + return (sslPolicyErrors == SslPolicyErrors.None); + } + else + { + return _userCertificateValidationCallback(this, certificate, chain, sslPolicyErrors); + } + } + + private X509Certificate UserCertSelectionCallbackWrapper(string targetHost, X509CertificateCollection localCertificates, X509Certificate remoteCertificate, string[] acceptableIssuers) + { + return _userCertificateSelectionCallback(this, targetHost, localCertificates, remoteCertificate, acceptableIssuers); + } + + // + // Client side auth. + // + public virtual void AuthenticateAsClient(string targetHost) + { + AuthenticateAsClient(targetHost, new X509CertificateCollection(), DefaultProtocols, false); + } + + public virtual void AuthenticateAsClient(string targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, bool checkCertificateRevocation) + { + _sslState.ValidateCreateContext(false, targetHost, enabledSslProtocols, null, clientCertificates, true, checkCertificateRevocation); + _sslState.ProcessAuthentication(null); + } + + internal virtual IAsyncResult BeginAuthenticateAsClient(string targetHost, AsyncCallback asyncCallback, object asyncState) + { + return BeginAuthenticateAsClient(targetHost, new X509CertificateCollection(), DefaultProtocols, false, + asyncCallback, asyncState); + } + + internal virtual IAsyncResult BeginAuthenticateAsClient(string targetHost, X509CertificateCollection clientCertificates, + SslProtocols enabledSslProtocols, bool checkCertificateRevocation, + AsyncCallback asyncCallback, object asyncState) + { + _sslState.ValidateCreateContext(false, targetHost, enabledSslProtocols, null, clientCertificates, true, checkCertificateRevocation); + + LazyAsyncResult result = new LazyAsyncResult(_sslState, asyncState, asyncCallback); + _sslState.ProcessAuthentication(result); + return result; + } + + internal virtual void EndAuthenticateAsClient(IAsyncResult asyncResult) + { + _sslState.EndProcessAuthentication(asyncResult); + } + + // + // Server side auth. + // + public virtual void AuthenticateAsServer(X509Certificate serverCertificate) + { + AuthenticateAsServer(serverCertificate, false, DefaultProtocols, false); + } + + public virtual void AuthenticateAsServer(X509Certificate serverCertificate, bool clientCertificateRequired, + SslProtocols enabledSslProtocols, bool checkCertificateRevocation) + { + _sslState.ValidateCreateContext(true, string.Empty, enabledSslProtocols, serverCertificate, null, clientCertificateRequired, checkCertificateRevocation); + _sslState.ProcessAuthentication(null); + } + + internal virtual IAsyncResult BeginAuthenticateAsServer(X509Certificate serverCertificate, AsyncCallback asyncCallback, object asyncState) + + { + return BeginAuthenticateAsServer(serverCertificate, false, DefaultProtocols, false, + asyncCallback, + asyncState); + } + + internal virtual IAsyncResult BeginAuthenticateAsServer(X509Certificate serverCertificate, bool clientCertificateRequired, + SslProtocols enabledSslProtocols, bool checkCertificateRevocation, + AsyncCallback asyncCallback, + object asyncState) + { + _sslState.ValidateCreateContext(true, string.Empty, enabledSslProtocols, serverCertificate, null, clientCertificateRequired, checkCertificateRevocation); + LazyAsyncResult result = new LazyAsyncResult(_sslState, asyncState, asyncCallback); + _sslState.ProcessAuthentication(result); + return result; + } + + internal virtual void EndAuthenticateAsServer(IAsyncResult asyncResult) + { + _sslState.EndProcessAuthentication(asyncResult); + } + + public TransportContext TransportContext + { + get + { + return new SslStreamContext(this); + } + } + + internal ChannelBinding GetChannelBinding(ChannelBindingKind kind) + { + return _sslState.GetChannelBinding(kind); + } + + #region Task-based async public methods + public virtual Task AuthenticateAsClientAsync(string targetHost) + { + return Task.Factory.FromAsync(BeginAuthenticateAsClient, EndAuthenticateAsClient, targetHost, null); + } + + public virtual Task AuthenticateAsClientAsync(string targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, bool checkCertificateRevocation) + { + return Task.Factory.FromAsync((callback, state) => BeginAuthenticateAsClient(targetHost, clientCertificates, enabledSslProtocols, checkCertificateRevocation, callback, state), EndAuthenticateAsClient, null); + } + + public virtual Task AuthenticateAsServerAsync(X509Certificate serverCertificate) + { + return Task.Factory.FromAsync(BeginAuthenticateAsServer, EndAuthenticateAsServer, serverCertificate, null); + } + + public virtual Task AuthenticateAsServerAsync(X509Certificate serverCertificate, bool clientCertificateRequired, SslProtocols enabledSslProtocols, bool checkCertificateRevocation) + { + return Task.Factory.FromAsync((callback, state) => BeginAuthenticateAsServer(serverCertificate, clientCertificateRequired, enabledSslProtocols, checkCertificateRevocation, callback, state), EndAuthenticateAsServer, null); + } + #endregion + + public override bool IsAuthenticated + { + get + { + return _sslState.IsAuthenticated; + } + } + + public override bool IsMutuallyAuthenticated + { + get + { + return _sslState.IsMutuallyAuthenticated; + } + } + + public override bool IsEncrypted + { + get + { + return IsAuthenticated; + } + } + + public override bool IsSigned + { + get + { + return IsAuthenticated; + } + } + + public override bool IsServer + { + get + { + return _sslState.IsServer; + } + } + + public virtual SslProtocols SslProtocol + { + get + { + return _sslState.SslProtocol; + } + } + + public virtual bool CheckCertRevocationStatus + { + get + { + return _sslState.CheckCertRevocationStatus; + } + } + + public virtual X509Certificate LocalCertificate + { + get + { + return _sslState.LocalCertificate; + } + } + + public virtual X509Certificate RemoteCertificate + { + get + { + _sslState.CheckThrow(true); + + object chkCertificateOrBytes = _remoteCertificateOrBytes; + if (chkCertificateOrBytes != null && chkCertificateOrBytes.GetType() == typeof(byte[])) + { + return (X509Certificate)(_remoteCertificateOrBytes = new X509Certificate((byte[])chkCertificateOrBytes)); + } + else + { + return chkCertificateOrBytes as X509Certificate; + } + } + } + + public virtual CipherAlgorithmType CipherAlgorithm + { + get + { + return _sslState.CipherAlgorithm; + } + } + + public virtual int CipherStrength + { + get + { + return _sslState.CipherStrength; + } + } + + public virtual HashAlgorithmType HashAlgorithm + { + get + { + return _sslState.HashAlgorithm; + } + } + + public virtual int HashStrength + { + get + { + return _sslState.HashStrength; + } + } + + public virtual ExchangeAlgorithmType KeyExchangeAlgorithm + { + get + { + return _sslState.KeyExchangeAlgorithm; + } + } + + public virtual int KeyExchangeStrength + { + get + { + return _sslState.KeyExchangeStrength; + } + } + + // + // Stream contract implementation. + // + public override bool CanSeek + { + get + { + return false; + } + } + + public override bool CanRead + { + get + { + return _sslState.IsAuthenticated && InnerStream.CanRead; + } + } + + public override bool CanTimeout + { + get + { + return InnerStream.CanTimeout; + } + } + + public override bool CanWrite + { + get + { + return _sslState.IsAuthenticated && InnerStream.CanWrite; + } + } + + public override int ReadTimeout + { + get + { + return InnerStream.ReadTimeout; + } + set + { + InnerStream.ReadTimeout = value; + } + } + + public override int WriteTimeout + { + get + { + return InnerStream.WriteTimeout; + } + set + { + InnerStream.WriteTimeout = value; + } + } + + public override long Length + { + get + { + return InnerStream.Length; + } + } + + public override long Position + { + get + { + return InnerStream.Position; + } + set + { + throw new NotSupportedException(SR.net_noseek); + } + } + + public override void SetLength(long value) + { + InnerStream.SetLength(value); + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(SR.net_noseek); + } + + public override void Flush() + { + _sslState.Flush(); + } + + protected override void Dispose(bool disposing) + { + try + { + _sslState.Close(); + } + finally + { + base.Dispose(disposing); + } + } + + public override int Read(byte[] buffer, int offset, int count) + { + return _sslState.SecureStream.Read(buffer, offset, count); + } + + public void Write(byte[] buffer) + { + _sslState.SecureStream.Write(buffer, 0, buffer.Length); + } + + public override void Write(byte[] buffer, int offset, int count) + { + _sslState.SecureStream.Write(buffer, offset, count); + } + } +} diff --git a/src/System.Net.Security/src/System/Net/SecureProtocols/SslStreamContext.cs b/src/System.Net.Security/src/System/Net/SecureProtocols/SslStreamContext.cs new file mode 100644 index 000000000000..9f4e15982c4b --- /dev/null +++ b/src/System.Net.Security/src/System/Net/SecureProtocols/SslStreamContext.cs @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Net.Security; +using System.Security.Authentication.ExtendedProtection; + +namespace System.Net +{ + internal class SslStreamContext : TransportContext + { + internal SslStreamContext(SslStream sslStream) + { + GlobalLog.Assert(sslStream != null, "SslStreamContext..ctor(): Not expecting a null sslStream!"); + _sslStream = sslStream; + } + + public override ChannelBinding GetChannelBinding(ChannelBindingKind kind) + { + return _sslStream.GetChannelBinding(kind); + } + + private readonly SslStream _sslStream; + } +} diff --git a/src/System.Net.Security/src/System/Net/SecureProtocols/_FixedSizeReader.cs b/src/System.Net.Security/src/System/Net/SecureProtocols/_FixedSizeReader.cs new file mode 100644 index 000000000000..98f6f3793a2b --- /dev/null +++ b/src/System.Net.Security/src/System/Net/SecureProtocols/_FixedSizeReader.cs @@ -0,0 +1,151 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.IO; + +namespace System.Net +{ + // + // The class is a simple wrapper on top of a read stream. It will read the exact number of bytes requested. + // It will throw if EOF is reached before the expected number of bytes is returned. + // + internal class FixedSizeReader + { + private static readonly AsyncCallback s_readCallback = new AsyncCallback(ReadCallback); + + // TODO (Issue #3114): Implement this using TPL instead of APM. + private readonly StreamAsyncHelper _transportAPM; + private readonly Stream _transport; + private AsyncProtocolRequest _request; + private int _totalRead; + + public FixedSizeReader(Stream transport) + { + _transport = transport; + _transportAPM = new StreamAsyncHelper(transport); + } + + // + // Returns 0 on legitimate EOF or if 0 bytes were requested, otherwise reads as directed or throws. + // Returns count on success. + // + public int ReadPacket(byte[] buffer, int offset, int count) + { + int tempCount = count; + do + { + int bytes = _transport.Read(buffer, offset, tempCount); + + if (bytes == 0) + { + if (tempCount != count) + { + throw new IOException(SR.net_io_eof); + } + + return 0; + } + + tempCount -= bytes; + offset += bytes; + } while (tempCount != 0); + + return count; + } + + // + // Completes "_Request" with 0 if 0 bytes was requested or legitimate EOF received. + // Otherwise, reads as directed or completes "_Request" with an Exception or throws. + // + public void AsyncReadPacket(AsyncProtocolRequest request) + { + _request = request; + _totalRead = 0; + StartReading(); + } + // + // Loops while subsequent completions are sync. + // + private void StartReading() + { + while (true) + { + IAsyncResult ar = _transportAPM.BeginRead(_request.Buffer, _request.Offset + _totalRead, _request.Count - _totalRead, s_readCallback, this); + if (!ar.CompletedSynchronously) + { +#if DEBUG + _request._DebugAsyncChain = ar; +#endif + break; + } + + int bytes = _transportAPM.EndRead(ar); + + if (CheckCompletionBeforeNextRead(bytes)) + { + break; + } + } + } + + private bool CheckCompletionBeforeNextRead(int bytes) + { + if (bytes == 0) + { + // 0 bytes was requested or EOF in the beginning of a frame, the caller should decide whether it's OK. + if (_totalRead == 0) + { + _request.CompleteRequest(0); + return true; + } + + // EOF in the middle of a frame. + throw new IOException(SR.net_io_eof); + } + + GlobalLog.Assert(_totalRead + bytes <= _request.Count, "FixedSizeReader::CheckCompletion()|State got out of range. Total:{0} Count:{1}", _totalRead + bytes, _request.Count); + + if ((_totalRead += bytes) == _request.Count) + { + _request.CompleteRequest(_request.Count); + return true; + } + + return false; + } + + private static void ReadCallback(IAsyncResult transportResult) + { + GlobalLog.Assert(transportResult.AsyncState is FixedSizeReader, "ReadCallback|State type is wrong, expected FixedSizeReader."); + if (transportResult.CompletedSynchronously) + { + return; + } + + FixedSizeReader reader = (FixedSizeReader)transportResult.AsyncState; + AsyncProtocolRequest request = reader._request; + + // Async completion. + try + { + int bytes = reader._transportAPM.EndRead(transportResult); + + if (reader.CheckCompletionBeforeNextRead(bytes)) + { + return; + } + + reader.StartReading(); + } + catch (Exception e) + { + if (request.IsUserCompleted) + { + throw; + } + + request.CompleteWithError(e); + } + } + } +} diff --git a/src/System.Net.Security/src/System/Net/SecureProtocols/_HelperAsyncResults.cs b/src/System.Net.Security/src/System/Net/SecureProtocols/_HelperAsyncResults.cs new file mode 100644 index 000000000000..290e1b20d53c --- /dev/null +++ b/src/System.Net.Security/src/System/Net/SecureProtocols/_HelperAsyncResults.cs @@ -0,0 +1,166 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Threading; + +namespace System.Net +{ + // + // Used when we want to wrap a user IO request and we need + // to preserve the original request buffer & sizes. + // + internal class BufferAsyncResult : LazyAsyncResult + { + public byte[] Buffer; + public BufferOffsetSize[] Buffers; + public int Offset; + public int Count; + public bool IsWrite; + + // MultipleWriteOnly + // + public BufferAsyncResult(object asyncObject, BufferOffsetSize[] buffers, object asyncState, AsyncCallback asyncCallback) + : base(asyncObject, asyncState, asyncCallback) + { + Buffers = buffers; + IsWrite = true; + } + + public BufferAsyncResult(object asyncObject, byte[] buffer, int offset, int count, object asyncState, AsyncCallback asyncCallback) + : this(asyncObject, buffer, offset, count, false, asyncState, asyncCallback) + { + } + + public BufferAsyncResult(object asyncObject, byte[] buffer, int offset, int count, bool isWrite, object asyncState, AsyncCallback asyncCallback) + : base(asyncObject, asyncState, asyncCallback) + { + Buffer = buffer; + Offset = offset; + Count = count; + IsWrite = isWrite; + } + } + + // The callback type used with below AsyncProtocolRequest class + internal delegate void AsyncProtocolCallback(AsyncProtocolRequest asyncRequest); + + // + // The class mimics LazyAsyncResult although it does not need to be thread safe nor it does need an Event. + // We use this to implement iterative protocol logic: + // 1) it can be reused for handshake-like or multi-IO request protocols + // 2) it won't block async IO since there is NO event handler exposed + // + // UserAsyncResult property is a link into original user IO request (could be a BufferAsyncResult). + // + internal class AsyncProtocolRequest + { +#if DEBUG + internal object _DebugAsyncChain; // Optionally used to track chains of async calls. +#endif + + private AsyncProtocolCallback _Callback; + private int _CompletionStatus; + + private const int StatusNotStarted = 0; + private const int StatusCompleted = 1; + private const int StatusCheckedOnSyncCompletion = 2; + + + public LazyAsyncResult UserAsyncResult; + public int Result; + public object AsyncState; + + public byte[] Buffer; // temp buffer reused by a protocol. + public int Offset; + public int Count; + + public AsyncProtocolRequest(LazyAsyncResult userAsyncResult) + { + GlobalLog.Assert(userAsyncResult != null, "AsyncProtocolRequest()|userAsyncResult == null"); + GlobalLog.Assert(!userAsyncResult.InternalPeekCompleted, "AsyncProtocolRequest()|userAsyncResult is already completed."); + UserAsyncResult = userAsyncResult; + } + + public void SetNextRequest(byte[] buffer, int offset, int count, AsyncProtocolCallback callback) + { + if (_CompletionStatus != StatusNotStarted) + { + throw new InternalException(); // pending op is in progress + } + + Buffer = buffer; + Offset = offset; + Count = count; + _Callback = callback; + } + + internal object AsyncObject + { + get + { + return UserAsyncResult.AsyncObject; + } + } + + // + // Notify protocol so a next stage could be started + // + internal void CompleteRequest(int result) + { + Result = result; + int status = Interlocked.Exchange(ref _CompletionStatus, StatusCompleted); + if (status == StatusCompleted) + { + throw new InternalException(); // only allow one call + } + + if (status == StatusCheckedOnSyncCompletion) + { + _CompletionStatus = StatusNotStarted; + _Callback(this); + } + } + + public bool MustCompleteSynchronously + { + get + { + int status = Interlocked.Exchange(ref _CompletionStatus, StatusCheckedOnSyncCompletion); + if (status == StatusCheckedOnSyncCompletion) + { + throw new InternalException(); // only allow one call + } + + if (status == StatusCompleted) + { + _CompletionStatus = StatusNotStarted; + return true; + } + return false; + } + } + + // + // Important: This will abandon _Callback and directly notify UserAsyncResult. + // + internal void CompleteWithError(Exception e) + { + UserAsyncResult.InvokeCallback(e); + } + + internal void CompleteUser() + { + UserAsyncResult.InvokeCallback(); + } + + internal void CompleteUser(object userResult) + { + UserAsyncResult.InvokeCallback(userResult); + } + + internal bool IsUserCompleted + { + get { return UserAsyncResult.InternalPeekCompleted; } + } + } +} diff --git a/src/System.Net.Security/src/System/Net/SecureProtocols/_SecuritySafeHandles.Windows.cs b/src/System.Net.Security/src/System/Net/SecureProtocols/_SecuritySafeHandles.Windows.cs new file mode 100644 index 000000000000..2bbc65d0f3dd --- /dev/null +++ b/src/System.Net.Security/src/System/Net/SecureProtocols/_SecuritySafeHandles.Windows.cs @@ -0,0 +1,1241 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Win32.SafeHandles; + +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Security.Authentication.ExtendedProtection; + +namespace System.Net.Security +{ + // + // Used when working with SSPI APIs, like SafeSspiAuthDataHandle(). Holds the pointer to the auth data blob. + // +#if DEBUG + internal sealed class SafeSspiAuthDataHandle : DebugSafeHandle + { +#else + internal sealed class SafeSspiAuthDataHandle : SafeHandleZeroOrMinusOneIsInvalid + { +#endif + public SafeSspiAuthDataHandle() : base(true) + { + } + + protected override bool ReleaseHandle() + { + return Interop.Secur32.SspiFreeAuthIdentity(handle) == Interop.SecurityStatus.OK; + } + } + + // + // A set of Safe Handles that depend on native FreeContextBuffer finalizer + // +#if DEBUG + internal abstract class SafeFreeContextBuffer : DebugSafeHandle + { +#else + internal abstract class SafeFreeContextBuffer : SafeHandleZeroOrMinusOneIsInvalid + { +#endif + protected SafeFreeContextBuffer() : base(true) { } + + // This must be ONLY called from this file. + internal void Set(IntPtr value) + { + this.handle = value; + } + + internal static int EnumeratePackages(out int pkgnum, out SafeFreeContextBuffer pkgArray) + { + int res = -1; + SafeFreeContextBuffer_SECURITY pkgArray_SECURITY = null; + res = Interop.Secur32.EnumerateSecurityPackagesW(out pkgnum, out pkgArray_SECURITY); + pkgArray = pkgArray_SECURITY; + + if (res != 0 && pkgArray != null) + { + pkgArray.SetHandleAsInvalid(); + } + + return res; + } + + internal static SafeFreeContextBuffer CreateEmptyHandle() + { + return new SafeFreeContextBuffer_SECURITY(); + } + + // + // After PInvoke call the method will fix the refHandle.handle with the returned value. + // The caller is responsible for creating a correct SafeHandle template or null can be passed if no handle is returned. + // + // This method switches between three non-interruptible helper methods. (This method can't be both non-interruptible and + // reference imports from all three DLLs - doing so would cause all three DLLs to try to be bound to.) + // + public unsafe static int QueryContextAttributes(SafeDeleteContext phContext, Interop.Secur32.ContextAttribute contextAttribute, byte* buffer, SafeHandle refHandle) + { + return QueryContextAttributes_SECURITY(phContext, contextAttribute, buffer, refHandle); + } + + private unsafe static int QueryContextAttributes_SECURITY( + SafeDeleteContext phContext, + Interop.Secur32.ContextAttribute contextAttribute, + byte* buffer, + SafeHandle refHandle) + { + int status = (int)Interop.SecurityStatus.InvalidHandle; + + try + { + bool ignore = false; + phContext.DangerousAddRef(ref ignore); + status = Interop.Secur32.QueryContextAttributesW(ref phContext._handle, contextAttribute, buffer); + } + finally + { + phContext.DangerousRelease(); + } + + if (status == 0 && refHandle != null) + { + if (refHandle is SafeFreeContextBuffer) + { + ((SafeFreeContextBuffer)refHandle).Set(*(IntPtr*)buffer); + } + else + { + ((SafeFreeCertContext)refHandle).Set(*(IntPtr*)buffer); + } + } + + if (status != 0 && refHandle != null) + { + refHandle.SetHandleAsInvalid(); + } + + return status; + } + + public static int SetContextAttributes( + SafeDeleteContext phContext, + Interop.Secur32.ContextAttribute contextAttribute, byte[] buffer) + { + return SetContextAttributes_SECURITY(phContext, contextAttribute, buffer); + } + + private static int SetContextAttributes_SECURITY( + SafeDeleteContext phContext, + Interop.Secur32.ContextAttribute contextAttribute, + byte[] buffer) + { + try + { + bool ignore = false; + phContext.DangerousAddRef(ref ignore); + return Interop.Secur32.SetContextAttributesW(ref phContext._handle, contextAttribute, buffer, buffer.Length); + } + finally + { + phContext.DangerousRelease(); + } + } + } + + internal sealed class SafeFreeContextBuffer_SECURITY : SafeFreeContextBuffer + { + internal SafeFreeContextBuffer_SECURITY() : base() { } + + protected override bool ReleaseHandle() + { + return Interop.Secur32.FreeContextBuffer(handle) == 0; + } + } + + // + // Implementation of handles required CertFreeCertificateContext + // +#if DEBUG + internal sealed class SafeFreeCertContext : DebugSafeHandle + { +#else + internal sealed class SafeFreeCertContext : SafeHandleZeroOrMinusOneIsInvalid + { +#endif + + internal SafeFreeCertContext() : base(true) { } + + // This must be ONLY called from this file. + internal void Set(IntPtr value) + { + this.handle = value; + } + + private const uint CRYPT_ACQUIRE_SILENT_FLAG = 0x00000040; + + protected override bool ReleaseHandle() + { + Interop.Crypt32.CertFreeCertificateContext(handle); + return true; + } + } + + // + // Implementation of handles dependable on FreeCredentialsHandle + // +#if DEBUG + internal abstract class SafeFreeCredentials : DebugSafeHandle + { +#else + internal abstract class SafeFreeCredentials : SafeHandle + { +#endif + + internal Interop.Secur32.SSPIHandle _handle; //should be always used as by ref in PInvokes parameters + + protected SafeFreeCredentials() : base(IntPtr.Zero, true) + { + _handle = new Interop.Secur32.SSPIHandle(); + } + +#if TRACE_VERBOSE + public override string ToString() + { + return "0x" + _handle.ToString(); + } +#endif + + public override bool IsInvalid + { + get { return IsClosed || _handle.IsZero; } + } + +#if DEBUG + public new IntPtr DangerousGetHandle() + { + Debug.Fail("This method should never be called for this type"); + throw NotImplemented.ByDesign; + } +#endif + + public unsafe static int AcquireCredentialsHandle( + string package, + Interop.Secur32.CredentialUse intent, + ref Interop.Secur32.AuthIdentity authdata, + out SafeFreeCredentials outCredential) + { + GlobalLog.Print("SafeFreeCredentials::AcquireCredentialsHandle#1(" + + package + ", " + + intent + ", " + + authdata + ")"); + + int errorCode = -1; + long timeStamp; + + outCredential = new SafeFreeCredential_SECURITY(); + + errorCode = Interop.Secur32.AcquireCredentialsHandleW( + null, + package, + (int)intent, + null, + ref authdata, + null, + null, + ref outCredential._handle, + out timeStamp); +#if TRACE_VERBOSE + GlobalLog.Print("Unmanaged::AcquireCredentialsHandle() returns 0x" + + String.Format("{0:x}", errorCode) + + ", handle = " + outCredential.ToString()); +#endif + + if (errorCode != 0) + { + outCredential.SetHandleAsInvalid(); + } + + return errorCode; + } + + public unsafe static int AcquireDefaultCredential( + string package, + Interop.Secur32.CredentialUse intent, + out SafeFreeCredentials outCredential) + { + GlobalLog.Print("SafeFreeCredentials::AcquireDefaultCredential(" + + package + ", " + + intent + ")"); + + int errorCode = -1; + long timeStamp; + + outCredential = new SafeFreeCredential_SECURITY(); + + errorCode = Interop.Secur32.AcquireCredentialsHandleW( + null, + package, + (int)intent, + null, + IntPtr.Zero, + null, + null, + ref outCredential._handle, + out timeStamp); + +#if TRACE_VERBOSE + GlobalLog.Print("Unmanaged::AcquireCredentialsHandle() returns 0x" + + errorCode.ToString("x") + + ", handle = " + outCredential.ToString()); +#endif + + if (errorCode != 0) + { + outCredential.SetHandleAsInvalid(); + } + + return errorCode; + } + + public unsafe static int AcquireCredentialsHandle( + string package, + Interop.Secur32.CredentialUse intent, + ref SafeSspiAuthDataHandle authdata, + out SafeFreeCredentials outCredential) + { + int errorCode = -1; + long timeStamp; + + outCredential = new SafeFreeCredential_SECURITY(); + errorCode = Interop.Secur32.AcquireCredentialsHandleW( + null, + package, + (int)intent, + null, + authdata, + null, + null, + ref outCredential._handle, + out timeStamp); + + if (errorCode != 0) + { + outCredential.SetHandleAsInvalid(); + } + + return errorCode; + } + + public unsafe static int AcquireCredentialsHandle( + string package, + Interop.Secur32.CredentialUse intent, + ref Interop.Secur32.SecureCredential authdata, + out SafeFreeCredentials outCredential) + { + GlobalLog.Print("SafeFreeCredentials::AcquireCredentialsHandle#2(" + + package + ", " + + intent + ", " + + authdata + ")"); + + int errorCode = -1; + long timeStamp; + + + // If there is a certificate, wrap it into an array. + // Not threadsafe. + IntPtr copiedPtr = authdata.certContextArray; + try + { + IntPtr certArrayPtr = new IntPtr(&copiedPtr); + if (copiedPtr != IntPtr.Zero) + { + authdata.certContextArray = certArrayPtr; + } + + outCredential = new SafeFreeCredential_SECURITY(); + + errorCode = Interop.Secur32.AcquireCredentialsHandleW( + null, + package, + (int)intent, + null, + ref authdata, + null, + null, + ref outCredential._handle, + out timeStamp); + } + finally + { + authdata.certContextArray = copiedPtr; + } + +#if TRACE_VERBOSE + GlobalLog.Print("Unmanaged::AcquireCredentialsHandle() returns 0x" + + errorCode.ToString("x") + + ", handle = " + outCredential.ToString()); +#endif + + if (errorCode != 0) + { + outCredential.SetHandleAsInvalid(); + } + + return errorCode; + } + } + + // + // This is a class holding a Credential handle reference, used for static handles cache + // +#if DEBUG + internal sealed class SafeCredentialReference : DebugCriticalHandleMinusOneIsInvalid + { +#else + internal sealed class SafeCredentialReference : CriticalHandleMinusOneIsInvalid + { +#endif + + // + // Static cache will return the target handle if found the reference in the table. + // + internal SafeFreeCredentials _Target; + + internal static SafeCredentialReference CreateReference(SafeFreeCredentials target) + { + SafeCredentialReference result = new SafeCredentialReference(target); + if (result.IsInvalid) + { + return null; + } + + return result; + } + private SafeCredentialReference(SafeFreeCredentials target) : base() + { + // Bumps up the refcount on Target to signify that target handle is statically cached so + // its dispose should be postponed + bool ignore = false; + target.DangerousAddRef(ref ignore); + _Target = target; + SetHandle(new IntPtr(0)); // make this handle valid + } + + protected override bool ReleaseHandle() + { + SafeFreeCredentials target = _Target; + if (target != null) + { + target.DangerousRelease(); + } + + _Target = null; + return true; + } + } + + internal sealed class SafeFreeCredential_SECURITY : SafeFreeCredentials + { + public SafeFreeCredential_SECURITY() : base() { } + + protected override bool ReleaseHandle() + { + return Interop.Secur32.FreeCredentialsHandle(ref _handle) == 0; + } + } + + // + // Implementation of handles that are dependent on DeleteSecurityContext + // +#if DEBUG + internal abstract class SafeDeleteContext : DebugSafeHandle + { +#else + internal abstract class SafeDeleteContext : SafeHandle + { +#endif + private const string dummyStr = " "; + private static readonly byte[] s_dummyBytes = new byte[] { 0 }; + + // + // ATN: _handle is internal since it is used on PInvokes by other wrapper methods. + // However all such wrappers MUST manually and reliably adjust refCounter of SafeDeleteContext handle. + // + internal Interop.Secur32.SSPIHandle _handle; + + protected SafeFreeCredentials _EffectiveCredential; + + protected SafeDeleteContext() : base(IntPtr.Zero, true) + { + _handle = new Interop.Secur32.SSPIHandle(); + } + + public override bool IsInvalid + { + get + { + return IsClosed || _handle.IsZero; + } + } + + public override string ToString() + { + return _handle.ToString(); + } + +#if DEBUG + //This method should never be called for this type + public new IntPtr DangerousGetHandle() + { + throw new InvalidOperationException(); + } +#endif + + //------------------------------------------------------------------- + internal unsafe static int InitializeSecurityContext( + ref SafeFreeCredentials inCredentials, + ref SafeDeleteContext refContext, + string targetName, + Interop.Secur32.ContextFlags inFlags, + Interop.Secur32.Endianness endianness, + SecurityBuffer inSecBuffer, + SecurityBuffer[] inSecBuffers, + SecurityBuffer outSecBuffer, + ref Interop.Secur32.ContextFlags outFlags) + { +#if TRACE_VERBOSE + GlobalLog.Enter("SafeDeleteContext::InitializeSecurityContext"); + GlobalLog.Print(" credential = " + inCredentials.ToString()); + GlobalLog.Print(" refContext = " + Logging.ObjectToString(refContext)); + GlobalLog.Print(" targetName = " + targetName); + GlobalLog.Print(" inFlags = " + inFlags); + GlobalLog.Print(" reservedI = 0x0"); + GlobalLog.Print(" endianness = " + endianness); + + if (inSecBuffers == null) + { + GlobalLog.Print(" inSecBuffers = (null)"); + } + else + { + GlobalLog.Print(" inSecBuffers[] = length:" + inSecBuffers.Length); + } +#endif + GlobalLog.Assert(outSecBuffer != null, "SafeDeleteContext::InitializeSecurityContext()|outSecBuffer != null"); + GlobalLog.Assert(inSecBuffer == null || inSecBuffers == null, "SafeDeleteContext::InitializeSecurityContext()|inSecBuffer == null || inSecBuffers == null"); + + if (inCredentials == null) + { + throw new ArgumentNullException("inCredentials"); + } + + Interop.Secur32.SecurityBufferDescriptor inSecurityBufferDescriptor = null; + if (inSecBuffer != null) + { + inSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(1); + } + else if (inSecBuffers != null) + { + inSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(inSecBuffers.Length); + } + + Interop.Secur32.SecurityBufferDescriptor outSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(1); + + // Actually, this is returned in outFlags. + bool isSspiAllocated = (inFlags & Interop.Secur32.ContextFlags.AllocateMemory) != 0 ? true : false; + + int errorCode = -1; + + Interop.Secur32.SSPIHandle contextHandle = new Interop.Secur32.SSPIHandle(); + if (refContext != null) + { + contextHandle = refContext._handle; + } + + // These are pinned user byte arrays passed along with SecurityBuffers. + GCHandle[] pinnedInBytes = null; + GCHandle pinnedOutBytes = new GCHandle(); + + // Optional output buffer that may need to be freed. + SafeFreeContextBuffer outFreeContextBuffer = null; + try + { + pinnedOutBytes = GCHandle.Alloc(outSecBuffer.token, GCHandleType.Pinned); + Interop.Secur32.SecurityBufferStruct[] inUnmanagedBuffer = new Interop.Secur32.SecurityBufferStruct[inSecurityBufferDescriptor == null ? 1 : inSecurityBufferDescriptor.Count]; + fixed (void* inUnmanagedBufferPtr = inUnmanagedBuffer) + { + if (inSecurityBufferDescriptor != null) + { + // Fix Descriptor pointer that points to unmanaged SecurityBuffers. + inSecurityBufferDescriptor.UnmanagedPointer = inUnmanagedBufferPtr; + pinnedInBytes = new GCHandle[inSecurityBufferDescriptor.Count]; + SecurityBuffer securityBuffer; + for (int index = 0; index < inSecurityBufferDescriptor.Count; ++index) + { + securityBuffer = inSecBuffer != null ? inSecBuffer : inSecBuffers[index]; + if (securityBuffer != null) + { + // Copy the SecurityBuffer content into unmanaged place holder. + inUnmanagedBuffer[index].count = securityBuffer.size; + inUnmanagedBuffer[index].type = securityBuffer.type; + + // Use the unmanaged token if it's not null; otherwise use the managed buffer. + if (securityBuffer.unmanagedToken != null) + { + inUnmanagedBuffer[index].token = securityBuffer.unmanagedToken.DangerousGetHandle(); + } + else if (securityBuffer.token == null || securityBuffer.token.Length == 0) + { + inUnmanagedBuffer[index].token = IntPtr.Zero; + } + else + { + pinnedInBytes[index] = GCHandle.Alloc(securityBuffer.token, GCHandleType.Pinned); + inUnmanagedBuffer[index].token = Marshal.UnsafeAddrOfPinnedArrayElement(securityBuffer.token, securityBuffer.offset); + } +#if TRACE_VERBOSE + GlobalLog.Print("SecBuffer: cbBuffer:" + securityBuffer.size + " BufferType:" + securityBuffer.type); +#endif + } + } + } + + Interop.Secur32.SecurityBufferStruct[] outUnmanagedBuffer = new Interop.Secur32.SecurityBufferStruct[1]; + fixed (void* outUnmanagedBufferPtr = outUnmanagedBuffer) + { + // Fix Descriptor pointer that points to unmanaged SecurityBuffers. + outSecurityBufferDescriptor.UnmanagedPointer = outUnmanagedBufferPtr; + outUnmanagedBuffer[0].count = outSecBuffer.size; + outUnmanagedBuffer[0].type = outSecBuffer.type; + if (outSecBuffer.token == null || outSecBuffer.token.Length == 0) + { + outUnmanagedBuffer[0].token = IntPtr.Zero; + } + else + { + outUnmanagedBuffer[0].token = Marshal.UnsafeAddrOfPinnedArrayElement(outSecBuffer.token, outSecBuffer.offset); + } + + if (isSspiAllocated) + { + outFreeContextBuffer = SafeFreeContextBuffer.CreateEmptyHandle(); + } + + if (refContext == null || refContext.IsInvalid) + { + refContext = new SafeDeleteContext_SECURITY(); + } + + if (targetName == null || targetName.Length == 0) + { + targetName = dummyStr; + } + + fixed (char* namePtr = targetName) + { + errorCode = MustRunInitializeSecurityContext_SECURITY( + ref inCredentials, + contextHandle.IsZero ? null : &contextHandle, + (byte*)(((object)targetName == (object)dummyStr) ? null : namePtr), + inFlags, + endianness, + inSecurityBufferDescriptor, + refContext, + outSecurityBufferDescriptor, + ref outFlags, + outFreeContextBuffer); + } + + GlobalLog.Print("SafeDeleteContext:InitializeSecurityContext Marshalling OUT buffer"); + // Get unmanaged buffer with index 0 as the only one passed into PInvoke. + outSecBuffer.size = outUnmanagedBuffer[0].count; + outSecBuffer.type = outUnmanagedBuffer[0].type; + if (outSecBuffer.size > 0) + { + outSecBuffer.token = new byte[outSecBuffer.size]; + Marshal.Copy(outUnmanagedBuffer[0].token, outSecBuffer.token, 0, outSecBuffer.size); + } + else + { + outSecBuffer.token = null; + } + } + } + } + finally + { + if (pinnedInBytes != null) + { + for (int index = 0; index < pinnedInBytes.Length; index++) + { + if (pinnedInBytes[index].IsAllocated) + { + pinnedInBytes[index].Free(); + } + } + } + if (pinnedOutBytes.IsAllocated) + { + pinnedOutBytes.Free(); + } + + if (outFreeContextBuffer != null) + { + outFreeContextBuffer.Dispose(); + } + } + + GlobalLog.Leave("SafeDeleteContext::InitializeSecurityContext() unmanaged InitializeSecurityContext()", "errorCode:0x" + errorCode.ToString("x8") + " refContext:" + Logging.ObjectToString(refContext)); + + return errorCode; + } + + // + // After PInvoke call the method will fix the handleTemplate.handle with the returned value. + // The caller is responsible for creating a correct SafeFreeContextBuffer_XXX flavour or null can be passed if no handle is returned. + // + private static unsafe int MustRunInitializeSecurityContext_SECURITY( + ref SafeFreeCredentials inCredentials, + void* inContextPtr, + byte* targetName, + Interop.Secur32.ContextFlags inFlags, + Interop.Secur32.Endianness endianness, + Interop.Secur32.SecurityBufferDescriptor inputBuffer, + SafeDeleteContext outContext, + Interop.Secur32.SecurityBufferDescriptor outputBuffer, + ref Interop.Secur32.ContextFlags attributes, + SafeFreeContextBuffer handleTemplate) + { + int errorCode = (int)Interop.SecurityStatus.InvalidHandle; + + try + { + bool ignore = false; + inCredentials.DangerousAddRef(ref ignore); + outContext.DangerousAddRef(ref ignore); + + Interop.Secur32.SSPIHandle credentialHandle = inCredentials._handle; + + long timeStamp; + + errorCode = Interop.Secur32.InitializeSecurityContextW( + ref credentialHandle, + inContextPtr, + targetName, + inFlags, + 0, + endianness, + inputBuffer, + 0, + ref outContext._handle, + outputBuffer, + ref attributes, + out timeStamp); + } + finally + { + // + // When a credential handle is first associated with the context we keep credential + // ref count bumped up to ensure ordered finalization. + // If the credential handle has been changed we de-ref the old one and associate the + // context with the new cred handle but only if the call was successful. + if (outContext._EffectiveCredential != inCredentials && (errorCode & 0x80000000) == 0) + { + // Disassociate the previous credential handle + if (outContext._EffectiveCredential != null) + { + outContext._EffectiveCredential.DangerousRelease(); + } + + outContext._EffectiveCredential = inCredentials; + } + else + { + inCredentials.DangerousRelease(); + } + + outContext.DangerousRelease(); + } + + // The idea is that SSPI has allocated a block and filled up outUnmanagedBuffer+8 slot with the pointer. + if (handleTemplate != null) + { + //ATTN: on 64 BIT that is still +8 cause of 2* c++ unsigned long == 8 bytes + handleTemplate.Set(((Interop.Secur32.SecurityBufferStruct*)outputBuffer.UnmanagedPointer)->token); + if (handleTemplate.IsInvalid) + { + handleTemplate.SetHandleAsInvalid(); + } + } + + if (inContextPtr == null && (errorCode & 0x80000000) != 0) + { + // an error on the first call, need to set the out handle to invalid value + outContext._handle.SetToInvalid(); + } + + return errorCode; + } + + //------------------------------------------------------------------- + internal unsafe static int AcceptSecurityContext( + ref SafeFreeCredentials inCredentials, + ref SafeDeleteContext refContext, + Interop.Secur32.ContextFlags inFlags, + Interop.Secur32.Endianness endianness, + SecurityBuffer inSecBuffer, + SecurityBuffer[] inSecBuffers, + SecurityBuffer outSecBuffer, + ref Interop.Secur32.ContextFlags outFlags) + { +#if TRACE_VERBOSE + GlobalLog.Enter("SafeDeleteContext::AcceptSecurityContex"); + GlobalLog.Print(" credential = " + inCredentials.ToString()); + GlobalLog.Print(" refContext = " + Logging.ObjectToString(refContext)); + + GlobalLog.Print(" inFlags = " + inFlags); + + if (inSecBuffers == null) + { + GlobalLog.Print(" inSecBuffers = (null)"); + } + else + { + GlobalLog.Print(" inSecBuffers[] = length:" + inSecBuffers.Length); + } +#endif + GlobalLog.Assert(outSecBuffer != null, "SafeDeleteContext::AcceptSecurityContext()|outSecBuffer != null"); + GlobalLog.Assert(inSecBuffer == null || inSecBuffers == null, "SafeDeleteContext::AcceptSecurityContext()|inSecBuffer == null || inSecBuffers == null"); + + if (inCredentials == null) + { + throw new ArgumentNullException("inCredentials"); + } + + Interop.Secur32.SecurityBufferDescriptor inSecurityBufferDescriptor = null; + if (inSecBuffer != null) + { + inSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(1); + } + else if (inSecBuffers != null) + { + inSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(inSecBuffers.Length); + } + + Interop.Secur32.SecurityBufferDescriptor outSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(1); + + // Actually, this is returned in outFlags. + bool isSspiAllocated = (inFlags & Interop.Secur32.ContextFlags.AllocateMemory) != 0 ? true : false; + + int errorCode = -1; + + Interop.Secur32.SSPIHandle contextHandle = new Interop.Secur32.SSPIHandle(); + if (refContext != null) + { + contextHandle = refContext._handle; + } + + // These are pinned user byte arrays passed along with SecurityBuffers. + GCHandle[] pinnedInBytes = null; + GCHandle pinnedOutBytes = new GCHandle(); + + // Optional output buffer that may need to be freed. + SafeFreeContextBuffer outFreeContextBuffer = null; + try + { + pinnedOutBytes = GCHandle.Alloc(outSecBuffer.token, GCHandleType.Pinned); + var inUnmanagedBuffer = new Interop.Secur32.SecurityBufferStruct[inSecurityBufferDescriptor == null ? 1 : inSecurityBufferDescriptor.Count]; + fixed (void* inUnmanagedBufferPtr = inUnmanagedBuffer) + { + if (inSecurityBufferDescriptor != null) + { + // Fix Descriptor pointer that points to unmanaged SecurityBuffers. + inSecurityBufferDescriptor.UnmanagedPointer = inUnmanagedBufferPtr; + pinnedInBytes = new GCHandle[inSecurityBufferDescriptor.Count]; + SecurityBuffer securityBuffer; + for (int index = 0; index < inSecurityBufferDescriptor.Count; ++index) + { + securityBuffer = inSecBuffer != null ? inSecBuffer : inSecBuffers[index]; + if (securityBuffer != null) + { + // Copy the SecurityBuffer content into unmanaged place holder. + inUnmanagedBuffer[index].count = securityBuffer.size; + inUnmanagedBuffer[index].type = securityBuffer.type; + + // Use the unmanaged token if it's not null; otherwise use the managed buffer. + if (securityBuffer.unmanagedToken != null) + { + inUnmanagedBuffer[index].token = securityBuffer.unmanagedToken.DangerousGetHandle(); + } + else if (securityBuffer.token == null || securityBuffer.token.Length == 0) + { + inUnmanagedBuffer[index].token = IntPtr.Zero; + } + else + { + pinnedInBytes[index] = GCHandle.Alloc(securityBuffer.token, GCHandleType.Pinned); + inUnmanagedBuffer[index].token = Marshal.UnsafeAddrOfPinnedArrayElement(securityBuffer.token, securityBuffer.offset); + } +#if TRACE_VERBOSE + GlobalLog.Print("SecBuffer: cbBuffer:" + securityBuffer.size + " BufferType:" + securityBuffer.type); +#endif + } + } + } + + var outUnmanagedBuffer = new Interop.Secur32.SecurityBufferStruct[1]; + fixed (void* outUnmanagedBufferPtr = outUnmanagedBuffer) + { + // Fix Descriptor pointer that points to unmanaged SecurityBuffers. + outSecurityBufferDescriptor.UnmanagedPointer = outUnmanagedBufferPtr; + // Copy the SecurityBuffer content into unmanaged place holder. + outUnmanagedBuffer[0].count = outSecBuffer.size; + outUnmanagedBuffer[0].type = outSecBuffer.type; + + if (outSecBuffer.token == null || outSecBuffer.token.Length == 0) + { + outUnmanagedBuffer[0].token = IntPtr.Zero; + } + else + { + outUnmanagedBuffer[0].token = Marshal.UnsafeAddrOfPinnedArrayElement(outSecBuffer.token, outSecBuffer.offset); + } + + if (isSspiAllocated) + { + outFreeContextBuffer = SafeFreeContextBuffer.CreateEmptyHandle(); + } + + if (refContext == null || refContext.IsInvalid) + { + refContext = new SafeDeleteContext_SECURITY(); + } + + errorCode = MustRunAcceptSecurityContext_SECURITY( + ref inCredentials, + contextHandle.IsZero ? null : &contextHandle, + inSecurityBufferDescriptor, + inFlags, + endianness, + refContext, + outSecurityBufferDescriptor, + ref outFlags, + outFreeContextBuffer); + + GlobalLog.Print("SafeDeleteContext:AcceptSecurityContext Marshalling OUT buffer"); + // Get unmanaged buffer with index 0 as the only one passed into PInvoke. + outSecBuffer.size = outUnmanagedBuffer[0].count; + outSecBuffer.type = outUnmanagedBuffer[0].type; + if (outSecBuffer.size > 0) + { + outSecBuffer.token = new byte[outSecBuffer.size]; + Marshal.Copy(outUnmanagedBuffer[0].token, outSecBuffer.token, 0, outSecBuffer.size); + } + else + { + outSecBuffer.token = null; + } + } + } + } + finally + { + if (pinnedInBytes != null) + { + for (int index = 0; index < pinnedInBytes.Length; index++) + { + if (pinnedInBytes[index].IsAllocated) + { + pinnedInBytes[index].Free(); + } + } + } + + if (pinnedOutBytes.IsAllocated) + { + pinnedOutBytes.Free(); + } + + if (outFreeContextBuffer != null) + { + outFreeContextBuffer.Dispose(); + } + } + + GlobalLog.Leave("SafeDeleteContext::AcceptSecurityContex() unmanaged AcceptSecurityContex()", "errorCode:0x" + errorCode.ToString("x8") + " refContext:" + Logging.ObjectToString(refContext)); + + return errorCode; + } + + // + // After PInvoke call the method will fix the handleTemplate.handle with the returned value. + // The caller is responsible for creating a correct SafeFreeContextBuffer_XXX flavour or null can be passed if no handle is returned. + // + private static unsafe int MustRunAcceptSecurityContext_SECURITY( + ref SafeFreeCredentials inCredentials, + void* inContextPtr, + Interop.Secur32.SecurityBufferDescriptor inputBuffer, + Interop.Secur32.ContextFlags inFlags, + Interop.Secur32.Endianness endianness, + SafeDeleteContext outContext, + Interop.Secur32.SecurityBufferDescriptor outputBuffer, + ref Interop.Secur32.ContextFlags outFlags, + SafeFreeContextBuffer handleTemplate) + { + int errorCode = (int)Interop.SecurityStatus.InvalidHandle; + + // Run the body of this method as a non-interruptible block. + try + { + bool ignore = false; + + inCredentials.DangerousAddRef(ref ignore); + outContext.DangerousAddRef(ref ignore); + + Interop.Secur32.SSPIHandle credentialHandle = inCredentials._handle; + long timeStamp; + + errorCode = Interop.Secur32.AcceptSecurityContext( + ref credentialHandle, + inContextPtr, + inputBuffer, + inFlags, + endianness, + ref outContext._handle, + outputBuffer, + ref outFlags, + out timeStamp); + } + finally + { + // + // When a credential handle is first associated with the context we keep credential + // ref count bumped up to ensure ordered finalization. + // If the credential handle has been changed we de-ref the old one and associate the + // context with the new cred handle but only if the call was successful. + if (outContext._EffectiveCredential != inCredentials && (errorCode & 0x80000000) == 0) + { + // Disassociate the previous credential handle. + if (outContext._EffectiveCredential != null) + { + outContext._EffectiveCredential.DangerousRelease(); + } + + outContext._EffectiveCredential = inCredentials; + } + else + { + inCredentials.DangerousRelease(); + } + + outContext.DangerousRelease(); + } + + // The idea is that SSPI has allocated a block and filled up outUnmanagedBuffer+8 slot with the pointer. + if (handleTemplate != null) + { + //ATTN: on 64 BIT that is still +8 cause of 2* c++ unsigned long == 8 bytes. + handleTemplate.Set(((Interop.Secur32.SecurityBufferStruct*)outputBuffer.UnmanagedPointer)->token); + if (handleTemplate.IsInvalid) + { + handleTemplate.SetHandleAsInvalid(); + } + } + + if (inContextPtr == null && (errorCode & 0x80000000) != 0) + { + // An error on the first call, need to set the out handle to invalid value. + outContext._handle.SetToInvalid(); + } + + return errorCode; + } + + internal unsafe static int CompleteAuthToken( + ref SafeDeleteContext refContext, + SecurityBuffer[] inSecBuffers) + { + GlobalLog.Enter("SafeDeleteContext::CompleteAuthToken"); + GlobalLog.Print(" refContext = " + Logging.ObjectToString(refContext)); +#if TRACE_VERBOSE + GlobalLog.Print(" inSecBuffers[] = length:" + inSecBuffers.Length); +#endif + GlobalLog.Assert(inSecBuffers != null, "SafeDeleteContext::CompleteAuthToken()|inSecBuffers == null"); + var inSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(inSecBuffers.Length); + + int errorCode = (int)Interop.SecurityStatus.InvalidHandle; + + // These are pinned user byte arrays passed along with SecurityBuffers. + GCHandle[] pinnedInBytes = null; + + var inUnmanagedBuffer = new Interop.Secur32.SecurityBufferStruct[inSecurityBufferDescriptor.Count]; + fixed (void* inUnmanagedBufferPtr = inUnmanagedBuffer) + { + // Fix Descriptor pointer that points to unmanaged SecurityBuffers. + inSecurityBufferDescriptor.UnmanagedPointer = inUnmanagedBufferPtr; + pinnedInBytes = new GCHandle[inSecurityBufferDescriptor.Count]; + SecurityBuffer securityBuffer; + for (int index = 0; index < inSecurityBufferDescriptor.Count; ++index) + { + securityBuffer = inSecBuffers[index]; + if (securityBuffer != null) + { + inUnmanagedBuffer[index].count = securityBuffer.size; + inUnmanagedBuffer[index].type = securityBuffer.type; + + // Use the unmanaged token if it's not null; otherwise use the managed buffer. + if (securityBuffer.unmanagedToken != null) + { + inUnmanagedBuffer[index].token = securityBuffer.unmanagedToken.DangerousGetHandle(); + } + else if (securityBuffer.token == null || securityBuffer.token.Length == 0) + { + inUnmanagedBuffer[index].token = IntPtr.Zero; + } + else + { + pinnedInBytes[index] = GCHandle.Alloc(securityBuffer.token, GCHandleType.Pinned); + inUnmanagedBuffer[index].token = Marshal.UnsafeAddrOfPinnedArrayElement(securityBuffer.token, securityBuffer.offset); + } +#if TRACE_VERBOSE + GlobalLog.Print("SecBuffer: cbBuffer:" + securityBuffer.size + " BufferType:" + securityBuffer.type); +#endif + } + } + + Interop.Secur32.SSPIHandle contextHandle = new Interop.Secur32.SSPIHandle(); + if (refContext != null) + { + contextHandle = refContext._handle; + } + try + { + if (refContext == null || refContext.IsInvalid) + { + refContext = new SafeDeleteContext_SECURITY(); + } + + try + { + bool ignore = false; + refContext.DangerousAddRef(ref ignore); + errorCode = Interop.Secur32.CompleteAuthToken(contextHandle.IsZero ? null : &contextHandle, inSecurityBufferDescriptor); + } + finally + { + refContext.DangerousRelease(); + } + } + finally + { + if (pinnedInBytes != null) + { + for (int index = 0; index < pinnedInBytes.Length; index++) + { + if (pinnedInBytes[index].IsAllocated) + { + pinnedInBytes[index].Free(); + } + } + } + } + } + + GlobalLog.Leave("SafeDeleteContext::CompleteAuthToken() unmanaged CompleteAuthToken()", "errorCode:0x" + errorCode.ToString("x8") + " refContext:" + Logging.ObjectToString(refContext)); + + return errorCode; + } + } + + internal sealed class SafeDeleteContext_SECURITY : SafeDeleteContext + { + internal SafeDeleteContext_SECURITY() : base() { } + + protected override bool ReleaseHandle() + { + if (this._EffectiveCredential != null) + { + this._EffectiveCredential.DangerousRelease(); + } + + return Interop.Secur32.DeleteSecurityContext(ref _handle) == 0; + } + } + + // Based on SafeFreeContextBuffer. + internal abstract class SafeFreeContextBufferChannelBinding : ChannelBinding + { + private int _size; + + public override int Size + { + get { return _size; } + } + + public override bool IsInvalid + { + get { return handle == new IntPtr(0) || handle == new IntPtr(-1); } + } + + internal unsafe void Set(IntPtr value) + { + this.handle = value; + } + + internal static SafeFreeContextBufferChannelBinding CreateEmptyHandle() + { + return new SafeFreeContextBufferChannelBinding_SECURITY(); + } + + public unsafe static int QueryContextChannelBinding(SafeDeleteContext phContext, Interop.Secur32.ContextAttribute contextAttribute, Bindings* buffer, SafeFreeContextBufferChannelBinding refHandle) + { + return QueryContextChannelBinding_SECURITY(phContext, contextAttribute, buffer, refHandle); + } + + private unsafe static int QueryContextChannelBinding_SECURITY(SafeDeleteContext phContext, Interop.Secur32.ContextAttribute contextAttribute, Bindings* buffer, SafeFreeContextBufferChannelBinding refHandle) + { + int status = (int)Interop.SecurityStatus.InvalidHandle; + + // SCHANNEL only supports SECPKG_ATTR_ENDPOINT_BINDINGS and SECPKG_ATTR_UNIQUE_BINDINGS which + // map to our enum ChannelBindingKind.Endpoint and ChannelBindingKind.Unique. + if (contextAttribute != Interop.Secur32.ContextAttribute.EndpointBindings && + contextAttribute != Interop.Secur32.ContextAttribute.UniqueBindings) + { + return status; + } + + try + { + bool ignore = false; + phContext.DangerousAddRef(ref ignore); + status = Interop.Secur32.QueryContextAttributesW(ref phContext._handle, contextAttribute, buffer); + } + finally + { + phContext.DangerousRelease(); + } + + if (status == 0 && refHandle != null) + { + refHandle.Set((*buffer).pBindings); + refHandle._size = (*buffer).BindingsLength; + } + + if (status != 0 && refHandle != null) + { + refHandle.SetHandleAsInvalid(); + } + + return status; + } + } + + internal sealed class SafeFreeContextBufferChannelBinding_SECURITY : SafeFreeContextBufferChannelBinding + { + protected override bool ReleaseHandle() + { + return Interop.Secur32.FreeContextBuffer(handle) == 0; + } + } +} diff --git a/src/System.Net.Security/src/System/Net/SecureProtocols/_SslState.cs b/src/System.Net.Security/src/System/Net/SecureProtocols/_SslState.cs new file mode 100644 index 000000000000..7031455408f0 --- /dev/null +++ b/src/System.Net.Security/src/System/Net/SecureProtocols/_SslState.cs @@ -0,0 +1,1809 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.ComponentModel; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Security.Authentication; +using System.Security.Authentication.ExtendedProtection; +using System.Security.Cryptography.X509Certificates; +using System.Threading; + +namespace System.Net.Security +{ + internal class SslState + { + private static int s_uniqueNameInteger = 123; + private static AsyncProtocolCallback s_partialFrameCallback = new AsyncProtocolCallback(PartialFrameCallback); + private static AsyncProtocolCallback s_readFrameCallback = new AsyncProtocolCallback(ReadFrameCallback); + private static AsyncCallback s_writeCallback = new AsyncCallback(WriteCallback); + + private RemoteCertValidationCallback _certValidationDelegate; + private LocalCertSelectionCallback _certSelectionDelegate; + + private Stream _innerStream; + + // TODO (Issue #3114): Implement using TPL instead of APM. + private StreamAsyncHelper _innerStreamAPM; + + private _SslStream _secureStream; + + private FixedSizeReader _reader; + + private int _nestedAuth; + private SecureChannel _context; + + private bool _handshakeCompleted; + private bool _certValidationFailed; + private Interop.SecurityStatus _securityStatus; + private Exception _exception; + + private enum CachedSessionStatus : byte + { + Unknown = 0, + IsNotCached = 1, + IsCached = 2, + Renegotiated = 3 + } + private CachedSessionStatus _CachedSession; + + // This block is used by rehandshake code to buffer data decryptred with the old key. + private byte[] _queuedReadData; + private int _queuedReadCount; + private bool _pendingReHandshake; + private const int MaxQueuedReadBytes = 1024 * 128; + + // + // This block is used to rule the >>re-handshakes<< that are concurent with read/write io requests. + // + private const int LockNone = 0; + private const int LockWrite = 1; + private const int LockHandshake = 2; + private const int LockPendingWrite = 3; + private const int LockRead = 4; + private const int LockPendingRead = 6; + + private int _lockWriteState; + private object _queuedWriteStateRequest; + + private int _lockReadState; + private object _queuedReadStateRequest; + + private readonly EncryptionPolicy _encryptionPolicy; + + // + // The public Client and Server classes enforce the parameters rules before + // calling into this .ctor. + // + internal SslState(Stream innerStream, RemoteCertValidationCallback certValidationCallback, LocalCertSelectionCallback certSelectionCallback, EncryptionPolicy encryptionPolicy) + { + _innerStream = innerStream; + _innerStreamAPM = new StreamAsyncHelper(innerStream); + _reader = new FixedSizeReader(innerStream); + _certValidationDelegate = certValidationCallback; + _certSelectionDelegate = certSelectionCallback; + _encryptionPolicy = encryptionPolicy; + } + // + // + // + internal void ValidateCreateContext(bool isServer, string targetHost, SslProtocols enabledSslProtocols, X509Certificate serverCertificate, X509CertificateCollection clientCertificates, bool remoteCertRequired, bool checkCertRevocationStatus) + { + ValidateCreateContext(isServer, targetHost, enabledSslProtocols, serverCertificate, clientCertificates, remoteCertRequired, + checkCertRevocationStatus, !isServer); + } + + internal void ValidateCreateContext(bool isServer, string targetHost, SslProtocols enabledSslProtocols, X509Certificate serverCertificate, X509CertificateCollection clientCertificates, bool remoteCertRequired, bool checkCertRevocationStatus, bool checkCertName) + { + // + // We don't support SSL alerts right now, hence any exception is fatal and cannot be retried. + // + if (_exception != null) + { + throw _exception; + } + + if (Context != null && Context.IsValidContext) + { + throw new InvalidOperationException(SR.net_auth_reauth); + } + + if (Context != null && IsServer != isServer) + { + throw new InvalidOperationException(SR.net_auth_client_server); + } + + if (targetHost == null) + { + throw new ArgumentNullException("targetHost"); + } + + if (isServer) + { + enabledSslProtocols &= (SslProtocols)Interop.SChannel.ServerProtocolMask; + if (serverCertificate == null) + { + throw new ArgumentNullException("serverCertificate"); + } + } + else + { + enabledSslProtocols &= (SslProtocols)Interop.SChannel.ClientProtocolMask; + } + + if ((int)enabledSslProtocols == 0) + { + throw new ArgumentException(SR.Format(SR.net_invalid_enum, "SslProtocolType"), "sslProtocolType"); + } + + if (clientCertificates == null) + { + clientCertificates = new X509CertificateCollection(); + } + + if (targetHost.Length == 0) + { + targetHost = "?" + Interlocked.Increment(ref s_uniqueNameInteger).ToString(NumberFormatInfo.InvariantInfo); + } + + _exception = null; + try + { + _context = new SecureChannel(targetHost, isServer, (int)enabledSslProtocols, serverCertificate, clientCertificates, remoteCertRequired, + checkCertName, checkCertRevocationStatus, _encryptionPolicy, _certSelectionDelegate); + } + catch (Win32Exception e) + { + throw new AuthenticationException(SR.net_auth_SSPI, e); + } + } + + internal bool IsAuthenticated + { + get + { + return _context != null && _context.IsValidContext && _exception == null && HandshakeCompleted; + } + } + + internal bool IsMutuallyAuthenticated + { + get + { + return + IsAuthenticated && + (Context.IsServer ? Context.LocalServerCertificate : Context.LocalClientCertificate) != null && + Context.IsRemoteCertificateAvailable; /* does not work: Context.IsMutualAuthFlag;*/ + } + } + + internal bool RemoteCertRequired + { + get + { + return Context == null || Context.RemoteCertRequired; + } + } + + internal bool IsServer + { + get + { + return Context != null && Context.IsServer; + } + } + + // + // SSL related properties + // + internal void SetCertValidationDelegate(RemoteCertValidationCallback certValidationCallback) + { + _certValidationDelegate = certValidationCallback; + } + + // + // This will return selected local cert for both client/server streams + // + internal X509Certificate LocalCertificate + { + get + { + CheckThrow(true); + return InternalLocalCertificate; + } + } + + private X509Certificate InternalLocalCertificate + { + get + { + return Context.IsServer ? Context.LocalServerCertificate : Context.LocalClientCertificate; + } + } + + internal ChannelBinding GetChannelBinding(ChannelBindingKind kind) + { + return (Context == null) ? null : Context.GetChannelBinding(kind); + } + + internal bool CheckCertRevocationStatus + { + get + { + return Context != null && Context.CheckCertRevocationStatus; + } + } + + internal Interop.SecurityStatus LastSecurityStatus + { + get { return _securityStatus; } + } + + internal bool IsCertValidationFailed + { + get + { + return _certValidationFailed; + } + } + + internal bool DataAvailable + { + get + { + return IsAuthenticated && (SecureStream.DataAvailable || _queuedReadCount != 0); + } + } + + internal CipherAlgorithmType CipherAlgorithm + { + get + { + CheckThrow(true); + SslConnectionInfo info = Context.ConnectionInfo; + if (info == null) + { + return CipherAlgorithmType.None; + } + return (CipherAlgorithmType)info.DataCipherAlg; + } + } + + internal int CipherStrength + { + get + { + CheckThrow(true); + SslConnectionInfo info = Context.ConnectionInfo; + if (info == null) + { + return 0; + } + + return info.DataKeySize; + } + } + + internal HashAlgorithmType HashAlgorithm + { + get + { + CheckThrow(true); + SslConnectionInfo info = Context.ConnectionInfo; + if (info == null) + { + return (HashAlgorithmType)0; + } + return (HashAlgorithmType)info.DataHashAlg; + } + } + + internal int HashStrength + { + get + { + CheckThrow(true); + SslConnectionInfo info = Context.ConnectionInfo; + if (info == null) + { + return 0; + } + + return info.DataHashKeySize; + } + } + + internal ExchangeAlgorithmType KeyExchangeAlgorithm + { + get + { + CheckThrow(true); + SslConnectionInfo info = Context.ConnectionInfo; + if (info == null) + { + return (ExchangeAlgorithmType)0; + } + + return (ExchangeAlgorithmType)info.KeyExchangeAlg; + } + } + + internal int KeyExchangeStrength + { + get + { + CheckThrow(true); + SslConnectionInfo info = Context.ConnectionInfo; + if (info == null) + { + return 0; + } + + return info.KeyExchKeySize; + } + } + + internal SslProtocols SslProtocol + { + get + { + CheckThrow(true); + SslConnectionInfo info = Context.ConnectionInfo; + if (info == null) + { + return SslProtocols.None; + } + + SslProtocols proto = (SslProtocols)info.Protocol; + SslProtocols ret = SslProtocols.None; + + // Restore client/server bits so the result maps exactly on published constants. + if ((proto & SslProtocols.Ssl2) != 0) + { + ret |= SslProtocols.Ssl2; + } + + if ((proto & SslProtocols.Ssl3) != 0) + { + ret |= SslProtocols.Ssl3; + } + + if ((proto & SslProtocols.Tls) != 0) + { + ret |= SslProtocols.Tls; + } + + if ((proto & SslProtocols.Tls11) != 0) + { + ret |= SslProtocols.Tls11; + } + + if ((proto & SslProtocols.Tls12) != 0) + { + ret |= SslProtocols.Tls12; + } + + return ret; + } + } + + internal Stream InnerStream + { + get + { + return _innerStream; + } + } + + internal StreamAsyncHelper InnerStreamAPM + { + get + { + return _innerStreamAPM; + } + } + + internal _SslStream SecureStream + { + get + { + CheckThrow(true); + if (_secureStream == null) + { + Interlocked.CompareExchange<_SslStream>(ref _secureStream, new _SslStream(this), null); + } + + return _secureStream; + } + } + + internal int HeaderSize + { + get + { + return Context.HeaderSize; + } + } + + internal int MaxDataSize + { + get + { + return Context.MaxDataSize; + } + } + + private Exception SetException(Exception e) + { + if (_exception == null) + { + _exception = e; + } + + if (_exception != null && Context != null) + { + Context.Close(); + } + + return _exception; + } + + private bool HandshakeCompleted + { + get + { + return _handshakeCompleted; + } + } + + private SecureChannel Context + { + get + { + return _context; + } + } + + internal void CheckThrow(bool authSucessCheck) + { + if (_exception != null) + { + throw _exception; + } + + if (authSucessCheck && !IsAuthenticated) + { + throw new InvalidOperationException(SR.net_auth_noauth); + } + } + + internal void Flush() + { + InnerStream.Flush(); + } + + // + // This is to not depend on GC&SafeHandle class if the context is not needed anymore. + // + internal void Close() + { + _exception = new ObjectDisposedException("SslStream"); + if (Context != null) + { + Context.Close(); + } + } + + internal Interop.SecurityStatus EncryptData(byte[] buffer, int offset, int count, ref byte[] outBuffer, out int outSize) + { + CheckThrow(true); + return Context.Encrypt(buffer, offset, count, ref outBuffer, out outSize); + } + + internal Interop.SecurityStatus DecryptData(byte[] buffer, ref int offset, ref int count) + { + CheckThrow(true); + return PrivateDecryptData(buffer, ref offset, ref count); + } + + private Interop.SecurityStatus PrivateDecryptData(byte[] buffer, ref int offset, ref int count) + { + return Context.Decrypt(buffer, ref offset, ref count); + } + + // + // Called by re-handshake if found data decrypted with the old key + // + private Exception EnqueueOldKeyDecryptedData(byte[] buffer, int offset, int count) + { + lock (this) + { + if (_queuedReadCount + count > MaxQueuedReadBytes) + { + return new IOException(SR.Format(SR.net_auth_ignored_reauth, MaxQueuedReadBytes.ToString(NumberFormatInfo.CurrentInfo))); + } + + if (count != 0) + { + // This is inefficient yet simple and that should be a rare case of receiving data encrypted with "old" key. + _queuedReadData = EnsureBufferSize(_queuedReadData, _queuedReadCount, _queuedReadCount + count); + Buffer.BlockCopy(buffer, offset, _queuedReadData, _queuedReadCount, count); + _queuedReadCount += count; + FinishHandshakeRead(LockHandshake); + } + } + return null; + } + + // + // When re-handshaking the "old" key decrypted data are queued until the handshake is done. + // When stream calls for decryption we will feed it queued data left from "old" encryption key. + // + // Must be called under the lock in case concurent handshake is going. + // + internal int CheckOldKeyDecryptedData(byte[] buffer, int offset, int count) + { + CheckThrow(true); + if (_queuedReadData != null) + { + // This is inefficient yet simple and should be a REALLY rare case. + int toCopy = Math.Min(_queuedReadCount, count); + Buffer.BlockCopy(_queuedReadData, 0, buffer, offset, toCopy); + _queuedReadCount -= toCopy; + if (_queuedReadCount == 0) + { + _queuedReadData = null; + } + else + { + Buffer.BlockCopy(_queuedReadData, toCopy, _queuedReadData, 0, _queuedReadCount); + } + + return toCopy; + } + return -1; + } + // + // This method assumes that a SSPI context is already in a good shape. + // For example it is either a fresh context or already authenticated context that needs renegotiation. + // + internal void ProcessAuthentication(LazyAsyncResult lazyResult) + { + if (Interlocked.Exchange(ref _nestedAuth, 1) == 1) + { + throw new InvalidOperationException(SR.Format(SR.net_io_invalidnestedcall, lazyResult == null ? "BeginAuthenticate" : "Authenticate", "authenticate")); + } + + try + { + CheckThrow(false); + AsyncProtocolRequest asyncRequest = null; + if (lazyResult != null) + { + asyncRequest = new AsyncProtocolRequest(lazyResult); + asyncRequest.Buffer = null; +#if DEBUG + lazyResult._DebugAsyncChain = asyncRequest; +#endif + } + + // A trick to discover and avoid cached sessions. + _CachedSession = CachedSessionStatus.Unknown; + + ForceAuthentication(Context.IsServer, null, asyncRequest); + + // Not aync so the connection is completed at this point. + if (lazyResult == null && Logging.On) + { + Logging.PrintInfo(Logging.Web, SR.Format(SR.net_log_sspi_selected_cipher_suite, + "ProcessAuthentication", + SslProtocol, + CipherAlgorithm, + CipherStrength, + HashAlgorithm, + HashStrength, + KeyExchangeAlgorithm, + KeyExchangeStrength)); + } + } + finally + { + if (lazyResult == null || _exception != null) + { + _nestedAuth = 0; + } + } + } + + // + // This is used to reply on re-handshake when received SEC_I_RENEGOTIATE on Read(). + // + internal void ReplyOnReAuthentication(byte[] buffer) + { + lock (this) + { + // Note we are already inside the read, so checking for already going concurent handshake. + _lockReadState = LockHandshake; + + if (_pendingReHandshake) + { + // A concurent handshake is pending, resume. + FinishRead(buffer); + return; + } + } + + // Start rehandshake from here. + + // Forcing async mode. The caller will queue another Read as soon as we return using its preferred + // calling convention, which will be woken up when the handshake completes. The callback is just + // to capture any SocketErrors that happen during the handshake so they can be surfaced from the Read. + AsyncProtocolRequest asyncRequest = new AsyncProtocolRequest(new LazyAsyncResult(this, null, new AsyncCallback(RehandshakeCompleteCallback))); + // Buffer contains a result from DecryptMessage that will be passed to ISC/ASC + asyncRequest.Buffer = buffer; + ForceAuthentication(false, buffer, asyncRequest); + } + + // + // This method attempts to start authentication. + // Incoming buffer is either null or is the result of "renegotiate" decrypted message + // If write is in progress the method will either wait or be put on hold + // + private void ForceAuthentication(bool receiveFirst, byte[] buffer, AsyncProtocolRequest asyncRequest) + { + if (CheckEnqueueHandshake(buffer, asyncRequest)) + { + // Async handshake is enqueued and will resume later. + return; + } + // Either Sync handshake is ready to go or async handshake won the race over write. + + // This will tell that we don't know the framing yet (what SSL version is) + _Framing = Framing.Unknown; + + try + { + if (receiveFirst) + { + // Listen for a client blob. + StartReceiveBlob(buffer, asyncRequest); + } + else + { + // We start with the first blob. + StartSendBlob(buffer, (buffer == null ? 0 : buffer.Length), asyncRequest); + } + } + catch (Exception e) + { + // Failed auth, reset the framing if any. + _Framing = Framing.Unknown; + _handshakeCompleted = false; + + if (SetException(e) == e) + { + throw; + } + else + { + throw _exception; + } + } + finally + { + if (_exception != null) + { + // This a failed handshake. Release waiting IO if any. + FinishHandshake(null, null); + } + } + } + + internal void EndProcessAuthentication(IAsyncResult result) + { + if (result == null) + { + throw new ArgumentNullException("asyncResult"); + } + + LazyAsyncResult lazyResult = result as LazyAsyncResult; + if (lazyResult == null) + { + throw new ArgumentException(SR.Format(SR.net_io_async_result, result.GetType().FullName), "asyncResult"); + } + + if (Interlocked.Exchange(ref _nestedAuth, 0) == 0) + { + throw new InvalidOperationException(SR.Format(SR.net_io_invalidendcall, "EndAuthenticate")); + } + + InternalEndProcessAuthentication(lazyResult); + + // Connection is completed at this point. + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, SR.Format(SR.net_log_sspi_selected_cipher_suite, + "EndProcessAuthentication", + SslProtocol, + CipherAlgorithm, + CipherStrength, + HashAlgorithm, + HashStrength, + KeyExchangeAlgorithm, + KeyExchangeStrength)); + } + } + // + // + // + internal void InternalEndProcessAuthentication(LazyAsyncResult lazyResult) + { + // No "artificial" timeouts implemented so far, InnerStream controls that. + lazyResult.InternalWaitForCompletion(); + Exception e = lazyResult.Result as Exception; + + if (e != null) + { + // Failed auth, reset the framing if any. + _Framing = Framing.Unknown; + _handshakeCompleted = false; + + throw SetException(e); + } + } + + // + // Client side starts here, but server also loops through this method. + // + private void StartSendBlob(byte[] incoming, int count, AsyncProtocolRequest asyncRequest) + { + ProtocolToken message = Context.NextMessage(incoming, 0, count); + _securityStatus = message.Status; + + if (message.Size != 0) + { + if (Context.IsServer && _CachedSession == CachedSessionStatus.Unknown) + { + // + //[Schannel] If the first call to ASC returns a token less than 200 bytes, + // then it's a reconnect (a handshake based on a cache entry). + // + _CachedSession = message.Size < 200 ? CachedSessionStatus.IsCached : CachedSessionStatus.IsNotCached; + } + + if (_Framing == Framing.Unified) + { + _Framing = DetectFraming(message.Payload, message.Payload.Length); + } + + if (asyncRequest == null) + { + InnerStream.Write(message.Payload, 0, message.Size); + } + else + { + asyncRequest.AsyncState = message; + IAsyncResult ar = InnerStreamAPM.BeginWrite(message.Payload, 0, message.Size, s_writeCallback, asyncRequest); + if (!ar.CompletedSynchronously) + { +#if DEBUG + asyncRequest._DebugAsyncChain = ar; +#endif + return; + } + + InnerStreamAPM.EndWrite(ar); + } + } + + CheckCompletionBeforeNextReceive(message, asyncRequest); + } + + // + // This will check and logically complete / fail the auth handshake. + // + private void CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest) + { + if (message.Failed) + { + StartSendAuthResetSignal(null, asyncRequest, new AuthenticationException(SR.net_auth_SSPI, message.GetException())); + return; + } + else if (message.Done && !_pendingReHandshake) + { + if (!CompleteHandshake()) + { + StartSendAuthResetSignal(null, asyncRequest, new AuthenticationException(SR.net_ssl_io_cert_validation, null)); + return; + } + + // Release waiting IO if any. Presumably it should not throw. + // Otheriwse application may get not expected type of the exception. + FinishHandshake(null, asyncRequest); + return; + } + + StartReceiveBlob(message.Payload, asyncRequest); + } + + // + // Server side starts here, but client also loops through this method. + // + private void StartReceiveBlob(byte[] buffer, AsyncProtocolRequest asyncRequest) + { + if (_pendingReHandshake) + { + if (CheckEnqueueHandshakeRead(ref buffer, asyncRequest)) + { + return; + } + + if (!_pendingReHandshake) + { + // Renegotiate: proceed to the next step. + ProcessReceivedBlob(buffer, buffer.Length, asyncRequest); + return; + } + } + + //This is first server read. + buffer = EnsureBufferSize(buffer, 0, SecureChannel.ReadHeaderSize); + + int readBytes = 0; + if (asyncRequest == null) + { + readBytes = _reader.ReadPacket(buffer, 0, SecureChannel.ReadHeaderSize); + } + else + { + asyncRequest.SetNextRequest(buffer, 0, SecureChannel.ReadHeaderSize, s_partialFrameCallback); + _reader.AsyncReadPacket(asyncRequest); + if (!asyncRequest.MustCompleteSynchronously) + { + return; + } + + readBytes = asyncRequest.Result; + } + + StartReadFrame(buffer, readBytes, asyncRequest); + } + // + private void StartReadFrame(byte[] buffer, int readBytes, AsyncProtocolRequest asyncRequest) + { + if (readBytes == 0) + { + // EOF received + throw new IOException(SR.net_auth_eof); + } + + if (_Framing == Framing.Unknown) + { + _Framing = DetectFraming(buffer, readBytes); + } + + int restBytes = GetRemainingFrameSize(buffer, readBytes); + + if (restBytes < 0) + { + throw new IOException(SR.net_ssl_io_frame); + } + + if (restBytes == 0) + { + // EOF received + throw new AuthenticationException(SR.net_auth_eof, null); + } + + buffer = EnsureBufferSize(buffer, readBytes, readBytes + restBytes); + + if (asyncRequest == null) + { + restBytes = _reader.ReadPacket(buffer, readBytes, restBytes); + } + else + { + asyncRequest.SetNextRequest(buffer, readBytes, restBytes, s_readFrameCallback); + _reader.AsyncReadPacket(asyncRequest); + if (!asyncRequest.MustCompleteSynchronously) + { + return; + } + + restBytes = asyncRequest.Result; + if (restBytes == 0) + { + //EOF received: fail. + readBytes = 0; + } + } + ProcessReceivedBlob(buffer, readBytes + restBytes, asyncRequest); + } + + private void ProcessReceivedBlob(byte[] buffer, int count, AsyncProtocolRequest asyncRequest) + { + if (count == 0) + { + // EOF received. + throw new AuthenticationException(SR.net_auth_eof, null); + } + + if (_pendingReHandshake) + { + int offset = 0; + Interop.SecurityStatus status = PrivateDecryptData(buffer, ref offset, ref count); + + if (status == Interop.SecurityStatus.OK) + { + Exception e = EnqueueOldKeyDecryptedData(buffer, offset, count); + if (e != null) + { + StartSendAuthResetSignal(null, asyncRequest, e); + return; + } + + _Framing = Framing.Unknown; + StartReceiveBlob(buffer, asyncRequest); + return; + } + else if (status != Interop.SecurityStatus.Renegotiate) + { + // Fail re-handshake. + ProtocolToken message = new ProtocolToken(null, status); + StartSendAuthResetSignal(null, asyncRequest, new AuthenticationException(SR.net_auth_SSPI, message.GetException())); + return; + } + + // We expect only handshake messages from now. + _pendingReHandshake = false; + if (offset != 0) + { + Buffer.BlockCopy(buffer, offset, buffer, 0, count); + } + } + StartSendBlob(buffer, count, asyncRequest); + } + + // + // This is to reset auth state on remote side. + // If this write succeeds we will allow auth retrying. + // + private void StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, Exception exception) + { + if (message == null || message.Size == 0) + { + // + // We don't have an alert to send so cannot retry and fail prematurely. + // + throw exception; + } + + if (asyncRequest == null) + { + InnerStream.Write(message.Payload, 0, message.Size); + } + else + { + asyncRequest.AsyncState = exception; + IAsyncResult ar = InnerStreamAPM.BeginWrite(message.Payload, 0, message.Size, s_writeCallback, asyncRequest); + if (!ar.CompletedSynchronously) + { + return; + } + InnerStreamAPM.EndWrite(ar); + } + + throw exception; + } + + // - Loads the channel parameters + // - Optionally verifies the Remote Certificate + // - Sets HandshakeCompleted flag + // - Sets the guarding event if other thread is waiting for + // handshake completino + // + // - Returns false if failed to verify the Remote Cert + // + private bool CompleteHandshake() + { + GlobalLog.Enter("CompleteHandshake"); + Context.ProcessHandshakeSuccess(); + + if (!Context.VerifyRemoteCertificate(_certValidationDelegate)) + { + _handshakeCompleted = false; + _certValidationFailed = true; + GlobalLog.Leave("CompleteHandshake", false); + return false; + } + + _certValidationFailed = false; + _handshakeCompleted = true; + GlobalLog.Leave("CompleteHandshake", true); + return true; + } + + private static void WriteCallback(IAsyncResult transportResult) + { + if (transportResult.CompletedSynchronously) + { + return; + } + + AsyncProtocolRequest asyncRequest; + SslState sslState; + +#if DEBUG + try + { +#endif + asyncRequest = (AsyncProtocolRequest)transportResult.AsyncState; + sslState = (SslState)asyncRequest.AsyncObject; +#if DEBUG + } + catch (Exception exception) + { + if (!ExceptionCheck.IsFatal(exception)) + { + GlobalLog.Assert("SslState::WriteCallback", "Exception while decoding context. type:" + exception.GetType().ToString() + " message:" + exception.Message); + } + + throw; + } +#endif + + // Async completion. + try + { + sslState.InnerStreamAPM.EndWrite(transportResult); + + // Special case for an error notification. + object asyncState = asyncRequest.AsyncState; + Exception exception = asyncState as Exception; + if (exception != null) + { + throw exception; + } + + sslState.CheckCompletionBeforeNextReceive((ProtocolToken)asyncState, asyncRequest); + } + catch (Exception e) + { + if (asyncRequest.IsUserCompleted) + { + // This will throw on a worker thread. + throw; + } + + sslState.FinishHandshake(e, asyncRequest); + } + } + + private static void PartialFrameCallback(AsyncProtocolRequest asyncRequest) + { + GlobalLog.Print("SslState::PartialFrameCallback()"); + + // Async ONLY completion. + SslState sslState = (SslState)asyncRequest.AsyncObject; + try + { + sslState.StartReadFrame(asyncRequest.Buffer, asyncRequest.Result, asyncRequest); + } + catch (Exception e) + { + if (asyncRequest.IsUserCompleted) + { + // This will throw on a worker thread. + throw; + } + + sslState.FinishHandshake(e, asyncRequest); + } + } + // + // + private static void ReadFrameCallback(AsyncProtocolRequest asyncRequest) + { + GlobalLog.Print("SslState::ReadFrameCallback()"); + + // Async ONLY completion. + SslState sslState = (SslState)asyncRequest.AsyncObject; + try + { + if (asyncRequest.Result == 0) + { + //EOF received: will fail. + asyncRequest.Offset = 0; + } + + sslState.ProcessReceivedBlob(asyncRequest.Buffer, asyncRequest.Offset + asyncRequest.Result, asyncRequest); + } + catch (Exception e) + { + if (asyncRequest.IsUserCompleted) + { + // This will throw on a worker thread. + throw; + } + + sslState.FinishHandshake(e, asyncRequest); + } + } + + private bool CheckEnqueueHandshakeRead(ref byte[] buffer, AsyncProtocolRequest request) + { + LazyAsyncResult lazyResult = null; + lock (this) + { + if (_lockReadState == LockPendingRead) + { + return false; + } + + int lockState = Interlocked.Exchange(ref _lockReadState, LockHandshake); + if (lockState != LockRead) + { + return false; + } + + if (request != null) + { + _queuedReadStateRequest = request; + return true; + } + + lazyResult = new LazyAsyncResult(null, null, /*must be */ null); + _queuedReadStateRequest = lazyResult; + } + + // Need to exit from lock before waiting. + lazyResult.InternalWaitForCompletion(); + buffer = (byte[])lazyResult.Result; + return false; + } + + private void FinishHandshakeRead(int newState) + { + lock (this) + { + // Lock is redundant here. Included for clarity. + int lockState = Interlocked.Exchange(ref _lockReadState, newState); + + if (lockState != LockPendingRead) + { + return; + } + + _lockReadState = LockRead; + object obj = _queuedReadStateRequest; + if (obj == null) + { + // Other thread did not get under the lock yet. + return; + } + + _queuedReadStateRequest = null; + if (obj is LazyAsyncResult) + { + ((LazyAsyncResult)obj).InvokeCallback(); + } + else + { + ThreadPool.QueueUserWorkItem(new WaitCallback(CompleteRequestWaitCallback), obj); + } + } + } + + // Returns: + // -1 - proceed + // 0 - queued + // X - some bytes are ready, no need for IO + internal int CheckEnqueueRead(byte[] buffer, int offset, int count, AsyncProtocolRequest request) + { + int lockState = Interlocked.CompareExchange(ref _lockReadState, LockRead, LockNone); + + if (lockState != LockHandshake) + { + // Proceed, no concurent handshake is ongoing so no need for a lock. + return CheckOldKeyDecryptedData(buffer, offset, count); + } + + LazyAsyncResult lazyResult = null; + lock (this) + { + int result = CheckOldKeyDecryptedData(buffer, offset, count); + if (result != -1) + { + return result; + } + + // Check again under lock. + if (_lockReadState != LockHandshake) + { + // The other thread has finished before we grabbed the lock. + _lockReadState = LockRead; + return -1; + } + + _lockReadState = LockPendingRead; + + if (request != null) + { + // Request queued. + _queuedReadStateRequest = request; + return 0; + } + lazyResult = new LazyAsyncResult(null, null, /*must be */ null); + _queuedReadStateRequest = lazyResult; + } + // Need to exit from lock before waiting. + lazyResult.InternalWaitForCompletion(); + lock (this) + { + return CheckOldKeyDecryptedData(buffer, offset, count); + } + } + + internal void FinishRead(byte[] renegotiateBuffer) + { + int lockState = Interlocked.CompareExchange(ref _lockReadState, LockNone, LockRead); + + if (lockState != LockHandshake) + { + return; + } + + lock (this) + { + LazyAsyncResult ar = _queuedReadStateRequest as LazyAsyncResult; + if (ar != null) + { + _queuedReadStateRequest = null; + ar.InvokeCallback(renegotiateBuffer); + } + else + { + AsyncProtocolRequest request = (AsyncProtocolRequest)_queuedReadStateRequest; + request.Buffer = renegotiateBuffer; + _queuedReadStateRequest = null; + ThreadPool.QueueUserWorkItem(new WaitCallback(AsyncResumeHandshakeRead), request); + } + } + } + + // Returns: + // true - operation queued + // false - operation can proceed + internal bool CheckEnqueueWrite(AsyncProtocolRequest asyncRequest) + { + // Clear previous request. + _queuedWriteStateRequest = null; + int lockState = Interlocked.CompareExchange(ref _lockWriteState, LockWrite, LockNone); + if (lockState != LockHandshake) + { + // Proceed with write. + return false; + } + + LazyAsyncResult lazyResult = null; + lock (this) + { + if (_lockWriteState != LockHandshake) + { + // Handshake has completed before we grabbed the lock. + CheckThrow(true); + return false; + } + + _lockWriteState = LockPendingWrite; + + // Still pending, wait or enqueue. + if (asyncRequest != null) + { + _queuedWriteStateRequest = asyncRequest; + return true; + } + + lazyResult = new LazyAsyncResult(null, null, /*must be */null); + _queuedWriteStateRequest = lazyResult; + } + + // Need to exit from lock before waiting. + lazyResult.InternalWaitForCompletion(); + CheckThrow(true); + return false; + } + + internal void FinishWrite() + { + int lockState = Interlocked.CompareExchange(ref _lockWriteState, LockNone, LockWrite); + if (lockState != LockHandshake) + { + return; + } + + lock (this) + { + object obj = _queuedWriteStateRequest; + if (obj == null) + { + // A repeated call. + return; + } + + _queuedWriteStateRequest = null; + if (obj is LazyAsyncResult) + { + // Sync handshake is waiting on other thread. + ((LazyAsyncResult)obj).InvokeCallback(); + } + else + { + // Async handshake is pending, start it on other thread. + // Consider: we could start it in on this thread but that will delay THIS write completion + ThreadPool.QueueUserWorkItem(new WaitCallback(AsyncResumeHandshake), obj); + } + } + } + + // Returns: + // true - operation queued + // false - operation can proceed + private bool CheckEnqueueHandshake(byte[] buffer, AsyncProtocolRequest asyncRequest) + { + LazyAsyncResult lazyResult = null; + + lock (this) + { + if (_lockWriteState == LockPendingWrite) + { + return false; + } + + int lockState = Interlocked.Exchange(ref _lockWriteState, LockHandshake); + if (lockState != LockWrite) + { + // Proceed with handshake. + return false; + } + + if (asyncRequest != null) + { + asyncRequest.Buffer = buffer; + _queuedWriteStateRequest = asyncRequest; + return true; + } + + lazyResult = new LazyAsyncResult(null, null, /*must be*/null); + _queuedWriteStateRequest = lazyResult; + } + lazyResult.InternalWaitForCompletion(); + return false; + } + + private void FinishHandshake(Exception e, AsyncProtocolRequest asyncRequest) + { + try + { + lock (this) + { + if (e != null) + { + SetException(e); + } + + // Release read if any. + FinishHandshakeRead(LockNone); + + // If there is a pending write we want to keep it's lock state. + int lockState = Interlocked.CompareExchange(ref _lockWriteState, LockNone, LockHandshake); + if (lockState != LockPendingWrite) + { + return; + } + + _lockWriteState = LockWrite; + object obj = _queuedWriteStateRequest; + if (obj == null) + { + // We finished before Write has grabbed the lock. + return; + } + + _queuedWriteStateRequest = null; + + if (obj is LazyAsyncResult) + { + // Sync write is waiting on other thread. + ((LazyAsyncResult)obj).InvokeCallback(); + } + else + { + // Async write is pending, start it on other thread. + // Consider: we could start it in on this thread but that will delay THIS handshake completion + ThreadPool.QueueUserWorkItem(new WaitCallback(CompleteRequestWaitCallback), obj); + } + } + } + finally + { + if (asyncRequest != null) + { + if (e != null) + { + asyncRequest.CompleteWithError(e); + } + else + { + asyncRequest.CompleteUser(); + } + } + } + } + + private static byte[] EnsureBufferSize(byte[] buffer, int copyCount, int size) + { + if (buffer == null || buffer.Length < size) + { + byte[] saved = buffer; + buffer = new byte[size]; + if (saved != null && copyCount != 0) + { + Buffer.BlockCopy(saved, 0, buffer, 0, copyCount); + } + } + return buffer; + } + + private enum Framing + { + Unknown = 0, + BeforeSSL3, + SinceSSL3, + Unified, + Invalid + } + + // This is set on the first packet to figure out the framing style. + private Framing _Framing = Framing.Unknown; + + // SSL3/TLS protocol frames definitions. + private enum FrameType : byte + { + ChangeCipherSpec = 20, + Alert = 21, + Handshake = 22, + AppData = 23 + } + + // We need at least 5 bytes to determine what we have. + private Framing DetectFraming(byte[] bytes, int length) + { + /* PCTv1.0 Hello starts with + * RECORD_LENGTH_MSB (ignore) + * RECORD_LENGTH_LSB (ignore) + * PCT1_CLIENT_HELLO (must be equal) + * PCT1_CLIENT_VERSION_MSB (if version greater than PCTv1) + * PCT1_CLIENT_VERSION_LSB (if version greater than PCTv1) + * + * ... PCT hello ... + */ + + /* Microsft Unihello starts with + * RECORD_LENGTH_MSB (ignore) + * RECORD_LENGTH_LSB (ignore) + * SSL2_CLIENT_HELLO (must be equal) + * SSL2_CLIENT_VERSION_MSB (if version greater than SSLv2) ( or v3) + * SSL2_CLIENT_VERSION_LSB (if version greater than SSLv2) ( or v3) + * + * ... SSLv2 Compatible Hello ... + */ + + /* SSLv2 CLIENT_HELLO starts with + * RECORD_LENGTH_MSB (ignore) + * RECORD_LENGTH_LSB (ignore) + * SSL2_CLIENT_HELLO (must be equal) + * SSL2_CLIENT_VERSION_MSB (if version greater than SSLv2) ( or v3) + * SSL2_CLIENT_VERSION_LSB (if version greater than SSLv2) ( or v3) + * + * ... SSLv2 CLIENT_HELLO ... + */ + + /* SSLv2 SERVER_HELLO starts with + * RECORD_LENGTH_MSB (ignore) + * RECORD_LENGTH_LSB (ignore) + * SSL2_SERVER_HELLO (must be equal) + * SSL2_SESSION_ID_HIT (ignore) + * SSL2_CERTIFICATE_TYPE (ignore) + * SSL2_CLIENT_VERSION_MSB (if version greater than SSLv2) ( or v3) + * SSL2_CLIENT_VERSION_LSB (if version greater than SSLv2) ( or v3) + * + * ... SSLv2 SERVER_HELLO ... + */ + + /* SSLv3 Type 2 Hello starts with + * RECORD_LENGTH_MSB (ignore) + * RECORD_LENGTH_LSB (ignore) + * SSL2_CLIENT_HELLO (must be equal) + * SSL2_CLIENT_VERSION_MSB (if version greater than SSLv3) + * SSL2_CLIENT_VERSION_LSB (if version greater than SSLv3) + * + * ... SSLv2 Compatible Hello ... + */ + + /* SSLv3 Type 3 Hello starts with + * 22 (HANDSHAKE MESSAGE) + * VERSION MSB + * VERSION LSB + * RECORD_LENGTH_MSB (ignore) + * RECORD_LENGTH_LSB (ignore) + * HS TYPE (CLIENT_HELLO) + * 3 bytes HS record length + * HS Version + * HS Version + */ + + /* SSLv2 message codes + * SSL_MT_ERROR 0 + * SSL_MT_CLIENT_HELLO 1 + * SSL_MT_CLIENT_MASTER_KEY 2 + * SSL_MT_CLIENT_FINISHED 3 + * SSL_MT_SERVER_HELLO 4 + * SSL_MT_SERVER_VERIFY 5 + * SSL_MT_SERVER_FINISHED 6 + * SSL_MT_REQUEST_CERTIFICATE 7 + * SSL_MT_CLIENT_CERTIFICATE 8 + */ + + int version = -1; + + GlobalLog.Assert((bytes != null && bytes.Length > 0), "SslState::DetectFraming()|Header buffer is not allocated will boom shortly."); + + // If the first byte is SSL3 HandShake, then check if we have a SSLv3 Type3 client hello. + if (bytes[0] == (byte)FrameType.Handshake || bytes[0] == (byte)FrameType.AppData + || bytes[0] == (byte)FrameType.Alert) + { + if (length < 3) + { + return Framing.Invalid; + } + +#if TRACE_VERBOSE + if (bytes[1] != 3) + { + GlobalLog.Print("WARNING: SslState::DetectFraming() SSL protocol is > 3, trying SSL3 framing in retail = " + bytes[1].ToString("x", NumberFormatInfo.InvariantInfo)); + } +#endif + + version = (bytes[1] << 8) | bytes[2]; + if (version < 0x300 || version >= 0x500) + { + return Framing.Invalid; + } + + // + // This is an SSL3 Framing + // + return Framing.SinceSSL3; + } + +#if TRACE_VERBOSE + if ((bytes[0] & 0x80) == 0) + { + // We have a three-byte header format + GlobalLog.Print("WARNING: SslState::DetectFraming() SSL v <=2 HELLO has no high bit set for 3 bytes header, we are broken, received byte = " + bytes[0].ToString("x", NumberFormatInfo.InvariantInfo)); + } +#endif + + if (length < 3) + { + return Framing.Invalid; + } + + if (bytes[2] > 8) + { + return Framing.Invalid; + } + + if (bytes[2] == 0x1) // SSL_MT_CLIENT_HELLO + { + if (length >= 5) + { + version = (bytes[3] << 8) | bytes[4]; + } + } + else if (bytes[2] == 0x4) // SSL_MT_SERVER_HELLO + { + if (length >= 7) + { + version = (bytes[5] << 8) | bytes[6]; + } + } + + if (version != -1) + { + // If this is the first packet, the client may start with an SSL2 packet + // but stating that the version is 3.x, so check the full range. + // For the subsequent packets we assume that an SSL2 packet should have a 2.x version. + if (_Framing == Framing.Unknown) + { + if (version != 0x0002 && (version < 0x200 || version >= 0x500)) + { + return Framing.Invalid; + } + } + else + { + if (version != 0x0002) + { + return Framing.Invalid; + } + } + } + + // When server has replied the framing is already fixed depending on the prior client packet + if (!Context.IsServer || _Framing == Framing.Unified) + { + return Framing.BeforeSSL3; + } + + return Framing.Unified; // Will use Ssl2 just for this frame. + } + + // + // This is called from SslStream class too. + internal int GetRemainingFrameSize(byte[] buffer, int dataSize) + { + GlobalLog.Enter("GetRemainingFrameSize", "dataSize = " + dataSize); + int payloadSize = -1; + switch (_Framing) + { + case Framing.Unified: + case Framing.BeforeSSL3: + if (dataSize < 2) + { + throw new System.IO.IOException(SR.net_ssl_io_frame); + } + // Note: Cannot detect version mismatch for <= SSL2 + + if ((buffer[0] & 0x80) != 0) + { + // Two bytes + payloadSize = (((buffer[0] & 0x7f) << 8) | buffer[1]) + 2; + payloadSize -= dataSize; + } + else + { + // Three bytes + payloadSize = (((buffer[0] & 0x3f) << 8) | buffer[1]) + 3; + payloadSize -= dataSize; + } + + break; + case Framing.SinceSSL3: + if (dataSize < 5) + { + throw new System.IO.IOException(SR.net_ssl_io_frame); + } + + payloadSize = ((buffer[3] << 8) | buffer[4]) + 5; + payloadSize -= dataSize; + break; + default: + break; + } + GlobalLog.Leave("GetRemainingFrameSize", payloadSize); + return payloadSize; + } + + // + // Called with no user stack. + // + private void AsyncResumeHandshake(object state) + { + AsyncProtocolRequest request = state as AsyncProtocolRequest; + Debug.Assert(request != null, "Expected an AsyncProtocolRequest reference."); + + try + { + ForceAuthentication(Context.IsServer, request.Buffer, request); + } + catch (Exception e) + { + request.CompleteWithError(e); + } + } + + // + // Called with no user stack. + // + private void AsyncResumeHandshakeRead(object state) + { + AsyncProtocolRequest asyncRequest = (AsyncProtocolRequest)state; + try + { + if (_pendingReHandshake) + { + // Resume as read a blob. + StartReceiveBlob(asyncRequest.Buffer, asyncRequest); + } + else + { + // Resume as process the blob. + ProcessReceivedBlob(asyncRequest.Buffer, asyncRequest.Buffer == null ? 0 : asyncRequest.Buffer.Length, asyncRequest); + } + } + catch (Exception e) + { + if (asyncRequest.IsUserCompleted) + { + // This will throw on a worker thread. + throw; + } + + FinishHandshake(e, asyncRequest); + } + } + + // + // Called with no user stack. + // + private void CompleteRequestWaitCallback(object state) + { + AsyncProtocolRequest request = (AsyncProtocolRequest)state; + + // Force async completion. + if (request.MustCompleteSynchronously) + { + throw new InternalException(); + } + + request.CompleteRequest(0); + } + + private void RehandshakeCompleteCallback(IAsyncResult result) + { + LazyAsyncResult lazyAsyncResult = (LazyAsyncResult)result; + GlobalLog.Assert(lazyAsyncResult != null, "SslState::RehandshakeCompleteCallback()|result is null!"); + GlobalLog.Assert(lazyAsyncResult.InternalPeekCompleted, "SslState::RehandshakeCompleteCallback()|result is not completed!"); + + // If the rehandshake succeeded, FinishHandshake has already been called; if there was a SocketException + // during the handshake, this gets called directly from FixedSizeReader, and we need to call + // FinishHandshake to wake up the Read that triggered this rehandshake so the error gets back to the caller + Exception exception = lazyAsyncResult.InternalWaitForCompletion() as Exception; + if (exception != null) + { + // We may be calling FinishHandshake reentrantly, as FinishHandshake can call + // asyncRequest.CompleteWithError, which will result in this method being called. + // This is not a problem because: + // + // 1. We pass null as the asyncRequest parameter, so this second call to FinishHandshake won't loop + // back here. + // + // 2. _QueuedWriteStateRequest and _QueuedReadStateRequest are set to null after the first call, + // so, we won't invoke their callbacks again. + // + // 3. SetException won't overwrite an already-set _Exception. + // + // 4. There are three possibilites for _LockReadState and _LockWriteState: + // + // a. They were set back to None by the first call to FinishHandshake, and this will set them to + // None again: a no-op. + // + // b. They were set to None by the first call to FinishHandshake, but as soon as the lock was given + // up, another thread took a read/write lock. Calling FinishHandshake again will set them back + // to None, but that's fine because that thread will be throwing _Exception before it actually + // does any reading or writing and setting them back to None in a catch block anyways. + // + // c. If there is a Read/Write going on another thread, and the second FinishHandshake clears its + // read/write lock, it's fine because no other Read/Write can look at the lock until the current + // one gives up _SslStream._NestedRead/Write, and no handshake will look at the lock because + // handshakes are only triggered in response to successful reads (which won't happen once + // _Exception is set). + + FinishHandshake(exception, null); + } + } + } +} diff --git a/src/System.Net.Security/src/System/Net/SecureProtocols/_SslStream.cs b/src/System.Net.Security/src/System/Net/SecureProtocols/_SslStream.cs new file mode 100644 index 000000000000..c8a70d6acdca --- /dev/null +++ b/src/System.Net.Security/src/System/Net/SecureProtocols/_SslStream.cs @@ -0,0 +1,748 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.IO; +using System.Threading; + +namespace System.Net.Security +{ + // + // This is a wrapping stream that does data encryption/decryption based on a successfully authenticated SSPI context. + // + internal class _SslStream + { + private static AsyncCallback s_writeCallback = new AsyncCallback(WriteCallback); + private static AsyncProtocolCallback s_resumeAsyncWriteCallback = new AsyncProtocolCallback(ResumeAsyncWriteCallback); + private static AsyncProtocolCallback s_resumeAsyncReadCallback = new AsyncProtocolCallback(ResumeAsyncReadCallback); + private static AsyncProtocolCallback s_readHeaderCallback = new AsyncProtocolCallback(ReadHeaderCallback); + private static AsyncProtocolCallback s_readFrameCallback = new AsyncProtocolCallback(ReadFrameCallback); + + private const int PinnableReadBufferSize = 4096 * 4 + 32; // We read in 16K chunks + headers. + private static PinnableBufferCache s_PinnableReadBufferCache = new PinnableBufferCache("System.Net.SslStream", PinnableReadBufferSize); + private const int PinnableWriteBufferSize = 4096 + 1024; // We write in 4K chunks + encryption overhead. + private static PinnableBufferCache s_PinnableWriteBufferCache = new PinnableBufferCache("System.Net.SslStream", PinnableWriteBufferSize); + + private SslState _SslState; + private int _NestedWrite; + private int _NestedRead; + + // Never updated directly, special properties are used. This is the read buffer. + private byte[] _InternalBuffer; + private bool _InternalBufferFromPinnableCache; + + private byte[] _PinnableOutputBuffer; // Used for writes when we can do it. + private byte[] _PinnableOutputBufferInUse; // Remembers what UNENCRYPTED buffer is using _PinnableOutputBuffer. + + private int _InternalOffset; + private int _InternalBufferCount; + + private FixedSizeReader _Reader; + + internal _SslStream(SslState sslState) + { + if (PinnableBufferCacheEventSource.Log.IsEnabled()) + { + PinnableBufferCacheEventSource.Log.DebugMessage1("CTOR: In System.Net._SslStream.SslStream", this.GetHashCode()); + } + + _SslState = sslState; + _Reader = new FixedSizeReader(_SslState.InnerStream); + } + + // If we have a read buffer from the pinnable cache, return it. + private void FreeReadBuffer() + { + if (_InternalBufferFromPinnableCache) + { + s_PinnableReadBufferCache.FreeBuffer(_InternalBuffer); + _InternalBufferFromPinnableCache = false; + } + + _InternalBuffer = null; + } + + ~_SslStream() + { + if (_InternalBufferFromPinnableCache) + { + if (PinnableBufferCacheEventSource.Log.IsEnabled()) + { + PinnableBufferCacheEventSource.Log.DebugMessage2("DTOR: In System.Net._SslStream.~SslStream Freeing Read Buffer", this.GetHashCode(), PinnableBufferCacheEventSource.AddressOfByteArray(_InternalBuffer)); + } + + FreeReadBuffer(); + } + if (_PinnableOutputBuffer != null) + { + if (PinnableBufferCacheEventSource.Log.IsEnabled()) + { + PinnableBufferCacheEventSource.Log.DebugMessage2("DTOR: In System.Net._SslStream.~SslStream Freeing Write Buffer", this.GetHashCode(), PinnableBufferCacheEventSource.AddressOfByteArray(_PinnableOutputBuffer)); + } + + s_PinnableWriteBufferCache.FreeBuffer(_PinnableOutputBuffer); + } + } + + internal int Read(byte[] buffer, int offset, int count) + { + return ProcessRead(buffer, offset, count, null); + } + + internal void Write(byte[] buffer, int offset, int count) + { + ProcessWrite(buffer, offset, count, null); + } + + internal bool DataAvailable + { + get { return InternalBufferCount != 0; } + } + + private byte[] InternalBuffer + { + get + { + return _InternalBuffer; + } + } + + private int InternalOffset + { + get + { + return _InternalOffset; + } + } + + private int InternalBufferCount + { + get + { + return _InternalBufferCount; + } + } + + private void SkipBytes(int decrCount) + { + _InternalOffset += decrCount; + _InternalBufferCount -= decrCount; + } + + // + // This will set the internal offset to "curOffset" and ensure internal buffer. + // If not enough, reallocate and copy up to "curOffset". + // + private void EnsureInternalBufferSize(int curOffset, int addSize) + { + if (_InternalBuffer == null || _InternalBuffer.Length < addSize + curOffset) + { + bool wasPinnable = _InternalBufferFromPinnableCache; + byte[] saved = _InternalBuffer; + + int newSize = addSize + curOffset; + if (newSize <= PinnableReadBufferSize) + { + if (PinnableBufferCacheEventSource.Log.IsEnabled()) + { + PinnableBufferCacheEventSource.Log.DebugMessage2("In System.Net._SslStream.EnsureInternalBufferSize IS pinnable", this.GetHashCode(), newSize); + } + + _InternalBufferFromPinnableCache = true; + _InternalBuffer = s_PinnableReadBufferCache.AllocateBuffer(); + } + else + { + if (PinnableBufferCacheEventSource.Log.IsEnabled()) + { + PinnableBufferCacheEventSource.Log.DebugMessage2("In System.Net._SslStream.EnsureInternalBufferSize NOT pinnable", this.GetHashCode(), newSize); + } + + _InternalBufferFromPinnableCache = false; + _InternalBuffer = new byte[newSize]; + } + + if (saved != null && curOffset != 0) + { + Buffer.BlockCopy(saved, 0, _InternalBuffer, 0, curOffset); + } + + if (wasPinnable) + { + s_PinnableReadBufferCache.FreeBuffer(saved); + } + } + _InternalOffset = curOffset; + _InternalBufferCount = curOffset + addSize; + } + + // + // Validates user parameteres for all Read/Write methods. + // + private void ValidateParameters(byte[] buffer, int offset, int count) + { + if (buffer == null) + { + throw new ArgumentNullException("buffer"); + } + + if (offset < 0) + { + throw new ArgumentOutOfRangeException("offset"); + } + + if (count < 0) + { + throw new ArgumentOutOfRangeException("count"); + } + + if (count > buffer.Length - offset) + { + throw new ArgumentOutOfRangeException("count", SR.net_offset_plus_count); + } + } + + // + // Combined sync/async write method. For sync case asyncRequest==null. + // + private void ProcessWrite(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) + { + ValidateParameters(buffer, offset, count); + + if (Interlocked.Exchange(ref _NestedWrite, 1) == 1) + { + throw new NotSupportedException(SR.Format(SR.net_io_invalidnestedcall, (asyncRequest != null ? "BeginWrite" : "Write"), "write")); + } + + bool failed = false; + try + { + StartWriting(buffer, offset, count, asyncRequest); + } + catch (Exception e) + { + _SslState.FinishWrite(); + + failed = true; + if (e is IOException) + { + throw; + } + + throw new IOException(SR.net_io_write, e); + } + finally + { + if (asyncRequest == null || failed) + { + _NestedWrite = 0; + } + } + } + + private void StartWriting(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) + { + if (asyncRequest != null) + { + asyncRequest.SetNextRequest(buffer, offset, count, s_resumeAsyncWriteCallback); + } + + // We loop to this method from the callback. + // If the last chunk was just completed from async callback (count < 0), we complete user request. + if (count >= 0) + { + byte[] outBuffer = null; + if (_PinnableOutputBufferInUse == null) + { + if (_PinnableOutputBuffer == null) + { + _PinnableOutputBuffer = s_PinnableWriteBufferCache.AllocateBuffer(); + } + + _PinnableOutputBufferInUse = buffer; + outBuffer = _PinnableOutputBuffer; + if (PinnableBufferCacheEventSource.Log.IsEnabled()) + { + PinnableBufferCacheEventSource.Log.DebugMessage3("In System.Net._SslStream.StartWriting Trying Pinnable", this.GetHashCode(), count, PinnableBufferCacheEventSource.AddressOfByteArray(outBuffer)); + } + } + else + { + if (PinnableBufferCacheEventSource.Log.IsEnabled()) + { + PinnableBufferCacheEventSource.Log.DebugMessage2("In System.Net._SslStream.StartWriting BufferInUse", this.GetHashCode(), count); + } + } + + do + { + // Request a write IO slot. + if (_SslState.CheckEnqueueWrite(asyncRequest)) + { + // Operation is async and has been queued, return. + return; + } + + int chunkBytes = Math.Min(count, _SslState.MaxDataSize); + int encryptedBytes; + Interop.SecurityStatus errorCode = _SslState.EncryptData(buffer, offset, chunkBytes, ref outBuffer, out encryptedBytes); + if (errorCode != Interop.SecurityStatus.OK) + { + ProtocolToken message = new ProtocolToken(null, errorCode); + throw new IOException(SR.net_io_encrypt, message.GetException()); + } + + if (PinnableBufferCacheEventSource.Log.IsEnabled()) + { + PinnableBufferCacheEventSource.Log.DebugMessage3("In System.Net._SslStream.StartWriting Got Encrypted Buffer", + this.GetHashCode(), encryptedBytes, PinnableBufferCacheEventSource.AddressOfByteArray(outBuffer)); + } + + if (asyncRequest != null) + { + // Prepare for the next request. + asyncRequest.SetNextRequest(buffer, offset + chunkBytes, count - chunkBytes, s_resumeAsyncWriteCallback); + IAsyncResult ar = _SslState.InnerStreamAPM.BeginWrite(outBuffer, 0, encryptedBytes, s_writeCallback, asyncRequest); + if (!ar.CompletedSynchronously) + { + return; + } + + _SslState.InnerStreamAPM.EndWrite(ar); + } + else + { + _SslState.InnerStream.Write(outBuffer, 0, encryptedBytes); + } + + offset += chunkBytes; + count -= chunkBytes; + + // Release write IO slot. + _SslState.FinishWrite(); + } while (count != 0); + } + + if (asyncRequest != null) + { + asyncRequest.CompleteUser(); + } + + if (buffer == _PinnableOutputBufferInUse) + { + _PinnableOutputBufferInUse = null; + if (PinnableBufferCacheEventSource.Log.IsEnabled()) + { + PinnableBufferCacheEventSource.Log.DebugMessage1("In System.Net._SslStream.StartWriting Freeing buffer.", this.GetHashCode()); + } + } + } + + // + // Combined sync/async read method. For sync request asyncRequest==null + // There is a little overhead because we need to pass buffer/offset/count used only in sync. + // Still the benefit is that we have a common sync/async code path. + // + private int ProcessRead(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) + { + ValidateParameters(buffer, offset, count); + + if (Interlocked.Exchange(ref _NestedRead, 1) == 1) + { + throw new NotSupportedException(SR.Format(SR.net_io_invalidnestedcall, (asyncRequest != null ? "BeginRead" : "Read"), "read")); + } + + bool failed = false; + try + { + int copyBytes; + if (InternalBufferCount != 0) + { + copyBytes = InternalBufferCount > count ? count : InternalBufferCount; + if (copyBytes != 0) + { + Buffer.BlockCopy(InternalBuffer, InternalOffset, buffer, offset, copyBytes); + SkipBytes(copyBytes); + } + + if (asyncRequest != null) + { + asyncRequest.CompleteUser((object)copyBytes); + } + + return copyBytes; + } + + return StartReading(buffer, offset, count, asyncRequest); + } + catch (Exception e) + { + _SslState.FinishRead(null); + failed = true; + if (e is IOException) + { + throw; + } + + throw new IOException(SR.net_io_read, e); + } + finally + { + // If sync request or exception. + if (asyncRequest == null || failed) + { + _NestedRead = 0; + } + } + } + + // + // To avoid recursion when decrypted 0 bytes this method will loop until a decrypted result at least 1 byte. + // + private int StartReading(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) + { + int result = 0; + + GlobalLog.Assert(InternalBufferCount == 0, "SslStream::StartReading()|Previous frame was not consumed. InternalBufferCount:{0}", InternalBufferCount); + + do + { + if (asyncRequest != null) + { + asyncRequest.SetNextRequest(buffer, offset, count, s_resumeAsyncReadCallback); + } + + int copyBytes = _SslState.CheckEnqueueRead(buffer, offset, count, asyncRequest); + if (copyBytes == 0) + { + //Queued but not completed! + return 0; + } + + if (copyBytes != -1) + { + if (asyncRequest != null) + { + asyncRequest.CompleteUser((object)copyBytes); + } + + return copyBytes; + } + } + + // When we read -1 bytes means we have decrypted 0 bytes or rehandshaking, need looping. + while ((result = StartFrameHeader(buffer, offset, count, asyncRequest)) == -1); + + return result; + } + + // + // Need read frame size first + // + private int StartFrameHeader(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) + { + int readBytes = 0; + + // + // Always pass InternalBuffer for SSPI "in place" decryption. + // A user buffer can be shared by many threads in that case decryption/integrity check may fail cause of data corruption. + // + + // Reset internal buffer for a new frame. + EnsureInternalBufferSize(0, SecureChannel.ReadHeaderSize); + + if (asyncRequest != null) + { + asyncRequest.SetNextRequest(InternalBuffer, 0, SecureChannel.ReadHeaderSize, s_readHeaderCallback); + _Reader.AsyncReadPacket(asyncRequest); + if (!asyncRequest.MustCompleteSynchronously) + { + return 0; + } + + readBytes = asyncRequest.Result; + } + else + { + readBytes = _Reader.ReadPacket(InternalBuffer, 0, SecureChannel.ReadHeaderSize); + } + + return StartFrameBody(readBytes, buffer, offset, count, asyncRequest); + } + + private int StartFrameBody(int readBytes, byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) + { + if (readBytes == 0) + { + //EOF : Reset the buffer as we did not read anything into it. + SkipBytes(InternalBufferCount); + if (asyncRequest != null) + { + asyncRequest.CompleteUser((object)0); + } + + return 0; + } + + // Now readBytes is a payload size. + readBytes = _SslState.GetRemainingFrameSize(InternalBuffer, readBytes); + + if (readBytes < 0) + { + throw new IOException(SR.net_frame_read_size); + } + + EnsureInternalBufferSize(SecureChannel.ReadHeaderSize, readBytes); + + if (asyncRequest != null) //Async + { + asyncRequest.SetNextRequest(InternalBuffer, SecureChannel.ReadHeaderSize, readBytes, s_readFrameCallback); + + _Reader.AsyncReadPacket(asyncRequest); + + if (!asyncRequest.MustCompleteSynchronously) + { + return 0; + } + + readBytes = asyncRequest.Result; + } + else //Sync + { + readBytes = _Reader.ReadPacket(InternalBuffer, SecureChannel.ReadHeaderSize, readBytes); + } + + return ProcessFrameBody(readBytes, buffer, offset, count, asyncRequest); + } + + // + // readBytes == SSL Data Payload size on input or 0 on EOF + // + private int ProcessFrameBody(int readBytes, byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) + { + if (readBytes == 0) + { + // EOF + throw new IOException(SR.net_io_eof); + } + + // Set readBytes to total number of received bytes. + readBytes += SecureChannel.ReadHeaderSize; + + // Decrypt into internal buffer, change "readBytes" to count now _Decrypted Bytes_. + int data_offset = 0; + + Interop.SecurityStatus errorCode = _SslState.DecryptData(InternalBuffer, ref data_offset, ref readBytes); + + if (errorCode != Interop.SecurityStatus.OK) + { + byte[] extraBuffer = null; + if (readBytes != 0) + { + extraBuffer = new byte[readBytes]; + Buffer.BlockCopy(InternalBuffer, data_offset, extraBuffer, 0, readBytes); + } + + // Reset internal buffer count. + SkipBytes(InternalBufferCount); + return ProcessReadErrorCode(errorCode, buffer, offset, count, asyncRequest, extraBuffer); + } + + + if (readBytes == 0 && count != 0) + { + // Read again since remote side has sent encrypted 0 bytes. + SkipBytes(InternalBufferCount); + return -1; + } + + // Decrypted data start from "data_offset" offset, the total count can be shrunk after decryption. + EnsureInternalBufferSize(0, data_offset + readBytes); + SkipBytes(data_offset); + + if (readBytes > count) + { + readBytes = count; + } + + Buffer.BlockCopy(InternalBuffer, InternalOffset, buffer, offset, readBytes); + + // This will adjust both the remaining internal buffer count and the offset. + SkipBytes(readBytes); + + _SslState.FinishRead(null); + if (asyncRequest != null) + { + asyncRequest.CompleteUser((object)readBytes); + } + + return readBytes; + } + + // + // Only processing SEC_I_RENEGOTIATE. + // + private int ProcessReadErrorCode(Interop.SecurityStatus errorCode, byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest, byte[] extraBuffer) + { + // ERROR - examine what kind + ProtocolToken message = new ProtocolToken(null, errorCode); + + GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::***Processing an error Status = " + message.Status.ToString()); + + if (message.Renegotiate) + { + _SslState.ReplyOnReAuthentication(extraBuffer); + + // Loop on read. + return -1; + } + + if (message.CloseConnection) + { + _SslState.FinishRead(null); + if (asyncRequest != null) + { + asyncRequest.CompleteUser((object)0); + } + + return 0; + } + + throw new IOException(SR.net_io_decrypt, message.GetException()); + } + + private static void WriteCallback(IAsyncResult transportResult) + { + if (transportResult.CompletedSynchronously) + { + return; + } + + GlobalLog.Assert(transportResult.AsyncState is AsyncProtocolRequest, "SslStream::WriteCallback|State type is wrong, expected AsyncProtocolRequest."); + AsyncProtocolRequest asyncRequest = (AsyncProtocolRequest)transportResult.AsyncState; + + _SslStream sslStream = (_SslStream)asyncRequest.AsyncObject; + try + { + sslStream._SslState.InnerStreamAPM.EndWrite(transportResult); + sslStream._SslState.FinishWrite(); + + if (asyncRequest.Count == 0) + { + // This was the last chunk. + asyncRequest.Count = -1; + } + + sslStream.StartWriting(asyncRequest.Buffer, asyncRequest.Offset, asyncRequest.Count, asyncRequest); + } + catch (Exception e) + { + if (asyncRequest.IsUserCompleted) + { + // This will throw on a worker thread. + throw; + } + + sslStream._SslState.FinishWrite(); + asyncRequest.CompleteWithError(e); + } + } + + // + // This is used in a rare situation when async Read is resumed from completed handshake. + // + private static void ResumeAsyncReadCallback(AsyncProtocolRequest request) + { + try + { + ((_SslStream)request.AsyncObject).StartReading(request.Buffer, request.Offset, request.Count, request); + } + catch (Exception e) + { + if (request.IsUserCompleted) + { + // This will throw on a worker thread. + throw; + } + + ((_SslStream)request.AsyncObject)._SslState.FinishRead(null); + request.CompleteWithError(e); + } + } + + // + // This is used in a rare situation when async Write is resumed from completed handshake + // + private static void ResumeAsyncWriteCallback(AsyncProtocolRequest asyncRequest) + { + try + { + ((_SslStream)asyncRequest.AsyncObject).StartWriting( + asyncRequest.Buffer, + asyncRequest.Offset, + asyncRequest.Count, + asyncRequest); + } + catch (Exception e) + { + if (asyncRequest.IsUserCompleted) + { + // This will throw on a worker thread. + throw; + } + + ((_SslStream)asyncRequest.AsyncObject)._SslState.FinishWrite(); + asyncRequest.CompleteWithError(e); + } + } + + private static void ReadHeaderCallback(AsyncProtocolRequest asyncRequest) + { + // Async ONLY completion. + try + { + _SslStream sslStream = (_SslStream)asyncRequest.AsyncObject; + BufferAsyncResult bufferResult = (BufferAsyncResult)asyncRequest.UserAsyncResult; + if (-1 == sslStream.StartFrameBody(asyncRequest.Result, bufferResult.Buffer, bufferResult.Offset, bufferResult.Count, asyncRequest)) + { + // In case we decrypted 0 bytes start another reading. + sslStream.StartReading(bufferResult.Buffer, bufferResult.Offset, bufferResult.Count, asyncRequest); + } + } + catch (Exception e) + { + if (asyncRequest.IsUserCompleted) + { + // This will throw on a worker thread. + throw; + } + + asyncRequest.CompleteWithError(e); + } + } + + private static void ReadFrameCallback(AsyncProtocolRequest asyncRequest) + { + // Async ONLY completion. + try + { + _SslStream sslStream = (_SslStream)asyncRequest.AsyncObject; + BufferAsyncResult bufferResult = (BufferAsyncResult)asyncRequest.UserAsyncResult; + if (-1 == sslStream.ProcessFrameBody(asyncRequest.Result, bufferResult.Buffer, bufferResult.Offset, bufferResult.Count, asyncRequest)) + { + // In case we decrypted 0 bytes start another reading. + sslStream.StartReading(bufferResult.Buffer, bufferResult.Offset, bufferResult.Count, asyncRequest); + } + } + catch (Exception e) + { + if (asyncRequest.IsUserCompleted) + { + // This will throw on a worker thread. + throw; + } + + asyncRequest.CompleteWithError(e); + } + } + } +} diff --git a/src/System.Net.Security/src/System/Net/SecurityContextTokenHandle.cs b/src/System.Net.Security/src/System/Net/SecurityContextTokenHandle.cs new file mode 100644 index 000000000000..89d7fd923de8 --- /dev/null +++ b/src/System.Net.Security/src/System/Net/SecurityContextTokenHandle.cs @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Win32.SafeHandles; + +using System.Threading; + +namespace System.Net.Security +{ +#if DEBUG + internal sealed class SecurityContextTokenHandle : DebugCriticalHandleZeroOrMinusOneIsInvalid + { +#else + internal sealed class SecurityContextTokenHandle : CriticalHandleZeroOrMinusOneIsInvalid + { +#endif + private int _disposed; + + private SecurityContextTokenHandle() : base() + { + } + + protected override bool ReleaseHandle() + { + if (!IsInvalid) + { + if (Interlocked.Increment(ref _disposed) == 1) + { + return Interop.mincore.CloseHandle(handle); + } + } + return true; + } + } +} diff --git a/src/System.Net.Security/src/System/Net/_NativeSSPI.cs b/src/System.Net.Security/src/System/Net/_NativeSSPI.cs new file mode 100644 index 000000000000..209675c6d671 --- /dev/null +++ b/src/System.Net.Security/src/System/Net/_NativeSSPI.cs @@ -0,0 +1,395 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Globalization; +using System.Net.Security; +using System.Runtime.InteropServices; + +namespace System.Net +{ + // Need a global so we can pass the interfaces as variables. + internal static class GlobalSSPI + { + internal static SSPIInterface SSPIAuth = new SSPIAuthType(); + internal static SSPIInterface SSPISecureChannel = new SSPISecureChannelType(); + } + + // Used to define the interface for security to use. + internal interface SSPIInterface + { + SecurityPackageInfoClass[] SecurityPackages { get; set; } + int EnumerateSecurityPackages(out int pkgnum, out SafeFreeContextBuffer pkgArray); + int AcquireCredentialsHandle(string moduleName, Interop.Secur32.CredentialUse usage, ref Interop.Secur32.AuthIdentity authdata, out SafeFreeCredentials outCredential); + int AcquireCredentialsHandle(string moduleName, Interop.Secur32.CredentialUse usage, ref SafeSspiAuthDataHandle authdata, out SafeFreeCredentials outCredential); + int AcquireDefaultCredential(string moduleName, Interop.Secur32.CredentialUse usage, out SafeFreeCredentials outCredential); + int AcquireCredentialsHandle(string moduleName, Interop.Secur32.CredentialUse usage, ref Interop.Secur32.SecureCredential authdata, out SafeFreeCredentials outCredential); + int AcceptSecurityContext(ref SafeFreeCredentials credential, ref SafeDeleteContext context, SecurityBuffer inputBuffer, Interop.Secur32.ContextFlags inFlags, Interop.Secur32.Endianness endianness, SecurityBuffer outputBuffer, ref Interop.Secur32.ContextFlags outFlags); + int AcceptSecurityContext(SafeFreeCredentials credential, ref SafeDeleteContext context, SecurityBuffer[] inputBuffers, Interop.Secur32.ContextFlags inFlags, Interop.Secur32.Endianness endianness, SecurityBuffer outputBuffer, ref Interop.Secur32.ContextFlags outFlags); + int InitializeSecurityContext(ref SafeFreeCredentials credential, ref SafeDeleteContext context, string targetName, Interop.Secur32.ContextFlags inFlags, Interop.Secur32.Endianness endianness, SecurityBuffer inputBuffer, SecurityBuffer outputBuffer, ref Interop.Secur32.ContextFlags outFlags); + int InitializeSecurityContext(SafeFreeCredentials credential, ref SafeDeleteContext context, string targetName, Interop.Secur32.ContextFlags inFlags, Interop.Secur32.Endianness endianness, SecurityBuffer[] inputBuffers, SecurityBuffer outputBuffer, ref Interop.Secur32.ContextFlags outFlags); + int EncryptMessage(SafeDeleteContext context, Interop.Secur32.SecurityBufferDescriptor inputOutput, uint sequenceNumber); + int DecryptMessage(SafeDeleteContext context, Interop.Secur32.SecurityBufferDescriptor inputOutput, uint sequenceNumber); + int MakeSignature(SafeDeleteContext context, Interop.Secur32.SecurityBufferDescriptor inputOutput, uint sequenceNumber); + int VerifySignature(SafeDeleteContext context, Interop.Secur32.SecurityBufferDescriptor inputOutput, uint sequenceNumber); + + int QueryContextChannelBinding(SafeDeleteContext phContext, Interop.Secur32.ContextAttribute attribute, out SafeFreeContextBufferChannelBinding refHandle); + int QueryContextAttributes(SafeDeleteContext phContext, Interop.Secur32.ContextAttribute attribute, byte[] buffer, Type handleType, out SafeHandle refHandle); + int SetContextAttributes(SafeDeleteContext phContext, Interop.Secur32.ContextAttribute attribute, byte[] buffer); + int QuerySecurityContextToken(SafeDeleteContext phContext, out SecurityContextTokenHandle phToken); + int CompleteAuthToken(ref SafeDeleteContext refContext, SecurityBuffer[] inputBuffers); + } + + // For SSL connections: + internal class SSPISecureChannelType : SSPIInterface + { + private static volatile SecurityPackageInfoClass[] s_securityPackages; + + public SecurityPackageInfoClass[] SecurityPackages + { + get + { + return s_securityPackages; + } + set + { + s_securityPackages = value; + } + } + + public int EnumerateSecurityPackages(out int pkgnum, out SafeFreeContextBuffer pkgArray) + { + GlobalLog.Print("SSPISecureChannelType::EnumerateSecurityPackages()"); + return SafeFreeContextBuffer.EnumeratePackages(out pkgnum, out pkgArray); + } + + public int AcquireCredentialsHandle(string moduleName, Interop.Secur32.CredentialUse usage, ref Interop.Secur32.AuthIdentity authdata, out SafeFreeCredentials outCredential) + { + return SafeFreeCredentials.AcquireCredentialsHandle(moduleName, usage, ref authdata, out outCredential); + } + + public int AcquireCredentialsHandle(string moduleName, Interop.Secur32.CredentialUse usage, ref SafeSspiAuthDataHandle authdata, out SafeFreeCredentials outCredential) + { + return SafeFreeCredentials.AcquireCredentialsHandle(moduleName, usage, ref authdata, out outCredential); + } + + public int AcquireDefaultCredential(string moduleName, Interop.Secur32.CredentialUse usage, out SafeFreeCredentials outCredential) + { + return SafeFreeCredentials.AcquireDefaultCredential(moduleName, usage, out outCredential); + } + + public int AcquireCredentialsHandle(string moduleName, Interop.Secur32.CredentialUse usage, ref Interop.Secur32.SecureCredential authdata, out SafeFreeCredentials outCredential) + { + return SafeFreeCredentials.AcquireCredentialsHandle(moduleName, usage, ref authdata, out outCredential); + } + + public int AcceptSecurityContext(ref SafeFreeCredentials credential, ref SafeDeleteContext context, SecurityBuffer inputBuffer, Interop.Secur32.ContextFlags inFlags, Interop.Secur32.Endianness endianness, SecurityBuffer outputBuffer, ref Interop.Secur32.ContextFlags outFlags) + { + return SafeDeleteContext.AcceptSecurityContext(ref credential, ref context, inFlags, endianness, inputBuffer, null, outputBuffer, ref outFlags); + } + + public int AcceptSecurityContext(SafeFreeCredentials credential, ref SafeDeleteContext context, SecurityBuffer[] inputBuffers, Interop.Secur32.ContextFlags inFlags, Interop.Secur32.Endianness endianness, SecurityBuffer outputBuffer, ref Interop.Secur32.ContextFlags outFlags) + { + return SafeDeleteContext.AcceptSecurityContext(ref credential, ref context, inFlags, endianness, null, inputBuffers, outputBuffer, ref outFlags); + } + + public int InitializeSecurityContext(ref SafeFreeCredentials credential, ref SafeDeleteContext context, string targetName, Interop.Secur32.ContextFlags inFlags, Interop.Secur32.Endianness endianness, SecurityBuffer inputBuffer, SecurityBuffer outputBuffer, ref Interop.Secur32.ContextFlags outFlags) + { + return SafeDeleteContext.InitializeSecurityContext(ref credential, ref context, targetName, inFlags, endianness, inputBuffer, null, outputBuffer, ref outFlags); + } + + public int InitializeSecurityContext(SafeFreeCredentials credential, ref SafeDeleteContext context, string targetName, Interop.Secur32.ContextFlags inFlags, Interop.Secur32.Endianness endianness, SecurityBuffer[] inputBuffers, SecurityBuffer outputBuffer, ref Interop.Secur32.ContextFlags outFlags) + { + return SafeDeleteContext.InitializeSecurityContext(ref credential, ref context, targetName, inFlags, endianness, null, inputBuffers, outputBuffer, ref outFlags); + } + + public int EncryptMessage(SafeDeleteContext context, Interop.Secur32.SecurityBufferDescriptor inputOutput, uint sequenceNumber) + { + try + { + bool ignore = false; + context.DangerousAddRef(ref ignore); + return Interop.Secur32.EncryptMessage(ref context._handle, 0, inputOutput, sequenceNumber); + } + finally + { + context.DangerousRelease(); + } + } + + public unsafe int DecryptMessage(SafeDeleteContext context, Interop.Secur32.SecurityBufferDescriptor inputOutput, + uint sequenceNumber) + { + try + { + bool ignore = false; + context.DangerousAddRef(ref ignore); + return Interop.Secur32.DecryptMessage(ref context._handle, inputOutput, sequenceNumber, null); + } + finally + { + context.DangerousRelease(); + } + } + + public int MakeSignature(SafeDeleteContext context, Interop.Secur32.SecurityBufferDescriptor inputOutput, uint sequenceNumber) + { + throw NotImplemented.ByDesignWithMessage(SR.net_MethodNotImplementedException); + } + + public int VerifySignature(SafeDeleteContext context, Interop.Secur32.SecurityBufferDescriptor inputOutput, uint sequenceNumber) + { + throw NotImplemented.ByDesignWithMessage(SR.net_MethodNotImplementedException); + } + + public unsafe int QueryContextChannelBinding(SafeDeleteContext phContext, Interop.Secur32.ContextAttribute attribute, out SafeFreeContextBufferChannelBinding refHandle) + { + refHandle = SafeFreeContextBufferChannelBinding.CreateEmptyHandle(); + + // Bindings is on the stack, so there's no need for a fixed block. + Bindings bindings = new Bindings(); + return SafeFreeContextBufferChannelBinding.QueryContextChannelBinding(phContext, attribute, &bindings, refHandle); + } + + public unsafe int QueryContextAttributes(SafeDeleteContext phContext, Interop.Secur32.ContextAttribute attribute, byte[] buffer, Type handleType, out SafeHandle refHandle) + { + refHandle = null; + if (handleType != null) + { + if (handleType == typeof(SafeFreeContextBuffer)) + { + refHandle = SafeFreeContextBuffer.CreateEmptyHandle(); + } + else if (handleType == typeof(SafeFreeCertContext)) + { + refHandle = new SafeFreeCertContext(); + } + else + { + throw new ArgumentException(SR.Format(SR.SSPIInvalidHandleType, handleType.FullName), "handleType"); + } + } + fixed (byte* bufferPtr = buffer) + { + return SafeFreeContextBuffer.QueryContextAttributes(phContext, attribute, bufferPtr, refHandle); + } + } + + public int SetContextAttributes(SafeDeleteContext phContext, Interop.Secur32.ContextAttribute attribute, byte[] buffer) + { + return SafeFreeContextBuffer.SetContextAttributes(phContext, attribute, buffer); + } + + public int QuerySecurityContextToken(SafeDeleteContext phContext, out SecurityContextTokenHandle phToken) + { + throw new NotSupportedException(); + } + + public int CompleteAuthToken(ref SafeDeleteContext refContext, SecurityBuffer[] inputBuffers) + { + throw new NotSupportedException(); + } + } + + + // For Authentication (Kerberos, NTLM, Negotiate and WDigest): + internal class SSPIAuthType : SSPIInterface + { + private static volatile SecurityPackageInfoClass[] s_securityPackages; + + public SecurityPackageInfoClass[] SecurityPackages + { + get + { + return s_securityPackages; + } + set + { + s_securityPackages = value; + } + } + + public int EnumerateSecurityPackages(out int pkgnum, out SafeFreeContextBuffer pkgArray) + { + GlobalLog.Print("SSPIAuthType::EnumerateSecurityPackages()"); + return SafeFreeContextBuffer.EnumeratePackages(out pkgnum, out pkgArray); + } + + public int AcquireCredentialsHandle(string moduleName, Interop.Secur32.CredentialUse usage, ref Interop.Secur32.AuthIdentity authdata, out SafeFreeCredentials outCredential) + { + return SafeFreeCredentials.AcquireCredentialsHandle(moduleName, usage, ref authdata, out outCredential); + } + + public int AcquireCredentialsHandle(string moduleName, Interop.Secur32.CredentialUse usage, ref SafeSspiAuthDataHandle authdata, out SafeFreeCredentials outCredential) + { + return SafeFreeCredentials.AcquireCredentialsHandle(moduleName, usage, ref authdata, out outCredential); + } + + public int AcquireDefaultCredential(string moduleName, Interop.Secur32.CredentialUse usage, out SafeFreeCredentials outCredential) + { + return SafeFreeCredentials.AcquireDefaultCredential(moduleName, usage, out outCredential); + } + + public int AcquireCredentialsHandle(string moduleName, Interop.Secur32.CredentialUse usage, ref Interop.Secur32.SecureCredential authdata, out SafeFreeCredentials outCredential) + { + return SafeFreeCredentials.AcquireCredentialsHandle(moduleName, usage, ref authdata, out outCredential); + } + + public int AcceptSecurityContext(ref SafeFreeCredentials credential, ref SafeDeleteContext context, SecurityBuffer inputBuffer, Interop.Secur32.ContextFlags inFlags, Interop.Secur32.Endianness endianness, SecurityBuffer outputBuffer, ref Interop.Secur32.ContextFlags outFlags) + { + return SafeDeleteContext.AcceptSecurityContext(ref credential, ref context, inFlags, endianness, inputBuffer, null, outputBuffer, ref outFlags); + } + + public int AcceptSecurityContext(SafeFreeCredentials credential, ref SafeDeleteContext context, SecurityBuffer[] inputBuffers, Interop.Secur32.ContextFlags inFlags, Interop.Secur32.Endianness endianness, SecurityBuffer outputBuffer, ref Interop.Secur32.ContextFlags outFlags) + { + return SafeDeleteContext.AcceptSecurityContext(ref credential, ref context, inFlags, endianness, null, inputBuffers, outputBuffer, ref outFlags); + } + + public int InitializeSecurityContext(ref SafeFreeCredentials credential, ref SafeDeleteContext context, string targetName, Interop.Secur32.ContextFlags inFlags, Interop.Secur32.Endianness endianness, SecurityBuffer inputBuffer, SecurityBuffer outputBuffer, ref Interop.Secur32.ContextFlags outFlags) + { + return SafeDeleteContext.InitializeSecurityContext(ref credential, ref context, targetName, inFlags, endianness, inputBuffer, null, outputBuffer, ref outFlags); + } + + public int InitializeSecurityContext(SafeFreeCredentials credential, ref SafeDeleteContext context, string targetName, Interop.Secur32.ContextFlags inFlags, Interop.Secur32.Endianness endianness, SecurityBuffer[] inputBuffers, SecurityBuffer outputBuffer, ref Interop.Secur32.ContextFlags outFlags) + { + return SafeDeleteContext.InitializeSecurityContext(ref credential, ref context, targetName, inFlags, endianness, null, inputBuffers, outputBuffer, ref outFlags); + } + + + public int EncryptMessage(SafeDeleteContext context, Interop.Secur32.SecurityBufferDescriptor inputOutput, uint sequenceNumber) + { + try + { + bool ignore = false; + + context.DangerousAddRef(ref ignore); + return Interop.Secur32.EncryptMessage(ref context._handle, 0, inputOutput, sequenceNumber); + } + finally + { + context.DangerousRelease(); + } + } + + public unsafe int DecryptMessage(SafeDeleteContext context, Interop.Secur32.SecurityBufferDescriptor inputOutput, uint sequenceNumber) + { + int status = (int)Interop.SecurityStatus.InvalidHandle; + uint qop = 0; + + try + { + bool ignore = false; + context.DangerousAddRef(ref ignore); + status = Interop.Secur32.DecryptMessage(ref context._handle, inputOutput, sequenceNumber, &qop); + } + finally + { + context.DangerousRelease(); + } + + + if (status == 0 && qop == Interop.Secur32.SECQOP_WRAP_NO_ENCRYPT) + { + GlobalLog.Assert("Secur32.DecryptMessage", "Expected qop = 0, returned value = " + qop.ToString("x", CultureInfo.InvariantCulture)); + throw new InvalidOperationException(SR.net_auth_message_not_encrypted); + } + + + return status; + } + + public int MakeSignature(SafeDeleteContext context, Interop.Secur32.SecurityBufferDescriptor inputOutput, uint sequenceNumber) + { + try + { + bool ignore = false; + + context.DangerousAddRef(ref ignore); + + return Interop.Secur32.EncryptMessage(ref context._handle, Interop.Secur32.SECQOP_WRAP_NO_ENCRYPT, inputOutput, sequenceNumber); + } + finally + { + context.DangerousRelease(); + } + } + + public unsafe int VerifySignature(SafeDeleteContext context, Interop.Secur32.SecurityBufferDescriptor inputOutput, uint sequenceNumber) + { + try + { + bool ignore = false; + uint qop = 0; + + context.DangerousAddRef(ref ignore); + return Interop.Secur32.DecryptMessage(ref context._handle, inputOutput, sequenceNumber, &qop); + } + finally + { + context.DangerousRelease(); + } + } + + public int QueryContextChannelBinding(SafeDeleteContext context, Interop.Secur32.ContextAttribute attribute, out SafeFreeContextBufferChannelBinding binding) + { + // Querying an auth SSP for a CBT doesn't make sense + binding = null; + throw new NotSupportedException(); + } + + public unsafe int QueryContextAttributes(SafeDeleteContext context, Interop.Secur32.ContextAttribute attribute, byte[] buffer, Type handleType, out SafeHandle refHandle) + { + refHandle = null; + if (handleType != null) + { + if (handleType == typeof(SafeFreeContextBuffer)) + { + refHandle = SafeFreeContextBuffer.CreateEmptyHandle(); + } + else if (handleType == typeof(SafeFreeCertContext)) + { + refHandle = new SafeFreeCertContext(); + } + else + { + throw new ArgumentException(SR.Format(SR.SSPIInvalidHandleType, handleType.FullName), "handleType"); + } + } + + fixed (byte* bufferPtr = buffer) + { + return SafeFreeContextBuffer.QueryContextAttributes(context, attribute, bufferPtr, refHandle); + } + } + + public int SetContextAttributes(SafeDeleteContext context, Interop.Secur32.ContextAttribute attribute, byte[] buffer) + { + throw NotImplemented.ByDesignWithMessage(SR.net_MethodNotImplementedException); + } + + public int QuerySecurityContextToken(SafeDeleteContext phContext, out SecurityContextTokenHandle phToken) + { + return GetSecurityContextToken(phContext, out phToken); + } + + public int CompleteAuthToken(ref SafeDeleteContext refContext, SecurityBuffer[] inputBuffers) + { + return SafeDeleteContext.CompleteAuthToken(ref refContext, inputBuffers); + } + + private static int GetSecurityContextToken(SafeDeleteContext phContext, out SecurityContextTokenHandle safeHandle) + { + safeHandle = null; + + try + { + bool ignore = false; + phContext.DangerousAddRef(ref ignore); + return Interop.Secur32.QuerySecurityContextToken(ref phContext._handle, out safeHandle); + } + finally + { + phContext.DangerousRelease(); + } + } + } +} diff --git a/src/System.Net.Security/src/System/Net/_SSPIWrapper.cs b/src/System.Net.Security/src/System/Net/_SSPIWrapper.cs new file mode 100644 index 000000000000..3d45cb27e05a --- /dev/null +++ b/src/System.Net.Security/src/System/Net/_SSPIWrapper.cs @@ -0,0 +1,931 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.ComponentModel; +using System.Globalization; +using System.Net.Security; +using System.Runtime.InteropServices; + +namespace System.Net +{ + internal static class SSPIWrapper + { + internal static SecurityPackageInfoClass[] EnumerateSecurityPackages(SSPIInterface secModule) + { + GlobalLog.Enter("EnumerateSecurityPackages"); + if (secModule.SecurityPackages == null) + { + lock (secModule) + { + if (secModule.SecurityPackages == null) + { + int moduleCount = 0; + SafeFreeContextBuffer arrayBaseHandle = null; + try + { + int errorCode = secModule.EnumerateSecurityPackages(out moduleCount, out arrayBaseHandle); + GlobalLog.Print("SSPIWrapper::arrayBase: " + (arrayBaseHandle.DangerousGetHandle().ToString("x"))); + if (errorCode != 0) + { + throw new Win32Exception(errorCode); + } + + SecurityPackageInfoClass[] securityPackages = new SecurityPackageInfoClass[moduleCount]; + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, SR.net_log_sspi_enumerating_security_packages); + } + + int i; + for (i = 0; i < moduleCount; i++) + { + securityPackages[i] = new SecurityPackageInfoClass(arrayBaseHandle, i); + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, " " + securityPackages[i].Name); + } + } + + secModule.SecurityPackages = securityPackages; + } + finally + { + if (arrayBaseHandle != null) + { + arrayBaseHandle.Dispose(); + } + } + } + } + } + GlobalLog.Leave("EnumerateSecurityPackages"); + return secModule.SecurityPackages; + } + + internal static SecurityPackageInfoClass GetVerifyPackageInfo(SSPIInterface secModule, string packageName) + { + return GetVerifyPackageInfo(secModule, packageName, false); + } + + internal static SecurityPackageInfoClass GetVerifyPackageInfo(SSPIInterface secModule, string packageName, bool throwIfMissing) + { + SecurityPackageInfoClass[] supportedSecurityPackages = EnumerateSecurityPackages(secModule); + if (supportedSecurityPackages != null) + { + for (int i = 0; i < supportedSecurityPackages.Length; i++) + { + if (string.Compare(supportedSecurityPackages[i].Name, packageName, StringComparison.OrdinalIgnoreCase) == 0) + { + return supportedSecurityPackages[i]; + } + } + } + + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, SR.Format(SR.net_log_sspi_security_package_not_found, packageName)); + } + + if (throwIfMissing) + { + throw new NotSupportedException(SR.net_securitypackagesupport); + } + + return null; + } + + public static SafeFreeCredentials AcquireDefaultCredential(SSPIInterface secModule, string package, Interop.Secur32.CredentialUse intent) + { + GlobalLog.Print("SSPIWrapper::AcquireDefaultCredential(): using " + package); + if (Logging.On) + { + Logging.PrintInfo( + Logging.Web, + "AcquireDefaultCredential(" + + "package = " + package + ", " + + "intent = " + intent + ")"); + } + + SafeFreeCredentials outCredential = null; + int errorCode = secModule.AcquireDefaultCredential(package, intent, out outCredential); + + if (errorCode != 0) + { +#if TRACE_VERBOSE + GlobalLog.Print("SSPIWrapper::AcquireDefaultCredential(): error " + Interop.MapSecurityStatus((uint)errorCode)); +#endif + + if (Logging.On) + { + Logging.PrintError(Logging.Web, SR.Format(SR.net_log_operation_failed_with_error, "AcquireDefaultCredential()", String.Format(CultureInfo.CurrentCulture, "0X{0:X}", errorCode))); + } + + throw new Win32Exception(errorCode); + } + return outCredential; + } + + public static SafeFreeCredentials AcquireCredentialsHandle(SSPIInterface secModule, string package, Interop.Secur32.CredentialUse intent, ref Interop.Secur32.AuthIdentity authdata) + { + GlobalLog.Print("SSPIWrapper::AcquireCredentialsHandle#2(): using " + package); + + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, + "AcquireCredentialsHandle(" + + "package = " + package + ", " + + "intent = " + intent + ", " + + "authdata = " + authdata + ")"); + } + + SafeFreeCredentials credentialsHandle = null; + int errorCode = secModule.AcquireCredentialsHandle(package, + intent, + ref authdata, + out credentialsHandle + ); + + if (errorCode != 0) + { +#if TRACE_VERBOSE + GlobalLog.Print("SSPIWrapper::AcquireCredentialsHandle#2(): error " + Interop.MapSecurityStatus((uint)errorCode)); +#endif + if (Logging.On) + { + Logging.PrintError(Logging.Web, SR.Format(SR.net_log_operation_failed_with_error, "AcquireCredentialsHandle()", String.Format(CultureInfo.CurrentCulture, "0X{0:X}", errorCode))); + } + + throw new Win32Exception(errorCode); + } + return credentialsHandle; + } + + public static SafeFreeCredentials AcquireCredentialsHandle(SSPIInterface secModule, string package, Interop.Secur32.CredentialUse intent, ref SafeSspiAuthDataHandle authdata) + { + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, + "AcquireCredentialsHandle(" + + "package = " + package + ", " + + "intent = " + intent + ", " + + "authdata = " + authdata + ")"); + } + + SafeFreeCredentials credentialsHandle = null; + int errorCode = secModule.AcquireCredentialsHandle(package, intent, ref authdata, out credentialsHandle); + + if (errorCode != 0) + { + if (Logging.On) + { + Logging.PrintError(Logging.Web, SR.Format(SR.net_log_operation_failed_with_error, "AcquireCredentialsHandle()", String.Format(CultureInfo.CurrentCulture, "0X{0:X}", errorCode))); + } + + throw new Win32Exception(errorCode); + } + + return credentialsHandle; + } + + public static SafeFreeCredentials AcquireCredentialsHandle(SSPIInterface secModule, string package, Interop.Secur32.CredentialUse intent, Interop.Secur32.SecureCredential scc) + { + GlobalLog.Print("SSPIWrapper::AcquireCredentialsHandle#3(): using " + package); + + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, + "AcquireCredentialsHandle(" + + "package = " + package + ", " + + "intent = " + intent + ", " + + "scc = " + scc + ")"); + } + + SafeFreeCredentials outCredential = null; + int errorCode = secModule.AcquireCredentialsHandle( + package, + intent, + ref scc, + out outCredential + ); + if (errorCode != 0) + { +#if TRACE_VERBOSE + GlobalLog.Print("SSPIWrapper::AcquireCredentialsHandle#3(): error " + Interop.MapSecurityStatus((uint)errorCode)); +#endif + + if (Logging.On) + { + Logging.PrintError(Logging.Web, SR.Format(SR.net_log_operation_failed_with_error, "AcquireCredentialsHandle()", String.Format(CultureInfo.CurrentCulture, "0X{0:X}", errorCode))); + } + + throw new Win32Exception(errorCode); + } + +#if TRACE_VERBOSE + GlobalLog.Print("SSPIWrapper::AcquireCredentialsHandle#3(): cred handle = " + outCredential.ToString()); +#endif + return outCredential; + } + + internal static int InitializeSecurityContext(SSPIInterface secModule, ref SafeFreeCredentials credential, ref SafeDeleteContext context, string targetName, Interop.Secur32.ContextFlags inFlags, Interop.Secur32.Endianness datarep, SecurityBuffer inputBuffer, SecurityBuffer outputBuffer, ref Interop.Secur32.ContextFlags outFlags) + { + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, + "InitializeSecurityContext(" + + "credential = " + credential.ToString() + ", " + + "context = " + Logging.ObjectToString(context) + ", " + + "targetName = " + targetName + ", " + + "inFlags = " + inFlags + ")"); + } + + int errorCode = secModule.InitializeSecurityContext(ref credential, ref context, targetName, inFlags, datarep, inputBuffer, outputBuffer, ref outFlags); + + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, SR.Format(SR.net_log_sspi_security_context_input_buffer, "InitializeSecurityContext", (inputBuffer == null ? 0 : inputBuffer.size), outputBuffer.size, (Interop.SecurityStatus)errorCode)); + } + + return errorCode; + } + + internal static int InitializeSecurityContext(SSPIInterface secModule, SafeFreeCredentials credential, ref SafeDeleteContext context, string targetName, Interop.Secur32.ContextFlags inFlags, Interop.Secur32.Endianness datarep, SecurityBuffer[] inputBuffers, SecurityBuffer outputBuffer, ref Interop.Secur32.ContextFlags outFlags) + { + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, + "InitializeSecurityContext(" + + "credential = " + credential.ToString() + ", " + + "context = " + Logging.ObjectToString(context) + ", " + + "targetName = " + targetName + ", " + + "inFlags = " + inFlags + ")"); + } + + int errorCode = secModule.InitializeSecurityContext(credential, ref context, targetName, inFlags, datarep, inputBuffers, outputBuffer, ref outFlags); + + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, SR.Format(SR.net_log_sspi_security_context_input_buffers, "InitializeSecurityContext", (inputBuffers == null ? 0 : inputBuffers.Length), outputBuffer.size, (Interop.SecurityStatus)errorCode)); + } + + return errorCode; + } + + internal static int AcceptSecurityContext(SSPIInterface secModule, ref SafeFreeCredentials credential, ref SafeDeleteContext context, Interop.Secur32.ContextFlags inFlags, Interop.Secur32.Endianness datarep, SecurityBuffer inputBuffer, SecurityBuffer outputBuffer, ref Interop.Secur32.ContextFlags outFlags) + { + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, + "AcceptSecurityContext(" + + "credential = " + credential.ToString() + ", " + + "context = " + Logging.ObjectToString(context) + ", " + + "inFlags = " + inFlags + ")"); + } + + int errorCode = secModule.AcceptSecurityContext(ref credential, ref context, inputBuffer, inFlags, datarep, outputBuffer, ref outFlags); + + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, SR.Format(SR.net_log_sspi_security_context_input_buffer, "AcceptSecurityContext", (inputBuffer == null ? 0 : inputBuffer.size), outputBuffer.size, (Interop.SecurityStatus)errorCode)); + } + + return errorCode; + } + + internal static int AcceptSecurityContext(SSPIInterface secModule, SafeFreeCredentials credential, ref SafeDeleteContext context, Interop.Secur32.ContextFlags inFlags, Interop.Secur32.Endianness datarep, SecurityBuffer[] inputBuffers, SecurityBuffer outputBuffer, ref Interop.Secur32.ContextFlags outFlags) + { + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, + "AcceptSecurityContext(" + + "credential = " + credential.ToString() + ", " + + "context = " + Logging.ObjectToString(context) + ", " + + "inFlags = " + inFlags + ")"); + } + + int errorCode = secModule.AcceptSecurityContext(credential, ref context, inputBuffers, inFlags, datarep, outputBuffer, ref outFlags); + + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, SR.Format(SR.net_log_sspi_security_context_input_buffers, "AcceptSecurityContext", (inputBuffers == null ? 0 : inputBuffers.Length), outputBuffer.size, (Interop.SecurityStatus)errorCode)); + } + + return errorCode; + } + + internal static int CompleteAuthToken(SSPIInterface secModule, ref SafeDeleteContext context, SecurityBuffer[] inputBuffers) + { + int errorCode = secModule.CompleteAuthToken(ref context, inputBuffers); + + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, SR.Format(SR.net_log_operation_returned_something, "CompleteAuthToken()", (Interop.SecurityStatus)errorCode)); + } + + return errorCode; + } + + public static int QuerySecurityContextToken(SSPIInterface secModule, SafeDeleteContext context, out SecurityContextTokenHandle token) + { + return secModule.QuerySecurityContextToken(context, out token); + } + + public static int EncryptMessage(SSPIInterface secModule, SafeDeleteContext context, SecurityBuffer[] input, uint sequenceNumber) + { + return EncryptDecryptHelper(OP.Encrypt, secModule, context, input, sequenceNumber); + } + + public static int DecryptMessage(SSPIInterface secModule, SafeDeleteContext context, SecurityBuffer[] input, uint sequenceNumber) + { + return EncryptDecryptHelper(OP.Decrypt, secModule, context, input, sequenceNumber); + } + + internal static int MakeSignature(SSPIInterface secModule, SafeDeleteContext context, SecurityBuffer[] input, uint sequenceNumber) + { + return EncryptDecryptHelper(OP.MakeSignature, secModule, context, input, sequenceNumber); + } + + public static int VerifySignature(SSPIInterface secModule, SafeDeleteContext context, SecurityBuffer[] input, uint sequenceNumber) + { + return EncryptDecryptHelper(OP.VerifySignature, secModule, context, input, sequenceNumber); + } + + private enum OP + { + Encrypt = 1, + Decrypt, + MakeSignature, + VerifySignature + } + + private unsafe static int EncryptDecryptHelper(OP op, SSPIInterface secModule, SafeDeleteContext context, SecurityBuffer[] input, uint sequenceNumber) + { + Interop.Secur32.SecurityBufferDescriptor sdcInOut = new Interop.Secur32.SecurityBufferDescriptor(input.Length); + var unmanagedBuffer = new Interop.Secur32.SecurityBufferStruct[input.Length]; + + fixed (Interop.Secur32.SecurityBufferStruct* unmanagedBufferPtr = unmanagedBuffer) + { + sdcInOut.UnmanagedPointer = unmanagedBufferPtr; + GCHandle[] pinnedBuffers = new GCHandle[input.Length]; + byte[][] buffers = new byte[input.Length][]; + try + { + for (int i = 0; i < input.Length; i++) + { + SecurityBuffer iBuffer = input[i]; + unmanagedBuffer[i].count = iBuffer.size; + unmanagedBuffer[i].type = iBuffer.type; + if (iBuffer.token == null || iBuffer.token.Length == 0) + { + unmanagedBuffer[i].token = IntPtr.Zero; + } + else + { + pinnedBuffers[i] = GCHandle.Alloc(iBuffer.token, GCHandleType.Pinned); + unmanagedBuffer[i].token = Marshal.UnsafeAddrOfPinnedArrayElement(iBuffer.token, iBuffer.offset); + buffers[i] = iBuffer.token; + } + } + + // The result is written in the input Buffer passed as type=BufferType.Data. + int errorCode; + switch (op) + { + case OP.Encrypt: + errorCode = secModule.EncryptMessage(context, sdcInOut, sequenceNumber); + break; + + case OP.Decrypt: + errorCode = secModule.DecryptMessage(context, sdcInOut, sequenceNumber); + break; + + case OP.MakeSignature: + errorCode = secModule.MakeSignature(context, sdcInOut, sequenceNumber); + break; + + case OP.VerifySignature: + errorCode = secModule.VerifySignature(context, sdcInOut, sequenceNumber); + break; + + default: + GlobalLog.Assert("SSPIWrapper::EncryptDecryptHelper", "Unknown OP: " + op); + throw NotImplemented.ByDesignWithMessage(SR.net_MethodNotImplementedException); + } + + // Marshalling back returned sizes / data. + for (int i = 0; i < input.Length; i++) + { + SecurityBuffer iBuffer = input[i]; + iBuffer.size = unmanagedBuffer[i].count; + iBuffer.type = unmanagedBuffer[i].type; + + if (iBuffer.size == 0) + { + iBuffer.offset = 0; + iBuffer.token = null; + } + else + { + checked + { + // Find the buffer this is inside of. Usually they all point inside buffer 0. + int j; + for (j = 0; j < input.Length; j++) + { + if (buffers[j] == null) + { + continue; + } + + byte* bufferAddress = (byte*)Marshal.UnsafeAddrOfPinnedArrayElement(buffers[j], 0); + if ((byte*)unmanagedBuffer[i].token >= bufferAddress && + (byte*)unmanagedBuffer[i].token + iBuffer.size <= bufferAddress + buffers[j].Length) + { + iBuffer.offset = (int)((byte*)unmanagedBuffer[i].token - bufferAddress); + iBuffer.token = buffers[j]; + break; + } + } + + if (j >= input.Length) + { + GlobalLog.Assert("SSPIWrapper::EncryptDecryptHelper", "Output buffer out of range."); + iBuffer.size = 0; + iBuffer.offset = 0; + iBuffer.token = null; + } + } + } + + // Backup validate the new sizes. + GlobalLog.Assert(iBuffer.offset >= 0 && iBuffer.offset <= (iBuffer.token == null ? 0 : iBuffer.token.Length), "SSPIWrapper::EncryptDecryptHelper|'offset' out of range. [{0}]", iBuffer.offset); + GlobalLog.Assert(iBuffer.size >= 0 && iBuffer.size <= (iBuffer.token == null ? 0 : iBuffer.token.Length - iBuffer.offset), "SSPIWrapper::EncryptDecryptHelper|'size' out of range. [{0}]", iBuffer.size); + } + + if (errorCode != 0 && Logging.On) + { + if (errorCode == Interop.Secur32.SEC_I_RENEGOTIATE) + { + Logging.PrintError(Logging.Web, SR.Format(SR.net_log_operation_returned_something, op, "SEC_I_RENEGOTIATE")); + } + else + { + Logging.PrintError(Logging.Web, SR.Format(SR.net_log_operation_failed_with_error, op, String.Format(CultureInfo.CurrentCulture, "0X{0:X}", errorCode))); + } + } + + return errorCode; + } + finally + { + for (int i = 0; i < pinnedBuffers.Length; ++i) + { + if (pinnedBuffers[i].IsAllocated) + { + pinnedBuffers[i].Free(); + } + } + } + } + } + + public static SafeFreeContextBufferChannelBinding QueryContextChannelBinding(SSPIInterface secModule, SafeDeleteContext securityContext, Interop.Secur32.ContextAttribute contextAttribute) + { + GlobalLog.Enter("QueryContextChannelBinding", contextAttribute.ToString()); + + SafeFreeContextBufferChannelBinding result; + int errorCode = secModule.QueryContextChannelBinding(securityContext, contextAttribute, out result); + if (errorCode != 0) + { + GlobalLog.Leave("QueryContextChannelBinding", "ERROR = " + ErrorDescription(errorCode)); + return null; + } + + GlobalLog.Leave("QueryContextChannelBinding", Logging.HashString(result)); + return result; + } + + public static object QueryContextAttributes(SSPIInterface secModule, SafeDeleteContext securityContext, Interop.Secur32.ContextAttribute contextAttribute) + { + int errorCode; + return QueryContextAttributes(secModule, securityContext, contextAttribute, out errorCode); + } + + public static object QueryContextAttributes(SSPIInterface secModule, SafeDeleteContext securityContext, Interop.Secur32.ContextAttribute contextAttribute, out int errorCode) + { + GlobalLog.Enter("QueryContextAttributes", contextAttribute.ToString()); + + int nativeBlockSize = IntPtr.Size; + Type handleType = null; + + switch (contextAttribute) + { + case Interop.Secur32.ContextAttribute.Sizes: + nativeBlockSize = SecSizes.SizeOf; + break; + case Interop.Secur32.ContextAttribute.StreamSizes: + nativeBlockSize = StreamSizes.SizeOf; + break; + + case Interop.Secur32.ContextAttribute.Names: + handleType = typeof(SafeFreeContextBuffer); + break; + + case Interop.Secur32.ContextAttribute.PackageInfo: + handleType = typeof(SafeFreeContextBuffer); + break; + + case Interop.Secur32.ContextAttribute.NegotiationInfo: + handleType = typeof(SafeFreeContextBuffer); + nativeBlockSize = Marshal.SizeOf(); + break; + + case Interop.Secur32.ContextAttribute.ClientSpecifiedSpn: + handleType = typeof(SafeFreeContextBuffer); + break; + + case Interop.Secur32.ContextAttribute.RemoteCertificate: + handleType = typeof(SafeFreeCertContext); + break; + + case Interop.Secur32.ContextAttribute.LocalCertificate: + handleType = typeof(SafeFreeCertContext); + break; + + case Interop.Secur32.ContextAttribute.IssuerListInfoEx: + nativeBlockSize = Marshal.SizeOf(); + handleType = typeof(SafeFreeContextBuffer); + break; + + case Interop.Secur32.ContextAttribute.ConnectionInfo: + nativeBlockSize = Marshal.SizeOf(); + break; + + default: + throw new ArgumentException(SR.Format(SR.net_invalid_enum, "ContextAttribute"), "contextAttribute"); + } + + SafeHandle sspiHandle = null; + object attribute = null; + + try + { + byte[] nativeBuffer = new byte[nativeBlockSize]; + errorCode = secModule.QueryContextAttributes(securityContext, contextAttribute, nativeBuffer, handleType, out sspiHandle); + if (errorCode != 0) + { + GlobalLog.Leave("Win32:QueryContextAttributes", "ERROR = " + ErrorDescription(errorCode)); + return null; + } + + switch (contextAttribute) + { + case Interop.Secur32.ContextAttribute.Sizes: + attribute = new SecSizes(nativeBuffer); + break; + + case Interop.Secur32.ContextAttribute.StreamSizes: + attribute = new StreamSizes(nativeBuffer); + break; + + case Interop.Secur32.ContextAttribute.Names: + attribute = Marshal.PtrToStringUni(sspiHandle.DangerousGetHandle()); + break; + + case Interop.Secur32.ContextAttribute.PackageInfo: + attribute = new SecurityPackageInfoClass(sspiHandle, 0); + break; + + case Interop.Secur32.ContextAttribute.NegotiationInfo: + unsafe + { + fixed (void* ptr = nativeBuffer) + { + attribute = new NegotiationInfoClass(sspiHandle, Marshal.ReadInt32(new IntPtr(ptr), NegotiationInfo.NegotiationStateOffest)); + } + } + break; + + case Interop.Secur32.ContextAttribute.ClientSpecifiedSpn: + attribute = Marshal.PtrToStringUni(sspiHandle.DangerousGetHandle()); + break; + + case Interop.Secur32.ContextAttribute.LocalCertificate: + // Fall-through to RemoteCertificate is intentional. + case Interop.Secur32.ContextAttribute.RemoteCertificate: + attribute = sspiHandle; + sspiHandle = null; + break; + + case Interop.Secur32.ContextAttribute.IssuerListInfoEx: + attribute = new Interop.Secur32.IssuerListInfoEx(sspiHandle, nativeBuffer); + sspiHandle = null; + break; + + case Interop.Secur32.ContextAttribute.ConnectionInfo: + attribute = new SslConnectionInfo(nativeBuffer); + break; + default: + // Will return null. + break; + } + } + finally + { + if (sspiHandle != null) + { + sspiHandle.Dispose(); + } + } + GlobalLog.Leave("QueryContextAttributes", Logging.ObjectToString(attribute)); + return attribute; + } + + public static string ErrorDescription(int errorCode) + { + if (errorCode == -1) + { + return "An exception when invoking Win32 API"; + } + + switch ((Interop.SecurityStatus)errorCode) + { + case Interop.SecurityStatus.InvalidHandle: + return "Invalid handle"; + case Interop.SecurityStatus.InvalidToken: + return "Invalid token"; + case Interop.SecurityStatus.ContinueNeeded: + return "Continue needed"; + case Interop.SecurityStatus.IncompleteMessage: + return "Message incomplete"; + case Interop.SecurityStatus.WrongPrincipal: + return "Wrong principal"; + case Interop.SecurityStatus.TargetUnknown: + return "Target unknown"; + case Interop.SecurityStatus.PackageNotFound: + return "Package not found"; + case Interop.SecurityStatus.BufferNotEnough: + return "Buffer not enough"; + case Interop.SecurityStatus.MessageAltered: + return "Message altered"; + case Interop.SecurityStatus.UntrustedRoot: + return "Untrusted root"; + default: + return "0x" + errorCode.ToString("x", NumberFormatInfo.InvariantInfo); + } + } + } // class SSPIWrapper + + + [StructLayout(LayoutKind.Sequential)] + internal class StreamSizes + { + public int header; + public int trailer; + public int maximumMessage; + public int buffersCount; + public int blockSize; + + internal unsafe StreamSizes(byte[] memory) + { + fixed (void* voidPtr = memory) + { + IntPtr unmanagedAddress = new IntPtr(voidPtr); + try + { + header = (int)checked((uint)Marshal.ReadInt32(unmanagedAddress)); + trailer = (int)checked((uint)Marshal.ReadInt32(unmanagedAddress, 4)); + maximumMessage = (int)checked((uint)Marshal.ReadInt32(unmanagedAddress, 8)); + buffersCount = (int)checked((uint)Marshal.ReadInt32(unmanagedAddress, 12)); + blockSize = (int)checked((uint)Marshal.ReadInt32(unmanagedAddress, 16)); + } + catch (OverflowException) + { + GlobalLog.Assert(false, "StreamSizes::.ctor", "Negative size."); + throw; + } + } + } + public static readonly int SizeOf = Marshal.SizeOf(); + } + + [StructLayout(LayoutKind.Sequential)] + internal class SecSizes + { + public readonly int MaxToken; + public readonly int MaxSignature; + public readonly int BlockSize; + public readonly int SecurityTrailer; + + internal unsafe SecSizes(byte[] memory) + { + fixed (void* voidPtr = memory) + { + IntPtr unmanagedAddress = new IntPtr(voidPtr); + try + { + MaxToken = (int)checked((uint)Marshal.ReadInt32(unmanagedAddress)); + MaxSignature = (int)checked((uint)Marshal.ReadInt32(unmanagedAddress, 4)); + BlockSize = (int)checked((uint)Marshal.ReadInt32(unmanagedAddress, 8)); + SecurityTrailer = (int)checked((uint)Marshal.ReadInt32(unmanagedAddress, 12)); + } + catch (OverflowException) + { + GlobalLog.Assert(false, "SecSizes::.ctor", "Negative size."); + throw; + } + } + } + public static readonly int SizeOf = Marshal.SizeOf(); + } + + // TODO (Issue #3114): Move to Interop. + // Investigate if this can be safely converted to a struct. + // From Schannel.h + [StructLayout(LayoutKind.Sequential)] + internal class SslConnectionInfo + { + public readonly int Protocol; + public readonly int DataCipherAlg; + public readonly int DataKeySize; + public readonly int DataHashAlg; + public readonly int DataHashKeySize; + public readonly int KeyExchangeAlg; + public readonly int KeyExchKeySize; + + internal unsafe SslConnectionInfo(byte[] nativeBuffer) + { + fixed (void* voidPtr = nativeBuffer) + { + try + { + // TODO (Issue #3114): replace with Marshal.PtrToStructure. + IntPtr unmanagedAddress = new IntPtr(voidPtr); + Protocol = Marshal.ReadInt32(unmanagedAddress); + DataCipherAlg = Marshal.ReadInt32(unmanagedAddress, 4); + DataKeySize = Marshal.ReadInt32(unmanagedAddress, 8); + DataHashAlg = Marshal.ReadInt32(unmanagedAddress, 12); + DataHashKeySize = Marshal.ReadInt32(unmanagedAddress, 16); + KeyExchangeAlg = Marshal.ReadInt32(unmanagedAddress, 20); + KeyExchKeySize = Marshal.ReadInt32(unmanagedAddress, 24); + } + catch (OverflowException) + { + GlobalLog.Assert(false, "SslConnectionInfo::.ctor", "Negative size."); + throw; + } + } + } + } + + [StructLayout(LayoutKind.Sequential)] + internal struct NegotiationInfo + { + // see SecPkgContext_NegotiationInfoW in + + // [MarshalAs(UnmanagedType.LPStruct)] internal SecurityPackageInfo PackageInfo; + internal IntPtr PackageInfo; + internal uint NegotiationState; + internal static readonly int Size = Marshal.SizeOf(); + internal static readonly int NegotiationStateOffest = (int)Marshal.OffsetOf("NegotiationState"); + } + + // we keep it simple since we use this only to know if NTLM or + // Kerberos are used in the context of a Negotiate handshake + internal class NegotiationInfoClass + { + internal const string NTLM = "NTLM"; + internal const string Kerberos = "Kerberos"; + internal const string WDigest = "WDigest"; + internal const string Negotiate = "Negotiate"; + internal string AuthenticationPackage; + + internal NegotiationInfoClass(SafeHandle safeHandle, int negotiationState) + { + if (safeHandle.IsInvalid) + { + GlobalLog.Print("NegotiationInfoClass::.ctor() the handle is invalid:" + (safeHandle.DangerousGetHandle()).ToString("x")); + return; + } + + IntPtr packageInfo = safeHandle.DangerousGetHandle(); + GlobalLog.Print("NegotiationInfoClass::.ctor() packageInfo:" + packageInfo.ToString("x8") + " negotiationState:" + negotiationState.ToString("x8")); + + if (negotiationState == Interop.Secur32.SECPKG_NEGOTIATION_COMPLETE + || negotiationState == Interop.Secur32.SECPKG_NEGOTIATION_OPTIMISTIC) + { + IntPtr unmanagedString = Marshal.ReadIntPtr(packageInfo, SecurityPackageInfo.NameOffest); + string name = null; + if (unmanagedString != IntPtr.Zero) + { + name = Marshal.PtrToStringUni(unmanagedString); + } + + GlobalLog.Print("NegotiationInfoClass::.ctor() packageInfo:" + packageInfo.ToString("x8") + " negotiationState:" + negotiationState.ToString("x8") + " name:" + Logging.ObjectToString(name)); + + // an optimization for future string comparisons + if (string.Compare(name, Kerberos, StringComparison.OrdinalIgnoreCase) == 0) + { + AuthenticationPackage = Kerberos; + } + else if (string.Compare(name, NTLM, StringComparison.OrdinalIgnoreCase) == 0) + { + AuthenticationPackage = NTLM; + } + else if (string.Compare(name, WDigest, StringComparison.OrdinalIgnoreCase) == 0) + { + AuthenticationPackage = WDigest; + } + else + { + AuthenticationPackage = name; + } + } + } + } + + [StructLayout(LayoutKind.Sequential)] + internal struct SecurityPackageInfo + { + // see SecPkgInfoW in + internal int Capabilities; + internal short Version; + internal short RPCID; + internal int MaxToken; + internal IntPtr Name; + internal IntPtr Comment; + + internal static readonly int Size = Marshal.SizeOf(); + internal static readonly int NameOffest = (int)Marshal.OffsetOf("Name"); + } + + internal class SecurityPackageInfoClass + { + internal int Capabilities = 0; + internal short Version = 0; + internal short RPCID = 0; + internal int MaxToken = 0; + internal string Name = null; + internal string Comment = null; + + /* + * This is to support SSL under semi trusted environment. + * Note that it is only for SSL with no client cert + * + * Important: safeHandle should not be Disposed during construction of this object. + */ + internal SecurityPackageInfoClass(SafeHandle safeHandle, int index) + { + if (safeHandle.IsInvalid) + { + GlobalLog.Print("SecurityPackageInfoClass::.ctor() the pointer is invalid: " + (safeHandle.DangerousGetHandle()).ToString("x")); + return; + } + + IntPtr unmanagedAddress = IntPtrHelper.Add(safeHandle.DangerousGetHandle(), SecurityPackageInfo.Size * index); + GlobalLog.Print("SecurityPackageInfoClass::.ctor() unmanagedPointer: " + ((long)unmanagedAddress).ToString("x")); + + Capabilities = Marshal.ReadInt32(unmanagedAddress, (int)Marshal.OffsetOf("Capabilities")); + Version = Marshal.ReadInt16(unmanagedAddress, (int)Marshal.OffsetOf("Version")); + RPCID = Marshal.ReadInt16(unmanagedAddress, (int)Marshal.OffsetOf("RPCID")); + MaxToken = Marshal.ReadInt32(unmanagedAddress, (int)Marshal.OffsetOf("MaxToken")); + + IntPtr unmanagedString; + + unmanagedString = Marshal.ReadIntPtr(unmanagedAddress, (int)Marshal.OffsetOf("Name")); + if (unmanagedString != IntPtr.Zero) + { + Name = Marshal.PtrToStringUni(unmanagedString); + GlobalLog.Print("Name: " + Name); + } + + unmanagedString = Marshal.ReadIntPtr(unmanagedAddress, (int)Marshal.OffsetOf("Comment")); + if (unmanagedString != IntPtr.Zero) + { + Comment = Marshal.PtrToStringUni(unmanagedString); + GlobalLog.Print("Comment: " + Comment); + } + + GlobalLog.Print("SecurityPackageInfoClass::.ctor(): " + ToString()); + } + + public override string ToString() + { + return "Capabilities:" + String.Format(CultureInfo.InvariantCulture, "0x{0:x}", Capabilities) + + " Version:" + Version.ToString(NumberFormatInfo.InvariantInfo) + + " RPCID:" + RPCID.ToString(NumberFormatInfo.InvariantInfo) + + " MaxToken:" + MaxToken.ToString(NumberFormatInfo.InvariantInfo) + + " Name:" + ((Name == null) ? "(null)" : Name) + + " Comment:" + ((Comment == null) ? "(null)" : Comment + ); + } + } + + [StructLayout(LayoutKind.Sequential)] + internal struct Bindings + { + // see SecPkgContext_Bindings in + internal int BindingsLength; + internal IntPtr pBindings; + } +} diff --git a/src/System.Net.Security/src/System/Net/_SecureChannel.cs b/src/System.Net.Security/src/System/Net/_SecureChannel.cs new file mode 100644 index 000000000000..3199d9bdf81b --- /dev/null +++ b/src/System.Net.Security/src/System/Net/_SecureChannel.cs @@ -0,0 +1,1614 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Win32.SafeHandles; + +using System.Collections; +using System.ComponentModel; +using System.Diagnostics; +using System.Globalization; +using System.Runtime.InteropServices; +using System.Security; +using System.Security.Authentication.ExtendedProtection; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; +using System.Security.Principal; + +namespace System.Net.Security +{ + // + // SecureChannel - a wrapper on SSPI based functionality. + // Provides an additional abstraction layer over SSPI for SslStream. + // + internal class SecureChannel + { + //also used as a lock object + internal const string SecurityPackage = "Microsoft Unified Security Protocol Provider"; + private static readonly object s_syncObject = new object(); + + private const Interop.Secur32.ContextFlags RequiredFlags = + Interop.Secur32.ContextFlags.ReplayDetect | + Interop.Secur32.ContextFlags.SequenceDetect | + Interop.Secur32.ContextFlags.Confidentiality | + Interop.Secur32.ContextFlags.AllocateMemory; + + private const Interop.Secur32.ContextFlags ServerRequiredFlags = + RequiredFlags | Interop.Secur32.ContextFlags.AcceptStream; + + private const int ChainRevocationCheckExcludeRoot = 0x40000000; + + // When reading a frame from the wire first read this many bytes for the header. + internal const int ReadHeaderSize = 5; + + private static volatile X509Store s_myCertStoreEx; + private static volatile X509Store s_myMachineCertStoreEx; + + private SafeFreeCredentials _credentialsHandle; + private SafeDeleteContext _securityContext; + private Interop.Secur32.ContextFlags _attributes; + private readonly string _destination; + private readonly string _hostName; + + private readonly bool _serverMode; + private readonly bool _remoteCertRequired; + private readonly int _protocolFlags; + private readonly EncryptionPolicy _encryptionPolicy; + private SslConnectionInfo _connectionInfo; + + private X509Certificate _serverCertificate; + private X509Certificate _selectedClientCertificate; + private bool _isRemoteCertificateAvailable; + + private readonly X509CertificateCollection _clientCertificates; + private LocalCertSelectionCallback _certSelectionDelegate; + + // These are the MAX encrypt buffer output sizes, not the actual sizes. + private int _headerSize = 5; //ATTN must be set to at least 5 by default + private int _trailerSize = 16; + private int _maxDataSize = 16354; + + private bool _checkCertRevocation; + private bool _checkCertName; + + private bool _refreshCredentialNeeded; + + + internal SecureChannel(string hostname, bool serverMode, int protocolFlags, X509Certificate serverCertificate, X509CertificateCollection clientCertificates, bool remoteCertRequired, bool checkCertName, + bool checkCertRevocationStatus, EncryptionPolicy encryptionPolicy, LocalCertSelectionCallback certSelectionDelegate) + { + GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::.ctor", "hostname:" + hostname + " #clientCertificates=" + ((clientCertificates == null) ? "0" : clientCertificates.Count.ToString(NumberFormatInfo.InvariantInfo))); + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, this, ".ctor", "hostname=" + hostname + ", #clientCertificates=" + ((clientCertificates == null) ? "0" : clientCertificates.Count.ToString(NumberFormatInfo.InvariantInfo)) + ", encryptionPolicy=" + encryptionPolicy); + } + + SSPIWrapper.GetVerifyPackageInfo(GlobalSSPI.SSPISecureChannel, SecurityPackage, true); + + _destination = hostname; + + GlobalLog.Assert(hostname != null, "SecureChannel#{0}::.ctor()|hostname == null", Logging.HashString(this)); + _hostName = hostname; + _serverMode = serverMode; + + if (serverMode) + { + _protocolFlags = (protocolFlags & Interop.SChannel.ServerProtocolMask); + } + else + { + _protocolFlags = (protocolFlags & Interop.SChannel.ClientProtocolMask); + } + + _serverCertificate = serverCertificate; + _clientCertificates = clientCertificates; + _remoteCertRequired = remoteCertRequired; + _securityContext = null; + _checkCertRevocation = checkCertRevocationStatus; + _checkCertName = checkCertName; + _certSelectionDelegate = certSelectionDelegate; + _refreshCredentialNeeded = true; + _encryptionPolicy = encryptionPolicy; + GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::.ctor"); + } + + // + // SecureChannel properties + // + // LocalServerCertificate - local certificate for server mode channel + // LocalClientCertificate - selected certificated used in the client channel mode otherwise null + // IsRemoteCertificateAvailable - true if the remote side has provided a certificate + // HeaderSize - Header & trailer sizes used in the TLS stream + // TrailerSize - + // + internal X509Certificate LocalServerCertificate + { + get + { + return _serverCertificate; + } + } + + internal X509Certificate LocalClientCertificate + { + get + { + return _selectedClientCertificate; + } + } + + internal bool IsRemoteCertificateAvailable + { + get + { + return _isRemoteCertificateAvailable; + } + } + + private unsafe static class UnmanagedCertificateContext + { + internal static X509Certificate2Collection GetRemoteCertificatesFromStoreContext(SafeFreeCertContext certContext) + { + X509Certificate2Collection result = new X509Certificate2Collection(); + + if (certContext.IsInvalid) + { + return result; + } + + Interop.Crypt32.CERT_CONTEXT context = + Marshal.PtrToStructure(certContext.DangerousGetHandle()); + + if (context.hCertStore != IntPtr.Zero) + { + X509Store store = null; + try + { + store = X509StoreExtensions.CreateFromNativeHandle(context.hCertStore); + result = store.Certificates; + } + finally + { + if (store != null) + { + store.Dispose(); + } + } + } + return result; + } + } + + // + // Extracts a remote certificate upon request. + // + internal X509Certificate2 GetRemoteCertificate(out X509Certificate2Collection remoteCertificateStore) + { + remoteCertificateStore = null; + + if (_securityContext == null) + { + return null; + } + + GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::RemoteCertificate{get;}"); + X509Certificate2 result = null; + SafeFreeCertContext remoteContext = null; + try + { + remoteContext = SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPISecureChannel, _securityContext, Interop.Secur32.ContextAttribute.RemoteCertificate) as SafeFreeCertContext; + if (remoteContext != null && !remoteContext.IsInvalid) + { + result = new X509Certificate2(remoteContext.DangerousGetHandle()); + } + } + finally + { + if (remoteContext != null && !remoteContext.IsInvalid) + { + remoteCertificateStore = UnmanagedCertificateContext.GetRemoteCertificatesFromStoreContext(remoteContext); + + remoteContext.Dispose(); + } + } + + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, SR.Format(SR.net_log_remote_certificate, (result == null ? "null" : result.ToString(true)))); + } + + GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::RemoteCertificate{get;}", (result == null ? "null" : result.Subject)); + + return result; + } + + internal ChannelBinding GetChannelBinding(ChannelBindingKind kind) + { + GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::GetChannelBindingToken", kind.ToString()); + + ChannelBinding result = null; + if (_securityContext != null) + { + result = SSPIWrapper.QueryContextChannelBinding(GlobalSSPI.SSPISecureChannel, _securityContext, (Interop.Secur32.ContextAttribute)kind); + } + + GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::GetChannelBindingToken", Logging.HashString(result)); + return result; + } + + internal bool CheckCertRevocationStatus + { + get + { + return _checkCertRevocation; + } + } + + internal X509CertificateCollection ClientCertificates + { + get + { + return _clientCertificates; + } + } + + internal int HeaderSize + { + get + { + return _headerSize; + } + } + + internal int MaxDataSize + { + get + { + return _maxDataSize; + } + } + + internal SslConnectionInfo ConnectionInfo + { + get + { + return _connectionInfo; + } + } + + internal bool IsValidContext + { + get + { + return !(_securityContext == null || _securityContext.IsInvalid); + } + } + + internal bool IsServer + { + get + { + return _serverMode; + } + } + + internal bool RemoteCertRequired + { + get + { + return _remoteCertRequired; + } + } + + internal void SetRefreshCredentialNeeded() + { + _refreshCredentialNeeded = true; + } + + internal void Close() + { + if (_securityContext != null) + { + _securityContext.Dispose(); + } + + if (_credentialsHandle != null) + { + _credentialsHandle.Dispose(); + } + } + + // + // SECURITY: we open a private key container on behalf of the caller + // and we require the caller to have permission associated with that operation. + // + private X509Certificate2 EnsurePrivateKey(X509Certificate certificate) + { + if (certificate == null) + { + return null; + } + + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, this, SR.Format(SR.net_log_locating_private_key_for_certificate, certificate.ToString(true))); + } + + try + { + string certHash = null; + + // Protecting from X509Certificate2 derived classes. + X509Certificate2 certEx = MakeEx(certificate); + + certHash = certEx.Thumbprint; + + if (certEx != null) + { + if (certEx.HasPrivateKey) + { + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, this, SR.net_log_cert_is_of_type_2); + } + + return certEx; + } + + if ((object)certificate != (object)certEx) + { + certEx.Dispose(); + } + } + + X509Certificate2Collection collectionEx; + + // ELSE Try the MY user and machine stores for private key check. + // For server side mode MY machine store takes priority. + X509Store store = EnsureStoreOpened(_serverMode); + if (store != null) + { + collectionEx = store.Certificates.Find(X509FindType.FindByThumbprint, certHash, false); + if (collectionEx.Count > 0 && collectionEx[0].HasPrivateKey) + { + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, this, SR.Format(SR.net_log_found_cert_in_store, (_serverMode ? "LocalMachine" : "CurrentUser"))); + } + + return collectionEx[0]; + } + } + + store = EnsureStoreOpened(!_serverMode); + if (store != null) + { + collectionEx = store.Certificates.Find(X509FindType.FindByThumbprint, certHash, false); + if (collectionEx.Count > 0 && collectionEx[0].HasPrivateKey) + { + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, this, SR.Format(SR.net_log_found_cert_in_store, (_serverMode ? "CurrentUser" : "LocalMachine"))); + } + + return collectionEx[0]; + } + } + } + catch (CryptographicException) + { + } + + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, this, SR.net_log_did_not_find_cert_in_store); + } + + return null; + } + + // + // Security: We temporarily reset thread token to open the cert store under process account. + // + internal static X509Store EnsureStoreOpened(bool isMachineStore) + { + X509Store store = isMachineStore ? s_myMachineCertStoreEx : s_myCertStoreEx; + if (store == null) + { + lock (s_syncObject) + { + store = isMachineStore ? s_myMachineCertStoreEx : s_myCertStoreEx; + if (store == null) + { + // NOTE: that if this call fails we won't keep track and the next time we enter we will try to open the store again. + StoreLocation storeLocation = isMachineStore ? StoreLocation.LocalMachine : StoreLocation.CurrentUser; + store = new X509Store(StoreName.My, storeLocation); + try + { + // For app-compat We want to ensure the store is opened under the **process** account. + try + { + WindowsIdentity.RunImpersonated(SafeAccessTokenHandle.InvalidHandle, () => + { + store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly); + GlobalLog.Print("SecureChannel::EnsureStoreOpened() storeLocation:" + storeLocation + " returned store:" + store.GetHashCode().ToString("x")); + }); + } + catch + { + throw; + } + + if (isMachineStore) + { + s_myMachineCertStoreEx = store; + } + else + { + s_myCertStoreEx = store; + } + + return store; + } + catch (Exception exception) + { + if (exception is CryptographicException || exception is SecurityException) + { + GlobalLog.Assert("SecureChannel::EnsureStoreOpened()", "Failed to open cert store, location:" + storeLocation + " exception:" + exception); + return null; + } + + if (Logging.On) + { + Logging.PrintError(Logging.Web, SR.Format(SR.net_log_open_store_failed, storeLocation, exception)); + } + + throw; + } + } + } + } + return store; + } + + private static X509Certificate2 MakeEx(X509Certificate certificate) + { + Debug.Assert(certificate != null, "certificate != null"); + + if (certificate.GetType() == typeof(X509Certificate2)) + { + return (X509Certificate2)certificate; + } + + X509Certificate2 certificateEx = null; + try + { + if (certificate.Handle != IntPtr.Zero) + { + certificateEx = new X509Certificate2(certificate.Handle); + } + } + catch (SecurityException) { } + catch (CryptographicException) { } + + return certificateEx; + } + + // + // Get certificate_authorities list, according to RFC 5246, Section 7.4.4. + // Used only by client SSL code, never returns null. + // + private string[] GetRequestCertificateAuthorities() + { + string[] issuers = Array.Empty(); + + if (IsValidContext) + { + Interop.Secur32.IssuerListInfoEx issuerList = (Interop.Secur32.IssuerListInfoEx)SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPISecureChannel, _securityContext, Interop.Secur32.ContextAttribute.IssuerListInfoEx); + try + { + if (issuerList.cIssuers > 0) + { + unsafe + { + uint count = issuerList.cIssuers; + issuers = new string[issuerList.cIssuers]; + Interop.Secur32._CERT_CHAIN_ELEMENT* pIL = (Interop.Secur32._CERT_CHAIN_ELEMENT*)issuerList.aIssuers.DangerousGetHandle(); + for (int i = 0; i < count; ++i) + { + Interop.Secur32._CERT_CHAIN_ELEMENT* pIL2 = pIL + i; + GlobalLog.Assert(pIL2->cbSize > 0, "SecureChannel::GetIssuers()", "Interop.Secur32._CERT_CHAIN_ELEMENT size is not positive: " + pIL2->cbSize.ToString()); + if (pIL2->cbSize > 0) + { + uint size = pIL2->cbSize; + byte* ptr = (byte*)(pIL2->pCertContext); + byte[] x = new byte[size]; + for (int j = 0; j < size; j++) + { + x[j] = *(ptr + j); + } + + X500DistinguishedName x500DistinguishedName = new X500DistinguishedName(x); + issuers[i] = x500DistinguishedName.Name; + GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::GetIssuers() IssuerListEx[" + i + "]:" + issuers[i]); + } + } + } + } + } + finally + { + if (issuerList.aIssuers != null) + { + issuerList.aIssuers.Dispose(); + } + } + } + return issuers; + } + + /*++ + AcquireCredentials - Attempts to find Client Credential + Information, that can be sent to the server. In our case, + this is only Client Certificates, that we have Credential Info. + + How it works: + case 0: Cert Selection delegate is present + Always use its result as the client cert answer. + Try to use cached credential handle whenever feasible. + Do not use cached anonymous creds if the delegate has returned null + and the collection is not empty (allow responding with the cert later). + + case 1: Certs collection is empty + Always use the same statically acquired anonymous SSL Credential + + case 2: Before our Connection with the Server + If we have a cached credential handle keyed by first X509Certificate + **content** in the passed collection, then we use that cached + credential and hoping to restart a session. + + Otherwise create a new anonymous (allow responding with the cert later). + + case 3: After our Connection with the Server (i.e. during handshake or re-handshake) + The server has requested that we send it a Certificate then + we Enumerate a list of server sent Issuers trying to match against + our list of Certificates, the first match is sent to the server. + + Once we got a cert we again try to match cached credential handle if possible. + This will not restart a session but helps minimizing the number of handles we create. + + In the case of an error getting a Certificate or checking its private Key we fall back + to the behavior of having no certs, case 1. + + Returns: True if cached creds were used, false otherwise. + + --*/ + + private bool AcquireClientCredentials(ref byte[] thumbPrint) + { + GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials"); + + // Acquire possible Client Certificate information and set it on the handle. + X509Certificate clientCertificate = null; // This is a candidate that can come from the user callback or be guessed when targeting a session restart. + ArrayList filteredCerts = new ArrayList(); // This is an intermediate client certs collection that try to use if no selectedCert is available yet. + string[] issuers = null; // This is a list of issuers sent by the server, only valid is we do know what the server cert is. + + bool sessionRestartAttempt = false; // If true and no cached creds we will use anonymous creds. + + if (_certSelectionDelegate != null) + { + issuers = GetRequestCertificateAuthorities(); + + GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials() calling CertificateSelectionCallback"); + + X509Certificate2 remoteCert = null; + try + { + X509Certificate2Collection dummyCollection; + remoteCert = GetRemoteCertificate(out dummyCollection); + clientCertificate = _certSelectionDelegate(_hostName, ClientCertificates, remoteCert, issuers); + } + finally + { + if (remoteCert != null) + { + remoteCert.Dispose(); + } + } + + + if (clientCertificate != null) + { + if (_credentialsHandle == null) + { + sessionRestartAttempt = true; + } + + filteredCerts.Add(clientCertificate); + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, this, SR.net_log_got_certificate_from_delegate); + } + } + else + { + if (ClientCertificates.Count == 0) + { + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, this, SR.net_log_no_delegate_and_have_no_client_cert); + } + + sessionRestartAttempt = true; + } + else + { + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, this, SR.net_log_no_delegate_but_have_client_cert); + } + } + } + } + else if (_credentialsHandle == null && _clientCertificates != null && _clientCertificates.Count > 0) + { + // This is where we attempt to restart a session by picking the FIRST cert from the collection. + // Otherwise it is either server sending a client cert request or the session is renegotiated. + clientCertificate = ClientCertificates[0]; + sessionRestartAttempt = true; + if (clientCertificate != null) + { + filteredCerts.Add(clientCertificate); + } + + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, this, SR.Format(SR.net_log_attempting_restart_using_cert, (clientCertificate == null ? "null" : clientCertificate.ToString(true)))); + } + } + else if (_clientCertificates != null && _clientCertificates.Count > 0) + { + // + // This should be a server request for the client cert sent over currently anonymous sessions. + // + issuers = GetRequestCertificateAuthorities(); + + if (Logging.On) + { + if (issuers == null || issuers.Length == 0) + { + Logging.PrintInfo(Logging.Web, this, SR.net_log_no_issuers_try_all_certs); + } + else + { + Logging.PrintInfo(Logging.Web, this, SR.Format(SR.net_log_server_issuers_look_for_matching_certs, issuers.Length)); + } + } + + for (int i = 0; i < _clientCertificates.Count; ++i) + { + // + // Make sure we add only if the cert matches one of the issuers. + // If no issuers were sent and then try all client certs starting with the first one. + // + if (issuers != null && issuers.Length != 0) + { + X509Certificate2 certificateEx = null; + X509Chain chain = null; + try + { + certificateEx = MakeEx(_clientCertificates[i]); + if (certificateEx == null) + { + continue; + } + + GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials() root cert:" + certificateEx.Issuer); + chain = new X509Chain(); + + chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; + chain.ChainPolicy.VerificationFlags = X509VerificationFlags.IgnoreInvalidName; + chain.Build(certificateEx); + bool found = false; + + // + // We ignore any errors happened with chain. + // + if (chain.ChainElements.Count > 0) + { + for (int ii = 0; ii < chain.ChainElements.Count; ++ii) + { + string issuer = chain.ChainElements[ii].Certificate.Issuer; + found = Array.IndexOf(issuers, issuer) != -1; + if (found) + { + GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials() matched:" + issuer); + break; + } + GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials() no match:" + issuer); + } + } + + if (!found) + { + continue; + } + } + finally + { + if (chain != null) + { + chain.Dispose(); + } + + if (certificateEx != null && (object)certificateEx != (object)_clientCertificates[i]) + { + certificateEx.Dispose(); + } + } + } + + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, this, SR.Format(SR.net_log_selected_cert, _clientCertificates[i].ToString(true))); + } + + filteredCerts.Add(_clientCertificates[i]); + } + } + + bool cachedCred = false; // This is a return result from this method. + X509Certificate2 selectedCert = null; // This is a final selected cert (ensured that it does have private key with it). + + clientCertificate = null; + + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, this, SR.Format(SR.net_log_n_certs_after_filtering, filteredCerts.Count)); + if (filteredCerts.Count != 0) + { + Logging.PrintInfo(Logging.Web, this, SR.net_log_finding_matching_certs); + } + } + + // + // ATTN: When the client cert was returned by the user callback OR it was guessed AND it has no private key, + // THEN anonymous (no client cert) credential will be used. + // + // SECURITY: Accessing X509 cert Credential is disabled for semitrust. + // We no longer need to demand for unmanaged code permissions. + // EnsurePrivateKey should do the right demand for us. + for (int i = 0; i < filteredCerts.Count; ++i) + { + clientCertificate = filteredCerts[i] as X509Certificate; + if ((selectedCert = EnsurePrivateKey(clientCertificate)) != null) + { + break; + } + + clientCertificate = null; + selectedCert = null; + } + + GlobalLog.Assert(((object)clientCertificate == (object)selectedCert) || clientCertificate.Equals(selectedCert), "AcquireClientCredentials()|'selectedCert' does not match 'clientCertificate'."); + + GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials() Selected Cert = " + (selectedCert == null ? "null" : selectedCert.Subject)); + try + { + // Try to locate cached creds first. + // + // SECURITY: selectedCert ref if not null is a safe object that does not depend on possible **user** inherited X509Certificate type. + // + byte[] guessedThumbPrint = selectedCert == null ? null : selectedCert.GetCertHash(); + SafeFreeCredentials cachedCredentialHandle = SslSessionsCache.TryCachedCredential(guessedThumbPrint, _protocolFlags, _encryptionPolicy); + + // We can probably do some optimization here. If the selectedCert is returned by the delegate + // we can always go ahead and use the certificate to create our credential + // (instead of going anonymous as we do here). + if (sessionRestartAttempt && cachedCredentialHandle == null && selectedCert != null) + { + GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials() Reset to anonymous session."); + + // IIS does not renegotiate a restarted session if client cert is needed. + // So we don't want to reuse **anonymous** cached credential for a new SSL connection if the client has passed some certificate. + // The following block happens if client did specify a certificate but no cached creds were found in the cache. + // Since we don't restart a session the server side can still challenge for a client cert. + if ((object)clientCertificate != (object)selectedCert) + { + selectedCert.Dispose(); + } + + guessedThumbPrint = null; + selectedCert = null; + clientCertificate = null; + } + + if (cachedCredentialHandle != null) + { + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, SR.net_log_using_cached_credential); + } + + _credentialsHandle = cachedCredentialHandle; + _selectedClientCertificate = clientCertificate; + cachedCred = true; + } + else + { + Interop.Secur32.SecureCredential.Flags flags = Interop.Secur32.SecureCredential.Flags.ValidateManual | Interop.Secur32.SecureCredential.Flags.NoDefaultCred; + + // CoreFX: always opt-in SCH_USE_STRONG_CRYPTO except for SSL3. + if (((_protocolFlags & (Interop.SChannel.SP_PROT_TLS1_0 | Interop.SChannel.SP_PROT_TLS1_1 | Interop.SChannel.SP_PROT_TLS1_2)) != 0) + && (_encryptionPolicy != EncryptionPolicy.AllowNoEncryption) && (_encryptionPolicy != EncryptionPolicy.NoEncryption)) + { + flags |= Interop.Secur32.SecureCredential.Flags.UseStrongCrypto; + } + + Interop.Secur32.SecureCredential secureCredential = CreateSecureCredential( + Interop.Secur32.SecureCredential.CurrentVersion, + selectedCert, + flags, + _protocolFlags, + _encryptionPolicy); + + _credentialsHandle = AcquireCredentialsHandle(Interop.Secur32.CredentialUse.Outbound, secureCredential); + thumbPrint = guessedThumbPrint; // Delay until here in case something above threw. + _selectedClientCertificate = clientCertificate; + } + } + finally + { + // An extra cert could have been created, dispose it now. + if (selectedCert != null && (object)clientCertificate != (object)selectedCert) + { + selectedCert.Dispose(); + } + } + + GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials, cachedCreds = " + cachedCred.ToString(), Logging.ObjectToString(_credentialsHandle)); + return cachedCred; + } + + + // + // Acquire Server Side Certificate information and set it on the class. + // + private bool AcquireServerCredentials(ref byte[] thumbPrint) + { + GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::AcquireServerCredentials"); + + X509Certificate localCertificate = null; + bool cachedCred = false; + + if (_certSelectionDelegate != null) + { + X509CertificateCollection tempCollection = new X509CertificateCollection(); + tempCollection.Add(_serverCertificate); + localCertificate = _certSelectionDelegate(string.Empty, tempCollection, null, Array.Empty()); + GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireServerCredentials() Use delegate selected Cert"); + } + else + { + localCertificate = _serverCertificate; + } + + if (localCertificate == null) + { + throw new NotSupportedException(SR.net_ssl_io_no_server_cert); + } + + // SECURITY: Accessing X509 cert Credential is disabled for semitrust. + // We no longer need to demand for unmanaged code permissions. + // EnsurePrivateKey should do the right demand for us. + X509Certificate2 selectedCert = EnsurePrivateKey(localCertificate); + + if (selectedCert == null) + { + throw new NotSupportedException(SR.net_ssl_io_no_server_cert); + } + + GlobalLog.Assert(localCertificate.Equals(selectedCert), "AcquireServerCredentials()|'selectedCert' does not match 'localCertificate'."); + + // + // Note selectedCert is a safe ref possibly cloned from the user passed Cert object + // + byte[] guessedThumbPrint = selectedCert.GetCertHash(); + try + { + SafeFreeCredentials cachedCredentialHandle = SslSessionsCache.TryCachedCredential(guessedThumbPrint, _protocolFlags, _encryptionPolicy); + + if (cachedCredentialHandle != null) + { + _credentialsHandle = cachedCredentialHandle; + _serverCertificate = localCertificate; + cachedCred = true; + } + else + { + Interop.Secur32.SecureCredential secureCredential = CreateSecureCredential( + Interop.Secur32.SecureCredential.CurrentVersion, + selectedCert, + Interop.Secur32.SecureCredential.Flags.Zero, + _protocolFlags, + _encryptionPolicy); + + _credentialsHandle = AcquireCredentialsHandle(Interop.Secur32.CredentialUse.Inbound, secureCredential); + thumbPrint = guessedThumbPrint; + _serverCertificate = localCertificate; + } + } + finally + { + // An extra cert could have been created, dispose it now. + if ((object)localCertificate != (object)selectedCert) + { + selectedCert.Dispose(); + } + } + + GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::AcquireServerCredentials, cachedCreds = " + cachedCred.ToString(), Logging.ObjectToString(_credentialsHandle)); + return cachedCred; + } + + + // + // Security: we temporarily reset thread token to open the handle under process account. + // + private SafeFreeCredentials AcquireCredentialsHandle(Interop.Secur32.CredentialUse credUsage, Interop.Secur32.SecureCredential secureCredential) + { + // First try without impersonation, if it fails, then try the process account. + // I.E. We don't know which account the certificate context was created under. + try + { + // + // For app-compat we want to ensure the credential are accessed under >>process<< acount. + // + return WindowsIdentity.RunImpersonated(SafeAccessTokenHandle.InvalidHandle, () => + { + return SSPIWrapper.AcquireCredentialsHandle(GlobalSSPI.SSPISecureChannel, SecurityPackage, credUsage, secureCredential); + }); + } + catch + { + return SSPIWrapper.AcquireCredentialsHandle(GlobalSSPI.SSPISecureChannel, SecurityPackage, credUsage, secureCredential); + } + } + + // + internal ProtocolToken NextMessage(byte[] incoming, int offset, int count) + { + GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::NextMessage"); + byte[] nextmsg = null; + Interop.SecurityStatus errorCode = GenerateToken(incoming, offset, count, ref nextmsg); + + if (!_serverMode && errorCode == Interop.SecurityStatus.CredentialsNeeded) + { + GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::NextMessage() returned SecurityStatus.CredentialsNeeded"); + SetRefreshCredentialNeeded(); + errorCode = GenerateToken(incoming, offset, count, ref nextmsg); + } + + ProtocolToken token = new ProtocolToken(nextmsg, errorCode); + GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::NextMessage", token.ToString()); + return token; + } + + /*++ + GenerateToken - Called after each successive state + in the Client - Server handshake. This function + generates a set of bytes that will be sent next to + the server. The server responds, each response, + is pass then into this function, again, and the cycle + repeats until successful connection, or failure. + + Input: + input - bytes from the wire + output - ref to byte [], what we will send to the + server in response + Return: + errorCode - an SSPI error code + --*/ + private Interop.SecurityStatus GenerateToken(byte[] input, int offset, int count, ref byte[] output) + { +#if TRACE_VERBOSE + GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::GenerateToken, _refreshCredentialNeeded = " + _refreshCredentialNeeded); +#endif + + if (offset < 0 || offset > (input == null ? 0 : input.Length)) + { + GlobalLog.Assert(false, "SecureChannel#" + Logging.HashString(this) + "::GenerateToken", "Argument 'offset' out of range."); + throw new ArgumentOutOfRangeException("offset"); + } + + if (count < 0 || count > (input == null ? 0 : input.Length - offset)) + { + GlobalLog.Assert(false, "SecureChannel#" + Logging.HashString(this) + "::GenerateToken", "Argument 'count' out of range."); + throw new ArgumentOutOfRangeException("count"); + } + + SecurityBuffer incomingSecurity = null; + SecurityBuffer[] incomingSecurityBuffers = null; + + if (input != null) + { + incomingSecurity = new SecurityBuffer(input, offset, count, SecurityBufferType.Token); + incomingSecurityBuffers = new SecurityBuffer[] + { + incomingSecurity, + new SecurityBuffer(null, 0, 0, SecurityBufferType.Empty) + }; + } + + SecurityBuffer outgoingSecurity = new SecurityBuffer(null, SecurityBufferType.Token); + + int errorCode = 0; + + bool cachedCreds = false; + byte[] thumbPrint = null; + + // + // Looping through ASC or ISC with potentially cached credential that could have been + // already disposed from a different thread before ISC or ASC dir increment a cred ref count. + // + try + { + do + { + thumbPrint = null; + if (_refreshCredentialNeeded) + { + cachedCreds = _serverMode + ? AcquireServerCredentials(ref thumbPrint) + : AcquireClientCredentials(ref thumbPrint); + } + + if (_serverMode) + { + errorCode = SSPIWrapper.AcceptSecurityContext( + GlobalSSPI.SSPISecureChannel, + ref _credentialsHandle, + ref _securityContext, + ServerRequiredFlags | (_remoteCertRequired ? Interop.Secur32.ContextFlags.MutualAuth : Interop.Secur32.ContextFlags.Zero), + Interop.Secur32.Endianness.Native, + incomingSecurity, + outgoingSecurity, + ref _attributes + ); + } + else + { + if (incomingSecurity == null) + { + errorCode = SSPIWrapper.InitializeSecurityContext( + GlobalSSPI.SSPISecureChannel, + ref _credentialsHandle, + ref _securityContext, + _destination, + RequiredFlags | Interop.Secur32.ContextFlags.InitManualCredValidation, + Interop.Secur32.Endianness.Native, + incomingSecurity, + outgoingSecurity, + ref _attributes + ); + } + else + { + errorCode = SSPIWrapper.InitializeSecurityContext( + GlobalSSPI.SSPISecureChannel, + _credentialsHandle, + ref _securityContext, + _destination, + RequiredFlags | Interop.Secur32.ContextFlags.InitManualCredValidation, + Interop.Secur32.Endianness.Native, + incomingSecurityBuffers, + outgoingSecurity, + ref _attributes + ); + } + } + } while (cachedCreds && _credentialsHandle == null); + } + finally + { + if (_refreshCredentialNeeded) + { + _refreshCredentialNeeded = false; + + // + // Assuming the ISC or ASC has referenced the credential, + // we want to call dispose so to decrement the effective ref count. + // + if (_credentialsHandle != null) + { + _credentialsHandle.Dispose(); + } + + // + // This call may bump up the credential reference count further. + // Note that thumbPrint is retrieved from a safe cert object that was possible cloned from the user passed cert. + // + if (!cachedCreds && _securityContext != null && !_securityContext.IsInvalid && _credentialsHandle != null && !_credentialsHandle.IsInvalid) + { + SslSessionsCache.CacheCredential(_credentialsHandle, thumbPrint, _protocolFlags, _encryptionPolicy); + } + } + } + + output = outgoingSecurity.token; + +#if TRACE_VERBOSE + GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::GenerateToken()", Interop.MapSecurityStatus((uint)errorCode)); +#endif + return (Interop.SecurityStatus)errorCode; + } + + /*++ + ProcessHandshakeSuccess - + Called on successful completion of Handshake - + used to set header/trailer sizes for encryption use + + Fills in the information about established protocol + --*/ + internal void ProcessHandshakeSuccess() + { + GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::ProcessHandshakeSuccess"); + StreamSizes streamSizes = SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPISecureChannel, _securityContext, Interop.Secur32.ContextAttribute.StreamSizes) as StreamSizes; + if (streamSizes != null) + { + try + { + _headerSize = streamSizes.header; + _trailerSize = streamSizes.trailer; + _maxDataSize = checked(streamSizes.maximumMessage - (_headerSize + _trailerSize)); + } + catch (Exception e) + { + if (!ExceptionCheck.IsFatal(e)) + { + GlobalLog.Assert(false, "SecureChannel#" + Logging.HashString(this) + "::ProcessHandshakeSuccess", "StreamSizes out of range."); + } + + throw; + } + } + _connectionInfo = SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPISecureChannel, _securityContext, Interop.Secur32.ContextAttribute.ConnectionInfo) as SslConnectionInfo; + GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::ProcessHandshakeSuccess"); + } + + /*++ + Encrypt - Encrypts our bytes before we send them over the wire + + PERF: make more efficient, this does an extra copy when the offset + is non-zero. + + Input: + buffer - bytes for sending + offset - + size - + output - Encrypted bytes + --*/ + internal Interop.SecurityStatus Encrypt(byte[] buffer, int offset, int size, ref byte[] output, out int resultSize) + { + GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::Encrypt"); + GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::Encrypt() - offset: " + offset.ToString() + " size: " + size.ToString() + " buffersize: " + buffer.Length.ToString()); + GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::Encrypt() buffer:"); + GlobalLog.Dump(buffer, Math.Min(buffer.Length, 128)); + + byte[] writeBuffer; + try + { + if (offset < 0 || offset > (buffer == null ? 0 : buffer.Length)) + { + throw new ArgumentOutOfRangeException("offset"); + } + + if (size < 0 || size > (buffer == null ? 0 : buffer.Length - offset)) + { + throw new ArgumentOutOfRangeException("size"); + } + + resultSize = 0; + + int bufferSizeNeeded = checked(size + _headerSize + _trailerSize); + if (output != null && bufferSizeNeeded <= output.Length) + { + writeBuffer = output; + } + else + { + writeBuffer = new byte[bufferSizeNeeded]; + } + + Buffer.BlockCopy(buffer, offset, writeBuffer, _headerSize, size); + } + catch (Exception e) + { + if (!ExceptionCheck.IsFatal(e)) + { + GlobalLog.Assert(false, "SecureChannel#" + Logging.HashString(this) + "::Encrypt", "Arguments out of range."); + } + + throw; + } + + // Encryption using SCHANNEL requires 4 buffers: header, payload, trailer, empty. + SecurityBuffer[] securityBuffer = new SecurityBuffer[4]; + + securityBuffer[0] = new SecurityBuffer(writeBuffer, 0, _headerSize, SecurityBufferType.Header); + securityBuffer[1] = new SecurityBuffer(writeBuffer, _headerSize, size, SecurityBufferType.Data); + securityBuffer[2] = new SecurityBuffer(writeBuffer, _headerSize + size, _trailerSize, SecurityBufferType.Trailer); + securityBuffer[3] = new SecurityBuffer(null, SecurityBufferType.Empty); + + int errorCode = SSPIWrapper.EncryptMessage(GlobalSSPI.SSPISecureChannel, _securityContext, securityBuffer, 0); + + if (errorCode != 0) + { + GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::Encrypt ERROR", errorCode.ToString("x")); + return (Interop.SecurityStatus)errorCode; + } + else + { + output = writeBuffer; + + // The full buffer may not be used. + resultSize = securityBuffer[0].size + securityBuffer[1].size + securityBuffer[2].size; + GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::Encrypt OK", "data size:" + resultSize.ToString()); + return Interop.SecurityStatus.OK; + } + } + + internal Interop.SecurityStatus Decrypt(byte[] payload, ref int offset, ref int count) + { + GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::Decrypt() - offset: " + offset.ToString() + " size: " + count.ToString() + " buffersize: " + payload.Length.ToString()); + + if (offset < 0 || offset > (payload == null ? 0 : payload.Length)) + { + GlobalLog.Assert(false, "SecureChannel#" + Logging.HashString(this) + "::Encrypt", "Argument 'offset' out of range."); + throw new ArgumentOutOfRangeException("offset"); + } + + if (count < 0 || count > (payload == null ? 0 : payload.Length - offset)) + { + GlobalLog.Assert(false, "SecureChannel#" + Logging.HashString(this) + "::Encrypt", "Argument 'count' out of range."); + throw new ArgumentOutOfRangeException("count"); + } + + // Decryption using SCHANNEL requires four buffers. + SecurityBuffer[] decspc = new SecurityBuffer[4]; + decspc[0] = new SecurityBuffer(payload, offset, count, SecurityBufferType.Data); + decspc[1] = new SecurityBuffer(null, SecurityBufferType.Empty); + decspc[2] = new SecurityBuffer(null, SecurityBufferType.Empty); + decspc[3] = new SecurityBuffer(null, SecurityBufferType.Empty); + + Interop.SecurityStatus errorCode = (Interop.SecurityStatus)SSPIWrapper.DecryptMessage(GlobalSSPI.SSPISecureChannel, _securityContext, decspc, 0); + + count = 0; + for (int i = 0; i < decspc.Length; i++) + { + // Successfully decoded data and placed it at the following position in the buffer, + if ((errorCode == Interop.SecurityStatus.OK && decspc[i].type == SecurityBufferType.Data) + // or we failed to decode the data, here is the encoded data. + || (errorCode != Interop.SecurityStatus.OK && decspc[i].type == SecurityBufferType.Extra)) + { + offset = decspc[i].offset; + count = decspc[i].size; + break; + } + } + + return errorCode; + } + + /*++ + VerifyRemoteCertificate - Validates the content of a Remote Certificate + + checkCRL if true, checks the certificate revocation list for validity. + checkCertName, if true checks the CN field of the certificate + --*/ + + //This method validates a remote certificate. + //SECURITY: The scenario is allowed in semitrust StorePermission is asserted for Chain.Build + // A user callback has unique signature so it is safe to call it under permission assert. + // + internal bool VerifyRemoteCertificate(RemoteCertValidationCallback remoteCertValidationCallback) + { + GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::VerifyRemoteCertificate"); + SslPolicyErrors sslPolicyErrors = SslPolicyErrors.None; + + // We don't catch exceptions in this method, so it's safe for "accepted" be initialized with true. + bool success = false; + X509Chain chain = null; + X509Certificate2 remoteCertificateEx = null; + + try + { + X509Certificate2Collection remoteCertificateStore; + remoteCertificateEx = GetRemoteCertificate(out remoteCertificateStore); + _isRemoteCertificateAvailable = remoteCertificateEx != null; + + if (remoteCertificateEx == null) + { + GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::VerifyRemoteCertificate (no remote cert)", (!_remoteCertRequired).ToString()); + sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNotAvailable; + } + else + { + chain = new X509Chain(); + chain.ChainPolicy.RevocationMode = _checkCertRevocation ? X509RevocationMode.Online : X509RevocationMode.NoCheck; + chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot; + if (remoteCertificateStore != null) + { + chain.ChainPolicy.ExtraStore.AddRange(remoteCertificateStore); + } + + if (!chain.Build(remoteCertificateEx) // Build failed on handle or on policy. + && chain.SafeHandle.DangerousGetHandle() == IntPtr.Zero) // Build failed to generate a valid handle. + { + throw new CryptographicException(Marshal.GetLastWin32Error()); + } + + if (_checkCertName) + { + unsafe + { + uint status = 0; + + var eppStruct = new Interop.Crypt32.SSL_EXTRA_CERT_CHAIN_POLICY_PARA() + { + cbSize = (uint)Marshal.SizeOf(), + dwAuthType = IsServer ? Interop.Crypt32.AuthType.AUTHTYPE_SERVER : Interop.Crypt32.AuthType.AUTHTYPE_CLIENT, + fdwChecks = 0, + pwszServerName = null + }; + + var cppStruct = new Interop.Crypt32.CERT_CHAIN_POLICY_PARA() + { + cbSize = (uint)Marshal.SizeOf(), + dwFlags = 0, + pvExtraPolicyPara = &eppStruct + }; + + fixed (char* namePtr = _hostName) + { + eppStruct.pwszServerName = namePtr; + cppStruct.dwFlags |= + (Interop.Crypt32.CertChainPolicyIgnoreFlags.CERT_CHAIN_POLICY_IGNORE_ALL & + ~Interop.Crypt32.CertChainPolicyIgnoreFlags.CERT_CHAIN_POLICY_IGNORE_INVALID_NAME_FLAG); + + SafeX509ChainHandle chainContext = chain.SafeHandle; + status = Verify(chainContext, ref cppStruct); + if (status == Interop.Crypt32.CertChainPolicyErrors.CERT_E_CN_NO_MATCH) + { + sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNameMismatch; + } + } + } + } + + X509ChainStatus[] chainStatusArray = chain.ChainStatus; + if (chainStatusArray != null && chainStatusArray.Length != 0) + { + sslPolicyErrors |= SslPolicyErrors.RemoteCertificateChainErrors; + } + } + + if (remoteCertValidationCallback != null) + { + success = remoteCertValidationCallback(_hostName, remoteCertificateEx, chain, sslPolicyErrors); + } + else + { + if (sslPolicyErrors == SslPolicyErrors.RemoteCertificateNotAvailable && !_remoteCertRequired) + { + success = true; + } + else + { + success = (sslPolicyErrors == SslPolicyErrors.None); + } + } + + if (Logging.On) + { + if (sslPolicyErrors != SslPolicyErrors.None) + { + Logging.PrintInfo(Logging.Web, this, SR.net_log_remote_cert_has_errors); + if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateNotAvailable) != 0) + { + Logging.PrintInfo(Logging.Web, this, "\t" + SR.net_log_remote_cert_not_available); + } + + if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateNameMismatch) != 0) + { + Logging.PrintInfo(Logging.Web, this, "\t" + SR.net_log_remote_cert_name_mismatch); + } + + if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateChainErrors) != 0) + { + foreach (X509ChainStatus chainStatus in chain.ChainStatus) + { + Logging.PrintInfo(Logging.Web, this, "\t" + chainStatus.StatusInformation); + } + } + } + if (success) + { + if (remoteCertValidationCallback != null) + { + Logging.PrintInfo(Logging.Web, this, SR.net_log_remote_cert_user_declared_valid); + } + else + { + Logging.PrintInfo(Logging.Web, this, SR.net_log_remote_cert_has_no_errors); + } + } + else + { + if (remoteCertValidationCallback != null) + { + Logging.PrintInfo(Logging.Web, this, SR.net_log_remote_cert_user_declared_invalid); + } + } + } + GlobalLog.Print("Cert Validation, remote cert = " + (remoteCertificateEx == null ? "" : remoteCertificateEx.ToString(true))); + } + finally + { + // At least on Win2k server the chain is found to have dependencies on the original cert context. + // So it should be closed first. + if (chain != null) + { + chain.Dispose(); + } + + if (remoteCertificateEx != null) + { + remoteCertificateEx.Dispose(); + } + } + GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::VerifyRemoteCertificate", success.ToString()); + return success; + } + + internal static uint Verify(SafeX509ChainHandle chainContext, ref Interop.Crypt32.CERT_CHAIN_POLICY_PARA cpp) + { + GlobalLog.Enter("SecureChannel::VerifyChainPolicy", "chainContext=" + chainContext + ", options=" + String.Format("0x{0:x}", cpp.dwFlags)); + var status = new Interop.Crypt32.CERT_CHAIN_POLICY_STATUS(); + status.cbSize = (uint)Marshal.SizeOf(); + + bool errorCode = + Interop.Crypt32.CertVerifyCertificateChainPolicy( + (IntPtr)Interop.Crypt32.CertChainPolicy.CERT_CHAIN_POLICY_SSL, + chainContext, + ref cpp, + ref status); + + GlobalLog.Print("SecureChannel::VerifyChainPolicy() CertVerifyCertificateChainPolicy returned: " + errorCode); +#if TRACE_VERBOSE + GlobalLog.Print("SecureChannel::VerifyChainPolicy() error code: " + status.dwError + String.Format(" [0x{0:x8}", status.dwError) + " " + Interop.MapSecurityStatus(status.dwError) + "]"); +#endif + GlobalLog.Leave("SecureChannel::VerifyChainPolicy", status.dwError.ToString()); + return status.dwError; + } + + public Interop.Secur32.SecureCredential CreateSecureCredential( + int version, + X509Certificate certificate, + Interop.Secur32.SecureCredential.Flags flags, + int protocols, EncryptionPolicy policy) + { + var credential = new Interop.Secur32.SecureCredential() + { + rootStore = IntPtr.Zero, + phMappers = IntPtr.Zero, + palgSupportedAlgs = IntPtr.Zero, + certContextArray = IntPtr.Zero, + cCreds = 0, + cMappers = 0, + cSupportedAlgs = 0, + dwSessionLifespan = 0, + reserved = 0 + }; + + if (policy == EncryptionPolicy.RequireEncryption) + { + // Prohibit null encryption cipher. + credential.dwMinimumCipherStrength = 0; + credential.dwMaximumCipherStrength = 0; + } + else if (policy == EncryptionPolicy.AllowNoEncryption) + { + // Allow null encryption cipher in addition to other ciphers. + credential.dwMinimumCipherStrength = -1; + credential.dwMaximumCipherStrength = 0; + } + else if (policy == EncryptionPolicy.NoEncryption) + { + // Suppress all encryption and require null encryption cipher only + credential.dwMinimumCipherStrength = -1; + credential.dwMaximumCipherStrength = -1; + } + else + { + throw new ArgumentException(SR.Format(SR.net_invalid_enum, "EncryptionPolicy"), "policy"); + } + + credential.version = version; + credential.dwFlags = flags; + credential.grbitEnabledProtocols = protocols; + if (certificate != null) + { + credential.certContextArray = certificate.Handle; + credential.cCreds = 1; + } + + return credential; + } + } + + // + // ProtocolToken - used to process and handle the return codes + // from the SSPI wrapper + // + + internal class ProtocolToken + { + internal Interop.SecurityStatus Status; + internal byte[] Payload; + internal int Size; + + internal bool Failed + { + get + { + return ((Status != Interop.SecurityStatus.OK) && (Status != Interop.SecurityStatus.ContinueNeeded)); + } + } + + internal bool Done + { + get + { + return (Status == Interop.SecurityStatus.OK); + } + } + + internal bool Renegotiate + { + get + { + return (Status == Interop.SecurityStatus.Renegotiate); + } + } + + internal bool CloseConnection + { + get + { + return (Status == Interop.SecurityStatus.ContextExpired); + } + } + + internal ProtocolToken(byte[] data, Interop.SecurityStatus errorCode) + { + Status = errorCode; + Payload = data; + Size = data != null ? data.Length : 0; + } + + internal Win32Exception GetException() + { + // If it's not done, then there's got to be an error, even if it's + // a Handshake message up, and we only have a Warning message. + return this.Done ? null : new Win32Exception((int)Status); + } + +#if TRACE_VERBOSE + public override string ToString() + { + return "Status=" + Status.ToString() + ", data size=" + Size; + } +#endif + } +} + diff --git a/src/System.Net.Security/src/System/Net/_SecurityBuffer.cs b/src/System.Net.Security/src/System/Net/_SecurityBuffer.cs new file mode 100644 index 000000000000..401462f7f63e --- /dev/null +++ b/src/System.Net.Security/src/System/Net/_SecurityBuffer.cs @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Runtime.InteropServices; +using System.Security.Authentication.ExtendedProtection; + +namespace System.Net.Security +{ + internal class SecurityBuffer + { + public int size; + public SecurityBufferType type; + public byte[] token; + public SafeHandle unmanagedToken; + public int offset; + + public SecurityBuffer(byte[] data, int offset, int size, SecurityBufferType tokentype) + { + GlobalLog.Assert(offset >= 0 && offset <= (data == null ? 0 : data.Length), "SecurityBuffer::.ctor", "'offset' out of range. [" + offset + "]"); + GlobalLog.Assert(size >= 0 && size <= (data == null ? 0 : data.Length - offset), "SecurityBuffer::.ctor", "'size' out of range. [" + size + "]"); + + this.offset = data == null || offset < 0 ? 0 : Math.Min(offset, data.Length); + this.size = data == null || size < 0 ? 0 : Math.Min(size, data.Length - this.offset); + this.type = tokentype; + this.token = size == 0 ? null : data; + } + + public SecurityBuffer(byte[] data, SecurityBufferType tokentype) + { + this.size = data == null ? 0 : data.Length; + this.type = tokentype; + this.token = size == 0 ? null : data; + } + + public SecurityBuffer(int size, SecurityBufferType tokentype) + { + GlobalLog.Assert(size >= 0, "SecurityBuffer::.ctor", "'size' out of range. [" + size + "]"); + + this.size = size; + this.type = tokentype; + this.token = size == 0 ? null : new byte[size]; + } + + public SecurityBuffer(ChannelBinding binding) + { + this.size = (binding == null ? 0 : binding.Size); + this.type = SecurityBufferType.ChannelBindings; + this.unmanagedToken = binding; + } + } +} diff --git a/src/System.Net.Security/src/System/Net/_SecurityBufferType.cs b/src/System.Net.Security/src/System/Net/_SecurityBufferType.cs new file mode 100644 index 000000000000..3fe08171c2e6 --- /dev/null +++ b/src/System.Net.Security/src/System/Net/_SecurityBufferType.cs @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Net.Security +{ + internal enum SecurityBufferType + { + Empty = 0x00, + Data = 0x01, + Token = 0x02, + Parameters = 0x03, + Missing = 0x04, + Extra = 0x05, + Trailer = 0x06, + Header = 0x07, + Padding = 0x09, // non-data padding + Stream = 0x0A, + ChannelBindings = 0x0E, + TargetHost = 0x10, + ReadOnlyFlag = unchecked((int)0x80000000), + ReadOnlyWithChecksum = 0x10000000 + } +} diff --git a/src/System.Net.Security/src/System/Net/_SslSessionsCache.cs b/src/System.Net.Security/src/System/Net/_SslSessionsCache.cs new file mode 100644 index 000000000000..8bc18369cba6 --- /dev/null +++ b/src/System.Net.Security/src/System/Net/_SslSessionsCache.cs @@ -0,0 +1,226 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections; + +namespace System.Net.Security +{ + // Implements SSL session caching mechanism based on a static table of SSL credentials. + internal static class SslSessionsCache + { + private const int CheckExpiredModulo = 32; + private static Hashtable s_CachedCreds = new Hashtable(32); + + // + // Uses certificate thumb-print comparison. + // + private struct SslCredKey + { + private byte[] _CertThumbPrint; + private int _AllowedProtocols; + private EncryptionPolicy _EncryptionPolicy; + private readonly int _HashCode; + + // + // SECURITY: X509Certificate.GetCertHash() is virtual hence before going here, + // the caller of this ctor has to ensure that a user cert object was inspected and + // optionally cloned. + // + internal SslCredKey(byte[] thumbPrint, int allowedProtocols, EncryptionPolicy encryptionPolicy) + { + _CertThumbPrint = thumbPrint == null ? Array.Empty() : thumbPrint; + _HashCode = 0; + if (thumbPrint != null) + { + _HashCode ^= _CertThumbPrint[0]; + if (1 < _CertThumbPrint.Length) + { + _HashCode ^= (_CertThumbPrint[1] << 8); + } + + if (2 < _CertThumbPrint.Length) + { + _HashCode ^= (_CertThumbPrint[2] << 16); + } + + if (3 < _CertThumbPrint.Length) + { + _HashCode ^= (_CertThumbPrint[3] << 24); + } + } + + _HashCode ^= allowedProtocols; + _HashCode ^= (int)encryptionPolicy; + _AllowedProtocols = allowedProtocols; + _EncryptionPolicy = encryptionPolicy; + } + + public override int GetHashCode() + { + return _HashCode; + } + + public static bool operator ==(SslCredKey sslCredKey1, + SslCredKey sslCredKey2) + { + return sslCredKey1.Equals(sslCredKey2); + } + + public static bool operator !=(SslCredKey sslCredKey1, + SslCredKey sslCredKey2) + { + return !sslCredKey1.Equals(sslCredKey2); + } + + public override bool Equals(Object y) + { + SslCredKey other = (SslCredKey)y; + + if (_CertThumbPrint.Length != other._CertThumbPrint.Length) + { + return false; + } + + if (_HashCode != other._HashCode) + { + return false; + } + + if (_EncryptionPolicy != other._EncryptionPolicy) + { + return false; + } + + if (_AllowedProtocols != other._AllowedProtocols) + { + return false; + } + + for (int i = 0; i < _CertThumbPrint.Length; ++i) + { + if (_CertThumbPrint[i] != other._CertThumbPrint[i]) + { + return false; + } + } + + return true; + } + } + + // + // Returns null or previously cached cred handle. + // + // ATTN: The returned handle can be invalid, the callers of InitializeSecurityContext and AcceptSecurityContext + // must be prepared to execute a back-out code if the call fails. + // + internal static SafeFreeCredentials TryCachedCredential(byte[] thumbPrint, int allowedProtocols, EncryptionPolicy encryptionPolicy) + { + if (s_CachedCreds.Count == 0) + { + GlobalLog.Print("TryCachedCredential() Not found, Current Cache Count = " + s_CachedCreds.Count); + return null; + } + + object key = new SslCredKey(thumbPrint, allowedProtocols, encryptionPolicy); + + SafeCredentialReference cached = s_CachedCreds[key] as SafeCredentialReference; + + if (cached == null || cached.IsClosed || cached._Target.IsInvalid) + { + GlobalLog.Print("TryCachedCredential() Not found or invalid, Current Cache Count = " + s_CachedCreds.Count); + return null; + } + + GlobalLog.Print("TryCachedCredential() Found a cached Handle = " + cached._Target.ToString()); + + return cached._Target; + } + + // + // The app is calling this method after starting an SSL handshake. + // + // ATTN: The thumbPrint must be from inspected and possibly cloned user Cert object or we get a security hole in SslCredKey ctor. + // + internal static void CacheCredential(SafeFreeCredentials creds, byte[] thumbPrint, int allowedProtocols, EncryptionPolicy encryptionPolicy) + { + GlobalLog.Assert(creds != null, "CacheCredential|creds == null"); + if (creds.IsInvalid) + { + GlobalLog.Print("CacheCredential() Refused to cache an Invalid Handle = " + creds.ToString() + ", Current Cache Count = " + s_CachedCreds.Count); + return; + } + + object key = new SslCredKey(thumbPrint, allowedProtocols, encryptionPolicy); + + SafeCredentialReference cached = s_CachedCreds[key] as SafeCredentialReference; + + if (cached == null || cached.IsClosed || cached._Target.IsInvalid) + { + lock (s_CachedCreds) + { + cached = s_CachedCreds[key] as SafeCredentialReference; + + if (cached == null || cached.IsClosed) + { + cached = SafeCredentialReference.CreateReference(creds); + + if (cached == null) + { + // Means the handle got closed in between, return it back and let caller deal with the issue. + return; + } + + s_CachedCreds[key] = cached; + GlobalLog.Print("CacheCredential() Caching New Handle = " + creds.ToString() + ", Current Cache Count = " + s_CachedCreds.Count); + + // + // A simplest way of preventing infinite cache grows. + // + // Security relief (DoS): + // A number of active creds is never greater than a number of _outstanding_ + // security sessions, i.e. SSL connections. + // So we will try to shrink cache to the number of active creds once in a while. + // + // We won't shrink cache in the case when NO new handles are coming to it. + // + if ((s_CachedCreds.Count % CheckExpiredModulo) == 0) + { + DictionaryEntry[] toRemoveAttempt = new DictionaryEntry[s_CachedCreds.Count]; + s_CachedCreds.CopyTo(toRemoveAttempt, 0); + + for (int i = 0; i < toRemoveAttempt.Length; ++i) + { + cached = toRemoveAttempt[i].Value as SafeCredentialReference; + + if (cached != null) + { + creds = cached._Target; + cached.Dispose(); + + if (!creds.IsClosed && !creds.IsInvalid && (cached = SafeCredentialReference.CreateReference(creds)) != null) + { + s_CachedCreds[toRemoveAttempt[i].Key] = cached; + } + else + { + s_CachedCreds.Remove(toRemoveAttempt[i].Key); + } + } + } + GlobalLog.Print("Scavenged cache, New Cache Count = " + s_CachedCreds.Count); + } + } + else + { + GlobalLog.Print("CacheCredential() (locked retry) Found already cached Handle = " + cached._Target.ToString()); + } + } + } + else + { + GlobalLog.Print("CacheCredential() Ignoring incoming handle = " + creds.ToString() + " since found already cached Handle = " + cached._Target.ToString()); + } + } + } +} diff --git a/src/System.Net.Security/src/System/PinnableBufferCache.cs b/src/System.Net.Security/src/System/PinnableBufferCache.cs new file mode 100644 index 000000000000..ebe02a06e967 --- /dev/null +++ b/src/System.Net.Security/src/System/PinnableBufferCache.cs @@ -0,0 +1,589 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics.Tracing; +using System.Runtime.InteropServices; +using System.Threading; + +namespace System +{ + internal sealed class PinnableBufferCache + { + /// + /// Create a new cache for pinned byte[] buffers. + /// + /// A name used in diagnostic messages + /// The size of byte[] buffers in the cache (they are all the same size) + public PinnableBufferCache(string cacheName, int numberOfElements) : this(cacheName, () => new byte[numberOfElements]) { } + + /// + /// Get a buffer from the buffer manager. If no buffers exist, allocate a new one. + /// + public byte[] AllocateBuffer() { return (byte[])Allocate(); } + + /// + /// Return a buffer back to the buffer manager. + /// + public void FreeBuffer(byte[] buffer) { Free(buffer); } + + /// + /// Create a PinnableBufferCache that works on any object (it is intended for OverlappedData) + /// + internal PinnableBufferCache(string cacheName, Func factory) + { + _notGen2 = new List(DefaultNumberOfBuffers); + _factory = factory; + + PinnableBufferCacheEventSource.Log.Create(cacheName); + _cacheName = cacheName; + } + + /// + /// Get a object from the buffer manager. If no buffers exist, allocate a new one. + /// + [System.Security.SecuritySafeCritical] + internal object Allocate() + { + // Fast path, get it from our Gen2 aged _freeList. + object returnBuffer; + if (!_freeList.TryPop(out returnBuffer)) + { + Restock(out returnBuffer); + } + + // Computing free count is expensive enough that we don't want to compute it unless logging is on. + if (PinnableBufferCacheEventSource.Log.IsEnabled()) + { + int numAllocCalls = Interlocked.Increment(ref _numAllocCalls); + if (numAllocCalls >= 1024) + { + lock (this) + { + int previousNumAllocCalls = Interlocked.Exchange(ref _numAllocCalls, 0); + if (previousNumAllocCalls >= 1024) + { + int nonGen2Count = 0; + foreach (object o in _freeList) + { + if (GC.GetGeneration(o) < GC.MaxGeneration) + { + nonGen2Count++; + } + } + + PinnableBufferCacheEventSource.Log.WalkFreeListResult(_cacheName, _freeList.Count, nonGen2Count); + } + } + } + + PinnableBufferCacheEventSource.Log.AllocateBuffer(_cacheName, PinnableBufferCacheEventSource.AddressOf(returnBuffer), returnBuffer.GetHashCode(), GC.GetGeneration(returnBuffer), _freeList.Count); + } + return returnBuffer; + } + + /// + /// Return a buffer back to the buffer manager. + /// + [System.Security.SecuritySafeCritical] + internal void Free(object buffer) + { + if (PinnableBufferCacheEventSource.Log.IsEnabled()) + { + PinnableBufferCacheEventSource.Log.FreeBuffer(_cacheName, PinnableBufferCacheEventSource.AddressOf(buffer), buffer.GetHashCode(), _freeList.Count); + } + + + // After we've done 3 gen1 GCs, assume that all buffers have aged into gen2 on the free path. + if ((_gen1CountAtLastRestock + 3) > GC.CollectionCount(GC.MaxGeneration - 1)) + { + lock (this) + { + if (GC.GetGeneration(buffer) < GC.MaxGeneration) + { + // The buffer is not aged, so put it in the non-aged free list. + _moreThanFreeListNeeded = true; + PinnableBufferCacheEventSource.Log.FreeBufferStillTooYoung(_cacheName, _notGen2.Count); + _notGen2.Add(buffer); + _gen1CountAtLastRestock = GC.CollectionCount(GC.MaxGeneration - 1); + return; + } + } + } + + // If we discovered that it is indeed Gen2, great, put it in the Gen2 list. + _freeList.Push(buffer); + } + + #region Private + + /// + /// Called when we don't have any buffers in our free list to give out. + /// + /// + [System.Security.SecuritySafeCritical] + private void Restock(out object returnBuffer) + { + lock (this) + { + // Try again after getting the lock as another thread could have just filled the free list. If we don't check + // then we unnecessarily grab a new set of buffers because we think we are out. + if (_freeList.TryPop(out returnBuffer)) + { + return; + } + + // Lazy init, Ask that TrimFreeListIfNeeded be called on every Gen 2 GC. + if (_restockSize == 0) + { + Gen2GcCallback.Register(Gen2GcCallbackFunc, this); + } + + // Indicate to the trimming policy that the free list is insufficient. + _moreThanFreeListNeeded = true; + PinnableBufferCacheEventSource.Log.AllocateBufferFreeListEmpty(_cacheName, _notGen2.Count); + + // Get more buffers if needed. + if (_notGen2.Count == 0) + { + CreateNewBuffers(); + } + + // We have no buffers in the aged freelist, so get one from the newer list. Try to pick the best one. + // Debug.Assert(_notGen2.Count != 0); + int idx = _notGen2.Count - 1; + if (GC.GetGeneration(_notGen2[idx]) < GC.MaxGeneration && GC.GetGeneration(_notGen2[0]) == GC.MaxGeneration) + { + idx = 0; + } + + returnBuffer = _notGen2[idx]; + _notGen2.RemoveAt(idx); + + // Remember any sub-optimal buffer so we don't put it on the free list when it gets freed. + if (PinnableBufferCacheEventSource.Log.IsEnabled() && GC.GetGeneration(returnBuffer) < GC.MaxGeneration) + { + PinnableBufferCacheEventSource.Log.AllocateBufferFromNotGen2(_cacheName, _notGen2.Count); + } + + // If we have a Gen1 collection, then everything on _notGen2 should have aged. Move them to the _freeList. + if (!AgePendingBuffers()) + { + // Before we could age at set of buffers, we have handed out half of them. + // This implies we should be proactive about allocating more (since we will trim them if we over-allocate). + if (_notGen2.Count == _restockSize / 2) + { + PinnableBufferCacheEventSource.Log.DebugMessage("Proactively adding more buffers to aging pool"); + CreateNewBuffers(); + } + } + } + } + + /// + /// See if we can promote the buffers to the free list. Returns true if successful. + /// + [System.Security.SecuritySafeCritical] + private bool AgePendingBuffers() + { + if (_gen1CountAtLastRestock < GC.CollectionCount(GC.MaxGeneration - 1)) + { + // Allocate a temp list of buffers that are not actually in gen2, and swap it in once + // we're done scanning all buffers. + int promotedCount = 0; + List notInGen2 = new List(); + PinnableBufferCacheEventSource.Log.AllocateBufferAged(_cacheName, _notGen2.Count); + for (int i = 0; i < _notGen2.Count; i++) + { + // We actually check every object to ensure that we aren't putting non-aged buffers into the free list. + object currentBuffer = _notGen2[i]; + if (GC.GetGeneration(currentBuffer) >= GC.MaxGeneration) + { + _freeList.Push(currentBuffer); + promotedCount++; + } + else + { + notInGen2.Add(currentBuffer); + } + } + PinnableBufferCacheEventSource.Log.AgePendingBuffersResults(_cacheName, promotedCount, notInGen2.Count); + _notGen2 = notInGen2; + + return true; + } + return false; + } + + /// + /// Generates some buffers to age into Gen2. + /// + private void CreateNewBuffers() + { + // We choose a very modest number of buffers initially because for the client case. This is often enough. + if (_restockSize == 0) + { + _restockSize = 4; + } + else if (_restockSize < DefaultNumberOfBuffers) + { + _restockSize = DefaultNumberOfBuffers; + } + else if (_restockSize < 256) + { + _restockSize = _restockSize * 2; // Grow quickly at small sizes + } + else if (_restockSize < 4096) + { + _restockSize = _restockSize * 3 / 2; // Less aggressively at large ones + } + else + { + _restockSize = 4096; // Cap how aggressive we are + } + + // Ensure we hit our minimums + if (_minBufferCount > _buffersUnderManagement) + _restockSize = Math.Max(_restockSize, _minBufferCount - _buffersUnderManagement); + + PinnableBufferCacheEventSource.Log.AllocateBufferCreatingNewBuffers(_cacheName, _buffersUnderManagement, _restockSize); + for (int i = 0; i < _restockSize; i++) + { + // Make a new buffer. + object newBuffer = _factory(); + + // Create space between the objects. We do this because otherwise it forms a single plug (group of objects) + // and the GC pins the entire plug making them NOT move to Gen1 and Gen2. by putting space between them + // we ensure that object get a chance to move independently (even if some are pinned). + var dummyObject = new object(); + _notGen2.Add(newBuffer); + } + _buffersUnderManagement += _restockSize; + _gen1CountAtLastRestock = GC.CollectionCount(GC.MaxGeneration - 1); + } + + /// + /// This is the static function that is called from the gen2 GC callback. + /// The input object is the cache itself. + /// NOTE: The reason that we make this function static and take the cache as a parameter is that + /// otherwise, we root the cache to the Gen2GcCallback object, and leak the cache even when + /// the application no longer needs it. + /// + [System.Security.SecuritySafeCritical] + private static bool Gen2GcCallbackFunc(object targetObj) + { + return ((PinnableBufferCache)(targetObj)).TrimFreeListIfNeeded(); + } + + /// + /// This is called on every gen2 GC to see if we need to trim the free list. + /// NOTE: DO NOT CALL THIS DIRECTLY FROM THE GEN2GCCALLBACK. INSTEAD CALL IT VIA A STATIC FUNCTION (SEE ABOVE). + /// If you register a non-static function as a callback, then this object will be leaked. + /// + [System.Security.SecuritySafeCritical] + private bool TrimFreeListIfNeeded() + { + int curMSec = Environment.TickCount; + int deltaMSec = curMSec - _msecNoUseBeyondFreeListSinceThisTime; + PinnableBufferCacheEventSource.Log.TrimCheck(_cacheName, _buffersUnderManagement, _moreThanFreeListNeeded, deltaMSec); + + // If we needed more than just the set of aged buffers since the last time we were called, + // we obviously should not be trimming any memory, so do nothing except reset the flag + if (_moreThanFreeListNeeded) + { + _moreThanFreeListNeeded = false; + _trimmingExperimentInProgress = false; + _msecNoUseBeyondFreeListSinceThisTime = curMSec; + return true; + } + + // We require a minimum amount of clock time to pass (10 seconds) before we trim. Ideally this time + // is larger than the typical buffer hold time. + if (0 <= deltaMSec && deltaMSec < 10000) + { + return true; + } + + // If we got here we have spend the last few second without needing to lengthen the free list. Thus + // we have 'enough' buffers, but maybe we have too many. + // See if we can trim + lock (this) + { + // Hit a race, try again later. + if (_moreThanFreeListNeeded) + { + _moreThanFreeListNeeded = false; + _trimmingExperimentInProgress = false; + _msecNoUseBeyondFreeListSinceThisTime = curMSec; + return true; + } + + var freeCount = _freeList.Count; // This is expensive to fetch, do it once. + + // If there is something in _notGen2 it was not used for the last few seconds, it is trim-able. + if (_notGen2.Count > 0) + { + // If we are not performing an experiment and we have stuff that is waiting to go into the + // free list but has not made it there, it could be because the 'slow path' of restocking + // has not happened, so force this (which should flush the list) and start over. + if (!_trimmingExperimentInProgress) + { + PinnableBufferCacheEventSource.Log.TrimFlush(_cacheName, _buffersUnderManagement, freeCount, _notGen2.Count); + AgePendingBuffers(); + _trimmingExperimentInProgress = true; + return true; + } + + PinnableBufferCacheEventSource.Log.TrimFree(_cacheName, _buffersUnderManagement, freeCount, _notGen2.Count); + _buffersUnderManagement -= _notGen2.Count; + + // Possibly revise the restocking down. We don't want to grow aggressively if we are trimming. + var newRestockSize = _buffersUnderManagement / 4; + if (newRestockSize < _restockSize) + { + _restockSize = Math.Max(newRestockSize, DefaultNumberOfBuffers); + } + + _notGen2.Clear(); + _trimmingExperimentInProgress = false; + return true; + } + + // Set up an experiment where we use 25% less buffers in our free list. We put them in + // _notGen2, and if they are needed they will be put back in the free list again. + var trimSize = freeCount / 4 + 1; + + // We are OK with a 15% overhead, do nothing in that case. + if (freeCount * 15 <= _buffersUnderManagement || _buffersUnderManagement - trimSize <= _minBufferCount) + { + PinnableBufferCacheEventSource.Log.TrimFreeSizeOK(_cacheName, _buffersUnderManagement, freeCount); + return true; + } + + // Move buffers from the free list back to the non-aged list. If we don't use them by next time, then we'll consider trimming them. + PinnableBufferCacheEventSource.Log.TrimExperiment(_cacheName, _buffersUnderManagement, freeCount, trimSize); + object buffer; + for (int i = 0; i < trimSize; i++) + { + if (_freeList.TryPop(out buffer)) + { + _notGen2.Add(buffer); + } + } + _msecNoUseBeyondFreeListSinceThisTime = curMSec; + _trimmingExperimentInProgress = true; + } + + // Indicate that we want to be called back on the next Gen 2 GC. + return true; + } + + private const int DefaultNumberOfBuffers = 16; + private string _cacheName; + private Func _factory; + + /// + /// Contains 'good' buffers to reuse. They are guaranteed to be Gen 2 ENFORCED! + /// + private ConcurrentStack _freeList = new ConcurrentStack(); + /// + /// Contains buffers that are not gen 2 and thus we do not wish to give out unless we have to. + /// To implement trimming we sometimes put aged buffers in here as a place to 'park' them + /// before true deletion. + /// + private List _notGen2; + /// + /// What whas the gen 1 count the last time re restocked? If it is now greater, then + /// we know that all objects are in Gen 2 so we don't have to check. Should be updated + /// every time something gets added to the _notGen2 list. + /// + private int _gen1CountAtLastRestock; + + /// + /// Used to ensure we have a minimum time between trimmings. + /// + private int _msecNoUseBeyondFreeListSinceThisTime; + /// + /// To trim, we remove things from the free list (which is Gen 2) and see if we 'hit bottom' + /// This flag indicates that we hit bottom (we really needed a bigger free list). + /// + private bool _moreThanFreeListNeeded; + /// + /// The total number of buffers that this cache has ever allocated. + /// Used in trimming heuristics. + /// + private int _buffersUnderManagement; + /// + /// The number of buffers we added the last time we restocked. + /// + private int _restockSize; + /// + /// Did we put some buffers into _notGen2 to see if we can trim? + /// + private bool _trimmingExperimentInProgress; + /// + /// A forced minimum number of buffers. + /// + private int _minBufferCount = 0; + /// + /// The number of calls to Allocate. + /// + private int _numAllocCalls; + #endregion + } + + /// + /// Schedules a callback roughly every gen 2 GC (you may see a Gen 0 an Gen 1 but only once) + /// (We can fix this by capturing the Gen 2 count at startup and testing, but I mostly don't care) + /// + internal sealed class Gen2GcCallback //: CriticalFinalizerObject + { + [System.Security.SecuritySafeCritical] + public Gen2GcCallback() + : base() + { + } + + /// + /// Schedule 'callback' to be called in the next GC. If the callback returns true it is + /// rescheduled for the next Gen 2 GC. Otherwise the callbacks stop. + /// + /// NOTE: This callback will be kept alive until either the callback function returns false, + /// or the target object dies. + /// + public static void Register(Func callback, object targetObj) + { + // Create a unreachable object that remembers the callback function and target object. + Gen2GcCallback gcCallback = new Gen2GcCallback(); + gcCallback.Setup(callback, targetObj); + } + + #region Private + + private Func _callback; + private GCHandle _weakTargetObj; + + [System.Security.SecuritySafeCritical] + private void Setup(Func callback, object targetObj) + { + _callback = callback; + _weakTargetObj = GCHandle.Alloc(targetObj, GCHandleType.Weak); + } + + [System.Security.SecuritySafeCritical] + ~Gen2GcCallback() + { + // Check to see if the target object is still alive. + object targetObj = _weakTargetObj.Target; + if (targetObj == null) + { + // The target object is dead, so this callback object is no longer needed. + _weakTargetObj.Free(); + return; + } + + // Execute the callback method. + try + { + if (!_callback(targetObj)) + { + // If the callback returns false, this callback object is no longer needed. + return; + } + } + catch + { + // Ensure that we still get a chance to resurrect this object, even if the callback throws an exception. + } + + // Resurrect ourselves by re-registering for finalization. + if (!Environment.HasShutdownStarted) + { + GC.ReRegisterForFinalize(this); + } + } + #endregion + } + + /// + /// PinnableBufferCacheEventSource is a private eventSource that we are using to + /// debug and monitor the effectiveness of PinnableBufferCache + /// + + // The following EventSource Name must be unique per DLL: + [EventSource(Name = "Microsoft-DotNETRuntime-PinnableBufferCache-Networking")] + internal sealed class PinnableBufferCacheEventSource : EventSource + { + public static readonly PinnableBufferCacheEventSource Log = new PinnableBufferCacheEventSource(); + + [Event(1, Level = EventLevel.Verbose)] + public void DebugMessage(string message) { if (IsEnabled()) WriteEvent(1, message); } + [Event(2, Level = EventLevel.Verbose)] + public void DebugMessage1(string message, long value) { if (IsEnabled()) WriteEvent(2, message, value); } + [Event(3, Level = EventLevel.Verbose)] + public void DebugMessage2(string message, long value1, long value2) { if (IsEnabled()) WriteEvent(3, message, value1, value2); } + [Event(18, Level = EventLevel.Verbose)] + public void DebugMessage3(string message, long value1, long value2, long value3) { if (IsEnabled()) WriteEvent(18, message, value1, value2, value3); } + + [Event(4)] + public void Create(string cacheName) { if (IsEnabled()) WriteEvent(4, cacheName); } + + [Event(5, Level = EventLevel.Verbose)] + public void AllocateBuffer(string cacheName, ulong objectId, int objectHash, int objectGen, int freeCountAfter) { if (IsEnabled()) WriteEvent(5, cacheName, objectId, objectHash, objectGen, freeCountAfter); } + [Event(6)] + public void AllocateBufferFromNotGen2(string cacheName, int notGen2CountAfter) { if (IsEnabled()) WriteEvent(6, cacheName, notGen2CountAfter); } + [Event(7)] + public void AllocateBufferCreatingNewBuffers(string cacheName, int totalBuffsBefore, int objectCount) { if (IsEnabled()) WriteEvent(7, cacheName, totalBuffsBefore, objectCount); } + [Event(8)] + public void AllocateBufferAged(string cacheName, int agedCount) { if (IsEnabled()) WriteEvent(8, cacheName, agedCount); } + [Event(9)] + public void AllocateBufferFreeListEmpty(string cacheName, int notGen2CountBefore) { if (IsEnabled()) WriteEvent(9, cacheName, notGen2CountBefore); } + + [Event(10, Level = EventLevel.Verbose)] + public void FreeBuffer(string cacheName, ulong objectId, int objectHash, int freeCountBefore) { if (IsEnabled()) WriteEvent(10, cacheName, objectId, objectHash, freeCountBefore); } + [Event(11)] + public void FreeBufferStillTooYoung(string cacheName, int notGen2CountBefore) { if (IsEnabled()) WriteEvent(11, cacheName, notGen2CountBefore); } + + [Event(13)] + public void TrimCheck(string cacheName, int totalBuffs, bool neededMoreThanFreeList, int deltaMSec) { if (IsEnabled()) WriteEvent(13, cacheName, totalBuffs, neededMoreThanFreeList, deltaMSec); } + [Event(14)] + public void TrimFree(string cacheName, int totalBuffs, int freeListCount, int toBeFreed) { if (IsEnabled()) WriteEvent(14, cacheName, totalBuffs, freeListCount, toBeFreed); } + [Event(15)] + public void TrimExperiment(string cacheName, int totalBuffs, int freeListCount, int numTrimTrial) { if (IsEnabled()) WriteEvent(15, cacheName, totalBuffs, freeListCount, numTrimTrial); } + [Event(16)] + public void TrimFreeSizeOK(string cacheName, int totalBuffs, int freeListCount) { if (IsEnabled()) WriteEvent(16, cacheName, totalBuffs, freeListCount); } + [Event(17)] + public void TrimFlush(string cacheName, int totalBuffs, int freeListCount, int notGen2CountBefore) { if (IsEnabled()) WriteEvent(17, cacheName, totalBuffs, freeListCount, notGen2CountBefore); } + [Event(20)] + public void AgePendingBuffersResults(string cacheName, int promotedToFreeListCount, int heldBackCount) { if (IsEnabled()) WriteEvent(20, cacheName, promotedToFreeListCount, heldBackCount); } + [Event(21)] + public void WalkFreeListResult(string cacheName, int freeListCount, int gen0BuffersInFreeList) { if (IsEnabled()) WriteEvent(21, cacheName, freeListCount, gen0BuffersInFreeList); } + + + static internal ulong AddressOf(object obj) + { + var asByteArray = obj as byte[]; + if (asByteArray != null) + { + return (ulong)AddressOfByteArray(asByteArray); + } + + return 0; + } + + [System.Security.SecuritySafeCritical] + static internal unsafe long AddressOfByteArray(byte[] array) + { + if (array == null) + { + return 0; + } + + fixed (byte* ptr = array) + { + return (long)(ptr - 2 * sizeof(void*)); + } + } + } +} diff --git a/src/System.Net.Security/src/System/Security/Authentication/ExtendedProtection/ExtendedProtectionPolicy.cs b/src/System.Net.Security/src/System/Security/Authentication/ExtendedProtection/ExtendedProtectionPolicy.cs new file mode 100644 index 000000000000..1c61173480ec --- /dev/null +++ b/src/System.Net.Security/src/System/Security/Authentication/ExtendedProtection/ExtendedProtectionPolicy.cs @@ -0,0 +1,150 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections; +using System.Text; + +namespace System.Security.Authentication.ExtendedProtection +{ + /// + /// This class contains the necessary settings for specifying how Extended Protection + /// should behave. Use one of the Build* methods to create an instance of this type. + /// + public class ExtendedProtectionPolicy + { + private const string policyEnforcementName = "policyEnforcement"; + private const string protectionScenarioName = "protectionScenario"; + private const string customServiceNamesName = "customServiceNames"; + private const string customChannelBindingName = "customChannelBinding"; + + private ServiceNameCollection _customServiceNames; + private PolicyEnforcement _policyEnforcement; + private ProtectionScenario _protectionScenario; + private ChannelBinding _customChannelBinding; + + public ExtendedProtectionPolicy(PolicyEnforcement policyEnforcement, + ProtectionScenario protectionScenario, + ServiceNameCollection customServiceNames) + { + if (policyEnforcement == PolicyEnforcement.Never) + { + throw new ArgumentException(SR.security_ExtendedProtectionPolicy_UseDifferentConstructorForNever, "policyEnforcement"); + } + + if (customServiceNames != null && customServiceNames.Count == 0) + { + throw new ArgumentException(SR.security_ExtendedProtectionPolicy_NoEmptyServiceNameCollection, "customServiceNames"); + } + + _policyEnforcement = policyEnforcement; + _protectionScenario = protectionScenario; + _customServiceNames = customServiceNames; + } + + public ExtendedProtectionPolicy(PolicyEnforcement policyEnforcement, + ProtectionScenario protectionScenario, + ICollection customServiceNames) + : this(policyEnforcement, protectionScenario, + customServiceNames == null ? (ServiceNameCollection)null : new ServiceNameCollection(customServiceNames)) + { + } + + public ExtendedProtectionPolicy(PolicyEnforcement policyEnforcement, + ChannelBinding customChannelBinding) + { + if (policyEnforcement == PolicyEnforcement.Never) + { + throw new ArgumentException(SR.security_ExtendedProtectionPolicy_UseDifferentConstructorForNever, "policyEnforcement"); + } + + if (customChannelBinding == null) + { + throw new ArgumentNullException("customChannelBinding"); + } + + _policyEnforcement = policyEnforcement; + _protectionScenario = ProtectionScenario.TransportSelected; + _customChannelBinding = customChannelBinding; + } + + public ExtendedProtectionPolicy(PolicyEnforcement policyEnforcement) + { + // This is the only constructor which allows PolicyEnforcement.Never. + _policyEnforcement = policyEnforcement; + _protectionScenario = ProtectionScenario.TransportSelected; + } + + public ServiceNameCollection CustomServiceNames + { + get { return _customServiceNames; } + } + + public PolicyEnforcement PolicyEnforcement + { + get { return _policyEnforcement; } + } + + public ProtectionScenario ProtectionScenario + { + get { return _protectionScenario; } + } + + public ChannelBinding CustomChannelBinding + { + get { return _customChannelBinding; } + } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("ProtectionScenario="); + sb.Append(_protectionScenario.ToString()); + sb.Append("; PolicyEnforcement="); + sb.Append(_policyEnforcement.ToString()); + + sb.Append("; CustomChannelBinding="); + if (_customChannelBinding == null) + { + sb.Append(""); + } + else + { + sb.Append(_customChannelBinding.ToString()); + } + + sb.Append("; ServiceNames="); + if (_customServiceNames == null) + { + sb.Append(""); + } + else + { + bool first = true; + foreach (string serviceName in _customServiceNames) + { + if (first) + { + first = false; + } + else + { + sb.Append(", "); + } + + sb.Append(serviceName); + } + } + + return sb.ToString(); + } + + public static bool OSSupportsExtendedProtection + { + get + { + // CoreFX is supported only on Win7+ where ExtendedProtection is supported. + return true; + } + } + } +} diff --git a/src/System.Net.Security/src/System/Security/Authentication/ExtendedProtection/PolicyEnforcement.cs b/src/System.Net.Security/src/System/Security/Authentication/ExtendedProtection/PolicyEnforcement.cs new file mode 100644 index 000000000000..7da59ca3f52d --- /dev/null +++ b/src/System.Net.Security/src/System/Security/Authentication/ExtendedProtection/PolicyEnforcement.cs @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Security.Authentication.ExtendedProtection +{ + public enum PolicyEnforcement + { + Never, + WhenSupported, + Always + } +} diff --git a/src/System.Net.Security/src/System/Security/Authentication/ExtendedProtection/ProtectionScenario.cs b/src/System.Net.Security/src/System/Security/Authentication/ExtendedProtection/ProtectionScenario.cs new file mode 100644 index 000000000000..237f1bc4d316 --- /dev/null +++ b/src/System.Net.Security/src/System/Security/Authentication/ExtendedProtection/ProtectionScenario.cs @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Security.Authentication.ExtendedProtection +{ + public enum ProtectionScenario + { + TransportSelected, + TrustedProxy + } +} diff --git a/src/System.Net.Security/src/System/Security/Authentication/ExtendedProtection/ServiceNameCollection.cs b/src/System.Net.Security/src/System/Security/Authentication/ExtendedProtection/ServiceNameCollection.cs new file mode 100644 index 000000000000..d6709e1963cf --- /dev/null +++ b/src/System.Net.Security/src/System/Security/Authentication/ExtendedProtection/ServiceNameCollection.cs @@ -0,0 +1,206 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections; +using System.Diagnostics; +using System.Globalization; +using System.Net; + +namespace System.Security.Authentication.ExtendedProtection +{ + public class ServiceNameCollection : ReadOnlyCollectionBase + { + public ServiceNameCollection(ICollection items) + { + if (items == null) + { + throw new ArgumentNullException("items"); + } + + // Normalize and filter for duplicates. + foreach (string serviceName in items) + { + AddIfNew(InnerList, serviceName); + } + } + + public ServiceNameCollection Merge(string serviceName) + { + ArrayList newServiceNames = new ArrayList(); + newServiceNames.AddRange(this.InnerList); + + AddIfNew(newServiceNames, serviceName); + + ServiceNameCollection newCollection = new ServiceNameCollection(newServiceNames); + return newCollection; + } + + public ServiceNameCollection Merge(IEnumerable serviceNames) + { + ArrayList newServiceNames = new ArrayList(); + newServiceNames.AddRange(this.InnerList); + + // We have a pretty bad performance here: O(n^2), but since service name lists should + // be small (<<50) and Merge() should not be called frequently, this shouldn't be an issue. + foreach (object item in serviceNames) + { + AddIfNew(newServiceNames, item as string); + } + + ServiceNameCollection newCollection = new ServiceNameCollection(newServiceNames); + return newCollection; + } + + // Normalize, check for duplicates, and add if the value is unique. + private static void AddIfNew(ArrayList newServiceNames, string serviceName) + { + if (String.IsNullOrEmpty(serviceName)) + { + throw new ArgumentException(SR.security_ServiceNameCollection_EmptyServiceName); + } + + serviceName = NormalizeServiceName(serviceName); + + if (!Contains(serviceName, newServiceNames)) + { + newServiceNames.Add(serviceName); + } + } + + // Assumes searchServiceName and serviceNames have already been normalized. + internal static bool Contains(string searchServiceName, ICollection serviceNames) + { + Debug.Assert(serviceNames != null); + Debug.Assert(!String.IsNullOrEmpty(searchServiceName)); + + foreach (string serviceName in serviceNames) + { + if (Match(serviceName, searchServiceName)) + { + return true; + } + } + + return false; + } + + public bool Contains(string searchServiceName) + { + string searchName = NormalizeServiceName(searchServiceName); + + return Contains(searchName, InnerList); + } + + // Normalizes any punycode to unicode in an Service Name (SPN) host. + // If the algorithm fails at any point then the original input is returned. + // ServiceName is in one of the following forms: + // prefix/host + // prefix/host:port + // prefix/host/DistinguishedName + // prefix/host:port/DistinguishedName + internal static string NormalizeServiceName(string inputServiceName) + { + if (string.IsNullOrWhiteSpace(inputServiceName)) + { + return inputServiceName; + } + + // Separate out the prefix + int slashIndex = inputServiceName.IndexOf('/'); + if (slashIndex < 0) + { + return inputServiceName; + } + + string prefix = inputServiceName.Substring(0, slashIndex + 1); // Includes slash + string hostPortAndDistinguisher = inputServiceName.Substring(slashIndex + 1); // Excludes slash + + if (string.IsNullOrWhiteSpace(hostPortAndDistinguisher)) + { + return inputServiceName; + } + + string host = hostPortAndDistinguisher; + string port = string.Empty; + string distinguisher = string.Empty; + + // Check for the absence of a port or distinguisher. + UriHostNameType hostType = Uri.CheckHostName(hostPortAndDistinguisher); + if (hostType == UriHostNameType.Unknown) + { + string hostAndPort = hostPortAndDistinguisher; + + // Check for distinguisher. + int nextSlashIndex = hostPortAndDistinguisher.IndexOf('/'); + if (nextSlashIndex >= 0) + { + // host:port/distinguisher or host/distinguisher + hostAndPort = hostPortAndDistinguisher.Substring(0, nextSlashIndex); // Excludes Slash + distinguisher = hostPortAndDistinguisher.Substring(nextSlashIndex); // Includes Slash + host = hostAndPort; // We don't know if there is a port yet. + // No need to validate the distinguisher. + } + + // Check for port. + int colonIndex = hostAndPort.LastIndexOf(':'); // Allow IPv6 addresses. + if (colonIndex >= 0) + { + // host:port + host = hostAndPort.Substring(0, colonIndex); // Excludes colon + port = hostAndPort.Substring(colonIndex + 1); // Excludes colon + + // Loosely validate the port just to make sure it was a port and not something else. + UInt16 portValue; + if (!UInt16.TryParse(port, NumberStyles.Integer, CultureInfo.InvariantCulture, out portValue)) + { + return inputServiceName; + } + + // Re-include the colon for the final output. Do not change the port format. + port = hostAndPort.Substring(colonIndex); + } + + hostType = Uri.CheckHostName(host); // Re-validate the host. + } + + if (hostType != UriHostNameType.Dns) + { + // UriHostNameType.IPv4, UriHostNameType.IPv6: Do not normalize IPv4/6 hosts. + // UriHostNameType.Basic: This is never returned by CheckHostName today + // UriHostNameType.Unknown: Nothing recognizable to normalize + // default Some new UriHostNameType? + return inputServiceName; + } + + // Now we have a valid DNS host, normalize it. + + Uri constructedUri; + + // We need to avoid any unexpected exceptions on this code path. + if (!Uri.TryCreate(UriScheme.Http + UriScheme.SchemeDelimiter + host, UriKind.Absolute, out constructedUri)) + { + return inputServiceName; + } + + string normalizedHost = constructedUri.GetComponents( + UriComponents.NormalizedHost, UriFormat.SafeUnescaped); + + string normalizedServiceName = string.Format(CultureInfo.InvariantCulture, + "{0}{1}{2}{3}", prefix, normalizedHost, port, distinguisher); + + // Don't return the new one unless we absolutely have to. It may have only changed casing. + if (Match(inputServiceName, normalizedServiceName)) + { + return inputServiceName; + } + + return normalizedServiceName; + } + + // Assumes already normalized. + internal static bool Match(string serviceName1, string serviceName2) + { + return (String.Compare(serviceName1, serviceName2, StringComparison.OrdinalIgnoreCase) == 0); + } + } +} diff --git a/src/System.Net.Security/src/project.json b/src/System.Net.Security/src/project.json new file mode 100644 index 000000000000..e5c79a982a16 --- /dev/null +++ b/src/System.Net.Security/src/project.json @@ -0,0 +1,10 @@ +{ + "dependencies": { + "System.Diagnostics.Contracts": "4.0.0-*", + "System.Threading": "4.0.0-*", + "System.Net.Primitives": "4.0.10-beta-*" + }, + "frameworks": { + "dnxcore50": {} + } +} diff --git a/src/System.Net.Security/src/project.lock.json b/src/System.Net.Security/src/project.lock.json new file mode 100644 index 000000000000..eb9d3c9aab32 --- /dev/null +++ b/src/System.Net.Security/src/project.lock.json @@ -0,0 +1,1842 @@ +{ + "locked": true, + "version": 1, + "targets": { + "DNXCore,Version=v5.0": { + "Microsoft.Win32.Primitives/4.0.0-beta-23127": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.20-beta-23127", + "System.Runtime.InteropServices": "4.0.20-beta-23127" + }, + "compile": { + "ref/dotnet/Microsoft.Win32.Primitives.dll": {} + }, + "runtime": { + "lib/dotnet/Microsoft.Win32.Primitives.dll": {} + } + }, + "System.Collections/4.0.10-beta-23127": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.20-beta-23127" + }, + "compile": { + "ref/dotnet/System.Collections.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Collections.dll": {} + } + }, + "System.Collections.Concurrent/4.0.0-beta-23127": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.0-beta-23127", + "System.Threading.Tasks": "4.0.0-beta-23127" + }, + "compile": { + "ref/dotnet/System.Collections.Concurrent.dll": {} + } + }, + "System.Collections.NonGeneric/4.0.0-beta-23127": { + "type": "package", + "dependencies": { + "System.Diagnostics.Debug": "4.0.10-beta-23127", + "System.Globalization": "4.0.10-beta-23127", + "System.Resources.ResourceManager": "4.0.0-beta-23127", + "System.Runtime": "4.0.20-beta-23127", + "System.Runtime.Extensions": "4.0.10-beta-23127", + "System.Threading": "4.0.10-beta-23127" + }, + "compile": { + "ref/dotnet/System.Collections.NonGeneric.dll": {} + }, + "runtime": { + "lib/dotnet/System.Collections.NonGeneric.dll": {} + } + }, + "System.ComponentModel.EventBasedAsync/4.0.10-beta-23127": { + "type": "package", + "dependencies": { + "System.Resources.ResourceManager": "4.0.0-beta-23127", + "System.Runtime": "4.0.20-beta-23127", + "System.Threading": "4.0.10-beta-23127", + "System.Threading.Tasks": "4.0.10-beta-23127" + }, + "compile": { + "ref/dotnet/System.ComponentModel.EventBasedAsync.dll": {} + }, + "runtime": { + "lib/dotnet/System.ComponentModel.EventBasedAsync.dll": {} + } + }, + "System.Diagnostics.Contracts/4.0.0": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.0" + }, + "compile": { + "ref/dotnet/System.Diagnostics.Contracts.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Diagnostics.Contracts.dll": {} + } + }, + "System.Diagnostics.Debug/4.0.10-beta-23127": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.0-beta-23127" + }, + "compile": { + "ref/dotnet/System.Diagnostics.Debug.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Diagnostics.Debug.dll": {} + } + }, + "System.Diagnostics.Tracing/4.0.20-beta-23127": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.0-beta-23127" + }, + "compile": { + "ref/dotnet/System.Diagnostics.Tracing.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Diagnostics.Tracing.dll": {} + } + }, + "System.Globalization/4.0.10-beta-23127": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.0-beta-23127" + }, + "compile": { + "ref/dotnet/System.Globalization.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Globalization.dll": {} + } + }, + "System.Globalization.Calendars/4.0.0-beta-23127": { + "type": "package", + "dependencies": { + "System.Globalization": "4.0.0-beta-23127", + "System.Runtime": "4.0.0-beta-23127" + }, + "compile": { + "ref/dotnet/System.Globalization.Calendars.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Globalization.Calendars.dll": {} + } + }, + "System.IO/4.0.10-beta-23127": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.20-beta-23127", + "System.Text.Encoding": "4.0.0-beta-23127", + "System.Threading.Tasks": "4.0.0-beta-23127" + }, + "compile": { + "ref/dotnet/System.IO.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.IO.dll": {} + } + }, + "System.IO.FileSystem/4.0.0-beta-23127": { + "type": "package", + "dependencies": { + "System.Collections": "4.0.10-beta-23127", + "System.IO": "4.0.10-beta-23127", + "System.IO.FileSystem.Primitives": "4.0.0-beta-23127", + "System.Resources.ResourceManager": "4.0.0-beta-23127", + "System.Runtime": "4.0.20-beta-23127", + "System.Runtime.Extensions": "4.0.10-beta-23127", + "System.Runtime.Handles": "4.0.0-beta-23127", + "System.Runtime.InteropServices": "4.0.20-beta-23127", + "System.Text.Encoding": "4.0.10-beta-23127", + "System.Text.Encoding.Extensions": "4.0.10-beta-23127", + "System.Threading": "4.0.10-beta-23127", + "System.Threading.Overlapped": "4.0.0-beta-23127", + "System.Threading.Tasks": "4.0.10-beta-23127" + }, + "compile": { + "ref/dotnet/System.IO.FileSystem.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.IO.FileSystem.dll": {} + } + }, + "System.IO.FileSystem.Primitives/4.0.0-beta-23127": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.20-beta-23127" + }, + "compile": { + "ref/dotnet/System.IO.FileSystem.Primitives.dll": {} + }, + "runtime": { + "lib/dotnet/System.IO.FileSystem.Primitives.dll": {} + } + }, + "System.Net.Primitives/4.0.10-beta-23127": { + "type": "package", + "dependencies": { + "System.Private.Networking": "4.0.0-beta-23127" + }, + "compile": { + "ref/dotnet/System.Net.Primitives.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Net.Primitives.dll": {} + } + }, + "System.Private.Networking/4.0.0-beta-23127": { + "type": "package", + "dependencies": { + "Microsoft.Win32.Primitives": "4.0.0-beta-23127", + "System.Collections": "4.0.10-beta-23127", + "System.Collections.Concurrent": "4.0.0-beta-23127", + "System.Collections.NonGeneric": "4.0.0-beta-23127", + "System.ComponentModel.EventBasedAsync": "4.0.10-beta-23127", + "System.Diagnostics.Debug": "4.0.10-beta-23127", + "System.Diagnostics.Tracing": "4.0.20-beta-23127", + "System.Globalization": "4.0.10-beta-23127", + "System.IO": "4.0.10-beta-23127", + "System.IO.FileSystem": "4.0.0-beta-23127", + "System.IO.FileSystem.Primitives": "4.0.0-beta-23127", + "System.Resources.ResourceManager": "4.0.0-beta-23127", + "System.Runtime": "4.0.20-beta-23127", + "System.Runtime.Extensions": "4.0.10-beta-23127", + "System.Runtime.Handles": "4.0.0-beta-23127", + "System.Runtime.InteropServices": "4.0.20-beta-23127", + "System.Security.Cryptography.Primitives": "4.0.0-beta-23127", + "System.Security.Cryptography.X509Certificates": "4.0.0-beta-23127", + "System.Security.Principal.Windows": "4.0.0-beta-23127", + "System.Security.SecureString": "4.0.0-beta-23127", + "System.Threading": "4.0.10-beta-23127", + "System.Threading.Overlapped": "4.0.0-beta-23127", + "System.Threading.Tasks": "4.0.10-beta-23127", + "System.Threading.ThreadPool": "4.0.10-beta-23127" + }, + "compile": { + "ref/dnxcore50/_._": {} + }, + "runtime": { + "lib/DNXCore50/System.Private.Networking.dll": {} + } + }, + "System.Private.Uri/4.0.0-beta-23127": { + "type": "package", + "compile": { + "ref/dnxcore50/_._": {} + }, + "runtime": { + "lib/DNXCore50/System.Private.Uri.dll": {} + } + }, + "System.Reflection/4.0.0-beta-23127": { + "type": "package", + "dependencies": { + "System.IO": "4.0.0-beta-23127", + "System.Reflection.Primitives": "4.0.0-beta-23127", + "System.Runtime": "4.0.0-beta-23127" + }, + "compile": { + "ref/dotnet/System.Reflection.dll": {} + } + }, + "System.Reflection.Primitives/4.0.0-beta-23127": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.0-beta-23127" + }, + "compile": { + "ref/dotnet/System.Reflection.Primitives.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Reflection.Primitives.dll": {} + } + }, + "System.Resources.ResourceManager/4.0.0-beta-23127": { + "type": "package", + "dependencies": { + "System.Globalization": "4.0.0-beta-23127", + "System.Reflection": "4.0.0-beta-23127", + "System.Runtime": "4.0.0-beta-23127" + }, + "compile": { + "ref/dotnet/System.Resources.ResourceManager.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Resources.ResourceManager.dll": {} + } + }, + "System.Runtime/4.0.20-beta-23127": { + "type": "package", + "dependencies": { + "System.Private.Uri": "4.0.0-beta-23127" + }, + "compile": { + "ref/dotnet/System.Runtime.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Runtime.dll": {} + } + }, + "System.Runtime.Extensions/4.0.10-beta-23127": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.20-beta-23127" + }, + "compile": { + "ref/dotnet/System.Runtime.Extensions.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Runtime.Extensions.dll": {} + } + }, + "System.Runtime.Handles/4.0.0-beta-23127": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.0-beta-23127" + }, + "compile": { + "ref/dotnet/System.Runtime.Handles.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Runtime.Handles.dll": {} + } + }, + "System.Runtime.InteropServices/4.0.20-beta-23127": { + "type": "package", + "dependencies": { + "System.Reflection": "4.0.0-beta-23127", + "System.Reflection.Primitives": "4.0.0-beta-23127", + "System.Runtime": "4.0.0-beta-23127", + "System.Runtime.Handles": "4.0.0-beta-23127" + }, + "compile": { + "ref/dotnet/System.Runtime.InteropServices.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Runtime.InteropServices.dll": {} + } + }, + "System.Runtime.Numerics/4.0.0-beta-23127": { + "type": "package", + "dependencies": { + "System.Globalization": "4.0.10-beta-23127", + "System.Resources.ResourceManager": "4.0.0-beta-23127", + "System.Runtime": "4.0.20-beta-23127", + "System.Runtime.Extensions": "4.0.10-beta-23127" + }, + "compile": { + "ref/dotnet/System.Runtime.Numerics.dll": {} + }, + "runtime": { + "lib/dotnet/System.Runtime.Numerics.dll": {} + } + }, + "System.Security.Claims/4.0.0-beta-23127": { + "type": "package", + "dependencies": { + "System.Collections": "4.0.0-beta-23127", + "System.Diagnostics.Debug": "4.0.0-beta-23127", + "System.Globalization": "4.0.0-beta-23127", + "System.IO": "4.0.0-beta-23127", + "System.Resources.ResourceManager": "4.0.0-beta-23127", + "System.Runtime": "4.0.20-beta-23127", + "System.Runtime.Extensions": "4.0.0-beta-23127", + "System.Security.Principal": "4.0.0-beta-23127" + }, + "compile": { + "ref/dotnet/System.Security.Claims.dll": {} + }, + "runtime": { + "lib/dotnet/System.Security.Claims.dll": {} + } + }, + "System.Security.Cryptography.Algorithms/4.0.0-beta-23127": { + "type": "package", + "dependencies": { + "System.IO": "4.0.0-beta-23127", + "System.Resources.ResourceManager": "4.0.0-beta-23127", + "System.Runtime": "4.0.20-beta-23127", + "System.Runtime.Handles": "4.0.0-beta-23127", + "System.Security.Cryptography.Primitives": "4.0.0-beta-23127", + "System.Text.Encoding": "4.0.0-beta-23127", + "System.Text.Encoding.Extensions": "4.0.0-beta-23127" + }, + "compile": { + "ref/dotnet/System.Security.Cryptography.Algorithms.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Security.Cryptography.Algorithms.dll": {} + } + }, + "System.Security.Cryptography.Csp/4.0.0-beta-23127": { + "type": "package", + "dependencies": { + "System.IO": "4.0.0-beta-23127", + "System.Reflection": "4.0.0-beta-23127", + "System.Resources.ResourceManager": "4.0.0-beta-23127", + "System.Runtime": "4.0.20-beta-23127", + "System.Runtime.Extensions": "4.0.10-beta-23127", + "System.Runtime.Handles": "4.0.0-beta-23127", + "System.Runtime.InteropServices": "4.0.20-beta-23127", + "System.Security.Cryptography.Algorithms": "4.0.0-beta-23127", + "System.Security.Cryptography.Encoding": "4.0.0-beta-23127", + "System.Security.Cryptography.Primitives": "4.0.0-beta-23127", + "System.Threading": "4.0.10-beta-23127" + }, + "compile": { + "ref/dotnet/System.Security.Cryptography.Csp.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Security.Cryptography.Csp.dll": {} + } + }, + "System.Security.Cryptography.Encoding/4.0.0-beta-23127": { + "type": "package", + "dependencies": { + "System.Diagnostics.Debug": "4.0.10-beta-23127", + "System.Resources.ResourceManager": "4.0.0-beta-23127", + "System.Runtime": "4.0.20-beta-23127", + "System.Runtime.Handles": "4.0.0-beta-23127", + "System.Runtime.InteropServices": "4.0.20-beta-23127", + "System.Security.Cryptography.Primitives": "4.0.0-beta-23127" + }, + "compile": { + "ref/dotnet/System.Security.Cryptography.Encoding.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Security.Cryptography.Encoding.dll": {} + } + }, + "System.Security.Cryptography.Primitives/4.0.0-beta-23127": { + "type": "package", + "dependencies": { + "System.Globalization": "4.0.0-beta-23127", + "System.IO": "4.0.10-beta-23127", + "System.Resources.ResourceManager": "4.0.0-beta-23127", + "System.Runtime": "4.0.20-beta-23127" + }, + "compile": { + "ref/dotnet/System.Security.Cryptography.Primitives.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Security.Cryptography.Primitives.dll": {} + } + }, + "System.Security.Cryptography.X509Certificates/4.0.0-beta-23127": { + "type": "package", + "dependencies": { + "System.Collections": "4.0.10-beta-23127", + "System.Diagnostics.Debug": "4.0.10-beta-23127", + "System.Globalization": "4.0.10-beta-23127", + "System.Globalization.Calendars": "4.0.0-beta-23127", + "System.IO": "4.0.10-beta-23127", + "System.IO.FileSystem": "4.0.0-beta-23127", + "System.Resources.ResourceManager": "4.0.0-beta-23127", + "System.Runtime": "4.0.20-beta-23127", + "System.Runtime.Extensions": "4.0.10-beta-23127", + "System.Runtime.Handles": "4.0.0-beta-23127", + "System.Runtime.InteropServices": "4.0.20-beta-23127", + "System.Runtime.Numerics": "4.0.0-beta-23127", + "System.Security.Cryptography.Algorithms": "4.0.0-beta-23127", + "System.Security.Cryptography.Csp": "4.0.0-beta-23127", + "System.Security.Cryptography.Encoding": "4.0.0-beta-23127", + "System.Security.Cryptography.Primitives": "4.0.0-beta-23127", + "System.Text.Encoding": "4.0.10-beta-23127", + "System.Threading": "4.0.10-beta-23127" + }, + "compile": { + "ref/dotnet/System.Security.Cryptography.X509Certificates.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Security.Cryptography.X509Certificates.dll": {} + } + }, + "System.Security.Principal/4.0.0-beta-23127": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.0-beta-23127" + }, + "compile": { + "ref/dotnet/System.Security.Principal.dll": {} + }, + "runtime": { + "lib/dotnet/System.Security.Principal.dll": {} + } + }, + "System.Security.Principal.Windows/4.0.0-beta-23127": { + "type": "package", + "dependencies": { + "System.Collections": "4.0.0-beta-23127", + "System.Diagnostics.Debug": "4.0.0-beta-23127", + "System.Reflection": "4.0.0-beta-23127", + "System.Resources.ResourceManager": "4.0.0-beta-23127", + "System.Runtime": "4.0.20-beta-23127", + "System.Runtime.Extensions": "4.0.0-beta-23127", + "System.Runtime.InteropServices": "4.0.0-beta-23127", + "System.Security.Claims": "4.0.0-beta-23127", + "System.Security.Principal": "4.0.0-beta-23127", + "System.Threading": "4.0.10-beta-23127" + }, + "compile": { + "ref/dotnet/System.Security.Principal.Windows.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Security.Principal.Windows.dll": {} + } + }, + "System.Security.SecureString/4.0.0-beta-23127": { + "type": "package", + "dependencies": { + "System.Resources.ResourceManager": "4.0.0-beta-23127", + "System.Runtime": "4.0.20-beta-23127", + "System.Runtime.Handles": "4.0.0-beta-23127", + "System.Runtime.InteropServices": "4.0.20-beta-23127", + "System.Security.Cryptography.Primitives": "4.0.0-beta-23127", + "System.Threading": "4.0.10-beta-23127" + }, + "compile": { + "ref/dotnet/System.Security.SecureString.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Security.SecureString.dll": {} + } + }, + "System.Text.Encoding/4.0.10-beta-23127": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.0-beta-23127" + }, + "compile": { + "ref/dotnet/System.Text.Encoding.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Text.Encoding.dll": {} + } + }, + "System.Text.Encoding.Extensions/4.0.10-beta-23127": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.0-beta-23127", + "System.Text.Encoding": "4.0.10-beta-23127" + }, + "compile": { + "ref/dotnet/System.Text.Encoding.Extensions.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Text.Encoding.Extensions.dll": {} + } + }, + "System.Threading/4.0.0": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.0", + "System.Threading.Tasks": "4.0.0" + }, + "compile": { + "ref/dotnet/System.Threading.dll": {} + } + }, + "System.Threading.Overlapped/4.0.0-beta-23127": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.0-beta-23127", + "System.Runtime.Handles": "4.0.0-beta-23127" + }, + "compile": { + "ref/dotnet/System.Threading.Overlapped.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Threading.Overlapped.dll": {} + } + }, + "System.Threading.Tasks/4.0.10-beta-23127": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.0-beta-23127" + }, + "compile": { + "ref/dotnet/System.Threading.Tasks.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Threading.Tasks.dll": {} + } + }, + "System.Threading.ThreadPool/4.0.10-beta-23127": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.0-beta-23127", + "System.Runtime.InteropServices": "4.0.0-beta-23127" + }, + "compile": { + "ref/dotnet/System.Threading.ThreadPool.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Threading.ThreadPool.dll": {} + } + } + } + }, + "libraries": { + "Microsoft.Win32.Primitives/4.0.0-beta-23127": { + "type": "package", + "serviceable": true, + "sha512": "RhBDkPQpFEEx6gHmNlge7eG9up6U0lC41Sbgh8ugosNeputVZRzbskXMOPkgNz3I5FMU/E+g0YuJB/T8K0Slhg==", + "files": [ + "lib/dotnet/Microsoft.Win32.Primitives.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/Microsoft.Win32.Primitives.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "Microsoft.Win32.Primitives.4.0.0-beta-23127.nupkg", + "Microsoft.Win32.Primitives.4.0.0-beta-23127.nupkg.sha512", + "Microsoft.Win32.Primitives.nuspec", + "ref/dotnet/de/Microsoft.Win32.Primitives.xml", + "ref/dotnet/es/Microsoft.Win32.Primitives.xml", + "ref/dotnet/fr/Microsoft.Win32.Primitives.xml", + "ref/dotnet/it/Microsoft.Win32.Primitives.xml", + "ref/dotnet/ja/Microsoft.Win32.Primitives.xml", + "ref/dotnet/ko/Microsoft.Win32.Primitives.xml", + "ref/dotnet/Microsoft.Win32.Primitives.dll", + "ref/dotnet/Microsoft.Win32.Primitives.xml", + "ref/dotnet/ru/Microsoft.Win32.Primitives.xml", + "ref/dotnet/zh-hans/Microsoft.Win32.Primitives.xml", + "ref/dotnet/zh-hant/Microsoft.Win32.Primitives.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/Microsoft.Win32.Primitives.dll", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._" + ] + }, + "System.Collections/4.0.10-beta-23127": { + "type": "package", + "serviceable": true, + "sha512": "1XSlnhJpGCiRzmHn68jcX6yKPmJEdlUd1iE9KBTOR6posRM9xbFIgVMz8YxNSm76iFi5ukP8PVgs1ks0gWdkZQ==", + "files": [ + "lib/DNXCore50/System.Collections.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/_._", + "lib/netcore50/System.Collections.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/de/System.Collections.xml", + "ref/dotnet/es/System.Collections.xml", + "ref/dotnet/fr/System.Collections.xml", + "ref/dotnet/it/System.Collections.xml", + "ref/dotnet/ja/System.Collections.xml", + "ref/dotnet/ko/System.Collections.xml", + "ref/dotnet/ru/System.Collections.xml", + "ref/dotnet/System.Collections.dll", + "ref/dotnet/System.Collections.xml", + "ref/dotnet/zh-hans/System.Collections.xml", + "ref/dotnet/zh-hant/System.Collections.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "runtimes/win8-aot/lib/netcore50/System.Collections.dll", + "System.Collections.4.0.10-beta-23127.nupkg", + "System.Collections.4.0.10-beta-23127.nupkg.sha512", + "System.Collections.nuspec" + ] + }, + "System.Collections.Concurrent/4.0.0-beta-23127": { + "type": "package", + "sha512": "j8ufZHr70QG/Huw22TNMa2PNbTl81zdTdaYyruFbdHCuAjnzuIaumzspDpSGy6jmm8XMecbF6FjCpuqQ4T26cQ==", + "files": [ + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net45/_._", + "lib/win8/_._", + "lib/wpa81/_._", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "License.rtf", + "ref/dotnet/de/System.Collections.Concurrent.xml", + "ref/dotnet/es/System.Collections.Concurrent.xml", + "ref/dotnet/fr/System.Collections.Concurrent.xml", + "ref/dotnet/it/System.Collections.Concurrent.xml", + "ref/dotnet/ja/System.Collections.Concurrent.xml", + "ref/dotnet/ko/System.Collections.Concurrent.xml", + "ref/dotnet/ru/System.Collections.Concurrent.xml", + "ref/dotnet/System.Collections.Concurrent.dll", + "ref/dotnet/System.Collections.Concurrent.xml", + "ref/dotnet/zh-hans/System.Collections.Concurrent.xml", + "ref/dotnet/zh-hant/System.Collections.Concurrent.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net45/_._", + "ref/netcore50/de/System.Collections.Concurrent.xml", + "ref/netcore50/es/System.Collections.Concurrent.xml", + "ref/netcore50/fr/System.Collections.Concurrent.xml", + "ref/netcore50/it/System.Collections.Concurrent.xml", + "ref/netcore50/ja/System.Collections.Concurrent.xml", + "ref/netcore50/ko/System.Collections.Concurrent.xml", + "ref/netcore50/ru/System.Collections.Concurrent.xml", + "ref/netcore50/System.Collections.Concurrent.dll", + "ref/netcore50/System.Collections.Concurrent.xml", + "ref/netcore50/zh-hans/System.Collections.Concurrent.xml", + "ref/netcore50/zh-hant/System.Collections.Concurrent.xml", + "ref/win8/_._", + "ref/wpa81/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "System.Collections.Concurrent.4.0.0-beta-23127.nupkg", + "System.Collections.Concurrent.4.0.0-beta-23127.nupkg.sha512", + "System.Collections.Concurrent.nuspec" + ] + }, + "System.Collections.NonGeneric/4.0.0-beta-23127": { + "type": "package", + "serviceable": true, + "sha512": "/J9iHpOqRwPRM1WFY+F8pPqD9kJyPQLJRqlK40cncyHqzeNArDfjlVKtP8qTMxydZVWJy9RfSzelTeFUU8+xAQ==", + "files": [ + "lib/dotnet/System.Collections.NonGeneric.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/System.Collections.NonGeneric.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/de/System.Collections.NonGeneric.xml", + "ref/dotnet/es/System.Collections.NonGeneric.xml", + "ref/dotnet/fr/System.Collections.NonGeneric.xml", + "ref/dotnet/it/System.Collections.NonGeneric.xml", + "ref/dotnet/ja/System.Collections.NonGeneric.xml", + "ref/dotnet/ko/System.Collections.NonGeneric.xml", + "ref/dotnet/ru/System.Collections.NonGeneric.xml", + "ref/dotnet/System.Collections.NonGeneric.dll", + "ref/dotnet/System.Collections.NonGeneric.xml", + "ref/dotnet/zh-hans/System.Collections.NonGeneric.xml", + "ref/dotnet/zh-hant/System.Collections.NonGeneric.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/System.Collections.NonGeneric.dll", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "System.Collections.NonGeneric.4.0.0-beta-23127.nupkg", + "System.Collections.NonGeneric.4.0.0-beta-23127.nupkg.sha512", + "System.Collections.NonGeneric.nuspec" + ] + }, + "System.ComponentModel.EventBasedAsync/4.0.10-beta-23127": { + "type": "package", + "serviceable": true, + "sha512": "0QNgn7RwPaZxqLajGOGJrhubVIR/03Ruq3NrPZ9fzE6ff7guRafiYCOjjP5N1/UsOAaCqMmukArO7DbPBo3MjQ==", + "files": [ + "lib/dotnet/System.ComponentModel.EventBasedAsync.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/_._", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/de/System.ComponentModel.EventBasedAsync.xml", + "ref/dotnet/es/System.ComponentModel.EventBasedAsync.xml", + "ref/dotnet/fr/System.ComponentModel.EventBasedAsync.xml", + "ref/dotnet/it/System.ComponentModel.EventBasedAsync.xml", + "ref/dotnet/ja/System.ComponentModel.EventBasedAsync.xml", + "ref/dotnet/ko/System.ComponentModel.EventBasedAsync.xml", + "ref/dotnet/ru/System.ComponentModel.EventBasedAsync.xml", + "ref/dotnet/System.ComponentModel.EventBasedAsync.dll", + "ref/dotnet/System.ComponentModel.EventBasedAsync.xml", + "ref/dotnet/zh-hans/System.ComponentModel.EventBasedAsync.xml", + "ref/dotnet/zh-hant/System.ComponentModel.EventBasedAsync.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "System.ComponentModel.EventBasedAsync.4.0.10-beta-23127.nupkg", + "System.ComponentModel.EventBasedAsync.4.0.10-beta-23127.nupkg.sha512", + "System.ComponentModel.EventBasedAsync.nuspec" + ] + }, + "System.Diagnostics.Contracts/4.0.0": { + "type": "package", + "sha512": "lMc7HNmyIsu0pKTdA4wf+FMq5jvouUd+oUpV4BdtyqoV0Pkbg9u/7lTKFGqpjZRQosWHq1+B32Lch2wf4AmloA==", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/DNXCore50/System.Diagnostics.Contracts.dll", + "lib/net45/_._", + "lib/netcore50/System.Diagnostics.Contracts.dll", + "lib/win8/_._", + "lib/wp80/_._", + "lib/wpa81/_._", + "package/services/metadata/core-properties/c6cd3d0bbc304cbca14dc3d6bff6579c.psmdcp", + "ref/dotnet/de/System.Diagnostics.Contracts.xml", + "ref/dotnet/es/System.Diagnostics.Contracts.xml", + "ref/dotnet/fr/System.Diagnostics.Contracts.xml", + "ref/dotnet/it/System.Diagnostics.Contracts.xml", + "ref/dotnet/ja/System.Diagnostics.Contracts.xml", + "ref/dotnet/ko/System.Diagnostics.Contracts.xml", + "ref/dotnet/ru/System.Diagnostics.Contracts.xml", + "ref/dotnet/System.Diagnostics.Contracts.dll", + "ref/dotnet/System.Diagnostics.Contracts.xml", + "ref/dotnet/zh-hans/System.Diagnostics.Contracts.xml", + "ref/dotnet/zh-hant/System.Diagnostics.Contracts.xml", + "ref/net45/_._", + "ref/netcore50/System.Diagnostics.Contracts.dll", + "ref/netcore50/System.Diagnostics.Contracts.xml", + "ref/win8/_._", + "ref/wp80/_._", + "ref/wpa81/_._", + "runtimes/win8-aot/lib/netcore50/System.Diagnostics.Contracts.dll", + "System.Diagnostics.Contracts.nuspec" + ] + }, + "System.Diagnostics.Debug/4.0.10-beta-23127": { + "type": "package", + "serviceable": true, + "sha512": "n1wYReuu+uj36Lyu8FGkxGBsuQH6o1wCRMMd0z1daTiDS38MFvq8zGJdY7zv/s9S5dHRLHpTJSMFL56ByU+Ujg==", + "files": [ + "lib/DNXCore50/System.Diagnostics.Debug.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/_._", + "lib/netcore50/System.Diagnostics.Debug.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/de/System.Diagnostics.Debug.xml", + "ref/dotnet/es/System.Diagnostics.Debug.xml", + "ref/dotnet/fr/System.Diagnostics.Debug.xml", + "ref/dotnet/it/System.Diagnostics.Debug.xml", + "ref/dotnet/ja/System.Diagnostics.Debug.xml", + "ref/dotnet/ko/System.Diagnostics.Debug.xml", + "ref/dotnet/ru/System.Diagnostics.Debug.xml", + "ref/dotnet/System.Diagnostics.Debug.dll", + "ref/dotnet/System.Diagnostics.Debug.xml", + "ref/dotnet/zh-hans/System.Diagnostics.Debug.xml", + "ref/dotnet/zh-hant/System.Diagnostics.Debug.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "runtimes/win8-aot/lib/netcore50/System.Diagnostics.Debug.dll", + "System.Diagnostics.Debug.4.0.10-beta-23127.nupkg", + "System.Diagnostics.Debug.4.0.10-beta-23127.nupkg.sha512", + "System.Diagnostics.Debug.nuspec" + ] + }, + "System.Diagnostics.Tracing/4.0.20-beta-23127": { + "type": "package", + "serviceable": true, + "sha512": "6F+pXNXx5JTRQqK6hlhfKpFc82g1CfFIQdrkyzMs5dFH0kGnRz5SBzoteg8V1BE2AoDLltuW8RGnwTXJYT3Whg==", + "files": [ + "lib/DNXCore50/System.Diagnostics.Tracing.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/_._", + "lib/netcore50/System.Diagnostics.Tracing.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/de/System.Diagnostics.Tracing.xml", + "ref/dotnet/es/System.Diagnostics.Tracing.xml", + "ref/dotnet/fr/System.Diagnostics.Tracing.xml", + "ref/dotnet/it/System.Diagnostics.Tracing.xml", + "ref/dotnet/ja/System.Diagnostics.Tracing.xml", + "ref/dotnet/ko/System.Diagnostics.Tracing.xml", + "ref/dotnet/ru/System.Diagnostics.Tracing.xml", + "ref/dotnet/System.Diagnostics.Tracing.dll", + "ref/dotnet/System.Diagnostics.Tracing.xml", + "ref/dotnet/zh-hans/System.Diagnostics.Tracing.xml", + "ref/dotnet/zh-hant/System.Diagnostics.Tracing.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "runtimes/win8-aot/lib/netcore50/System.Diagnostics.Tracing.dll", + "System.Diagnostics.Tracing.4.0.20-beta-23127.nupkg", + "System.Diagnostics.Tracing.4.0.20-beta-23127.nupkg.sha512", + "System.Diagnostics.Tracing.nuspec" + ] + }, + "System.Globalization/4.0.10-beta-23127": { + "type": "package", + "sha512": "DtN6tLsL7WD6s9PEsP/XQ8vkkmKOstNqfbvuoEikyKRlmNhFoXn2VfJgxoEj31W/oSCSqfpiVAR2cTs9ha/7lQ==", + "files": [ + "lib/DNXCore50/System.Globalization.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/_._", + "lib/netcore50/System.Globalization.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/de/System.Globalization.xml", + "ref/dotnet/es/System.Globalization.xml", + "ref/dotnet/fr/System.Globalization.xml", + "ref/dotnet/it/System.Globalization.xml", + "ref/dotnet/ja/System.Globalization.xml", + "ref/dotnet/ko/System.Globalization.xml", + "ref/dotnet/ru/System.Globalization.xml", + "ref/dotnet/System.Globalization.dll", + "ref/dotnet/System.Globalization.xml", + "ref/dotnet/zh-hans/System.Globalization.xml", + "ref/dotnet/zh-hant/System.Globalization.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "runtimes/win8-aot/lib/netcore50/System.Globalization.dll", + "System.Globalization.4.0.10-beta-23127.nupkg", + "System.Globalization.4.0.10-beta-23127.nupkg.sha512", + "System.Globalization.nuspec" + ] + }, + "System.Globalization.Calendars/4.0.0-beta-23127": { + "type": "package", + "sha512": "qGG4XuUE9Mj3akqNbZdjmbV32hFBrNEyg9NaVT9kiccEmFN3N7nFcu9fsHg5TgiNrHzyWoqYFCcwjfAF0Qx7nw==", + "files": [ + "lib/DNXCore50/System.Globalization.Calendars.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/System.Globalization.Calendars.dll", + "lib/netcore50/System.Globalization.Calendars.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/de/System.Globalization.Calendars.xml", + "ref/dotnet/es/System.Globalization.Calendars.xml", + "ref/dotnet/fr/System.Globalization.Calendars.xml", + "ref/dotnet/it/System.Globalization.Calendars.xml", + "ref/dotnet/ja/System.Globalization.Calendars.xml", + "ref/dotnet/ko/System.Globalization.Calendars.xml", + "ref/dotnet/ru/System.Globalization.Calendars.xml", + "ref/dotnet/System.Globalization.Calendars.dll", + "ref/dotnet/System.Globalization.Calendars.xml", + "ref/dotnet/zh-hans/System.Globalization.Calendars.xml", + "ref/dotnet/zh-hant/System.Globalization.Calendars.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/System.Globalization.Calendars.dll", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "runtimes/win8-aot/lib/netcore50/System.Globalization.Calendars.dll", + "System.Globalization.Calendars.4.0.0-beta-23127.nupkg", + "System.Globalization.Calendars.4.0.0-beta-23127.nupkg.sha512", + "System.Globalization.Calendars.nuspec" + ] + }, + "System.IO/4.0.10-beta-23127": { + "type": "package", + "serviceable": true, + "sha512": "YOBBR0IcbiCRKyv+WDz1ofHSj8m+uGeBA3NJtZTcKMQxo3kJaB15+LIlh3qprRz3WxhQ08uPy7P/orbQ7vBHkQ==", + "files": [ + "lib/DNXCore50/System.IO.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/_._", + "lib/netcore50/System.IO.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/de/System.IO.xml", + "ref/dotnet/es/System.IO.xml", + "ref/dotnet/fr/System.IO.xml", + "ref/dotnet/it/System.IO.xml", + "ref/dotnet/ja/System.IO.xml", + "ref/dotnet/ko/System.IO.xml", + "ref/dotnet/ru/System.IO.xml", + "ref/dotnet/System.IO.dll", + "ref/dotnet/System.IO.xml", + "ref/dotnet/zh-hans/System.IO.xml", + "ref/dotnet/zh-hant/System.IO.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "runtimes/win8-aot/lib/netcore50/System.IO.dll", + "System.IO.4.0.10-beta-23127.nupkg", + "System.IO.4.0.10-beta-23127.nupkg.sha512", + "System.IO.nuspec" + ] + }, + "System.IO.FileSystem/4.0.0-beta-23127": { + "type": "package", + "serviceable": true, + "sha512": "kqCi4we0nY7GWnW0qbjALOX7BPQNaOpsDNbBDDoX2YSp+cEbqWPpcutqHNLeD7YjsZ/ZgrDvNJpAi2eXYeCtRQ==", + "files": [ + "lib/DNXCore50/System.IO.FileSystem.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/System.IO.FileSystem.dll", + "lib/netcore50/System.IO.FileSystem.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/de/System.IO.FileSystem.xml", + "ref/dotnet/es/System.IO.FileSystem.xml", + "ref/dotnet/fr/System.IO.FileSystem.xml", + "ref/dotnet/it/System.IO.FileSystem.xml", + "ref/dotnet/ja/System.IO.FileSystem.xml", + "ref/dotnet/ko/System.IO.FileSystem.xml", + "ref/dotnet/ru/System.IO.FileSystem.xml", + "ref/dotnet/System.IO.FileSystem.dll", + "ref/dotnet/System.IO.FileSystem.xml", + "ref/dotnet/zh-hans/System.IO.FileSystem.xml", + "ref/dotnet/zh-hant/System.IO.FileSystem.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/System.IO.FileSystem.dll", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "System.IO.FileSystem.4.0.0-beta-23127.nupkg", + "System.IO.FileSystem.4.0.0-beta-23127.nupkg.sha512", + "System.IO.FileSystem.nuspec" + ] + }, + "System.IO.FileSystem.Primitives/4.0.0-beta-23127": { + "type": "package", + "serviceable": true, + "sha512": "xyAAsqf/198kaCGfaL5KLnVCdkP877b2ohtQPVS5ilkhZ0pkjZ3Uy3fwGmGXVseBI9m8lpO1KDb3OG+cQRhRiw==", + "files": [ + "lib/dotnet/System.IO.FileSystem.Primitives.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/System.IO.FileSystem.Primitives.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/de/System.IO.FileSystem.Primitives.xml", + "ref/dotnet/es/System.IO.FileSystem.Primitives.xml", + "ref/dotnet/fr/System.IO.FileSystem.Primitives.xml", + "ref/dotnet/it/System.IO.FileSystem.Primitives.xml", + "ref/dotnet/ja/System.IO.FileSystem.Primitives.xml", + "ref/dotnet/ko/System.IO.FileSystem.Primitives.xml", + "ref/dotnet/ru/System.IO.FileSystem.Primitives.xml", + "ref/dotnet/System.IO.FileSystem.Primitives.dll", + "ref/dotnet/System.IO.FileSystem.Primitives.xml", + "ref/dotnet/zh-hans/System.IO.FileSystem.Primitives.xml", + "ref/dotnet/zh-hant/System.IO.FileSystem.Primitives.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/System.IO.FileSystem.Primitives.dll", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "System.IO.FileSystem.Primitives.4.0.0-beta-23127.nupkg", + "System.IO.FileSystem.Primitives.4.0.0-beta-23127.nupkg.sha512", + "System.IO.FileSystem.Primitives.nuspec" + ] + }, + "System.Net.Primitives/4.0.10-beta-23127": { + "type": "package", + "serviceable": true, + "sha512": "iMopReygV88cUUXWeem9y9vrb1Sn8gOXXaRClKWW1KrRozBklOh6Og+b/gpsVQJpz2ztZLJI3k96ttoie2M2QA==", + "files": [ + "lib/DNXCore50/System.Net.Primitives.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/_._", + "lib/netcore50/System.Net.Primitives.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/de/System.Net.Primitives.xml", + "ref/dotnet/es/System.Net.Primitives.xml", + "ref/dotnet/fr/System.Net.Primitives.xml", + "ref/dotnet/it/System.Net.Primitives.xml", + "ref/dotnet/ja/System.Net.Primitives.xml", + "ref/dotnet/ko/System.Net.Primitives.xml", + "ref/dotnet/ru/System.Net.Primitives.xml", + "ref/dotnet/System.Net.Primitives.dll", + "ref/dotnet/System.Net.Primitives.xml", + "ref/dotnet/zh-hans/System.Net.Primitives.xml", + "ref/dotnet/zh-hant/System.Net.Primitives.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "System.Net.Primitives.4.0.10-beta-23127.nupkg", + "System.Net.Primitives.4.0.10-beta-23127.nupkg.sha512", + "System.Net.Primitives.nuspec" + ] + }, + "System.Private.Networking/4.0.0-beta-23127": { + "type": "package", + "serviceable": true, + "sha512": "KgVFtvhIvZX36Mat5xGyLwKqmo1syvm8aH+Y8sMbbrKEeMOn6QuyiDSyUy1ahu8WbUQdnRCLB0VqgKUDwzeZ2w==", + "files": [ + "lib/DNXCore50/System.Private.Networking.dll", + "lib/netcore50/System.Private.Networking.dll", + "ref/dnxcore50/_._", + "ref/netcore50/_._", + "System.Private.Networking.4.0.0-beta-23127.nupkg", + "System.Private.Networking.4.0.0-beta-23127.nupkg.sha512", + "System.Private.Networking.nuspec" + ] + }, + "System.Private.Uri/4.0.0-beta-23127": { + "type": "package", + "serviceable": true, + "sha512": "KT9JGnTYRf51pwPluZtpewmdBPiROzemamLmpzgzl3Pu3Y0vmH2CBLZktngD4I4YPNFO6ieCupeM0X3R1u26kA==", + "files": [ + "lib/DNXCore50/System.Private.Uri.dll", + "lib/netcore50/System.Private.Uri.dll", + "ref/dnxcore50/_._", + "ref/netcore50/_._", + "runtimes/win8-aot/lib/netcore50/System.Private.Uri.dll", + "System.Private.Uri.4.0.0-beta-23127.nupkg", + "System.Private.Uri.4.0.0-beta-23127.nupkg.sha512", + "System.Private.Uri.nuspec" + ] + }, + "System.Reflection/4.0.0-beta-23127": { + "type": "package", + "sha512": "C2H07xfQjIbtyFuD5T/g0QYc8sE0rhq3lNpL/LUmlQ7jS8xTm2hxTOvYqyPbmf4pYtBRQ3fS7/8mwRexPdN1wA==", + "files": [ + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net45/_._", + "lib/win8/_._", + "lib/wp80/_._", + "lib/wpa81/_._", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "License.rtf", + "ref/dotnet/de/System.Reflection.xml", + "ref/dotnet/es/System.Reflection.xml", + "ref/dotnet/fr/System.Reflection.xml", + "ref/dotnet/it/System.Reflection.xml", + "ref/dotnet/ja/System.Reflection.xml", + "ref/dotnet/ko/System.Reflection.xml", + "ref/dotnet/ru/System.Reflection.xml", + "ref/dotnet/System.Reflection.dll", + "ref/dotnet/System.Reflection.xml", + "ref/dotnet/zh-hans/System.Reflection.xml", + "ref/dotnet/zh-hant/System.Reflection.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net45/_._", + "ref/netcore50/de/System.Reflection.xml", + "ref/netcore50/es/System.Reflection.xml", + "ref/netcore50/fr/System.Reflection.xml", + "ref/netcore50/it/System.Reflection.xml", + "ref/netcore50/ja/System.Reflection.xml", + "ref/netcore50/ko/System.Reflection.xml", + "ref/netcore50/ru/System.Reflection.xml", + "ref/netcore50/System.Reflection.dll", + "ref/netcore50/System.Reflection.xml", + "ref/netcore50/zh-hans/System.Reflection.xml", + "ref/netcore50/zh-hant/System.Reflection.xml", + "ref/win8/_._", + "ref/wp80/_._", + "ref/wpa81/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "System.Reflection.4.0.0-beta-23127.nupkg", + "System.Reflection.4.0.0-beta-23127.nupkg.sha512", + "System.Reflection.nuspec" + ] + }, + "System.Reflection.Primitives/4.0.0-beta-23127": { + "type": "package", + "serviceable": true, + "sha512": "qUjIaT8GBhxh5pyY1xhQd3/Rn5CJMu023GGNWXObr6/I/lX9LWpJD+UJAsPcLMEXOFq3QaKk6+giNjaqIdcf7Q==", + "files": [ + "lib/DNXCore50/System.Reflection.Primitives.dll", + "lib/net45/_._", + "lib/netcore50/System.Reflection.Primitives.dll", + "lib/win8/_._", + "lib/wp80/_._", + "lib/wpa81/_._", + "ref/dotnet/de/System.Reflection.Primitives.xml", + "ref/dotnet/es/System.Reflection.Primitives.xml", + "ref/dotnet/fr/System.Reflection.Primitives.xml", + "ref/dotnet/it/System.Reflection.Primitives.xml", + "ref/dotnet/ja/System.Reflection.Primitives.xml", + "ref/dotnet/ko/System.Reflection.Primitives.xml", + "ref/dotnet/ru/System.Reflection.Primitives.xml", + "ref/dotnet/System.Reflection.Primitives.dll", + "ref/dotnet/System.Reflection.Primitives.xml", + "ref/dotnet/zh-hans/System.Reflection.Primitives.xml", + "ref/dotnet/zh-hant/System.Reflection.Primitives.xml", + "ref/net45/_._", + "ref/netcore50/System.Reflection.Primitives.dll", + "ref/netcore50/System.Reflection.Primitives.xml", + "ref/win8/_._", + "ref/wp80/_._", + "ref/wpa81/_._", + "runtimes/win8-aot/lib/netcore50/System.Reflection.Primitives.dll", + "System.Reflection.Primitives.4.0.0-beta-23127.nupkg", + "System.Reflection.Primitives.4.0.0-beta-23127.nupkg.sha512", + "System.Reflection.Primitives.nuspec" + ] + }, + "System.Resources.ResourceManager/4.0.0-beta-23127": { + "type": "package", + "serviceable": true, + "sha512": "+stu9oGQvmjeFJfhg4zRf/D0jNGa2L7MIkGz3ik70loEFHLE3OrOXFt3T+3eG37Z6md2KCWKe+85ct6VDaEtWA==", + "files": [ + "lib/DNXCore50/System.Resources.ResourceManager.dll", + "lib/net45/_._", + "lib/netcore50/System.Resources.ResourceManager.dll", + "lib/win8/_._", + "lib/wp80/_._", + "lib/wpa81/_._", + "ref/dotnet/de/System.Resources.ResourceManager.xml", + "ref/dotnet/es/System.Resources.ResourceManager.xml", + "ref/dotnet/fr/System.Resources.ResourceManager.xml", + "ref/dotnet/it/System.Resources.ResourceManager.xml", + "ref/dotnet/ja/System.Resources.ResourceManager.xml", + "ref/dotnet/ko/System.Resources.ResourceManager.xml", + "ref/dotnet/ru/System.Resources.ResourceManager.xml", + "ref/dotnet/System.Resources.ResourceManager.dll", + "ref/dotnet/System.Resources.ResourceManager.xml", + "ref/dotnet/zh-hans/System.Resources.ResourceManager.xml", + "ref/dotnet/zh-hant/System.Resources.ResourceManager.xml", + "ref/net45/_._", + "ref/netcore50/System.Resources.ResourceManager.dll", + "ref/netcore50/System.Resources.ResourceManager.xml", + "ref/win8/_._", + "ref/wp80/_._", + "ref/wpa81/_._", + "runtimes/win8-aot/lib/netcore50/System.Resources.ResourceManager.dll", + "System.Resources.ResourceManager.4.0.0-beta-23127.nupkg", + "System.Resources.ResourceManager.4.0.0-beta-23127.nupkg.sha512", + "System.Resources.ResourceManager.nuspec" + ] + }, + "System.Runtime/4.0.20-beta-23127": { + "type": "package", + "serviceable": true, + "sha512": "naLsXkry4PBYCdXLOGx2r9TRuFWJpdZvV7W9rk4QRTPTS7H9911J09o8KXrhX+NW28YVsCgvcw8Wr0JsFEQdLQ==", + "files": [ + "lib/DNXCore50/System.Runtime.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/_._", + "lib/netcore50/System.Runtime.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/de/System.Runtime.xml", + "ref/dotnet/es/System.Runtime.xml", + "ref/dotnet/fr/System.Runtime.xml", + "ref/dotnet/it/System.Runtime.xml", + "ref/dotnet/ja/System.Runtime.xml", + "ref/dotnet/ko/System.Runtime.xml", + "ref/dotnet/ru/System.Runtime.xml", + "ref/dotnet/System.Runtime.dll", + "ref/dotnet/System.Runtime.xml", + "ref/dotnet/zh-hans/System.Runtime.xml", + "ref/dotnet/zh-hant/System.Runtime.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "runtimes/win8-aot/lib/netcore50/System.Runtime.dll", + "System.Runtime.4.0.20-beta-23127.nupkg", + "System.Runtime.4.0.20-beta-23127.nupkg.sha512", + "System.Runtime.nuspec" + ] + }, + "System.Runtime.Extensions/4.0.10-beta-23127": { + "type": "package", + "serviceable": true, + "sha512": "YwtpybYxpRqjF+TnBzmNdgGq2jNtEO9MkxYSIMW36lV7F6qEph+nCcKDLsCslgSz7dn44eSCnnsgBQQsF85eQQ==", + "files": [ + "lib/DNXCore50/System.Runtime.Extensions.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/_._", + "lib/netcore50/System.Runtime.Extensions.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/de/System.Runtime.Extensions.xml", + "ref/dotnet/es/System.Runtime.Extensions.xml", + "ref/dotnet/fr/System.Runtime.Extensions.xml", + "ref/dotnet/it/System.Runtime.Extensions.xml", + "ref/dotnet/ja/System.Runtime.Extensions.xml", + "ref/dotnet/ko/System.Runtime.Extensions.xml", + "ref/dotnet/ru/System.Runtime.Extensions.xml", + "ref/dotnet/System.Runtime.Extensions.dll", + "ref/dotnet/System.Runtime.Extensions.xml", + "ref/dotnet/zh-hans/System.Runtime.Extensions.xml", + "ref/dotnet/zh-hant/System.Runtime.Extensions.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "runtimes/win8-aot/lib/netcore50/System.Runtime.Extensions.dll", + "System.Runtime.Extensions.4.0.10-beta-23127.nupkg", + "System.Runtime.Extensions.4.0.10-beta-23127.nupkg.sha512", + "System.Runtime.Extensions.nuspec" + ] + }, + "System.Runtime.Handles/4.0.0-beta-23127": { + "type": "package", + "serviceable": true, + "sha512": "q+CqdcecC00xfyVHTQhtned/RNzZhAtS/04uchISsl5ovKEAnnSRCOPOJJud/dl9iW12U+Lt8YlKub/LoxbZtQ==", + "files": [ + "lib/DNXCore50/System.Runtime.Handles.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/_._", + "lib/netcore50/System.Runtime.Handles.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/de/System.Runtime.Handles.xml", + "ref/dotnet/es/System.Runtime.Handles.xml", + "ref/dotnet/fr/System.Runtime.Handles.xml", + "ref/dotnet/it/System.Runtime.Handles.xml", + "ref/dotnet/ja/System.Runtime.Handles.xml", + "ref/dotnet/ko/System.Runtime.Handles.xml", + "ref/dotnet/ru/System.Runtime.Handles.xml", + "ref/dotnet/System.Runtime.Handles.dll", + "ref/dotnet/System.Runtime.Handles.xml", + "ref/dotnet/zh-hans/System.Runtime.Handles.xml", + "ref/dotnet/zh-hant/System.Runtime.Handles.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "runtimes/win8-aot/lib/netcore50/System.Runtime.Handles.dll", + "System.Runtime.Handles.4.0.0-beta-23127.nupkg", + "System.Runtime.Handles.4.0.0-beta-23127.nupkg.sha512", + "System.Runtime.Handles.nuspec" + ] + }, + "System.Runtime.InteropServices/4.0.20-beta-23127": { + "type": "package", + "serviceable": true, + "sha512": "oJpQACYOQ/TXcIEZh8MdIqkDlRrnXV9DoPiVnXUgnKYFub7NnKb02sx65eWrNPwutt0ewDD9hNAuPjAGBC1MQA==", + "files": [ + "lib/DNXCore50/System.Runtime.InteropServices.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/_._", + "lib/netcore50/System.Runtime.InteropServices.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/de/System.Runtime.InteropServices.xml", + "ref/dotnet/es/System.Runtime.InteropServices.xml", + "ref/dotnet/fr/System.Runtime.InteropServices.xml", + "ref/dotnet/it/System.Runtime.InteropServices.xml", + "ref/dotnet/ja/System.Runtime.InteropServices.xml", + "ref/dotnet/ko/System.Runtime.InteropServices.xml", + "ref/dotnet/ru/System.Runtime.InteropServices.xml", + "ref/dotnet/System.Runtime.InteropServices.dll", + "ref/dotnet/System.Runtime.InteropServices.xml", + "ref/dotnet/zh-hans/System.Runtime.InteropServices.xml", + "ref/dotnet/zh-hant/System.Runtime.InteropServices.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "runtimes/win8-aot/lib/netcore50/System.Runtime.InteropServices.dll", + "System.Runtime.InteropServices.4.0.20-beta-23127.nupkg", + "System.Runtime.InteropServices.4.0.20-beta-23127.nupkg.sha512", + "System.Runtime.InteropServices.nuspec" + ] + }, + "System.Runtime.Numerics/4.0.0-beta-23127": { + "type": "package", + "serviceable": true, + "sha512": "qB+XSAhTz7gwZG8XUV+8Z4XgygM2OWiKCwepK1GecRfDT3XBzA+FCU9xgpwyGSpz5zExN0tjsbBG2J1Au6xHKw==", + "files": [ + "lib/dotnet/System.Runtime.Numerics.dll", + "lib/net45/_._", + "lib/netcore50/System.Runtime.Numerics.dll", + "lib/win8/_._", + "lib/wpa81/_._", + "ref/dotnet/de/System.Runtime.Numerics.xml", + "ref/dotnet/es/System.Runtime.Numerics.xml", + "ref/dotnet/fr/System.Runtime.Numerics.xml", + "ref/dotnet/it/System.Runtime.Numerics.xml", + "ref/dotnet/ja/System.Runtime.Numerics.xml", + "ref/dotnet/ko/System.Runtime.Numerics.xml", + "ref/dotnet/ru/System.Runtime.Numerics.xml", + "ref/dotnet/System.Runtime.Numerics.dll", + "ref/dotnet/System.Runtime.Numerics.xml", + "ref/dotnet/zh-hans/System.Runtime.Numerics.xml", + "ref/dotnet/zh-hant/System.Runtime.Numerics.xml", + "ref/net45/_._", + "ref/netcore50/System.Runtime.Numerics.dll", + "ref/netcore50/System.Runtime.Numerics.xml", + "ref/win8/_._", + "ref/wpa81/_._", + "System.Runtime.Numerics.4.0.0-beta-23127.nupkg", + "System.Runtime.Numerics.4.0.0-beta-23127.nupkg.sha512", + "System.Runtime.Numerics.nuspec" + ] + }, + "System.Security.Claims/4.0.0-beta-23127": { + "type": "package", + "serviceable": true, + "sha512": "WxCXTjY6iqWA+26Oq8NUV8K5zNBc/m2yRfmBGa96+Ch2HSeINwJLio1a6VlD7m16aeqfIDxCkIM9GNl2sYGIww==", + "files": [ + "lib/dotnet/System.Security.Claims.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/System.Security.Claims.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/de/System.Security.Claims.xml", + "ref/dotnet/es/System.Security.Claims.xml", + "ref/dotnet/fr/System.Security.Claims.xml", + "ref/dotnet/it/System.Security.Claims.xml", + "ref/dotnet/ja/System.Security.Claims.xml", + "ref/dotnet/ko/System.Security.Claims.xml", + "ref/dotnet/ru/System.Security.Claims.xml", + "ref/dotnet/System.Security.Claims.dll", + "ref/dotnet/System.Security.Claims.xml", + "ref/dotnet/zh-hans/System.Security.Claims.xml", + "ref/dotnet/zh-hant/System.Security.Claims.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/System.Security.Claims.dll", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "System.Security.Claims.4.0.0-beta-23127.nupkg", + "System.Security.Claims.4.0.0-beta-23127.nupkg.sha512", + "System.Security.Claims.nuspec" + ] + }, + "System.Security.Cryptography.Algorithms/4.0.0-beta-23127": { + "type": "package", + "serviceable": true, + "sha512": "yFHIFZ323kXmA0HE/k2yUnUNitaQYOf+sRxvV29KCUFGOmoWOTKRm9dn+z71xhux5V2i7ZuPhb4KOjskEiTMGA==", + "files": [ + "lib/DNXCore50/System.Security.Cryptography.Algorithms.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/System.Security.Cryptography.Algorithms.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/System.Security.Cryptography.Algorithms.dll", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/System.Security.Cryptography.Algorithms.dll", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "System.Security.Cryptography.Algorithms.4.0.0-beta-23127.nupkg", + "System.Security.Cryptography.Algorithms.4.0.0-beta-23127.nupkg.sha512", + "System.Security.Cryptography.Algorithms.nuspec" + ] + }, + "System.Security.Cryptography.Csp/4.0.0-beta-23127": { + "type": "package", + "serviceable": true, + "sha512": "0heOYE/0HnQU6rcEL2g+OzgAyeVepegmva1/B8cMdYRATREz/mNwrpd7qOoW0SWjq51fUfBd3wTGU78lV7MOEA==", + "files": [ + "lib/DNXCore50/System.Security.Cryptography.Csp.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/System.Security.Cryptography.Csp.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/System.Security.Cryptography.Csp.dll", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/System.Security.Cryptography.Csp.dll", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "System.Security.Cryptography.Csp.4.0.0-beta-23127.nupkg", + "System.Security.Cryptography.Csp.4.0.0-beta-23127.nupkg.sha512", + "System.Security.Cryptography.Csp.nuspec" + ] + }, + "System.Security.Cryptography.Encoding/4.0.0-beta-23127": { + "type": "package", + "serviceable": true, + "sha512": "Asq9e58QLgiZ32YEp5aCJFSgMHM7rotzxexdq+VbBSWD7bBJybUVY9g85LN1FCsv0AeCxayZ6Hscyr0Rwd8R6g==", + "files": [ + "lib/DNXCore50/System.Security.Cryptography.Encoding.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/System.Security.Cryptography.Encoding.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/de/System.Security.Cryptography.Encoding.xml", + "ref/dotnet/es/System.Security.Cryptography.Encoding.xml", + "ref/dotnet/fr/System.Security.Cryptography.Encoding.xml", + "ref/dotnet/it/System.Security.Cryptography.Encoding.xml", + "ref/dotnet/ja/System.Security.Cryptography.Encoding.xml", + "ref/dotnet/ko/System.Security.Cryptography.Encoding.xml", + "ref/dotnet/ru/System.Security.Cryptography.Encoding.xml", + "ref/dotnet/System.Security.Cryptography.Encoding.dll", + "ref/dotnet/System.Security.Cryptography.Encoding.xml", + "ref/dotnet/zh-hans/System.Security.Cryptography.Encoding.xml", + "ref/dotnet/zh-hant/System.Security.Cryptography.Encoding.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/System.Security.Cryptography.Encoding.dll", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "System.Security.Cryptography.Encoding.4.0.0-beta-23127.nupkg", + "System.Security.Cryptography.Encoding.4.0.0-beta-23127.nupkg.sha512", + "System.Security.Cryptography.Encoding.nuspec" + ] + }, + "System.Security.Cryptography.Primitives/4.0.0-beta-23127": { + "type": "package", + "serviceable": true, + "sha512": "DfVrthXW+V8VnNhbiil7gfVysbkqZD5oRCLL8JiUypE8nuHvQxfFvyxi/PagTTOBin8no8in9Z+Oth66FLWb/w==", + "files": [ + "lib/DNXCore50/System.Security.Cryptography.Primitives.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/System.Security.Cryptography.Primitives.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/System.Security.Cryptography.Primitives.dll", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/System.Security.Cryptography.Primitives.dll", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "System.Security.Cryptography.Primitives.4.0.0-beta-23127.nupkg", + "System.Security.Cryptography.Primitives.4.0.0-beta-23127.nupkg.sha512", + "System.Security.Cryptography.Primitives.nuspec" + ] + }, + "System.Security.Cryptography.X509Certificates/4.0.0-beta-23127": { + "type": "package", + "serviceable": true, + "sha512": "Qyr6GUDmYwoX1eN9rRXmolE8V71zf1sLFtYwlVmccPcr8nis5HHW4wmwalXYQKGC2iR0PoVqiVGSLLSnnabBjQ==", + "files": [ + "lib/DNXCore50/System.Security.Cryptography.X509Certificates.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/System.Security.Cryptography.X509Certificates.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/de/System.Security.Cryptography.X509Certificates.xml", + "ref/dotnet/es/System.Security.Cryptography.X509Certificates.xml", + "ref/dotnet/fr/System.Security.Cryptography.X509Certificates.xml", + "ref/dotnet/it/System.Security.Cryptography.X509Certificates.xml", + "ref/dotnet/ja/System.Security.Cryptography.X509Certificates.xml", + "ref/dotnet/ko/System.Security.Cryptography.X509Certificates.xml", + "ref/dotnet/ru/System.Security.Cryptography.X509Certificates.xml", + "ref/dotnet/System.Security.Cryptography.X509Certificates.dll", + "ref/dotnet/System.Security.Cryptography.X509Certificates.xml", + "ref/dotnet/zh-hans/System.Security.Cryptography.X509Certificates.xml", + "ref/dotnet/zh-hant/System.Security.Cryptography.X509Certificates.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/System.Security.Cryptography.X509Certificates.dll", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "System.Security.Cryptography.X509Certificates.4.0.0-beta-23127.nupkg", + "System.Security.Cryptography.X509Certificates.4.0.0-beta-23127.nupkg.sha512", + "System.Security.Cryptography.X509Certificates.nuspec" + ] + }, + "System.Security.Principal/4.0.0-beta-23127": { + "type": "package", + "serviceable": true, + "sha512": "XiETY0hBbuL6VCgE/jyTiMuZpBRi/iv1irzWVRiXfsyPxD/iww7gCcepot9XD0lKiLq/H4F0dVh0EX7lib1Mxg==", + "files": [ + "lib/dotnet/System.Security.Principal.dll", + "lib/net45/_._", + "lib/netcore50/System.Security.Principal.dll", + "lib/win8/_._", + "lib/wp80/_._", + "lib/wpa81/_._", + "ref/dotnet/de/System.Security.Principal.xml", + "ref/dotnet/es/System.Security.Principal.xml", + "ref/dotnet/fr/System.Security.Principal.xml", + "ref/dotnet/it/System.Security.Principal.xml", + "ref/dotnet/ja/System.Security.Principal.xml", + "ref/dotnet/ko/System.Security.Principal.xml", + "ref/dotnet/ru/System.Security.Principal.xml", + "ref/dotnet/System.Security.Principal.dll", + "ref/dotnet/System.Security.Principal.xml", + "ref/dotnet/zh-hans/System.Security.Principal.xml", + "ref/dotnet/zh-hant/System.Security.Principal.xml", + "ref/net45/_._", + "ref/netcore50/System.Security.Principal.dll", + "ref/netcore50/System.Security.Principal.xml", + "ref/win8/_._", + "ref/wp80/_._", + "ref/wpa81/_._", + "System.Security.Principal.4.0.0-beta-23127.nupkg", + "System.Security.Principal.4.0.0-beta-23127.nupkg.sha512", + "System.Security.Principal.nuspec" + ] + }, + "System.Security.Principal.Windows/4.0.0-beta-23127": { + "type": "package", + "serviceable": true, + "sha512": "Wwce3jHkchtiKxvCaclE2gkquZbr7ASopk/ppFPnVYwQ9UZcf4e/T5+/5bHqOJMnjGY5ywcnnEM6OKwvsy9zeA==", + "files": [ + "lib/DNXCore50/System.Security.Principal.Windows.dll", + "lib/net46/System.Security.Principal.Windows.dll", + "ref/dotnet/de/System.Security.Principal.Windows.xml", + "ref/dotnet/es/System.Security.Principal.Windows.xml", + "ref/dotnet/fr/System.Security.Principal.Windows.xml", + "ref/dotnet/it/System.Security.Principal.Windows.xml", + "ref/dotnet/ja/System.Security.Principal.Windows.xml", + "ref/dotnet/ko/System.Security.Principal.Windows.xml", + "ref/dotnet/ru/System.Security.Principal.Windows.xml", + "ref/dotnet/System.Security.Principal.Windows.dll", + "ref/dotnet/System.Security.Principal.Windows.xml", + "ref/dotnet/zh-hans/System.Security.Principal.Windows.xml", + "ref/dotnet/zh-hant/System.Security.Principal.Windows.xml", + "ref/net46/System.Security.Principal.Windows.dll", + "System.Security.Principal.Windows.4.0.0-beta-23127.nupkg", + "System.Security.Principal.Windows.4.0.0-beta-23127.nupkg.sha512", + "System.Security.Principal.Windows.nuspec" + ] + }, + "System.Security.SecureString/4.0.0-beta-23127": { + "type": "package", + "serviceable": true, + "sha512": "4gotwKWDrZBpSzxqxSg1iuY44LvyMAcqX3Lb3owSLXi9feEj23cY6QznxVJZEYqPs31jNF4a2G8yEKTC7Jh1CA==", + "files": [ + "lib/DNXCore50/System.Security.SecureString.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/System.Security.SecureString.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/de/System.Security.SecureString.xml", + "ref/dotnet/es/System.Security.SecureString.xml", + "ref/dotnet/fr/System.Security.SecureString.xml", + "ref/dotnet/it/System.Security.SecureString.xml", + "ref/dotnet/ja/System.Security.SecureString.xml", + "ref/dotnet/ko/System.Security.SecureString.xml", + "ref/dotnet/ru/System.Security.SecureString.xml", + "ref/dotnet/System.Security.SecureString.dll", + "ref/dotnet/System.Security.SecureString.xml", + "ref/dotnet/zh-hans/System.Security.SecureString.xml", + "ref/dotnet/zh-hant/System.Security.SecureString.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/System.Security.SecureString.dll", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "System.Security.SecureString.4.0.0-beta-23127.nupkg", + "System.Security.SecureString.4.0.0-beta-23127.nupkg.sha512", + "System.Security.SecureString.nuspec" + ] + }, + "System.Text.Encoding/4.0.10-beta-23127": { + "type": "package", + "sha512": "XUOP6mx45Fk4fUcinHnUdeXGzQaXGskTBvI4/v195wCyUhsHQXFvnVVDevMoFlrcjb7Lvm6UdIORmqA1y4onmg==", + "files": [ + "lib/DNXCore50/System.Text.Encoding.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/_._", + "lib/netcore50/System.Text.Encoding.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/de/System.Text.Encoding.xml", + "ref/dotnet/es/System.Text.Encoding.xml", + "ref/dotnet/fr/System.Text.Encoding.xml", + "ref/dotnet/it/System.Text.Encoding.xml", + "ref/dotnet/ja/System.Text.Encoding.xml", + "ref/dotnet/ko/System.Text.Encoding.xml", + "ref/dotnet/ru/System.Text.Encoding.xml", + "ref/dotnet/System.Text.Encoding.dll", + "ref/dotnet/System.Text.Encoding.xml", + "ref/dotnet/zh-hans/System.Text.Encoding.xml", + "ref/dotnet/zh-hant/System.Text.Encoding.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "runtimes/win8-aot/lib/netcore50/System.Text.Encoding.dll", + "System.Text.Encoding.4.0.10-beta-23127.nupkg", + "System.Text.Encoding.4.0.10-beta-23127.nupkg.sha512", + "System.Text.Encoding.nuspec" + ] + }, + "System.Text.Encoding.Extensions/4.0.10-beta-23127": { + "type": "package", + "sha512": "Vrbl+i8CCNo4Z8K1tNJ5GURvvbq+sS0J9mWsEZglFH8fJeq6oLTHPQYehrTe/dorz0gnSALUINGoOwHkCbki+Q==", + "files": [ + "lib/DNXCore50/System.Text.Encoding.Extensions.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/_._", + "lib/netcore50/System.Text.Encoding.Extensions.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/de/System.Text.Encoding.Extensions.xml", + "ref/dotnet/es/System.Text.Encoding.Extensions.xml", + "ref/dotnet/fr/System.Text.Encoding.Extensions.xml", + "ref/dotnet/it/System.Text.Encoding.Extensions.xml", + "ref/dotnet/ja/System.Text.Encoding.Extensions.xml", + "ref/dotnet/ko/System.Text.Encoding.Extensions.xml", + "ref/dotnet/ru/System.Text.Encoding.Extensions.xml", + "ref/dotnet/System.Text.Encoding.Extensions.dll", + "ref/dotnet/System.Text.Encoding.Extensions.xml", + "ref/dotnet/zh-hans/System.Text.Encoding.Extensions.xml", + "ref/dotnet/zh-hant/System.Text.Encoding.Extensions.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "runtimes/win8-aot/lib/netcore50/System.Text.Encoding.Extensions.dll", + "System.Text.Encoding.Extensions.4.0.10-beta-23127.nupkg", + "System.Text.Encoding.Extensions.4.0.10-beta-23127.nupkg.sha512", + "System.Text.Encoding.Extensions.nuspec" + ] + }, + "System.Threading/4.0.0": { + "type": "package", + "sha512": "H6O/9gUrjPDNYanh/7OFGAZHjVXvEuITD0RcnjfvIV04HOGrOPqUBU0kmz9RIX/7YGgCQn1o1S2DX6Cuv8kVGQ==", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net45/_._", + "lib/win8/_._", + "lib/wp80/_._", + "lib/wpa81/_._", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "License.rtf", + "package/services/metadata/core-properties/bec033e95dbf4d6ba6595d2be7bb7e25.psmdcp", + "ref/dotnet/de/System.Threading.xml", + "ref/dotnet/es/System.Threading.xml", + "ref/dotnet/fr/System.Threading.xml", + "ref/dotnet/it/System.Threading.xml", + "ref/dotnet/ja/System.Threading.xml", + "ref/dotnet/ko/System.Threading.xml", + "ref/dotnet/ru/System.Threading.xml", + "ref/dotnet/System.Threading.dll", + "ref/dotnet/System.Threading.xml", + "ref/dotnet/zh-hans/System.Threading.xml", + "ref/dotnet/zh-hant/System.Threading.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net45/_._", + "ref/netcore50/de/System.Threading.xml", + "ref/netcore50/es/System.Threading.xml", + "ref/netcore50/fr/System.Threading.xml", + "ref/netcore50/it/System.Threading.xml", + "ref/netcore50/ja/System.Threading.xml", + "ref/netcore50/ko/System.Threading.xml", + "ref/netcore50/ru/System.Threading.xml", + "ref/netcore50/System.Threading.dll", + "ref/netcore50/System.Threading.xml", + "ref/netcore50/zh-hans/System.Threading.xml", + "ref/netcore50/zh-hant/System.Threading.xml", + "ref/win8/_._", + "ref/wp80/_._", + "ref/wpa81/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "System.Threading.nuspec" + ] + }, + "System.Threading.Overlapped/4.0.0-beta-23127": { + "type": "package", + "serviceable": true, + "sha512": "Do4dCnys5YNKU9OSaCVIS3pM9Ke0O7x41b+Gbxs6sXJ4zEYg0zbc/hI9t5fdeXXGFqQ7C6uDilQhHAz5GePyJA==", + "files": [ + "lib/DNXCore50/System.Threading.Overlapped.dll", + "lib/net46/System.Threading.Overlapped.dll", + "lib/netcore50/System.Threading.Overlapped.dll", + "ref/dotnet/de/System.Threading.Overlapped.xml", + "ref/dotnet/es/System.Threading.Overlapped.xml", + "ref/dotnet/fr/System.Threading.Overlapped.xml", + "ref/dotnet/it/System.Threading.Overlapped.xml", + "ref/dotnet/ja/System.Threading.Overlapped.xml", + "ref/dotnet/ko/System.Threading.Overlapped.xml", + "ref/dotnet/ru/System.Threading.Overlapped.xml", + "ref/dotnet/System.Threading.Overlapped.dll", + "ref/dotnet/System.Threading.Overlapped.xml", + "ref/dotnet/zh-hans/System.Threading.Overlapped.xml", + "ref/dotnet/zh-hant/System.Threading.Overlapped.xml", + "ref/net46/System.Threading.Overlapped.dll", + "System.Threading.Overlapped.4.0.0-beta-23127.nupkg", + "System.Threading.Overlapped.4.0.0-beta-23127.nupkg.sha512", + "System.Threading.Overlapped.nuspec" + ] + }, + "System.Threading.Tasks/4.0.10-beta-23127": { + "type": "package", + "serviceable": true, + "sha512": "5K6t1u3aT7Yh8PbqmXyTnjDo4OJWDCCqHmAccauJ35hnXthzgSBiMvVr2wxtAl7A8eK/lVcSPKJIheJ6MZnLcg==", + "files": [ + "lib/DNXCore50/System.Threading.Tasks.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/_._", + "lib/netcore50/System.Threading.Tasks.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/de/System.Threading.Tasks.xml", + "ref/dotnet/es/System.Threading.Tasks.xml", + "ref/dotnet/fr/System.Threading.Tasks.xml", + "ref/dotnet/it/System.Threading.Tasks.xml", + "ref/dotnet/ja/System.Threading.Tasks.xml", + "ref/dotnet/ko/System.Threading.Tasks.xml", + "ref/dotnet/ru/System.Threading.Tasks.xml", + "ref/dotnet/System.Threading.Tasks.dll", + "ref/dotnet/System.Threading.Tasks.xml", + "ref/dotnet/zh-hans/System.Threading.Tasks.xml", + "ref/dotnet/zh-hant/System.Threading.Tasks.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "runtimes/win8-aot/lib/netcore50/System.Threading.Tasks.dll", + "System.Threading.Tasks.4.0.10-beta-23127.nupkg", + "System.Threading.Tasks.4.0.10-beta-23127.nupkg.sha512", + "System.Threading.Tasks.nuspec" + ] + }, + "System.Threading.ThreadPool/4.0.10-beta-23127": { + "type": "package", + "sha512": "Z99U+/mlNrB1+1XL7NkwoqEnUJvDZISG9InPJFmnrNKIHX1TywFK5F8/O+B5QJXB18XCvEMpXbOk0BQ241iYoQ==", + "files": [ + "lib/DNXCore50/System.Threading.ThreadPool.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/System.Threading.ThreadPool.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/de/System.Threading.ThreadPool.xml", + "ref/dotnet/es/System.Threading.ThreadPool.xml", + "ref/dotnet/fr/System.Threading.ThreadPool.xml", + "ref/dotnet/it/System.Threading.ThreadPool.xml", + "ref/dotnet/ja/System.Threading.ThreadPool.xml", + "ref/dotnet/ko/System.Threading.ThreadPool.xml", + "ref/dotnet/ru/System.Threading.ThreadPool.xml", + "ref/dotnet/System.Threading.ThreadPool.dll", + "ref/dotnet/System.Threading.ThreadPool.xml", + "ref/dotnet/zh-hans/System.Threading.ThreadPool.xml", + "ref/dotnet/zh-hant/System.Threading.ThreadPool.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/System.Threading.ThreadPool.dll", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "System.Threading.ThreadPool.4.0.10-beta-23127.nupkg", + "System.Threading.ThreadPool.4.0.10-beta-23127.nupkg.sha512", + "System.Threading.ThreadPool.nuspec" + ] + } + }, + "projectFileDependencyGroups": { + "": [ + "System.Diagnostics.Contracts >= 4.0.0-*", + "System.Threading >= 4.0.0-*", + "System.Net.Primitives >= 4.0.10-beta-*" + ], + "DNXCore,Version=v5.0": [] + } +} \ No newline at end of file diff --git a/src/System.Net.Security/tests/FunctionalTests/ClientAsyncAuthenticateTest.cs b/src/System.Net.Security/tests/FunctionalTests/ClientAsyncAuthenticateTest.cs new file mode 100644 index 000000000000..cdde9d7a2f8e --- /dev/null +++ b/src/System.Net.Security/tests/FunctionalTests/ClientAsyncAuthenticateTest.cs @@ -0,0 +1,204 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.ComponentModel; +using System.IO; +using System.Net.Sockets; +using System.Net.Test.Common; +using System.Security.Authentication; +using System.Security.Cryptography.X509Certificates; + +using Xunit; +using Xunit.Abstractions; + +namespace System.Net.Security.Tests +{ + public class ClientAsyncAuthenticateTest + { + private readonly ITestOutputHelper _log; + + private const SslProtocols AllSslProtocols = + SslProtocols.Ssl2 + | SslProtocols.Ssl3 + | SslProtocols.Tls + | SslProtocols.Tls11 + | SslProtocols.Tls12; + + private static readonly SslProtocols[] s_eachSslProtocol = new SslProtocols[] + { + SslProtocols.Ssl2, + SslProtocols.Ssl3, + SslProtocols.Tls, + SslProtocols.Tls11, + SslProtocols.Tls12, + }; + + public ClientAsyncAuthenticateTest() + { + _log = TestLogging.GetInstance(); + } + + [Fact] + public void ClientAsyncAuthenticate_ServerRequireEncryption_ConnectWithEncryption() + { + ClientAsyncSslHelper(EncryptionPolicy.RequireEncryption); + } + + [Fact] + public void ClientAsyncAuthenticate_ServerNoEncryption_NoConnect() + { + Assert.Throws(() => + { + ClientAsyncSslHelper(EncryptionPolicy.NoEncryption); + }); + } + + [Fact] + public void ClientAsyncAuthenticate_EachProtocol_Success() + { + foreach (SslProtocols protocol in s_eachSslProtocol) + { + ClientAsyncSslHelper(protocol, protocol); + } + } + + [Fact] + public void ClientAsyncAuthenticate_MismatchProtocols_Fails() + { + foreach (SslProtocols serverProtocol in s_eachSslProtocol) + { + foreach (SslProtocols clientProtocol in s_eachSslProtocol) + { + if (serverProtocol != clientProtocol) + { + try + { + ClientAsyncSslHelper(serverProtocol, clientProtocol); + Assert.True(false, serverProtocol + "; " + clientProtocol); + } + catch (AuthenticationException) { } + catch (IOException) { } + } + } + } + } + + [Fact] + public void ClientAsyncAuthenticate_Ssl2Tls12ServerSsl2Client_Fails() + { + Assert.Throws(() => + { + // Ssl2 and Tls 1.2 are mutually exclusive. + ClientAsyncSslHelper(SslProtocols.Ssl2 | SslProtocols.Tls12, SslProtocols.Ssl2); + }); + } + + [Fact] + public void ClientAsyncAuthenticate_Ssl2Tls12ServerTls12Client_Fails() + { + Assert.Throws(() => + { + // Ssl2 and Tls 1.2 are mutually exclusive. + ClientAsyncSslHelper(SslProtocols.Ssl2 | SslProtocols.Tls12, SslProtocols.Tls12); + }); + } + + [Fact] + public void ClientAsyncAuthenticate_Ssl2ServerSsl2Tls12Client_Success() + { + ClientAsyncSslHelper(SslProtocols.Ssl2, SslProtocols.Ssl2 | SslProtocols.Tls12); + } + + [Fact] + public void ClientAsyncAuthenticate_Tls12ServerSsl2Tls12Client_Success() + { + ClientAsyncSslHelper(SslProtocols.Tls12, SslProtocols.Ssl2 | SslProtocols.Tls12); + } + + [Fact] + public void ClientAsyncAuthenticate_AllServerAllClient_Success() + { + // Drop Ssl2, it's incompatible with Tls 1.2 + SslProtocols sslProtocols = AllSslProtocols & ~SslProtocols.Ssl2; + ClientAsyncSslHelper(sslProtocols, sslProtocols); + } + + [Fact] + public void ClientAsyncAuthenticate_AllServerVsIndividualClientProtocols_Success() + { + foreach (SslProtocols clientProtocol in s_eachSslProtocol) + { + if (clientProtocol != SslProtocols.Ssl2) // Incompatible with Tls 1.2 + { + ClientAsyncSslHelper(clientProtocol, AllSslProtocols); + } + } + } + + [Fact] + public void ClientAsyncAuthenticate_IndividualServerVsAllClientProtocols_Success() + { + SslProtocols clientProtocols = AllSslProtocols & ~SslProtocols.Ssl2; // Incompatible with Tls 1.2 + foreach (SslProtocols serverProtocol in s_eachSslProtocol) + { + if (serverProtocol != SslProtocols.Ssl2) // Incompatible with Tls 1.2 + { + ClientAsyncSslHelper(clientProtocols, serverProtocol); + // Cached Tls creds fail when used against Tls servers of higher versions. + // Servers are not expected to dynamically change versions. + } + } + } + + #region Helpers + + private void ClientAsyncSslHelper(EncryptionPolicy encryptionPolicy) + { + ClientAsyncSslHelper(encryptionPolicy, TestConfiguration.DefaultSslProtocols, TestConfiguration.DefaultSslProtocols); + } + + private void ClientAsyncSslHelper(SslProtocols clientSslProtocols, SslProtocols serverSslProtocols) + { + ClientAsyncSslHelper(EncryptionPolicy.RequireEncryption, clientSslProtocols, serverSslProtocols); + } + + private void ClientAsyncSslHelper(EncryptionPolicy encryptionPolicy, SslProtocols clientSslProtocols, + SslProtocols serverSslProtocols) + { + _log.WriteLine("Server: " + serverSslProtocols + "; Client: " + clientSslProtocols); + + IPEndPoint endPoint = new IPEndPoint(IPAddress.IPv6Loopback, 0); + + using (var server = new DummyTcpServer(endPoint, encryptionPolicy)) + using (var client = new TcpClient(AddressFamily.InterNetworkV6)) + { + server.SslProtocols = serverSslProtocols; + client.Connect(server.RemoteEndPoint); + using (SslStream sslStream = new SslStream(client.GetStream(), false, AllowAnyServerCertificate, null)) + { + IAsyncResult async = sslStream.BeginAuthenticateAsClient("localhost", null, clientSslProtocols, false, null, null); + Assert.True(async.AsyncWaitHandle.WaitOne(10000), "Timed Out"); + sslStream.EndAuthenticateAsClient(async); + + _log.WriteLine("Client({0}) authenticated to server({1}) with encryption cipher: {2} {3}-bit strength", + client.Client.LocalEndPoint, client.Client.RemoteEndPoint, + sslStream.CipherAlgorithm, sslStream.CipherStrength); + Assert.True(sslStream.CipherAlgorithm != CipherAlgorithmType.Null, "Cipher algorithm should not be NULL"); + Assert.True(sslStream.CipherStrength > 0, "Cipher strength should be greater than 0"); + } + } + } + + // The following method is invoked by the RemoteCertificateValidationDelegate. + public bool AllowAnyServerCertificate( + object sender, + X509Certificate certificate, + X509Chain chain, + SslPolicyErrors sslPolicyErrors) + { + return true; // allow everything + } + #endregion Helpers + } +} + diff --git a/src/System.Net.Security/tests/FunctionalTests/ClientDefaultEncryptionTest.cs b/src/System.Net.Security/tests/FunctionalTests/ClientDefaultEncryptionTest.cs new file mode 100644 index 000000000000..130a06b24d16 --- /dev/null +++ b/src/System.Net.Security/tests/FunctionalTests/ClientDefaultEncryptionTest.cs @@ -0,0 +1,96 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.IO; +using System.Net.Sockets; +using System.Net.Test.Common; +using System.Security.Authentication; +using System.Security.Cryptography.X509Certificates; + +using Xunit; +using Xunit.Abstractions; + +namespace System.Net.Security.Tests +{ + public class ClientDefaultEncryptionTest + { + private readonly ITestOutputHelper _log; + + public ClientDefaultEncryptionTest() + { + _log = TestLogging.GetInstance(); + } + + // The following method is invoked by the RemoteCertificateValidationDelegate. + public bool AllowAnyServerCertificate( + object sender, + X509Certificate certificate, + X509Chain chain, + SslPolicyErrors sslPolicyErrors) + { + return true; // allow everything + } + + [Fact] + public void ClientDefaultEncryption_ServerRequireEncryption_ConnectWithEncryption() + { + using (var serverRequireEncryption = new DummyTcpServer( + new IPEndPoint(IPAddress.Loopback, 0), EncryptionPolicy.RequireEncryption)) + using (var client = new TcpClient()) + { + client.Connect(serverRequireEncryption.RemoteEndPoint); + + using (var sslStream = new SslStream(client.GetStream(), false, AllowAnyServerCertificate, null)) + { + sslStream.AuthenticateAsClient("localhost", null, TestConfiguration.DefaultSslProtocols, false); + _log.WriteLine("Client({0}) authenticated to server({1}) with encryption cipher: {2} {3}-bit strength", + client.Client.LocalEndPoint, client.Client.RemoteEndPoint, + sslStream.CipherAlgorithm, sslStream.CipherStrength); + Assert.True(sslStream.CipherAlgorithm != CipherAlgorithmType.Null, "Cipher algorithm should not be NULL"); + Assert.True(sslStream.CipherStrength > 0, "Cipher strength should be greater than 0"); + } + } + } + + [Fact] + public void ClientDefaultEncryption_ServerAllowNoEncryption_ConnectWithEncryption() + { + using (var serverAllowNoEncryption = new DummyTcpServer( + new IPEndPoint(IPAddress.Loopback, 0), EncryptionPolicy.AllowNoEncryption)) + using (var client = new TcpClient()) + { + client.Connect(serverAllowNoEncryption.RemoteEndPoint); + + using (var sslStream = new SslStream(client.GetStream(), false, AllowAnyServerCertificate, null)) + { + sslStream.AuthenticateAsClient("localhost", null, TestConfiguration.DefaultSslProtocols, false); + _log.WriteLine("Client({0}) authenticated to server({1}) with encryption cipher: {2} {3}-bit strength", + client.Client.LocalEndPoint, client.Client.RemoteEndPoint, + sslStream.CipherAlgorithm, sslStream.CipherStrength); + Assert.True(sslStream.CipherAlgorithm != CipherAlgorithmType.Null, "Cipher algorithm should not be NULL"); + Assert.True(sslStream.CipherStrength > 0, "Cipher strength should be greater than 0"); + } + } + } + + [Fact] + public void ClientDefaultEncryption_ServerNoEncryption_NoConnect() + { + using (var serverNoEncryption = new DummyTcpServer( + new IPEndPoint(IPAddress.Loopback, 0), EncryptionPolicy.NoEncryption)) + using (var client = new TcpClient()) + { + client.Connect(serverNoEncryption.RemoteEndPoint); + + using (var sslStream = new SslStream(client.GetStream(), false, AllowAnyServerCertificate, null)) + { + Assert.Throws(() => + { + sslStream.AuthenticateAsClient("localhost", null, TestConfiguration.DefaultSslProtocols, false); + }); + } + } + } + } +} + diff --git a/src/System.Net.Security/tests/FunctionalTests/DummyTcpServer.cs b/src/System.Net.Security/tests/FunctionalTests/DummyTcpServer.cs new file mode 100644 index 000000000000..b3348a65c6d7 --- /dev/null +++ b/src/System.Net.Security/tests/FunctionalTests/DummyTcpServer.cs @@ -0,0 +1,319 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.IO; +using System.Net.Sockets; +using System.Net.Test.Common; +using System.Security.Authentication; +using System.Security.Cryptography.X509Certificates; + +using Xunit; + +namespace System.Net.Security.Tests +{ + // Callback method that is called when the server receives data from a connected client. + // The callback method should return a byte array and the number of bytes to send from that array. + public delegate void DummyTcpServerReceiveCallback(byte[] bufferReceived, int bytesReceived, Stream stream); + + // Provides a dummy TCP/IP server that accepts connections and supports SSL/TLS. + // It normally echoes data received but can be configured to write a byte array + // specified by a callback method. + public class DummyTcpServer : IDisposable + { + private VerboseTestLogging _log; + private TcpListener _listener; + private bool _useSsl; + private SslProtocols _sslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls; + private EncryptionPolicy _sslEncryptionPolicy; + private IPEndPoint _remoteEndPoint; + private DummyTcpServerReceiveCallback _receiveCallback; + + private void StartListener(IPEndPoint endPoint) + { + _listener = new TcpListener(endPoint); + _listener.Start(5); + _log.WriteLine("Server {0} listening", endPoint.Address.ToString()); + _listener.BeginAcceptTcpClient(OnAccept, null); + } + + public DummyTcpServer(IPEndPoint endPoint) : this(endPoint, null) + { + } + + public DummyTcpServer(IPEndPoint endPoint, EncryptionPolicy? sslEncryptionPolicy) + { + _log = VerboseTestLogging.GetInstance(); + + if (sslEncryptionPolicy != null) + { + _remoteEndPoint = endPoint; + _useSsl = true; + _sslEncryptionPolicy = (EncryptionPolicy)sslEncryptionPolicy; + } + + StartListener(endPoint); + } + + public IPEndPoint RemoteEndPoint + { + get { return (IPEndPoint)_listener.LocalEndpoint; } + } + + public SslProtocols SslProtocols + { + get { return _sslProtocols; } + set { _sslProtocols = value; } + } + + protected DummyTcpServerReceiveCallback ReceiveCallback + { + get { return _receiveCallback; } + set { _receiveCallback = value; } + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _listener.Stop(); + } + } + + protected virtual void OnClientAccepted(TcpClient client) + { + } + + private void OnAuthenticate(IAsyncResult result) + { + ClientState state = (ClientState)result.AsyncState; + SslStream sslStream = (SslStream)state.Stream; + + try + { + sslStream.EndAuthenticateAsServer(result); + _log.WriteLine("Server({0}) authenticated to client({1}) with encryption cipher: {2} {3}-bit strength", + state.TcpClient.Client.LocalEndPoint, state.TcpClient.Client.RemoteEndPoint, + sslStream.CipherAlgorithm, sslStream.CipherStrength); + + // Start listening for data from the client connection. + sslStream.BeginRead(state.ReceiveBuffer, 0, state.ReceiveBuffer.Length, OnReceive, state); + } + catch (AuthenticationException authEx) + { + _log.WriteLine( + "Server({0}) disconnecting from client({1}) during authentication. No shared SSL/TLS algorithm. ({2})", + state.TcpClient.Client.LocalEndPoint, + state.TcpClient.Client.RemoteEndPoint, + authEx); + } + catch (Exception ex) + { + _log.WriteLine("Server({0}) disconnecting from client({1}) during authentication. Exception: {2}", + state.TcpClient.Client.LocalEndPoint, state.TcpClient.Client.RemoteEndPoint, ex.Message); + } + finally + { + state.Dispose(); + } + } + + private void OnAccept(IAsyncResult result) + { + TcpClient client = null; + + // Accept current connection + try + { + client = _listener.EndAcceptTcpClient(result); + } + catch + { + } + + // If we have a connection, then process it + if (client != null) + { + OnClientAccepted(client); + + ClientState state; + + // Start authentication for SSL? + if (_useSsl) + { + state = new ClientState(client, _sslEncryptionPolicy); + _log.WriteLine("Server: starting SSL authentication."); + + + SslStream sslStream = null; + X509Certificate2 certificate = TestConfiguration.GetServerCertificate(); + + try + { + sslStream = (SslStream)state.Stream; + + _log.WriteLine("Server: attempting to open SslStream."); + sslStream.BeginAuthenticateAsServer(certificate, false, _sslProtocols, false, OnAuthenticate, state); + } + catch (Exception ex) + { + _log.WriteLine("Server: Exception: {0}", ex); + + state.Dispose(); // close connection to client + } + } + else + { + state = new ClientState(client); + + // Start listening for data from the client connection + try + { + state.Stream.BeginRead(state.ReceiveBuffer, 0, state.ReceiveBuffer.Length, OnReceive, state); + } + catch + { + } + } + } + + // Listen for more client connections + try + { + _listener.BeginAcceptTcpClient(OnAccept, null); + } + catch + { + } + } + + private void OnReceive(IAsyncResult result) + { + ClientState state = (ClientState)result.AsyncState; + + try + { + int bytesReceived = state.Stream.EndRead(result); + if (bytesReceived == 0) + { + state.Dispose(); + return; + } + + if (_receiveCallback != null) + { + _receiveCallback(state.ReceiveBuffer, bytesReceived, state.Stream); + } + else + { + // Echo back what we received + state.Stream.Write(state.ReceiveBuffer, 0, bytesReceived); + } + + // Read more from client (asynchronous) + state.Stream.BeginRead(state.ReceiveBuffer, 0, state.ReceiveBuffer.Length, OnReceive, state); + } + catch (IOException) + { + state.Dispose(); + return; + } + catch (SocketException) + { + state.Dispose(); + return; + } + catch (ObjectDisposedException) + { + state.Dispose(); + return; + } + } + + // The following method is invoked by the RemoteCertificateValidationDelegate. + public static bool AlwaysValidServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) + { + return true; // allow everything + } + + private class ClientState + { + private TcpClient _tcpClient; + private byte[] _receiveBuffer; + private bool _useSsl; + private SslStream _sslStream; + private bool _closed; + + public ClientState(TcpClient client) + { + _tcpClient = client; + _receiveBuffer = new byte[1024]; + _useSsl = false; + _closed = false; + } + + public ClientState(TcpClient client, EncryptionPolicy sslEncryptionPolicy) + { + _tcpClient = client; + _receiveBuffer = new byte[1024]; + _useSsl = true; + _sslStream = new SslStream(client.GetStream(), false, AlwaysValidServerCertificate, null, sslEncryptionPolicy); + _closed = false; + } + + public void Dispose() + { + if (!_closed) + { + if (_useSsl) + { + _sslStream.Dispose(); + } + + _tcpClient.Dispose(); + _closed = true; + } + } + + public TcpClient TcpClient + { + get { return _tcpClient; } + } + + public byte[] ReceiveBuffer + { + get { return _receiveBuffer; } + } + + public bool UseSsl + { + get { return _useSsl; } + } + + public bool Closed + { + get { return _closed; } + } + + public Stream Stream + { + get + { + if (_useSsl) + { + return _sslStream; + } + else + { + return _tcpClient.GetStream(); + } + } + } + } + } +} + diff --git a/src/System.Net.Security/tests/FunctionalTests/ParameterValidationTest.cs b/src/System.Net.Security/tests/FunctionalTests/ParameterValidationTest.cs new file mode 100644 index 000000000000..455bc72f9489 --- /dev/null +++ b/src/System.Net.Security/tests/FunctionalTests/ParameterValidationTest.cs @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Net.Sockets; +using System.Security.Cryptography.X509Certificates; + +using Xunit; + +namespace System.Net.Security.Tests +{ + public class ParameterValidationTest + { + // The following method is invoked by the RemoteCertificateValidationDelegate. + public bool AllowAnyServerCertificate( + object sender, + X509Certificate certificate, + X509Chain chain, + SslPolicyErrors sslPolicyErrors) + { + return true; // allow everything + } + + [Fact] + public void SslStreamConstructor_BadEncryptionPolicy_ThrowException() + { + using (var _remoteServer = new DummyTcpServer( + new IPEndPoint(IPAddress.Loopback, 600), EncryptionPolicy.RequireEncryption)) + using (var client = new TcpClient()) + { + client.Connect(_remoteServer.RemoteEndPoint); + + Assert.Throws(() => + { + SslStream sslStream = new SslStream(client.GetStream(), false, AllowAnyServerCertificate, null, (EncryptionPolicy)100); + }); + } + } + } +} + diff --git a/src/System.Net.Security/tests/FunctionalTests/ServerAllowNoEncryptionTest.cs b/src/System.Net.Security/tests/FunctionalTests/ServerAllowNoEncryptionTest.cs new file mode 100644 index 000000000000..baaae554b018 --- /dev/null +++ b/src/System.Net.Security/tests/FunctionalTests/ServerAllowNoEncryptionTest.cs @@ -0,0 +1,99 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Net.Sockets; +using System.Net.Test.Common; +using System.Security.Authentication; +using System.Security.Cryptography.X509Certificates; + +using Xunit; +using Xunit.Abstractions; + +namespace System.Net.Security.Tests +{ + public class ServerAllowNoEncryptionTest + { + private readonly ITestOutputHelper _log; + + public ServerAllowNoEncryptionTest() + { + _log = TestLogging.GetInstance(); + } + + // The following method is invoked by the RemoteCertificateValidationDelegate. + public bool AllowAnyServerCertificate( + object sender, + X509Certificate certificate, + X509Chain chain, + SslPolicyErrors sslPolicyErrors) + { + return true; // allow everything + } + + [Fact] + public void ServerAllowNoEncryption_ClientRequireEncryption_ConnectWithEncryption() + { + using (var serverAllowNoEncryption = new DummyTcpServer( + new IPEndPoint(IPAddress.Loopback, 0), EncryptionPolicy.AllowNoEncryption)) + using (var client = new TcpClient()) + { + client.Connect(serverAllowNoEncryption.RemoteEndPoint); + + using (var sslStream = new SslStream(client.GetStream(), false, AllowAnyServerCertificate, null, EncryptionPolicy.RequireEncryption)) + { + sslStream.AuthenticateAsClient("localhost", null, TestConfiguration.DefaultSslProtocols, false); + _log.WriteLine("Client({0}) authenticated to server({1}) with encryption cipher: {2} {3}-bit strength", + client.Client.LocalEndPoint, client.Client.RemoteEndPoint, + sslStream.CipherAlgorithm, sslStream.CipherStrength); + Assert.NotEqual(CipherAlgorithmType.Null, sslStream.CipherAlgorithm); + Assert.True(sslStream.CipherStrength > 0); + } + } + } + + [Fact] + public void ServerAllowNoEncryption_ClientAllowNoEncryption_ConnectWithEncryption() + { + using (var serverAllowNoEncryption = new DummyTcpServer( + new IPEndPoint(IPAddress.Loopback, 0), EncryptionPolicy.AllowNoEncryption)) + using (var client = new TcpClient()) + { + client.Connect(serverAllowNoEncryption.RemoteEndPoint); + + using (var sslStream = new SslStream(client.GetStream(), false, AllowAnyServerCertificate, null, EncryptionPolicy.AllowNoEncryption)) + { + sslStream.AuthenticateAsClient("localhost", null, TestConfiguration.DefaultSslProtocols, false); + _log.WriteLine("Client({0}) authenticated to server({1}) with encryption cipher: {2} {3}-bit strength", + client.Client.LocalEndPoint, client.Client.RemoteEndPoint, + sslStream.CipherAlgorithm, sslStream.CipherStrength); + Assert.NotEqual(CipherAlgorithmType.Null, sslStream.CipherAlgorithm); + Assert.True(sslStream.CipherStrength > 0, "Cipher strength should be greater than 0"); + } + } + } + + [Fact] + public void ServerAllowNoEncryption_ClientNoEncryption_ConnectWithNoEncryption() + { + using (var serverAllowNoEncryption = new DummyTcpServer( + new IPEndPoint(IPAddress.Loopback, 0), EncryptionPolicy.AllowNoEncryption)) + using (var client = new TcpClient()) + { + client.Connect(serverAllowNoEncryption.RemoteEndPoint); + + using (var sslStream = new SslStream(client.GetStream(), false, AllowAnyServerCertificate, null, EncryptionPolicy.NoEncryption)) + { + sslStream.AuthenticateAsClient("localhost", null, TestConfiguration.DefaultSslProtocols, false); + _log.WriteLine("Client({0}) authenticated to server({1}) with encryption cipher: {2} {3}-bit strength", + client.Client.LocalEndPoint, client.Client.RemoteEndPoint, + sslStream.CipherAlgorithm, sslStream.CipherStrength); + + CipherAlgorithmType expected = CipherAlgorithmType.Null; + Assert.Equal(expected, sslStream.CipherAlgorithm); + Assert.Equal(0, sslStream.CipherStrength); + } + } + } + } +} + diff --git a/src/System.Net.Security/tests/FunctionalTests/ServerNoEncryptionTest.cs b/src/System.Net.Security/tests/FunctionalTests/ServerNoEncryptionTest.cs new file mode 100644 index 000000000000..809b0e14d762 --- /dev/null +++ b/src/System.Net.Security/tests/FunctionalTests/ServerNoEncryptionTest.cs @@ -0,0 +1,101 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.IO; +using System.Net.Sockets; +using System.Net.Test.Common; +using System.Security.Authentication; +using System.Security.Cryptography.X509Certificates; + +using Xunit; +using Xunit.Abstractions; + +namespace System.Net.Security.Tests +{ + public class ServerNoEncryptionTest + { + private readonly ITestOutputHelper _log; + + public ServerNoEncryptionTest() + { + _log = TestLogging.GetInstance(); + } + + // The following method is invoked by the RemoteCertificateValidationDelegate. + public bool AllowAnyServerCertificate( + object sender, + X509Certificate certificate, + X509Chain chain, + SslPolicyErrors sslPolicyErrors) + { + return true; // allow everything + } + + [Fact] + public void ServerNoEncryption_ClientRequireEncryption_NoConnect() + { + using (var serverNoEncryption = new DummyTcpServer( + new IPEndPoint(IPAddress.Loopback, 0), EncryptionPolicy.NoEncryption)) + using (var client = new TcpClient()) + { + client.Connect(serverNoEncryption.RemoteEndPoint); + + using (var sslStream = new SslStream(client.GetStream(), false, AllowAnyServerCertificate, null, EncryptionPolicy.RequireEncryption)) + { + Assert.Throws(() => + { + sslStream.AuthenticateAsClient("localhost", null, TestConfiguration.DefaultSslProtocols, false); + }); + } + } + } + + [Fact] + public void ServerNoEncryption_ClientAllowNoEncryption_ConnectWithNoEncryption() + { + using (var serverNoEncryption = new DummyTcpServer( + new IPEndPoint(IPAddress.Loopback, 0), EncryptionPolicy.NoEncryption)) + using (var client = new TcpClient()) + { + client.Connect(serverNoEncryption.RemoteEndPoint); + + using (var sslStream = new SslStream(client.GetStream(), false, AllowAnyServerCertificate, null, EncryptionPolicy.AllowNoEncryption)) + { + sslStream.AuthenticateAsClient("localhost", null, TestConfiguration.DefaultSslProtocols, false); + + _log.WriteLine("Client({0}) authenticated to server({1}) with encryption cipher: {2} {3}-bit strength", + client.Client.LocalEndPoint, client.Client.RemoteEndPoint, + sslStream.CipherAlgorithm, sslStream.CipherStrength); + + CipherAlgorithmType expected = CipherAlgorithmType.Null; + Assert.Equal(expected, sslStream.CipherAlgorithm); + Assert.Equal(0, sslStream.CipherStrength); + } + } + } + + [Fact] + public void ServerNoEncryption_ClientNoEncryption_ConnectWithNoEncryption() + { + using (var serverNoEncryption = new DummyTcpServer( + new IPEndPoint(IPAddress.Loopback, 0), EncryptionPolicy.NoEncryption)) + using (var client = new TcpClient()) + { + client.Connect(serverNoEncryption.RemoteEndPoint); + + using (var sslStream = new SslStream(client.GetStream(), false, AllowAnyServerCertificate, null, EncryptionPolicy.NoEncryption)) + { + sslStream.AuthenticateAsClient("localhost", null, TestConfiguration.DefaultSslProtocols, false); + _log.WriteLine("Client({0}) authenticated to server({1}) with encryption cipher: {2} {3}-bit strength", + client.Client.LocalEndPoint, client.Client.RemoteEndPoint, + sslStream.CipherAlgorithm, sslStream.CipherStrength); + + CipherAlgorithmType expected = CipherAlgorithmType.Null; + Assert.Equal(expected, sslStream.CipherAlgorithm); + Assert.Equal(0, sslStream.CipherStrength); + } + } + } + } +} + diff --git a/src/System.Net.Security/tests/FunctionalTests/ServerRequireEncryptionTest.cs b/src/System.Net.Security/tests/FunctionalTests/ServerRequireEncryptionTest.cs new file mode 100644 index 000000000000..473d8cc10466 --- /dev/null +++ b/src/System.Net.Security/tests/FunctionalTests/ServerRequireEncryptionTest.cs @@ -0,0 +1,94 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.IO; +using System.Net.Sockets; +using System.Net.Test.Common; +using System.Security.Authentication; +using System.Security.Cryptography.X509Certificates; + +using Xunit; +using Xunit.Abstractions; + +namespace System.Net.Security.Tests +{ + public class ServerRequireEncryptionTest + { + private readonly ITestOutputHelper _log; + + public ServerRequireEncryptionTest() + { + _log = TestLogging.GetInstance(); + } + + // The following method is invoked by the RemoteCertificateValidationDelegate. + public bool AllowAnyServerCertificate( + object sender, + X509Certificate certificate, + X509Chain chain, + SslPolicyErrors sslPolicyErrors) + { + return true; // allow everything + } + + [Fact] + public void ServerRequireEncryption_ClientRequireEncryption_ConnectWithEncryption() + { + using (var serverRequireEncryption = new DummyTcpServer( + new IPEndPoint(IPAddress.Loopback, 0), EncryptionPolicy.RequireEncryption)) + using (var client = new TcpClient()) + { + client.Connect(serverRequireEncryption.RemoteEndPoint); + + using (var sslStream = new SslStream(client.GetStream(), false, AllowAnyServerCertificate, null, EncryptionPolicy.RequireEncryption)) + { + sslStream.AuthenticateAsClient("localhost", null, TestConfiguration.DefaultSslProtocols, false); + _log.WriteLine("Client({0}) authenticated to server({1}) with encryption cipher: {2} {3}-bit strength", + client.Client.LocalEndPoint, client.Client.RemoteEndPoint, + sslStream.CipherAlgorithm, sslStream.CipherStrength); + Assert.True(sslStream.CipherAlgorithm != CipherAlgorithmType.Null, "Cipher algorithm should not be NULL"); + Assert.True(sslStream.CipherStrength > 0, "Cipher strength should be greater than 0"); + } + } + } + + [Fact] + public void ServerRequireEncryption_ClientAllowNoEncryption_ConnectWithEncryption() + { + using (var serverRequireEncryption = new DummyTcpServer( + new IPEndPoint(IPAddress.Loopback, 0), EncryptionPolicy.RequireEncryption)) + using (var client = new TcpClient()) + { + client.Connect(serverRequireEncryption.RemoteEndPoint); + + using (var sslStream = new SslStream(client.GetStream(), false, AllowAnyServerCertificate, null, EncryptionPolicy.AllowNoEncryption)) + { + sslStream.AuthenticateAsClient("localhost", null, TestConfiguration.DefaultSslProtocols, false); + _log.WriteLine("Client({0}) authenticated to server({1}) with encryption cipher: {2} {3}-bit strength", + client.Client.LocalEndPoint, client.Client.RemoteEndPoint, + sslStream.CipherAlgorithm, sslStream.CipherStrength); + Assert.True(sslStream.CipherAlgorithm != CipherAlgorithmType.Null, "Cipher algorithm should not be NULL"); + Assert.True(sslStream.CipherStrength > 0, "Cipher strength should be greater than 0"); + } + } + } + + [Fact] + public void ServerRequireEncryption_ClientNoEncryption_NoConnect() + { + using (var serverRequireEncryption = new DummyTcpServer( + new IPEndPoint(IPAddress.Loopback, 0), EncryptionPolicy.RequireEncryption)) + using (var client = new TcpClient()) + { + client.Connect(serverRequireEncryption.RemoteEndPoint); + using (var sslStream = new SslStream(client.GetStream(), false, AllowAnyServerCertificate, null, EncryptionPolicy.NoEncryption)) + { + Assert.Throws(() => + { + sslStream.AuthenticateAsClient("localhost", null, TestConfiguration.DefaultSslProtocols, false); + }); + } + } + } + } +} diff --git a/src/System.Net.Security/tests/FunctionalTests/SslStreamAPMExtensions.cs b/src/System.Net.Security/tests/FunctionalTests/SslStreamAPMExtensions.cs new file mode 100644 index 000000000000..1a919823f4c5 --- /dev/null +++ b/src/System.Net.Security/tests/FunctionalTests/SslStreamAPMExtensions.cs @@ -0,0 +1,61 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/// +/// Extensions that add the legacy APM Pattern (Begin/End) for generic Streams +/// + + +using System.Threading.Tasks; +using System.Security.Authentication; +using System.Security.Cryptography.X509Certificates; + +namespace System.Net.Security +{ + public static class SslStreamAPMExtensions + { + public static IAsyncResult BeginAuthenticateAsClient( + this SslStream s, + string targetHost, + X509CertificateCollection clientCertificates, + SslProtocols enabledSslProtocols, + bool checkCertificateRevocation, + AsyncCallback asyncCallback, + Object asyncState) + { + return s.AuthenticateAsClientAsync( + targetHost, + clientCertificates, + enabledSslProtocols, + checkCertificateRevocation).ToApm(asyncCallback, asyncState); + } + + public static void EndAuthenticateAsClient(this SslStream s, IAsyncResult asyncResult) + { + Task t = (Task)asyncResult; + t.GetAwaiter().GetResult(); + } + + public static IAsyncResult BeginAuthenticateAsServer( + this SslStream s, + X509Certificate serverCertificate, + bool clientCertificateRequired, + SslProtocols enabledSslProtocols, + bool checkCertificateRevocation, + AsyncCallback asyncCallback, + Object asyncState) + { + return s.AuthenticateAsServerAsync( + serverCertificate, + clientCertificateRequired, + enabledSslProtocols, + checkCertificateRevocation).ToApm(asyncCallback, asyncState); + } + + public static void EndAuthenticateAsServer(this SslStream s, IAsyncResult asyncResult) + { + Task t = (Task)asyncResult; + t.GetAwaiter().GetResult(); + } + } +} diff --git a/src/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs b/src/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs new file mode 100644 index 000000000000..acfb77381e35 --- /dev/null +++ b/src/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs @@ -0,0 +1,229 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Generic; +using System.IO; +using System.Security.Authentication; +using System.Security.Cryptography.X509Certificates; +using System.Threading; +using System.Threading.Tasks; + +using Xunit; + +namespace System.Net.Security.Tests +{ + public class SslStreamStreamToStreamTest + { + [Fact] + public void SslStream_StreamToStream_Authentication_Success() + { + MockNetwork network = new MockNetwork(); + + using (var clientStream = new FakeNetworkStream(false, network)) + using (var serverStream = new FakeNetworkStream(true, network)) + using (var client = new SslStream(clientStream, false, AllowAnyServerCertificate)) + using (var server = new SslStream(serverStream)) + { + X509Certificate2 certificate = TestConfiguration.GetServerCertificate(); + Task[] auth = new Task[2]; + auth[0] = client.AuthenticateAsClientAsync(certificate.Subject); + auth[1] = server.AuthenticateAsServerAsync(certificate); + + Task.WaitAll(auth); + } + } + + public bool AllowAnyServerCertificate( + object sender, + X509Certificate certificate, + X509Chain chain, + SslPolicyErrors sslPolicyErrors) + { + if (sslPolicyErrors != SslPolicyErrors.RemoteCertificateNameMismatch) + { + return true; + } + + return false; + } + + [Fact] + public void SslStream_StreamToStream_Authentication_IncorrectServerName_Fail() + { + MockNetwork network = new MockNetwork(); + + using (var clientStream = new FakeNetworkStream(false, network)) + using (var serverStream = new FakeNetworkStream(true, network)) + using (var client = new SslStream(clientStream)) + using (var server = new SslStream(serverStream)) + { + Task[] auth = new Task[2]; + auth[0] = client.AuthenticateAsClientAsync("incorrectServer"); + auth[1] = server.AuthenticateAsServerAsync(TestConfiguration.GetServerCertificate()); + + Assert.Throws(() => + { + auth[0].GetAwaiter().GetResult(); + }); + + auth[1].GetAwaiter().GetResult(); + } + } + + internal class MockNetwork + { + private readonly Queue _clientWriteQueue = new Queue(); + private readonly Queue _serverWriteQueue = new Queue(); + + private readonly SemaphoreSlim _clientDataAvailable = new SemaphoreSlim(0); + private readonly SemaphoreSlim _serverDataAvailable = new SemaphoreSlim(0); + + public MockNetwork() + { + } + + public void ReadFrame(bool server, out byte[] buffer) + { + SemaphoreSlim semaphore; + Queue packetQueue; + + if (server) + { + semaphore = _clientDataAvailable; + packetQueue = _clientWriteQueue; + } + else + { + semaphore = _serverDataAvailable; + packetQueue = _serverWriteQueue; + } + + semaphore.Wait(); + buffer = packetQueue.Dequeue(); + } + + public void WriteFrame(bool server, byte[] buffer) + { + SemaphoreSlim semaphore; + Queue packetQueue; + + if (server) + { + semaphore = _serverDataAvailable; + packetQueue = _serverWriteQueue; + } + else + { + semaphore = _clientDataAvailable; + packetQueue = _clientWriteQueue; + } + + byte[] innerBuffer = new byte[buffer.Length]; + buffer.CopyTo(innerBuffer, 0); + + packetQueue.Enqueue(innerBuffer); + semaphore.Release(); + } + } + + internal class FakeNetworkStream : Stream + { + private readonly MockNetwork _network; + private MemoryStream _readStream; + private readonly bool _isServer; + + public FakeNetworkStream(bool isServer, MockNetwork network) + { + _network = network; + _isServer = isServer; + } + + public override bool CanRead + { + get + { + return true; + } + } + + public override bool CanSeek + { + get + { + return false; + } + } + + public override bool CanWrite + { + get + { + return true; + } + } + + public override long Length + { + get + { + throw new NotImplementedException(); + } + } + + public override long Position + { + get + { + throw new NotImplementedException(); + } + + set + { + throw new NotImplementedException(); + } + } + + public override void Flush() + { + throw new NotImplementedException(); + } + + public override void SetLength(long value) + { + throw new NotImplementedException(); + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotImplementedException(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + UpdateReadStream(); + return _readStream.Read(buffer, offset, count); + } + + public override void Write(byte[] buffer, int offset, int count) + { + byte[] innerBuffer = new byte[count]; + + Buffer.BlockCopy(buffer, offset, innerBuffer, 0, count); + _network.WriteFrame(_isServer, buffer); + } + + private void UpdateReadStream() + { + if (_readStream != null && (_readStream.Position < _readStream.Length)) + { + return; + } + + byte[] innerBuffer; + _network.ReadFrame(_isServer, out innerBuffer); + + _readStream = new MemoryStream(innerBuffer); + } + } + } +} diff --git a/src/System.Net.Security/tests/FunctionalTests/StreamAPMExtensions.cs b/src/System.Net.Security/tests/FunctionalTests/StreamAPMExtensions.cs new file mode 100644 index 000000000000..9f13740aab83 --- /dev/null +++ b/src/System.Net.Security/tests/FunctionalTests/StreamAPMExtensions.cs @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Threading.Tasks; + +/// +/// Extensions that add the legacy APM Pattern (Begin/End) for generic Streams +/// + + +namespace System.IO +{ + public static class StreamAPMExtensions + { + public static IAsyncResult BeginRead(this Stream s, byte[] buffer, int offset, int count, AsyncCallback callback, object state) + { + return s.ReadAsync(buffer, offset, count).ToApm(callback, state); + } + + public static IAsyncResult BeginWrite(this Stream s, byte[] buffer, int offset, int count, AsyncCallback callback, object state) + { + return s.WriteAsync(buffer, offset, count).ToApm(callback, state); + } + + public static int EndRead(this Stream s, IAsyncResult asyncResult) + { + var t = (Task)asyncResult; + return t.GetAwaiter().GetResult(); + } + + public static void EndWrite(this Stream s, IAsyncResult asyncResult) + { + Task t = (Task)asyncResult; + t.GetAwaiter().GetResult(); + } + } +} diff --git a/src/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj b/src/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj new file mode 100644 index 000000000000..afddd70e7c80 --- /dev/null +++ b/src/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj @@ -0,0 +1,73 @@ + + + + + Debug + AnyCPU + {A55A2B9A-830F-4330-A0E7-02A9FB30ABD2} + Library + Linux;OSX;FreeBSD + + + + + + + + + + + + + + + + + + + + + Common\System.Net\TestLogging.cs + + + Common\System.Net\VerboseTestLogging.cs + + + Common\System.Net\EventSourceTestLogging.cs + + + Common\System.Net\TaskAPMExtensions.cs + + + + + + + + {89F37791-6254-4D60-AB96-ACD3CCA0E771} + System.Net.Security + + + + + + + + + + + + System.Security.Cryptography.X509Certificates.TestData\1.0.0-prerelease + %(TestTargetFramework.Folder) + + + + + + + + + + + \ No newline at end of file diff --git a/src/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.nuget.props b/src/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.nuget.props new file mode 100644 index 000000000000..b6c7b2445997 --- /dev/null +++ b/src/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.nuget.props @@ -0,0 +1,9 @@ + + + + C:\Users\crispop\.nuget\packages\ + + + + + \ No newline at end of file diff --git a/src/System.Net.Security/tests/FunctionalTests/TestConfiguration.cs b/src/System.Net.Security/tests/FunctionalTests/TestConfiguration.cs new file mode 100644 index 000000000000..f972dcc11062 --- /dev/null +++ b/src/System.Net.Security/tests/FunctionalTests/TestConfiguration.cs @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.IO; +using System.Security.Authentication; +using System.Security.Cryptography.X509Certificates; +using Xunit; + +namespace System.Net.Security.Tests +{ + internal static class TestConfiguration + { + public const SslProtocols DefaultSslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls; + + public static X509Certificate2 GetServerCertificate() + { + X509Certificate2 certificate = null; + + var certCollection = new X509Certificate2Collection(); + certCollection.Import(Path.Combine("TestData", "DummyTcpServer.pfx")); + + foreach (X509Certificate2 c in certCollection) + { + if (c.HasPrivateKey) + { + certificate = c; + break; + } + } + + Assert.NotNull(certificate); + return certificate; + } + } +} diff --git a/src/System.Net.Security/tests/FunctionalTests/TransportContextTest.cs b/src/System.Net.Security/tests/FunctionalTests/TransportContextTest.cs new file mode 100644 index 000000000000..e90669f29164 --- /dev/null +++ b/src/System.Net.Security/tests/FunctionalTests/TransportContextTest.cs @@ -0,0 +1,72 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Net.Sockets; +using System.Runtime.InteropServices; +using System.Security.Authentication; +using System.Security.Authentication.ExtendedProtection; +using System.Security.Cryptography.X509Certificates; + +using Xunit; + +namespace System.Net.Security.Tests +{ + public class TransportContextTest + { + // The following method is invoked by the RemoteCertificateValidationDelegate. + public bool AllowAnyServerCertificate( + object sender, + X509Certificate certificate, + X509Chain chain, + SslPolicyErrors sslPolicyErrors) + { + return true; // allow everything + } + + [Fact] + public void TransportContext_ConnectToServerWithSsl_GetExpectedChannelBindings() + { + using (var testServer = new DummyTcpServer( + new IPEndPoint(IPAddress.Loopback, 0), EncryptionPolicy.RequireEncryption)) + using (var client = new TcpClient()) + { + client.Connect(testServer.RemoteEndPoint); + + using (var sslStream = new SslStream(client.GetStream(), false, AllowAnyServerCertificate, null, EncryptionPolicy.RequireEncryption)) + { + sslStream.AuthenticateAsClient("localhost", null, SslProtocols.Tls, false); + + TransportContext context = sslStream.TransportContext; + CheckTransportContext(context); + } + } + } + + public void CheckTransportContext(TransportContext context) + { + var cbt1 = context.GetChannelBinding(ChannelBindingKind.Endpoint); + var cbt2 = context.GetChannelBinding(ChannelBindingKind.Unique); + var cbt3 = context.GetChannelBinding(ChannelBindingKind.Unknown); + + CheckChannelBinding(cbt1); + CheckChannelBinding(cbt2); + CheckChannelBinding(cbt3); + + Assert.True(cbt1 != null, "ChannelBindingKind.Endpoint token data should be returned from SCHANNEL."); + Assert.True(cbt2 != null, "ChannelBindingKind.Unique token data should be returned from SCHANNEL."); + Assert.True(cbt3 == null, "ChannelBindingKind.Unknown token data should not be returned from SCHANNEL since it does not map to a defined context attribute."); + } + + public void CheckChannelBinding(ChannelBinding channelBinding) + { + if (channelBinding != null) + { + Assert.True(!channelBinding.IsInvalid, "Channel binding token should be marked as a valid SafeHandle."); + Assert.True(channelBinding.Size > 0, "Number of bytes in a valid channel binding token should be greater than zero."); + var bytes = new byte[channelBinding.Size]; + Marshal.Copy(channelBinding.DangerousGetHandle(), bytes, 0, channelBinding.Size); + Assert.Equal(channelBinding.Size, bytes.Length); + } + } + } +} diff --git a/src/System.Net.Security/tests/FunctionalTests/project.json b/src/System.Net.Security/tests/FunctionalTests/project.json new file mode 100644 index 000000000000..7f336f1215bf --- /dev/null +++ b/src/System.Net.Security/tests/FunctionalTests/project.json @@ -0,0 +1,13 @@ +{ + "dependencies": { + "System.Net.Primitives": "4.0.10-beta-*", + "System.Net.Sockets": "4.1.0-beta-*", + "System.Security.Cryptography.X509Certificates.TestData": "1.0.0-prerelease", + + "xunit": "2.1.0-beta3-*", + "xunit.netcore.extensions": "1.0.0-prerelease-*" + }, + "frameworks": { + "dnxcore50": {} + } +} diff --git a/src/System.Net.Security/tests/FunctionalTests/project.lock.json b/src/System.Net.Security/tests/FunctionalTests/project.lock.json new file mode 100644 index 000000000000..0b9be5b2e5dc --- /dev/null +++ b/src/System.Net.Security/tests/FunctionalTests/project.lock.json @@ -0,0 +1,2164 @@ +{ + "locked": true, + "version": 1, + "targets": { + "DNXCore,Version=v5.0": { + "Microsoft.Win32.Primitives/4.0.0": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.20", + "System.Runtime.InteropServices": "4.0.20" + }, + "compile": { + "ref/dotnet/Microsoft.Win32.Primitives.dll": {} + }, + "runtime": { + "lib/dotnet/Microsoft.Win32.Primitives.dll": {} + } + }, + "System.Collections/4.0.10": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.20" + }, + "compile": { + "ref/dotnet/System.Collections.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Collections.dll": {} + } + }, + "System.Collections.Concurrent/4.0.0": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.0", + "System.Threading.Tasks": "4.0.0" + }, + "compile": { + "ref/dotnet/System.Collections.Concurrent.dll": {} + } + }, + "System.Collections.NonGeneric/4.0.0": { + "type": "package", + "dependencies": { + "System.Diagnostics.Debug": "4.0.10", + "System.Globalization": "4.0.10", + "System.Resources.ResourceManager": "4.0.0", + "System.Runtime": "4.0.20", + "System.Runtime.Extensions": "4.0.10", + "System.Threading": "4.0.10" + }, + "compile": { + "ref/dotnet/System.Collections.NonGeneric.dll": {} + }, + "runtime": { + "lib/dotnet/System.Collections.NonGeneric.dll": {} + } + }, + "System.ComponentModel.EventBasedAsync/4.0.10": { + "type": "package", + "dependencies": { + "System.Resources.ResourceManager": "4.0.0", + "System.Runtime": "4.0.20", + "System.Threading": "4.0.10", + "System.Threading.Tasks": "4.0.10" + }, + "compile": { + "ref/dotnet/System.ComponentModel.EventBasedAsync.dll": {} + }, + "runtime": { + "lib/dotnet/System.ComponentModel.EventBasedAsync.dll": {} + } + }, + "System.Diagnostics.Debug/4.0.10": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.0" + }, + "compile": { + "ref/dotnet/System.Diagnostics.Debug.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Diagnostics.Debug.dll": {} + } + }, + "System.Diagnostics.Tracing/4.0.20": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.0" + }, + "compile": { + "ref/dotnet/System.Diagnostics.Tracing.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Diagnostics.Tracing.dll": {} + } + }, + "System.Globalization/4.0.10": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.0" + }, + "compile": { + "ref/dotnet/System.Globalization.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Globalization.dll": {} + } + }, + "System.Globalization.Calendars/4.0.0": { + "type": "package", + "dependencies": { + "System.Globalization": "4.0.0", + "System.Runtime": "4.0.0" + }, + "compile": { + "ref/dotnet/System.Globalization.Calendars.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Globalization.Calendars.dll": {} + } + }, + "System.IO/4.0.10": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.20", + "System.Text.Encoding": "4.0.0", + "System.Threading.Tasks": "4.0.0" + }, + "compile": { + "ref/dotnet/System.IO.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.IO.dll": {} + } + }, + "System.IO.FileSystem/4.0.0": { + "type": "package", + "dependencies": { + "System.Collections": "4.0.10", + "System.IO": "4.0.10", + "System.IO.FileSystem.Primitives": "4.0.0", + "System.Resources.ResourceManager": "4.0.0", + "System.Runtime": "4.0.20", + "System.Runtime.Extensions": "4.0.10", + "System.Runtime.Handles": "4.0.0", + "System.Runtime.InteropServices": "4.0.20", + "System.Text.Encoding": "4.0.10", + "System.Text.Encoding.Extensions": "4.0.10", + "System.Threading": "4.0.10", + "System.Threading.Overlapped": "4.0.0", + "System.Threading.Tasks": "4.0.10" + }, + "compile": { + "ref/dotnet/System.IO.FileSystem.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.IO.FileSystem.dll": {} + } + }, + "System.IO.FileSystem.Primitives/4.0.0": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.20" + }, + "compile": { + "ref/dotnet/System.IO.FileSystem.Primitives.dll": {} + }, + "runtime": { + "lib/dotnet/System.IO.FileSystem.Primitives.dll": {} + } + }, + "System.Linq/4.0.0": { + "type": "package", + "dependencies": { + "System.Collections": "4.0.10", + "System.Diagnostics.Debug": "4.0.10", + "System.Resources.ResourceManager": "4.0.0", + "System.Runtime": "4.0.20", + "System.Runtime.Extensions": "4.0.10" + }, + "compile": { + "ref/dotnet/System.Linq.dll": {} + }, + "runtime": { + "lib/dotnet/System.Linq.dll": {} + } + }, + "System.Net.Primitives/4.0.10-beta-23127": { + "type": "package", + "dependencies": { + "System.Private.Networking": "4.0.0-beta-23127" + }, + "compile": { + "ref/dotnet/System.Net.Primitives.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Net.Primitives.dll": {} + } + }, + "System.Net.Sockets/4.1.0-beta-23316": { + "type": "package", + "dependencies": { + "System.Private.Networking": "4.0.1-beta-23316", + "System.Runtime": "4.0.20" + }, + "compile": { + "ref/dotnet/System.Net.Sockets.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Net.Sockets.dll": {} + } + }, + "System.Private.Networking/4.0.1-beta-23316": { + "type": "package", + "dependencies": { + "Microsoft.Win32.Primitives": "4.0.0", + "System.Collections": "4.0.10", + "System.Collections.Concurrent": "4.0.0", + "System.Collections.NonGeneric": "4.0.0", + "System.ComponentModel.EventBasedAsync": "4.0.10", + "System.Diagnostics.Debug": "4.0.10", + "System.Diagnostics.Tracing": "4.0.20", + "System.Globalization": "4.0.10", + "System.IO": "4.0.10", + "System.IO.FileSystem": "4.0.0", + "System.IO.FileSystem.Primitives": "4.0.0", + "System.Resources.ResourceManager": "4.0.0", + "System.Runtime": "4.0.20", + "System.Runtime.Extensions": "4.0.10", + "System.Runtime.Handles": "4.0.0", + "System.Runtime.InteropServices": "4.0.20", + "System.Security.Cryptography.Primitives": "4.0.0-beta-23316", + "System.Security.Cryptography.X509Certificates": "4.0.0-beta-23316", + "System.Security.Principal.Windows": "4.0.0-beta-23316", + "System.Security.SecureString": "4.0.0-beta-23316", + "System.Threading": "4.0.10", + "System.Threading.Overlapped": "4.0.0", + "System.Threading.Tasks": "4.0.10", + "System.Threading.ThreadPool": "4.0.10-beta-23316" + }, + "compile": { + "ref/dnxcore50/_._": {} + }, + "runtime": { + "lib/DNXCore50/System.Private.Networking.dll": {} + } + }, + "System.Private.Uri/4.0.0": { + "type": "package", + "compile": { + "ref/dnxcore50/_._": {} + }, + "runtime": { + "lib/DNXCore50/System.Private.Uri.dll": {} + } + }, + "System.Reflection/4.0.10": { + "type": "package", + "dependencies": { + "System.IO": "4.0.0", + "System.Reflection.Primitives": "4.0.0", + "System.Runtime": "4.0.20" + }, + "compile": { + "ref/dotnet/System.Reflection.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Reflection.dll": {} + } + }, + "System.Reflection.Primitives/4.0.0": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.0" + }, + "compile": { + "ref/dotnet/System.Reflection.Primitives.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Reflection.Primitives.dll": {} + } + }, + "System.Resources.ResourceManager/4.0.0": { + "type": "package", + "dependencies": { + "System.Globalization": "4.0.0", + "System.Reflection": "4.0.0", + "System.Runtime": "4.0.0" + }, + "compile": { + "ref/dotnet/System.Resources.ResourceManager.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Resources.ResourceManager.dll": {} + } + }, + "System.Runtime/4.0.20": { + "type": "package", + "dependencies": { + "System.Private.Uri": "4.0.0" + }, + "compile": { + "ref/dotnet/System.Runtime.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Runtime.dll": {} + } + }, + "System.Runtime.Extensions/4.0.10": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.20" + }, + "compile": { + "ref/dotnet/System.Runtime.Extensions.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Runtime.Extensions.dll": {} + } + }, + "System.Runtime.Handles/4.0.0": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.0" + }, + "compile": { + "ref/dotnet/System.Runtime.Handles.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Runtime.Handles.dll": {} + } + }, + "System.Runtime.InteropServices/4.0.20": { + "type": "package", + "dependencies": { + "System.Reflection": "4.0.0", + "System.Reflection.Primitives": "4.0.0", + "System.Runtime": "4.0.0", + "System.Runtime.Handles": "4.0.0" + }, + "compile": { + "ref/dotnet/System.Runtime.InteropServices.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Runtime.InteropServices.dll": {} + } + }, + "System.Runtime.InteropServices.RuntimeInformation/4.0.0-beta-23213": { + "type": "package", + "dependencies": { + "System.Resources.ResourceManager": "4.0.0", + "System.Runtime": "4.0.20" + }, + "compile": { + "ref/dotnet/System.Runtime.InteropServices.RuntimeInformation.dll": {} + }, + "runtime": { + "lib/dotnet/System.Runtime.InteropServices.RuntimeInformation.dll": {} + } + }, + "System.Runtime.Numerics/4.0.0": { + "type": "package", + "dependencies": { + "System.Globalization": "4.0.10", + "System.Resources.ResourceManager": "4.0.0", + "System.Runtime": "4.0.20", + "System.Runtime.Extensions": "4.0.10" + }, + "compile": { + "ref/dotnet/System.Runtime.Numerics.dll": {} + }, + "runtime": { + "lib/dotnet/System.Runtime.Numerics.dll": {} + } + }, + "System.Security.Claims/4.0.0": { + "type": "package", + "dependencies": { + "System.Collections": "4.0.0", + "System.Diagnostics.Debug": "4.0.0", + "System.Globalization": "4.0.0", + "System.IO": "4.0.0", + "System.Resources.ResourceManager": "4.0.0", + "System.Runtime": "4.0.20", + "System.Runtime.Extensions": "4.0.0", + "System.Security.Principal": "4.0.0" + }, + "compile": { + "ref/dotnet/System.Security.Claims.dll": {} + }, + "runtime": { + "lib/dotnet/System.Security.Claims.dll": {} + } + }, + "System.Security.Cryptography.Algorithms/4.0.0-beta-23316": { + "type": "package", + "dependencies": { + "System.IO": "4.0.10", + "System.Resources.ResourceManager": "4.0.0", + "System.Runtime": "4.0.20", + "System.Runtime.Handles": "4.0.0", + "System.Runtime.InteropServices": "4.0.20", + "System.Security.Cryptography.Primitives": "4.0.0-beta-23316", + "System.Text.Encoding": "4.0.0", + "System.Text.Encoding.Extensions": "4.0.0" + }, + "compile": { + "ref/dotnet/System.Security.Cryptography.Algorithms.dll": {} + }, + "runtime": { + "lib/dotnet/System.Security.Cryptography.Algorithms.dll": {} + } + }, + "System.Security.Cryptography.Cng/4.0.0-beta-23316": { + "type": "package", + "dependencies": { + "System.IO": "4.0.10", + "System.Resources.ResourceManager": "4.0.0", + "System.Runtime": "4.0.20", + "System.Runtime.Extensions": "4.0.0", + "System.Runtime.Handles": "4.0.0", + "System.Runtime.InteropServices": "4.0.20", + "System.Security.Cryptography.Algorithms": "4.0.0-beta-23316", + "System.Security.Cryptography.Primitives": "4.0.0-beta-23316" + }, + "compile": { + "ref/dotnet/System.Security.Cryptography.Cng.dll": {} + }, + "runtime": { + "lib/dotnet/System.Security.Cryptography.Cng.dll": {} + } + }, + "System.Security.Cryptography.Csp/4.0.0-beta-23316": { + "type": "package", + "dependencies": { + "System.IO": "4.0.10", + "System.Reflection": "4.0.0", + "System.Resources.ResourceManager": "4.0.0", + "System.Runtime": "4.0.20", + "System.Runtime.Extensions": "4.0.10", + "System.Runtime.Handles": "4.0.0", + "System.Runtime.InteropServices": "4.0.20", + "System.Security.Cryptography.Algorithms": "4.0.0-beta-23316", + "System.Security.Cryptography.Encoding": "4.0.0-beta-23316", + "System.Security.Cryptography.Primitives": "4.0.0-beta-23316", + "System.Text.Encoding": "4.0.10", + "System.Threading": "4.0.10" + }, + "compile": { + "ref/dotnet/System.Security.Cryptography.Csp.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Security.Cryptography.Csp.dll": {} + } + }, + "System.Security.Cryptography.Encoding/4.0.0-beta-23316": { + "type": "package", + "dependencies": { + "System.Diagnostics.Debug": "4.0.10", + "System.Resources.ResourceManager": "4.0.0", + "System.Runtime": "4.0.20", + "System.Runtime.Handles": "4.0.0", + "System.Runtime.InteropServices": "4.0.20", + "System.Security.Cryptography.Primitives": "4.0.0-beta-23316" + }, + "compile": { + "ref/dotnet/System.Security.Cryptography.Encoding.dll": {} + }, + "runtime": { + "lib/dotnet/System.Security.Cryptography.Encoding.dll": {} + } + }, + "System.Security.Cryptography.Primitives/4.0.0-beta-23316": { + "type": "package", + "dependencies": { + "System.Diagnostics.Debug": "4.0.0", + "System.Globalization": "4.0.0", + "System.IO": "4.0.10", + "System.Resources.ResourceManager": "4.0.0", + "System.Runtime": "4.0.20", + "System.Threading": "4.0.0", + "System.Threading.Tasks": "4.0.0" + }, + "compile": { + "ref/dotnet/System.Security.Cryptography.Primitives.dll": {} + }, + "runtime": { + "lib/dotnet/System.Security.Cryptography.Primitives.dll": {} + } + }, + "System.Security.Cryptography.X509Certificates/4.0.0-beta-23316": { + "type": "package", + "dependencies": { + "System.Collections": "4.0.10", + "System.Globalization": "4.0.10", + "System.Globalization.Calendars": "4.0.0", + "System.IO": "4.0.10", + "System.IO.FileSystem": "4.0.0", + "System.Resources.ResourceManager": "4.0.0", + "System.Runtime": "4.0.20", + "System.Runtime.Extensions": "4.0.10", + "System.Runtime.Handles": "4.0.0", + "System.Runtime.InteropServices": "4.0.20", + "System.Runtime.Numerics": "4.0.0", + "System.Security.Cryptography.Algorithms": "4.0.0-beta-23316", + "System.Security.Cryptography.Cng": "4.0.0-beta-23316", + "System.Security.Cryptography.Csp": "4.0.0-beta-23316", + "System.Security.Cryptography.Encoding": "4.0.0-beta-23316", + "System.Security.Cryptography.Primitives": "4.0.0-beta-23316", + "System.Text.Encoding": "4.0.10", + "System.Threading": "4.0.10" + }, + "compile": { + "ref/dotnet/System.Security.Cryptography.X509Certificates.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Security.Cryptography.X509Certificates.dll": {} + } + }, + "System.Security.Cryptography.X509Certificates.TestData/1.0.0-prerelease": { + "type": "package" + }, + "System.Security.Principal/4.0.0": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.0" + }, + "compile": { + "ref/dotnet/System.Security.Principal.dll": {} + }, + "runtime": { + "lib/dotnet/System.Security.Principal.dll": {} + } + }, + "System.Security.Principal.Windows/4.0.0-beta-23316": { + "type": "package", + "dependencies": { + "System.Collections": "4.0.0", + "System.Diagnostics.Debug": "4.0.10", + "System.Reflection": "4.0.10", + "System.Resources.ResourceManager": "4.0.0", + "System.Runtime": "4.0.20", + "System.Runtime.Extensions": "4.0.0", + "System.Runtime.Handles": "4.0.0", + "System.Runtime.InteropServices": "4.0.20", + "System.Security.Claims": "4.0.0", + "System.Security.Principal": "4.0.0", + "System.Text.Encoding": "4.0.10", + "System.Threading": "4.0.10" + }, + "compile": { + "ref/dotnet/System.Security.Principal.Windows.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Security.Principal.Windows.dll": {} + } + }, + "System.Security.SecureString/4.0.0-beta-23316": { + "type": "package", + "dependencies": { + "System.Resources.ResourceManager": "4.0.0", + "System.Runtime": "4.0.20", + "System.Runtime.Handles": "4.0.0", + "System.Runtime.InteropServices": "4.0.20", + "System.Security.Cryptography.Primitives": "4.0.0-beta-23316", + "System.Threading": "4.0.10" + }, + "compile": { + "ref/dotnet/System.Security.SecureString.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Security.SecureString.dll": {} + } + }, + "System.Text.Encoding/4.0.10": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.0" + }, + "compile": { + "ref/dotnet/System.Text.Encoding.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Text.Encoding.dll": {} + } + }, + "System.Text.Encoding.Extensions/4.0.10": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.0", + "System.Text.Encoding": "4.0.10" + }, + "compile": { + "ref/dotnet/System.Text.Encoding.Extensions.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Text.Encoding.Extensions.dll": {} + } + }, + "System.Threading/4.0.10": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.0", + "System.Threading.Tasks": "4.0.0" + }, + "compile": { + "ref/dotnet/System.Threading.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Threading.dll": {} + } + }, + "System.Threading.Overlapped/4.0.0": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.0", + "System.Runtime.Handles": "4.0.0" + }, + "compile": { + "ref/dotnet/System.Threading.Overlapped.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Threading.Overlapped.dll": {} + } + }, + "System.Threading.Tasks/4.0.10": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.0" + }, + "compile": { + "ref/dotnet/System.Threading.Tasks.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Threading.Tasks.dll": {} + } + }, + "System.Threading.ThreadPool/4.0.10-beta-23316": { + "type": "package", + "dependencies": { + "System.Runtime": "4.0.0", + "System.Runtime.InteropServices": "4.0.0" + }, + "compile": { + "ref/dotnet/System.Threading.ThreadPool.dll": {} + }, + "runtime": { + "lib/DNXCore50/System.Threading.ThreadPool.dll": {} + } + }, + "xunit/2.1.0-beta3-build3029": { + "type": "package", + "dependencies": { + "xunit.assert": "[2.1.0-beta3-build3029]", + "xunit.core": "[2.1.0-beta3-build3029]" + } + }, + "xunit.abstractions/2.0.0": { + "type": "package", + "compile": { + "lib/portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS/xunit.abstractions.dll": {} + }, + "runtime": { + "lib/portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS/xunit.abstractions.dll": {} + } + }, + "xunit.assert/2.1.0-beta3-build3029": { + "type": "package", + "compile": { + "lib/portable-net45+dnxcore50+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS/xunit.assert.dll": {} + }, + "runtime": { + "lib/portable-net45+dnxcore50+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS/xunit.assert.dll": {} + } + }, + "xunit.core/2.1.0-beta3-build3029": { + "type": "package", + "dependencies": { + "xunit.extensibility.core": "[2.1.0-beta3-build3029]", + "xunit.extensibility.execution": "[2.1.0-beta3-build3029]" + } + }, + "xunit.extensibility.core/2.1.0-beta3-build3029": { + "type": "package", + "dependencies": { + "xunit.abstractions": "[2.0.0]" + }, + "compile": { + "lib/portable-net45+dnxcore50+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS/xunit.core.dll": {} + }, + "runtime": { + "lib/portable-net45+dnxcore50+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS/xunit.core.dll": {}, + "lib/portable-net45+dnxcore50+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS/xunit.runner.tdnet.dll": {}, + "lib/portable-net45+dnxcore50+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS/xunit.runner.utility.desktop.dll": {} + } + }, + "xunit.extensibility.execution/2.1.0-beta3-build3029": { + "type": "package", + "dependencies": { + "xunit.extensibility.core": "[2.1.0-beta3-build3029]" + }, + "compile": { + "lib/dnxcore50/xunit.execution.dnx.dll": {} + }, + "runtime": { + "lib/dnxcore50/xunit.execution.dnx.dll": {} + } + }, + "xunit.netcore.extensions/1.0.0-prerelease-00087": { + "type": "package", + "dependencies": { + "System.Diagnostics.Debug": "4.0.10", + "System.IO": "4.0.10", + "System.Linq": "4.0.0", + "System.Reflection": "4.0.10", + "System.Reflection.Primitives": "4.0.0", + "System.Runtime": "4.0.20", + "System.Runtime.Extensions": "4.0.10", + "System.Runtime.Handles": "4.0.0", + "System.Runtime.InteropServices": "4.0.20", + "System.Runtime.InteropServices.RuntimeInformation": "4.0.0-beta-23213", + "System.Text.Encoding": "4.0.10", + "System.Threading": "4.0.10", + "System.Threading.Tasks": "4.0.10", + "xunit": "2.1.0-beta3-build3029" + }, + "compile": { + "lib/dotnet/Xunit.NetCore.Extensions.dll": {} + }, + "runtime": { + "lib/dotnet/Xunit.NetCore.Extensions.dll": {} + } + } + } + }, + "libraries": { + "Microsoft.Win32.Primitives/4.0.0": { + "type": "package", + "sha512": "CypEz9/lLOup8CEhiAmvr7aLs1zKPYyEU1sxQeEr6G0Ci8/F0Y6pYR1zzkROjM8j8Mq0typmbu676oYyvErQvg==", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/dotnet/Microsoft.Win32.Primitives.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/Microsoft.Win32.Primitives.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "Microsoft.Win32.Primitives.nuspec", + "package/services/metadata/core-properties/1d4eb9d0228b48b88d2df3822fba2d86.psmdcp", + "ref/dotnet/de/Microsoft.Win32.Primitives.xml", + "ref/dotnet/es/Microsoft.Win32.Primitives.xml", + "ref/dotnet/fr/Microsoft.Win32.Primitives.xml", + "ref/dotnet/it/Microsoft.Win32.Primitives.xml", + "ref/dotnet/ja/Microsoft.Win32.Primitives.xml", + "ref/dotnet/ko/Microsoft.Win32.Primitives.xml", + "ref/dotnet/Microsoft.Win32.Primitives.dll", + "ref/dotnet/Microsoft.Win32.Primitives.xml", + "ref/dotnet/ru/Microsoft.Win32.Primitives.xml", + "ref/dotnet/zh-hans/Microsoft.Win32.Primitives.xml", + "ref/dotnet/zh-hant/Microsoft.Win32.Primitives.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/Microsoft.Win32.Primitives.dll", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._" + ] + }, + "System.Collections/4.0.10": { + "type": "package", + "sha512": "ux6ilcZZjV/Gp7JEZpe+2V1eTueq6NuoGRM3eZCFuPM25hLVVgCRuea6STW8hvqreIOE59irJk5/ovpA5xQipw==", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/DNXCore50/System.Collections.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/_._", + "lib/netcore50/System.Collections.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "package/services/metadata/core-properties/b4f8061406e54dbda8f11b23186be11a.psmdcp", + "ref/dotnet/de/System.Collections.xml", + "ref/dotnet/es/System.Collections.xml", + "ref/dotnet/fr/System.Collections.xml", + "ref/dotnet/it/System.Collections.xml", + "ref/dotnet/ja/System.Collections.xml", + "ref/dotnet/ko/System.Collections.xml", + "ref/dotnet/ru/System.Collections.xml", + "ref/dotnet/System.Collections.dll", + "ref/dotnet/System.Collections.xml", + "ref/dotnet/zh-hans/System.Collections.xml", + "ref/dotnet/zh-hant/System.Collections.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "runtimes/win8-aot/lib/netcore50/System.Collections.dll", + "System.Collections.nuspec" + ] + }, + "System.Collections.Concurrent/4.0.0": { + "type": "package", + "sha512": "1f5SWoX7UlFkvUt7A8JoG5lXgZDw4cRAcKG8Eaxa+3Sq6e/UgVWl2YWew1evJv+p+edNNlIIorDfREKcoEDHGw==", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net45/_._", + "lib/win8/_._", + "lib/wpa81/_._", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "License.rtf", + "package/services/metadata/core-properties/de16aa9cd7f743838ce5d61abe1af45a.psmdcp", + "ref/dotnet/de/System.Collections.Concurrent.xml", + "ref/dotnet/es/System.Collections.Concurrent.xml", + "ref/dotnet/fr/System.Collections.Concurrent.xml", + "ref/dotnet/it/System.Collections.Concurrent.xml", + "ref/dotnet/ja/System.Collections.Concurrent.xml", + "ref/dotnet/ko/System.Collections.Concurrent.xml", + "ref/dotnet/ru/System.Collections.Concurrent.xml", + "ref/dotnet/System.Collections.Concurrent.dll", + "ref/dotnet/System.Collections.Concurrent.xml", + "ref/dotnet/zh-hans/System.Collections.Concurrent.xml", + "ref/dotnet/zh-hant/System.Collections.Concurrent.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net45/_._", + "ref/netcore50/de/System.Collections.Concurrent.xml", + "ref/netcore50/es/System.Collections.Concurrent.xml", + "ref/netcore50/fr/System.Collections.Concurrent.xml", + "ref/netcore50/it/System.Collections.Concurrent.xml", + "ref/netcore50/ja/System.Collections.Concurrent.xml", + "ref/netcore50/ko/System.Collections.Concurrent.xml", + "ref/netcore50/ru/System.Collections.Concurrent.xml", + "ref/netcore50/System.Collections.Concurrent.dll", + "ref/netcore50/System.Collections.Concurrent.xml", + "ref/netcore50/zh-hans/System.Collections.Concurrent.xml", + "ref/netcore50/zh-hant/System.Collections.Concurrent.xml", + "ref/win8/_._", + "ref/wpa81/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "System.Collections.Concurrent.nuspec" + ] + }, + "System.Collections.NonGeneric/4.0.0": { + "type": "package", + "sha512": "rVgwrFBMkmp8LI6GhAYd6Bx+2uLIXjRfNg6Ie+ASfX8ESuh9e2HNxFy2yh1MPIXZq3OAYa+0mmULVwpnEC6UDA==", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/dotnet/System.Collections.NonGeneric.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/System.Collections.NonGeneric.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "package/services/metadata/core-properties/185704b1dc164b078b61038bde9ab31a.psmdcp", + "ref/dotnet/de/System.Collections.NonGeneric.xml", + "ref/dotnet/es/System.Collections.NonGeneric.xml", + "ref/dotnet/fr/System.Collections.NonGeneric.xml", + "ref/dotnet/it/System.Collections.NonGeneric.xml", + "ref/dotnet/ja/System.Collections.NonGeneric.xml", + "ref/dotnet/ko/System.Collections.NonGeneric.xml", + "ref/dotnet/ru/System.Collections.NonGeneric.xml", + "ref/dotnet/System.Collections.NonGeneric.dll", + "ref/dotnet/System.Collections.NonGeneric.xml", + "ref/dotnet/zh-hans/System.Collections.NonGeneric.xml", + "ref/dotnet/zh-hant/System.Collections.NonGeneric.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/System.Collections.NonGeneric.dll", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "System.Collections.NonGeneric.nuspec" + ] + }, + "System.ComponentModel.EventBasedAsync/4.0.10": { + "type": "package", + "sha512": "d6kXcHUgP0jSPXEQ6hXJYCO6CzfoCi7t9vR3BfjSQLrj4HzpuATpx1gkN7itmTW1O+wjuw6rai4378Nj6N70yw==", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/dotnet/System.ComponentModel.EventBasedAsync.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/_._", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "package/services/metadata/core-properties/5094900f1f7e4f4dae27507acc72f2a5.psmdcp", + "ref/dotnet/de/System.ComponentModel.EventBasedAsync.xml", + "ref/dotnet/es/System.ComponentModel.EventBasedAsync.xml", + "ref/dotnet/fr/System.ComponentModel.EventBasedAsync.xml", + "ref/dotnet/it/System.ComponentModel.EventBasedAsync.xml", + "ref/dotnet/ja/System.ComponentModel.EventBasedAsync.xml", + "ref/dotnet/ko/System.ComponentModel.EventBasedAsync.xml", + "ref/dotnet/ru/System.ComponentModel.EventBasedAsync.xml", + "ref/dotnet/System.ComponentModel.EventBasedAsync.dll", + "ref/dotnet/System.ComponentModel.EventBasedAsync.xml", + "ref/dotnet/zh-hans/System.ComponentModel.EventBasedAsync.xml", + "ref/dotnet/zh-hant/System.ComponentModel.EventBasedAsync.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "System.ComponentModel.EventBasedAsync.nuspec" + ] + }, + "System.Diagnostics.Debug/4.0.10": { + "type": "package", + "sha512": "pi2KthuvI2LWV2c2V+fwReDsDiKpNl040h6DcwFOb59SafsPT/V1fCy0z66OKwysurJkBMmp5j5CBe3Um+ub0g==", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/DNXCore50/System.Diagnostics.Debug.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/_._", + "lib/netcore50/System.Diagnostics.Debug.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "package/services/metadata/core-properties/bfb05c26051f4a5f9015321db9cb045c.psmdcp", + "ref/dotnet/de/System.Diagnostics.Debug.xml", + "ref/dotnet/es/System.Diagnostics.Debug.xml", + "ref/dotnet/fr/System.Diagnostics.Debug.xml", + "ref/dotnet/it/System.Diagnostics.Debug.xml", + "ref/dotnet/ja/System.Diagnostics.Debug.xml", + "ref/dotnet/ko/System.Diagnostics.Debug.xml", + "ref/dotnet/ru/System.Diagnostics.Debug.xml", + "ref/dotnet/System.Diagnostics.Debug.dll", + "ref/dotnet/System.Diagnostics.Debug.xml", + "ref/dotnet/zh-hans/System.Diagnostics.Debug.xml", + "ref/dotnet/zh-hant/System.Diagnostics.Debug.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "runtimes/win8-aot/lib/netcore50/System.Diagnostics.Debug.dll", + "System.Diagnostics.Debug.nuspec" + ] + }, + "System.Diagnostics.Tracing/4.0.20": { + "type": "package", + "sha512": "gn/wexGHc35Fv++5L1gYHMY5g25COfiZ0PGrL+3PfwzoJd4X2LbTAm/U8d385SI6BKQBI/z4dQfvneS9J27+Tw==", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/DNXCore50/System.Diagnostics.Tracing.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/_._", + "lib/netcore50/System.Diagnostics.Tracing.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "package/services/metadata/core-properties/13423e75e6344b289b3779b51522737c.psmdcp", + "ref/dotnet/de/System.Diagnostics.Tracing.xml", + "ref/dotnet/es/System.Diagnostics.Tracing.xml", + "ref/dotnet/fr/System.Diagnostics.Tracing.xml", + "ref/dotnet/it/System.Diagnostics.Tracing.xml", + "ref/dotnet/ja/System.Diagnostics.Tracing.xml", + "ref/dotnet/ko/System.Diagnostics.Tracing.xml", + "ref/dotnet/ru/System.Diagnostics.Tracing.xml", + "ref/dotnet/System.Diagnostics.Tracing.dll", + "ref/dotnet/System.Diagnostics.Tracing.xml", + "ref/dotnet/zh-hans/System.Diagnostics.Tracing.xml", + "ref/dotnet/zh-hant/System.Diagnostics.Tracing.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "runtimes/win8-aot/lib/netcore50/System.Diagnostics.Tracing.dll", + "System.Diagnostics.Tracing.nuspec" + ] + }, + "System.Globalization/4.0.10": { + "type": "package", + "sha512": "kzRtbbCNAxdafFBDogcM36ehA3th8c1PGiz8QRkZn8O5yMBorDHSK8/TGJPYOaCS5zdsGk0u9qXHnW91nqy7fw==", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/DNXCore50/System.Globalization.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/_._", + "lib/netcore50/System.Globalization.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "package/services/metadata/core-properties/93bcad242a4e4ad7afd0b53244748763.psmdcp", + "ref/dotnet/de/System.Globalization.xml", + "ref/dotnet/es/System.Globalization.xml", + "ref/dotnet/fr/System.Globalization.xml", + "ref/dotnet/it/System.Globalization.xml", + "ref/dotnet/ja/System.Globalization.xml", + "ref/dotnet/ko/System.Globalization.xml", + "ref/dotnet/ru/System.Globalization.xml", + "ref/dotnet/System.Globalization.dll", + "ref/dotnet/System.Globalization.xml", + "ref/dotnet/zh-hans/System.Globalization.xml", + "ref/dotnet/zh-hant/System.Globalization.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "runtimes/win8-aot/lib/netcore50/System.Globalization.dll", + "System.Globalization.nuspec" + ] + }, + "System.Globalization.Calendars/4.0.0": { + "type": "package", + "sha512": "cL6WrdGKnNBx9W/iTr+jbffsEO4RLjEtOYcpVSzPNDoli6X5Q6bAfWtJYbJNOPi8Q0fXgBEvKK1ncFL/3FTqlA==", + "files": [ + "lib/DNXCore50/System.Globalization.Calendars.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/System.Globalization.Calendars.dll", + "lib/netcore50/System.Globalization.Calendars.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/de/System.Globalization.Calendars.xml", + "ref/dotnet/es/System.Globalization.Calendars.xml", + "ref/dotnet/fr/System.Globalization.Calendars.xml", + "ref/dotnet/it/System.Globalization.Calendars.xml", + "ref/dotnet/ja/System.Globalization.Calendars.xml", + "ref/dotnet/ko/System.Globalization.Calendars.xml", + "ref/dotnet/ru/System.Globalization.Calendars.xml", + "ref/dotnet/System.Globalization.Calendars.dll", + "ref/dotnet/System.Globalization.Calendars.xml", + "ref/dotnet/zh-hans/System.Globalization.Calendars.xml", + "ref/dotnet/zh-hant/System.Globalization.Calendars.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/System.Globalization.Calendars.dll", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "runtimes/win8-aot/lib/netcore50/System.Globalization.Calendars.dll", + "System.Globalization.Calendars.4.0.0.nupkg", + "System.Globalization.Calendars.4.0.0.nupkg.sha512", + "System.Globalization.Calendars.nuspec" + ] + }, + "System.IO/4.0.10": { + "type": "package", + "sha512": "kghf1CeYT+W2lw8a50/GxFz5HR9t6RkL4BvjxtTp1NxtEFWywnMA9W8FH/KYXiDNThcw9u/GOViDON4iJFGXIQ==", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/DNXCore50/System.IO.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/_._", + "lib/netcore50/System.IO.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "package/services/metadata/core-properties/db72fd58a86b4d13a6d2858ebec46705.psmdcp", + "ref/dotnet/de/System.IO.xml", + "ref/dotnet/es/System.IO.xml", + "ref/dotnet/fr/System.IO.xml", + "ref/dotnet/it/System.IO.xml", + "ref/dotnet/ja/System.IO.xml", + "ref/dotnet/ko/System.IO.xml", + "ref/dotnet/ru/System.IO.xml", + "ref/dotnet/System.IO.dll", + "ref/dotnet/System.IO.xml", + "ref/dotnet/zh-hans/System.IO.xml", + "ref/dotnet/zh-hant/System.IO.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "runtimes/win8-aot/lib/netcore50/System.IO.dll", + "System.IO.nuspec" + ] + }, + "System.IO.FileSystem/4.0.0": { + "type": "package", + "sha512": "eo05SPWfG+54UA0wxgRIYOuOslq+2QrJLXZaJDDsfLXG15OLguaItW39NYZTqUb4DeGOkU4R0wpOLOW4ynMUDQ==", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/DNXCore50/System.IO.FileSystem.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/System.IO.FileSystem.dll", + "lib/netcore50/System.IO.FileSystem.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "package/services/metadata/core-properties/0405bad2bcdd403884f42a0a79534bc1.psmdcp", + "ref/dotnet/de/System.IO.FileSystem.xml", + "ref/dotnet/es/System.IO.FileSystem.xml", + "ref/dotnet/fr/System.IO.FileSystem.xml", + "ref/dotnet/it/System.IO.FileSystem.xml", + "ref/dotnet/ja/System.IO.FileSystem.xml", + "ref/dotnet/ko/System.IO.FileSystem.xml", + "ref/dotnet/ru/System.IO.FileSystem.xml", + "ref/dotnet/System.IO.FileSystem.dll", + "ref/dotnet/System.IO.FileSystem.xml", + "ref/dotnet/zh-hans/System.IO.FileSystem.xml", + "ref/dotnet/zh-hant/System.IO.FileSystem.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/System.IO.FileSystem.dll", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "System.IO.FileSystem.nuspec" + ] + }, + "System.IO.FileSystem.Primitives/4.0.0": { + "type": "package", + "sha512": "7pJUvYi/Yq3A5nagqCCiOw3+aJp3xXc/Cjr8dnJDnER3/6kX3LEencfqmXUcPl9+7OvRNyPMNhqsLAcMK6K/KA==", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/dotnet/System.IO.FileSystem.Primitives.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/System.IO.FileSystem.Primitives.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "package/services/metadata/core-properties/2cf3542156f0426483f92b9e37d8d381.psmdcp", + "ref/dotnet/de/System.IO.FileSystem.Primitives.xml", + "ref/dotnet/es/System.IO.FileSystem.Primitives.xml", + "ref/dotnet/fr/System.IO.FileSystem.Primitives.xml", + "ref/dotnet/it/System.IO.FileSystem.Primitives.xml", + "ref/dotnet/ja/System.IO.FileSystem.Primitives.xml", + "ref/dotnet/ko/System.IO.FileSystem.Primitives.xml", + "ref/dotnet/ru/System.IO.FileSystem.Primitives.xml", + "ref/dotnet/System.IO.FileSystem.Primitives.dll", + "ref/dotnet/System.IO.FileSystem.Primitives.xml", + "ref/dotnet/zh-hans/System.IO.FileSystem.Primitives.xml", + "ref/dotnet/zh-hant/System.IO.FileSystem.Primitives.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/System.IO.FileSystem.Primitives.dll", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "System.IO.FileSystem.Primitives.nuspec" + ] + }, + "System.Linq/4.0.0": { + "type": "package", + "serviceable": true, + "sha512": "r6Hlc+ytE6m/9UBr+nNRRdoJEWjoeQiT3L3lXYFDHoXk3VYsRBCDNXrawcexw7KPLaH0zamQLiAb6avhZ50cGg==", + "files": [ + "lib/dotnet/System.Linq.dll", + "lib/net45/_._", + "lib/netcore50/System.Linq.dll", + "lib/win8/_._", + "lib/wp80/_._", + "lib/wpa81/_._", + "ref/dotnet/de/System.Linq.xml", + "ref/dotnet/es/System.Linq.xml", + "ref/dotnet/fr/System.Linq.xml", + "ref/dotnet/it/System.Linq.xml", + "ref/dotnet/ja/System.Linq.xml", + "ref/dotnet/ko/System.Linq.xml", + "ref/dotnet/ru/System.Linq.xml", + "ref/dotnet/System.Linq.dll", + "ref/dotnet/System.Linq.xml", + "ref/dotnet/zh-hans/System.Linq.xml", + "ref/dotnet/zh-hant/System.Linq.xml", + "ref/net45/_._", + "ref/netcore50/System.Linq.dll", + "ref/netcore50/System.Linq.xml", + "ref/win8/_._", + "ref/wp80/_._", + "ref/wpa81/_._", + "System.Linq.4.0.0.nupkg", + "System.Linq.4.0.0.nupkg.sha512", + "System.Linq.nuspec" + ] + }, + "System.Net.Primitives/4.0.10-beta-23127": { + "type": "package", + "serviceable": true, + "sha512": "iMopReygV88cUUXWeem9y9vrb1Sn8gOXXaRClKWW1KrRozBklOh6Og+b/gpsVQJpz2ztZLJI3k96ttoie2M2QA==", + "files": [ + "lib/DNXCore50/System.Net.Primitives.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/_._", + "lib/netcore50/System.Net.Primitives.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/de/System.Net.Primitives.xml", + "ref/dotnet/es/System.Net.Primitives.xml", + "ref/dotnet/fr/System.Net.Primitives.xml", + "ref/dotnet/it/System.Net.Primitives.xml", + "ref/dotnet/ja/System.Net.Primitives.xml", + "ref/dotnet/ko/System.Net.Primitives.xml", + "ref/dotnet/ru/System.Net.Primitives.xml", + "ref/dotnet/System.Net.Primitives.dll", + "ref/dotnet/System.Net.Primitives.xml", + "ref/dotnet/zh-hans/System.Net.Primitives.xml", + "ref/dotnet/zh-hant/System.Net.Primitives.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "System.Net.Primitives.4.0.10-beta-23127.nupkg", + "System.Net.Primitives.4.0.10-beta-23127.nupkg.sha512", + "System.Net.Primitives.nuspec" + ] + }, + "System.Net.Sockets/4.1.0-beta-23316": { + "type": "package", + "serviceable": true, + "sha512": "mYezWfpit2UdM8O1VWcgLG18VDu2KTW5wM60DnXMvVUEPfo1J1opBiVPYhBM0xXxo2FyIYvFIFxdGmFyZYyRCQ==", + "files": [ + "de/System.Net.Sockets.xml", + "es/System.Net.Sockets.xml", + "fr/System.Net.Sockets.xml", + "it/System.Net.Sockets.xml", + "ja/System.Net.Sockets.xml", + "ko/System.Net.Sockets.xml", + "lib/DNXCore50/System.Net.Sockets.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/System.Net.Sockets.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/System.Net.Sockets.dll", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/System.Net.Sockets.dll", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ru/System.Net.Sockets.xml", + "System.Net.Sockets.4.1.0-beta-23316.nupkg", + "System.Net.Sockets.4.1.0-beta-23316.nupkg.sha512", + "System.Net.Sockets.nuspec", + "System.Net.Sockets.xml", + "zh-hans/System.Net.Sockets.xml", + "zh-hant/System.Net.Sockets.xml" + ] + }, + "System.Private.Networking/4.0.1-beta-23316": { + "type": "package", + "serviceable": true, + "sha512": "ccZvi75qVr2y+HZTp8pQ9HHzl2A+rBiN6ljTPPyiHxWrmjT/dIsVud1yGuvnE6emeQDPod8vmPjkZUw+aKz+GA==", + "files": [ + "lib/DNXCore50/System.Private.Networking.dll", + "lib/netcore50/System.Private.Networking.dll", + "ref/dnxcore50/_._", + "ref/netcore50/_._", + "System.Private.Networking.4.0.1-beta-23316.nupkg", + "System.Private.Networking.4.0.1-beta-23316.nupkg.sha512", + "System.Private.Networking.nuspec" + ] + }, + "System.Private.Uri/4.0.0": { + "type": "package", + "sha512": "CtuxaCKcRIvPcsqquVl3mPp79EDZPMr2UogfiFCxCs+t2z1VjbpQsKNs1GHZ8VQetqbk1mr0V1yAfMe6y8CHDA==", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/DNXCore50/System.Private.Uri.dll", + "lib/netcore50/System.Private.Uri.dll", + "package/services/metadata/core-properties/86377e21a22d44bbba860094428d894c.psmdcp", + "ref/dnxcore50/_._", + "ref/netcore50/_._", + "runtimes/win8-aot/lib/netcore50/System.Private.Uri.dll", + "System.Private.Uri.nuspec" + ] + }, + "System.Reflection/4.0.10": { + "type": "package", + "sha512": "WZ+4lEE4gqGx6mrqLhSiW4oi6QLPWwdNjzhhTONmhELOrW8Cw9phlO9tltgvRUuQUqYtBiliFwhO5S5fCJElVw==", + "files": [ + "lib/DNXCore50/System.Reflection.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/_._", + "lib/netcore50/System.Reflection.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/de/System.Reflection.xml", + "ref/dotnet/es/System.Reflection.xml", + "ref/dotnet/fr/System.Reflection.xml", + "ref/dotnet/it/System.Reflection.xml", + "ref/dotnet/ja/System.Reflection.xml", + "ref/dotnet/ko/System.Reflection.xml", + "ref/dotnet/ru/System.Reflection.xml", + "ref/dotnet/System.Reflection.dll", + "ref/dotnet/System.Reflection.xml", + "ref/dotnet/zh-hans/System.Reflection.xml", + "ref/dotnet/zh-hant/System.Reflection.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "runtimes/win8-aot/lib/netcore50/System.Reflection.dll", + "System.Reflection.4.0.10.nupkg", + "System.Reflection.4.0.10.nupkg.sha512", + "System.Reflection.nuspec" + ] + }, + "System.Reflection.Primitives/4.0.0": { + "type": "package", + "sha512": "n9S0XpKv2ruc17FSnaiX6nV47VfHTZ1wLjKZlAirUZCvDQCH71mVp+Ohabn0xXLh5pK2PKp45HCxkqu5Fxn/lA==", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/DNXCore50/System.Reflection.Primitives.dll", + "lib/net45/_._", + "lib/netcore50/System.Reflection.Primitives.dll", + "lib/win8/_._", + "lib/wp80/_._", + "lib/wpa81/_._", + "package/services/metadata/core-properties/7070509f3bfd418d859635361251dab0.psmdcp", + "ref/dotnet/de/System.Reflection.Primitives.xml", + "ref/dotnet/es/System.Reflection.Primitives.xml", + "ref/dotnet/fr/System.Reflection.Primitives.xml", + "ref/dotnet/it/System.Reflection.Primitives.xml", + "ref/dotnet/ja/System.Reflection.Primitives.xml", + "ref/dotnet/ko/System.Reflection.Primitives.xml", + "ref/dotnet/ru/System.Reflection.Primitives.xml", + "ref/dotnet/System.Reflection.Primitives.dll", + "ref/dotnet/System.Reflection.Primitives.xml", + "ref/dotnet/zh-hans/System.Reflection.Primitives.xml", + "ref/dotnet/zh-hant/System.Reflection.Primitives.xml", + "ref/net45/_._", + "ref/netcore50/System.Reflection.Primitives.dll", + "ref/netcore50/System.Reflection.Primitives.xml", + "ref/win8/_._", + "ref/wp80/_._", + "ref/wpa81/_._", + "runtimes/win8-aot/lib/netcore50/System.Reflection.Primitives.dll", + "System.Reflection.Primitives.nuspec" + ] + }, + "System.Resources.ResourceManager/4.0.0": { + "type": "package", + "sha512": "qmqeZ4BJgjfU+G2JbrZt4Dk1LsMxO4t+f/9HarNY6w8pBgweO6jT+cknUH7c3qIrGvyUqraBhU45Eo6UtA0fAw==", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/DNXCore50/System.Resources.ResourceManager.dll", + "lib/net45/_._", + "lib/netcore50/System.Resources.ResourceManager.dll", + "lib/win8/_._", + "lib/wp80/_._", + "lib/wpa81/_._", + "package/services/metadata/core-properties/657a73ee3f09479c9fedb9538ade8eac.psmdcp", + "ref/dotnet/de/System.Resources.ResourceManager.xml", + "ref/dotnet/es/System.Resources.ResourceManager.xml", + "ref/dotnet/fr/System.Resources.ResourceManager.xml", + "ref/dotnet/it/System.Resources.ResourceManager.xml", + "ref/dotnet/ja/System.Resources.ResourceManager.xml", + "ref/dotnet/ko/System.Resources.ResourceManager.xml", + "ref/dotnet/ru/System.Resources.ResourceManager.xml", + "ref/dotnet/System.Resources.ResourceManager.dll", + "ref/dotnet/System.Resources.ResourceManager.xml", + "ref/dotnet/zh-hans/System.Resources.ResourceManager.xml", + "ref/dotnet/zh-hant/System.Resources.ResourceManager.xml", + "ref/net45/_._", + "ref/netcore50/System.Resources.ResourceManager.dll", + "ref/netcore50/System.Resources.ResourceManager.xml", + "ref/win8/_._", + "ref/wp80/_._", + "ref/wpa81/_._", + "runtimes/win8-aot/lib/netcore50/System.Resources.ResourceManager.dll", + "System.Resources.ResourceManager.nuspec" + ] + }, + "System.Runtime/4.0.20": { + "type": "package", + "sha512": "X7N/9Bz7jVPorqdVFO86ns1sX6MlQM+WTxELtx+Z4VG45x9+LKmWH0GRqjgKprUnVuwmfB9EJ9DQng14Z7/zwg==", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/DNXCore50/System.Runtime.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/_._", + "lib/netcore50/System.Runtime.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "package/services/metadata/core-properties/d1ded52f75da4446b1c962f9292aa3ef.psmdcp", + "ref/dotnet/de/System.Runtime.xml", + "ref/dotnet/es/System.Runtime.xml", + "ref/dotnet/fr/System.Runtime.xml", + "ref/dotnet/it/System.Runtime.xml", + "ref/dotnet/ja/System.Runtime.xml", + "ref/dotnet/ko/System.Runtime.xml", + "ref/dotnet/ru/System.Runtime.xml", + "ref/dotnet/System.Runtime.dll", + "ref/dotnet/System.Runtime.xml", + "ref/dotnet/zh-hans/System.Runtime.xml", + "ref/dotnet/zh-hant/System.Runtime.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "runtimes/win8-aot/lib/netcore50/System.Runtime.dll", + "System.Runtime.nuspec" + ] + }, + "System.Runtime.Extensions/4.0.10": { + "type": "package", + "sha512": "5dsEwf3Iml7d5OZeT20iyOjT+r+okWpN7xI2v+R4cgd3WSj4DeRPTvPFjDpacbVW4skCAZ8B9hxXJYgkCFKJ1A==", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/DNXCore50/System.Runtime.Extensions.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/_._", + "lib/netcore50/System.Runtime.Extensions.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "package/services/metadata/core-properties/c7fee76a13d04c7ea49fb1a24c184f37.psmdcp", + "ref/dotnet/de/System.Runtime.Extensions.xml", + "ref/dotnet/es/System.Runtime.Extensions.xml", + "ref/dotnet/fr/System.Runtime.Extensions.xml", + "ref/dotnet/it/System.Runtime.Extensions.xml", + "ref/dotnet/ja/System.Runtime.Extensions.xml", + "ref/dotnet/ko/System.Runtime.Extensions.xml", + "ref/dotnet/ru/System.Runtime.Extensions.xml", + "ref/dotnet/System.Runtime.Extensions.dll", + "ref/dotnet/System.Runtime.Extensions.xml", + "ref/dotnet/zh-hans/System.Runtime.Extensions.xml", + "ref/dotnet/zh-hant/System.Runtime.Extensions.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "runtimes/win8-aot/lib/netcore50/System.Runtime.Extensions.dll", + "System.Runtime.Extensions.nuspec" + ] + }, + "System.Runtime.Handles/4.0.0": { + "type": "package", + "sha512": "638VhpRq63tVcQ6HDb3um3R/J2BtR1Sa96toHo6PcJGPXEPEsleCuqhBgX2gFCz0y0qkutANwW6VPPY5wQu1XQ==", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/DNXCore50/System.Runtime.Handles.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/_._", + "lib/netcore50/System.Runtime.Handles.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "package/services/metadata/core-properties/da57aa32ff2441d1acfe85bee4f101ab.psmdcp", + "ref/dotnet/de/System.Runtime.Handles.xml", + "ref/dotnet/es/System.Runtime.Handles.xml", + "ref/dotnet/fr/System.Runtime.Handles.xml", + "ref/dotnet/it/System.Runtime.Handles.xml", + "ref/dotnet/ja/System.Runtime.Handles.xml", + "ref/dotnet/ko/System.Runtime.Handles.xml", + "ref/dotnet/ru/System.Runtime.Handles.xml", + "ref/dotnet/System.Runtime.Handles.dll", + "ref/dotnet/System.Runtime.Handles.xml", + "ref/dotnet/zh-hans/System.Runtime.Handles.xml", + "ref/dotnet/zh-hant/System.Runtime.Handles.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "runtimes/win8-aot/lib/netcore50/System.Runtime.Handles.dll", + "System.Runtime.Handles.nuspec" + ] + }, + "System.Runtime.InteropServices/4.0.20": { + "type": "package", + "sha512": "ZgDyBYfEnjWoz/viS6VOswA6XOkDSH2DzgbpczbW50RywhnCgTl+w3JEvtAiOGyIh8cyx1NJq80jsNBSUr8Pig==", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/DNXCore50/System.Runtime.InteropServices.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/_._", + "lib/netcore50/System.Runtime.InteropServices.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "package/services/metadata/core-properties/78e7f61876374acba2a95834f272d262.psmdcp", + "ref/dotnet/de/System.Runtime.InteropServices.xml", + "ref/dotnet/es/System.Runtime.InteropServices.xml", + "ref/dotnet/fr/System.Runtime.InteropServices.xml", + "ref/dotnet/it/System.Runtime.InteropServices.xml", + "ref/dotnet/ja/System.Runtime.InteropServices.xml", + "ref/dotnet/ko/System.Runtime.InteropServices.xml", + "ref/dotnet/ru/System.Runtime.InteropServices.xml", + "ref/dotnet/System.Runtime.InteropServices.dll", + "ref/dotnet/System.Runtime.InteropServices.xml", + "ref/dotnet/zh-hans/System.Runtime.InteropServices.xml", + "ref/dotnet/zh-hant/System.Runtime.InteropServices.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "runtimes/win8-aot/lib/netcore50/System.Runtime.InteropServices.dll", + "System.Runtime.InteropServices.nuspec" + ] + }, + "System.Runtime.InteropServices.RuntimeInformation/4.0.0-beta-23213": { + "type": "package", + "serviceable": true, + "sha512": "yzVJM7dF6XqnGTkv2IRufKs8AiqDpfdfBvMT5sVgY2fCtUXdkcjxiIWzaVIau8IYrJUlQDmSpeQ8NV6l1vz0Lg==", + "files": [ + "lib/dotnet/System.Runtime.InteropServices.RuntimeInformation.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/System.Runtime.InteropServices.RuntimeInformation.dll", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "System.Runtime.InteropServices.RuntimeInformation.4.0.0-beta-23213.nupkg", + "System.Runtime.InteropServices.RuntimeInformation.4.0.0-beta-23213.nupkg.sha512", + "System.Runtime.InteropServices.RuntimeInformation.nuspec" + ] + }, + "System.Runtime.Numerics/4.0.0": { + "type": "package", + "serviceable": true, + "sha512": "aAYGEOE01nabQLufQ4YO8WuSyZzOqGcksi8m1BRW8ppkmssR7en8TqiXcBkB2gTkCnKG/Ai2NQY8CgdmgZw/fw==", + "files": [ + "lib/dotnet/System.Runtime.Numerics.dll", + "lib/net45/_._", + "lib/netcore50/System.Runtime.Numerics.dll", + "lib/win8/_._", + "lib/wpa81/_._", + "ref/dotnet/de/System.Runtime.Numerics.xml", + "ref/dotnet/es/System.Runtime.Numerics.xml", + "ref/dotnet/fr/System.Runtime.Numerics.xml", + "ref/dotnet/it/System.Runtime.Numerics.xml", + "ref/dotnet/ja/System.Runtime.Numerics.xml", + "ref/dotnet/ko/System.Runtime.Numerics.xml", + "ref/dotnet/ru/System.Runtime.Numerics.xml", + "ref/dotnet/System.Runtime.Numerics.dll", + "ref/dotnet/System.Runtime.Numerics.xml", + "ref/dotnet/zh-hans/System.Runtime.Numerics.xml", + "ref/dotnet/zh-hant/System.Runtime.Numerics.xml", + "ref/net45/_._", + "ref/netcore50/System.Runtime.Numerics.dll", + "ref/netcore50/System.Runtime.Numerics.xml", + "ref/win8/_._", + "ref/wpa81/_._", + "System.Runtime.Numerics.4.0.0.nupkg", + "System.Runtime.Numerics.4.0.0.nupkg.sha512", + "System.Runtime.Numerics.nuspec" + ] + }, + "System.Security.Claims/4.0.0": { + "type": "package", + "serviceable": true, + "sha512": "94NFR/7JN3YdyTH7hl2iSvYmdA8aqShriTHectcK+EbizT71YczMaG6LuqJBQP/HWo66AQyikYYM9aw+4EzGXg==", + "files": [ + "lib/dotnet/System.Security.Claims.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/System.Security.Claims.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/de/System.Security.Claims.xml", + "ref/dotnet/es/System.Security.Claims.xml", + "ref/dotnet/fr/System.Security.Claims.xml", + "ref/dotnet/it/System.Security.Claims.xml", + "ref/dotnet/ja/System.Security.Claims.xml", + "ref/dotnet/ko/System.Security.Claims.xml", + "ref/dotnet/ru/System.Security.Claims.xml", + "ref/dotnet/System.Security.Claims.dll", + "ref/dotnet/System.Security.Claims.xml", + "ref/dotnet/zh-hans/System.Security.Claims.xml", + "ref/dotnet/zh-hant/System.Security.Claims.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/System.Security.Claims.dll", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "System.Security.Claims.4.0.0.nupkg", + "System.Security.Claims.4.0.0.nupkg.sha512", + "System.Security.Claims.nuspec" + ] + }, + "System.Security.Cryptography.Algorithms/4.0.0-beta-23316": { + "type": "package", + "serviceable": true, + "sha512": "PfvnB/k9vKqA7GafjztuvqLjupcG9KbnRZrp9R9duSTotzFJIbrD2I46cLq/a6WKP+uz2Nwy8l6F0zCOBSSvRQ==", + "files": [ + "lib/dotnet/System.Security.Cryptography.Algorithms.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/System.Security.Cryptography.Algorithms.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/System.Security.Cryptography.Algorithms.dll", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/System.Security.Cryptography.Algorithms.dll", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "System.Security.Cryptography.Algorithms.4.0.0-beta-23316.nupkg", + "System.Security.Cryptography.Algorithms.4.0.0-beta-23316.nupkg.sha512", + "System.Security.Cryptography.Algorithms.nuspec" + ] + }, + "System.Security.Cryptography.Cng/4.0.0-beta-23316": { + "type": "package", + "serviceable": true, + "sha512": "K0tiPjRVr3ctEDhahr5wvhMvrEHT4H+wRFSuai3i7I8kQ7Ba/yH/zNBA7rR93AJMWhqw2bxMPywn0q7I0FtlRQ==", + "files": [ + "lib/dotnet/System.Security.Cryptography.Cng.dll", + "lib/net46/System.Security.Cryptography.Cng.dll", + "ref/dotnet/System.Security.Cryptography.Cng.dll", + "ref/net46/System.Security.Cryptography.Cng.dll", + "System.Security.Cryptography.Cng.4.0.0-beta-23316.nupkg", + "System.Security.Cryptography.Cng.4.0.0-beta-23316.nupkg.sha512", + "System.Security.Cryptography.Cng.nuspec" + ] + }, + "System.Security.Cryptography.Csp/4.0.0-beta-23316": { + "type": "package", + "serviceable": true, + "sha512": "wSKdNzPjbLqlixIM03DnzY5e/XzAyY7S9VbRi8zdjWnaiytGLBYbzocTeli8begAF4+lT42+tCeu4k1dm1SyrA==", + "files": [ + "lib/DNXCore50/System.Security.Cryptography.Csp.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/System.Security.Cryptography.Csp.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/System.Security.Cryptography.Csp.dll", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/System.Security.Cryptography.Csp.dll", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "System.Security.Cryptography.Csp.4.0.0-beta-23316.nupkg", + "System.Security.Cryptography.Csp.4.0.0-beta-23316.nupkg.sha512", + "System.Security.Cryptography.Csp.nuspec" + ] + }, + "System.Security.Cryptography.Encoding/4.0.0-beta-23316": { + "type": "package", + "serviceable": true, + "sha512": "MF4r9s346IqjU0VIJUjr06sd8gL+Wjce1vKmFdQ4w577ky1CsPSv3/tU+ofMsNnLNUqA7ZMOdd66alFdMEsp9g==", + "files": [ + "de/System.Security.Cryptography.Encoding.xml", + "es/System.Security.Cryptography.Encoding.xml", + "fr/System.Security.Cryptography.Encoding.xml", + "it/System.Security.Cryptography.Encoding.xml", + "ja/System.Security.Cryptography.Encoding.xml", + "ko/System.Security.Cryptography.Encoding.xml", + "lib/dotnet/System.Security.Cryptography.Encoding.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/System.Security.Cryptography.Encoding.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/System.Security.Cryptography.Encoding.dll", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/System.Security.Cryptography.Encoding.dll", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ru/System.Security.Cryptography.Encoding.xml", + "System.Security.Cryptography.Encoding.4.0.0-beta-23316.nupkg", + "System.Security.Cryptography.Encoding.4.0.0-beta-23316.nupkg.sha512", + "System.Security.Cryptography.Encoding.nuspec", + "System.Security.Cryptography.Encoding.xml", + "zh-hans/System.Security.Cryptography.Encoding.xml", + "zh-hant/System.Security.Cryptography.Encoding.xml" + ] + }, + "System.Security.Cryptography.Primitives/4.0.0-beta-23316": { + "type": "package", + "serviceable": true, + "sha512": "wIzGlW1T3xIMrFvXUBKU5/iP8a4QkYhHmFB0Zxp09gPDPPifeCROtYzv1Sj/y5ZVRoKBnDAPiMMGIp1LMj7fOg==", + "files": [ + "lib/dotnet/System.Security.Cryptography.Primitives.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/System.Security.Cryptography.Primitives.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/System.Security.Cryptography.Primitives.dll", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/System.Security.Cryptography.Primitives.dll", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "System.Security.Cryptography.Primitives.4.0.0-beta-23316.nupkg", + "System.Security.Cryptography.Primitives.4.0.0-beta-23316.nupkg.sha512", + "System.Security.Cryptography.Primitives.nuspec" + ] + }, + "System.Security.Cryptography.X509Certificates/4.0.0-beta-23316": { + "type": "package", + "serviceable": true, + "sha512": "RXSU+z0BiJZS9g/fyPyiKTDhPe5V8Reh+OtUaOtZlKvL55e0gCBAe33KifI9d9e12TSjnaDa439Yl9ZwIASysQ==", + "files": [ + "de/System.Security.Cryptography.X509Certificates.xml", + "es/System.Security.Cryptography.X509Certificates.xml", + "fr/System.Security.Cryptography.X509Certificates.xml", + "it/System.Security.Cryptography.X509Certificates.xml", + "ja/System.Security.Cryptography.X509Certificates.xml", + "ko/System.Security.Cryptography.X509Certificates.xml", + "lib/DNXCore50/System.Security.Cryptography.X509Certificates.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/System.Security.Cryptography.X509Certificates.dll", + "lib/netcore50/System.Security.Cryptography.X509Certificates.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/System.Security.Cryptography.X509Certificates.dll", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/System.Security.Cryptography.X509Certificates.dll", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ru/System.Security.Cryptography.X509Certificates.xml", + "System.Security.Cryptography.X509Certificates.4.0.0-beta-23316.nupkg", + "System.Security.Cryptography.X509Certificates.4.0.0-beta-23316.nupkg.sha512", + "System.Security.Cryptography.X509Certificates.nuspec", + "System.Security.Cryptography.X509Certificates.xml", + "zh-hans/System.Security.Cryptography.X509Certificates.xml", + "zh-hant/System.Security.Cryptography.X509Certificates.xml" + ] + }, + "System.Security.Cryptography.X509Certificates.TestData/1.0.0-prerelease": { + "type": "package", + "sha512": "UbpXPyovZcwfKhYg/O85pLjFEO3hkrEjCLGus7P9y45Peoqrfc8XKzdCW5k5WIDCtLw9M1PJHGlOFV/U0D1tkg==", + "files": [ + "content/TestData/DummyTcpServer.pfx", + "content/TestData/microsoft.cer", + "content/TestData/MS.cer", + "content/TestData/My.cer", + "content/TestData/My.pfx", + "content/TestData/test.cer", + "content/TestData/test.pfx", + "content/TestData/Windows6.1-KB3004361-x64.msu", + "System.Security.Cryptography.X509Certificates.TestData.1.0.0-prerelease.nupkg", + "System.Security.Cryptography.X509Certificates.TestData.1.0.0-prerelease.nupkg.sha512", + "System.Security.Cryptography.X509Certificates.TestData.nuspec" + ] + }, + "System.Security.Principal/4.0.0": { + "type": "package", + "serviceable": true, + "sha512": "FOhq3jUOONi6fp5j3nPYJMrKtSJlqAURpjiO3FaDIV4DJNEYymWW5uh1pfxySEB8dtAW+I66IypzNge/w9OzZQ==", + "files": [ + "lib/dotnet/System.Security.Principal.dll", + "lib/net45/_._", + "lib/netcore50/System.Security.Principal.dll", + "lib/win8/_._", + "lib/wp80/_._", + "lib/wpa81/_._", + "ref/dotnet/de/System.Security.Principal.xml", + "ref/dotnet/es/System.Security.Principal.xml", + "ref/dotnet/fr/System.Security.Principal.xml", + "ref/dotnet/it/System.Security.Principal.xml", + "ref/dotnet/ja/System.Security.Principal.xml", + "ref/dotnet/ko/System.Security.Principal.xml", + "ref/dotnet/ru/System.Security.Principal.xml", + "ref/dotnet/System.Security.Principal.dll", + "ref/dotnet/System.Security.Principal.xml", + "ref/dotnet/zh-hans/System.Security.Principal.xml", + "ref/dotnet/zh-hant/System.Security.Principal.xml", + "ref/net45/_._", + "ref/netcore50/System.Security.Principal.dll", + "ref/netcore50/System.Security.Principal.xml", + "ref/win8/_._", + "ref/wp80/_._", + "ref/wpa81/_._", + "System.Security.Principal.4.0.0.nupkg", + "System.Security.Principal.4.0.0.nupkg.sha512", + "System.Security.Principal.nuspec" + ] + }, + "System.Security.Principal.Windows/4.0.0-beta-23316": { + "type": "package", + "serviceable": true, + "sha512": "nhGXagP2GEqOO6xI8GNpu66rdvmk+2PpOqSnq80ftKpHv43AdUtSfBIcNfI9sYzh5Vthtx24x0cXyeX3jp0pEQ==", + "files": [ + "de/System.Security.Principal.Windows.xml", + "es/System.Security.Principal.Windows.xml", + "fr/System.Security.Principal.Windows.xml", + "it/System.Security.Principal.Windows.xml", + "ja/System.Security.Principal.Windows.xml", + "ko/System.Security.Principal.Windows.xml", + "lib/DNXCore50/System.Security.Principal.Windows.dll", + "lib/net46/System.Security.Principal.Windows.dll", + "ref/dotnet/System.Security.Principal.Windows.dll", + "ref/net46/System.Security.Principal.Windows.dll", + "ru/System.Security.Principal.Windows.xml", + "System.Security.Principal.Windows.4.0.0-beta-23316.nupkg", + "System.Security.Principal.Windows.4.0.0-beta-23316.nupkg.sha512", + "System.Security.Principal.Windows.nuspec", + "System.Security.Principal.Windows.xml", + "zh-hans/System.Security.Principal.Windows.xml", + "zh-hant/System.Security.Principal.Windows.xml" + ] + }, + "System.Security.SecureString/4.0.0-beta-23316": { + "type": "package", + "serviceable": true, + "sha512": "WL2EHHhjou9OBwEPXWxm5w27zvG9VJ2WpFbgU3sR/HhbWgJdvHzYMFU2c6D/6gJZyUZs3tq5HXaQvTralvYL9g==", + "files": [ + "de/System.Security.SecureString.xml", + "es/System.Security.SecureString.xml", + "fr/System.Security.SecureString.xml", + "it/System.Security.SecureString.xml", + "ja/System.Security.SecureString.xml", + "ko/System.Security.SecureString.xml", + "lib/DNXCore50/System.Security.SecureString.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/System.Security.SecureString.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/System.Security.SecureString.dll", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/System.Security.SecureString.dll", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ru/System.Security.SecureString.xml", + "System.Security.SecureString.4.0.0-beta-23316.nupkg", + "System.Security.SecureString.4.0.0-beta-23316.nupkg.sha512", + "System.Security.SecureString.nuspec", + "System.Security.SecureString.xml", + "zh-hans/System.Security.SecureString.xml", + "zh-hant/System.Security.SecureString.xml" + ] + }, + "System.Text.Encoding/4.0.10": { + "type": "package", + "sha512": "fNlSFgy4OuDlJrP9SFFxMlaLazq6ipv15sU5TiEgg9UCVnA/OgoVUfymFp4AOk1jOkW5SVxWbeeIUptcM+m/Vw==", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/DNXCore50/System.Text.Encoding.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/_._", + "lib/netcore50/System.Text.Encoding.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "package/services/metadata/core-properties/829e172aadac4937a5a6a4b386855282.psmdcp", + "ref/dotnet/de/System.Text.Encoding.xml", + "ref/dotnet/es/System.Text.Encoding.xml", + "ref/dotnet/fr/System.Text.Encoding.xml", + "ref/dotnet/it/System.Text.Encoding.xml", + "ref/dotnet/ja/System.Text.Encoding.xml", + "ref/dotnet/ko/System.Text.Encoding.xml", + "ref/dotnet/ru/System.Text.Encoding.xml", + "ref/dotnet/System.Text.Encoding.dll", + "ref/dotnet/System.Text.Encoding.xml", + "ref/dotnet/zh-hans/System.Text.Encoding.xml", + "ref/dotnet/zh-hant/System.Text.Encoding.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "runtimes/win8-aot/lib/netcore50/System.Text.Encoding.dll", + "System.Text.Encoding.nuspec" + ] + }, + "System.Text.Encoding.Extensions/4.0.10": { + "type": "package", + "sha512": "TZvlwXMxKo3bSRIcsWZLCIzIhLbvlz+mGeKYRZv/zUiSoQzGOwkYeBu6hOw2XPQgKqT0F4Rv8zqKdvmp2fWKYg==", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/DNXCore50/System.Text.Encoding.Extensions.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/_._", + "lib/netcore50/System.Text.Encoding.Extensions.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "package/services/metadata/core-properties/894d51cf918c4bca91e81a732d958707.psmdcp", + "ref/dotnet/de/System.Text.Encoding.Extensions.xml", + "ref/dotnet/es/System.Text.Encoding.Extensions.xml", + "ref/dotnet/fr/System.Text.Encoding.Extensions.xml", + "ref/dotnet/it/System.Text.Encoding.Extensions.xml", + "ref/dotnet/ja/System.Text.Encoding.Extensions.xml", + "ref/dotnet/ko/System.Text.Encoding.Extensions.xml", + "ref/dotnet/ru/System.Text.Encoding.Extensions.xml", + "ref/dotnet/System.Text.Encoding.Extensions.dll", + "ref/dotnet/System.Text.Encoding.Extensions.xml", + "ref/dotnet/zh-hans/System.Text.Encoding.Extensions.xml", + "ref/dotnet/zh-hant/System.Text.Encoding.Extensions.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "runtimes/win8-aot/lib/netcore50/System.Text.Encoding.Extensions.dll", + "System.Text.Encoding.Extensions.nuspec" + ] + }, + "System.Threading/4.0.10": { + "type": "package", + "sha512": "0w6pRxIEE7wuiOJeKabkDgeIKmqf4ER1VNrs6qFwHnooEE78yHwi/bKkg5Jo8/pzGLm0xQJw0nEmPXt1QBAIUA==", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/DNXCore50/System.Threading.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/_._", + "lib/netcore50/System.Threading.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "package/services/metadata/core-properties/c17c3791d8fa4efbb8aded2ca8c71fbe.psmdcp", + "ref/dotnet/de/System.Threading.xml", + "ref/dotnet/es/System.Threading.xml", + "ref/dotnet/fr/System.Threading.xml", + "ref/dotnet/it/System.Threading.xml", + "ref/dotnet/ja/System.Threading.xml", + "ref/dotnet/ko/System.Threading.xml", + "ref/dotnet/ru/System.Threading.xml", + "ref/dotnet/System.Threading.dll", + "ref/dotnet/System.Threading.xml", + "ref/dotnet/zh-hans/System.Threading.xml", + "ref/dotnet/zh-hant/System.Threading.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "runtimes/win8-aot/lib/netcore50/System.Threading.dll", + "System.Threading.nuspec" + ] + }, + "System.Threading.Overlapped/4.0.0": { + "type": "package", + "sha512": "X5LuQFhM5FTqaez3eXKJ9CbfSGZ7wj6j4hSVtxct3zmwQXLqG95qoWdvILcgN7xtrDOBIFtpiyDg0vmoI0jE2A==", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/DNXCore50/System.Threading.Overlapped.dll", + "lib/net46/System.Threading.Overlapped.dll", + "lib/netcore50/System.Threading.Overlapped.dll", + "package/services/metadata/core-properties/e9846a81e829434aafa4ae2e8c3517d7.psmdcp", + "ref/dotnet/de/System.Threading.Overlapped.xml", + "ref/dotnet/es/System.Threading.Overlapped.xml", + "ref/dotnet/fr/System.Threading.Overlapped.xml", + "ref/dotnet/it/System.Threading.Overlapped.xml", + "ref/dotnet/ja/System.Threading.Overlapped.xml", + "ref/dotnet/ko/System.Threading.Overlapped.xml", + "ref/dotnet/ru/System.Threading.Overlapped.xml", + "ref/dotnet/System.Threading.Overlapped.dll", + "ref/dotnet/System.Threading.Overlapped.xml", + "ref/dotnet/zh-hans/System.Threading.Overlapped.xml", + "ref/dotnet/zh-hant/System.Threading.Overlapped.xml", + "ref/net46/System.Threading.Overlapped.dll", + "System.Threading.Overlapped.nuspec" + ] + }, + "System.Threading.Tasks/4.0.10": { + "type": "package", + "sha512": "NOwJGDfk79jR0bnzosbXLVD/PdI8KzBeESoa3CofEM5v9R5EBfcI0Jyf18stx+0IYV9okmDIDxVtxq9TbnR9bQ==", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/DNXCore50/System.Threading.Tasks.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/_._", + "lib/netcore50/System.Threading.Tasks.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "package/services/metadata/core-properties/a4ed35f8764a4b68bb39ec8d13b3e730.psmdcp", + "ref/dotnet/de/System.Threading.Tasks.xml", + "ref/dotnet/es/System.Threading.Tasks.xml", + "ref/dotnet/fr/System.Threading.Tasks.xml", + "ref/dotnet/it/System.Threading.Tasks.xml", + "ref/dotnet/ja/System.Threading.Tasks.xml", + "ref/dotnet/ko/System.Threading.Tasks.xml", + "ref/dotnet/ru/System.Threading.Tasks.xml", + "ref/dotnet/System.Threading.Tasks.dll", + "ref/dotnet/System.Threading.Tasks.xml", + "ref/dotnet/zh-hans/System.Threading.Tasks.xml", + "ref/dotnet/zh-hant/System.Threading.Tasks.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "runtimes/win8-aot/lib/netcore50/System.Threading.Tasks.dll", + "System.Threading.Tasks.nuspec" + ] + }, + "System.Threading.ThreadPool/4.0.10-beta-23316": { + "type": "package", + "serviceable": true, + "sha512": "bLByUFcpDs94+guIu/2of2rOA/zB/7dzPks3HNv98AqIQ1ObeQCpPkrSitr+E/pW6nDvdIH4I47KGve6yiBMFg==", + "files": [ + "lib/DNXCore50/System.Threading.ThreadPool.dll", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/System.Threading.ThreadPool.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "ref/dotnet/System.Threading.ThreadPool.dll", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/System.Threading.ThreadPool.dll", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "System.Threading.ThreadPool.4.0.10-beta-23316.nupkg", + "System.Threading.ThreadPool.4.0.10-beta-23316.nupkg.sha512", + "System.Threading.ThreadPool.nuspec" + ] + }, + "xunit/2.1.0-beta3-build3029": { + "type": "package", + "sha512": "NMFXV0ePe/GrfhMSPGAlWmiUZCzjaatpdAGcavf2B6vYTRyMTpyJT01LI6jemMV/VSDXLrtHp0Ov9xZyR1cLLg==", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "package/services/metadata/core-properties/d8f65b6e50974443be49b52c7aaafb11.psmdcp", + "xunit.nuspec" + ] + }, + "xunit.abstractions/2.0.0": { + "type": "package", + "sha512": "NAdxKQRzuLnCZ0g++x6i87/8rMBpQoRiRlRNLAqfODm2zJPbteHRoSER3DXfxnqrHXyBJT8rFaZ8uveBeQyaMA==", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/net35/xunit.abstractions.dll", + "lib/net35/xunit.abstractions.xml", + "lib/portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS/xunit.abstractions.dll", + "lib/portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS/xunit.abstractions.xml", + "package/services/metadata/core-properties/24083640fee244bf9de77f4c35d40a72.psmdcp", + "xunit.abstractions.nuspec" + ] + }, + "xunit.assert/2.1.0-beta3-build3029": { + "type": "package", + "sha512": "AMS7Fv77DayXVRCBMmVEDwOXPcbxk8dCBA/iACsve+6+UQqopMtNyAynyIcXPFRK/peeitUKID4ChOXWisJmUw==", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/portable-net45+dnxcore50+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS/xunit.assert.dll", + "lib/portable-net45+dnxcore50+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS/xunit.assert.pdb", + "lib/portable-net45+dnxcore50+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS/xunit.assert.xml", + "package/services/metadata/core-properties/38c52763215f45f28d084a9c1b6e4fa2.psmdcp", + "xunit.assert.nuspec" + ] + }, + "xunit.core/2.1.0-beta3-build3029": { + "type": "package", + "sha512": "uDUBbwZSRx226BMwj6VylzXQPVpEIelNIulT+LxbSEH52y2a4btR9d5ptQmkSVjmJXP5/hGCc4cu1DSCu0pgUA==", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "build/_Desktop/xunit.execution.desktop.dll", + "build/monoandroid/xunit.core.props", + "build/monoandroid/xunit.execution.MonoAndroid.dll", + "build/monotouch/xunit.core.props", + "build/monotouch/xunit.execution.MonoTouch.dll", + "build/portable-net45+dnxcore50+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS/xunit.core.props", + "build/portable-win81+wpa81/xunit.core.props", + "build/portable-win81+wpa81/xunit.core.targets", + "build/portable-win81+wpa81/xunit.execution.universal.dll", + "build/portable-win81+wpa81/xunit.execution.universal.pri", + "build/wp8/xunit.core.props", + "build/wp8/xunit.core.targets", + "build/wp8/xunit.execution.wp8.dll", + "build/Xamarin.iOS/xunit.core.props", + "build/Xamarin.iOS/xunit.execution.iOS-Universal.dll", + "package/services/metadata/core-properties/7cc532c455474d1dac8f8b0cfe0b3522.psmdcp", + "xunit.core.nuspec" + ] + }, + "xunit.extensibility.core/2.1.0-beta3-build3029": { + "type": "package", + "sha512": "lsPro5U3NLasHI/RwqjKzXiRlh9N0IOlR3cluwXYVtihXbGtySeSnU/Fh5MTcWYxh+MVpoNop5zDD0/A2nrHsA==", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/portable-net45+dnxcore50+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS/xunit.core.dll", + "lib/portable-net45+dnxcore50+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS/xunit.core.dll.tdnet", + "lib/portable-net45+dnxcore50+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS/xunit.core.pdb", + "lib/portable-net45+dnxcore50+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS/xunit.core.xml", + "lib/portable-net45+dnxcore50+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS/xunit.runner.tdnet.dll", + "lib/portable-net45+dnxcore50+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS/xunit.runner.utility.desktop.dll", + "package/services/metadata/core-properties/40eb326fb1ea4e05a77fef0e7c6571cc.psmdcp", + "xunit.extensibility.core.nuspec" + ] + }, + "xunit.extensibility.execution/2.1.0-beta3-build3029": { + "type": "package", + "sha512": "WuUYamK4RHrHxihvNuX7NkryMhQrpH1+ziJ/mPIQbm18zevSgre8BwUuVZvmLZa8uVob3xS4dvAah2+HCgLiXg==", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/dnx451/xunit.execution.dnx.dll", + "lib/dnx451/xunit.execution.dnx.pdb", + "lib/dnx451/xunit.execution.dnx.xml", + "lib/dnxcore50/xunit.execution.dnx.dll", + "lib/dnxcore50/xunit.execution.dnx.pdb", + "lib/dnxcore50/xunit.execution.dnx.xml", + "lib/monoandroid/xunit.execution.MonoAndroid.dll", + "lib/monoandroid/xunit.execution.MonoAndroid.pdb", + "lib/monoandroid/xunit.execution.MonoAndroid.xml", + "lib/monotouch/xunit.execution.MonoTouch.dll", + "lib/monotouch/xunit.execution.MonoTouch.pdb", + "lib/monotouch/xunit.execution.MonoTouch.xml", + "lib/net45/xunit.execution.desktop.dll", + "lib/net45/xunit.execution.desktop.pdb", + "lib/net45/xunit.execution.desktop.xml", + "lib/portable-wpa81+win81/xunit.execution.universal.dll", + "lib/portable-wpa81+win81/xunit.execution.universal.pdb", + "lib/portable-wpa81+win81/xunit.execution.universal.pri", + "lib/portable-wpa81+win81/xunit.execution.universal.xml", + "lib/wp8/xunit.execution.wp8.dll", + "lib/wp8/xunit.execution.wp8.pdb", + "lib/wp8/xunit.execution.wp8.xml", + "lib/Xamarin.iOS/xunit.execution.iOS-Universal.dll", + "lib/Xamarin.iOS/xunit.execution.iOS-Universal.pdb", + "lib/Xamarin.iOS/xunit.execution.iOS-Universal.xml", + "package/services/metadata/core-properties/632d17654a7d4ee58b8c7032b6bae6bf.psmdcp", + "xunit.extensibility.execution.nuspec" + ] + }, + "xunit.netcore.extensions/1.0.0-prerelease-00087": { + "type": "package", + "serviceable": true, + "sha512": "zn7ZwF2Q9TPKht3VzK79IGBO/O7nxk+j01KmwnwbR2FmDcWEONaLBZFlymlDmpjX+KP+re+vvfXxzMABD9jRoQ==", + "files": [ + "lib/dotnet/Xunit.NetCore.Extensions.dll", + "xunit.netcore.extensions.1.0.0-prerelease-00087.nupkg", + "xunit.netcore.extensions.1.0.0-prerelease-00087.nupkg.sha512", + "xunit.netcore.extensions.nuspec" + ] + } + }, + "projectFileDependencyGroups": { + "": [ + "System.Net.Primitives >= 4.0.10-beta-*", + "System.Net.Sockets >= 4.1.0-beta-*", + "System.Security.Cryptography.X509Certificates.TestData >= 1.0.0-prerelease", + "xunit >= 2.1.0-beta3-*", + "xunit.netcore.extensions >= 1.0.0-prerelease-*" + ], + "DNXCore,Version=v5.0": [] + } +} \ No newline at end of file