1 /* 2 * Copyright (c) 1996, 2009, 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.*; 29 import java.math.BigInteger; 30 import java.util.Date; 31 import sun.misc.IOUtils; 32 33 /** 34 * Represents a single DER-encoded value. DER encoding rules are a subset 35 * of the "Basic" Encoding Rules (BER), but they only support a single way 36 * ("Definite" encoding) to encode any given value. 37 * 38 * <P>All DER-encoded data are triples <em>{type, length, data}</em>. This 39 * class represents such tagged values as they have been read (or constructed), 40 * and provides structured access to the encoded data. 41 * 42 * <P>At this time, this class supports only a subset of the types of DER 43 * data encodings which are defined. That subset is sufficient for parsing 44 * most X.509 certificates, and working with selected additional formats 45 * (such as PKCS #10 certificate requests, and some kinds of PKCS #7 data). 46 * 47 * A note with respect to T61/Teletex strings: From RFC 1617, section 4.1.3 48 * and RFC 3280, section 4.1.2.4., we assume that this kind of string will 49 * contain ISO-8859-1 characters only. 50 * 51 * 52 * @author David Brownell 53 * @author Amit Kapoor 54 * @author Hemma Prafullchandra 55 */ 56 public class DerValue { 57 /** The tag class types */ 58 public static final byte TAG_UNIVERSAL = (byte)0x000; 59 public static final byte TAG_APPLICATION = (byte)0x040; 60 public static final byte TAG_CONTEXT = (byte)0x080; 61 public static final byte TAG_PRIVATE = (byte)0x0c0; 62 63 /** The DER tag of the value; one of the tag_ constants. */ 64 public byte tag; 65 66 protected DerInputBuffer buffer; 67 68 /** 69 * The DER-encoded data of the value, never null 70 */ 71 public final DerInputStream data; 72 73 private int length; 74 75 /** 76 * The original encoded form of the whole value (tag, length, and value) 77 * or null if the form was not provided or was not retained during parsing. 78 */ 79 private byte[] originalEncodedForm; 80 81 /* 82 * The type starts at the first byte of the encoding, and 83 * is one of these tag_* values. That may be all the type 84 * data that is needed. 85 */ 86 87 /* 88 * These tags are the "universal" tags ... they mean the same 89 * in all contexts. (Mask with 0x1f -- five bits.) 90 */ 91 92 /** Tag value indicating an ASN.1 "BOOLEAN" value. */ 93 public final static byte tag_Boolean = 0x01; 94 95 /** Tag value indicating an ASN.1 "INTEGER" value. */ 96 public final static byte tag_Integer = 0x02; 97 98 /** Tag value indicating an ASN.1 "BIT STRING" value. */ 99 public final static byte tag_BitString = 0x03; 100 101 /** Tag value indicating an ASN.1 "OCTET STRING" value. */ 102 public final static byte tag_OctetString = 0x04; 103 104 /** Tag value indicating an ASN.1 "NULL" value. */ 105 public final static byte tag_Null = 0x05; 106 107 /** Tag value indicating an ASN.1 "OBJECT IDENTIFIER" value. */ 108 public final static byte tag_ObjectId = 0x06; 109 110 /** Tag value including an ASN.1 "ENUMERATED" value */ 111 public final static byte tag_Enumerated = 0x0A; 112 113 /** Tag value indicating an ASN.1 "UTF8String" value. */ 114 public final static byte tag_UTF8String = 0x0C; 115 116 /** Tag value including a "printable" string */ 117 public final static byte tag_PrintableString = 0x13; 118 119 /** Tag value including a "teletype" string */ 120 public final static byte tag_T61String = 0x14; 121 122 /** Tag value including an ASCII string */ 123 public final static byte tag_IA5String = 0x16; 124 125 /** Tag value indicating an ASN.1 "UTCTime" value. */ 126 public final static byte tag_UtcTime = 0x17; 127 128 /** Tag value indicating an ASN.1 "GeneralizedTime" value. */ 129 public final static byte tag_GeneralizedTime = 0x18; 130 131 /** Tag value indicating an ASN.1 "GenerallString" value. */ 132 public final static byte tag_GeneralString = 0x1B; 133 134 /** Tag value indicating an ASN.1 "UniversalString" value. */ 135 public final static byte tag_UniversalString = 0x1C; 136 137 /** Tag value indicating an ASN.1 "BMPString" value. */ 138 public final static byte tag_BMPString = 0x1E; 139 140 // CONSTRUCTED seq/set 141 142 /** 143 * Tag value indicating an ASN.1 144 * "SEQUENCE" (zero to N elements, order is significant). 145 */ 146 public final static byte tag_Sequence = 0x30; 147 148 /** 149 * Tag value indicating an ASN.1 150 * "SEQUENCE OF" (one to N elements, order is significant). 151 */ 152 public final static byte tag_SequenceOf = 0x30; 153 154 /** 155 * Tag value indicating an ASN.1 156 * "SET" (zero to N members, order does not matter). 157 */ 158 public final static byte tag_Set = 0x31; 159 160 /** 161 * Tag value indicating an ASN.1 162 * "SET OF" (one to N members, order does not matter). 163 */ 164 public final static byte tag_SetOf = 0x31; 165 166 /* 167 * These values are the high order bits for the other kinds of tags. 168 */ 169 170 /** 171 * Returns true if the tag class is UNIVERSAL. 172 */ 173 public boolean isUniversal() { return ((tag & 0x0c0) == 0x000); } 174 175 /** 176 * Returns true if the tag class is APPLICATION. 177 */ 178 public boolean isApplication() { return ((tag & 0x0c0) == 0x040); } 179 180 /** 181 * Returns true iff the CONTEXT SPECIFIC bit is set in the type tag. 182 * This is associated with the ASN.1 "DEFINED BY" syntax. 183 */ 184 public boolean isContextSpecific() { return ((tag & 0x0c0) == 0x080); } 185 186 /** 187 * Returns true iff the CONTEXT SPECIFIC TAG matches the passed tag. 188 */ 189 public boolean isContextSpecific(byte cntxtTag) { 190 if (!isContextSpecific()) { 191 return false; 192 } 193 return ((tag & 0x01f) == cntxtTag); 194 } 195 196 boolean isPrivate() { return ((tag & 0x0c0) == 0x0c0); } 197 198 /** Returns true iff the CONSTRUCTED bit is set in the type tag. */ 199 public boolean isConstructed() { return ((tag & 0x020) == 0x020); } 200 201 /** 202 * Returns true iff the CONSTRUCTED TAG matches the passed tag. 203 */ 204 public boolean isConstructed(byte constructedTag) { 205 if (!isConstructed()) { 206 return false; 207 } 208 return ((tag & 0x01f) == constructedTag); 209 } 210 211 /** 212 * Creates a PrintableString or UTF8string DER value from a string 213 */ 214 public DerValue(String value) throws IOException { 215 boolean isPrintableString = true; 216 for (int i = 0; i < value.length(); i++) { 217 if (!isPrintableStringChar(value.charAt(i))) { 218 isPrintableString = false; 219 break; 220 } 221 } 222 223 data = init(isPrintableString ? tag_PrintableString : tag_UTF8String, value); 224 } 225 226 /** 227 * Creates a string type DER value from a String object 228 * @param stringTag the tag for the DER value to create 229 * @param value the String object to use for the DER value 230 */ 231 public DerValue(byte stringTag, String value) throws IOException { 232 data = init(stringTag, value); 233 } 234 235 /** 236 * Creates a DerValue from a tag and some DER-encoded data. 237 * 238 * @param tag the DER type tag 239 * @param data the DER-encoded data 240 */ 241 public DerValue(byte tag, byte[] data) { 242 this.tag = tag; 243 buffer = new DerInputBuffer(data.clone()); 244 length = data.length; 245 this.data = new DerInputStream(buffer); 246 this.data.mark(Integer.MAX_VALUE); 247 } 248 249 /* 250 * package private 251 */ 252 DerValue(DerInputBuffer in, boolean originalEncodedFormRetained) 253 throws IOException { 254 // XXX must also parse BER-encoded constructed 255 // values such as sequences, sets... 256 257 int startPosInInput = in.getPos(); 258 tag = (byte)in.read(); 259 byte lenByte = (byte)in.read(); 260 length = DerInputStream.getLength((lenByte & 0xff), in); 261 if (length == -1) { // indefinite length encoding found 262 DerInputBuffer inbuf = in.dup(); 263 int readLen = inbuf.available(); 264 int offset = 2; // for tag and length bytes 265 byte[] indefData = new byte[readLen + offset]; 266 indefData[0] = tag; 267 indefData[1] = lenByte; 268 DataInputStream dis = new DataInputStream(inbuf); 269 dis.readFully(indefData, offset, readLen); 270 dis.close(); 271 DerIndefLenConverter derIn = new DerIndefLenConverter(); 272 inbuf = new DerInputBuffer(derIn.convert(indefData)); 273 if (tag != inbuf.read()) 274 throw new IOException 275 ("Indefinite length encoding not supported"); 276 length = DerInputStream.getLength(inbuf); 277 buffer = inbuf.dup(); 278 buffer.truncate(length); 279 data = new DerInputStream(buffer); 280 // indefinite form is encoded by sending a length field with a 281 // length of 0. - i.e. [1000|0000]. 282 // the object is ended by sending two zero bytes. 283 in.skip(length + offset); 284 } else { 285 286 buffer = in.dup(); 287 buffer.truncate(length); 288 data = new DerInputStream(buffer); 289 290 in.skip(length); 291 } 292 293 if (originalEncodedFormRetained) { 294 int consumed = in.getPos() - startPosInInput; 295 originalEncodedForm = in.getSlice(startPosInInput, consumed); 296 } 297 } 298 299 /** 300 * Get an ASN.1/DER encoded datum from a buffer. The 301 * entire buffer must hold exactly one datum, including 302 * its tag and length. 303 * 304 * @param buf buffer holding a single DER-encoded datum. 305 */ 306 public DerValue(byte[] buf) throws IOException { 307 data = init(true, new ByteArrayInputStream(buf)); 308 } 309 310 /** 311 * Get an ASN.1/DER encoded datum from part of a buffer. 312 * That part of the buffer must hold exactly one datum, including 313 * its tag and length. 314 * 315 * @param buf the buffer 316 * @param offset start point of the single DER-encoded dataum 317 * @param length how many bytes are in the encoded datum 318 */ 319 public DerValue(byte[] buf, int offset, int len) throws IOException { 320 data = init(true, new ByteArrayInputStream(buf, offset, len)); 321 } 322 323 /** 324 * Get an ASN1/DER encoded datum from an input stream. The 325 * stream may have additional data following the encoded datum. 326 * In case of indefinite length encoded datum, the input stream 327 * must hold only one datum. 328 * 329 * @param in the input stream holding a single DER datum, 330 * which may be followed by additional data 331 */ 332 public DerValue(InputStream in) throws IOException { 333 data = init(false, in); 334 } 335 336 private DerInputStream init(byte stringTag, String value) throws IOException { 337 String enc = null; 338 339 tag = stringTag; 340 341 switch (stringTag) { 342 case tag_PrintableString: 343 case tag_IA5String: 344 case tag_GeneralString: 345 enc = "ASCII"; 346 break; 347 case tag_T61String: 348 enc = "ISO-8859-1"; 349 break; 350 case tag_BMPString: 351 enc = "UnicodeBigUnmarked"; 352 break; 353 case tag_UTF8String: 354 enc = "UTF8"; 355 break; 356 // TBD: Need encoder for UniversalString before it can 357 // be handled. 358 default: 359 throw new IllegalArgumentException("Unsupported DER string type"); 360 } 361 362 byte[] buf = value.getBytes(enc); 363 length = buf.length; 364 buffer = new DerInputBuffer(buf); 365 DerInputStream result = new DerInputStream(buffer); 366 result.mark(Integer.MAX_VALUE); 367 return result; 368 } 369 370 /* 371 * helper routine 372 */ 373 private DerInputStream init(boolean fullyBuffered, InputStream in) 374 throws IOException { 375 376 tag = (byte)in.read(); 377 byte lenByte = (byte)in.read(); 378 length = DerInputStream.getLength((lenByte & 0xff), in); 379 if (length == -1) { // indefinite length encoding found 380 int readLen = in.available(); 381 int offset = 2; // for tag and length bytes 382 byte[] indefData = new byte[readLen + offset]; 383 indefData[0] = tag; 384 indefData[1] = lenByte; 385 DataInputStream dis = new DataInputStream(in); 386 dis.readFully(indefData, offset, readLen); 387 dis.close(); 388 DerIndefLenConverter derIn = new DerIndefLenConverter(); 389 in = new ByteArrayInputStream(derIn.convert(indefData)); 390 if (tag != in.read()) 391 throw new IOException 392 ("Indefinite length encoding not supported"); 393 length = DerInputStream.getLength(in); 394 } 395 396 if (fullyBuffered && in.available() != length) 397 throw new IOException("extra data given to DerValue constructor"); 398 399 byte[] bytes = IOUtils.readFully(in, length, true); 400 401 buffer = new DerInputBuffer(bytes); 402 return new DerInputStream(buffer); 403 } 404 405 /** 406 * Encode an ASN1/DER encoded datum onto a DER output stream. 407 */ 408 public void encode(DerOutputStream out) 409 throws IOException { 410 out.write(tag); 411 out.putLength(length); 412 // XXX yeech, excess copies ... DerInputBuffer.write(OutStream) 413 if (length > 0) { 414 byte[] value = new byte[length]; 415 // always synchronized on data 416 synchronized (data) { 417 buffer.reset(); 418 if (buffer.read(value) != length) { 419 throw new IOException("short DER value read (encode)"); 420 } 421 out.write(value); 422 } 423 } 424 } 425 426 public final DerInputStream getData() { 427 return data; 428 } 429 430 public final byte getTag() { 431 return tag; 432 } 433 434 /** 435 * Returns an ASN.1 BOOLEAN 436 * 437 * @return the boolean held in this DER value 438 */ 439 public boolean getBoolean() throws IOException { 440 if (tag != tag_Boolean) { 441 throw new IOException("DerValue.getBoolean, not a BOOLEAN " + tag); 442 } 443 if (length != 1) { 444 throw new IOException("DerValue.getBoolean, invalid length " 445 + length); 446 } 447 if (buffer.read() != 0) { 448 return true; 449 } 450 return false; 451 } 452 453 /** 454 * Returns an ASN.1 OBJECT IDENTIFIER. 455 * 456 * @return the OID held in this DER value 457 */ 458 public ObjectIdentifier getOID() throws IOException { 459 if (tag != tag_ObjectId) 460 throw new IOException("DerValue.getOID, not an OID " + tag); 461 return new ObjectIdentifier(buffer); 462 } 463 464 private byte[] append(byte[] a, byte[] b) { 465 if (a == null) 466 return b; 467 468 byte[] ret = new byte[a.length + b.length]; 469 System.arraycopy(a, 0, ret, 0, a.length); 470 System.arraycopy(b, 0, ret, a.length, b.length); 471 472 return ret; 473 } 474 475 /** 476 * Returns an ASN.1 OCTET STRING 477 * 478 * @return the octet string held in this DER value 479 */ 480 public byte[] getOctetString() throws IOException { 481 byte[] bytes; 482 483 if (tag != tag_OctetString && !isConstructed(tag_OctetString)) { 484 throw new IOException( 485 "DerValue.getOctetString, not an Octet String: " + tag); 486 } 487 bytes = new byte[length]; 488 // Note: do not tempt to call buffer.read(bytes) at all. There's a 489 // known bug that it returns -1 instead of 0. 490 if (length == 0) { 491 return bytes; 492 } 493 if (buffer.read(bytes) != length) 494 throw new IOException("short read on DerValue buffer"); 495 if (isConstructed()) { 496 DerInputStream in = new DerInputStream(bytes); 497 bytes = null; 498 while (in.available() != 0) { 499 bytes = append(bytes, in.getOctetString()); 500 } 501 } 502 return bytes; 503 } 504 505 /** 506 * Returns an ASN.1 INTEGER value as an integer. 507 * 508 * @return the integer held in this DER value. 509 */ 510 public int getInteger() throws IOException { 511 if (tag != tag_Integer) { 512 throw new IOException("DerValue.getInteger, not an int " + tag); 513 } 514 return buffer.getInteger(data.available()); 515 } 516 517 /** 518 * Returns an ASN.1 INTEGER value as a BigInteger. 519 * 520 * @return the integer held in this DER value as a BigInteger. 521 */ 522 public BigInteger getBigInteger() throws IOException { 523 if (tag != tag_Integer) 524 throw new IOException("DerValue.getBigInteger, not an int " + tag); 525 return buffer.getBigInteger(data.available(), false); 526 } 527 528 /** 529 * Returns an ASN.1 INTEGER value as a positive BigInteger. 530 * This is just to deal with implementations that incorrectly encode 531 * some values as negative. 532 * 533 * @return the integer held in this DER value as a BigInteger. 534 */ 535 public BigInteger getPositiveBigInteger() throws IOException { 536 if (tag != tag_Integer) 537 throw new IOException("DerValue.getBigInteger, not an int " + tag); 538 return buffer.getBigInteger(data.available(), true); 539 } 540 541 /** 542 * Returns an ASN.1 ENUMERATED value. 543 * 544 * @return the integer held in this DER value. 545 */ 546 public int getEnumerated() throws IOException { 547 if (tag != tag_Enumerated) { 548 throw new IOException("DerValue.getEnumerated, incorrect tag: " 549 + tag); 550 } 551 return buffer.getInteger(data.available()); 552 } 553 554 /** 555 * Returns an ASN.1 BIT STRING value. The bit string must be byte-aligned. 556 * 557 * @return the bit string held in this value 558 */ 559 public byte[] getBitString() throws IOException { 560 if (tag != tag_BitString) 561 throw new IOException( 562 "DerValue.getBitString, not a bit string " + tag); 563 564 return buffer.getBitString(); 565 } 566 567 /** 568 * Returns an ASN.1 BIT STRING value that need not be byte-aligned. 569 * 570 * @return a BitArray representing the bit string held in this value 571 */ 572 public BitArray getUnalignedBitString() throws IOException { 573 if (tag != tag_BitString) 574 throw new IOException( 575 "DerValue.getBitString, not a bit string " + tag); 576 577 return buffer.getUnalignedBitString(); 578 } 579 580 /** 581 * Returns the name component as a Java string, regardless of its 582 * encoding restrictions (ASCII, T61, Printable, IA5, BMP, UTF8). 583 */ 584 // TBD: Need encoder for UniversalString before it can be handled. 585 public String getAsString() throws IOException { 586 if (tag == tag_UTF8String) 587 return getUTF8String(); 588 else if (tag == tag_PrintableString) 589 return getPrintableString(); 590 else if (tag == tag_T61String) 591 return getT61String(); 592 else if (tag == tag_IA5String) 593 return getIA5String(); 594 /* 595 else if (tag == tag_UniversalString) 596 return getUniversalString(); 597 */ 598 else if (tag == tag_BMPString) 599 return getBMPString(); 600 else if (tag == tag_GeneralString) 601 return getGeneralString(); 602 else 603 return null; 604 } 605 606 /** 607 * Returns an ASN.1 BIT STRING value, with the tag assumed implicit 608 * based on the parameter. The bit string must be byte-aligned. 609 * 610 * @params tagImplicit if true, the tag is assumed implicit. 611 * @return the bit string held in this value 612 */ 613 public byte[] getBitString(boolean tagImplicit) throws IOException { 614 if (!tagImplicit) { 615 if (tag != tag_BitString) 616 throw new IOException("DerValue.getBitString, not a bit string " 617 + tag); 618 } 619 return buffer.getBitString(); 620 } 621 622 /** 623 * Returns an ASN.1 BIT STRING value, with the tag assumed implicit 624 * based on the parameter. The bit string need not be byte-aligned. 625 * 626 * @params tagImplicit if true, the tag is assumed implicit. 627 * @return the bit string held in this value 628 */ 629 public BitArray getUnalignedBitString(boolean tagImplicit) 630 throws IOException { 631 if (!tagImplicit) { 632 if (tag != tag_BitString) 633 throw new IOException("DerValue.getBitString, not a bit string " 634 + tag); 635 } 636 return buffer.getUnalignedBitString(); 637 } 638 639 /** 640 * Helper routine to return all the bytes contained in the 641 * DerInputStream associated with this object. 642 */ 643 public byte[] getDataBytes() throws IOException { 644 byte[] retVal = new byte[length]; 645 synchronized (data) { 646 data.reset(); 647 data.getBytes(retVal); 648 } 649 return retVal; 650 } 651 652 /** 653 * Returns an ASN.1 STRING value 654 * 655 * @return the printable string held in this value 656 */ 657 public String getPrintableString() 658 throws IOException { 659 if (tag != tag_PrintableString) 660 throw new IOException( 661 "DerValue.getPrintableString, not a string " + tag); 662 663 return new String(getDataBytes(), "ASCII"); 664 } 665 666 /** 667 * Returns an ASN.1 T61 (Teletype) STRING value 668 * 669 * @return the teletype string held in this value 670 */ 671 public String getT61String() throws IOException { 672 if (tag != tag_T61String) 673 throw new IOException( 674 "DerValue.getT61String, not T61 " + tag); 675 676 return new String(getDataBytes(), "ISO-8859-1"); 677 } 678 679 /** 680 * Returns an ASN.1 IA5 (ASCII) STRING value 681 * 682 * @return the ASCII string held in this value 683 */ 684 public String getIA5String() throws IOException { 685 if (tag != tag_IA5String) 686 throw new IOException( 687 "DerValue.getIA5String, not IA5 " + tag); 688 689 return new String(getDataBytes(), "ASCII"); 690 } 691 692 /** 693 * Returns the ASN.1 BMP (Unicode) STRING value as a Java string. 694 * 695 * @return a string corresponding to the encoded BMPString held in 696 * this value 697 */ 698 public String getBMPString() throws IOException { 699 if (tag != tag_BMPString) 700 throw new IOException( 701 "DerValue.getBMPString, not BMP " + tag); 702 703 // BMPString is the same as Unicode in big endian, unmarked 704 // format. 705 return new String(getDataBytes(), "UnicodeBigUnmarked"); 706 } 707 708 /** 709 * Returns the ASN.1 UTF-8 STRING value as a Java String. 710 * 711 * @return a string corresponding to the encoded UTF8String held in 712 * this value 713 */ 714 public String getUTF8String() throws IOException { 715 if (tag != tag_UTF8String) 716 throw new IOException( 717 "DerValue.getUTF8String, not UTF-8 " + tag); 718 719 return new String(getDataBytes(), "UTF8"); 720 } 721 722 /** 723 * Returns the ASN.1 GENERAL STRING value as a Java String. 724 * 725 * @return a string corresponding to the encoded GeneralString held in 726 * this value 727 */ 728 public String getGeneralString() throws IOException { 729 if (tag != tag_GeneralString) 730 throw new IOException( 731 "DerValue.getGeneralString, not GeneralString " + tag); 732 733 return new String(getDataBytes(), "ASCII"); 734 } 735 736 /** 737 * Returns a Date if the DerValue is UtcTime. 738 * 739 * @return the Date held in this DER value 740 */ 741 public Date getUTCTime() throws IOException { 742 if (tag != tag_UtcTime) { 743 throw new IOException("DerValue.getUTCTime, not a UtcTime: " + tag); 744 } 745 return buffer.getUTCTime(data.available()); 746 } 747 748 /** 749 * Returns a Date if the DerValue is GeneralizedTime. 750 * 751 * @return the Date held in this DER value 752 */ 753 public Date getGeneralizedTime() throws IOException { 754 if (tag != tag_GeneralizedTime) { 755 throw new IOException( 756 "DerValue.getGeneralizedTime, not a GeneralizedTime: " + tag); 757 } 758 return buffer.getGeneralizedTime(data.available()); 759 } 760 761 /** 762 * Returns true iff the other object is a DER value which 763 * is bitwise equal to this one. 764 * 765 * @param other the object being compared with this one 766 */ 767 public boolean equals(Object other) { 768 if (other instanceof DerValue) 769 return equals((DerValue)other); 770 else 771 return false; 772 } 773 774 /** 775 * Bitwise equality comparison. DER encoded values have a single 776 * encoding, so that bitwise equality of the encoded values is an 777 * efficient way to establish equivalence of the unencoded values. 778 * 779 * @param other the object being compared with this one 780 */ 781 public boolean equals(DerValue other) { 782 if (this == other) { 783 return true; 784 } 785 if (tag != other.tag) { 786 return false; 787 } 788 if (data == other.data) { 789 return true; 790 } 791 792 // make sure the order of lock is always consistent to avoid a deadlock 793 return (System.identityHashCode(this.data) 794 > System.identityHashCode(other.data)) ? 795 doEquals(this, other): 796 doEquals(other, this); 797 } 798 799 /** 800 * Helper for public method equals() 801 */ 802 private static boolean doEquals(DerValue d1, DerValue d2) { 803 synchronized (d1.data) { 804 synchronized (d2.data) { 805 d1.data.reset(); 806 d2.data.reset(); 807 return d1.buffer.equals(d2.buffer); 808 } 809 } 810 } 811 812 /** 813 * Returns a printable representation of the value. 814 * 815 * @return printable representation of the value 816 */ 817 public String toString() { 818 try { 819 820 String str = getAsString(); 821 if (str != null) 822 return "\"" + str + "\""; 823 if (tag == tag_Null) 824 return "[DerValue, null]"; 825 if (tag == tag_ObjectId) 826 return "OID." + getOID(); 827 828 // integers 829 else 830 return "[DerValue, tag = " + tag 831 + ", length = " + length + "]"; 832 } catch (IOException e) { 833 throw new IllegalArgumentException("misformatted DER value"); 834 } 835 } 836 837 /** 838 * Returns the original encoded form or {@code null} if the form was not 839 * retained or is not available. 840 */ 841 public byte[] getOriginalEncodedForm() { 842 return (originalEncodedForm != null) 843 ? originalEncodedForm.clone() : null; 844 } 845 846 /** 847 * Returns a DER-encoded value, such that if it's passed to the 848 * DerValue constructor, a value equivalent to "this" is returned. 849 * 850 * @return DER-encoded value, including tag and length. 851 */ 852 public byte[] toByteArray() throws IOException { 853 DerOutputStream out = new DerOutputStream(); 854 855 encode(out); 856 data.reset(); 857 return out.toByteArray(); 858 } 859 860 /** 861 * For "set" and "sequence" types, this function may be used 862 * to return a DER stream of the members of the set or sequence. 863 * This operation is not supported for primitive types such as 864 * integers or bit strings. 865 */ 866 public DerInputStream toDerInputStream() throws IOException { 867 if (tag == tag_Sequence || tag == tag_Set) 868 return new DerInputStream(buffer); 869 throw new IOException("toDerInputStream rejects tag type " + tag); 870 } 871 872 /** 873 * Get the length of the encoded value. 874 */ 875 public int length() { 876 return length; 877 } 878 879 /** 880 * Determine if a character is one of the permissible characters for 881 * PrintableString: 882 * A-Z, a-z, 0-9, space, apostrophe (39), left and right parentheses, 883 * plus sign, comma, hyphen, period, slash, colon, equals sign, 884 * and question mark. 885 * 886 * Characters that are *not* allowed in PrintableString include 887 * exclamation point, quotation mark, number sign, dollar sign, 888 * percent sign, ampersand, asterisk, semicolon, less than sign, 889 * greater than sign, at sign, left and right square brackets, 890 * backslash, circumflex (94), underscore, back quote (96), 891 * left and right curly brackets, vertical line, tilde, 892 * and the control codes (0-31 and 127). 893 * 894 * This list is based on X.680 (the ASN.1 spec). 895 */ 896 public static boolean isPrintableStringChar(char ch) { 897 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || 898 (ch >= '0' && ch <= '9')) { 899 return true; 900 } else { 901 switch (ch) { 902 case ' ': /* space */ 903 case '\'': /* apostrophe */ 904 case '(': /* left paren */ 905 case ')': /* right paren */ 906 case '+': /* plus */ 907 case ',': /* comma */ 908 case '-': /* hyphen */ 909 case '.': /* period */ 910 case '/': /* slash */ 911 case ':': /* colon */ 912 case '=': /* equals */ 913 case '?': /* question mark */ 914 return true; 915 default: 916 return false; 917 } 918 } 919 } 920 921 /** 922 * Create the tag of the attribute. 923 * 924 * @params class the tag class type, one of UNIVERSAL, CONTEXT, 925 * APPLICATION or PRIVATE 926 * @params form if true, the value is constructed, otherwise it 927 * is primitive. 928 * @params val the tag value 929 */ 930 public static byte createTag(byte tagClass, boolean form, byte val) { 931 byte tag = (byte)(tagClass | val); 932 if (form) { 933 tag |= (byte)0x20; 934 } 935 return (tag); 936 } 937 938 /** 939 * Set the tag of the attribute. Commonly used to reset the 940 * tag value used for IMPLICIT encodings. 941 * 942 * @params tag the tag value 943 */ 944 public void resetTag(byte tag) { 945 this.tag = tag; 946 } 947 948 /** 949 * Returns a hashcode for this DerValue. 950 * 951 * @return a hashcode for this DerValue. 952 */ 953 public int hashCode() { 954 return toString().hashCode(); 955 } 956 } 957