diff options
-rw-r--r-- | crypto/src/asn1/Asn1Sequence.cs | 8 | ||||
-rw-r--r-- | crypto/src/asn1/Asn1TaggedObject.cs | 18 | ||||
-rw-r--r-- | crypto/src/asn1/BerSequence.cs | 14 | ||||
-rw-r--r-- | crypto/src/asn1/DERExternal.cs | 319 | ||||
-rw-r--r-- | crypto/src/asn1/DerSequence.cs | 10 |
5 files changed, 234 insertions, 135 deletions
diff --git a/crypto/src/asn1/Asn1Sequence.cs b/crypto/src/asn1/Asn1Sequence.cs index 286b731f5..ecc773a1a 100644 --- a/crypto/src/asn1/Asn1Sequence.cs +++ b/crypto/src/asn1/Asn1Sequence.cs @@ -128,6 +128,11 @@ namespace Org.BouncyCastle.Asn1 this.elements = Asn1EncodableVector.CloneElements(elements); } + internal Asn1Sequence(Asn1Encodable[] elements, bool clone) + { + this.elements = clone ? Asn1EncodableVector.CloneElements(elements) : elements; + } + protected internal Asn1Sequence(Asn1EncodableVector elementVector) { if (null == elementVector) @@ -248,5 +253,8 @@ namespace Org.BouncyCastle.Asn1 { return CollectionUtilities.ToString(elements); } + + // TODO[asn1] Preferably return an Asn1External (doesn't exist yet) + internal abstract DerExternal ToAsn1External(); } } diff --git a/crypto/src/asn1/Asn1TaggedObject.cs b/crypto/src/asn1/Asn1TaggedObject.cs index 501f877ab..5eb0441ed 100644 --- a/crypto/src/asn1/Asn1TaggedObject.cs +++ b/crypto/src/asn1/Asn1TaggedObject.cs @@ -145,12 +145,26 @@ namespace Org.BouncyCastle.Asn1 return obj.ToAsn1Object(); } - /** + /** + * Needed for open types, until we have better type-guided parsing support. Use + * sparingly for other purposes, and prefer {@link #getExplicitBaseTagged()} or + * {@link #getBaseUniversal(boolean, int)} where possible. Before using, check + * for matching tag {@link #getTagClass() class} and {@link #getTagNo() number}. + */ + public Asn1Object GetExplicitBaseObject() + { + if (!IsExplicit()) + throw new InvalidOperationException("object implicit - explicit expected."); + + return obj.ToAsn1Object(); + } + + /** * Return the object held in this tagged object as a parser assuming it has * the type of the passed in tag. If the object doesn't have a parser * associated with it, the base object is returned. */ - public IAsn1Convertible GetObjectParser( + public IAsn1Convertible GetObjectParser( int tag, bool isExplicit) { diff --git a/crypto/src/asn1/BerSequence.cs b/crypto/src/asn1/BerSequence.cs index 068f0a2a8..1795025f2 100644 --- a/crypto/src/asn1/BerSequence.cs +++ b/crypto/src/asn1/BerSequence.cs @@ -43,6 +43,11 @@ namespace Org.BouncyCastle.Asn1 { } + internal BerSequence(Asn1Encodable[] elements, bool clone) + : base(elements, clone) + { + } + internal override int EncodedLength(bool withID) { throw Platform.CreateNotImplementedException("BerSequence.EncodedLength"); @@ -59,5 +64,12 @@ namespace Org.BouncyCastle.Asn1 base.Encode(asn1Out, withID); } } - } + + internal override DerExternal ToAsn1External() + { + // TODO There is currently no BerExternal class (or ToDLObject/ToDerObject) + //return ((Asn1Sequence)ToDLObject()).ToAsn1External(); + return new DerSequence(elements, false).ToAsn1External(); + } + } } diff --git a/crypto/src/asn1/DERExternal.cs b/crypto/src/asn1/DERExternal.cs index f457917ca..faf64c266 100644 --- a/crypto/src/asn1/DERExternal.cs +++ b/crypto/src/asn1/DERExternal.cs @@ -11,54 +11,98 @@ namespace Org.BouncyCastle.Asn1 public class DerExternal : Asn1Object { - private DerObjectIdentifier directReference; - private DerInteger indirectReference; - private Asn1Object dataValueDescriptor; - private int encoding; - private Asn1Object externalContent; - - public DerExternal( - Asn1EncodableVector vector) + public static DerExternal GetInstance(object obj) + { + if (obj == null || obj is DerExternal) + { + return (DerExternal)obj; + } + if (obj is Asn1Encodable) + { + Asn1Object asn1 = ((Asn1Encodable)obj).ToAsn1Object(); + if (asn1 is DerExternal) + return (DerExternal)asn1; + } + if (obj is byte[]) + { + try + { + return GetInstance(FromByteArray((byte[])obj)); + } + catch (Exception e) + { + throw new ArgumentException("encoding error in GetInstance: " + e.ToString(), "obj"); + } + } + + throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj), "obj"); + } + + public static DerExternal GetInstance(Asn1TaggedObject taggedObject, bool isExplicit) + { + Asn1Object baseObject = taggedObject.GetObject(); + + if (isExplicit || baseObject is DerExternal) + { + return GetInstance(baseObject); + } + + return Asn1Sequence.GetInstance(taggedObject, false).ToAsn1External(); + } + + private readonly DerObjectIdentifier directReference; + private readonly DerInteger indirectReference; + private readonly Asn1ObjectDescriptor dataValueDescriptor; + private readonly int encoding; + private readonly Asn1Object externalContent; + + [Obsolete("Use constructor taking an Asn1Sequence instead.")] + public DerExternal(Asn1EncodableVector vector) + : this(new DerSequence(vector)) + { + } + + public DerExternal(DerSequence sequence) { int offset = 0; - Asn1Object enc = GetObjFromVector(vector, offset); - if (enc is DerObjectIdentifier) + + Asn1Object asn1 = GetObjFromSequence(sequence, offset); + if (asn1 is DerObjectIdentifier) { - directReference = (DerObjectIdentifier)enc; - offset++; - enc = GetObjFromVector(vector, offset); + directReference = (DerObjectIdentifier)asn1; + asn1 = GetObjFromSequence(sequence, ++offset); } - if (enc is DerInteger) + if (asn1 is DerInteger) { - indirectReference = (DerInteger) enc; - offset++; - enc = GetObjFromVector(vector, offset); + indirectReference = (DerInteger)asn1; + asn1 = GetObjFromSequence(sequence, ++offset); } - if (!(enc is Asn1TaggedObject)) + if (!(asn1 is Asn1TaggedObject)) { - dataValueDescriptor = enc; - offset++; - enc = GetObjFromVector(vector, offset); + dataValueDescriptor = (Asn1ObjectDescriptor)asn1; + asn1 = GetObjFromSequence(sequence, ++offset); } - if (vector.Count != offset + 1) - throw new ArgumentException("input vector too large", "vector"); + if (sequence.Count != offset + 1) + throw new ArgumentException("input sequence too large", "sequence"); - if (!(enc is Asn1TaggedObject)) - throw new ArgumentException("No tagged object found in vector. Structure doesn't seem to be of type External", "vector"); + if (!(asn1 is Asn1TaggedObject)) + throw new ArgumentException( + "No tagged object found in sequence. Structure doesn't seem to be of type External", "sequence"); - Asn1TaggedObject obj = (Asn1TaggedObject)enc; - - // Use property accessor to include check on value - Encoding = obj.TagNo; - - if (encoding < 0 || encoding > 2) - throw new InvalidOperationException("invalid encoding value"); + Asn1TaggedObject obj = (Asn1TaggedObject)asn1; + this.encoding = CheckEncoding(obj.TagNo); + this.externalContent = GetExternalContent(obj); + } - externalContent = obj.GetObject(); + [Obsolete("Use constructor with dataValueDescriptor of type Asn1ObjectDescriptor")] + public DerExternal(DerObjectIdentifier directReference, DerInteger indirectReference, + Asn1Object dataValueDescriptor, DerTaggedObject externalData) + : this(directReference, indirectReference, CheckDataValueDescriptor(dataValueDescriptor), externalData) + { } - /** + /** * Creates a new instance of DerExternal * See X.690 for more informations about the meaning of these parameters * @param directReference The direct reference or <code>null</code> if not set. @@ -66,12 +110,25 @@ namespace Org.BouncyCastle.Asn1 * @param dataValueDescriptor The data value descriptor or <code>null</code> if not set. * @param externalData The external data in its encoded form. */ - public DerExternal(DerObjectIdentifier directReference, DerInteger indirectReference, Asn1Object dataValueDescriptor, DerTaggedObject externalData) - : this(directReference, indirectReference, dataValueDescriptor, externalData.TagNo, externalData.ToAsn1Object()) + public DerExternal(DerObjectIdentifier directReference, DerInteger indirectReference, + Asn1ObjectDescriptor dataValueDescriptor, DerTaggedObject externalData) + { + this.directReference = directReference; + this.indirectReference = indirectReference; + this.dataValueDescriptor = dataValueDescriptor; + this.encoding = CheckEncoding(externalData.TagNo); + this.externalContent = GetExternalContent(externalData); + } + + [Obsolete("Use constructor with dataValueDescriptor of type Asn1ObjectDescriptor")] + public DerExternal(DerObjectIdentifier directReference, DerInteger indirectReference, + Asn1Object dataValueDescriptor, int encoding, Asn1Object externalData) + : this(directReference, indirectReference, CheckDataValueDescriptor(dataValueDescriptor), encoding, + externalData) { } - /** + /** * Creates a new instance of DerExternal. * See X.690 for more informations about the meaning of these parameters * @param directReference The direct reference or <code>null</code> if not set. @@ -80,96 +137,63 @@ namespace Org.BouncyCastle.Asn1 * @param encoding The encoding to be used for the external data * @param externalData The external data */ - public DerExternal(DerObjectIdentifier directReference, DerInteger indirectReference, Asn1Object dataValueDescriptor, int encoding, Asn1Object externalData) - { - DirectReference = directReference; - IndirectReference = indirectReference; - DataValueDescriptor = dataValueDescriptor; - Encoding = encoding; - ExternalContent = externalData.ToAsn1Object(); - } - - internal override int EncodedLength(bool withID) + public DerExternal(DerObjectIdentifier directReference, DerInteger indirectReference, + Asn1ObjectDescriptor dataValueDescriptor, int encoding, Asn1Object externalData) { - int contentsLength = 0; - if (directReference != null) - { - contentsLength += directReference.EncodedLength(true); - } - if (indirectReference != null) - { - contentsLength += indirectReference.EncodedLength(true); - } - if (dataValueDescriptor != null) - { - // TODO[asn1] - //contentsLength += dataValueDescriptor.ToDerObject().EncodedLength(true); - contentsLength += dataValueDescriptor.GetDerEncoded().Length; - } + this.directReference = directReference; + this.indirectReference = indirectReference; + this.dataValueDescriptor = dataValueDescriptor; + this.encoding = CheckEncoding(encoding); + this.externalContent = CheckExternalContent(encoding, externalData); + } - // TODO[asn1] - //contentsLength += new DerTaggedObject(true, encoding, externalContent).EncodedLength(true); - contentsLength += new DerTaggedObject(Asn1Tags.External, externalContent).EncodedLength(true); + internal Asn1Sequence BuildSequence() + { + Asn1EncodableVector v = new Asn1EncodableVector(4); + v.AddOptional(directReference, indirectReference, dataValueDescriptor); + v.Add(new DerTaggedObject(0 == encoding, encoding, externalContent)); + return new DerSequence(v); + } - return Asn1OutputStream.GetLengthOfEncodingDL(withID, contentsLength); + internal override int EncodedLength(bool withID) + { + return BuildSequence().EncodedLength(withID); } internal override void Encode(Asn1OutputStream asn1Out, bool withID) - { - MemoryStream ms = new MemoryStream(); - WriteEncodable(ms, directReference); - WriteEncodable(ms, indirectReference); - WriteEncodable(ms, dataValueDescriptor); - WriteEncodable(ms, new DerTaggedObject(Asn1Tags.External, externalContent)); - - asn1Out.WriteEncodingDL(withID, Asn1Tags.Constructed | Asn1Tags.External, ms.ToArray()); - } + { + asn1Out.WriteIdentifier(withID, Asn1Tags.Constructed | Asn1Tags.External); + BuildSequence().Encode(asn1Out, false); + } - protected override int Asn1GetHashCode() + protected override int Asn1GetHashCode() { - int ret = externalContent.GetHashCode(); - if (directReference != null) - { - ret ^= directReference.GetHashCode(); - } - if (indirectReference != null) - { - ret ^= indirectReference.GetHashCode(); - } - if (dataValueDescriptor != null) - { - ret ^= dataValueDescriptor.GetHashCode(); - } - return ret; + return Platform.GetHashCode(this.directReference) + ^ Platform.GetHashCode(this.indirectReference) + ^ Platform.GetHashCode(this.dataValueDescriptor) + ^ this.encoding + ^ this.externalContent.GetHashCode(); } - protected override bool Asn1Equals( - Asn1Object asn1Object) + protected override bool Asn1Equals(Asn1Object asn1Object) { - if (this == asn1Object) - return true; - - DerExternal other = asn1Object as DerExternal; - - if (other == null) - return false; - - return Platform.Equals(directReference, other.directReference) - && Platform.Equals(indirectReference, other.indirectReference) - && Platform.Equals(dataValueDescriptor, other.dataValueDescriptor) - && externalContent.Equals(other.externalContent); + DerExternal that = asn1Object as DerExternal; + return null != that + && Platform.Equals(this.directReference, that.directReference) + && Platform.Equals(this.indirectReference, that.indirectReference) + && Platform.Equals(this.dataValueDescriptor, that.dataValueDescriptor) + && this.encoding == that.encoding + && this.externalContent.Equals(that.externalContent); } - public Asn1Object DataValueDescriptor + public Asn1ObjectDescriptor DataValueDescriptor { get { return dataValueDescriptor; } - set { this.dataValueDescriptor = value; } } public DerObjectIdentifier DirectReference { get { return directReference; } - set { this.directReference = value; } } /** @@ -182,46 +206,77 @@ namespace Org.BouncyCastle.Asn1 */ public int Encoding { - get - { - return encoding; - } - set - { - if (encoding < 0 || encoding > 2) - throw new InvalidOperationException("invalid encoding value: " + encoding); - - this.encoding = value; - } + get { return encoding; } } public Asn1Object ExternalContent { get { return externalContent; } - set { this.externalContent = value; } } public DerInteger IndirectReference { get { return indirectReference; } - set { this.indirectReference = value; } } - private static Asn1Object GetObjFromVector(Asn1EncodableVector v, int index) - { - if (v.Count <= index) - throw new ArgumentException("too few objects in input vector", "v"); + private static Asn1ObjectDescriptor CheckDataValueDescriptor(Asn1Object dataValueDescriptor) + { + if (dataValueDescriptor is Asn1ObjectDescriptor) + return (Asn1ObjectDescriptor)dataValueDescriptor; + if (dataValueDescriptor is DerGraphicString) + return new Asn1ObjectDescriptor((DerGraphicString)dataValueDescriptor); - return v[index].ToAsn1Object(); - } + throw new ArgumentException("incompatible type for data-value-descriptor", "dataValueDescriptor"); + } - private static void WriteEncodable(MemoryStream ms, Asn1Encodable e) + private static int CheckEncoding(int encoding) + { + if (encoding < 0 || encoding > 2) + throw new InvalidOperationException("invalid encoding value: " + encoding); + + return encoding; + } + + private static Asn1Object CheckExternalContent(int tagNo, Asn1Object externalContent) + { + switch (tagNo) + { + case 1: + //return ASN1OctetString.TYPE.checkedCast(externalContent); + return (Asn1OctetString)externalContent; + case 2: + //return ASN1BitString.TYPE.checkedCast(externalContent); + return (DerBitString)externalContent; + default: + return externalContent; + } + } + + private static Asn1Object GetExternalContent(Asn1TaggedObject encoding) + { + int tagClass = encoding.TagClass, tagNo = encoding.TagNo; + if (Asn1Tags.ContextSpecific != tagClass) + throw new ArgumentException("invalid tag: " + Asn1Utilities.GetTagText(tagClass, tagNo), "encoding"); + + switch (tagNo) + { + case 0: + return encoding.GetExplicitBaseObject(); + case 1: + return Asn1OctetString.GetInstance(encoding, false); + case 2: + return DerBitString.GetInstance(encoding, false); + default: + throw new ArgumentException("invalid tag: " + Asn1Utilities.GetTagText(tagClass, tagNo), "encoding"); + } + } + + private static Asn1Object GetObjFromSequence(Asn1Sequence sequence, int index) { - if (e != null) - { - byte[] bs = e.GetDerEncoded(); - ms.Write(bs, 0, bs.Length); - } + if (sequence.Count <= index) + throw new ArgumentException("too few objects in input sequence", "sequence"); + + return sequence[index].ToAsn1Object(); } } } diff --git a/crypto/src/asn1/DerSequence.cs b/crypto/src/asn1/DerSequence.cs index 6750b8a50..d703cd0f5 100644 --- a/crypto/src/asn1/DerSequence.cs +++ b/crypto/src/asn1/DerSequence.cs @@ -45,6 +45,11 @@ namespace Org.BouncyCastle.Asn1 { } + internal DerSequence(Asn1Encodable[] elements, bool clone) + : base(elements, clone) + { + } + internal override int EncodedLength(bool withID) { throw Platform.CreateNotImplementedException("DerSequence.EncodedLength"); @@ -84,5 +89,10 @@ namespace Org.BouncyCastle.Asn1 Platform.Dispose(dOut); } + + internal override DerExternal ToAsn1External() + { + return new DerExternal(this); + } } } |