summary refs log tree commit diff
path: root/crypto/src/asn1/x509
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2013-06-28 15:26:06 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2013-06-28 15:26:06 +0700
commit44288db4414158ac9b98a507b15e81d0d3c66ca6 (patch)
treeaa5ef88948ebb68ed6c8df81eb5da889641a9b50 /crypto/src/asn1/x509
parentSet up text/binary handling for existing file types (diff)
downloadBouncyCastle.NET-ed25519-44288db4414158ac9b98a507b15e81d0d3c66ca6.tar.xz
Initial import of old CVS repository
Diffstat (limited to 'crypto/src/asn1/x509')
-rw-r--r--crypto/src/asn1/x509/AccessDescription.cs83
-rw-r--r--crypto/src/asn1/x509/AlgorithmIdentifier.cs109
-rw-r--r--crypto/src/asn1/x509/AttCertIssuer.cs86
-rw-r--r--crypto/src/asn1/x509/AttCertValidityPeriod.cs78
-rw-r--r--crypto/src/asn1/x509/Attribute.cs82
-rw-r--r--crypto/src/asn1/x509/AttributeCertificate.cs81
-rw-r--r--crypto/src/asn1/x509/AttributeCertificateInfo.cs156
-rw-r--r--crypto/src/asn1/x509/AttributeTable.cs73
-rw-r--r--crypto/src/asn1/x509/AuthorityInformationAccess.cs105
-rw-r--r--crypto/src/asn1/x509/AuthorityKeyIdentifier.cs211
-rw-r--r--crypto/src/asn1/x509/BasicConstraints.cs133
-rw-r--r--crypto/src/asn1/x509/CRLDistPoint.cs93
-rw-r--r--crypto/src/asn1/x509/CRLNumber.cs30
-rw-r--r--crypto/src/asn1/x509/CRLReason.cs61
-rw-r--r--crypto/src/asn1/x509/CertPolicyId.cs20
-rw-r--r--crypto/src/asn1/x509/CertificateList.cs108
-rw-r--r--crypto/src/asn1/x509/CertificatePair.cs160
-rw-r--r--crypto/src/asn1/x509/CertificatePolicies.cs81
-rw-r--r--crypto/src/asn1/x509/DSAParameter.cs77
-rw-r--r--crypto/src/asn1/x509/DigestInfo.cs76
-rw-r--r--crypto/src/asn1/x509/DisplayText.cs172
-rw-r--r--crypto/src/asn1/x509/DistributionPoint.cs161
-rw-r--r--crypto/src/asn1/x509/DistributionPointName.cs130
-rw-r--r--crypto/src/asn1/x509/ExtendedKeyUsage.cs131
-rw-r--r--crypto/src/asn1/x509/GeneralName.cs418
-rw-r--r--crypto/src/asn1/x509/GeneralNames.cs95
-rw-r--r--crypto/src/asn1/x509/GeneralSubtree.cs189
-rw-r--r--crypto/src/asn1/x509/Holder.cs257
-rw-r--r--crypto/src/asn1/x509/IetfAttrSyntax.cs161
-rw-r--r--crypto/src/asn1/x509/IssuerSerial.cs98
-rw-r--r--crypto/src/asn1/x509/IssuingDistributionPoint.cs247
-rw-r--r--crypto/src/asn1/x509/KeyPurposeId.cs36
-rw-r--r--crypto/src/asn1/x509/KeyUsage.cs79
-rw-r--r--crypto/src/asn1/x509/NameConstraints.cs118
-rw-r--r--crypto/src/asn1/x509/NoticeReference.cs138
-rw-r--r--crypto/src/asn1/x509/ObjectDigestInfo.cs177
-rw-r--r--crypto/src/asn1/x509/PolicyInformation.cs80
-rw-r--r--crypto/src/asn1/x509/PolicyMappings.cs70
-rw-r--r--crypto/src/asn1/x509/PolicyQualifierId.cs28
-rw-r--r--crypto/src/asn1/x509/PolicyQualifierInfo.cs101
-rw-r--r--crypto/src/asn1/x509/PrivateKeyUsagePeriod.cs82
-rw-r--r--crypto/src/asn1/x509/RSAPublicKeyStructure.cs92
-rw-r--r--crypto/src/asn1/x509/ReasonFlags.cs46
-rw-r--r--crypto/src/asn1/x509/RoleSyntax.cs230
-rw-r--r--crypto/src/asn1/x509/SubjectDirectoryAttributes.cs142
-rw-r--r--crypto/src/asn1/x509/SubjectKeyIdentifier.cs141
-rw-r--r--crypto/src/asn1/x509/SubjectPublicKeyInfo.cs102
-rw-r--r--crypto/src/asn1/x509/TBSCertList.cs274
-rw-r--r--crypto/src/asn1/x509/TBSCertificateStructure.cs185
-rw-r--r--crypto/src/asn1/x509/Target.cs139
-rw-r--r--crypto/src/asn1/x509/TargetInformation.cs123
-rw-r--r--crypto/src/asn1/x509/Targets.cs121
-rw-r--r--crypto/src/asn1/x509/Time.cs120
-rw-r--r--crypto/src/asn1/x509/UserNotice.cs104
-rw-r--r--crypto/src/asn1/x509/V1TBSCertificateGenerator.cs108
-rw-r--r--crypto/src/asn1/x509/V2AttributeCertificateInfoGenerator.cs137
-rw-r--r--crypto/src/asn1/x509/V2Form.cs137
-rw-r--r--crypto/src/asn1/x509/V2TBSCertListGenerator.cs201
-rw-r--r--crypto/src/asn1/x509/V3TBSCertificateGenerator.cs168
-rw-r--r--crypto/src/asn1/x509/X509Attributes.cs9
-rw-r--r--crypto/src/asn1/x509/X509CertificateStructure.cs129
-rw-r--r--crypto/src/asn1/x509/X509DefaultEntryConverter.cs63
-rw-r--r--crypto/src/asn1/x509/X509Extension.cs79
-rw-r--r--crypto/src/asn1/x509/X509Extensions.cs451
-rw-r--r--crypto/src/asn1/x509/X509ExtensionsGenerator.cs81
-rw-r--r--crypto/src/asn1/x509/X509Name.cs1188
-rw-r--r--crypto/src/asn1/x509/X509NameEntryConverter.cs89
-rw-r--r--crypto/src/asn1/x509/X509NameTokenizer.cs104
-rw-r--r--crypto/src/asn1/x509/X509ObjectIdentifiers.cs59
-rw-r--r--crypto/src/asn1/x509/qualified/BiometricData.cs112
-rw-r--r--crypto/src/asn1/x509/qualified/ETSIQCObjectIdentifiers.cs19
-rw-r--r--crypto/src/asn1/x509/qualified/Iso4217CurrencyCode.cs84
-rw-r--r--crypto/src/asn1/x509/qualified/MonetaryValue.cs83
-rw-r--r--crypto/src/asn1/x509/qualified/QCStatement.cs85
-rw-r--r--crypto/src/asn1/x509/qualified/RFC3739QCObjectIdentifiers.cs21
-rw-r--r--crypto/src/asn1/x509/qualified/SemanticsInformation.cs124
-rw-r--r--crypto/src/asn1/x509/qualified/TypeOfBiometricData.cs91
-rw-r--r--crypto/src/asn1/x509/sigi/NameOrPseudonym.cs177
-rw-r--r--crypto/src/asn1/x509/sigi/PersonalData.cs210
-rw-r--r--crypto/src/asn1/x509/sigi/SigIObjectIdentifiers.cs49
80 files changed, 10748 insertions, 0 deletions
diff --git a/crypto/src/asn1/x509/AccessDescription.cs b/crypto/src/asn1/x509/AccessDescription.cs
new file mode 100644
index 000000000..09b5b5920
--- /dev/null
+++ b/crypto/src/asn1/x509/AccessDescription.cs
@@ -0,0 +1,83 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * The AccessDescription object.
+	 * <pre>
+	 * AccessDescription  ::=  SEQUENCE {
+	 *       accessMethod          OBJECT IDENTIFIER,
+	 *       accessLocation        GeneralName  }
+	 * </pre>
+	 */
+	public class AccessDescription
+		: Asn1Encodable
+	{
+		public readonly static DerObjectIdentifier IdADCAIssuers = new DerObjectIdentifier("1.3.6.1.5.5.7.48.2");
+		public readonly static DerObjectIdentifier IdADOcsp = new DerObjectIdentifier("1.3.6.1.5.5.7.48.1");
+
+		private readonly DerObjectIdentifier accessMethod;
+		private readonly GeneralName accessLocation;
+
+		public static AccessDescription GetInstance(
+			object obj)
+		{
+			if (obj is AccessDescription)
+				return (AccessDescription) obj;
+
+			if (obj is Asn1Sequence)
+				return new AccessDescription((Asn1Sequence) obj);
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		private AccessDescription(
+			Asn1Sequence seq)
+		{
+			if (seq.Count != 2)
+				throw new ArgumentException("wrong number of elements in sequence");
+
+			accessMethod = DerObjectIdentifier.GetInstance(seq[0]);
+			accessLocation = GeneralName.GetInstance(seq[1]);
+		}
+
+		/**
+		 * create an AccessDescription with the oid and location provided.
+		 */
+		public AccessDescription(
+			DerObjectIdentifier	oid,
+			GeneralName			location)
+		{
+			accessMethod = oid;
+			accessLocation = location;
+		}
+
+		/**
+		 *
+		 * @return the access method.
+		 */
+		public DerObjectIdentifier AccessMethod
+		{
+			get { return accessMethod; }
+		}
+
+		/**
+		 *
+		 * @return the access location
+		 */
+		public GeneralName AccessLocation
+		{
+			get { return accessLocation; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(accessMethod, accessLocation);
+		}
+
+		public override string ToString()
+		{
+			return "AccessDescription: Oid(" + this.accessMethod.Id + ")";
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/AlgorithmIdentifier.cs b/crypto/src/asn1/x509/AlgorithmIdentifier.cs
new file mode 100644
index 000000000..4ed3a400d
--- /dev/null
+++ b/crypto/src/asn1/x509/AlgorithmIdentifier.cs
@@ -0,0 +1,109 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class AlgorithmIdentifier
+        : Asn1Encodable
+    {
+        private readonly DerObjectIdentifier	objectID;
+        private readonly Asn1Encodable			parameters;
+        private readonly bool					parametersDefined;
+
+        public static AlgorithmIdentifier GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+        public static AlgorithmIdentifier GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is AlgorithmIdentifier)
+                return (AlgorithmIdentifier) obj;
+
+            // TODO: delete
+            if (obj is DerObjectIdentifier)
+                return new AlgorithmIdentifier((DerObjectIdentifier) obj);
+
+            // TODO: delete
+            if (obj is string)
+                return new AlgorithmIdentifier((string) obj);
+
+            return new AlgorithmIdentifier(Asn1Sequence.GetInstance(obj));
+        }
+
+        public AlgorithmIdentifier(
+            DerObjectIdentifier objectID)
+        {
+            this.objectID = objectID;
+        }
+
+        public AlgorithmIdentifier(
+            string objectID)
+        {
+            this.objectID = new DerObjectIdentifier(objectID);
+        }
+
+        public AlgorithmIdentifier(
+            DerObjectIdentifier	objectID,
+            Asn1Encodable		parameters)
+        {
+            this.objectID = objectID;
+            this.parameters = parameters;
+            this.parametersDefined = true;
+        }
+
+        internal AlgorithmIdentifier(
+            Asn1Sequence seq)
+        {
+            if (seq.Count < 1 || seq.Count > 2)
+                throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+            this.objectID = DerObjectIdentifier.GetInstance(seq[0]);
+            this.parametersDefined = (seq.Count == 2);
+
+            if (parametersDefined)
+            {
+                this.parameters = seq[1];
+            }
+        }
+
+        public virtual DerObjectIdentifier ObjectID
+        {
+            get { return objectID; }
+        }
+
+        public Asn1Encodable Parameters
+        {
+            get { return parameters; }
+        }
+
+        /**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *      AlgorithmIdentifier ::= Sequence {
+         *                            algorithm OBJECT IDENTIFIER,
+         *                            parameters ANY DEFINED BY algorithm OPTIONAL }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(objectID);
+
+            if (parametersDefined)
+            {
+                if (parameters != null)
+                {
+                    v.Add(parameters);
+                }
+                else
+                {
+                    v.Add(DerNull.Instance);
+                }
+            }
+
+            return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/AttCertIssuer.cs b/crypto/src/asn1/x509/AttCertIssuer.cs
new file mode 100644
index 000000000..e9314fa92
--- /dev/null
+++ b/crypto/src/asn1/x509/AttCertIssuer.cs
@@ -0,0 +1,86 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class AttCertIssuer
+        : Asn1Encodable, IAsn1Choice
+    {
+        internal readonly Asn1Encodable	obj;
+        internal readonly Asn1Object	choiceObj;
+
+		public static AttCertIssuer GetInstance(
+			object obj)
+		{
+			if (obj is AttCertIssuer)
+			{
+				return (AttCertIssuer)obj;
+			}
+			else if (obj is V2Form)
+			{
+				return new AttCertIssuer(V2Form.GetInstance(obj));
+			}
+			else if (obj is GeneralNames)
+			{
+				return new AttCertIssuer((GeneralNames)obj);
+			}
+			else if (obj is Asn1TaggedObject)
+			{
+				return new AttCertIssuer(V2Form.GetInstance((Asn1TaggedObject)obj, false));
+			}
+			else if (obj is Asn1Sequence)
+			{
+				return new AttCertIssuer(GeneralNames.GetInstance(obj));
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public static AttCertIssuer GetInstance(
+			Asn1TaggedObject	obj,
+			bool				isExplicit)
+		{
+			return GetInstance(obj.GetObject()); // must be explictly tagged
+		}
+
+		/// <summary>
+		/// Don't use this one if you are trying to be RFC 3281 compliant.
+		/// Use it for v1 attribute certificates only.
+		/// </summary>
+		/// <param name="names">Our GeneralNames structure</param>
+		public AttCertIssuer(
+			GeneralNames names)
+		{
+			obj = names;
+			choiceObj = obj.ToAsn1Object();
+		}
+
+		public AttCertIssuer(
+            V2Form v2Form)
+        {
+            obj = v2Form;
+            choiceObj = new DerTaggedObject(false, 0, obj);
+        }
+
+		public Asn1Encodable Issuer
+		{
+			get { return obj; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *  AttCertIssuer ::= CHOICE {
+         *       v1Form   GeneralNames,  -- MUST NOT be used in this
+         *                               -- profile
+         *       v2Form   [0] V2Form     -- v2 only
+         *  }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return choiceObj;
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/AttCertValidityPeriod.cs b/crypto/src/asn1/x509/AttCertValidityPeriod.cs
new file mode 100644
index 000000000..7f86cd0b8
--- /dev/null
+++ b/crypto/src/asn1/x509/AttCertValidityPeriod.cs
@@ -0,0 +1,78 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class AttCertValidityPeriod
+        : Asn1Encodable
+    {
+        private readonly DerGeneralizedTime	notBeforeTime;
+        private readonly DerGeneralizedTime	notAfterTime;
+
+		public static AttCertValidityPeriod GetInstance(
+            object obj)
+        {
+            if (obj is AttCertValidityPeriod || obj == null)
+            {
+                return (AttCertValidityPeriod) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new AttCertValidityPeriod((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public static AttCertValidityPeriod GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		private AttCertValidityPeriod(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+			notBeforeTime = DerGeneralizedTime.GetInstance(seq[0]);
+			notAfterTime = DerGeneralizedTime.GetInstance(seq[1]);
+        }
+
+		public AttCertValidityPeriod(
+            DerGeneralizedTime	notBeforeTime,
+            DerGeneralizedTime	notAfterTime)
+        {
+            this.notBeforeTime = notBeforeTime;
+            this.notAfterTime = notAfterTime;
+        }
+
+		public DerGeneralizedTime NotBeforeTime
+		{
+			get { return notBeforeTime; }
+		}
+
+		public DerGeneralizedTime NotAfterTime
+		{
+			get { return notAfterTime; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *  AttCertValidityPeriod  ::= Sequence {
+         *       notBeforeTime  GeneralizedTime,
+         *       notAfterTime   GeneralizedTime
+         *  }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(notBeforeTime, notAfterTime);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/Attribute.cs b/crypto/src/asn1/x509/Attribute.cs
new file mode 100644
index 000000000..d26db93e9
--- /dev/null
+++ b/crypto/src/asn1/x509/Attribute.cs
@@ -0,0 +1,82 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class AttributeX509
+        : Asn1Encodable
+    {
+        private readonly DerObjectIdentifier	attrType;
+        private readonly Asn1Set				attrValues;
+
+		/**
+         * return an Attr object from the given object.
+         *
+         * @param o the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static AttributeX509 GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is AttributeX509)
+            {
+                return (AttributeX509) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new AttributeX509((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		private AttributeX509(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+			attrType = DerObjectIdentifier.GetInstance(seq[0]);
+			attrValues = Asn1Set.GetInstance(seq[1]);
+        }
+
+		public AttributeX509(
+            DerObjectIdentifier	attrType,
+            Asn1Set				attrValues)
+        {
+            this.attrType = attrType;
+            this.attrValues = attrValues;
+        }
+
+		public DerObjectIdentifier AttrType
+		{
+			get { return attrType; }
+		}
+
+		public Asn1Encodable[] GetAttributeValues()
+		{
+			return attrValues.ToArray();
+		}
+
+		public Asn1Set AttrValues
+		{
+			get { return attrValues; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * Attr ::= Sequence {
+         *     attrType OBJECT IDENTIFIER,
+         *     attrValues Set OF AttributeValue
+         * }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(attrType, attrValues);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/AttributeCertificate.cs b/crypto/src/asn1/x509/AttributeCertificate.cs
new file mode 100644
index 000000000..5f85910da
--- /dev/null
+++ b/crypto/src/asn1/x509/AttributeCertificate.cs
@@ -0,0 +1,81 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class AttributeCertificate
+        : Asn1Encodable
+    {
+        private readonly AttributeCertificateInfo	acinfo;
+        private readonly AlgorithmIdentifier		signatureAlgorithm;
+        private readonly DerBitString				signatureValue;
+
+		/**
+         * @param obj
+         * @return
+         */
+        public static AttributeCertificate GetInstance(
+			object obj)
+        {
+            if (obj is AttributeCertificate)
+                return (AttributeCertificate) obj;
+
+			if (obj != null)
+				return new AttributeCertificate(Asn1Sequence.GetInstance(obj));
+
+			return null;
+		}
+
+		public AttributeCertificate(
+            AttributeCertificateInfo	acinfo,
+            AlgorithmIdentifier			signatureAlgorithm,
+            DerBitString				signatureValue)
+        {
+            this.acinfo = acinfo;
+            this.signatureAlgorithm = signatureAlgorithm;
+            this.signatureValue = signatureValue;
+        }
+
+		private AttributeCertificate(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 3)
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+			this.acinfo = AttributeCertificateInfo.GetInstance(seq[0]);
+            this.signatureAlgorithm = AlgorithmIdentifier.GetInstance(seq[1]);
+            this.signatureValue = DerBitString.GetInstance(seq[2]);
+        }
+
+		public AttributeCertificateInfo ACInfo
+		{
+			get { return acinfo; }
+		}
+
+		public AlgorithmIdentifier SignatureAlgorithm
+		{
+			get { return signatureAlgorithm; }
+		}
+
+		public DerBitString SignatureValue
+		{
+			get { return signatureValue; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *  AttributeCertificate ::= Sequence {
+         *       acinfo               AttributeCertificateInfo,
+         *       signatureAlgorithm   AlgorithmIdentifier,
+         *       signatureValue       BIT STRING
+         *  }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(acinfo, signatureAlgorithm, signatureValue);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/AttributeCertificateInfo.cs b/crypto/src/asn1/x509/AttributeCertificateInfo.cs
new file mode 100644
index 000000000..dcef3d472
--- /dev/null
+++ b/crypto/src/asn1/x509/AttributeCertificateInfo.cs
@@ -0,0 +1,156 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class AttributeCertificateInfo
+        : Asn1Encodable
+    {
+        internal readonly DerInteger			version;
+        internal readonly Holder				holder;
+        internal readonly AttCertIssuer			issuer;
+        internal readonly AlgorithmIdentifier	signature;
+        internal readonly DerInteger			serialNumber;
+        internal readonly AttCertValidityPeriod	attrCertValidityPeriod;
+        internal readonly Asn1Sequence			attributes;
+        internal readonly DerBitString			issuerUniqueID;
+        internal readonly X509Extensions		extensions;
+
+		public static AttributeCertificateInfo GetInstance(
+            Asn1TaggedObject	obj,
+            bool				isExplicit)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+        }
+
+		public static AttributeCertificateInfo GetInstance(
+            object obj)
+        {
+            if (obj is AttributeCertificateInfo)
+            {
+                return (AttributeCertificateInfo) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new AttributeCertificateInfo((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		private AttributeCertificateInfo(
+            Asn1Sequence seq)
+        {
+			if (seq.Count < 7 || seq.Count > 9)
+			{
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+			}
+
+			this.version = DerInteger.GetInstance(seq[0]);
+            this.holder = Holder.GetInstance(seq[1]);
+            this.issuer = AttCertIssuer.GetInstance(seq[2]);
+            this.signature = AlgorithmIdentifier.GetInstance(seq[3]);
+            this.serialNumber = DerInteger.GetInstance(seq[4]);
+            this.attrCertValidityPeriod = AttCertValidityPeriod.GetInstance(seq[5]);
+            this.attributes = Asn1Sequence.GetInstance(seq[6]);
+
+			for (int i = 7; i < seq.Count; i++)
+            {
+                Asn1Encodable obj = (Asn1Encodable) seq[i];
+
+				if (obj is DerBitString)
+                {
+                    this.issuerUniqueID = DerBitString.GetInstance(seq[i]);
+                }
+                else if (obj is Asn1Sequence || obj is X509Extensions)
+                {
+                    this.extensions = X509Extensions.GetInstance(seq[i]);
+                }
+            }
+        }
+
+		public DerInteger Version
+		{
+			get { return version; }
+		}
+
+		public Holder Holder
+		{
+			get { return holder; }
+		}
+
+		public AttCertIssuer Issuer
+		{
+			get { return issuer; }
+		}
+
+		public AlgorithmIdentifier Signature
+		{
+			get { return signature; }
+		}
+
+		public DerInteger SerialNumber
+		{
+			get { return serialNumber; }
+		}
+
+		public AttCertValidityPeriod AttrCertValidityPeriod
+		{
+			get { return attrCertValidityPeriod; }
+		}
+
+		public Asn1Sequence Attributes
+		{
+			get { return attributes; }
+		}
+
+		public DerBitString IssuerUniqueID
+		{
+			get { return issuerUniqueID; }
+		}
+
+		public X509Extensions Extensions
+		{
+			get { return extensions; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *  AttributeCertificateInfo ::= Sequence {
+         *       version              AttCertVersion -- version is v2,
+         *       holder               Holder,
+         *       issuer               AttCertIssuer,
+         *       signature            AlgorithmIdentifier,
+         *       serialNumber         CertificateSerialNumber,
+         *       attrCertValidityPeriod   AttCertValidityPeriod,
+         *       attributes           Sequence OF Attr,
+         *       issuerUniqueID       UniqueIdentifier OPTIONAL,
+         *       extensions           Extensions OPTIONAL
+         *  }
+         *
+         *  AttCertVersion ::= Integer { v2(1) }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(
+				version, holder, issuer, signature, serialNumber,
+				attrCertValidityPeriod, attributes);
+
+			if (issuerUniqueID != null)
+            {
+                v.Add(issuerUniqueID);
+            }
+
+			if (extensions != null)
+            {
+                v.Add(extensions);
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/AttributeTable.cs b/crypto/src/asn1/x509/AttributeTable.cs
new file mode 100644
index 000000000..ffe0ea935
--- /dev/null
+++ b/crypto/src/asn1/x509/AttributeTable.cs
@@ -0,0 +1,73 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class AttributeTable
+    {
+        private readonly IDictionary attributes;
+
+        public AttributeTable(
+            IDictionary attrs)
+        {
+            this.attributes = Platform.CreateHashtable(attrs);
+        }
+
+#if !SILVERLIGHT
+        [Obsolete]
+        public AttributeTable(
+            Hashtable attrs)
+        {
+            this.attributes = Platform.CreateHashtable(attrs);
+        }
+#endif
+
+		public AttributeTable(
+            Asn1EncodableVector v)
+        {
+            this.attributes = Platform.CreateHashtable(v.Count);
+
+			for (int i = 0; i != v.Count; i++)
+            {
+                AttributeX509 a = AttributeX509.GetInstance(v[i]);
+
+				attributes.Add(a.AttrType, a);
+            }
+        }
+
+		public AttributeTable(
+            Asn1Set s)
+        {
+            this.attributes = Platform.CreateHashtable(s.Count);
+
+			for (int i = 0; i != s.Count; i++)
+            {
+                AttributeX509 a = AttributeX509.GetInstance(s[i]);
+
+				attributes.Add(a.AttrType, a);
+            }
+        }
+
+		public AttributeX509 Get(
+            DerObjectIdentifier oid)
+        {
+            return (AttributeX509) attributes[oid];
+        }
+
+#if !SILVERLIGHT
+        [Obsolete("Use 'ToDictionary' instead")]
+		public Hashtable ToHashtable()
+        {
+            return new Hashtable(attributes);
+        }
+#endif
+
+        public IDictionary ToDictionary()
+        {
+            return Platform.CreateHashtable(attributes);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/AuthorityInformationAccess.cs b/crypto/src/asn1/x509/AuthorityInformationAccess.cs
new file mode 100644
index 000000000..3eeba8cd2
--- /dev/null
+++ b/crypto/src/asn1/x509/AuthorityInformationAccess.cs
@@ -0,0 +1,105 @@
+using System;
+using System.Collections;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * The AuthorityInformationAccess object.
+	 * <pre>
+	 * id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 }
+	 *
+	 * AuthorityInfoAccessSyntax  ::=
+	 *      Sequence SIZE (1..MAX) OF AccessDescription
+	 * AccessDescription  ::=  Sequence {
+	 *       accessMethod          OBJECT IDENTIFIER,
+	 *       accessLocation        GeneralName  }
+	 *
+	 * id-ad OBJECT IDENTIFIER ::= { id-pkix 48 }
+	 * id-ad-caIssuers OBJECT IDENTIFIER ::= { id-ad 2 }
+	 * id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 }
+	 * </pre>
+	 */
+	public class AuthorityInformationAccess
+		: Asn1Encodable
+	{
+		private readonly AccessDescription[] descriptions;
+
+		public static AuthorityInformationAccess GetInstance(
+			object obj)
+		{
+			if (obj is AuthorityInformationAccess)
+				return (AuthorityInformationAccess) obj;
+
+			if (obj is Asn1Sequence)
+				return new AuthorityInformationAccess((Asn1Sequence) obj);
+
+			if (obj is X509Extension)
+				return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj));
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		private AuthorityInformationAccess(
+			Asn1Sequence seq)
+		{
+			if (seq.Count < 1)
+				throw new ArgumentException("sequence may not be empty");
+
+			this.descriptions = new AccessDescription[seq.Count];
+
+			for (int i = 0; i < seq.Count; ++i)
+			{
+				descriptions[i] = AccessDescription.GetInstance(seq[i]);
+			}
+		}
+
+		/**
+		 * create an AuthorityInformationAccess with the oid and location provided.
+		 */
+		[Obsolete("Use version taking an AccessDescription instead")]
+		public AuthorityInformationAccess(
+			DerObjectIdentifier	oid,
+			GeneralName			location)
+		{
+			this.descriptions = new AccessDescription[]{ new AccessDescription(oid, location) };
+		}
+
+		public AuthorityInformationAccess(
+			AccessDescription description)
+		{
+			this.descriptions = new AccessDescription[]{ description };
+		}
+
+		public AccessDescription[] GetAccessDescriptions()
+		{
+			return (AccessDescription[]) descriptions.Clone();
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(descriptions);
+		}
+
+		public override string ToString()
+		{
+			StringBuilder buf = new StringBuilder();
+			string sep = Platform.NewLine;
+
+			buf.Append("AuthorityInformationAccess:");
+			buf.Append(sep);
+
+			foreach (AccessDescription description in descriptions)
+			{
+				buf.Append("    ");
+				buf.Append(description);
+				buf.Append(sep);
+			}
+
+			return buf.ToString();
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/AuthorityKeyIdentifier.cs b/crypto/src/asn1/x509/AuthorityKeyIdentifier.cs
new file mode 100644
index 000000000..12ccacfc7
--- /dev/null
+++ b/crypto/src/asn1/x509/AuthorityKeyIdentifier.cs
@@ -0,0 +1,211 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The AuthorityKeyIdentifier object.
+     * <pre>
+     * id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::=  { id-ce 35 }
+     *
+     *   AuthorityKeyIdentifier ::= Sequence {
+     *      keyIdentifier             [0] IMPLICIT KeyIdentifier           OPTIONAL,
+     *      authorityCertIssuer       [1] IMPLICIT GeneralNames            OPTIONAL,
+     *      authorityCertSerialNumber [2] IMPLICIT CertificateSerialNumber OPTIONAL  }
+     *
+     *   KeyIdentifier ::= OCTET STRING
+     * </pre>
+     *
+     */
+    public class AuthorityKeyIdentifier
+        : Asn1Encodable
+    {
+        internal readonly Asn1OctetString	keyidentifier;
+        internal readonly GeneralNames		certissuer;
+        internal readonly DerInteger		certserno;
+
+		public static AuthorityKeyIdentifier GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static AuthorityKeyIdentifier GetInstance(
+            object obj)
+        {
+            if (obj is AuthorityKeyIdentifier)
+            {
+                return (AuthorityKeyIdentifier) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new AuthorityKeyIdentifier((Asn1Sequence) obj);
+            }
+
+	        if (obj is X509Extension)
+			{
+				return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj));
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		protected internal AuthorityKeyIdentifier(
+            Asn1Sequence seq)
+        {
+			foreach (Asn1TaggedObject o in seq)
+			{
+				switch (o.TagNo)
+                {
+					case 0:
+						this.keyidentifier = Asn1OctetString.GetInstance(o, false);
+						break;
+					case 1:
+						this.certissuer = GeneralNames.GetInstance(o, false);
+						break;
+					case 2:
+						this.certserno = DerInteger.GetInstance(o, false);
+						break;
+					default:
+						throw new ArgumentException("illegal tag");
+                }
+            }
+        }
+
+		/**
+         *
+         * Calulates the keyidentifier using a SHA1 hash over the BIT STRING
+         * from SubjectPublicKeyInfo as defined in RFC2459.
+         *
+         * Example of making a AuthorityKeyIdentifier:
+         * <pre>
+	     *   SubjectPublicKeyInfo apki = new SubjectPublicKeyInfo((ASN1Sequence)new ASN1InputStream(
+		 *       publicKey.getEncoded()).readObject());
+         *   AuthorityKeyIdentifier aki = new AuthorityKeyIdentifier(apki);
+         * </pre>
+         *
+         **/
+        public AuthorityKeyIdentifier(
+            SubjectPublicKeyInfo spki)
+        {
+            IDigest digest = new Sha1Digest();
+            byte[] resBuf = new byte[digest.GetDigestSize()];
+
+			byte[] bytes = spki.PublicKeyData.GetBytes();
+            digest.BlockUpdate(bytes, 0, bytes.Length);
+            digest.DoFinal(resBuf, 0);
+            this.keyidentifier = new DerOctetString(resBuf);
+        }
+
+        /**
+         * create an AuthorityKeyIdentifier with the GeneralNames tag and
+         * the serial number provided as well.
+         */
+        public AuthorityKeyIdentifier(
+            SubjectPublicKeyInfo	spki,
+            GeneralNames			name,
+            BigInteger				serialNumber)
+        {
+            IDigest digest = new Sha1Digest();
+            byte[] resBuf = new byte[digest.GetDigestSize()];
+
+			byte[] bytes = spki.PublicKeyData.GetBytes();
+            digest.BlockUpdate(bytes, 0, bytes.Length);
+            digest.DoFinal(resBuf, 0);
+
+			this.keyidentifier = new DerOctetString(resBuf);
+            this.certissuer = name;
+            this.certserno = new DerInteger(serialNumber);
+        }
+
+		/**
+		 * create an AuthorityKeyIdentifier with the GeneralNames tag and
+		 * the serial number provided.
+		 */
+		public AuthorityKeyIdentifier(
+			GeneralNames	name,
+			BigInteger		serialNumber)
+		{
+			this.keyidentifier = null;
+			this.certissuer = GeneralNames.GetInstance(name.ToAsn1Object());
+			this.certserno = new DerInteger(serialNumber);
+		}
+
+		/**
+		 * create an AuthorityKeyIdentifier with a precomputed key identifier
+		 */
+		public AuthorityKeyIdentifier(
+			byte[] keyIdentifier)
+		{
+			this.keyidentifier = new DerOctetString(keyIdentifier);
+			this.certissuer = null;
+			this.certserno = null;
+		}
+
+		/**
+		 * create an AuthorityKeyIdentifier with a precomupted key identifier
+		 * and the GeneralNames tag and the serial number provided as well.
+		 */
+		public AuthorityKeyIdentifier(
+			byte[]			keyIdentifier,
+			GeneralNames	name,
+			BigInteger		serialNumber)
+		{
+			this.keyidentifier = new DerOctetString(keyIdentifier);
+			this.certissuer = GeneralNames.GetInstance(name.ToAsn1Object());
+			this.certserno = new DerInteger(serialNumber);
+		}
+
+		public byte[] GetKeyIdentifier()
+        {
+			return keyidentifier == null ? null : keyidentifier.GetOctets();
+        }
+
+		public GeneralNames AuthorityCertIssuer
+		{
+			get { return certissuer; }
+		}
+
+		public BigInteger AuthorityCertSerialNumber
+        {
+            get { return certserno == null ? null : certserno.Value; }
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (keyidentifier != null)
+            {
+                v.Add(new DerTaggedObject(false, 0, keyidentifier));
+            }
+
+			if (certissuer != null)
+            {
+                v.Add(new DerTaggedObject(false, 1, certissuer));
+            }
+
+			if (certserno != null)
+            {
+                v.Add(new DerTaggedObject(false, 2, certserno));
+            }
+
+			return new DerSequence(v);
+        }
+
+		public override string ToString()
+        {
+            return ("AuthorityKeyIdentifier: KeyID(" + this.keyidentifier.GetOctets() + ")");
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/BasicConstraints.cs b/crypto/src/asn1/x509/BasicConstraints.cs
new file mode 100644
index 000000000..522cb61cc
--- /dev/null
+++ b/crypto/src/asn1/x509/BasicConstraints.cs
@@ -0,0 +1,133 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class BasicConstraints
+        : Asn1Encodable
+    {
+        private readonly DerBoolean	cA;
+        private readonly DerInteger	pathLenConstraint;
+
+		public static BasicConstraints GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static BasicConstraints GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is BasicConstraints)
+            {
+                return (BasicConstraints) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new BasicConstraints((Asn1Sequence) obj);
+            }
+
+			if (obj is X509Extension)
+			{
+				return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj));
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		private BasicConstraints(
+            Asn1Sequence seq)
+        {
+			if (seq.Count > 0)
+			{
+				if (seq[0] is DerBoolean)
+				{
+					this.cA = DerBoolean.GetInstance(seq[0]);
+				}
+				else
+				{
+					this.pathLenConstraint = DerInteger.GetInstance(seq[0]);
+				}
+
+				if (seq.Count > 1)
+				{
+					if (this.cA == null)
+						throw new ArgumentException("wrong sequence in constructor", "seq");
+
+					this.pathLenConstraint = DerInteger.GetInstance(seq[1]);
+				}
+			}
+        }
+
+		public BasicConstraints(
+            bool cA)
+        {
+			if (cA)
+			{
+				this.cA = DerBoolean.True;
+			}
+        }
+
+		/**
+         * create a cA=true object for the given path length constraint.
+         *
+         * @param pathLenConstraint
+         */
+        public BasicConstraints(
+            int pathLenConstraint)
+        {
+            this.cA = DerBoolean.True;
+            this.pathLenConstraint = new DerInteger(pathLenConstraint);
+        }
+
+		public bool IsCA()
+        {
+            return cA != null && cA.IsTrue;
+        }
+
+		public BigInteger PathLenConstraint
+        {
+            get { return pathLenConstraint == null ? null : pathLenConstraint.Value; }
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * BasicConstraints := Sequence {
+         *    cA                  Boolean DEFAULT FALSE,
+         *    pathLenConstraint   Integer (0..MAX) OPTIONAL
+         * }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (cA != null)
+			{
+				v.Add(cA);
+			}
+
+            if (pathLenConstraint != null)  // yes some people actually do this when cA is false...
+            {
+                v.Add(pathLenConstraint);
+            }
+
+			return new DerSequence(v);
+        }
+
+		public override string ToString()
+        {
+            if (pathLenConstraint == null)
+            {
+				return "BasicConstraints: isCa(" + this.IsCA() + ")";
+            }
+
+			return "BasicConstraints: isCa(" + this.IsCA() + "), pathLenConstraint = " + pathLenConstraint.Value;
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/CRLDistPoint.cs b/crypto/src/asn1/x509/CRLDistPoint.cs
new file mode 100644
index 000000000..2b5c19798
--- /dev/null
+++ b/crypto/src/asn1/x509/CRLDistPoint.cs
@@ -0,0 +1,93 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class CrlDistPoint
+        : Asn1Encodable
+    {
+        internal readonly Asn1Sequence seq;
+
+		public static CrlDistPoint GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static CrlDistPoint GetInstance(
+            object obj)
+        {
+            if (obj is CrlDistPoint || obj == null)
+            {
+                return (CrlDistPoint) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new CrlDistPoint((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		private CrlDistPoint(
+            Asn1Sequence seq)
+        {
+            this.seq = seq;
+        }
+
+		public CrlDistPoint(
+            DistributionPoint[] points)
+        {
+			seq = new DerSequence(points);
+        }
+
+		/**
+         * Return the distribution points making up the sequence.
+         *
+         * @return DistributionPoint[]
+         */
+        public DistributionPoint[] GetDistributionPoints()
+        {
+            DistributionPoint[] dp = new DistributionPoint[seq.Count];
+
+			for (int i = 0; i != seq.Count; ++i)
+            {
+                dp[i] = DistributionPoint.GetInstance(seq[i]);
+            }
+
+			return dp;
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * CrlDistPoint ::= Sequence SIZE {1..MAX} OF DistributionPoint
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return seq;
+        }
+
+		public override string ToString()
+		{
+			StringBuilder buf = new StringBuilder();
+			string sep = Platform.NewLine;
+
+			buf.Append("CRLDistPoint:");
+			buf.Append(sep);
+			DistributionPoint[] dp = GetDistributionPoints();
+			for (int i = 0; i != dp.Length; i++)
+			{
+				buf.Append("    ");
+				buf.Append(dp[i]);
+				buf.Append(sep);
+			}
+			return buf.ToString();
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/CRLNumber.cs b/crypto/src/asn1/x509/CRLNumber.cs
new file mode 100644
index 000000000..d744416a5
--- /dev/null
+++ b/crypto/src/asn1/x509/CRLNumber.cs
@@ -0,0 +1,30 @@
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The CRLNumber object.
+     * <pre>
+     * CRLNumber::= Integer(0..MAX)
+     * </pre>
+     */
+    public class CrlNumber
+        : DerInteger
+    {
+        public CrlNumber(
+			BigInteger number)
+			: base(number)
+        {
+        }
+
+		public BigInteger Number
+		{
+			get { return PositiveValue; }
+		}
+
+		public override string ToString()
+		{
+			return "CRLNumber: " + Number;
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/CRLReason.cs b/crypto/src/asn1/x509/CRLReason.cs
new file mode 100644
index 000000000..e8eb53a59
--- /dev/null
+++ b/crypto/src/asn1/x509/CRLReason.cs
@@ -0,0 +1,61 @@
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The CRLReason enumeration.
+     * <pre>
+     * CRLReason ::= Enumerated {
+     *  unspecified             (0),
+     *  keyCompromise           (1),
+     *  cACompromise            (2),
+     *  affiliationChanged      (3),
+     *  superseded              (4),
+     *  cessationOfOperation    (5),
+     *  certificateHold         (6),
+     *  removeFromCRL           (8),
+     *  privilegeWithdrawn      (9),
+     *  aACompromise           (10)
+     * }
+     * </pre>
+     */
+    public class CrlReason
+        : DerEnumerated
+    {
+        public const int Unspecified = 0;
+        public const int KeyCompromise = 1;
+        public const int CACompromise = 2;
+        public const int AffiliationChanged = 3;
+        public const int Superseded = 4;
+        public const int CessationOfOperation  = 5;
+        public const int CertificateHold = 6;
+		// 7 -> Unknown
+        public const int RemoveFromCrl = 8;
+        public const int PrivilegeWithdrawn = 9;
+        public const int AACompromise = 10;
+
+		private static readonly string[] ReasonString = new string[]
+		{
+			"Unspecified", "KeyCompromise", "CACompromise", "AffiliationChanged",
+			"Superseded", "CessationOfOperation", "CertificateHold", "Unknown",
+			"RemoveFromCrl", "PrivilegeWithdrawn", "AACompromise"
+		};
+
+		public CrlReason(
+			int reason)
+			: base(reason)
+        {
+        }
+
+		public CrlReason(
+			DerEnumerated reason)
+			: base(reason.Value.IntValue)
+        {
+        }
+
+		public override string ToString()
+		{
+			int reason = Value.IntValue;
+			string str = (reason < 0 || reason > 10) ? "Invalid" : ReasonString[reason];
+			return "CrlReason: " + str;
+		}    
+	}
+}
diff --git a/crypto/src/asn1/x509/CertPolicyId.cs b/crypto/src/asn1/x509/CertPolicyId.cs
new file mode 100644
index 000000000..11cebcdd7
--- /dev/null
+++ b/crypto/src/asn1/x509/CertPolicyId.cs
@@ -0,0 +1,20 @@
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * CertPolicyId, used in the CertificatePolicies and PolicyMappings
+     * X509V3 Extensions.
+     *
+     * <pre>
+     *     CertPolicyId ::= OBJECT IDENTIFIER
+     * </pre>
+     */
+     public class CertPolicyID
+		 : DerObjectIdentifier
+    {
+       public CertPolicyID(
+		   string id)
+		   : base(id)
+       {
+       }
+    }
+}
diff --git a/crypto/src/asn1/x509/CertificateList.cs b/crypto/src/asn1/x509/CertificateList.cs
new file mode 100644
index 000000000..0412e0816
--- /dev/null
+++ b/crypto/src/asn1/x509/CertificateList.cs
@@ -0,0 +1,108 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * PKIX RFC-2459
+     *
+     * The X.509 v2 CRL syntax is as follows.  For signature calculation,
+     * the data that is to be signed is ASN.1 Der encoded.
+     *
+     * <pre>
+     * CertificateList  ::=  Sequence  {
+     *      tbsCertList          TbsCertList,
+     *      signatureAlgorithm   AlgorithmIdentifier,
+     *      signatureValue       BIT STRING  }
+     * </pre>
+     */
+    public class CertificateList
+        : Asn1Encodable
+    {
+        private readonly TbsCertificateList	tbsCertList;
+        private readonly AlgorithmIdentifier sigAlgID;
+        private readonly DerBitString sig;
+
+		public static CertificateList GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static CertificateList GetInstance(
+            object obj)
+        {
+            if (obj is CertificateList)
+                return (CertificateList) obj;
+
+			if (obj != null)
+				return new CertificateList(Asn1Sequence.GetInstance(obj));
+
+			return null;
+		}
+
+		private CertificateList(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 3)
+				throw new ArgumentException("sequence wrong size for CertificateList", "seq");
+
+			tbsCertList = TbsCertificateList.GetInstance(seq[0]);
+			sigAlgID = AlgorithmIdentifier.GetInstance(seq[1]);
+			sig = DerBitString.GetInstance(seq[2]);
+        }
+
+		public TbsCertificateList TbsCertList
+		{
+			get { return tbsCertList; }
+		}
+
+		public CrlEntry[] GetRevokedCertificates()
+        {
+            return tbsCertList.GetRevokedCertificates();
+        }
+
+		public IEnumerable GetRevokedCertificateEnumeration()
+		{
+			return tbsCertList.GetRevokedCertificateEnumeration();
+		}
+
+		public AlgorithmIdentifier SignatureAlgorithm
+		{
+			get { return sigAlgID; }
+		}
+
+		public DerBitString Signature
+		{
+			get { return sig; }
+		}
+
+		public int Version
+		{
+			get { return tbsCertList.Version; }
+		}
+
+		public X509Name Issuer
+		{
+			get { return tbsCertList.Issuer; }
+		}
+
+		public Time ThisUpdate
+		{
+			get { return tbsCertList.ThisUpdate; }
+		}
+
+		public Time NextUpdate
+		{
+			get { return tbsCertList.NextUpdate; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(tbsCertList, sigAlgID, sig);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/CertificatePair.cs b/crypto/src/asn1/x509/CertificatePair.cs
new file mode 100644
index 000000000..8baa64719
--- /dev/null
+++ b/crypto/src/asn1/x509/CertificatePair.cs
@@ -0,0 +1,160 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	* This class helps to support crossCerfificatePairs in a LDAP directory
+	* according RFC 2587
+	*
+	* <pre>
+	*     crossCertificatePairATTRIBUTE::={
+	*       WITH SYNTAX   CertificatePair
+	*       EQUALITY MATCHING RULE certificatePairExactMatch
+	*       ID joint-iso-ccitt(2) ds(5) attributeType(4) crossCertificatePair(40)}
+	* </pre>
+	*
+	* <blockquote> The forward elements of the crossCertificatePair attribute of a
+	* CA's directory entry shall be used to store all, except self-issued
+	* certificates issued to this CA. Optionally, the reverse elements of the
+	* crossCertificatePair attribute, of a CA's directory entry may contain a
+	* subset of certificates issued by this CA to other CAs. When both the forward
+	* and the reverse elements are present in a single attribute value, issuer name
+	* in one certificate shall match the subject name in the other and vice versa,
+	* and the subject public key in one certificate shall be capable of verifying
+	* the digital signature on the other certificate and vice versa.
+	*
+	* When a reverse element is present, the forward element value and the reverse
+	* element value need not be stored in the same attribute value; in other words,
+	* they can be stored in either a single attribute value or two attribute
+	* values. </blockquote>
+	*
+	* <pre>
+	*       CertificatePair ::= SEQUENCE {
+	*         forward		[0]	Certificate OPTIONAL,
+	*         reverse		[1]	Certificate OPTIONAL,
+	*         -- at least one of the pair shall be present -- }
+	* </pre>
+	*/
+	public class CertificatePair
+		: Asn1Encodable
+	{
+		private X509CertificateStructure forward, reverse;
+
+		public static CertificatePair GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is CertificatePair)
+			{
+				return (CertificatePair) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new CertificatePair((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		* Constructor from Asn1Sequence.
+		* <p/>
+		* The sequence is of type CertificatePair:
+		* <p/>
+		* <pre>
+		*       CertificatePair ::= SEQUENCE {
+		*         forward		[0]	Certificate OPTIONAL,
+		*         reverse		[1]	Certificate OPTIONAL,
+		*         -- at least one of the pair shall be present -- }
+		* </pre>
+		*
+		* @param seq The ASN.1 sequence.
+		*/
+		private CertificatePair(
+			Asn1Sequence seq)
+		{
+			if (seq.Count != 1 && seq.Count != 2)
+			{
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+			}
+
+			foreach (object obj in seq)
+			{
+				Asn1TaggedObject o = Asn1TaggedObject.GetInstance(obj);
+				if (o.TagNo == 0)
+				{
+					forward = X509CertificateStructure.GetInstance(o, true);
+				}
+				else if (o.TagNo == 1)
+				{
+					reverse = X509CertificateStructure.GetInstance(o, true);
+				}
+				else
+				{
+					throw new ArgumentException("Bad tag number: " + o.TagNo);
+				}
+			}
+		}
+
+		/**
+		* Constructor from a given details.
+		*
+		* @param forward Certificates issued to this CA.
+		* @param reverse Certificates issued by this CA to other CAs.
+		*/
+		public CertificatePair(
+			X509CertificateStructure	forward,
+			X509CertificateStructure	reverse)
+		{
+			this.forward = forward;
+			this.reverse = reverse;
+		}
+
+		/**
+		* Produce an object suitable for an Asn1OutputStream.
+		* <p/>
+		* Returns:
+		* <p/>
+		* <pre>
+		*       CertificatePair ::= SEQUENCE {
+		*         forward		[0]	Certificate OPTIONAL,
+		*         reverse		[1]	Certificate OPTIONAL,
+		*         -- at least one of the pair shall be present -- }
+		* </pre>
+		*
+		* @return a DERObject
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector vec = new Asn1EncodableVector();
+
+			if (forward != null)
+			{
+				vec.Add(new DerTaggedObject(0, forward));
+			}
+
+			if (reverse != null)
+			{
+				vec.Add(new DerTaggedObject(1, reverse));
+			}
+
+			return new DerSequence(vec);
+		}
+
+		/**
+		* @return Returns the forward.
+		*/
+		public X509CertificateStructure Forward
+		{
+			get { return forward; }
+		}
+
+		/**
+		* @return Returns the reverse.
+		*/
+		public X509CertificateStructure Reverse
+		{
+			get { return reverse; }
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/CertificatePolicies.cs b/crypto/src/asn1/x509/CertificatePolicies.cs
new file mode 100644
index 000000000..a83565bb2
--- /dev/null
+++ b/crypto/src/asn1/x509/CertificatePolicies.cs
@@ -0,0 +1,81 @@
+using System;
+using System.Text;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class CertificatePolicies
+        : Asn1Encodable
+    {
+        private readonly PolicyInformation[] policyInformation;
+
+        public static CertificatePolicies GetInstance(object obj)
+        {
+            if (obj == null || obj is CertificatePolicies)
+                return (CertificatePolicies)obj;
+
+            return new CertificatePolicies(Asn1Sequence.GetInstance(obj));
+        }
+
+        public static CertificatePolicies GetInstance(Asn1TaggedObject obj, bool isExplicit)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+        }
+
+        /**
+         * Construct a CertificatePolicies object containing one PolicyInformation.
+         * 
+         * @param name the name to be contained.
+         */
+        public CertificatePolicies(PolicyInformation name)
+        {
+            this.policyInformation = new PolicyInformation[] { name };
+        }
+
+        public CertificatePolicies(PolicyInformation[] policyInformation)
+        {
+            this.policyInformation = policyInformation;
+        }
+
+        private CertificatePolicies(Asn1Sequence seq)
+        {
+            this.policyInformation = new PolicyInformation[seq.Count];
+
+            for (int i = 0; i < seq.Count; ++i)
+            {
+                policyInformation[i] = PolicyInformation.GetInstance(seq[i]);
+            }
+        }
+
+        public virtual PolicyInformation[] GetPolicyInformation()
+        {
+            return (PolicyInformation[])policyInformation.Clone();
+        }
+
+        /**
+         * Produce an object suitable for an ASN1OutputStream.
+         * <pre>
+         * CertificatePolicies ::= SEQUENCE SIZE {1..MAX} OF PolicyInformation
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return new DerSequence(policyInformation);
+        }
+
+        public override string ToString()
+        {
+            StringBuilder sb = new StringBuilder("CertificatePolicies:");
+            if (policyInformation != null && policyInformation.Length > 0)
+            {
+                sb.Append(' ');
+                sb.Append(policyInformation[0]);
+                for (int i = 1; i < policyInformation.Length; ++i)
+                {
+                    sb.Append(", ");
+                    sb.Append(policyInformation[i]);
+                }
+            }
+            return sb.ToString();
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/DSAParameter.cs b/crypto/src/asn1/x509/DSAParameter.cs
new file mode 100644
index 000000000..b2b325f4d
--- /dev/null
+++ b/crypto/src/asn1/x509/DSAParameter.cs
@@ -0,0 +1,77 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class DsaParameter
+        : Asn1Encodable
+    {
+        internal readonly DerInteger p, q, g;
+
+		public static DsaParameter GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static DsaParameter GetInstance(
+            object obj)
+        {
+            if(obj == null || obj is DsaParameter)
+            {
+                return (DsaParameter) obj;
+            }
+
+			if(obj is Asn1Sequence)
+            {
+                return new DsaParameter((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("Invalid DsaParameter: " + obj.GetType().Name);
+        }
+
+		public DsaParameter(
+            BigInteger	p,
+            BigInteger	q,
+            BigInteger	g)
+        {
+            this.p = new DerInteger(p);
+            this.q = new DerInteger(q);
+            this.g = new DerInteger(g);
+        }
+
+		private DsaParameter(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 3)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			this.p = DerInteger.GetInstance(seq[0]);
+			this.q = DerInteger.GetInstance(seq[1]);
+			this.g = DerInteger.GetInstance(seq[2]);
+        }
+
+		public BigInteger P
+		{
+			get { return p.PositiveValue; }
+		}
+
+		public BigInteger Q
+		{
+			get { return q.PositiveValue; }
+		}
+
+		public BigInteger G
+		{
+			get { return g.PositiveValue; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(p, q, g);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/DigestInfo.cs b/crypto/src/asn1/x509/DigestInfo.cs
new file mode 100644
index 000000000..1dec227fa
--- /dev/null
+++ b/crypto/src/asn1/x509/DigestInfo.cs
@@ -0,0 +1,76 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The DigestInfo object.
+     * <pre>
+     * DigestInfo::=Sequence{
+     *          digestAlgorithm  AlgorithmIdentifier,
+     *          digest OCTET STRING }
+     * </pre>
+     */
+    public class DigestInfo
+        : Asn1Encodable
+    {
+        private readonly byte[] digest;
+        private readonly AlgorithmIdentifier algID;
+
+		public static DigestInfo GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static DigestInfo GetInstance(
+            object obj)
+        {
+            if (obj is DigestInfo)
+            {
+                return (DigestInfo) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new DigestInfo((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public DigestInfo(
+            AlgorithmIdentifier	algID,
+            byte[]				digest)
+        {
+            this.digest = digest;
+            this.algID = algID;
+        }
+
+		private DigestInfo(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+            algID = AlgorithmIdentifier.GetInstance(seq[0]);
+			digest = Asn1OctetString.GetInstance(seq[1]).GetOctets();
+		}
+
+		public AlgorithmIdentifier AlgorithmID
+		{
+			get { return algID; }
+		}
+
+		public byte[] GetDigest()
+        {
+            return digest;
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(algID, new DerOctetString(digest));
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/DisplayText.cs b/crypto/src/asn1/x509/DisplayText.cs
new file mode 100644
index 000000000..699f39031
--- /dev/null
+++ b/crypto/src/asn1/x509/DisplayText.cs
@@ -0,0 +1,172 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * <code>DisplayText</code> class, used in
+	 * <code>CertificatePolicies</code> X509 V3 extensions (in policy qualifiers).
+	 *
+	 * <p>It stores a string in a chosen encoding.
+	 * <pre>
+	 * DisplayText ::= CHOICE {
+	 *      ia5String        IA5String      (SIZE (1..200)),
+	 *      visibleString    VisibleString  (SIZE (1..200)),
+	 *      bmpString        BMPString      (SIZE (1..200)),
+	 *      utf8String       UTF8String     (SIZE (1..200)) }
+	 * </pre></p>
+	 * @see PolicyQualifierInfo
+	 * @see PolicyInformation
+	 */
+	public class DisplayText
+		: Asn1Encodable, IAsn1Choice
+	{
+		/**
+		 * Constant corresponding to ia5String encoding.
+		 *
+		 */
+		public const int ContentTypeIA5String = 0;
+		/**
+		 * Constant corresponding to bmpString encoding.
+		 *
+		 */
+		public const int ContentTypeBmpString = 1;
+		/**
+		 * Constant corresponding to utf8String encoding.
+		 *
+		 */
+		public const int ContentTypeUtf8String = 2;
+		/**
+		 * Constant corresponding to visibleString encoding.
+		 *
+		 */
+		public const int ContentTypeVisibleString = 3;
+		/**
+		 * Describe constant <code>DisplayTextMaximumSize</code> here.
+		 *
+		 */
+		public const int DisplayTextMaximumSize = 200;
+
+		internal readonly int contentType;
+		internal readonly IAsn1String contents;
+
+		/**
+		 * Creates a new <code>DisplayText</code> instance.
+		 *
+		 * @param type the desired encoding type for the text.
+		 * @param text the text to store. Strings longer than 200
+		 * characters are truncated.
+		 */
+		public DisplayText(
+			int		type,
+			string	text)
+		{
+			if (text.Length > DisplayTextMaximumSize)
+			{
+				// RFC3280 limits these strings to 200 chars
+				// truncate the string
+				text = text.Substring(0, DisplayTextMaximumSize);
+			}
+
+			contentType = type;
+			switch (type)
+			{
+				case ContentTypeIA5String:
+					contents = (IAsn1String)new DerIA5String (text);
+					break;
+				case ContentTypeUtf8String:
+					contents = (IAsn1String)new DerUtf8String(text);
+					break;
+				case ContentTypeVisibleString:
+					contents = (IAsn1String)new DerVisibleString(text);
+					break;
+				case ContentTypeBmpString:
+					contents = (IAsn1String)new DerBmpString(text);
+					break;
+				default:
+					contents = (IAsn1String)new DerUtf8String(text);
+					break;
+			}
+		}
+
+//		/**
+//		 * return true if the passed in string can be represented without
+//		 * loss as a PrintableString, false otherwise.
+//		 */
+//		private bool CanBePrintable(
+//			string str)
+//		{
+//			for (int i = str.Length - 1; i >= 0; i--)
+//			{
+//				if (str[i] > 0x007f)
+//				{
+//					return false;
+//				}
+//			}
+//
+//			return true;
+//		}
+
+		/**
+		 * Creates a new <code>DisplayText</code> instance.
+		 *
+		 * @param text the text to encapsulate. Strings longer than 200
+		 * characters are truncated.
+		 */
+		public DisplayText(
+			string text)
+		{
+			// by default use UTF8String
+			if (text.Length > DisplayTextMaximumSize)
+			{
+				text = text.Substring(0, DisplayTextMaximumSize);
+			}
+
+			contentType = ContentTypeUtf8String;
+			contents = new DerUtf8String(text);
+		}
+
+		/**
+		 * Creates a new <code>DisplayText</code> instance.
+		 * <p>Useful when reading back a <code>DisplayText</code> class
+		 * from it's Asn1Encodable form.</p>
+		 *
+		 * @param contents an <code>Asn1Encodable</code> instance.
+		 */
+		public DisplayText(
+			IAsn1String contents)
+		{
+			this.contents = contents;
+		}
+
+		public static DisplayText GetInstance(
+			object obj)
+		{
+			if (obj is IAsn1String)
+			{
+				return new DisplayText((IAsn1String) obj);
+			}
+
+			if (obj is DisplayText)
+			{
+				return (DisplayText) obj;
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return (Asn1Object) contents;
+		}
+
+		/**
+		 * Returns the stored <code>string</code> object.
+		 *
+		 * @return the stored text as a <code>string</code>.
+		 */
+		public string GetString()
+		{
+			return contents.GetString();
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/DistributionPoint.cs b/crypto/src/asn1/x509/DistributionPoint.cs
new file mode 100644
index 000000000..ad1d3989e
--- /dev/null
+++ b/crypto/src/asn1/x509/DistributionPoint.cs
@@ -0,0 +1,161 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The DistributionPoint object.
+     * <pre>
+     * DistributionPoint ::= Sequence {
+     *      distributionPoint [0] DistributionPointName OPTIONAL,
+     *      reasons           [1] ReasonFlags OPTIONAL,
+     *      cRLIssuer         [2] GeneralNames OPTIONAL
+     * }
+     * </pre>
+     */
+    public class DistributionPoint
+        : Asn1Encodable
+    {
+        internal readonly DistributionPointName	distributionPoint;
+        internal readonly ReasonFlags			reasons;
+        internal readonly GeneralNames			cRLIssuer;
+
+		public static DistributionPoint GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static DistributionPoint GetInstance(
+            object obj)
+        {
+            if(obj == null || obj is DistributionPoint)
+            {
+                return (DistributionPoint) obj;
+            }
+
+			if(obj is Asn1Sequence)
+            {
+                return new DistributionPoint((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("Invalid DistributionPoint: " + obj.GetType().Name);
+        }
+
+		private DistributionPoint(
+            Asn1Sequence seq)
+        {
+            for (int i = 0; i != seq.Count; i++)
+            {
+				Asn1TaggedObject t = Asn1TaggedObject.GetInstance(seq[i]);
+
+				switch (t.TagNo)
+                {
+                case 0:
+                    distributionPoint = DistributionPointName.GetInstance(t, true);
+                    break;
+                case 1:
+                    reasons = new ReasonFlags(DerBitString.GetInstance(t, false));
+                    break;
+                case 2:
+                    cRLIssuer = GeneralNames.GetInstance(t, false);
+                    break;
+                }
+            }
+        }
+
+		public DistributionPoint(
+            DistributionPointName	distributionPointName,
+            ReasonFlags				reasons,
+            GeneralNames			crlIssuer)
+        {
+            this.distributionPoint = distributionPointName;
+            this.reasons = reasons;
+            this.cRLIssuer = crlIssuer;
+        }
+
+		public DistributionPointName DistributionPointName
+        {
+			get { return distributionPoint; }
+        }
+
+		public ReasonFlags Reasons
+        {
+			get { return reasons; }
+        }
+
+		public GeneralNames CrlIssuer
+        {
+			get { return cRLIssuer; }
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (distributionPoint != null)
+            {
+                //
+                // as this is a CHOICE it must be explicitly tagged
+                //
+                v.Add(new DerTaggedObject(0, distributionPoint));
+            }
+
+			if (reasons != null)
+            {
+                v.Add(new DerTaggedObject(false, 1, reasons));
+            }
+
+			if (cRLIssuer != null)
+            {
+                v.Add(new DerTaggedObject(false, 2, cRLIssuer));
+            }
+
+			return new DerSequence(v);
+        }
+
+		public override string ToString()
+		{
+			string sep = Platform.NewLine;
+			StringBuilder buf = new StringBuilder();
+			buf.Append("DistributionPoint: [");
+			buf.Append(sep);
+			if (distributionPoint != null)
+			{
+				appendObject(buf, sep, "distributionPoint", distributionPoint.ToString());
+			}
+			if (reasons != null)
+			{
+				appendObject(buf, sep, "reasons", reasons.ToString());
+			}
+			if (cRLIssuer != null)
+			{
+				appendObject(buf, sep, "cRLIssuer", cRLIssuer.ToString());
+			}
+			buf.Append("]");
+			buf.Append(sep);
+			return buf.ToString();
+		}
+
+		private void appendObject(
+			StringBuilder	buf,
+			string			sep,
+			string			name,
+			string			val)
+		{
+			string indent = "    ";
+
+			buf.Append(indent);
+			buf.Append(name);
+			buf.Append(":");
+			buf.Append(sep);
+			buf.Append(indent);
+			buf.Append(indent);
+			buf.Append(val);
+			buf.Append(sep);
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/DistributionPointName.cs b/crypto/src/asn1/x509/DistributionPointName.cs
new file mode 100644
index 000000000..1a9d24241
--- /dev/null
+++ b/crypto/src/asn1/x509/DistributionPointName.cs
@@ -0,0 +1,130 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The DistributionPointName object.
+     * <pre>
+     * DistributionPointName ::= CHOICE {
+     *     fullName                 [0] GeneralNames,
+     *     nameRelativeToCRLIssuer  [1] RDN
+     * }
+     * </pre>
+     */
+    public class DistributionPointName
+        : Asn1Encodable, IAsn1Choice
+    {
+        internal readonly Asn1Encodable	name;
+        internal readonly int			type;
+
+		public const int FullName					= 0;
+        public const int NameRelativeToCrlIssuer	= 1;
+
+		public static DistributionPointName GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1TaggedObject.GetInstance(obj, true));
+        }
+
+		public static DistributionPointName GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is DistributionPointName)
+            {
+                return (DistributionPointName) obj;
+            }
+
+			if (obj is Asn1TaggedObject)
+            {
+                return new DistributionPointName((Asn1TaggedObject) obj);
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+        public DistributionPointName(
+            int				type,
+            Asn1Encodable	name)
+        {
+            this.type = type;
+            this.name = name;
+        }
+
+		public DistributionPointName(
+			GeneralNames name)
+			:	this(FullName, name)
+		{
+		}
+
+		public int PointType
+        {
+			get { return type; }
+        }
+
+		public Asn1Encodable Name
+        {
+			get { return name; }
+        }
+
+		public DistributionPointName(
+            Asn1TaggedObject obj)
+        {
+            this.type = obj.TagNo;
+
+			if (type == FullName)
+            {
+                this.name = GeneralNames.GetInstance(obj, false);
+            }
+            else
+            {
+                this.name = Asn1Set.GetInstance(obj, false);
+            }
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+            return new DerTaggedObject(false, type, name);
+        }
+
+		public override string ToString()
+		{
+			string sep = Platform.NewLine;
+			StringBuilder buf = new StringBuilder();
+			buf.Append("DistributionPointName: [");
+			buf.Append(sep);
+			if (type == FullName)
+			{
+				appendObject(buf, sep, "fullName", name.ToString());
+			}
+			else
+			{
+				appendObject(buf, sep, "nameRelativeToCRLIssuer", name.ToString());
+			}
+			buf.Append("]");
+			buf.Append(sep);
+			return buf.ToString();
+		}
+
+		private void appendObject(
+			StringBuilder	buf,
+			string			sep,
+			string			name,
+			string			val)
+		{
+			string indent = "    ";
+
+			buf.Append(indent);
+			buf.Append(name);
+			buf.Append(":");
+			buf.Append(sep);
+			buf.Append(indent);
+			buf.Append(indent);
+			buf.Append(val);
+			buf.Append(sep);
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/ExtendedKeyUsage.cs b/crypto/src/asn1/x509/ExtendedKeyUsage.cs
new file mode 100644
index 000000000..b5e4b7f8d
--- /dev/null
+++ b/crypto/src/asn1/x509/ExtendedKeyUsage.cs
@@ -0,0 +1,131 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The extendedKeyUsage object.
+     * <pre>
+     *      extendedKeyUsage ::= Sequence SIZE (1..MAX) OF KeyPurposeId
+     * </pre>
+     */
+    public class ExtendedKeyUsage
+        : Asn1Encodable
+    {
+        internal readonly IDictionary usageTable = Platform.CreateHashtable();
+        internal readonly Asn1Sequence seq;
+
+		public static ExtendedKeyUsage GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static ExtendedKeyUsage GetInstance(
+            object obj)
+        {
+            if (obj is ExtendedKeyUsage)
+            {
+                return (ExtendedKeyUsage) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new ExtendedKeyUsage((Asn1Sequence) obj);
+            }
+
+			if (obj is X509Extension)
+			{
+				return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj));
+			}
+
+			throw new ArgumentException("Invalid ExtendedKeyUsage: " + obj.GetType().Name);
+        }
+
+		private ExtendedKeyUsage(
+            Asn1Sequence seq)
+        {
+            this.seq = seq;
+
+			foreach (object o in seq)
+			{
+				if (!(o is DerObjectIdentifier))
+					throw new ArgumentException("Only DerObjectIdentifier instances allowed in ExtendedKeyUsage.");
+
+				this.usageTable.Add(o, o);
+            }
+        }
+
+		public ExtendedKeyUsage(
+			params KeyPurposeID[] usages)
+		{
+			this.seq = new DerSequence(usages);
+
+			foreach (KeyPurposeID usage in usages)
+			{
+				this.usageTable.Add(usage, usage);
+			}
+		}
+
+#if !SILVERLIGHT
+        [Obsolete]
+        public ExtendedKeyUsage(
+            ArrayList usages)
+            : this((IEnumerable)usages)
+        {
+        }
+#endif
+
+        public ExtendedKeyUsage(
+            IEnumerable usages)
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+			foreach (Asn1Object o in usages)
+            {
+				v.Add(o);
+
+				this.usageTable.Add(o, o);
+            }
+
+			this.seq = new DerSequence(v);
+        }
+
+		public bool HasKeyPurposeId(
+            KeyPurposeID keyPurposeId)
+        {
+            return usageTable[keyPurposeId] != null;
+        }
+
+#if !SILVERLIGHT
+        [Obsolete("Use 'GetAllUsages'")]
+        public ArrayList GetUsages()
+        {
+            return new ArrayList(usageTable.Values);
+        }
+#endif
+
+        /**
+		 * Returns all extended key usages.
+		 * The returned ArrayList contains DerObjectIdentifier instances.
+		 * @return An ArrayList with all key purposes.
+		 */
+		public IList GetAllUsages()
+		{
+			return Platform.CreateArrayList(usageTable.Values);
+		}
+
+        public int Count
+		{
+			get { return usageTable.Count; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+            return seq;
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/GeneralName.cs b/crypto/src/asn1/x509/GeneralName.cs
new file mode 100644
index 000000000..710ddc922
--- /dev/null
+++ b/crypto/src/asn1/x509/GeneralName.cs
@@ -0,0 +1,418 @@
+using System;
+using System.Collections;
+using System.Globalization;
+using System.IO;
+using System.Text;
+
+using NetUtils = Org.BouncyCastle.Utilities.Net;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The GeneralName object.
+     * <pre>
+     * GeneralName ::= CHOICE {
+     *      otherName                       [0]     OtherName,
+     *      rfc822Name                      [1]     IA5String,
+     *      dNSName                         [2]     IA5String,
+     *      x400Address                     [3]     ORAddress,
+     *      directoryName                   [4]     Name,
+     *      ediPartyName                    [5]     EDIPartyName,
+     *      uniformResourceIdentifier       [6]     IA5String,
+     *      iPAddress                       [7]     OCTET STRING,
+     *      registeredID                    [8]     OBJECT IDENTIFIER}
+     *
+     * OtherName ::= Sequence {
+     *      type-id    OBJECT IDENTIFIER,
+     *      value      [0] EXPLICIT ANY DEFINED BY type-id }
+     *
+     * EDIPartyName ::= Sequence {
+     *      nameAssigner            [0]     DirectoryString OPTIONAL,
+     *      partyName               [1]     DirectoryString }
+     * </pre>
+     */
+    public class GeneralName
+        : Asn1Encodable, IAsn1Choice
+    {
+        public const int OtherName					= 0;
+        public const int Rfc822Name					= 1;
+        public const int DnsName					= 2;
+        public const int X400Address				= 3;
+        public const int DirectoryName				= 4;
+        public const int EdiPartyName				= 5;
+        public const int UniformResourceIdentifier	= 6;
+        public const int IPAddress					= 7;
+        public const int RegisteredID				= 8;
+
+		internal readonly Asn1Encodable	obj;
+        internal readonly int			tag;
+
+		public GeneralName(
+            X509Name directoryName)
+        {
+            this.obj = directoryName;
+            this.tag = 4;
+        }
+
+		/**
+         * When the subjectAltName extension contains an Internet mail address,
+         * the address MUST be included as an rfc822Name. The format of an
+         * rfc822Name is an "addr-spec" as defined in RFC 822 [RFC 822].
+         *
+         * When the subjectAltName extension contains a domain name service
+         * label, the domain name MUST be stored in the dNSName (an IA5String).
+         * The name MUST be in the "preferred name syntax," as specified by RFC
+         * 1034 [RFC 1034].
+         *
+         * When the subjectAltName extension contains a URI, the name MUST be
+         * stored in the uniformResourceIdentifier (an IA5String). The name MUST
+         * be a non-relative URL, and MUST follow the URL syntax and encoding
+         * rules specified in [RFC 1738].  The name must include both a scheme
+         * (e.g., "http" or "ftp") and a scheme-specific-part.  The scheme-
+         * specific-part must include a fully qualified domain name or IP
+         * address as the host.
+         *
+         * When the subjectAltName extension contains a iPAddress, the address
+         * MUST be stored in the octet string in "network byte order," as
+         * specified in RFC 791 [RFC 791]. The least significant bit (LSB) of
+         * each octet is the LSB of the corresponding byte in the network
+         * address. For IP Version 4, as specified in RFC 791, the octet string
+         * MUST contain exactly four octets.  For IP Version 6, as specified in
+         * RFC 1883, the octet string MUST contain exactly sixteen octets [RFC
+         * 1883].
+         */
+        public GeneralName(
+            Asn1Object	name,
+			int			tag)
+        {
+            this.obj = name;
+            this.tag = tag;
+        }
+
+		public GeneralName(
+            int				tag,
+            Asn1Encodable	name)
+        {
+            this.obj = name;
+            this.tag = tag;
+        }
+
+		/**
+		 * Create a GeneralName for the given tag from the passed in string.
+		 * <p>
+		 * This constructor can handle:
+		 * <ul>
+		 * <li>rfc822Name</li>
+		 * <li>iPAddress</li>
+		 * <li>directoryName</li>
+		 * <li>dNSName</li>
+		 * <li>uniformResourceIdentifier</li>
+		 * <li>registeredID</li>
+		 * </ul>
+		 * For x400Address, otherName and ediPartyName there is no common string
+		 * format defined.
+		 * </p><p>
+		 * Note: A directory name can be encoded in different ways into a byte
+		 * representation. Be aware of this if the byte representation is used for
+		 * comparing results.
+		 * </p>
+		 *
+		 * @param tag tag number
+		 * @param name string representation of name
+		 * @throws ArgumentException if the string encoding is not correct or
+		 *             not supported.
+		 */
+		public GeneralName(
+            int		tag,
+            string	name)
+        {
+			this.tag = tag;
+
+			if (tag == Rfc822Name || tag == DnsName || tag == UniformResourceIdentifier)
+			{
+				this.obj = new DerIA5String(name);
+			}
+			else if (tag == RegisteredID)
+			{
+				this.obj = new DerObjectIdentifier(name);
+			}
+			else if (tag == DirectoryName)
+			{
+				this.obj = new X509Name(name);
+			}
+			else if (tag == IPAddress)
+			{
+				byte[] enc = toGeneralNameEncoding(name);
+				if (enc == null)
+					throw new ArgumentException("IP Address is invalid", "name");
+
+				this.obj = new DerOctetString(enc);
+			}
+			else
+			{
+				throw new ArgumentException("can't process string for tag: " + tag, "tag");
+			}
+		}
+
+		public static GeneralName GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is GeneralName)
+            {
+                return (GeneralName) obj;
+            }
+
+            if (obj is Asn1TaggedObject)
+            {
+                Asn1TaggedObject	tagObj = (Asn1TaggedObject) obj;
+                int					tag = tagObj.TagNo;
+
+				switch (tag)
+				{
+					case OtherName:
+						return new GeneralName(tag, Asn1Sequence.GetInstance(tagObj, false));
+					case Rfc822Name:
+						return new GeneralName(tag, DerIA5String.GetInstance(tagObj, false));
+					case DnsName:
+						return new GeneralName(tag, DerIA5String.GetInstance(tagObj, false));
+					case X400Address:
+						throw new ArgumentException("unknown tag: " + tag);
+					case DirectoryName:
+						return new GeneralName(tag, X509Name.GetInstance(tagObj, true));
+					case EdiPartyName:
+						return new GeneralName(tag, Asn1Sequence.GetInstance(tagObj, false));
+					case UniformResourceIdentifier:
+						return new GeneralName(tag, DerIA5String.GetInstance(tagObj, false));
+					case IPAddress:
+						return new GeneralName(tag, Asn1OctetString.GetInstance(tagObj, false));
+					case RegisteredID:
+						return new GeneralName(tag, DerObjectIdentifier.GetInstance(tagObj, false));
+				}
+	        }
+
+            if (obj is byte[])
+	        {
+	            try
+	            {
+	                return GetInstance(Asn1Object.FromByteArray((byte[])obj));
+	            }
+	            catch (IOException)
+	            {
+	                throw new ArgumentException("unable to parse encoded general name");
+	            }
+	        }
+
+			throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+		}
+
+		public static GeneralName GetInstance(
+            Asn1TaggedObject	tagObj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1TaggedObject.GetInstance(tagObj, true));
+        }
+
+		public int TagNo
+		{
+			get { return tag; }
+		}
+
+		public Asn1Encodable Name
+		{
+			get { return obj; }
+		}
+
+		public override string ToString()
+		{
+			StringBuilder buf = new StringBuilder();
+			buf.Append(tag);
+			buf.Append(": ");
+
+			switch (tag)
+			{
+				case Rfc822Name:
+				case DnsName:
+				case UniformResourceIdentifier:
+					buf.Append(DerIA5String.GetInstance(obj).GetString());
+					break;
+				case DirectoryName:
+					buf.Append(X509Name.GetInstance(obj).ToString());
+					break;
+				default:
+					buf.Append(obj.ToString());
+					break;
+			}
+
+			return buf.ToString();
+		}
+
+		private byte[] toGeneralNameEncoding(
+			string ip)
+		{
+			if (NetUtils.IPAddress.IsValidIPv6WithNetmask(ip) || NetUtils.IPAddress.IsValidIPv6(ip))
+			{
+				int slashIndex = ip.IndexOf('/');
+
+				if (slashIndex < 0)
+				{
+					byte[] addr = new byte[16];
+					int[]  parsedIp = parseIPv6(ip);
+					copyInts(parsedIp, addr, 0);
+
+					return addr;
+				}
+				else
+				{
+					byte[] addr = new byte[32];
+					int[]  parsedIp = parseIPv6(ip.Substring(0, slashIndex));
+					copyInts(parsedIp, addr, 0);
+					string mask = ip.Substring(slashIndex + 1);
+					if (mask.IndexOf(':') > 0)
+					{
+						parsedIp = parseIPv6(mask);
+					}
+					else
+					{
+						parsedIp = parseMask(mask);
+					}
+					copyInts(parsedIp, addr, 16);
+
+					return addr;
+				}
+			}
+			else if (NetUtils.IPAddress.IsValidIPv4WithNetmask(ip) || NetUtils.IPAddress.IsValidIPv4(ip))
+			{
+				int slashIndex = ip.IndexOf('/');
+
+				if (slashIndex < 0)
+				{
+					byte[] addr = new byte[4];
+
+					parseIPv4(ip, addr, 0);
+
+					return addr;
+				}
+				else
+				{
+					byte[] addr = new byte[8];
+
+					parseIPv4(ip.Substring(0, slashIndex), addr, 0);
+
+					string mask = ip.Substring(slashIndex + 1);
+					if (mask.IndexOf('.') > 0)
+					{
+						parseIPv4(mask, addr, 4);
+					}
+					else
+					{
+						parseIPv4Mask(mask, addr, 4);
+					}
+
+					return addr;
+				}
+			}
+
+			return null;
+		}
+
+		private void parseIPv4Mask(string mask, byte[] addr, int offset)
+		{
+			int maskVal = Int32.Parse(mask);
+
+			for (int i = 0; i != maskVal; i++)
+			{
+				addr[(i / 8) + offset] |= (byte)(1 << (i % 8));
+			}
+		}
+
+		private void parseIPv4(string ip, byte[] addr, int offset)
+		{
+			foreach (string token in ip.Split('.', '/'))
+			{
+				addr[offset++] = (byte)Int32.Parse(token);
+			}
+		}
+
+		private int[] parseMask(string mask)
+		{
+			int[] res = new int[8];
+			int   maskVal = Int32.Parse(mask);
+
+			for (int i = 0; i != maskVal; i++)
+			{
+				res[i / 16] |= 1 << (i % 16);
+			}
+			return res;
+		}
+
+		private void copyInts(int[] parsedIp, byte[] addr, int offSet)
+		{
+			for (int i = 0; i != parsedIp.Length; i++)
+			{
+				addr[(i * 2) + offSet] = (byte)(parsedIp[i] >> 8);
+				addr[(i * 2 + 1) + offSet] = (byte)parsedIp[i];
+			}
+		}
+
+		private int[] parseIPv6(string ip)
+		{
+			if (ip.StartsWith("::"))
+			{
+				ip = ip.Substring(1);
+			}
+			else if (ip.EndsWith("::"))
+			{
+				ip = ip.Substring(0, ip.Length - 1);
+			}
+
+			IEnumerator sEnum = ip.Split(':').GetEnumerator();
+
+			int index = 0;
+			int[] val = new int[8];
+
+			int doubleColon = -1;
+
+			while (sEnum.MoveNext())
+			{
+				string e = (string) sEnum.Current;
+
+				if (e.Length == 0)
+				{
+					doubleColon = index;
+					val[index++] = 0;
+				}
+				else
+				{
+					if (e.IndexOf('.') < 0)
+					{
+						val[index++] = Int32.Parse(e, NumberStyles.AllowHexSpecifier);
+					}
+					else
+					{
+						string[] tokens = e.Split('.');
+
+						val[index++] = (Int32.Parse(tokens[0]) << 8) | Int32.Parse(tokens[1]);
+						val[index++] = (Int32.Parse(tokens[2]) << 8) | Int32.Parse(tokens[3]);
+					}
+				}
+			}
+
+			if (index != val.Length)
+			{
+				Array.Copy(val, doubleColon, val, val.Length - (index - doubleColon), index - doubleColon);
+				for (int i = doubleColon; i != val.Length - (index - doubleColon); i++)
+				{
+					val[i] = 0;
+				}
+			}
+
+			return val;
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+			// Explicitly tagged if DirectoryName
+			return new DerTaggedObject(tag == DirectoryName, tag, obj);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/GeneralNames.cs b/crypto/src/asn1/x509/GeneralNames.cs
new file mode 100644
index 000000000..6c5c8e690
--- /dev/null
+++ b/crypto/src/asn1/x509/GeneralNames.cs
@@ -0,0 +1,95 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	public class GeneralNames
+		: Asn1Encodable
+	{
+		private readonly GeneralName[] names;
+
+		public static GeneralNames GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is GeneralNames)
+			{
+				return (GeneralNames) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new GeneralNames((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public static GeneralNames GetInstance(
+			Asn1TaggedObject	obj,
+			bool				explicitly)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+		}
+
+		/// <summary>Construct a GeneralNames object containing one GeneralName.</summary>
+		/// <param name="name">The name to be contained.</param>
+		public GeneralNames(
+			GeneralName name)
+		{
+			names = new GeneralName[]{ name };
+		}
+
+        public GeneralNames(
+            GeneralName[] names)
+        {
+            this.names = (GeneralName[])names.Clone();
+        }
+
+		private GeneralNames(
+			Asn1Sequence seq)
+		{
+			this.names = new GeneralName[seq.Count];
+
+			for (int i = 0; i != seq.Count; i++)
+			{
+				names[i] = GeneralName.GetInstance(seq[i]);
+			}
+		}
+
+		public GeneralName[] GetNames()
+		{
+			return (GeneralName[]) names.Clone();
+		}
+
+		/**
+		 * Produce an object suitable for an Asn1OutputStream.
+		 * <pre>
+		 * GeneralNames ::= Sequence SIZE {1..MAX} OF GeneralName
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(names);
+		}
+
+		public override string ToString()
+		{
+			StringBuilder buf = new StringBuilder();
+			string sep = Platform.NewLine;
+
+			buf.Append("GeneralNames:");
+			buf.Append(sep);
+
+			foreach (GeneralName name in names)
+			{
+				buf.Append("    ");
+				buf.Append(name);
+				buf.Append(sep);
+			}
+
+			return buf.ToString();
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/GeneralSubtree.cs b/crypto/src/asn1/x509/GeneralSubtree.cs
new file mode 100644
index 000000000..e918a0277
--- /dev/null
+++ b/crypto/src/asn1/x509/GeneralSubtree.cs
@@ -0,0 +1,189 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * Class for containing a restriction object subtrees in NameConstraints. See
+	 * RFC 3280.
+	 *
+	 * <pre>
+	 *
+	 *       GeneralSubtree ::= SEQUENCE
+	 *       {
+	 *         baseName                    GeneralName,
+	 *         minimum         [0]     BaseDistance DEFAULT 0,
+	 *         maximum         [1]     BaseDistance OPTIONAL
+	 *       }
+	 * </pre>
+	 *
+	 * @see org.bouncycastle.asn1.x509.NameConstraints
+	 *
+	 */
+	public class GeneralSubtree
+		: Asn1Encodable
+	{
+		private readonly GeneralName	baseName;
+		private readonly DerInteger		minimum;
+		private readonly DerInteger		maximum;
+
+		private GeneralSubtree(
+			Asn1Sequence seq)
+		{
+			baseName = GeneralName.GetInstance(seq[0]);
+
+			switch (seq.Count)
+			{
+				case 1:
+					break;
+				case 2:
+				{
+					Asn1TaggedObject o = Asn1TaggedObject.GetInstance(seq[1]);
+					switch (o.TagNo)
+					{
+						case 0:
+							minimum = DerInteger.GetInstance(o, false);
+							break;
+						case 1:
+							maximum = DerInteger.GetInstance(o, false);
+							break;
+						default:
+							throw new ArgumentException("Bad tag number: " + o.TagNo);
+					}
+					break;
+				}
+				case 3:
+				{
+					{
+						Asn1TaggedObject oMin = Asn1TaggedObject.GetInstance(seq[1]);
+						if (oMin.TagNo != 0)
+							throw new ArgumentException("Bad tag number for 'minimum': " + oMin.TagNo);
+						minimum = DerInteger.GetInstance(oMin, false);
+					}
+
+					{
+						Asn1TaggedObject oMax = Asn1TaggedObject.GetInstance(seq[2]);
+						if (oMax.TagNo != 1)
+							throw new ArgumentException("Bad tag number for 'maximum': " + oMax.TagNo);
+						maximum = DerInteger.GetInstance(oMax, false);
+					}
+
+					break;
+				}
+				default:
+					throw new ArgumentException("Bad sequence size: " + seq.Count);
+			}
+		}
+
+		/**
+		 * Constructor from a given details.
+		 *
+		 * According RFC 3280, the minimum and maximum fields are not used with any
+		 * name forms, thus minimum MUST be zero, and maximum MUST be absent.
+		 * <p>
+		 * If minimum is <code>null</code>, zero is assumed, if
+		 * maximum is <code>null</code>, maximum is absent.</p>
+		 *
+		 * @param baseName
+		 *            A restriction.
+		 * @param minimum
+		 *            Minimum
+		 *
+		 * @param maximum
+		 *            Maximum
+		 */
+		public GeneralSubtree(
+			GeneralName	baseName,
+			BigInteger	minimum,
+			BigInteger	maximum)
+		{
+			this.baseName = baseName;
+			if (minimum != null)
+			{
+				this.minimum = new DerInteger(minimum);
+			}
+			if (maximum != null)
+			{
+				this.maximum = new DerInteger(maximum);
+			}
+		}
+
+		public GeneralSubtree(
+			GeneralName baseName)
+			: this(baseName, null, null)
+		{
+		}
+
+		public static GeneralSubtree GetInstance(
+			Asn1TaggedObject	o,
+			bool				isExplicit)
+		{
+			return new GeneralSubtree(Asn1Sequence.GetInstance(o, isExplicit));
+		}
+
+		public static GeneralSubtree GetInstance(
+			object obj)
+		{
+			if (obj == null)
+			{
+				return null;
+			}
+
+			if (obj is GeneralSubtree)
+			{
+				return (GeneralSubtree) obj;
+			}
+
+			return new GeneralSubtree(Asn1Sequence.GetInstance(obj));
+		}
+
+		public GeneralName Base
+		{
+			get { return baseName; }
+		}
+
+		public BigInteger Minimum
+		{
+			get { return minimum == null ? BigInteger.Zero : minimum.Value; }
+		}
+
+		public BigInteger Maximum
+		{
+			get { return maximum == null ? null : maximum.Value; }
+		}
+
+		/**
+		 * Produce an object suitable for an Asn1OutputStream.
+		 *
+		 * Returns:
+		 *
+		 * <pre>
+		 *       GeneralSubtree ::= SEQUENCE
+		 *       {
+		 *         baseName                    GeneralName,
+		 *         minimum         [0]     BaseDistance DEFAULT 0,
+		 *         maximum         [1]     BaseDistance OPTIONAL
+		 *       }
+		 * </pre>
+		 *
+		 * @return a DERObject
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(baseName);
+
+			if (minimum != null && minimum.Value.SignValue != 0)
+			{
+				v.Add(new DerTaggedObject(false, 0, minimum));
+			}
+
+			if (maximum != null)
+			{
+				v.Add(new DerTaggedObject(false, 1, maximum));
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/Holder.cs b/crypto/src/asn1/x509/Holder.cs
new file mode 100644
index 000000000..d04f1cb60
--- /dev/null
+++ b/crypto/src/asn1/x509/Holder.cs
@@ -0,0 +1,257 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * The Holder object.
+	 * <p>
+	 * For an v2 attribute certificate this is:
+	 * 
+	 * <pre>
+	 *            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
+	 *            }
+	 * </pre>
+	 * </p>
+	 * <p>
+	 * For an v1 attribute certificate this is:
+	 * 
+	 * <pre>
+	 *         subject CHOICE {
+	 *          baseCertificateID [0] IssuerSerial,
+	 *          -- associated with a Public Key Certificate
+	 *          subjectName [1] GeneralNames },
+	 *          -- associated with a name
+	 * </pre>
+	 * </p>
+	 */
+	public class Holder
+        : Asn1Encodable
+    {
+		internal readonly IssuerSerial		baseCertificateID;
+        internal readonly GeneralNames		entityName;
+        internal readonly ObjectDigestInfo	objectDigestInfo;
+		private readonly int version;
+
+		public static Holder GetInstance(
+            object obj)
+        {
+            if (obj is Holder)
+            {
+                return (Holder) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new Holder((Asn1Sequence) obj);
+            }
+
+			if (obj is Asn1TaggedObject)
+			{
+				return new Holder((Asn1TaggedObject) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		 * Constructor for a holder for an v1 attribute certificate.
+		 * 
+		 * @param tagObj The ASN.1 tagged holder object.
+		 */
+		public Holder(
+			Asn1TaggedObject tagObj)
+		{
+			switch (tagObj.TagNo)
+			{
+				case 0:
+					baseCertificateID = IssuerSerial.GetInstance(tagObj, false);
+					break;
+				case 1:
+					entityName = GeneralNames.GetInstance(tagObj, false);
+					break;
+				default:
+					throw new ArgumentException("unknown tag in Holder");
+			}
+
+			this.version = 0;
+		}
+
+		/**
+		 * Constructor for a holder for an v2 attribute certificate. *
+		 * 
+		 * @param seq The ASN.1 sequence.
+		 */
+		private Holder(
+            Asn1Sequence seq)
+        {
+			if (seq.Count > 3)
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+			for (int i = 0; i != seq.Count; i++)
+            {
+				Asn1TaggedObject tObj = Asn1TaggedObject.GetInstance(seq[i]);
+
+				switch (tObj.TagNo)
+                {
+                    case 0:
+                        baseCertificateID = IssuerSerial.GetInstance(tObj, false);
+                        break;
+                    case 1:
+                        entityName = GeneralNames.GetInstance(tObj, false);
+                        break;
+                    case 2:
+                        objectDigestInfo = ObjectDigestInfo.GetInstance(tObj, false);
+                        break;
+                    default:
+                        throw new ArgumentException("unknown tag in Holder");
+                }
+            }
+
+			this.version = 1;
+		}
+
+		public Holder(
+			IssuerSerial baseCertificateID)
+			: this(baseCertificateID, 1)
+		{
+		}
+
+		/**
+		 * Constructs a holder from a IssuerSerial.
+		 * @param baseCertificateID The IssuerSerial.
+		 * @param version The version of the attribute certificate. 
+		 */
+		public Holder(
+			IssuerSerial	baseCertificateID,
+			int				version)
+		{
+			this.baseCertificateID = baseCertificateID;
+			this.version = version;
+		}
+
+		/**
+		 * Returns 1 for v2 attribute certificates or 0 for v1 attribute
+		 * certificates. 
+		 * @return The version of the attribute certificate.
+		 */
+		public int Version
+		{
+			get { return version; }
+		}
+
+		/**
+		 * Constructs a holder with an entityName for v2 attribute certificates or
+		 * with a subjectName for v1 attribute certificates.
+		 * 
+		 * @param entityName The entity or subject name.
+		 */
+		public Holder(
+			GeneralNames entityName)
+			: this(entityName, 1)
+		{
+		}
+
+		/**
+		 * Constructs a holder with an entityName for v2 attribute certificates or
+		 * with a subjectName for v1 attribute certificates.
+		 * 
+		 * @param entityName The entity or subject name.
+		 * @param version The version of the attribute certificate. 
+		 */
+		public Holder(
+			GeneralNames	entityName,
+			int				version)
+		{
+			this.entityName = entityName;
+			this.version = version;
+		}
+
+		/**
+		 * Constructs a holder from an object digest info.
+		 * 
+		 * @param objectDigestInfo The object digest info object.
+		 */
+		public Holder(
+			ObjectDigestInfo objectDigestInfo)
+		{
+			this.objectDigestInfo = objectDigestInfo;
+			this.version = 1;
+		}
+
+		public IssuerSerial BaseCertificateID
+		{
+			get { return baseCertificateID; }
+		}
+
+		/**
+		 * Returns the entityName for an v2 attribute certificate or the subjectName
+		 * for an v1 attribute certificate.
+		 * 
+		 * @return The entityname or subjectname.
+		 */
+		public GeneralNames EntityName
+		{
+			get { return entityName; }
+		}
+
+		public ObjectDigestInfo ObjectDigestInfo
+		{
+			get { return objectDigestInfo; }
+		}
+
+		/**
+         * The Holder object.
+         * <pre>
+         *  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
+         *  }
+         * </pre>
+         */
+		public override Asn1Object ToAsn1Object()
+		{
+			if (version == 1)
+			{
+				Asn1EncodableVector v = new Asn1EncodableVector();
+
+				if (baseCertificateID != null)
+				{
+					v.Add(new DerTaggedObject(false, 0, baseCertificateID));
+				}
+
+				if (entityName != null)
+				{
+					v.Add(new DerTaggedObject(false, 1, entityName));
+				}
+
+				if (objectDigestInfo != null)
+				{
+					v.Add(new DerTaggedObject(false, 2, objectDigestInfo));
+				}
+
+				return new DerSequence(v);
+			}
+
+			if (entityName != null)
+			{
+				return new DerTaggedObject(false, 1, entityName);
+			}
+
+			return new DerTaggedObject(false, 0, baseCertificateID);
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/IetfAttrSyntax.cs b/crypto/src/asn1/x509/IetfAttrSyntax.cs
new file mode 100644
index 000000000..e719865b3
--- /dev/null
+++ b/crypto/src/asn1/x509/IetfAttrSyntax.cs
@@ -0,0 +1,161 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * Implementation of <code>IetfAttrSyntax</code> as specified by RFC3281.
+     */
+    public class IetfAttrSyntax
+        : Asn1Encodable
+    {
+        public const int ValueOctets	= 1;
+        public const int ValueOid		= 2;
+        public const int ValueUtf8		= 3;
+
+		internal readonly GeneralNames	policyAuthority;
+        internal readonly Asn1EncodableVector values = new Asn1EncodableVector();
+
+		internal int valueChoice = -1;
+
+		/**
+         *
+         */
+        public IetfAttrSyntax(
+			Asn1Sequence seq)
+        {
+            int i = 0;
+
+            if (seq[0] is Asn1TaggedObject)
+            {
+                policyAuthority = GeneralNames.GetInstance(((Asn1TaggedObject)seq[0]), false);
+                i++;
+            }
+            else if (seq.Count == 2)
+            { // VOMS fix
+                policyAuthority = GeneralNames.GetInstance(seq[0]);
+                i++;
+            }
+
+			if (!(seq[i] is Asn1Sequence))
+            {
+                throw new ArgumentException("Non-IetfAttrSyntax encoding");
+            }
+
+			seq = (Asn1Sequence) seq[i];
+
+			foreach (Asn1Object obj in seq)
+			{
+                int type;
+
+                if (obj is DerObjectIdentifier)
+                {
+                    type = ValueOid;
+                }
+                else if (obj is DerUtf8String)
+                {
+                    type = ValueUtf8;
+                }
+                else if (obj is DerOctetString)
+                {
+                    type = ValueOctets;
+                }
+                else
+                {
+                    throw new ArgumentException("Bad value type encoding IetfAttrSyntax");
+                }
+
+				if (valueChoice < 0)
+                {
+                    valueChoice = type;
+                }
+
+				if (type != valueChoice)
+                {
+                    throw new ArgumentException("Mix of value types in IetfAttrSyntax");
+                }
+
+				values.Add(obj);
+            }
+        }
+
+		public GeneralNames PolicyAuthority
+		{
+			get { return policyAuthority; }
+		}
+
+		public int ValueType
+		{
+			get { return valueChoice; }
+		}
+
+		public object[] GetValues()
+        {
+            if (this.ValueType == ValueOctets)
+            {
+                Asn1OctetString[] tmp = new Asn1OctetString[values.Count];
+
+				for (int i = 0; i != tmp.Length; i++)
+                {
+                    tmp[i] = (Asn1OctetString) values[i];
+                }
+
+				return tmp;
+            }
+
+			if (this.ValueType == ValueOid)
+            {
+                DerObjectIdentifier[] tmp = new DerObjectIdentifier[values.Count];
+
+                for (int i = 0; i != tmp.Length; i++)
+                {
+                    tmp[i] = (DerObjectIdentifier) values[i];
+                }
+
+				return tmp;
+            }
+
+			{
+				DerUtf8String[] tmp = new DerUtf8String[values.Count];
+
+				for (int i = 0; i != tmp.Length; i++)
+				{
+					tmp[i] = (DerUtf8String) values[i];
+				}
+
+				return tmp;
+			}
+        }
+
+		/**
+         *
+         * <pre>
+         *
+         *  IetfAttrSyntax ::= Sequence {
+         *    policyAuthority [0] GeneralNames OPTIONAL,
+         *    values Sequence OF CHOICE {
+         *      octets OCTET STRING,
+         *      oid OBJECT IDENTIFIER,
+         *      string UTF8String
+         *    }
+         *  }
+         *
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (policyAuthority != null)
+            {
+                v.Add(new DerTaggedObject(0, policyAuthority));
+            }
+
+			v.Add(new DerSequence(values));
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/IssuerSerial.cs b/crypto/src/asn1/x509/IssuerSerial.cs
new file mode 100644
index 000000000..6a24e7333
--- /dev/null
+++ b/crypto/src/asn1/x509/IssuerSerial.cs
@@ -0,0 +1,98 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class IssuerSerial
+        : Asn1Encodable
+    {
+        internal readonly GeneralNames	issuer;
+        internal readonly DerInteger	serial;
+        internal readonly DerBitString	issuerUid;
+
+		public static IssuerSerial GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is IssuerSerial)
+            {
+                return (IssuerSerial) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new IssuerSerial((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+        public static IssuerSerial GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		private IssuerSerial(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2 && seq.Count != 3)
+			{
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+			}
+
+			issuer = GeneralNames.GetInstance(seq[0]);
+			serial = DerInteger.GetInstance(seq[1]);
+
+			if (seq.Count == 3)
+            {
+				issuerUid = DerBitString.GetInstance(seq[2]);
+			}
+        }
+
+		public IssuerSerial(
+			GeneralNames	issuer,
+			DerInteger		serial)
+		{
+			this.issuer = issuer;
+			this.serial = serial;
+		}
+
+		public GeneralNames Issuer
+		{
+			get { return issuer; }
+		}
+
+		public DerInteger Serial
+		{
+			get { return serial; }
+		}
+
+		public DerBitString IssuerUid
+		{
+			get { return issuerUid; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *  IssuerSerial  ::=  Sequence {
+         *       issuer         GeneralNames,
+         *       serial         CertificateSerialNumber,
+         *       issuerUid      UniqueIdentifier OPTIONAL
+         *  }
+         * </pre>
+         */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(
+				issuer, serial);
+
+			if (issuerUid != null)
+			{
+				v.Add(issuerUid);
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/IssuingDistributionPoint.cs b/crypto/src/asn1/x509/IssuingDistributionPoint.cs
new file mode 100644
index 000000000..3af0d565f
--- /dev/null
+++ b/crypto/src/asn1/x509/IssuingDistributionPoint.cs
@@ -0,0 +1,247 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * <pre>
+	 * IssuingDistributionPoint ::= SEQUENCE { 
+	 *   distributionPoint          [0] DistributionPointName OPTIONAL, 
+	 *   onlyContainsUserCerts      [1] BOOLEAN DEFAULT FALSE, 
+	 *   onlyContainsCACerts        [2] BOOLEAN DEFAULT FALSE, 
+	 *   onlySomeReasons            [3] ReasonFlags OPTIONAL, 
+	 *   indirectCRL                [4] BOOLEAN DEFAULT FALSE,
+	 *   onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE }
+	 * </pre>
+	 */
+	public class IssuingDistributionPoint
+        : Asn1Encodable
+    {
+		private readonly DistributionPointName	_distributionPoint;
+		private readonly bool					_onlyContainsUserCerts;
+        private readonly bool					_onlyContainsCACerts;
+		private readonly ReasonFlags			_onlySomeReasons;
+		private readonly bool					_indirectCRL;
+        private readonly bool					_onlyContainsAttributeCerts;
+
+		private readonly Asn1Sequence seq;
+
+		public static IssuingDistributionPoint GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static IssuingDistributionPoint GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is IssuingDistributionPoint)
+            {
+                return (IssuingDistributionPoint) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new IssuingDistributionPoint((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		 * Constructor from given details.
+		 * 
+		 * @param distributionPoint
+		 *            May contain an URI as pointer to most current CRL.
+		 * @param onlyContainsUserCerts Covers revocation information for end certificates.
+		 * @param onlyContainsCACerts Covers revocation information for CA certificates.
+		 * 
+		 * @param onlySomeReasons
+		 *            Which revocation reasons does this point cover.
+		 * @param indirectCRL
+		 *            If <code>true</code> then the CRL contains revocation
+		 *            information about certificates ssued by other CAs.
+		 * @param onlyContainsAttributeCerts Covers revocation information for attribute certificates.
+		 */
+		public IssuingDistributionPoint(
+			DistributionPointName	distributionPoint,
+			bool					onlyContainsUserCerts,
+			bool					onlyContainsCACerts,
+			ReasonFlags				onlySomeReasons,
+			bool					indirectCRL,
+			bool					onlyContainsAttributeCerts)
+		{
+			this._distributionPoint = distributionPoint;
+			this._indirectCRL = indirectCRL;
+			this._onlyContainsAttributeCerts = onlyContainsAttributeCerts;
+			this._onlyContainsCACerts = onlyContainsCACerts;
+			this._onlyContainsUserCerts = onlyContainsUserCerts;
+			this._onlySomeReasons = onlySomeReasons;
+
+			Asn1EncodableVector vec = new Asn1EncodableVector();
+			if (distributionPoint != null)
+			{	// CHOICE item so explicitly tagged
+				vec.Add(new DerTaggedObject(true, 0, distributionPoint));
+			}
+			if (onlyContainsUserCerts)
+			{
+				vec.Add(new DerTaggedObject(false, 1, DerBoolean.True));
+			}
+			if (onlyContainsCACerts)
+			{
+				vec.Add(new DerTaggedObject(false, 2, DerBoolean.True));
+			}
+			if (onlySomeReasons != null)
+			{
+				vec.Add(new DerTaggedObject(false, 3, onlySomeReasons));
+			}
+			if (indirectCRL)
+			{
+				vec.Add(new DerTaggedObject(false, 4, DerBoolean.True));
+			}
+			if (onlyContainsAttributeCerts)
+			{
+				vec.Add(new DerTaggedObject(false, 5, DerBoolean.True));
+			}
+
+			seq = new DerSequence(vec);
+		}
+
+		/**
+         * Constructor from Asn1Sequence
+         */
+        private IssuingDistributionPoint(
+            Asn1Sequence seq)
+        {
+            this.seq = seq;
+
+			for (int i = 0; i != seq.Count; i++)
+            {
+				Asn1TaggedObject o = Asn1TaggedObject.GetInstance(seq[i]);
+
+				switch (o.TagNo)
+                {
+					case 0:
+						// CHOICE so explicit
+						_distributionPoint = DistributionPointName.GetInstance(o, true);
+						break;
+					case 1:
+						_onlyContainsUserCerts = DerBoolean.GetInstance(o, false).IsTrue;
+						break;
+					case 2:
+						_onlyContainsCACerts = DerBoolean.GetInstance(o, false).IsTrue;
+						break;
+					case 3:
+						_onlySomeReasons = new ReasonFlags(ReasonFlags.GetInstance(o, false));
+						break;
+					case 4:
+						_indirectCRL = DerBoolean.GetInstance(o, false).IsTrue;
+						break;
+					case 5:
+						_onlyContainsAttributeCerts = DerBoolean.GetInstance(o, false).IsTrue;
+						break;
+					default:
+						throw new ArgumentException("unknown tag in IssuingDistributionPoint");
+                }
+            }
+        }
+
+		public bool OnlyContainsUserCerts
+		{
+			get { return _onlyContainsUserCerts; }
+		}
+
+		public bool OnlyContainsCACerts
+		{
+			get { return _onlyContainsCACerts; }
+		}
+
+		public bool IsIndirectCrl
+		{
+			get { return _indirectCRL; }
+		}
+
+		public bool OnlyContainsAttributeCerts
+		{
+			get { return _onlyContainsAttributeCerts; }
+		}
+
+		/**
+		 * @return Returns the distributionPoint.
+		 */
+		public DistributionPointName DistributionPoint
+		{
+			get { return _distributionPoint; }
+		}
+
+		/**
+		 * @return Returns the onlySomeReasons.
+		 */
+		public ReasonFlags OnlySomeReasons
+		{
+			get { return _onlySomeReasons; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+            return seq;
+        }
+
+		public override string ToString()
+		{
+			string sep = Platform.NewLine;
+			StringBuilder buf = new StringBuilder();
+
+			buf.Append("IssuingDistributionPoint: [");
+			buf.Append(sep);
+			if (_distributionPoint != null)
+			{
+				appendObject(buf, sep, "distributionPoint", _distributionPoint.ToString());
+			}
+			if (_onlyContainsUserCerts)
+			{
+				appendObject(buf, sep, "onlyContainsUserCerts", _onlyContainsUserCerts.ToString());
+			}
+			if (_onlyContainsCACerts)
+			{
+				appendObject(buf, sep, "onlyContainsCACerts", _onlyContainsCACerts.ToString());
+			}
+			if (_onlySomeReasons != null)
+			{
+				appendObject(buf, sep, "onlySomeReasons", _onlySomeReasons.ToString());
+			}
+			if (_onlyContainsAttributeCerts)
+			{
+				appendObject(buf, sep, "onlyContainsAttributeCerts", _onlyContainsAttributeCerts.ToString());
+			}
+			if (_indirectCRL)
+			{
+				appendObject(buf, sep, "indirectCRL", _indirectCRL.ToString());
+			}
+			buf.Append("]");
+			buf.Append(sep);
+			return buf.ToString();
+		}
+
+		private void appendObject(
+			StringBuilder	buf,
+			string			sep,
+			string			name,
+			string			val)
+		{
+			string indent = "    ";
+
+			buf.Append(indent);
+			buf.Append(name);
+			buf.Append(":");
+			buf.Append(sep);
+			buf.Append(indent);
+			buf.Append(indent);
+			buf.Append(val);
+			buf.Append(sep);
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/KeyPurposeId.cs b/crypto/src/asn1/x509/KeyPurposeId.cs
new file mode 100644
index 000000000..4b48a9b51
--- /dev/null
+++ b/crypto/src/asn1/x509/KeyPurposeId.cs
@@ -0,0 +1,36 @@
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The KeyPurposeID object.
+     * <pre>
+     *     KeyPurposeID ::= OBJECT IDENTIFIER
+     * </pre>
+     */
+    public sealed class KeyPurposeID
+        : DerObjectIdentifier
+    {
+        private const string IdKP = "1.3.6.1.5.5.7.3";
+
+		private KeyPurposeID(
+			string id)
+			: base(id)
+        {
+        }
+
+		public static readonly KeyPurposeID AnyExtendedKeyUsage = new KeyPurposeID(X509Extensions.ExtendedKeyUsage.Id + ".0");
+        public static readonly KeyPurposeID IdKPServerAuth = new KeyPurposeID(IdKP + ".1");
+        public static readonly KeyPurposeID IdKPClientAuth = new KeyPurposeID(IdKP + ".2");
+        public static readonly KeyPurposeID IdKPCodeSigning = new KeyPurposeID(IdKP + ".3");
+        public static readonly KeyPurposeID IdKPEmailProtection = new KeyPurposeID(IdKP + ".4");
+        public static readonly KeyPurposeID IdKPIpsecEndSystem = new KeyPurposeID(IdKP + ".5");
+        public static readonly KeyPurposeID IdKPIpsecTunnel = new KeyPurposeID(IdKP + ".6");
+        public static readonly KeyPurposeID IdKPIpsecUser = new KeyPurposeID(IdKP + ".7");
+        public static readonly KeyPurposeID IdKPTimeStamping = new KeyPurposeID(IdKP + ".8");
+        public static readonly KeyPurposeID IdKPOcspSigning = new KeyPurposeID(IdKP + ".9");
+
+		//
+        // microsoft key purpose ids
+        //
+        public static readonly KeyPurposeID IdKPSmartCardLogon = new KeyPurposeID("1.3.6.1.4.1.311.20.2.2");
+    }
+}
diff --git a/crypto/src/asn1/x509/KeyUsage.cs b/crypto/src/asn1/x509/KeyUsage.cs
new file mode 100644
index 000000000..fef04e8b9
--- /dev/null
+++ b/crypto/src/asn1/x509/KeyUsage.cs
@@ -0,0 +1,79 @@
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The KeyUsage object.
+     * <pre>
+     *    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) }
+     * </pre>
+     */
+    public class KeyUsage
+        : DerBitString
+    {
+        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);
+
+		public static new KeyUsage GetInstance(
+			object obj)
+		{
+			if (obj is KeyUsage)
+			{
+				return (KeyUsage)obj;
+			}
+
+			if (obj is X509Extension)
+			{
+				return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj));
+			}
+
+			return new KeyUsage(DerBitString.GetInstance(obj));
+		}
+
+		/**
+         * Basic constructor.
+         *
+         * @param usage - the bitwise OR of the Key Usage flags giving the
+         * allowed uses for the key.
+         * e.g. (KeyUsage.keyEncipherment | KeyUsage.dataEncipherment)
+         */
+        public KeyUsage(
+			int usage)
+			: base(GetBytes(usage), GetPadBits(usage))
+        {
+        }
+
+		private KeyUsage(
+			DerBitString usage)
+			: base(usage.GetBytes(), usage.PadBits)
+        {
+        }
+
+		public override string ToString()
+        {
+			byte[] data = GetBytes();
+            if (data.Length == 1)
+            {
+				return "KeyUsage: 0x" + (data[0] & 0xff).ToString("X");
+            }
+
+			return "KeyUsage: 0x" + ((data[1] & 0xff) << 8 | (data[0] & 0xff)).ToString("X");
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/NameConstraints.cs b/crypto/src/asn1/x509/NameConstraints.cs
new file mode 100644
index 000000000..8374ff60a
--- /dev/null
+++ b/crypto/src/asn1/x509/NameConstraints.cs
@@ -0,0 +1,118 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	public class NameConstraints
+		: Asn1Encodable
+	{
+		private Asn1Sequence permitted, excluded;
+
+		public static NameConstraints GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is NameConstraints)
+			{
+				return (NameConstraints) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new NameConstraints((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public NameConstraints(
+			Asn1Sequence seq)
+		{
+			foreach (Asn1TaggedObject o in seq)
+			{
+				switch (o.TagNo)
+				{
+					case 0:
+						permitted = Asn1Sequence.GetInstance(o, false);
+						break;
+					case 1:
+						excluded = Asn1Sequence.GetInstance(o, false);
+						break;
+				}
+			}
+		}
+
+#if !SILVERLIGHT
+        public NameConstraints(
+            ArrayList permitted,
+            ArrayList excluded)
+            : this((IList)permitted, (IList)excluded)
+        {
+        }
+#endif
+
+        /**
+		 * Constructor from a given details.
+		 *
+		 * <p>permitted and excluded are Vectors of GeneralSubtree objects.</p>
+		 *
+		 * @param permitted Permitted subtrees
+		 * @param excluded Excluded subtrees
+		 */
+		public NameConstraints(
+			IList   permitted,
+			IList   excluded)
+		{
+			if (permitted != null)
+			{
+				this.permitted = CreateSequence(permitted);
+			}
+
+			if (excluded != null)
+			{
+				this.excluded = CreateSequence(excluded);
+			}
+		}
+
+		private DerSequence CreateSequence(
+			IList subtrees)
+		{
+            GeneralSubtree[] gsts = new GeneralSubtree[subtrees.Count];
+            for (int i = 0; i < subtrees.Count; ++i)
+            {
+                gsts[i] = (GeneralSubtree)subtrees[i];
+            }
+            return new DerSequence(gsts);
+		}
+
+		public Asn1Sequence PermittedSubtrees
+		{
+			get { return permitted; }
+		}
+
+		public Asn1Sequence ExcludedSubtrees
+		{
+			get { return excluded; }
+		}
+
+		/*
+		 * NameConstraints ::= SEQUENCE { permittedSubtrees [0] GeneralSubtrees
+		 * OPTIONAL, excludedSubtrees [1] GeneralSubtrees OPTIONAL }
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (permitted != null)
+			{
+				v.Add(new DerTaggedObject(false, 0, permitted));
+			}
+
+			if (excluded != null)
+			{
+				v.Add(new DerTaggedObject(false, 1, excluded));
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/NoticeReference.cs b/crypto/src/asn1/x509/NoticeReference.cs
new file mode 100644
index 000000000..86a51c5b7
--- /dev/null
+++ b/crypto/src/asn1/x509/NoticeReference.cs
@@ -0,0 +1,138 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * <code>NoticeReference</code> class, used in
+	 * <code>CertificatePolicies</code> X509 V3 extensions
+	 * (in policy qualifiers).
+	 *
+	 * <pre>
+	 *  NoticeReference ::= Sequence {
+	 *      organization     DisplayText,
+	 *      noticeNumbers    Sequence OF Integer }
+	 *
+	 * </pre>
+	 *
+	 * @see PolicyQualifierInfo
+	 * @see PolicyInformation
+	 */
+	public class NoticeReference
+		: Asn1Encodable
+	{
+		internal readonly DisplayText organization;
+		internal readonly Asn1Sequence noticeNumbers;
+
+#if !SILVERLIGHT
+        [Obsolete]
+        public NoticeReference(
+            string orgName,
+            ArrayList numbers)
+            : this(orgName, (IList)numbers)
+        {
+        }
+#endif
+
+        /**
+		* Creates a new <code>NoticeReference</code> instance.
+		*
+		* @param orgName a <code>string</code> value
+		* @param numbers a <code>ArrayList</code> value
+		*/
+		public NoticeReference(
+			string  orgName,
+			IList   numbers)
+		{
+			organization = new DisplayText(orgName);
+
+			object o = numbers[0];
+
+			Asn1EncodableVector av = new Asn1EncodableVector();
+			if (o is int)
+			{
+				foreach (int nm in numbers)
+				{
+					av.Add(new DerInteger(nm));
+				}
+			}
+
+			noticeNumbers = new DerSequence(av);
+		}
+
+		/**
+		 * Creates a new <code>NoticeReference</code> instance.
+		 *
+		 * @param orgName a <code>string</code> value
+		 * @param numbers an <code>Asn1Sequence</code> value
+		 */
+		public NoticeReference(
+			string			orgName,
+			Asn1Sequence	numbers)
+		{
+			organization = new DisplayText(orgName);
+			noticeNumbers = numbers;
+		}
+
+		/**
+		 * Creates a new <code>NoticeReference</code> instance.
+		 *
+		 * @param displayTextType an <code>int</code> value
+		 * @param orgName a <code>string</code> value
+		 * @param numbers an <code>Asn1Sequence</code> value
+		 */
+		public NoticeReference(
+			int				displayTextType,
+			string			orgName,
+			Asn1Sequence	numbers)
+		{
+			organization = new DisplayText(displayTextType, orgName);
+			noticeNumbers = numbers;
+		}
+
+		/**
+		 * Creates a new <code>NoticeReference</code> instance.
+		 * <p>Useful for reconstructing a <code>NoticeReference</code>
+		 * instance from its encodable/encoded form.</p>
+		 *
+		 * @param as an <code>Asn1Sequence</code> value obtained from either
+		 * calling @{link ToAsn1Object()} for a <code>NoticeReference</code>
+		 * instance or from parsing it from a Der-encoded stream.
+		 */
+		private NoticeReference(
+			Asn1Sequence seq)
+		{
+			if (seq.Count != 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			organization = DisplayText.GetInstance(seq[0]);
+			noticeNumbers = Asn1Sequence.GetInstance(seq[1]);
+		}
+
+		public static NoticeReference GetInstance(
+			object obj)
+		{
+			if (obj is NoticeReference)
+			{
+				return (NoticeReference) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new NoticeReference((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+		}
+
+		/**
+		 * Describe <code>ToAsn1Object</code> method here.
+		 *
+		 * @return a <code>Asn1Object</code> value
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(organization, noticeNumbers);
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/ObjectDigestInfo.cs b/crypto/src/asn1/x509/ObjectDigestInfo.cs
new file mode 100644
index 000000000..6d5b9c692
--- /dev/null
+++ b/crypto/src/asn1/x509/ObjectDigestInfo.cs
@@ -0,0 +1,177 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * ObjectDigestInfo ASN.1 structure used in v2 attribute certificates.
+	 * 
+	 * <pre>
+	 *  
+	 *    ObjectDigestInfo ::= SEQUENCE {
+	 *         digestedObjectType  ENUMERATED {
+	 *                 publicKey            (0),
+	 *                 publicKeyCert        (1),
+	 *                 otherObjectTypes     (2) },
+	 *                         -- otherObjectTypes MUST NOT
+	 *                         -- be used in this profile
+	 *         otherObjectTypeID   OBJECT IDENTIFIER OPTIONAL,
+	 *         digestAlgorithm     AlgorithmIdentifier,
+	 *         objectDigest        BIT STRING
+	 *    }
+	 *   
+	 * </pre>
+	 * 
+	 */
+	public class ObjectDigestInfo
+        : Asn1Encodable
+    {
+		/**
+		 * The public key is hashed.
+		 */
+		public const int PublicKey = 0;
+
+		/**
+		 * The public key certificate is hashed.
+		 */
+		public const int PublicKeyCert = 1;
+
+		/**
+		 * An other object is hashed.
+		 */
+		public const int OtherObjectDigest = 2;
+
+		internal readonly DerEnumerated			digestedObjectType;
+        internal readonly DerObjectIdentifier	otherObjectTypeID;
+        internal readonly AlgorithmIdentifier	digestAlgorithm;
+        internal readonly DerBitString			objectDigest;
+
+		public static ObjectDigestInfo GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is ObjectDigestInfo)
+            {
+                return (ObjectDigestInfo) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new ObjectDigestInfo((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public static ObjectDigestInfo GetInstance(
+            Asn1TaggedObject	obj,
+            bool				isExplicit)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+        }
+
+		/**
+		 * Constructor from given details.
+		 * <p>
+		 * If <code>digestedObjectType</code> is not {@link #publicKeyCert} or
+		 * {@link #publicKey} <code>otherObjectTypeID</code> must be given,
+		 * otherwise it is ignored.</p>
+		 * 
+		 * @param digestedObjectType The digest object type.
+		 * @param otherObjectTypeID The object type ID for
+		 *            <code>otherObjectDigest</code>.
+		 * @param digestAlgorithm The algorithm identifier for the hash.
+		 * @param objectDigest The hash value.
+		 */
+		public ObjectDigestInfo(
+			int					digestedObjectType,
+			string				otherObjectTypeID,
+			AlgorithmIdentifier	digestAlgorithm,
+			byte[]				objectDigest)
+		{
+			this.digestedObjectType = new DerEnumerated(digestedObjectType);
+
+			if (digestedObjectType == OtherObjectDigest)
+			{
+				this.otherObjectTypeID = new DerObjectIdentifier(otherObjectTypeID);
+			}
+
+			this.digestAlgorithm = digestAlgorithm; 
+
+			this.objectDigest = new DerBitString(objectDigest);
+		}
+
+		private ObjectDigestInfo(
+			Asn1Sequence seq)
+        {
+			if (seq.Count > 4 || seq.Count < 3)
+			{
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+			}
+
+			digestedObjectType = DerEnumerated.GetInstance(seq[0]);
+
+			int offset = 0;
+
+			if (seq.Count == 4)
+            {
+                otherObjectTypeID = DerObjectIdentifier.GetInstance(seq[1]);
+                offset++;
+            }
+
+			digestAlgorithm = AlgorithmIdentifier.GetInstance(seq[1 + offset]);
+			objectDigest = DerBitString.GetInstance(seq[2 + offset]);
+		}
+
+		public DerEnumerated DigestedObjectType
+		{
+			get { return digestedObjectType; }
+		}
+
+		public DerObjectIdentifier OtherObjectTypeID
+		{
+			get { return otherObjectTypeID; }
+		}
+
+		public AlgorithmIdentifier DigestAlgorithm
+		{
+			get { return digestAlgorithm; }
+		}
+
+		public DerBitString ObjectDigest
+		{
+			get { return objectDigest; }
+		}
+
+		/**
+		 * Produce an object suitable for an Asn1OutputStream.
+		 * 
+		 * <pre>
+		 *  
+		 *    ObjectDigestInfo ::= SEQUENCE {
+		 *         digestedObjectType  ENUMERATED {
+		 *                 publicKey            (0),
+		 *                 publicKeyCert        (1),
+		 *                 otherObjectTypes     (2) },
+		 *                         -- otherObjectTypes MUST NOT
+		 *                         -- be used in this profile
+		 *         otherObjectTypeID   OBJECT IDENTIFIER OPTIONAL,
+		 *         digestAlgorithm     AlgorithmIdentifier,
+		 *         objectDigest        BIT STRING
+		 *    }
+		 *   
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(digestedObjectType);
+
+			if (otherObjectTypeID != null)
+            {
+                v.Add(otherObjectTypeID);
+            }
+
+			v.Add(digestAlgorithm, objectDigest);
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/PolicyInformation.cs b/crypto/src/asn1/x509/PolicyInformation.cs
new file mode 100644
index 000000000..29d245084
--- /dev/null
+++ b/crypto/src/asn1/x509/PolicyInformation.cs
@@ -0,0 +1,80 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class PolicyInformation
+        : Asn1Encodable
+    {
+        private readonly DerObjectIdentifier	policyIdentifier;
+        private readonly Asn1Sequence			policyQualifiers;
+
+		private PolicyInformation(
+            Asn1Sequence seq)
+        {
+			if (seq.Count < 1 || seq.Count > 2)
+			{
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+			}
+
+			policyIdentifier = DerObjectIdentifier.GetInstance(seq[0]);
+
+			if (seq.Count > 1)
+			{
+				policyQualifiers = Asn1Sequence.GetInstance(seq[1]);
+			}
+        }
+
+		public PolicyInformation(
+            DerObjectIdentifier policyIdentifier)
+        {
+            this.policyIdentifier = policyIdentifier;
+        }
+
+		public PolicyInformation(
+            DerObjectIdentifier	policyIdentifier,
+            Asn1Sequence		policyQualifiers)
+        {
+            this.policyIdentifier = policyIdentifier;
+            this.policyQualifiers = policyQualifiers;
+        }
+
+		public static PolicyInformation GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is PolicyInformation)
+            {
+                return (PolicyInformation) obj;
+            }
+
+			return new PolicyInformation(Asn1Sequence.GetInstance(obj));
+        }
+
+		public DerObjectIdentifier PolicyIdentifier
+		{
+			get { return policyIdentifier; }
+		}
+
+		public Asn1Sequence PolicyQualifiers
+		{
+			get { return policyQualifiers; }
+		}
+
+		/*
+         * PolicyInformation ::= Sequence {
+         *      policyIdentifier   CertPolicyId,
+         *      policyQualifiers   Sequence SIZE (1..MAX) OF
+         *              PolicyQualifierInfo OPTIONAL }
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(policyIdentifier);
+
+			if (policyQualifiers != null)
+            {
+                v.Add(policyQualifiers);
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/PolicyMappings.cs b/crypto/src/asn1/x509/PolicyMappings.cs
new file mode 100644
index 000000000..3ad351107
--- /dev/null
+++ b/crypto/src/asn1/x509/PolicyMappings.cs
@@ -0,0 +1,70 @@
+using System.Collections;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * PolicyMappings V3 extension, described in RFC3280.
+	 * <pre>
+	 *    PolicyMappings ::= Sequence SIZE (1..MAX) OF Sequence {
+	 *      issuerDomainPolicy      CertPolicyId,
+	 *      subjectDomainPolicy     CertPolicyId }
+	 * </pre>
+	 *
+	 * @see <a href="http://www.faqs.org/rfc/rfc3280.txt">RFC 3280, section 4.2.1.6</a>
+	 */
+	public class PolicyMappings
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence seq;
+
+		/**
+		 * Creates a new <code>PolicyMappings</code> instance.
+		 *
+		 * @param seq an <code>Asn1Sequence</code> constructed as specified
+		 * in RFC 3280
+		 */
+		public PolicyMappings(
+			Asn1Sequence seq)
+		{
+			this.seq = seq;
+		}
+
+#if !SILVERLIGHT
+        public PolicyMappings(
+            Hashtable mappings)
+            : this((IDictionary)mappings)
+        {
+        }
+#endif
+
+        /**
+		 * Creates a new <code>PolicyMappings</code> instance.
+		 *
+		 * @param mappings a <code>HashMap</code> value that maps
+		 * <code>string</code> oids
+		 * to other <code>string</code> oids.
+		 */
+		public PolicyMappings(
+			IDictionary mappings)
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			foreach (string idp in mappings.Keys)
+			{
+				string sdp = (string) mappings[idp];
+
+				v.Add(
+					new DerSequence(
+						new DerObjectIdentifier(idp),
+						new DerObjectIdentifier(sdp)));
+			}
+
+			seq = new DerSequence(v);
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return seq;
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/PolicyQualifierId.cs b/crypto/src/asn1/x509/PolicyQualifierId.cs
new file mode 100644
index 000000000..c858f0864
--- /dev/null
+++ b/crypto/src/asn1/x509/PolicyQualifierId.cs
@@ -0,0 +1,28 @@
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * PolicyQualifierId, used in the CertificatePolicies
+	 * X509V3 extension.
+	 *
+	 * <pre>
+	 *    id-qt          OBJECT IDENTIFIER ::=  { id-pkix 2 }
+	 *    id-qt-cps      OBJECT IDENTIFIER ::=  { id-qt 1 }
+	 *    id-qt-unotice  OBJECT IDENTIFIER ::=  { id-qt 2 }
+	 *  PolicyQualifierId ::=
+	 *       OBJECT IDENTIFIER ( id-qt-cps | id-qt-unotice )
+	 * </pre>
+	 */
+	public sealed class PolicyQualifierID : DerObjectIdentifier
+	{
+		private const string IdQt = "1.3.6.1.5.5.7.2";
+
+		private PolicyQualifierID(
+			string id)
+			: base(id)
+		{
+		}
+
+		public static readonly PolicyQualifierID IdQtCps = new PolicyQualifierID(IdQt + ".1");
+		public static readonly PolicyQualifierID IdQtUnotice = new PolicyQualifierID(IdQt + ".2");
+	}
+}
diff --git a/crypto/src/asn1/x509/PolicyQualifierInfo.cs b/crypto/src/asn1/x509/PolicyQualifierInfo.cs
new file mode 100644
index 000000000..f2c617ff6
--- /dev/null
+++ b/crypto/src/asn1/x509/PolicyQualifierInfo.cs
@@ -0,0 +1,101 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * Policy qualifiers, used in the X509V3 CertificatePolicies
+	 * extension.
+	 *
+	 * <pre>
+	 *   PolicyQualifierInfo ::= Sequence {
+	 *       policyQualifierId  PolicyQualifierId,
+	 *       qualifier          ANY DEFINED BY policyQualifierId }
+	 * </pre>
+	 */
+	public class PolicyQualifierInfo
+		: Asn1Encodable
+	{
+		internal readonly DerObjectIdentifier	policyQualifierId;
+		internal readonly Asn1Encodable			qualifier;
+
+		/**
+		 * Creates a new <code>PolicyQualifierInfo</code> instance.
+		 *
+		 * @param policyQualifierId a <code>PolicyQualifierId</code> value
+		 * @param qualifier the qualifier, defined by the above field.
+		 */
+		public PolicyQualifierInfo(
+			DerObjectIdentifier	policyQualifierId,
+			Asn1Encodable		qualifier)
+		{
+			this.policyQualifierId = policyQualifierId;
+			this.qualifier = qualifier;
+		}
+
+		/**
+		 * Creates a new <code>PolicyQualifierInfo</code> containing a
+		 * cPSuri qualifier.
+		 *
+		 * @param cps the CPS (certification practice statement) uri as a
+		 * <code>string</code>.
+		 */
+		public PolicyQualifierInfo(
+			string cps)
+		{
+			policyQualifierId = PolicyQualifierID.IdQtCps;
+			qualifier = new DerIA5String(cps);
+		}
+
+		/**
+		 * Creates a new <code>PolicyQualifierInfo</code> instance.
+		 *
+		 * @param as <code>PolicyQualifierInfo</code> X509 structure
+		 * encoded as an Asn1Sequence.
+		 */
+		private PolicyQualifierInfo(
+			Asn1Sequence seq)
+		{
+			if (seq.Count != 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			policyQualifierId = DerObjectIdentifier.GetInstance(seq[0]);
+			qualifier = seq[1];
+		}
+
+		public static PolicyQualifierInfo GetInstance(
+			object obj)
+		{
+			if (obj is PolicyQualifierInfo)
+			{
+				return (PolicyQualifierInfo) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new PolicyQualifierInfo((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+		}
+
+        public virtual DerObjectIdentifier PolicyQualifierId
+        {
+            get { return policyQualifierId; }
+        }
+
+        public virtual Asn1Encodable Qualifier
+        {
+            get { return qualifier; }
+        }
+
+        /**
+		 * Returns a Der-encodable representation of this instance.
+		 *
+		 * @return a <code>Asn1Object</code> value
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(policyQualifierId, qualifier);
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/PrivateKeyUsagePeriod.cs b/crypto/src/asn1/x509/PrivateKeyUsagePeriod.cs
new file mode 100644
index 000000000..ad2961eb0
--- /dev/null
+++ b/crypto/src/asn1/x509/PrivateKeyUsagePeriod.cs
@@ -0,0 +1,82 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/// <remarks>
+	/// <pre>
+	/// PrivateKeyUsagePeriod ::= SEQUENCE
+	/// {
+	/// notBefore       [0]     GeneralizedTime OPTIONAL,
+	/// notAfter        [1]     GeneralizedTime OPTIONAL }
+	/// </pre>
+	/// </remarks>
+	public class PrivateKeyUsagePeriod
+		: Asn1Encodable
+	{
+		public static PrivateKeyUsagePeriod GetInstance(
+			object obj)
+		{
+			if (obj is PrivateKeyUsagePeriod)
+			{
+				return (PrivateKeyUsagePeriod) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new PrivateKeyUsagePeriod((Asn1Sequence) obj);
+			}
+
+			if (obj is X509Extension)
+			{
+				return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj));
+			}
+
+			throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+		}
+
+		private DerGeneralizedTime _notBefore, _notAfter;
+
+		private PrivateKeyUsagePeriod(
+			Asn1Sequence seq)
+		{
+			foreach (Asn1TaggedObject tObj in seq)
+			{
+				if (tObj.TagNo == 0)
+				{
+					_notBefore = DerGeneralizedTime.GetInstance(tObj, false);
+				}
+				else if (tObj.TagNo == 1)
+				{
+					_notAfter = DerGeneralizedTime.GetInstance(tObj, false);
+				}
+			}
+		}
+
+		public DerGeneralizedTime NotBefore
+		{
+			get { return _notBefore; }
+		}
+
+		public DerGeneralizedTime NotAfter
+		{
+			get { return _notAfter; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (_notBefore != null)
+			{
+				v.Add(new DerTaggedObject(false, 0, _notBefore));
+			}
+
+			if (_notAfter != null)
+			{
+				v.Add(new DerTaggedObject(false, 1, _notAfter));
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/RSAPublicKeyStructure.cs b/crypto/src/asn1/x509/RSAPublicKeyStructure.cs
new file mode 100644
index 000000000..bdcba783e
--- /dev/null
+++ b/crypto/src/asn1/x509/RSAPublicKeyStructure.cs
@@ -0,0 +1,92 @@
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class RsaPublicKeyStructure
+        : Asn1Encodable
+    {
+        private BigInteger modulus;
+        private BigInteger publicExponent;
+
+		public static RsaPublicKeyStructure GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static RsaPublicKeyStructure GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is RsaPublicKeyStructure)
+            {
+                return (RsaPublicKeyStructure) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new RsaPublicKeyStructure((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("Invalid RsaPublicKeyStructure: " + obj.GetType().Name);
+        }
+
+		public RsaPublicKeyStructure(
+            BigInteger	modulus,
+            BigInteger	publicExponent)
+        {
+			if (modulus == null)
+				throw new ArgumentNullException("modulus");
+			if (publicExponent == null)
+				throw new ArgumentNullException("publicExponent");
+			if (modulus.SignValue <= 0)
+				throw new ArgumentException("Not a valid RSA modulus", "modulus");
+			if (publicExponent.SignValue <= 0)
+				throw new ArgumentException("Not a valid RSA public exponent", "publicExponent");
+
+            this.modulus = modulus;
+            this.publicExponent = publicExponent;
+        }
+
+		private RsaPublicKeyStructure(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+			// Note: we are accepting technically incorrect (i.e. negative) values here
+			modulus = DerInteger.GetInstance(seq[0]).PositiveValue;
+			publicExponent = DerInteger.GetInstance(seq[1]).PositiveValue;
+		}
+
+		public BigInteger Modulus
+        {
+            get { return modulus; }
+        }
+
+		public BigInteger PublicExponent
+        {
+            get { return publicExponent; }
+        }
+
+		/**
+         * This outputs the key in Pkcs1v2 format.
+         * <pre>
+         *      RSAPublicKey ::= Sequence {
+         *                          modulus Integer, -- n
+         *                          publicExponent Integer, -- e
+         *                      }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(
+				new DerInteger(Modulus),
+				new DerInteger(PublicExponent));
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/ReasonFlags.cs b/crypto/src/asn1/x509/ReasonFlags.cs
new file mode 100644
index 000000000..f204c36aa
--- /dev/null
+++ b/crypto/src/asn1/x509/ReasonFlags.cs
@@ -0,0 +1,46 @@
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The ReasonFlags object.
+     * <pre>
+     * ReasonFlags ::= BIT STRING {
+     *    unused(0),
+     *    keyCompromise(1),
+     *    cACompromise(2),
+     *    affiliationChanged(3),
+     *    superseded(4),
+     *    cessationOfOperation(5),
+     *    certficateHold(6)
+     * }
+     * </pre>
+     */
+    public class ReasonFlags
+        : DerBitString
+    {
+        public const int Unused                 = (1 << 7);
+        public const int KeyCompromise          = (1 << 6);
+        public const int CACompromise           = (1 << 5);
+        public const int AffiliationChanged     = (1 << 4);
+        public const int Superseded             = (1 << 3);
+        public const int CessationOfOperation   = (1 << 2);
+        public const int CertificateHold        = (1 << 1);
+        public const int PrivilegeWithdrawn     = (1 << 0);
+        public const int AACompromise           = (1 << 15);
+
+		/**
+         * @param reasons - the bitwise OR of the Key Reason flags giving the
+         * allowed uses for the key.
+         */
+        public ReasonFlags(
+            int reasons)
+             : base(GetBytes(reasons), GetPadBits(reasons))
+        {
+        }
+
+		public ReasonFlags(
+            DerBitString reasons)
+             : base(reasons.GetBytes(), reasons.PadBits)
+        {
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/RoleSyntax.cs b/crypto/src/asn1/x509/RoleSyntax.cs
new file mode 100644
index 000000000..48c3c6cae
--- /dev/null
+++ b/crypto/src/asn1/x509/RoleSyntax.cs
@@ -0,0 +1,230 @@
+using System;
+using System.Text;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	* Implementation of the RoleSyntax object as specified by the RFC3281.
+	*
+	* <pre>
+	* RoleSyntax ::= SEQUENCE {
+	*                 roleAuthority  [0] GeneralNames OPTIONAL,
+	*                 roleName       [1] GeneralName
+	*           }
+	* </pre>
+	*/
+	public class RoleSyntax
+		: Asn1Encodable
+	{
+		private readonly GeneralNames	roleAuthority;
+		private readonly GeneralName	roleName;
+
+		/**
+		 * RoleSyntax factory method.
+		 * @param obj the object used to construct an instance of <code>
+		 * RoleSyntax</code>. It must be an instance of <code>RoleSyntax
+		 * </code> or <code>Asn1Sequence</code>.
+		 * @return the instance of <code>RoleSyntax</code> built from the
+		 * supplied object.
+		 * @throws java.lang.ArgumentException if the object passed
+		 * to the factory is not an instance of <code>RoleSyntax</code> or
+		 * <code>Asn1Sequence</code>.
+		 */
+		public static RoleSyntax GetInstance(
+			object obj)
+		{
+			if (obj is RoleSyntax)
+				return (RoleSyntax)obj;
+
+			if (obj != null)
+				return new RoleSyntax(Asn1Sequence.GetInstance(obj));
+
+			return null;
+		}
+
+		/**
+		* Constructor.
+		* @param roleAuthority the role authority of this RoleSyntax.
+		* @param roleName    the role name of this RoleSyntax.
+		*/
+		public RoleSyntax(
+			GeneralNames	roleAuthority,
+			GeneralName		roleName)
+		{
+			if (roleName == null
+				|| roleName.TagNo != GeneralName.UniformResourceIdentifier
+				|| ((IAsn1String) roleName.Name).GetString().Equals(""))
+			{
+				throw new ArgumentException("the role name MUST be non empty and MUST " +
+					"use the URI option of GeneralName");
+			}
+
+			this.roleAuthority = roleAuthority;
+			this.roleName = roleName;
+		}
+
+		/**
+		* Constructor. Invoking this constructor is the same as invoking
+		* <code>new RoleSyntax(null, roleName)</code>.
+		* @param roleName    the role name of this RoleSyntax.
+		*/
+		public RoleSyntax(
+			GeneralName roleName)
+			: this(null, roleName)
+		{
+		}
+
+		/**
+		* Utility constructor. Takes a <code>string</code> argument representing
+		* the role name, builds a <code>GeneralName</code> to hold the role name
+		* and calls the constructor that takes a <code>GeneralName</code>.
+		* @param roleName
+		*/
+		public RoleSyntax(
+			string roleName)
+			: this(new GeneralName(GeneralName.UniformResourceIdentifier,
+				(roleName == null)? "": roleName))
+		{
+		}
+
+		/**
+		* Constructor that builds an instance of <code>RoleSyntax</code> by
+		* extracting the encoded elements from the <code>Asn1Sequence</code>
+		* object supplied.
+		* @param seq    an instance of <code>Asn1Sequence</code> that holds
+		* the encoded elements used to build this <code>RoleSyntax</code>.
+		*/
+		private RoleSyntax(
+			Asn1Sequence seq)
+		{
+			if (seq.Count < 1 || seq.Count > 2)
+			{
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+			}
+
+			for (int i = 0; i != seq.Count; i++)
+			{
+				Asn1TaggedObject taggedObject = Asn1TaggedObject.GetInstance(seq[i]);
+				switch (taggedObject.TagNo)
+				{
+					case 0:
+						roleAuthority = GeneralNames.GetInstance(taggedObject, false);
+						break;
+					case 1:
+						roleName = GeneralName.GetInstance(taggedObject, true);
+						break;
+					default:
+						throw new ArgumentException("Unknown tag in RoleSyntax");
+				}
+			}
+		}
+
+		/**
+		* Gets the role authority of this RoleSyntax.
+		* @return    an instance of <code>GeneralNames</code> holding the
+		* role authority of this RoleSyntax.
+		*/
+		public GeneralNames RoleAuthority
+		{
+			get { return this.roleAuthority; }
+		}
+
+		/**
+		* Gets the role name of this RoleSyntax.
+		* @return    an instance of <code>GeneralName</code> holding the
+		* role name of this RoleSyntax.
+		*/
+		public GeneralName RoleName
+		{
+			get { return this.roleName; }
+		}
+
+		/**
+		* Gets the role name as a <code>java.lang.string</code> object.
+		* @return    the role name of this RoleSyntax represented as a
+		* <code>string</code> object.
+		*/
+		public string GetRoleNameAsString()
+		{
+			return ((IAsn1String) this.roleName.Name).GetString();
+		}
+
+		/**
+		* Gets the role authority as a <code>string[]</code> object.
+		* @return the role authority of this RoleSyntax represented as a
+		* <code>string[]</code> array.
+		*/
+		public string[] GetRoleAuthorityAsString()
+		{
+			if (roleAuthority == null)
+			{
+				return new string[0];
+			}
+
+			GeneralName[] names = roleAuthority.GetNames();
+			string[] namesString = new string[names.Length];
+			for(int i = 0; i < names.Length; i++)
+			{
+				Asn1Encodable asn1Value = names[i].Name;
+				if (asn1Value is IAsn1String)
+				{
+					namesString[i] = ((IAsn1String) asn1Value).GetString();
+				}
+				else
+				{
+					namesString[i] = asn1Value.ToString();
+				}
+			}
+
+			return namesString;
+		}
+
+		/**
+		* Implementation of the method <code>ToAsn1Object</code> as
+		* required by the superclass <code>ASN1Encodable</code>.
+		*
+		* <pre>
+		* RoleSyntax ::= SEQUENCE {
+		*                 roleAuthority  [0] GeneralNames OPTIONAL,
+		*                 roleName       [1] GeneralName
+		*           }
+		* </pre>
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (this.roleAuthority != null)
+			{
+				v.Add(new DerTaggedObject(false, 0, roleAuthority));
+			}
+
+			v.Add(new DerTaggedObject(true, 1, roleName));
+
+			return new DerSequence(v);
+		}
+
+		public override string ToString()
+		{
+			StringBuilder buff = new StringBuilder("Name: " + this.GetRoleNameAsString() +
+				" - Auth: ");
+
+			if (this.roleAuthority == null || roleAuthority.GetNames().Length == 0)
+			{
+				buff.Append("N/A");
+			}
+			else
+			{
+				string[] names = this.GetRoleAuthorityAsString();
+				buff.Append('[').Append(names[0]);
+				for(int i = 1; i < names.Length; i++)
+				{
+					buff.Append(", ").Append(names[i]);
+				}
+				buff.Append(']');
+			}
+
+			return buff.ToString();
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/SubjectDirectoryAttributes.cs b/crypto/src/asn1/x509/SubjectDirectoryAttributes.cs
new file mode 100644
index 000000000..fcb30290d
--- /dev/null
+++ b/crypto/src/asn1/x509/SubjectDirectoryAttributes.cs
@@ -0,0 +1,142 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * This extension may contain further X.500 attributes of the subject. See also
+	 * RFC 3039.
+	 *
+	 * <pre>
+	 *     SubjectDirectoryAttributes ::= Attributes
+	 *     Attributes ::= SEQUENCE SIZE (1..MAX) OF Attribute
+	 *     Attribute ::= SEQUENCE
+	 *     {
+	 *       type AttributeType
+	 *       values SET OF AttributeValue
+	 *     }
+	 *
+	 *     AttributeType ::= OBJECT IDENTIFIER
+	 *     AttributeValue ::= ANY DEFINED BY AttributeType
+	 * </pre>
+	 *
+	 * @see org.bouncycastle.asn1.x509.X509Name for AttributeType ObjectIdentifiers.
+	 */
+	public class SubjectDirectoryAttributes
+		: Asn1Encodable
+	{
+		private readonly IList attributes;
+
+		public static SubjectDirectoryAttributes GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is SubjectDirectoryAttributes)
+			{
+				return (SubjectDirectoryAttributes) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new SubjectDirectoryAttributes((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		 * Constructor from Asn1Sequence.
+		 *
+		 * The sequence is of type SubjectDirectoryAttributes:
+		 *
+		 * <pre>
+		 *      SubjectDirectoryAttributes ::= Attributes
+		 *      Attributes ::= SEQUENCE SIZE (1..MAX) OF Attribute
+		 *      Attribute ::= SEQUENCE
+		 *      {
+		 *        type AttributeType
+		 *        values SET OF AttributeValue
+		 *      }
+		 *
+		 *      AttributeType ::= OBJECT IDENTIFIER
+		 *      AttributeValue ::= ANY DEFINED BY AttributeType
+		 * </pre>
+		 *
+		 * @param seq
+		 *            The ASN.1 sequence.
+		 */
+		private SubjectDirectoryAttributes(
+			Asn1Sequence seq)
+		{
+            this.attributes = Platform.CreateArrayList();
+            foreach (object o in seq)
+			{
+				Asn1Sequence s = Asn1Sequence.GetInstance(o);
+				attributes.Add(AttributeX509.GetInstance(s));
+			}
+		}
+
+#if !SILVERLIGHT
+        [Obsolete]
+        public SubjectDirectoryAttributes(
+            ArrayList attributes)
+            : this((IList)attributes)
+        {
+        }
+#endif
+
+        /**
+		 * Constructor from an ArrayList of attributes.
+		 *
+		 * The ArrayList consists of attributes of type {@link Attribute Attribute}
+		 *
+		 * @param attributes The attributes.
+		 *
+		 */
+		public SubjectDirectoryAttributes(
+			IList attributes)
+		{
+            this.attributes = Platform.CreateArrayList(attributes);
+        }
+
+		/**
+		 * Produce an object suitable for an Asn1OutputStream.
+		 *
+		 * Returns:
+		 *
+		 * <pre>
+		 *      SubjectDirectoryAttributes ::= Attributes
+		 *      Attributes ::= SEQUENCE SIZE (1..MAX) OF Attribute
+		 *      Attribute ::= SEQUENCE
+		 *      {
+		 *        type AttributeType
+		 *        values SET OF AttributeValue
+		 *      }
+		 *
+		 *      AttributeType ::= OBJECT IDENTIFIER
+		 *      AttributeValue ::= ANY DEFINED BY AttributeType
+		 * </pre>
+		 *
+		 * @return a DERObject
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+            AttributeX509[] v = new AttributeX509[attributes.Count];
+            for (int i = 0; i < attributes.Count; ++i)
+            {
+                v[i] = (AttributeX509)attributes[i];
+            }
+            return new DerSequence(v);
+		}
+
+        /**
+		 * @return Returns the attributes.
+		 */
+		public IEnumerable Attributes
+		{
+			get { return new EnumerableProxy(attributes); }
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/SubjectKeyIdentifier.cs b/crypto/src/asn1/x509/SubjectKeyIdentifier.cs
new file mode 100644
index 000000000..e640760f3
--- /dev/null
+++ b/crypto/src/asn1/x509/SubjectKeyIdentifier.cs
@@ -0,0 +1,141 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The SubjectKeyIdentifier object.
+     * <pre>
+     * SubjectKeyIdentifier::= OCTET STRING
+     * </pre>
+     */
+    public class SubjectKeyIdentifier
+        : Asn1Encodable
+    {
+        private readonly byte[] keyIdentifier;
+
+		public static SubjectKeyIdentifier GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1OctetString.GetInstance(obj, explicitly));
+        }
+
+		public static SubjectKeyIdentifier GetInstance(
+            object obj)
+        {
+            if (obj is SubjectKeyIdentifier)
+            {
+                return (SubjectKeyIdentifier) obj;
+            }
+
+			if (obj is SubjectPublicKeyInfo)
+            {
+                return new SubjectKeyIdentifier((SubjectPublicKeyInfo) obj);
+            }
+
+			if (obj is Asn1OctetString)
+            {
+                return new SubjectKeyIdentifier((Asn1OctetString) obj);
+            }
+
+			if (obj is X509Extension)
+			{
+				return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj));
+			}
+
+			throw new ArgumentException("Invalid SubjectKeyIdentifier: " + obj.GetType().Name);
+        }
+
+		public SubjectKeyIdentifier(
+            byte[] keyID)
+        {
+			if (keyID == null)
+				throw new ArgumentNullException("keyID");
+
+			this.keyIdentifier = keyID;
+        }
+
+		public SubjectKeyIdentifier(
+            Asn1OctetString keyID)
+        {
+            this.keyIdentifier = keyID.GetOctets();
+        }
+
+		/**
+		 * Calculates the keyIdentifier using a SHA1 hash over the BIT STRING
+		 * from SubjectPublicKeyInfo as defined in RFC3280.
+		 *
+		 * @param spki the subject public key info.
+		 */
+		public SubjectKeyIdentifier(
+			SubjectPublicKeyInfo spki)
+		{
+			this.keyIdentifier = GetDigest(spki);
+		}
+
+		public byte[] GetKeyIdentifier()
+		{
+			return keyIdentifier;
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerOctetString(keyIdentifier);
+		}
+
+		/**
+		 * Return a RFC 3280 type 1 key identifier. As in:
+		 * <pre>
+		 * (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the
+		 * value of the BIT STRING subjectPublicKey (excluding the tag,
+		 * length, and number of unused bits).
+		 * </pre>
+		 * @param keyInfo the key info object containing the subjectPublicKey field.
+		 * @return the key identifier.
+		 */
+		public static SubjectKeyIdentifier CreateSha1KeyIdentifier(
+			SubjectPublicKeyInfo keyInfo)
+		{
+			return new SubjectKeyIdentifier(keyInfo);
+		}
+
+		/**
+		 * Return a RFC 3280 type 2 key identifier. As in:
+		 * <pre>
+		 * (2) The keyIdentifier is composed of a four bit type field with
+		 * the value 0100 followed by the least significant 60 bits of the
+		 * SHA-1 hash of the value of the BIT STRING subjectPublicKey.
+		 * </pre>
+		 * @param keyInfo the key info object containing the subjectPublicKey field.
+		 * @return the key identifier.
+		 */
+		public static SubjectKeyIdentifier CreateTruncatedSha1KeyIdentifier(
+			SubjectPublicKeyInfo keyInfo)
+		{
+			byte[] dig = GetDigest(keyInfo);
+			byte[] id = new byte[8];
+
+			Array.Copy(dig, dig.Length - 8, id, 0, id.Length);
+
+			id[0] &= 0x0f;
+			id[0] |= 0x40;
+
+			return new SubjectKeyIdentifier(id);
+		}
+
+		private static byte[] GetDigest(
+			SubjectPublicKeyInfo spki)
+		{
+            IDigest digest = new Sha1Digest();
+            byte[] resBuf = new byte[digest.GetDigestSize()];
+
+			byte[] bytes = spki.PublicKeyData.GetBytes();
+            digest.BlockUpdate(bytes, 0, bytes.Length);
+            digest.DoFinal(resBuf, 0);
+            return resBuf;
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/SubjectPublicKeyInfo.cs b/crypto/src/asn1/x509/SubjectPublicKeyInfo.cs
new file mode 100644
index 000000000..8ce4b2762
--- /dev/null
+++ b/crypto/src/asn1/x509/SubjectPublicKeyInfo.cs
@@ -0,0 +1,102 @@
+using System;
+using System.Collections;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The object that contains the public key stored in a certficate.
+     * <p>
+     * The GetEncoded() method in the public keys in the JCE produces a DER
+     * encoded one of these.</p>
+     */
+    public class SubjectPublicKeyInfo
+        : Asn1Encodable
+    {
+        private readonly AlgorithmIdentifier	algID;
+        private readonly DerBitString			keyData;
+
+		public static SubjectPublicKeyInfo GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static SubjectPublicKeyInfo GetInstance(
+            object obj)
+        {
+            if (obj is SubjectPublicKeyInfo)
+                return (SubjectPublicKeyInfo) obj;
+
+			if (obj != null)
+				return new SubjectPublicKeyInfo(Asn1Sequence.GetInstance(obj));
+
+			return null;
+        }
+
+		public SubjectPublicKeyInfo(
+            AlgorithmIdentifier	algID,
+            Asn1Encodable		publicKey)
+        {
+            this.keyData = new DerBitString(publicKey);
+            this.algID = algID;
+        }
+
+		public SubjectPublicKeyInfo(
+            AlgorithmIdentifier	algID,
+            byte[]				publicKey)
+        {
+            this.keyData = new DerBitString(publicKey);
+            this.algID = algID;
+        }
+
+		private SubjectPublicKeyInfo(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+            this.algID = AlgorithmIdentifier.GetInstance(seq[0]);
+			this.keyData = DerBitString.GetInstance(seq[1]);
+		}
+
+		public AlgorithmIdentifier AlgorithmID
+        {
+			get { return algID; }
+        }
+
+		/**
+         * for when the public key is an encoded object - if the bitstring
+         * can't be decoded this routine raises an IOException.
+         *
+         * @exception IOException - if the bit string doesn't represent a Der
+         * encoded object.
+         */
+        public Asn1Object GetPublicKey()
+        {
+			return Asn1Object.FromByteArray(keyData.GetBytes());
+        }
+
+		/**
+         * for when the public key is raw bits...
+         */
+        public DerBitString PublicKeyData
+        {
+			get { return keyData; }
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * SubjectPublicKeyInfo ::= Sequence {
+         *                          algorithm AlgorithmIdentifier,
+         *                          publicKey BIT STRING }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(algID, keyData);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/TBSCertList.cs b/crypto/src/asn1/x509/TBSCertList.cs
new file mode 100644
index 000000000..b5934a230
--- /dev/null
+++ b/crypto/src/asn1/x509/TBSCertList.cs
@@ -0,0 +1,274 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	public class CrlEntry
+		: Asn1Encodable
+	{
+		internal Asn1Sequence	seq;
+		internal DerInteger		userCertificate;
+		internal Time			revocationDate;
+		internal X509Extensions	crlEntryExtensions;
+
+		public CrlEntry(
+			Asn1Sequence seq)
+		{
+			if (seq.Count < 2 || seq.Count > 3)
+			{
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+			}
+
+			this.seq = seq;
+
+			userCertificate = DerInteger.GetInstance(seq[0]);
+			revocationDate = Time.GetInstance(seq[1]);
+		}
+
+		public DerInteger UserCertificate
+		{
+			get { return userCertificate; }
+		}
+
+		public Time RevocationDate
+		{
+			get { return revocationDate; }
+		}
+
+		public X509Extensions Extensions
+		{
+			get
+			{
+				if (crlEntryExtensions == null && seq.Count == 3)
+				{
+					crlEntryExtensions = X509Extensions.GetInstance(seq[2]);
+				}
+
+				return crlEntryExtensions;
+			}
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return seq;
+		}
+	}
+
+	/**
+     * PKIX RFC-2459 - TbsCertList object.
+     * <pre>
+     * TbsCertList  ::=  Sequence  {
+     *      version                 Version OPTIONAL,
+     *                                   -- if present, shall be v2
+     *      signature               AlgorithmIdentifier,
+     *      issuer                  Name,
+     *      thisUpdate              Time,
+     *      nextUpdate              Time OPTIONAL,
+     *      revokedCertificates     Sequence OF Sequence  {
+     *           userCertificate         CertificateSerialNumber,
+     *           revocationDate          Time,
+     *           crlEntryExtensions      Extensions OPTIONAL
+     *                                         -- if present, shall be v2
+     *                                }  OPTIONAL,
+     *      crlExtensions           [0]  EXPLICIT Extensions OPTIONAL
+     *                                         -- if present, shall be v2
+     *                                }
+     * </pre>
+     */
+    public class TbsCertificateList
+        : Asn1Encodable
+    {
+		private class RevokedCertificatesEnumeration
+			: IEnumerable
+		{
+			private readonly IEnumerable en;
+
+			internal RevokedCertificatesEnumeration(
+				IEnumerable en)
+			{
+				this.en = en;
+			}
+
+			public IEnumerator GetEnumerator()
+			{
+				return new RevokedCertificatesEnumerator(en.GetEnumerator());
+			}
+
+			private class RevokedCertificatesEnumerator
+				: IEnumerator
+			{
+				private readonly IEnumerator e;
+
+				internal RevokedCertificatesEnumerator(
+					IEnumerator e)
+				{
+					this.e = e;
+				}
+
+				public bool MoveNext()
+				{
+					return e.MoveNext();
+				}
+
+				public void Reset()
+				{
+					e.Reset();
+				}
+
+				public object Current
+				{
+					get { return new CrlEntry(Asn1Sequence.GetInstance(e.Current)); }
+				}
+			}
+		}
+
+		internal Asn1Sequence			seq;
+		internal DerInteger				version;
+        internal AlgorithmIdentifier	signature;
+        internal X509Name				issuer;
+        internal Time					thisUpdate;
+        internal Time					nextUpdate;
+		internal Asn1Sequence			revokedCertificates;
+		internal X509Extensions			crlExtensions;
+
+		public static TbsCertificateList GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static TbsCertificateList GetInstance(
+            object obj)
+        {
+            TbsCertificateList list = obj as TbsCertificateList;
+
+			if (obj == null || list != null)
+            {
+                return list;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new TbsCertificateList((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+        }
+
+		internal TbsCertificateList(
+            Asn1Sequence seq)
+        {
+			if (seq.Count < 3 || seq.Count > 7)
+			{
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+			}
+
+			int seqPos = 0;
+
+			this.seq = seq;
+
+			if (seq[seqPos] is DerInteger)
+            {
+				version = DerInteger.GetInstance(seq[seqPos++]);
+			}
+            else
+            {
+                version = new DerInteger(0);
+            }
+
+			signature = AlgorithmIdentifier.GetInstance(seq[seqPos++]);
+            issuer = X509Name.GetInstance(seq[seqPos++]);
+            thisUpdate = Time.GetInstance(seq[seqPos++]);
+
+			if (seqPos < seq.Count
+                && (seq[seqPos] is DerUtcTime
+                   || seq[seqPos] is DerGeneralizedTime
+                   || seq[seqPos] is Time))
+            {
+                nextUpdate = Time.GetInstance(seq[seqPos++]);
+            }
+
+			if (seqPos < seq.Count
+                && !(seq[seqPos] is DerTaggedObject))
+            {
+				revokedCertificates = Asn1Sequence.GetInstance(seq[seqPos++]);
+			}
+
+			if (seqPos < seq.Count
+                && seq[seqPos] is DerTaggedObject)
+            {
+				crlExtensions = X509Extensions.GetInstance(seq[seqPos]);
+			}
+        }
+
+		public int Version
+        {
+            get { return version.Value.IntValue + 1; }
+        }
+
+		public DerInteger VersionNumber
+        {
+            get { return version; }
+        }
+
+		public AlgorithmIdentifier Signature
+        {
+            get { return signature; }
+        }
+
+		public X509Name Issuer
+        {
+            get { return issuer; }
+        }
+
+		public Time ThisUpdate
+        {
+            get { return thisUpdate; }
+        }
+
+		public Time NextUpdate
+        {
+            get { return nextUpdate; }
+        }
+
+		public CrlEntry[] GetRevokedCertificates()
+        {
+			if (revokedCertificates == null)
+			{
+				return new CrlEntry[0];
+			}
+
+			CrlEntry[] entries = new CrlEntry[revokedCertificates.Count];
+
+			for (int i = 0; i < entries.Length; i++)
+			{
+				entries[i] = new CrlEntry(Asn1Sequence.GetInstance(revokedCertificates[i]));
+			}
+
+			return entries;
+		}
+
+		public IEnumerable GetRevokedCertificateEnumeration()
+		{
+			if (revokedCertificates == null)
+			{
+				return EmptyEnumerable.Instance;
+			}
+
+			return new RevokedCertificatesEnumeration(revokedCertificates);
+		}
+
+		public X509Extensions Extensions
+        {
+            get { return crlExtensions; }
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+            return seq;
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/TBSCertificateStructure.cs b/crypto/src/asn1/x509/TBSCertificateStructure.cs
new file mode 100644
index 000000000..fc7c39ba2
--- /dev/null
+++ b/crypto/src/asn1/x509/TBSCertificateStructure.cs
@@ -0,0 +1,185 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Pkcs;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The TbsCertificate object.
+     * <pre>
+     * TbsCertificate ::= Sequence {
+     *      version          [ 0 ]  Version DEFAULT v1(0),
+     *      serialNumber            CertificateSerialNumber,
+     *      signature               AlgorithmIdentifier,
+     *      issuer                  Name,
+     *      validity                Validity,
+     *      subject                 Name,
+     *      subjectPublicKeyInfo    SubjectPublicKeyInfo,
+     *      issuerUniqueID    [ 1 ] IMPLICIT UniqueIdentifier OPTIONAL,
+     *      subjectUniqueID   [ 2 ] IMPLICIT UniqueIdentifier OPTIONAL,
+     *      extensions        [ 3 ] Extensions OPTIONAL
+     *      }
+     * </pre>
+     * <p>
+     * Note: issuerUniqueID and subjectUniqueID are both deprecated by the IETF. This class
+     * will parse them, but you really shouldn't be creating new ones.</p>
+     */
+	public class TbsCertificateStructure
+		: Asn1Encodable
+	{
+		internal Asn1Sequence            seq;
+		internal DerInteger              version;
+		internal DerInteger              serialNumber;
+		internal AlgorithmIdentifier     signature;
+		internal X509Name                issuer;
+		internal Time                    startDate, endDate;
+		internal X509Name                subject;
+		internal SubjectPublicKeyInfo    subjectPublicKeyInfo;
+		internal DerBitString            issuerUniqueID;
+		internal DerBitString            subjectUniqueID;
+		internal X509Extensions          extensions;
+
+		public static TbsCertificateStructure GetInstance(
+			Asn1TaggedObject	obj,
+			bool				explicitly)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+		}
+
+		public static TbsCertificateStructure GetInstance(
+			object obj)
+		{
+			if (obj is TbsCertificateStructure)
+				return (TbsCertificateStructure) obj;
+
+			if (obj != null)
+				return new TbsCertificateStructure(Asn1Sequence.GetInstance(obj));
+
+			return null;
+		}
+
+		internal TbsCertificateStructure(
+			Asn1Sequence seq)
+		{
+			int seqStart = 0;
+
+			this.seq = seq;
+
+			//
+			// some certficates don't include a version number - we assume v1
+			//
+			if (seq[0] is DerTaggedObject)
+			{
+				version = DerInteger.GetInstance((Asn1TaggedObject)seq[0], true);
+			}
+			else
+			{
+				seqStart = -1;          // field 0 is missing!
+				version = new DerInteger(0);
+			}
+
+			serialNumber = DerInteger.GetInstance(seq[seqStart + 1]);
+
+			signature = AlgorithmIdentifier.GetInstance(seq[seqStart + 2]);
+			issuer = X509Name.GetInstance(seq[seqStart + 3]);
+
+			//
+			// before and after dates
+			//
+			Asn1Sequence  dates = (Asn1Sequence)seq[seqStart + 4];
+
+			startDate = Time.GetInstance(dates[0]);
+			endDate = Time.GetInstance(dates[1]);
+
+			subject = X509Name.GetInstance(seq[seqStart + 5]);
+
+			//
+			// public key info.
+			//
+			subjectPublicKeyInfo = SubjectPublicKeyInfo.GetInstance(seq[seqStart + 6]);
+
+			for (int extras = seq.Count - (seqStart + 6) - 1; extras > 0; extras--)
+			{
+				DerTaggedObject extra = (DerTaggedObject) seq[seqStart + 6 + extras];
+
+				switch (extra.TagNo)
+				{
+					case 1:
+						issuerUniqueID = DerBitString.GetInstance(extra, false);
+						break;
+					case 2:
+						subjectUniqueID = DerBitString.GetInstance(extra, false);
+						break;
+					case 3:
+						extensions = X509Extensions.GetInstance(extra);
+						break;
+				}
+			}
+		}
+
+		public int Version
+		{
+			get { return version.Value.IntValue + 1; }
+		}
+
+		public DerInteger VersionNumber
+		{
+			get { return version; }
+		}
+
+		public DerInteger SerialNumber
+		{
+			get { return serialNumber; }
+		}
+
+		public AlgorithmIdentifier Signature
+		{
+			get { return signature; }
+		}
+
+		public X509Name Issuer
+		{
+			get { return issuer; }
+		}
+
+		public Time StartDate
+		{
+			get { return startDate; }
+		}
+
+		public Time EndDate
+		{
+			get { return endDate; }
+		}
+
+		public X509Name Subject
+		{
+			get { return subject; }
+		}
+
+		public SubjectPublicKeyInfo SubjectPublicKeyInfo
+		{
+			get { return subjectPublicKeyInfo; }
+		}
+
+		public DerBitString IssuerUniqueID
+		{
+			get { return issuerUniqueID; }
+        }
+
+		public DerBitString SubjectUniqueID
+        {
+			get { return subjectUniqueID; }
+        }
+
+		public X509Extensions Extensions
+        {
+			get { return extensions; }
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+            return seq;
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/Target.cs b/crypto/src/asn1/x509/Target.cs
new file mode 100644
index 000000000..309b28c95
--- /dev/null
+++ b/crypto/src/asn1/x509/Target.cs
@@ -0,0 +1,139 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * Target structure used in target information extension for attribute
+	 * certificates from RFC 3281.
+	 * 
+	 * <pre>
+	 *     Target  ::= CHOICE {
+	 *       targetName          [0] GeneralName,
+	 *       targetGroup         [1] GeneralName,
+	 *       targetCert          [2] TargetCert
+	 *     }
+	 * </pre>
+	 * 
+	 * <p>
+	 * The targetCert field is currently not supported and must not be used
+	 * according to RFC 3281.</p>
+	 */
+	public class Target
+		: Asn1Encodable, IAsn1Choice
+	{
+		public enum Choice
+		{
+			Name = 0,
+			Group = 1
+		};
+
+		private readonly GeneralName targetName;
+		private readonly GeneralName targetGroup;
+
+		/**
+		* Creates an instance of a Target from the given object.
+		* <p>
+		* <code>obj</code> can be a Target or a {@link Asn1TaggedObject}</p>
+		* 
+		* @param obj The object.
+		* @return A Target instance.
+		* @throws ArgumentException if the given object cannot be
+		*             interpreted as Target.
+		*/
+		public static Target GetInstance(
+			object obj)
+		{
+			if (obj is Target)
+			{
+				return (Target) obj;
+			}
+
+			if (obj is Asn1TaggedObject)
+			{
+				return new Target((Asn1TaggedObject) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		 * Constructor from Asn1TaggedObject.
+		 * 
+		 * @param tagObj The tagged object.
+		 * @throws ArgumentException if the encoding is wrong.
+		 */
+		private Target(
+			Asn1TaggedObject tagObj)
+		{
+			switch ((Choice) tagObj.TagNo)
+			{
+				case Choice.Name:	// GeneralName is already a choice so explicit
+					targetName = GeneralName.GetInstance(tagObj, true);
+					break;
+				case Choice.Group:
+					targetGroup = GeneralName.GetInstance(tagObj, true);
+					break;
+				default:
+					throw new ArgumentException("unknown tag: " + tagObj.TagNo);
+			}
+		}
+
+		/**
+		 * Constructor from given details.
+		 * <p>
+		 * Exactly one of the parameters must be not <code>null</code>.</p>
+		 *
+		 * @param type the choice type to apply to the name.
+		 * @param name the general name.
+		 * @throws ArgumentException if type is invalid.
+		 */
+		public Target(
+			Choice		type,
+			GeneralName	name)
+			: this(new DerTaggedObject((int) type, name))
+		{
+		}
+
+		/**
+		 * @return Returns the targetGroup.
+		 */
+		public virtual GeneralName TargetGroup
+		{
+			get { return targetGroup; }
+		}
+
+		/**
+		 * @return Returns the targetName.
+		 */
+		public virtual GeneralName TargetName
+		{
+			get { return targetName; }
+		}
+
+		/**
+		 * Produce an object suitable for an Asn1OutputStream.
+		 * 
+		 * Returns:
+		 * 
+		 * <pre>
+		 *     Target  ::= CHOICE {
+		 *       targetName          [0] GeneralName,
+		 *       targetGroup         [1] GeneralName,
+		 *       targetCert          [2] TargetCert
+		 *     }
+		 * </pre>
+		 * 
+		 * @return an Asn1Object
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			// GeneralName is a choice already so most be explicitly tagged
+			if (targetName != null)
+			{
+				return new DerTaggedObject(true, 0, targetName);
+			}
+
+			return new DerTaggedObject(true, 1, targetGroup);
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/TargetInformation.cs b/crypto/src/asn1/x509/TargetInformation.cs
new file mode 100644
index 000000000..75b18c0c9
--- /dev/null
+++ b/crypto/src/asn1/x509/TargetInformation.cs
@@ -0,0 +1,123 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * Target information extension for attributes certificates according to RFC
+	 * 3281.
+	 * 
+	 * <pre>
+	 *           SEQUENCE OF Targets
+	 * </pre>
+	 * 
+	 */
+	public class TargetInformation
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence targets;
+
+		/**
+		 * Creates an instance of a TargetInformation from the given object.
+		 * <p>
+		 * <code>obj</code> can be a TargetInformation or a {@link Asn1Sequence}</p>
+		 * 
+		 * @param obj The object.
+		 * @return A TargetInformation instance.
+		 * @throws ArgumentException if the given object cannot be interpreted as TargetInformation.
+		 */
+		public static TargetInformation GetInstance(
+			object obj)
+		{
+			if (obj is TargetInformation)
+			{
+				return (TargetInformation) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new TargetInformation((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		 * Constructor from a Asn1Sequence.
+		 * 
+		 * @param seq The Asn1Sequence.
+		 * @throws ArgumentException if the sequence does not contain
+		 *             correctly encoded Targets elements.
+		 */
+		private TargetInformation(
+			Asn1Sequence targets)
+		{
+			this.targets = targets;
+		}
+
+		/**
+		 * Returns the targets in this target information extension.
+		 * <p>
+		 * The ArrayList is cloned before it is returned.</p>
+		 * 
+		 * @return Returns the targets.
+		 */
+		public virtual Targets[] GetTargetsObjects()
+		{
+			Targets[] result = new Targets[targets.Count];
+
+			for (int i = 0; i < targets.Count; ++i)
+			{
+				result[i] = Targets.GetInstance(targets[i]);
+			}
+
+			return result;
+		}
+
+		/**
+		 * Constructs a target information from a single targets element. 
+		 * According to RFC 3281 only one targets element must be produced.
+		 * 
+		 * @param targets A Targets instance.
+		 */
+		public TargetInformation(
+			Targets targets)
+		{
+			this.targets = new DerSequence(targets);
+		}
+
+		/**
+		 * According to RFC 3281 only one targets element must be produced. If
+		 * multiple targets are given they must be merged in
+		 * into one targets element.
+		 *
+		 * @param targets An array with {@link Targets}.
+		 */
+		public TargetInformation(
+			Target[] targets)
+			: this(new Targets(targets))
+		{
+		}
+
+		/**
+		 * Produce an object suitable for an Asn1OutputStream.
+		 * 
+		 * Returns:
+		 * 
+		 * <pre>
+		 *          SEQUENCE OF Targets
+		 * </pre>
+		 * 
+		 * <p>
+		 * According to RFC 3281 only one targets element must be produced. If
+		 * multiple targets are given in the constructor they are merged into one
+		 * targets element. If this was produced from a
+		 * {@link Org.BouncyCastle.Asn1.Asn1Sequence} the encoding is kept.</p>
+		 * 
+		 * @return an Asn1Object
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return targets;
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/Targets.cs b/crypto/src/asn1/x509/Targets.cs
new file mode 100644
index 000000000..3e436d8d8
--- /dev/null
+++ b/crypto/src/asn1/x509/Targets.cs
@@ -0,0 +1,121 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * Targets structure used in target information extension for attribute
+	 * certificates from RFC 3281.
+	 * 
+	 * <pre>
+	 *            Targets ::= SEQUENCE OF Target
+	 *           
+	 *            Target  ::= CHOICE {
+	 *              targetName          [0] GeneralName,
+	 *              targetGroup         [1] GeneralName,
+	 *              targetCert          [2] TargetCert
+	 *            }
+	 *           
+	 *            TargetCert  ::= SEQUENCE {
+	 *              targetCertificate    IssuerSerial,
+	 *              targetName           GeneralName OPTIONAL,
+	 *              certDigestInfo       ObjectDigestInfo OPTIONAL
+	 *            }
+	 * </pre>
+	 * 
+	 * @see org.bouncycastle.asn1.x509.Target
+	 * @see org.bouncycastle.asn1.x509.TargetInformation
+	 */
+	public class Targets
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence targets;
+
+		/**
+		 * Creates an instance of a Targets from the given object.
+		 * <p>
+		 * <code>obj</code> can be a Targets or a {@link Asn1Sequence}</p>
+		 * 
+		 * @param obj The object.
+		 * @return A Targets instance.
+		 * @throws ArgumentException if the given object cannot be interpreted as Target.
+		 */
+		public static Targets GetInstance(
+			object obj)
+		{
+			if (obj is Targets)
+			{
+				return (Targets) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new Targets((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		 * Constructor from Asn1Sequence.
+		 * 
+		 * @param targets The ASN.1 SEQUENCE.
+		 * @throws ArgumentException if the contents of the sequence are
+		 *             invalid.
+		 */
+		private Targets(
+			Asn1Sequence targets)
+		{
+			this.targets = targets;
+		}
+
+		/**
+		 * Constructor from given targets.
+		 * <p>
+		 * The ArrayList is copied.</p>
+		 * 
+		 * @param targets An <code>ArrayList</code> of {@link Target}s.
+		 * @see Target
+		 * @throws ArgumentException if the ArrayList contains not only Targets.
+		 */
+		public Targets(
+			Target[] targets)
+		{
+			this.targets = new DerSequence(targets);
+		}
+
+		/**
+		 * Returns the targets in an <code>ArrayList</code>.
+		 * <p>
+		 * The ArrayList is cloned before it is returned.</p>
+		 * 
+		 * @return Returns the targets.
+		 */
+		public virtual Target[] GetTargets()
+		{
+			Target[] result = new Target[targets.Count];
+
+			for (int i = 0; i < targets.Count; ++i)
+			{
+				result[i] = Target.GetInstance(targets[i]);
+			}
+
+			return result;
+		}
+
+		/**
+		 * Produce an object suitable for an Asn1OutputStream.
+		 * 
+		 * Returns:
+		 * 
+		 * <pre>
+		 *            Targets ::= SEQUENCE OF Target
+		 * </pre>
+		 * 
+		 * @return an Asn1Object
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return targets;
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/Time.cs b/crypto/src/asn1/x509/Time.cs
new file mode 100644
index 000000000..0f2511e6d
--- /dev/null
+++ b/crypto/src/asn1/x509/Time.cs
@@ -0,0 +1,120 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class Time
+        : Asn1Encodable, IAsn1Choice
+    {
+        internal Asn1Object time;
+
+        public static Time GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(obj.GetObject());
+        }
+
+        public Time(
+            Asn1Object time)
+        {
+            if (time == null)
+                throw new ArgumentNullException("time");
+
+            if (!(time is DerUtcTime) && !(time is DerGeneralizedTime))
+            {
+                throw new ArgumentException("unknown object passed to Time");
+            }
+
+            this.time = time;
+        }
+
+        /**
+         * creates a time object from a given date - if the date is between 1950
+         * and 2049 a UTCTime object is Generated, otherwise a GeneralizedTime
+         * is used.
+         */
+        public Time(
+            DateTime date)
+        {
+            string d = date.ToString("yyyyMMddHHmmss") + "Z";
+
+            int year = Int32.Parse(d.Substring(0, 4));
+
+            if (year < 1950 || year > 2049)
+            {
+                time = new DerGeneralizedTime(d);
+            }
+            else
+            {
+                time = new DerUtcTime(d.Substring(2));
+            }
+        }
+
+        public static Time GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is Time)
+                return (Time) obj;
+
+            if (obj is DerUtcTime)
+                return new Time((DerUtcTime) obj);
+
+            if (obj is DerGeneralizedTime)
+                return new Time((DerGeneralizedTime) obj);
+
+            throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+        }
+
+        public string GetTime()
+        {
+            if (time is DerUtcTime)
+            {
+                return ((DerUtcTime) time).AdjustedTimeString;
+            }
+
+            return ((DerGeneralizedTime) time).GetTime();
+        }
+
+        /// <summary>
+        /// Return our time as DateTime.
+        /// </summary>
+        /// <returns>A date time.</returns>
+        public DateTime ToDateTime()
+        {
+            try
+            {
+                if (time is DerUtcTime)
+                {
+                    return ((DerUtcTime)time).ToAdjustedDateTime();
+                }
+                else
+                {
+                    return ((DerGeneralizedTime)time).ToDateTime();
+                }
+            }
+            catch (FormatException e)
+            {
+                // this should never happen
+                throw new InvalidOperationException("invalid date string: " + e.Message);
+            }
+        }
+
+        /**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * Time ::= CHOICE {
+         *             utcTime        UTCTime,
+         *             generalTime    GeneralizedTime }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return time;
+        }
+
+        public override string ToString()
+        {
+            return GetTime();
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/UserNotice.cs b/crypto/src/asn1/x509/UserNotice.cs
new file mode 100644
index 000000000..2878a180f
--- /dev/null
+++ b/crypto/src/asn1/x509/UserNotice.cs
@@ -0,0 +1,104 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * <code>UserNotice</code> class, used in
+     * <code>CertificatePolicies</code> X509 extensions (in policy
+     * qualifiers).
+     * <pre>
+     * UserNotice ::= Sequence {
+     *      noticeRef        NoticeReference OPTIONAL,
+     *      explicitText     DisplayText OPTIONAL}
+     *
+     * </pre>
+     *
+     * @see PolicyQualifierId
+     * @see PolicyInformation
+     */
+    public class UserNotice
+        : Asn1Encodable
+    {
+        internal NoticeReference	noticeRef;
+        internal DisplayText		explicitText;
+
+		/**
+         * Creates a new <code>UserNotice</code> instance.
+         *
+         * @param noticeRef a <code>NoticeReference</code> value
+         * @param explicitText a <code>DisplayText</code> value
+         */
+        public UserNotice(
+            NoticeReference	noticeRef,
+            DisplayText		explicitText)
+        {
+            this.noticeRef = noticeRef;
+            this.explicitText = explicitText;
+        }
+
+		/**
+         * Creates a new <code>UserNotice</code> instance.
+         *
+         * @param noticeRef a <code>NoticeReference</code> value
+         * @param str the explicitText field as a string.
+         */
+        public UserNotice(
+            NoticeReference	noticeRef,
+            string			str)
+        {
+            this.noticeRef = noticeRef;
+            this.explicitText = new DisplayText(str);
+        }
+
+		/**
+		 * Creates a new <code>UserNotice</code> instance.
+		 * <p>Useful from reconstructing a <code>UserNotice</code> instance
+		 * from its encodable/encoded form.
+		 *
+		 * @param as an <code>ASN1Sequence</code> value obtained from either
+		 * calling @{link toASN1Object()} for a <code>UserNotice</code>
+		 * instance or from parsing it from a DER-encoded stream.</p>
+		 */
+		public UserNotice(
+			Asn1Sequence seq)
+		{
+			if (seq.Count == 2)
+			{
+				noticeRef = NoticeReference.GetInstance(seq[0]);
+				explicitText = DisplayText.GetInstance(seq[1]);
+			}
+			else if (seq.Count == 1)
+			{
+				if (seq[0].ToAsn1Object() is Asn1Sequence)
+				{
+					noticeRef = NoticeReference.GetInstance(seq[0]);
+				}
+				else
+				{
+					explicitText = DisplayText.GetInstance(seq[0]);
+				}
+			}
+			else
+			{
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+			}
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector av = new Asn1EncodableVector();
+
+			if (noticeRef != null)
+            {
+                av.Add(noticeRef);
+            }
+
+			if (explicitText != null)
+            {
+                av.Add(explicitText);
+            }
+
+			return new DerSequence(av);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/V1TBSCertificateGenerator.cs b/crypto/src/asn1/x509/V1TBSCertificateGenerator.cs
new file mode 100644
index 000000000..20b525a48
--- /dev/null
+++ b/crypto/src/asn1/x509/V1TBSCertificateGenerator.cs
@@ -0,0 +1,108 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * Generator for Version 1 TbsCertificateStructures.
+     * <pre>
+     * TbsCertificate ::= Sequence {
+     *      version          [ 0 ]  Version DEFAULT v1(0),
+     *      serialNumber            CertificateSerialNumber,
+     *      signature               AlgorithmIdentifier,
+     *      issuer                  Name,
+     *      validity                Validity,
+     *      subject                 Name,
+     *      subjectPublicKeyInfo    SubjectPublicKeyInfo,
+     *      }
+     * </pre>
+     *
+     */
+    public class V1TbsCertificateGenerator
+    {
+        internal DerTaggedObject		version = new DerTaggedObject(0, new DerInteger(0));
+        internal DerInteger				serialNumber;
+        internal AlgorithmIdentifier	signature;
+        internal X509Name				issuer;
+        internal Time					startDate, endDate;
+        internal X509Name				subject;
+        internal SubjectPublicKeyInfo	subjectPublicKeyInfo;
+
+		public V1TbsCertificateGenerator()
+        {
+        }
+
+		public void SetSerialNumber(
+            DerInteger serialNumber)
+        {
+            this.serialNumber = serialNumber;
+        }
+
+		public void SetSignature(
+            AlgorithmIdentifier signature)
+        {
+            this.signature = signature;
+        }
+
+		public void SetIssuer(
+            X509Name issuer)
+        {
+            this.issuer = issuer;
+        }
+
+		public void SetStartDate(
+            Time startDate)
+        {
+            this.startDate = startDate;
+        }
+
+		public void SetStartDate(
+            DerUtcTime startDate)
+        {
+            this.startDate = new Time(startDate);
+        }
+
+		public void SetEndDate(
+            Time endDate)
+        {
+            this.endDate = endDate;
+        }
+
+		public void SetEndDate(
+            DerUtcTime endDate)
+        {
+            this.endDate = new Time(endDate);
+        }
+
+		public void SetSubject(
+            X509Name subject)
+        {
+            this.subject = subject;
+        }
+
+		public void SetSubjectPublicKeyInfo(
+            SubjectPublicKeyInfo pubKeyInfo)
+        {
+            this.subjectPublicKeyInfo = pubKeyInfo;
+        }
+
+		public TbsCertificateStructure GenerateTbsCertificate()
+        {
+            if ((serialNumber == null) || (signature == null)
+                || (issuer == null) || (startDate == null) || (endDate == null)
+                || (subject == null) || (subjectPublicKeyInfo == null))
+            {
+                throw new InvalidOperationException("not all mandatory fields set in V1 TBScertificate generator");
+            }
+
+			return new TbsCertificateStructure(
+				new DerSequence(
+					//version, - not required as default value
+					serialNumber,
+					signature,
+					issuer,
+					new DerSequence(startDate, endDate), // before and after dates
+					subject,
+					subjectPublicKeyInfo));
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/V2AttributeCertificateInfoGenerator.cs b/crypto/src/asn1/x509/V2AttributeCertificateInfoGenerator.cs
new file mode 100644
index 000000000..02580b5b8
--- /dev/null
+++ b/crypto/src/asn1/x509/V2AttributeCertificateInfoGenerator.cs
@@ -0,0 +1,137 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * Generator for Version 2 AttributeCertificateInfo
+     * <pre>
+     * AttributeCertificateInfo ::= Sequence {
+     *       version              AttCertVersion -- version is v2,
+     *       holder               Holder,
+     *       issuer               AttCertIssuer,
+     *       signature            AlgorithmIdentifier,
+     *       serialNumber         CertificateSerialNumber,
+     *       attrCertValidityPeriod   AttCertValidityPeriod,
+     *       attributes           Sequence OF Attr,
+     *       issuerUniqueID       UniqueIdentifier OPTIONAL,
+     *       extensions           Extensions OPTIONAL
+     * }
+     * </pre>
+     *
+     */
+    public class V2AttributeCertificateInfoGenerator
+    {
+        internal DerInteger				version;
+        internal Holder					holder;
+        internal AttCertIssuer			issuer;
+        internal AlgorithmIdentifier	signature;
+        internal DerInteger				serialNumber;
+//        internal AttCertValidityPeriod	attrCertValidityPeriod;
+        internal Asn1EncodableVector	attributes;
+        internal DerBitString			issuerUniqueID;
+        internal X509Extensions			extensions;
+        internal DerGeneralizedTime		startDate, endDate;
+
+		public V2AttributeCertificateInfoGenerator()
+        {
+            this.version = new DerInteger(1);
+            attributes = new Asn1EncodableVector();
+        }
+
+		public void SetHolder(
+			Holder holder)
+        {
+            this.holder = holder;
+        }
+
+		public void AddAttribute(
+			string			oid,
+			Asn1Encodable	value)
+        {
+            attributes.Add(new AttributeX509(new DerObjectIdentifier(oid), new DerSet(value)));
+        }
+
+		/**
+         * @param attribute
+         */
+        public void AddAttribute(AttributeX509 attribute)
+        {
+            attributes.Add(attribute);
+        }
+
+		public void SetSerialNumber(
+            DerInteger serialNumber)
+        {
+            this.serialNumber = serialNumber;
+        }
+
+		public void SetSignature(
+            AlgorithmIdentifier signature)
+        {
+            this.signature = signature;
+        }
+
+		public void SetIssuer(
+            AttCertIssuer issuer)
+        {
+            this.issuer = issuer;
+        }
+
+		public void SetStartDate(
+            DerGeneralizedTime startDate)
+        {
+            this.startDate = startDate;
+        }
+
+		public void SetEndDate(
+            DerGeneralizedTime endDate)
+        {
+            this.endDate = endDate;
+        }
+
+		public void SetIssuerUniqueID(
+            DerBitString issuerUniqueID)
+        {
+            this.issuerUniqueID = issuerUniqueID;
+        }
+
+		public void SetExtensions(
+            X509Extensions extensions)
+        {
+            this.extensions = extensions;
+        }
+
+		public AttributeCertificateInfo GenerateAttributeCertificateInfo()
+        {
+            if ((serialNumber == null) || (signature == null)
+                || (issuer == null) || (startDate == null) || (endDate == null)
+                || (holder == null) || (attributes == null))
+            {
+                throw new InvalidOperationException("not all mandatory fields set in V2 AttributeCertificateInfo generator");
+            }
+
+			Asn1EncodableVector v = new Asn1EncodableVector(
+				version, holder, issuer, signature, serialNumber);
+
+			//
+            // before and after dates => AttCertValidityPeriod
+            //
+            v.Add(new AttCertValidityPeriod(startDate, endDate));
+
+			// Attributes
+            v.Add(new DerSequence(attributes));
+
+			if (issuerUniqueID != null)
+            {
+                v.Add(issuerUniqueID);
+            }
+
+			if (extensions != null)
+            {
+                v.Add(extensions);
+            }
+
+			return AttributeCertificateInfo.GetInstance(new DerSequence(v));
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/V2Form.cs b/crypto/src/asn1/x509/V2Form.cs
new file mode 100644
index 000000000..2c6e54a77
--- /dev/null
+++ b/crypto/src/asn1/x509/V2Form.cs
@@ -0,0 +1,137 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class V2Form
+        : Asn1Encodable
+    {
+        internal GeneralNames        issuerName;
+        internal IssuerSerial        baseCertificateID;
+        internal ObjectDigestInfo    objectDigestInfo;
+
+        public static V2Form GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+        public static V2Form GetInstance(object obj)
+        {
+            if (obj is V2Form)
+                return (V2Form)obj;
+            if (obj != null)
+                return new V2Form(Asn1Sequence.GetInstance(obj));
+            return null;
+        }
+
+        public V2Form(GeneralNames issuerName)
+            : this(issuerName, null, null)
+        {
+        }
+
+        public V2Form(GeneralNames issuerName, IssuerSerial baseCertificateID)
+            : this(issuerName, baseCertificateID, null)
+        {
+        }
+
+        public V2Form(GeneralNames issuerName, ObjectDigestInfo objectDigestInfo)
+            : this(issuerName, null, objectDigestInfo)
+        {
+        }
+
+        public V2Form(
+            GeneralNames issuerName,
+            IssuerSerial baseCertificateID,
+            ObjectDigestInfo objectDigestInfo)
+        {
+            this.issuerName = issuerName;
+            this.baseCertificateID = baseCertificateID;
+            this.objectDigestInfo = objectDigestInfo;
+        }
+
+        private V2Form(
+            Asn1Sequence seq)
+        {
+            if (seq.Count > 3)
+            {
+                throw new ArgumentException("Bad sequence size: " + seq.Count);
+            }
+
+            int index = 0;
+
+            if (!(seq[0] is Asn1TaggedObject))
+            {
+                index++;
+                this.issuerName = GeneralNames.GetInstance(seq[0]);
+            }
+
+            for (int i = index; i != seq.Count; i++)
+            {
+                Asn1TaggedObject o = Asn1TaggedObject.GetInstance(seq[i]);
+                if (o.TagNo == 0)
+                {
+                    baseCertificateID = IssuerSerial.GetInstance(o, false);
+                }
+                else if (o.TagNo == 1)
+                {
+                    objectDigestInfo = ObjectDigestInfo.GetInstance(o, false);
+                }
+                else
+                {
+                    throw new ArgumentException("Bad tag number: " + o.TagNo);
+                }
+            }
+        }
+
+        public GeneralNames IssuerName
+        {
+            get { return issuerName; }
+        }
+
+        public IssuerSerial BaseCertificateID
+        {
+            get { return baseCertificateID; }
+        }
+
+        public ObjectDigestInfo ObjectDigestInfo
+        {
+            get { return objectDigestInfo; }
+        }
+
+        /**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *  V2Form ::= Sequence {
+         *       issuerName            GeneralNames  OPTIONAL,
+         *       baseCertificateID     [0] IssuerSerial  OPTIONAL,
+         *       objectDigestInfo      [1] ObjectDigestInfo  OPTIONAL
+         *         -- issuerName MUST be present in this profile
+         *         -- baseCertificateID and objectDigestInfo MUST NOT
+         *         -- be present in this profile
+         *  }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+            if (issuerName != null)
+            {
+                v.Add(issuerName);
+            }
+
+            if (baseCertificateID != null)
+            {
+                v.Add(new DerTaggedObject(false, 0, baseCertificateID));
+            }
+
+            if (objectDigestInfo != null)
+            {
+                v.Add(new DerTaggedObject(false, 1, objectDigestInfo));
+            }
+
+            return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/V2TBSCertListGenerator.cs b/crypto/src/asn1/x509/V2TBSCertListGenerator.cs
new file mode 100644
index 000000000..2c929188f
--- /dev/null
+++ b/crypto/src/asn1/x509/V2TBSCertListGenerator.cs
@@ -0,0 +1,201 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * Generator for Version 2 TbsCertList structures.
+     * <pre>
+     *  TbsCertList  ::=  Sequence  {
+     *       version                 Version OPTIONAL,
+     *                                    -- if present, shall be v2
+     *       signature               AlgorithmIdentifier,
+     *       issuer                  Name,
+     *       thisUpdate              Time,
+     *       nextUpdate              Time OPTIONAL,
+     *       revokedCertificates     Sequence OF Sequence  {
+     *            userCertificate         CertificateSerialNumber,
+     *            revocationDate          Time,
+     *            crlEntryExtensions      Extensions OPTIONAL
+     *                                          -- if present, shall be v2
+     *                                 }  OPTIONAL,
+     *       crlExtensions           [0]  EXPLICIT Extensions OPTIONAL
+     *                                          -- if present, shall be v2
+     *                                 }
+     * </pre>
+     *
+     * <b>Note: This class may be subject to change</b>
+     */
+    public class V2TbsCertListGenerator
+    {
+        private DerInteger			version = new DerInteger(1);
+        private AlgorithmIdentifier	signature;
+        private X509Name			issuer;
+        private Time				thisUpdate, nextUpdate;
+        private X509Extensions		extensions;
+        private IList			    crlEntries;
+
+		public V2TbsCertListGenerator()
+        {
+        }
+
+		public void SetSignature(
+            AlgorithmIdentifier signature)
+        {
+            this.signature = signature;
+        }
+
+		public void SetIssuer(
+            X509Name issuer)
+        {
+            this.issuer = issuer;
+        }
+
+		public void SetThisUpdate(
+            DerUtcTime thisUpdate)
+        {
+            this.thisUpdate = new Time(thisUpdate);
+        }
+
+		public void SetNextUpdate(
+            DerUtcTime nextUpdate)
+        {
+            this.nextUpdate = (nextUpdate != null)
+				?	new Time(nextUpdate)
+				:	null;
+        }
+
+		public void SetThisUpdate(
+            Time thisUpdate)
+        {
+            this.thisUpdate = thisUpdate;
+        }
+
+		public void SetNextUpdate(
+            Time nextUpdate)
+        {
+            this.nextUpdate = nextUpdate;
+        }
+
+		public void AddCrlEntry(
+			Asn1Sequence crlEntry)
+		{
+			if (crlEntries == null)
+			{
+				crlEntries = Platform.CreateArrayList();
+			}
+
+			crlEntries.Add(crlEntry);
+		}
+
+		public void AddCrlEntry(DerInteger userCertificate, DerUtcTime revocationDate, int reason)
+		{
+			AddCrlEntry(userCertificate, new Time(revocationDate), reason);
+		}
+
+		public void AddCrlEntry(DerInteger userCertificate, Time revocationDate, int reason)
+		{
+			AddCrlEntry(userCertificate, revocationDate, reason, null);
+		}
+
+		public void AddCrlEntry(DerInteger userCertificate, Time revocationDate, int reason,
+			DerGeneralizedTime invalidityDate)
+		{
+            IList extOids = Platform.CreateArrayList();
+            IList extValues = Platform.CreateArrayList();
+
+			if (reason != 0)
+			{
+				CrlReason crlReason = new CrlReason(reason);
+
+				try
+				{
+					extOids.Add(X509Extensions.ReasonCode);
+					extValues.Add(new X509Extension(false, new DerOctetString(crlReason.GetEncoded())));
+				}
+				catch (IOException e)
+				{
+					throw new ArgumentException("error encoding reason: " + e);
+				}
+			}
+
+			if (invalidityDate != null)
+			{
+				try
+				{
+					extOids.Add(X509Extensions.InvalidityDate);
+					extValues.Add(new X509Extension(false, new DerOctetString(invalidityDate.GetEncoded())));
+				}
+				catch (IOException e)
+				{
+					throw new ArgumentException("error encoding invalidityDate: " + e);
+				}
+			}
+
+			if (extOids.Count != 0)
+			{
+				AddCrlEntry(userCertificate, revocationDate, new X509Extensions(extOids, extValues));
+			}
+			else
+			{
+				AddCrlEntry(userCertificate, revocationDate, null);
+			}
+		}
+
+		public void AddCrlEntry(DerInteger userCertificate, Time revocationDate, X509Extensions extensions)
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(
+				userCertificate, revocationDate);
+
+			if (extensions != null)
+			{
+				v.Add(extensions);
+			}
+
+			AddCrlEntry(new DerSequence(v));
+		}
+
+		public void SetExtensions(
+            X509Extensions extensions)
+        {
+            this.extensions = extensions;
+        }
+
+		public TbsCertificateList GenerateTbsCertList()
+        {
+            if ((signature == null) || (issuer == null) || (thisUpdate == null))
+            {
+                throw new InvalidOperationException("Not all mandatory fields set in V2 TbsCertList generator.");
+            }
+
+			Asn1EncodableVector v = new Asn1EncodableVector(
+				version, signature, issuer, thisUpdate);
+
+			if (nextUpdate != null)
+            {
+                v.Add(nextUpdate);
+            }
+
+			// Add CRLEntries if they exist
+            if (crlEntries != null)
+            {
+                Asn1Sequence[] certs = new Asn1Sequence[crlEntries.Count];
+                for (int i = 0; i < crlEntries.Count; ++i)
+                {
+                    certs[i] = (Asn1Sequence)crlEntries[i];
+                }
+				v.Add(new DerSequence(certs));
+            }
+
+			if (extensions != null)
+            {
+                v.Add(new DerTaggedObject(0, extensions));
+            }
+
+			return new TbsCertificateList(new DerSequence(v));
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/V3TBSCertificateGenerator.cs b/crypto/src/asn1/x509/V3TBSCertificateGenerator.cs
new file mode 100644
index 000000000..beb469a0d
--- /dev/null
+++ b/crypto/src/asn1/x509/V3TBSCertificateGenerator.cs
@@ -0,0 +1,168 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * Generator for Version 3 TbsCertificateStructures.
+     * <pre>
+     * TbsCertificate ::= Sequence {
+     *      version          [ 0 ]  Version DEFAULT v1(0),
+     *      serialNumber            CertificateSerialNumber,
+     *      signature               AlgorithmIdentifier,
+     *      issuer                  Name,
+     *      validity                Validity,
+     *      subject                 Name,
+     *      subjectPublicKeyInfo    SubjectPublicKeyInfo,
+     *      issuerUniqueID    [ 1 ] IMPLICIT UniqueIdentifier OPTIONAL,
+     *      subjectUniqueID   [ 2 ] IMPLICIT UniqueIdentifier OPTIONAL,
+     *      extensions        [ 3 ] Extensions OPTIONAL
+     *      }
+     * </pre>
+     *
+     */
+    public class V3TbsCertificateGenerator
+    {
+        internal DerTaggedObject         version = new DerTaggedObject(0, new DerInteger(2));
+        internal DerInteger              serialNumber;
+        internal AlgorithmIdentifier     signature;
+        internal X509Name                issuer;
+        internal Time                    startDate, endDate;
+        internal X509Name                subject;
+        internal SubjectPublicKeyInfo    subjectPublicKeyInfo;
+        internal X509Extensions          extensions;
+
+		private bool altNamePresentAndCritical;
+		private DerBitString issuerUniqueID;
+		private DerBitString subjectUniqueID;
+
+		public V3TbsCertificateGenerator()
+        {
+        }
+
+		public void SetSerialNumber(
+            DerInteger serialNumber)
+        {
+            this.serialNumber = serialNumber;
+        }
+
+		public void SetSignature(
+            AlgorithmIdentifier signature)
+        {
+            this.signature = signature;
+        }
+
+		public void SetIssuer(
+            X509Name issuer)
+        {
+            this.issuer = issuer;
+        }
+
+		public void SetStartDate(
+            DerUtcTime startDate)
+        {
+            this.startDate = new Time(startDate);
+        }
+
+		public void SetStartDate(
+            Time startDate)
+        {
+            this.startDate = startDate;
+        }
+
+		public void SetEndDate(
+            DerUtcTime endDate)
+        {
+            this.endDate = new Time(endDate);
+        }
+
+		public void SetEndDate(
+            Time endDate)
+        {
+            this.endDate = endDate;
+        }
+
+		public void SetSubject(
+            X509Name subject)
+        {
+            this.subject = subject;
+        }
+
+		public void SetIssuerUniqueID(
+			DerBitString uniqueID)
+		{
+			this.issuerUniqueID = uniqueID;
+		}
+
+		public void SetSubjectUniqueID(
+			DerBitString uniqueID)
+		{
+			this.subjectUniqueID = uniqueID;
+		}
+
+		public void SetSubjectPublicKeyInfo(
+            SubjectPublicKeyInfo pubKeyInfo)
+        {
+            this.subjectPublicKeyInfo = pubKeyInfo;
+        }
+
+		public void SetExtensions(
+            X509Extensions extensions)
+        {
+            this.extensions = extensions;
+
+			if (extensions != null)
+			{
+				X509Extension altName = extensions.GetExtension(X509Extensions.SubjectAlternativeName);
+
+				if (altName != null && altName.IsCritical)
+				{
+					altNamePresentAndCritical = true;
+				}
+			}
+		}
+
+		public TbsCertificateStructure GenerateTbsCertificate()
+        {
+            if ((serialNumber == null) || (signature == null)
+                || (issuer == null) || (startDate == null) || (endDate == null)
+				|| (subject == null && !altNamePresentAndCritical)
+				|| (subjectPublicKeyInfo == null))
+            {
+                throw new InvalidOperationException("not all mandatory fields set in V3 TBScertificate generator");
+            }
+
+			DerSequence validity = new DerSequence(startDate, endDate); // before and after dates
+
+			Asn1EncodableVector v = new Asn1EncodableVector(
+				version, serialNumber, signature, issuer, validity);
+
+			if (subject != null)
+			{
+				v.Add(subject);
+			}
+			else
+			{
+				v.Add(DerSequence.Empty);
+			}
+
+			v.Add(subjectPublicKeyInfo);
+
+			if (issuerUniqueID != null)
+			{
+				v.Add(new DerTaggedObject(false, 1, issuerUniqueID));
+			}
+
+			if (subjectUniqueID != null)
+			{
+				v.Add(new DerTaggedObject(false, 2, subjectUniqueID));
+			}
+
+			if (extensions != null)
+            {
+                v.Add(new DerTaggedObject(3, extensions));
+            }
+
+			return new TbsCertificateStructure(new DerSequence(v));
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/X509Attributes.cs b/crypto/src/asn1/x509/X509Attributes.cs
new file mode 100644
index 000000000..291329a62
--- /dev/null
+++ b/crypto/src/asn1/x509/X509Attributes.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	public class X509Attributes
+	{
+		public static readonly DerObjectIdentifier RoleSyntax = new DerObjectIdentifier("2.5.4.72");
+	}
+}
diff --git a/crypto/src/asn1/x509/X509CertificateStructure.cs b/crypto/src/asn1/x509/X509CertificateStructure.cs
new file mode 100644
index 000000000..e50d3563b
--- /dev/null
+++ b/crypto/src/asn1/x509/X509CertificateStructure.cs
@@ -0,0 +1,129 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Pkcs;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * an X509Certificate structure.
+     * <pre>
+     *  Certificate ::= Sequence {
+     *      tbsCertificate          TbsCertificate,
+     *      signatureAlgorithm      AlgorithmIdentifier,
+     *      signature               BIT STRING
+     *  }
+     * </pre>
+     */
+    public class X509CertificateStructure
+        : Asn1Encodable
+    {
+        private readonly TbsCertificateStructure	tbsCert;
+        private readonly AlgorithmIdentifier		sigAlgID;
+        private readonly DerBitString				sig;
+
+		public static X509CertificateStructure GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static X509CertificateStructure GetInstance(
+            object obj)
+        {
+            if (obj is X509CertificateStructure)
+                return (X509CertificateStructure)obj;
+
+			if (obj != null)
+				return new X509CertificateStructure(Asn1Sequence.GetInstance(obj));
+
+			return null;
+        }
+
+		public X509CertificateStructure(
+			TbsCertificateStructure	tbsCert,
+			AlgorithmIdentifier		sigAlgID,
+			DerBitString			sig)
+		{
+			if (tbsCert == null)
+				throw new ArgumentNullException("tbsCert");
+			if (sigAlgID == null)
+				throw new ArgumentNullException("sigAlgID");
+			if (sig == null)
+				throw new ArgumentNullException("sig");
+
+			this.tbsCert = tbsCert;
+			this.sigAlgID = sigAlgID;
+			this.sig = sig;
+		}
+
+		private X509CertificateStructure(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 3)
+				throw new ArgumentException("sequence wrong size for a certificate", "seq");
+
+			//
+            // correct x509 certficate
+            //
+			tbsCert = TbsCertificateStructure.GetInstance(seq[0]);
+			sigAlgID = AlgorithmIdentifier.GetInstance(seq[1]);
+			sig = DerBitString.GetInstance(seq[2]);
+        }
+
+		public TbsCertificateStructure TbsCertificate
+        {
+			get { return tbsCert; }
+        }
+
+		public int Version
+        {
+            get { return tbsCert.Version; }
+        }
+
+		public DerInteger SerialNumber
+        {
+            get { return tbsCert.SerialNumber; }
+        }
+
+		public X509Name Issuer
+        {
+            get { return tbsCert.Issuer; }
+        }
+
+		public Time StartDate
+        {
+            get { return tbsCert.StartDate; }
+        }
+
+		public Time EndDate
+        {
+            get { return tbsCert.EndDate; }
+        }
+
+		public X509Name Subject
+        {
+            get { return tbsCert.Subject; }
+        }
+
+		public SubjectPublicKeyInfo SubjectPublicKeyInfo
+        {
+            get { return tbsCert.SubjectPublicKeyInfo; }
+        }
+
+		public AlgorithmIdentifier SignatureAlgorithm
+        {
+            get { return sigAlgID; }
+        }
+
+		public DerBitString Signature
+        {
+            get { return sig; }
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(tbsCert, sigAlgID, sig);
+        }
+	}
+}
diff --git a/crypto/src/asn1/x509/X509DefaultEntryConverter.cs b/crypto/src/asn1/x509/X509DefaultEntryConverter.cs
new file mode 100644
index 000000000..7282ead26
--- /dev/null
+++ b/crypto/src/asn1/x509/X509DefaultEntryConverter.cs
@@ -0,0 +1,63 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The default converter for X509 DN entries when going from their
+     * string value to ASN.1 strings.
+     */
+    public class X509DefaultEntryConverter
+        : X509NameEntryConverter
+    {
+        /**
+         * Apply default conversion for the given value depending on the oid
+         * and the character range of the value.
+         *
+         * @param oid the object identifier for the DN entry
+         * @param value the value associated with it
+         * @return the ASN.1 equivalent for the string value.
+         */
+        public override Asn1Object GetConvertedValue(
+            DerObjectIdentifier	oid,
+            string				value)
+        {
+            if (value.Length != 0 && value[0] == '#')
+            {
+				try
+				{
+					return ConvertHexEncoded(value, 1);
+				}
+				catch (IOException)
+				{
+					throw new Exception("can't recode value for oid " + oid.Id);
+				}
+			}
+
+			if (value.Length != 0 && value[0] == '\\')
+			{
+				value = value.Substring(1);
+			}
+
+			if (oid.Equals(X509Name.EmailAddress) || oid.Equals(X509Name.DC))
+            {
+                return new DerIA5String(value);
+            }
+
+			if (oid.Equals(X509Name.DateOfBirth)) // accept time string as well as # (for compatibility)
+			{
+				return new DerGeneralizedTime(value);
+			}
+
+			if (oid.Equals(X509Name.C)
+				|| oid.Equals(X509Name.SerialNumber)
+				|| oid.Equals(X509Name.DnQualifier)
+				|| oid.Equals(X509Name.TelephoneNumber))
+			{
+				return new DerPrintableString(value);
+			}
+
+			return new DerUtf8String(value);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/X509Extension.cs b/crypto/src/asn1/x509/X509Extension.cs
new file mode 100644
index 000000000..430ce4447
--- /dev/null
+++ b/crypto/src/asn1/x509/X509Extension.cs
@@ -0,0 +1,79 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * an object for the elements in the X.509 V3 extension block.
+     */
+    public class X509Extension
+    {
+        internal bool				critical;
+        internal Asn1OctetString	value;
+
+		public X509Extension(
+            DerBoolean		critical,
+            Asn1OctetString	value)
+        {
+            if (critical == null)
+            {
+                throw new ArgumentNullException("critical");
+            }
+
+			this.critical = critical.IsTrue;
+            this.value = value;
+        }
+
+		public X509Extension(
+            bool			critical,
+            Asn1OctetString	value)
+        {
+            this.critical = critical;
+            this.value = value;
+        }
+
+		public bool IsCritical { get { return critical; } }
+
+		public Asn1OctetString Value { get { return value; } }
+
+		public Asn1Encodable GetParsedValue()
+		{
+			return ConvertValueToObject(this);
+		}
+
+		public override int GetHashCode()
+        {
+			int vh = this.Value.GetHashCode();
+
+			return IsCritical ? vh : ~vh;
+        }
+
+		public override bool Equals(
+            object obj)
+        {
+            X509Extension other = obj as X509Extension;
+            if (other == null)
+            {
+                return false;
+            }
+
+			return Value.Equals(other.Value) && IsCritical == other.IsCritical;
+        }
+
+		/// <sumary>Convert the value of the passed in extension to an object.</sumary>
+		/// <param name="ext">The extension to parse.</param>
+		/// <returns>The object the value string contains.</returns>
+		/// <exception cref="ArgumentException">If conversion is not possible.</exception>
+		public static Asn1Object ConvertValueToObject(
+			X509Extension ext)
+		{
+			try
+			{
+				return Asn1Object.FromByteArray(ext.Value.GetOctets());
+			}
+			catch (Exception e)
+			{
+				throw new ArgumentException("can't convert extension", e);
+			}
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/X509Extensions.cs b/crypto/src/asn1/x509/X509Extensions.cs
new file mode 100644
index 000000000..5dce5622d
--- /dev/null
+++ b/crypto/src/asn1/x509/X509Extensions.cs
@@ -0,0 +1,451 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class X509Extensions
+        : Asn1Encodable
+    {
+		/**
+		 * Subject Directory Attributes
+		 */
+		public static readonly DerObjectIdentifier SubjectDirectoryAttributes = new DerObjectIdentifier("2.5.29.9");
+
+		/**
+         * Subject Key Identifier
+         */
+        public static readonly DerObjectIdentifier SubjectKeyIdentifier = new DerObjectIdentifier("2.5.29.14");
+
+		/**
+         * Key Usage
+         */
+        public static readonly DerObjectIdentifier KeyUsage = new DerObjectIdentifier("2.5.29.15");
+
+		/**
+         * Private Key Usage Period
+         */
+        public static readonly DerObjectIdentifier PrivateKeyUsagePeriod = new DerObjectIdentifier("2.5.29.16");
+
+		/**
+         * Subject Alternative Name
+         */
+        public static readonly DerObjectIdentifier SubjectAlternativeName = new DerObjectIdentifier("2.5.29.17");
+
+		/**
+         * Issuer Alternative Name
+         */
+        public static readonly DerObjectIdentifier IssuerAlternativeName = new DerObjectIdentifier("2.5.29.18");
+
+		/**
+         * Basic Constraints
+         */
+        public static readonly DerObjectIdentifier BasicConstraints = new DerObjectIdentifier("2.5.29.19");
+
+		/**
+         * CRL Number
+         */
+        public static readonly DerObjectIdentifier CrlNumber = new DerObjectIdentifier("2.5.29.20");
+
+		/**
+         * Reason code
+         */
+        public static readonly DerObjectIdentifier ReasonCode = new DerObjectIdentifier("2.5.29.21");
+
+		/**
+         * Hold Instruction Code
+         */
+        public static readonly DerObjectIdentifier InstructionCode = new DerObjectIdentifier("2.5.29.23");
+
+		/**
+         * Invalidity Date
+         */
+        public static readonly DerObjectIdentifier InvalidityDate = new DerObjectIdentifier("2.5.29.24");
+
+		/**
+         * Delta CRL indicator
+         */
+        public static readonly DerObjectIdentifier DeltaCrlIndicator = new DerObjectIdentifier("2.5.29.27");
+
+		/**
+         * Issuing Distribution Point
+         */
+        public static readonly DerObjectIdentifier IssuingDistributionPoint = new DerObjectIdentifier("2.5.29.28");
+
+		/**
+         * Certificate Issuer
+         */
+        public static readonly DerObjectIdentifier CertificateIssuer = new DerObjectIdentifier("2.5.29.29");
+
+		/**
+         * Name Constraints
+         */
+        public static readonly DerObjectIdentifier NameConstraints = new DerObjectIdentifier("2.5.29.30");
+
+		/**
+         * CRL Distribution Points
+         */
+        public static readonly DerObjectIdentifier CrlDistributionPoints = new DerObjectIdentifier("2.5.29.31");
+
+		/**
+         * Certificate Policies
+         */
+        public static readonly DerObjectIdentifier CertificatePolicies = new DerObjectIdentifier("2.5.29.32");
+
+		/**
+         * Policy Mappings
+         */
+        public static readonly DerObjectIdentifier PolicyMappings = new DerObjectIdentifier("2.5.29.33");
+
+		/**
+         * Authority Key Identifier
+         */
+        public static readonly DerObjectIdentifier AuthorityKeyIdentifier = new DerObjectIdentifier("2.5.29.35");
+
+		/**
+         * Policy Constraints
+         */
+        public static readonly DerObjectIdentifier PolicyConstraints = new DerObjectIdentifier("2.5.29.36");
+
+		/**
+         * Extended Key Usage
+         */
+        public static readonly DerObjectIdentifier ExtendedKeyUsage = new DerObjectIdentifier("2.5.29.37");
+
+		/**
+		 * Freshest CRL
+		 */
+		public static readonly DerObjectIdentifier FreshestCrl = new DerObjectIdentifier("2.5.29.46");
+
+		/**
+         * Inhibit Any Policy
+         */
+        public static readonly DerObjectIdentifier InhibitAnyPolicy = new DerObjectIdentifier("2.5.29.54");
+
+		/**
+         * Authority Info Access
+         */
+		public static readonly DerObjectIdentifier AuthorityInfoAccess = new DerObjectIdentifier("1.3.6.1.5.5.7.1.1");
+
+		/**
+		 * Subject Info Access
+		 */
+		public static readonly DerObjectIdentifier SubjectInfoAccess = new DerObjectIdentifier("1.3.6.1.5.5.7.1.11");
+
+		/**
+		 * Logo Type
+		 */
+		public static readonly DerObjectIdentifier LogoType = new DerObjectIdentifier("1.3.6.1.5.5.7.1.12");
+
+		/**
+		 * BiometricInfo
+		 */
+		public static readonly DerObjectIdentifier BiometricInfo = new DerObjectIdentifier("1.3.6.1.5.5.7.1.2");
+
+		/**
+		 * QCStatements
+		 */
+		public static readonly DerObjectIdentifier QCStatements = new DerObjectIdentifier("1.3.6.1.5.5.7.1.3");
+
+		/**
+		 * Audit identity extension in attribute certificates.
+		 */
+		public static readonly DerObjectIdentifier AuditIdentity = new DerObjectIdentifier("1.3.6.1.5.5.7.1.4");
+
+		/**
+		 * NoRevAvail extension in attribute certificates.
+		 */
+		public static readonly DerObjectIdentifier NoRevAvail = new DerObjectIdentifier("2.5.29.56");
+
+		/**
+		 * TargetInformation extension in attribute certificates.
+		 */
+		public static readonly DerObjectIdentifier TargetInformation = new DerObjectIdentifier("2.5.29.55");
+
+        private readonly IDictionary extensions = Platform.CreateHashtable();
+        private readonly IList ordering;
+
+		public static X509Extensions GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static X509Extensions GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is X509Extensions)
+            {
+                return (X509Extensions) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new X509Extensions((Asn1Sequence) obj);
+            }
+
+			if (obj is Asn1TaggedObject)
+            {
+                return GetInstance(((Asn1TaggedObject) obj).GetObject());
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+         * Constructor from Asn1Sequence.
+         *
+         * the extensions are a list of constructed sequences, either with (Oid, OctetString) or (Oid, Boolean, OctetString)
+         */
+        private X509Extensions(
+            Asn1Sequence seq)
+        {
+            this.ordering = Platform.CreateArrayList();
+
+			foreach (Asn1Encodable ae in seq)
+			{
+				Asn1Sequence s = Asn1Sequence.GetInstance(ae.ToAsn1Object());
+
+				if (s.Count < 2 || s.Count > 3)
+					throw new ArgumentException("Bad sequence size: " + s.Count);
+
+				DerObjectIdentifier oid = DerObjectIdentifier.GetInstance(s[0].ToAsn1Object());
+
+				bool isCritical = s.Count == 3
+					&& DerBoolean.GetInstance(s[1].ToAsn1Object()).IsTrue;
+
+				Asn1OctetString octets = Asn1OctetString.GetInstance(s[s.Count - 1].ToAsn1Object());
+
+				extensions.Add(oid, new X509Extension(isCritical, octets));
+				ordering.Add(oid);
+			}
+        }
+
+        /**
+         * constructor from a table of extensions.
+         * <p>
+         * it's is assumed the table contains Oid/string pairs.</p>
+         */
+        public X509Extensions(
+            IDictionary extensions)
+            : this(null, extensions)
+        {
+        }
+
+        /**
+         * Constructor from a table of extensions with ordering.
+         * <p>
+         * It's is assumed the table contains Oid/string pairs.</p>
+         */
+        public X509Extensions(
+            IList       ordering,
+            IDictionary extensions)
+        {
+            if (ordering == null)
+            {
+                this.ordering = Platform.CreateArrayList(extensions.Keys);
+            }
+            else
+            {
+                this.ordering = Platform.CreateArrayList(ordering);
+            }
+
+            foreach (DerObjectIdentifier oid in this.ordering)
+            {
+                this.extensions.Add(oid, (X509Extension)extensions[oid]);
+            }
+        }
+
+        /**
+         * Constructor from two vectors
+         *
+         * @param objectIDs an ArrayList of the object identifiers.
+         * @param values an ArrayList of the extension values.
+         */
+        public X509Extensions(
+            IList oids,
+            IList values)
+        {
+            this.ordering = Platform.CreateArrayList(oids);
+
+            int count = 0;
+            foreach (DerObjectIdentifier oid in this.ordering)
+            {
+                this.extensions.Add(oid, (X509Extension)values[count++]);
+            }
+        }
+
+#if !SILVERLIGHT
+		/**
+         * constructor from a table of extensions.
+         * <p>
+         * it's is assumed the table contains Oid/string pairs.</p>
+         */
+        [Obsolete]
+        public X509Extensions(
+            Hashtable extensions)
+             : this(null, extensions)
+        {
+        }
+
+		/**
+         * Constructor from a table of extensions with ordering.
+         * <p>
+         * It's is assumed the table contains Oid/string pairs.</p>
+         */
+        [Obsolete]
+        public X509Extensions(
+            ArrayList	ordering,
+            Hashtable	extensions)
+        {
+            if (ordering == null)
+            {
+                this.ordering = Platform.CreateArrayList(extensions.Keys);
+            }
+            else
+            {
+                this.ordering = Platform.CreateArrayList(ordering);
+            }
+
+            foreach (DerObjectIdentifier oid in this.ordering)
+			{
+				this.extensions.Add(oid, (X509Extension) extensions[oid]);
+			}
+        }
+
+		/**
+		 * Constructor from two vectors
+		 *
+		 * @param objectIDs an ArrayList of the object identifiers.
+		 * @param values an ArrayList of the extension values.
+		 */
+        [Obsolete]
+		public X509Extensions(
+			ArrayList	oids,
+			ArrayList	values)
+		{
+            this.ordering = Platform.CreateArrayList(oids);
+
+            int count = 0;
+			foreach (DerObjectIdentifier oid in this.ordering)
+			{
+				this.extensions.Add(oid, (X509Extension) values[count++]);
+			}
+		}
+#endif
+
+        [Obsolete("Use ExtensionOids IEnumerable property")]
+		public IEnumerator Oids()
+		{
+			return ExtensionOids.GetEnumerator();
+		}
+
+		/**
+		 * return an Enumeration of the extension field's object ids.
+		 */
+		public IEnumerable ExtensionOids
+        {
+			get { return new EnumerableProxy(ordering); }
+        }
+
+		/**
+         * return the extension represented by the object identifier
+         * passed in.
+         *
+         * @return the extension if it's present, null otherwise.
+         */
+        public X509Extension GetExtension(
+            DerObjectIdentifier oid)
+        {
+             return (X509Extension) extensions[oid];
+        }
+
+		/**
+		 * <pre>
+		 *     Extensions        ::=   SEQUENCE SIZE (1..MAX) OF Extension
+		 *
+		 *     Extension         ::=   SEQUENCE {
+		 *        extnId            EXTENSION.&amp;id ({ExtensionSet}),
+		 *        critical          BOOLEAN DEFAULT FALSE,
+		 *        extnValue         OCTET STRING }
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector	vec = new Asn1EncodableVector();
+
+			foreach (DerObjectIdentifier oid in ordering)
+			{
+                X509Extension ext = (X509Extension) extensions[oid];
+                Asn1EncodableVector	v = new Asn1EncodableVector(oid);
+
+				if (ext.IsCritical)
+                {
+                    v.Add(DerBoolean.True);
+                }
+
+				v.Add(ext.Value);
+
+				vec.Add(new DerSequence(v));
+            }
+
+			return new DerSequence(vec);
+        }
+
+		public bool Equivalent(
+			X509Extensions other)
+		{
+			if (extensions.Count != other.extensions.Count)
+				return false;
+
+			foreach (DerObjectIdentifier oid in extensions.Keys)
+			{
+				if (!extensions[oid].Equals(other.extensions[oid]))
+					return false;
+			}
+
+			return true;
+		}
+
+		public DerObjectIdentifier[] GetExtensionOids()
+		{
+			return ToOidArray(ordering);
+		}
+
+		public DerObjectIdentifier[] GetNonCriticalExtensionOids()
+		{
+			return GetExtensionOids(false);
+		}
+
+		public DerObjectIdentifier[] GetCriticalExtensionOids()
+		{
+			return GetExtensionOids(true);
+		}
+
+		private DerObjectIdentifier[] GetExtensionOids(bool isCritical)
+		{
+			IList oids = Platform.CreateArrayList();
+
+			foreach (DerObjectIdentifier oid in this.ordering)
+            {
+				X509Extension ext = (X509Extension)extensions[oid];
+				if (ext.IsCritical == isCritical)
+				{
+					oids.Add(oid);
+				}
+            }
+
+			return ToOidArray(oids);
+		}
+
+		private static DerObjectIdentifier[] ToOidArray(IList oids)
+		{
+			DerObjectIdentifier[] oidArray = new DerObjectIdentifier[oids.Count];
+			oids.CopyTo(oidArray, 0);
+			return oidArray;
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/X509ExtensionsGenerator.cs b/crypto/src/asn1/x509/X509ExtensionsGenerator.cs
new file mode 100644
index 000000000..d6f567b22
--- /dev/null
+++ b/crypto/src/asn1/x509/X509ExtensionsGenerator.cs
@@ -0,0 +1,81 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/// <remarks>Generator for X.509 extensions</remarks>
+	public class X509ExtensionsGenerator
+	{
+		private IDictionary extensions = Platform.CreateHashtable();
+        private IList extOrdering = Platform.CreateArrayList();
+
+		/// <summary>Reset the generator</summary>
+		public void Reset()
+		{
+            extensions = Platform.CreateHashtable();
+            extOrdering = Platform.CreateArrayList();
+		}
+
+		/// <summary>
+		/// Add an extension with the given oid and the passed in value to be included
+		/// in the OCTET STRING associated with the extension.
+		/// </summary>
+		/// <param name="oid">OID for the extension.</param>
+		/// <param name="critical">True if critical, false otherwise.</param>
+		/// <param name="extValue">The ASN.1 object to be included in the extension.</param>
+		public void AddExtension(
+			DerObjectIdentifier	oid,
+			bool				critical,
+			Asn1Encodable		extValue)
+		{
+			byte[] encoded;
+			try
+			{
+				encoded = extValue.GetDerEncoded();
+			}
+			catch (Exception e)
+			{
+				throw new ArgumentException("error encoding value: " + e);
+			}
+
+			this.AddExtension(oid, critical, encoded);
+		}
+
+		/// <summary>
+		/// Add an extension with the given oid and the passed in byte array to be wrapped
+		/// in the OCTET STRING associated with the extension.
+		/// </summary>
+		/// <param name="oid">OID for the extension.</param>
+		/// <param name="critical">True if critical, false otherwise.</param>
+		/// <param name="extValue">The byte array to be wrapped.</param>
+		public void AddExtension(
+			DerObjectIdentifier	oid,
+			bool				critical,
+			byte[]				extValue)
+		{
+			if (extensions.Contains(oid))
+			{
+				throw new ArgumentException("extension " + oid + " already added");
+			}
+
+			extOrdering.Add(oid);
+			extensions.Add(oid, new X509Extension(critical, new DerOctetString(extValue)));
+		}
+
+		/// <summary>Return true if there are no extension present in this generator.</summary>
+		/// <returns>True if empty, false otherwise</returns>
+		public bool IsEmpty
+		{
+			get { return extOrdering.Count < 1; }
+		}
+
+		/// <summary>Generate an X509Extensions object based on the current state of the generator.</summary>
+		/// <returns>An <c>X509Extensions</c> object</returns>
+		public X509Extensions Generate()
+		{
+			return new X509Extensions(extOrdering, extensions);
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/X509Name.cs b/crypto/src/asn1/x509/X509Name.cs
new file mode 100644
index 000000000..a77707354
--- /dev/null
+++ b/crypto/src/asn1/x509/X509Name.cs
@@ -0,0 +1,1188 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+#if SILVERLIGHT
+using System.Collections.Generic;
+#endif
+
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+    * <pre>
+    *     RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+    *
+    *     RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue
+    *
+    *     AttributeTypeAndValue ::= SEQUENCE {
+    *                                   type  OBJECT IDENTIFIER,
+    *                                   value ANY }
+    * </pre>
+    */
+    public class X509Name
+        : Asn1Encodable
+    {
+        /**
+        * country code - StringType(SIZE(2))
+        */
+        public static readonly DerObjectIdentifier C = new DerObjectIdentifier("2.5.4.6");
+
+        /**
+        * organization - StringType(SIZE(1..64))
+        */
+        public static readonly DerObjectIdentifier O = new DerObjectIdentifier("2.5.4.10");
+
+        /**
+        * organizational unit name - StringType(SIZE(1..64))
+        */
+        public static readonly DerObjectIdentifier OU = new DerObjectIdentifier("2.5.4.11");
+
+        /**
+        * Title
+        */
+        public static readonly DerObjectIdentifier T = new DerObjectIdentifier("2.5.4.12");
+
+        /**
+        * common name - StringType(SIZE(1..64))
+        */
+        public static readonly DerObjectIdentifier CN = new DerObjectIdentifier("2.5.4.3");
+
+		/**
+		* street - StringType(SIZE(1..64))
+		*/
+		public static readonly DerObjectIdentifier Street = new DerObjectIdentifier("2.5.4.9");
+
+		/**
+		* device serial number name - StringType(SIZE(1..64))
+		*/
+		public static readonly DerObjectIdentifier SerialNumber = new DerObjectIdentifier("2.5.4.5");
+
+		/**
+        * locality name - StringType(SIZE(1..64))
+        */
+        public static readonly DerObjectIdentifier L = new DerObjectIdentifier("2.5.4.7");
+
+        /**
+        * state, or province name - StringType(SIZE(1..64))
+        */
+        public static readonly DerObjectIdentifier ST = new DerObjectIdentifier("2.5.4.8");
+
+        /**
+        * Naming attributes of type X520name
+        */
+        public static readonly DerObjectIdentifier Surname = new DerObjectIdentifier("2.5.4.4");
+        public static readonly DerObjectIdentifier GivenName = new DerObjectIdentifier("2.5.4.42");
+        public static readonly DerObjectIdentifier Initials = new DerObjectIdentifier("2.5.4.43");
+        public static readonly DerObjectIdentifier Generation = new DerObjectIdentifier("2.5.4.44");
+        public static readonly DerObjectIdentifier UniqueIdentifier = new DerObjectIdentifier("2.5.4.45");
+
+		/**
+		 * businessCategory - DirectoryString(SIZE(1..128)
+		 */
+		public static readonly DerObjectIdentifier BusinessCategory = new DerObjectIdentifier(
+																	   "2.5.4.15");
+
+		/**
+		 * postalCode - DirectoryString(SIZE(1..40)
+		 */
+		public static readonly DerObjectIdentifier PostalCode = new DerObjectIdentifier(
+																 "2.5.4.17");
+
+		/**
+		 * dnQualifier - DirectoryString(SIZE(1..64)
+		 */
+		public static readonly DerObjectIdentifier DnQualifier = new DerObjectIdentifier(
+														 "2.5.4.46");
+
+		/**
+		 * RFC 3039 Pseudonym - DirectoryString(SIZE(1..64)
+		 */
+		public static readonly DerObjectIdentifier Pseudonym = new DerObjectIdentifier(
+																"2.5.4.65");
+
+		/**
+		 * RFC 3039 DateOfBirth - GeneralizedTime - YYYYMMDD000000Z
+		 */
+		public static readonly DerObjectIdentifier DateOfBirth = new DerObjectIdentifier(
+																  "1.3.6.1.5.5.7.9.1");
+
+		/**
+		 * RFC 3039 PlaceOfBirth - DirectoryString(SIZE(1..128)
+		 */
+		public static readonly DerObjectIdentifier PlaceOfBirth = new DerObjectIdentifier(
+																   "1.3.6.1.5.5.7.9.2");
+
+		/**
+		 * RFC 3039 DateOfBirth - PrintableString (SIZE(1)) -- "M", "F", "m" or "f"
+		 */
+		public static readonly DerObjectIdentifier Gender = new DerObjectIdentifier(
+																   "1.3.6.1.5.5.7.9.3");
+
+		/**
+		 * RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166
+		 * codes only
+		 */
+		public static readonly DerObjectIdentifier CountryOfCitizenship = new DerObjectIdentifier(
+																		   "1.3.6.1.5.5.7.9.4");
+
+		/**
+		 * RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166
+		 * codes only
+		 */
+		public static readonly DerObjectIdentifier CountryOfResidence = new DerObjectIdentifier(
+																		 "1.3.6.1.5.5.7.9.5");
+
+		/**
+		 * ISIS-MTT NameAtBirth - DirectoryString(SIZE(1..64)
+		 */
+		public static readonly DerObjectIdentifier NameAtBirth =  new DerObjectIdentifier("1.3.36.8.3.14");
+
+		/**
+		 * RFC 3039 PostalAddress - SEQUENCE SIZE (1..6) OF
+		 * DirectoryString(SIZE(1..30))
+		 */
+		public static readonly DerObjectIdentifier PostalAddress = new DerObjectIdentifier("2.5.4.16");
+
+		/**
+		 * RFC 2256 dmdName
+		 */
+		public static readonly DerObjectIdentifier DmdName = new DerObjectIdentifier("2.5.4.54");
+
+		/**
+		 * id-at-telephoneNumber
+		 */
+		public static readonly DerObjectIdentifier TelephoneNumber = X509ObjectIdentifiers.id_at_telephoneNumber;
+
+		/**
+		 * id-at-name
+		 */
+		public static readonly DerObjectIdentifier Name = X509ObjectIdentifiers.id_at_name;
+
+		/**
+        * Email address (RSA PKCS#9 extension) - IA5String.
+        * <p>Note: if you're trying to be ultra orthodox, don't use this! It shouldn't be in here.</p>
+        */
+        public static readonly DerObjectIdentifier EmailAddress = PkcsObjectIdentifiers.Pkcs9AtEmailAddress;
+
+        /**
+        * more from PKCS#9
+        */
+        public static readonly DerObjectIdentifier UnstructuredName = PkcsObjectIdentifiers.Pkcs9AtUnstructuredName;
+        public static readonly DerObjectIdentifier UnstructuredAddress = PkcsObjectIdentifiers.Pkcs9AtUnstructuredAddress;
+
+        /**
+        * email address in Verisign certificates
+        */
+        public static readonly DerObjectIdentifier E = EmailAddress;
+
+        /*
+        * others...
+        */
+        public static readonly DerObjectIdentifier DC = new DerObjectIdentifier("0.9.2342.19200300.100.1.25");
+
+        /**
+        * LDAP User id.
+        */
+        public static readonly DerObjectIdentifier UID = new DerObjectIdentifier("0.9.2342.19200300.100.1.1");
+
+        /**
+        * determines whether or not strings should be processed and printed
+        * from back to front.
+        */
+//        public static bool DefaultReverse = false;
+		public static bool DefaultReverse
+		{
+			get { return defaultReverse[0]; }
+			set { defaultReverse[0] = value; }
+		}
+
+		private static readonly bool[] defaultReverse = { false };
+
+#if SILVERLIGHT
+		/**
+		* default look up table translating OID values into their common symbols following
+		* the convention in RFC 2253 with a few extras
+		*/
+		public static readonly IDictionary DefaultSymbols = Platform.CreateHashtable();
+
+		/**
+		 * look up table translating OID values into their common symbols following the convention in RFC 2253
+		 */
+		public static readonly IDictionary RFC2253Symbols = Platform.CreateHashtable();
+
+		/**
+		 * look up table translating OID values into their common symbols following the convention in RFC 1779
+		 *
+		 */
+		public static readonly IDictionary RFC1779Symbols = Platform.CreateHashtable();
+
+        /**
+        * look up table translating common symbols into their OIDS.
+        */
+        public static readonly IDictionary DefaultLookup = Platform.CreateHashtable();
+#else
+        /**
+		* default look up table translating OID values into their common symbols following
+		* the convention in RFC 2253 with a few extras
+		*/
+		public static readonly Hashtable DefaultSymbols = new Hashtable();
+
+		/**
+		 * look up table translating OID values into their common symbols following the convention in RFC 2253
+		 */
+		public static readonly Hashtable RFC2253Symbols = new Hashtable();
+
+		/**
+		 * look up table translating OID values into their common symbols following the convention in RFC 1779
+		 *
+		 */
+		public static readonly Hashtable RFC1779Symbols = new Hashtable();
+
+        /**
+        * look up table translating common symbols into their OIDS.
+        */
+        public static readonly Hashtable DefaultLookup = new Hashtable();
+#endif
+
+        static X509Name()
+        {
+            DefaultSymbols.Add(C, "C");
+            DefaultSymbols.Add(O, "O");
+            DefaultSymbols.Add(T, "T");
+            DefaultSymbols.Add(OU, "OU");
+            DefaultSymbols.Add(CN, "CN");
+            DefaultSymbols.Add(L, "L");
+            DefaultSymbols.Add(ST, "ST");
+            DefaultSymbols.Add(SerialNumber, "SERIALNUMBER");
+            DefaultSymbols.Add(EmailAddress, "E");
+            DefaultSymbols.Add(DC, "DC");
+            DefaultSymbols.Add(UID, "UID");
+			DefaultSymbols.Add(Street, "STREET");
+            DefaultSymbols.Add(Surname, "SURNAME");
+            DefaultSymbols.Add(GivenName, "GIVENNAME");
+            DefaultSymbols.Add(Initials, "INITIALS");
+            DefaultSymbols.Add(Generation, "GENERATION");
+            DefaultSymbols.Add(UnstructuredAddress, "unstructuredAddress");
+            DefaultSymbols.Add(UnstructuredName, "unstructuredName");
+			DefaultSymbols.Add(UniqueIdentifier, "UniqueIdentifier");
+			DefaultSymbols.Add(DnQualifier, "DN");
+			DefaultSymbols.Add(Pseudonym, "Pseudonym");
+			DefaultSymbols.Add(PostalAddress, "PostalAddress");
+			DefaultSymbols.Add(NameAtBirth, "NameAtBirth");
+			DefaultSymbols.Add(CountryOfCitizenship, "CountryOfCitizenship");
+			DefaultSymbols.Add(CountryOfResidence, "CountryOfResidence");
+			DefaultSymbols.Add(Gender, "Gender");
+			DefaultSymbols.Add(PlaceOfBirth, "PlaceOfBirth");
+			DefaultSymbols.Add(DateOfBirth, "DateOfBirth");
+			DefaultSymbols.Add(PostalCode, "PostalCode");
+			DefaultSymbols.Add(BusinessCategory, "BusinessCategory");
+			DefaultSymbols.Add(TelephoneNumber, "TelephoneNumber");
+
+            RFC2253Symbols.Add(C, "C");
+            RFC2253Symbols.Add(O, "O");
+            RFC2253Symbols.Add(OU, "OU");
+            RFC2253Symbols.Add(CN, "CN");
+            RFC2253Symbols.Add(L, "L");
+            RFC2253Symbols.Add(ST, "ST");
+			RFC2253Symbols.Add(Street, "STREET");
+			RFC2253Symbols.Add(DC, "DC");
+            RFC2253Symbols.Add(UID, "UID");
+
+			RFC1779Symbols.Add(C, "C");
+			RFC1779Symbols.Add(O, "O");
+			RFC1779Symbols.Add(OU, "OU");
+			RFC1779Symbols.Add(CN, "CN");
+			RFC1779Symbols.Add(L, "L");
+			RFC1779Symbols.Add(ST, "ST");
+			RFC1779Symbols.Add(Street, "STREET");
+
+			DefaultLookup.Add("c", C);
+            DefaultLookup.Add("o", O);
+            DefaultLookup.Add("t", T);
+            DefaultLookup.Add("ou", OU);
+            DefaultLookup.Add("cn", CN);
+            DefaultLookup.Add("l", L);
+            DefaultLookup.Add("st", ST);
+			DefaultLookup.Add("serialnumber", SerialNumber);
+			DefaultLookup.Add("street", Street);
+			DefaultLookup.Add("emailaddress", E);
+            DefaultLookup.Add("dc", DC);
+            DefaultLookup.Add("e", E);
+            DefaultLookup.Add("uid", UID);
+            DefaultLookup.Add("surname", Surname);
+            DefaultLookup.Add("givenname", GivenName);
+            DefaultLookup.Add("initials", Initials);
+            DefaultLookup.Add("generation", Generation);
+            DefaultLookup.Add("unstructuredaddress", UnstructuredAddress);
+            DefaultLookup.Add("unstructuredname", UnstructuredName);
+			DefaultLookup.Add("uniqueidentifier", UniqueIdentifier);
+			DefaultLookup.Add("dn", DnQualifier);
+			DefaultLookup.Add("pseudonym", Pseudonym);
+			DefaultLookup.Add("postaladdress", PostalAddress);
+			DefaultLookup.Add("nameofbirth", NameAtBirth);
+			DefaultLookup.Add("countryofcitizenship", CountryOfCitizenship);
+			DefaultLookup.Add("countryofresidence", CountryOfResidence);
+			DefaultLookup.Add("gender", Gender);
+			DefaultLookup.Add("placeofbirth", PlaceOfBirth);
+			DefaultLookup.Add("dateofbirth", DateOfBirth);
+			DefaultLookup.Add("postalcode", PostalCode);
+			DefaultLookup.Add("businesscategory", BusinessCategory);
+			DefaultLookup.Add("telephonenumber", TelephoneNumber);
+		}
+
+        private readonly IList ordering = Platform.CreateArrayList();
+		private readonly X509NameEntryConverter converter;
+
+		private IList		    values = Platform.CreateArrayList();
+        private IList           added = Platform.CreateArrayList();
+        private Asn1Sequence	seq;
+
+		/**
+        * Return a X509Name based on the passed in tagged object.
+        *
+        * @param obj tag object holding name.
+        * @param explicitly true if explicitly tagged false otherwise.
+        * @return the X509Name
+        */
+        public static X509Name GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static X509Name GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is X509Name)
+                return (X509Name)obj;
+
+			if (obj != null)
+				return new X509Name(Asn1Sequence.GetInstance(obj));
+
+			throw new ArgumentException("null object in factory", "obj");
+        }
+
+		protected X509Name()
+		{
+		}
+
+		/**
+        * Constructor from Asn1Sequence
+        *
+        * the principal will be a list of constructed sets, each containing an (OID, string) pair.
+        */
+        protected X509Name(
+            Asn1Sequence seq)
+        {
+            this.seq = seq;
+
+			foreach (Asn1Encodable asn1Obj in seq)
+			{
+				Asn1Set asn1Set = Asn1Set.GetInstance(asn1Obj.ToAsn1Object());
+
+				for (int i = 0; i < asn1Set.Count; i++)
+                {
+					Asn1Sequence s = Asn1Sequence.GetInstance(asn1Set[i].ToAsn1Object());
+
+					if (s.Count != 2)
+						throw new ArgumentException("badly sized pair");
+
+					ordering.Add(DerObjectIdentifier.GetInstance(s[0].ToAsn1Object()));
+
+					Asn1Object derValue = s[1].ToAsn1Object();
+					if (derValue is IAsn1String && !(derValue is DerUniversalString))
+					{
+						string v = ((IAsn1String)derValue).GetString();
+						if (v.StartsWith("#"))
+						{
+							v = "\\" + v;
+						}
+
+						values.Add(v);
+					}
+                    else
+                    {
+						values.Add("#" + Hex.ToHexString(derValue.GetEncoded()));
+                    }
+
+					added.Add(i != 0);
+                }
+            }
+        }
+
+#if !SILVERLIGHT
+        [Obsolete]
+        public X509Name(
+            ArrayList ordering,
+            Hashtable attributes)
+            : this(ordering, attributes, new X509DefaultEntryConverter())
+        {
+        }
+#endif
+
+        /**
+        * Constructor from a table of attributes with ordering.
+        * <p>
+        * it's is assumed the table contains OID/string pairs, and the contents
+        * of the table are copied into an internal table as part of the
+        * construction process. The ordering ArrayList should contain the OIDs
+        * in the order they are meant to be encoded or printed in ToString.</p>
+        */
+        public X509Name(
+            IList       ordering,
+            IDictionary attributes)
+            : this(ordering, attributes, new X509DefaultEntryConverter())
+        {
+        }
+
+#if !SILVERLIGHT
+        [Obsolete]
+        public X509Name(
+            ArrayList				ordering,
+            Hashtable				attributes,
+            X509NameEntryConverter	converter)
+            : this((IList)ordering, (IDictionary)attributes, converter)
+        {
+        }
+#endif
+
+		/**
+        * Constructor from a table of attributes with ordering.
+        * <p>
+        * it's is assumed the table contains OID/string pairs, and the contents
+        * of the table are copied into an internal table as part of the
+        * construction process. The ordering ArrayList should contain the OIDs
+        * in the order they are meant to be encoded or printed in ToString.</p>
+        * <p>
+        * The passed in converter will be used to convert the strings into their
+        * ASN.1 counterparts.</p>
+        */
+        public X509Name(
+            IList                   ordering,
+            IDictionary             attributes,
+            X509NameEntryConverter	converter)
+        {
+			this.converter = converter;
+
+			foreach (DerObjectIdentifier oid in ordering)
+			{
+				object attribute = attributes[oid];
+				if (attribute == null)
+				{
+					throw new ArgumentException("No attribute for object id - " + oid + " - passed to distinguished name");
+				}
+
+				this.ordering.Add(oid);
+				this.added.Add(false);
+				this.values.Add(attribute); // copy the hash table
+			}
+        }
+
+#if !SILVERLIGHT
+        [Obsolete]
+        public X509Name(
+            ArrayList oids,
+            ArrayList values)
+            : this(oids, values, new X509DefaultEntryConverter())
+        {
+        }
+#endif
+
+		/**
+        * Takes two vectors one of the oids and the other of the values.
+        */
+        public X509Name(
+            IList   oids,
+            IList   values)
+            : this(oids, values, new X509DefaultEntryConverter())
+        {
+        }
+
+#if !SILVERLIGHT
+        [Obsolete]
+        public X509Name(
+            ArrayList				oids,
+            ArrayList				values,
+            X509NameEntryConverter	converter)
+            : this((IList)oids, (IList)values, converter)
+        {
+        }
+#endif
+
+		/**
+        * Takes two vectors one of the oids and the other of the values.
+        * <p>
+        * The passed in converter will be used to convert the strings into their
+        * ASN.1 counterparts.</p>
+        */
+        public X509Name(
+            IList			    	oids,
+            IList		    		values,
+            X509NameEntryConverter	converter)
+        {
+            this.converter = converter;
+
+			if (oids.Count != values.Count)
+            {
+                throw new ArgumentException("'oids' must be same length as 'values'.");
+            }
+
+			for (int i = 0; i < oids.Count; i++)
+            {
+                this.ordering.Add(oids[i]);
+                this.values.Add(values[i]);
+                this.added.Add(false);
+            }
+        }
+
+//		private static bool IsEncoded(
+//			string s)
+//		{
+//			return s.StartsWith("#");
+//		}
+
+		/**
+        * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+        * some such, converting it into an ordered set of name attributes.
+        */
+        public X509Name(
+            string dirName)
+            : this(DefaultReverse, (IDictionary)DefaultLookup, dirName)
+        {
+        }
+
+		/**
+        * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+        * some such, converting it into an ordered set of name attributes with each
+        * string value being converted to its associated ASN.1 type using the passed
+        * in converter.
+        */
+        public X509Name(
+            string					dirName,
+            X509NameEntryConverter	converter)
+            : this(DefaultReverse, DefaultLookup, dirName, converter)
+        {
+        }
+
+		/**
+        * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+        * some such, converting it into an ordered set of name attributes. If reverse
+        * is true, create the encoded version of the sequence starting from the
+        * last element in the string.
+        */
+        public X509Name(
+            bool	reverse,
+            string	dirName)
+            : this(reverse, (IDictionary)DefaultLookup, dirName)
+        {
+        }
+
+		/**
+        * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+        * some such, converting it into an ordered set of name attributes with each
+        * string value being converted to its associated ASN.1 type using the passed
+        * in converter. If reverse is true the ASN.1 sequence representing the DN will
+        * be built by starting at the end of the string, rather than the start.
+        */
+        public X509Name(
+            bool					reverse,
+            string					dirName,
+            X509NameEntryConverter	converter)
+            : this(reverse, DefaultLookup, dirName, converter)
+        {
+        }
+
+#if !SILVERLIGHT
+        [Obsolete]
+        public X509Name(
+            bool reverse,
+            Hashtable lookUp,
+            string dirName)
+            : this(reverse, lookUp, dirName, new X509DefaultEntryConverter())
+        {
+        }
+#endif
+
+		/**
+        * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+        * some such, converting it into an ordered set of name attributes. lookUp
+        * should provide a table of lookups, indexed by lowercase only strings and
+        * yielding a DerObjectIdentifier, other than that OID. and numeric oids
+        * will be processed automatically.
+        * <br/>
+        * If reverse is true, create the encoded version of the sequence
+        * starting from the last element in the string.
+        * @param reverse true if we should start scanning from the end (RFC 2553).
+        * @param lookUp table of names and their oids.
+        * @param dirName the X.500 string to be parsed.
+        */
+        public X509Name(
+            bool		reverse,
+            IDictionary lookUp,
+            string		dirName)
+            : this(reverse, lookUp, dirName, new X509DefaultEntryConverter())
+        {
+        }
+
+		private DerObjectIdentifier DecodeOid(
+            string		name,
+            IDictionary lookUp)
+        {
+            if (Platform.ToUpperInvariant(name).StartsWith("OID."))
+            {
+                return new DerObjectIdentifier(name.Substring(4));
+            }
+            else if (name[0] >= '0' && name[0] <= '9')
+            {
+                return new DerObjectIdentifier(name);
+            }
+
+			DerObjectIdentifier oid = (DerObjectIdentifier)lookUp[Platform.ToLowerInvariant(name)];
+            if (oid == null)
+            {
+                throw new ArgumentException("Unknown object id - " + name + " - passed to distinguished name");
+            }
+
+			return oid;
+        }
+
+		/**
+        * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+        * some such, converting it into an ordered set of name attributes. lookUp
+        * should provide a table of lookups, indexed by lowercase only strings and
+        * yielding a DerObjectIdentifier, other than that OID. and numeric oids
+        * will be processed automatically. The passed in converter is used to convert the
+        * string values to the right of each equals sign to their ASN.1 counterparts.
+        * <br/>
+        * @param reverse true if we should start scanning from the end, false otherwise.
+        * @param lookUp table of names and oids.
+        * @param dirName the string dirName
+        * @param converter the converter to convert string values into their ASN.1 equivalents
+        */
+        public X509Name(
+            bool					reverse,
+            IDictionary				lookUp,
+            string					dirName,
+            X509NameEntryConverter	converter)
+        {
+            this.converter = converter;
+            X509NameTokenizer nTok = new X509NameTokenizer(dirName);
+
+			while (nTok.HasMoreTokens())
+            {
+                string token = nTok.NextToken();
+                int index = token.IndexOf('=');
+
+				if (index == -1)
+                {
+                    throw new ArgumentException("badly formated directory string");
+                }
+
+				string name = token.Substring(0, index);
+                string value = token.Substring(index + 1);
+                DerObjectIdentifier	oid = DecodeOid(name, lookUp);
+
+				if (value.IndexOf('+') > 0)
+                {
+                    X509NameTokenizer vTok = new X509NameTokenizer(value, '+');
+					string v = vTok.NextToken();
+
+					this.ordering.Add(oid);
+                    this.values.Add(v);
+                    this.added.Add(false);
+
+					while (vTok.HasMoreTokens())
+                    {
+                        string sv = vTok.NextToken();
+                        int ndx = sv.IndexOf('=');
+
+                        string nm = sv.Substring(0, ndx);
+                        string vl = sv.Substring(ndx + 1);
+                        this.ordering.Add(DecodeOid(nm, lookUp));
+                        this.values.Add(vl);
+                        this.added.Add(true);
+                    }
+                }
+                else
+                {
+                    this.ordering.Add(oid);
+                    this.values.Add(value);
+                    this.added.Add(false);
+                }
+            }
+
+			if (reverse)
+            {
+//				this.ordering.Reverse();
+//				this.values.Reverse();
+//				this.added.Reverse();
+				IList o = Platform.CreateArrayList();
+                IList v = Platform.CreateArrayList();
+                IList a = Platform.CreateArrayList();
+				int count = 1;
+
+				for (int i = 0; i < this.ordering.Count; i++)
+				{
+					if (!((bool) this.added[i]))
+					{
+						count = 0;
+					}
+
+					int index = count++;
+
+					o.Insert(index, this.ordering[i]);
+					v.Insert(index, this.values[i]);
+					a.Insert(index, this.added[i]);
+				}
+
+				this.ordering = o;
+				this.values = v;
+				this.added = a;
+			}
+        }
+
+#if !SILVERLIGHT
+		/**
+		* return an ArrayList of the oids in the name, in the order they were found.
+		*/
+        [Obsolete("Use 'GetOidList' instead")]
+        public ArrayList GetOids()
+        {
+            return new ArrayList(ordering);
+        }
+#endif
+
+        /**
+        * return an IList of the oids in the name, in the order they were found.
+        */
+        public IList GetOidList()
+        {
+            return Platform.CreateArrayList(ordering);
+        }
+
+#if !SILVERLIGHT
+		/**
+		* return an ArrayList of the values found in the name, in the order they
+		* were found.
+		*/
+        [Obsolete("Use 'GetValueList' instead")]
+		public ArrayList GetValues()
+		{
+            return new ArrayList(values);
+		}
+#endif
+
+        /**
+        * return an IList of the values found in the name, in the order they
+        * were found.
+        */
+        public IList GetValueList()
+        {
+            return Platform.CreateArrayList(values);
+        }
+
+#if !SILVERLIGHT
+		/**
+		 * return an ArrayList of the values found in the name, in the order they
+		 * were found, with the DN label corresponding to passed in oid.
+		 */
+		public ArrayList GetValues(
+			DerObjectIdentifier oid)
+		{
+			ArrayList v = new ArrayList();
+            DoGetValueList(oid, v);
+			return v;
+		}
+#endif
+
+		/**
+		 * return an IList of the values found in the name, in the order they
+		 * were found, with the DN label corresponding to passed in oid.
+		 */
+        public IList GetValueList(DerObjectIdentifier oid)
+        {
+            IList v = Platform.CreateArrayList();
+            DoGetValueList(oid, v);
+            return v;
+        }
+
+        private void DoGetValueList(DerObjectIdentifier oid, IList v)
+        {
+            for (int i = 0; i != values.Count; i++)
+            {
+                if (ordering[i].Equals(oid))
+                {
+                    string val = (string)values[i];
+
+                    if (val.StartsWith("\\#"))
+                    {
+                        val = val.Substring(1);
+                    }
+
+                    v.Add(val);
+                }
+            }
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+            if (seq == null)
+            {
+                Asn1EncodableVector vec = new Asn1EncodableVector();
+                Asn1EncodableVector sVec = new Asn1EncodableVector();
+                DerObjectIdentifier lstOid = null;
+
+				for (int i = 0; i != ordering.Count; i++)
+                {
+                    DerObjectIdentifier oid = (DerObjectIdentifier)ordering[i];
+					string str = (string)values[i];
+
+					if (lstOid == null
+                        || ((bool)this.added[i]))
+                    {
+                    }
+                    else
+                    {
+                        vec.Add(new DerSet(sVec));
+                        sVec = new Asn1EncodableVector();
+                    }
+
+					sVec.Add(
+						new DerSequence(
+							oid,
+							converter.GetConvertedValue(oid, str)));
+
+					lstOid = oid;
+                }
+
+				vec.Add(new DerSet(sVec));
+
+				seq = new DerSequence(vec);
+            }
+
+            return seq;
+        }
+
+        /// <param name="other">The X509Name object to test equivalency against.</param>
+		/// <param name="inOrder">If true, the order of elements must be the same,
+		/// as well as the values associated with each element.</param>
+		public bool Equivalent(
+			X509Name	other,
+			bool		inOrder)
+		{
+			if (!inOrder)
+				return this.Equivalent(other);
+
+			if (other == null)
+				return false;
+
+			if (other == this)
+				return true;
+
+			int orderingSize = ordering.Count;
+
+			if (orderingSize != other.ordering.Count)
+				return false;
+
+			for (int i = 0; i < orderingSize; i++)
+			{
+				DerObjectIdentifier oid = (DerObjectIdentifier) ordering[i];
+				DerObjectIdentifier oOid = (DerObjectIdentifier) other.ordering[i];
+
+				if (!oid.Equals(oOid))
+					return false;
+
+				string val = (string) values[i];
+				string oVal = (string) other.values[i];
+
+				if (!equivalentStrings(val, oVal))
+					return false;
+			}
+
+			return true;
+		}
+
+        /**
+		 * test for equivalence - note: case is ignored.
+		 */
+		public bool Equivalent(
+			X509Name other)
+		{
+			if (other == null)
+				return false;
+
+			if (other == this)
+				return true;
+
+			int orderingSize = ordering.Count;
+
+			if (orderingSize != other.ordering.Count)
+			{
+				return false;
+			}
+
+			bool[] indexes = new bool[orderingSize];
+			int start, end, delta;
+
+			if (ordering[0].Equals(other.ordering[0]))   // guess forward
+			{
+				start = 0;
+				end = orderingSize;
+				delta = 1;
+			}
+			else  // guess reversed - most common problem
+			{
+				start = orderingSize - 1;
+				end = -1;
+				delta = -1;
+			}
+
+			for (int i = start; i != end; i += delta)
+			{
+				bool found = false;
+				DerObjectIdentifier  oid = (DerObjectIdentifier)ordering[i];
+				string value = (string)values[i];
+
+				for (int j = 0; j < orderingSize; j++)
+				{
+					if (indexes[j])
+					{
+						continue;
+					}
+
+					DerObjectIdentifier oOid = (DerObjectIdentifier)other.ordering[j];
+
+					if (oid.Equals(oOid))
+					{
+						string oValue = (string)other.values[j];
+
+						if (equivalentStrings(value, oValue))
+						{
+							indexes[j] = true;
+							found      = true;
+							break;
+						}
+					}
+				}
+
+				if (!found)
+				{
+					return false;
+				}
+			}
+
+			return true;
+		}
+
+		private static bool equivalentStrings(
+			string	s1,
+			string	s2)
+		{
+			string v1 = canonicalize(s1);
+			string v2 = canonicalize(s2);
+
+			if (!v1.Equals(v2))
+			{
+				v1 = stripInternalSpaces(v1);
+				v2 = stripInternalSpaces(v2);
+
+				if (!v1.Equals(v2))
+				{
+					return false;
+				}
+			}
+
+			return true;
+		}
+
+		private static string canonicalize(
+			string s)
+		{
+            string v = Platform.ToLowerInvariant(s).Trim();
+
+            if (v.StartsWith("#"))
+			{
+				Asn1Object obj = decodeObject(v);
+
+				if (obj is IAsn1String)
+				{
+					v = Platform.ToLowerInvariant(((IAsn1String)obj).GetString()).Trim();
+				}
+			}
+
+			return v;
+		}
+
+		private static Asn1Object decodeObject(
+			string v)
+		{
+			try
+			{
+				return Asn1Object.FromByteArray(Hex.Decode(v.Substring(1)));
+			}
+			catch (IOException e)
+			{
+				throw new InvalidOperationException("unknown encoding in name: " + e.Message, e);
+			}
+		}
+
+		private static string stripInternalSpaces(
+			string str)
+		{
+			StringBuilder res = new StringBuilder();
+
+			if (str.Length != 0)
+			{
+				char c1 = str[0];
+
+				res.Append(c1);
+
+				for (int k = 1; k < str.Length; k++)
+				{
+					char c2 = str[k];
+					if (!(c1 == ' ' && c2 == ' '))
+					{
+						res.Append(c2);
+					}
+					c1 = c2;
+				}
+			}
+
+			return res.ToString();
+		}
+
+		private void AppendValue(
+            StringBuilder		buf,
+            IDictionary         oidSymbols,
+            DerObjectIdentifier	oid,
+            string				val)
+        {
+            string sym = (string)oidSymbols[oid];
+
+            if (sym != null)
+            {
+                buf.Append(sym);
+            }
+            else
+            {
+                buf.Append(oid.Id);
+            }
+
+            buf.Append('=');
+
+            int index = buf.Length;
+
+            buf.Append(val);
+
+            int end = buf.Length;
+
+			if (val.StartsWith("\\#"))
+			{
+				index += 2;
+			}
+
+			while (index != end)
+            {
+                if ((buf[index] == ',')
+                || (buf[index] == '"')
+                || (buf[index] == '\\')
+                || (buf[index] == '+')
+				|| (buf[index] == '=')
+                || (buf[index] == '<')
+                || (buf[index] == '>')
+                || (buf[index] == ';'))
+                {
+                    buf.Insert(index++, "\\");
+                    end++;
+                }
+
+                index++;
+            }
+        }
+
+#if !SILVERLIGHT
+        [Obsolete]
+        public string ToString(
+            bool        reverse,
+            Hashtable   oidSymbols)
+        {
+            return ToString(reverse, (IDictionary)oidSymbols);
+        }
+#endif
+
+        /**
+        * convert the structure to a string - if reverse is true the
+        * oids and values are listed out starting with the last element
+        * in the sequence (ala RFC 2253), otherwise the string will begin
+        * with the first element of the structure. If no string definition
+        * for the oid is found in oidSymbols the string value of the oid is
+        * added. Two standard symbol tables are provided DefaultSymbols, and
+        * RFC2253Symbols as part of this class.
+        *
+        * @param reverse if true start at the end of the sequence and work back.
+        * @param oidSymbols look up table strings for oids.
+        */
+        public string ToString(
+            bool		reverse,
+            IDictionary oidSymbols)
+        {
+#if SILVERLIGHT
+            List<object> components = new List<object>();
+#else
+			ArrayList components = new ArrayList();
+#endif
+
+            StringBuilder ava = null;
+
+			for (int i = 0; i < ordering.Count; i++)
+			{
+				if ((bool) added[i])
+				{
+					ava.Append('+');
+					AppendValue(ava, oidSymbols,
+						(DerObjectIdentifier)ordering[i],
+						(string)values[i]);
+				}
+				else
+				{
+					ava = new StringBuilder();
+					AppendValue(ava, oidSymbols,
+						(DerObjectIdentifier)ordering[i],
+						(string)values[i]);
+					components.Add(ava);
+				}
+			}
+
+			if (reverse)
+			{
+				components.Reverse();
+			}
+
+			StringBuilder buf = new StringBuilder();
+
+			if (components.Count > 0)
+			{
+				buf.Append(components[0].ToString());
+
+				for (int i = 1; i < components.Count; ++i)
+				{
+					buf.Append(',');
+					buf.Append(components[i].ToString());
+				}
+			}
+
+			return buf.ToString();
+		}
+
+		public override string ToString()
+        {
+            return ToString(DefaultReverse, (IDictionary)DefaultSymbols);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/X509NameEntryConverter.cs b/crypto/src/asn1/x509/X509NameEntryConverter.cs
new file mode 100644
index 000000000..5872656a9
--- /dev/null
+++ b/crypto/src/asn1/x509/X509NameEntryConverter.cs
@@ -0,0 +1,89 @@
+using System;
+using System.Globalization;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * It turns out that the number of standard ways the fields in a DN should be
+     * encoded into their ASN.1 counterparts is rapidly approaching the
+     * number of machines on the internet. By default the X509Name class
+     * will produce UTF8Strings in line with the current recommendations (RFC 3280).
+     * <p>
+     * An example of an encoder look like below:
+     * <pre>
+     * public class X509DirEntryConverter
+     *     : X509NameEntryConverter
+     * {
+     *     public Asn1Object GetConvertedValue(
+     *         DerObjectIdentifier  oid,
+     *         string               value)
+     *     {
+     *         if (str.Length() != 0 &amp;&amp; str.charAt(0) == '#')
+     *         {
+     *             return ConvertHexEncoded(str, 1);
+     *         }
+     *         if (oid.Equals(EmailAddress))
+     *         {
+     *             return new DerIA5String(str);
+     *         }
+     *         else if (CanBePrintable(str))
+     *         {
+     *             return new DerPrintableString(str);
+     *         }
+     *         else if (CanBeUTF8(str))
+     *         {
+     *             return new DerUtf8String(str);
+     *         }
+     *         else
+     *         {
+     *             return new DerBmpString(str);
+     *         }
+     *     }
+     * }
+	 * </pre>
+	 * </p>
+     */
+    public abstract class X509NameEntryConverter
+    {
+        /**
+         * Convert an inline encoded hex string rendition of an ASN.1
+         * object back into its corresponding ASN.1 object.
+         *
+         * @param str the hex encoded object
+         * @param off the index at which the encoding starts
+         * @return the decoded object
+         */
+        protected Asn1Object ConvertHexEncoded(
+            string	hexString,
+            int		offset)
+        {
+			string str = hexString.Substring(offset);
+
+			return Asn1Object.FromByteArray(Hex.Decode(str));
+        }
+
+		/**
+         * return true if the passed in string can be represented without
+         * loss as a PrintableString, false otherwise.
+         */
+        protected bool CanBePrintable(
+            string str)
+        {
+			return DerPrintableString.IsPrintableString(str);
+        }
+
+		/**
+         * Convert the passed in string value into the appropriate ASN.1
+         * encoded object.
+         *
+         * @param oid the oid associated with the value in the DN.
+         * @param value the value of the particular DN component.
+         * @return the ASN.1 equivalent for the value.
+         */
+        public abstract Asn1Object GetConvertedValue(DerObjectIdentifier oid, string value);
+    }
+}
diff --git a/crypto/src/asn1/x509/X509NameTokenizer.cs b/crypto/src/asn1/x509/X509NameTokenizer.cs
new file mode 100644
index 000000000..ab5529535
--- /dev/null
+++ b/crypto/src/asn1/x509/X509NameTokenizer.cs
@@ -0,0 +1,104 @@
+using System.Text;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * class for breaking up an X500 Name into it's component tokens, ala
+     * java.util.StringTokenizer. We need this class as some of the
+     * lightweight Java environment don't support classes like
+     * StringTokenizer.
+     */
+    public class X509NameTokenizer
+    {
+        private string			value;
+        private int				index;
+        private char			separator;
+        private StringBuilder	buffer = new StringBuilder();
+
+		public X509NameTokenizer(
+            string oid)
+            : this(oid, ',')
+        {
+        }
+
+		public X509NameTokenizer(
+            string	oid,
+            char	separator)
+        {
+            this.value = oid;
+            this.index = -1;
+            this.separator = separator;
+        }
+
+		public bool HasMoreTokens()
+        {
+            return index != value.Length;
+        }
+
+		public string NextToken()
+        {
+            if (index == value.Length)
+            {
+                return null;
+            }
+
+            int end = index + 1;
+            bool quoted = false;
+            bool escaped = false;
+
+			buffer.Remove(0, buffer.Length);
+
+			while (end != value.Length)
+            {
+                char c = value[end];
+
+				if (c == '"')
+                {
+                    if (!escaped)
+                    {
+                        quoted = !quoted;
+                    }
+                    else
+                    {
+                        buffer.Append(c);
+						escaped = false;
+                    }
+                }
+                else
+                {
+                    if (escaped || quoted)
+                    {
+						if (c == '#' && buffer[buffer.Length - 1] == '=')
+						{
+							buffer.Append('\\');
+						}
+						else if (c == '+' && separator != '+')
+						{
+							buffer.Append('\\');
+						}
+						buffer.Append(c);
+                        escaped = false;
+                    }
+                    else if (c == '\\')
+                    {
+                        escaped = true;
+                    }
+                    else if (c == separator)
+                    {
+                        break;
+                    }
+                    else
+                    {
+                        buffer.Append(c);
+                    }
+                }
+
+				end++;
+            }
+
+			index = end;
+
+			return buffer.ToString().Trim();
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/X509ObjectIdentifiers.cs b/crypto/src/asn1/x509/X509ObjectIdentifiers.cs
new file mode 100644
index 000000000..f00e31475
--- /dev/null
+++ b/crypto/src/asn1/x509/X509ObjectIdentifiers.cs
@@ -0,0 +1,59 @@
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public abstract class X509ObjectIdentifiers
+    {
+        //
+        // base id
+        //
+        internal const string ID = "2.5.4";
+
+		public static readonly DerObjectIdentifier CommonName              = new DerObjectIdentifier(ID + ".3");
+        public static readonly DerObjectIdentifier CountryName             = new DerObjectIdentifier(ID + ".6");
+        public static readonly DerObjectIdentifier LocalityName            = new DerObjectIdentifier(ID + ".7");
+        public static readonly DerObjectIdentifier StateOrProvinceName     = new DerObjectIdentifier(ID + ".8");
+        public static readonly DerObjectIdentifier Organization            = new DerObjectIdentifier(ID + ".10");
+        public static readonly DerObjectIdentifier OrganizationalUnitName  = new DerObjectIdentifier(ID + ".11");
+
+		public static readonly DerObjectIdentifier id_at_telephoneNumber   = new DerObjectIdentifier(ID + ".20");
+		public static readonly DerObjectIdentifier id_at_name              = new DerObjectIdentifier(ID + ".41");
+
+		// id-SHA1 OBJECT IDENTIFIER ::=
+        //   {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 }    //
+        public static readonly DerObjectIdentifier IdSha1 = new DerObjectIdentifier("1.3.14.3.2.26");
+
+		//
+        // ripemd160 OBJECT IDENTIFIER ::=
+        //      {iso(1) identified-organization(3) TeleTrust(36) algorithm(3) hashAlgorithm(2) RipeMD-160(1)}
+        //
+        public static readonly DerObjectIdentifier RipeMD160 = new DerObjectIdentifier("1.3.36.3.2.1");
+
+		//
+        // ripemd160WithRSAEncryption OBJECT IDENTIFIER ::=
+        //      {iso(1) identified-organization(3) TeleTrust(36) algorithm(3) signatureAlgorithm(3) rsaSignature(1) rsaSignatureWithripemd160(2) }
+        //
+        public static readonly DerObjectIdentifier RipeMD160WithRsaEncryption = new DerObjectIdentifier("1.3.36.3.3.1.2");
+
+		public static readonly DerObjectIdentifier IdEARsa = new DerObjectIdentifier("2.5.8.1.1");
+
+		// id-pkix
+		public static readonly DerObjectIdentifier IdPkix = new DerObjectIdentifier("1.3.6.1.5.5.7");
+
+		//
+		// private internet extensions
+		//
+		public static readonly DerObjectIdentifier IdPE = new DerObjectIdentifier(IdPkix + ".1");
+
+		//
+		// authority information access
+		//
+		public static readonly DerObjectIdentifier IdAD = new DerObjectIdentifier(IdPkix + ".48");
+		public static readonly DerObjectIdentifier IdADCAIssuers = new DerObjectIdentifier(IdAD + ".2");
+		public static readonly DerObjectIdentifier IdADOcsp = new DerObjectIdentifier(IdAD + ".1");
+
+		//
+		// OID for ocsp and crl uri in AuthorityInformationAccess extension
+		//
+		public static readonly DerObjectIdentifier OcspAccessMethod = IdADOcsp;
+		public static readonly DerObjectIdentifier CrlAccessMethod = IdADCAIssuers;
+    }
+}
diff --git a/crypto/src/asn1/x509/qualified/BiometricData.cs b/crypto/src/asn1/x509/qualified/BiometricData.cs
new file mode 100644
index 000000000..61d7c99cb
--- /dev/null
+++ b/crypto/src/asn1/x509/qualified/BiometricData.cs
@@ -0,0 +1,112 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.X509.Qualified
+{
+    /**
+    * The BiometricData object.
+    * <pre>
+    * BiometricData  ::=  SEQUENCE {
+    *       typeOfBiometricData  TypeOfBiometricData,
+    *       hashAlgorithm        AlgorithmIdentifier,
+    *       biometricDataHash    OCTET STRING,
+    *       sourceDataUri        IA5String OPTIONAL  }
+    * </pre>
+    */
+    public class BiometricData
+        : Asn1Encodable
+    {
+        private readonly TypeOfBiometricData typeOfBiometricData;
+        private readonly AlgorithmIdentifier hashAlgorithm;
+        private readonly Asn1OctetString     biometricDataHash;
+        private readonly DerIA5String        sourceDataUri;
+
+        public static BiometricData GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is BiometricData)
+            {
+                return (BiometricData)obj;
+            }
+
+            if (obj is Asn1Sequence)
+            {
+				return new BiometricData(Asn1Sequence.GetInstance(obj));
+            }
+
+			throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+		}
+
+		private BiometricData(
+			Asn1Sequence seq)
+        {
+			typeOfBiometricData = TypeOfBiometricData.GetInstance(seq[0]);
+			hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[1]);
+			biometricDataHash = Asn1OctetString.GetInstance(seq[2]);
+
+			if (seq.Count > 3)
+			{
+				sourceDataUri = DerIA5String.GetInstance(seq[3]);
+			}
+        }
+
+		public BiometricData(
+            TypeOfBiometricData	typeOfBiometricData,
+            AlgorithmIdentifier	hashAlgorithm,
+            Asn1OctetString		biometricDataHash,
+            DerIA5String		sourceDataUri)
+        {
+            this.typeOfBiometricData = typeOfBiometricData;
+            this.hashAlgorithm = hashAlgorithm;
+            this.biometricDataHash = biometricDataHash;
+            this.sourceDataUri = sourceDataUri;
+        }
+
+        public BiometricData(
+            TypeOfBiometricData	typeOfBiometricData,
+            AlgorithmIdentifier	hashAlgorithm,
+            Asn1OctetString		biometricDataHash)
+        {
+            this.typeOfBiometricData = typeOfBiometricData;
+            this.hashAlgorithm = hashAlgorithm;
+            this.biometricDataHash = biometricDataHash;
+            this.sourceDataUri = null;
+        }
+
+        public TypeOfBiometricData TypeOfBiometricData
+        {
+			get { return typeOfBiometricData; }
+        }
+
+		public AlgorithmIdentifier HashAlgorithm
+		{
+			get { return hashAlgorithm; }
+		}
+
+		public Asn1OctetString BiometricDataHash
+		{
+			get { return biometricDataHash; }
+		}
+
+		public DerIA5String SourceDataUri
+		{
+			get { return sourceDataUri; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector seq = new Asn1EncodableVector(
+				typeOfBiometricData, hashAlgorithm, biometricDataHash);
+
+			if (sourceDataUri != null)
+            {
+                seq.Add(sourceDataUri);
+            }
+
+			return new DerSequence(seq);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/qualified/ETSIQCObjectIdentifiers.cs b/crypto/src/asn1/x509/qualified/ETSIQCObjectIdentifiers.cs
new file mode 100644
index 000000000..86a4eee0a
--- /dev/null
+++ b/crypto/src/asn1/x509/qualified/ETSIQCObjectIdentifiers.cs
@@ -0,0 +1,19 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509.Qualified
+{
+	public abstract class EtsiQCObjectIdentifiers
+	{
+		//
+		// base id
+		//
+		public static readonly DerObjectIdentifier IdEtsiQcs                 = new DerObjectIdentifier("0.4.0.1862.1");
+
+		public static readonly DerObjectIdentifier IdEtsiQcsQcCompliance     = new DerObjectIdentifier(IdEtsiQcs+".1");
+		public static readonly DerObjectIdentifier IdEtsiQcsLimitValue       = new DerObjectIdentifier(IdEtsiQcs+".2");
+		public static readonly DerObjectIdentifier IdEtsiQcsRetentionPeriod  = new DerObjectIdentifier(IdEtsiQcs+".3");
+		public static readonly DerObjectIdentifier IdEtsiQcsQcSscd           = new DerObjectIdentifier(IdEtsiQcs+".4");
+	}
+}
diff --git a/crypto/src/asn1/x509/qualified/Iso4217CurrencyCode.cs b/crypto/src/asn1/x509/qualified/Iso4217CurrencyCode.cs
new file mode 100644
index 000000000..3300562c8
--- /dev/null
+++ b/crypto/src/asn1/x509/qualified/Iso4217CurrencyCode.cs
@@ -0,0 +1,84 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509.Qualified
+{
+    /**
+    * The Iso4217CurrencyCode object.
+    * <pre>
+    * Iso4217CurrencyCode  ::=  CHOICE {
+    *       alphabetic              PrintableString (SIZE 3), --Recommended
+    *       numeric              INTEGER (1..999) }
+    * -- Alphabetic or numeric currency code as defined in ISO 4217
+    * -- It is recommended that the Alphabetic form is used
+    * </pre>
+    */
+    public class Iso4217CurrencyCode
+        : Asn1Encodable, IAsn1Choice
+    {
+        internal const int AlphabeticMaxSize = 3;
+        internal const int NumericMinSize = 1;
+        internal const int NumericMaxSize = 999;
+
+		internal Asn1Encodable	obj;
+//        internal int			numeric;
+
+		public static Iso4217CurrencyCode GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is Iso4217CurrencyCode)
+            {
+                return (Iso4217CurrencyCode) obj;
+            }
+
+			if (obj is DerInteger)
+            {
+                DerInteger numericobj = DerInteger.GetInstance(obj);
+                int numeric = numericobj.Value.IntValue;
+                return new Iso4217CurrencyCode(numeric);
+            }
+
+			if (obj is DerPrintableString)
+            {
+                DerPrintableString alphabetic = DerPrintableString.GetInstance(obj);
+                return new Iso4217CurrencyCode(alphabetic.GetString());
+            }
+
+			throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+        }
+
+		public Iso4217CurrencyCode(
+            int numeric)
+        {
+            if (numeric > NumericMaxSize || numeric < NumericMinSize)
+            {
+                throw new ArgumentException("wrong size in numeric code : not in (" +NumericMinSize +".."+ NumericMaxSize +")");
+            }
+
+			obj = new DerInteger(numeric);
+        }
+
+		public Iso4217CurrencyCode(
+            string alphabetic)
+        {
+            if (alphabetic.Length > AlphabeticMaxSize)
+            {
+                throw new ArgumentException("wrong size in alphabetic code : max size is " + AlphabeticMaxSize);
+            }
+
+			obj = new DerPrintableString(alphabetic);
+        }
+
+		public bool IsAlphabetic { get { return obj is DerPrintableString; } }
+
+		public string Alphabetic { get { return ((DerPrintableString) obj).GetString(); } }
+
+		public int Numeric { get { return ((DerInteger)obj).Value.IntValue; } }
+
+		public override Asn1Object ToAsn1Object()
+        {
+            return obj.ToAsn1Object();
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/qualified/MonetaryValue.cs b/crypto/src/asn1/x509/qualified/MonetaryValue.cs
new file mode 100644
index 000000000..45e113671
--- /dev/null
+++ b/crypto/src/asn1/x509/qualified/MonetaryValue.cs
@@ -0,0 +1,83 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.X509.Qualified
+{
+    /**
+    * The MonetaryValue object.
+    * <pre>
+    * MonetaryValue  ::=  SEQUENCE {
+    *       currency              Iso4217CurrencyCode,
+    *       amount               INTEGER,
+    *       exponent             INTEGER }
+    * -- value = amount * 10^exponent
+    * </pre>
+    */
+    public class MonetaryValue
+        : Asn1Encodable
+    {
+        internal Iso4217CurrencyCode	currency;
+        internal DerInteger				amount;
+        internal DerInteger				exponent;
+
+		public static MonetaryValue GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is MonetaryValue)
+            {
+                return (MonetaryValue) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new MonetaryValue(Asn1Sequence.GetInstance(obj));
+            }
+
+			throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+		}
+
+		private MonetaryValue(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 3)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+            currency = Iso4217CurrencyCode.GetInstance(seq[0]);
+            amount = DerInteger.GetInstance(seq[1]);
+            exponent = DerInteger.GetInstance(seq[2]);
+        }
+
+		public MonetaryValue(
+            Iso4217CurrencyCode	currency,
+            int					amount,
+            int					exponent)
+        {
+            this.currency = currency;
+            this.amount = new DerInteger(amount);
+            this.exponent = new DerInteger(exponent);
+        }
+
+		public Iso4217CurrencyCode Currency
+		{
+			get { return currency; }
+		}
+
+		public BigInteger Amount
+		{
+			get { return amount.Value; }
+		}
+
+		public BigInteger Exponent
+		{
+			get { return exponent.Value; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(currency, amount, exponent);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/qualified/QCStatement.cs b/crypto/src/asn1/x509/qualified/QCStatement.cs
new file mode 100644
index 000000000..317f03447
--- /dev/null
+++ b/crypto/src/asn1/x509/qualified/QCStatement.cs
@@ -0,0 +1,85 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509.Qualified
+{
+    /**
+    * The QCStatement object.
+    * <pre>
+    * QCStatement ::= SEQUENCE {
+    *   statementId        OBJECT IDENTIFIER,
+    *   statementInfo      ANY DEFINED BY statementId OPTIONAL}
+    * </pre>
+    */
+    public class QCStatement
+        : Asn1Encodable
+    {
+        private readonly DerObjectIdentifier	qcStatementId;
+        private readonly Asn1Encodable			qcStatementInfo;
+
+		public static QCStatement GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is QCStatement)
+            {
+                return (QCStatement) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+				return new QCStatement(Asn1Sequence.GetInstance(obj));
+            }
+
+			throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+		}
+
+		private QCStatement(
+            Asn1Sequence seq)
+        {
+			qcStatementId = DerObjectIdentifier.GetInstance(seq[0]);
+
+			if (seq.Count > 1)
+			{
+				qcStatementInfo = seq[1];
+			}
+        }
+
+		public QCStatement(
+            DerObjectIdentifier qcStatementId)
+        {
+            this.qcStatementId = qcStatementId;
+        }
+
+        public QCStatement(
+            DerObjectIdentifier qcStatementId,
+            Asn1Encodable       qcStatementInfo)
+        {
+            this.qcStatementId = qcStatementId;
+            this.qcStatementInfo = qcStatementInfo;
+        }
+
+		public DerObjectIdentifier StatementId
+		{
+			get { return qcStatementId; }
+		}
+
+		public Asn1Encodable StatementInfo
+		{
+			get { return qcStatementInfo; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector seq = new Asn1EncodableVector(qcStatementId);
+
+			if (qcStatementInfo != null)
+            {
+                seq.Add(qcStatementInfo);
+            }
+
+			return new DerSequence(seq);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/qualified/RFC3739QCObjectIdentifiers.cs b/crypto/src/asn1/x509/qualified/RFC3739QCObjectIdentifiers.cs
new file mode 100644
index 000000000..8ebd69edb
--- /dev/null
+++ b/crypto/src/asn1/x509/qualified/RFC3739QCObjectIdentifiers.cs
@@ -0,0 +1,21 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509.Qualified
+{
+    public sealed class Rfc3739QCObjectIdentifiers
+    {
+		private Rfc3739QCObjectIdentifiers()
+		{
+		}
+
+		//
+        // base id
+        //
+        public static readonly DerObjectIdentifier IdQcs = new DerObjectIdentifier("1.3.6.1.5.5.7.11");
+
+        public static readonly DerObjectIdentifier IdQcsPkixQCSyntaxV1 = new DerObjectIdentifier(IdQcs+".1");
+        public static readonly DerObjectIdentifier IdQcsPkixQCSyntaxV2 = new DerObjectIdentifier(IdQcs+".2");
+    }
+}
diff --git a/crypto/src/asn1/x509/qualified/SemanticsInformation.cs b/crypto/src/asn1/x509/qualified/SemanticsInformation.cs
new file mode 100644
index 000000000..72e7cd0e1
--- /dev/null
+++ b/crypto/src/asn1/x509/qualified/SemanticsInformation.cs
@@ -0,0 +1,124 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.X509.Qualified
+{
+    /**
+    * The SemanticsInformation object.
+    * <pre>
+    *       SemanticsInformation ::= SEQUENCE {
+    *         semanticsIdentifier        OBJECT IDENTIFIER   OPTIONAL,
+    *         nameRegistrationAuthorities NameRegistrationAuthorities
+    *                                                         OPTIONAL }
+    *         (WITH COMPONENTS {..., semanticsIdentifier PRESENT}|
+    *          WITH COMPONENTS {..., nameRegistrationAuthorities PRESENT})
+    *
+    *     NameRegistrationAuthorities ::=  SEQUENCE SIZE (1..MAX) OF
+    *         GeneralName
+    * </pre>
+    */
+    public class SemanticsInformation
+		: Asn1Encodable
+    {
+        private readonly DerObjectIdentifier	semanticsIdentifier;
+        private readonly GeneralName[]			nameRegistrationAuthorities;
+
+		public static SemanticsInformation GetInstance(
+			object obj)
+        {
+            if (obj == null || obj is SemanticsInformation)
+            {
+                return (SemanticsInformation) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new SemanticsInformation(Asn1Sequence.GetInstance(obj));
+            }
+
+			throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+		}
+
+		public SemanticsInformation(
+			Asn1Sequence seq)
+        {
+            if (seq.Count < 1)
+            {
+                throw new ArgumentException("no objects in SemanticsInformation");
+            }
+
+			IEnumerator e = seq.GetEnumerator();
+			e.MoveNext();
+            object obj = e.Current;
+            if (obj is DerObjectIdentifier)
+            {
+                semanticsIdentifier = DerObjectIdentifier.GetInstance(obj);
+                if (e.MoveNext())
+                {
+                    obj  = e.Current;
+                }
+                else
+                {
+                    obj  = null;
+                }
+            }
+
+			if (obj  != null)
+            {
+                Asn1Sequence generalNameSeq = Asn1Sequence.GetInstance(obj );
+                nameRegistrationAuthorities = new GeneralName[generalNameSeq.Count];
+                for (int i= 0; i < generalNameSeq.Count; i++)
+                {
+                    nameRegistrationAuthorities[i] = GeneralName.GetInstance(generalNameSeq[i]);
+                }
+            }
+        }
+
+		public SemanticsInformation(
+            DerObjectIdentifier semanticsIdentifier,
+            GeneralName[] generalNames)
+        {
+            this.semanticsIdentifier = semanticsIdentifier;
+            this.nameRegistrationAuthorities = generalNames;
+        }
+
+		public SemanticsInformation(
+			DerObjectIdentifier semanticsIdentifier)
+        {
+            this.semanticsIdentifier = semanticsIdentifier;
+        }
+
+        public SemanticsInformation(
+			GeneralName[] generalNames)
+        {
+            this.nameRegistrationAuthorities = generalNames;
+        }
+
+		public DerObjectIdentifier SemanticsIdentifier { get { return semanticsIdentifier; } }
+
+		public GeneralName[] GetNameRegistrationAuthorities()
+        {
+            return nameRegistrationAuthorities;
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector seq = new Asn1EncodableVector();
+
+            if (this.semanticsIdentifier != null)
+            {
+                seq.Add(semanticsIdentifier);
+            }
+
+			if (this.nameRegistrationAuthorities != null)
+            {
+                seq.Add(new DerSequence(nameRegistrationAuthorities));
+            }
+
+			return new DerSequence(seq);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/qualified/TypeOfBiometricData.cs b/crypto/src/asn1/x509/qualified/TypeOfBiometricData.cs
new file mode 100644
index 000000000..a77e54acb
--- /dev/null
+++ b/crypto/src/asn1/x509/qualified/TypeOfBiometricData.cs
@@ -0,0 +1,91 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509.Qualified
+{
+    /**
+    * The TypeOfBiometricData object.
+    * <pre>
+    * TypeOfBiometricData ::= CHOICE {
+    *   predefinedBiometricType   PredefinedBiometricType,
+    *   biometricDataOid          OBJECT IDENTIFIER }
+    *
+    * PredefinedBiometricType ::= INTEGER {
+    *   picture(0),handwritten-signature(1)}
+    *   (picture|handwritten-signature)
+    * </pre>
+    */
+    public class TypeOfBiometricData
+        : Asn1Encodable, IAsn1Choice
+    {
+        public const int Picture				= 0;
+        public const int HandwrittenSignature	= 1;
+
+		internal Asn1Encodable obj;
+
+		public static TypeOfBiometricData GetInstance(
+			object obj)
+        {
+            if (obj == null || obj is TypeOfBiometricData)
+            {
+                return (TypeOfBiometricData) obj;
+            }
+
+			if (obj is DerInteger)
+            {
+                DerInteger predefinedBiometricTypeObj = DerInteger.GetInstance(obj);
+                int predefinedBiometricType = predefinedBiometricTypeObj.Value.IntValue;
+
+				return new TypeOfBiometricData(predefinedBiometricType);
+            }
+
+			if (obj is DerObjectIdentifier)
+            {
+                DerObjectIdentifier BiometricDataOid = DerObjectIdentifier.GetInstance(obj);
+                return new TypeOfBiometricData(BiometricDataOid);
+            }
+
+			throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+		}
+
+		public TypeOfBiometricData(
+			int predefinedBiometricType)
+        {
+            if (predefinedBiometricType == Picture || predefinedBiometricType == HandwrittenSignature)
+            {
+                obj = new DerInteger(predefinedBiometricType);
+            }
+            else
+            {
+                throw new ArgumentException("unknow PredefinedBiometricType : " + predefinedBiometricType);
+            }
+        }
+
+		public TypeOfBiometricData(
+			DerObjectIdentifier biometricDataOid)
+        {
+            obj = biometricDataOid;
+        }
+
+		public bool IsPredefined
+		{
+			get { return obj is DerInteger; }
+		}
+
+		public int PredefinedBiometricType
+		{
+			get { return ((DerInteger) obj).Value.IntValue; }
+		}
+
+		public DerObjectIdentifier BiometricDataOid
+		{
+			get { return (DerObjectIdentifier) obj; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+            return obj.ToAsn1Object();
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/sigi/NameOrPseudonym.cs b/crypto/src/asn1/x509/sigi/NameOrPseudonym.cs
new file mode 100644
index 000000000..222895cf1
--- /dev/null
+++ b/crypto/src/asn1/x509/sigi/NameOrPseudonym.cs
@@ -0,0 +1,177 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X500;
+
+namespace Org.BouncyCastle.Asn1.X509.SigI
+{
+	/**
+	* Structure for a name or pseudonym.
+	* 
+	* <pre>
+	*       NameOrPseudonym ::= CHOICE {
+	*     	   surAndGivenName SEQUENCE {
+	*     	     surName DirectoryString,
+	*     	     givenName SEQUENCE OF DirectoryString 
+	*         },
+	*     	   pseudonym DirectoryString 
+	*       }
+	* </pre>
+	* 
+	* @see org.bouncycastle.asn1.x509.sigi.PersonalData
+	* 
+	*/
+	public class NameOrPseudonym
+		: Asn1Encodable, IAsn1Choice
+	{
+		private readonly DirectoryString	pseudonym;
+		private readonly DirectoryString	surname;
+		private readonly Asn1Sequence		givenName;
+
+		public static NameOrPseudonym GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is NameOrPseudonym)
+			{
+				return (NameOrPseudonym)obj;
+			}
+
+			if (obj is IAsn1String)
+			{
+				return new NameOrPseudonym(DirectoryString.GetInstance(obj));
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new NameOrPseudonym((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		* Constructor from DERString.
+		* <p/>
+		* The sequence is of type NameOrPseudonym:
+		* <p/>
+		* <pre>
+		*       NameOrPseudonym ::= CHOICE {
+		*     	   surAndGivenName SEQUENCE {
+		*     	     surName DirectoryString,
+		*     	     givenName SEQUENCE OF DirectoryString
+		*         },
+		*     	   pseudonym DirectoryString
+		*       }
+		* </pre>
+		* @param pseudonym pseudonym value to use.
+		*/
+		public NameOrPseudonym(
+			DirectoryString pseudonym)
+		{
+			this.pseudonym = pseudonym;
+		}
+
+		/**
+		* Constructor from Asn1Sequence.
+		* <p/>
+		* The sequence is of type NameOrPseudonym:
+		* <p/>
+		* <pre>
+		*       NameOrPseudonym ::= CHOICE {
+		*     	   surAndGivenName SEQUENCE {
+		*     	     surName DirectoryString,
+		*     	     givenName SEQUENCE OF DirectoryString
+		*         },
+		*     	   pseudonym DirectoryString
+		*       }
+		* </pre>
+		*
+		* @param seq The ASN.1 sequence.
+		*/
+		private NameOrPseudonym(
+			Asn1Sequence seq)
+		{
+			if (seq.Count != 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+			if (!(seq[0] is IAsn1String))
+				throw new ArgumentException("Bad object encountered: " + seq[0].GetType().Name);
+
+			surname = DirectoryString.GetInstance(seq[0]);
+			givenName = Asn1Sequence.GetInstance(seq[1]);
+		}
+
+		/**
+		* Constructor from a given details.
+		*
+		* @param pseudonym The pseudonym.
+		*/
+		public NameOrPseudonym(
+			string pseudonym)
+			: this(new DirectoryString(pseudonym))
+		{
+		}
+
+		/**
+		 * Constructor from a given details.
+		 *
+		 * @param surname   The surname.
+		 * @param givenName A sequence of directory strings making up the givenName
+		 */
+		public NameOrPseudonym(
+			DirectoryString	surname,
+			Asn1Sequence	givenName)
+		{
+			this.surname = surname;
+			this.givenName = givenName;
+		}
+
+		public DirectoryString Pseudonym
+		{
+			get { return pseudonym; }
+		}
+
+		public DirectoryString Surname
+		{
+			get { return surname; }
+		}
+
+		public DirectoryString[] GetGivenName()
+		{
+			DirectoryString[] items = new DirectoryString[givenName.Count];
+			int count = 0;
+			foreach (object o in givenName)
+			{
+				items[count++] = DirectoryString.GetInstance(o);
+			}
+			return items;
+		}
+
+		/**
+		* Produce an object suitable for an Asn1OutputStream.
+		* <p/>
+		* Returns:
+		* <p/>
+		* <pre>
+		*       NameOrPseudonym ::= CHOICE {
+		*     	   surAndGivenName SEQUENCE {
+		*     	     surName DirectoryString,
+		*     	     givenName SEQUENCE OF DirectoryString
+		*         },
+		*     	   pseudonym DirectoryString
+		*       }
+		* </pre>
+		*
+		* @return an Asn1Object
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			if (pseudonym != null)
+			{
+				return pseudonym.ToAsn1Object();
+			}
+
+			return new DerSequence(surname, givenName);
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/sigi/PersonalData.cs b/crypto/src/asn1/x509/sigi/PersonalData.cs
new file mode 100644
index 000000000..6acdc7308
--- /dev/null
+++ b/crypto/src/asn1/x509/sigi/PersonalData.cs
@@ -0,0 +1,210 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X500;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.X509.SigI
+{
+	/**
+	* Contains personal data for the otherName field in the subjectAltNames
+	* extension.
+	* <p/>
+	* <pre>
+	*     PersonalData ::= SEQUENCE {
+	*       nameOrPseudonym NameOrPseudonym,
+	*       nameDistinguisher [0] INTEGER OPTIONAL,
+	*       dateOfBirth [1] GeneralizedTime OPTIONAL,
+	*       placeOfBirth [2] DirectoryString OPTIONAL,
+	*       gender [3] PrintableString OPTIONAL,
+	*       postalAddress [4] DirectoryString OPTIONAL
+	*       }
+	* </pre>
+	*
+	* @see org.bouncycastle.asn1.x509.sigi.NameOrPseudonym
+	* @see org.bouncycastle.asn1.x509.sigi.SigIObjectIdentifiers
+	*/
+	public class PersonalData
+		: Asn1Encodable
+	{
+		private readonly NameOrPseudonym	nameOrPseudonym;
+		private readonly BigInteger			nameDistinguisher;
+		private readonly DerGeneralizedTime	dateOfBirth;
+		private readonly DirectoryString	placeOfBirth;
+		private readonly string				gender;
+		private readonly DirectoryString	postalAddress;
+
+		public static PersonalData GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is PersonalData)
+			{
+				return (PersonalData) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new PersonalData((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		* Constructor from Asn1Sequence.
+		* <p/>
+		* The sequence is of type NameOrPseudonym:
+		* <p/>
+		* <pre>
+		*     PersonalData ::= SEQUENCE {
+		*       nameOrPseudonym NameOrPseudonym,
+		*       nameDistinguisher [0] INTEGER OPTIONAL,
+		*       dateOfBirth [1] GeneralizedTime OPTIONAL,
+		*       placeOfBirth [2] DirectoryString OPTIONAL,
+		*       gender [3] PrintableString OPTIONAL,
+		*       postalAddress [4] DirectoryString OPTIONAL
+		*       }
+		* </pre>
+		*
+		* @param seq The ASN.1 sequence.
+		*/
+		private PersonalData(
+			Asn1Sequence seq)
+		{
+			if (seq.Count < 1)
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+			IEnumerator e = seq.GetEnumerator();
+			e.MoveNext();
+
+			nameOrPseudonym = NameOrPseudonym.GetInstance(e.Current);
+
+			while (e.MoveNext())
+			{
+				Asn1TaggedObject o = Asn1TaggedObject.GetInstance(e.Current);
+				int tag = o.TagNo;
+				switch (tag)
+				{
+					case 0:
+						nameDistinguisher = DerInteger.GetInstance(o, false).Value;
+						break;
+					case 1:
+						dateOfBirth = DerGeneralizedTime.GetInstance(o, false);
+						break;
+					case 2:
+						placeOfBirth = DirectoryString.GetInstance(o, true);
+						break;
+					case 3:
+						gender = DerPrintableString.GetInstance(o, false).GetString();
+						break;
+					case 4:
+						postalAddress = DirectoryString.GetInstance(o, true);
+						break;
+					default:
+						throw new ArgumentException("Bad tag number: " + o.TagNo);
+				}
+			}
+		}
+
+		/**
+		* Constructor from a given details.
+		*
+		* @param nameOrPseudonym  Name or pseudonym.
+		* @param nameDistinguisher Name distinguisher.
+		* @param dateOfBirth      Date of birth.
+		* @param placeOfBirth     Place of birth.
+		* @param gender           Gender.
+		* @param postalAddress    Postal Address.
+		*/
+		public PersonalData(
+			NameOrPseudonym		nameOrPseudonym,
+			BigInteger			nameDistinguisher,
+			DerGeneralizedTime	dateOfBirth,
+			DirectoryString		placeOfBirth,
+			string				gender,
+			DirectoryString		postalAddress)
+		{
+			this.nameOrPseudonym = nameOrPseudonym;
+			this.dateOfBirth = dateOfBirth;
+			this.gender = gender;
+			this.nameDistinguisher = nameDistinguisher;
+			this.postalAddress = postalAddress;
+			this.placeOfBirth = placeOfBirth;
+		}
+
+		public NameOrPseudonym NameOrPseudonym
+		{
+			get { return nameOrPseudonym; }
+		}
+
+		public BigInteger NameDistinguisher
+		{
+			get { return nameDistinguisher; }
+		}
+
+		public DerGeneralizedTime DateOfBirth
+		{
+			get { return dateOfBirth; }
+		}
+
+		public DirectoryString PlaceOfBirth
+		{
+			get { return placeOfBirth; }
+		}
+
+		public string Gender
+		{
+			get { return gender; }
+		}
+
+		public DirectoryString PostalAddress
+		{
+			get { return postalAddress; }
+		}
+
+		/**
+		* Produce an object suitable for an Asn1OutputStream.
+		* <p/>
+		* Returns:
+		* <p/>
+		* <pre>
+		*     PersonalData ::= SEQUENCE {
+		*       nameOrPseudonym NameOrPseudonym,
+		*       nameDistinguisher [0] INTEGER OPTIONAL,
+		*       dateOfBirth [1] GeneralizedTime OPTIONAL,
+		*       placeOfBirth [2] DirectoryString OPTIONAL,
+		*       gender [3] PrintableString OPTIONAL,
+		*       postalAddress [4] DirectoryString OPTIONAL
+		*       }
+		* </pre>
+		*
+		* @return an Asn1Object
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector vec = new Asn1EncodableVector();
+			vec.Add(nameOrPseudonym);
+			if (nameDistinguisher != null)
+			{
+				vec.Add(new DerTaggedObject(false, 0, new DerInteger(nameDistinguisher)));
+			}
+			if (dateOfBirth != null)
+			{
+				vec.Add(new DerTaggedObject(false, 1, dateOfBirth));
+			}
+			if (placeOfBirth != null)
+			{
+				vec.Add(new DerTaggedObject(true, 2, placeOfBirth));
+			}
+			if (gender != null)
+			{
+				vec.Add(new DerTaggedObject(false, 3, new DerPrintableString(gender, true)));
+			}
+			if (postalAddress != null)
+			{
+				vec.Add(new DerTaggedObject(true, 4, postalAddress));
+			}
+			return new DerSequence(vec);
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/sigi/SigIObjectIdentifiers.cs b/crypto/src/asn1/x509/sigi/SigIObjectIdentifiers.cs
new file mode 100644
index 000000000..682311adc
--- /dev/null
+++ b/crypto/src/asn1/x509/sigi/SigIObjectIdentifiers.cs
@@ -0,0 +1,49 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509.SigI
+{
+	/**
+	 * Object Identifiers of SigI specifciation (German Signature Law
+	 * Interoperability specification).
+	 */
+	public sealed class SigIObjectIdentifiers
+	{
+		private SigIObjectIdentifiers()
+		{
+		}
+
+		public readonly static DerObjectIdentifier IdSigI = new DerObjectIdentifier("1.3.36.8");
+
+		/**
+		* Key purpose IDs for German SigI (Signature Interoperability
+		* Specification)
+		*/
+		public readonly static DerObjectIdentifier IdSigIKP = new DerObjectIdentifier(IdSigI + ".2");
+
+		/**
+		* Certificate policy IDs for German SigI (Signature Interoperability
+		* Specification)
+		*/
+		public readonly static DerObjectIdentifier IdSigICP = new DerObjectIdentifier(IdSigI + ".1");
+
+		/**
+		* Other Name IDs for German SigI (Signature Interoperability Specification)
+		*/
+		public readonly static DerObjectIdentifier IdSigION = new DerObjectIdentifier(IdSigI + ".4");
+
+		/**
+		* To be used for for the generation of directory service certificates.
+		*/
+		public static readonly DerObjectIdentifier IdSigIKPDirectoryService = new DerObjectIdentifier(IdSigIKP + ".1");
+
+		/**
+		* ID for PersonalData
+		*/
+		public static readonly DerObjectIdentifier IdSigIONPersonalData = new DerObjectIdentifier(IdSigION + ".1");
+
+		/**
+		* Certificate is conform to german signature law.
+		*/
+		public static readonly DerObjectIdentifier IdSigICPSigConform = new DerObjectIdentifier(IdSigICP + ".1");
+	}
+}