2004-10-29 Sebastien Pouliot <sebastien@ximian.com>
[mono.git] / mcs / class / corlib / Mono.Security / ASN1.cs
index 09e4b2dcb00407365cde4040af6c6dd86473bb02..62c3f55fa01c8efeda357e8475ecffcaa622029f 100644 (file)
@@ -6,9 +6,28 @@
 //     Jesper Pedersen  <jep@itplus.dk>
 //
 // (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
-// (C) 2004 Novell (http://www.novell.com)
+// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
 // (C) 2004 IT+ A/S (http://www.itplus.dk)
 //
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
 
 using System;
 using System.Collections;
@@ -28,9 +47,9 @@ namespace Mono.Security {
 #endif
        class ASN1 {
 
-               protected byte m_nTag;
-               protected byte[] m_aValue;
-               protected ArrayList elist;
+               private byte m_nTag;
+               private byte[] m_aValue;
+               private ArrayList elist;
 
                public ASN1 () : this (0x00, null) {}
 
@@ -58,9 +77,13 @@ namespace Mono.Security {
                                        nLength += data [i + 2];
                                }
                        }
+                       else if (nLength == 0x80) {
+                               // undefined length encoding
+                               throw new NotSupportedException ("Undefined length encoding.");
+                       }
 
                        m_aValue = new byte [nLength];
-                       Array.Copy (data, (2 + nLenLength), m_aValue, 0, nLength);
+                       Buffer.BlockCopy (data, (2 + nLenLength), m_aValue, 0, nLength);
 
                        if ((m_nTag & 0x20) == 0x20) {
                                int nStart = (2 + nLenLength);
@@ -118,12 +141,12 @@ namespace Mono.Security {
                        return CompareArray (this.GetBytes (), asn1);
                }
 
-               public bool CompareValue (byte[] aValue) 
+               public bool CompareValue (byte[] value) 
                {
-                       return CompareArray (m_aValue, aValue);
+                       return CompareArray (m_aValue, value);
                }
 
-               public virtual ASN1 Add (ASN1 asn1) 
+               public ASN1 Add (ASN1 asn1) 
                {
                        if (asn1 != null) {
                                if (elist == null)
@@ -151,7 +174,7 @@ namespace Mono.Security {
                                int pos = 0;
                                for (int i=0; i < elist.Count; i++) {
                                        byte[] item = (byte[]) al[i];
-                                       Array.Copy (item, 0, val, pos, item.Length);
+                                       Buffer.BlockCopy (item, 0, val, pos, item.Length);
                                        pos += item.Length;
                                }
                        }
@@ -163,23 +186,43 @@ namespace Mono.Security {
                                int nLength = val.Length;
                                // special for length > 127
                                if (nLength > 127) {
-                                       if (nLength < 256) {
+                                       if (nLength <= Byte.MaxValue) {
                                                der = new byte [3 + nLength];
-                                               Array.Copy (val, 0, der, 3, nLength);
-                                               nLengthLen += 0x81;
+                                               Buffer.BlockCopy (val, 0, der, 3, nLength);
+                                               nLengthLen = 0x81;
                                                der[2] = (byte)(nLength);
                                        }
-                                       else {
+                                       else if (nLength <= UInt16.MaxValue) {
                                                der = new byte [4 + nLength];
-                                               Array.Copy (val, 0, der, 4, nLength);
-                                               nLengthLen += 0x82;
-                                               der[2] = (byte)(nLength / 256);
-                                               der[3] = (byte)(nLength % 256);
+                                               Buffer.BlockCopy (val, 0, der, 4, nLength);
+                                               nLengthLen = 0x82;
+                                               der[2] = (byte)(nLength >> 8);
+                                               der[3] = (byte)(nLength);
+                                       }
+                                       else if (nLength <= 0xFFFFFF) {
+                                               // 24 bits
+                                               der = new byte [5 + nLength];
+                                               Buffer.BlockCopy (val, 0, der, 5, nLength);
+                                               nLengthLen = 0x83;
+                                               der [2] = (byte)(nLength >> 16);
+                                               der [3] = (byte)(nLength >> 8);
+                                               der [4] = (byte)(nLength);
+                                       }
+                                       else {
+                                               // max (Length is an integer) 32 bits
+                                               der = new byte [6 + nLength];
+                                               Buffer.BlockCopy (val, 0, der, 6, nLength);
+                                               nLengthLen = 0x84;
+                                               der [2] = (byte)(nLength >> 24);
+                                               der [3] = (byte)(nLength >> 16);
+                                               der [4] = (byte)(nLength >> 8);
+                                               der [5] = (byte)(nLength);
                                        }
                                }
                                else {
+                                       // basic case (no encoding)
                                        der = new byte [2 + nLength];
-                                       Array.Copy (val, 0, der, 2, nLength);
+                                       Buffer.BlockCopy (val, 0, der, 2, nLength);
                                        nLengthLen = nLength;
                                }
                                if (m_aValue == null)
@@ -217,31 +260,31 @@ namespace Mono.Security {
                }
 
                // TLV : Tag - Length - Value
-               protected void DecodeTLV (byte[] asn1, ref int anPos, out byte anTag, out int anLength, out byte[] aValue
+               protected void DecodeTLV (byte[] asn1, ref int pos, out byte tag, out int length, out byte[] content
                {
-                       anTag = asn1 [anPos++];
-                       anLength = asn1 [anPos++];
+                       tag = asn1 [pos++];
+                       length = asn1 [pos++];
 
                        // special case where L contains the Length of the Length + 0x80
-                       if ((anLength & 0x80) == 0x80) {
-                               int nLengthLen = anLength & 0x7F;
-                               anLength = 0;
+                       if ((length & 0x80) == 0x80) {
+                               int nLengthLen = length & 0x7F;
+                               length = 0;
                                for (int i = 0; i < nLengthLen; i++)
-                                       anLength = anLength * 256 + asn1 [anPos++];
+                                       length = length * 256 + asn1 [pos++];
                        }
 
-                       aValue = new byte [anLength];
-                       Array.Copy (asn1, anPos, aValue, 0, anLength);
+                       content = new byte [length];
+                       Buffer.BlockCopy (asn1, pos, content, 0, length);
                }
 
                public ASN1 this [int index] {
                        get {           
                                try {
-                                       if (index >= elist.Count)
+                                       if ((elist == null) || (index >= elist.Count))
                                                return null;
                                        return (ASN1) elist [index];
                                }
-                               catch {
+                               catch (ArgumentOutOfRangeException) {
                                        return null;
                                }
                        }
@@ -250,7 +293,7 @@ namespace Mono.Security {
                public ASN1 Element (int index, byte anTag) 
                {
                        try {
-                               if (index >= elist.Count)
+                               if ((elist == null) || (index >= elist.Count))
                                        return null;
 
                                ASN1 elm = (ASN1) elist [index];
@@ -259,34 +302,28 @@ namespace Mono.Security {
                                else
                                        return null;
                        }
-                       catch {
+                       catch (ArgumentOutOfRangeException) {
                                return null;
                        }
                }
 
                public override string ToString()
                {
-                       string lineSeperator = Environment.NewLine;
-
                        StringBuilder hexLine = new StringBuilder ();
             
                        // Add tag
-                       hexLine.Append ("Tag: ");
-                       hexLine.Append (System.Convert.ToString (Tag, 16));
-                       hexLine.Append (lineSeperator);
+                       hexLine.AppendFormat ("Tag: {0} {1}", m_nTag.ToString ("X2"), Environment.NewLine);
+
+                       // Add length
+                       hexLine.AppendFormat ("Length: {0} {1}", Value.Length, Environment.NewLine);
 
                        // Add value
                        hexLine.Append ("Value: ");
-                       hexLine.Append (lineSeperator);
+                       hexLine.Append (Environment.NewLine);
                        for (int i = 0; i < Value.Length; i++) {
-                               if (Value[i] < 16) {
-                                       hexLine.Append ("0");
-                               }
-                               hexLine.Append (System.Convert.ToString (Value [i], 16));
-                               hexLine.Append (" ");
-                               if ((i+1) % 16 == 0) {
-                                       hexLine.Append (lineSeperator);
-                               }
+                               hexLine.AppendFormat ("{0} ", Value [i].ToString ("X2"));
+                               if ((i+1) % 16 == 0)
+                                       hexLine.AppendFormat (Environment.NewLine);
                        }
                        return hexLine.ToString ();
                }