1 /* 2 * Copyright (c) 1996, 2006, 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(getLength(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(getLength(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(getLength(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(getLength(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(getLength(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 int length = getLength(buffer) - 1; 231 232 /* 233 * First byte = number of excess bits in the last octet of the 234 * representation. 235 */ 236 int validBits = length*8 - buffer.read(); 237 238 byte[] repn = new byte[length]; 239 240 if ((length != 0) && (buffer.read(repn) != length)) 241 throw new IOException("short read of DER bit string"); 242 return new BitArray(validBits, repn); 243 } 244 245 /** 246 * Returns an ASN.1 OCTET STRING from the input stream. 247 */ 248 public byte[] getOctetString() throws IOException { 249 if (buffer.read() != DerValue.tag_OctetString) 250 throw new IOException("DER input not an octet string"); 251 252 int length = getLength(buffer); 253 byte[] retval = new byte[length]; 254 if ((length != 0) && (buffer.read(retval) != length)) 255 throw new IOException("short read of DER octet string"); 256 257 return retval; 258 } 259 260 /** 261 * Returns the asked number of bytes from the input stream. 262 */ 263 public void getBytes(byte[] val) throws IOException { 264 if ((val.length != 0) && (buffer.read(val) != val.length)) { 265 throw new IOException("short read of DER octet string"); 266 } 267 } 268 269 /** 270 * Reads an encoded null value from the input stream. 271 */ 272 public void getNull() throws IOException { 273 if (buffer.read() != DerValue.tag_Null || buffer.read() != 0) 274 throw new IOException("getNull, bad data"); 275 } 276 277 /** 278 * Reads an X.200 style Object Identifier from the stream. 279 */ 280 public ObjectIdentifier getOID() throws IOException { 281 return new ObjectIdentifier(this); 282 } 283 284 /** 285 * Return a sequence of encoded entities. ASN.1 sequences are 286 * ordered, and they are often used, like a "struct" in C or C++, 287 * to group data values. They may have optional or context 288 * specific values. 289 * 290 * @param startLen guess about how long the sequence will be 291 * (used to initialize an auto-growing data structure) 292 * @return array of the values in the sequence 293 */ 294 public DerValue[] getSequence(int startLen, 295 boolean originalEncodedFormRetained) throws IOException { 296 tag = (byte)buffer.read(); 297 if (tag != DerValue.tag_Sequence) 298 throw new IOException("Sequence tag error"); 299 return readVector(startLen, originalEncodedFormRetained); 300 } 301 302 /** 303 * Return a sequence of encoded entities. ASN.1 sequences are 304 * ordered, and they are often used, like a "struct" in C or C++, 305 * to group data values. They may have optional or context 306 * specific values. 307 * 308 * @param startLen guess about how long the sequence will be 309 * (used to initialize an auto-growing data structure) 310 * @return array of the values in the sequence 311 */ 312 public DerValue[] getSequence(int startLen) throws IOException { 313 return getSequence( 314 startLen, 315 false); // no need to retain original encoded form 316 } 317 318 /** 319 * Return a set of encoded entities. ASN.1 sets are unordered, 320 * though DER may specify an order for some kinds of sets (such 321 * as the attributes in an X.500 relative distinguished name) 322 * to facilitate binary comparisons of encoded values. 323 * 324 * @param startLen guess about how large the set will be 325 * (used to initialize an auto-growing data structure) 326 * @return array of the values in the sequence 327 */ 328 public DerValue[] getSet(int startLen) throws IOException { 329 tag = (byte)buffer.read(); 330 if (tag != DerValue.tag_Set) 331 throw new IOException("Set tag error"); 332 return readVector(startLen); 333 } 334 335 /** 336 * Return a set of encoded entities. ASN.1 sets are unordered, 337 * though DER may specify an order for some kinds of sets (such 338 * as the attributes in an X.500 relative distinguished name) 339 * to facilitate binary comparisons of encoded values. 340 * 341 * @param startLen guess about how large the set will be 342 * (used to initialize an auto-growing data structure) 343 * @param implicit if true tag is assumed implicit. 344 * @return array of the values in the sequence 345 */ 346 public DerValue[] getSet(int startLen, boolean implicit) 347 throws IOException { 348 return getSet( 349 startLen, 350 implicit, 351 false); // no need to retain original encoded form 352 } 353 354 public DerValue[] getSet(int startLen, boolean implicit, 355 boolean originalEncodedFormRetained) 356 throws IOException { 357 tag = (byte)buffer.read(); 358 if (!implicit) { 359 if (tag != DerValue.tag_Set) { 360 throw new IOException("Set tag error"); 361 } 362 } 363 return (readVector(startLen, originalEncodedFormRetained)); 364 } 365 366 /* 367 * Read a "vector" of values ... set or sequence have the 368 * same encoding, except for the initial tag, so both use 369 * this same helper routine. 370 */ 371 protected DerValue[] readVector(int startLen) throws IOException { 372 return readVector( 373 startLen, 374 false); // no need to retain original encoded form 375 } 376 377 /* 378 * Read a "vector" of values ... set or sequence have the 379 * same encoding, except for the initial tag, so both use 380 * this same helper routine. 381 */ 382 protected DerValue[] readVector(int startLen, 383 boolean originalEncodedFormRetained) throws IOException { 384 DerInputStream newstr; 385 386 byte lenByte = (byte)buffer.read(); 387 int len = getLength((lenByte & 0xff), buffer); 388 389 if (len == -1) { 390 // indefinite length encoding found 391 int readLen = buffer.available(); 392 int offset = 2; // for tag and length bytes 393 byte[] indefData = new byte[readLen + offset]; 394 indefData[0] = tag; 395 indefData[1] = lenByte; 396 DataInputStream dis = new DataInputStream(buffer); 397 dis.readFully(indefData, offset, readLen); 398 dis.close(); 399 DerIndefLenConverter derIn = new DerIndefLenConverter(); 400 buffer = new DerInputBuffer(derIn.convert(indefData)); 401 if (tag != buffer.read()) 402 throw new IOException("Indefinite length encoding" + 403 " not supported"); 404 len = DerInputStream.getLength(buffer); 405 } 406 407 if (len == 0) 408 // return empty array instead of null, which should be 409 // used only for missing optionals 410 return new DerValue[0]; 411 412 /* 413 * Create a temporary stream from which to read the data, 414 * unless it's not really needed. 415 */ 416 if (buffer.available() == len) 417 newstr = this; 418 else 419 newstr = subStream(len, true); 420 421 /* 422 * Pull values out of the stream. 423 */ 424 Vector<DerValue> vec = new Vector<DerValue>(startLen); 425 DerValue value; 426 427 do { 428 value = new DerValue(newstr.buffer, originalEncodedFormRetained); 429 vec.addElement(value); 430 } while (newstr.available() > 0); 431 432 if (newstr.available() != 0) 433 throw new IOException("extra data at end of vector"); 434 435 /* 436 * Now stick them into the array we're returning. 437 */ 438 int i, max = vec.size(); 439 DerValue[] retval = new DerValue[max]; 440 441 for (i = 0; i < max; i++) 442 retval[i] = vec.elementAt(i); 443 444 return retval; 445 } 446 447 /** 448 * Get a single DER-encoded value from the input stream. 449 * It can often be useful to pull a value from the stream 450 * and defer parsing it. For example, you can pull a nested 451 * sequence out with one call, and only examine its elements 452 * later when you really need to. 453 */ 454 public DerValue getDerValue() throws IOException { 455 return new DerValue(buffer); 456 } 457 458 /** 459 * Read a string that was encoded as a UTF8String DER value. 460 */ 461 public String getUTF8String() throws IOException { 462 return readString(DerValue.tag_UTF8String, "UTF-8", "UTF8"); 463 } 464 465 /** 466 * Read a string that was encoded as a PrintableString DER value. 467 */ 468 public String getPrintableString() throws IOException { 469 return readString(DerValue.tag_PrintableString, "Printable", 470 "ASCII"); 471 } 472 473 /** 474 * Read a string that was encoded as a T61String DER value. 475 */ 476 public String getT61String() throws IOException { 477 /* 478 * Works for common characters between T61 and ASCII. 479 */ 480 return readString(DerValue.tag_T61String, "T61", "ISO-8859-1"); 481 } 482 483 /** 484 * Read a string that was encoded as a IA5tring DER value. 485 */ 486 public String getIA5String() throws IOException { 487 return readString(DerValue.tag_IA5String, "IA5", "ASCII"); 488 } 489 490 /** 491 * Read a string that was encoded as a BMPString DER value. 492 */ 493 public String getBMPString() throws IOException { 494 return readString(DerValue.tag_BMPString, "BMP", 495 "UnicodeBigUnmarked"); 496 } 497 498 /** 499 * Read a string that was encoded as a GeneralString DER value. 500 */ 501 public String getGeneralString() throws IOException { 502 return readString(DerValue.tag_GeneralString, "General", 503 "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 */ 514 private String readString(byte stringTag, String stringName, 515 String enc) throws IOException { 516 517 if (buffer.read() != stringTag) 518 throw new IOException("DER input not a " + 519 stringName + " string"); 520 521 int length = getLength(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, enc); 528 } 529 530 /** 531 * Get a UTC encoded time value from the input stream. 532 */ 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(getLength(buffer)); 537 } 538 539 /** 540 * Get a Generalized encoded time value from the input stream. 541 */ 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(getLength(buffer)); 546 } 547 548 /* 549 * Get a byte from the input stream. 550 */ 551 // package private 552 int getByte() throws IOException { 553 return (0x00ff & buffer.read()); 554 } 555 556 public int peekByte() throws IOException { 557 return buffer.peek(); 558 } 559 560 // package private 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 */ 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 */ 583 static int getLength(int lenByte, InputStream in) throws IOException { 584 int value, tmp; 585 586 tmp = lenByte; 587 if ((tmp & 0x080) == 0x00) { // short form, 1 byte datum 588 value = tmp; 589 } else { // long form or indefinite 590 tmp &= 0x07f; 591 592 /* 593 * NOTE: tmp == 0 indicates indefinite length encoded data. 594 * tmp > 4 indicates more than 4Gb of data. 595 */ 596 if (tmp == 0) 597 return -1; 598 if (tmp < 0 || tmp > 4) 599 throw new IOException("DerInputStream.getLength(): lengthTag=" 600 + tmp + ", " 601 + ((tmp < 0) ? "incorrect DER encoding." : "too big.")); 602 603 for (value = 0; tmp > 0; tmp --) { 604 value <<= 8; 605 value += 0x0ff & in.read(); 606 } 607 if (value < 0) { 608 throw new IOException("DerInputStream.getLength(): " 609 + "Invalid length bytes"); 610 } 611 } 612 return value; 613 } 614 615 /** 616 * Mark the current position in the buffer, so that 617 * a later call to <code>reset</code> will return here. 618 */ 619 public void mark(int value) { buffer.mark(value); } 620 621 622 /** 623 * Return to the position of the last <code>mark</code> 624 * call. A mark is implicitly set at the beginning of 625 * the stream when it is created. 626 */ 627 public void reset() { buffer.reset(); } 628 629 630 /** 631 * Returns the number of bytes available for reading. 632 * This is most useful for testing whether the stream is 633 * empty. 634 */ 635 public int available() { return buffer.available(); } 636 } 637