1 /* 2 * Copyright (c) 1996, 2019, 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.InputStream; 29 import java.io.IOException; 30 import java.math.BigInteger; 31 import java.nio.charset.Charset; 32 import java.util.Date; 33 import java.util.Vector; 34 35 import static java.nio.charset.StandardCharsets.*; 36 37 /** 38 * A DER input stream, used for parsing ASN.1 DER-encoded data such as 39 * that found in X.509 certificates. DER is a subset of BER/1, which has 40 * the advantage that it allows only a single encoding of primitive data. 41 * (High level data such as dates still support many encodings.) That is, 42 * it uses the "Definite" Encoding Rules (DER) not the "Basic" ones (BER). 43 * 44 * <P>Note that, like BER/1, DER streams are streams of explicitly 45 * tagged data values. Accordingly, this programming interface does 46 * not expose any variant of the java.io.InputStream interface, since 47 * that kind of input stream holds untagged data values and using that 48 * I/O model could prevent correct parsing of the DER data. 49 * 50 * <P>At this time, this class supports only a subset of the types of DER 51 * data encodings which are defined. That subset is sufficient for parsing 52 * most X.509 certificates. 53 * 54 * 55 * @author David Brownell 56 * @author Amit Kapoor 57 * @author Hemma Prafullchandra 58 */ 59 60 public class DerInputStream { 61 62 /* 63 * This version only supports fully buffered DER. This is easy to 64 * work with, though if large objects are manipulated DER becomes 65 * awkward to deal with. That's where BER is useful, since BER 66 * handles streaming data relatively well. 67 */ 68 DerInputBuffer buffer; 69 70 /** The DER tag of the value; one of the tag_ constants. */ 71 public byte tag; 72 73 /** 74 * Create a DER input stream from a data buffer. The buffer is not 75 * copied, it is shared. Accordingly, the buffer should be treated 76 * as read-only. 77 * 78 * @param data the buffer from which to create the string (CONSUMED) 79 */ DerInputStream(byte[] data)80 public DerInputStream(byte[] data) throws IOException { 81 init(data, 0, data.length, true); 82 } 83 84 /** 85 * Create a DER input stream from part of a data buffer with 86 * additional arg to control whether DER checks are enforced. 87 * The buffer is not copied, it is shared. Accordingly, the 88 * buffer should be treated as read-only. 89 * 90 * @param data the buffer from which to create the string (CONSUMED) 91 * @param offset the first index of <em>data</em> which will 92 * be read as DER input in the new stream 93 * @param len how long a chunk of the buffer to use, 94 * starting at "offset" 95 * @param allowBER whether to allow constructed indefinite-length 96 * encoding as well as tolerate leading 0s 97 */ DerInputStream(byte[] data, int offset, int len, boolean allowBER)98 public DerInputStream(byte[] data, int offset, int len, 99 boolean allowBER) throws IOException { 100 init(data, offset, len, allowBER); 101 } 102 103 /** 104 * Create a DER input stream from part of a data buffer. 105 * The buffer is not copied, it is shared. Accordingly, the 106 * buffer should be treated as read-only. 107 * 108 * @param data the buffer from which to create the string (CONSUMED) 109 * @param offset the first index of <em>data</em> which will 110 * be read as DER input in the new stream 111 * @param len how long a chunk of the buffer to use, 112 * starting at "offset" 113 */ DerInputStream(byte[] data, int offset, int len)114 public DerInputStream(byte[] data, int offset, int len) throws IOException { 115 init(data, offset, len, true); 116 } 117 118 /* 119 * private helper routine 120 */ init(byte[] data, int offset, int len, boolean allowBER)121 private void init(byte[] data, int offset, int len, boolean allowBER) throws IOException { 122 if ((offset+2 > data.length) || (offset+len > data.length)) { 123 throw new IOException("Encoding bytes too short"); 124 } 125 // check for indefinite length encoding 126 if (DerIndefLenConverter.isIndefinite(data[offset+1])) { 127 if (!allowBER) { 128 throw new IOException("Indefinite length BER encoding found"); 129 } else { 130 byte[] inData = new byte[len]; 131 System.arraycopy(data, offset, inData, 0, len); 132 133 DerIndefLenConverter derIn = new DerIndefLenConverter(); 134 byte[] result = derIn.convertBytes(inData); 135 if (result == null) { 136 throw new IOException("not all indef len BER resolved"); 137 } else { 138 buffer = new DerInputBuffer(result, allowBER); 139 } 140 } 141 } else { 142 buffer = new DerInputBuffer(data, offset, len, allowBER); 143 } 144 buffer.mark(Integer.MAX_VALUE); 145 } 146 DerInputStream(DerInputBuffer buf)147 DerInputStream(DerInputBuffer buf) { 148 buffer = buf; 149 buffer.mark(Integer.MAX_VALUE); 150 } 151 152 /** 153 * Creates a new DER input stream from part of this input stream. 154 * 155 * @param len how long a chunk of the current input stream to use, 156 * starting at the current position. 157 * @param do_skip true if the existing data in the input stream should 158 * be skipped. If this value is false, the next data read 159 * on this stream and the newly created stream will be the 160 * same. 161 */ subStream(int len, boolean do_skip)162 public DerInputStream subStream(int len, boolean do_skip) 163 throws IOException { 164 DerInputBuffer newbuf = buffer.dup(); 165 166 newbuf.truncate(len); 167 if (do_skip) { 168 buffer.skip(len); 169 } 170 return new DerInputStream(newbuf); 171 } 172 173 /** 174 * Return what has been written to this DerInputStream 175 * as a byte array. Useful for debugging. 176 */ toByteArray()177 public byte[] toByteArray() { 178 return buffer.toByteArray(); 179 } 180 181 /* 182 * PRIMITIVES -- these are "universal" ASN.1 simple types. 183 * 184 * INTEGER, ENUMERATED, BIT STRING, OCTET STRING, NULL 185 * OBJECT IDENTIFIER, SEQUENCE (OF), SET (OF) 186 * UTF8String, PrintableString, T61String, IA5String, UTCTime, 187 * GeneralizedTime, BMPString. 188 * Note: UniversalString not supported till encoder is available. 189 */ 190 191 /** 192 * Get an integer from the input stream as an integer. 193 * 194 * @return the integer held in this DER input stream. 195 */ getInteger()196 public int getInteger() throws IOException { 197 if (buffer.read() != DerValue.tag_Integer) { 198 throw new IOException("DER input, Integer tag error"); 199 } 200 return buffer.getInteger(getDefiniteLength(buffer)); 201 } 202 203 /** 204 * Get a integer from the input stream as a BigInteger object. 205 * 206 * @return the integer held in this DER input stream. 207 */ getBigInteger()208 public BigInteger getBigInteger() throws IOException { 209 if (buffer.read() != DerValue.tag_Integer) { 210 throw new IOException("DER input, Integer tag error"); 211 } 212 return buffer.getBigInteger(getDefiniteLength(buffer), false); 213 } 214 215 /** 216 * Returns an ASN.1 INTEGER value as a positive BigInteger. 217 * This is just to deal with implementations that incorrectly encode 218 * some values as negative. 219 * 220 * @return the integer held in this DER value as a BigInteger. 221 */ getPositiveBigInteger()222 public BigInteger getPositiveBigInteger() throws IOException { 223 if (buffer.read() != DerValue.tag_Integer) { 224 throw new IOException("DER input, Integer tag error"); 225 } 226 return buffer.getBigInteger(getDefiniteLength(buffer), true); 227 } 228 229 /** 230 * Get an enumerated from the input stream. 231 * 232 * @return the integer held in this DER input stream. 233 */ getEnumerated()234 public int getEnumerated() throws IOException { 235 if (buffer.read() != DerValue.tag_Enumerated) { 236 throw new IOException("DER input, Enumerated tag error"); 237 } 238 return buffer.getInteger(getDefiniteLength(buffer)); 239 } 240 241 /** 242 * Get a bit string from the input stream. Padded bits (if any) 243 * will be stripped off before the bit string is returned. 244 */ getBitString()245 public byte[] getBitString() throws IOException { 246 if (buffer.read() != DerValue.tag_BitString) 247 throw new IOException("DER input not an bit string"); 248 249 return buffer.getBitString(getDefiniteLength(buffer)); 250 } 251 252 /** 253 * Get a bit string from the input stream. The bit string need 254 * not be byte-aligned. 255 */ getUnalignedBitString()256 public BitArray getUnalignedBitString() throws IOException { 257 if (buffer.read() != DerValue.tag_BitString) { 258 throw new IOException("DER input not a bit string"); 259 } 260 261 int length = getDefiniteLength(buffer); 262 263 if (length == 0) { 264 return new BitArray(0); 265 } 266 267 /* 268 * First byte = number of excess bits in the last octet of the 269 * representation. 270 */ 271 length--; 272 int excessBits = buffer.read(); 273 if (excessBits < 0) { 274 throw new IOException("Unused bits of bit string invalid"); 275 } 276 int validBits = length*8 - excessBits; 277 if (validBits < 0) { 278 throw new IOException("Valid bits of bit string invalid"); 279 } 280 281 byte[] repn = new byte[length]; 282 283 if ((length != 0) && (buffer.read(repn) != length)) { 284 throw new IOException("Short read of DER bit string"); 285 } 286 287 return new BitArray(validBits, repn); 288 } 289 290 /** 291 * Returns an ASN.1 OCTET STRING from the input stream. 292 */ getOctetString()293 public byte[] getOctetString() throws IOException { 294 if (buffer.read() != DerValue.tag_OctetString) 295 throw new IOException("DER input not an octet string"); 296 297 int length = getDefiniteLength(buffer); 298 byte[] retval = new byte[length]; 299 if ((length != 0) && (buffer.read(retval) != length)) 300 throw new IOException("Short read of DER octet string"); 301 302 return retval; 303 } 304 305 /** 306 * Returns the asked number of bytes from the input stream. 307 */ getBytes(byte[] val)308 public void getBytes(byte[] val) throws IOException { 309 if ((val.length != 0) && (buffer.read(val) != val.length)) { 310 throw new IOException("Short read of DER octet string"); 311 } 312 } 313 314 /** 315 * Reads an encoded null value from the input stream. 316 */ getNull()317 public void getNull() throws IOException { 318 if (buffer.read() != DerValue.tag_Null || buffer.read() != 0) 319 throw new IOException("getNull, bad data"); 320 } 321 322 /** 323 * Reads an X.200 style Object Identifier from the stream. 324 */ getOID()325 public ObjectIdentifier getOID() throws IOException { 326 return new ObjectIdentifier(this); 327 } 328 329 /** 330 * Return a sequence of encoded entities. ASN.1 sequences are 331 * ordered, and they are often used, like a "struct" in C or C++, 332 * to group data values. They may have optional or context 333 * specific values. 334 * 335 * @param startLen guess about how long the sequence will be 336 * (used to initialize an auto-growing data structure) 337 * @return array of the values in the sequence 338 */ getSequence(int startLen)339 public DerValue[] getSequence(int startLen) throws IOException { 340 tag = (byte)buffer.read(); 341 if (tag != DerValue.tag_Sequence) 342 throw new IOException("Sequence tag error"); 343 return readVector(startLen); 344 } 345 346 /** 347 * Return a set of encoded entities. ASN.1 sets are unordered, 348 * though DER may specify an order for some kinds of sets (such 349 * as the attributes in an X.500 relative distinguished name) 350 * to facilitate binary comparisons of encoded values. 351 * 352 * @param startLen guess about how large the set will be 353 * (used to initialize an auto-growing data structure) 354 * @return array of the values in the sequence 355 */ getSet(int startLen)356 public DerValue[] getSet(int startLen) throws IOException { 357 tag = (byte)buffer.read(); 358 if (tag != DerValue.tag_Set) 359 throw new IOException("Set tag error"); 360 return readVector(startLen); 361 } 362 363 /** 364 * Return a set of encoded entities. ASN.1 sets are unordered, 365 * though DER may specify an order for some kinds of sets (such 366 * as the attributes in an X.500 relative distinguished name) 367 * to facilitate binary comparisons of encoded values. 368 * 369 * @param startLen guess about how large the set will be 370 * (used to initialize an auto-growing data structure) 371 * @param implicit if true tag is assumed implicit. 372 * @return array of the values in the sequence 373 */ getSet(int startLen, boolean implicit)374 public DerValue[] getSet(int startLen, boolean implicit) 375 throws IOException { 376 tag = (byte)buffer.read(); 377 if (!implicit) { 378 if (tag != DerValue.tag_Set) { 379 throw new IOException("Set tag error"); 380 } 381 } 382 return (readVector(startLen)); 383 } 384 385 /* 386 * Read a "vector" of values ... set or sequence have the 387 * same encoding, except for the initial tag, so both use 388 * this same helper routine. 389 */ readVector(int startLen)390 protected DerValue[] readVector(int startLen) throws IOException { 391 DerInputStream newstr; 392 393 byte lenByte = (byte)buffer.read(); 394 int len = getLength(lenByte, buffer); 395 396 if (len == -1) { 397 // indefinite length encoding found 398 buffer = new DerInputBuffer( 399 DerIndefLenConverter.convertStream(buffer, lenByte, tag), 400 buffer.allowBER); 401 402 if (tag != buffer.read()) 403 throw new IOException("Indefinite length encoding" + 404 " not supported"); 405 len = DerInputStream.getDefiniteLength(buffer); 406 } 407 408 if (len == 0) 409 // return empty array instead of null, which should be 410 // used only for missing optionals 411 return new DerValue[0]; 412 413 /* 414 * Create a temporary stream from which to read the data, 415 * unless it's not really needed. 416 */ 417 if (buffer.available() == len) 418 newstr = this; 419 else 420 newstr = subStream(len, true); 421 422 /* 423 * Pull values out of the stream. 424 */ 425 Vector<DerValue> vec = new Vector<>(startLen); 426 DerValue value; 427 428 do { 429 value = new DerValue(newstr.buffer, buffer.allowBER); 430 vec.addElement(value); 431 } while (newstr.available() > 0); 432 433 if (newstr.available() != 0) 434 throw new IOException("Extra data at end of vector"); 435 436 /* 437 * Now stick them into the array we're returning. 438 */ 439 int i, max = vec.size(); 440 DerValue[] retval = new DerValue[max]; 441 442 for (i = 0; i < max; i++) 443 retval[i] = vec.elementAt(i); 444 445 return retval; 446 } 447 448 /** 449 * Get a single DER-encoded value from the input stream. 450 * It can often be useful to pull a value from the stream 451 * and defer parsing it. For example, you can pull a nested 452 * sequence out with one call, and only examine its elements 453 * later when you really need to. 454 */ getDerValue()455 public DerValue getDerValue() throws IOException { 456 return new DerValue(buffer); 457 } 458 459 /** 460 * Read a string that was encoded as a UTF8String DER value. 461 */ getUTF8String()462 public String getUTF8String() throws IOException { 463 return readString(DerValue.tag_UTF8String, "UTF-8", UTF_8); 464 } 465 466 /** 467 * Read a string that was encoded as a PrintableString DER value. 468 */ getPrintableString()469 public String getPrintableString() throws IOException { 470 return readString(DerValue.tag_PrintableString, "Printable", 471 US_ASCII); 472 } 473 474 /** 475 * Read a string that was encoded as a T61String DER value. 476 */ getT61String()477 public String getT61String() throws IOException { 478 /* 479 * Works for common characters between T61 and ASCII. 480 */ 481 return readString(DerValue.tag_T61String, "T61", ISO_8859_1); 482 } 483 484 /** 485 * Read a string that was encoded as a IA5String DER value. 486 */ getIA5String()487 public String getIA5String() throws IOException { 488 return readString(DerValue.tag_IA5String, "IA5", US_ASCII); 489 } 490 491 /** 492 * Read a string that was encoded as a BMPString DER value. 493 */ getBMPString()494 public String getBMPString() throws IOException { 495 return readString(DerValue.tag_BMPString, "BMP", UTF_16BE); 496 } 497 498 /** 499 * Read a string that was encoded as a GeneralString DER value. 500 */ getGeneralString()501 public String getGeneralString() throws IOException { 502 return readString(DerValue.tag_GeneralString, "General", 503 US_ASCII); 504 } 505 506 /** 507 * Private helper routine to read an encoded string from the input 508 * stream. 509 * @param stringTag the tag for the type of string to read 510 * @param stringName a name to display in error messages 511 * @param enc the encoder to use to interpret the data. Should 512 * correspond to the stringTag above. 513 */ readString(byte stringTag, String stringName, Charset charset)514 private String readString(byte stringTag, String stringName, 515 Charset charset) throws IOException { 516 517 if (buffer.read() != stringTag) 518 throw new IOException("DER input not a " + 519 stringName + " string"); 520 521 int length = getDefiniteLength(buffer); 522 byte[] retval = new byte[length]; 523 if ((length != 0) && (buffer.read(retval) != length)) 524 throw new IOException("Short read of DER " + 525 stringName + " string"); 526 527 return new String(retval, charset); 528 } 529 530 /** 531 * Get a UTC encoded time value from the input stream. 532 */ getUTCTime()533 public Date getUTCTime() throws IOException { 534 if (buffer.read() != DerValue.tag_UtcTime) 535 throw new IOException("DER input, UTCtime tag invalid "); 536 return buffer.getUTCTime(getDefiniteLength(buffer)); 537 } 538 539 /** 540 * Get a Generalized encoded time value from the input stream. 541 */ getGeneralizedTime()542 public Date getGeneralizedTime() throws IOException { 543 if (buffer.read() != DerValue.tag_GeneralizedTime) 544 throw new IOException("DER input, GeneralizedTime tag invalid "); 545 return buffer.getGeneralizedTime(getDefiniteLength(buffer)); 546 } 547 548 /* 549 * Get a byte from the input stream. 550 */ 551 // package private getByte()552 int getByte() throws IOException { 553 return (0x00ff & buffer.read()); 554 } 555 peekByte()556 public int peekByte() throws IOException { 557 return buffer.peek(); 558 } 559 560 // package private getLength()561 int getLength() throws IOException { 562 return getLength(buffer); 563 } 564 565 /* 566 * Get a length from the input stream, allowing for at most 32 bits of 567 * encoding to be used. (Not the same as getting a tagged integer!) 568 * 569 * @return the length or -1 if indefinite length found. 570 * @exception IOException on parsing error or unsupported lengths. 571 */ getLength(InputStream in)572 static int getLength(InputStream in) throws IOException { 573 return getLength(in.read(), in); 574 } 575 576 /* 577 * Get a length from the input stream, allowing for at most 32 bits of 578 * encoding to be used. (Not the same as getting a tagged integer!) 579 * 580 * @return the length or -1 if indefinite length found. 581 * @exception IOException on parsing error or unsupported lengths. 582 */ getLength(int lenByte, InputStream in)583 static int getLength(int lenByte, InputStream in) throws IOException { 584 int value, tmp; 585 if (lenByte == -1) { 586 throw new IOException("Short read of DER length"); 587 } 588 589 String mdName = "DerInputStream.getLength(): "; 590 tmp = lenByte; 591 if ((tmp & 0x080) == 0x00) { // short form, 1 byte datum 592 value = tmp; 593 } else { // long form or indefinite 594 tmp &= 0x07f; 595 596 /* 597 * NOTE: tmp == 0 indicates indefinite length encoded data. 598 * tmp > 4 indicates more than 4Gb of data. 599 */ 600 if (tmp == 0) 601 return -1; 602 if (tmp < 0 || tmp > 4) 603 throw new IOException(mdName + "lengthTag=" + tmp + ", " 604 + ((tmp < 0) ? "incorrect DER encoding." : "too big.")); 605 606 value = 0x0ff & in.read(); 607 tmp--; 608 if (value == 0) { 609 // DER requires length value be encoded in minimum number of bytes 610 throw new IOException(mdName + "Redundant length bytes found"); 611 } 612 while (tmp-- > 0) { 613 value <<= 8; 614 value += 0x0ff & in.read(); 615 } 616 if (value < 0) { 617 throw new IOException(mdName + "Invalid length bytes"); 618 } else if (value <= 127) { 619 throw new IOException(mdName + "Should use short form for length"); 620 } 621 } 622 return value; 623 } 624 getDefiniteLength()625 int getDefiniteLength() throws IOException { 626 return getDefiniteLength(buffer); 627 } 628 629 /* 630 * Get a length from the input stream. 631 * 632 * @return the length 633 * @exception IOException on parsing error or if indefinite length found. 634 */ getDefiniteLength(InputStream in)635 static int getDefiniteLength(InputStream in) throws IOException { 636 int len = getLength(in); 637 if (len < 0) { 638 throw new IOException("Indefinite length encoding not supported"); 639 } 640 return len; 641 } 642 643 /** 644 * Mark the current position in the buffer, so that 645 * a later call to <code>reset</code> will return here. 646 */ mark(int value)647 public void mark(int value) { buffer.mark(value); } 648 649 650 /** 651 * Return to the position of the last <code>mark</code> 652 * call. A mark is implicitly set at the beginning of 653 * the stream when it is created. 654 */ reset()655 public void reset() { buffer.reset(); } 656 657 658 /** 659 * Returns the number of bytes available for reading. 660 * This is most useful for testing whether the stream is 661 * empty. 662 */ available()663 public int available() { return buffer.available(); } 664 } 665