1 /* 2 * Copyright (c) 1998, 2021, 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.io.InputStream; 30 import java.util.ArrayList; 31 import java.util.Arrays; 32 33 /** 34 * A package private utility class to convert indefinite length BER 35 * encoded byte arrays to definite length DER encoded byte arrays. 36 * <p> 37 * Note: This class only substitute indefinite length octets to definite 38 * length octets. It does not update the contents even if they are not DER. 39 * <p> 40 * This assumes that the basic data structure is "tag, length, value" 41 * triplet. In the case where the length is "indefinite", terminating 42 * end-of-contents bytes are expected. 43 * 44 * @author Hemma Prafullchandra 45 */ 46 class DerIndefLenConverter { 47 48 private static final int LEN_LONG = 0x80; // bit 8 set 49 private static final int LEN_MASK = 0x7f; // bits 7 - 1 50 51 private byte[] data, newData; 52 private int newDataPos, dataPos, dataSize, index; 53 private int unresolved = 0; 54 55 // A list to store each indefinite length occurrence. Whenever an indef 56 // length is seen, the position after the 0x80 byte is appended to the 57 // list as an integer. Whenever its matching EOC is seen, we know the 58 // actual length and the position value is substituted with a calculated 59 // length octets. At the end, the new DER encoding is a concatenation of 60 // all existing tags, existing definite length octets, existing contents, 61 // and the newly created definte length octets in this list. 62 private ArrayList<Object> ndefsList = new ArrayList<Object>(); 63 64 // Length of extra bytes needed to convert indefinite encoding to definite. 65 // For each resolved indefinite length encoding, the starting 0x80 byte 66 // and the ending 00 00 bytes will be removed and a new definite length 67 // octets will be added. This value might be positive or negative. 68 private int numOfTotalLenBytes = 0; 69 isEOC(byte[] data, int pos)70 private static boolean isEOC(byte[] data, int pos) { 71 return data[pos] == 0 && data[pos + 1] == 0; 72 } 73 74 // if bit 8 is set then it implies either indefinite length or long form isLongForm(int lengthByte)75 static boolean isLongForm(int lengthByte) { 76 return ((lengthByte & LEN_LONG) == LEN_LONG); 77 } 78 79 /* 80 * Default package private constructor 81 */ DerIndefLenConverter()82 DerIndefLenConverter() { } 83 84 /** 85 * Checks whether the given length byte is of the form 86 * <em>Indefinite</em>. 87 * 88 * @param lengthByte the length byte from a DER encoded 89 * object. 90 * @return true if the byte is of Indefinite form otherwise 91 * returns false. 92 */ isIndefinite(int lengthByte)93 static boolean isIndefinite(int lengthByte) { 94 return (isLongForm(lengthByte) && ((lengthByte & LEN_MASK) == 0)); 95 } 96 97 /** 98 * Consumes the tag at {@code dataPos}. 99 * <p> 100 * If it is EOC then replace the matching start position (i.e. the previous 101 * {@code dataPos} where an indefinite length was found by #parseLength) 102 * in {@code ndefsList} with a length octets for this section. 103 */ parseTag()104 private void parseTag() throws IOException { 105 if (isEOC(data, dataPos)) { 106 int numOfEncapsulatedLenBytes = 0; 107 Object elem = null; 108 int index; 109 for (index = ndefsList.size()-1; index >= 0; index--) { 110 // Determine the first element in the vector that does not 111 // have a matching EOC 112 elem = ndefsList.get(index); 113 if (elem instanceof Integer) { 114 break; 115 } else { 116 // For each existing converted part, 3 bytes (80 at the 117 // beginning and 00 00 at the end) are removed and a 118 // new length octets is added. 119 numOfEncapsulatedLenBytes += ((byte[])elem).length - 3; 120 } 121 } 122 if (index < 0) { 123 throw new IOException("EOC does not have matching " + 124 "indefinite-length tag"); 125 } 126 int sectionLen = dataPos - ((Integer)elem).intValue() + 127 numOfEncapsulatedLenBytes; 128 byte[] sectionLenBytes = getLengthBytes(sectionLen); 129 ndefsList.set(index, sectionLenBytes); 130 assert unresolved > 0; 131 unresolved--; 132 133 // Add the number of bytes required to represent this section 134 // to the total number of length bytes, 135 // and subtract the indefinite-length tag (1 byte) and 136 // EOC bytes (2 bytes) for this section 137 numOfTotalLenBytes += (sectionLenBytes.length - 3); 138 } 139 dataPos++; 140 } 141 142 /** 143 * Write the tag and if it is an end-of-contents tag 144 * then skip the tag and its 1 byte length of zero. 145 */ writeTag()146 private void writeTag() { 147 if (dataPos == dataSize) { 148 return; 149 } 150 assert dataPos + 1 < dataSize; 151 if (isEOC(data, dataPos)) { 152 dataPos += 2; // skip tag and length 153 writeTag(); 154 } else { 155 newData[newDataPos++] = data[dataPos++]; 156 } 157 } 158 159 /** 160 * Parse the length octets started at {@code dataPos}. After this method 161 * is called, {@code dataPos} is placed after the length octets except 162 * -1 is returned. 163 * 164 * @return a) the length of definite length data next 165 * b) -1, if it is a definite length data next but the length 166 * octets is not complete to determine the actual length 167 * c) 0, if it is an indefinite length. Also, append the current 168 * position to the {@code ndefsList} vector. 169 * @throws IOException if invalid data is read 170 */ 171 private int parseLength() throws IOException { 172 if (dataPos == dataSize) { 173 return 0; 174 } 175 int lenByte = data[dataPos++] & 0xff; 176 if (isIndefinite(lenByte)) { 177 ndefsList.add(dataPos); 178 unresolved++; 179 return 0; 180 } 181 int curLen = 0; 182 if (isLongForm(lenByte)) { 183 lenByte &= LEN_MASK; 184 if (lenByte > 4) { 185 throw new IOException("Too much data"); 186 } 187 if ((dataSize - dataPos) < (lenByte + 1)) { 188 return -1; 189 } 190 for (int i = 0; i < lenByte; i++) { 191 curLen = (curLen << 8) + (data[dataPos++] & 0xff); 192 } 193 if (curLen < 0) { 194 throw new IOException("Invalid length bytes"); 195 } 196 } else { 197 curLen = (lenByte & LEN_MASK); 198 } 199 return curLen; 200 } 201 202 /** 203 * Write the length and value. 204 * <p> 205 * If it was definite length, just re-write the length and copy the value. 206 * If it was an indefinite length, copy the precalculated definite octets 207 * from {@code ndefsList}. There is no values here because they will be 208 * sub-encodings of a constructed encoding. 209 */ writeLengthAndValue()210 private void writeLengthAndValue() throws IOException { 211 if (dataPos == dataSize) { 212 return; 213 } 214 int curLen = 0; 215 int lenByte = data[dataPos++] & 0xff; 216 if (isIndefinite(lenByte)) { 217 byte[] lenBytes = (byte[])ndefsList.get(index++); 218 System.arraycopy(lenBytes, 0, newData, newDataPos, 219 lenBytes.length); 220 newDataPos += lenBytes.length; 221 } else { 222 if (isLongForm(lenByte)) { 223 lenByte &= LEN_MASK; 224 for (int i = 0; i < lenByte; i++) { 225 curLen = (curLen << 8) + (data[dataPos++] & 0xff); 226 } 227 if (curLen < 0) { 228 throw new IOException("Invalid length bytes"); 229 } 230 } else { 231 curLen = (lenByte & LEN_MASK); 232 } 233 writeLength(curLen); 234 writeValue(curLen); 235 } 236 } 237 writeLength(int curLen)238 private void writeLength(int curLen) { 239 if (curLen < 128) { 240 newData[newDataPos++] = (byte)curLen; 241 242 } else if (curLen < (1 << 8)) { 243 newData[newDataPos++] = (byte)0x81; 244 newData[newDataPos++] = (byte)curLen; 245 246 } else if (curLen < (1 << 16)) { 247 newData[newDataPos++] = (byte)0x82; 248 newData[newDataPos++] = (byte)(curLen >> 8); 249 newData[newDataPos++] = (byte)curLen; 250 251 } else if (curLen < (1 << 24)) { 252 newData[newDataPos++] = (byte)0x83; 253 newData[newDataPos++] = (byte)(curLen >> 16); 254 newData[newDataPos++] = (byte)(curLen >> 8); 255 newData[newDataPos++] = (byte)curLen; 256 257 } else { 258 newData[newDataPos++] = (byte)0x84; 259 newData[newDataPos++] = (byte)(curLen >> 24); 260 newData[newDataPos++] = (byte)(curLen >> 16); 261 newData[newDataPos++] = (byte)(curLen >> 8); 262 newData[newDataPos++] = (byte)curLen; 263 } 264 } 265 getLengthBytes(int curLen)266 private byte[] getLengthBytes(int curLen) { 267 byte[] lenBytes; 268 int index = 0; 269 270 if (curLen < 128) { 271 lenBytes = new byte[1]; 272 lenBytes[index++] = (byte)curLen; 273 274 } else if (curLen < (1 << 8)) { 275 lenBytes = new byte[2]; 276 lenBytes[index++] = (byte)0x81; 277 lenBytes[index++] = (byte)curLen; 278 279 } else if (curLen < (1 << 16)) { 280 lenBytes = new byte[3]; 281 lenBytes[index++] = (byte)0x82; 282 lenBytes[index++] = (byte)(curLen >> 8); 283 lenBytes[index++] = (byte)curLen; 284 285 } else if (curLen < (1 << 24)) { 286 lenBytes = new byte[4]; 287 lenBytes[index++] = (byte)0x83; 288 lenBytes[index++] = (byte)(curLen >> 16); 289 lenBytes[index++] = (byte)(curLen >> 8); 290 lenBytes[index++] = (byte)curLen; 291 292 } else { 293 lenBytes = new byte[5]; 294 lenBytes[index++] = (byte)0x84; 295 lenBytes[index++] = (byte)(curLen >> 24); 296 lenBytes[index++] = (byte)(curLen >> 16); 297 lenBytes[index++] = (byte)(curLen >> 8); 298 lenBytes[index++] = (byte)curLen; 299 } 300 301 return lenBytes; 302 } 303 304 // Returns the number of bytes needed to represent the given length 305 // in ASN.1 notation getNumOfLenBytes(int len)306 private int getNumOfLenBytes(int len) { 307 int numOfLenBytes = 0; 308 309 if (len < 128) { 310 numOfLenBytes = 1; 311 } else if (len < (1 << 8)) { 312 numOfLenBytes = 2; 313 } else if (len < (1 << 16)) { 314 numOfLenBytes = 3; 315 } else if (len < (1 << 24)) { 316 numOfLenBytes = 4; 317 } else { 318 numOfLenBytes = 5; 319 } 320 return numOfLenBytes; 321 } 322 323 /** 324 * Write the value; 325 */ writeValue(int curLen)326 private void writeValue(int curLen) { 327 System.arraycopy(data, dataPos, newData, newDataPos, curLen); 328 dataPos += curLen; 329 newDataPos += curLen; 330 } 331 332 /** 333 * Converts a indefinite length DER encoded byte array to 334 * a definte length DER encoding. 335 * 336 * @param indefData the byte array holding the indefinite 337 * length encoding. 338 * @return the byte array containing the definite length 339 * DER encoding, or null if there is not enough data. 340 * @exception IOException on parsing or re-writing errors. 341 */ convertBytes(byte[] indefData)342 byte[] convertBytes(byte[] indefData) throws IOException { 343 data = indefData; 344 dataPos = 0; 345 dataSize = data.length; 346 347 // parse and set up the vectors of all the indefinite-lengths 348 while (dataPos < dataSize) { 349 if (dataPos + 2 > dataSize) { 350 // There should be at least one tag and one length 351 return null; 352 } 353 parseTag(); 354 int len = parseLength(); 355 if (len < 0) { 356 return null; 357 } 358 dataPos += len; 359 if (dataPos < 0) { 360 // overflow 361 throw new IOException("Data overflow"); 362 } 363 if (unresolved == 0) { 364 assert !ndefsList.isEmpty() && ndefsList.get(0) instanceof byte[]; 365 break; 366 } 367 } 368 369 if (unresolved != 0) { 370 return null; 371 } 372 373 int unused = dataSize - dataPos; 374 assert unused >= 0; 375 dataSize = dataPos; 376 377 newData = new byte[dataSize + numOfTotalLenBytes + unused]; 378 dataPos = 0; newDataPos = 0; index = 0; 379 380 // write out the new byte array replacing all the indefinite-lengths 381 // and EOCs 382 while (dataPos < dataSize) { 383 writeTag(); 384 writeLengthAndValue(); 385 } 386 System.arraycopy(indefData, dataSize, 387 newData, dataSize + numOfTotalLenBytes, unused); 388 389 return newData; 390 } 391 392 /** 393 * Read the input stream into a DER byte array. If an indef len BER is 394 * not resolved this method will try to read more data until EOF is reached. 395 * This may block. 396 * 397 * @param in the input stream with tag and lenByte already read 398 * @param lenByte the length of the length field to remember 399 * @param tag the tag to remember 400 * @return a DER byte array 401 * @throws IOException if not all indef len BER 402 * can be resolved or another I/O error happens 403 */ convertStream(InputStream in, byte lenByte, byte tag)404 public static byte[] convertStream(InputStream in, byte lenByte, byte tag) 405 throws IOException { 406 int offset = 2; // for tag and length bytes 407 int readLen = in.available(); 408 byte[] indefData = new byte[readLen + offset]; 409 indefData[0] = tag; 410 indefData[1] = lenByte; 411 while (true) { 412 int bytesRead = in.readNBytes(indefData, offset, readLen); 413 if (bytesRead != readLen) { 414 readLen = bytesRead; 415 indefData = Arrays.copyOf(indefData, offset + bytesRead); 416 } 417 DerIndefLenConverter derIn = new DerIndefLenConverter(); 418 byte[] result = derIn.convertBytes(indefData); 419 if (result == null) { 420 int next = in.read(); // This could block, but we need more 421 if (next == -1) { 422 throw new IOException("not enough data to resolve indef len BER"); 423 } 424 int more = in.available(); 425 // expand array to include next and more 426 indefData = Arrays.copyOf(indefData, offset + readLen + 1 + more); 427 indefData[offset + readLen] = (byte)next; 428 offset = offset + readLen + 1; 429 readLen = more; 430 } else { 431 return result; 432 } 433 } 434 } 435 } 436