2 // ASN1.cs: Abstract Syntax Notation 1 - micro-parser and generator
5 // Sebastien Pouliot <sebastien@ximian.com>
6 // Jesper Pedersen <jep@itplus.dk>
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)
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:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
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.
33 using System
.Collections
;
37 namespace Mono
.Security
{
40 // a. ITU ASN.1 standards (free download)
41 // http://www.itu.int/ITU-T/studygroups/com17/languages/
51 private byte[] m_aValue
;
52 private ArrayList elist
;
54 public ASN1 () : this (0x00, null) {}
56 public ASN1 (byte tag
) : this (tag
, null) {}
58 public ASN1 (byte tag
, byte[] data
)
64 public ASN1 (byte[] data
)
69 int nLength
= data
[1];
73 nLenLength
= nLength
- 0x80;
75 for (int i
= 0; i
< nLenLength
; i
++) {
77 nLength
+= data
[i
+ 2];
80 else if (nLength
== 0x80) {
81 // undefined length encoding
82 throw new NotSupportedException ("Undefined length encoding.");
85 m_aValue
= new byte [nLength
];
86 Buffer
.BlockCopy (data
, (2 + nLenLength
), m_aValue
, 0, nLength
);
88 if ((m_nTag
& 0x20) == 0x20) {
89 int nStart
= (2 + nLenLength
);
90 Decode (data
, ref nStart
, data
.Length
);
103 get { return m_nTag; }
108 if (m_aValue
!= null)
109 return m_aValue
.Length
;
115 public byte[] Value
{
117 if (m_aValue
== null)
119 return (byte[]) m_aValue
.Clone ();
123 m_aValue
= (byte[]) value.Clone ();
127 private bool CompareArray (byte[] array1
, byte[] array2
)
129 bool bResult
= (array1
.Length
== array2
.Length
);
131 for (int i
= 0; i
< array1
.Length
; i
++) {
132 if (array1
[i
] != array2
[i
])
139 public bool Equals (byte[] asn1
)
141 return CompareArray (this.GetBytes (), asn1
);
144 public bool CompareValue (byte[] value)
146 return CompareArray (m_aValue
, value);
149 public ASN1
Add (ASN1 asn1
)
153 elist
= new ArrayList ();
159 public virtual byte[] GetBytes ()
162 if (m_aValue
!= null) {
165 else if (Count
> 0) {
167 ArrayList al
= new ArrayList ();
168 foreach (ASN1 a
in elist
) {
169 byte[] item
= a
.GetBytes ();
171 esize
+= item
.Length
;
173 val
= new byte [esize
];
175 for (int i
=0; i
< elist
.Count
; i
++) {
176 byte[] item
= (byte[]) al
[i
];
177 Buffer
.BlockCopy (item
, 0, val
, pos
, item
.Length
);
186 int nLength
= val
.Length
;
187 // special for length > 127
189 if (nLength
<= Byte
.MaxValue
) {
190 der
= new byte [3 + nLength
];
191 Buffer
.BlockCopy (val
, 0, der
, 3, nLength
);
193 der
[2] = (byte)(nLength
);
195 else if (nLength
<= UInt16
.MaxValue
) {
196 der
= new byte [4 + nLength
];
197 Buffer
.BlockCopy (val
, 0, der
, 4, nLength
);
199 der
[2] = (byte)(nLength
>> 8);
200 der
[3] = (byte)(nLength
);
202 else if (nLength
<= 0xFFFFFF) {
204 der
= new byte [5 + nLength
];
205 Buffer
.BlockCopy (val
, 0, der
, 5, nLength
);
207 der
[2] = (byte)(nLength
>> 16);
208 der
[3] = (byte)(nLength
>> 8);
209 der
[4] = (byte)(nLength
);
212 // max (Length is an integer) 32 bits
213 der
= new byte [6 + nLength
];
214 Buffer
.BlockCopy (val
, 0, der
, 6, nLength
);
216 der
[2] = (byte)(nLength
>> 24);
217 der
[3] = (byte)(nLength
>> 16);
218 der
[4] = (byte)(nLength
>> 8);
219 der
[5] = (byte)(nLength
);
223 // basic case (no encoding)
224 der
= new byte [2 + nLength
];
225 Buffer
.BlockCopy (val
, 0, der
, 2, nLength
);
226 nLengthLen
= nLength
;
228 if (m_aValue
== null)
235 der
[1] = (byte)nLengthLen
;
241 protected void Decode (byte[] asn1
, ref int anPos
, int anLength
)
247 // minimum is 2 bytes (tag + length of 0)
248 while (anPos
< anLength
- 1) {
250 DecodeTLV (asn1
, ref anPos
, out nTag
, out nLength
, out aValue
);
252 ASN1 elm
= Add (new ASN1 (nTag
, aValue
));
254 if ((nTag
& 0x20) == 0x20) {
255 int nConstructedPos
= anPos
;
256 elm
.Decode (asn1
, ref nConstructedPos
, nConstructedPos
+ nLength
);
258 anPos
+= nLength
; // value length
262 // TLV : Tag - Length - Value
263 protected void DecodeTLV (byte[] asn1
, ref int pos
, out byte tag
, out int length
, out byte[] content
)
266 length
= asn1
[pos
++];
268 // special case where L contains the Length of the Length + 0x80
269 if ((length
& 0x80) == 0x80) {
270 int nLengthLen
= length
& 0x7F;
272 for (int i
= 0; i
< nLengthLen
; i
++)
273 length
= length
* 256 + asn1
[pos
++];
276 content
= new byte [length
];
277 Buffer
.BlockCopy (asn1
, pos
, content
, 0, length
);
280 public ASN1
this [int index
] {
283 if ((elist
== null) || (index
>= elist
.Count
))
285 return (ASN1
) elist
[index
];
287 catch (ArgumentOutOfRangeException
) {
293 public ASN1
Element (int index
, byte anTag
)
296 if ((elist
== null) || (index
>= elist
.Count
))
299 ASN1 elm
= (ASN1
) elist
[index
];
300 if (elm
.Tag
== anTag
)
305 catch (ArgumentOutOfRangeException
) {
310 public override string ToString()
312 StringBuilder hexLine
= new StringBuilder ();
315 hexLine
.AppendFormat ("Tag: {0} {1}", m_nTag
.ToString ("X2"), Environment
.NewLine
);
318 hexLine
.AppendFormat ("Length: {0} {1}", Value
.Length
, Environment
.NewLine
);
321 hexLine
.Append ("Value: ");
322 hexLine
.Append (Environment
.NewLine
);
323 for (int i
= 0; i
< Value
.Length
; i
++) {
324 hexLine
.AppendFormat ("{0} ", Value
[i
].ToString ("X2"));
326 hexLine
.AppendFormat (Environment
.NewLine
);
328 return hexLine
.ToString ();
331 public void SaveToFile (string filename
)
333 if (filename
== null)
334 throw new ArgumentNullException ("filename");
336 using (FileStream fs
= File
.OpenWrite (filename
)) {
337 byte[] data
= GetBytes ();
338 fs
.Write (data
, 0, data
.Length
);