1 /* 2 * Copyright (c) 1996, 2016, 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.ByteArrayInputStream; 29 import java.io.IOException; 30 import java.io.OutputStream; 31 import java.math.BigInteger; 32 import java.util.Date; 33 import sun.util.calendar.CalendarDate; 34 import sun.util.calendar.CalendarSystem; 35 36 /** 37 * DER input buffer ... this is the main abstraction in the DER library 38 * which actively works with the "untyped byte stream" abstraction. It 39 * does so with impunity, since it's not intended to be exposed to 40 * anyone who could violate the "typed value stream" DER model and hence 41 * corrupt the input stream of DER values. 42 * 43 * @author David Brownell 44 */ 45 class DerInputBuffer extends ByteArrayInputStream implements Cloneable { 46 DerInputBuffer(byte[] buf)47 DerInputBuffer(byte[] buf) { super(buf); } 48 DerInputBuffer(byte[] buf, int offset, int len)49 DerInputBuffer(byte[] buf, int offset, int len) { 50 super(buf, offset, len); 51 } 52 dup()53 DerInputBuffer dup() { 54 try { 55 DerInputBuffer retval = (DerInputBuffer)clone(); 56 57 retval.mark(Integer.MAX_VALUE); 58 return retval; 59 } catch (CloneNotSupportedException e) { 60 throw new IllegalArgumentException(e.toString()); 61 } 62 } 63 toByteArray()64 byte[] toByteArray() { 65 int len = available(); 66 if (len <= 0) 67 return null; 68 byte[] retval = new byte[len]; 69 70 System.arraycopy(buf, pos, retval, 0, len); 71 return retval; 72 } 73 74 // BEGIN Android-added: Added getPos & getSlice, needed for APK parsing getPos()75 int getPos() { 76 return pos; 77 } 78 getSlice(int startPos, int size)79 byte[] getSlice(int startPos, int size) { 80 byte[] result = new byte[size]; 81 System.arraycopy(buf, startPos, result, 0, size); 82 return result; 83 } 84 // END Android-added: Added getPos & getSlice, needed for APK parsing 85 peek()86 int peek() throws IOException { 87 if (pos >= count) 88 throw new IOException("out of data"); 89 else 90 return buf[pos]; 91 } 92 93 /** 94 * Compares this DerInputBuffer for equality with the specified 95 * object. 96 */ equals(Object other)97 public boolean equals(Object other) { 98 if (other instanceof DerInputBuffer) 99 return equals((DerInputBuffer)other); 100 else 101 return false; 102 } 103 equals(DerInputBuffer other)104 boolean equals(DerInputBuffer other) { 105 if (this == other) 106 return true; 107 108 int max = this.available(); 109 if (other.available() != max) 110 return false; 111 for (int i = 0; i < max; i++) { 112 if (this.buf[this.pos + i] != other.buf[other.pos + i]) { 113 return false; 114 } 115 } 116 return true; 117 } 118 119 /** 120 * Returns a hashcode for this DerInputBuffer. 121 * 122 * @return a hashcode for this DerInputBuffer. 123 */ hashCode()124 public int hashCode() { 125 int retval = 0; 126 127 int len = available(); 128 int p = pos; 129 130 for (int i = 0; i < len; i++) 131 retval += buf[p + i] * i; 132 return retval; 133 } 134 truncate(int len)135 void truncate(int len) throws IOException { 136 if (len > available()) 137 throw new IOException("insufficient data"); 138 count = pos + len; 139 } 140 141 /** 142 * Returns the integer which takes up the specified number 143 * of bytes in this buffer as a BigInteger. 144 * @param len the number of bytes to use. 145 * @param makePositive whether to always return a positive value, 146 * irrespective of actual encoding 147 * @return the integer as a BigInteger. 148 */ getBigInteger(int len, boolean makePositive)149 BigInteger getBigInteger(int len, boolean makePositive) throws IOException { 150 if (len > available()) 151 throw new IOException("short read of integer"); 152 153 if (len == 0) { 154 throw new IOException("Invalid encoding: zero length Int value"); 155 } 156 157 byte[] bytes = new byte[len]; 158 159 System.arraycopy(buf, pos, bytes, 0, len); 160 skip(len); 161 162 // check to make sure no extra leading 0s for DER 163 if (len >= 2 && (bytes[0] == 0) && (bytes[1] >= 0)) { 164 throw new IOException("Invalid encoding: redundant leading 0s"); 165 } 166 167 if (makePositive) { 168 return new BigInteger(1, bytes); 169 } else { 170 return new BigInteger(bytes); 171 } 172 } 173 174 /** 175 * Returns the integer which takes up the specified number 176 * of bytes in this buffer. 177 * @throws IOException if the result is not within the valid 178 * range for integer, i.e. between Integer.MIN_VALUE and 179 * Integer.MAX_VALUE. 180 * @param len the number of bytes to use. 181 * @return the integer. 182 */ getInteger(int len)183 public int getInteger(int len) throws IOException { 184 185 BigInteger result = getBigInteger(len, false); 186 if (result.compareTo(BigInteger.valueOf(Integer.MIN_VALUE)) < 0) { 187 throw new IOException("Integer below minimum valid value"); 188 } 189 if (result.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) > 0) { 190 throw new IOException("Integer exceeds maximum valid value"); 191 } 192 return result.intValue(); 193 } 194 195 /** 196 * Returns the bit string which takes up the specified 197 * number of bytes in this buffer. 198 */ getBitString(int len)199 public byte[] getBitString(int len) throws IOException { 200 if (len > available()) 201 throw new IOException("short read of bit string"); 202 203 if (len == 0) { 204 throw new IOException("Invalid encoding: zero length bit string"); 205 } 206 207 int numOfPadBits = buf[pos]; 208 if ((numOfPadBits < 0) || (numOfPadBits > 7)) { 209 throw new IOException("Invalid number of padding bits"); 210 } 211 // minus the first byte which indicates the number of padding bits 212 byte[] retval = new byte[len - 1]; 213 System.arraycopy(buf, pos + 1, retval, 0, len - 1); 214 if (numOfPadBits != 0) { 215 // get rid of the padding bits 216 retval[len - 2] &= (0xff << numOfPadBits); 217 } 218 skip(len); 219 return retval; 220 } 221 222 /** 223 * Returns the bit string which takes up the rest of this buffer. 224 */ getBitString()225 byte[] getBitString() throws IOException { 226 return getBitString(available()); 227 } 228 229 /** 230 * Returns the bit string which takes up the rest of this buffer. 231 * The bit string need not be byte-aligned. 232 */ getUnalignedBitString()233 BitArray getUnalignedBitString() throws IOException { 234 if (pos >= count) 235 return null; 236 /* 237 * Just copy the data into an aligned, padded octet buffer, 238 * and consume the rest of the buffer. 239 */ 240 int len = available(); 241 int unusedBits = buf[pos] & 0xff; 242 if (unusedBits > 7 ) { 243 throw new IOException("Invalid value for unused bits: " + unusedBits); 244 } 245 byte[] bits = new byte[len - 1]; 246 // number of valid bits 247 int length = (bits.length == 0) ? 0 : bits.length * 8 - unusedBits; 248 249 System.arraycopy(buf, pos + 1, bits, 0, len - 1); 250 251 BitArray bitArray = new BitArray(length, bits); 252 pos = count; 253 return bitArray; 254 } 255 256 /** 257 * Returns the UTC Time value that takes up the specified number 258 * of bytes in this buffer. 259 * @param len the number of bytes to use 260 */ getUTCTime(int len)261 public Date getUTCTime(int len) throws IOException { 262 if (len > available()) 263 throw new IOException("short read of DER UTC Time"); 264 265 if (len < 11 || len > 17) 266 throw new IOException("DER UTC Time length error"); 267 268 return getTime(len, false); 269 } 270 271 /** 272 * Returns the Generalized Time value that takes up the specified 273 * number of bytes in this buffer. 274 * @param len the number of bytes to use 275 */ getGeneralizedTime(int len)276 public Date getGeneralizedTime(int len) throws IOException { 277 if (len > available()) 278 throw new IOException("short read of DER Generalized Time"); 279 280 if (len < 13 || len > 23) 281 throw new IOException("DER Generalized Time length error"); 282 283 return getTime(len, true); 284 285 } 286 287 /** 288 * Private helper routine to extract time from the der value. 289 * @param len the number of bytes to use 290 * @param generalized true if Generalized Time is to be read, false 291 * if UTC Time is to be read. 292 */ getTime(int len, boolean generalized)293 private Date getTime(int len, boolean generalized) throws IOException { 294 295 /* 296 * UTC time encoded as ASCII chars: 297 * YYMMDDhhmmZ 298 * YYMMDDhhmmssZ 299 * YYMMDDhhmm+hhmm 300 * YYMMDDhhmm-hhmm 301 * YYMMDDhhmmss+hhmm 302 * YYMMDDhhmmss-hhmm 303 * UTC Time is broken in storing only two digits of year. 304 * If YY < 50, we assume 20YY; 305 * if YY >= 50, we assume 19YY, as per RFC 3280. 306 * 307 * Generalized time has a four-digit year and allows any 308 * precision specified in ISO 8601. However, for our purposes, 309 * we will only allow the same format as UTC time, except that 310 * fractional seconds (millisecond precision) are supported. 311 */ 312 313 int year, month, day, hour, minute, second, millis; 314 String type = null; 315 316 if (generalized) { 317 type = "Generalized"; 318 year = 1000 * Character.digit((char)buf[pos++], 10); 319 year += 100 * Character.digit((char)buf[pos++], 10); 320 year += 10 * Character.digit((char)buf[pos++], 10); 321 year += Character.digit((char)buf[pos++], 10); 322 len -= 2; // For the two extra YY 323 } else { 324 type = "UTC"; 325 year = 10 * Character.digit((char)buf[pos++], 10); 326 year += Character.digit((char)buf[pos++], 10); 327 328 if (year < 50) // origin 2000 329 year += 2000; 330 else 331 year += 1900; // origin 1900 332 } 333 334 month = 10 * Character.digit((char)buf[pos++], 10); 335 month += Character.digit((char)buf[pos++], 10); 336 337 day = 10 * Character.digit((char)buf[pos++], 10); 338 day += Character.digit((char)buf[pos++], 10); 339 340 hour = 10 * Character.digit((char)buf[pos++], 10); 341 hour += Character.digit((char)buf[pos++], 10); 342 343 minute = 10 * Character.digit((char)buf[pos++], 10); 344 minute += Character.digit((char)buf[pos++], 10); 345 346 len -= 10; // YYMMDDhhmm 347 348 /* 349 * We allow for non-encoded seconds, even though the 350 * IETF-PKIX specification says that the seconds should 351 * always be encoded even if it is zero. 352 */ 353 354 millis = 0; 355 if (len > 2 && len < 12) { 356 second = 10 * Character.digit((char)buf[pos++], 10); 357 second += Character.digit((char)buf[pos++], 10); 358 len -= 2; 359 // handle fractional seconds (if present) 360 if (buf[pos] == '.' || buf[pos] == ',') { 361 len --; 362 pos++; 363 // handle upto milisecond precision only 364 int precision = 0; 365 int peek = pos; 366 while (buf[peek] != 'Z' && 367 buf[peek] != '+' && 368 buf[peek] != '-') { 369 peek++; 370 precision++; 371 } 372 switch (precision) { 373 case 3: 374 millis += 100 * Character.digit((char)buf[pos++], 10); 375 millis += 10 * Character.digit((char)buf[pos++], 10); 376 millis += Character.digit((char)buf[pos++], 10); 377 break; 378 case 2: 379 millis += 100 * Character.digit((char)buf[pos++], 10); 380 millis += 10 * Character.digit((char)buf[pos++], 10); 381 break; 382 case 1: 383 millis += 100 * Character.digit((char)buf[pos++], 10); 384 break; 385 default: 386 throw new IOException("Parse " + type + 387 " time, unsupported precision for seconds value"); 388 } 389 len -= precision; 390 } 391 } else 392 second = 0; 393 394 if (month == 0 || day == 0 395 || month > 12 || day > 31 396 || hour >= 24 || minute >= 60 || second >= 60) 397 throw new IOException("Parse " + type + " time, invalid format"); 398 399 /* 400 * Generalized time can theoretically allow any precision, 401 * but we're not supporting that. 402 */ 403 CalendarSystem gcal = CalendarSystem.getGregorianCalendar(); 404 CalendarDate date = gcal.newCalendarDate(null); // no time zone 405 date.setDate(year, month, day); 406 date.setTimeOfDay(hour, minute, second, millis); 407 long time = gcal.getTime(date); 408 409 /* 410 * Finally, "Z" or "+hhmm" or "-hhmm" ... offsets change hhmm 411 */ 412 if (! (len == 1 || len == 5)) 413 throw new IOException("Parse " + type + " time, invalid offset"); 414 415 int hr, min; 416 417 switch (buf[pos++]) { 418 case '+': 419 hr = 10 * Character.digit((char)buf[pos++], 10); 420 hr += Character.digit((char)buf[pos++], 10); 421 min = 10 * Character.digit((char)buf[pos++], 10); 422 min += Character.digit((char)buf[pos++], 10); 423 424 if (hr >= 24 || min >= 60) 425 throw new IOException("Parse " + type + " time, +hhmm"); 426 427 time -= ((hr * 60) + min) * 60 * 1000; 428 break; 429 430 case '-': 431 hr = 10 * Character.digit((char)buf[pos++], 10); 432 hr += Character.digit((char)buf[pos++], 10); 433 min = 10 * Character.digit((char)buf[pos++], 10); 434 min += Character.digit((char)buf[pos++], 10); 435 436 if (hr >= 24 || min >= 60) 437 throw new IOException("Parse " + type + " time, -hhmm"); 438 439 time += ((hr * 60) + min) * 60 * 1000; 440 break; 441 442 case 'Z': 443 break; 444 445 default: 446 throw new IOException("Parse " + type + " time, garbage offset"); 447 } 448 return new Date(time); 449 } 450 } 451