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