/// <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> /// Check the signature of the CRL Message /// </summary> /// <param name="CRLData">CRL as byte array</param> /// <returns>true in case of success</returns> /// <exception cref="CRLExpection">Returns this exception in case of failure</exception> private bool CheckCRLMessageSignature(byte[] CRLData) { GCHandle pCertContext = GCHandle.Alloc(IntPtr.Zero, GCHandleType.Pinned); //WinCrypt32.CRL_CONTEXT CrlCntxt = (WinCrypt32.CRL_CONTEXT)Marshal.PtrToStructure(CRLContext, typeof(WinCrypt32.CRL_CONTEXT)); //WinCrypt32.CRL_INFO CrlInfo = (WinCrypt32.CRL_INFO)Marshal.PtrToStructure(CrlCntxt.pCrlInfo, typeof(WinCrypt32.CRL_INFO)); try { IntPtr CRLContext = WinCrypt32.CertCreateCRLContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, CRLData, CRLData.Length); if (IntPtr.Zero == CRLContext) { throw new CRLExpection("Invalid CRL format"); } //CRYPT_DATA_BLOB CRLBlob = new CRYPT_DATA_BLOB(); //GCHandle pinnedArray = GCHandle.Alloc(CRLData, GCHandleType.Pinned); //CRLBlob.pbData = pinnedArray.AddrOfPinnedObject(); //CRLBlob.cbData = CRLData.Length; WinCrypt32.CRYPT_VERIFY_MESSAGE_PARA VerifyParams = new WinCrypt32.CRYPT_VERIFY_MESSAGE_PARA(); VerifyParams.cbSize = Marshal.SizeOf(VerifyParams); VerifyParams.dwMsgAndCertEncodingType = WinCrypt32.MY_TYPE; VerifyParams.hCryptProv = IntPtr.Zero; VerifyParams.pfnGetSignerCertificate = IntPtr.Zero; VerifyParams.pvGetArg = IntPtr.Zero; //int cbDecodedMessageBlob = 0; //#endif IntPtr IssuerCertContext = WinCrypt32.CertCreateCertificateContext(WinCrypt32.MY_TYPE, IssuerCertificate.RawData, IssuerCertificate.RawData.Length); bool result = WinCrypt32.CryptVerifyCertificateSignatureEx(IntPtr.Zero, WinCrypt32.MY_TYPE, 3, CRLContext, 2, IssuerCertContext, 1, IntPtr.Zero); //ref VerifyParams, // Verify parameters. //0, // Signer index. //CRLData, // Pointer to signed BLOB. //CRLData.Length, // Size of signed BLOB. //null, // Buffer for decoded message. //ref cbDecodedMessageBlob, // Size of buffer. //pCertContext.AddrOfPinnedObject() // Pointer to signer certificate. //); /*if (!result)*/ WinCrypt32.CertFreeCRLContext(CRLContext); WinCrypt32.CertFreeCertificateContext(IssuerCertContext); if (!result) { throw new CRLExpection("CRL Signature Error - Error Number " + Marshal.GetLastWin32Error()); } return(result); } catch (CRLExpection e) { throw e; } catch { return(false); } finally { pCertContext.Free(); } }
/// <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); }