1 /* 2 * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.security.util; 27 28 import java.io.IOException; 29 import java.util.ArrayList; 30 31 /** 32 * A package private utility class to convert indefinite length DER 33 * encoded byte arrays to definite length DER encoded byte arrays. 34 * 35 * This assumes that the basic data structure is "tag, length, value" 36 * triplet. In the case where the length is "indefinite", terminating 37 * end-of-contents bytes are expected. 38 * 39 * @author Hemma Prafullchandra 40 */ 41 class DerIndefLenConverter { 42 43 private static final int TAG_MASK = 0x1f; // bits 5-1 44 private static final int FORM_MASK = 0x20; // bits 6 45 private static final int CLASS_MASK = 0xC0; // bits 8 and 7 46 47 private static final int LEN_LONG = 0x80; // bit 8 set 48 private static final int LEN_MASK = 0x7f; // bits 7 - 1 49 private static final int SKIP_EOC_BYTES = 2; 50 51 private byte[] data, newData; 52 private int newDataPos, dataPos, dataSize, index; 53 private int unresolved = 0; 54 55 private ArrayList<Object> ndefsList = new ArrayList<Object>(); 56 57 private int numOfTotalLenBytes = 0; 58 59 private boolean isEOC(int tag) { 60 return (((tag & TAG_MASK) == 0x00) && // EOC 61 ((tag & FORM_MASK) == 0x00) && // primitive 62 ((tag & CLASS_MASK) == 0x00)); // universal 63 } 64 65 // if bit 8 is set then it implies either indefinite length or long form 66 static boolean isLongForm(int lengthByte) { 67 return ((lengthByte & LEN_LONG) == LEN_LONG); 68 } 69 70 /* 71 * Default package private constructor 72 */ 73 DerIndefLenConverter() { } 74 75 /** 76 * Checks whether the given length byte is of the form 77 * <em>Indefinite</em>. 78 * 79 * @param lengthByte the length byte from a DER encoded 80 * object. 81 * @return true if the byte is of Indefinite form otherwise 82 * returns false. 83 */ 84 static boolean isIndefinite(int lengthByte) { 85 return (isLongForm(lengthByte) && ((lengthByte & LEN_MASK) == 0)); 86 } 87 88 /** 89 * Parse the tag and if it is an end-of-contents tag then 90 * add the current position to the <code>eocList</code> vector. 91 */ 92 private void parseTag() throws IOException { 93 if (dataPos == dataSize) 94 return; 95 if (isEOC(data[dataPos]) && (data[dataPos + 1] == 0)) { 96 int numOfEncapsulatedLenBytes = 0; 97 Object elem = null; 98 int index; 99 for (index = ndefsList.size()-1; index >= 0; index--) { 100 // Determine the first element in the vector that does not 101 // have a matching EOC 102 elem = ndefsList.get(index); 103 if (elem instanceof Integer) { 104 break; 105 } else { 106 numOfEncapsulatedLenBytes += ((byte[])elem).length - 3; 107 } 108 } 109 if (index < 0) { 110 throw new IOException("EOC does not have matching " + 111 "indefinite-length tag"); 112 } 113 int sectionLen = dataPos - ((Integer)elem).intValue() + 114 numOfEncapsulatedLenBytes; 115 byte[] sectionLenBytes = getLengthBytes(sectionLen); 116 ndefsList.set(index, sectionLenBytes); 117 unresolved--; 118 119 // Add the number of bytes required to represent this section 120 // to the total number of length bytes, 121 // and subtract the indefinite-length tag (1 byte) and 122 // EOC bytes (2 bytes) for this section 123 numOfTotalLenBytes += (sectionLenBytes.length - 3); 124 } 125 dataPos++; 126 } 127 128 /** 129 * Write the tag and if it is an end-of-contents tag 130 * then skip the tag and its 1 byte length of zero. 131 */ 132 private void writeTag() { 133 if (dataPos == dataSize) 134 return; 135 int tag = data[dataPos++]; 136 if (isEOC(tag) && (data[dataPos] == 0)) { 137 dataPos++; // skip length 138 writeTag(); 139 } else 140 newData[newDataPos++] = (byte)tag; 141 } 142 143 /** 144 * Parse the length and if it is an indefinite length then add 145 * the current position to the <code>ndefsList</code> vector. 146 */ 147 private int parseLength() throws IOException { 148 int curLen = 0; 149 if (dataPos == dataSize) 150 return curLen; 151 int lenByte = data[dataPos++] & 0xff; 152 if (isIndefinite(lenByte)) { 153 ndefsList.add(new Integer(dataPos)); 154 unresolved++; 155 return curLen; 156 } 157 if (isLongForm(lenByte)) { 158 lenByte &= LEN_MASK; 159 if (lenByte > 4) 160 throw new IOException("Too much data"); 161 if ((dataSize - dataPos) < (lenByte + 1)) 162 throw new IOException("Too little data"); 163 for (int i = 0; i < lenByte; i++) 164 curLen = (curLen << 8) + (data[dataPos++] & 0xff); 165 } else { 166 curLen = (lenByte & LEN_MASK); 167 } 168 return curLen; 169 } 170 171 /** 172 * Write the length and if it is an indefinite length 173 * then calculate the definite length from the positions 174 * of the indefinite length and its matching EOC terminator. 175 * Then, write the value. 176 */ 177 private void writeLengthAndValue() throws IOException { 178 if (dataPos == dataSize) 179 return; 180 int curLen = 0; 181 int lenByte = data[dataPos++] & 0xff; 182 if (isIndefinite(lenByte)) { 183 byte[] lenBytes = (byte[])ndefsList.get(index++); 184 System.arraycopy(lenBytes, 0, newData, newDataPos, 185 lenBytes.length); 186 newDataPos += lenBytes.length; 187 return; 188 } 189 if (isLongForm(lenByte)) { 190 lenByte &= LEN_MASK; 191 for (int i = 0; i < lenByte; i++) 192 curLen = (curLen << 8) + (data[dataPos++] & 0xff); 193 } else 194 curLen = (lenByte & LEN_MASK); 195 writeLength(curLen); 196 writeValue(curLen); 197 } 198 199 private void writeLength(int curLen) { 200 if (curLen < 128) { 201 newData[newDataPos++] = (byte)curLen; 202 203 } else if (curLen < (1 << 8)) { 204 newData[newDataPos++] = (byte)0x81; 205 newData[newDataPos++] = (byte)curLen; 206 207 } else if (curLen < (1 << 16)) { 208 newData[newDataPos++] = (byte)0x82; 209 newData[newDataPos++] = (byte)(curLen >> 8); 210 newData[newDataPos++] = (byte)curLen; 211 212 } else if (curLen < (1 << 24)) { 213 newData[newDataPos++] = (byte)0x83; 214 newData[newDataPos++] = (byte)(curLen >> 16); 215 newData[newDataPos++] = (byte)(curLen >> 8); 216 newData[newDataPos++] = (byte)curLen; 217 218 } else { 219 newData[newDataPos++] = (byte)0x84; 220 newData[newDataPos++] = (byte)(curLen >> 24); 221 newData[newDataPos++] = (byte)(curLen >> 16); 222 newData[newDataPos++] = (byte)(curLen >> 8); 223 newData[newDataPos++] = (byte)curLen; 224 } 225 } 226 227 private byte[] getLengthBytes(int curLen) { 228 byte[] lenBytes; 229 int index = 0; 230 231 if (curLen < 128) { 232 lenBytes = new byte[1]; 233 lenBytes[index++] = (byte)curLen; 234 235 } else if (curLen < (1 << 8)) { 236 lenBytes = new byte[2]; 237 lenBytes[index++] = (byte)0x81; 238 lenBytes[index++] = (byte)curLen; 239 240 } else if (curLen < (1 << 16)) { 241 lenBytes = new byte[3]; 242 lenBytes[index++] = (byte)0x82; 243 lenBytes[index++] = (byte)(curLen >> 8); 244 lenBytes[index++] = (byte)curLen; 245 246 } else if (curLen < (1 << 24)) { 247 lenBytes = new byte[4]; 248 lenBytes[index++] = (byte)0x83; 249 lenBytes[index++] = (byte)(curLen >> 16); 250 lenBytes[index++] = (byte)(curLen >> 8); 251 lenBytes[index++] = (byte)curLen; 252 253 } else { 254 lenBytes = new byte[5]; 255 lenBytes[index++] = (byte)0x84; 256 lenBytes[index++] = (byte)(curLen >> 24); 257 lenBytes[index++] = (byte)(curLen >> 16); 258 lenBytes[index++] = (byte)(curLen >> 8); 259 lenBytes[index++] = (byte)curLen; 260 } 261 262 return lenBytes; 263 } 264 265 // Returns the number of bytes needed to represent the given length 266 // in ASN.1 notation 267 private int getNumOfLenBytes(int len) { 268 int numOfLenBytes = 0; 269 270 if (len < 128) { 271 numOfLenBytes = 1; 272 } else if (len < (1 << 8)) { 273 numOfLenBytes = 2; 274 } else if (len < (1 << 16)) { 275 numOfLenBytes = 3; 276 } else if (len < (1 << 24)) { 277 numOfLenBytes = 4; 278 } else { 279 numOfLenBytes = 5; 280 } 281 return numOfLenBytes; 282 } 283 284 /** 285 * Parse the value; 286 */ 287 private void parseValue(int curLen) { 288 dataPos += curLen; 289 } 290 291 /** 292 * Write the value; 293 */ 294 private void writeValue(int curLen) { 295 for (int i=0; i < curLen; i++) 296 newData[newDataPos++] = data[dataPos++]; 297 } 298 299 /** 300 * Converts a indefinite length DER encoded byte array to 301 * a definte length DER encoding. 302 * 303 * @param indefData the byte array holding the indefinite 304 * length encoding. 305 * @return the byte array containing the definite length 306 * DER encoding. 307 * @exception IOException on parsing or re-writing errors. 308 */ 309 byte[] convert(byte[] indefData) throws IOException { 310 data = indefData; 311 dataPos=0; index=0; 312 dataSize = data.length; 313 int len=0; 314 int unused = 0; 315 316 // parse and set up the vectors of all the indefinite-lengths 317 while (dataPos < dataSize) { 318 parseTag(); 319 len = parseLength(); 320 parseValue(len); 321 if (unresolved == 0) { 322 unused = dataSize - dataPos; 323 dataSize = dataPos; 324 break; 325 } 326 } 327 328 if (unresolved != 0) { 329 throw new IOException("not all indef len BER resolved"); 330 } 331 332 newData = new byte[dataSize + numOfTotalLenBytes + unused]; 333 dataPos=0; newDataPos=0; index=0; 334 335 // write out the new byte array replacing all the indefinite-lengths 336 // and EOCs 337 while (dataPos < dataSize) { 338 writeTag(); 339 writeLengthAndValue(); 340 } 341 System.arraycopy(indefData, dataSize, 342 newData, dataSize + numOfTotalLenBytes, unused); 343 344 return newData; 345 } 346 } 347