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