From ad0b6c99d34da50d5473a9c14837a9ce199d0200 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Wed, 19 Feb 2020 21:03:22 +0700 Subject: ASN.1 updates from bc-java --- crypto/src/asn1/ASN1StreamParser.cs | 11 +-- crypto/src/asn1/Asn1InputStream.cs | 110 +++++++++++++++++++++------ crypto/src/asn1/Asn1OctetString.cs | 15 +--- crypto/src/asn1/BerOctetString.cs | 103 ++++++++++++++----------- crypto/src/asn1/ConstructedOctetStream.cs | 45 ++++++----- crypto/src/asn1/DefiniteLengthInputStream.cs | 23 ++++-- crypto/src/asn1/DerBMPString.cs | 28 +++++-- crypto/src/asn1/DerInteger.cs | 25 ++++++ crypto/src/asn1/DerOctetString.cs | 12 ++- crypto/src/asn1/LimitedInputStream.cs | 19 ++--- crypto/src/asn1/cms/SignedData.cs | 13 ++-- 11 files changed, 261 insertions(+), 143 deletions(-) (limited to 'crypto/src/asn1') diff --git a/crypto/src/asn1/ASN1StreamParser.cs b/crypto/src/asn1/ASN1StreamParser.cs index 3eaaadaee..860dc99b1 100644 --- a/crypto/src/asn1/ASN1StreamParser.cs +++ b/crypto/src/asn1/ASN1StreamParser.cs @@ -59,7 +59,7 @@ namespace Org.BouncyCastle.Asn1 if (_in is IndefiniteLengthInputStream) { if (!constructed) - throw new IOException("indefinite length primitive encoding encountered"); + throw new IOException("indefinite-length primitive encoding encountered"); return ReadIndef(tag); } @@ -134,12 +134,13 @@ namespace Org.BouncyCastle.Asn1 // // calculate length // - int length = Asn1InputStream.ReadLength(_in, _limit); + int length = Asn1InputStream.ReadLength(_in, _limit, + tagNo == Asn1Tags.OctetString || tagNo == Asn1Tags.Sequence || tagNo == Asn1Tags.Set || tagNo == Asn1Tags.External); - if (length < 0) // indefinite length method + if (length < 0) // indefinite-length method { if (!isConstructed) - throw new IOException("indefinite length primitive encoding encountered"); + throw new IOException("indefinite-length primitive encoding encountered"); IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(_in, _limit); Asn1StreamParser sp = new Asn1StreamParser(indIn, _limit); @@ -158,7 +159,7 @@ namespace Org.BouncyCastle.Asn1 } else { - DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(_in, length); + DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(_in, length, _limit); if ((tag & Asn1Tags.Application) != 0) { diff --git a/crypto/src/asn1/Asn1InputStream.cs b/crypto/src/asn1/Asn1InputStream.cs index 0c7461c98..4f99301b3 100644 --- a/crypto/src/asn1/Asn1InputStream.cs +++ b/crypto/src/asn1/Asn1InputStream.cs @@ -2,6 +2,7 @@ using System; using System.Diagnostics; using System.IO; +using Org.BouncyCastle.Utilities; using Org.BouncyCastle.Utilities.IO; namespace Org.BouncyCastle.Asn1 @@ -22,10 +23,12 @@ namespace Org.BouncyCastle.Asn1 internal static int FindLimit(Stream input) { if (input is LimitedInputStream) - { - return ((LimitedInputStream)input).GetRemaining(); - } - else if (input is MemoryStream) + return ((LimitedInputStream)input).Limit; + + if (input is Asn1InputStream) + return ((Asn1InputStream)input).Limit; + + if (input is MemoryStream) { MemoryStream mem = (MemoryStream)input; return (int)(mem.Length - mem.Position); @@ -77,7 +80,7 @@ namespace Org.BouncyCastle.Asn1 { bool isConstructed = (tag & Asn1Tags.Constructed) != 0; - DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(this.s, length); + DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(this.s, length, limit); if ((tag & Asn1Tags.Application) != 0) { @@ -95,10 +98,27 @@ namespace Org.BouncyCastle.Asn1 switch (tagNo) { case Asn1Tags.OctetString: + { // // yes, people actually do this... // - return new BerOctetString(ReadVector(defIn)); + Asn1EncodableVector v = ReadVector(defIn); + Asn1OctetString[] strings = new Asn1OctetString[v.Count]; + + for (int i = 0; i != strings.Length; i++) + { + Asn1Encodable asn1Obj = v[i]; + if (!(asn1Obj is Asn1OctetString)) + { + throw new Asn1Exception("unknown object encountered in constructed OCTET STRING: " + + Platform.GetTypeName(asn1Obj)); + } + + strings[i] = (Asn1OctetString)asn1Obj; + } + + return new BerOctetString(strings); + } case Asn1Tags.Sequence: return CreateDerSequence(defIn); case Asn1Tags.Set: @@ -162,12 +182,12 @@ namespace Org.BouncyCastle.Asn1 // // calculate length // - int length = ReadLength(this.s, limit); + int length = ReadLength(this.s, limit, false); - if (length < 0) // indefinite length method + if (length < 0) // indefinite-length method { if (!isConstructed) - throw new IOException("indefinite length primitive encoding encountered"); + throw new IOException("indefinite-length primitive encoding encountered"); IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(this.s, limit); Asn1StreamParser sp = new Asn1StreamParser(indIn, limit); @@ -210,6 +230,11 @@ namespace Org.BouncyCastle.Asn1 } } + internal virtual int Limit + { + get { return limit; } + } + internal static int ReadTagNumber( Stream s, int tag) @@ -228,9 +253,7 @@ namespace Org.BouncyCastle.Asn1 // X.690-0207 8.1.2.4.2 // "c) bits 7 to 1 of the first subsequent octet shall not all be zero." if ((b & 0x7f) == 0) // Note: -1 will pass - { - throw new IOException("Corrupted stream - invalid high tag number found"); - } + throw new IOException("corrupted stream - invalid high tag number found"); while ((b >= 0) && ((b & 0x80) != 0)) { @@ -248,9 +271,7 @@ namespace Org.BouncyCastle.Asn1 return tagNo; } - internal static int ReadLength( - Stream s, - int limit) + internal static int ReadLength(Stream s, int limit, bool isParsing) { int length = s.ReadByte(); if (length < 0) @@ -279,18 +300,18 @@ namespace Org.BouncyCastle.Asn1 } if (length < 0) - throw new IOException("Corrupted stream - negative length found"); + throw new IOException("corrupted stream - negative length found"); - if (length >= limit) // after all we must have read at least 1 byte - throw new IOException("Corrupted stream - out of bounds length found"); + if (length >= limit && !isParsing) // after all we must have read at least 1 byte + throw new IOException("corrupted stream - out of bounds length found: " + length + " >= " + limit); } return length; } - internal static byte[] GetBuffer(DefiniteLengthInputStream defIn, byte[][] tmpBuffers) + private static byte[] GetBuffer(DefiniteLengthInputStream defIn, byte[][] tmpBuffers) { - int len = defIn.GetRemaining(); + int len = defIn.Remaining; if (len >= tmpBuffers.Length) { return defIn.ToArray(); @@ -307,6 +328,49 @@ namespace Org.BouncyCastle.Asn1 return buf; } + private static char[] GetBmpCharBuffer(DefiniteLengthInputStream defIn) + { + int remainingBytes = defIn.Remaining; + if (0 != (remainingBytes & 1)) + throw new IOException("malformed BMPString encoding encountered"); + + char[] str = new char[remainingBytes / 2]; + int stringPos = 0; + + byte[] buf = new byte[8]; + while (remainingBytes >= 8) + { + if (Streams.ReadFully(defIn, buf, 0, 8) != 8) + throw new EndOfStreamException("EOF encountered in middle of BMPString"); + + str[stringPos ] = (char)((buf[0] << 8) | (buf[1] & 0xFF)); + str[stringPos + 1] = (char)((buf[2] << 8) | (buf[3] & 0xFF)); + str[stringPos + 2] = (char)((buf[4] << 8) | (buf[5] & 0xFF)); + str[stringPos + 3] = (char)((buf[6] << 8) | (buf[7] & 0xFF)); + stringPos += 4; + remainingBytes -= 8; + } + if (remainingBytes > 0) + { + if (Streams.ReadFully(defIn, buf, 0, remainingBytes) != remainingBytes) + throw new EndOfStreamException("EOF encountered in middle of BMPString"); + + int bufPos = 0; + do + { + int b1 = buf[bufPos++] << 8; + int b2 = buf[bufPos++] & 0xFF; + str[stringPos++] = (char)(b1 | b2); + } + while (bufPos < remainingBytes); + } + + if (0 != defIn.Remaining || str.Length != stringPos) + throw new InvalidOperationException(); + + return str; + } + internal static Asn1Object CreatePrimitiveDerObject( int tagNo, DefiniteLengthInputStream defIn, @@ -314,6 +378,8 @@ namespace Org.BouncyCastle.Asn1 { switch (tagNo) { + case Asn1Tags.BmpString: + return new DerBmpString(GetBmpCharBuffer(defIn)); case Asn1Tags.Boolean: return DerBoolean.FromOctetString(GetBuffer(defIn, tmpBuffers)); case Asn1Tags.Enumerated: @@ -328,8 +394,6 @@ namespace Org.BouncyCastle.Asn1 { case Asn1Tags.BitString: return DerBitString.FromAsn1Octets(bytes); - case Asn1Tags.BmpString: - return new DerBmpString(bytes); case Asn1Tags.GeneralizedTime: return new DerGeneralizedTime(bytes); case Asn1Tags.GeneralString: @@ -339,7 +403,7 @@ namespace Org.BouncyCastle.Asn1 case Asn1Tags.IA5String: return new DerIA5String(bytes); case Asn1Tags.Integer: - return new DerInteger(bytes); + return new DerInteger(bytes, false); case Asn1Tags.Null: return DerNull.Instance; // actual content is ignored (enforce 0 length?) case Asn1Tags.NumericString: diff --git a/crypto/src/asn1/Asn1OctetString.cs b/crypto/src/asn1/Asn1OctetString.cs index 73b6e51bf..da7dfae46 100644 --- a/crypto/src/asn1/Asn1OctetString.cs +++ b/crypto/src/asn1/Asn1OctetString.cs @@ -67,20 +67,7 @@ namespace Org.BouncyCastle.Asn1 this.str = str; } - internal Asn1OctetString( - Asn1Encodable obj) - { - try - { - this.str = obj.GetEncoded(Asn1Encodable.Der); - } - catch (IOException e) - { - throw new ArgumentException("Error processing object : " + e.ToString()); - } - } - - public Stream GetOctetStream() + public Stream GetOctetStream() { return new MemoryStream(str, false); } diff --git a/crypto/src/asn1/BerOctetString.cs b/crypto/src/asn1/BerOctetString.cs index a7c8ad33e..fb4291612 100644 --- a/crypto/src/asn1/BerOctetString.cs +++ b/crypto/src/asn1/BerOctetString.cs @@ -9,66 +9,77 @@ namespace Org.BouncyCastle.Asn1 public class BerOctetString : DerOctetString, IEnumerable { - public static BerOctetString FromSequence(Asn1Sequence seq) - { - IList v = Platform.CreateArrayList(); - - foreach (Asn1Encodable obj in seq) - { - v.Add(obj); - } - - return new BerOctetString(v); - } + private static readonly int DefaultChunkSize = 1000; - private const int MaxLength = 1000; + public static BerOctetString FromSequence(Asn1Sequence seq) + { + int count = seq.Count; + Asn1OctetString[] v = new Asn1OctetString[count]; + for (int i = 0; i < count; ++i) + { + v[i] = Asn1OctetString.GetInstance(seq[i]); + } + return new BerOctetString(v); + } - /** - * convert a vector of octet strings into a single byte string - */ - private static byte[] ToBytes( - IEnumerable octs) + private static byte[] ToBytes(Asn1OctetString[] octs) { MemoryStream bOut = new MemoryStream(); - foreach (DerOctetString o in octs) - { + foreach (Asn1OctetString o in octs) + { byte[] octets = o.GetOctets(); bOut.Write(octets, 0, octets.Length); } - return bOut.ToArray(); + return bOut.ToArray(); + } + + private static Asn1OctetString[] ToOctetStringArray(IEnumerable e) + { + IList list = Platform.CreateArrayList(e); + + int count = list.Count; + Asn1OctetString[] v = new Asn1OctetString[count]; + for (int i = 0; i < count; ++i) + { + v[i] = Asn1OctetString.GetInstance(list[i]); + } + return v; } - private readonly IEnumerable octs; + private readonly int chunkSize; + private readonly Asn1OctetString[] octs; + + [Obsolete("Will be removed")] + public BerOctetString(IEnumerable e) + : this(ToOctetStringArray(e)) + { + } - /// The octets making up the octet string. - public BerOctetString( - byte[] str) - : base(str) + public BerOctetString(byte[] str) + : this(str, DefaultChunkSize) { } - public BerOctetString( - IEnumerable octets) - : base(ToBytes(octets)) + public BerOctetString(Asn1OctetString[] octs) + : this(octs, DefaultChunkSize) { - this.octs = octets; } - public BerOctetString( - Asn1Object obj) - : base(obj) + public BerOctetString(byte[] str, int chunkSize) + : this(str, null, chunkSize) { } - public BerOctetString( - Asn1Encodable obj) - : base(obj.ToAsn1Object()) + public BerOctetString(Asn1OctetString[] octs, int chunkSize) + : this(ToBytes(octs), octs, chunkSize) { } - public override byte[] GetOctets() + private BerOctetString(byte[] str, Asn1OctetString[] octs, int chunkSize) + : base(str) { - return str; + this.octs = octs; + this.chunkSize = chunkSize; } /** @@ -93,17 +104,17 @@ namespace Org.BouncyCastle.Asn1 private IList GenerateOcts() { IList vec = Platform.CreateArrayList(); - for (int i = 0; i < str.Length; i += MaxLength) - { - int end = System.Math.Min(str.Length, i + MaxLength); + for (int i = 0; i < str.Length; i += chunkSize) + { + int end = System.Math.Min(str.Length, i + chunkSize); - byte[] nStr = new byte[end - i]; + byte[] nStr = new byte[end - i]; - Array.Copy(str, i, nStr, 0, nStr.Length); + Array.Copy(str, i, nStr, 0, nStr.Length); - vec.Add(new DerOctetString(nStr)); - } - return vec; + vec.Add(new DerOctetString(nStr)); + } + return vec; } internal override void Encode( @@ -118,7 +129,7 @@ namespace Org.BouncyCastle.Asn1 // // write out the octet array // - foreach (DerOctetString oct in this) + foreach (Asn1OctetString oct in this) { derOut.WriteObject(oct); } diff --git a/crypto/src/asn1/ConstructedOctetStream.cs b/crypto/src/asn1/ConstructedOctetStream.cs index 1773b22cc..829a9a427 100644 --- a/crypto/src/asn1/ConstructedOctetStream.cs +++ b/crypto/src/asn1/ConstructedOctetStream.cs @@ -1,5 +1,6 @@ using System.IO; +using Org.BouncyCastle.Utilities; using Org.BouncyCastle.Utilities.IO; namespace Org.BouncyCastle.Asn1 @@ -25,13 +26,12 @@ namespace Org.BouncyCastle.Asn1 if (!_first) return 0; - Asn1OctetStringParser s = (Asn1OctetStringParser)_parser.ReadObject(); - - if (s == null) - return 0; + Asn1OctetStringParser next = GetNextParser(); + if (next == null) + return 0; _first = false; - _currentStream = s.GetOctetStream(); + _currentStream = next.GetOctetStream(); } int totalRead = 0; @@ -49,15 +49,14 @@ namespace Org.BouncyCastle.Asn1 } else { - Asn1OctetStringParser aos = (Asn1OctetStringParser)_parser.ReadObject(); - - if (aos == null) + Asn1OctetStringParser next = GetNextParser(); + if (next == null) { _currentStream = null; return totalRead; } - _currentStream = aos.GetOctetStream(); + _currentStream = next.GetOctetStream(); } } } @@ -69,13 +68,12 @@ namespace Org.BouncyCastle.Asn1 if (!_first) return 0; - Asn1OctetStringParser s = (Asn1OctetStringParser)_parser.ReadObject(); - - if (s == null) + Asn1OctetStringParser next = GetNextParser(); + if (next == null) return 0; _first = false; - _currentStream = s.GetOctetStream(); + _currentStream = next.GetOctetStream(); } for (;;) @@ -83,20 +81,29 @@ namespace Org.BouncyCastle.Asn1 int b = _currentStream.ReadByte(); if (b >= 0) - { return b; - } - - Asn1OctetStringParser aos = (Asn1OctetStringParser)_parser.ReadObject(); - if (aos == null) + Asn1OctetStringParser next = GetNextParser(); + if (next == null) { _currentStream = null; return -1; } - _currentStream = aos.GetOctetStream(); + _currentStream = next.GetOctetStream(); } } + + private Asn1OctetStringParser GetNextParser() + { + IAsn1Convertible asn1Obj = _parser.ReadObject(); + if (asn1Obj == null) + return null; + + if (asn1Obj is Asn1OctetStringParser) + return (Asn1OctetStringParser)asn1Obj; + + throw new IOException("unknown object encountered: " + Platform.GetTypeName(asn1Obj)); + } } } diff --git a/crypto/src/asn1/DefiniteLengthInputStream.cs b/crypto/src/asn1/DefiniteLengthInputStream.cs index 4ae803c0e..d10ea4d12 100644 --- a/crypto/src/asn1/DefiniteLengthInputStream.cs +++ b/crypto/src/asn1/DefiniteLengthInputStream.cs @@ -13,10 +13,8 @@ namespace Org.BouncyCastle.Asn1 private readonly int _originalLength; private int _remaining; - internal DefiniteLengthInputStream( - Stream inStream, - int length) - : base(inStream, length) + internal DefiniteLengthInputStream(Stream inStream, int length, int limit) + : base(inStream, limit) { if (length < 0) throw new ArgumentException("negative lengths not allowed", "length"); @@ -30,7 +28,7 @@ namespace Org.BouncyCastle.Asn1 } } - internal int Remaining + internal int Remaining { get { return _remaining; } } @@ -80,6 +78,14 @@ namespace Org.BouncyCastle.Asn1 if (_remaining != buf.Length) throw new ArgumentException("buffer length not right for data"); + if (_remaining == 0) + return; + + // make sure it's safe to do this! + int limit = Limit; + if (_remaining >= limit) + throw new IOException("corrupted stream - out of bounds length found: " + _remaining + " >= " + limit); + if ((_remaining -= Streams.ReadFully(_in, buf)) != 0) throw new EndOfStreamException("DEF length " + _originalLength + " object truncated by " + _remaining); SetParentEofDetect(true); @@ -90,7 +96,12 @@ namespace Org.BouncyCastle.Asn1 if (_remaining == 0) return EmptyBytes; - byte[] bytes = new byte[_remaining]; + // make sure it's safe to do this! + int limit = Limit; + if (_remaining >= limit) + throw new IOException("corrupted stream - out of bounds length found: " + _remaining + " >= " + limit); + + byte[] bytes = new byte[_remaining]; if ((_remaining -= Streams.ReadFully(_in, bytes)) != 0) throw new EndOfStreamException("DEF length " + _originalLength + " object truncated by " + _remaining); SetParentEofDetect(true); diff --git a/crypto/src/asn1/DerBMPString.cs b/crypto/src/asn1/DerBMPString.cs index 33d950ff8..061900b9c 100644 --- a/crypto/src/asn1/DerBMPString.cs +++ b/crypto/src/asn1/DerBMPString.cs @@ -55,32 +55,44 @@ namespace Org.BouncyCastle.Asn1 /** * basic constructor - byte encoded string. */ - public DerBmpString( - byte[] str) + [Obsolete("Will become internal")] + public DerBmpString(byte[] str) { if (str == null) throw new ArgumentNullException("str"); - char[] cs = new char[str.Length / 2]; + int byteLen = str.Length; + if (0 != (byteLen & 1)) + throw new ArgumentException("malformed BMPString encoding encountered", "str"); - for (int i = 0; i != cs.Length; i++) + int charLen = byteLen / 2; + char[] cs = new char[charLen]; + + for (int i = 0; i != charLen; i++) { cs[i] = (char)((str[2 * i] << 8) | (str[2 * i + 1] & 0xff)); } - this.str = new string(cs); + this.str = new string(cs); + } + + internal DerBmpString(char[] str) + { + if (str == null) + throw new ArgumentNullException("str"); + + this.str = new string(str); } /** * basic constructor */ - public DerBmpString( - string str) + public DerBmpString(string str) { if (str == null) throw new ArgumentNullException("str"); - this.str = str; + this.str = str; } public override string GetString() diff --git a/crypto/src/asn1/DerInteger.cs b/crypto/src/asn1/DerInteger.cs index 3e19a07b6..4f7b68d35 100644 --- a/crypto/src/asn1/DerInteger.cs +++ b/crypto/src/asn1/DerInteger.cs @@ -145,6 +145,18 @@ namespace Org.BouncyCastle.Asn1 } } + public long LongValueExact + { + get + { + int count = bytes.Length - start; + if (count > 8) + throw new ArithmeticException("ASN.1 Integer out of long range"); + + return LongValue(bytes, start, SignExtSigned); + } + } + internal override void Encode(DerOutputStream derOut) { derOut.WriteEncoded(Asn1Tags.Integer, bytes); @@ -182,6 +194,19 @@ namespace Org.BouncyCastle.Asn1 return val; } + internal static long LongValue(byte[] bytes, int start, int signExt) + { + int length = bytes.Length; + int pos = System.Math.Max(start, length - 8); + + long val = (sbyte)bytes[pos] & signExt; + while (++pos < length) + { + val = (val << 8) | bytes[pos]; + } + return val; + } + /** * Apply the correct validation for an INTEGER primitive following the BER rules. * diff --git a/crypto/src/asn1/DerOctetString.cs b/crypto/src/asn1/DerOctetString.cs index c046c9402..d79607950 100644 --- a/crypto/src/asn1/DerOctetString.cs +++ b/crypto/src/asn1/DerOctetString.cs @@ -1,3 +1,5 @@ +using System; + namespace Org.BouncyCastle.Asn1 { public class DerOctetString @@ -10,9 +12,13 @@ namespace Org.BouncyCastle.Asn1 { } - public DerOctetString( - Asn1Encodable obj) - : base(obj) + public DerOctetString(IAsn1Convertible obj) + : this(obj.ToAsn1Object()) + { + } + + public DerOctetString(Asn1Encodable obj) + : base(obj.GetEncoded(Asn1Encodable.Der)) { } diff --git a/crypto/src/asn1/LimitedInputStream.cs b/crypto/src/asn1/LimitedInputStream.cs index 62486aa77..98a45876d 100644 --- a/crypto/src/asn1/LimitedInputStream.cs +++ b/crypto/src/asn1/LimitedInputStream.cs @@ -8,23 +8,20 @@ namespace Org.BouncyCastle.Asn1 : BaseInputStream { protected readonly Stream _in; - private int _limit; + private int _limit; - internal LimitedInputStream( - Stream inStream, - int limit) + internal LimitedInputStream(Stream inStream, int limit) { this._in = inStream; - this._limit = limit; + this._limit = limit; } - internal virtual int GetRemaining() - { - // TODO: maybe one day this can become more accurate - return _limit; - } + internal virtual int Limit + { + get { return _limit; } + } - protected virtual void SetParentEofDetect(bool on) + protected virtual void SetParentEofDetect(bool on) { if (_in is IndefiniteLengthInputStream) { diff --git a/crypto/src/asn1/cms/SignedData.cs b/crypto/src/asn1/cms/SignedData.cs index dfc1e2829..5eba8390d 100644 --- a/crypto/src/asn1/cms/SignedData.cs +++ b/crypto/src/asn1/cms/SignedData.cs @@ -25,16 +25,13 @@ namespace Org.BouncyCastle.Asn1.Cms private readonly bool certsBer; private readonly bool crlsBer; - public static SignedData GetInstance( - object obj) + public static SignedData GetInstance(object obj) { if (obj is SignedData) - return (SignedData) obj; - - if (obj is Asn1Sequence) - return new SignedData((Asn1Sequence) obj); - - throw new ArgumentException("Unknown object in factory: " + Platform.GetTypeName(obj), "obj"); + return (SignedData)obj; + if (obj == null) + return null; + return new SignedData(Asn1Sequence.GetInstance(obj)); } public SignedData( -- cgit 1.4.1