2
0

ASN1.cs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. //
  2. // ASN1.cs: Abstract Syntax Notation 1 - micro-parser and generator
  3. //
  4. // Authors:
  5. // Sebastien Pouliot <sebastien@ximian.com>
  6. // Jesper Pedersen <jep@itplus.dk>
  7. //
  8. // (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
  9. // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
  10. // (C) 2004 IT+ A/S (http://www.itplus.dk)
  11. //
  12. // Permission is hereby granted, free of charge, to any person obtaining
  13. // a copy of this software and associated documentation files (the
  14. // "Software"), to deal in the Software without restriction, including
  15. // without limitation the rights to use, copy, modify, merge, publish,
  16. // distribute, sublicense, and/or sell copies of the Software, and to
  17. // permit persons to whom the Software is furnished to do so, subject to
  18. // the following conditions:
  19. //
  20. // The above copyright notice and this permission notice shall be
  21. // included in all copies or substantial portions of the Software.
  22. //
  23. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  24. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  25. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  26. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  27. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  28. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  29. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  30. //
  31. using System;
  32. using System.Collections;
  33. using System.IO;
  34. using System.Text;
  35. namespace Emby.Server.Core.Cryptography
  36. {
  37. // References:
  38. // a. ITU ASN.1 standards (free download)
  39. // http://www.itu.int/ITU-T/studygroups/com17/languages/
  40. public class ASN1 {
  41. private byte m_nTag;
  42. private byte[] m_aValue;
  43. private ArrayList elist;
  44. public ASN1 () : this (0x00, null) {}
  45. public ASN1 (byte tag) : this (tag, null) {}
  46. public ASN1 (byte tag, byte[] data)
  47. {
  48. m_nTag = tag;
  49. m_aValue = data;
  50. }
  51. public ASN1 (byte[] data)
  52. {
  53. m_nTag = data [0];
  54. int nLenLength = 0;
  55. int nLength = data [1];
  56. if (nLength > 0x80) {
  57. // composed length
  58. nLenLength = nLength - 0x80;
  59. nLength = 0;
  60. for (int i = 0; i < nLenLength; i++) {
  61. nLength *= 256;
  62. nLength += data [i + 2];
  63. }
  64. }
  65. else if (nLength == 0x80) {
  66. // undefined length encoding
  67. throw new NotSupportedException ("Undefined length encoding.");
  68. }
  69. m_aValue = new byte [nLength];
  70. Buffer.BlockCopy (data, (2 + nLenLength), m_aValue, 0, nLength);
  71. if ((m_nTag & 0x20) == 0x20) {
  72. int nStart = (2 + nLenLength);
  73. Decode (data, ref nStart, data.Length);
  74. }
  75. }
  76. public int Count {
  77. get {
  78. if (elist == null)
  79. return 0;
  80. return elist.Count;
  81. }
  82. }
  83. public byte Tag {
  84. get { return m_nTag; }
  85. }
  86. public int Length {
  87. get {
  88. if (m_aValue != null)
  89. return m_aValue.Length;
  90. else
  91. return 0;
  92. }
  93. }
  94. public byte[] Value {
  95. get {
  96. if (m_aValue == null)
  97. GetBytes ();
  98. return (byte[]) m_aValue.Clone ();
  99. }
  100. set {
  101. if (value != null)
  102. m_aValue = (byte[]) value.Clone ();
  103. }
  104. }
  105. private bool CompareArray (byte[] array1, byte[] array2)
  106. {
  107. bool bResult = (array1.Length == array2.Length);
  108. if (bResult) {
  109. for (int i = 0; i < array1.Length; i++) {
  110. if (array1[i] != array2[i])
  111. return false;
  112. }
  113. }
  114. return bResult;
  115. }
  116. public bool Equals (byte[] asn1)
  117. {
  118. return CompareArray (this.GetBytes (), asn1);
  119. }
  120. public bool CompareValue (byte[] value)
  121. {
  122. return CompareArray (m_aValue, value);
  123. }
  124. public ASN1 Add (ASN1 asn1)
  125. {
  126. if (asn1 != null) {
  127. if (elist == null)
  128. elist = new ArrayList ();
  129. elist.Add (asn1);
  130. }
  131. return asn1;
  132. }
  133. public virtual byte[] GetBytes ()
  134. {
  135. byte[] val = null;
  136. if (Count > 0) {
  137. int esize = 0;
  138. ArrayList al = new ArrayList ();
  139. foreach (ASN1 a in elist) {
  140. byte[] item = a.GetBytes ();
  141. al.Add (item);
  142. esize += item.Length;
  143. }
  144. val = new byte [esize];
  145. int pos = 0;
  146. for (int i=0; i < elist.Count; i++) {
  147. byte[] item = (byte[]) al[i];
  148. Buffer.BlockCopy (item, 0, val, pos, item.Length);
  149. pos += item.Length;
  150. }
  151. } else if (m_aValue != null) {
  152. val = m_aValue;
  153. }
  154. byte[] der;
  155. int nLengthLen = 0;
  156. if (val != null) {
  157. int nLength = val.Length;
  158. // special for length > 127
  159. if (nLength > 127) {
  160. if (nLength <= Byte.MaxValue) {
  161. der = new byte [3 + nLength];
  162. Buffer.BlockCopy (val, 0, der, 3, nLength);
  163. nLengthLen = 0x81;
  164. der[2] = (byte)(nLength);
  165. }
  166. else if (nLength <= UInt16.MaxValue) {
  167. der = new byte [4 + nLength];
  168. Buffer.BlockCopy (val, 0, der, 4, nLength);
  169. nLengthLen = 0x82;
  170. der[2] = (byte)(nLength >> 8);
  171. der[3] = (byte)(nLength);
  172. }
  173. else if (nLength <= 0xFFFFFF) {
  174. // 24 bits
  175. der = new byte [5 + nLength];
  176. Buffer.BlockCopy (val, 0, der, 5, nLength);
  177. nLengthLen = 0x83;
  178. der [2] = (byte)(nLength >> 16);
  179. der [3] = (byte)(nLength >> 8);
  180. der [4] = (byte)(nLength);
  181. }
  182. else {
  183. // max (Length is an integer) 32 bits
  184. der = new byte [6 + nLength];
  185. Buffer.BlockCopy (val, 0, der, 6, nLength);
  186. nLengthLen = 0x84;
  187. der [2] = (byte)(nLength >> 24);
  188. der [3] = (byte)(nLength >> 16);
  189. der [4] = (byte)(nLength >> 8);
  190. der [5] = (byte)(nLength);
  191. }
  192. }
  193. else {
  194. // basic case (no encoding)
  195. der = new byte [2 + nLength];
  196. Buffer.BlockCopy (val, 0, der, 2, nLength);
  197. nLengthLen = nLength;
  198. }
  199. if (m_aValue == null)
  200. m_aValue = val;
  201. }
  202. else
  203. der = new byte[2];
  204. der[0] = m_nTag;
  205. der[1] = (byte)nLengthLen;
  206. return der;
  207. }
  208. // Note: Recursive
  209. protected void Decode (byte[] asn1, ref int anPos, int anLength)
  210. {
  211. byte nTag;
  212. int nLength;
  213. byte[] aValue;
  214. // minimum is 2 bytes (tag + length of 0)
  215. while (anPos < anLength - 1) {
  216. DecodeTLV (asn1, ref anPos, out nTag, out nLength, out aValue);
  217. // sometimes we get trailing 0
  218. if (nTag == 0)
  219. continue;
  220. ASN1 elm = Add (new ASN1 (nTag, aValue));
  221. if ((nTag & 0x20) == 0x20) {
  222. int nConstructedPos = anPos;
  223. elm.Decode (asn1, ref nConstructedPos, nConstructedPos + nLength);
  224. }
  225. anPos += nLength; // value length
  226. }
  227. }
  228. // TLV : Tag - Length - Value
  229. protected void DecodeTLV (byte[] asn1, ref int pos, out byte tag, out int length, out byte[] content)
  230. {
  231. tag = asn1 [pos++];
  232. length = asn1 [pos++];
  233. // special case where L contains the Length of the Length + 0x80
  234. if ((length & 0x80) == 0x80) {
  235. int nLengthLen = length & 0x7F;
  236. length = 0;
  237. for (int i = 0; i < nLengthLen; i++)
  238. length = length * 256 + asn1 [pos++];
  239. }
  240. content = new byte [length];
  241. Buffer.BlockCopy (asn1, pos, content, 0, length);
  242. }
  243. public ASN1 this [int index] {
  244. get {
  245. try {
  246. if ((elist == null) || (index >= elist.Count))
  247. return null;
  248. return (ASN1) elist [index];
  249. }
  250. catch (ArgumentOutOfRangeException) {
  251. return null;
  252. }
  253. }
  254. }
  255. public ASN1 Element (int index, byte anTag)
  256. {
  257. try {
  258. if ((elist == null) || (index >= elist.Count))
  259. return null;
  260. ASN1 elm = (ASN1) elist [index];
  261. if (elm.Tag == anTag)
  262. return elm;
  263. else
  264. return null;
  265. }
  266. catch (ArgumentOutOfRangeException) {
  267. return null;
  268. }
  269. }
  270. public override string ToString()
  271. {
  272. StringBuilder hexLine = new StringBuilder ();
  273. // Add tag
  274. hexLine.AppendFormat ("Tag: {0} {1}", m_nTag.ToString ("X2"), Environment.NewLine);
  275. // Add length
  276. hexLine.AppendFormat ("Length: {0} {1}", Value.Length, Environment.NewLine);
  277. // Add value
  278. hexLine.Append ("Value: ");
  279. hexLine.Append (Environment.NewLine);
  280. for (int i = 0; i < Value.Length; i++) {
  281. hexLine.AppendFormat ("{0} ", Value [i].ToString ("X2"));
  282. if ((i+1) % 16 == 0)
  283. hexLine.AppendFormat (Environment.NewLine);
  284. }
  285. return hexLine.ToString ();
  286. }
  287. public void SaveToFile (string filename)
  288. {
  289. if (filename == null)
  290. throw new ArgumentNullException ("filename");
  291. using (FileStream fs = File.Create (filename)) {
  292. byte[] data = GetBytes ();
  293. fs.Write (data, 0, data.Length);
  294. }
  295. }
  296. }
  297. }