PageRenderTime 110ms CodeModel.GetById 36ms RepoModel.GetById 0ms app.codeStats 0ms

/BladeLogic/sshNET/Renci.SshNet/Common/DerData.cs

#
C# | 339 lines | 207 code | 51 blank | 81 comment | 21 complexity | 3c82d97309c1ef34918b49c822ff85ee MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. namespace Renci.SshNet.Common
  6. {
  7. /// <summary>
  8. /// Base class for DER encoded data.
  9. /// </summary>
  10. public class DerData
  11. {
  12. private const byte CONSTRUCTED = 0x20;
  13. private const byte BOOLEAN = 0x01;
  14. private const byte INTEGER = 0x02;
  15. //private const byte BITSTRING = 0x03;
  16. private const byte OCTETSTRING = 0x04;
  17. private const byte NULL = 0x05;
  18. private const byte OBJECTIDENTIFIER = 0x06;
  19. //private const byte EXTERNAL = 0x08;
  20. //private const byte ENUMERATED = 0x0a;
  21. private const byte SEQUENCE = 0x10;
  22. //private const byte SEQUENCEOF = 0x10; // for completeness
  23. //private const byte SET = 0x11;
  24. //private const byte SETOF = 0x11; // for completeness
  25. //private const byte NUMERICSTRING = 0x12;
  26. //private const byte PRINTABLESTRING = 0x13;
  27. //private const byte T61STRING = 0x14;
  28. //private const byte VIDEOTEXSTRING = 0x15;
  29. //private const byte IA5STRING = 0x16;
  30. //private const byte UTCTIME = 0x17;
  31. //private const byte GENERALIZEDTIME = 0x18;
  32. //private const byte GRAPHICSTRING = 0x19;
  33. //private const byte VISIBLESTRING = 0x1a;
  34. //private const byte GENERALSTRING = 0x1b;
  35. //private const byte UNIVERSALSTRING = 0x1c;
  36. //private const byte BMPSTRING = 0x1e;
  37. //private const byte UTF8STRING = 0x0c;
  38. //private const byte APPLICATION = 0x40;
  39. //private const byte TAGGED = 0x80;
  40. private List<byte> _data;
  41. private int _readerIndex = 0;
  42. private int _lastIndex;
  43. /// <summary>
  44. /// Gets a value indicating whether end of data is reached.
  45. /// </summary>
  46. /// <value>
  47. /// <c>true</c> if end of data is reached; otherwise, <c>false</c>.
  48. /// </value>
  49. public bool IsEndOfData
  50. {
  51. get
  52. {
  53. return this._readerIndex >= this._lastIndex;
  54. }
  55. }
  56. /// <summary>
  57. /// Initializes a new instance of the <see cref="DerData"/> class.
  58. /// </summary>
  59. public DerData()
  60. {
  61. this._data = new List<byte>();
  62. }
  63. /// <summary>
  64. /// Initializes a new instance of the <see cref="DerData"/> class.
  65. /// </summary>
  66. /// <param name="data">DER encoded data.</param>
  67. public DerData(byte[] data)
  68. {
  69. this._data = new List<byte>(data);
  70. var dataType = this.ReadByte();
  71. var length = this.ReadLength();
  72. this._lastIndex = this._readerIndex + length;
  73. }
  74. /// <summary>
  75. /// Encodes written data as DER byte array.
  76. /// </summary>
  77. /// <returns></returns>
  78. public byte[] Encode()
  79. {
  80. var length = this._data.Count();
  81. var lengthBytes = this.GetLength(length);
  82. this._data.InsertRange(0, lengthBytes);
  83. this._data.Insert(0, CONSTRUCTED | SEQUENCE);
  84. return this._data.ToArray();
  85. }
  86. /// <summary>
  87. /// Reads next mpint data type from internal buffer.
  88. /// </summary>
  89. /// <returns>mpint read.</returns>
  90. public BigInteger ReadBigInteger()
  91. {
  92. var type = this.ReadByte();
  93. if (type != INTEGER)
  94. throw new InvalidOperationException("Invalid data type, INTEGER(02) is expected.");
  95. var length = this.ReadLength();
  96. var data = this.ReadBytes(length);
  97. return new BigInteger(data.Reverse().ToArray());
  98. }
  99. /// <summary>
  100. /// Reads next int data type from internal buffer.
  101. /// </summary>
  102. /// <returns>int read.</returns>
  103. public int ReadInteger()
  104. {
  105. var type = this.ReadByte();
  106. if (type != INTEGER)
  107. throw new InvalidOperationException("Invalid data type, INTEGER(02) is expected.");
  108. var length = this.ReadLength();
  109. var data = this.ReadBytes(length);
  110. if (length > 4)
  111. throw new InvalidOperationException("Integer type cannot occupy more then 4 bytes");
  112. var result = 0;
  113. var shift = (length - 1) * 8;
  114. for (int i = 0; i < length; i++)
  115. {
  116. result |= data[i] << shift;
  117. shift -= 8;
  118. }
  119. //return (int)(data[0] << 56 | data[1] << 48 | data[2] << 40 | data[3] << 32 | data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]);
  120. return result;
  121. }
  122. /// <summary>
  123. /// Writes BOOLEAN data into internal buffer.
  124. /// </summary>
  125. /// <param name="data">UInt32 data to write.</param>
  126. public void Write(bool data)
  127. {
  128. this._data.Add(BOOLEAN);
  129. this._data.Add(1);
  130. this._data.Add((byte)(data ? 1 : 0));
  131. }
  132. /// <summary>
  133. /// Writes UInt32 data into internal buffer.
  134. /// </summary>
  135. /// <param name="data">UInt32 data to write.</param>
  136. public void Write(UInt32 data)
  137. {
  138. var bytes = data.GetBytes();
  139. this._data.Add(INTEGER);
  140. var length = this.GetLength(bytes.Length);
  141. this.WriteBytes(length);
  142. this.WriteBytes(bytes);
  143. }
  144. /// <summary>
  145. /// Writes INTEGER data into internal buffer.
  146. /// </summary>
  147. /// <param name="data">BigInteger data to write.</param>
  148. public void Write(BigInteger data)
  149. {
  150. var bytes = data.ToByteArray().Reverse().ToList();
  151. this._data.Add(INTEGER);
  152. var length = this.GetLength(bytes.Count);
  153. this.WriteBytes(length);
  154. this.WriteBytes(bytes);
  155. }
  156. /// <summary>
  157. /// Writes OCTETSTRING data into internal buffer.
  158. /// </summary>
  159. /// <param name="data">The data.</param>
  160. public void Write(byte[] data)
  161. {
  162. this._data.Add(OCTETSTRING);
  163. var length = this.GetLength(data.Length);
  164. this.WriteBytes(length);
  165. this.WriteBytes(data);
  166. }
  167. /// <summary>
  168. /// Writes OBJECTIDENTIFIER data into internal buffer.
  169. /// </summary>
  170. /// <param name="identifier">The identifier.</param>
  171. public void Write(ObjectIdentifier identifier)
  172. {
  173. var temp = new ulong[identifier.Identifiers.Length - 1];
  174. temp[0] = identifier.Identifiers[0] * 40 + identifier.Identifiers[1];
  175. Buffer.BlockCopy(identifier.Identifiers, 2 * sizeof(ulong), temp, 1 * sizeof(ulong), (identifier.Identifiers.Length - 2) * sizeof(ulong));
  176. //Array.Copy(identifier.Identifiers, 2, temp, 1, identifier.Identifiers.Length - 2);
  177. var bytes = new List<byte>();
  178. foreach (var subidentifier in temp)
  179. {
  180. var item = subidentifier;
  181. var buffer = new byte[8];
  182. var bufferIndex = buffer.Length - 1;
  183. var current = (byte)(item & 0x7F);
  184. do
  185. {
  186. buffer[bufferIndex] = current;
  187. if (bufferIndex < buffer.Length - 1)
  188. buffer[bufferIndex] |= (byte)0x80;
  189. item >>= 7;
  190. current = (byte)(item & 0x7F);
  191. bufferIndex--;
  192. }
  193. while (current > 0);
  194. for (int i = bufferIndex + 1; i < buffer.Length; i++)
  195. {
  196. bytes.Add(buffer[i]);
  197. }
  198. }
  199. this._data.Add(OBJECTIDENTIFIER);
  200. var length = this.GetLength(bytes.Count);
  201. this.WriteBytes(length);
  202. this.WriteBytes(bytes);
  203. }
  204. /// <summary>
  205. /// Writes NULL data into internal buffer.
  206. /// </summary>
  207. public void WriteNull()
  208. {
  209. this._data.Add(NULL);
  210. this._data.Add(0);
  211. }
  212. /// <summary>
  213. /// Writes DerData data into internal buffer.
  214. /// </summary>
  215. /// <param name="data">DerData data to write.</param>
  216. public void Write(DerData data)
  217. {
  218. var bytes = data.Encode();
  219. this._data.AddRange(bytes);
  220. }
  221. private byte[] GetLength(int length)
  222. {
  223. if (length > 127)
  224. {
  225. int size = 1;
  226. int val = length;
  227. while ((val >>= 8) != 0)
  228. size++;
  229. var data = new byte[size];
  230. data[0] = (byte)(size | 0x80);
  231. for (int i = (size - 1) * 8, j = 1; i >= 0; i -= 8, j++)
  232. {
  233. data[j] = (byte)(length >> i);
  234. }
  235. return data;
  236. }
  237. else
  238. {
  239. return new byte[] { (byte)length };
  240. }
  241. }
  242. private int ReadLength()
  243. {
  244. int length = this.ReadByte();
  245. if (length == 0x80)
  246. {
  247. throw new NotSupportedException("Indefinite-length encoding is not supported.");
  248. }
  249. if (length > 127)
  250. {
  251. int size = length & 0x7f;
  252. // Note: The invalid long form "0xff" (see X.690 8.1.3.5c) will be caught here
  253. if (size > 4)
  254. throw new InvalidOperationException(string.Format("DER length is '{0}' and cannot be more than 4 bytes.", size));
  255. length = 0;
  256. for (int i = 0; i < size; i++)
  257. {
  258. int next = this.ReadByte();
  259. length = (length << 8) + next;
  260. }
  261. if (length < 0)
  262. throw new InvalidOperationException("Corrupted data - negative length found");
  263. //if (length >= limit) // after all we must have read at least 1 byte
  264. // throw new IOException("Corrupted stream - out of bounds length found");
  265. }
  266. return length;
  267. }
  268. private void WriteBytes(IEnumerable<byte> data)
  269. {
  270. this._data.AddRange(data);
  271. }
  272. private byte ReadByte()
  273. {
  274. if (this._readerIndex > this._data.Count)
  275. throw new InvalidOperationException("Read out of boundaries.");
  276. return this._data[this._readerIndex++];
  277. }
  278. private byte[] ReadBytes(int length)
  279. {
  280. if (this._readerIndex + length > this._data.Count)
  281. throw new InvalidOperationException("Read out of boundaries.");
  282. var result = new byte[length];
  283. this._data.CopyTo(this._readerIndex, result, 0, length);
  284. this._readerIndex += length;
  285. return result;
  286. }
  287. }
  288. }