ASN1.cs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  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 MediaBrowser.Server.Mono.Security {
  36. // References:
  37. // a. ITU ASN.1 standards (free download)
  38. // http://www.itu.int/ITU-T/studygroups/com17/languages/
  39. public class ASN1 {
  40. private byte m_nTag;
  41. private byte[] m_aValue;
  42. private ArrayList elist;
  43. public ASN1 () : this (0x00, null) {}
  44. public ASN1 (byte tag) : this (tag, null) {}
  45. public ASN1 (byte tag, byte[] data)
  46. {
  47. m_nTag = tag;
  48. m_aValue = data;
  49. }
  50. public ASN1 (byte[] data)
  51. {
  52. m_nTag = data [0];
  53. int nLenLength = 0;
  54. int nLength = data [1];
  55. if (nLength > 0x80) {
  56. // composed length
  57. nLenLength = nLength - 0x80;
  58. nLength = 0;
  59. for (int i = 0; i < nLenLength; i++) {
  60. nLength *= 256;
  61. nLength += data [i + 2];
  62. }
  63. }
  64. else if (nLength == 0x80) {
  65. // undefined length encoding
  66. throw new NotSupportedException ("Undefined length encoding.");
  67. }
  68. m_aValue = new byte [nLength];
  69. Buffer.BlockCopy (data, (2 + nLenLength), m_aValue, 0, nLength);
  70. if ((m_nTag & 0x20) == 0x20) {
  71. int nStart = (2 + nLenLength);
  72. Decode (data, ref nStart, data.Length);
  73. }
  74. }
  75. public int Count {
  76. get {
  77. if (elist == null)
  78. return 0;
  79. return elist.Count;
  80. }
  81. }
  82. public byte Tag {
  83. get { return m_nTag; }
  84. }
  85. public int Length {
  86. get {
  87. if (m_aValue != null)
  88. return m_aValue.Length;
  89. else
  90. return 0;
  91. }
  92. }
  93. public byte[] Value {
  94. get {
  95. if (m_aValue == null)
  96. GetBytes ();
  97. return (byte[]) m_aValue.Clone ();
  98. }
  99. set {
  100. if (value != null)
  101. m_aValue = (byte[]) value.Clone ();
  102. }
  103. }
  104. private bool CompareArray (byte[] array1, byte[] array2)
  105. {
  106. bool bResult = (array1.Length == array2.Length);
  107. if (bResult) {
  108. for (int i = 0; i < array1.Length; i++) {
  109. if (array1[i] != array2[i])
  110. return false;
  111. }
  112. }
  113. return bResult;
  114. }
  115. public bool Equals (byte[] asn1)
  116. {
  117. return CompareArray (this.GetBytes (), asn1);
  118. }
  119. public bool CompareValue (byte[] value)
  120. {
  121. return CompareArray (m_aValue, value);
  122. }
  123. public ASN1 Add (ASN1 asn1)
  124. {
  125. if (asn1 != null) {
  126. if (elist == null)
  127. elist = new ArrayList ();
  128. elist.Add (asn1);
  129. }
  130. return asn1;
  131. }
  132. public virtual byte[] GetBytes ()
  133. {
  134. byte[] val = null;
  135. if (Count > 0) {
  136. int esize = 0;
  137. ArrayList al = new ArrayList ();
  138. foreach (ASN1 a in elist) {
  139. byte[] item = a.GetBytes ();
  140. al.Add (item);
  141. esize += item.Length;
  142. }
  143. val = new byte [esize];
  144. int pos = 0;
  145. for (int i=0; i < elist.Count; i++) {
  146. byte[] item = (byte[]) al[i];
  147. Buffer.BlockCopy (item, 0, val, pos, item.Length);
  148. pos += item.Length;
  149. }
  150. } else if (m_aValue != null) {
  151. val = m_aValue;
  152. }
  153. byte[] der;
  154. int nLengthLen = 0;
  155. if (val != null) {
  156. int nLength = val.Length;
  157. // special for length > 127
  158. if (nLength > 127) {
  159. if (nLength <= Byte.MaxValue) {
  160. der = new byte [3 + nLength];
  161. Buffer.BlockCopy (val, 0, der, 3, nLength);
  162. nLengthLen = 0x81;
  163. der[2] = (byte)(nLength);
  164. }
  165. else if (nLength <= UInt16.MaxValue) {
  166. der = new byte [4 + nLength];
  167. Buffer.BlockCopy (val, 0, der, 4, nLength);
  168. nLengthLen = 0x82;
  169. der[2] = (byte)(nLength >> 8);
  170. der[3] = (byte)(nLength);
  171. }
  172. else if (nLength <= 0xFFFFFF) {
  173. // 24 bits
  174. der = new byte [5 + nLength];
  175. Buffer.BlockCopy (val, 0, der, 5, nLength);
  176. nLengthLen = 0x83;
  177. der [2] = (byte)(nLength >> 16);
  178. der [3] = (byte)(nLength >> 8);
  179. der [4] = (byte)(nLength);
  180. }
  181. else {
  182. // max (Length is an integer) 32 bits
  183. der = new byte [6 + nLength];
  184. Buffer.BlockCopy (val, 0, der, 6, nLength);
  185. nLengthLen = 0x84;
  186. der [2] = (byte)(nLength >> 24);
  187. der [3] = (byte)(nLength >> 16);
  188. der [4] = (byte)(nLength >> 8);
  189. der [5] = (byte)(nLength);
  190. }
  191. }
  192. else {
  193. // basic case (no encoding)
  194. der = new byte [2 + nLength];
  195. Buffer.BlockCopy (val, 0, der, 2, nLength);
  196. nLengthLen = nLength;
  197. }
  198. if (m_aValue == null)
  199. m_aValue = val;
  200. }
  201. else
  202. der = new byte[2];
  203. der[0] = m_nTag;
  204. der[1] = (byte)nLengthLen;
  205. return der;
  206. }
  207. // Note: Recursive
  208. protected void Decode (byte[] asn1, ref int anPos, int anLength)
  209. {
  210. byte nTag;
  211. int nLength;
  212. byte[] aValue;
  213. // minimum is 2 bytes (tag + length of 0)
  214. while (anPos < anLength - 1) {
  215. DecodeTLV (asn1, ref anPos, out nTag, out nLength, out aValue);
  216. // sometimes we get trailing 0
  217. if (nTag == 0)
  218. continue;
  219. ASN1 elm = Add (new ASN1 (nTag, aValue));
  220. if ((nTag & 0x20) == 0x20) {
  221. int nConstructedPos = anPos;
  222. elm.Decode (asn1, ref nConstructedPos, nConstructedPos + nLength);
  223. }
  224. anPos += nLength; // value length
  225. }
  226. }
  227. // TLV : Tag - Length - Value
  228. protected void DecodeTLV (byte[] asn1, ref int pos, out byte tag, out int length, out byte[] content)
  229. {
  230. tag = asn1 [pos++];
  231. length = asn1 [pos++];
  232. // special case where L contains the Length of the Length + 0x80
  233. if ((length & 0x80) == 0x80) {
  234. int nLengthLen = length & 0x7F;
  235. length = 0;
  236. for (int i = 0; i < nLengthLen; i++)
  237. length = length * 256 + asn1 [pos++];
  238. }
  239. content = new byte [length];
  240. Buffer.BlockCopy (asn1, pos, content, 0, length);
  241. }
  242. public ASN1 this [int index] {
  243. get {
  244. try {
  245. if ((elist == null) || (index >= elist.Count))
  246. return null;
  247. return (ASN1) elist [index];
  248. }
  249. catch (ArgumentOutOfRangeException) {
  250. return null;
  251. }
  252. }
  253. }
  254. public ASN1 Element (int index, byte anTag)
  255. {
  256. try {
  257. if ((elist == null) || (index >= elist.Count))
  258. return null;
  259. ASN1 elm = (ASN1) elist [index];
  260. if (elm.Tag == anTag)
  261. return elm;
  262. else
  263. return null;
  264. }
  265. catch (ArgumentOutOfRangeException) {
  266. return null;
  267. }
  268. }
  269. public override string ToString()
  270. {
  271. StringBuilder hexLine = new StringBuilder ();
  272. // Add tag
  273. hexLine.AppendFormat ("Tag: {0} {1}", m_nTag.ToString ("X2"), Environment.NewLine);
  274. // Add length
  275. hexLine.AppendFormat ("Length: {0} {1}", Value.Length, Environment.NewLine);
  276. // Add value
  277. hexLine.Append ("Value: ");
  278. hexLine.Append (Environment.NewLine);
  279. for (int i = 0; i < Value.Length; i++) {
  280. hexLine.AppendFormat ("{0} ", Value [i].ToString ("X2"));
  281. if ((i+1) % 16 == 0)
  282. hexLine.AppendFormat (Environment.NewLine);
  283. }
  284. return hexLine.ToString ();
  285. }
  286. public void SaveToFile (string filename)
  287. {
  288. if (filename == null)
  289. throw new ArgumentNullException ("filename");
  290. using (FileStream fs = File.Create (filename)) {
  291. byte[] data = GetBytes ();
  292. fs.Write (data, 0, data.Length);
  293. }
  294. }
  295. }
  296. }