/// <summary> /// In case of delta CRL this function will return the delta CRL location. /// </summary> /// <param name="stCrlInfo"> win32 CRL INFO</param> /// <returns>URL for CRL</returns> private string GetDeltaCrlUrl(WinCrypt32.CRL_INFO stCrlInfo) { IntPtr rgExtension = stCrlInfo.rgExtension; X509Extension deltaCrlExtension = null; for (int i = 0; i < stCrlInfo.cExtension; i++) { WinCrypt32.CERT_EXTENSION stCrlExt = (WinCrypt32.CERT_EXTENSION)Marshal.PtrToStructure(rgExtension, typeof(WinCrypt32.CERT_EXTENSION)); if (stCrlExt.Value.pbData != IntPtr.Zero && stCrlExt.pszObjId == CRL_FRESH_DELTA_OID) { byte[] rawData = new byte[stCrlExt.Value.cbData]; Marshal.Copy(stCrlExt.Value.pbData, rawData, 0, rawData.Length); deltaCrlExtension = new X509Extension(stCrlExt.pszObjId, rawData, stCrlExt.fCritical); break; } rgExtension = (IntPtr)((Int32)rgExtension + Marshal.SizeOf(typeof(WinCrypt32.CERT_EXTENSION))); } if (deltaCrlExtension == null) { return(null); } return(GetCrlUrlFromExtension(deltaCrlExtension)); }
/// <summary> /// Checks if the Certificate is in the specific CRL list /// </summary> /// <param name="cert">Certificate</param> /// <param name="stCrlInfo">CRL structure ASN.1</param> /// <returns>true in case of certificate is in the revocation list</returns> private bool IsCertificateInCrl(X509Certificate2 cert, WinCrypt32.CRL_INFO stCrlInfo) { IntPtr rgCrlEntry = stCrlInfo.rgCRLEntry; for (int i = 0; i < stCrlInfo.cCRLEntry; i++) { string serial = string.Empty; WinCrypt32.CRL_ENTRY stCrlEntry = (WinCrypt32.CRL_ENTRY)Marshal.PtrToStructure(rgCrlEntry, typeof(WinCrypt32.CRL_ENTRY)); IntPtr pByte = stCrlEntry.SerialNumber.pbData; for (int j = 0; j < stCrlEntry.SerialNumber.cbData; j++) { Byte bByte = Marshal.ReadByte(pByte); serial = bByte.ToString("X").PadLeft(2, '0') + serial; pByte = (IntPtr)((Int32)pByte + Marshal.SizeOf(typeof(Byte))); } if (cert.SerialNumber == serial) { return(true); } rgCrlEntry = (IntPtr)((Int32)rgCrlEntry + Marshal.SizeOf(typeof(WinCrypt32.CRL_ENTRY))); } return(false); }
/// <summary> /// can be used to check if the certificate is available in a specific File for CRL. /// </summary> /// <param name="cert"></param> /// <param name="CRLFilePath"></param> /// <returns></returns> internal bool IsCertificateInCrlFile(X509Certificate2 cert, string CRLFilePath) { CRLData = File.ReadAllBytes(CRLFilePath); if (!CheckCRLMessageSignature(CRLData)) { return(false); } IntPtr phCertStore = IntPtr.Zero; IntPtr pvContext = IntPtr.Zero; GCHandle hCrlData = new GCHandle(); GCHandle hCryptBlob = new GCHandle(); try { hCrlData = GCHandle.Alloc(CRLData, GCHandleType.Pinned); WinCrypt32.CRYPTOAPI_BLOB stCryptBlob; stCryptBlob.cbData = CRLData.Length; stCryptBlob.pbData = hCrlData.AddrOfPinnedObject(); hCryptBlob = GCHandle.Alloc(stCryptBlob, GCHandleType.Pinned); if (!WinCrypt32.CryptQueryObject( WinCrypt32.CERT_QUERY_OBJECT_BLOB, hCryptBlob.AddrOfPinnedObject(), WinCrypt32.CERT_QUERY_CONTENT_FLAG_CRL, WinCrypt32.CERT_QUERY_FORMAT_FLAG_BINARY, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, ref phCertStore, IntPtr.Zero, ref pvContext )) { throw new Win32Exception(Marshal.GetLastWin32Error()); } WinCrypt32.CRL_CONTEXT stCrlContext = (WinCrypt32.CRL_CONTEXT)Marshal.PtrToStructure(pvContext, typeof(WinCrypt32.CRL_CONTEXT)); WinCrypt32.CRL_INFO stCrlInfo = (WinCrypt32.CRL_INFO)Marshal.PtrToStructure(stCrlContext.pCrlInfo, typeof(WinCrypt32.CRL_INFO)); CRLNextUpdate = WinCrypt32.FiletimeToDateTime(stCrlInfo.NextUpdate); if (CRLNextUpdate < DateTime.Now) { throw new CRLExpection("CRL has expired"); } if (IsCertificateInCrl(cert, stCrlInfo)) { return(true); } } finally { if (hCrlData.IsAllocated) { hCrlData.Free(); } if (hCryptBlob.IsAllocated) { hCryptBlob.Free(); } if (!pvContext.Equals(IntPtr.Zero)) { WinCrypt32.CertFreeCRLContext(pvContext); } } return(false); }
/// <summary> /// can be used to check if the certificate is available in a specific URL for CRL. A proxy can be optionally used. /// </summary> /// <param name="cert"></param> /// <param name="url"></param> /// <param name="proxy"></param> /// <returns></returns> internal bool IsCertificateInOnlineCRL(X509Certificate2 cert, string url, WebProxy proxy = null) { if (CRLNextUpdate < DateTime.Now /* is CRLNextupdate expired*/ || CRLDownloadedExpiry < DateTime.Now /*is Downloaded CRL expired*/)//check if locally cached CRL is still valid. { WebClient wc = new WebClient(); if (proxy != null) { wc.Proxy = proxy; } CRLData = wc.DownloadData(url); CRLDownloadedExpiry = DateTime.Now.AddHours(1); } if (!CheckCRLMessageSignature(CRLData)) { return(false); } IntPtr phCertStore = IntPtr.Zero; IntPtr pvContext = IntPtr.Zero; GCHandle hCrlData = new GCHandle(); GCHandle hCryptBlob = new GCHandle(); try { hCrlData = GCHandle.Alloc(CRLData, GCHandleType.Pinned); WinCrypt32.CRYPTOAPI_BLOB stCryptBlob; stCryptBlob.cbData = CRLData.Length; stCryptBlob.pbData = hCrlData.AddrOfPinnedObject(); hCryptBlob = GCHandle.Alloc(stCryptBlob, GCHandleType.Pinned); if (!WinCrypt32.CryptQueryObject( WinCrypt32.CERT_QUERY_OBJECT_BLOB, hCryptBlob.AddrOfPinnedObject(), WinCrypt32.CERT_QUERY_CONTENT_FLAG_CRL, WinCrypt32.CERT_QUERY_FORMAT_FLAG_BINARY, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, ref phCertStore, IntPtr.Zero, ref pvContext )) { throw new Win32Exception(Marshal.GetLastWin32Error()); } WinCrypt32.CRL_CONTEXT stCrlContext = (WinCrypt32.CRL_CONTEXT)Marshal.PtrToStructure(pvContext, typeof(WinCrypt32.CRL_CONTEXT)); WinCrypt32.CRL_INFO stCrlInfo = (WinCrypt32.CRL_INFO)Marshal.PtrToStructure(stCrlContext.pCrlInfo, typeof(WinCrypt32.CRL_INFO)); CRLNextUpdate = WinCrypt32.FiletimeToDateTime(stCrlInfo.NextUpdate); if (CRLNextUpdate < DateTime.Now) { throw new CRLExpection("CRL has expired"); } if (IsCertificateInCrl(cert, stCrlInfo)) { return(true); } else { url = GetDeltaCrlUrl(stCrlInfo); if (!string.IsNullOrEmpty(url)) { return(IsCertificateInOnlineCRL(cert, url)); } } } finally { if (hCrlData.IsAllocated) { hCrlData.Free(); } if (hCryptBlob.IsAllocated) { hCryptBlob.Free(); } if (!pvContext.Equals(IntPtr.Zero)) { WinCrypt32.CertFreeCRLContext(pvContext); } } return(false); }