mscorlib(4.0.0.0) API with additions
X509Chain.cs
1 using Microsoft.Win32.SafeHandles;
2 using System.Net;
6 
8 {
10  public class X509Chain : IDisposable
11  {
12  private struct X509ChainErrorMapping
13  {
14  public readonly uint Win32Flag;
15 
16  public readonly int Win32ErrorCode;
17 
18  public readonly X509ChainStatusFlags ChainStatusFlag;
19 
20  public X509ChainErrorMapping(uint win32Flag, int win32ErrorCode, X509ChainStatusFlags chainStatusFlag)
21  {
22  Win32Flag = win32Flag;
23  Win32ErrorCode = win32ErrorCode;
24  ChainStatusFlag = chainStatusFlag;
25  }
26  }
27 
28  private uint m_status;
29 
30  private X509ChainPolicy m_chainPolicy;
31 
32  private X509ChainStatus[] m_chainStatus;
33 
34  private X509ChainElementCollection m_chainElementCollection;
35 
36  [SecurityCritical]
37  private SafeX509ChainHandle m_safeCertChainHandle;
38 
39  private bool m_useMachineContext;
40 
41  private readonly object m_syncRoot = new object();
42 
43  private static readonly X509ChainErrorMapping[] s_x509ChainErrorMappings = new X509ChainErrorMapping[23]
44  {
45  new X509ChainErrorMapping(8u, -2146869244, X509ChainStatusFlags.NotSignatureValid),
46  new X509ChainErrorMapping(262144u, -2146869244, X509ChainStatusFlags.CtlNotSignatureValid),
47  new X509ChainErrorMapping(32u, -2146762487, X509ChainStatusFlags.UntrustedRoot),
48  new X509ChainErrorMapping(65536u, -2146762486, X509ChainStatusFlags.PartialChain),
49  new X509ChainErrorMapping(4u, -2146885616, X509ChainStatusFlags.Revoked),
50  new X509ChainErrorMapping(16u, -2146762480, X509ChainStatusFlags.NotValidForUsage),
51  new X509ChainErrorMapping(524288u, -2146762480, X509ChainStatusFlags.CtlNotValidForUsage),
52  new X509ChainErrorMapping(1u, -2146762495, X509ChainStatusFlags.NotTimeValid),
53  new X509ChainErrorMapping(131072u, -2146762495, X509ChainStatusFlags.CtlNotTimeValid),
54  new X509ChainErrorMapping(2048u, -2146762476, X509ChainStatusFlags.InvalidNameConstraints),
55  new X509ChainErrorMapping(4096u, -2146762476, X509ChainStatusFlags.HasNotSupportedNameConstraint),
56  new X509ChainErrorMapping(8192u, -2146762476, X509ChainStatusFlags.HasNotDefinedNameConstraint),
57  new X509ChainErrorMapping(16384u, -2146762476, X509ChainStatusFlags.HasNotPermittedNameConstraint),
58  new X509ChainErrorMapping(32768u, -2146762476, X509ChainStatusFlags.HasExcludedNameConstraint),
59  new X509ChainErrorMapping(512u, -2146762477, X509ChainStatusFlags.InvalidPolicyConstraints),
60  new X509ChainErrorMapping(33554432u, -2146762477, X509ChainStatusFlags.NoIssuanceChainPolicy),
61  new X509ChainErrorMapping(1024u, -2146869223, X509ChainStatusFlags.InvalidBasicConstraints),
62  new X509ChainErrorMapping(2u, -2146762494, X509ChainStatusFlags.NotTimeNested),
63  new X509ChainErrorMapping(64u, -2146885614, X509ChainStatusFlags.RevocationStatusUnknown),
64  new X509ChainErrorMapping(16777216u, -2146885613, X509ChainStatusFlags.OfflineRevocation),
65  new X509ChainErrorMapping(67108864u, -2146762479, X509ChainStatusFlags.ExplicitDistrust),
66  new X509ChainErrorMapping(134217728u, -2146762491, X509ChainStatusFlags.HasNotSupportedCriticalExtension),
67  new X509ChainErrorMapping(1048576u, -2146877418, X509ChainStatusFlags.HasWeakSignature)
68  };
69 
72  public IntPtr ChainContext
73  {
74  [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
75  [SecurityPermission(SecurityAction.InheritanceDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
76  get
77  {
78  return m_safeCertChainHandle.DangerousGetHandle();
79  }
80  }
81 
84  public SafeX509ChainHandle SafeHandle
85  {
86  [SecurityCritical]
87  [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
88  [SecurityPermission(SecurityAction.InheritanceDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
89  get
90  {
91  return m_safeCertChainHandle;
92  }
93  }
94 
99  {
100  get
101  {
102  if (m_chainPolicy == null)
103  {
104  m_chainPolicy = new X509ChainPolicy();
105  }
106  return m_chainPolicy;
107  }
108  set
109  {
110  if (value == null)
111  {
112  throw new ArgumentNullException("value");
113  }
114  m_chainPolicy = value;
115  }
116  }
117 
121  {
122  get
123  {
124  if (m_chainStatus == null)
125  {
126  if (m_status == 0)
127  {
128  m_chainStatus = new X509ChainStatus[0];
129  }
130  else
131  {
132  m_chainStatus = GetChainStatusInformation(m_status);
133  }
134  }
135  return m_chainStatus;
136  }
137  }
138 
141  public X509ChainElementCollection ChainElements => m_chainElementCollection;
142 
145  public static X509Chain Create()
146  {
147  return (X509Chain)CryptoConfig.CreateFromName("X509Chain");
148  }
149 
151  [SecurityCritical]
152  public X509Chain()
153  : this(useMachineContext: false)
154  {
155  }
156 
160  [SecurityCritical]
161  public X509Chain(bool useMachineContext)
162  {
163  m_status = 0u;
164  m_chainPolicy = null;
165  m_chainStatus = null;
166  m_chainElementCollection = new X509ChainElementCollection();
167  m_safeCertChainHandle = SafeX509ChainHandle.InvalidHandle;
168  m_useMachineContext = useMachineContext;
169  }
170 
175  [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
176  [SecurityPermission(SecurityAction.InheritanceDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
177  public X509Chain(IntPtr chainContext)
178  {
179  if (chainContext == IntPtr.Zero)
180  {
181  throw new ArgumentNullException("chainContext");
182  }
183  m_safeCertChainHandle = CAPISafe.CertDuplicateCertificateChain(chainContext);
184  if (m_safeCertChainHandle == null || m_safeCertChainHandle == SafeX509ChainHandle.InvalidHandle)
185  {
186  throw new CryptographicException(SR.GetString("Cryptography_InvalidContextHandle"), "chainContext");
187  }
188  Init();
189  }
190 
197  [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
198  [PermissionSet(SecurityAction.InheritanceDemand, Unrestricted = true)]
199  public bool Build(X509Certificate2 certificate)
200  {
201  lock (m_syncRoot)
202  {
203  if (certificate == null || certificate.CertContext.IsInvalid)
204  {
205  throw new ArgumentException(SR.GetString("Cryptography_InvalidContextHandle"), "certificate");
206  }
207  StorePermission storePermission = new StorePermission(StorePermissionFlags.OpenStore | StorePermissionFlags.EnumerateCertificates);
208  storePermission.Demand();
209  X509ChainPolicy chainPolicy = ChainPolicy;
210  if (chainPolicy.RevocationMode == X509RevocationMode.Online && (certificate.Extensions["2.5.29.31"] != null || certificate.Extensions["1.3.6.1.5.5.7.1.1"] != null))
211  {
212  PermissionSet permissionSet = new PermissionSet(PermissionState.None);
213  permissionSet.AddPermission(new WebPermission(PermissionState.Unrestricted));
214  permissionSet.AddPermission(new StorePermission(StorePermissionFlags.AddToStore));
215  permissionSet.Demand();
216  }
217  Reset();
218  if (BuildChain(m_useMachineContext ? new IntPtr(1L) : new IntPtr(0L), certificate.CertContext, chainPolicy.ExtraStore, chainPolicy.ApplicationPolicy, chainPolicy.CertificatePolicy, chainPolicy.RevocationMode, chainPolicy.RevocationFlag, chainPolicy.VerificationTime, chainPolicy.UrlRetrievalTimeout, ref m_safeCertChainHandle) != 0)
219  {
220  return false;
221  }
222  Init();
223  CAPIBase.CERT_CHAIN_POLICY_PARA pPolicyPara = new CAPIBase.CERT_CHAIN_POLICY_PARA(Marshal.SizeOf(typeof(CAPIBase.CERT_CHAIN_POLICY_PARA)));
224  CAPIBase.CERT_CHAIN_POLICY_STATUS pPolicyStatus = new CAPIBase.CERT_CHAIN_POLICY_STATUS(Marshal.SizeOf(typeof(CAPIBase.CERT_CHAIN_POLICY_STATUS)));
225  pPolicyPara.dwFlags = (uint)chainPolicy.VerificationFlags;
226  if (!CAPISafe.CertVerifyCertificateChainPolicy(new IntPtr(1L), m_safeCertChainHandle, ref pPolicyPara, ref pPolicyStatus))
227  {
229  }
230  CAPISafe.SetLastError(pPolicyStatus.dwError);
231  return pPolicyStatus.dwError == 0;
232  }
233  }
234 
236  [SecurityCritical]
237  [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
238  [PermissionSet(SecurityAction.InheritanceDemand, Unrestricted = true)]
239  public void Reset()
240  {
241  m_status = 0u;
242  m_chainStatus = null;
243  m_chainElementCollection = new X509ChainElementCollection();
244  if (!m_safeCertChainHandle.IsInvalid)
245  {
246  m_safeCertChainHandle.Dispose();
247  m_safeCertChainHandle = SafeX509ChainHandle.InvalidHandle;
248  }
249  }
250 
252  [SecuritySafeCritical]
253  public void Dispose()
254  {
255  Dispose(disposing: true);
256  GC.SuppressFinalize(this);
257  }
258 
262  [SecuritySafeCritical]
263  protected virtual void Dispose(bool disposing)
264  {
265  if (disposing)
266  {
267  Reset();
268  }
269  }
270 
271  [SecurityCritical]
272  private unsafe void Init()
273  {
274  using (SafeX509ChainHandle safeX509ChainHandle = CAPISafe.CertDuplicateCertificateChain(m_safeCertChainHandle))
275  {
276  CAPIBase.CERT_CHAIN_CONTEXT cERT_CHAIN_CONTEXT = new CAPIBase.CERT_CHAIN_CONTEXT(Marshal.SizeOf(typeof(CAPIBase.CERT_CHAIN_CONTEXT)));
277  uint num = (uint)Marshal.ReadInt32(safeX509ChainHandle.DangerousGetHandle());
278  if (num > Marshal.SizeOf((object)cERT_CHAIN_CONTEXT))
279  {
280  num = (uint)Marshal.SizeOf((object)cERT_CHAIN_CONTEXT);
281  }
282  System.Security.Cryptography.X509Certificates.X509Utils.memcpy(m_safeCertChainHandle.DangerousGetHandle(), new IntPtr(&cERT_CHAIN_CONTEXT), num);
283  m_status = cERT_CHAIN_CONTEXT.dwErrorStatus;
284  m_chainElementCollection = new X509ChainElementCollection(Marshal.ReadIntPtr(cERT_CHAIN_CONTEXT.rgpChain));
285  }
286  }
287 
288  internal static X509ChainStatus[] GetChainStatusInformation(uint dwStatus)
289  {
290  if (dwStatus == 0)
291  {
292  return new X509ChainStatus[0];
293  }
294  int num = 0;
295  for (uint num2 = dwStatus; num2 != 0; num2 >>= 1)
296  {
297  if ((num2 & 1) != 0)
298  {
299  num++;
300  }
301  }
302  X509ChainStatus[] array = new X509ChainStatus[num];
303  int num3 = 0;
304  X509ChainErrorMapping[] array2 = s_x509ChainErrorMappings;
305  foreach (X509ChainErrorMapping x509ChainErrorMapping in array2)
306  {
307  if ((dwStatus & x509ChainErrorMapping.Win32Flag) != 0)
308  {
309  array[num3].StatusInformation = System.Security.Cryptography.X509Certificates.X509Utils.GetSystemErrorString(x509ChainErrorMapping.Win32ErrorCode);
310  array[num3].Status = x509ChainErrorMapping.ChainStatusFlag;
311  num3++;
312  dwStatus &= ~x509ChainErrorMapping.Win32Flag;
313  }
314  }
315  int num4 = 0;
316  for (uint num5 = dwStatus; num5 != 0; num5 >>= 1)
317  {
318  if ((num5 & 1) != 0)
319  {
320  array[num3].Status = (X509ChainStatusFlags)(1 << num4);
321  array[num3].StatusInformation = SR.GetString("Unknown_Error");
322  num3++;
323  }
324  num4++;
325  }
326  return array;
327  }
328 
329  [SecurityCritical]
330  internal unsafe static int BuildChain(IntPtr hChainEngine, System.Security.Cryptography.SafeCertContextHandle pCertContext, X509Certificate2Collection extraStore, OidCollection applicationPolicy, OidCollection certificatePolicy, X509RevocationMode revocationMode, X509RevocationFlag revocationFlag, DateTime verificationTime, TimeSpan timeout, ref SafeX509ChainHandle ppChainContext)
331  {
332  if (pCertContext == null || pCertContext.IsInvalid)
333  {
334  throw new ArgumentException(SR.GetString("Cryptography_InvalidContextHandle"), "pCertContext");
335  }
337  if (extraStore != null && extraStore.Count > 0)
338  {
339  hAdditionalStore = System.Security.Cryptography.X509Certificates.X509Utils.ExportToMemoryStore(extraStore);
340  }
341  CAPIBase.CERT_CHAIN_PARA pChainPara = default(CAPIBase.CERT_CHAIN_PARA);
342  pChainPara.cbSize = (uint)Marshal.SizeOf((object)pChainPara);
343  SafeLocalAllocHandle safeLocalAllocHandle = SafeLocalAllocHandle.InvalidHandle;
344  SafeLocalAllocHandle safeLocalAllocHandle2 = SafeLocalAllocHandle.InvalidHandle;
345  try
346  {
347  if (applicationPolicy != null && applicationPolicy.Count > 0)
348  {
349  pChainPara.RequestedUsage.dwType = 0u;
350  pChainPara.RequestedUsage.Usage.cUsageIdentifier = (uint)applicationPolicy.Count;
351  safeLocalAllocHandle = System.Security.Cryptography.X509Certificates.X509Utils.CopyOidsToUnmanagedMemory(applicationPolicy);
352  pChainPara.RequestedUsage.Usage.rgpszUsageIdentifier = safeLocalAllocHandle.DangerousGetHandle();
353  }
354  if (certificatePolicy != null && certificatePolicy.Count > 0)
355  {
356  pChainPara.RequestedIssuancePolicy.dwType = 0u;
357  pChainPara.RequestedIssuancePolicy.Usage.cUsageIdentifier = (uint)certificatePolicy.Count;
358  safeLocalAllocHandle2 = System.Security.Cryptography.X509Certificates.X509Utils.CopyOidsToUnmanagedMemory(certificatePolicy);
359  pChainPara.RequestedIssuancePolicy.Usage.rgpszUsageIdentifier = safeLocalAllocHandle2.DangerousGetHandle();
360  }
361  pChainPara.dwUrlRetrievalTimeout = (uint)Math.Floor(timeout.TotalMilliseconds);
363  *(long*)(&pTime) = verificationTime.ToFileTime();
364  uint dwFlags = System.Security.Cryptography.X509Certificates.X509Utils.MapRevocationFlags(revocationMode, revocationFlag);
365  if (!CAPISafe.CertGetCertificateChain(hChainEngine, pCertContext, ref pTime, hAdditionalStore, ref pChainPara, dwFlags, IntPtr.Zero, ref ppChainContext))
366  {
368  }
369  }
370  finally
371  {
372  safeLocalAllocHandle.Dispose();
373  safeLocalAllocHandle2.Dispose();
374  }
375  return 0;
376  }
377  }
378 }
The exception that is thrown when an error occurs during a cryptographic operation.
static int ReadInt32([In] [MarshalAs(UnmanagedType.AsAny)] object ptr, int ofs)
Reads a 32-bit signed integer at a given offset from unmanaged memory.
The exception that is thrown when a null reference (Nothing in Visual Basic) is passed to a method th...
Describes a set of security permissions applied to code. This class cannot be inherited.
void Dispose()
Releases all of the resources used by this T:System.Security.Cryptography.X509Certificates....
Definition: X509Chain.cs:253
X509Chain(bool useMachineContext)
Initializes a new instance of the T:System.Security.Cryptography.X509Certificates....
Definition: X509Chain.cs:161
X509Certificate2Collection ExtraStore
Represents an additional collection of certificates that can be searched by the chaining engine when ...
static void SuppressFinalize(object obj)
Requests that the common language runtime not call the finalizer for the specified object.
Definition: GC.cs:308
void Demand()
Forces a T:System.Security.SecurityException at run time if all callers higher in the call stack have...
Provides a simple structure for storing X509 chain status and error information.
virtual void Dispose(bool disposing)
Releases the unmanaged resources used by this T:System.Security.Cryptography.X509Certificates....
Definition: X509Chain.cs:263
Provides a mechanism for releasing unmanaged resources.To browse the .NET Framework source code for t...
Definition: IDisposable.cs:8
static object CreateFromName(string name, params object[] args)
Creates a new instance of the specified cryptographic object with the specified arguments.
Definition: __Canon.cs:3
static int SizeOf(object structure)
Returns the unmanaged size of an object in bytes.
Definition: Marshal.cs:159
X509ChainPolicy ChainPolicy
Gets or sets the T:System.Security.Cryptography.X509Certificates.X509ChainPolicy to use when building...
Definition: X509Chain.cs:99
Represents a collection of T:System.Security.Cryptography.X509Certificates.X509ChainElement objects....
static int GetHRForLastWin32Error()
Returns the HRESULT corresponding to the last error incurred by Win32 code executed using T:System....
Definition: Marshal.cs:1072
X509RevocationFlag RevocationFlag
Gets or sets values for X509 revocation flags.
X509RevocationMode
Specifies the mode used to check for X509 certificate revocation.
IPermission AddPermission(IPermission perm)
Adds a specified permission to the T:System.Security.PermissionSet.
Represents a wrapper class for operating system handles. This class must be inherited.
Definition: SafeHandle.cs:12
DateTime VerificationTime
The time that the certificate was verified expressed in local time.
SecurityAction
Specifies the security actions that can be performed using declarative security.
X509ExtensionCollection Extensions
Gets a collection of T:System.Security.Cryptography.X509Certificates.X509Extension objects.
Represents a collection that can contain many different types of permissions.
Accesses the cryptography configuration information.
Definition: CryptoConfig.cs:17
bool Build(X509Certificate2 certificate)
Builds an X.509 chain using the policy specified in T:System.Security.Cryptography....
Definition: X509Chain.cs:199
OidCollection CertificatePolicy
Gets a collection of object identifiers (OIDs) specifying which certificate policies the certificate ...
Controls rights to access HTTP Internet resources.
Controls access to stores containing X.509 certificates. This class cannot be inherited.
A platform-specific type that is used to represent a pointer or a handle.
Definition: IntPtr.cs:14
X509VerificationFlags VerificationFlags
Gets verification flags for the certificate.
Represents the chain policy to be applied when building an X509 certificate chain....
Provides a collection of methods for allocating unmanaged memory, copying unmanaged memory blocks,...
Definition: Marshal.cs:15
Represents a chain-building engine for T:System.Security.Cryptography.X509Certificates....
Definition: X509Chain.cs:10
X509ChainStatus [] ChainStatus
Gets the status of each element in an T:System.Security.Cryptography.X509Certificates....
Definition: X509Chain.cs:121
Controls the system garbage collector, a service that automatically reclaims unused memory.
Definition: GC.cs:11
static X509Chain Create()
Creates an T:System.Security.Cryptography.X509Certificates.X509Chain object after querying for the ma...
Definition: X509Chain.cs:145
StorePermissionFlags
Specifies the permitted access to X.509 certificate stores.
The exception that is thrown when one of the arguments provided to a method is not valid.
void Demand()
Forces a T:System.Security.SecurityException at run time if all callers higher in the call stack have...
Represents the number of 100-nanosecond intervals since January 1, 1601. This structure is a 64-bit v...
Definition: FILETIME.cs:5
PermissionState
Specifies whether a permission should have all or no access to resources at creation.
static readonly IntPtr Zero
A read-only field that represents a pointer or handle that has been initialized to zero.
Definition: IntPtr.cs:20
IntPtr ChainContext
Gets a handle to an X.509 chain.
Definition: X509Chain.cs:73
X509Chain()
Initializes a new instance of the T:System.Security.Cryptography.X509Certificates....
Definition: X509Chain.cs:152
void Reset()
Clears the current T:System.Security.Cryptography.X509Certificates.X509Chain object.
Definition: X509Chain.cs:239
TimeSpan UrlRetrievalTimeout
Gets the time span that elapsed during online revocation verification or downloading the certificate ...
X509ChainStatusFlags
Defines the status of an X509 chain.
static int GetLastWin32Error()
Returns the error code returned by the last unmanaged function that was called using platform invoke ...
X509RevocationMode RevocationMode
Gets or sets values for X509 certificate revocation mode.
SecurityPermissionFlag
Specifies access flags for the security permission object.
X509ChainElementCollection ChainElements
Gets a collection of T:System.Security.Cryptography.X509Certificates.X509ChainElement objects.
Definition: X509Chain.cs:141
X509RevocationFlag
Specifies which X509 certificates in the chain should be checked for revocation.
X509Chain(IntPtr chainContext)
Initializes a new instance of the T:System.Security.Cryptography.X509Certificates....
Definition: X509Chain.cs:177
OidCollection ApplicationPolicy
Gets a collection of object identifiers (OIDs) specifying which application policies or enhanced key ...
static IntPtr ReadIntPtr([In] [MarshalAs(UnmanagedType.AsAny)] object ptr, int ofs)
Reads a processor native sized integer from unmanaged memory.
Definition: Marshal.cs:681