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);
+ }
}
}
|