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