Code:
/ DotNET / DotNET / 8.0 / untmp / whidbey / REDBITS / ndp / fx / src / security / system / security / cryptography / x509 / X509Certificate2.cs / 3 / X509Certificate2.cs
// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== // // X509Certificate2.cs // // 09/22/2002 // namespace System.Security.Cryptography.X509Certificates { using System; using System.Diagnostics; using System.IO; using System.Text; using System.Reflection; using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; using System.Security.Cryptography; using System.Security.Permissions; using _FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME; public enum X509NameType { SimpleName = 0, EmailName, UpnName, DnsName, DnsFromAlternativeName, UrlName } public enum X509IncludeOption { None = 0, ExcludeRoot, EndCertOnly, WholeChain } public sealed class PublicKey { private AsnEncodedData m_encodedKeyValue; private AsnEncodedData m_encodedParameters; private Oid m_oid; private uint m_aiPubKey = 0; private byte[] m_cspBlobData = null; private AsymmetricAlgorithm m_key = null; private PublicKey() {} public PublicKey (Oid oid, AsnEncodedData parameters, AsnEncodedData keyValue) { m_oid = new Oid(oid); m_encodedParameters = new AsnEncodedData(parameters); m_encodedKeyValue = new AsnEncodedData(keyValue); } internal PublicKey (PublicKey publicKey) { m_oid = new Oid(publicKey.m_oid); m_encodedParameters = new AsnEncodedData(publicKey.m_encodedParameters); m_encodedKeyValue = new AsnEncodedData(publicKey.m_encodedKeyValue); } internal uint AlgorithmId { get { if (m_aiPubKey == 0) m_aiPubKey = X509Utils.OidToAlgId(m_oid.Value); return m_aiPubKey; } } private byte[] CspBlobData { get { if (m_cspBlobData == null) DecodePublicKeyObject(AlgorithmId, m_encodedKeyValue.RawData, m_encodedParameters.RawData, out m_cspBlobData); return m_cspBlobData; } } public AsymmetricAlgorithm Key { get { if (m_key == null) { switch (AlgorithmId) { case CAPI.CALG_RSA_KEYX: case CAPI.CALG_RSA_SIGN: RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); rsa.ImportCspBlob(CspBlobData); m_key = rsa; break; case CAPI.CALG_DSS_SIGN: DSACryptoServiceProvider dsa = new DSACryptoServiceProvider(); dsa.ImportCspBlob(CspBlobData); m_key = dsa; break; default: throw new NotSupportedException(SR.GetString(SR.NotSupported_KeyAlgorithm)); } } return m_key; } } public Oid Oid { get { return new Oid(m_oid); } } public AsnEncodedData EncodedKeyValue { get { return m_encodedKeyValue; } } public AsnEncodedData EncodedParameters { get { return m_encodedParameters; } } // // private static methods. // private static void DecodePublicKeyObject(uint aiPubKey, byte[] encodedKeyValue, byte[] encodedParameters, out byte[] decodedData) { // Initialize the out parameter decodedData = null; IntPtr pszStructType = IntPtr.Zero; switch (aiPubKey) { case CAPI.CALG_DSS_SIGN: pszStructType = new IntPtr(CAPI.X509_DSS_PUBLICKEY); break; case CAPI.CALG_RSA_SIGN: case CAPI.CALG_RSA_KEYX: pszStructType = new IntPtr(CAPI.RSA_CSP_PUBLICKEYBLOB); break; case CAPI.CALG_DH_SF: case CAPI.CALG_DH_EPHEM: // We don't support DH for now throw new NotSupportedException(SR.GetString(SR.NotSupported_KeyAlgorithm)); default: // We should never get here Debug.Assert(false); throw new NotSupportedException(SR.GetString(SR.NotSupported_KeyAlgorithm)); } SafeLocalAllocHandle decodedKeyValue = null; uint cbDecodedKeyValue = 0; bool result = CAPI.DecodeObject(pszStructType, encodedKeyValue, out decodedKeyValue, out cbDecodedKeyValue); if (!result) throw new CryptographicException(Marshal.GetLastWin32Error()); if ((uint) pszStructType == CAPI.RSA_CSP_PUBLICKEYBLOB) { decodedData = new byte[cbDecodedKeyValue]; Marshal.Copy(decodedKeyValue.DangerousGetHandle(), decodedData, 0, decodedData.Length); } else if ((uint) pszStructType == CAPI.X509_DSS_PUBLICKEY) { // We need to decode the parameters as well SafeLocalAllocHandle decodedParameters = null; uint cbDecodedParameters = 0; result = CAPI.DecodeObject(new IntPtr(CAPI.X509_DSS_PARAMETERS), encodedParameters, out decodedParameters, out cbDecodedParameters); if (!result) throw new CryptographicException(Marshal.GetLastWin32Error()); decodedData = ConstructDSSPubKeyCspBlob(decodedKeyValue, decodedParameters); decodedParameters.Dispose(); } decodedKeyValue.Dispose(); } private static byte[] ConstructDSSPubKeyCspBlob (SafeLocalAllocHandle decodedKeyValue, SafeLocalAllocHandle decodedParameters) { // The CAPI DSS public key representation consists of the following sequence: // - PUBLICKEYSTRUC // - DSSPUBKEY // - rgbP[cbKey] // - rgbQ[20] // - rgbG[cbKey] // - rgbY[cbKey] // - DSSSEED CAPI.CRYPTOAPI_BLOB pDssPubKey = (CAPI.CRYPTOAPI_BLOB) Marshal.PtrToStructure(decodedKeyValue.DangerousGetHandle(), typeof(CAPI.CRYPTOAPI_BLOB)); CAPI.CERT_DSS_PARAMETERS pDssParameters = (CAPI.CERT_DSS_PARAMETERS) Marshal.PtrToStructure(decodedParameters.DangerousGetHandle(), typeof(CAPI.CERT_DSS_PARAMETERS)); uint cbKey = pDssParameters.p.cbData; if (cbKey == 0) throw new CryptographicException(CAPI.NTE_BAD_PUBLIC_KEY); const uint DSS_Q_LEN = 20; uint cbKeyBlob = 8 /* sizeof(CAPI.BLOBHEADER) */ + 8 /* sizeof(CAPI.DSSPUBKEY) */ + cbKey + DSS_Q_LEN + cbKey + cbKey + 24 /* sizeof(CAPI.DSSSEED) */; MemoryStream keyBlob = new MemoryStream((int) cbKeyBlob); BinaryWriter bw = new BinaryWriter(keyBlob); // PUBLICKEYSTRUC bw.Write(CAPI.PUBLICKEYBLOB); // pPubKeyStruc->bType = PUBLICKEYBLOB bw.Write(CAPI.CUR_BLOB_VERSION); // pPubKeyStruc->bVersion = CUR_BLOB_VERSION bw.Write((short) 0); // pPubKeyStruc->reserved = 0; bw.Write(CAPI.CALG_DSS_SIGN); // pPubKeyStruc->aiKeyAlg = CALG_DSS_SIGN; // DSSPUBKEY bw.Write(CAPI.DSS_MAGIC); // pCspPubKey->magic = DSS_MAGIC; We are constructing a DSS1 Csp blob. bw.Write(cbKey * 8); // pCspPubKey->bitlen = cbKey * 8; // rgbP[cbKey] byte[] p = new byte[pDssParameters.p.cbData]; Marshal.Copy(pDssParameters.p.pbData, p, 0, p.Length); bw.Write(p); // rgbQ[20] uint cb = pDssParameters.q.cbData; if (cb == 0 || cb > DSS_Q_LEN) throw new CryptographicException(CAPI.NTE_BAD_PUBLIC_KEY); byte[] q = new byte[pDssParameters.q.cbData]; Marshal.Copy(pDssParameters.q.pbData, q, 0, q.Length); bw.Write(q); if (DSS_Q_LEN > cb) bw.Write(new byte[DSS_Q_LEN - cb]); // rgbG[cbKey] cb = pDssParameters.g.cbData; if (cb == 0 || cb > cbKey) throw new CryptographicException(CAPI.NTE_BAD_PUBLIC_KEY); byte[] g = new byte[pDssParameters.g.cbData]; Marshal.Copy(pDssParameters.g.pbData, g, 0, g.Length); bw.Write(g); if (cbKey > cb) bw.Write(new byte[cbKey - cb]); // rgbY[cbKey] cb = pDssPubKey.cbData; if (cb == 0 || cb > cbKey) throw new CryptographicException(CAPI.NTE_BAD_PUBLIC_KEY); byte[] y = new byte[pDssPubKey.cbData]; Marshal.Copy(pDssPubKey.pbData, y, 0, y.Length); bw.Write(y); if (cbKey > cb) bw.Write(new byte[cbKey - cb]); // DSSSEED: set counter to 0xFFFFFFFF to indicate not available bw.Write(0xFFFFFFFF); bw.Write(new byte[20]); return keyBlob.ToArray(); } } public class X509Certificate2 : X509Certificate { private int m_version; private DateTime m_notBefore; private DateTime m_notAfter; private AsymmetricAlgorithm m_privateKey; private PublicKey m_publicKey; private X509ExtensionCollection m_extensions; private Oid m_signatureAlgorithm; private X500DistinguishedName m_subjectName; private X500DistinguishedName m_issuerName; private SafeCertContextHandle m_safeCertContext = SafeCertContextHandle.InvalidHandle; private bool m_randomKeyContainer; private static int s_publicKeyOffset; // // public constructors // public X509Certificate2 () : base() {} public X509Certificate2 (byte[] rawData) : base (rawData) { m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle); m_randomKeyContainer = true; } public X509Certificate2 (byte[] rawData, string password) : base (rawData, password) { m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle); m_randomKeyContainer = true; } public X509Certificate2 (byte[] rawData, SecureString password) : base (rawData, password) { m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle); m_randomKeyContainer = true; } public X509Certificate2 (byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags) : base (rawData, password, keyStorageFlags) { m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle); m_randomKeyContainer = true; } public X509Certificate2 (byte[] rawData, SecureString password, X509KeyStorageFlags keyStorageFlags) : base (rawData, password, keyStorageFlags) { m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle); m_randomKeyContainer = true; } public X509Certificate2 (string fileName) : base (fileName) { m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle); m_randomKeyContainer = true; } public X509Certificate2 (string fileName, string password) : base (fileName, password) { m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle); m_randomKeyContainer = true; } public X509Certificate2 (string fileName, SecureString password) : base (fileName, password) { m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle); m_randomKeyContainer = true; } public X509Certificate2 (string fileName, string password, X509KeyStorageFlags keyStorageFlags) : base (fileName, password, keyStorageFlags) { m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle); m_randomKeyContainer = true; } public X509Certificate2 (string fileName, SecureString password, X509KeyStorageFlags keyStorageFlags) : base (fileName, password, keyStorageFlags) { m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle); m_randomKeyContainer = true; } // Package protected constructor for creating a certificate from a PCCERT_CONTEXT [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] [SecurityPermissionAttribute(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] public X509Certificate2 (IntPtr handle) : base (handle) { m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle); } public X509Certificate2 (X509Certificate certificate) : base(certificate) { m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle); X509Certificate2 source = certificate as X509Certificate2; if (source != null) m_randomKeyContainer = source.m_randomKeyContainer; } public override string ToString() { return base.ToString(true); } public override string ToString(bool verbose) { if (verbose == false || m_safeCertContext.IsInvalid) return ToString(); StringBuilder sb = new StringBuilder(); // Version sb.Append("[Version]" + Environment.NewLine + " "); sb.Append("V" + this.Version); // Subject sb.Append(Environment.NewLine + Environment.NewLine + "[Subject]" + Environment.NewLine + " "); sb.Append(this.SubjectName.Name); string simpleName = GetNameInfo(X509NameType.SimpleName, false); if (simpleName.Length > 0) { sb.Append(Environment.NewLine + " Simple Name: "); sb.Append(simpleName); } string emailName = GetNameInfo(X509NameType.EmailName, false); if (emailName.Length > 0) { sb.Append(Environment.NewLine + " Email Name: "); sb.Append(emailName); } string upnName = GetNameInfo(X509NameType.UpnName, false); if (upnName.Length > 0) { sb.Append(Environment.NewLine + " UPN Name: "); sb.Append(upnName); } string dnsName = GetNameInfo(X509NameType.DnsName, false); if (dnsName.Length > 0) { sb.Append(Environment.NewLine + " DNS Name: "); sb.Append(dnsName); } // Issuer sb.Append(Environment.NewLine + Environment.NewLine + "[Issuer]" + Environment.NewLine + " "); sb.Append(this.IssuerName.Name); simpleName = GetNameInfo(X509NameType.SimpleName, true); if (simpleName.Length > 0) { sb.Append(Environment.NewLine + " Simple Name: "); sb.Append(simpleName); } emailName = GetNameInfo(X509NameType.EmailName, true); if (emailName.Length > 0) { sb.Append(Environment.NewLine + " Email Name: "); sb.Append(emailName); } upnName = GetNameInfo(X509NameType.UpnName, true); if (upnName.Length > 0) { sb.Append(Environment.NewLine + " UPN Name: "); sb.Append(upnName); } dnsName = GetNameInfo(X509NameType.DnsName, true); if (dnsName.Length > 0) { sb.Append(Environment.NewLine + " DNS Name: "); sb.Append(dnsName); } // Serial Number sb.Append(Environment.NewLine + Environment.NewLine + "[Serial Number]" + Environment.NewLine + " "); sb.Append(this.SerialNumber); // NotBefore sb.Append(Environment.NewLine + Environment.NewLine + "[Not Before]" + Environment.NewLine + " "); sb.Append(this.NotBefore); // NotAfter sb.Append(Environment.NewLine + Environment.NewLine + "[Not After]" + Environment.NewLine + " "); sb.Append(this.NotAfter); // Thumbprint sb.Append(Environment.NewLine + Environment.NewLine + "[Thumbprint]" + Environment.NewLine + " "); sb.Append(this.Thumbprint); // Signature Algorithm sb.Append(Environment.NewLine + Environment.NewLine + "[Signature Algorithm]" + Environment.NewLine + " "); sb.Append(this.SignatureAlgorithm.FriendlyName + "(" + this.SignatureAlgorithm.Value + ")"); // Public Key PublicKey pubKey = this.PublicKey; sb.Append(Environment.NewLine + Environment.NewLine + "[Public Key]" + Environment.NewLine + " Algorithm: "); sb.Append(pubKey.Oid.FriendlyName); sb.Append(Environment.NewLine + " Length: "); sb.Append(pubKey.Key.KeySize); sb.Append(Environment.NewLine + " Key Blob: "); sb.Append(pubKey.EncodedKeyValue.Format(true)); sb.Append(Environment.NewLine + " Parameters: "); sb.Append(pubKey.EncodedParameters.Format(true)); // Private key AppendPrivateKeyInfo(sb); // Extensions X509ExtensionCollection extensions = this.Extensions; if (extensions.Count > 0) { sb.Append(Environment.NewLine + Environment.NewLine + "[Extensions]"); foreach(X509Extension extension in extensions) { sb.Append(Environment.NewLine + "* " + extension.Oid.FriendlyName + "(" + extension.Oid.Value + "):" + Environment.NewLine + " " + extension.Format(true)); } } sb.Append(Environment.NewLine); return sb.ToString(); } public bool Archived { get { if (m_safeCertContext.IsInvalid) throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext"); uint cbData = 0; return CAPI.CertGetCertificateContextProperty(m_safeCertContext, CAPI.CERT_ARCHIVED_PROP_ID, SafeLocalAllocHandle.InvalidHandle, ref cbData); } set { SafeLocalAllocHandle ptr = SafeLocalAllocHandle.InvalidHandle; if (value == true) ptr = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(Marshal.SizeOf(typeof(CAPI.CRYPTOAPI_BLOB)))); if (!CAPI.CertSetCertificateContextProperty(m_safeCertContext, CAPI.CERT_ARCHIVED_PROP_ID, 0, ptr)) throw new CryptographicException(Marshal.GetLastWin32Error()); ptr.Dispose(); } } public X509ExtensionCollection Extensions { get { if (m_safeCertContext.IsInvalid) throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext"); if (m_extensions == null) m_extensions = new X509ExtensionCollection(m_safeCertContext); return m_extensions; } } public string FriendlyName { get { if (m_safeCertContext.IsInvalid) throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext"); SafeLocalAllocHandle ptr = SafeLocalAllocHandle.InvalidHandle; uint cbData = 0; if (!CAPI.CertGetCertificateContextProperty(m_safeCertContext, CAPI.CERT_FRIENDLY_NAME_PROP_ID, ptr, ref cbData)) return String.Empty; ptr = CAPI.LocalAlloc(CAPI.LMEM_FIXED, new IntPtr(cbData)); if (!CAPI.CertGetCertificateContextProperty(m_safeCertContext, CAPI.CERT_FRIENDLY_NAME_PROP_ID, ptr, ref cbData)) return String.Empty; string friendlyName = Marshal.PtrToStringUni(ptr.DangerousGetHandle()); ptr.Dispose(); return friendlyName; } set { if (m_safeCertContext.IsInvalid) throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext"); if (value == null) value = String.Empty; SetFriendlyNameExtendedProperty(m_safeCertContext, value); } } public X500DistinguishedName IssuerName { get { if (m_safeCertContext.IsInvalid) throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext"); if (m_issuerName == null) { unsafe { CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) m_safeCertContext.DangerousGetHandle()); CAPI.CERT_INFO pCertInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO)); m_issuerName = new X500DistinguishedName(pCertInfo.Issuer); } } return m_issuerName; } } public DateTime NotAfter { get { if (m_safeCertContext.IsInvalid) throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext"); if (m_notAfter == DateTime.MinValue) { unsafe { CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) m_safeCertContext.DangerousGetHandle()); CAPI.CERT_INFO pCertInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO)); long dt = (((long)(uint)pCertInfo.NotAfter.dwHighDateTime) << 32) | ((long)(uint)pCertInfo.NotAfter.dwLowDateTime); m_notAfter = DateTime.FromFileTime(dt); } } return m_notAfter; } } public DateTime NotBefore { get { if (m_safeCertContext.IsInvalid) throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext"); if (m_notBefore == DateTime.MinValue) { unsafe { CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) m_safeCertContext.DangerousGetHandle()); CAPI.CERT_INFO pCertInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO)); long dt = (((long)(uint)pCertInfo.NotBefore.dwHighDateTime) << 32) | ((long)(uint)pCertInfo.NotBefore.dwLowDateTime); m_notBefore = DateTime.FromFileTime(dt); } } return m_notBefore; } } public bool HasPrivateKey { get { if (m_safeCertContext.IsInvalid) throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext"); uint cbData = 0; return CAPI.CertGetCertificateContextProperty(m_safeCertContext, CAPI.CERT_KEY_PROV_INFO_PROP_ID, SafeLocalAllocHandle.InvalidHandle, ref cbData); } } // flag that RSACryptoServiceProvider will take to mean that the key container name was randomly generated private static uint randomKeyContainerFlag = 0xFFFFFFFF; private static uint RandomKeyContainerFlag { get { if(randomKeyContainerFlag == 0xFFFFFFFF) { FieldInfo keyContainerField = typeof(RSACryptoServiceProvider).GetField( "RandomKeyContainerFlag", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.DeclaredOnly); if (keyContainerField != null) randomKeyContainerFlag = (uint)keyContainerField.GetValue(null); else randomKeyContainerFlag = 0x00000000; } return randomKeyContainerFlag; } } public AsymmetricAlgorithm PrivateKey { get { if (!this.HasPrivateKey) return null; if (m_privateKey == null) { CspParameters parameters = new CspParameters(); if (!GetPrivateKeyInfo(m_safeCertContext, ref parameters)) return null; // We never want to stomp over certificate private keys. parameters.Flags |= CspProviderFlags.UseExistingKey; switch (this.PublicKey.AlgorithmId) { case CAPI.CALG_RSA_KEYX: case CAPI.CALG_RSA_SIGN: if (m_randomKeyContainer) { KeyContainerPermission permission = new KeyContainerPermission(PermissionState.None); permission.AccessEntries.Add(new KeyContainerPermissionAccessEntry(parameters, KeyContainerPermissionFlags.Open)); permission.Assert(); // Tell RSACryptoServiceProvider the key container was randomly generated parameters.Flags = (CspProviderFlags)(((uint)parameters.Flags) | RandomKeyContainerFlag); } m_privateKey = new RSACryptoServiceProvider(parameters); if (m_randomKeyContainer) CodeAccessPermission.RevertAssert(); break; case CAPI.CALG_DSS_SIGN: m_privateKey = new DSACryptoServiceProvider(parameters); break; default: throw new NotSupportedException(SR.GetString(SR.NotSupported_KeyAlgorithm)); } } return m_privateKey; } set { if (m_safeCertContext.IsInvalid) throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext"); // we do not support keys in non-CAPI storage for now. ICspAsymmetricAlgorithm asymmetricAlgorithm = value as ICspAsymmetricAlgorithm; if (value != null && asymmetricAlgorithm == null) throw new NotSupportedException(SR.GetString(SR.NotSupported_InvalidKeyImpl)); // A null value can be passed in to remove the link to the private key from the certificate. if (asymmetricAlgorithm != null) { if (asymmetricAlgorithm.CspKeyContainerInfo == null) throw new ArgumentException("CspKeyContainerInfo"); // check that the public key in the certificate corresponds to the private key passed in. // // note that it should be legal to set a key which matches in every aspect but the usage // i.e. to use a CALG_RSA_KEYX private key to match a CALG_RSA_SIGN public key. A // PUBLICKEYBLOB is defined as: // // BLOBHEADER publickeystruc // RSAPUBKEY rsapubkey // BYTE modulus[rsapubkey.bitlen/8] // // To allow keys which differ by key usage only, we skip over the BLOBHEADER of the key, // and start comparing bytes at the RSAPUBKEY structure. if(s_publicKeyOffset == 0) s_publicKeyOffset = Marshal.SizeOf(typeof(CAPIBase.BLOBHEADER)); ICspAsymmetricAlgorithm publicKey = this.PublicKey.Key as ICspAsymmetricAlgorithm; byte[] array1 = publicKey.ExportCspBlob(false); byte[] array2 = asymmetricAlgorithm.ExportCspBlob(false); if (array1 == null || array2 == null || array1.Length != array2.Length || array1.Length <= s_publicKeyOffset) throw new CryptographicUnexpectedOperationException(SR.GetString(SR.Cryptography_X509_KeyMismatch)); for (int index = s_publicKeyOffset; index < array1.Length; index++) { if (array1[index] != array2[index]) throw new CryptographicUnexpectedOperationException(SR.GetString(SR.Cryptography_X509_KeyMismatch)); } } // Establish the link between the certificate and the key container. SetPrivateKeyProperty(m_safeCertContext, asymmetricAlgorithm); m_privateKey = value; } } public PublicKey PublicKey { get { if (m_safeCertContext.IsInvalid) throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext"); if (m_publicKey == null) { string friendlyName = this.GetKeyAlgorithm(); byte[] parameters = this.GetKeyAlgorithmParameters(); byte[] keyValue = this.GetPublicKey(); Oid oid = new Oid(friendlyName, OidGroup.PublicKeyAlgorithm, true); m_publicKey = new PublicKey(oid, new AsnEncodedData(oid, parameters), new AsnEncodedData(oid, keyValue)); } return m_publicKey; } } public byte[] RawData { get { return GetRawCertData(); } } public string SerialNumber { get { return GetSerialNumberString(); } } public X500DistinguishedName SubjectName { get { if (m_safeCertContext.IsInvalid) throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext"); if (m_subjectName == null) { unsafe { CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) m_safeCertContext.DangerousGetHandle()); CAPI.CERT_INFO pCertInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO)); m_subjectName = new X500DistinguishedName(pCertInfo.Subject); } } return m_subjectName; } } public Oid SignatureAlgorithm { get { if (m_safeCertContext.IsInvalid) throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext"); if (m_signatureAlgorithm == null) m_signatureAlgorithm = GetSignatureAlgorithm(m_safeCertContext); return m_signatureAlgorithm; } } public string Thumbprint { get { return GetCertHashString(); } } public int Version { get { if (m_safeCertContext.IsInvalid) throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext"); if (m_version == 0) m_version = (int) GetVersion(m_safeCertContext); return m_version; } } public unsafe string GetNameInfo(X509NameType nameType, bool forIssuer) { uint issuerFlag = forIssuer ? CAPI.CERT_NAME_ISSUER_FLAG : 0; uint type = X509Utils.MapNameType(nameType); switch(type) { case CAPI.CERT_NAME_SIMPLE_DISPLAY_TYPE: return CAPI.GetCertNameInfo(m_safeCertContext, issuerFlag, type); case CAPI.CERT_NAME_EMAIL_TYPE: return CAPI.GetCertNameInfo(m_safeCertContext, issuerFlag, type); } string name = String.Empty; // If the type requested is not supported in downlevel platforms; we try to decode the alt name extension by hand. CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) m_safeCertContext.DangerousGetHandle()); CAPI.CERT_INFO pCertInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO)); IntPtr[] pAltName = new IntPtr[2]; pAltName[0] = CAPI.CertFindExtension(forIssuer ? CAPI.szOID_ISSUER_ALT_NAME : CAPI.szOID_SUBJECT_ALT_NAME, pCertInfo.cExtension, pCertInfo.rgExtension); pAltName[1] = CAPI.CertFindExtension(forIssuer ? CAPI.szOID_ISSUER_ALT_NAME2 : CAPI.szOID_SUBJECT_ALT_NAME2, pCertInfo.cExtension, pCertInfo.rgExtension); for (int i = 0; i < pAltName.Length; i++) { if (pAltName[i] != IntPtr.Zero) { CAPI.CERT_EXTENSION extension = (CAPI.CERT_EXTENSION) Marshal.PtrToStructure(pAltName[i], typeof(CAPI.CERT_EXTENSION)); byte[] rawData = new byte[extension.Value.cbData]; Marshal.Copy(extension.Value.pbData, rawData, 0, rawData.Length); uint cbDecoded = 0; SafeLocalAllocHandle decoded = null; // Decode the extension. SafeLocalAllocHandle ptr = X509Utils.StringToAnsiPtr(extension.pszObjId); bool result = CAPI.DecodeObject(ptr.DangerousGetHandle(), rawData, out decoded, out cbDecoded); ptr.Dispose(); if (result) { CAPI.CERT_ALT_NAME_INFO altNameInfo = (CAPI.CERT_ALT_NAME_INFO) Marshal.PtrToStructure(decoded.DangerousGetHandle(), typeof(CAPI.CERT_ALT_NAME_INFO)); for (int index = 0; index < altNameInfo.cAltEntry; index++) { IntPtr pAltInfoPtr = new IntPtr((long) altNameInfo.rgAltEntry + index * Marshal.SizeOf(typeof(CAPI.CERT_ALT_NAME_ENTRY))); CAPI.CERT_ALT_NAME_ENTRY altNameEntry = (CAPI.CERT_ALT_NAME_ENTRY) Marshal.PtrToStructure(pAltInfoPtr, typeof(CAPI.CERT_ALT_NAME_ENTRY)); switch(type) { case CAPI.CERT_NAME_UPN_TYPE: if (altNameEntry.dwAltNameChoice == CAPI.CERT_ALT_NAME_OTHER_NAME) { CAPI.CERT_OTHER_NAME otherName = (CAPI.CERT_OTHER_NAME) Marshal.PtrToStructure(altNameEntry.Value.pOtherName, typeof(CAPI.CERT_OTHER_NAME)); if (otherName.pszObjId == CAPI.szOID_NT_PRINCIPAL_NAME) { uint cbUpnName = 0; SafeLocalAllocHandle pUpnName = null; result = CAPI.DecodeObject(new IntPtr(CAPI.X509_UNICODE_ANY_STRING), X509Utils.PtrToByte(otherName.Value.pbData, otherName.Value.cbData), out pUpnName, out cbUpnName); if (result) { CAPI.CERT_NAME_VALUE nameValue = (CAPI.CERT_NAME_VALUE) Marshal.PtrToStructure(pUpnName.DangerousGetHandle(), typeof(CAPI.CERT_NAME_VALUE)); if (X509Utils.IsCertRdnCharString(nameValue.dwValueType)) name = Marshal.PtrToStringUni(nameValue.Value.pbData); pUpnName.Dispose(); } } } break; case CAPI.CERT_NAME_DNS_TYPE: if (altNameEntry.dwAltNameChoice == CAPI.CERT_ALT_NAME_DNS_NAME) name = Marshal.PtrToStringUni(altNameEntry.Value.pwszDNSName); break; case CAPI.CERT_NAME_URL_TYPE: if (altNameEntry.dwAltNameChoice == CAPI.CERT_ALT_NAME_URL) name = Marshal.PtrToStringUni(altNameEntry.Value.pwszURL); break; } } decoded.Dispose(); } } } if (nameType == X509NameType.DnsName) { // If no DNS name is found in the CERT_ALT_NAME extension, return the CommonName. // Commercial CAs such as Verisign don't include a SubjectAltName extension in the certificates they use for SSL server authentication. // Instead they use the CommonName in the subject RDN as the server's DNS name. if (name == null || name.Length == 0) name = CAPI.GetCertNameInfo(m_safeCertContext, issuerFlag, CAPI.CERT_NAME_ATTR_TYPE); } return name; } [PermissionSetAttribute(SecurityAction.LinkDemand, Unrestricted=true)] [PermissionSetAttribute(SecurityAction.InheritanceDemand, Unrestricted=true)] public override void Import(byte[] rawData) { Reset(); base.Import(rawData); m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle); } [PermissionSetAttribute(SecurityAction.LinkDemand, Unrestricted=true)] [PermissionSetAttribute(SecurityAction.InheritanceDemand, Unrestricted=true)] public override void Import(byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags) { Reset(); base.Import(rawData, password, keyStorageFlags); m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle); } [PermissionSetAttribute(SecurityAction.LinkDemand, Unrestricted=true)] [PermissionSetAttribute(SecurityAction.InheritanceDemand, Unrestricted=true)] public override void Import(byte[] rawData, SecureString password, X509KeyStorageFlags keyStorageFlags) { Reset(); base.Import(rawData, password, keyStorageFlags); m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle); } [PermissionSetAttribute(SecurityAction.LinkDemand, Unrestricted=true)] [PermissionSetAttribute(SecurityAction.InheritanceDemand, Unrestricted=true)] public override void Import(string fileName) { Reset(); base.Import(fileName); m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle); } [PermissionSetAttribute(SecurityAction.LinkDemand, Unrestricted=true)] [PermissionSetAttribute(SecurityAction.InheritanceDemand, Unrestricted=true)] public override void Import(string fileName, string password, X509KeyStorageFlags keyStorageFlags) { Reset(); base.Import(fileName, password, keyStorageFlags); m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle); } [PermissionSetAttribute(SecurityAction.LinkDemand, Unrestricted=true)] [PermissionSetAttribute(SecurityAction.InheritanceDemand, Unrestricted=true)] public override void Import(string fileName, SecureString password, X509KeyStorageFlags keyStorageFlags) { Reset(); base.Import(fileName, password, keyStorageFlags); m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle); } [PermissionSetAttribute(SecurityAction.LinkDemand, Unrestricted=true)] [PermissionSetAttribute(SecurityAction.InheritanceDemand, Unrestricted=true)] public override void Reset () { m_version = 0; m_notBefore = DateTime.MinValue; m_notAfter = DateTime.MinValue; m_privateKey = null; m_publicKey = null; m_extensions = null; m_signatureAlgorithm = null; m_subjectName = null; m_issuerName = null; if (!m_safeCertContext.IsInvalid) { // Free the current certificate handle m_safeCertContext.Dispose(); m_safeCertContext = SafeCertContextHandle.InvalidHandle; } base.Reset(); } public bool Verify () { if (m_safeCertContext.IsInvalid) throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext"); int hr = X509Utils.VerifyCertificate(this.CertContext, null, null, X509RevocationMode.Online, // We default to online revocation check. X509RevocationFlag.ExcludeRoot, DateTime.Now, new TimeSpan(0, 0, 0), // default null, new IntPtr(CAPI.CERT_CHAIN_POLICY_BASE), IntPtr.Zero); return (hr == CAPI.S_OK); } // // public static methods // public static X509ContentType GetCertContentType (byte[] rawData) { if (rawData == null || rawData.Length == 0) throw new ArgumentException(SR.GetString(SR.Arg_EmptyOrNullArray), "rawData"); uint contentType = QueryCertBlobType(rawData); return X509Utils.MapContentType(contentType); } public static X509ContentType GetCertContentType (string fileName) { if (fileName == null) throw new ArgumentNullException("fileName"); string fullPath = Path.GetFullPath(fileName); new FileIOPermission (FileIOPermissionAccess.Read, fullPath).Demand(); uint contentType = QueryCertFileType(fileName); return X509Utils.MapContentType(contentType); } // // Internal // internal SafeCertContextHandle CertContext { get { return m_safeCertContext; } } internal static bool GetPrivateKeyInfo (SafeCertContextHandle safeCertContext, ref CspParameters parameters) { SafeLocalAllocHandle ptr = SafeLocalAllocHandle.InvalidHandle; uint cbData = 0; if (!CAPI.CertGetCertificateContextProperty(safeCertContext, CAPI.CERT_KEY_PROV_INFO_PROP_ID, ptr, ref cbData)) { int dwErrorCode = Marshal.GetLastWin32Error(); if (dwErrorCode == CAPI.CRYPT_E_NOT_FOUND) return false; else throw new CryptographicException(Marshal.GetLastWin32Error()); } ptr = CAPI.LocalAlloc(CAPI.LMEM_FIXED, new IntPtr(cbData)); if (!CAPI.CertGetCertificateContextProperty(safeCertContext, CAPI.CERT_KEY_PROV_INFO_PROP_ID, ptr, ref cbData)) { int dwErrorCode = Marshal.GetLastWin32Error(); if (dwErrorCode == CAPI.CRYPT_E_NOT_FOUND) return false; else throw new CryptographicException(Marshal.GetLastWin32Error()); } CAPI.CRYPT_KEY_PROV_INFO pKeyProvInfo = (CAPI.CRYPT_KEY_PROV_INFO) Marshal.PtrToStructure(ptr.DangerousGetHandle(), typeof(CAPI.CRYPT_KEY_PROV_INFO)); parameters.ProviderName = pKeyProvInfo.pwszProvName; parameters.KeyContainerName = pKeyProvInfo.pwszContainerName; parameters.ProviderType = (int) pKeyProvInfo.dwProvType; parameters.KeyNumber = (int) pKeyProvInfo.dwKeySpec; parameters.Flags = (CspProviderFlags) ((pKeyProvInfo.dwFlags & CAPI.CRYPT_MACHINE_KEYSET) == CAPI.CRYPT_MACHINE_KEYSET ? CspProviderFlags.UseMachineKeyStore : 0); ptr.Dispose(); return true; } // // Private // private void AppendPrivateKeyInfo (StringBuilder sb) { CspKeyContainerInfo cspKeyContainerInfo = null; try { if (this.HasPrivateKey) { CspParameters parameters = new CspParameters(); if (GetPrivateKeyInfo(m_safeCertContext, ref parameters)) cspKeyContainerInfo = new CspKeyContainerInfo(parameters); } } // We don't have the permission to access the key container. Just return. catch (SecurityException) {} // We could not access the key container. Just return. catch (CryptographicException) {} if (cspKeyContainerInfo == null) return; sb.Append(Environment.NewLine + Environment.NewLine + "[Private Key]"); sb.Append(Environment.NewLine + " Key Store: "); sb.Append(cspKeyContainerInfo.MachineKeyStore ? "Machine" : "User"); sb.Append(Environment.NewLine + " Provider Name: "); sb.Append(cspKeyContainerInfo.ProviderName); sb.Append(Environment.NewLine + " Provider type: "); sb.Append(cspKeyContainerInfo.ProviderType); sb.Append(Environment.NewLine + " Key Spec: "); sb.Append(cspKeyContainerInfo.KeyNumber); sb.Append(Environment.NewLine + " Key Container Name: "); sb.Append(cspKeyContainerInfo.KeyContainerName); try { string uniqueKeyContainer = cspKeyContainerInfo.UniqueKeyContainerName; sb.Append(Environment.NewLine + " Unique Key Container Name: "); sb.Append(uniqueKeyContainer); } catch (CryptographicException) {} catch (NotSupportedException) {} bool b = false; try { b = cspKeyContainerInfo.HardwareDevice; sb.Append(Environment.NewLine + " Hardware Device: "); sb.Append(b); } catch (CryptographicException) {} try { b = cspKeyContainerInfo.Removable; sb.Append(Environment.NewLine + " Removable: "); sb.Append(b); } catch (CryptographicException) {} try { b = cspKeyContainerInfo.Protected; sb.Append(Environment.NewLine + " Protected: "); sb.Append(b); } catch (CryptographicException) {} catch (NotSupportedException) {} } private static unsafe Oid GetSignatureAlgorithm (SafeCertContextHandle safeCertContextHandle) { CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) safeCertContextHandle.DangerousGetHandle()); CAPI.CERT_INFO pCertInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO)); return new Oid(pCertInfo.SignatureAlgorithm.pszObjId, OidGroup.SignatureAlgorithm, false); } private static unsafe uint GetVersion (SafeCertContextHandle safeCertContextHandle) { CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) safeCertContextHandle.DangerousGetHandle()); CAPI.CERT_INFO pCertInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO)); return (pCertInfo.dwVersion + 1); } private static unsafe uint QueryCertBlobType(byte[] rawData) { uint contentType = 0; if (!CAPI.CryptQueryObject(CAPI.CERT_QUERY_OBJECT_BLOB, rawData, CAPI.CERT_QUERY_CONTENT_FLAG_ALL, CAPI.CERT_QUERY_FORMAT_FLAG_ALL, 0, IntPtr.Zero, new IntPtr(&contentType), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero)) throw new CryptographicException(Marshal.GetLastWin32Error()); return contentType; } private static unsafe uint QueryCertFileType(string fileName) { uint contentType = 0; if (!CAPI.CryptQueryObject(CAPI.CERT_QUERY_OBJECT_FILE, fileName, CAPI.CERT_QUERY_CONTENT_FLAG_ALL, CAPI.CERT_QUERY_FORMAT_FLAG_ALL, 0, IntPtr.Zero, new IntPtr(&contentType), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero)) throw new CryptographicException(Marshal.GetLastWin32Error()); return contentType; } private static unsafe void SetFriendlyNameExtendedProperty (SafeCertContextHandle safeCertContextHandle, string name) { SafeLocalAllocHandle ptr = X509Utils.StringToUniPtr(name); using (ptr) { CAPI.CRYPTOAPI_BLOB DataBlob = new CAPI.CRYPTOAPI_BLOB(); DataBlob.cbData = 2 * ((uint) name.Length + 1); DataBlob.pbData = ptr.DangerousGetHandle(); if (!CAPI.CertSetCertificateContextProperty(safeCertContextHandle, CAPI.CERT_FRIENDLY_NAME_PROP_ID, 0, new IntPtr(&DataBlob))) throw new CryptographicException(Marshal.GetLastWin32Error()); } } private static unsafe void SetPrivateKeyProperty (SafeCertContextHandle safeCertContextHandle, ICspAsymmetricAlgorithm asymmetricAlgorithm) { SafeLocalAllocHandle ptr = SafeLocalAllocHandle.InvalidHandle; if (asymmetricAlgorithm != null) { CAPI.CRYPT_KEY_PROV_INFO keyProvInfo = new CAPI.CRYPT_KEY_PROV_INFO(); keyProvInfo.pwszContainerName = asymmetricAlgorithm.CspKeyContainerInfo.KeyContainerName; keyProvInfo.pwszProvName = asymmetricAlgorithm.CspKeyContainerInfo.ProviderName; keyProvInfo.dwProvType = (uint) asymmetricAlgorithm.CspKeyContainerInfo.ProviderType; keyProvInfo.dwFlags = asymmetricAlgorithm.CspKeyContainerInfo.MachineKeyStore ? CAPI.CRYPT_MACHINE_KEYSET : 0; keyProvInfo.cProvParam = 0; keyProvInfo.rgProvParam = IntPtr.Zero; keyProvInfo.dwKeySpec = (uint) asymmetricAlgorithm.CspKeyContainerInfo.KeyNumber; ptr = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(Marshal.SizeOf(typeof(CAPI.CRYPT_KEY_PROV_INFO)))); Marshal.StructureToPtr(keyProvInfo, ptr.DangerousGetHandle(), false); } try { if (!CAPI.CertSetCertificateContextProperty(safeCertContextHandle, CAPI.CERT_KEY_PROV_INFO_PROP_ID, 0, ptr)) throw new CryptographicException(Marshal.GetLastWin32Error()); } finally { if (!ptr.IsInvalid) { Marshal.DestroyStructure(ptr.DangerousGetHandle(), typeof(CAPI.CRYPT_KEY_PROV_INFO)); ptr.Dispose(); } } } } }
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- Propagator.cs
- SQLGuid.cs
- WebExceptionStatus.cs
- DataPointer.cs
- StrokeNodeEnumerator.cs
- ThreadExceptionEvent.cs
- SpinWait.cs
- SectionXmlInfo.cs
- EntityDataSourceContextCreatedEventArgs.cs
- WebPartVerbCollection.cs
- WebPartEditVerb.cs
- BindingCompleteEventArgs.cs
- SynchronizationHandlesCodeDomSerializer.cs
- ObjectConverter.cs
- SystemInfo.cs
- ResourcePool.cs
- DeclarativeCatalogPart.cs
- WebPartVerbCollection.cs
- DropShadowBitmapEffect.cs
- ResourceCategoryAttribute.cs
- Int64Converter.cs
- DataGridViewRowDividerDoubleClickEventArgs.cs
- XamlSerializationHelper.cs
- SqlProviderManifest.cs
- TagPrefixAttribute.cs
- Assign.cs
- DataRelationPropertyDescriptor.cs
- DataListAutoFormat.cs
- SkinBuilder.cs
- ClientCultureInfo.cs
- GenericPrincipal.cs
- SystemIcmpV4Statistics.cs
- OleAutBinder.cs
- WebPartConnectionsCloseVerb.cs
- OleDbInfoMessageEvent.cs
- Operator.cs
- __Filters.cs
- OutputCacheSettings.cs
- ViewManager.cs
- DragDropHelper.cs
- StringDictionaryWithComparer.cs
- Scripts.cs
- LogWriteRestartAreaState.cs
- DataGridViewRowsAddedEventArgs.cs
- ToolStripRenderer.cs
- OleDbFactory.cs
- FindProgressChangedEventArgs.cs
- FormatException.cs
- EventMappingSettings.cs
- BamlTreeUpdater.cs
- ArgumentOutOfRangeException.cs
- FrameworkPropertyMetadata.cs
- ToolStripProgressBar.cs
- PropertyRecord.cs
- WebBrowserBase.cs
- HttpAsyncResult.cs
- DecoderFallback.cs
- GridViewRow.cs
- ScriptResourceHandler.cs
- RelationshipConverter.cs
- DtdParser.cs
- DispatcherHookEventArgs.cs
- ConfigurationStrings.cs
- RuntimeResourceSet.cs
- ColumnHeaderConverter.cs
- ItemPager.cs
- TextProperties.cs
- Tool.cs
- CombinedHttpChannel.cs
- CommonGetThemePartSize.cs
- LinearGradientBrush.cs
- SoapReflector.cs
- SecurityElement.cs
- RankException.cs
- SystemIcons.cs
- ProviderSettings.cs
- UriSection.cs
- UserUseLicenseDictionaryLoader.cs
- TreeWalker.cs
- AttributeUsageAttribute.cs
- GridViewEditEventArgs.cs
- EtwTrackingBehaviorElement.cs
- CommandLibraryHelper.cs
- OdbcDataReader.cs
- DirectoryNotFoundException.cs
- DoubleAnimation.cs
- X509Chain.cs
- ILGen.cs
- StandardRuntimeEnumValidatorAttribute.cs
- GridViewCancelEditEventArgs.cs
- StyleXamlParser.cs
- keycontainerpermission.cs
- StatusStrip.cs
- OdbcConnection.cs
- TdsParserHelperClasses.cs
- cookie.cs
- VarRefManager.cs
- FormsAuthenticationUserCollection.cs
- ThreadSafeList.cs
- MSAANativeProvider.cs