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  * Implicitly tagged ASN.1 type.
     30  *
     31  * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
     32  */
     33 public final class ASN1Implicit extends ASN1Type {
     34 
     35     /** primitive type of tagging */
     36     private static final int TAGGING_PRIMITIVE = 0;
     37 
     38     /** constructed type of tagging */
     39     private static final int TAGGING_CONSTRUCTED = 1;
     40 
     41     /** string type of tagging */
     42     private static final int TAGGING_STRING = 2;
     43 
     44     /** tagged ASN.1 type */
     45     private final ASN1Type type;
     46 
     47     /**
     48      * type of tagging. There are three of them
     49      * 1) primitive: only primitive identifier is valid
     50      * 2) constructed: only constructed identifier is valid
     51      * 3) string: both identifiers are valid
     52      */
     53     private final int taggingType;
     54 
     55     /**
     56      * Constructs implicitly tagged ASN.1 type
     57      * with context-specific tag class and specified tag number.
     58      *
     59      * @param tagNumber - ASN.1 tag number
     60      * @param type - ASN.1 type to be tagged
     61      * @throws IllegalArgumentException - if tagNumber or type is invalid
     62      */
     63     public ASN1Implicit(int tagNumber, ASN1Type type) {
     64         super(CLASS_CONTEXTSPECIFIC, tagNumber);
     65 
     66         if ((type instanceof ASN1Choice) || (type instanceof ASN1Any)) {
     67             // According to X.680:
     68             // 'The IMPLICIT alternative shall not be used if the type
     69             // defined by "Type" is an untagged choice type or an
     70             // untagged open type'
     71             throw new IllegalArgumentException("Implicit tagging can not be used for ASN.1 ANY or CHOICE type");
     72         }
     73 
     74         this.type = type;
     75 
     76         if (type.checkTag(type.id)) {
     77             if (type.checkTag(type.constrId)) {
     78                 // the base encoding can be primitive ot constructed
     79                 // use both encodings
     80                 taggingType = TAGGING_STRING;
     81             } else {
     82                 // if the base encoding is primitive use primitive encoding
     83                 taggingType = TAGGING_PRIMITIVE;
     84             }
     85         } else {
     86             // if the base encoding is constructed use constructed encoding
     87             taggingType = TAGGING_CONSTRUCTED;
     88         }
     89     }
     90 
     91     public final boolean checkTag(int identifier) {
     92         switch (taggingType) {
     93         case TAGGING_PRIMITIVE:
     94             return id == identifier;
     95         case TAGGING_CONSTRUCTED:
     96             return constrId == identifier;
     97         default: // TAGGING_STRING
     98             return id == identifier || constrId == identifier;
     99         }
    100     }
    101 
    102     public Object decode(BerInputStream in) throws IOException {
    103         if (!checkTag(in.tag)) {
    104             // FIXME need look for tagging type
    105             throw new ASN1Exception("ASN.1 implicitly tagged type expected at " +
    106                     "[" + in.tagOffset + "]. Expected tag: " + Integer.toHexString(id) + ", " +
    107                     "but got " + Integer.toHexString(in.tag));
    108         }
    109 
    110         // substitute identifier for further decoding
    111         if (id == in.tag) {
    112             in.tag = type.id;
    113         } else {
    114             in.tag = type.constrId;
    115         }
    116         in.content = type.decode(in);
    117 
    118         if (in.isVerify) {
    119             return null;
    120         }
    121         return getDecodedObject(in);
    122     }
    123 
    124     public void encodeASN(BerOutputStream out) {
    125         //FIXME need another way for specifying identifier to be encoded
    126         if (taggingType == TAGGING_CONSTRUCTED) {
    127             out.encodeTag(constrId);
    128         } else {
    129             out.encodeTag(id);
    130         }
    131         encodeContent(out);
    132     }
    133 
    134     public void encodeContent(BerOutputStream out) {
    135         type.encodeContent(out);
    136     }
    137 
    138     public void setEncodingContent(BerOutputStream out) {
    139         type.setEncodingContent(out);
    140     }
    141 }
    142