Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 4e0b645

Browse files
committed
Merge pull request #1990 from bartonjs/add-cryptography-x509
Add System.Security.Cryptography.X509Certificates Source and Test
2 parents eb32fdd + 9021b97 commit 4e0b645

File tree

104 files changed

+14700
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

104 files changed

+14700
-0
lines changed

src/Common/src/Interop/Unix/Interop.Libraries.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ private static partial class Libraries
99
internal const string LibCoreClr= "libcoreclr"; // CoreCLR runtime
1010
internal const string LibCrypto = "libcrypto"; // OpenSSL crypto library
1111
internal const string Zlib = "libz"; // zlib compression library
12+
internal const string CryptoInterop = "System.Security.Cryptography.Native";
1213
}
1314
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System;
5+
using System.Runtime.InteropServices;
6+
using System.Security.Cryptography;
7+
using System.Security.Cryptography.X509Certificates;
8+
9+
using Microsoft.Win32.SafeHandles;
10+
11+
internal static partial class Interop
12+
{
13+
internal static partial class NativeCrypto
14+
{
15+
[DllImport(Libraries.CryptoInterop)]
16+
internal static extern int GetX509Thumbprint(SafeX509Handle x509, byte[] buf, int cBuf);
17+
18+
[DllImport(Libraries.CryptoInterop)]
19+
internal static extern int GetX509NameRawBytes(IntPtr x509Name, byte[] buf, int cBuf);
20+
21+
[DllImport(Libraries.CryptoInterop)]
22+
internal static extern IntPtr GetX509NotBefore(SafeX509Handle x509);
23+
24+
[DllImport(Libraries.CryptoInterop)]
25+
internal static extern IntPtr GetX509NotAfter(SafeX509Handle x509);
26+
27+
[DllImport(Libraries.CryptoInterop)]
28+
internal static extern int GetX509Version(SafeX509Handle x509);
29+
30+
[DllImport(Libraries.CryptoInterop)]
31+
internal static extern IntPtr GetX509SignatureAlgorithm(SafeX509Handle x509);
32+
33+
[DllImport(Libraries.CryptoInterop)]
34+
internal static extern IntPtr GetX509PublicKeyAlgorithm(SafeX509Handle x509);
35+
36+
[DllImport(Libraries.CryptoInterop)]
37+
internal static extern int GetX509PublicKeyParameterBytes(SafeX509Handle x509, byte[] buf, int cBuf);
38+
39+
[DllImport(Libraries.CryptoInterop)]
40+
internal static extern IntPtr GetX509PublicKeyBytes(SafeX509Handle x509);
41+
42+
[DllImport(Libraries.CryptoInterop)]
43+
internal static extern int GetX509EkuFieldCount(SafeEkuExtensionHandle eku);
44+
45+
[DllImport(Libraries.CryptoInterop)]
46+
internal static extern IntPtr GetX509EkuField(SafeEkuExtensionHandle eku, int loc);
47+
48+
[DllImport(Libraries.CryptoInterop)]
49+
internal static extern SafeBioHandle GetX509NameInfo(SafeX509Handle x509, int nameType, [MarshalAs(UnmanagedType.Bool)] bool forIssuer);
50+
51+
[DllImport(Libraries.CryptoInterop)]
52+
private static extern int GetAsn1StringBytes(IntPtr asn1, byte[] buf, int cBuf);
53+
54+
internal static byte[] GetAsn1StringBytes(IntPtr asn1)
55+
{
56+
int negativeSize = GetAsn1StringBytes(asn1, null, 0);
57+
58+
if (negativeSize > 0)
59+
{
60+
throw new CryptographicException();
61+
}
62+
63+
byte[] bytes = new byte[-negativeSize];
64+
65+
int ret = GetAsn1StringBytes(asn1, bytes, bytes.Length);
66+
67+
if (ret != 1)
68+
{
69+
throw new CryptographicException();
70+
}
71+
72+
return bytes;
73+
}
74+
}
75+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System;
5+
using System.Runtime.InteropServices;
6+
using System.Security.Cryptography;
7+
8+
using Microsoft.Win32.SafeHandles;
9+
10+
using NativeULong=System.UIntPtr;
11+
12+
internal static partial class Interop
13+
{
14+
internal static partial class libcrypto
15+
{
16+
[DllImport(Libraries.LibCrypto)]
17+
internal static extern void X509_free(IntPtr a);
18+
19+
[DllImport(Libraries.LibCrypto)]
20+
internal static unsafe extern SafeX509Handle d2i_X509(IntPtr zero, byte** ppin, int len);
21+
22+
[DllImport(Libraries.LibCrypto)]
23+
internal static extern unsafe int i2d_X509(SafeX509Handle x, byte** @out);
24+
25+
[DllImport(Libraries.LibCrypto)]
26+
internal static extern IntPtr X509_get_serialNumber(SafeX509Handle x);
27+
28+
[DllImport(Libraries.LibCrypto)]
29+
internal static unsafe extern SafeX509NameHandle d2i_X509_NAME(IntPtr zero, byte** ppin, int len);
30+
31+
[DllImport(Libraries.LibCrypto)]
32+
internal static extern int X509_NAME_print_ex(SafeBioHandle @out, SafeX509NameHandle nm, int indent, NativeULong flags);
33+
34+
[DllImport(Libraries.LibCrypto)]
35+
internal static extern void X509_NAME_free(IntPtr a);
36+
37+
[DllImport(Libraries.LibCrypto)]
38+
internal static extern IntPtr X509_get_issuer_name(SafeX509Handle a);
39+
40+
[DllImport(Libraries.LibCrypto)]
41+
internal static extern IntPtr X509_get_subject_name(SafeX509Handle a);
42+
43+
[DllImport(Libraries.LibCrypto)]
44+
[return: MarshalAs(UnmanagedType.Bool)]
45+
internal static extern bool X509_check_purpose(SafeX509Handle x, int id, int ca);
46+
47+
[DllImport(Libraries.LibCrypto)]
48+
internal static extern int X509_get_ext_count(SafeX509Handle x);
49+
50+
// Returns a pointer already being tracked by the SafeX509Handle, shouldn't be SafeHandle tracked/freed.
51+
// Bounds checking is in place for "loc", IntPtr.Zero is returned on violations.
52+
[DllImport(Libraries.LibCrypto)]
53+
internal static extern IntPtr X509_get_ext(SafeX509Handle x, int loc);
54+
55+
// Returns a pointer already being tracked by a SafeX509Handle, shouldn't be SafeHandle tracked/freed.
56+
[DllImport(Libraries.LibCrypto)]
57+
internal static extern IntPtr X509_EXTENSION_get_object(IntPtr ex);
58+
59+
// Returns a pointer already being tracked by a SafeX509Handle, shouldn't be SafeHandle tracked/freed.
60+
[DllImport(Libraries.LibCrypto)]
61+
internal static extern IntPtr X509_EXTENSION_get_data(IntPtr ex);
62+
63+
[DllImport(Libraries.LibCrypto)]
64+
[return: MarshalAs(UnmanagedType.Bool)]
65+
internal static extern bool X509_EXTENSION_get_critical(IntPtr ex);
66+
}
67+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System;
5+
using System.Diagnostics;
6+
using System.Runtime.InteropServices;
7+
using System.Security.Cryptography;
8+
9+
internal static partial class Interop
10+
{
11+
internal static partial class libcrypto
12+
{
13+
internal unsafe delegate THandle D2IFunc<out THandle>(IntPtr zero, byte** ppin, int len);
14+
15+
internal unsafe delegate int I2DFunc<in THandle>(THandle handle, byte** @out);
16+
17+
internal static unsafe THandle OpenSslD2I<THandle>(D2IFunc<THandle> d2i, byte[] data)
18+
where THandle : SafeHandle
19+
{
20+
// The OpenSSL d2i_* functions are set up for cascaded calls, so they increment *ppData while reading.
21+
// Since only the outermost caller (that'd be this method) knows who the outermost caller is, it's their
22+
// job to keep a pointer to the original data.
23+
fixed (byte* pDataFixed = data)
24+
{
25+
byte* pData = pDataFixed;
26+
byte** ppData = &pData;
27+
28+
THandle handle = d2i(IntPtr.Zero, ppData, data.Length);
29+
30+
if (handle.IsInvalid)
31+
{
32+
throw new CryptographicException(GetOpenSslErrorString());
33+
}
34+
35+
return handle;
36+
}
37+
}
38+
39+
internal static unsafe byte[] OpenSslI2D<THandle>(I2DFunc<THandle> i2d, THandle handle)
40+
where THandle : SafeHandle
41+
{
42+
int size = i2d(handle, null);
43+
44+
if (size < 1)
45+
{
46+
throw new CryptographicException();
47+
}
48+
49+
byte[] data = new byte[size];
50+
51+
fixed (byte* pDataFixed = data)
52+
{
53+
byte* pData = pDataFixed;
54+
byte** ppData = &pData;
55+
56+
int size2 = i2d(handle, ppData);
57+
58+
Debug.Assert(size == size2);
59+
}
60+
61+
return data;
62+
}
63+
}
64+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System;
5+
using System.Security;
6+
using System.Runtime.InteropServices;
7+
8+
namespace Microsoft.Win32.SafeHandles
9+
{
10+
[SecurityCritical]
11+
internal sealed class SafeX509Handle : SafeHandle
12+
{
13+
private SafeX509Handle() :
14+
base(IntPtr.Zero, ownsHandle: true)
15+
{
16+
}
17+
18+
[SecurityCritical]
19+
protected override bool ReleaseHandle()
20+
{
21+
Interop.libcrypto.X509_free(handle);
22+
SetHandle(IntPtr.Zero);
23+
return true;
24+
}
25+
26+
public override bool IsInvalid
27+
{
28+
[SecurityCritical]
29+
get { return handle == IntPtr.Zero; }
30+
}
31+
}
32+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System;
5+
using System.Security;
6+
using System.Runtime.InteropServices;
7+
8+
namespace Microsoft.Win32.SafeHandles
9+
{
10+
[SecurityCritical]
11+
internal sealed class SafeX509NameHandle : SafeHandle
12+
{
13+
private SafeX509NameHandle() :
14+
base(IntPtr.Zero, ownsHandle: true)
15+
{
16+
}
17+
18+
protected override bool ReleaseHandle()
19+
{
20+
Interop.libcrypto.X509_NAME_free(handle);
21+
SetHandle(IntPtr.Zero);
22+
return true;
23+
}
24+
25+
public override bool IsInvalid
26+
{
27+
get { return handle == IntPtr.Zero; }
28+
}
29+
}
30+
}

src/Common/src/System/Collections/Generic/LowLevelList.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,15 @@ public T[] ToArray()
497497
/// </summary>
498498
internal sealed class LowLevelListWithIList<T> : LowLevelList<T>, IList<T>
499499
{
500+
public LowLevelListWithIList()
501+
{
502+
}
503+
504+
public LowLevelListWithIList(int capacity)
505+
: base(capacity)
506+
{
507+
}
508+
500509
// Is this List read-only?
501510
bool ICollection<T>.IsReadOnly
502511
{
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio 14
4+
VisualStudioVersion = 14.0.22911.2
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Security.Cryptography.X509Certificates", "src\System.Security.Cryptography.X509Certificates.csproj", "{6F8576C2-6CD0-4DF3-8394-00B002D82E40}"
7+
EndProject
8+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Security.Cryptography.X509Certificates.Tests", "tests\System.Security.Cryptography.X509Certificates.Tests.csproj", "{A28B0064-EFB2-4B77-B97C-DECF5DAB074E}"
9+
EndProject
10+
Global
11+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
12+
Linux_Debug|Any CPU = Linux_Debug|Any CPU
13+
Linux_Release|Any CPU = Linux_Release|Any CPU
14+
OSX_Debug|Any CPU = OSX_Debug|Any CPU
15+
OSX_Release|Any CPU = OSX_Release|Any CPU
16+
Windows_Debug|Any CPU = Windows_Debug|Any CPU
17+
Windows_Release|Any CPU = Windows_Release|Any CPU
18+
EndGlobalSection
19+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
20+
{6F8576C2-6CD0-4DF3-8394-00B002D82E40}.Linux_Debug|Any CPU.ActiveCfg = Linux_Debug|Any CPU
21+
{6F8576C2-6CD0-4DF3-8394-00B002D82E40}.Linux_Debug|Any CPU.Build.0 = Linux_Debug|Any CPU
22+
{6F8576C2-6CD0-4DF3-8394-00B002D82E40}.Linux_Release|Any CPU.ActiveCfg = Linux_Release|Any CPU
23+
{6F8576C2-6CD0-4DF3-8394-00B002D82E40}.Linux_Release|Any CPU.Build.0 = Linux_Release|Any CPU
24+
{6F8576C2-6CD0-4DF3-8394-00B002D82E40}.OSX_Debug|Any CPU.ActiveCfg = OSX_Debug|Any CPU
25+
{6F8576C2-6CD0-4DF3-8394-00B002D82E40}.OSX_Debug|Any CPU.Build.0 = OSX_Debug|Any CPU
26+
{6F8576C2-6CD0-4DF3-8394-00B002D82E40}.OSX_Release|Any CPU.ActiveCfg = OSX_Release|Any CPU
27+
{6F8576C2-6CD0-4DF3-8394-00B002D82E40}.OSX_Release|Any CPU.Build.0 = OSX_Release|Any CPU
28+
{6F8576C2-6CD0-4DF3-8394-00B002D82E40}.Windows_Debug|Any CPU.ActiveCfg = Windows_Debug|Any CPU
29+
{6F8576C2-6CD0-4DF3-8394-00B002D82E40}.Windows_Debug|Any CPU.Build.0 = Windows_Debug|Any CPU
30+
{6F8576C2-6CD0-4DF3-8394-00B002D82E40}.Windows_Release|Any CPU.ActiveCfg = Windows_Release|Any CPU
31+
{6F8576C2-6CD0-4DF3-8394-00B002D82E40}.Windows_Release|Any CPU.Build.0 = Windows_Release|Any CPU
32+
{A28B0064-EFB2-4B77-B97C-DECF5DAB074E}.Linux_Debug|Any CPU.ActiveCfg = Debug|Any CPU
33+
{A28B0064-EFB2-4B77-B97C-DECF5DAB074E}.Linux_Debug|Any CPU.Build.0 = Debug|Any CPU
34+
{A28B0064-EFB2-4B77-B97C-DECF5DAB074E}.Linux_Release|Any CPU.ActiveCfg = Debug|Any CPU
35+
{A28B0064-EFB2-4B77-B97C-DECF5DAB074E}.Linux_Release|Any CPU.Build.0 = Debug|Any CPU
36+
{A28B0064-EFB2-4B77-B97C-DECF5DAB074E}.OSX_Debug|Any CPU.ActiveCfg = Debug|Any CPU
37+
{A28B0064-EFB2-4B77-B97C-DECF5DAB074E}.OSX_Debug|Any CPU.Build.0 = Debug|Any CPU
38+
{A28B0064-EFB2-4B77-B97C-DECF5DAB074E}.OSX_Release|Any CPU.ActiveCfg = Debug|Any CPU
39+
{A28B0064-EFB2-4B77-B97C-DECF5DAB074E}.OSX_Release|Any CPU.Build.0 = Debug|Any CPU
40+
{A28B0064-EFB2-4B77-B97C-DECF5DAB074E}.Windows_Debug|Any CPU.ActiveCfg = Debug|Any CPU
41+
{A28B0064-EFB2-4B77-B97C-DECF5DAB074E}.Windows_Debug|Any CPU.Build.0 = Debug|Any CPU
42+
{A28B0064-EFB2-4B77-B97C-DECF5DAB074E}.Windows_Release|Any CPU.ActiveCfg = Debug|Any CPU
43+
{A28B0064-EFB2-4B77-B97C-DECF5DAB074E}.Windows_Release|Any CPU.Build.0 = Debug|Any CPU
44+
EndGlobalSection
45+
GlobalSection(SolutionProperties) = preSolution
46+
HideSolutionNode = FALSE
47+
EndGlobalSection
48+
EndGlobal
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System;
5+
using System.Text;
6+
using System.Diagnostics;
7+
using System.Globalization;
8+
using System.Security.Cryptography;
9+
10+
namespace Internal.Cryptography
11+
{
12+
//
13+
// Error codes for specific throw sites. Defined outside of Internal.Crytography.Pal.Native as some non-Pal code uses these.
14+
// Since these error codes are publically surfaced through the Exception class, these hresults are effectively managed exchange values despite
15+
// their Win32 origin.
16+
//
17+
internal static class ErrorCode
18+
{
19+
public const int CERT_E_CHAINING = unchecked((int)0x800B010A);
20+
public const int CERT_E_EXPIRED = unchecked((int)0x800B0101);
21+
public const int CERT_E_INVALID_NAME = unchecked((int)0x800B0114);
22+
public const int CERT_E_INVALID_POLICY = unchecked((int)0x800B0113);
23+
public const int CERT_E_UNTRUSTEDROOT = unchecked((int)0x800B0109);
24+
public const int CERT_E_VALIDITYPERIODNESTING = unchecked((int)0x800B0102);
25+
public const int CERT_E_WRONG_USAGE = unchecked((int)0x800B0110);
26+
public const int CRYPT_E_NO_REVOCATION_CHECK = unchecked((int)0x80092012);
27+
public const int CRYPT_E_NOT_FOUND = unchecked((int)0x80092004);
28+
public const int CRYPT_E_REVOCATION_OFFLINE = unchecked((int)0x80092013);
29+
public const int CRYPT_E_REVOKED = unchecked((int)0x80092010);
30+
public const int CRYPT_E_SIGNER_NOT_FOUND = unchecked((int)0x8009100e);
31+
public const int E_POINTER = unchecked((int)0x80004003);
32+
public const int ERROR_INVALID_PARAMETER = 0x00000057;
33+
public const int HRESULT_INVALID_HANDLE = unchecked((int)0x80070006);
34+
public const int NTE_BAD_PUBLIC_KEY = unchecked((int)0x80090015);
35+
public const int TRUST_E_BASIC_CONSTRAINTS = unchecked((int)0x80096019);
36+
public const int TRUST_E_CERT_SIGNATURE = unchecked((int)0x80096004);
37+
}
38+
}

0 commit comments

Comments
 (0)