From 44288db4414158ac9b98a507b15e81d0d3c66ca6 Mon Sep 17 00:00:00 2001
From: Peter Dettman It stores a string in a chosen encoding.
+ *
+ * AccessDescription ::= SEQUENCE {
+ * accessMethod OBJECT IDENTIFIER,
+ * accessLocation GeneralName }
+ *
+ */
+ 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.
+ *
+ * AlgorithmIdentifier ::= Sequence {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL }
+ *
+ */
+ 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
+ }
+
+ ///
+ * AttCertIssuer ::= CHOICE {
+ * v1Form GeneralNames, -- MUST NOT be used in this
+ * -- profile
+ * v2Form [0] V2Form -- v2 only
+ * }
+ *
+ */
+ 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.
+ *
+ * AttCertValidityPeriod ::= Sequence {
+ * notBeforeTime GeneralizedTime,
+ * notAfterTime GeneralizedTime
+ * }
+ *
+ */
+ 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.
+ *
+ * Attr ::= Sequence {
+ * attrType OBJECT IDENTIFIER,
+ * attrValues Set OF AttributeValue
+ * }
+ *
+ */
+ 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.
+ *
+ * AttributeCertificate ::= Sequence {
+ * acinfo AttributeCertificateInfo,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signatureValue BIT STRING
+ * }
+ *
+ */
+ 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.
+ *
+ * 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) }
+ *
+ */
+ 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.
+ *
+ * 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 }
+ *
+ */
+ 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.
+ *
+ * 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
+ *
+ *
+ */
+ 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:
+ *
+ * SubjectPublicKeyInfo apki = new SubjectPublicKeyInfo((ASN1Sequence)new ASN1InputStream(
+ * publicKey.getEncoded()).readObject());
+ * AuthorityKeyIdentifier aki = new AuthorityKeyIdentifier(apki);
+ *
+ *
+ **/
+ 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.
+ *
+ * BasicConstraints := Sequence {
+ * cA Boolean DEFAULT FALSE,
+ * pathLenConstraint Integer (0..MAX) OPTIONAL
+ * }
+ *
+ */
+ 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.
+ *
+ * CrlDistPoint ::= Sequence SIZE {1..MAX} OF DistributionPoint
+ *
+ */
+ 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.
+ *
+ * CRLNumber::= Integer(0..MAX)
+ *
+ */
+ 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.
+ *
+ * CRLReason ::= Enumerated {
+ * unspecified (0),
+ * keyCompromise (1),
+ * cACompromise (2),
+ * affiliationChanged (3),
+ * superseded (4),
+ * cessationOfOperation (5),
+ * certificateHold (6),
+ * removeFromCRL (8),
+ * privilegeWithdrawn (9),
+ * aACompromise (10)
+ * }
+ *
+ */
+ 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.
+ *
+ *
+ * CertPolicyId ::= OBJECT IDENTIFIER
+ *
+ */
+ 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.
+ *
+ *
+ * CertificateList ::= Sequence {
+ * tbsCertList TbsCertList,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signatureValue BIT STRING }
+ *
+ */
+ 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
+ *
+ *
+ * crossCertificatePairATTRIBUTE::={
+ * WITH SYNTAX CertificatePair
+ * EQUALITY MATCHING RULE certificatePairExactMatch
+ * ID joint-iso-ccitt(2) ds(5) attributeType(4) crossCertificatePair(40)}
+ *
+ *
+ * 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.
+ *
+ *
+ * CertificatePair ::= SEQUENCE {
+ * forward [0] Certificate OPTIONAL,
+ * reverse [1] Certificate OPTIONAL,
+ * -- at least one of the pair shall be present -- }
+ *
+ */
+ 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.
+ *
+ * The sequence is of type CertificatePair:
+ *
+ *
+ * CertificatePair ::= SEQUENCE {
+ * forward [0] Certificate OPTIONAL,
+ * reverse [1] Certificate OPTIONAL,
+ * -- at least one of the pair shall be present -- }
+ *
+ *
+ * @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.
+ *
+ * Returns:
+ *
+ *
+ * CertificatePair ::= SEQUENCE {
+ * forward [0] Certificate OPTIONAL,
+ * reverse [1] Certificate OPTIONAL,
+ * -- at least one of the pair shall be present -- }
+ *
+ *
+ * @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.
+ *
+ * CertificatePolicies ::= SEQUENCE SIZE {1..MAX} OF PolicyInformation
+ *
+ */
+ 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.
+ *
+ * DigestInfo::=Sequence{
+ * digestAlgorithm AlgorithmIdentifier,
+ * digest OCTET STRING }
+ *
+ */
+ 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
+{
+ /**
+ * DisplayText
class, used in
+ * CertificatePolicies
X509 V3 extensions (in policy qualifiers).
+ *
+ *
+ * DisplayText ::= CHOICE {
+ * ia5String IA5String (SIZE (1..200)),
+ * visibleString VisibleString (SIZE (1..200)),
+ * bmpString BMPString (SIZE (1..200)),
+ * utf8String UTF8String (SIZE (1..200)) }
+ *
DisplayTextMaximumSize
here.
+ *
+ */
+ public const int DisplayTextMaximumSize = 200;
+
+ internal readonly int contentType;
+ internal readonly IAsn1String contents;
+
+ /**
+ * Creates a new DisplayText
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 DisplayText
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 DisplayText
instance.
+ * Useful when reading back a DisplayText
class
+ * from it's Asn1Encodable form.
Asn1Encodable
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 string
object.
+ *
+ * @return the stored text as a string
.
+ */
+ 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.
+ * + * DistributionPoint ::= Sequence { + * distributionPoint [0] DistributionPointName OPTIONAL, + * reasons [1] ReasonFlags OPTIONAL, + * cRLIssuer [2] GeneralNames OPTIONAL + * } + *+ */ + 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. + *
+ * DistributionPointName ::= CHOICE { + * fullName [0] GeneralNames, + * nameRelativeToCRLIssuer [1] RDN + * } + *+ */ + 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. + *
+ * extendedKeyUsage ::= Sequence SIZE (1..MAX) OF KeyPurposeId + *+ */ + 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. + *
+ * 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 } + *+ */ + 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. + *
+ * This constructor can handle: + *
+ * 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. + *
+ * + * @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)); + } + + ///+ * GeneralNames ::= Sequence SIZE {1..MAX} OF GeneralName + *+ */ + 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. + * + *
+ * + * GeneralSubtree ::= SEQUENCE + * { + * baseName GeneralName, + * minimum [0] BaseDistance DEFAULT 0, + * maximum [1] BaseDistance OPTIONAL + * } + *+ * + * @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. + *
+ * If minimum is null
, zero is assumed, if
+ * maximum is null
, maximum is absent.
+ * GeneralSubtree ::= SEQUENCE + * { + * baseName GeneralName, + * minimum [0] BaseDistance DEFAULT 0, + * maximum [1] BaseDistance OPTIONAL + * } + *+ * + * @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. + *
+ * For an v2 attribute certificate this is: + * + *
+ * 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 + * } + *+ * + *
+ * For an v1 attribute certificate this is: + * + *
+ * subject CHOICE { + * baseCertificateID [0] IssuerSerial, + * -- associated with a Public Key Certificate + * subjectName [1] GeneralNames }, + * -- associated with a name + *+ * + */ + 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. + *
+ * Holder ::= Sequence { + * baseCertificateID [0] IssuerSerial OPTIONAL, + * -- the issuer and serial number of + * -- the holder's Public Key Certificate + * entityName [1] GeneralNames OPTIONAL, + * -- the name of the claimant or role + * objectDigestInfo [2] ObjectDigestInfo OPTIONAL + * -- used to directly authenticate the holder, + * -- for example, an executable + * } + *+ */ + public 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
IetfAttrSyntax
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;
+ }
+ }
+
+ /**
+ *
+ * + * + * IetfAttrSyntax ::= Sequence { + * policyAuthority [0] GeneralNames OPTIONAL, + * values Sequence OF CHOICE { + * octets OCTET STRING, + * oid OBJECT IDENTIFIER, + * string UTF8String + * } + * } + * + *+ */ + 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. + *
+ * IssuerSerial ::= Sequence { + * issuer GeneralNames, + * serial CertificateSerialNumber, + * issuerUid UniqueIdentifier OPTIONAL + * } + *+ */ + 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 +{ + /** + *
+ * 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 } + *+ */ + 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
true
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.
+ * + * KeyPurposeID ::= OBJECT IDENTIFIER + *+ */ + 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. + *
+ * id-ce-keyUsage OBJECT IDENTIFIER ::= { id-ce 15 } + * + * KeyUsage ::= BIT STRING { + * digitalSignature (0), + * nonRepudiation (1), + * keyEncipherment (2), + * dataEncipherment (3), + * keyAgreement (4), + * keyCertSign (5), + * cRLSign (6), + * encipherOnly (7), + * decipherOnly (8) } + *+ */ + public class 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. + * + *
permitted and excluded are Vectors of GeneralSubtree objects.
+ * + * @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 +{ + /** + *NoticeReference
class, used in
+ * CertificatePolicies
X509 V3 extensions
+ * (in policy qualifiers).
+ *
+ * + * NoticeReference ::= Sequence { + * organization DisplayText, + * noticeNumbers Sequence OF Integer } + * + *+ * + * @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
NoticeReference
instance.
+ *
+ * @param orgName a string
value
+ * @param numbers a ArrayList
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 NoticeReference
instance.
+ *
+ * @param orgName a string
value
+ * @param numbers an Asn1Sequence
value
+ */
+ public NoticeReference(
+ string orgName,
+ Asn1Sequence numbers)
+ {
+ organization = new DisplayText(orgName);
+ noticeNumbers = numbers;
+ }
+
+ /**
+ * Creates a new NoticeReference
instance.
+ *
+ * @param displayTextType an int
value
+ * @param orgName a string
value
+ * @param numbers an Asn1Sequence
value
+ */
+ public NoticeReference(
+ int displayTextType,
+ string orgName,
+ Asn1Sequence numbers)
+ {
+ organization = new DisplayText(displayTextType, orgName);
+ noticeNumbers = numbers;
+ }
+
+ /**
+ * Creates a new NoticeReference
instance.
+ * Useful for reconstructing a NoticeReference
+ * instance from its encodable/encoded form.
Asn1Sequence
value obtained from either
+ * calling @{link ToAsn1Object()} for a NoticeReference
+ * 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 ToAsn1Object
method here.
+ *
+ * @return a Asn1Object
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.
+ *
+ * + * + * 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 + * } + * + *+ * + */ + 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. + *
+ * If digestedObjectType
is not {@link #publicKeyCert} or
+ * {@link #publicKey} otherObjectTypeID
must be given,
+ * otherwise it is ignored.
otherObjectDigest
.
+ * @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.
+ *
+ * + * + * 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 + * } + * + *+ */ + 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. + *
+ * PolicyMappings ::= Sequence SIZE (1..MAX) OF Sequence { + * issuerDomainPolicy CertPolicyId, + * subjectDomainPolicy CertPolicyId } + *+ * + * @see RFC 3280, section 4.2.1.6 + */ + public class PolicyMappings + : Asn1Encodable + { + private readonly Asn1Sequence seq; + + /** + * Creates a new
PolicyMappings
instance.
+ *
+ * @param seq an Asn1Sequence
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 PolicyMappings
instance.
+ *
+ * @param mappings a HashMap
value that maps
+ * string
oids
+ * to other string
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.
+ *
+ * + * 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 ) + *+ */ + 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. + * + *
+ * PolicyQualifierInfo ::= Sequence { + * policyQualifierId PolicyQualifierId, + * qualifier ANY DEFINED BY policyQualifierId } + *+ */ + public class PolicyQualifierInfo + : Asn1Encodable + { + internal readonly DerObjectIdentifier policyQualifierId; + internal readonly Asn1Encodable qualifier; + + /** + * Creates a new
PolicyQualifierInfo
instance.
+ *
+ * @param policyQualifierId a PolicyQualifierId
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 PolicyQualifierInfo
containing a
+ * cPSuri qualifier.
+ *
+ * @param cps the CPS (certification practice statement) uri as a
+ * string
.
+ */
+ public PolicyQualifierInfo(
+ string cps)
+ {
+ policyQualifierId = PolicyQualifierID.IdQtCps;
+ qualifier = new DerIA5String(cps);
+ }
+
+ /**
+ * Creates a new PolicyQualifierInfo
instance.
+ *
+ * @param as PolicyQualifierInfo
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 Asn1Object
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
+{
+ /// + /// PrivateKeyUsagePeriod ::= SEQUENCE + /// { + /// notBefore [0] GeneralizedTime OPTIONAL, + /// notAfter [1] GeneralizedTime OPTIONAL } + ///+ ///
+ * RSAPublicKey ::= Sequence { + * modulus Integer, -- n + * publicExponent Integer, -- e + * } + *+ */ + 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. + *
+ * ReasonFlags ::= BIT STRING { + * unused(0), + * keyCompromise(1), + * cACompromise(2), + * affiliationChanged(3), + * superseded(4), + * cessationOfOperation(5), + * certficateHold(6) + * } + *+ */ + 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. + * + *
+ * RoleSyntax ::= SEQUENCE { + * roleAuthority [0] GeneralNames OPTIONAL, + * roleName [1] GeneralName + * } + *+ */ + 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
+ * RoleSyntax
. It must be an instance of RoleSyntax
+ *
or Asn1Sequence
.
+ * @return the instance of RoleSyntax
built from the
+ * supplied object.
+ * @throws java.lang.ArgumentException if the object passed
+ * to the factory is not an instance of RoleSyntax
or
+ * Asn1Sequence
.
+ */
+ 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
+ * new RoleSyntax(null, roleName)
.
+ * @param roleName the role name of this RoleSyntax.
+ */
+ public RoleSyntax(
+ GeneralName roleName)
+ : this(null, roleName)
+ {
+ }
+
+ /**
+ * Utility constructor. Takes a string
argument representing
+ * the role name, builds a GeneralName
to hold the role name
+ * and calls the constructor that takes a GeneralName
.
+ * @param roleName
+ */
+ public RoleSyntax(
+ string roleName)
+ : this(new GeneralName(GeneralName.UniformResourceIdentifier,
+ (roleName == null)? "": roleName))
+ {
+ }
+
+ /**
+ * Constructor that builds an instance of RoleSyntax
by
+ * extracting the encoded elements from the Asn1Sequence
+ * object supplied.
+ * @param seq an instance of Asn1Sequence
that holds
+ * the encoded elements used to build this RoleSyntax
.
+ */
+ 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 GeneralNames
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 GeneralName
holding the
+ * role name of this RoleSyntax.
+ */
+ public GeneralName RoleName
+ {
+ get { return this.roleName; }
+ }
+
+ /**
+ * Gets the role name as a java.lang.string
object.
+ * @return the role name of this RoleSyntax represented as a
+ * string
object.
+ */
+ public string GetRoleNameAsString()
+ {
+ return ((IAsn1String) this.roleName.Name).GetString();
+ }
+
+ /**
+ * Gets the role authority as a string[]
object.
+ * @return the role authority of this RoleSyntax represented as a
+ * string[]
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 ToAsn1Object
as
+ * required by the superclass ASN1Encodable
.
+ *
+ * + * RoleSyntax ::= SEQUENCE { + * roleAuthority [0] GeneralNames OPTIONAL, + * roleName [1] GeneralName + * } + *+ */ + 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. + * + *
+ * 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 + *+ * + * @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: + * + *
+ * 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 + *+ * + * @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: + * + *
+ * 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 + *+ * + * @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. + *
+ * SubjectKeyIdentifier::= OCTET STRING + *+ */ + 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: + *
+ * (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). + *+ * @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: + *
+ * (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. + *+ * @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. + *
+ * The GetEncoded() method in the public keys in the JCE produces a DER + * encoded one of these.
+ */ + 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. + *+ * SubjectPublicKeyInfo ::= Sequence { + * algorithm AlgorithmIdentifier, + * publicKey BIT STRING } + *+ */ + 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. + *
+ * 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 + * } + *+ */ + 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. + *
+ * 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 + * } + *+ *
+ * Note: issuerUniqueID and subjectUniqueID are both deprecated by the IETF. This class + * will parse them, but you really shouldn't be creating new ones.
+ */ + 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. + * + *+ * Target ::= CHOICE { + * targetName [0] GeneralName, + * targetGroup [1] GeneralName, + * targetCert [2] TargetCert + * } + *+ * + *
+ * The targetCert field is currently not supported and must not be used + * according to RFC 3281.
+ */ + 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. + *
+ * obj
can be a Target or a {@link Asn1TaggedObject}
+ * Exactly one of the parameters must be not null
.
+ * Target ::= CHOICE { + * targetName [0] GeneralName, + * targetGroup [1] GeneralName, + * targetCert [2] TargetCert + * } + *+ * + * @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. + * + *
+ * SEQUENCE OF Targets + *+ * + */ + public class TargetInformation + : Asn1Encodable + { + private readonly Asn1Sequence targets; + + /** + * Creates an instance of a TargetInformation from the given object. + *
+ * obj
can be a TargetInformation or a {@link Asn1Sequence}
+ * The ArrayList is cloned before it is returned.
+ * + * @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: + * + *+ * SEQUENCE OF Targets + *+ * + *
+ * 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.
+ * + * @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. + * + *+ * 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 + * } + *+ * + * @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. + *
+ * obj
can be a Targets or a {@link Asn1Sequence}
+ * The ArrayList is copied.
+ * + * @param targets AnArrayList
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 ArrayList
.
+ * + * The ArrayList is cloned before it is returned.
+ * + * @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: + * + *+ * Targets ::= SEQUENCE OF Target + *+ * + * @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(); + } + + ///
+ * Time ::= CHOICE { + * utcTime UTCTime, + * generalTime GeneralizedTime } + *+ */ + 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 +{ + /** + *
UserNotice
class, used in
+ * CertificatePolicies
X509 extensions (in policy
+ * qualifiers).
+ * + * UserNotice ::= Sequence { + * noticeRef NoticeReference OPTIONAL, + * explicitText DisplayText OPTIONAL} + * + *+ * + * @see PolicyQualifierId + * @see PolicyInformation + */ + public class UserNotice + : Asn1Encodable + { + internal NoticeReference noticeRef; + internal DisplayText explicitText; + + /** + * Creates a new
UserNotice
instance.
+ *
+ * @param noticeRef a NoticeReference
value
+ * @param explicitText a DisplayText
value
+ */
+ public UserNotice(
+ NoticeReference noticeRef,
+ DisplayText explicitText)
+ {
+ this.noticeRef = noticeRef;
+ this.explicitText = explicitText;
+ }
+
+ /**
+ * Creates a new UserNotice
instance.
+ *
+ * @param noticeRef a NoticeReference
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 UserNotice
instance.
+ * Useful from reconstructing a UserNotice
instance
+ * from its encodable/encoded form.
+ *
+ * @param as an ASN1Sequence
value obtained from either
+ * calling @{link toASN1Object()} for a UserNotice
+ * instance or from parsing it from a DER-encoded stream.
+ * TbsCertificate ::= Sequence { + * version [ 0 ] Version DEFAULT v1(0), + * serialNumber CertificateSerialNumber, + * signature AlgorithmIdentifier, + * issuer Name, + * validity Validity, + * subject Name, + * subjectPublicKeyInfo SubjectPublicKeyInfo, + * } + *+ * + */ + 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 + *
+ * 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 + * } + *+ * + */ + 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. + *
+ * 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 + * } + *+ */ + 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. + *
+ * 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 + * } + *+ * + * Note: This class may be subject to change + */ + 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. + *
+ * 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 + * } + *+ * + */ + 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. + *
+ * Certificate ::= Sequence { + * tbsCertificate TbsCertificate, + * signatureAlgorithm AlgorithmIdentifier, + * signature BIT STRING + * } + *+ */ + 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; + } + + ///
+ * it's is assumed the table contains Oid/string pairs.
+ */ + public X509Extensions( + IDictionary extensions) + : this(null, extensions) + { + } + + /** + * Constructor from a table of extensions with ordering. + *+ * It's is assumed the table contains Oid/string pairs.
+ */ + 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. + *+ * it's is assumed the table contains Oid/string pairs.
+ */ + [Obsolete] + public X509Extensions( + Hashtable extensions) + : this(null, extensions) + { + } + + /** + * Constructor from a table of extensions with ordering. + *+ * It's is assumed the table contains Oid/string pairs.
+ */ + [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]; + } + + /** + *+ * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension + * + * Extension ::= SEQUENCE { + * extnId EXTENSION.&id ({ExtensionSet}), + * critical BOOLEAN DEFAULT FALSE, + * extnValue OCTET STRING } + *+ */ + 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 +{ + ///
+ * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName + * + * RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue + * + * AttributeTypeAndValue ::= SEQUENCE { + * type OBJECT IDENTIFIER, + * value ANY } + *+ */ + 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. + *
Note: if you're trying to be ultra orthodox, don't use this! It shouldn't be in here.
+ */ + 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. + *+ * 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.
+ */ + 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. + *+ * 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.
+ *+ * The passed in converter will be used to convert the strings into their + * ASN.1 counterparts.
+ */ + 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. + *+ * The passed in converter will be used to convert the strings into their + * ASN.1 counterparts.
+ */ + 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. + *