You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
243 lines
7.0 KiB
243 lines
7.0 KiB
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR) |
|
#pragma warning disable |
|
using System; |
|
using System.Collections; |
|
using System.Diagnostics; |
|
|
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities; |
|
|
|
namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1 |
|
{ |
|
public class BerOctetString |
|
: DerOctetString, IEnumerable |
|
{ |
|
private const int DefaultSegmentLimit = 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] = GetInstance(seq[i]); |
|
} |
|
return new BerOctetString(v); |
|
} |
|
|
|
internal static byte[] FlattenOctetStrings(Asn1OctetString[] octetStrings) |
|
{ |
|
int count = octetStrings.Length; |
|
switch (count) |
|
{ |
|
case 0: |
|
return EmptyOctets; |
|
case 1: |
|
return octetStrings[0].str; |
|
default: |
|
{ |
|
int totalOctets = 0; |
|
for (int i = 0; i < count; ++i) |
|
{ |
|
totalOctets += octetStrings[i].str.Length; |
|
} |
|
|
|
byte[] str = new byte[totalOctets]; |
|
int pos = 0; |
|
for (int i = 0; i < count; ++i) |
|
{ |
|
byte[] octets = octetStrings[i].str; |
|
Array.Copy(octets, 0, str, pos, octets.Length); |
|
pos += octets.Length; |
|
} |
|
|
|
Debug.Assert(pos == totalOctets); |
|
return str; |
|
} |
|
} |
|
} |
|
|
|
private static Asn1OctetString[] ToOctetStringArray(IEnumerable e) |
|
{ |
|
IList list = BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.CreateArrayList(e); |
|
|
|
int count = list.Count; |
|
Asn1OctetString[] v = new Asn1OctetString[count]; |
|
for (int i = 0; i < count; ++i) |
|
{ |
|
v[i] = GetInstance(list[i]); |
|
} |
|
return v; |
|
} |
|
|
|
private readonly int segmentLimit; |
|
private readonly Asn1OctetString[] elements; |
|
|
|
|
|
public BerOctetString(IEnumerable e) |
|
: this(ToOctetStringArray(e)) |
|
{ |
|
} |
|
|
|
public BerOctetString(byte[] str) |
|
: this(str, DefaultSegmentLimit) |
|
{ |
|
} |
|
|
|
public BerOctetString(Asn1OctetString[] elements) |
|
: this(elements, DefaultSegmentLimit) |
|
{ |
|
} |
|
|
|
public BerOctetString(byte[] str, int segmentLimit) |
|
: this(str, null, segmentLimit) |
|
{ |
|
} |
|
|
|
public BerOctetString(Asn1OctetString[] elements, int segmentLimit) |
|
: this(FlattenOctetStrings(elements), elements, segmentLimit) |
|
{ |
|
} |
|
|
|
private BerOctetString(byte[] octets, Asn1OctetString[] elements, int segmentLimit) |
|
: base(octets) |
|
{ |
|
this.elements = elements; |
|
this.segmentLimit = segmentLimit; |
|
} |
|
|
|
/** |
|
* return the DER octets that make up this string. |
|
*/ |
|
public IEnumerator GetEnumerator() |
|
{ |
|
if (elements == null) |
|
return new ChunkEnumerator(str, segmentLimit); |
|
|
|
return elements.GetEnumerator(); |
|
} |
|
|
|
|
|
public IEnumerator GetObjects() |
|
{ |
|
return GetEnumerator(); |
|
} |
|
|
|
private bool IsConstructed |
|
{ |
|
get { return null != elements || str.Length > segmentLimit; } |
|
} |
|
|
|
internal override int EncodedLength(bool withID) |
|
{ |
|
throw BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.CreateNotImplementedException("BerOctetString.EncodedLength"); |
|
|
|
// TODO This depends on knowing it's not DER |
|
//if (!IsConstructed) |
|
// return EncodedLength(withID, str.Length); |
|
|
|
//int totalLength = withID ? 4 : 3; |
|
|
|
//if (null != elements) |
|
//{ |
|
// for (int i = 0; i < elements.Length; ++i) |
|
// { |
|
// totalLength += elements[i].EncodedLength(true); |
|
// } |
|
//} |
|
//else |
|
//{ |
|
// int fullSegments = str.Length / segmentLimit; |
|
// totalLength += fullSegments * EncodedLength(true, segmentLimit); |
|
|
|
// int lastSegmentLength = str.Length - (fullSegments * segmentLimit); |
|
// if (lastSegmentLength > 0) |
|
// { |
|
// totalLength += EncodedLength(true, lastSegmentLength); |
|
// } |
|
//} |
|
|
|
//return totalLength; |
|
} |
|
|
|
internal override void Encode(Asn1OutputStream asn1Out, bool withID) |
|
{ |
|
if (!asn1Out.IsBer || !IsConstructed) |
|
{ |
|
base.Encode(asn1Out, withID); |
|
return; |
|
} |
|
|
|
asn1Out.WriteIdentifier(withID, Asn1Tags.Constructed | Asn1Tags.OctetString); |
|
asn1Out.WriteByte(0x80); |
|
|
|
if (null != elements) |
|
{ |
|
asn1Out.WritePrimitives(elements); |
|
} |
|
else |
|
{ |
|
int pos = 0; |
|
while (pos < str.Length) |
|
{ |
|
int segmentLength = System.Math.Min(str.Length - pos, segmentLimit); |
|
Encode(asn1Out, true, str, pos, segmentLength); |
|
pos += segmentLength; |
|
} |
|
} |
|
|
|
asn1Out.WriteByte(0x00); |
|
asn1Out.WriteByte(0x00); |
|
} |
|
|
|
private class ChunkEnumerator |
|
: IEnumerator |
|
{ |
|
private readonly byte[] octets; |
|
private readonly int segmentLimit; |
|
|
|
private DerOctetString currentSegment = null; |
|
private int nextSegmentPos = 0; |
|
|
|
internal ChunkEnumerator(byte[] octets, int segmentLimit) |
|
{ |
|
this.octets = octets; |
|
this.segmentLimit = segmentLimit; |
|
} |
|
|
|
public object Current |
|
{ |
|
get |
|
{ |
|
if (null == currentSegment) |
|
throw new InvalidOperationException(); |
|
|
|
return currentSegment; |
|
} |
|
} |
|
|
|
public bool MoveNext() |
|
{ |
|
if (nextSegmentPos >= octets.Length) |
|
{ |
|
this.currentSegment = null; |
|
return false; |
|
} |
|
|
|
int length = System.Math.Min(octets.Length - nextSegmentPos, segmentLimit); |
|
byte[] segment = new byte[length]; |
|
Array.Copy(octets, nextSegmentPos, segment, 0, length); |
|
this.currentSegment = new DerOctetString(segment); |
|
this.nextSegmentPos += length; |
|
return true; |
|
} |
|
|
|
public void Reset() |
|
{ |
|
this.currentSegment = null; |
|
this.nextSegmentPos = 0; |
|
} |
|
} |
|
} |
|
} |
|
#pragma warning restore |
|
#endif
|
|
|