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