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