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