BERBitString.cs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using System.Diagnostics;
  5. using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  6. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1
  7. {
  8. public class BerBitString
  9. : DerBitString
  10. {
  11. private const int DefaultSegmentLimit = 1000;
  12. internal static byte[] FlattenBitStrings(DerBitString[] bitStrings)
  13. {
  14. int count = bitStrings.Length;
  15. switch (count)
  16. {
  17. case 0:
  18. // No bits
  19. return new byte[]{ 0 };
  20. case 1:
  21. return bitStrings[0].contents;
  22. default:
  23. {
  24. int last = count - 1, totalLength = 0;
  25. for (int i = 0; i < last; ++i)
  26. {
  27. byte[] elementContents = bitStrings[i].contents;
  28. if (elementContents[0] != 0)
  29. throw new ArgumentException("only the last nested bitstring can have padding", "bitStrings");
  30. totalLength += elementContents.Length - 1;
  31. }
  32. // Last one can have padding
  33. byte[] lastElementContents = bitStrings[last].contents;
  34. byte padBits = lastElementContents[0];
  35. totalLength += lastElementContents.Length;
  36. byte[] contents = new byte[totalLength];
  37. contents[0] = padBits;
  38. int pos = 1;
  39. for (int i = 0; i < count; ++i)
  40. {
  41. byte[] elementContents = bitStrings[i].contents;
  42. int length = elementContents.Length - 1;
  43. Array.Copy(elementContents, 1, contents, pos, length);
  44. pos += length;
  45. }
  46. Debug.Assert(pos == totalLength);
  47. return contents;
  48. }
  49. }
  50. }
  51. private readonly int segmentLimit;
  52. private readonly DerBitString[] elements;
  53. public BerBitString(byte data, int padBits)
  54. : base(data, padBits)
  55. {
  56. this.elements = null;
  57. this.segmentLimit = DefaultSegmentLimit;
  58. }
  59. public BerBitString(byte[] data)
  60. : this(data, 0)
  61. {
  62. }
  63. public BerBitString(byte[] data, int padBits)
  64. : this(data, padBits, DefaultSegmentLimit)
  65. {
  66. }
  67. public BerBitString(byte[] data, int padBits, int segmentLimit)
  68. : base(data, padBits)
  69. {
  70. this.elements = null;
  71. this.segmentLimit = segmentLimit;
  72. }
  73. public BerBitString(int namedBits)
  74. : base(namedBits)
  75. {
  76. this.elements = null;
  77. this.segmentLimit = DefaultSegmentLimit;
  78. }
  79. public BerBitString(Asn1Encodable obj)
  80. : this(obj.GetDerEncoded(), 0)
  81. {
  82. }
  83. public BerBitString(DerBitString[] elements)
  84. : this(elements, DefaultSegmentLimit)
  85. {
  86. }
  87. public BerBitString(DerBitString[] elements, int segmentLimit)
  88. : base(FlattenBitStrings(elements), false)
  89. {
  90. this.elements = elements;
  91. this.segmentLimit = segmentLimit;
  92. }
  93. internal BerBitString(byte[] contents, bool check)
  94. : base(contents, check)
  95. {
  96. this.elements = null;
  97. this.segmentLimit = DefaultSegmentLimit;
  98. }
  99. private bool IsConstructed
  100. {
  101. get { return null != elements || contents.Length > segmentLimit; }
  102. }
  103. internal override int EncodedLength(bool withID)
  104. {
  105. throw BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.CreateNotImplementedException("BerBitString.EncodedLength");
  106. // TODO This depends on knowing it's not DER
  107. //if (!IsConstructed)
  108. // return EncodedLength(withID, contents.Length);
  109. //int totalLength = withID ? 4 : 3;
  110. //if (null != elements)
  111. //{
  112. // for (int i = 0; i < elements.Length; ++i)
  113. // {
  114. // totalLength += elements[i].EncodedLength(true);
  115. // }
  116. //}
  117. //else if (contents.Length < 2)
  118. //{
  119. // // No bits
  120. //}
  121. //else
  122. //{
  123. // int extraSegments = (contents.Length - 2) / (segmentLimit - 1);
  124. // totalLength += extraSegments * EncodedLength(true, segmentLimit);
  125. // int lastSegmentLength = contents.Length - (extraSegments * (segmentLimit - 1));
  126. // totalLength += EncodedLength(true, lastSegmentLength);
  127. //}
  128. //return totalLength;
  129. }
  130. internal override void Encode(Asn1OutputStream asn1Out, bool withID)
  131. {
  132. if (!asn1Out.IsBer)
  133. {
  134. base.Encode(asn1Out, withID);
  135. return;
  136. }
  137. if (!IsConstructed)
  138. {
  139. Encode(asn1Out, withID, contents, 0, contents.Length);
  140. return;
  141. }
  142. asn1Out.WriteIdentifier(withID, Asn1Tags.Constructed | Asn1Tags.BitString);
  143. asn1Out.WriteByte(0x80);
  144. if (null != elements)
  145. {
  146. asn1Out.WritePrimitives(elements);
  147. }
  148. else if (contents.Length < 2)
  149. {
  150. // No bits
  151. }
  152. else
  153. {
  154. byte pad = contents[0];
  155. int length = contents.Length;
  156. int remaining = length - 1;
  157. int segmentLength = segmentLimit - 1;
  158. while (remaining > segmentLength)
  159. {
  160. Encode(asn1Out, true, (byte)0, contents, length - remaining, segmentLength);
  161. remaining -= segmentLength;
  162. }
  163. Encode(asn1Out, true, pad, contents, length - remaining, remaining);
  164. }
  165. asn1Out.WriteByte(0x00);
  166. asn1Out.WriteByte(0x00);
  167. }
  168. }
  169. }
  170. #pragma warning restore
  171. #endif