namespace com.hitrust.Security.Certificates { using com.hitrust.Security; using System; using System.Collections; using System.Runtime.InteropServices; using System.Threading; public class CertificateChain { private com.hitrust.Security.Certificates.Certificate m_Certificate; private IntPtr m_Handle; public CertificateChain(com.hitrust.Security.Certificates.Certificate cert) : this(cert, null) { } public CertificateChain(com.hitrust.Security.Certificates.Certificate cert, CertificateStore additional) : this(cert, additional, CertificateChainOptions.Default) { } public CertificateChain(com.hitrust.Security.Certificates.Certificate cert, CertificateStore additional, CertificateChainOptions options) { if (cert == null) { throw new ArgumentNullException(); } IntPtr hAdditionalStore = (additional == null) ? IntPtr.Zero : additional.Handle; ChainParameters pChainPara = new ChainParameters { cbSize = Marshal.SizeOf(typeof(ChainParameters)), RequestedUsagecUsageIdentifier = 0, RequestedUsagedwType = 0, RequestedUsagergpszUsageIdentifier = IntPtr.Zero }; if (SspiProvider.CertGetCertificateChain(IntPtr.Zero, cert.Handle, IntPtr.Zero, hAdditionalStore, ref pChainPara, (int) options, IntPtr.Zero, ref this.m_Handle) == 0) { throw new CertificateException("Unable to find the certificate chain."); } this.m_Certificate = cert; } public virtual IAsyncResult BeginVerifyChain(string server, AuthType type, VerificationFlags flags, AsyncCallback callback, object asyncState) { CertificateVerificationResult state = new CertificateVerificationResult(this, server, type, flags, callback, asyncState); if (!ThreadPool.QueueUserWorkItem(new WaitCallback(this.StartVerification), state)) { throw new CertificateException("Could not schedule the certificate chain for verification."); } return state; } public virtual CertificateStatus EndVerifyChain(IAsyncResult ar) { CertificateVerificationResult result; if (ar == null) { throw new ArgumentNullException(); } try { result = (CertificateVerificationResult) ar; } catch { throw new ArgumentException(); } if (result.Chain != this) { throw new ArgumentException(); } if (result.HasEnded) { throw new InvalidOperationException(); } if (result.ThrowException != null) { throw result.ThrowException; } result.HasEnded = true; return result.Status; } ~CertificateChain() { if (this.m_Handle != IntPtr.Zero) { SspiProvider.CertFreeCertificateChain(this.m_Handle); this.m_Handle = IntPtr.Zero; } } public virtual com.hitrust.Security.Certificates.Certificate[] GetCertificates() { ArrayList list = new ArrayList(); IntPtr handle = ((com.hitrust.Security.Certificates.Certificate) this.Certificate.Clone()).Handle; CertificateStoreCollection store = this.Certificate.Store as CertificateStoreCollection; if (store != null) { store = new CertificateStoreCollection(store); } else { store = new CertificateStoreCollection(new CertificateStore[0]); store.AddStore(new CertificateStore(this.Certificate.m_Context.hCertStore, true)); } store.AddStore(new CertificateStore("Root")); IntPtr hCertStore = store.Handle; while (handle != IntPtr.Zero) { list.Add(new com.hitrust.Security.Certificates.Certificate(handle, true)); int pdwFlags = 0; handle = SspiProvider.CertGetIssuerCertificateFromStore(hCertStore, handle, IntPtr.Zero, ref pdwFlags); } return (com.hitrust.Security.Certificates.Certificate[]) list.ToArray(typeof(com.hitrust.Security.Certificates.Certificate)); } protected void StartVerification(object state) { if (state != null) { CertificateVerificationResult result; CertificateStatus status; try { result = (CertificateVerificationResult) state; } catch { return; } try { status = this.VerifyChain(result.Server, result.Type, result.Flags); } catch (CertificateException exception) { result.VerificationCompleted(exception, CertificateStatus.OtherError); return; } catch (Exception exception2) { result.VerificationCompleted(new CertificateException("Could not verify the certificate chain.", exception2), CertificateStatus.OtherError); return; } result.VerificationCompleted(null, status); } } public virtual CertificateStatus VerifyChain(string server, AuthType type) { return this.VerifyChain(server, type, VerificationFlags.None); } public virtual CertificateStatus VerifyChain(string server, AuthType type, VerificationFlags flags) { CertificateStatus otherError; IntPtr zero = IntPtr.Zero; IntPtr ptr = IntPtr.Zero; try { if (server == null) { zero = IntPtr.Zero; } else { zero = Marshal.StringToHGlobalUni(server); } SslPolicyParameters structure = new SslPolicyParameters { cbSize = Marshal.SizeOf(typeof(SslPolicyParameters)), dwAuthType = (int) type, pwszServerName = zero, fdwChecks = (int) flags }; ptr = Marshal.AllocHGlobal(structure.cbSize); Marshal.StructureToPtr(structure, ptr, false); ChainPolicyParameters pPolicyPara = new ChainPolicyParameters { cbSize = Marshal.SizeOf(typeof(ChainPolicyParameters)), dwFlags = (int) flags, pvExtraPolicyPara = ptr }; ChainPolicyStatus pPolicyStatus = new ChainPolicyStatus { cbSize = Marshal.SizeOf(typeof(ChainPolicyStatus)) }; if (SspiProvider.CertVerifyCertificateChainPolicy(new IntPtr(4), this.m_Handle, ref pPolicyPara, ref pPolicyStatus) == 0) { throw new CertificateException("Unable to verify the certificate."); } if (Enum.IsDefined(typeof(CertificateStatus), pPolicyStatus.dwError)) { return (CertificateStatus) pPolicyStatus.dwError; } otherError = CertificateStatus.OtherError; } finally { if (ptr != IntPtr.Zero) { Marshal.FreeHGlobal(ptr); } if (zero != IntPtr.Zero) { Marshal.FreeHGlobal(zero); } } return otherError; } public virtual CertificateStatus VerifyChain(string server, AuthType type, VerificationFlags flags, byte[] crl) { CertificateStatus status = this.VerifyChain(server, type, flags); if ((status != CertificateStatus.ValidCertificate) || (crl == null)) { return status; } try { if (!this.m_Certificate.VerifyRevocation(crl)) { return CertificateStatus.Revoked; } return status; } catch { return CertificateStatus.RevocationFailure; } } protected com.hitrust.Security.Certificates.Certificate Certificate { get { return this.m_Certificate; } } } }