You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

239 lines
9.0 KiB

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 addstore = (additional == null) ? IntPtr.Zero : additional.Handle;
ChainParameters para = new ChainParameters {
cbSize = Marshal.SizeOf(typeof(ChainParameters)),
RequestedUsagecUsageIdentifier = 0,
RequestedUsagedwType = 0,
RequestedUsagergpszUsageIdentifier = IntPtr.Zero
};
if (SspiProvider.CertGetCertificateChain(IntPtr.Zero, cert.Handle, IntPtr.Zero, addstore, ref para, (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 ret = new CertificateVerificationResult(this, server, type, flags, callback, asyncState);
if (!ThreadPool.QueueUserWorkItem(new WaitCallback(this.StartVerification), ret))
{
throw new CertificateException("Could not schedule the certificate chain for verification.");
}
return ret;
}
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 ret = new ArrayList();
IntPtr cert = ((com.hitrust.Security.Certificates.Certificate) this.Certificate.Clone()).Handle;
CertificateStoreCollection csc = this.Certificate.Store as CertificateStoreCollection;
if (csc != null)
{
csc = new CertificateStoreCollection(csc);
}
else
{
csc = new CertificateStoreCollection(new CertificateStore[0]);
csc.AddStore(new CertificateStore(this.Certificate.m_Context.hCertStore, true));
}
csc.AddStore(new CertificateStore("Root"));
IntPtr store = csc.Handle;
while (cert != IntPtr.Zero)
{
ret.Add(new com.hitrust.Security.Certificates.Certificate(cert, true));
int dwVerificationFlags = 0;
cert = SspiProvider.CertGetIssuerCertificateFromStore(store, cert, IntPtr.Zero, ref dwVerificationFlags);
}
return (com.hitrust.Security.Certificates.Certificate[]) ret.ToArray(typeof(com.hitrust.Security.Certificates.Certificate));
}
protected void StartVerification(object state)
{
if (state != null)
{
CertificateVerificationResult result;
CertificateStatus ret;
try
{
result = (CertificateVerificationResult) state;
}
catch
{
return;
}
try
{
ret = this.VerifyChain(result.Server, result.Type, result.Flags);
}
catch (CertificateException ce)
{
result.VerificationCompleted(ce, CertificateStatus.OtherError);
return;
}
catch (Exception e)
{
result.VerificationCompleted(new CertificateException("Could not verify the certificate chain.", e), CertificateStatus.OtherError);
return;
}
result.VerificationCompleted(null, ret);
}
}
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 certificateStatus;
IntPtr serverName = IntPtr.Zero;
IntPtr dataPtr = IntPtr.Zero;
try
{
if (server == null)
{
serverName = IntPtr.Zero;
}
else
{
serverName = Marshal.StringToHGlobalUni(server);
}
SslPolicyParameters data = new SslPolicyParameters {
cbSize = Marshal.SizeOf(typeof(SslPolicyParameters)),
dwAuthType = (int) type,
pwszServerName = serverName,
fdwChecks = (int) flags
};
dataPtr = Marshal.AllocHGlobal(data.cbSize);
Marshal.StructureToPtr(data, dataPtr, false);
ChainPolicyParameters para = new ChainPolicyParameters {
cbSize = Marshal.SizeOf(typeof(ChainPolicyParameters)),
dwFlags = (int) flags,
pvExtraPolicyPara = dataPtr
};
ChainPolicyStatus status = new ChainPolicyStatus {
cbSize = Marshal.SizeOf(typeof(ChainPolicyStatus))
};
if (SspiProvider.CertVerifyCertificateChainPolicy(new IntPtr(4), this.m_Handle, ref para, ref status) == 0)
{
throw new CertificateException("Unable to verify the certificate.");
}
if (Enum.IsDefined(typeof(CertificateStatus), status.dwError))
{
return (CertificateStatus) status.dwError;
}
certificateStatus = CertificateStatus.OtherError;
}
finally
{
if (dataPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(dataPtr);
}
if (serverName != IntPtr.Zero)
{
Marshal.FreeHGlobal(serverName);
}
}
return certificateStatus;
}
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;
}
}
}
}