using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Misc;
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.Encoders;
using Org.BouncyCastle.X509.Extension;
namespace Org.BouncyCastle.X509
{
///
/// An Object representing an X509 Certificate.
/// Has static methods for loading Certificates encoded in many forms that return X509Certificate Objects.
///
public class X509Certificate
: X509ExtensionBase
// , PKCS12BagAttributeCarrier
{
private class CachedEncoding
{
private readonly byte[] encoding;
private readonly CertificateEncodingException exception;
internal CachedEncoding(byte[] encoding, CertificateEncodingException exception)
{
this.encoding = encoding;
this.exception = exception;
}
internal byte[] Encoding
{
get { return encoding; }
}
internal byte[] GetEncoded()
{
if (null != exception)
throw exception;
if (null == encoding)
throw new CertificateEncodingException();
return encoding;
}
}
private readonly X509CertificateStructure c;
//private Dictionary<> pkcs12Attributes = new Dictionary<>();
//private List<> pkcs12Ordering = new List<>();
private readonly string sigAlgName;
private readonly byte[] sigAlgParams;
private readonly BasicConstraints basicConstraints;
private readonly bool[] keyUsage;
private readonly object cacheLock = new object();
private AsymmetricKeyParameter publicKeyValue;
private CachedEncoding cachedEncoding;
private volatile bool hashValueSet;
private volatile int hashValue;
protected X509Certificate()
{
}
public X509Certificate(byte[] certData)
: this(X509CertificateStructure.GetInstance(certData))
{
}
public X509Certificate(X509CertificateStructure c)
{
this.c = c;
try
{
this.sigAlgName = X509SignatureUtilities.GetSignatureName(c.SignatureAlgorithm);
Asn1Encodable parameters = c.SignatureAlgorithm.Parameters;
this.sigAlgParams = (null == parameters) ? null : parameters.GetEncoded(Asn1Encodable.Der);
}
catch (Exception e)
{
throw new CertificateParsingException("Certificate contents invalid: " + e);
}
try
{
Asn1OctetString str = GetExtensionValue(X509Extensions.BasicConstraints);
if (str != null)
{
basicConstraints = BasicConstraints.GetInstance(X509ExtensionUtilities.FromExtensionValue(str));
}
}
catch (Exception e)
{
throw new CertificateParsingException("cannot construct BasicConstraints: " + e);
}
try
{
Asn1OctetString str = GetExtensionValue(X509Extensions.KeyUsage);
if (str != null)
{
DerBitString bits = DerBitString.GetInstance(X509ExtensionUtilities.FromExtensionValue(str));
byte[] bytes = bits.GetBytes();
int length = (bytes.Length * 8) - bits.PadBits;
keyUsage = new bool[(length < 9) ? 9 : length];
for (int i = 0; i != length; i++)
{
keyUsage[i] = (bytes[i / 8] & (0x80 >> (i % 8))) != 0;
}
}
else
{
keyUsage = null;
}
}
catch (Exception e)
{
throw new CertificateParsingException("cannot construct KeyUsage: " + e);
}
}
// internal X509Certificate(
// Asn1Sequence seq)
// {
// this.c = X509CertificateStructure.GetInstance(seq);
// }
// ///
// /// Load certificate from byte array.
// ///
// /// Byte array containing encoded X509Certificate.
// public X509Certificate(
// byte[] encoded)
// : this((Asn1Sequence) new Asn1InputStream(encoded).ReadObject())
// {
// }
//
// ///
// /// Load certificate from Stream.
// /// Must be positioned at start of certificate.
// ///
// ///
// public X509Certificate(
// Stream input)
// : this((Asn1Sequence) new Asn1InputStream(input).ReadObject())
// {
// }
public virtual X509CertificateStructure CertificateStructure
{
get { return c; }
}
///
/// Return true if the current time is within the start and end times nominated on the certificate.
///
/// true id certificate is valid for the current time.
public virtual bool IsValidNow
{
get { return IsValid(DateTime.UtcNow); }
}
///
/// Return true if the nominated time is within the start and end times nominated on the certificate.
///
/// The time to test validity against.
/// True if certificate is valid for nominated time.
public virtual bool IsValid(
DateTime time)
{
return time.CompareTo(NotBefore) >= 0 && time.CompareTo(NotAfter) <= 0;
}
///
/// Checks if the current date is within certificate's validity period.
///
public virtual void CheckValidity()
{
this.CheckValidity(DateTime.UtcNow);
}
///
/// Checks if the given date is within certificate's validity period.
///
/// if the certificate is expired by given date
/// if the certificate is not yet valid on given date
public virtual void CheckValidity(
DateTime time)
{
if (time.CompareTo(NotAfter) > 0)
throw new CertificateExpiredException("certificate expired on " + c.EndDate);
if (time.CompareTo(NotBefore) < 0)
throw new CertificateNotYetValidException("certificate not valid until " + c.StartDate);
}
///
/// Return the certificate's version.
///
/// An integer whose value Equals the version of the cerficate.
public virtual int Version
{
get { return c.Version; }
}
///
/// Return a BigInteger containing the serial number.
///
/// The Serial number.
public virtual BigInteger SerialNumber
{
get { return c.SerialNumber.Value; }
}
///
/// Get the Issuer Distinguished Name. (Who signed the certificate.)
///
/// And X509Object containing name and value pairs.
// public IPrincipal IssuerDN
public virtual X509Name IssuerDN
{
get { return c.Issuer; }
}
///
/// Get the subject of this certificate.
///
/// An X509Name object containing name and value pairs.
// public IPrincipal SubjectDN
public virtual X509Name SubjectDN
{
get { return c.Subject; }
}
///
/// The time that this certificate is valid from.
///
/// A DateTime object representing that time in the local time zone.
public virtual DateTime NotBefore
{
get { return c.StartDate.ToDateTime(); }
}
///
/// The time that this certificate is valid up to.
///
/// A DateTime object representing that time in the local time zone.
public virtual DateTime NotAfter
{
get { return c.EndDate.ToDateTime(); }
}
///
/// Return the Der encoded TbsCertificate data.
/// This is the certificate component less the signature.
/// To Get the whole certificate call the GetEncoded() member.
///
/// A byte array containing the Der encoded Certificate component.
public virtual byte[] GetTbsCertificate()
{
return c.TbsCertificate.GetDerEncoded();
}
///
/// The signature.
///
/// A byte array containg the signature of the certificate.
public virtual byte[] GetSignature()
{
return c.GetSignatureOctets();
}
///
/// A meaningful version of the Signature Algorithm. (EG SHA1WITHRSA)
///
/// A sting representing the signature algorithm.
public virtual string SigAlgName
{
get { return sigAlgName; }
}
///
/// Get the Signature Algorithms Object ID.
///
/// A string containg a '.' separated object id.
public virtual string SigAlgOid
{
get { return c.SignatureAlgorithm.Algorithm.Id; }
}
///
/// Get the signature algorithms parameters. (EG DSA Parameters)
///
/// A byte array containing the Der encoded version of the parameters or null if there are none.
public virtual byte[] GetSigAlgParams()
{
return Arrays.Clone(sigAlgParams);
}
///
/// Get the issuers UID.
///
/// A DerBitString.
public virtual DerBitString IssuerUniqueID
{
get { return c.TbsCertificate.IssuerUniqueID; }
}
///
/// Get the subjects UID.
///
/// A DerBitString.
public virtual DerBitString SubjectUniqueID
{
get { return c.TbsCertificate.SubjectUniqueID; }
}
///
/// Get a key usage guidlines.
///
public virtual bool[] GetKeyUsage()
{
return Arrays.Clone(keyUsage);
}
// TODO Replace with something that returns a list of DerObjectIdentifier
public virtual IList GetExtendedKeyUsage()
{
Asn1OctetString str = GetExtensionValue(X509Extensions.ExtendedKeyUsage);
if (str == null)
return null;
try
{
Asn1Sequence seq = Asn1Sequence.GetInstance(X509ExtensionUtilities.FromExtensionValue(str));
var result = new List();
foreach (DerObjectIdentifier oid in seq)
{
result.Add(oid);
}
return result;
}
catch (Exception e)
{
throw new CertificateParsingException("error processing extended key usage extension", e);
}
}
public virtual int GetBasicConstraints()
{
if (basicConstraints != null && basicConstraints.IsCA())
{
if (basicConstraints.PathLenConstraint == null)
{
return int.MaxValue;
}
return basicConstraints.PathLenConstraint.IntValue;
}
return -1;
}
public virtual GeneralNames GetIssuerAlternativeNameExtension()
{
return GetAlternativeNameExtension(X509Extensions.IssuerAlternativeName);
}
public virtual GeneralNames GetSubjectAlternativeNameExtension()
{
return GetAlternativeNameExtension(X509Extensions.SubjectAlternativeName);
}
public virtual IList> GetIssuerAlternativeNames()
{
return GetAlternativeNames(X509Extensions.IssuerAlternativeName);
}
public virtual IList> GetSubjectAlternativeNames()
{
return GetAlternativeNames(X509Extensions.SubjectAlternativeName);
}
protected virtual GeneralNames GetAlternativeNameExtension(DerObjectIdentifier oid)
{
Asn1OctetString altNames = GetExtensionValue(oid);
if (altNames == null)
return null;
Asn1Object asn1Object = X509ExtensionUtilities.FromExtensionValue(altNames);
return GeneralNames.GetInstance(asn1Object);
}
protected virtual IList> GetAlternativeNames(DerObjectIdentifier oid)
{
var generalNames = GetAlternativeNameExtension(oid);
if (generalNames == null)
return null;
var gns = generalNames.GetNames();
var result = new List>(gns.Length);
foreach (GeneralName gn in gns)
{
var entry = new List