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