1 /* 2 * Copyright (c) 1998, 2012, 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 } 162 if ((dataSize - dataPos) < (lenByte + 1)) { 163 throw new IOException("Too little data"); 164 } 165 for (int i = 0; i < lenByte; i++) { 166 curLen = (curLen << 8) + (data[dataPos++] & 0xff); 167 } 168 if (curLen < 0) { 169 throw new IOException("Invalid length bytes"); 170 } 171 } else { 172 curLen = (lenByte & LEN_MASK); 173 } 174 return curLen; 175 } 176 177 /** 178 * Write the length and if it is an indefinite length 179 * then calculate the definite length from the positions 180 * of the indefinite length and its matching EOC terminator. 181 * Then, write the value. 182 */ 183 private void writeLengthAndValue() throws IOException { 184 if (dataPos == dataSize) 185 return; 186 int curLen = 0; 187 int lenByte = data[dataPos++] & 0xff; 188 if (isIndefinite(lenByte)) { 189 byte[] lenBytes = (byte[])ndefsList.get(index++); 190 System.arraycopy(lenBytes, 0, newData, newDataPos, 191 lenBytes.length); 192 newDataPos += lenBytes.length; 193 return; 194 } 195 if (isLongForm(lenByte)) { 196 lenByte &= LEN_MASK; 197 for (int i = 0; i < lenByte; i++) { 198 curLen = (curLen << 8) + (data[dataPos++] & 0xff); 199 } 200 if (curLen < 0) { 201 throw new IOException("Invalid length bytes"); 202 } 203 } else { 204 curLen = (lenByte & LEN_MASK); 205 } 206 writeLength(curLen); 207 writeValue(curLen); 208 } 209 210 private void writeLength(int curLen) { 211 if (curLen < 128) { 212 newData[newDataPos++] = (byte)curLen; 213 214 } else if (curLen < (1 << 8)) { 215 newData[newDataPos++] = (byte)0x81; 216 newData[newDataPos++] = (byte)curLen; 217 218 } else if (curLen < (1 << 16)) { 219 newData[newDataPos++] = (byte)0x82; 220 newData[newDataPos++] = (byte)(curLen >> 8); 221 newData[newDataPos++] = (byte)curLen; 222 223 } else if (curLen < (1 << 24)) { 224 newData[newDataPos++] = (byte)0x83; 225 newData[newDataPos++] = (byte)(curLen >> 16); 226 newData[newDataPos++] = (byte)(curLen >> 8); 227 newData[newDataPos++] = (byte)curLen; 228 229 } else { 230 newData[newDataPos++] = (byte)0x84; 231 newData[newDataPos++] = (byte)(curLen >> 24); 232 newData[newDataPos++] = (byte)(curLen >> 16); 233 newData[newDataPos++] = (byte)(curLen >> 8); 234 newData[newDataPos++] = (byte)curLen; 235 } 236 } 237 238 private byte[] getLengthBytes(int curLen) { 239 byte[] lenBytes; 240 int index = 0; 241 242 if (curLen < 128) { 243 lenBytes = new byte[1]; 244 lenBytes[index++] = (byte)curLen; 245 246 } else if (curLen < (1 << 8)) { 247 lenBytes = new byte[2]; 248 lenBytes[index++] = (byte)0x81; 249 lenBytes[index++] = (byte)curLen; 250 251 } else if (curLen < (1 << 16)) { 252 lenBytes = new byte[3]; 253 lenBytes[index++] = (byte)0x82; 254 lenBytes[index++] = (byte)(curLen >> 8); 255 lenBytes[index++] = (byte)curLen; 256 257 } else if (curLen < (1 << 24)) { 258 lenBytes = new byte[4]; 259 lenBytes[index++] = (byte)0x83; 260 lenBytes[index++] = (byte)(curLen >> 16); 261 lenBytes[index++] = (byte)(curLen >> 8); 262 lenBytes[index++] = (byte)curLen; 263 264 } else { 265 lenBytes = new byte[5]; 266 lenBytes[index++] = (byte)0x84; 267 lenBytes[index++] = (byte)(curLen >> 24); 268 lenBytes[index++] = (byte)(curLen >> 16); 269 lenBytes[index++] = (byte)(curLen >> 8); 270 lenBytes[index++] = (byte)curLen; 271 } 272 273 return lenBytes; 274 } 275 276 // Returns the number of bytes needed to represent the given length 277 // in ASN.1 notation 278 private int getNumOfLenBytes(int len) { 279 int numOfLenBytes = 0; 280 281 if (len < 128) { 282 numOfLenBytes = 1; 283 } else if (len < (1 << 8)) { 284 numOfLenBytes = 2; 285 } else if (len < (1 << 16)) { 286 numOfLenBytes = 3; 287 } else if (len < (1 << 24)) { 288 numOfLenBytes = 4; 289 } else { 290 numOfLenBytes = 5; 291 } 292 return numOfLenBytes; 293 } 294 295 /** 296 * Parse the value; 297 */ 298 private void parseValue(int curLen) { 299 dataPos += curLen; 300 } 301 302 /** 303 * Write the value; 304 */ 305 private void writeValue(int curLen) { 306 for (int i=0; i < curLen; i++) 307 newData[newDataPos++] = data[dataPos++]; 308 } 309 310 /** 311 * Converts a indefinite length DER encoded byte array to 312 * a definte length DER encoding. 313 * 314 * @param indefData the byte array holding the indefinite 315 * length encoding. 316 * @return the byte array containing the definite length 317 * DER encoding. 318 * @exception IOException on parsing or re-writing errors. 319 */ 320 byte[] convert(byte[] indefData) throws IOException { 321 data = indefData; 322 dataPos=0; index=0; 323 dataSize = data.length; 324 int len=0; 325 int unused = 0; 326 327 // parse and set up the vectors of all the indefinite-lengths 328 while (dataPos < dataSize) { 329 parseTag(); 330 len = parseLength(); 331 parseValue(len); 332 if (unresolved == 0) { 333 unused = dataSize - dataPos; 334 dataSize = dataPos; 335 break; 336 } 337 } 338 339 if (unresolved != 0) { 340 throw new IOException("not all indef len BER resolved"); 341 } 342 343 newData = new byte[dataSize + numOfTotalLenBytes + unused]; 344 dataPos=0; newDataPos=0; index=0; 345 346 // write out the new byte array replacing all the indefinite-lengths 347 // and EOCs 348 while (dataPos < dataSize) { 349 writeTag(); 350 writeLengthAndValue(); 351 } 352 System.arraycopy(indefData, dataSize, 353 newData, dataSize + numOfTotalLenBytes, unused); 354 355 return newData; 356 } 357 } 358