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 34 public class ASN1Oid extends ASN1Primitive { 35 36 // default implementation 37 private static final ASN1Oid ASN1 = new ASN1Oid(); 38 39 /** 40 * Constructs ASN.1 Object Identifier type 41 * 42 * The constructor is provided for inheritance purposes 43 * when there is a need to create a custom ASN.1 Object Identifier type. 44 * To get a default implementation it is recommended to use 45 * getInstance() method. 46 */ 47 public ASN1Oid() { 48 super(TAG_OID); 49 } 50 51 /** 52 * Returns ASN.1 Object Identifier type default implementation 53 * 54 * The default implementation works with encoding 55 * that is represented as array of integers. 56 * 57 * @return ASN.1 Object Identifier type default implementation 58 */ 59 public static ASN1Oid getInstance() { 60 return ASN1; 61 } 62 63 // 64 // 65 // Decode 66 // 67 // 68 69 public Object decode(BerInputStream in) throws IOException { 70 in.readOID(); 71 72 if (in.isVerify) { 73 return null; 74 } 75 return getDecodedObject(in); 76 } 77 78 /** 79 * Extracts array of integers from BER input stream. 80 * 81 * @param in - BER input stream 82 * @return array of integers 83 */ 84 public Object getDecodedObject(BerInputStream in) throws IOException { 85 // Allocate and decode 86 int oidElement = in.oidElement; 87 int[] oid = new int[oidElement]; 88 for (int id = 1, i = 0; id < oid.length; id++, i++) { 89 int octet = in.buffer[in.contentOffset + i]; 90 oidElement = octet & 0x7F; 91 while ((octet & 0x80) != 0) { 92 i++; 93 octet = in.buffer[in.contentOffset + i]; 94 oidElement = oidElement << 7 | (octet & 0x7f); 95 } 96 oid[id] = oidElement; 97 } 98 // Special handling for the first packed OID element 99 if (oid[1] > 79) { 100 oid[0] = 2; 101 oid[1] = oid[1] - 80; 102 } else { 103 oid[0] = oid[1] / 40; 104 oid[1] = oid[1] % 40; 105 } 106 return oid; 107 } 108 109 // 110 // 111 // Encode 112 // 113 // 114 115 public void encodeContent(BerOutputStream out) { 116 out.encodeOID(); 117 } 118 119 public void setEncodingContent(BerOutputStream out) { 120 int[] oid = (int[]) out.content; 121 122 int length = 0; 123 124 // first subidentifier 125 int elem = oid[0] * 40 + oid[1]; 126 if (elem == 0) { 127 length = 1; 128 } else { 129 for (; elem > 0; elem = elem >> 7) { 130 length++; 131 } 132 } 133 134 // the rest of subidentifiers 135 for (int i = 2; i < oid.length; i++) { 136 if (oid[i] == 0) { 137 length++; 138 continue; 139 } 140 for (elem = oid[i]; elem > 0; elem = elem >> 7) { 141 length++; 142 } 143 } 144 out.length = length; 145 } 146 147 // 148 // 149 // OID encoder/decoder for mapping to string 150 // 151 // 152 153 private final static ASN1Oid STRING_OID = new ASN1Oid() { 154 155 public Object getDecodedObject(BerInputStream in) throws IOException { 156 157 StringBuilder buf = new StringBuilder(); 158 159 int element; 160 161 //Special handling for the first packed OID element 162 int octet = in.buffer[in.contentOffset]; 163 element = octet & 0x7F; 164 165 int index = 0; 166 while ((octet & 0x80) != 0) { 167 index++; 168 octet = in.buffer[in.contentOffset + index]; 169 element = element << 7 | (octet & 0x7F); 170 } 171 172 if (element > 79) { 173 buf.append('2'); 174 buf.append('.'); 175 buf.append(element - 80); 176 } else { 177 buf.append(element / 40); 178 buf.append('.'); 179 buf.append(element % 40); 180 } 181 182 // the rest of subidentifiers 183 for (int j = 2; j < in.oidElement; j++) { 184 buf.append('.'); 185 186 index++; 187 octet = in.buffer[in.contentOffset + index]; 188 element = octet & 0x7F; 189 190 while ((octet & 0x80) != 0) { 191 index++; 192 octet = in.buffer[in.contentOffset + index]; 193 element = element << 7 | (octet & 0x7f); 194 } 195 196 buf.append(element); 197 } 198 199 return buf.toString(); 200 } 201 202 public void setEncodingContent(BerOutputStream out) { 203 204 //FIXME this is a stub for a while 205 out.content = ObjectIdentifier.toIntArray((String) out.content); 206 207 super.setEncodingContent(out); 208 } 209 }; 210 211 /** 212 * Returns ASN.1 Object Identifier type implementation 213 * 214 * This implementation works with encoding 215 * that is mapped to java.lang.String object. 216 * 217 * @return ASN.1 Object Identifier type implementation 218 */ 219 public static ASN1Oid getInstanceForString() { 220 return STRING_OID; 221 } 222 } 223