From 44288db4414158ac9b98a507b15e81d0d3c66ca6 Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Fri, 28 Jun 2013 15:26:06 +0700
Subject: Initial import of old CVS repository
---
crypto/src/x509/AttributeCertificateHolder.cs | 442 +++++++++++++++
crypto/src/x509/AttributeCertificateIssuer.cs | 199 +++++++
crypto/src/x509/IX509AttributeCertificate.cs | 57 ++
crypto/src/x509/IX509Extension.cs | 27 +
crypto/src/x509/PEMParser.cs | 94 ++++
crypto/src/x509/PrincipalUtil.cs | 70 +++
crypto/src/x509/SubjectPublicKeyInfoFactory.cs | 187 +++++++
crypto/src/x509/X509AttrCertParser.cs | 173 ++++++
crypto/src/x509/X509Attribute.cs | 76 +++
crypto/src/x509/X509CertPairParser.cs | 95 ++++
crypto/src/x509/X509Certificate.cs | 595 +++++++++++++++++++++
crypto/src/x509/X509CertificatePair.cs | 123 +++++
crypto/src/x509/X509CertificateParser.cs | 183 +++++++
crypto/src/x509/X509Crl.cs | 403 ++++++++++++++
crypto/src/x509/X509CrlEntry.cs | 201 +++++++
crypto/src/x509/X509CrlParser.cs | 195 +++++++
crypto/src/x509/X509ExtensionBase.cs | 82 +++
crypto/src/x509/X509KeyUsage.cs | 59 ++
crypto/src/x509/X509SignatureUtil.cs | 128 +++++
crypto/src/x509/X509Utilities.cs | 187 +++++++
crypto/src/x509/X509V1CertificateGenerator.cs | 205 +++++++
crypto/src/x509/X509V2AttributeCertificate.cs | 255 +++++++++
.../x509/X509V2AttributeCertificateGenerator.cs | 180 +++++++
crypto/src/x509/X509V2CRLGenerator.cs | 261 +++++++++
crypto/src/x509/X509V3CertificateGenerator.cs | 346 ++++++++++++
.../extension/AuthorityKeyIdentifierStructure.cs | 102 ++++
.../extension/SubjectKeyIdentifierStructure.cs | 49 ++
crypto/src/x509/extension/X509ExtensionUtil.cs | 89 +++
crypto/src/x509/store/IX509Selector.cs | 15 +
crypto/src/x509/store/IX509Store.cs | 11 +
crypto/src/x509/store/IX509StoreParameters.cs | 8 +
crypto/src/x509/store/NoSuchStoreException.cs | 28 +
crypto/src/x509/store/X509AttrCertStoreSelector.cs | 376 +++++++++++++
crypto/src/x509/store/X509CertPairStoreSelector.cs | 92 ++++
crypto/src/x509/store/X509CertStoreSelector.cs | 337 ++++++++++++
crypto/src/x509/store/X509CollectionStore.cs | 51 ++
.../x509/store/X509CollectionStoreParameters.cs | 60 +++
crypto/src/x509/store/X509CrlStoreSelector.cs | 283 ++++++++++
crypto/src/x509/store/X509StoreException.cs | 28 +
crypto/src/x509/store/X509StoreFactory.cs | 62 +++
40 files changed, 6414 insertions(+)
create mode 100644 crypto/src/x509/AttributeCertificateHolder.cs
create mode 100644 crypto/src/x509/AttributeCertificateIssuer.cs
create mode 100644 crypto/src/x509/IX509AttributeCertificate.cs
create mode 100644 crypto/src/x509/IX509Extension.cs
create mode 100644 crypto/src/x509/PEMParser.cs
create mode 100644 crypto/src/x509/PrincipalUtil.cs
create mode 100644 crypto/src/x509/SubjectPublicKeyInfoFactory.cs
create mode 100644 crypto/src/x509/X509AttrCertParser.cs
create mode 100644 crypto/src/x509/X509Attribute.cs
create mode 100644 crypto/src/x509/X509CertPairParser.cs
create mode 100644 crypto/src/x509/X509Certificate.cs
create mode 100644 crypto/src/x509/X509CertificatePair.cs
create mode 100644 crypto/src/x509/X509CertificateParser.cs
create mode 100644 crypto/src/x509/X509Crl.cs
create mode 100644 crypto/src/x509/X509CrlEntry.cs
create mode 100644 crypto/src/x509/X509CrlParser.cs
create mode 100644 crypto/src/x509/X509ExtensionBase.cs
create mode 100644 crypto/src/x509/X509KeyUsage.cs
create mode 100644 crypto/src/x509/X509SignatureUtil.cs
create mode 100644 crypto/src/x509/X509Utilities.cs
create mode 100644 crypto/src/x509/X509V1CertificateGenerator.cs
create mode 100644 crypto/src/x509/X509V2AttributeCertificate.cs
create mode 100644 crypto/src/x509/X509V2AttributeCertificateGenerator.cs
create mode 100644 crypto/src/x509/X509V2CRLGenerator.cs
create mode 100644 crypto/src/x509/X509V3CertificateGenerator.cs
create mode 100644 crypto/src/x509/extension/AuthorityKeyIdentifierStructure.cs
create mode 100644 crypto/src/x509/extension/SubjectKeyIdentifierStructure.cs
create mode 100644 crypto/src/x509/extension/X509ExtensionUtil.cs
create mode 100644 crypto/src/x509/store/IX509Selector.cs
create mode 100644 crypto/src/x509/store/IX509Store.cs
create mode 100644 crypto/src/x509/store/IX509StoreParameters.cs
create mode 100644 crypto/src/x509/store/NoSuchStoreException.cs
create mode 100644 crypto/src/x509/store/X509AttrCertStoreSelector.cs
create mode 100644 crypto/src/x509/store/X509CertPairStoreSelector.cs
create mode 100644 crypto/src/x509/store/X509CertStoreSelector.cs
create mode 100644 crypto/src/x509/store/X509CollectionStore.cs
create mode 100644 crypto/src/x509/store/X509CollectionStoreParameters.cs
create mode 100644 crypto/src/x509/store/X509CrlStoreSelector.cs
create mode 100644 crypto/src/x509/store/X509StoreException.cs
create mode 100644 crypto/src/x509/store/X509StoreFactory.cs
(limited to 'crypto/src/x509')
diff --git a/crypto/src/x509/AttributeCertificateHolder.cs b/crypto/src/x509/AttributeCertificateHolder.cs
new file mode 100644
index 000000000..3a6af4c20
--- /dev/null
+++ b/crypto/src/x509/AttributeCertificateHolder.cs
@@ -0,0 +1,442 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.X509
+{
+ ///
+ /// The Holder object.
+ ///
+ /// Holder ::= SEQUENCE {
+ /// baseCertificateID [0] IssuerSerial OPTIONAL,
+ /// -- the issuer and serial number of
+ /// -- the holder's Public Key Certificate
+ /// entityName [1] GeneralNames OPTIONAL,
+ /// -- the name of the claimant or role
+ /// objectDigestInfo [2] ObjectDigestInfo OPTIONAL
+ /// -- used to directly authenticate the holder,
+ /// -- for example, an executable
+ /// }
+ ///
+ ///
+ public class AttributeCertificateHolder
+ //: CertSelector, Selector
+ : IX509Selector
+ {
+ internal readonly Holder holder;
+
+ internal AttributeCertificateHolder(
+ Asn1Sequence seq)
+ {
+ holder = Holder.GetInstance(seq);
+ }
+
+ public AttributeCertificateHolder(
+ X509Name issuerName,
+ BigInteger serialNumber)
+ {
+ holder = new Holder(
+ new IssuerSerial(
+ GenerateGeneralNames(issuerName),
+ new DerInteger(serialNumber)));
+ }
+
+ public AttributeCertificateHolder(
+ X509Certificate cert)
+ {
+ X509Name name;
+ try
+ {
+ name = PrincipalUtilities.GetIssuerX509Principal(cert);
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException(e.Message);
+ }
+
+ holder = new Holder(new IssuerSerial(GenerateGeneralNames(name), new DerInteger(cert.SerialNumber)));
+ }
+
+ public AttributeCertificateHolder(
+ X509Name principal)
+ {
+ holder = new Holder(GenerateGeneralNames(principal));
+ }
+
+ /**
+ * Constructs a holder for v2 attribute certificates with a hash value for
+ * some type of object.
+ *
+ * digestedObjectType
can be one of the following:
+ *
+ * - 0 - publicKey - A hash of the public key of the holder must be
+ * passed.
+ * - 1 - publicKeyCert - A hash of the public key certificate of the
+ * holder must be passed.
+ * - 2 - otherObjectDigest - A hash of some other object type must be
+ * passed.
otherObjectTypeID
must not be empty.
+ *
+ *
+ * This cannot be used if a v1 attribute certificate is used.
+ *
+ * @param digestedObjectType The digest object type.
+ * @param digestAlgorithm The algorithm identifier for the hash.
+ * @param otherObjectTypeID The object type ID if
+ * digestedObjectType
is
+ * otherObjectDigest
.
+ * @param objectDigest The hash value.
+ */
+ public AttributeCertificateHolder(
+ int digestedObjectType,
+ string digestAlgorithm,
+ string otherObjectTypeID,
+ byte[] objectDigest)
+ {
+ // TODO Allow 'objectDigest' to be null?
+
+ holder = new Holder(new ObjectDigestInfo(digestedObjectType, otherObjectTypeID,
+ new AlgorithmIdentifier(digestAlgorithm), Arrays.Clone(objectDigest)));
+ }
+
+ /**
+ * Returns the digest object type if an object digest info is used.
+ *
+ *
+ * - 0 - publicKey - A hash of the public key of the holder must be
+ * passed.
+ * - 1 - publicKeyCert - A hash of the public key certificate of the
+ * holder must be passed.
+ * - 2 - otherObjectDigest - A hash of some other object type must be
+ * passed.
otherObjectTypeID
must not be empty.
+ *
+ *
+ *
+ * @return The digest object type or -1 if no object digest info is set.
+ */
+ public int DigestedObjectType
+ {
+ get
+ {
+ ObjectDigestInfo odi = holder.ObjectDigestInfo;
+
+ return odi == null
+ ? -1
+ : odi.DigestedObjectType.Value.IntValue;
+ }
+ }
+
+ /**
+ * Returns the other object type ID if an object digest info is used.
+ *
+ * @return The other object type ID or null
if no object
+ * digest info is set.
+ */
+ public string DigestAlgorithm
+ {
+ get
+ {
+ ObjectDigestInfo odi = holder.ObjectDigestInfo;
+
+ return odi == null
+ ? null
+ : odi.DigestAlgorithm.ObjectID.Id;
+ }
+ }
+
+ /**
+ * Returns the hash if an object digest info is used.
+ *
+ * @return The hash or null
if no object digest info is set.
+ */
+ public byte[] GetObjectDigest()
+ {
+ ObjectDigestInfo odi = holder.ObjectDigestInfo;
+
+ return odi == null
+ ? null
+ : odi.ObjectDigest.GetBytes();
+ }
+
+ /**
+ * Returns the digest algorithm ID if an object digest info is used.
+ *
+ * @return The digest algorithm ID or null
if no object
+ * digest info is set.
+ */
+ public string OtherObjectTypeID
+ {
+ get
+ {
+ ObjectDigestInfo odi = holder.ObjectDigestInfo;
+
+ return odi == null
+ ? null
+ : odi.OtherObjectTypeID.Id;
+ }
+ }
+
+ private GeneralNames GenerateGeneralNames(
+ X509Name principal)
+ {
+// return GeneralNames.GetInstance(new DerSequence(new GeneralName(principal)));
+ return new GeneralNames(new GeneralName(principal));
+ }
+
+ private bool MatchesDN(
+ X509Name subject,
+ GeneralNames targets)
+ {
+ GeneralName[] names = targets.GetNames();
+
+ for (int i = 0; i != names.Length; i++)
+ {
+ GeneralName gn = names[i];
+
+ if (gn.TagNo == GeneralName.DirectoryName)
+ {
+ try
+ {
+ if (X509Name.GetInstance(gn.Name).Equivalent(subject))
+ {
+ return true;
+ }
+ }
+ catch (Exception)
+ {
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private object[] GetNames(
+ GeneralName[] names)
+ {
+ int count = 0;
+ for (int i = 0; i != names.Length; i++)
+ {
+ if (names[i].TagNo == GeneralName.DirectoryName)
+ {
+ ++count;
+ }
+ }
+
+ object[] result = new object[count];
+
+ int pos = 0;
+ for (int i = 0; i != names.Length; i++)
+ {
+ if (names[i].TagNo == GeneralName.DirectoryName)
+ {
+ result[pos++] = X509Name.GetInstance(names[i].Name);
+ }
+ }
+
+ return result;
+ }
+
+ private X509Name[] GetPrincipals(
+ GeneralNames names)
+ {
+ object[] p = this.GetNames(names.GetNames());
+
+ int count = 0;
+
+ for (int i = 0; i != p.Length; i++)
+ {
+ if (p[i] is X509Name)
+ {
+ ++count;
+ }
+ }
+
+ X509Name[] result = new X509Name[count];
+
+ int pos = 0;
+ for (int i = 0; i != p.Length; i++)
+ {
+ if (p[i] is X509Name)
+ {
+ result[pos++] = (X509Name)p[i];
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Return any principal objects inside the attribute certificate holder entity names field.
+ *
+ * @return an array of IPrincipal objects (usually X509Name), null if no entity names field is set.
+ */
+ public X509Name[] GetEntityNames()
+ {
+ if (holder.EntityName != null)
+ {
+ return GetPrincipals(holder.EntityName);
+ }
+
+ return null;
+ }
+
+ /**
+ * Return the principals associated with the issuer attached to this holder
+ *
+ * @return an array of principals, null if no BaseCertificateID is set.
+ */
+ public X509Name[] GetIssuer()
+ {
+ if (holder.BaseCertificateID != null)
+ {
+ return GetPrincipals(holder.BaseCertificateID.Issuer);
+ }
+
+ return null;
+ }
+
+ /**
+ * Return the serial number associated with the issuer attached to this holder.
+ *
+ * @return the certificate serial number, null if no BaseCertificateID is set.
+ */
+ public BigInteger SerialNumber
+ {
+ get
+ {
+ if (holder.BaseCertificateID != null)
+ {
+ return holder.BaseCertificateID.Serial.Value;
+ }
+
+ return null;
+ }
+ }
+
+ public object Clone()
+ {
+ return new AttributeCertificateHolder((Asn1Sequence)holder.ToAsn1Object());
+ }
+
+ public bool Match(
+// Certificate cert)
+ X509Certificate x509Cert)
+ {
+// if (!(cert is X509Certificate))
+// {
+// return false;
+// }
+//
+// X509Certificate x509Cert = (X509Certificate)cert;
+
+ try
+ {
+ if (holder.BaseCertificateID != null)
+ {
+ return holder.BaseCertificateID.Serial.Value.Equals(x509Cert.SerialNumber)
+ && MatchesDN(PrincipalUtilities.GetIssuerX509Principal(x509Cert), holder.BaseCertificateID.Issuer);
+ }
+
+ if (holder.EntityName != null)
+ {
+ if (MatchesDN(PrincipalUtilities.GetSubjectX509Principal(x509Cert), holder.EntityName))
+ {
+ return true;
+ }
+ }
+
+ if (holder.ObjectDigestInfo != null)
+ {
+ IDigest md = null;
+ try
+ {
+ md = DigestUtilities.GetDigest(DigestAlgorithm);
+ }
+ catch (Exception)
+ {
+ return false;
+ }
+
+ switch (DigestedObjectType)
+ {
+ case ObjectDigestInfo.PublicKey:
+ {
+ // TODO: DSA Dss-parms
+
+ //byte[] b = x509Cert.GetPublicKey().getEncoded();
+ // TODO Is this the right way to encode?
+ byte[] b = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(
+ x509Cert.GetPublicKey()).GetEncoded();
+ md.BlockUpdate(b, 0, b.Length);
+ break;
+ }
+
+ case ObjectDigestInfo.PublicKeyCert:
+ {
+ byte[] b = x509Cert.GetEncoded();
+ md.BlockUpdate(b, 0, b.Length);
+ break;
+ }
+
+ // TODO Default handler?
+ }
+
+ // TODO Shouldn't this be the other way around?
+ if (!Arrays.AreEqual(DigestUtilities.DoFinal(md), GetObjectDigest()))
+ {
+ return false;
+ }
+ }
+ }
+ catch (CertificateEncodingException)
+ {
+ return false;
+ }
+
+ return false;
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ {
+ return true;
+ }
+
+ if (!(obj is AttributeCertificateHolder))
+ {
+ return false;
+ }
+
+ AttributeCertificateHolder other = (AttributeCertificateHolder)obj;
+
+ return this.holder.Equals(other.holder);
+ }
+
+ public override int GetHashCode()
+ {
+ return this.holder.GetHashCode();
+ }
+
+ public bool Match(
+ object obj)
+ {
+ if (!(obj is X509Certificate))
+ {
+ return false;
+ }
+
+// return Match((Certificate)obj);
+ return Match((X509Certificate)obj);
+ }
+ }
+}
diff --git a/crypto/src/x509/AttributeCertificateIssuer.cs b/crypto/src/x509/AttributeCertificateIssuer.cs
new file mode 100644
index 000000000..7df1416d3
--- /dev/null
+++ b/crypto/src/x509/AttributeCertificateIssuer.cs
@@ -0,0 +1,199 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.X509
+{
+ /**
+ * Carrying class for an attribute certificate issuer.
+ */
+ public class AttributeCertificateIssuer
+ //: CertSelector, Selector
+ : IX509Selector
+ {
+ internal readonly Asn1Encodable form;
+
+ /**
+ * Set the issuer directly with the ASN.1 structure.
+ *
+ * @param issuer The issuer
+ */
+ public AttributeCertificateIssuer(
+ AttCertIssuer issuer)
+ {
+ form = issuer.Issuer;
+ }
+
+ public AttributeCertificateIssuer(
+ X509Name principal)
+ {
+// form = new V2Form(GeneralNames.GetInstance(new DerSequence(new GeneralName(principal))));
+ form = new V2Form(new GeneralNames(new GeneralName(principal)));
+ }
+
+ private object[] GetNames()
+ {
+ GeneralNames name;
+ if (form is V2Form)
+ {
+ name = ((V2Form)form).IssuerName;
+ }
+ else
+ {
+ name = (GeneralNames)form;
+ }
+
+ GeneralName[] names = name.GetNames();
+
+ int count = 0;
+ for (int i = 0; i != names.Length; i++)
+ {
+ if (names[i].TagNo == GeneralName.DirectoryName)
+ {
+ ++count;
+ }
+ }
+
+ object[] result = new object[count];
+
+ int pos = 0;
+ for (int i = 0; i != names.Length; i++)
+ {
+ if (names[i].TagNo == GeneralName.DirectoryName)
+ {
+ result[pos++] = X509Name.GetInstance(names[i].Name);
+ }
+ }
+
+ return result;
+ }
+
+ /// Return any principal objects inside the attribute certificate issuer object.
+ /// An array of IPrincipal objects (usually X509Principal).
+ public X509Name[] GetPrincipals()
+ {
+ object[] p = this.GetNames();
+
+ int count = 0;
+ for (int i = 0; i != p.Length; i++)
+ {
+ if (p[i] is X509Name)
+ {
+ ++count;
+ }
+ }
+
+ X509Name[] result = new X509Name[count];
+
+ int pos = 0;
+ for (int i = 0; i != p.Length; i++)
+ {
+ if (p[i] is X509Name)
+ {
+ result[pos++] = (X509Name)p[i];
+ }
+ }
+
+ return result;
+ }
+
+ private bool MatchesDN(
+ X509Name subject,
+ GeneralNames targets)
+ {
+ GeneralName[] names = targets.GetNames();
+
+ for (int i = 0; i != names.Length; i++)
+ {
+ GeneralName gn = names[i];
+
+ if (gn.TagNo == GeneralName.DirectoryName)
+ {
+ try
+ {
+ if (X509Name.GetInstance(gn.Name).Equivalent(subject))
+ {
+ return true;
+ }
+ }
+ catch (Exception)
+ {
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public object Clone()
+ {
+ return new AttributeCertificateIssuer(AttCertIssuer.GetInstance(form));
+ }
+
+ public bool Match(
+// Certificate cert)
+ X509Certificate x509Cert)
+ {
+// if (!(cert is X509Certificate))
+// {
+// return false;
+// }
+//
+// X509Certificate x509Cert = (X509Certificate)cert;
+
+ if (form is V2Form)
+ {
+ V2Form issuer = (V2Form) form;
+ if (issuer.BaseCertificateID != null)
+ {
+ return issuer.BaseCertificateID.Serial.Value.Equals(x509Cert.SerialNumber)
+ && MatchesDN(x509Cert.IssuerDN, issuer.BaseCertificateID.Issuer);
+ }
+
+ return MatchesDN(x509Cert.SubjectDN, issuer.IssuerName);
+ }
+
+ return MatchesDN(x509Cert.SubjectDN, (GeneralNames) form);
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ {
+ return true;
+ }
+
+ if (!(obj is AttributeCertificateIssuer))
+ {
+ return false;
+ }
+
+ AttributeCertificateIssuer other = (AttributeCertificateIssuer)obj;
+
+ return this.form.Equals(other.form);
+ }
+
+ public override int GetHashCode()
+ {
+ return this.form.GetHashCode();
+ }
+
+ public bool Match(
+ object obj)
+ {
+ if (!(obj is X509Certificate))
+ {
+ return false;
+ }
+
+ //return Match((Certificate)obj);
+ return Match((X509Certificate)obj);
+ }
+ }
+}
diff --git a/crypto/src/x509/IX509AttributeCertificate.cs b/crypto/src/x509/IX509AttributeCertificate.cs
new file mode 100644
index 000000000..9a3004e01
--- /dev/null
+++ b/crypto/src/x509/IX509AttributeCertificate.cs
@@ -0,0 +1,57 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.X509
+{
+ /// Interface for an X.509 Attribute Certificate.
+ public interface IX509AttributeCertificate
+ : IX509Extension
+ {
+ /// The version number for the certificate.
+ int Version { get; }
+
+ /// The serial number for the certificate.
+ BigInteger SerialNumber { get; }
+
+ /// The UTC DateTime before which the certificate is not valid.
+ DateTime NotBefore { get; }
+
+ /// The UTC DateTime after which the certificate is not valid.
+ DateTime NotAfter { get; }
+
+ /// The holder of the certificate.
+ AttributeCertificateHolder Holder { get; }
+
+ /// The issuer details for the certificate.
+ AttributeCertificateIssuer Issuer { get; }
+
+ /// Return the attributes contained in the attribute block in the certificate.
+ /// An array of attributes.
+ X509Attribute[] GetAttributes();
+
+ /// Return the attributes with the same type as the passed in oid.
+ /// The object identifier we wish to match.
+ /// An array of matched attributes, null if there is no match.
+ X509Attribute[] GetAttributes(string oid);
+
+ bool[] GetIssuerUniqueID();
+
+ bool IsValidNow { get; }
+ bool IsValid(DateTime date);
+
+ void CheckValidity();
+ void CheckValidity(DateTime date);
+
+ byte[] GetSignature();
+
+ void Verify(AsymmetricKeyParameter publicKey);
+
+ /// Return an ASN.1 encoded byte array representing the attribute certificate.
+ /// An ASN.1 encoded byte array.
+ /// If the certificate cannot be encoded.
+ byte[] GetEncoded();
+ }
+}
diff --git a/crypto/src/x509/IX509Extension.cs b/crypto/src/x509/IX509Extension.cs
new file mode 100644
index 000000000..e861e8736
--- /dev/null
+++ b/crypto/src/x509/IX509Extension.cs
@@ -0,0 +1,27 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.X509
+{
+ public interface IX509Extension
+ {
+ ///
+ /// Get all critical extension values, by oid
+ ///
+ /// IDictionary with string (OID) keys and Asn1OctetString values
+ ISet GetCriticalExtensionOids();
+
+ ///
+ /// Get all non-critical extension values, by oid
+ ///
+ /// IDictionary with string (OID) keys and Asn1OctetString values
+ ISet GetNonCriticalExtensionOids();
+
+ [Obsolete("Use version taking a DerObjectIdentifier instead")]
+ Asn1OctetString GetExtensionValue(string oid);
+
+ Asn1OctetString GetExtensionValue(DerObjectIdentifier oid);
+ }
+}
diff --git a/crypto/src/x509/PEMParser.cs b/crypto/src/x509/PEMParser.cs
new file mode 100644
index 000000000..8c117f323
--- /dev/null
+++ b/crypto/src/x509/PEMParser.cs
@@ -0,0 +1,94 @@
+using System;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.X509
+{
+ class PemParser
+ {
+ private readonly string _header1;
+ private readonly string _header2;
+ private readonly string _footer1;
+ private readonly string _footer2;
+
+ internal PemParser(
+ string type)
+ {
+ _header1 = "-----BEGIN " + type + "-----";
+ _header2 = "-----BEGIN X509 " + type + "-----";
+ _footer1 = "-----END " + type + "-----";
+ _footer2 = "-----END X509 " + type + "-----";
+ }
+
+ private string ReadLine(
+ Stream inStream)
+ {
+ int c;
+ StringBuilder l = new StringBuilder();
+
+ do
+ {
+ while (((c = inStream.ReadByte()) != '\r') && c != '\n' && (c >= 0))
+ {
+ if (c == '\r')
+ {
+ continue;
+ }
+
+ l.Append((char)c);
+ }
+ }
+ while (c >= 0 && l.Length == 0);
+
+ if (c < 0)
+ {
+ return null;
+ }
+
+ return l.ToString();
+ }
+
+ internal Asn1Sequence ReadPemObject(
+ Stream inStream)
+ {
+ string line;
+ StringBuilder pemBuf = new StringBuilder();
+
+ while ((line = ReadLine(inStream)) != null)
+ {
+ if (line.StartsWith(_header1) || line.StartsWith(_header2))
+ {
+ break;
+ }
+ }
+
+ while ((line = ReadLine(inStream)) != null)
+ {
+ if (line.StartsWith(_footer1) || line.StartsWith(_footer2))
+ {
+ break;
+ }
+
+ pemBuf.Append(line);
+ }
+
+ if (pemBuf.Length != 0)
+ {
+ Asn1Object o = Asn1Object.FromByteArray(Base64.Decode(pemBuf.ToString()));
+
+ if (!(o is Asn1Sequence))
+ {
+ throw new IOException("malformed PEM data encountered");
+ }
+
+ return (Asn1Sequence) o;
+ }
+
+ return null;
+ }
+ }
+}
+
diff --git a/crypto/src/x509/PrincipalUtil.cs b/crypto/src/x509/PrincipalUtil.cs
new file mode 100644
index 000000000..0edc4a395
--- /dev/null
+++ b/crypto/src/x509/PrincipalUtil.cs
@@ -0,0 +1,70 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security.Certificates;
+
+namespace Org.BouncyCastle.X509
+{
+ ///
+ /// A utility class that will extract X509Principal objects from X.509 certificates.
+ ///
+ /// Use this in preference to trying to recreate a principal from a string, not all
+ /// DNs are what they should be, so it's best to leave them encoded where they
+ /// can be.
+ ///
+ public class PrincipalUtilities
+ {
+ /// Return the issuer of the given cert as an X509Principal.
+ public static X509Name GetIssuerX509Principal(
+ X509Certificate cert)
+ {
+ try
+ {
+ TbsCertificateStructure tbsCert = TbsCertificateStructure.GetInstance(
+ Asn1Object.FromByteArray(cert.GetTbsCertificate()));
+
+ return tbsCert.Issuer;
+ }
+ catch (Exception e)
+ {
+ throw new CertificateEncodingException("Could not extract issuer", e);
+ }
+ }
+
+ /// Return the subject of the given cert as an X509Principal.
+ public static X509Name GetSubjectX509Principal(
+ X509Certificate cert)
+ {
+ try
+ {
+ TbsCertificateStructure tbsCert = TbsCertificateStructure.GetInstance(
+ Asn1Object.FromByteArray(cert.GetTbsCertificate()));
+
+ return tbsCert.Subject;
+ }
+ catch (Exception e)
+ {
+ throw new CertificateEncodingException("Could not extract subject", e);
+ }
+ }
+
+ /// Return the issuer of the given CRL as an X509Principal.
+ public static X509Name GetIssuerX509Principal(
+ X509Crl crl)
+ {
+ try
+ {
+ TbsCertificateList tbsCertList = TbsCertificateList.GetInstance(
+ Asn1Object.FromByteArray(crl.GetTbsCertList()));
+
+ return tbsCertList.Issuer;
+ }
+ catch (Exception e)
+ {
+ throw new CrlException("Could not extract issuer", e);
+ }
+ }
+ }
+}
diff --git a/crypto/src/x509/SubjectPublicKeyInfoFactory.cs b/crypto/src/x509/SubjectPublicKeyInfoFactory.cs
new file mode 100644
index 000000000..54ca78090
--- /dev/null
+++ b/crypto/src/x509/SubjectPublicKeyInfoFactory.cs
@@ -0,0 +1,187 @@
+using System;
+using System.IO;
+using System.Collections;
+using System.Text;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.X509
+{
+ ///
+ /// A factory to produce Public Key Info Objects.
+ ///
+ public sealed class SubjectPublicKeyInfoFactory
+ {
+ private SubjectPublicKeyInfoFactory()
+ {
+ }
+
+ ///
+ /// Create a Subject Public Key Info object for a given public key.
+ ///
+ /// One of ElGammalPublicKeyParameters, DSAPublicKeyParameter, DHPublicKeyParameters, RsaKeyParameters or ECPublicKeyParameters
+ /// A subject public key info object.
+ /// Throw exception if object provided is not one of the above.
+ public static SubjectPublicKeyInfo CreateSubjectPublicKeyInfo(
+ AsymmetricKeyParameter key)
+ {
+ if (key == null)
+ throw new ArgumentNullException("key");
+ if (key.IsPrivate)
+ throw new ArgumentException("Private key passed - public key expected.", "key");
+
+ if (key is ElGamalPublicKeyParameters)
+ {
+ ElGamalPublicKeyParameters _key = (ElGamalPublicKeyParameters)key;
+ ElGamalParameters kp = _key.Parameters;
+
+ SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
+ new AlgorithmIdentifier(
+ OiwObjectIdentifiers.ElGamalAlgorithm,
+ new ElGamalParameter(kp.P, kp.G).ToAsn1Object()),
+ new DerInteger(_key.Y));
+
+ return info;
+ }
+
+ if (key is DsaPublicKeyParameters)
+ {
+ DsaPublicKeyParameters _key = (DsaPublicKeyParameters) key;
+ DsaParameters kp = _key.Parameters;
+ Asn1Encodable ae = kp == null
+ ? null
+ : new DsaParameter(kp.P, kp.Q, kp.G).ToAsn1Object();
+
+ return new SubjectPublicKeyInfo(
+ new AlgorithmIdentifier(X9ObjectIdentifiers.IdDsa, ae),
+ new DerInteger(_key.Y));
+ }
+
+ if (key is DHPublicKeyParameters)
+ {
+ DHPublicKeyParameters _key = (DHPublicKeyParameters) key;
+ DHParameters kp = _key.Parameters;
+
+ SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
+ new AlgorithmIdentifier(
+ _key.AlgorithmOid,
+ new DHParameter(kp.P, kp.G, kp.L).ToAsn1Object()),
+ new DerInteger(_key.Y));
+
+ return info;
+ } // End of DH
+
+ if (key is RsaKeyParameters)
+ {
+ RsaKeyParameters _key = (RsaKeyParameters) key;
+
+ SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
+ new AlgorithmIdentifier(PkcsObjectIdentifiers.RsaEncryption, DerNull.Instance),
+ new RsaPublicKeyStructure(_key.Modulus, _key.Exponent).ToAsn1Object());
+
+ return info;
+ } // End of RSA.
+
+ if (key is ECPublicKeyParameters)
+ {
+ ECPublicKeyParameters _key = (ECPublicKeyParameters) key;
+
+ if (_key.AlgorithmName == "ECGOST3410")
+ {
+ if (_key.PublicKeyParamSet == null)
+ throw Platform.CreateNotImplementedException("Not a CryptoPro parameter set");
+
+ ECPoint q = _key.Q;
+ BigInteger bX = q.X.ToBigInteger();
+ BigInteger bY = q.Y.ToBigInteger();
+
+ byte[] encKey = new byte[64];
+ ExtractBytes(encKey, 0, bX);
+ ExtractBytes(encKey, 32, bY);
+
+ Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters(
+ _key.PublicKeyParamSet, CryptoProObjectIdentifiers.GostR3411x94CryptoProParamSet);
+
+ AlgorithmIdentifier algID = new AlgorithmIdentifier(
+ CryptoProObjectIdentifiers.GostR3410x2001,
+ gostParams.ToAsn1Object());
+
+ return new SubjectPublicKeyInfo(algID, new DerOctetString(encKey));
+ }
+ else
+ {
+ X962Parameters x962;
+ if (_key.PublicKeyParamSet == null)
+ {
+ ECDomainParameters kp = _key.Parameters;
+ X9ECParameters ecP = new X9ECParameters(kp.Curve, kp.G, kp.N, kp.H, kp.GetSeed());
+
+ x962 = new X962Parameters(ecP);
+ }
+ else
+ {
+ x962 = new X962Parameters(_key.PublicKeyParamSet);
+ }
+
+ Asn1OctetString p = (Asn1OctetString)(new X9ECPoint(_key.Q).ToAsn1Object());
+
+ AlgorithmIdentifier algID = new AlgorithmIdentifier(
+ X9ObjectIdentifiers.IdECPublicKey, x962.ToAsn1Object());
+
+ return new SubjectPublicKeyInfo(algID, p.GetOctets());
+ }
+ } // End of EC
+
+ if (key is Gost3410PublicKeyParameters)
+ {
+ Gost3410PublicKeyParameters _key = (Gost3410PublicKeyParameters) key;
+
+ if (_key.PublicKeyParamSet == null)
+ throw Platform.CreateNotImplementedException("Not a CryptoPro parameter set");
+
+ byte[] keyEnc = _key.Y.ToByteArrayUnsigned();
+ byte[] keyBytes = new byte[keyEnc.Length];
+
+ for (int i = 0; i != keyBytes.Length; i++)
+ {
+ keyBytes[i] = keyEnc[keyEnc.Length - 1 - i]; // must be little endian
+ }
+
+ Gost3410PublicKeyAlgParameters algParams = new Gost3410PublicKeyAlgParameters(
+ _key.PublicKeyParamSet, CryptoProObjectIdentifiers.GostR3411x94CryptoProParamSet);
+
+ AlgorithmIdentifier algID = new AlgorithmIdentifier(
+ CryptoProObjectIdentifiers.GostR3410x94,
+ algParams.ToAsn1Object());
+
+ return new SubjectPublicKeyInfo(algID, new DerOctetString(keyBytes));
+ }
+
+ throw new ArgumentException("Class provided no convertible: " + key.GetType().FullName);
+ }
+
+ private static void ExtractBytes(
+ byte[] encKey,
+ int offset,
+ BigInteger bI)
+ {
+ byte[] val = bI.ToByteArray();
+ int n = (bI.BitLength + 7) / 8;
+
+ for (int i = 0; i < n; ++i)
+ {
+ encKey[offset + i] = val[val.Length - 1 - i];
+ }
+ }
+ }
+}
diff --git a/crypto/src/x509/X509AttrCertParser.cs b/crypto/src/x509/X509AttrCertParser.cs
new file mode 100644
index 000000000..a5c07362e
--- /dev/null
+++ b/crypto/src/x509/X509AttrCertParser.cs
@@ -0,0 +1,173 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.X509
+{
+ public class X509AttrCertParser
+ {
+ private static readonly PemParser PemAttrCertParser = new PemParser("ATTRIBUTE CERTIFICATE");
+
+ private Asn1Set sData;
+ private int sDataObjectCount;
+ private Stream currentStream;
+
+ private IX509AttributeCertificate ReadDerCertificate(
+ Asn1InputStream dIn)
+ {
+ Asn1Sequence seq = (Asn1Sequence)dIn.ReadObject();
+
+ if (seq.Count > 1 && seq[0] is DerObjectIdentifier)
+ {
+ if (seq[0].Equals(PkcsObjectIdentifiers.SignedData))
+ {
+ sData = SignedData.GetInstance(
+ Asn1Sequence.GetInstance((Asn1TaggedObject) seq[1], true)).Certificates;
+
+ return GetCertificate();
+ }
+ }
+
+// return new X509V2AttributeCertificate(seq.getEncoded());
+ return new X509V2AttributeCertificate(AttributeCertificate.GetInstance(seq));
+ }
+
+ private IX509AttributeCertificate GetCertificate()
+ {
+ if (sData != null)
+ {
+ while (sDataObjectCount < sData.Count)
+ {
+ object obj = sData[sDataObjectCount++];
+
+ if (obj is Asn1TaggedObject && ((Asn1TaggedObject)obj).TagNo == 2)
+ {
+ //return new X509V2AttributeCertificate(
+ // Asn1Sequence.GetInstance((Asn1TaggedObject)obj, false).GetEncoded());
+ return new X509V2AttributeCertificate(
+ AttributeCertificate.GetInstance(
+ Asn1Sequence.GetInstance((Asn1TaggedObject)obj, false)));
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private IX509AttributeCertificate ReadPemCertificate(
+ Stream inStream)
+ {
+ Asn1Sequence seq = PemAttrCertParser.ReadPemObject(inStream);
+
+ return seq == null
+ ? null
+ //: new X509V2AttributeCertificate(seq.getEncoded());
+ : new X509V2AttributeCertificate(AttributeCertificate.GetInstance(seq));
+ }
+
+ ///
+ /// Create loading data from byte array.
+ ///
+ ///
+ public IX509AttributeCertificate ReadAttrCert(
+ byte[] input)
+ {
+ return ReadAttrCert(new MemoryStream(input, false));
+ }
+
+ ///
+ /// Create loading data from byte array.
+ ///
+ ///
+ public ICollection ReadAttrCerts(
+ byte[] input)
+ {
+ return ReadAttrCerts(new MemoryStream(input, false));
+ }
+
+ /**
+ * Generates a certificate object and initializes it with the data
+ * read from the input stream inStream.
+ */
+ public IX509AttributeCertificate ReadAttrCert(
+ Stream inStream)
+ {
+ if (inStream == null)
+ throw new ArgumentNullException("inStream");
+ if (!inStream.CanRead)
+ throw new ArgumentException("inStream must be read-able", "inStream");
+
+ if (currentStream == null)
+ {
+ currentStream = inStream;
+ sData = null;
+ sDataObjectCount = 0;
+ }
+ else if (currentStream != inStream) // reset if input stream has changed
+ {
+ currentStream = inStream;
+ sData = null;
+ sDataObjectCount = 0;
+ }
+
+ try
+ {
+ if (sData != null)
+ {
+ if (sDataObjectCount != sData.Count)
+ {
+ return GetCertificate();
+ }
+
+ sData = null;
+ sDataObjectCount = 0;
+ return null;
+ }
+
+ PushbackStream pis = new PushbackStream(inStream);
+ int tag = pis.ReadByte();
+
+ if (tag < 0)
+ return null;
+
+ pis.Unread(tag);
+
+ if (tag != 0x30) // assume ascii PEM encoded.
+ {
+ return ReadPemCertificate(pis);
+ }
+
+ return ReadDerCertificate(new Asn1InputStream(pis));
+ }
+ catch (Exception e)
+ {
+ throw new CertificateException(e.ToString());
+ }
+ }
+
+ /**
+ * Returns a (possibly empty) collection view of the certificates
+ * read from the given input stream inStream.
+ */
+ public ICollection ReadAttrCerts(
+ Stream inStream)
+ {
+ IX509AttributeCertificate attrCert;
+ IList attrCerts = Platform.CreateArrayList();
+
+ while ((attrCert = ReadAttrCert(inStream)) != null)
+ {
+ attrCerts.Add(attrCert);
+ }
+
+ return attrCerts;
+ }
+ }
+}
\ No newline at end of file
diff --git a/crypto/src/x509/X509Attribute.cs b/crypto/src/x509/X509Attribute.cs
new file mode 100644
index 000000000..248d66cc4
--- /dev/null
+++ b/crypto/src/x509/X509Attribute.cs
@@ -0,0 +1,76 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.X509
+{
+ /**
+ * Class for carrying the values in an X.509 Attribute.
+ */
+ public class X509Attribute
+ : Asn1Encodable
+ {
+ private readonly AttributeX509 attr;
+
+ /**
+ * @param at an object representing an attribute.
+ */
+ internal X509Attribute(
+ Asn1Encodable at)
+ {
+ this.attr = AttributeX509.GetInstance(at);
+ }
+
+ /**
+ * Create an X.509 Attribute with the type given by the passed in oid and
+ * the value represented by an ASN.1 Set containing value.
+ *
+ * @param oid type of the attribute
+ * @param value value object to go into the atribute's value set.
+ */
+ public X509Attribute(
+ string oid,
+ Asn1Encodable value)
+ {
+ this.attr = new AttributeX509(new DerObjectIdentifier(oid), new DerSet(value));
+ }
+
+ /**
+ * Create an X.59 Attribute with the type given by the passed in oid and the
+ * value represented by an ASN.1 Set containing the objects in value.
+ *
+ * @param oid type of the attribute
+ * @param value vector of values to go in the attribute's value set.
+ */
+ public X509Attribute(
+ string oid,
+ Asn1EncodableVector value)
+ {
+ this.attr = new AttributeX509(new DerObjectIdentifier(oid), new DerSet(value));
+ }
+
+ public string Oid
+ {
+ get { return attr.AttrType.Id; }
+ }
+
+ public Asn1Encodable[] GetValues()
+ {
+ Asn1Set s = attr.AttrValues;
+ Asn1Encodable[] values = new Asn1Encodable[s.Count];
+
+ for (int i = 0; i != s.Count; i++)
+ {
+ values[i] = (Asn1Encodable)s[i];
+ }
+
+ return values;
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return attr.ToAsn1Object();
+ }
+ }
+}
diff --git a/crypto/src/x509/X509CertPairParser.cs b/crypto/src/x509/X509CertPairParser.cs
new file mode 100644
index 000000000..82612599b
--- /dev/null
+++ b/crypto/src/x509/X509CertPairParser.cs
@@ -0,0 +1,95 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.X509
+{
+ public class X509CertPairParser
+ {
+ private Stream currentStream;
+
+ private X509CertificatePair ReadDerCrossCertificatePair(
+ Stream inStream)
+ {
+ Asn1InputStream dIn = new Asn1InputStream(inStream);//, ProviderUtil.getReadLimit(in));
+ Asn1Sequence seq = (Asn1Sequence)dIn.ReadObject();
+ CertificatePair pair = CertificatePair.GetInstance(seq);
+ return new X509CertificatePair(pair);
+ }
+
+ ///
+ /// Create loading data from byte array.
+ ///
+ ///
+ public X509CertificatePair ReadCertPair(
+ byte[] input)
+ {
+ return ReadCertPair(new MemoryStream(input, false));
+ }
+
+ ///
+ /// Create loading data from byte array.
+ ///
+ ///
+ public ICollection ReadCertPairs(
+ byte[] input)
+ {
+ return ReadCertPairs(new MemoryStream(input, false));
+ }
+
+ public X509CertificatePair ReadCertPair(
+ Stream inStream)
+ {
+ if (inStream == null)
+ throw new ArgumentNullException("inStream");
+ if (!inStream.CanRead)
+ throw new ArgumentException("inStream must be read-able", "inStream");
+
+ if (currentStream == null)
+ {
+ currentStream = inStream;
+ }
+ else if (currentStream != inStream) // reset if input stream has changed
+ {
+ currentStream = inStream;
+ }
+
+ try
+ {
+ PushbackStream pis = new PushbackStream(inStream);
+ int tag = pis.ReadByte();
+
+ if (tag < 0)
+ return null;
+
+ pis.Unread(tag);
+
+ return ReadDerCrossCertificatePair(pis);
+ }
+ catch (Exception e)
+ {
+ throw new CertificateException(e.ToString());
+ }
+ }
+
+ public ICollection ReadCertPairs(
+ Stream inStream)
+ {
+ X509CertificatePair certPair;
+ IList certPairs = Platform.CreateArrayList();
+
+ while ((certPair = ReadCertPair(inStream)) != null)
+ {
+ certPairs.Add(certPair);
+ }
+
+ return certPairs;
+ }
+ }
+}
diff --git a/crypto/src/x509/X509Certificate.cs b/crypto/src/x509/X509Certificate.cs
new file mode 100644
index 000000000..f156f3147
--- /dev/null
+++ b/crypto/src/x509/X509Certificate.cs
@@ -0,0 +1,595 @@
+using System;
+using System.Collections;
+using System.IO;
+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.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 readonly X509CertificateStructure c;
+// private Hashtable pkcs12Attributes = new Hashtable();
+// private ArrayList pkcs12Ordering = new ArrayList();
+ private readonly BasicConstraints basicConstraints;
+ private readonly bool[] keyUsage;
+
+ private bool hashValueSet;
+ private int hashValue;
+
+ protected X509Certificate()
+ {
+ }
+
+ public X509Certificate(
+ X509CertificateStructure c)
+ {
+ this.c = c;
+
+ try
+ {
+ Asn1OctetString str = this.GetExtensionValue(new DerObjectIdentifier("2.5.29.19"));
+
+ if (str != null)
+ {
+ basicConstraints = BasicConstraints.GetInstance(
+ X509ExtensionUtilities.FromExtensionValue(str));
+ }
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("cannot construct BasicConstraints: " + e);
+ }
+
+ try
+ {
+ Asn1OctetString str = this.GetExtensionValue(new DerObjectIdentifier("2.5.29.15"));
+
+ 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;
+ 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.GetTime());
+ if (time.CompareTo(NotBefore) < 0)
+ throw new CertificateNotYetValidException("certificate not valid until " + c.StartDate.GetTime());
+ }
+
+ ///
+ /// 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.Signature.GetBytes();
+ }
+
+ ///
+ /// A meaningful version of the Signature Algorithm. (EG SHA1WITHRSA)
+ ///
+ /// A sting representing the signature algorithm.
+ public virtual string SigAlgName
+ {
+ get { return SignerUtilities.GetEncodingName(c.SignatureAlgorithm.ObjectID); }
+ }
+
+ ///
+ /// Get the Signature Algorithms Object ID.
+ ///
+ /// A string containg a '.' separated object id.
+ public virtual string SigAlgOid
+ {
+ get { return c.SignatureAlgorithm.ObjectID.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()
+ {
+ if (c.SignatureAlgorithm.Parameters != null)
+ {
+ return c.SignatureAlgorithm.Parameters.GetDerEncoded();
+ }
+
+ return null;
+ }
+
+ ///
+ /// 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 keyUsage == null ? null : (bool[]) keyUsage.Clone();
+ }
+
+ // TODO Replace with something that returns a list of DerObjectIdentifier
+ public virtual IList GetExtendedKeyUsage()
+ {
+ Asn1OctetString str = this.GetExtensionValue(new DerObjectIdentifier("2.5.29.37"));
+
+ if (str == null)
+ return null;
+
+ try
+ {
+ Asn1Sequence seq = Asn1Sequence.GetInstance(
+ X509ExtensionUtilities.FromExtensionValue(str));
+
+ IList list = Platform.CreateArrayList();
+
+ foreach (DerObjectIdentifier oid in seq)
+ {
+ list.Add(oid.Id);
+ }
+
+ return list;
+ }
+ 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 ICollection GetSubjectAlternativeNames()
+ {
+ return GetAlternativeNames("2.5.29.17");
+ }
+
+ public virtual ICollection GetIssuerAlternativeNames()
+ {
+ return GetAlternativeNames("2.5.29.18");
+ }
+
+ protected virtual ICollection GetAlternativeNames(
+ string oid)
+ {
+ Asn1OctetString altNames = GetExtensionValue(new DerObjectIdentifier(oid));
+
+ if (altNames == null)
+ return null;
+
+ Asn1Object asn1Object = X509ExtensionUtilities.FromExtensionValue(altNames);
+
+ GeneralNames gns = GeneralNames.GetInstance(asn1Object);
+
+ IList result = Platform.CreateArrayList();
+ foreach (GeneralName gn in gns.GetNames())
+ {
+ IList entry = Platform.CreateArrayList();
+ entry.Add(gn.TagNo);
+ entry.Add(gn.Name.ToString());
+ result.Add(entry);
+ }
+ return result;
+ }
+
+ protected override X509Extensions GetX509Extensions()
+ {
+ return c.Version == 3
+ ? c.TbsCertificate.Extensions
+ : null;
+ }
+
+ ///
+ /// Get the public key of the subject of the certificate.
+ ///
+ /// The public key parameters.
+ public virtual AsymmetricKeyParameter GetPublicKey()
+ {
+ return PublicKeyFactory.CreateKey(c.SubjectPublicKeyInfo);
+ }
+
+ ///
+ /// Return a Der encoded version of this certificate.
+ ///
+ /// A byte array.
+ public virtual byte[] GetEncoded()
+ {
+ return c.GetDerEncoded();
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ X509Certificate other = obj as X509Certificate;
+
+ if (other == null)
+ return false;
+
+ return c.Equals(other.c);
+
+ // NB: May prefer this implementation of Equals if more than one certificate implementation in play
+// return Arrays.AreEqual(this.GetEncoded(), other.GetEncoded());
+ }
+
+ public override int GetHashCode()
+ {
+ lock (this)
+ {
+ if (!hashValueSet)
+ {
+ hashValue = c.GetHashCode();
+ hashValueSet = true;
+ }
+ }
+
+ return hashValue;
+ }
+
+// public void setBagAttribute(
+// DERObjectIdentifier oid,
+// DEREncodable attribute)
+// {
+// pkcs12Attributes.put(oid, attribute);
+// pkcs12Ordering.addElement(oid);
+// }
+//
+// public DEREncodable getBagAttribute(
+// DERObjectIdentifier oid)
+// {
+// return (DEREncodable)pkcs12Attributes.get(oid);
+// }
+//
+// public Enumeration getBagAttributeKeys()
+// {
+// return pkcs12Ordering.elements();
+// }
+
+ public override string ToString()
+ {
+ StringBuilder buf = new StringBuilder();
+ string nl = Platform.NewLine;
+
+ buf.Append(" [0] Version: ").Append(this.Version).Append(nl);
+ buf.Append(" SerialNumber: ").Append(this.SerialNumber).Append(nl);
+ buf.Append(" IssuerDN: ").Append(this.IssuerDN).Append(nl);
+ buf.Append(" Start Date: ").Append(this.NotBefore).Append(nl);
+ buf.Append(" Final Date: ").Append(this.NotAfter).Append(nl);
+ buf.Append(" SubjectDN: ").Append(this.SubjectDN).Append(nl);
+ buf.Append(" Public Key: ").Append(this.GetPublicKey()).Append(nl);
+ buf.Append(" Signature Algorithm: ").Append(this.SigAlgName).Append(nl);
+
+ byte[] sig = this.GetSignature();
+ buf.Append(" Signature: ").Append(Hex.ToHexString(sig, 0, 20)).Append(nl);
+
+ for (int i = 20; i < sig.Length; i += 20)
+ {
+ int len = System.Math.Min(20, sig.Length - i);
+ buf.Append(" ").Append(Hex.ToHexString(sig, i, len)).Append(nl);
+ }
+
+ X509Extensions extensions = c.TbsCertificate.Extensions;
+
+ if (extensions != null)
+ {
+ IEnumerator e = extensions.ExtensionOids.GetEnumerator();
+
+ if (e.MoveNext())
+ {
+ buf.Append(" Extensions: \n");
+ }
+
+ do
+ {
+ DerObjectIdentifier oid = (DerObjectIdentifier)e.Current;
+ X509Extension ext = extensions.GetExtension(oid);
+
+ if (ext.Value != null)
+ {
+ byte[] octs = ext.Value.GetOctets();
+ Asn1Object obj = Asn1Object.FromByteArray(octs);
+ buf.Append(" critical(").Append(ext.IsCritical).Append(") ");
+ try
+ {
+ if (oid.Equals(X509Extensions.BasicConstraints))
+ {
+ buf.Append(BasicConstraints.GetInstance(obj));
+ }
+ else if (oid.Equals(X509Extensions.KeyUsage))
+ {
+ buf.Append(KeyUsage.GetInstance(obj));
+ }
+ else if (oid.Equals(MiscObjectIdentifiers.NetscapeCertType))
+ {
+ buf.Append(new NetscapeCertType((DerBitString) obj));
+ }
+ else if (oid.Equals(MiscObjectIdentifiers.NetscapeRevocationUrl))
+ {
+ buf.Append(new NetscapeRevocationUrl((DerIA5String) obj));
+ }
+ else if (oid.Equals(MiscObjectIdentifiers.VerisignCzagExtension))
+ {
+ buf.Append(new VerisignCzagExtension((DerIA5String) obj));
+ }
+ else
+ {
+ buf.Append(oid.Id);
+ buf.Append(" value = ").Append(Asn1Dump.DumpAsString(obj));
+ //buf.Append(" value = ").Append("*****").Append(nl);
+ }
+ }
+ catch (Exception)
+ {
+ buf.Append(oid.Id);
+ //buf.Append(" value = ").Append(new string(Hex.encode(ext.getValue().getOctets()))).Append(nl);
+ buf.Append(" value = ").Append("*****");
+ }
+ }
+
+ buf.Append(nl);
+ }
+ while (e.MoveNext());
+ }
+
+ return buf.ToString();
+ }
+
+ ///
+ /// Verify the certificate's signature using the nominated public key.
+ ///
+ /// An appropriate public key parameter object, RsaPublicKeyParameters, DsaPublicKeyParameters or ECDsaPublicKeyParameters
+ /// True if the signature is valid.
+ /// If key submitted is not of the above nominated types.
+ public virtual void Verify(
+ AsymmetricKeyParameter key)
+ {
+ string sigName = X509SignatureUtilities.GetSignatureName(c.SignatureAlgorithm);
+ ISigner signature = SignerUtilities.GetSigner(sigName);
+
+ CheckSignature(key, signature);
+ }
+
+ protected virtual void CheckSignature(
+ AsymmetricKeyParameter publicKey,
+ ISigner signature)
+ {
+ if (!IsAlgIDEqual(c.SignatureAlgorithm, c.TbsCertificate.Signature))
+ throw new CertificateException("signature algorithm in TBS cert not same as outer cert");
+
+ Asn1Encodable parameters = c.SignatureAlgorithm.Parameters;
+
+ X509SignatureUtilities.SetSignatureParameters(signature, parameters);
+
+ signature.Init(false, publicKey);
+
+ byte[] b = this.GetTbsCertificate();
+ signature.BlockUpdate(b, 0, b.Length);
+
+ byte[] sig = this.GetSignature();
+ if (!signature.VerifySignature(sig))
+ {
+ throw new InvalidKeyException("Public key presented not for certificate signature");
+ }
+ }
+
+ private static bool IsAlgIDEqual(AlgorithmIdentifier id1, AlgorithmIdentifier id2)
+ {
+ if (!id1.ObjectID.Equals(id2.ObjectID))
+ return false;
+
+ Asn1Encodable p1 = id1.Parameters;
+ Asn1Encodable p2 = id2.Parameters;
+
+ if ((p1 == null) == (p2 == null))
+ return Platform.Equals(p1, p2);
+
+ // Exactly one of p1, p2 is null at this point
+ return p1 == null
+ ? p2.ToAsn1Object() is Asn1Null
+ : p1.ToAsn1Object() is Asn1Null;
+ }
+ }
+}
diff --git a/crypto/src/x509/X509CertificatePair.cs b/crypto/src/x509/X509CertificatePair.cs
new file mode 100644
index 000000000..fbeba4dc6
--- /dev/null
+++ b/crypto/src/x509/X509CertificatePair.cs
@@ -0,0 +1,123 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.X509
+{
+ ///
+ /// This class contains a cross certificate pair. Cross certificates pairs may
+ /// contain two cross signed certificates from two CAs. A certificate from the
+ /// other CA to this CA is contained in the forward certificate, the certificate
+ /// from this CA to the other CA is contained in the reverse certificate.
+ ///
+ public class X509CertificatePair
+ {
+ private readonly X509Certificate forward;
+ private readonly X509Certificate reverse;
+
+ /// Constructor
+ /// Certificate from the other CA to this CA.
+ /// Certificate from this CA to the other CA.
+ public X509CertificatePair(
+ X509Certificate forward,
+ X509Certificate reverse)
+ {
+ this.forward = forward;
+ this.reverse = reverse;
+ }
+
+ /// Constructor from a ASN.1 CertificatePair structure.
+ /// The CertificatePair ASN.1 object.
+ public X509CertificatePair(
+ CertificatePair pair)
+ {
+ if (pair.Forward != null)
+ {
+ this.forward = new X509Certificate(pair.Forward);
+ }
+ if (pair.Reverse != null)
+ {
+ this.reverse = new X509Certificate(pair.Reverse);
+ }
+ }
+
+ public byte[] GetEncoded()
+ {
+ try
+ {
+ X509CertificateStructure f = null, r = null;
+
+ if (forward != null)
+ {
+ f = X509CertificateStructure.GetInstance(
+ Asn1Object.FromByteArray(forward.GetEncoded()));
+
+ if (f == null)
+ throw new CertificateEncodingException("unable to get encoding for forward");
+ }
+
+ if (reverse != null)
+ {
+ r = X509CertificateStructure.GetInstance(
+ Asn1Object.FromByteArray(reverse.GetEncoded()));
+
+ if (r == null)
+ throw new CertificateEncodingException("unable to get encoding for reverse");
+ }
+
+ return new CertificatePair(f, r).GetDerEncoded();
+ }
+ catch (Exception e)
+ {
+ // TODO
+// throw new ExtCertificateEncodingException(e.toString(), e);
+ throw new CertificateEncodingException(e.Message, e);
+ }
+ }
+
+ /// Returns the certificate from the other CA to this CA.
+ public X509Certificate Forward
+ {
+ get { return forward; }
+ }
+
+ /// Returns the certificate from this CA to the other CA.
+ public X509Certificate Reverse
+ {
+ get { return reverse; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ X509CertificatePair other = obj as X509CertificatePair;
+
+ if (other == null)
+ return false;
+
+ return Platform.Equals(this.forward, other.forward)
+ && Platform.Equals(this.reverse, other.reverse);
+ }
+
+ public override int GetHashCode()
+ {
+ int hash = -1;
+ if (forward != null)
+ {
+ hash ^= forward.GetHashCode();
+ }
+ if (reverse != null)
+ {
+ hash *= 17;
+ hash ^= reverse.GetHashCode();
+ }
+ return hash;
+ }
+ }
+}
diff --git a/crypto/src/x509/X509CertificateParser.cs b/crypto/src/x509/X509CertificateParser.cs
new file mode 100644
index 000000000..8f0e7406c
--- /dev/null
+++ b/crypto/src/x509/X509CertificateParser.cs
@@ -0,0 +1,183 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.X509
+{
+ /**
+ * class for dealing with X509 certificates.
+ *
+ * At the moment this will deal with "-----BEGIN CERTIFICATE-----" to "-----END CERTIFICATE-----"
+ * base 64 encoded certs, as well as the BER binaries of certificates and some classes of PKCS#7
+ * objects.
+ */
+ public class X509CertificateParser
+ {
+ private static readonly PemParser PemCertParser = new PemParser("CERTIFICATE");
+
+ private Asn1Set sData;
+ private int sDataObjectCount;
+ private Stream currentStream;
+
+ private X509Certificate ReadDerCertificate(
+ Asn1InputStream dIn)
+ {
+ Asn1Sequence seq = (Asn1Sequence)dIn.ReadObject();
+
+ if (seq.Count > 1 && seq[0] is DerObjectIdentifier)
+ {
+ if (seq[0].Equals(PkcsObjectIdentifiers.SignedData))
+ {
+ sData = SignedData.GetInstance(
+ Asn1Sequence.GetInstance((Asn1TaggedObject) seq[1], true)).Certificates;
+
+ return GetCertificate();
+ }
+ }
+
+ return CreateX509Certificate(X509CertificateStructure.GetInstance(seq));
+ }
+
+ private X509Certificate GetCertificate()
+ {
+ if (sData != null)
+ {
+ while (sDataObjectCount < sData.Count)
+ {
+ object obj = sData[sDataObjectCount++];
+
+ if (obj is Asn1Sequence)
+ {
+ return CreateX509Certificate(
+ X509CertificateStructure.GetInstance(obj));
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private X509Certificate ReadPemCertificate(
+ Stream inStream)
+ {
+ Asn1Sequence seq = PemCertParser.ReadPemObject(inStream);
+
+ return seq == null
+ ? null
+ : CreateX509Certificate(X509CertificateStructure.GetInstance(seq));
+ }
+
+ protected virtual X509Certificate CreateX509Certificate(
+ X509CertificateStructure c)
+ {
+ return new X509Certificate(c);
+ }
+
+ ///
+ /// Create loading data from byte array.
+ ///
+ ///
+ public X509Certificate ReadCertificate(
+ byte[] input)
+ {
+ return ReadCertificate(new MemoryStream(input, false));
+ }
+
+ ///
+ /// Create loading data from byte array.
+ ///
+ ///
+ public ICollection ReadCertificates(
+ byte[] input)
+ {
+ return ReadCertificates(new MemoryStream(input, false));
+ }
+
+ /**
+ * Generates a certificate object and initializes it with the data
+ * read from the input stream inStream.
+ */
+ public X509Certificate ReadCertificate(
+ Stream inStream)
+ {
+ if (inStream == null)
+ throw new ArgumentNullException("inStream");
+ if (!inStream.CanRead)
+ throw new ArgumentException("inStream must be read-able", "inStream");
+
+ if (currentStream == null)
+ {
+ currentStream = inStream;
+ sData = null;
+ sDataObjectCount = 0;
+ }
+ else if (currentStream != inStream) // reset if input stream has changed
+ {
+ currentStream = inStream;
+ sData = null;
+ sDataObjectCount = 0;
+ }
+
+ try
+ {
+ if (sData != null)
+ {
+ if (sDataObjectCount != sData.Count)
+ {
+ return GetCertificate();
+ }
+
+ sData = null;
+ sDataObjectCount = 0;
+ return null;
+ }
+
+ PushbackStream pis = new PushbackStream(inStream);
+ int tag = pis.ReadByte();
+
+ if (tag < 0)
+ return null;
+
+ pis.Unread(tag);
+
+ if (tag != 0x30) // assume ascii PEM encoded.
+ {
+ return ReadPemCertificate(pis);
+ }
+
+ return ReadDerCertificate(new Asn1InputStream(pis));
+ }
+ catch (Exception e)
+ {
+ throw new CertificateException("Failed to read certificate", e);
+ }
+ }
+
+ /**
+ * Returns a (possibly empty) collection view of the certificates
+ * read from the given input stream inStream.
+ */
+ public ICollection ReadCertificates(
+ Stream inStream)
+ {
+ X509Certificate cert;
+ IList certs = Platform.CreateArrayList();
+
+ while ((cert = ReadCertificate(inStream)) != null)
+ {
+ certs.Add(cert);
+ }
+
+ return certs;
+ }
+ }
+}
diff --git a/crypto/src/x509/X509Crl.cs b/crypto/src/x509/X509Crl.cs
new file mode 100644
index 000000000..7d0e7aa72
--- /dev/null
+++ b/crypto/src/x509/X509Crl.cs
@@ -0,0 +1,403 @@
+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.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
+{
+ /**
+ * The following extensions are listed in RFC 2459 as relevant to CRLs
+ *
+ * Authority Key Identifier
+ * Issuer Alternative Name
+ * CRL Number
+ * Delta CRL Indicator (critical)
+ * Issuing Distribution Point (critical)
+ */
+ public class X509Crl
+ : X509ExtensionBase
+ // TODO Add interface Crl?
+ {
+ private readonly CertificateList c;
+ private readonly string sigAlgName;
+ private readonly byte[] sigAlgParams;
+ private readonly bool isIndirect;
+
+ public X509Crl(
+ CertificateList c)
+ {
+ this.c = c;
+
+ try
+ {
+ this.sigAlgName = X509SignatureUtilities.GetSignatureName(c.SignatureAlgorithm);
+
+ if (c.SignatureAlgorithm.Parameters != null)
+ {
+ this.sigAlgParams = ((Asn1Encodable)c.SignatureAlgorithm.Parameters).GetDerEncoded();
+ }
+ else
+ {
+ this.sigAlgParams = null;
+ }
+
+ this.isIndirect = IsIndirectCrl;
+ }
+ catch (Exception e)
+ {
+ throw new CrlException("CRL contents invalid: " + e);
+ }
+ }
+
+ protected override X509Extensions GetX509Extensions()
+ {
+ return Version == 2
+ ? c.TbsCertList.Extensions
+ : null;
+ }
+
+ public virtual byte[] GetEncoded()
+ {
+ try
+ {
+ return c.GetDerEncoded();
+ }
+ catch (Exception e)
+ {
+ throw new CrlException(e.ToString());
+ }
+ }
+
+ public virtual void Verify(
+ AsymmetricKeyParameter publicKey)
+ {
+ if (!c.SignatureAlgorithm.Equals(c.TbsCertList.Signature))
+ {
+ throw new CrlException("Signature algorithm on CertificateList does not match TbsCertList.");
+ }
+
+ ISigner sig = SignerUtilities.GetSigner(SigAlgName);
+ sig.Init(false, publicKey);
+
+ byte[] encoded = this.GetTbsCertList();
+ sig.BlockUpdate(encoded, 0, encoded.Length);
+
+ if (!sig.VerifySignature(this.GetSignature()))
+ {
+ throw new SignatureException("CRL does not verify with supplied public key.");
+ }
+ }
+
+ public virtual int Version
+ {
+ get { return c.Version; }
+ }
+
+ public virtual X509Name IssuerDN
+ {
+ get { return c.Issuer; }
+ }
+
+ public virtual DateTime ThisUpdate
+ {
+ get { return c.ThisUpdate.ToDateTime(); }
+ }
+
+ public virtual DateTimeObject NextUpdate
+ {
+ get
+ {
+ return c.NextUpdate == null
+ ? null
+ : new DateTimeObject(c.NextUpdate.ToDateTime());
+ }
+ }
+
+ private ISet LoadCrlEntries()
+ {
+ ISet entrySet = new HashSet();
+ IEnumerable certs = c.GetRevokedCertificateEnumeration();
+
+ X509Name previousCertificateIssuer = IssuerDN;
+ foreach (CrlEntry entry in certs)
+ {
+ X509CrlEntry crlEntry = new X509CrlEntry(entry, isIndirect, previousCertificateIssuer);
+ entrySet.Add(crlEntry);
+ previousCertificateIssuer = crlEntry.GetCertificateIssuer();
+ }
+
+ return entrySet;
+ }
+
+ public virtual X509CrlEntry GetRevokedCertificate(
+ BigInteger serialNumber)
+ {
+ IEnumerable certs = c.GetRevokedCertificateEnumeration();
+
+ X509Name previousCertificateIssuer = IssuerDN;
+ foreach (CrlEntry entry in certs)
+ {
+ X509CrlEntry crlEntry = new X509CrlEntry(entry, isIndirect, previousCertificateIssuer);
+
+ if (serialNumber.Equals(entry.UserCertificate.Value))
+ {
+ return crlEntry;
+ }
+
+ previousCertificateIssuer = crlEntry.GetCertificateIssuer();
+ }
+
+ return null;
+ }
+
+ public virtual ISet GetRevokedCertificates()
+ {
+ ISet entrySet = LoadCrlEntries();
+
+ if (entrySet.Count > 0)
+ {
+ return entrySet; // TODO? Collections.unmodifiableSet(entrySet);
+ }
+
+ return null;
+ }
+
+ public virtual byte[] GetTbsCertList()
+ {
+ try
+ {
+ return c.TbsCertList.GetDerEncoded();
+ }
+ catch (Exception e)
+ {
+ throw new CrlException(e.ToString());
+ }
+ }
+
+ public virtual byte[] GetSignature()
+ {
+ return c.Signature.GetBytes();
+ }
+
+ public virtual string SigAlgName
+ {
+ get { return sigAlgName; }
+ }
+
+ public virtual string SigAlgOid
+ {
+ get { return c.SignatureAlgorithm.ObjectID.Id; }
+ }
+
+ public virtual byte[] GetSigAlgParams()
+ {
+ return Arrays.Clone(sigAlgParams);
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ X509Crl other = obj as X509Crl;
+
+ if (other == null)
+ return false;
+
+ return c.Equals(other.c);
+
+ // NB: May prefer this implementation of Equals if more than one certificate implementation in play
+ //return Arrays.AreEqual(this.GetEncoded(), other.GetEncoded());
+ }
+
+ public override int GetHashCode()
+ {
+ return c.GetHashCode();
+ }
+
+ /**
+ * Returns a string representation of this CRL.
+ *
+ * @return a string representation of this CRL.
+ */
+ public override string ToString()
+ {
+ StringBuilder buf = new StringBuilder();
+ string nl = Platform.NewLine;
+
+ buf.Append(" Version: ").Append(this.Version).Append(nl);
+ buf.Append(" IssuerDN: ").Append(this.IssuerDN).Append(nl);
+ buf.Append(" This update: ").Append(this.ThisUpdate).Append(nl);
+ buf.Append(" Next update: ").Append(this.NextUpdate).Append(nl);
+ buf.Append(" Signature Algorithm: ").Append(this.SigAlgName).Append(nl);
+
+ byte[] sig = this.GetSignature();
+
+ buf.Append(" Signature: ");
+ buf.Append(Hex.ToHexString(sig, 0, 20)).Append(nl);
+
+ for (int i = 20; i < sig.Length; i += 20)
+ {
+ int count = System.Math.Min(20, sig.Length - i);
+ buf.Append(" ");
+ buf.Append(Hex.ToHexString(sig, i, count)).Append(nl);
+ }
+
+ X509Extensions extensions = c.TbsCertList.Extensions;
+
+ if (extensions != null)
+ {
+ IEnumerator e = extensions.ExtensionOids.GetEnumerator();
+
+ if (e.MoveNext())
+ {
+ buf.Append(" Extensions: ").Append(nl);
+ }
+
+ do
+ {
+ DerObjectIdentifier oid = (DerObjectIdentifier) e.Current;
+ X509Extension ext = extensions.GetExtension(oid);
+
+ if (ext.Value != null)
+ {
+ Asn1Object asn1Value = X509ExtensionUtilities.FromExtensionValue(ext.Value);
+
+ buf.Append(" critical(").Append(ext.IsCritical).Append(") ");
+ try
+ {
+ if (oid.Equals(X509Extensions.CrlNumber))
+ {
+ buf.Append(new CrlNumber(DerInteger.GetInstance(asn1Value).PositiveValue)).Append(nl);
+ }
+ else if (oid.Equals(X509Extensions.DeltaCrlIndicator))
+ {
+ buf.Append(
+ "Base CRL: "
+ + new CrlNumber(DerInteger.GetInstance(
+ asn1Value).PositiveValue))
+ .Append(nl);
+ }
+ else if (oid.Equals(X509Extensions.IssuingDistributionPoint))
+ {
+ buf.Append(IssuingDistributionPoint.GetInstance((Asn1Sequence) asn1Value)).Append(nl);
+ }
+ else if (oid.Equals(X509Extensions.CrlDistributionPoints))
+ {
+ buf.Append(CrlDistPoint.GetInstance((Asn1Sequence) asn1Value)).Append(nl);
+ }
+ else if (oid.Equals(X509Extensions.FreshestCrl))
+ {
+ buf.Append(CrlDistPoint.GetInstance((Asn1Sequence) asn1Value)).Append(nl);
+ }
+ else
+ {
+ buf.Append(oid.Id);
+ buf.Append(" value = ").Append(
+ Asn1Dump.DumpAsString(asn1Value))
+ .Append(nl);
+ }
+ }
+ catch (Exception)
+ {
+ buf.Append(oid.Id);
+ buf.Append(" value = ").Append("*****").Append(nl);
+ }
+ }
+ else
+ {
+ buf.Append(nl);
+ }
+ }
+ while (e.MoveNext());
+ }
+
+ ISet certSet = GetRevokedCertificates();
+ if (certSet != null)
+ {
+ foreach (X509CrlEntry entry in certSet)
+ {
+ buf.Append(entry);
+ buf.Append(nl);
+ }
+ }
+
+ return buf.ToString();
+ }
+
+ /**
+ * Checks whether the given certificate is on this CRL.
+ *
+ * @param cert the certificate to check for.
+ * @return true if the given certificate is on this CRL,
+ * false otherwise.
+ */
+// public bool IsRevoked(
+// Certificate cert)
+// {
+// if (!cert.getType().Equals("X.509"))
+// {
+// throw new RuntimeException("X.509 CRL used with non X.509 Cert");
+// }
+ public virtual bool IsRevoked(
+ X509Certificate cert)
+ {
+ CrlEntry[] certs = c.GetRevokedCertificates();
+
+ if (certs != null)
+ {
+// BigInteger serial = ((X509Certificate)cert).SerialNumber;
+ BigInteger serial = cert.SerialNumber;
+
+ for (int i = 0; i < certs.Length; i++)
+ {
+ if (certs[i].UserCertificate.Value.Equals(serial))
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ protected virtual bool IsIndirectCrl
+ {
+ get
+ {
+ Asn1OctetString idp = GetExtensionValue(X509Extensions.IssuingDistributionPoint);
+ bool isIndirect = false;
+
+ try
+ {
+ if (idp != null)
+ {
+ isIndirect = IssuingDistributionPoint.GetInstance(
+ X509ExtensionUtilities.FromExtensionValue(idp)).IsIndirectCrl;
+ }
+ }
+ catch (Exception e)
+ {
+ // TODO
+// throw new ExtCrlException("Exception reading IssuingDistributionPoint", e);
+ throw new CrlException("Exception reading IssuingDistributionPoint" + e);
+ }
+
+ return isIndirect;
+ }
+ }
+ }
+}
diff --git a/crypto/src/x509/X509CrlEntry.cs b/crypto/src/x509/X509CrlEntry.cs
new file mode 100644
index 000000000..caca29470
--- /dev/null
+++ b/crypto/src/x509/X509CrlEntry.cs
@@ -0,0 +1,201 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Utilities;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509.Extension;
+
+namespace Org.BouncyCastle.X509
+{
+ /**
+ * The following extensions are listed in RFC 2459 as relevant to CRL Entries
+ *
+ * ReasonCode Hode Instruction Code Invalidity Date Certificate Issuer
+ * (critical)
+ */
+ public class X509CrlEntry
+ : X509ExtensionBase
+ {
+ private CrlEntry c;
+ private bool isIndirect;
+ private X509Name previousCertificateIssuer;
+ private X509Name certificateIssuer;
+
+ public X509CrlEntry(
+ CrlEntry c)
+ {
+ this.c = c;
+ this.certificateIssuer = loadCertificateIssuer();
+ }
+
+ /**
+ * Constructor for CRLEntries of indirect CRLs. If isIndirect
+ * is false
{@link #getCertificateIssuer()} will always
+ * return null
, previousCertificateIssuer
is
+ * ignored. If this isIndirect
is specified and this CrlEntry
+ * has no certificate issuer CRL entry extension
+ * previousCertificateIssuer
is returned by
+ * {@link #getCertificateIssuer()}.
+ *
+ * @param c
+ * TbsCertificateList.CrlEntry object.
+ * @param isIndirect
+ * true
if the corresponding CRL is a indirect
+ * CRL.
+ * @param previousCertificateIssuer
+ * Certificate issuer of the previous CrlEntry.
+ */
+ public X509CrlEntry(
+ CrlEntry c,
+ bool isIndirect,
+ X509Name previousCertificateIssuer)
+ {
+ this.c = c;
+ this.isIndirect = isIndirect;
+ this.previousCertificateIssuer = previousCertificateIssuer;
+ this.certificateIssuer = loadCertificateIssuer();
+ }
+
+ private X509Name loadCertificateIssuer()
+ {
+ if (!isIndirect)
+ {
+ return null;
+ }
+
+ Asn1OctetString ext = GetExtensionValue(X509Extensions.CertificateIssuer);
+ if (ext == null)
+ {
+ return previousCertificateIssuer;
+ }
+
+ try
+ {
+ GeneralName[] names = GeneralNames.GetInstance(
+ X509ExtensionUtilities.FromExtensionValue(ext)).GetNames();
+
+ for (int i = 0; i < names.Length; i++)
+ {
+ if (names[i].TagNo == GeneralName.DirectoryName)
+ {
+ return X509Name.GetInstance(names[i].Name);
+ }
+ }
+ }
+ catch (Exception)
+ {
+ }
+
+ return null;
+ }
+
+ public X509Name GetCertificateIssuer()
+ {
+ return certificateIssuer;
+ }
+
+ protected override X509Extensions GetX509Extensions()
+ {
+ return c.Extensions;
+ }
+
+ public byte[] GetEncoded()
+ {
+ try
+ {
+ return c.GetDerEncoded();
+ }
+ catch (Exception e)
+ {
+ throw new CrlException(e.ToString());
+ }
+ }
+
+ public BigInteger SerialNumber
+ {
+ get { return c.UserCertificate.Value; }
+ }
+
+ public DateTime RevocationDate
+ {
+ get { return c.RevocationDate.ToDateTime(); }
+ }
+
+ public bool HasExtensions
+ {
+ get { return c.Extensions != null; }
+ }
+
+ public override string ToString()
+ {
+ StringBuilder buf = new StringBuilder();
+ string nl = Platform.NewLine;
+
+ buf.Append(" userCertificate: ").Append(this.SerialNumber).Append(nl);
+ buf.Append(" revocationDate: ").Append(this.RevocationDate).Append(nl);
+ buf.Append(" certificateIssuer: ").Append(this.GetCertificateIssuer()).Append(nl);
+
+ X509Extensions extensions = c.Extensions;
+
+ if (extensions != null)
+ {
+ IEnumerator e = extensions.ExtensionOids.GetEnumerator();
+ if (e.MoveNext())
+ {
+ buf.Append(" crlEntryExtensions:").Append(nl);
+
+ do
+ {
+ DerObjectIdentifier oid = (DerObjectIdentifier)e.Current;
+ X509Extension ext = extensions.GetExtension(oid);
+
+ if (ext.Value != null)
+ {
+ Asn1Object obj = Asn1Object.FromByteArray(ext.Value.GetOctets());
+
+ buf.Append(" critical(")
+ .Append(ext.IsCritical)
+ .Append(") ");
+ try
+ {
+ if (oid.Equals(X509Extensions.ReasonCode))
+ {
+ buf.Append(new CrlReason(DerEnumerated.GetInstance(obj)));
+ }
+ else if (oid.Equals(X509Extensions.CertificateIssuer))
+ {
+ buf.Append("Certificate issuer: ").Append(
+ GeneralNames.GetInstance((Asn1Sequence)obj));
+ }
+ else
+ {
+ buf.Append(oid.Id);
+ buf.Append(" value = ").Append(Asn1Dump.DumpAsString(obj));
+ }
+ buf.Append(nl);
+ }
+ catch (Exception)
+ {
+ buf.Append(oid.Id);
+ buf.Append(" value = ").Append("*****").Append(nl);
+ }
+ }
+ else
+ {
+ buf.Append(nl);
+ }
+ }
+ while (e.MoveNext());
+ }
+ }
+
+ return buf.ToString();
+ }
+ }
+}
diff --git a/crypto/src/x509/X509CrlParser.cs b/crypto/src/x509/X509CrlParser.cs
new file mode 100644
index 000000000..d830bb9a6
--- /dev/null
+++ b/crypto/src/x509/X509CrlParser.cs
@@ -0,0 +1,195 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.X509
+{
+ public class X509CrlParser
+ {
+ private static readonly PemParser PemCrlParser = new PemParser("CRL");
+
+ private readonly bool lazyAsn1;
+
+ private Asn1Set sCrlData;
+ private int sCrlDataObjectCount;
+ private Stream currentCrlStream;
+
+ public X509CrlParser()
+ : this(false)
+ {
+ }
+
+ public X509CrlParser(
+ bool lazyAsn1)
+ {
+ this.lazyAsn1 = lazyAsn1;
+ }
+
+ private X509Crl ReadPemCrl(
+ Stream inStream)
+ {
+ Asn1Sequence seq = PemCrlParser.ReadPemObject(inStream);
+
+ return seq == null
+ ? null
+ : CreateX509Crl(CertificateList.GetInstance(seq));
+ }
+
+ private X509Crl ReadDerCrl(
+ Asn1InputStream dIn)
+ {
+ Asn1Sequence seq = (Asn1Sequence)dIn.ReadObject();
+
+ if (seq.Count > 1 && seq[0] is DerObjectIdentifier)
+ {
+ if (seq[0].Equals(PkcsObjectIdentifiers.SignedData))
+ {
+ sCrlData = SignedData.GetInstance(
+ Asn1Sequence.GetInstance((Asn1TaggedObject) seq[1], true)).Crls;
+
+ return GetCrl();
+ }
+ }
+
+ return CreateX509Crl(CertificateList.GetInstance(seq));
+ }
+
+ private X509Crl GetCrl()
+ {
+ if (sCrlData == null || sCrlDataObjectCount >= sCrlData.Count)
+ {
+ return null;
+ }
+
+ return CreateX509Crl(
+ CertificateList.GetInstance(
+ sCrlData[sCrlDataObjectCount++]));
+ }
+
+ protected virtual X509Crl CreateX509Crl(
+ CertificateList c)
+ {
+ return new X509Crl(c);
+ }
+
+ ///
+ /// Create loading data from byte array.
+ ///
+ ///
+ public X509Crl ReadCrl(
+ byte[] input)
+ {
+ return ReadCrl(new MemoryStream(input, false));
+ }
+
+ ///
+ /// Create loading data from byte array.
+ ///
+ ///
+ public ICollection ReadCrls(
+ byte[] input)
+ {
+ return ReadCrls(new MemoryStream(input, false));
+ }
+
+ /**
+ * Generates a certificate revocation list (CRL) object and initializes
+ * it with the data read from the input stream inStream.
+ */
+ public X509Crl ReadCrl(
+ Stream inStream)
+ {
+ if (inStream == null)
+ throw new ArgumentNullException("inStream");
+ if (!inStream.CanRead)
+ throw new ArgumentException("inStream must be read-able", "inStream");
+
+ if (currentCrlStream == null)
+ {
+ currentCrlStream = inStream;
+ sCrlData = null;
+ sCrlDataObjectCount = 0;
+ }
+ else if (currentCrlStream != inStream) // reset if input stream has changed
+ {
+ currentCrlStream = inStream;
+ sCrlData = null;
+ sCrlDataObjectCount = 0;
+ }
+
+ try
+ {
+ if (sCrlData != null)
+ {
+ if (sCrlDataObjectCount != sCrlData.Count)
+ {
+ return GetCrl();
+ }
+
+ sCrlData = null;
+ sCrlDataObjectCount = 0;
+ return null;
+ }
+
+ PushbackStream pis = new PushbackStream(inStream);
+ int tag = pis.ReadByte();
+
+ if (tag < 0)
+ return null;
+
+ pis.Unread(tag);
+
+ if (tag != 0x30) // assume ascii PEM encoded.
+ {
+ return ReadPemCrl(pis);
+ }
+
+ Asn1InputStream asn1 = lazyAsn1
+ ? new LazyAsn1InputStream(pis)
+ : new Asn1InputStream(pis);
+
+ return ReadDerCrl(asn1);
+ }
+ catch (CrlException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new CrlException(e.ToString());
+ }
+ }
+
+ /**
+ * Returns a (possibly empty) collection view of the CRLs read from
+ * the given input stream inStream.
+ *
+ * The inStream may contain a sequence of DER-encoded CRLs, or
+ * a PKCS#7 CRL set. This is a PKCS#7 SignedData object, with the
+ * only significant field being crls. In particular the signature
+ * and the contents are ignored.
+ */
+ public ICollection ReadCrls(
+ Stream inStream)
+ {
+ X509Crl crl;
+ IList crls = Platform.CreateArrayList();
+
+ while ((crl = ReadCrl(inStream)) != null)
+ {
+ crls.Add(crl);
+ }
+
+ return crls;
+ }
+ }
+}
diff --git a/crypto/src/x509/X509ExtensionBase.cs b/crypto/src/x509/X509ExtensionBase.cs
new file mode 100644
index 000000000..aaf6695c0
--- /dev/null
+++ b/crypto/src/x509/X509ExtensionBase.cs
@@ -0,0 +1,82 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.X509
+{
+ public abstract class X509ExtensionBase
+ : IX509Extension
+ {
+ protected abstract X509Extensions GetX509Extensions();
+
+ protected virtual ISet GetExtensionOids(
+ bool critical)
+ {
+ X509Extensions extensions = GetX509Extensions();
+ if (extensions != null)
+ {
+ HashSet set = new HashSet();
+ foreach (DerObjectIdentifier oid in extensions.ExtensionOids)
+ {
+ X509Extension ext = extensions.GetExtension(oid);
+ if (ext.IsCritical == critical)
+ {
+ set.Add(oid.Id);
+ }
+ }
+
+ return set;
+ }
+
+ return null;
+ }
+
+ ///
+ /// Get non critical extensions.
+ ///
+ /// A set of non critical extension oids.
+ public virtual ISet GetNonCriticalExtensionOids()
+ {
+ return GetExtensionOids(false);
+ }
+
+ ///
+ /// Get any critical extensions.
+ ///
+ /// A sorted list of critical entension.
+ public virtual ISet GetCriticalExtensionOids()
+ {
+ return GetExtensionOids(true);
+ }
+
+ ///
+ /// Get the value of a given extension.
+ ///
+ /// The object ID of the extension.
+ /// An Asn1OctetString object if that extension is found or null if not.
+ [Obsolete("Use version taking a DerObjectIdentifier instead")]
+ public Asn1OctetString GetExtensionValue(
+ string oid)
+ {
+ return GetExtensionValue(new DerObjectIdentifier(oid));
+ }
+
+ public virtual Asn1OctetString GetExtensionValue(
+ DerObjectIdentifier oid)
+ {
+ X509Extensions exts = GetX509Extensions();
+ if (exts != null)
+ {
+ X509Extension ext = exts.GetExtension(oid);
+ if (ext != null)
+ {
+ return ext.Value;
+ }
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/crypto/src/x509/X509KeyUsage.cs b/crypto/src/x509/X509KeyUsage.cs
new file mode 100644
index 000000000..e0a7b4939
--- /dev/null
+++ b/crypto/src/x509/X509KeyUsage.cs
@@ -0,0 +1,59 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.X509
+{
+ /**
+ * A holding class for constructing an X509 Key Usage extension.
+ *
+ *
+ * id-ce-keyUsage OBJECT IDENTIFIER ::= { id-ce 15 }
+ *
+ * KeyUsage ::= BIT STRING {
+ * digitalSignature (0),
+ * nonRepudiation (1),
+ * keyEncipherment (2),
+ * dataEncipherment (3),
+ * keyAgreement (4),
+ * keyCertSign (5),
+ * cRLSign (6),
+ * encipherOnly (7),
+ * decipherOnly (8) }
+ *
+ */
+ public class X509KeyUsage
+ : Asn1Encodable
+ {
+ public const int DigitalSignature = 1 << 7;
+ public const int NonRepudiation = 1 << 6;
+ public const int KeyEncipherment = 1 << 5;
+ public const int DataEncipherment = 1 << 4;
+ public const int KeyAgreement = 1 << 3;
+ public const int KeyCertSign = 1 << 2;
+ public const int CrlSign = 1 << 1;
+ public const int EncipherOnly = 1 << 0;
+ public const int DecipherOnly = 1 << 15;
+
+ private readonly int usage;
+
+ /**
+ * Basic constructor.
+ *
+ * @param usage - the bitwise OR of the Key Usage flags giving the
+ * allowed uses for the key.
+ * e.g. (X509KeyUsage.keyEncipherment | X509KeyUsage.dataEncipherment)
+ */
+ public X509KeyUsage(
+ int usage)
+ {
+ this.usage = usage;
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new KeyUsage(usage);
+ }
+ }
+}
diff --git a/crypto/src/x509/X509SignatureUtil.cs b/crypto/src/x509/X509SignatureUtil.cs
new file mode 100644
index 000000000..7a4ab1448
--- /dev/null
+++ b/crypto/src/x509/X509SignatureUtil.cs
@@ -0,0 +1,128 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.X509
+{
+ internal class X509SignatureUtilities
+ {
+ private static readonly Asn1Null derNull = DerNull.Instance;
+
+ internal static void SetSignatureParameters(
+ ISigner signature,
+ Asn1Encodable parameters)
+ {
+ if (parameters != null && !derNull.Equals(parameters))
+ {
+ // TODO Put back in
+// AlgorithmParameters sigParams = AlgorithmParameters.GetInstance(signature.getAlgorithm());
+//
+// try
+// {
+// sigParams.Init(parameters.ToAsn1Object().GetDerEncoded());
+// }
+// catch (IOException e)
+// {
+// throw new SignatureException("IOException decoding parameters: " + e.Message);
+// }
+//
+// if (signature.getAlgorithm().EndsWith("MGF1"))
+// {
+// try
+// {
+// signature.setParameter(sigParams.getParameterSpec(PSSParameterSpec.class));
+// }
+// catch (GeneralSecurityException e)
+// {
+// throw new SignatureException("Exception extracting parameters: " + e.Message);
+// }
+// }
+ }
+ }
+
+ internal static string GetSignatureName(
+ AlgorithmIdentifier sigAlgId)
+ {
+ Asn1Encodable parameters = sigAlgId.Parameters;
+
+ if (parameters != null && !derNull.Equals(parameters))
+ {
+ if (sigAlgId.ObjectID.Equals(PkcsObjectIdentifiers.IdRsassaPss))
+ {
+ RsassaPssParameters rsaParams = RsassaPssParameters.GetInstance(parameters);
+
+ return GetDigestAlgName(rsaParams.HashAlgorithm.ObjectID) + "withRSAandMGF1";
+ }
+ if (sigAlgId.ObjectID.Equals(X9ObjectIdentifiers.ECDsaWithSha2))
+ {
+ Asn1Sequence ecDsaParams = Asn1Sequence.GetInstance(parameters);
+
+ return GetDigestAlgName((DerObjectIdentifier)ecDsaParams[0]) + "withECDSA";
+ }
+ }
+
+ return sigAlgId.ObjectID.Id;
+ }
+
+ /**
+ * Return the digest algorithm using one of the standard JCA string
+ * representations rather than the algorithm identifier (if possible).
+ */
+ private static string GetDigestAlgName(
+ DerObjectIdentifier digestAlgOID)
+ {
+ if (PkcsObjectIdentifiers.MD5.Equals(digestAlgOID))
+ {
+ return "MD5";
+ }
+ else if (OiwObjectIdentifiers.IdSha1.Equals(digestAlgOID))
+ {
+ return "SHA1";
+ }
+ else if (NistObjectIdentifiers.IdSha224.Equals(digestAlgOID))
+ {
+ return "SHA224";
+ }
+ else if (NistObjectIdentifiers.IdSha256.Equals(digestAlgOID))
+ {
+ return "SHA256";
+ }
+ else if (NistObjectIdentifiers.IdSha384.Equals(digestAlgOID))
+ {
+ return "SHA384";
+ }
+ else if (NistObjectIdentifiers.IdSha512.Equals(digestAlgOID))
+ {
+ return "SHA512";
+ }
+ else if (TeleTrusTObjectIdentifiers.RipeMD128.Equals(digestAlgOID))
+ {
+ return "RIPEMD128";
+ }
+ else if (TeleTrusTObjectIdentifiers.RipeMD160.Equals(digestAlgOID))
+ {
+ return "RIPEMD160";
+ }
+ else if (TeleTrusTObjectIdentifiers.RipeMD256.Equals(digestAlgOID))
+ {
+ return "RIPEMD256";
+ }
+ else if (CryptoProObjectIdentifiers.GostR3411.Equals(digestAlgOID))
+ {
+ return "GOST3411";
+ }
+ else
+ {
+ return digestAlgOID.Id;
+ }
+ }
+ }
+}
diff --git a/crypto/src/x509/X509Utilities.cs b/crypto/src/x509/X509Utilities.cs
new file mode 100644
index 000000000..52a122c21
--- /dev/null
+++ b/crypto/src/x509/X509Utilities.cs
@@ -0,0 +1,187 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.X509
+{
+ internal class X509Utilities
+ {
+ private static readonly IDictionary algorithms = Platform.CreateHashtable();
+ private static readonly IDictionary exParams = Platform.CreateHashtable();
+ private static readonly ISet noParams = new HashSet();
+
+ static X509Utilities()
+ {
+ algorithms.Add("MD2WITHRSAENCRYPTION", PkcsObjectIdentifiers.MD2WithRsaEncryption);
+ algorithms.Add("MD2WITHRSA", PkcsObjectIdentifiers.MD2WithRsaEncryption);
+ algorithms.Add("MD5WITHRSAENCRYPTION", PkcsObjectIdentifiers.MD5WithRsaEncryption);
+ algorithms.Add("MD5WITHRSA", PkcsObjectIdentifiers.MD5WithRsaEncryption);
+ algorithms.Add("SHA1WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha1WithRsaEncryption);
+ algorithms.Add("SHA1WITHRSA", PkcsObjectIdentifiers.Sha1WithRsaEncryption);
+ algorithms.Add("SHA224WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha224WithRsaEncryption);
+ algorithms.Add("SHA224WITHRSA", PkcsObjectIdentifiers.Sha224WithRsaEncryption);
+ algorithms.Add("SHA256WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha256WithRsaEncryption);
+ algorithms.Add("SHA256WITHRSA", PkcsObjectIdentifiers.Sha256WithRsaEncryption);
+ algorithms.Add("SHA384WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha384WithRsaEncryption);
+ algorithms.Add("SHA384WITHRSA", PkcsObjectIdentifiers.Sha384WithRsaEncryption);
+ algorithms.Add("SHA512WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha512WithRsaEncryption);
+ algorithms.Add("SHA512WITHRSA", PkcsObjectIdentifiers.Sha512WithRsaEncryption);
+ algorithms.Add("SHA1WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+ algorithms.Add("SHA224WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+ algorithms.Add("SHA256WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+ algorithms.Add("SHA384WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+ algorithms.Add("SHA512WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+ algorithms.Add("RIPEMD160WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160);
+ algorithms.Add("RIPEMD160WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160);
+ algorithms.Add("RIPEMD128WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128);
+ algorithms.Add("RIPEMD128WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128);
+ algorithms.Add("RIPEMD256WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256);
+ algorithms.Add("RIPEMD256WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256);
+ algorithms.Add("SHA1WITHDSA", X9ObjectIdentifiers.IdDsaWithSha1);
+ algorithms.Add("DSAWITHSHA1", X9ObjectIdentifiers.IdDsaWithSha1);
+ algorithms.Add("SHA224WITHDSA", NistObjectIdentifiers.DsaWithSha224);
+ algorithms.Add("SHA256WITHDSA", NistObjectIdentifiers.DsaWithSha256);
+ algorithms.Add("SHA384WITHDSA", NistObjectIdentifiers.DsaWithSha384);
+ algorithms.Add("SHA512WITHDSA", NistObjectIdentifiers.DsaWithSha512);
+ algorithms.Add("SHA1WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha1);
+ algorithms.Add("ECDSAWITHSHA1", X9ObjectIdentifiers.ECDsaWithSha1);
+ algorithms.Add("SHA224WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha224);
+ algorithms.Add("SHA256WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha256);
+ algorithms.Add("SHA384WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha384);
+ algorithms.Add("SHA512WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha512);
+ algorithms.Add("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94);
+ algorithms.Add("GOST3411WITHGOST3410-94", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94);
+ algorithms.Add("GOST3411WITHECGOST3410", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+ algorithms.Add("GOST3411WITHECGOST3410-2001", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+ algorithms.Add("GOST3411WITHGOST3410-2001", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+
+ //
+ // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field.
+ // The parameters field SHALL be NULL for RSA based signature algorithms.
+ //
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha1);
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha224);
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha256);
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha384);
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha512);
+ noParams.Add(X9ObjectIdentifiers.IdDsaWithSha1);
+ noParams.Add(NistObjectIdentifiers.DsaWithSha224);
+ noParams.Add(NistObjectIdentifiers.DsaWithSha256);
+ noParams.Add(NistObjectIdentifiers.DsaWithSha384);
+ noParams.Add(NistObjectIdentifiers.DsaWithSha512);
+
+ //
+ // RFC 4491
+ //
+ noParams.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94);
+ noParams.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+
+ //
+ // explicit params
+ //
+ AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1, DerNull.Instance);
+ exParams.Add("SHA1WITHRSAANDMGF1", CreatePssParams(sha1AlgId, 20));
+
+ AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha224, DerNull.Instance);
+ exParams.Add("SHA224WITHRSAANDMGF1", CreatePssParams(sha224AlgId, 28));
+
+ AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha256, DerNull.Instance);
+ exParams.Add("SHA256WITHRSAANDMGF1", CreatePssParams(sha256AlgId, 32));
+
+ AlgorithmIdentifier sha384AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha384, DerNull.Instance);
+ exParams.Add("SHA384WITHRSAANDMGF1", CreatePssParams(sha384AlgId, 48));
+
+ AlgorithmIdentifier sha512AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha512, DerNull.Instance);
+ exParams.Add("SHA512WITHRSAANDMGF1", CreatePssParams(sha512AlgId, 64));
+ }
+
+ private static RsassaPssParameters CreatePssParams(
+ AlgorithmIdentifier hashAlgId,
+ int saltSize)
+ {
+ return new RsassaPssParameters(
+ hashAlgId,
+ new AlgorithmIdentifier(PkcsObjectIdentifiers.IdMgf1, hashAlgId),
+ new DerInteger(saltSize),
+ new DerInteger(1));
+ }
+
+ internal static DerObjectIdentifier GetAlgorithmOid(
+ string algorithmName)
+ {
+ algorithmName = Platform.ToUpperInvariant(algorithmName);
+
+ if (algorithms.Contains(algorithmName))
+ {
+ return (DerObjectIdentifier) algorithms[algorithmName];
+ }
+
+ return new DerObjectIdentifier(algorithmName);
+ }
+
+ internal static AlgorithmIdentifier GetSigAlgID(
+ DerObjectIdentifier sigOid,
+ string algorithmName)
+ {
+ if (noParams.Contains(sigOid))
+ {
+ return new AlgorithmIdentifier(sigOid);
+ }
+
+ algorithmName = Platform.ToUpperInvariant(algorithmName);
+
+ if (exParams.Contains(algorithmName))
+ {
+ return new AlgorithmIdentifier(sigOid, (Asn1Encodable) exParams[algorithmName]);
+ }
+
+ return new AlgorithmIdentifier(sigOid, DerNull.Instance);
+ }
+
+ internal static IEnumerable GetAlgNames()
+ {
+ return new EnumerableProxy(algorithms.Keys);
+ }
+
+ internal static byte[] GetSignatureForObject(
+ DerObjectIdentifier sigOid, // TODO Redundant now?
+ string sigName,
+ AsymmetricKeyParameter privateKey,
+ SecureRandom random,
+ Asn1Encodable ae)
+ {
+ if (sigOid == null)
+ throw new ArgumentNullException("sigOid");
+
+ ISigner sig = SignerUtilities.GetSigner(sigName);
+
+ if (random != null)
+ {
+ sig.Init(true, new ParametersWithRandom(privateKey, random));
+ }
+ else
+ {
+ sig.Init(true, privateKey);
+ }
+
+ byte[] encoded = ae.GetDerEncoded();
+ sig.BlockUpdate(encoded, 0, encoded.Length);
+
+ return sig.GenerateSignature();
+ }
+ }
+}
diff --git a/crypto/src/x509/X509V1CertificateGenerator.cs b/crypto/src/x509/X509V1CertificateGenerator.cs
new file mode 100644
index 000000000..02b58a198
--- /dev/null
+++ b/crypto/src/x509/X509V1CertificateGenerator.cs
@@ -0,0 +1,205 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+
+namespace Org.BouncyCastle.X509
+{
+ ///
+ /// Class to Generate X509V1 Certificates.
+ ///
+ public class X509V1CertificateGenerator
+ {
+ private V1TbsCertificateGenerator tbsGen;
+ private DerObjectIdentifier sigOID;
+ private AlgorithmIdentifier sigAlgId;
+ private string signatureAlgorithm;
+
+ ///
+ /// Default Constructor.
+ ///
+ public X509V1CertificateGenerator()
+ {
+ tbsGen = new V1TbsCertificateGenerator();
+ }
+
+ ///
+ /// Reset the generator.
+ ///
+ public void Reset()
+ {
+ tbsGen = new V1TbsCertificateGenerator();
+ }
+
+ ///
+ /// Set the certificate's serial number.
+ ///
+ /// Make serial numbers long, if you have no serial number policy make sure the number is at least 16 bytes of secure random data.
+ /// You will be surprised how ugly a serial number collision can get.
+ /// The serial number.
+ public void SetSerialNumber(
+ BigInteger serialNumber)
+ {
+ if (serialNumber.SignValue <= 0)
+ {
+ throw new ArgumentException("serial number must be a positive integer", "serialNumber");
+ }
+
+ tbsGen.SetSerialNumber(new DerInteger(serialNumber));
+ }
+
+ ///
+ /// Set the issuer distinguished name.
+ /// The issuer is the entity whose private key is used to sign the certificate.
+ ///
+ /// The issuers DN.
+ public void SetIssuerDN(
+ X509Name issuer)
+ {
+ tbsGen.SetIssuer(issuer);
+ }
+
+ ///
+ /// Set the date that this certificate is to be valid from.
+ ///
+ ///
+ public void SetNotBefore(
+ DateTime date)
+ {
+ tbsGen.SetStartDate(new Time(date));
+ }
+
+ ///
+ /// Set the date after which this certificate will no longer be valid.
+ ///
+ ///
+ public void SetNotAfter(
+ DateTime date)
+ {
+ tbsGen.SetEndDate(new Time(date));
+ }
+
+ ///
+ /// Set the subject distinguished name.
+ /// The subject describes the entity associated with the public key.
+ ///
+ ///
+ public void SetSubjectDN(
+ X509Name subject)
+ {
+ tbsGen.SetSubject(subject);
+ }
+
+ ///
+ /// Set the public key that this certificate identifies.
+ ///
+ ///
+ public void SetPublicKey(
+ AsymmetricKeyParameter publicKey)
+ {
+ try
+ {
+ tbsGen.SetSubjectPublicKeyInfo(
+ SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey));
+ }
+ catch (Exception e)
+ {
+ throw new ArgumentException("unable to process key - " + e.ToString());
+ }
+ }
+
+ ///
+ /// Set the signature algorithm that will be used to sign this certificate.
+ /// This can be either a name or an OID, names are treated as case insensitive.
+ ///
+ /// string representation of the algorithm name
+ public void SetSignatureAlgorithm(
+ string signatureAlgorithm)
+ {
+ this.signatureAlgorithm = signatureAlgorithm;
+
+ try
+ {
+ sigOID = X509Utilities.GetAlgorithmOid(signatureAlgorithm);
+ }
+ catch (Exception)
+ {
+ throw new ArgumentException("Unknown signature type requested", "signatureAlgorithm");
+ }
+
+ sigAlgId = X509Utilities.GetSigAlgID(sigOID, signatureAlgorithm);
+
+ tbsGen.SetSignature(sigAlgId);
+ }
+
+ ///
+ /// Generate a new X509Certificate.
+ ///
+ /// The private key of the issuer used to sign this certificate.
+ /// An X509Certificate.
+ public X509Certificate Generate(
+ AsymmetricKeyParameter privateKey)
+ {
+ return Generate(privateKey, null);
+ }
+
+ ///
+ /// Generate a new X509Certificate specifying a SecureRandom instance that you would like to use.
+ ///
+ /// The private key of the issuer used to sign this certificate.
+ /// The Secure Random you want to use.
+ /// An X509Certificate.
+ public X509Certificate Generate(
+ AsymmetricKeyParameter privateKey,
+ SecureRandom random)
+ {
+ TbsCertificateStructure tbsCert = tbsGen.GenerateTbsCertificate();
+ byte[] signature;
+
+ try
+ {
+ signature = X509Utilities.GetSignatureForObject(
+ sigOID, signatureAlgorithm, privateKey, random, tbsCert);
+ }
+ catch (Exception e)
+ {
+ // TODO
+// throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
+ throw new CertificateEncodingException("exception encoding TBS cert", e);
+ }
+
+ try
+ {
+ return GenerateJcaObject(tbsCert, signature);
+ }
+ catch (CertificateParsingException e)
+ {
+ // TODO
+ // throw new ExtCertificateEncodingException("exception producing certificate object", e);
+ throw new CertificateEncodingException("exception producing certificate object", e);
+ }
+ }
+
+ private X509Certificate GenerateJcaObject(
+ TbsCertificateStructure tbsCert,
+ byte[] signature)
+ {
+ return new X509Certificate(
+ new X509CertificateStructure(tbsCert, sigAlgId, new DerBitString(signature)));
+ }
+
+ ///
+ /// Allows enumeration of the signature names supported by the generator.
+ ///
+ public IEnumerable SignatureAlgNames
+ {
+ get { return X509Utilities.GetAlgNames(); }
+ }
+ }
+}
diff --git a/crypto/src/x509/X509V2AttributeCertificate.cs b/crypto/src/x509/X509V2AttributeCertificate.cs
new file mode 100644
index 000000000..117ac4cc2
--- /dev/null
+++ b/crypto/src/x509/X509V2AttributeCertificate.cs
@@ -0,0 +1,255 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.X509
+{
+ /// An implementation of a version 2 X.509 Attribute Certificate.
+ public class X509V2AttributeCertificate
+ : X509ExtensionBase, IX509AttributeCertificate
+ {
+ private readonly AttributeCertificate cert;
+ private readonly DateTime notBefore;
+ private readonly DateTime notAfter;
+
+ private static AttributeCertificate GetObject(Stream input)
+ {
+ try
+ {
+ return AttributeCertificate.GetInstance(Asn1Object.FromStream(input));
+ }
+ catch (IOException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new IOException("exception decoding certificate structure", e);
+ }
+ }
+
+ public X509V2AttributeCertificate(
+ Stream encIn)
+ : this(GetObject(encIn))
+ {
+ }
+
+ public X509V2AttributeCertificate(
+ byte[] encoded)
+ : this(new MemoryStream(encoded, false))
+ {
+ }
+
+ internal X509V2AttributeCertificate(
+ AttributeCertificate cert)
+ {
+ this.cert = cert;
+
+ try
+ {
+ this.notAfter = cert.ACInfo.AttrCertValidityPeriod.NotAfterTime.ToDateTime();
+ this.notBefore = cert.ACInfo.AttrCertValidityPeriod.NotBeforeTime.ToDateTime();
+ }
+ catch (Exception e)
+ {
+ throw new IOException("invalid data structure in certificate!", e);
+ }
+ }
+
+ public virtual int Version
+ {
+ get { return cert.ACInfo.Version.Value.IntValue + 1; }
+ }
+
+ public virtual BigInteger SerialNumber
+ {
+ get { return cert.ACInfo.SerialNumber.Value; }
+ }
+
+ public virtual AttributeCertificateHolder Holder
+ {
+ get
+ {
+ return new AttributeCertificateHolder((Asn1Sequence)cert.ACInfo.Holder.ToAsn1Object());
+ }
+ }
+
+ public virtual AttributeCertificateIssuer Issuer
+ {
+ get
+ {
+ return new AttributeCertificateIssuer(cert.ACInfo.Issuer);
+ }
+ }
+
+ public virtual DateTime NotBefore
+ {
+ get { return notBefore; }
+ }
+
+ public virtual DateTime NotAfter
+ {
+ get { return notAfter; }
+ }
+
+ public virtual bool[] GetIssuerUniqueID()
+ {
+ DerBitString id = cert.ACInfo.IssuerUniqueID;
+
+ if (id != null)
+ {
+ byte[] bytes = id.GetBytes();
+ bool[] boolId = new bool[bytes.Length * 8 - id.PadBits];
+
+ for (int i = 0; i != boolId.Length; i++)
+ {
+ //boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+ boolId[i] = (bytes[i / 8] & (0x80 >> (i % 8))) != 0;
+ }
+
+ return boolId;
+ }
+
+ return null;
+ }
+
+ public virtual bool IsValidNow
+ {
+ get { return IsValid(DateTime.UtcNow); }
+ }
+
+ public virtual bool IsValid(
+ DateTime date)
+ {
+ return date.CompareTo(NotBefore) >= 0 && date.CompareTo(NotAfter) <= 0;
+ }
+
+ public virtual void CheckValidity()
+ {
+ this.CheckValidity(DateTime.UtcNow);
+ }
+
+ public virtual void CheckValidity(
+ DateTime date)
+ {
+ if (date.CompareTo(NotAfter) > 0)
+ throw new CertificateExpiredException("certificate expired on " + NotAfter);
+ if (date.CompareTo(NotBefore) < 0)
+ throw new CertificateNotYetValidException("certificate not valid until " + NotBefore);
+ }
+
+ public virtual byte[] GetSignature()
+ {
+ return cert.SignatureValue.GetBytes();
+ }
+
+ public virtual void Verify(
+ AsymmetricKeyParameter publicKey)
+ {
+ if (!cert.SignatureAlgorithm.Equals(cert.ACInfo.Signature))
+ {
+ throw new CertificateException("Signature algorithm in certificate info not same as outer certificate");
+ }
+
+ ISigner signature = SignerUtilities.GetSigner(cert.SignatureAlgorithm.ObjectID.Id);
+
+ signature.Init(false, publicKey);
+
+ try
+ {
+ byte[] b = cert.ACInfo.GetEncoded();
+ signature.BlockUpdate(b, 0, b.Length);
+ }
+ catch (IOException e)
+ {
+ throw new SignatureException("Exception encoding certificate info object", e);
+ }
+
+ if (!signature.VerifySignature(this.GetSignature()))
+ {
+ throw new InvalidKeyException("Public key presented not for certificate signature");
+ }
+ }
+
+ public virtual byte[] GetEncoded()
+ {
+ return cert.GetEncoded();
+ }
+
+ protected override X509Extensions GetX509Extensions()
+ {
+ return cert.ACInfo.Extensions;
+ }
+
+ public virtual X509Attribute[] GetAttributes()
+ {
+ Asn1Sequence seq = cert.ACInfo.Attributes;
+ X509Attribute[] attrs = new X509Attribute[seq.Count];
+
+ for (int i = 0; i != seq.Count; i++)
+ {
+ attrs[i] = new X509Attribute((Asn1Encodable)seq[i]);
+ }
+
+ return attrs;
+ }
+
+ public virtual X509Attribute[] GetAttributes(
+ string oid)
+ {
+ Asn1Sequence seq = cert.ACInfo.Attributes;
+ IList list = Platform.CreateArrayList();
+
+ for (int i = 0; i != seq.Count; i++)
+ {
+ X509Attribute attr = new X509Attribute((Asn1Encodable)seq[i]);
+ if (attr.Oid.Equals(oid))
+ {
+ list.Add(attr);
+ }
+ }
+
+ if (list.Count < 1)
+ {
+ return null;
+ }
+
+ X509Attribute[] result = new X509Attribute[list.Count];
+ for (int i = 0; i < list.Count; ++i)
+ {
+ result[i] = (X509Attribute)list[i];
+ }
+ return result;
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ X509V2AttributeCertificate other = obj as X509V2AttributeCertificate;
+
+ if (other == null)
+ return false;
+
+ return cert.Equals(other.cert);
+
+ // NB: May prefer this implementation of Equals if more than one certificate implementation in play
+ //return Arrays.AreEqual(this.GetEncoded(), other.GetEncoded());
+ }
+
+ public override int GetHashCode()
+ {
+ return cert.GetHashCode();
+ }
+ }
+}
diff --git a/crypto/src/x509/X509V2AttributeCertificateGenerator.cs b/crypto/src/x509/X509V2AttributeCertificateGenerator.cs
new file mode 100644
index 000000000..a683d5e20
--- /dev/null
+++ b/crypto/src/x509/X509V2AttributeCertificateGenerator.cs
@@ -0,0 +1,180 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.X509
+{
+ /// Class to produce an X.509 Version 2 AttributeCertificate.
+ public class X509V2AttributeCertificateGenerator
+ {
+ private readonly X509ExtensionsGenerator extGenerator = new X509ExtensionsGenerator();
+
+ private V2AttributeCertificateInfoGenerator acInfoGen;
+ private DerObjectIdentifier sigOID;
+ private AlgorithmIdentifier sigAlgId;
+ private string signatureAlgorithm;
+
+ public X509V2AttributeCertificateGenerator()
+ {
+ acInfoGen = new V2AttributeCertificateInfoGenerator();
+ }
+
+ /// Reset the generator
+ public void Reset()
+ {
+ acInfoGen = new V2AttributeCertificateInfoGenerator();
+ extGenerator.Reset();
+ }
+
+ /// Set the Holder of this Attribute Certificate.
+ public void SetHolder(
+ AttributeCertificateHolder holder)
+ {
+ acInfoGen.SetHolder(holder.holder);
+ }
+
+ /// Set the issuer.
+ public void SetIssuer(
+ AttributeCertificateIssuer issuer)
+ {
+ acInfoGen.SetIssuer(AttCertIssuer.GetInstance(issuer.form));
+ }
+
+ /// Set the serial number for the certificate.
+ public void SetSerialNumber(
+ BigInteger serialNumber)
+ {
+ acInfoGen.SetSerialNumber(new DerInteger(serialNumber));
+ }
+
+ public void SetNotBefore(
+ DateTime date)
+ {
+ acInfoGen.SetStartDate(new DerGeneralizedTime(date));
+ }
+
+ public void SetNotAfter(
+ DateTime date)
+ {
+ acInfoGen.SetEndDate(new DerGeneralizedTime(date));
+ }
+
+ ///
+ /// Set the signature algorithm. This can be either a name or an OID, names
+ /// are treated as case insensitive.
+ ///
+ /// The algorithm name.
+ public void SetSignatureAlgorithm(
+ string signatureAlgorithm)
+ {
+ this.signatureAlgorithm = signatureAlgorithm;
+
+ try
+ {
+ sigOID = X509Utilities.GetAlgorithmOid(signatureAlgorithm);
+ }
+ catch (Exception)
+ {
+ throw new ArgumentException("Unknown signature type requested");
+ }
+
+ sigAlgId = X509Utilities.GetSigAlgID(sigOID, signatureAlgorithm);
+
+ acInfoGen.SetSignature(sigAlgId);
+ }
+
+ /// Add an attribute.
+ public void AddAttribute(
+ X509Attribute attribute)
+ {
+ acInfoGen.AddAttribute(AttributeX509.GetInstance(attribute.ToAsn1Object()));
+ }
+
+ public void SetIssuerUniqueId(
+ bool[] iui)
+ {
+ // TODO convert bool array to bit string
+ //acInfoGen.SetIssuerUniqueID(iui);
+ throw Platform.CreateNotImplementedException("SetIssuerUniqueId()");
+ }
+
+ /// Add a given extension field for the standard extensions tag.
+ public void AddExtension(
+ string oid,
+ bool critical,
+ Asn1Encodable extensionValue)
+ {
+ extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, extensionValue);
+ }
+
+ ///
+ /// Add a given extension field for the standard extensions tag.
+ /// The value parameter becomes the contents of the octet string associated
+ /// with the extension.
+ ///
+ public void AddExtension(
+ string oid,
+ bool critical,
+ byte[] extensionValue)
+ {
+ extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, extensionValue);
+ }
+
+ ///
+ /// Generate an X509 certificate, based on the current issuer and subject.
+ ///
+ public IX509AttributeCertificate Generate(
+ AsymmetricKeyParameter publicKey)
+ {
+ return Generate(publicKey, null);
+ }
+
+ ///
+ /// Generate an X509 certificate, based on the current issuer and subject,
+ /// using the supplied source of randomness, if required.
+ ///
+ public IX509AttributeCertificate Generate(
+ AsymmetricKeyParameter publicKey,
+ SecureRandom random)
+ {
+ if (!extGenerator.IsEmpty)
+ {
+ acInfoGen.SetExtensions(extGenerator.Generate());
+ }
+
+ AttributeCertificateInfo acInfo = acInfoGen.GenerateAttributeCertificateInfo();
+
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ v.Add(acInfo, sigAlgId);
+
+ try
+ {
+ v.Add(new DerBitString(X509Utilities.GetSignatureForObject(sigOID, signatureAlgorithm, publicKey, random, acInfo)));
+
+ return new X509V2AttributeCertificate(AttributeCertificate.GetInstance(new DerSequence(v)));
+ }
+ catch (Exception e)
+ {
+ // TODO
+// throw new ExtCertificateEncodingException("constructed invalid certificate", e);
+ throw new CertificateEncodingException("constructed invalid certificate", e);
+ }
+ }
+
+ ///
+ /// Allows enumeration of the signature names supported by the generator.
+ ///
+ public IEnumerable SignatureAlgNames
+ {
+ get { return X509Utilities.GetAlgNames(); }
+ }
+ }
+}
diff --git a/crypto/src/x509/X509V2CRLGenerator.cs b/crypto/src/x509/X509V2CRLGenerator.cs
new file mode 100644
index 000000000..a2293b333
--- /dev/null
+++ b/crypto/src/x509/X509V2CRLGenerator.cs
@@ -0,0 +1,261 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.X509
+{
+ /**
+ * class to produce an X.509 Version 2 CRL.
+ */
+ public class X509V2CrlGenerator
+ {
+ private readonly X509ExtensionsGenerator extGenerator = new X509ExtensionsGenerator();
+
+ private V2TbsCertListGenerator tbsGen;
+ private DerObjectIdentifier sigOID;
+ private AlgorithmIdentifier sigAlgId;
+ private string signatureAlgorithm;
+
+ public X509V2CrlGenerator()
+ {
+ tbsGen = new V2TbsCertListGenerator();
+ }
+
+ /**
+ * reset the generator
+ */
+ public void Reset()
+ {
+ tbsGen = new V2TbsCertListGenerator();
+ extGenerator.Reset();
+ }
+
+ /**
+ * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+ * certificate.
+ */
+ public void SetIssuerDN(
+ X509Name issuer)
+ {
+ tbsGen.SetIssuer(issuer);
+ }
+
+ public void SetThisUpdate(
+ DateTime date)
+ {
+ tbsGen.SetThisUpdate(new Time(date));
+ }
+
+ public void SetNextUpdate(
+ DateTime date)
+ {
+ tbsGen.SetNextUpdate(new Time(date));
+ }
+
+ /**
+ * Reason being as indicated by CrlReason, i.e. CrlReason.KeyCompromise
+ * or 0 if CrlReason is not to be used
+ **/
+ public void AddCrlEntry(
+ BigInteger userCertificate,
+ DateTime revocationDate,
+ int reason)
+ {
+ tbsGen.AddCrlEntry(new DerInteger(userCertificate), new Time(revocationDate), reason);
+ }
+
+ /**
+ * Add a CRL entry with an Invalidity Date extension as well as a CrlReason extension.
+ * Reason being as indicated by CrlReason, i.e. CrlReason.KeyCompromise
+ * or 0 if CrlReason is not to be used
+ **/
+ public void AddCrlEntry(
+ BigInteger userCertificate,
+ DateTime revocationDate,
+ int reason,
+ DateTime invalidityDate)
+ {
+ tbsGen.AddCrlEntry(new DerInteger(userCertificate), new Time(revocationDate), reason, new DerGeneralizedTime(invalidityDate));
+ }
+
+ /**
+ * Add a CRL entry with extensions.
+ **/
+ public void AddCrlEntry(
+ BigInteger userCertificate,
+ DateTime revocationDate,
+ X509Extensions extensions)
+ {
+ tbsGen.AddCrlEntry(new DerInteger(userCertificate), new Time(revocationDate), extensions);
+ }
+
+ /**
+ * Add the CRLEntry objects contained in a previous CRL.
+ *
+ * @param other the X509Crl to source the other entries from.
+ */
+ public void AddCrl(
+ X509Crl other)
+ {
+ if (other == null)
+ throw new ArgumentNullException("other");
+
+ ISet revocations = other.GetRevokedCertificates();
+
+ if (revocations != null)
+ {
+ foreach (X509CrlEntry entry in revocations)
+ {
+ try
+ {
+ tbsGen.AddCrlEntry(
+ Asn1Sequence.GetInstance(
+ Asn1Object.FromByteArray(entry.GetEncoded())));
+ }
+ catch (IOException e)
+ {
+ throw new CrlException("exception processing encoding of CRL", e);
+ }
+ }
+ }
+ }
+
+ /**
+ * Set the signature algorithm. This can be either a name or an oid, names
+ * are treated as case insensitive.
+ *
+ * @param signatureAlgorithm string representation of the algorithm name.
+ */
+ public void SetSignatureAlgorithm(
+ string signatureAlgorithm)
+ {
+ this.signatureAlgorithm = signatureAlgorithm;
+
+ try
+ {
+ sigOID = X509Utilities.GetAlgorithmOid(signatureAlgorithm);
+ }
+ catch (Exception e)
+ {
+ throw new ArgumentException("Unknown signature type requested", e);
+ }
+
+ sigAlgId = X509Utilities.GetSigAlgID(sigOID, signatureAlgorithm);
+
+ tbsGen.SetSignature(sigAlgId);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 0)
+ */
+ public void AddExtension(
+ string oid,
+ bool critical,
+ Asn1Encodable extensionValue)
+ {
+ extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, extensionValue);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 0)
+ */
+ public void AddExtension(
+ DerObjectIdentifier oid,
+ bool critical,
+ Asn1Encodable extensionValue)
+ {
+ extGenerator.AddExtension(oid, critical, extensionValue);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 0)
+ */
+ public void AddExtension(
+ string oid,
+ bool critical,
+ byte[] extensionValue)
+ {
+ extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, new DerOctetString(extensionValue));
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 0)
+ */
+ public void AddExtension(
+ DerObjectIdentifier oid,
+ bool critical,
+ byte[] extensionValue)
+ {
+ extGenerator.AddExtension(oid, critical, new DerOctetString(extensionValue));
+ }
+
+ /// Generate an X509 CRL, based on the current issuer and subject.
+ /// The key used for signing.
+ public X509Crl Generate(
+ AsymmetricKeyParameter privateKey)
+ {
+ return Generate(privateKey, null);
+ }
+
+ /// Generate an X509 CRL, based on the current issuer and subject.
+ /// The key used for signing.
+ /// A user-defined source of randomness.
+ public X509Crl Generate(
+ AsymmetricKeyParameter privateKey,
+ SecureRandom random)
+ {
+ TbsCertificateList tbsCrl = GenerateCertList();
+ byte[] signature;
+
+ try
+ {
+ signature = X509Utilities.GetSignatureForObject(
+ sigOID, signatureAlgorithm, privateKey, random, tbsCrl);
+ }
+ catch (IOException e)
+ {
+ // TODO
+// throw new ExtCrlException("cannot generate CRL encoding", e);
+ throw new CrlException("cannot generate CRL encoding", e);
+ }
+
+ return GenerateJcaObject(tbsCrl, signature);
+ }
+
+ private TbsCertificateList GenerateCertList()
+ {
+ if (!extGenerator.IsEmpty)
+ {
+ tbsGen.SetExtensions(extGenerator.Generate());
+ }
+
+ return tbsGen.GenerateTbsCertList();
+ }
+
+ private X509Crl GenerateJcaObject(
+ TbsCertificateList tbsCrl,
+ byte[] signature)
+ {
+ return new X509Crl(
+ CertificateList.GetInstance(
+ new DerSequence(tbsCrl, sigAlgId, new DerBitString(signature))));
+ }
+
+ ///
+ /// Allows enumeration of the signature names supported by the generator.
+ ///
+ public IEnumerable SignatureAlgNames
+ {
+ get { return X509Utilities.GetAlgNames(); }
+ }
+ }
+}
diff --git a/crypto/src/x509/X509V3CertificateGenerator.cs b/crypto/src/x509/X509V3CertificateGenerator.cs
new file mode 100644
index 000000000..bb0dd9cbc
--- /dev/null
+++ b/crypto/src/x509/X509V3CertificateGenerator.cs
@@ -0,0 +1,346 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.X509.Extension;
+
+namespace Org.BouncyCastle.X509
+{
+ ///
+ /// A class to Generate Version 3 X509Certificates.
+ ///
+ public class X509V3CertificateGenerator
+ {
+ private readonly X509ExtensionsGenerator extGenerator = new X509ExtensionsGenerator();
+
+ private V3TbsCertificateGenerator tbsGen;
+ private DerObjectIdentifier sigOid;
+ private AlgorithmIdentifier sigAlgId;
+ private string signatureAlgorithm;
+
+ public X509V3CertificateGenerator()
+ {
+ tbsGen = new V3TbsCertificateGenerator();
+ }
+
+ ///
+ /// Reset the Generator.
+ ///
+ public void Reset()
+ {
+ tbsGen = new V3TbsCertificateGenerator();
+ extGenerator.Reset();
+ }
+
+ ///
+ /// Set the certificate's serial number.
+ ///
+ /// Make serial numbers long, if you have no serial number policy make sure the number is at least 16 bytes of secure random data.
+ /// You will be surprised how ugly a serial number collision can Get.
+ /// The serial number.
+ public void SetSerialNumber(
+ BigInteger serialNumber)
+ {
+ if (serialNumber.SignValue <= 0)
+ {
+ throw new ArgumentException("serial number must be a positive integer", "serialNumber");
+ }
+
+ tbsGen.SetSerialNumber(new DerInteger(serialNumber));
+ }
+
+ ///
+ /// Set the distinguished name of the issuer.
+ /// The issuer is the entity which is signing the certificate.
+ ///
+ /// The issuer's DN.
+ public void SetIssuerDN(
+ X509Name issuer)
+ {
+ tbsGen.SetIssuer(issuer);
+ }
+
+ ///
+ /// Set the date that this certificate is to be valid from.
+ ///
+ ///
+ public void SetNotBefore(
+ DateTime date)
+ {
+ tbsGen.SetStartDate(new Time(date));
+ }
+
+ ///
+ /// Set the date after which this certificate will no longer be valid.
+ ///
+ ///
+ public void SetNotAfter(
+ DateTime date)
+ {
+ tbsGen.SetEndDate(new Time(date));
+ }
+
+ ///
+ /// Set the DN of the entity that this certificate is about.
+ ///
+ ///
+ public void SetSubjectDN(
+ X509Name subject)
+ {
+ tbsGen.SetSubject(subject);
+ }
+
+ ///
+ /// Set the public key that this certificate identifies.
+ ///
+ ///
+ public void SetPublicKey(
+ AsymmetricKeyParameter publicKey)
+ {
+ tbsGen.SetSubjectPublicKeyInfo(SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey));
+ }
+
+ ///
+ /// Set the signature algorithm that will be used to sign this certificate.
+ ///
+ ///
+ public void SetSignatureAlgorithm(
+ string signatureAlgorithm)
+ {
+ this.signatureAlgorithm = signatureAlgorithm;
+
+ try
+ {
+ sigOid = X509Utilities.GetAlgorithmOid(signatureAlgorithm);
+ }
+ catch (Exception)
+ {
+ throw new ArgumentException("Unknown signature type requested: " + signatureAlgorithm);
+ }
+
+ sigAlgId = X509Utilities.GetSigAlgID(sigOid, signatureAlgorithm);
+
+ tbsGen.SetSignature(sigAlgId);
+ }
+
+ ///
+ /// Set the subject unique ID - note: it is very rare that it is correct to do this.
+ ///
+ ///
+ public void SetSubjectUniqueID(
+ bool[] uniqueID)
+ {
+ tbsGen.SetSubjectUniqueID(booleanToBitString(uniqueID));
+ }
+
+ ///
+ /// Set the issuer unique ID - note: it is very rare that it is correct to do this.
+ ///
+ ///
+ public void SetIssuerUniqueID(
+ bool[] uniqueID)
+ {
+ tbsGen.SetIssuerUniqueID(booleanToBitString(uniqueID));
+ }
+
+ private DerBitString booleanToBitString(
+ bool[] id)
+ {
+ byte[] bytes = new byte[(id.Length + 7) / 8];
+
+ for (int i = 0; i != id.Length; i++)
+ {
+ if (id[i])
+ {
+ bytes[i / 8] |= (byte)(1 << ((7 - (i % 8))));
+ }
+ }
+
+ int pad = id.Length % 8;
+
+ if (pad == 0)
+ {
+ return new DerBitString(bytes);
+ }
+
+ return new DerBitString(bytes, 8 - pad);
+ }
+
+ ///
+ /// Add a given extension field for the standard extensions tag (tag 3).
+ ///
+ /// string containing a dotted decimal Object Identifier.
+ /// Is it critical.
+ /// The value.
+ public void AddExtension(
+ string oid,
+ bool critical,
+ Asn1Encodable extensionValue)
+ {
+ extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, extensionValue);
+ }
+
+ ///
+ /// Add an extension to this certificate.
+ ///
+ /// Its Object Identifier.
+ /// Is it critical.
+ /// The value.
+ public void AddExtension(
+ DerObjectIdentifier oid,
+ bool critical,
+ Asn1Encodable extensionValue)
+ {
+ extGenerator.AddExtension(oid, critical, extensionValue);
+ }
+
+ ///
+ /// Add an extension using a string with a dotted decimal OID.
+ ///
+ /// string containing a dotted decimal Object Identifier.
+ /// Is it critical.
+ /// byte[] containing the value of this extension.
+ public void AddExtension(
+ string oid,
+ bool critical,
+ byte[] extensionValue)
+ {
+ extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, new DerOctetString(extensionValue));
+ }
+
+ ///
+ /// Add an extension to this certificate.
+ ///
+ /// Its Object Identifier.
+ /// Is it critical.
+ /// byte[] containing the value of this extension.
+ public void AddExtension(
+ DerObjectIdentifier oid,
+ bool critical,
+ byte[] extensionValue)
+ {
+ extGenerator.AddExtension(oid, critical, new DerOctetString(extensionValue));
+ }
+
+ ///
+ /// Add a given extension field for the standard extensions tag (tag 3),
+ /// copying the extension value from another certificate.
+ ///
+ public void CopyAndAddExtension(
+ string oid,
+ bool critical,
+ X509Certificate cert)
+ {
+ CopyAndAddExtension(new DerObjectIdentifier(oid), critical, cert);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ * copying the extension value from another certificate.
+ * @throws CertificateParsingException if the extension cannot be extracted.
+ */
+ public void CopyAndAddExtension(
+ DerObjectIdentifier oid,
+ bool critical,
+ X509Certificate cert)
+ {
+ Asn1OctetString extValue = cert.GetExtensionValue(oid);
+
+ if (extValue == null)
+ {
+ throw new CertificateParsingException("extension " + oid + " not present");
+ }
+
+ try
+ {
+ Asn1Encodable value = X509ExtensionUtilities.FromExtensionValue(extValue);
+
+ this.AddExtension(oid, critical, value);
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException(e.Message, e);
+ }
+ }
+
+ ///
+ /// Generate an X509Certificate.
+ ///
+ /// The private key of the issuer that is signing this certificate.
+ /// An X509Certificate.
+ public X509Certificate Generate(
+ AsymmetricKeyParameter privateKey)
+ {
+ return Generate(privateKey, null);
+ }
+
+ ///
+ /// Generate an X509Certificate using your own SecureRandom.
+ ///
+ /// The private key of the issuer that is signing this certificate.
+ /// You Secure Random instance.
+ /// An X509Certificate.
+ public X509Certificate Generate(
+ AsymmetricKeyParameter privateKey,
+ SecureRandom random)
+ {
+ TbsCertificateStructure tbsCert = GenerateTbsCert();
+ byte[] signature;
+
+ try
+ {
+ signature = X509Utilities.GetSignatureForObject(
+ sigOid, signatureAlgorithm, privateKey, random, tbsCert);
+ }
+ catch (Exception e)
+ {
+ // TODO
+// throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
+ throw new CertificateEncodingException("exception encoding TBS cert", e);
+ }
+
+ try
+ {
+ return GenerateJcaObject(tbsCert, signature);
+ }
+ catch (CertificateParsingException e)
+ {
+ // TODO
+ // throw new ExtCertificateEncodingException("exception producing certificate object", e);
+ throw new CertificateEncodingException("exception producing certificate object", e);
+ }
+ }
+
+ private TbsCertificateStructure GenerateTbsCert()
+ {
+ if (!extGenerator.IsEmpty)
+ {
+ tbsGen.SetExtensions(extGenerator.Generate());
+ }
+
+ return tbsGen.GenerateTbsCertificate();
+ }
+
+ private X509Certificate GenerateJcaObject(
+ TbsCertificateStructure tbsCert,
+ byte[] signature)
+ {
+ return new X509Certificate(
+ new X509CertificateStructure(tbsCert, sigAlgId, new DerBitString(signature)));
+ }
+
+ ///
+ /// Allows enumeration of the signature names supported by the generator.
+ ///
+ public IEnumerable SignatureAlgNames
+ {
+ get { return X509Utilities.GetAlgNames(); }
+ }
+ }
+}
diff --git a/crypto/src/x509/extension/AuthorityKeyIdentifierStructure.cs b/crypto/src/x509/extension/AuthorityKeyIdentifierStructure.cs
new file mode 100644
index 000000000..006dc009b
--- /dev/null
+++ b/crypto/src/x509/extension/AuthorityKeyIdentifierStructure.cs
@@ -0,0 +1,102 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+
+namespace Org.BouncyCastle.X509.Extension
+{
+ /// A high level authority key identifier.
+ public class AuthorityKeyIdentifierStructure
+ : AuthorityKeyIdentifier
+ {
+ /**
+ * Constructor which will take the byte[] returned from getExtensionValue()
+ *
+ * @param encodedValue a DER octet encoded string with the extension structure in it.
+ * @throws IOException on parsing errors.
+ */
+ // TODO Add a functional constructor from byte[]?
+ public AuthorityKeyIdentifierStructure(
+ Asn1OctetString encodedValue)
+ : base((Asn1Sequence) X509ExtensionUtilities.FromExtensionValue(encodedValue))
+ {
+ }
+
+ private static Asn1Sequence FromCertificate(
+ X509Certificate certificate)
+ {
+ try
+ {
+ GeneralName genName = new GeneralName(
+ PrincipalUtilities.GetIssuerX509Principal(certificate));
+
+ if (certificate.Version == 3)
+ {
+ Asn1OctetString ext = certificate.GetExtensionValue(X509Extensions.SubjectKeyIdentifier);
+
+ if (ext != null)
+ {
+ Asn1OctetString str = (Asn1OctetString) X509ExtensionUtilities.FromExtensionValue(ext);
+
+ return (Asn1Sequence) new AuthorityKeyIdentifier(
+ str.GetOctets(), new GeneralNames(genName), certificate.SerialNumber).ToAsn1Object();
+ }
+ }
+
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(
+ certificate.GetPublicKey());
+
+ return (Asn1Sequence) new AuthorityKeyIdentifier(
+ info, new GeneralNames(genName), certificate.SerialNumber).ToAsn1Object();
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("Exception extracting certificate details", e);
+ }
+ }
+
+ private static Asn1Sequence FromKey(
+ AsymmetricKeyParameter pubKey)
+ {
+ try
+ {
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pubKey);
+
+ return (Asn1Sequence) new AuthorityKeyIdentifier(info).ToAsn1Object();
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeyException("can't process key: " + e);
+ }
+ }
+
+ /**
+ * Create an AuthorityKeyIdentifier using the passed in certificate's public
+ * key, issuer and serial number.
+ *
+ * @param certificate the certificate providing the information.
+ * @throws CertificateParsingException if there is a problem processing the certificate
+ */
+ public AuthorityKeyIdentifierStructure(
+ X509Certificate certificate)
+ : base(FromCertificate(certificate))
+ {
+ }
+
+ /**
+ * Create an AuthorityKeyIdentifier using just the hash of the
+ * public key.
+ *
+ * @param pubKey the key to generate the hash from.
+ * @throws InvalidKeyException if there is a problem using the key.
+ */
+ public AuthorityKeyIdentifierStructure(
+ AsymmetricKeyParameter pubKey)
+ : base(FromKey(pubKey))
+ {
+ }
+ }
+}
diff --git a/crypto/src/x509/extension/SubjectKeyIdentifierStructure.cs b/crypto/src/x509/extension/SubjectKeyIdentifierStructure.cs
new file mode 100644
index 000000000..4c7b79ab8
--- /dev/null
+++ b/crypto/src/x509/extension/SubjectKeyIdentifierStructure.cs
@@ -0,0 +1,49 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security.Certificates;
+
+namespace Org.BouncyCastle.X509.Extension
+{
+ /**
+ * A high level subject key identifier.
+ */
+ public class SubjectKeyIdentifierStructure
+ : SubjectKeyIdentifier
+ {
+ /**
+ * Constructor which will take the byte[] returned from getExtensionValue()
+ *
+ * @param encodedValue a DER octet encoded string with the extension structure in it.
+ * @throws IOException on parsing errors.
+ */
+ public SubjectKeyIdentifierStructure(
+ Asn1OctetString encodedValue)
+ : base((Asn1OctetString) X509ExtensionUtilities.FromExtensionValue(encodedValue))
+ {
+ }
+
+ private static Asn1OctetString FromPublicKey(
+ AsymmetricKeyParameter pubKey)
+ {
+ try
+ {
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pubKey);
+
+ return (Asn1OctetString) new SubjectKeyIdentifier(info).ToAsn1Object();
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("Exception extracting certificate details: " + e.ToString());
+ }
+ }
+
+ public SubjectKeyIdentifierStructure(
+ AsymmetricKeyParameter pubKey)
+ : base(FromPublicKey(pubKey))
+ {
+ }
+ }
+}
diff --git a/crypto/src/x509/extension/X509ExtensionUtil.cs b/crypto/src/x509/extension/X509ExtensionUtil.cs
new file mode 100644
index 000000000..845a87bad
--- /dev/null
+++ b/crypto/src/x509/extension/X509ExtensionUtil.cs
@@ -0,0 +1,89 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.X509.Extension
+{
+ public class X509ExtensionUtilities
+ {
+ public static Asn1Object FromExtensionValue(
+ Asn1OctetString extensionValue)
+ {
+ return Asn1Object.FromByteArray(extensionValue.GetOctets());
+ }
+
+ public static ICollection GetIssuerAlternativeNames(
+ X509Certificate cert)
+ {
+ Asn1OctetString extVal = cert.GetExtensionValue(X509Extensions.IssuerAlternativeName);
+
+ return GetAlternativeName(extVal);
+ }
+
+ public static ICollection GetSubjectAlternativeNames(
+ X509Certificate cert)
+ {
+ Asn1OctetString extVal = cert.GetExtensionValue(X509Extensions.SubjectAlternativeName);
+
+ return GetAlternativeName(extVal);
+ }
+
+ private static ICollection GetAlternativeName(
+ Asn1OctetString extVal)
+ {
+ IList temp = Platform.CreateArrayList();
+
+ if (extVal != null)
+ {
+ try
+ {
+ Asn1Sequence seq = DerSequence.GetInstance(FromExtensionValue(extVal));
+
+ foreach (GeneralName genName in seq)
+ {
+ IList list = Platform.CreateArrayList();
+ list.Add(genName.TagNo);
+
+ switch (genName.TagNo)
+ {
+ case GeneralName.EdiPartyName:
+ case GeneralName.X400Address:
+ case GeneralName.OtherName:
+ list.Add(genName.Name.ToAsn1Object());
+ break;
+ case GeneralName.DirectoryName:
+ list.Add(X509Name.GetInstance(genName.Name).ToString());
+ break;
+ case GeneralName.DnsName:
+ case GeneralName.Rfc822Name:
+ case GeneralName.UniformResourceIdentifier:
+ list.Add(((IAsn1String)genName.Name).GetString());
+ break;
+ case GeneralName.RegisteredID:
+ list.Add(DerObjectIdentifier.GetInstance(genName.Name).Id);
+ break;
+ case GeneralName.IPAddress:
+ list.Add(DerOctetString.GetInstance(genName.Name).GetOctets());
+ break;
+ default:
+ throw new IOException("Bad tag number: " + genName.TagNo);
+ }
+
+ temp.Add(list);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException(e.Message);
+ }
+ }
+
+ return temp;
+ }
+ }
+}
diff --git a/crypto/src/x509/store/IX509Selector.cs b/crypto/src/x509/store/IX509Selector.cs
new file mode 100644
index 000000000..09f6f1849
--- /dev/null
+++ b/crypto/src/x509/store/IX509Selector.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Org.BouncyCastle.X509.Store
+{
+ public interface IX509Selector
+#if !SILVERLIGHT
+ : ICloneable
+#endif
+ {
+#if SILVERLIGHT
+ object Clone();
+#endif
+ bool Match(object obj);
+ }
+}
diff --git a/crypto/src/x509/store/IX509Store.cs b/crypto/src/x509/store/IX509Store.cs
new file mode 100644
index 000000000..e5c3a462a
--- /dev/null
+++ b/crypto/src/x509/store/IX509Store.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.X509.Store
+{
+ public interface IX509Store
+ {
+// void Init(IX509StoreParameters parameters);
+ ICollection GetMatches(IX509Selector selector);
+ }
+}
diff --git a/crypto/src/x509/store/IX509StoreParameters.cs b/crypto/src/x509/store/IX509StoreParameters.cs
new file mode 100644
index 000000000..aee3036c2
--- /dev/null
+++ b/crypto/src/x509/store/IX509StoreParameters.cs
@@ -0,0 +1,8 @@
+using System;
+
+namespace Org.BouncyCastle.X509.Store
+{
+ public interface IX509StoreParameters
+ {
+ }
+}
diff --git a/crypto/src/x509/store/NoSuchStoreException.cs b/crypto/src/x509/store/NoSuchStoreException.cs
new file mode 100644
index 000000000..02c593245
--- /dev/null
+++ b/crypto/src/x509/store/NoSuchStoreException.cs
@@ -0,0 +1,28 @@
+using System;
+
+namespace Org.BouncyCastle.X509.Store
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+ [Serializable]
+#endif
+ public class NoSuchStoreException
+ : X509StoreException
+ {
+ public NoSuchStoreException()
+ {
+ }
+
+ public NoSuchStoreException(
+ string message)
+ : base(message)
+ {
+ }
+
+ public NoSuchStoreException(
+ string message,
+ Exception e)
+ : base(message, e)
+ {
+ }
+ }
+}
diff --git a/crypto/src/x509/store/X509AttrCertStoreSelector.cs b/crypto/src/x509/store/X509AttrCertStoreSelector.cs
new file mode 100644
index 000000000..9f1dc20d1
--- /dev/null
+++ b/crypto/src/x509/store/X509AttrCertStoreSelector.cs
@@ -0,0 +1,376 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.X509.Extension;
+
+namespace Org.BouncyCastle.X509.Store
+{
+ /**
+ * This class is an Selector
like implementation to select
+ * attribute certificates from a given set of criteria.
+ *
+ * @see org.bouncycastle.x509.X509AttributeCertificate
+ * @see org.bouncycastle.x509.X509Store
+ */
+ public class X509AttrCertStoreSelector
+ : IX509Selector
+ {
+ // TODO: name constraints???
+
+ private IX509AttributeCertificate attributeCert;
+ private DateTimeObject attributeCertificateValid;
+ private AttributeCertificateHolder holder;
+ private AttributeCertificateIssuer issuer;
+ private BigInteger serialNumber;
+ private ISet targetNames = new HashSet();
+ private ISet targetGroups = new HashSet();
+
+ public X509AttrCertStoreSelector()
+ {
+ }
+
+ private X509AttrCertStoreSelector(
+ X509AttrCertStoreSelector o)
+ {
+ this.attributeCert = o.attributeCert;
+ this.attributeCertificateValid = o.attributeCertificateValid;
+ this.holder = o.holder;
+ this.issuer = o.issuer;
+ this.serialNumber = o.serialNumber;
+ this.targetGroups = new HashSet(o.targetGroups);
+ this.targetNames = new HashSet(o.targetNames);
+ }
+
+ ///
+ /// Decides if the given attribute certificate should be selected.
+ ///
+ /// The attribute certificate to be checked.
+ /// true
if the object matches this selector.
+ public bool Match(
+ object obj)
+ {
+ if (obj == null)
+ throw new ArgumentNullException("obj");
+
+ IX509AttributeCertificate attrCert = obj as IX509AttributeCertificate;
+
+ if (attrCert == null)
+ return false;
+
+ if (this.attributeCert != null && !this.attributeCert.Equals(attrCert))
+ return false;
+
+ if (serialNumber != null && !attrCert.SerialNumber.Equals(serialNumber))
+ return false;
+
+ if (holder != null && !attrCert.Holder.Equals(holder))
+ return false;
+
+ if (issuer != null && !attrCert.Issuer.Equals(issuer))
+ return false;
+
+ if (attributeCertificateValid != null && !attrCert.IsValid(attributeCertificateValid.Value))
+ return false;
+
+ if (targetNames.Count > 0 || targetGroups.Count > 0)
+ {
+ Asn1OctetString targetInfoExt = attrCert.GetExtensionValue(
+ X509Extensions.TargetInformation);
+
+ if (targetInfoExt != null)
+ {
+ TargetInformation targetinfo;
+ try
+ {
+ targetinfo = TargetInformation.GetInstance(
+ X509ExtensionUtilities.FromExtensionValue(targetInfoExt));
+ }
+ catch (Exception)
+ {
+ return false;
+ }
+
+ Targets[] targetss = targetinfo.GetTargetsObjects();
+
+ if (targetNames.Count > 0)
+ {
+ bool found = false;
+
+ for (int i = 0; i < targetss.Length && !found; i++)
+ {
+ Target[] targets = targetss[i].GetTargets();
+
+ for (int j = 0; j < targets.Length; j++)
+ {
+ GeneralName targetName = targets[j].TargetName;
+
+ if (targetName != null && targetNames.Contains(targetName))
+ {
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found)
+ {
+ return false;
+ }
+ }
+
+ if (targetGroups.Count > 0)
+ {
+ bool found = false;
+
+ for (int i = 0; i < targetss.Length && !found; i++)
+ {
+ Target[] targets = targetss[i].GetTargets();
+
+ for (int j = 0; j < targets.Length; j++)
+ {
+ GeneralName targetGroup = targets[j].TargetGroup;
+
+ if (targetGroup != null && targetGroups.Contains(targetGroup))
+ {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found)
+ {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public object Clone()
+ {
+ return new X509AttrCertStoreSelector(this);
+ }
+
+ /// The attribute certificate which must be matched.
+ /// If null is given, any will do.
+ public IX509AttributeCertificate AttributeCert
+ {
+ get { return attributeCert; }
+ set { this.attributeCert = value; }
+ }
+
+ [Obsolete("Use AttributeCertificateValid instead")]
+ public DateTimeObject AttribueCertificateValid
+ {
+ get { return attributeCertificateValid; }
+ set { this.attributeCertificateValid = value; }
+ }
+
+ /// The criteria for validity
+ /// If null is given any will do.
+ public DateTimeObject AttributeCertificateValid
+ {
+ get { return attributeCertificateValid; }
+ set { this.attributeCertificateValid = value; }
+ }
+
+ /// The holder.
+ /// If null is given any will do.
+ public AttributeCertificateHolder Holder
+ {
+ get { return holder; }
+ set { this.holder = value; }
+ }
+
+ /// The issuer.
+ /// If null is given any will do.
+ public AttributeCertificateIssuer Issuer
+ {
+ get { return issuer; }
+ set { this.issuer = value; }
+ }
+
+ /// The serial number.
+ /// If null is given any will do.
+ public BigInteger SerialNumber
+ {
+ get { return serialNumber; }
+ set { this.serialNumber = value; }
+ }
+
+ /**
+ * Adds a target name criterion for the attribute certificate to the target
+ * information extension criteria. The X509AttributeCertificate
+ * must contain at least one of the specified target names.
+ *
+ * Each attribute certificate may contain a target information extension
+ * limiting the servers where this attribute certificate can be used. If
+ * this extension is not present, the attribute certificate is not targeted
+ * and may be accepted by any server.
+ *
+ *
+ * @param name The name as a GeneralName (not null
)
+ */
+ public void AddTargetName(
+ GeneralName name)
+ {
+ targetNames.Add(name);
+ }
+
+ /**
+ * Adds a target name criterion for the attribute certificate to the target
+ * information extension criteria. The X509AttributeCertificate
+ * must contain at least one of the specified target names.
+ *
+ * Each attribute certificate may contain a target information extension
+ * limiting the servers where this attribute certificate can be used. If
+ * this extension is not present, the attribute certificate is not targeted
+ * and may be accepted by any server.
+ *
+ *
+ * @param name a byte array containing the name in ASN.1 DER encoded form of a GeneralName
+ * @throws IOException if a parsing error occurs.
+ */
+ public void AddTargetName(
+ byte[] name)
+ {
+ AddTargetName(GeneralName.GetInstance(Asn1Object.FromByteArray(name)));
+ }
+
+ /**
+ * Adds a collection with target names criteria. If null
is
+ * given any will do.
+ *
+ * The collection consists of either GeneralName objects or byte[] arrays representing
+ * DER encoded GeneralName structures.
+ *
+ *
+ * @param names A collection of target names.
+ * @throws IOException if a parsing error occurs.
+ * @see #AddTargetName(byte[])
+ * @see #AddTargetName(GeneralName)
+ */
+ public void SetTargetNames(
+ IEnumerable names)
+ {
+ targetNames = ExtractGeneralNames(names);
+ }
+
+ /**
+ * Gets the target names. The collection consists of List
s
+ * made up of an Integer
in the first entry and a DER encoded
+ * byte array or a String
in the second entry.
+ * The returned collection is immutable.
+ *
+ * @return The collection of target names
+ * @see #setTargetNames(Collection)
+ */
+ public IEnumerable GetTargetNames()
+ {
+ return new EnumerableProxy(targetNames);
+ }
+
+ /**
+ * Adds a target group criterion for the attribute certificate to the target
+ * information extension criteria. The X509AttributeCertificate
+ * must contain at least one of the specified target groups.
+ *
+ * Each attribute certificate may contain a target information extension
+ * limiting the servers where this attribute certificate can be used. If
+ * this extension is not present, the attribute certificate is not targeted
+ * and may be accepted by any server.
+ *
+ *
+ * @param group The group as GeneralName form (not null
)
+ */
+ public void AddTargetGroup(
+ GeneralName group)
+ {
+ targetGroups.Add(group);
+ }
+
+ /**
+ * Adds a target group criterion for the attribute certificate to the target
+ * information extension criteria. The X509AttributeCertificate
+ * must contain at least one of the specified target groups.
+ *
+ * Each attribute certificate may contain a target information extension
+ * limiting the servers where this attribute certificate can be used. If
+ * this extension is not present, the attribute certificate is not targeted
+ * and may be accepted by any server.
+ *
+ *
+ * @param name a byte array containing the group in ASN.1 DER encoded form of a GeneralName
+ * @throws IOException if a parsing error occurs.
+ */
+ public void AddTargetGroup(
+ byte[] name)
+ {
+ AddTargetGroup(GeneralName.GetInstance(Asn1Object.FromByteArray(name)));
+ }
+
+ /**
+ * Adds a collection with target groups criteria. If null
is
+ * given any will do.
+ *
+ * The collection consists of GeneralName
objects or byte[]
+ * representing DER encoded GeneralNames.
+ *
+ *
+ * @param names A collection of target groups.
+ * @throws IOException if a parsing error occurs.
+ * @see #AddTargetGroup(byte[])
+ * @see #AddTargetGroup(GeneralName)
+ */
+ public void SetTargetGroups(
+ IEnumerable names)
+ {
+ targetGroups = ExtractGeneralNames(names);
+ }
+
+ /**
+ * Gets the target groups. The collection consists of List
s
+ * made up of an Integer
in the first entry and a DER encoded
+ * byte array or a String
in the second entry.
+ * The returned collection is immutable.
+ *
+ * @return The collection of target groups.
+ * @see #setTargetGroups(Collection)
+ */
+ public IEnumerable GetTargetGroups()
+ {
+ return new EnumerableProxy(targetGroups);
+ }
+
+ private ISet ExtractGeneralNames(
+ IEnumerable names)
+ {
+ ISet result = new HashSet();
+
+ if (names != null)
+ {
+ foreach (object o in names)
+ {
+ if (o is GeneralName)
+ {
+ result.Add(o);
+ }
+ else
+ {
+ result.Add(GeneralName.GetInstance(Asn1Object.FromByteArray((byte[]) o)));
+ }
+ }
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/crypto/src/x509/store/X509CertPairStoreSelector.cs b/crypto/src/x509/store/X509CertPairStoreSelector.cs
new file mode 100644
index 000000000..2796971c7
--- /dev/null
+++ b/crypto/src/x509/store/X509CertPairStoreSelector.cs
@@ -0,0 +1,92 @@
+using System;
+
+namespace Org.BouncyCastle.X509.Store
+{
+ ///
+ /// This class is an IX509Selector
implementation to select
+ /// certificate pairs, which are e.g. used for cross certificates. The set of
+ /// criteria is given from two X509CertStoreSelector
objects,
+ /// each of which, if present, must match the respective component of a pair.
+ ///
+ public class X509CertPairStoreSelector
+ : IX509Selector
+ {
+ private static X509CertStoreSelector CloneSelector(
+ X509CertStoreSelector s)
+ {
+ return s == null ? null : (X509CertStoreSelector) s.Clone();
+ }
+
+ private X509CertificatePair certPair;
+ private X509CertStoreSelector forwardSelector;
+ private X509CertStoreSelector reverseSelector;
+
+ public X509CertPairStoreSelector()
+ {
+ }
+
+ private X509CertPairStoreSelector(
+ X509CertPairStoreSelector o)
+ {
+ this.certPair = o.CertPair;
+ this.forwardSelector = o.ForwardSelector;
+ this.reverseSelector = o.ReverseSelector;
+ }
+
+ /// The certificate pair which is used for testing on equality.
+ public X509CertificatePair CertPair
+ {
+ get { return certPair; }
+ set { this.certPair = value; }
+ }
+
+ /// The certificate selector for the forward part.
+ public X509CertStoreSelector ForwardSelector
+ {
+ get { return CloneSelector(forwardSelector); }
+ set { this.forwardSelector = CloneSelector(value); }
+ }
+
+ /// The certificate selector for the reverse part.
+ public X509CertStoreSelector ReverseSelector
+ {
+ get { return CloneSelector(reverseSelector); }
+ set { this.reverseSelector = CloneSelector(value); }
+ }
+
+ ///
+ /// Decides if the given certificate pair should be selected. If
+ /// obj is not a X509CertificatePair
, this method
+ /// returns false
.
+ ///
+ /// The X509CertificatePair
to be tested.
+ /// true
if the object matches this selector.
+ public bool Match(
+ object obj)
+ {
+ if (obj == null)
+ throw new ArgumentNullException("obj");
+
+ X509CertificatePair pair = obj as X509CertificatePair;
+
+ if (pair == null)
+ return false;
+
+ if (certPair != null && !certPair.Equals(pair))
+ return false;
+
+ if (forwardSelector != null && !forwardSelector.Match(pair.Forward))
+ return false;
+
+ if (reverseSelector != null && !reverseSelector.Match(pair.Reverse))
+ return false;
+
+ return true;
+ }
+
+ public object Clone()
+ {
+ return new X509CertPairStoreSelector(this);
+ }
+ }
+}
diff --git a/crypto/src/x509/store/X509CertStoreSelector.cs b/crypto/src/x509/store/X509CertStoreSelector.cs
new file mode 100644
index 000000000..3874edf1d
--- /dev/null
+++ b/crypto/src/x509/store/X509CertStoreSelector.cs
@@ -0,0 +1,337 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.X509.Extension;
+
+namespace Org.BouncyCastle.X509.Store
+{
+ public class X509CertStoreSelector
+ : IX509Selector
+ {
+ // TODO Missing criteria?
+
+ private byte[] authorityKeyIdentifier;
+ private int basicConstraints = -1;
+ private X509Certificate certificate;
+ private DateTimeObject certificateValid;
+ private ISet extendedKeyUsage;
+ private X509Name issuer;
+ private bool[] keyUsage;
+ private ISet policy;
+ private DateTimeObject privateKeyValid;
+ private BigInteger serialNumber;
+ private X509Name subject;
+ private byte[] subjectKeyIdentifier;
+ private SubjectPublicKeyInfo subjectPublicKey;
+ private DerObjectIdentifier subjectPublicKeyAlgID;
+
+ public X509CertStoreSelector()
+ {
+ }
+
+ public X509CertStoreSelector(
+ X509CertStoreSelector o)
+ {
+ this.authorityKeyIdentifier = o.AuthorityKeyIdentifier;
+ this.basicConstraints = o.BasicConstraints;
+ this.certificate = o.Certificate;
+ this.certificateValid = o.CertificateValid;
+ this.extendedKeyUsage = o.ExtendedKeyUsage;
+ this.issuer = o.Issuer;
+ this.keyUsage = o.KeyUsage;
+ this.policy = o.Policy;
+ this.privateKeyValid = o.PrivateKeyValid;
+ this.serialNumber = o.SerialNumber;
+ this.subject = o.Subject;
+ this.subjectKeyIdentifier = o.SubjectKeyIdentifier;
+ this.subjectPublicKey = o.SubjectPublicKey;
+ this.subjectPublicKeyAlgID = o.SubjectPublicKeyAlgID;
+ }
+
+ public virtual object Clone()
+ {
+ return new X509CertStoreSelector(this);
+ }
+
+ public byte[] AuthorityKeyIdentifier
+ {
+ get { return Arrays.Clone(authorityKeyIdentifier); }
+ set { authorityKeyIdentifier = Arrays.Clone(value); }
+ }
+
+ public int BasicConstraints
+ {
+ get { return basicConstraints; }
+ set
+ {
+ if (value < -2)
+ throw new ArgumentException("value can't be less than -2", "value");
+
+ basicConstraints = value;
+ }
+ }
+
+ public X509Certificate Certificate
+ {
+ get { return certificate; }
+ set { this.certificate = value; }
+ }
+
+ public DateTimeObject CertificateValid
+ {
+ get { return certificateValid; }
+ set { certificateValid = value; }
+ }
+
+ public ISet ExtendedKeyUsage
+ {
+ get { return CopySet(extendedKeyUsage); }
+ set { extendedKeyUsage = CopySet(value); }
+ }
+
+ public X509Name Issuer
+ {
+ get { return issuer; }
+ set { issuer = value; }
+ }
+
+ [Obsolete("Avoid working with X509Name objects in string form")]
+ public string IssuerAsString
+ {
+ get { return issuer != null ? issuer.ToString() : null; }
+ }
+
+ public bool[] KeyUsage
+ {
+ get { return CopyBoolArray(keyUsage); }
+ set { keyUsage = CopyBoolArray(value); }
+ }
+
+ ///
+ /// An ISet
of DerObjectIdentifier
objects.
+ ///
+ public ISet Policy
+ {
+ get { return CopySet(policy); }
+ set { policy = CopySet(value); }
+ }
+
+ public DateTimeObject PrivateKeyValid
+ {
+ get { return privateKeyValid; }
+ set { privateKeyValid = value; }
+ }
+
+ public BigInteger SerialNumber
+ {
+ get { return serialNumber; }
+ set { serialNumber = value; }
+ }
+
+ public X509Name Subject
+ {
+ get { return subject; }
+ set { subject = value; }
+ }
+
+ public string SubjectAsString
+ {
+ get { return subject != null ? subject.ToString() : null; }
+ }
+
+ public byte[] SubjectKeyIdentifier
+ {
+ get { return Arrays.Clone(subjectKeyIdentifier); }
+ set { subjectKeyIdentifier = Arrays.Clone(value); }
+ }
+
+ public SubjectPublicKeyInfo SubjectPublicKey
+ {
+ get { return subjectPublicKey; }
+ set { subjectPublicKey = value; }
+ }
+
+ public DerObjectIdentifier SubjectPublicKeyAlgID
+ {
+ get { return subjectPublicKeyAlgID; }
+ set { subjectPublicKeyAlgID = value; }
+ }
+
+ public virtual bool Match(
+ object obj)
+ {
+ X509Certificate c = obj as X509Certificate;
+
+ if (c == null)
+ return false;
+
+ if (!MatchExtension(authorityKeyIdentifier, c, X509Extensions.AuthorityKeyIdentifier))
+ return false;
+
+ if (basicConstraints != -1)
+ {
+ int bc = c.GetBasicConstraints();
+
+ if (basicConstraints == -2)
+ {
+ if (bc != -1)
+ return false;
+ }
+ else
+ {
+ if (bc < basicConstraints)
+ return false;
+ }
+ }
+
+ if (certificate != null && !certificate.Equals(c))
+ return false;
+
+ if (certificateValid != null && !c.IsValid(certificateValid.Value))
+ return false;
+
+ if (extendedKeyUsage != null)
+ {
+ IList eku = c.GetExtendedKeyUsage();
+
+ // Note: if no extended key usage set, all key purposes are implicitly allowed
+
+ if (eku != null)
+ {
+ foreach (DerObjectIdentifier oid in extendedKeyUsage)
+ {
+ if (!eku.Contains(oid.Id))
+ return false;
+ }
+ }
+ }
+
+ if (issuer != null && !issuer.Equivalent(c.IssuerDN, true))
+ return false;
+
+ if (keyUsage != null)
+ {
+ bool[] ku = c.GetKeyUsage();
+
+ // Note: if no key usage set, all key purposes are implicitly allowed
+
+ if (ku != null)
+ {
+ for (int i = 0; i < 9; ++i)
+ {
+ if (keyUsage[i] && !ku[i])
+ return false;
+ }
+ }
+ }
+
+ if (policy != null)
+ {
+ Asn1OctetString extVal = c.GetExtensionValue(X509Extensions.CertificatePolicies);
+ if (extVal == null)
+ return false;
+
+ Asn1Sequence certPolicies = Asn1Sequence.GetInstance(
+ X509ExtensionUtilities.FromExtensionValue(extVal));
+
+ if (policy.Count < 1 && certPolicies.Count < 1)
+ return false;
+
+ bool found = false;
+ foreach (PolicyInformation pi in certPolicies)
+ {
+ if (policy.Contains(pi.PolicyIdentifier))
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ return false;
+ }
+
+ if (privateKeyValid != null)
+ {
+ Asn1OctetString extVal = c.GetExtensionValue(X509Extensions.PrivateKeyUsagePeriod);
+ if (extVal == null)
+ return false;
+
+ PrivateKeyUsagePeriod pkup = PrivateKeyUsagePeriod.GetInstance(
+ X509ExtensionUtilities.FromExtensionValue(extVal));
+
+ DateTime dt = privateKeyValid.Value;
+ DateTime notAfter = pkup.NotAfter.ToDateTime();
+ DateTime notBefore = pkup.NotBefore.ToDateTime();
+
+ if (dt.CompareTo(notAfter) > 0 || dt.CompareTo(notBefore) < 0)
+ return false;
+ }
+
+ if (serialNumber != null && !serialNumber.Equals(c.SerialNumber))
+ return false;
+
+ if (subject != null && !subject.Equivalent(c.SubjectDN, true))
+ return false;
+
+ if (!MatchExtension(subjectKeyIdentifier, c, X509Extensions.SubjectKeyIdentifier))
+ return false;
+
+ if (subjectPublicKey != null && !subjectPublicKey.Equals(GetSubjectPublicKey(c)))
+ return false;
+
+ if (subjectPublicKeyAlgID != null
+ && !subjectPublicKeyAlgID.Equals(GetSubjectPublicKey(c).AlgorithmID))
+ return false;
+
+ return true;
+ }
+
+ internal static bool IssuersMatch(
+ X509Name a,
+ X509Name b)
+ {
+ return a == null ? b == null : a.Equivalent(b, true);
+ }
+
+ private static bool[] CopyBoolArray(
+ bool[] b)
+ {
+ return b == null ? null : (bool[]) b.Clone();
+ }
+
+ private static ISet CopySet(
+ ISet s)
+ {
+ return s == null ? null : new HashSet(s);
+ }
+
+ private static SubjectPublicKeyInfo GetSubjectPublicKey(
+ X509Certificate c)
+ {
+ return SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(c.GetPublicKey());
+ }
+
+ private static bool MatchExtension(
+ byte[] b,
+ X509Certificate c,
+ DerObjectIdentifier oid)
+ {
+ if (b == null)
+ return true;
+
+ Asn1OctetString extVal = c.GetExtensionValue(oid);
+
+ if (extVal == null)
+ return false;
+
+ return Arrays.AreEqual(b, extVal.GetOctets());
+ }
+ }
+}
diff --git a/crypto/src/x509/store/X509CollectionStore.cs b/crypto/src/x509/store/X509CollectionStore.cs
new file mode 100644
index 000000000..92173140b
--- /dev/null
+++ b/crypto/src/x509/store/X509CollectionStore.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.X509.Store
+{
+ /**
+ * A simple collection backed store.
+ */
+ internal class X509CollectionStore
+ : IX509Store
+ {
+ private ICollection _local;
+
+ /**
+ * Basic constructor.
+ *
+ * @param collection - initial contents for the store, this is copied.
+ */
+ internal X509CollectionStore(
+ ICollection collection)
+ {
+ _local = Platform.CreateArrayList(collection);
+ }
+
+ /**
+ * Return the matches in the collection for the passed in selector.
+ *
+ * @param selector the selector to match against.
+ * @return a possibly empty collection of matching objects.
+ */
+ public ICollection GetMatches(
+ IX509Selector selector)
+ {
+ if (selector == null)
+ {
+ return Platform.CreateArrayList(_local);
+ }
+
+ IList result = Platform.CreateArrayList();
+ foreach (object obj in _local)
+ {
+ if (selector.Match(obj))
+ result.Add(obj);
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/crypto/src/x509/store/X509CollectionStoreParameters.cs b/crypto/src/x509/store/X509CollectionStoreParameters.cs
new file mode 100644
index 000000000..7fd047a47
--- /dev/null
+++ b/crypto/src/x509/store/X509CollectionStoreParameters.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.X509.Store
+{
+ /// This class contains a collection for collection based X509Store
s.
+ public class X509CollectionStoreParameters
+ : IX509StoreParameters
+ {
+ private readonly IList collection;
+
+ ///
+ /// Constructor.
+ ///
+ /// The collection is copied.
+ ///
+ ///
+ /// The collection containing X.509 object types.
+ /// If collection is null.
+ public X509CollectionStoreParameters(
+ ICollection collection)
+ {
+ if (collection == null)
+ throw new ArgumentNullException("collection");
+
+ this.collection = Platform.CreateArrayList(collection);
+ }
+
+ // TODO Do we need to be able to Clone() these, and should it really be shallow?
+// /**
+// * Returns a shallow clone. The returned contents are not copied, so adding
+// * or removing objects will effect this.
+// *
+// * @return a shallow clone.
+// */
+// public object Clone()
+// {
+// return new X509CollectionStoreParameters(collection);
+// }
+
+ /// Returns a copy of the ICollection
.
+ public ICollection GetCollection()
+ {
+ return Platform.CreateArrayList(collection);
+ }
+
+ /// Returns a formatted string describing the parameters.
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.Append("X509CollectionStoreParameters: [\n");
+ sb.Append(" collection: " + collection + "\n");
+ sb.Append("]");
+ return sb.ToString();
+ }
+ }
+}
diff --git a/crypto/src/x509/store/X509CrlStoreSelector.cs b/crypto/src/x509/store/X509CrlStoreSelector.cs
new file mode 100644
index 000000000..c4b0062c1
--- /dev/null
+++ b/crypto/src/x509/store/X509CrlStoreSelector.cs
@@ -0,0 +1,283 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Extension;
+
+namespace Org.BouncyCastle.X509.Store
+{
+ public class X509CrlStoreSelector
+ : IX509Selector
+ {
+ // TODO Missing criteria?
+
+ private X509Certificate certificateChecking;
+ private DateTimeObject dateAndTime;
+ private ICollection issuers;
+ private BigInteger maxCrlNumber;
+ private BigInteger minCrlNumber;
+
+ private IX509AttributeCertificate attrCertChecking;
+ private bool completeCrlEnabled;
+ private bool deltaCrlIndicatorEnabled;
+ private byte[] issuingDistributionPoint;
+ private bool issuingDistributionPointEnabled;
+ private BigInteger maxBaseCrlNumber;
+
+ public X509CrlStoreSelector()
+ {
+ }
+
+ public X509CrlStoreSelector(
+ X509CrlStoreSelector o)
+ {
+ this.certificateChecking = o.CertificateChecking;
+ this.dateAndTime = o.DateAndTime;
+ this.issuers = o.Issuers;
+ this.maxCrlNumber = o.MaxCrlNumber;
+ this.minCrlNumber = o.MinCrlNumber;
+
+ this.deltaCrlIndicatorEnabled = o.DeltaCrlIndicatorEnabled;
+ this.completeCrlEnabled = o.CompleteCrlEnabled;
+ this.maxBaseCrlNumber = o.MaxBaseCrlNumber;
+ this.attrCertChecking = o.AttrCertChecking;
+ this.issuingDistributionPointEnabled = o.IssuingDistributionPointEnabled;
+ this.issuingDistributionPoint = o.IssuingDistributionPoint;
+ }
+
+ public virtual object Clone()
+ {
+ return new X509CrlStoreSelector(this);
+ }
+
+ public X509Certificate CertificateChecking
+ {
+ get { return certificateChecking; }
+ set { certificateChecking = value; }
+ }
+
+ public DateTimeObject DateAndTime
+ {
+ get { return dateAndTime; }
+ set { dateAndTime = value; }
+ }
+
+ ///
+ /// An ICollection
of X509Name
objects
+ ///
+ public ICollection Issuers
+ {
+ get { return Platform.CreateArrayList(issuers); }
+ set { issuers = Platform.CreateArrayList(value); }
+ }
+
+ public BigInteger MaxCrlNumber
+ {
+ get { return maxCrlNumber; }
+ set { maxCrlNumber = value; }
+ }
+
+ public BigInteger MinCrlNumber
+ {
+ get { return minCrlNumber; }
+ set { minCrlNumber = value; }
+ }
+
+ /**
+ * The attribute certificate being checked. This is not a criterion.
+ * Rather, it is optional information that may help a {@link X509Store} find
+ * CRLs that would be relevant when checking revocation for the specified
+ * attribute certificate. If null
is specified, then no such
+ * optional information is provided.
+ *
+ * @param attrCert the IX509AttributeCertificate
being checked (or
+ * null
)
+ * @see #getAttrCertificateChecking()
+ */
+ public IX509AttributeCertificate AttrCertChecking
+ {
+ get { return attrCertChecking; }
+ set { this.attrCertChecking = value; }
+ }
+
+ /**
+ * If true
only complete CRLs are returned. Defaults to
+ * false
.
+ *
+ * @return true
if only complete CRLs are returned.
+ */
+ public bool CompleteCrlEnabled
+ {
+ get { return completeCrlEnabled; }
+ set { this.completeCrlEnabled = value; }
+ }
+
+ /**
+ * Returns if this selector must match CRLs with the delta CRL indicator
+ * extension set. Defaults to false
.
+ *
+ * @return Returns true
if only CRLs with the delta CRL
+ * indicator extension are selected.
+ */
+ public bool DeltaCrlIndicatorEnabled
+ {
+ get { return deltaCrlIndicatorEnabled; }
+ set { this.deltaCrlIndicatorEnabled = value; }
+ }
+
+ /**
+ * The issuing distribution point.
+ *
+ * The issuing distribution point extension is a CRL extension which
+ * identifies the scope and the distribution point of a CRL. The scope
+ * contains among others information about revocation reasons contained in
+ * the CRL. Delta CRLs and complete CRLs must have matching issuing
+ * distribution points.
+ *
+ * The byte array is cloned to protect against subsequent modifications.
+ *
+ * You must also enable or disable this criteria with
+ * {@link #setIssuingDistributionPointEnabled(bool)}.
+ *
+ * @param issuingDistributionPoint The issuing distribution point to set.
+ * This is the DER encoded OCTET STRING extension value.
+ * @see #getIssuingDistributionPoint()
+ */
+ public byte[] IssuingDistributionPoint
+ {
+ get { return Arrays.Clone(issuingDistributionPoint); }
+ set { this.issuingDistributionPoint = Arrays.Clone(value); }
+ }
+
+ /**
+ * Whether the issuing distribution point criteria should be applied.
+ * Defaults to false
.
+ *
+ * You may also set the issuing distribution point criteria if not a missing
+ * issuing distribution point should be assumed.
+ *
+ * @return Returns if the issuing distribution point check is enabled.
+ */
+ public bool IssuingDistributionPointEnabled
+ {
+ get { return issuingDistributionPointEnabled; }
+ set { this.issuingDistributionPointEnabled = value; }
+ }
+
+ /**
+ * The maximum base CRL number. Defaults to null
.
+ *
+ * @return Returns the maximum base CRL number.
+ * @see #setMaxBaseCRLNumber(BigInteger)
+ */
+ public BigInteger MaxBaseCrlNumber
+ {
+ get { return maxBaseCrlNumber; }
+ set { this.maxBaseCrlNumber = value; }
+ }
+
+ public virtual bool Match(
+ object obj)
+ {
+ X509Crl c = obj as X509Crl;
+
+ if (c == null)
+ return false;
+
+ if (dateAndTime != null)
+ {
+ DateTime dt = dateAndTime.Value;
+ DateTime tu = c.ThisUpdate;
+ DateTimeObject nu = c.NextUpdate;
+
+ if (dt.CompareTo(tu) < 0 || nu == null || dt.CompareTo(nu.Value) >= 0)
+ return false;
+ }
+
+ if (issuers != null)
+ {
+ X509Name i = c.IssuerDN;
+
+ bool found = false;
+
+ foreach (X509Name issuer in issuers)
+ {
+ if (issuer.Equivalent(i, true))
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ return false;
+ }
+
+ if (maxCrlNumber != null || minCrlNumber != null)
+ {
+ Asn1OctetString extVal = c.GetExtensionValue(X509Extensions.CrlNumber);
+ if (extVal == null)
+ return false;
+
+ BigInteger cn = CrlNumber.GetInstance(
+ X509ExtensionUtilities.FromExtensionValue(extVal)).PositiveValue;
+
+ if (maxCrlNumber != null && cn.CompareTo(maxCrlNumber) > 0)
+ return false;
+
+ if (minCrlNumber != null && cn.CompareTo(minCrlNumber) < 0)
+ return false;
+ }
+
+ DerInteger dci = null;
+ try
+ {
+ Asn1OctetString bytes = c.GetExtensionValue(X509Extensions.DeltaCrlIndicator);
+ if (bytes != null)
+ {
+ dci = DerInteger.GetInstance(X509ExtensionUtilities.FromExtensionValue(bytes));
+ }
+ }
+ catch (Exception)
+ {
+ return false;
+ }
+
+ if (dci == null)
+ {
+ if (DeltaCrlIndicatorEnabled)
+ return false;
+ }
+ else
+ {
+ if (CompleteCrlEnabled)
+ return false;
+
+ if (maxBaseCrlNumber != null && dci.PositiveValue.CompareTo(maxBaseCrlNumber) > 0)
+ return false;
+ }
+
+ if (issuingDistributionPointEnabled)
+ {
+ Asn1OctetString idp = c.GetExtensionValue(X509Extensions.IssuingDistributionPoint);
+ if (issuingDistributionPoint == null)
+ {
+ if (idp != null)
+ return false;
+ }
+ else
+ {
+ if (!Arrays.AreEqual(idp.GetOctets(), issuingDistributionPoint))
+ return false;
+ }
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/crypto/src/x509/store/X509StoreException.cs b/crypto/src/x509/store/X509StoreException.cs
new file mode 100644
index 000000000..f781291e2
--- /dev/null
+++ b/crypto/src/x509/store/X509StoreException.cs
@@ -0,0 +1,28 @@
+using System;
+
+namespace Org.BouncyCastle.X509.Store
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+ [Serializable]
+#endif
+ public class X509StoreException
+ : Exception
+ {
+ public X509StoreException()
+ {
+ }
+
+ public X509StoreException(
+ string message)
+ : base(message)
+ {
+ }
+
+ public X509StoreException(
+ string message,
+ Exception e)
+ : base(message, e)
+ {
+ }
+ }
+}
diff --git a/crypto/src/x509/store/X509StoreFactory.cs b/crypto/src/x509/store/X509StoreFactory.cs
new file mode 100644
index 000000000..96f22be3f
--- /dev/null
+++ b/crypto/src/x509/store/X509StoreFactory.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.X509.Store
+{
+ public sealed class X509StoreFactory
+ {
+ private X509StoreFactory()
+ {
+ }
+
+ public static IX509Store Create(
+ string type,
+ IX509StoreParameters parameters)
+ {
+ if (type == null)
+ throw new ArgumentNullException("type");
+
+ string[] parts = Platform.ToUpperInvariant(type).Split('/');
+
+ if (parts.Length < 2)
+ throw new ArgumentException("type");
+
+ if (parts[1] != "COLLECTION")
+ throw new NoSuchStoreException("X.509 store type '" + type + "' not available.");
+
+ X509CollectionStoreParameters p = (X509CollectionStoreParameters) parameters;
+ ICollection coll = p.GetCollection();
+
+ switch (parts[0])
+ {
+ case "ATTRIBUTECERTIFICATE":
+ checkCorrectType(coll, typeof(IX509AttributeCertificate));
+ break;
+ case "CERTIFICATE":
+ checkCorrectType(coll, typeof(X509Certificate));
+ break;
+ case "CERTIFICATEPAIR":
+ checkCorrectType(coll, typeof(X509CertificatePair));
+ break;
+ case "CRL":
+ checkCorrectType(coll, typeof(X509Crl));
+ break;
+ default:
+ throw new NoSuchStoreException("X.509 store type '" + type + "' not available.");
+ }
+
+ return new X509CollectionStore(coll);
+ }
+
+ private static void checkCorrectType(ICollection coll, Type t)
+ {
+ foreach (object o in coll)
+ {
+ if (!t.IsInstanceOfType(o))
+ throw new InvalidCastException("Can't cast object to type: " + t.FullName);
+ }
+ }
+ }
+}
--
cgit 1.4.1