Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/corefx.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Common/src/Interop/Unix/libcrypto/Interop.ASN1.cs115
-rw-r--r--src/Common/src/Interop/Unix/libcrypto/Interop.BIO.cs41
-rw-r--r--src/Common/src/Interop/Unix/libcrypto/Interop.X509Ext.cs59
-rw-r--r--src/Common/src/Interop/Windows/Crypt32/OidInfo.cs133
-rw-r--r--src/Common/src/Microsoft/Win32/SafeHandles/Asn1SafeHandles.Unix.cs71
-rw-r--r--src/Common/src/Microsoft/Win32/SafeHandles/SafeBioHandle.Unix.cs29
-rw-r--r--src/Common/src/Microsoft/Win32/SafeHandles/X509ExtensionSafeHandles.Unix.cs72
-rw-r--r--src/System.Security.Cryptography.Encoding/System.Security.Cryptography.Encoding.sln48
-rw-r--r--src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/AsnFormatter.Unix.cs14
-rw-r--r--src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/AsnFormatter.Windows.cs14
-rw-r--r--src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/AsnFormatter.cs63
-rw-r--r--src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/CngAsnFormatter.cs24
-rw-r--r--src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/Helpers.cs18
-rw-r--r--src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/OidLookup.Unix.cs75
-rw-r--r--src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/OidLookup.Windows.cs42
-rw-r--r--src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/OidLookup.cs73
-rw-r--r--src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/OpenSslAsnFormatter.cs62
-rw-r--r--src/System.Security.Cryptography.Encoding/src/Resources/Strings.resx135
-rw-r--r--src/System.Security.Cryptography.Encoding/src/System.Security.Cryptography.Encoding.csproj88
-rw-r--r--src/System.Security.Cryptography.Encoding/src/System/Security/Cryptography/AsnEncodedData.cs93
-rw-r--r--src/System.Security.Cryptography.Encoding/src/System/Security/Cryptography/Oid.cs114
-rw-r--r--src/System.Security.Cryptography.Encoding/src/System/Security/Cryptography/OidCollection.cs113
-rw-r--r--src/System.Security.Cryptography.Encoding/src/System/Security/Cryptography/OidEnumerator.cs50
-rw-r--r--src/System.Security.Cryptography.Encoding/src/System/Security/Cryptography/OidGroup.cs24
-rw-r--r--src/System.Security.Cryptography.Encoding/src/project.json13
-rw-r--r--src/System.Security.Cryptography.Encoding/tests/AsnEncodedData.cs69
-rw-r--r--src/System.Security.Cryptography.Encoding/tests/Oid.cs199
-rw-r--r--src/System.Security.Cryptography.Encoding/tests/OidCollection.cs92
-rw-r--r--src/System.Security.Cryptography.Encoding/tests/System.Security.Cryptography.Encoding.Tests.csproj27
-rw-r--r--src/System.Security.Cryptography.Encoding/tests/project.json18
30 files changed, 1988 insertions, 0 deletions
diff --git a/src/Common/src/Interop/Unix/libcrypto/Interop.ASN1.cs b/src/Common/src/Interop/Unix/libcrypto/Interop.ASN1.cs
new file mode 100644
index 0000000000..6549a3aa5f
--- /dev/null
+++ b/src/Common/src/Interop/Unix/libcrypto/Interop.ASN1.cs
@@ -0,0 +1,115 @@
+// 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.Diagnostics;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Text;
+
+using Microsoft.Win32.SafeHandles;
+
+// ASN1_INTEGER_get returns a long.
+// On Linux/MacOS x64 that means sizeof(void*)
+using NativeLong = System.IntPtr;
+
+internal static partial class Interop
+{
+ internal static partial class libcrypto
+ {
+ internal const int NID_undef = 0;
+
+ [DllImport(Libraries.LibCrypto)]
+ internal static extern NativeLong ASN1_INTEGER_get(IntPtr a);
+
+ [DllImport(Libraries.LibCrypto, CharSet = CharSet.Ansi)]
+ internal static extern SafeAsn1ObjectHandle OBJ_txt2obj(string s, [MarshalAs(UnmanagedType.Bool)] bool no_name);
+
+ [DllImport(Libraries.LibCrypto, CharSet = CharSet.Ansi)]
+ private static extern int OBJ_obj2txt(StringBuilder buf, int buf_len, IntPtr a, [MarshalAs(UnmanagedType.Bool)] bool no_name);
+
+ [DllImport(Libraries.LibCrypto, CharSet = CharSet.Ansi)]
+ internal static extern int OBJ_txt2nid(string s);
+
+ [DllImport(Libraries.LibCrypto, CharSet = CharSet.Ansi)]
+ internal static extern int OBJ_ln2nid(string ln);
+
+ [DllImport(Libraries.LibCrypto, CharSet = CharSet.Ansi)]
+ internal static extern int OBJ_sn2nid(string sn);
+
+ [DllImport(Libraries.LibCrypto, CharSet = CharSet.Ansi)]
+ internal static extern string OBJ_nid2ln(int n);
+
+ // Returns shared pointers, should not be tracked as a SafeHandle.
+ [DllImport(Libraries.LibCrypto)]
+ internal static extern IntPtr OBJ_nid2obj(int nid);
+
+ [DllImport(Libraries.LibCrypto)]
+ internal static extern void ASN1_OBJECT_free(IntPtr o);
+
+ [DllImport(Libraries.LibCrypto)]
+ internal static unsafe extern SafeAsn1BitStringHandle d2i_ASN1_BIT_STRING(IntPtr zero, byte** ppin, int len);
+
+ [DllImport(Libraries.LibCrypto)]
+ internal static extern void ASN1_BIT_STRING_free(IntPtr o);
+
+ [DllImport(Libraries.LibCrypto)]
+ internal static unsafe extern SafeAsn1OctetStringHandle d2i_ASN1_OCTET_STRING(IntPtr zero, byte** ppin, int len);
+
+ [DllImport(Libraries.LibCrypto)]
+ internal static extern SafeAsn1OctetStringHandle ASN1_OCTET_STRING_new();
+
+ [DllImport(Libraries.LibCrypto)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool ASN1_OCTET_STRING_set(SafeAsn1OctetStringHandle o, byte[] d, int len);
+
+ [DllImport(Libraries.LibCrypto)]
+ internal static extern void ASN1_OCTET_STRING_free(IntPtr o);
+
+ internal static string OBJ_obj2txt_helper(IntPtr asn1ObjectPtr)
+ {
+ // OBJ_obj2txt returns the number of bytes that should have been in the answer, but it does not accept
+ // a NULL buffer. The documentation says "A buffer length of 80 should be more than enough to handle
+ // any OID encountered in practice", so start with a buffer of size 80, and try again if required.
+ // Therefore, 512 should be quite sufficient.
+ StringBuilder buf = new StringBuilder(80);
+
+ int bytesNeeded = OBJ_obj2txt(buf, buf.Capacity, asn1ObjectPtr, true);
+
+ if (bytesNeeded < 0)
+ {
+ throw new CryptographicException(GetOpenSslErrorString());
+ }
+
+ Debug.Assert(bytesNeeded != 0, "OBJ_obj2txt reported a zero-length response");
+
+ if (bytesNeeded >= buf.Capacity)
+ {
+ int initialBytesNeeded = bytesNeeded;
+
+ // bytesNeeded does not count the \0 which will be written on the end (based on OpenSSL 1.0.1f),
+ // so make sure to leave room for it.
+ buf.EnsureCapacity(bytesNeeded + 1);
+
+ bytesNeeded = OBJ_obj2txt(buf, buf.Capacity, asn1ObjectPtr, true);
+
+ if (bytesNeeded < 0)
+ {
+ throw new CryptographicException(GetOpenSslErrorString());
+ }
+
+ Debug.Assert(
+ bytesNeeded == initialBytesNeeded,
+ "OBJ_obj2txt changed the required number of bytes for the realloc call");
+
+ if (bytesNeeded >= buf.Capacity)
+ {
+ // OBJ_obj2txt is demanding yet more memory
+ throw new CryptographicException();
+ }
+ }
+
+ return buf.ToString();
+ }
+ }
+}
diff --git a/src/Common/src/Interop/Unix/libcrypto/Interop.BIO.cs b/src/Common/src/Interop/Unix/libcrypto/Interop.BIO.cs
new file mode 100644
index 0000000000..4760e1bafc
--- /dev/null
+++ b/src/Common/src/Interop/Unix/libcrypto/Interop.BIO.cs
@@ -0,0 +1,41 @@
+// 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;
+using System.Text;
+
+using Microsoft.Win32.SafeHandles;
+
+using NativeLong=System.IntPtr;
+
+internal static partial class Interop
+{
+ internal static partial class libcrypto
+ {
+ private const int BIO_CTRL_INFO = 3;
+
+ [DllImport(Libraries.LibCrypto)]
+ internal static extern SafeBioHandle BIO_new(IntPtr type);
+
+ [DllImport(Libraries.LibCrypto)]
+ internal static extern IntPtr BIO_s_mem();
+
+ [DllImport(Libraries.LibCrypto)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool BIO_free(IntPtr a);
+
+ [DllImport(Libraries.LibCrypto, CharSet = CharSet.Ansi)]
+ internal static extern int BIO_gets(SafeBioHandle b, StringBuilder buf, int size);
+
+ [DllImport(Libraries.LibCrypto)]
+ private static extern NativeLong BIO_ctrl(SafeBioHandle bio, int cmd, NativeLong larg, IntPtr parg);
+
+ internal static int GetMemoryBioSize(SafeBioHandle bio)
+ {
+ // This method is equivalent to BIO_get_mem_data(bio, NULL), except not a macro,
+ // and doesn't expose the NULL.
+ return BIO_ctrl(bio, BIO_CTRL_INFO, IntPtr.Zero, IntPtr.Zero).ToInt32();
+ }
+ }
+}
diff --git a/src/Common/src/Interop/Unix/libcrypto/Interop.X509Ext.cs b/src/Common/src/Interop/Unix/libcrypto/Interop.X509Ext.cs
new file mode 100644
index 0000000000..e18ac1c2bc
--- /dev/null
+++ b/src/Common/src/Interop/Unix/libcrypto/Interop.X509Ext.cs
@@ -0,0 +1,59 @@
+// 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;
+
+using Microsoft.Win32.SafeHandles;
+
+internal static partial class Interop
+{
+ internal static partial class libcrypto
+ {
+ [DllImport(Libraries.LibCrypto)]
+ internal static extern SafeX509ExtensionHandle X509_EXTENSION_create_by_OBJ(
+ IntPtr zero,
+ SafeAsn1ObjectHandle oid,
+ [MarshalAs(UnmanagedType.Bool)] bool critical,
+ SafeAsn1OctetStringHandle data);
+
+ [DllImport(Libraries.LibCrypto)]
+ internal static extern int X509_EXTENSION_free(IntPtr x);
+
+ [DllImport(Libraries.LibCrypto)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool X509V3_EXT_print(SafeBioHandle buf, SafeX509ExtensionHandle ext, X509V3ExtPrintFlags flags, int indent);
+
+ [DllImport(Libraries.LibCrypto)]
+ internal static unsafe extern SafeBasicConstraintsHandle d2i_BASIC_CONSTRAINTS(IntPtr zero, byte** ppin, int len);
+
+ [DllImport(Libraries.LibCrypto)]
+ internal static extern void BASIC_CONSTRAINTS_free(IntPtr a);
+
+ [DllImport(Libraries.LibCrypto)]
+ internal static unsafe extern SafeEkuExtensionHandle d2i_EXTENDED_KEY_USAGE(IntPtr zero, byte** ppin, int len);
+
+ [DllImport(Libraries.LibCrypto)]
+ internal static extern void EXTENDED_KEY_USAGE_free(IntPtr a);
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct BASIC_CONSTRAINTS
+ {
+ // This is a boolean, but [MarshalAs(UnmanagedType.Bool)] produced a "true != true" answer.
+ internal int CA;
+ internal IntPtr pathlen;
+ }
+
+ // As of 2015-04-11 there is no documentation on openssl.org or within the header files
+ // which describes possible values of "flags" to X509V3_EXT_print.
+ //
+ // The flag which would be the most likely candidate is X509V3_EXT_MULTILINE, but that is a
+ // flag on the extension definition (and a test call providing that value had no discernable
+ // effect on OpenSSL 1.0.1f).
+ [Flags]
+ internal enum X509V3ExtPrintFlags
+ {
+ None = 0,
+ }
+ }
+}
diff --git a/src/Common/src/Interop/Windows/Crypt32/OidInfo.cs b/src/Common/src/Interop/Windows/Crypt32/OidInfo.cs
new file mode 100644
index 0000000000..a8a320bc5b
--- /dev/null
+++ b/src/Common/src/Interop/Windows/Crypt32/OidInfo.cs
@@ -0,0 +1,133 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using global::System;
+using global::System.Text;
+using global::System.Diagnostics;
+using global::System.Diagnostics.Contracts;
+using global::System.Collections.Generic;
+using global::System.Security.Cryptography;
+using global::System.Runtime.InteropServices;
+
+namespace Internal.NativeCrypto
+{
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct CRYPT_OID_INFO
+ {
+ public int cbSize;
+ public IntPtr pszOID;
+ public IntPtr pwszName;
+ public OidGroup dwGroupId;
+ public int AlgId;
+ public int cbData;
+ public IntPtr pbData;
+
+ public String OID
+ {
+ get
+ {
+ return Marshal.PtrToStringAnsi(pszOID);
+ }
+ }
+
+ public String Name
+ {
+ get
+ {
+ return Marshal.PtrToStringUni(pwszName);
+ }
+ }
+ }
+
+ internal enum CryptOidInfoKeyType : int
+ {
+ CRYPT_OID_INFO_OID_KEY = 1,
+ CRYPT_OID_INFO_NAME_KEY = 2,
+ CRYPT_OID_INFO_ALGID_KEY = 3,
+ }
+
+ internal static partial class OidInfo
+ {
+ private const String Capi2Dll = "Crypt32.dll";
+
+ public static CRYPT_OID_INFO FindOidInfo(CryptOidInfoKeyType keyType, String key, OidGroup group, bool fallBackToAllGroups)
+ {
+ const OidGroup CRYPT_OID_DISABLE_SEARCH_DS_FLAG = unchecked((OidGroup)0x80000000);
+ Debug.Assert(key != null);
+
+ IntPtr rawKey = IntPtr.Zero;
+
+ try
+ {
+ if (keyType == CryptOidInfoKeyType.CRYPT_OID_INFO_OID_KEY)
+ {
+ rawKey = Marshal.StringToCoTaskMemAnsi(key);
+ }
+ else if (keyType == CryptOidInfoKeyType.CRYPT_OID_INFO_NAME_KEY)
+ {
+ rawKey = Marshal.StringToCoTaskMemUni(key);
+ }
+ else
+ {
+ throw new NotSupportedException();
+ }
+
+ // If the group alone isn't sufficient to suppress an active directory lookup, then our
+ // first attempt should also include the suppression flag
+ if (!OidGroupWillNotUseActiveDirectory(group))
+ {
+ OidGroup localGroup = group | CRYPT_OID_DISABLE_SEARCH_DS_FLAG;
+ IntPtr localOidInfo = CryptFindOIDInfo(keyType, rawKey, localGroup);
+ if (localOidInfo != IntPtr.Zero)
+ {
+ return (CRYPT_OID_INFO)Marshal.PtrToStructure(localOidInfo, typeof(CRYPT_OID_INFO));
+ }
+ }
+
+ // Attempt to query with a specific group, to make try to avoid an AD lookup if possible
+ IntPtr fullOidInfo = CryptFindOIDInfo(keyType, rawKey, group);
+ if (fullOidInfo != IntPtr.Zero)
+ {
+ return (CRYPT_OID_INFO)Marshal.PtrToStructure(fullOidInfo, typeof(CRYPT_OID_INFO));
+ }
+
+ if (fallBackToAllGroups && group != OidGroup.All)
+ {
+ // Finally, for compatibility with previous runtimes, if we have a group specified retry the
+ // query with no group
+ IntPtr allGroupOidInfo = CryptFindOIDInfo(keyType, rawKey, OidGroup.All);
+ if (allGroupOidInfo != IntPtr.Zero)
+ {
+ return (CRYPT_OID_INFO)Marshal.PtrToStructure(fullOidInfo, typeof(CRYPT_OID_INFO));
+ }
+ }
+
+ // Otherwise the lookup failed.
+ return new CRYPT_OID_INFO() { AlgId = -1 };
+ }
+ finally
+ {
+ if (rawKey != IntPtr.Zero)
+ {
+ Marshal.FreeCoTaskMem(rawKey);
+ }
+ }
+ }
+
+ private static bool OidGroupWillNotUseActiveDirectory(OidGroup group)
+ {
+ // These groups will never cause an Active Directory query
+ return group == OidGroup.HashAlgorithm ||
+ group == OidGroup.EncryptionAlgorithm ||
+ group == OidGroup.PublicKeyAlgorithm ||
+ group == OidGroup.SignatureAlgorithm ||
+ group == OidGroup.Attribute ||
+ group == OidGroup.ExtensionOrAttribute ||
+ group == OidGroup.KeyDerivationFunction;
+ }
+
+ [DllImport(Capi2Dll, CharSet = CharSet.Unicode)]
+ private static extern IntPtr CryptFindOIDInfo(CryptOidInfoKeyType dwKeyType, IntPtr pvKey, OidGroup group);
+ }
+}
+
diff --git a/src/Common/src/Microsoft/Win32/SafeHandles/Asn1SafeHandles.Unix.cs b/src/Common/src/Microsoft/Win32/SafeHandles/Asn1SafeHandles.Unix.cs
new file mode 100644
index 0000000000..e23df85837
--- /dev/null
+++ b/src/Common/src/Microsoft/Win32/SafeHandles/Asn1SafeHandles.Unix.cs
@@ -0,0 +1,71 @@
+// 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;
+using System.Security;
+
+namespace Microsoft.Win32.SafeHandles
+{
+ [SecurityCritical]
+ internal sealed class SafeAsn1ObjectHandle : SafeHandle
+ {
+ private SafeAsn1ObjectHandle() :
+ base(IntPtr.Zero, ownsHandle: true)
+ {
+ }
+
+ protected override bool ReleaseHandle()
+ {
+ Interop.libcrypto.ASN1_OBJECT_free(handle);
+ SetHandle(IntPtr.Zero);
+ return true;
+ }
+
+ public override bool IsInvalid
+ {
+ get { return handle == IntPtr.Zero; }
+ }
+ }
+
+ [SecurityCritical]
+ internal sealed class SafeAsn1BitStringHandle : SafeHandle
+ {
+ private SafeAsn1BitStringHandle() :
+ base(IntPtr.Zero, ownsHandle: true)
+ {
+ }
+
+ protected override bool ReleaseHandle()
+ {
+ Interop.libcrypto.ASN1_BIT_STRING_free(handle);
+ SetHandle(IntPtr.Zero);
+ return true;
+ }
+
+ public override bool IsInvalid
+ {
+ get { return handle == IntPtr.Zero; }
+ }
+ }
+
+ [SecurityCritical]
+ internal sealed class SafeAsn1OctetStringHandle : SafeHandle
+ {
+ private SafeAsn1OctetStringHandle() :
+ base(IntPtr.Zero, ownsHandle: true)
+ {
+ }
+
+ protected override bool ReleaseHandle()
+ {
+ Interop.libcrypto.ASN1_OCTET_STRING_free(handle);
+ return true;
+ }
+
+ public override bool IsInvalid
+ {
+ get { return handle == IntPtr.Zero; }
+ }
+ }
+}
diff --git a/src/Common/src/Microsoft/Win32/SafeHandles/SafeBioHandle.Unix.cs b/src/Common/src/Microsoft/Win32/SafeHandles/SafeBioHandle.Unix.cs
new file mode 100644
index 0000000000..caf0cb7d01
--- /dev/null
+++ b/src/Common/src/Microsoft/Win32/SafeHandles/SafeBioHandle.Unix.cs
@@ -0,0 +1,29 @@
+// 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.Security;
+using System.Runtime.InteropServices;
+
+namespace Microsoft.Win32.SafeHandles
+{
+ [SecurityCritical]
+ internal sealed class SafeBioHandle : SafeHandle
+ {
+ private SafeBioHandle() :
+ base(IntPtr.Zero, ownsHandle: true)
+ {
+ }
+
+ protected override bool ReleaseHandle()
+ {
+ Interop.libcrypto.BIO_free(handle);
+ return true;
+ }
+
+ public override bool IsInvalid
+ {
+ get { return handle == IntPtr.Zero; }
+ }
+ }
+}
diff --git a/src/Common/src/Microsoft/Win32/SafeHandles/X509ExtensionSafeHandles.Unix.cs b/src/Common/src/Microsoft/Win32/SafeHandles/X509ExtensionSafeHandles.Unix.cs
new file mode 100644
index 0000000000..a18a278a1f
--- /dev/null
+++ b/src/Common/src/Microsoft/Win32/SafeHandles/X509ExtensionSafeHandles.Unix.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;
+using System.Runtime.InteropServices;
+using System.Security;
+
+namespace Microsoft.Win32.SafeHandles
+{
+ [SecurityCritical]
+ internal sealed class SafeX509ExtensionHandle : SafeHandle
+ {
+ private SafeX509ExtensionHandle() :
+ base(IntPtr.Zero, ownsHandle: true)
+ {
+ }
+
+ protected override bool ReleaseHandle()
+ {
+ Interop.libcrypto.X509_EXTENSION_free(handle);
+ SetHandle(IntPtr.Zero);
+ return true;
+ }
+
+ public override bool IsInvalid
+ {
+ get { return handle == IntPtr.Zero; }
+ }
+ }
+
+ [SecurityCritical]
+ internal sealed class SafeBasicConstraintsHandle : SafeHandle
+ {
+ private SafeBasicConstraintsHandle() :
+ base(IntPtr.Zero, ownsHandle: true)
+ {
+ }
+
+ protected override bool ReleaseHandle()
+ {
+ Interop.libcrypto.BASIC_CONSTRAINTS_free(handle);
+ SetHandle(IntPtr.Zero);
+ return true;
+ }
+
+ public override bool IsInvalid
+ {
+ get { return handle == IntPtr.Zero; }
+ }
+ }
+
+ [SecurityCritical]
+ internal sealed class SafeEkuExtensionHandle : SafeHandle
+ {
+ private SafeEkuExtensionHandle() :
+ base(IntPtr.Zero, ownsHandle: true)
+ {
+ }
+
+ protected override bool ReleaseHandle()
+ {
+ Interop.libcrypto.EXTENDED_KEY_USAGE_free(handle);
+ SetHandle(IntPtr.Zero);
+ return true;
+ }
+
+ public override bool IsInvalid
+ {
+ get { return handle == IntPtr.Zero; }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/System.Security.Cryptography.Encoding/System.Security.Cryptography.Encoding.sln b/src/System.Security.Cryptography.Encoding/System.Security.Cryptography.Encoding.sln
new file mode 100644
index 0000000000..237228d4b5
--- /dev/null
+++ b/src/System.Security.Cryptography.Encoding/System.Security.Cryptography.Encoding.sln
@@ -0,0 +1,48 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 14
+VisualStudioVersion = 14.0.22911.2
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Security.Cryptography.Encoding", "src\System.Security.Cryptography.Encoding.csproj", "{AA81E343-5E54-40B0-9381-C459419BE780}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Security.Cryptography.Encoding.Tests", "tests\System.Security.Cryptography.Encoding.Tests.csproj", "{0581E9FA-D639-4B88-96D8-D092760F90B0}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Linux_Debug|Any CPU = Linux_Debug|Any CPU
+ Linux_Release|Any CPU = Linux_Release|Any CPU
+ OSX_Debug|Any CPU = OSX_Debug|Any CPU
+ OSX_Release|Any CPU = OSX_Release|Any CPU
+ Windows_Debug|Any CPU = Windows_Debug|Any CPU
+ Windows_Release|Any CPU = Windows_Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {AA81E343-5E54-40B0-9381-C459419BE780}.Linux_Debug|Any CPU.ActiveCfg = Linux_Debug|Any CPU
+ {AA81E343-5E54-40B0-9381-C459419BE780}.Linux_Debug|Any CPU.Build.0 = Linux_Debug|Any CPU
+ {AA81E343-5E54-40B0-9381-C459419BE780}.Linux_Release|Any CPU.ActiveCfg = Linux_Release|Any CPU
+ {AA81E343-5E54-40B0-9381-C459419BE780}.Linux_Release|Any CPU.Build.0 = Linux_Release|Any CPU
+ {AA81E343-5E54-40B0-9381-C459419BE780}.OSX_Debug|Any CPU.ActiveCfg = OSX_Debug|Any CPU
+ {AA81E343-5E54-40B0-9381-C459419BE780}.OSX_Debug|Any CPU.Build.0 = OSX_Debug|Any CPU
+ {AA81E343-5E54-40B0-9381-C459419BE780}.OSX_Release|Any CPU.ActiveCfg = OSX_Release|Any CPU
+ {AA81E343-5E54-40B0-9381-C459419BE780}.OSX_Release|Any CPU.Build.0 = OSX_Release|Any CPU
+ {AA81E343-5E54-40B0-9381-C459419BE780}.Windows_Debug|Any CPU.ActiveCfg = Windows_Debug|Any CPU
+ {AA81E343-5E54-40B0-9381-C459419BE780}.Windows_Debug|Any CPU.Build.0 = Windows_Debug|Any CPU
+ {AA81E343-5E54-40B0-9381-C459419BE780}.Windows_Release|Any CPU.ActiveCfg = Windows_Release|Any CPU
+ {AA81E343-5E54-40B0-9381-C459419BE780}.Windows_Release|Any CPU.Build.0 = Windows_Release|Any CPU
+ {0581E9FA-D639-4B88-96D8-D092760F90B0}.Linux_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0581E9FA-D639-4B88-96D8-D092760F90B0}.Linux_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0581E9FA-D639-4B88-96D8-D092760F90B0}.Linux_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {0581E9FA-D639-4B88-96D8-D092760F90B0}.Linux_Release|Any CPU.Build.0 = Debug|Any CPU
+ {0581E9FA-D639-4B88-96D8-D092760F90B0}.OSX_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0581E9FA-D639-4B88-96D8-D092760F90B0}.OSX_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0581E9FA-D639-4B88-96D8-D092760F90B0}.OSX_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {0581E9FA-D639-4B88-96D8-D092760F90B0}.OSX_Release|Any CPU.Build.0 = Debug|Any CPU
+ {0581E9FA-D639-4B88-96D8-D092760F90B0}.Windows_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0581E9FA-D639-4B88-96D8-D092760F90B0}.Windows_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0581E9FA-D639-4B88-96D8-D092760F90B0}.Windows_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {0581E9FA-D639-4B88-96D8-D092760F90B0}.Windows_Release|Any CPU.Build.0 = Debug|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/AsnFormatter.Unix.cs b/src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/AsnFormatter.Unix.cs
new file mode 100644
index 0000000000..87986509c5
--- /dev/null
+++ b/src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/AsnFormatter.Unix.cs
@@ -0,0 +1,14 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+namespace Internal.Cryptography
+{
+ internal abstract partial class AsnFormatter
+ {
+ private static readonly AsnFormatter s_instance = new OpenSslAsnFormatter();
+
+ // -----------------------------
+ // ---- PAL layer ends here ----
+ // -----------------------------
+ }
+} \ No newline at end of file
diff --git a/src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/AsnFormatter.Windows.cs b/src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/AsnFormatter.Windows.cs
new file mode 100644
index 0000000000..041a561d28
--- /dev/null
+++ b/src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/AsnFormatter.Windows.cs
@@ -0,0 +1,14 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+namespace Internal.Cryptography
+{
+ internal abstract partial class AsnFormatter
+ {
+ private static readonly AsnFormatter s_instance = new CngAsnFormatter();
+
+ // -----------------------------
+ // ---- PAL layer ends here ----
+ // -----------------------------
+ }
+} \ No newline at end of file
diff --git a/src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/AsnFormatter.cs b/src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/AsnFormatter.cs
new file mode 100644
index 0000000000..faf799d9e0
--- /dev/null
+++ b/src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/AsnFormatter.cs
@@ -0,0 +1,63 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System.Security.Cryptography;
+
+namespace Internal.Cryptography
+{
+ internal abstract partial class AsnFormatter
+ {
+ private static readonly char[] s_hexValues =
+ { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+
+ internal static AsnFormatter Instance { get { return s_instance; } }
+
+ public string Format(Oid oid, byte[] rawData, bool multiLine)
+ {
+ return FormatNative(oid, rawData, multiLine) ?? EncodeHexString(rawData);
+ }
+
+ protected abstract string FormatNative(Oid oid, byte[] rawData, bool multiLine);
+
+ protected static string EncodeHexString(byte[] sArray, bool spaceSeparated = false)
+ {
+ return EncodeHexString(sArray, 0, (uint)sArray.Length, spaceSeparated);
+ }
+
+ private static string EncodeHexString(byte[] sArray, uint start, uint end, bool spaceSeparated)
+ {
+ string result = null;
+
+ if (sArray != null)
+ {
+ uint len = (end - start) * 2;
+
+ if (spaceSeparated)
+ {
+ // There will be n-1 spaces between n bytes.
+ len += (end - start - 1);
+ }
+
+ char[] hexOrder = new char[len];
+
+ for (uint i = start, j = 0; i < end; i++)
+ {
+ if (spaceSeparated && i > start)
+ {
+ hexOrder[j++] = ' ';
+ }
+
+ uint digit = (uint)((sArray[i] & 0xf0) >> 4);
+ hexOrder[j++] = s_hexValues[digit];
+
+ digit = (uint)(sArray[i] & 0x0f);
+ hexOrder[j++] = s_hexValues[digit];
+ }
+
+ result = new string(hexOrder);
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/CngAsnFormatter.cs b/src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/CngAsnFormatter.cs
new file mode 100644
index 0000000000..3d51a5e06b
--- /dev/null
+++ b/src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/CngAsnFormatter.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;
+using System.Security.Cryptography;
+
+using Internal.NativeCrypto;
+
+namespace Internal.Cryptography
+{
+ internal sealed class CngAsnFormatter : AsnFormatter
+ {
+ protected override string FormatNative(Oid oid, byte[] rawData, bool multiLine)
+ {
+ // If OID is not present, then we can force CryptFormatObject
+ // to use hex formatting by providing an empty OID string.
+ String oidValue = String.Empty;
+ if (oid != null && oid.Value != null)
+ oidValue = oid.Value;
+
+ return Cng.CryptFormatObject(oidValue, rawData, multiLine);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/Helpers.cs b/src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/Helpers.cs
new file mode 100644
index 0000000000..a9c72e3708
--- /dev/null
+++ b/src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/Helpers.cs
@@ -0,0 +1,18 @@
+// 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.Diagnostics;
+using System.Security.Cryptography;
+
+namespace Internal.Cryptography
+{
+ internal static class Helpers
+ {
+ public static byte[] CloneByteArray(this byte[] src)
+ {
+ return (byte[])(src.Clone());
+ }
+ }
+}
+
diff --git a/src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/OidLookup.Unix.cs b/src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/OidLookup.Unix.cs
new file mode 100644
index 0000000000..d7afa49349
--- /dev/null
+++ b/src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/OidLookup.Unix.cs
@@ -0,0 +1,75 @@
+// 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.Security.Cryptography;
+using System.Text;
+
+namespace Internal.Cryptography
+{
+ internal static partial class OidLookup
+ {
+ private static string NativeOidToFriendlyName(string oid, OidGroup oidGroup, bool fallBackToAllGroups)
+ {
+ // We're going to call OBJ_txt2nid, then OBJ_nid2obj. Anyone proficient in factor/label reduction
+ // would see that this should be equivalent to OBJ_txt2obj, but it isn't.
+ //
+ // OBJ_txt2obj, when given an OID value dotted string will decode the dotted string and return
+ // a blank(ish) object (which would need to be freed). We could then pass that to OBJ_obj2nid to
+ // look up the internal identifier. Then, if we got a NID which wasn't NID_undef we would know
+ // there was a match, and could call OBJ_nid2obj to get the shared pointer to the definition.
+ //
+ // In this case, the composition of functions that we want is OBJ_obj2nid(OBJ_txt2obj) => OBJ_txt2nid.
+
+ int nid = Interop.libcrypto.OBJ_txt2nid(oid);
+
+ if (nid == Interop.libcrypto.NID_undef)
+ {
+ return null;
+ }
+
+ return Interop.libcrypto.OBJ_nid2ln(nid);
+ }
+
+ private static string NativeFriendlyNameToOid(string friendlyName, OidGroup oidGroup, bool fallBackToAllGroups)
+ {
+ int nid = Interop.libcrypto.OBJ_ln2nid(friendlyName);
+
+ if (nid == Interop.libcrypto.NID_undef)
+ {
+ nid = Interop.libcrypto.OBJ_sn2nid(friendlyName);
+ }
+
+ if (nid == Interop.libcrypto.NID_undef)
+ {
+ return null;
+ }
+
+ IntPtr sharedObject = Interop.libcrypto.OBJ_nid2obj(nid);
+
+ if (sharedObject == IntPtr.Zero)
+ {
+ return null;
+ }
+
+ return Interop.libcrypto.OBJ_obj2txt_helper(sharedObject);
+ }
+
+ private static string FindFriendlyNameAlias(string userValue)
+ {
+ foreach (FriendlyNameAlias alias in s_friendlyNameAliases)
+ {
+ if (userValue.Equals(alias.Windows, StringComparison.OrdinalIgnoreCase))
+ {
+ return alias.OpenSsl;
+ }
+ }
+
+ return null;
+ }
+
+ // -----------------------------
+ // ---- PAL layer ends here ----
+ // -----------------------------
+ }
+} \ No newline at end of file
diff --git a/src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/OidLookup.Windows.cs b/src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/OidLookup.Windows.cs
new file mode 100644
index 0000000000..ad6d19d897
--- /dev/null
+++ b/src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/OidLookup.Windows.cs
@@ -0,0 +1,42 @@
+// 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.Security.Cryptography;
+
+using Internal.NativeCrypto;
+
+namespace Internal.Cryptography
+{
+ internal static partial class OidLookup
+ {
+ private static string NativeOidToFriendlyName(string oid, OidGroup oidGroup, bool fallBackToAllGroups)
+ {
+ CRYPT_OID_INFO oidInfo = OidInfo.FindOidInfo(CryptOidInfoKeyType.CRYPT_OID_INFO_OID_KEY, oid, oidGroup, fallBackToAllGroups);
+ return oidInfo.Name;
+ }
+
+ private static string NativeFriendlyNameToOid(string friendlyName, OidGroup oidGroup, bool fallBackToAllGroups)
+ {
+ CRYPT_OID_INFO oidInfo = OidInfo.FindOidInfo(CryptOidInfoKeyType.CRYPT_OID_INFO_NAME_KEY, friendlyName, oidGroup, fallBackToAllGroups);
+ return oidInfo.OID;
+ }
+
+ private static string FindFriendlyNameAlias(string userValue)
+ {
+ foreach (FriendlyNameAlias alias in s_friendlyNameAliases)
+ {
+ if (userValue.Equals(alias.OpenSsl, StringComparison.OrdinalIgnoreCase))
+ {
+ return alias.Windows;
+ }
+ }
+
+ return null;
+ }
+
+ // -----------------------------
+ // ---- PAL layer ends here ----
+ // -----------------------------
+ }
+} \ No newline at end of file
diff --git a/src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/OidLookup.cs b/src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/OidLookup.cs
new file mode 100644
index 0000000000..44ec448233
--- /dev/null
+++ b/src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/OidLookup.cs
@@ -0,0 +1,73 @@
+// 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.Security.Cryptography;
+
+namespace Internal.Cryptography
+{
+ internal static partial class OidLookup
+ {
+ private struct FriendlyNameAlias
+ {
+ internal string Windows { get; set; }
+ internal string OpenSsl { get; set; }
+ }
+
+ // The Windows cryptography API "Friendly Names" don't use the same name as the OIDs were given
+ // in their declaring RFCs. If a .NET developer learned to call the algorithm "sha1RSA" then we
+ // want to understand that it should be called "sha1WithRSAEncryption" when calling into OpenSSL.
+ //
+ // The canonical form of the Windows versions come from https://msdn.microsoft.com/en-us/library/ff635603.aspx
+ private static readonly FriendlyNameAlias[] s_friendlyNameAliases =
+ {
+ new FriendlyNameAlias { Windows = "RSA", OpenSsl = "rsaEncryption" }, // RFC 2313
+ new FriendlyNameAlias { Windows = "md2RSA", OpenSsl = "md2WithRSAEncryption" }, // RFC 2313
+ new FriendlyNameAlias { Windows = "md4RSA", OpenSsl = "md4WithRSAEncryption" }, // RFC 2313
+ new FriendlyNameAlias { Windows = "md5RSA", OpenSsl = "md5WithRSAEncryption" }, // RFC 2313
+ new FriendlyNameAlias { Windows = "sha1RSA", OpenSsl = "sha1WithRSAEncryption" }, // RFC 3447
+ new FriendlyNameAlias { Windows = "sha256RSA", OpenSsl = "sha256WithRSAEncryption" }, // RFC 3447
+ new FriendlyNameAlias { Windows = "sha384RSA", OpenSsl = "sha384WithRSAEncryption" }, // RFC 3447
+ new FriendlyNameAlias { Windows = "sha512RSA", OpenSsl = "sha512WithRSAEncryption" }, // RFC 3447
+
+ new FriendlyNameAlias { Windows = "DSA", OpenSsl = "dsaEncryption" }, // RFC 3370 calls this "id-dsa"
+ new FriendlyNameAlias { Windows = "sha1DSA", OpenSsl = "dsaWithSHA1" }, // RFC 3370 calls this "id-dsa-with-sha1"
+
+ // We can keep going for as many things as we want to support.
+ };
+
+ //
+ // Attempts to map a friendly name to an OID. Returns null if not a known name.
+ //
+ public static string ToFriendlyName(string oid, OidGroup oidGroup, bool fallBackToAllGroups)
+ {
+ if (oid == null)
+ throw new ArgumentNullException("oid");
+
+ return NativeOidToFriendlyName(oid, oidGroup, fallBackToAllGroups);
+ }
+
+ //
+ // Attempts to retrieve the friendly name for an OID. Returns null if not a known or valid OID.
+ //
+ public static string ToOid(string friendlyName, OidGroup oidGroup, bool fallBackToAllGroups)
+ {
+ if (friendlyName == null)
+ throw new ArgumentNullException("friendlyName");
+
+ string oid = NativeFriendlyNameToOid(friendlyName, oidGroup, fallBackToAllGroups);
+
+ if (oid == null)
+ {
+ string alias = FindFriendlyNameAlias(friendlyName);
+
+ if (alias != null)
+ {
+ oid = NativeFriendlyNameToOid(alias, oidGroup, fallBackToAllGroups);
+ }
+ }
+
+ return oid;
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/OpenSslAsnFormatter.cs b/src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/OpenSslAsnFormatter.cs
new file mode 100644
index 0000000000..5cc86d023c
--- /dev/null
+++ b/src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/OpenSslAsnFormatter.cs
@@ -0,0 +1,62 @@
+// 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.Security.Cryptography;
+using System.Text;
+
+using Microsoft.Win32.SafeHandles;
+
+namespace Internal.Cryptography
+{
+ internal sealed class OpenSslAsnFormatter : AsnFormatter
+ {
+ protected override string FormatNative(Oid oid, byte[] rawData, bool multiLine)
+ {
+ if (oid == null || string.IsNullOrEmpty(oid.Value))
+ {
+ return EncodeHexString(rawData, true);
+ }
+
+ // The established behavior for this method is to return the native answer, if possible,
+ // or to return null and let rawData get hex-encoded. CryptographicException should not
+ // be raised.
+
+ using (SafeAsn1ObjectHandle asnOid = Interop.libcrypto.OBJ_txt2obj(oid.Value, true))
+ using (SafeAsn1OctetStringHandle octetString = Interop.libcrypto.ASN1_OCTET_STRING_new())
+ {
+ if (asnOid.IsInvalid || octetString.IsInvalid)
+ {
+ return null;
+ }
+
+ if (!Interop.libcrypto.ASN1_OCTET_STRING_set(octetString, rawData, rawData.Length))
+ {
+ return null;
+ }
+
+ using (SafeBioHandle bio = Interop.libcrypto.BIO_new(Interop.libcrypto.BIO_s_mem()))
+ using (SafeX509ExtensionHandle x509Ext = Interop.libcrypto.X509_EXTENSION_create_by_OBJ(IntPtr.Zero, asnOid, false, octetString))
+ {
+ if (bio.IsInvalid || x509Ext.IsInvalid)
+ {
+ return null;
+ }
+
+ if (!Interop.libcrypto.X509V3_EXT_print(bio, x509Ext, Interop.libcrypto.X509V3ExtPrintFlags.None, 0))
+ {
+ return null;
+ }
+
+ int printLen = Interop.libcrypto.GetMemoryBioSize(bio);
+
+ // Account for the null terminator that it'll want to write.
+ StringBuilder builder = new StringBuilder(printLen + 1);
+ Interop.libcrypto.BIO_gets(bio, builder, builder.Capacity);
+
+ return builder.ToString();
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/System.Security.Cryptography.Encoding/src/Resources/Strings.resx b/src/System.Security.Cryptography.Encoding/src/Resources/Strings.resx
new file mode 100644
index 0000000000..c7396653a9
--- /dev/null
+++ b/src/System.Security.Cryptography.Encoding/src/Resources/Strings.resx
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" use="required" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <data name="Cryptography_Oid_InvalidValue" xml:space="preserve">
+ <value>The OID value is invalid.</value>
+ </data>
+ <data name="Cryptography_Oid_InvalidName" xml:space="preserve">
+ <value>No OID value matches this name.</value>
+ </data>
+ <data name="Arg_RankMultiDimNotSupported" xml:space="preserve">
+ <value>Only single dimensional arrays are supported for the requested action.</value>
+ </data>
+ <data name="ArgumentOutOfRange_Index" xml:space="preserve">
+ <value>Index was out of range. Must be non-negative and less than the size of the collection.</value>
+ </data>
+ <data name="Argument_InvalidOffLen" xml:space="preserve">
+ <value>Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection.</value>
+ </data>
+</root> \ No newline at end of file
diff --git a/src/System.Security.Cryptography.Encoding/src/System.Security.Cryptography.Encoding.csproj b/src/System.Security.Cryptography.Encoding/src/System.Security.Cryptography.Encoding.csproj
new file mode 100644
index 0000000000..96e5c2f4e8
--- /dev/null
+++ b/src/System.Security.Cryptography.Encoding/src/System.Security.Cryptography.Encoding.csproj
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Windows_Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{AA81E343-5E54-40B0-9381-C459419BE780}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AssemblyName>System.Security.Cryptography.Encoding</AssemblyName>
+ <AssemblyVersion>4.0.0.0</AssemblyVersion>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <CLSCompliant>false</CLSCompliant>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Linux_Debug|AnyCPU' " />
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Linux_Release|AnyCPU' " />
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'OSX_Debug|AnyCPU' " />
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'OSX_Release|AnyCPU' " />
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Windows_Debug|AnyCPU' " />
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Windows_Release|AnyCPU' " />
+ <ItemGroup>
+ <Compile Include="Internal\Cryptography\AsnFormatter.cs" />
+ <Compile Include="Internal\Cryptography\Helpers.cs" />
+ <Compile Include="Internal\Cryptography\OidLookup.cs" />
+ <Compile Include="System\Security\Cryptography\AsnEncodedData.cs" />
+ <Compile Include="System\Security\Cryptography\Oid.cs" />
+ <Compile Include="System\Security\Cryptography\OidCollection.cs" />
+ <Compile Include="System\Security\Cryptography\OidEnumerator.cs" />
+ <Compile Include="System\Security\Cryptography\OidGroup.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="$(CommonPath)\System\ArrayT.cs">
+ <Link>Common\System\ArrayT.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Collections\Generic\LowLevelList.cs">
+ <Link>Common\System\Collections\Generic\LowLevelList.cs</Link>
+ </Compile>
+ </ItemGroup>
+ <ItemGroup Condition=" '$(TargetsWindows)' == 'true' ">
+ <Compile Include="Internal\Cryptography\AsnFormatter.Windows.cs" />
+ <Compile Include="Internal\Cryptography\CngAsnFormatter.cs" />
+ <Compile Include="Internal\Cryptography\OidLookup.Windows.cs" />
+ <Compile Include="$(CommonPath)\Interop\Windows\BCrypt\Cng.cs">
+ <Link>Common\Interop\Windows\BCrypt\Cng.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\Crypt32\OidInfo.cs">
+ <Link>Common\Interop\Windows\Crypt32\OidInfo.cs</Link>
+ </Compile>
+ </ItemGroup>
+ <ItemGroup Condition=" '$(TargetsUnix)' == 'true' ">
+ <Compile Include="Internal\Cryptography\AsnFormatter.Unix.cs" />
+ <Compile Include="Internal\Cryptography\OidLookup.Unix.cs" />
+ <Compile Include="Internal\Cryptography\OpenSslAsnFormatter.cs" />
+ <Compile Include="$(CommonPath)\Interop\Unix\Interop.Libraries.cs">
+ <Link>Common\Interop\Unix\Interop.Libraries.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Unix\libcoreclr\Interop.EnsureOpenSslInitialized.cs">
+ <Link>Common\Interop\Unix\libcoreclr\Interop.EnsureOpenSslInitialized.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Unix\libcrypto\Interop.ASN1.cs">
+ <Link>Common\Interop\Unix\libcrypto\Interop.ASN1.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Unix\libcrypto\Interop.BIO.cs">
+ <Link>Common\Interop\Unix\libcrypto\Interop.BIO.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Unix\libcrypto\Interop.ERR.cs">
+ <Link>Common\Interop\Unix\libcrypto\Interop.ERR.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Unix\libcrypto\Interop.Initialization.cs">
+ <Link>Common\Interop\Unix\libcrypto\Interop.Initialization.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Unix\libcrypto\Interop.X509Ext.cs">
+ <Link>Common\Interop\Unix\libcrypto\Interop.X509Ext.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Microsoft\Win32\SafeHandles\Asn1SafeHandles.Unix.cs">
+ <Link>Common\Microsoft\Win32\SafeHandles\Asn1SafeHandles.Unix.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Microsoft\Win32\SafeHandles\SafeBioHandle.Unix.cs">
+ <Link>Common\Microsoft\Win32\SafeHandles\SafeBioHandle.Unix.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Microsoft\Win32\SafeHandles\X509ExtensionSafeHandles.Unix.cs">
+ <Link>Common\Microsoft\Win32\SafeHandles\X509ExtensionSafeHandles.Unix.cs</Link>
+ </Compile>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="project.json" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
diff --git a/src/System.Security.Cryptography.Encoding/src/System/Security/Cryptography/AsnEncodedData.cs b/src/System.Security.Cryptography.Encoding/src/System/Security/Cryptography/AsnEncodedData.cs
new file mode 100644
index 0000000000..1e64ccdf02
--- /dev/null
+++ b/src/System.Security.Cryptography.Encoding/src/System/Security/Cryptography/AsnEncodedData.cs
@@ -0,0 +1,93 @@
+// 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.Diagnostics;
+
+using Internal.Cryptography;
+
+namespace System.Security.Cryptography
+{
+ public class AsnEncodedData
+ {
+ protected AsnEncodedData()
+ {
+ }
+
+ public AsnEncodedData(byte[] rawData)
+ {
+ Reset(null, rawData);
+ }
+
+ public AsnEncodedData(AsnEncodedData asnEncodedData)
+ {
+ if (asnEncodedData == null)
+ throw new ArgumentNullException("asnEncodedData");
+ Reset(asnEncodedData._oid, asnEncodedData._rawData);
+ }
+
+ public AsnEncodedData(Oid oid, byte[] rawData)
+ {
+ Reset(oid, rawData);
+ }
+
+ public AsnEncodedData(String oid, byte[] rawData)
+ {
+ Reset(new Oid(oid), rawData);
+ }
+
+ public Oid Oid
+ {
+ get
+ {
+ return _oid;
+ }
+
+ set
+ {
+ _oid = (value == null) ? null : new Oid(value);
+ }
+ }
+
+ public byte[] RawData
+ {
+ get
+ {
+ // Desktop compat demands we return the array without copying.
+ return _rawData;
+ }
+
+ set
+ {
+ if (value == null)
+ throw new ArgumentNullException("value");
+ _rawData = value.CloneByteArray();
+ }
+ }
+
+ public virtual void CopyFrom(AsnEncodedData asnEncodedData)
+ {
+ if (asnEncodedData == null)
+ throw new ArgumentNullException("asnEncodedData");
+ Reset(asnEncodedData._oid, asnEncodedData._rawData);
+ }
+
+ public virtual String Format(bool multiLine)
+ {
+ // Return empty string if no data to format.
+ if (_rawData == null || _rawData.Length == 0)
+ return String.Empty;
+
+ return AsnFormatter.Instance.Format(_oid, _rawData, multiLine);
+ }
+
+ private void Reset(Oid oid, byte[] rawData)
+ {
+ this.Oid = oid;
+ this.RawData = rawData;
+ }
+
+ private Oid _oid = null;
+ private byte[] _rawData = null;
+ }
+}
diff --git a/src/System.Security.Cryptography.Encoding/src/System/Security/Cryptography/Oid.cs b/src/System.Security.Cryptography.Encoding/src/System/Security/Cryptography/Oid.cs
new file mode 100644
index 0000000000..bf7707abde
--- /dev/null
+++ b/src/System.Security.Cryptography.Encoding/src/System/Security/Cryptography/Oid.cs
@@ -0,0 +1,114 @@
+// 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.Diagnostics;
+
+using Internal.Cryptography;
+
+namespace System.Security.Cryptography
+{
+ public sealed class Oid
+ {
+ public Oid(String oid)
+ {
+ // If we were passed the friendly name, retrieve the value String.
+ String oidValue = OidLookup.ToOid(oid, OidGroup.All, fallBackToAllGroups: false);
+ if (oidValue == null)
+ {
+ oidValue = oid;
+ }
+ this.Value = oidValue;
+
+ _group = OidGroup.All;
+ }
+
+ public Oid(String value, String friendlyName)
+ {
+ _value = value;
+ _friendlyName = friendlyName;
+ }
+
+ public Oid(Oid oid)
+ {
+ if (oid == null)
+ throw new ArgumentNullException("oid");
+ _value = oid._value;
+ _friendlyName = oid._friendlyName;
+ _group = oid._group;
+ }
+
+ public static Oid FromFriendlyName(String friendlyName, OidGroup group)
+ {
+ if (friendlyName == null)
+ {
+ throw new ArgumentNullException("friendlyName");
+ }
+
+ String oidValue = OidLookup.ToOid(friendlyName, group, fallBackToAllGroups: false);
+ if (oidValue == null)
+ throw new CryptographicException(SR.Cryptography_Oid_InvalidName);
+
+ return new Oid(oidValue, friendlyName, group);
+ }
+
+ public static Oid FromOidValue(String oidValue, OidGroup group)
+ {
+ if (oidValue == null)
+ throw new ArgumentNullException("oidValue");
+
+ String friendlyName = OidLookup.ToFriendlyName(oidValue, group, fallBackToAllGroups: false);
+ if (friendlyName == null)
+ throw new CryptographicException(SR.Cryptography_Oid_InvalidValue);
+
+ return new Oid(oidValue, friendlyName, group);
+ }
+
+ public String Value
+ {
+ get { return _value; }
+ set { _value = value; }
+ }
+
+ public String FriendlyName
+ {
+ get
+ {
+ if (_friendlyName == null && _value != null)
+ {
+ _friendlyName = OidLookup.ToFriendlyName(_value, _group, fallBackToAllGroups: true);
+ }
+
+ return _friendlyName;
+ }
+ set
+ {
+ _friendlyName = value;
+ // If we can find the matching OID value, then update it as well
+ if (_friendlyName != null)
+ {
+ // If FindOidInfo fails, we return a null String
+ String oidValue = OidLookup.ToOid(_friendlyName, _group, fallBackToAllGroups: true);
+ if (oidValue != null)
+ {
+ _value = oidValue;
+ }
+ }
+ }
+ }
+
+ private Oid(String value, String friendlyName, OidGroup group)
+ {
+ Debug.Assert(value != null);
+ Debug.Assert(friendlyName != null);
+
+ _value = value;
+ _friendlyName = friendlyName;
+ _group = group;
+ }
+
+ private String _value = null;
+ private String _friendlyName = null;
+ private OidGroup _group = OidGroup.All;
+ }
+}
diff --git a/src/System.Security.Cryptography.Encoding/src/System/Security/Cryptography/OidCollection.cs b/src/System.Security.Cryptography.Encoding/src/System/Security/Cryptography/OidCollection.cs
new file mode 100644
index 0000000000..337a4dfaa0
--- /dev/null
+++ b/src/System.Security.Cryptography.Encoding/src/System/Security/Cryptography/OidCollection.cs
@@ -0,0 +1,113 @@
+// 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.Diagnostics;
+using System.Collections;
+using System.Collections.Generic;
+using Internal.Cryptography;
+
+namespace System.Security.Cryptography
+{
+ public sealed class OidCollection : ICollection
+ {
+ public OidCollection()
+ {
+ _list = new LowLevelListWithIList<Oid>();
+ }
+
+ public int Add(Oid oid)
+ {
+ int count = _list.Count;
+ _list.Add(oid);
+ return count;
+ }
+
+ public Oid this[int index]
+ {
+ get
+ {
+ return _list[index];
+ }
+ }
+
+ // Indexer using an OID friendly name or value.
+ public Oid this[String oid]
+ {
+ get
+ {
+ // If we were passed the friendly name, retrieve the value String.
+ String oidValue = OidLookup.ToOid(oid, OidGroup.All, fallBackToAllGroups: false);
+ if (oidValue == null)
+ {
+ oidValue = oid;
+ }
+ foreach (Oid entry in _list)
+ {
+ if (entry.Value == oidValue)
+ return entry;
+ }
+ return null;
+ }
+ }
+
+ public int Count
+ {
+ get
+ {
+ return _list.Count;
+ }
+ }
+
+ public OidEnumerator GetEnumerator()
+ {
+ return new OidEnumerator(this);
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return new OidEnumerator(this);
+ }
+
+ void ICollection.CopyTo(Array array, int index)
+ {
+ if (array == null)
+ throw new ArgumentNullException("array");
+ if (array.Rank != 1)
+ throw new ArgumentException(SR.Arg_RankMultiDimNotSupported);
+ if (index < 0 || index >= array.Length)
+ throw new ArgumentOutOfRangeException("index", SR.ArgumentOutOfRange_Index);
+ if (index + this.Count > array.Length)
+ throw new ArgumentException(SR.Argument_InvalidOffLen);
+
+ for (int i = 0; i < this.Count; i++)
+ {
+ array.SetValue(this[i], index);
+ index++;
+ }
+ }
+
+ public void CopyTo(Oid[] array, int index)
+ {
+ ((ICollection)this).CopyTo(array, index);
+ }
+
+ bool ICollection.IsSynchronized
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ Object ICollection.SyncRoot
+ {
+ get
+ {
+ return this;
+ }
+ }
+
+ private LowLevelListWithIList<Oid> _list;
+ }
+}
diff --git a/src/System.Security.Cryptography.Encoding/src/System/Security/Cryptography/OidEnumerator.cs b/src/System.Security.Cryptography.Encoding/src/System/Security/Cryptography/OidEnumerator.cs
new file mode 100644
index 0000000000..392e8e498f
--- /dev/null
+++ b/src/System.Security.Cryptography.Encoding/src/System/Security/Cryptography/OidEnumerator.cs
@@ -0,0 +1,50 @@
+// 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.Diagnostics;
+using System.Collections;
+
+namespace System.Security.Cryptography
+{
+ public sealed class OidEnumerator : IEnumerator
+ {
+ internal OidEnumerator(OidCollection oids)
+ {
+ _oids = oids;
+ _current = -1;
+ }
+
+ public Oid Current
+ {
+ get
+ {
+ return _oids[_current];
+ }
+ }
+
+ Object IEnumerator.Current
+ {
+ get
+ {
+ return _oids[_current];
+ }
+ }
+
+ public bool MoveNext()
+ {
+ if (_current == _oids.Count - 1)
+ return false;
+ _current++;
+ return true;
+ }
+
+ public void Reset()
+ {
+ _current = -1;
+ }
+
+ private OidCollection _oids;
+ private int _current;
+ }
+}
diff --git a/src/System.Security.Cryptography.Encoding/src/System/Security/Cryptography/OidGroup.cs b/src/System.Security.Cryptography.Encoding/src/System/Security/Cryptography/OidGroup.cs
new file mode 100644
index 0000000000..a9d1d7ad94
--- /dev/null
+++ b/src/System.Security.Cryptography.Encoding/src/System/Security/Cryptography/OidGroup.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;
+using System.Diagnostics;
+
+namespace System.Security.Cryptography
+{
+ // Values taken from wincrypt.h
+ public enum OidGroup
+ {
+ All = 0,
+ HashAlgorithm = 1,
+ EncryptionAlgorithm = 2,
+ PublicKeyAlgorithm = 3,
+ SignatureAlgorithm = 4,
+ Attribute = 5,
+ ExtensionOrAttribute = 6,
+ EnhancedKeyUsage = 7,
+ Policy = 8,
+ Template = 9,
+ KeyDerivationFunction = 10
+ }
+}
diff --git a/src/System.Security.Cryptography.Encoding/src/project.json b/src/System.Security.Cryptography.Encoding/src/project.json
new file mode 100644
index 0000000000..972f4933d4
--- /dev/null
+++ b/src/System.Security.Cryptography.Encoding/src/project.json
@@ -0,0 +1,13 @@
+{
+ "dependencies": {
+ "System.Diagnostics.Contracts": "4.0.0-beta-*",
+ "System.Diagnostics.Debug": "4.0.10-beta-*",
+ "System.Resources.ResourceManager": "4.0.0-beta-*",
+ "System.Runtime": "4.0.20-beta-*",
+ "System.Runtime.InteropServices": "4.0.20-beta-*",
+ "System.Security.Cryptography.Encryption": "4.0.0-beta-*",
+ },
+ "frameworks": {
+ "dnxcore50": {}
+ }
+}
diff --git a/src/System.Security.Cryptography.Encoding/tests/AsnEncodedData.cs b/src/System.Security.Cryptography.Encoding/tests/AsnEncodedData.cs
new file mode 100644
index 0000000000..6f938b7957
--- /dev/null
+++ b/src/System.Security.Cryptography.Encoding/tests/AsnEncodedData.cs
@@ -0,0 +1,69 @@
+// 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.Text;
+using Xunit;
+
+namespace System.Security.Cryptography.Encoding.Tests
+{
+ public class AsnEncodedDataTests
+ {
+ [Fact]
+ public static void FormatUnknownData()
+ {
+ byte[] rawData = { 0x41, 0x42, 0x43 };
+ AsnEncodedData a = new AsnEncodedData(rawData);
+ a.Oid = null;
+ String s = a.Format(true);
+ Assert.Equal("41 42 43", s);
+ return;
+ }
+
+ [Fact]
+ public static void FormatInvalidTypedData()
+ {
+ // This passes in data in an illegal format. AsnEncodedData.Format() swallows the error and falls back to a simple hex-encoding scheme.
+ byte[] rawData = { 0x41, 0x42, 0x43 };
+ AsnEncodedData a = new AsnEncodedData(rawData);
+ a.Oid = new Oid("1.3.6.1.4.1.311.2.1.27"); //SPC_FINANCIAL_CRITERIA_OBJID
+ String s = a.Format(true);
+ Assert.Equal("414243", s);
+ return;
+ }
+
+ [Fact]
+ public static void TestSubjectAlternativeName()
+ {
+ byte[] sanExtension =
+ {
+ 0x30, 0x31, 0x82, 0x0B, 0x65, 0x78, 0x61, 0x6D,
+ 0x70, 0x6C, 0x65, 0x2E, 0x6F, 0x72, 0x67, 0x82,
+ 0x0F, 0x73, 0x75, 0x62, 0x2E, 0x65, 0x78, 0x61,
+ 0x6D, 0x70, 0x6C, 0x65, 0x2E, 0x6F, 0x72, 0x67,
+ 0x82, 0x11, 0x2A, 0x2E, 0x73, 0x75, 0x62, 0x2E,
+ 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x2E,
+ 0x6F, 0x72, 0x67,
+ };
+
+ AsnEncodedData asnData = new AsnEncodedData(
+ new Oid("2.5.29.17"),
+ sanExtension);
+
+ string s = asnData.Format(false);
+ // Windows says: "DNS Name=example.org, DNS Name=sub.example.org, DNS Name=*.sub.example.org"
+ // X-Plat (OpenSSL) says: "DNS:example.org, DNS:sub.example.org, DNS:*.sub.example.org".
+ // This keeps the parsing generalized until we can get them to converge
+ string[] parts = s.Split(new[] { ':', '=', ',' }, StringSplitOptions.RemoveEmptyEntries);
+ // Parts is now { header, data, header, data, header, data }.
+ string[] output = new string[parts.Length / 2];
+
+ for (int i = 0; i < output.Length; i++)
+ {
+ output[i] = parts[2 * i + 1];
+ }
+
+ Assert.Equal(new[] { "example.org", "sub.example.org", "*.sub.example.org" }, output);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/System.Security.Cryptography.Encoding/tests/Oid.cs b/src/System.Security.Cryptography.Encoding/tests/Oid.cs
new file mode 100644
index 0000000000..d7c5614767
--- /dev/null
+++ b/src/System.Security.Cryptography.Encoding/tests/Oid.cs
@@ -0,0 +1,199 @@
+// 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.Text;
+using Xunit;
+
+namespace System.Security.Cryptography.Encoding.Tests
+{
+ public class OidTests
+ {
+ [Fact]
+ public static void TestStrConstructor()
+ {
+ Oid oid;
+
+ Assert.Throws<ArgumentNullException>(() => oid = new Oid((string)null));
+
+ oid = new Oid(SHA1_Oid);
+ Assert.Equal(SHA1_Name, oid.FriendlyName);
+ Assert.Equal(SHA1_Oid, oid.Value);
+
+ // Though the parameter is supposed to be an OID, the constructor will also accept a friendly name.
+ oid = new Oid(SHA1_Name);
+ Assert.Equal(SHA1_Name, oid.FriendlyName);
+ Assert.Equal(SHA1_Oid, oid.Value);
+
+ // No validation done on OID (other than the null check.)
+ oid = new Oid(Bogus_Name);
+ Assert.Equal(null, oid.FriendlyName);
+ Assert.Equal(Bogus_Name, oid.Value);
+
+ return;
+ }
+
+ [Fact]
+ public static void TestStrStrConstructor()
+ {
+ Oid oid;
+
+ // No validation at all.
+ oid = new Oid((string)null, (string)null);
+ Assert.Equal(null, oid.FriendlyName);
+ Assert.Equal(null, oid.Value);
+
+ // Can omit friendly-name - FriendlyName property demand-computes it.
+ oid = new Oid(SHA1_Oid, (string)null);
+ Assert.Equal(SHA1_Name, oid.FriendlyName);
+ Assert.Equal(SHA1_Oid, oid.Value);
+
+ oid = new Oid(SHA1_Oid, "BOGUS-NAME");
+ Assert.Equal("BOGUS-NAME", oid.FriendlyName);
+ Assert.Equal(SHA1_Oid, oid.Value);
+
+ // Can omit oid, Value property does no on-demand conversion.
+ oid = new Oid((string)null, SHA1_Name);
+ Assert.Equal(SHA1_Name, oid.FriendlyName);
+ Assert.Equal(null, oid.Value);
+
+ oid = new Oid("BOGUS-OID", SHA1_Name);
+ Assert.Equal(SHA1_Name, oid.FriendlyName);
+ Assert.Equal("BOGUS-OID", oid.Value);
+
+
+ return;
+ }
+
+ [Fact]
+ public static void TestValueProperty()
+ {
+ Oid oid = new Oid(null, null);
+
+ // Value property is just a field exposed as a property - no extra policy at all.
+
+ oid.Value = "BOGUS";
+ Assert.Equal("BOGUS", oid.Value);
+
+ oid.Value = null;
+ Assert.Equal(null, oid.Value);
+
+ return;
+ }
+
+ [Fact]
+ public static void TestFriendlyNameProperty()
+ {
+ Oid oid;
+
+ oid = new Oid(null, null);
+
+ // Friendly name property can initialize itself from the Value (but only
+ // if it was originally null.)
+
+ oid.Value = SHA1_Oid;
+ Assert.Equal(SHA1_Name, oid.FriendlyName);
+
+ oid.Value = SHA256_Oid;
+ Assert.Equal(SHA1_Name, oid.FriendlyName);
+
+ oid.Value = null;
+ Assert.Equal(SHA1_Name, oid.FriendlyName);
+
+ oid.Value = Bogus_Name;
+ Assert.Equal(SHA1_Name, oid.FriendlyName);
+
+ // Setting the FriendlyName can also updates the value if there a valid OID for the new name.
+ oid.FriendlyName = Bogus_Name;
+ Assert.Equal(Bogus_Name, oid.FriendlyName);
+ Assert.Equal(Bogus_Name, oid.Value);
+
+ oid.FriendlyName = SHA1_Name;
+ Assert.Equal(SHA1_Name, oid.FriendlyName);
+ Assert.Equal(SHA1_Oid, oid.Value);
+
+ oid.FriendlyName = SHA256_Name;
+ Assert.Equal(SHA256_Name, oid.FriendlyName);
+ Assert.Equal(SHA256_Oid, oid.Value);
+ }
+
+ [Fact]
+ public static void TestFromFriendlyName()
+ {
+ Oid oid;
+
+ oid = Oid.FromFriendlyName(SHA1_Name, OidGroup.HashAlgorithm);
+ Assert.Equal(SHA1_Name, oid.FriendlyName);
+ Assert.Equal(SHA1_Oid, oid.Value);
+
+ oid = Oid.FromFriendlyName(SHA256_Name, OidGroup.HashAlgorithm);
+ Assert.Equal(SHA256_Name, oid.FriendlyName);
+ Assert.Equal(SHA256_Oid, oid.Value);
+
+ Assert.Throws<ArgumentNullException>(() => Oid.FromFriendlyName(null, OidGroup.HashAlgorithm));
+ Assert.Throws<CryptographicException>(() => Oid.FromFriendlyName(Bogus_Name, OidGroup.HashAlgorithm));
+
+ // Oid group is implemented strictly - no fallback to OidGroup.All as with many other parts of Crypto.
+ Assert.Throws<CryptographicException>(() => Oid.FromFriendlyName(SHA1_Name, OidGroup.Policy));
+ }
+
+ [Fact]
+ public static void TestFromOidValue()
+ {
+ Oid oid;
+
+ oid = Oid.FromOidValue(SHA1_Oid, OidGroup.HashAlgorithm);
+ Assert.Equal(SHA1_Name, oid.FriendlyName);
+ Assert.Equal(SHA1_Oid, oid.Value);
+
+ oid = Oid.FromOidValue(SHA256_Oid, OidGroup.HashAlgorithm);
+ Assert.Equal(SHA256_Name, oid.FriendlyName);
+ Assert.Equal(SHA256_Oid, oid.Value);
+
+ Assert.Throws<ArgumentNullException>(() => Oid.FromOidValue(null, OidGroup.HashAlgorithm));
+ Assert.Throws<CryptographicException>(() => Oid.FromOidValue(Bogus_Name, OidGroup.HashAlgorithm));
+
+ // Oid group is implemented strictly - no fallback to OidGroup.All as with many other parts of Crypto.
+ Assert.Throws<CryptographicException>(() => Oid.FromOidValue(SHA1_Oid, OidGroup.Policy));
+ }
+
+ [Fact]
+ public static void TestKnownValues()
+ {
+ Oid oid;
+ oid = Oid.FromFriendlyName(SHA1_Name, OidGroup.All);
+ Assert.Equal(SHA1_Name, oid.FriendlyName);
+ Assert.Equal(SHA1_Oid, oid.Value);
+
+ oid = Oid.FromFriendlyName(SHA256_Name, OidGroup.All);
+ Assert.Equal(SHA256_Name, oid.FriendlyName);
+ Assert.Equal(SHA256_Oid, oid.Value);
+
+ // Note that oid lookup is case-insensitive, and we store the name in the form it was input to the constructor (rather than "normalizing" it
+ // to the official casing.)
+ oid = Oid.FromFriendlyName("MD5", OidGroup.All);
+ Assert.Equal("MD5", oid.FriendlyName);
+ Assert.Equal("1.2.840.113549.2.5", oid.Value);
+
+ oid = Oid.FromFriendlyName("sha384", OidGroup.All);
+ Assert.Equal("sha384", oid.FriendlyName);
+ Assert.Equal("2.16.840.1.101.3.4.2.2", oid.Value);
+
+ oid = Oid.FromFriendlyName("sha512", OidGroup.All);
+ Assert.Equal("sha512", oid.FriendlyName);
+ Assert.Equal("2.16.840.1.101.3.4.2.3", oid.Value);
+
+ oid = Oid.FromFriendlyName("3des", OidGroup.All);
+ Assert.Equal("3des", oid.FriendlyName);
+ Assert.Equal("1.2.840.113549.3.7", oid.Value);
+ }
+
+ private const string SHA1_Name = "sha1";
+ private const string SHA1_Oid = "1.3.14.3.2.26";
+
+ private const string SHA256_Name = "sha256";
+ private const string SHA256_Oid = "2.16.840.1.101.3.4.2.1";
+
+ private const string Bogus_Name = "BOGUS_BOGUS_BOGUS_BOGUS";
+ }
+} \ No newline at end of file
diff --git a/src/System.Security.Cryptography.Encoding/tests/OidCollection.cs b/src/System.Security.Cryptography.Encoding/tests/OidCollection.cs
new file mode 100644
index 0000000000..e55a264323
--- /dev/null
+++ b/src/System.Security.Cryptography.Encoding/tests/OidCollection.cs
@@ -0,0 +1,92 @@
+// 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.Text;
+using System.Collections;
+using Xunit;
+
+namespace System.Security.Cryptography.Encoding.Tests
+{
+ public class OidCollectionTests
+ {
+ [Fact]
+ public static void TestOidCollection()
+ {
+ int i;
+ OidCollection c = new OidCollection();
+ Assert.Equal(0, c.Count);
+
+ Oid o0 = new Oid(SHA1_Oid, SHA1_Name);
+ i = c.Add(o0);
+ Assert.Equal(0, i);
+
+ Oid o1 = new Oid(SHA256_Oid, SHA256_Name);
+ i = c.Add(o1);
+ Assert.Equal(1, i);
+
+ Assert.Equal(2, c.Count);
+
+ Assert.True(Object.ReferenceEquals(o0, c[0]));
+ Assert.True(Object.ReferenceEquals(o1, c[1]));
+ Assert.Throws<ArgumentOutOfRangeException>(() => GC.KeepAlive(c[-1]));
+ Assert.Throws<ArgumentOutOfRangeException>(() => GC.KeepAlive(c[c.Count]));
+
+ Oid o2 = new Oid(SHA1_Oid, SHA1_Name);
+ i = c.Add(o2);
+ Assert.Equal(2, i);
+
+ // If there multiple matches, the one with the lowest index wins.
+ Assert.True(Object.ReferenceEquals(o0, c[SHA1_Name]));
+ Assert.True(Object.ReferenceEquals(o0, c[SHA1_Oid]));
+
+ Assert.True(Object.ReferenceEquals(o1, c[SHA256_Name]));
+ Assert.True(Object.ReferenceEquals(o1, c[SHA256_Oid]));
+
+ Oid o3 = new Oid(null, null);
+ i = c.Add(o3);
+ Assert.Equal(3, i);
+ Assert.Throws<ArgumentNullException>(() => GC.KeepAlive(c[null]));
+
+ Object o = c["BOGUSBOGUS"];
+ Assert.Null(c["BOGUSBOGUS"]);
+
+ Oid[] a = new Oid[10];
+ for (int j = 0; j < a.Length; j++)
+ {
+ a[j] = new Oid(null, null);
+ }
+ Oid[] a2 = (Oid[])(a.Clone());
+
+ c.CopyTo(a2, 3);
+ Assert.Equal(a[0], a2[0]);
+ Assert.Equal(a[1], a2[1]);
+ Assert.Equal(a[2], a2[2]);
+ Assert.Equal(o0, a2[3]);
+ Assert.Equal(o1, a2[4]);
+ Assert.Equal(o2, a2[5]);
+ Assert.Equal(o3, a2[6]);
+ Assert.Equal(a[7], a2[7]);
+ Assert.Equal(a[8], a2[8]);
+ Assert.Equal(a[9], a2[9]);
+
+ Assert.Throws<ArgumentNullException>(() => c.CopyTo(null, 0));
+ Assert.Throws<ArgumentNullException>(() => c.CopyTo(null, -1));
+ Assert.Throws<ArgumentOutOfRangeException>(() => c.CopyTo(a, -1));
+ Assert.Throws<ArgumentException>(() => c.CopyTo(a, 7));
+ Assert.Throws<ArgumentOutOfRangeException>(() => c.CopyTo(a, 1000));
+
+ ICollection ic = c;
+ Assert.Throws<ArgumentException>(() => ic.CopyTo(new Oid[4, 3], 0));
+ Assert.Throws<InvalidCastException>(() => ic.CopyTo(new string[100], 0));
+
+ return;
+ }
+
+ private const string SHA1_Name = "sha1";
+ private const string SHA1_Oid = "1.3.14.3.2.26";
+
+ private const string SHA256_Name = "sha256";
+ private const string SHA256_Oid = "2.16.840.1.101.3.4.2.1";
+ }
+} \ No newline at end of file
diff --git a/src/System.Security.Cryptography.Encoding/tests/System.Security.Cryptography.Encoding.Tests.csproj b/src/System.Security.Cryptography.Encoding/tests/System.Security.Cryptography.Encoding.Tests.csproj
new file mode 100644
index 0000000000..53339ebbcc
--- /dev/null
+++ b/src/System.Security.Cryptography.Encoding/tests/System.Security.Cryptography.Encoding.Tests.csproj
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{0581E9FA-D639-4B88-96D8-D092760F90B0}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AssemblyName>System.Security.Cryptography.Encoding.Tests</AssemblyName>
+ <RootNamespace>System.Security.Cryptography.Encoding.Tests</RootNamespace>
+ </PropertyGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\src\System.Security.Cryptography.Encoding.csproj">
+ <Project>{AA81E343-5E54-40B0-9381-C459419BE780}</Project>
+ <Name>System.Security.Cryptography.Encoding</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="AsnEncodedData.cs" />
+ <Compile Include="Oid.cs" />
+ <Compile Include="OidCollection.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="project.json" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
diff --git a/src/System.Security.Cryptography.Encoding/tests/project.json b/src/System.Security.Cryptography.Encoding/tests/project.json
new file mode 100644
index 0000000000..9c4c015c85
--- /dev/null
+++ b/src/System.Security.Cryptography.Encoding/tests/project.json
@@ -0,0 +1,18 @@
+{
+ "dependencies": {
+ "System.Console": "4.0.0-beta-*",
+ "System.IO": "4.0.10-beta-*",
+ "System.Runtime": "4.0.20-beta-*",
+ "System.Runtime.Extensions": "4.0.10-beta-*",
+ "System.Security.Cryptography.Encryption": "4.0.0-beta-*",
+ "xunit": "2.0.0-beta5-build2785",
+ "xunit.abstractions.netcore": "1.0.0-prerelease",
+ "xunit.assert": "2.0.0-beta5-build2785",
+ "xunit.core.netcore": "1.0.1-prerelease",
+ "xunit.runner.visualstudio": "0.99.9-build1021",
+ "xunit.netcore.extensions": "1.0.0-prerelease-*"
+ },
+ "frameworks": {
+ "dnxcore50": {}
+ }
+}