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 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     // type of tagging. There are three of them
     48     // 1) primitive: only primitive identifier is valid
     49     // 2) constructed: only constructed identifier is valid
     50     // 3) string: both identifiers are valid
     51     private final int taggingType;
     52 
     53     /**
     54      * Constructs implicitly tagged ASN.1 type
     55      * with context-specific tag class and specified tag number.
     56      *
     57      * @param tagNumber - ASN.1 tag number
     58      * @param type - ASN.1 type to be tagged
     59      * @throws IllegalArgumentException - if tagNumber or type is invalid
     60      */
     61     public ASN1Implicit(int tagNumber, ASN1Type type) {
     62         this(CLASS_CONTEXTSPECIFIC, tagNumber, type);
     63     }
     64 
     65     /**
     66      * Constructs implicitly tagged ASN.1 type
     67      *
     68      * @param tagClass - ASN.1 tag class.
     69      * @param tagNumber - ASN.1 tag number
     70      * @param type - ASN.1 type to be tagged
     71      * @throws IllegalArgumentException - if tagNumber, tagClass or type is invalid
     72      */
     73     public ASN1Implicit(int tagClass, int tagNumber, ASN1Type type) {
     74         super(tagClass, tagNumber);
     75 
     76         if ((type instanceof ASN1Choice) || (type instanceof ASN1Any)) {
     77             // According to X.680:
     78             // 'The IMPLICIT alternative shall not be used if the type
     79             // defined by "Type" is an untagged choice type or an
     80             // untagged open type'
     81             throw new IllegalArgumentException("Implicit tagging can not be used for ASN.1 ANY or CHOICE type");
     82         }
     83 
     84         this.type = type;
     85 
     86         if (type.checkTag(type.id)) {
     87             if (type.checkTag(type.constrId)) {
     88                 // the base encoding can be primitive ot constructed
     89                 // use both encodings
     90                 taggingType = TAGGING_STRING;
     91             } else {
     92                 // if the base encoding is primitive use primitive encoding
     93                 taggingType = TAGGING_PRIMITIVE;
     94             }
     95         } else {
     96             // if the base encoding is constructed use constructed encoding
     97             taggingType = TAGGING_CONSTRUCTED;
     98         }
     99     }
    100 
    101     //
    102     //
    103     // Decode
    104     //
    105     //
    106 
    107     /**
    108      * TODO
    109      */
    110     public final boolean checkTag(int identifier) {
    111         switch (taggingType) {
    112         case TAGGING_PRIMITIVE:
    113             return id == identifier;
    114         case TAGGING_CONSTRUCTED:
    115             return constrId == identifier;
    116         default: // TAGGING_STRING
    117             return id == identifier || constrId == identifier;
    118         }
    119     }
    120 
    121     /**
    122      * TODO
    123      */
    124     public Object decode(BerInputStream in) throws IOException {
    125         if (!checkTag(in.tag)) {
    126             // FIXME need look for tagging type
    127             throw new ASN1Exception("ASN.1 implicitly tagged type expected at " +
    128                     "[" + in.tagOffset + "]. Expected tag: " + Integer.toHexString(id) + ", " +
    129                     "but got " + Integer.toHexString(in.tag));
    130         }
    131 
    132         // substitute indentifier for further decoding
    133         if (id == in.tag) {
    134             in.tag = type.id;
    135         } else {
    136             in.tag = type.constrId;
    137         }
    138         in.content = type.decode(in);
    139 
    140         if (in.isVerify) {
    141             return null;
    142         }
    143         return getDecodedObject(in);
    144     }
    145 
    146     //
    147     //
    148     // Encode
    149     //
    150     //
    151 
    152     public void encodeASN(BerOutputStream out) {
    153         //FIXME need another way for specifying identifier to be encoded
    154         if (taggingType == TAGGING_CONSTRUCTED) {
    155             out.encodeTag(constrId);
    156         } else {
    157             out.encodeTag(id);
    158         }
    159         encodeContent(out);
    160     }
    161 
    162     public void encodeContent(BerOutputStream out) {
    163         type.encodeContent(out);
    164     }
    165 
    166     public void setEncodingContent(BerOutputStream out) {
    167         type.setEncodingContent(out);
    168     }
    169 }
    170