329 lines
8.8 KiB
C#
329 lines
8.8 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Text;
|
|
using Org.BouncyCastle.Asn1;
|
|
using Org.BouncyCastle.Asn1.Utilities;
|
|
using Org.BouncyCastle.Asn1.X509;
|
|
using Org.BouncyCastle.Crypto;
|
|
using Org.BouncyCastle.Crypto.Operators;
|
|
using Org.BouncyCastle.Math;
|
|
using Org.BouncyCastle.Security;
|
|
using Org.BouncyCastle.Security.Certificates;
|
|
using Org.BouncyCastle.Utilities;
|
|
using Org.BouncyCastle.Utilities.Collections;
|
|
using Org.BouncyCastle.Utilities.Date;
|
|
using Org.BouncyCastle.Utilities.Encoders;
|
|
using Org.BouncyCastle.X509.Extension;
|
|
|
|
namespace Org.BouncyCastle.X509;
|
|
|
|
public class X509Crl : X509ExtensionBase
|
|
{
|
|
private readonly CertificateList c;
|
|
|
|
private readonly string sigAlgName;
|
|
|
|
private readonly byte[] sigAlgParams;
|
|
|
|
private readonly bool isIndirect;
|
|
|
|
public virtual int Version => c.Version;
|
|
|
|
public virtual X509Name IssuerDN => c.Issuer;
|
|
|
|
public virtual DateTime ThisUpdate => c.ThisUpdate.ToDateTime();
|
|
|
|
public virtual DateTimeObject NextUpdate
|
|
{
|
|
get
|
|
{
|
|
if (c.NextUpdate != null)
|
|
{
|
|
return new DateTimeObject(c.NextUpdate.ToDateTime());
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public virtual string SigAlgName => sigAlgName;
|
|
|
|
public virtual string SigAlgOid => c.SignatureAlgorithm.Algorithm.Id;
|
|
|
|
protected virtual bool IsIndirectCrl
|
|
{
|
|
get
|
|
{
|
|
Asn1OctetString extensionValue = GetExtensionValue(X509Extensions.IssuingDistributionPoint);
|
|
bool result = false;
|
|
try
|
|
{
|
|
if (extensionValue != null)
|
|
{
|
|
result = IssuingDistributionPoint.GetInstance(X509ExtensionUtilities.FromExtensionValue(extensionValue)).IsIndirectCrl;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new CrlException("Exception reading IssuingDistributionPoint" + ex);
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
|
|
public X509Crl(CertificateList c)
|
|
{
|
|
this.c = c;
|
|
try
|
|
{
|
|
sigAlgName = X509SignatureUtilities.GetSignatureName(c.SignatureAlgorithm);
|
|
if (c.SignatureAlgorithm.Parameters != null)
|
|
{
|
|
sigAlgParams = c.SignatureAlgorithm.Parameters.GetDerEncoded();
|
|
}
|
|
else
|
|
{
|
|
sigAlgParams = null;
|
|
}
|
|
isIndirect = IsIndirectCrl;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new CrlException("CRL contents invalid: " + ex);
|
|
}
|
|
}
|
|
|
|
protected override X509Extensions GetX509Extensions()
|
|
{
|
|
if (c.Version < 2)
|
|
{
|
|
return null;
|
|
}
|
|
return c.TbsCertList.Extensions;
|
|
}
|
|
|
|
public virtual byte[] GetEncoded()
|
|
{
|
|
try
|
|
{
|
|
return c.GetDerEncoded();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new CrlException(ex.ToString());
|
|
}
|
|
}
|
|
|
|
public virtual void Verify(AsymmetricKeyParameter publicKey)
|
|
{
|
|
Verify(new Asn1VerifierFactoryProvider(publicKey));
|
|
}
|
|
|
|
public virtual void Verify(IVerifierFactoryProvider verifierProvider)
|
|
{
|
|
CheckSignature(verifierProvider.CreateVerifierFactory(c.SignatureAlgorithm));
|
|
}
|
|
|
|
protected virtual void CheckSignature(IVerifierFactory verifier)
|
|
{
|
|
if (!c.SignatureAlgorithm.Equals(c.TbsCertList.Signature))
|
|
{
|
|
throw new CrlException("Signature algorithm on CertificateList does not match TbsCertList.");
|
|
}
|
|
_ = c.SignatureAlgorithm.Parameters;
|
|
IStreamCalculator streamCalculator = verifier.CreateCalculator();
|
|
byte[] tbsCertList = GetTbsCertList();
|
|
streamCalculator.Stream.Write(tbsCertList, 0, tbsCertList.Length);
|
|
Platform.Dispose(streamCalculator.Stream);
|
|
if (!((IVerifier)streamCalculator.GetResult()).IsVerified(GetSignature()))
|
|
{
|
|
throw new InvalidKeyException("CRL does not verify with supplied public key.");
|
|
}
|
|
}
|
|
|
|
private ISet LoadCrlEntries()
|
|
{
|
|
ISet set = new HashSet();
|
|
IEnumerable revokedCertificateEnumeration = c.GetRevokedCertificateEnumeration();
|
|
X509Name previousCertificateIssuer = IssuerDN;
|
|
foreach (CrlEntry item in revokedCertificateEnumeration)
|
|
{
|
|
X509CrlEntry x509CrlEntry = new X509CrlEntry(item, isIndirect, previousCertificateIssuer);
|
|
set.Add(x509CrlEntry);
|
|
previousCertificateIssuer = x509CrlEntry.GetCertificateIssuer();
|
|
}
|
|
return set;
|
|
}
|
|
|
|
public virtual X509CrlEntry GetRevokedCertificate(BigInteger serialNumber)
|
|
{
|
|
IEnumerable revokedCertificateEnumeration = c.GetRevokedCertificateEnumeration();
|
|
X509Name previousCertificateIssuer = IssuerDN;
|
|
foreach (CrlEntry item in revokedCertificateEnumeration)
|
|
{
|
|
X509CrlEntry x509CrlEntry = new X509CrlEntry(item, isIndirect, previousCertificateIssuer);
|
|
if (serialNumber.Equals(item.UserCertificate.Value))
|
|
{
|
|
return x509CrlEntry;
|
|
}
|
|
previousCertificateIssuer = x509CrlEntry.GetCertificateIssuer();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public virtual ISet GetRevokedCertificates()
|
|
{
|
|
ISet set = LoadCrlEntries();
|
|
if (set.Count > 0)
|
|
{
|
|
return set;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public virtual byte[] GetTbsCertList()
|
|
{
|
|
try
|
|
{
|
|
return c.TbsCertList.GetDerEncoded();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new CrlException(ex.ToString());
|
|
}
|
|
}
|
|
|
|
public virtual byte[] GetSignature()
|
|
{
|
|
return c.GetSignatureOctets();
|
|
}
|
|
|
|
public virtual byte[] GetSigAlgParams()
|
|
{
|
|
return Arrays.Clone(sigAlgParams);
|
|
}
|
|
|
|
public override bool Equals(object obj)
|
|
{
|
|
if (obj == this)
|
|
{
|
|
return true;
|
|
}
|
|
if (!(obj is X509Crl x509Crl))
|
|
{
|
|
return false;
|
|
}
|
|
return c.Equals(x509Crl.c);
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
return c.GetHashCode();
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
StringBuilder stringBuilder = new StringBuilder();
|
|
string newLine = Platform.NewLine;
|
|
stringBuilder.Append(" Version: ").Append(Version).Append(newLine);
|
|
stringBuilder.Append(" IssuerDN: ").Append(IssuerDN).Append(newLine);
|
|
stringBuilder.Append(" This update: ").Append(ThisUpdate).Append(newLine);
|
|
stringBuilder.Append(" Next update: ").Append(NextUpdate).Append(newLine);
|
|
stringBuilder.Append(" Signature Algorithm: ").Append(SigAlgName).Append(newLine);
|
|
byte[] signature = GetSignature();
|
|
stringBuilder.Append(" Signature: ");
|
|
stringBuilder.Append(Hex.ToHexString(signature, 0, 20)).Append(newLine);
|
|
for (int i = 20; i < signature.Length; i += 20)
|
|
{
|
|
int length = System.Math.Min(20, signature.Length - i);
|
|
stringBuilder.Append(" ");
|
|
stringBuilder.Append(Hex.ToHexString(signature, i, length)).Append(newLine);
|
|
}
|
|
X509Extensions extensions = c.TbsCertList.Extensions;
|
|
if (extensions != null)
|
|
{
|
|
IEnumerator enumerator = extensions.ExtensionOids.GetEnumerator();
|
|
if (enumerator.MoveNext())
|
|
{
|
|
stringBuilder.Append(" Extensions: ").Append(newLine);
|
|
}
|
|
do
|
|
{
|
|
DerObjectIdentifier derObjectIdentifier = (DerObjectIdentifier)enumerator.Current;
|
|
X509Extension extension = extensions.GetExtension(derObjectIdentifier);
|
|
if (extension.Value != null)
|
|
{
|
|
Asn1Object asn1Object = X509ExtensionUtilities.FromExtensionValue(extension.Value);
|
|
stringBuilder.Append(" critical(").Append(extension.IsCritical).Append(") ");
|
|
try
|
|
{
|
|
if (derObjectIdentifier.Equals(X509Extensions.CrlNumber))
|
|
{
|
|
stringBuilder.Append(new CrlNumber(DerInteger.GetInstance(asn1Object).PositiveValue)).Append(newLine);
|
|
continue;
|
|
}
|
|
if (derObjectIdentifier.Equals(X509Extensions.DeltaCrlIndicator))
|
|
{
|
|
stringBuilder.Append("Base CRL: " + new CrlNumber(DerInteger.GetInstance(asn1Object).PositiveValue)).Append(newLine);
|
|
continue;
|
|
}
|
|
if (derObjectIdentifier.Equals(X509Extensions.IssuingDistributionPoint))
|
|
{
|
|
stringBuilder.Append(IssuingDistributionPoint.GetInstance((Asn1Sequence)asn1Object)).Append(newLine);
|
|
continue;
|
|
}
|
|
if (derObjectIdentifier.Equals(X509Extensions.CrlDistributionPoints))
|
|
{
|
|
stringBuilder.Append(CrlDistPoint.GetInstance((Asn1Sequence)asn1Object)).Append(newLine);
|
|
continue;
|
|
}
|
|
if (derObjectIdentifier.Equals(X509Extensions.FreshestCrl))
|
|
{
|
|
stringBuilder.Append(CrlDistPoint.GetInstance((Asn1Sequence)asn1Object)).Append(newLine);
|
|
continue;
|
|
}
|
|
stringBuilder.Append(derObjectIdentifier.Id);
|
|
stringBuilder.Append(" value = ").Append(Asn1Dump.DumpAsString(asn1Object)).Append(newLine);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
stringBuilder.Append(derObjectIdentifier.Id);
|
|
stringBuilder.Append(" value = ").Append("*****").Append(newLine);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
stringBuilder.Append(newLine);
|
|
}
|
|
}
|
|
while (enumerator.MoveNext());
|
|
}
|
|
ISet revokedCertificates = GetRevokedCertificates();
|
|
if (revokedCertificates != null)
|
|
{
|
|
foreach (X509CrlEntry item in revokedCertificates)
|
|
{
|
|
stringBuilder.Append(item);
|
|
stringBuilder.Append(newLine);
|
|
}
|
|
}
|
|
return stringBuilder.ToString();
|
|
}
|
|
|
|
public virtual bool IsRevoked(X509Certificate cert)
|
|
{
|
|
CrlEntry[] revokedCertificates = c.GetRevokedCertificates();
|
|
if (revokedCertificates != null)
|
|
{
|
|
BigInteger serialNumber = cert.SerialNumber;
|
|
for (int i = 0; i < revokedCertificates.Length; i++)
|
|
{
|
|
if (revokedCertificates[i].UserCertificate.Value.Equals(serialNumber))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
}
|