Home | History | Annotate | Download | only in asn1
      1 package org.bouncycastle.asn1;
      2 
      3 import java.io.ByteArrayOutputStream;
      4 import java.io.IOException;
      5 import java.io.OutputStream;
      6 import java.math.BigInteger;
      7 
      8 public class DERObjectIdentifier
      9     extends ASN1Object
     10 {
     11     String      identifier;
     12 
     13     /**
     14      * return an OID from the passed in object
     15      *
     16      * @exception IllegalArgumentException if the object cannot be converted.
     17      */
     18     public static DERObjectIdentifier getInstance(
     19         Object  obj)
     20     {
     21         if (obj == null || obj instanceof DERObjectIdentifier)
     22         {
     23             return (DERObjectIdentifier)obj;
     24         }
     25 
     26         if (obj instanceof ASN1OctetString)
     27         {
     28             return new DERObjectIdentifier(((ASN1OctetString)obj).getOctets());
     29         }
     30 
     31         if (obj instanceof ASN1TaggedObject)
     32         {
     33             return getInstance(((ASN1TaggedObject)obj).getObject());
     34         }
     35 
     36         throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
     37     }
     38 
     39     /**
     40      * return an Object Identifier from a tagged object.
     41      *
     42      * @param obj the tagged object holding the object we want
     43      * @param explicit true if the object is meant to be explicitly
     44      *              tagged false otherwise.
     45      * @exception IllegalArgumentException if the tagged object cannot
     46      *               be converted.
     47      */
     48     public static DERObjectIdentifier getInstance(
     49         ASN1TaggedObject obj,
     50         boolean          explicit)
     51     {
     52         return getInstance(obj.getObject());
     53     }
     54 
     55 
     56     DERObjectIdentifier(
     57         byte[]  bytes)
     58     {
     59         StringBuffer    objId = new StringBuffer();
     60         long            value = 0;
     61         BigInteger      bigValue = null;
     62         boolean         first = true;
     63 
     64         for (int i = 0; i != bytes.length; i++)
     65         {
     66             int b = bytes[i] & 0xff;
     67 
     68             if (value < 0x80000000000000L)
     69             {
     70                 value = value * 128 + (b & 0x7f);
     71                 if ((b & 0x80) == 0)             // end of number reached
     72                 {
     73                     if (first)
     74                     {
     75                         switch ((int)value / 40)
     76                         {
     77                         case 0:
     78                             objId.append('0');
     79                             break;
     80                         case 1:
     81                             objId.append('1');
     82                             value -= 40;
     83                             break;
     84                         default:
     85                             objId.append('2');
     86                             value -= 80;
     87                         }
     88                         first = false;
     89                     }
     90 
     91                     objId.append('.');
     92                     objId.append(value);
     93                     value = 0;
     94                 }
     95             }
     96             else
     97             {
     98                 if (bigValue == null)
     99                 {
    100                     bigValue = BigInteger.valueOf(value);
    101                 }
    102                 bigValue = bigValue.shiftLeft(7);
    103                 bigValue = bigValue.or(BigInteger.valueOf(b & 0x7f));
    104                 if ((b & 0x80) == 0)
    105                 {
    106                     objId.append('.');
    107                     objId.append(bigValue);
    108                     bigValue = null;
    109                     value = 0;
    110                 }
    111             }
    112         }
    113 
    114         // BEGIN android-changed
    115         /*
    116          * Intern the identifier so there aren't hundreds of duplicates
    117          * (in practice).
    118          */
    119         this.identifier = objId.toString().intern();
    120         // END android-changed
    121     }
    122 
    123     public DERObjectIdentifier(
    124         String  identifier)
    125     {
    126         if (!isValidIdentifier(identifier))
    127         {
    128             throw new IllegalArgumentException("string " + identifier + " not an OID");
    129         }
    130 
    131         // BEGIN android-changed
    132         /*
    133          * Intern the identifier so there aren't hundreds of duplicates
    134          * (in practice).
    135          */
    136         this.identifier = identifier.intern();
    137         // END android-changed
    138     }
    139 
    140     public String getId()
    141     {
    142         return identifier;
    143     }
    144 
    145     private void writeField(
    146         OutputStream    out,
    147         long            fieldValue)
    148         throws IOException
    149     {
    150         if (fieldValue >= (1L << 7))
    151         {
    152             if (fieldValue >= (1L << 14))
    153             {
    154                 if (fieldValue >= (1L << 21))
    155                 {
    156                     if (fieldValue >= (1L << 28))
    157                     {
    158                         if (fieldValue >= (1L << 35))
    159                         {
    160                             if (fieldValue >= (1L << 42))
    161                             {
    162                                 if (fieldValue >= (1L << 49))
    163                                 {
    164                                     if (fieldValue >= (1L << 56))
    165                                     {
    166                                         out.write((int)(fieldValue >> 56) | 0x80);
    167                                     }
    168                                     out.write((int)(fieldValue >> 49) | 0x80);
    169                                 }
    170                                 out.write((int)(fieldValue >> 42) | 0x80);
    171                             }
    172                             out.write((int)(fieldValue >> 35) | 0x80);
    173                         }
    174                         out.write((int)(fieldValue >> 28) | 0x80);
    175                     }
    176                     out.write((int)(fieldValue >> 21) | 0x80);
    177                 }
    178                 out.write((int)(fieldValue >> 14) | 0x80);
    179             }
    180             out.write((int)(fieldValue >> 7) | 0x80);
    181         }
    182         out.write((int)fieldValue & 0x7f);
    183     }
    184 
    185     private void writeField(
    186         OutputStream    out,
    187         BigInteger      fieldValue)
    188         throws IOException
    189     {
    190         int byteCount = (fieldValue.bitLength()+6)/7;
    191         if (byteCount == 0)
    192         {
    193             out.write(0);
    194         }
    195         else
    196         {
    197             BigInteger tmpValue = fieldValue;
    198             byte[] tmp = new byte[byteCount];
    199             for (int i = byteCount-1; i >= 0; i--)
    200             {
    201                 tmp[i] = (byte) ((tmpValue.intValue() & 0x7f) | 0x80);
    202                 tmpValue = tmpValue.shiftRight(7);
    203             }
    204             tmp[byteCount-1] &= 0x7f;
    205             out.write(tmp);
    206         }
    207 
    208     }
    209 
    210     void encode(
    211         DEROutputStream out)
    212         throws IOException
    213     {
    214         OIDTokenizer            tok = new OIDTokenizer(identifier);
    215         ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
    216         DEROutputStream         dOut = new DEROutputStream(bOut);
    217 
    218         writeField(bOut,
    219                     Integer.parseInt(tok.nextToken()) * 40
    220                     + Integer.parseInt(tok.nextToken()));
    221 
    222         while (tok.hasMoreTokens())
    223         {
    224             String token = tok.nextToken();
    225             if (token.length() < 18)
    226             {
    227                 writeField(bOut, Long.parseLong(token));
    228             }
    229             else
    230             {
    231                 writeField(bOut, new BigInteger(token));
    232             }
    233         }
    234 
    235         dOut.close();
    236 
    237         byte[]  bytes = bOut.toByteArray();
    238 
    239         out.writeEncoded(OBJECT_IDENTIFIER, bytes);
    240     }
    241 
    242     public int hashCode()
    243     {
    244         return identifier.hashCode();
    245     }
    246 
    247     boolean asn1Equals(
    248         DERObject  o)
    249     {
    250         if (!(o instanceof DERObjectIdentifier))
    251         {
    252             return false;
    253         }
    254 
    255         return identifier.equals(((DERObjectIdentifier)o).identifier);
    256     }
    257 
    258     public String toString()
    259     {
    260         return getId();
    261     }
    262 
    263     private static boolean isValidIdentifier(
    264         String identifier)
    265     {
    266         if (identifier.length() < 3
    267             || identifier.charAt(1) != '.')
    268         {
    269             return false;
    270         }
    271 
    272         char first = identifier.charAt(0);
    273         if (first < '0' || first > '2')
    274         {
    275             return false;
    276         }
    277 
    278         boolean periodAllowed = false;
    279         for (int i = identifier.length() - 1; i >= 2; i--)
    280         {
    281             char ch = identifier.charAt(i);
    282 
    283             if ('0' <= ch && ch <= '9')
    284             {
    285                 periodAllowed = true;
    286                 continue;
    287             }
    288 
    289             if (ch == '.')
    290             {
    291                 if (!periodAllowed)
    292                 {
    293                     return false;
    294                 }
    295 
    296                 periodAllowed = false;
    297                 continue;
    298             }
    299 
    300             return false;
    301         }
    302 
    303         return periodAllowed;
    304     }
    305 }
    306