Home | History | Annotate | Download | only in asn1
      1 /*
      2  *  Licensed to the Apache Software Foundation (ASF) under one or more
      3  *  contributor license agreements.  See the NOTICE file distributed with
      4  *  this work for additional information regarding copyright ownership.
      5  *  The ASF licenses this file to You under the Apache License, Version 2.0
      6  *  (the "License"); you may not use this file except in compliance with
      7  *  the License.  You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  */
     17 
     18 /**
     19 * @author Vladimir N. Molotkov, Stepan M. Mishura
     20 * @version $Revision$
     21 */
     22 
     23 package org.apache.harmony.security.asn1;
     24 
     25 import java.io.IOException;
     26 
     27 
     28 /**
     29  * This class represents ASN.1 Object Identifier type.
     30  *
     31  * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
     32  */
     33 public class ASN1Oid extends ASN1Primitive {
     34 
     35     /** default implementation */
     36     private static final ASN1Oid ASN1 = new ASN1Oid();
     37 
     38     /**
     39      * Constructs ASN.1 Object Identifier type
     40      *
     41      * The constructor is provided for inheritance purposes
     42      * when there is a need to create a custom ASN.1 Object Identifier type.
     43      * To get a default implementation it is recommended to use
     44      * getInstance() method.
     45      */
     46     public ASN1Oid() {
     47         super(TAG_OID);
     48     }
     49 
     50     /**
     51      * Returns ASN.1 Object Identifier type default implementation
     52      *
     53      * The default implementation works with encoding
     54      * that is represented as array of integers.
     55      *
     56      * @return ASN.1 Object Identifier type default implementation
     57      */
     58     public static ASN1Oid getInstance() {
     59         return ASN1;
     60     }
     61 
     62     public Object decode(BerInputStream in) throws IOException {
     63         in.readOID();
     64 
     65         if (in.isVerify) {
     66             return null;
     67         }
     68         return getDecodedObject(in);
     69     }
     70 
     71     /**
     72      * Extracts array of integers from BER input stream.
     73      *
     74      * @return array of integers
     75      */
     76     @Override public Object getDecodedObject(BerInputStream in) throws IOException {
     77         // Allocate and decode
     78         int oidElement = in.oidElement;
     79         int[] oid = new int[oidElement];
     80         for (int id = 1, i = 0; id < oid.length; id++, i++) {
     81             int octet = in.buffer[in.contentOffset + i];
     82             oidElement = octet & 0x7F;
     83             while ((octet & 0x80) != 0) {
     84                 i++;
     85                 octet = in.buffer[in.contentOffset + i];
     86                 oidElement = oidElement << 7 | (octet & 0x7f);
     87             }
     88             oid[id] = oidElement;
     89         }
     90         // Special handling for the first packed OID element
     91         if (oid[1] > 79) {
     92             oid[0] = 2;
     93             oid[1] = oid[1] - 80;
     94         } else {
     95             oid[0] = oid[1] / 40;
     96             oid[1] = oid[1] % 40;
     97         }
     98         return oid;
     99     }
    100 
    101     public void encodeContent(BerOutputStream out) {
    102         out.encodeOID();
    103     }
    104 
    105     public void setEncodingContent(BerOutputStream out) {
    106         int[] oid = (int[]) out.content;
    107 
    108         int length = 0;
    109 
    110         // first subidentifier
    111         int elem = oid[0] * 40 + oid[1];
    112         if (elem == 0) {
    113             length = 1;
    114         } else {
    115             for (; elem > 0; elem = elem >> 7) {
    116                 length++;
    117             }
    118         }
    119 
    120         // the rest of subidentifiers
    121         for (int i = 2; i < oid.length; i++) {
    122             if (oid[i] == 0) {
    123                 length++;
    124                 continue;
    125             }
    126             for (elem = oid[i]; elem > 0; elem = elem >> 7) {
    127                 length++;
    128             }
    129         }
    130         out.length = length;
    131     }
    132 
    133     private static final ASN1Oid STRING_OID = new ASN1Oid() {
    134         @Override public Object getDecodedObject(BerInputStream in) throws IOException {
    135             StringBuilder buf = new StringBuilder();
    136 
    137             //Special handling for the first packed OID element
    138             int octet = in.buffer[in.contentOffset];
    139             int element = octet & 0x7F;
    140 
    141             int index = 0;
    142             while ((octet & 0x80) != 0) {
    143                 index++;
    144                 octet = in.buffer[in.contentOffset + index];
    145                 element = element << 7 | (octet & 0x7F);
    146             }
    147 
    148             if (element > 79) {
    149                 buf.append('2');
    150                 buf.append('.');
    151                 buf.append(element - 80);
    152             } else {
    153                 buf.append(element / 40);
    154                 buf.append('.');
    155                 buf.append(element % 40);
    156             }
    157 
    158             // the rest of subidentifiers
    159             for (int j = 2; j < in.oidElement; j++) {
    160                 buf.append('.');
    161 
    162                 index++;
    163                 octet = in.buffer[in.contentOffset + index];
    164                 element = octet & 0x7F;
    165 
    166                 while ((octet & 0x80) != 0) {
    167                     index++;
    168                     octet = in.buffer[in.contentOffset + index];
    169                     element = element << 7 | (octet & 0x7f);
    170                 }
    171 
    172                 buf.append(element);
    173             }
    174 
    175             return buf.toString();
    176         }
    177 
    178         @Override public void setEncodingContent(BerOutputStream out) {
    179             //FIXME this is a stub for a while
    180             out.content = ObjectIdentifier.toIntArray((String) out.content);
    181             super.setEncodingContent(out);
    182         }
    183     };
    184 
    185     /**
    186      * Returns ASN.1 Object Identifier type implementation
    187      *
    188      * This implementation works with encoding
    189      * that is mapped to java.lang.String object.
    190      *
    191      * @return ASN.1 Object Identifier type implementation
    192      */
    193     public static ASN1Oid getInstanceForString() {
    194         return STRING_OID;
    195     }
    196 }
    197