1 /** 2 * Copyright (c) 1996, 2017, 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 // Creates a DerValue from a tag and some DER-encoded data w/ additional 229 // arg to control whether DER checks are enforced. 230 DerValue(byte tag, byte[] data, boolean allowBER) { 231 this.tag = tag; 232 buffer = new DerInputBuffer(data.clone(), allowBER); 233 length = data.length; 234 this.data = new DerInputStream(buffer); 235 this.data.mark(Integer.MAX_VALUE); 236 } 237 238 /** 239 * Creates a DerValue from a tag and some DER-encoded data. 240 * 241 * @param tag the DER type tag 242 * @param data the DER-encoded data 243 */ 244 public DerValue(byte tag, byte[] data) { 245 this(tag, data, true); 246 } 247 248 /* 249 * package private 250 */ 251 DerValue(DerInputBuffer in) throws IOException { 252 253 // XXX must also parse BER-encoded constructed 254 // values such as sequences, sets... 255 tag = (byte)in.read(); 256 byte lenByte = (byte)in.read(); 257 length = DerInputStream.getLength(lenByte, in); 258 if (length == -1) { // indefinite length encoding found 259 DerInputBuffer inbuf = in.dup(); 260 int readLen = inbuf.available(); 261 int offset = 2; // for tag and length bytes 262 byte[] indefData = new byte[readLen + offset]; 263 indefData[0] = tag; 264 indefData[1] = lenByte; 265 DataInputStream dis = new DataInputStream(inbuf); 266 dis.readFully(indefData, offset, readLen); 267 dis.close(); 268 DerIndefLenConverter derIn = new DerIndefLenConverter(); 269 inbuf = new DerInputBuffer(derIn.convert(indefData), in.allowBER); 270 if (tag != inbuf.read()) 271 throw new IOException 272 ("Indefinite length encoding not supported"); 273 length = DerInputStream.getDefiniteLength(inbuf); 274 buffer = inbuf.dup(); 275 buffer.truncate(length); 276 data = new DerInputStream(buffer); 277 // indefinite form is encoded by sending a length field with a 278 // length of 0. - i.e. [1000|0000]. 279 // the object is ended by sending two zero bytes. 280 in.skip(length + offset); 281 } else { 282 283 buffer = in.dup(); 284 buffer.truncate(length); 285 data = new DerInputStream(buffer); 286 287 in.skip(length); 288 } 289 } 290 291 // Get an ASN.1/DER encoded datum from a buffer w/ additional 292 // arg to control whether DER checks are enforced. 293 DerValue(byte[] buf, boolean allowBER) throws IOException { 294 data = init(true, new ByteArrayInputStream(buf), allowBER); 295 } 296 297 /** 298 * Get an ASN.1/DER encoded datum from a buffer. The 299 * entire buffer must hold exactly one datum, including 300 * its tag and length. 301 * 302 * @param buf buffer holding a single DER-encoded datum. 303 */ 304 public DerValue(byte[] buf) throws IOException { 305 this(buf, true); 306 } 307 308 // Get an ASN.1/DER encoded datum from part of a buffer w/ additional 309 // arg to control whether DER checks are enforced. 310 DerValue(byte[] buf, int offset, int len, boolean allowBER) 311 throws IOException { 312 data = init(true, new ByteArrayInputStream(buf, offset, len), allowBER); 313 } 314 315 /** 316 * Get an ASN.1/DER encoded datum from part of a buffer. 317 * That part of the buffer must hold exactly one datum, including 318 * its tag and length. 319 * 320 * @param buf the buffer 321 * @param offset start point of the single DER-encoded dataum 322 * @param len how many bytes are in the encoded datum 323 */ 324 public DerValue(byte[] buf, int offset, int len) throws IOException { 325 this(buf, offset, len, true); 326 } 327 328 // Get an ASN1/DER encoded datum from an input stream w/ additional 329 // arg to control whether DER checks are enforced. 330 DerValue(InputStream in, boolean allowBER) throws IOException { 331 data = init(false, in, allowBER); 332 } 333 334 /** 335 * Get an ASN1/DER encoded datum from an input stream. The 336 * stream may have additional data following the encoded datum. 337 * In case of indefinite length encoded datum, the input stream 338 * must hold only one datum. 339 * 340 * @param in the input stream holding a single DER datum, 341 * which may be followed by additional data 342 */ 343 public DerValue(InputStream in) throws IOException { 344 this(in, true); 345 } 346 347 private DerInputStream init(byte stringTag, String value) 348 throws IOException { 349 String enc = null; 350 351 tag = stringTag; 352 353 switch (stringTag) { 354 case tag_PrintableString: 355 case tag_IA5String: 356 case tag_GeneralString: 357 enc = "ASCII"; 358 break; 359 case tag_T61String: 360 enc = "ISO-8859-1"; 361 break; 362 case tag_BMPString: 363 enc = "UnicodeBigUnmarked"; 364 break; 365 case tag_UTF8String: 366 enc = "UTF8"; 367 break; 368 // TBD: Need encoder for UniversalString before it can 369 // be handled. 370 default: 371 throw new IllegalArgumentException("Unsupported DER string type"); 372 } 373 374 byte[] buf = value.getBytes(enc); 375 length = buf.length; 376 buffer = new DerInputBuffer(buf, true); 377 DerInputStream result = new DerInputStream(buffer); 378 result.mark(Integer.MAX_VALUE); 379 return result; 380 } 381 382 /* 383 * helper routine 384 */ 385 private DerInputStream init(boolean fullyBuffered, InputStream in, 386 boolean allowBER) throws IOException { 387 388 tag = (byte)in.read(); 389 byte lenByte = (byte)in.read(); 390 length = DerInputStream.getLength(lenByte, in); 391 if (length == -1) { // indefinite length encoding found 392 int readLen = in.available(); 393 int offset = 2; // for tag and length bytes 394 byte[] indefData = new byte[readLen + offset]; 395 indefData[0] = tag; 396 indefData[1] = lenByte; 397 DataInputStream dis = new DataInputStream(in); 398 dis.readFully(indefData, offset, readLen); 399 dis.close(); 400 DerIndefLenConverter derIn = new DerIndefLenConverter(); 401 in = new ByteArrayInputStream(derIn.convert(indefData)); 402 if (tag != in.read()) 403 throw new IOException 404 ("Indefinite length encoding not supported"); 405 length = DerInputStream.getDefiniteLength(in); 406 } 407 408 if (fullyBuffered && in.available() != length) 409 throw new IOException("extra data given to DerValue constructor"); 410 411 byte[] bytes = IOUtils.readFully(in, length, true); 412 413 buffer = new DerInputBuffer(bytes, allowBER); 414 return new DerInputStream(buffer); 415 } 416 417 /** 418 * Encode an ASN1/DER encoded datum onto a DER output stream. 419 */ 420 public void encode(DerOutputStream out) 421 throws IOException { 422 out.write(tag); 423 out.putLength(length); 424 // XXX yeech, excess copies ... DerInputBuffer.write(OutStream) 425 if (length > 0) { 426 byte[] value = new byte[length]; 427 // always synchronized on data 428 synchronized (data) { 429 buffer.reset(); 430 if (buffer.read(value) != length) { 431 throw new IOException("short DER value read (encode)"); 432 } 433 out.write(value); 434 } 435 } 436 } 437 438 public final DerInputStream getData() { 439 return data; 440 } 441 442 public final byte getTag() { 443 return tag; 444 } 445 446 /** 447 * Returns an ASN.1 BOOLEAN 448 * 449 * @return the boolean held in this DER value 450 */ 451 public boolean getBoolean() throws IOException { 452 if (tag != tag_Boolean) { 453 throw new IOException("DerValue.getBoolean, not a BOOLEAN " + tag); 454 } 455 if (length != 1) { 456 throw new IOException("DerValue.getBoolean, invalid length " 457 + length); 458 } 459 if (buffer.read() != 0) { 460 return true; 461 } 462 return false; 463 } 464 465 /** 466 * Returns an ASN.1 OBJECT IDENTIFIER. 467 * 468 * @return the OID held in this DER value 469 */ 470 public ObjectIdentifier getOID() throws IOException { 471 if (tag != tag_ObjectId) 472 throw new IOException("DerValue.getOID, not an OID " + tag); 473 return new ObjectIdentifier(buffer); 474 } 475 476 private byte[] append(byte[] a, byte[] b) { 477 if (a == null) 478 return b; 479 480 byte[] ret = new byte[a.length + b.length]; 481 System.arraycopy(a, 0, ret, 0, a.length); 482 System.arraycopy(b, 0, ret, a.length, b.length); 483 484 return ret; 485 } 486 487 /** 488 * Returns an ASN.1 OCTET STRING 489 * 490 * @return the octet string held in this DER value 491 */ 492 public byte[] getOctetString() throws IOException { 493 byte[] bytes; 494 495 if (tag != tag_OctetString && !isConstructed(tag_OctetString)) { 496 throw new IOException( 497 "DerValue.getOctetString, not an Octet String: " + tag); 498 } 499 bytes = new byte[length]; 500 // Note: do not tempt to call buffer.read(bytes) at all. There's a 501 // known bug that it returns -1 instead of 0. 502 if (length == 0) { 503 return bytes; 504 } 505 if (buffer.read(bytes) != length) 506 throw new IOException("short read on DerValue buffer"); 507 if (isConstructed()) { 508 DerInputStream in = new DerInputStream(bytes, 0, bytes.length, 509 buffer.allowBER); 510 bytes = null; 511 while (in.available() != 0) { 512 bytes = append(bytes, in.getOctetString()); 513 } 514 } 515 return bytes; 516 } 517 518 /** 519 * Returns an ASN.1 INTEGER value as an integer. 520 * 521 * @return the integer held in this DER value. 522 */ 523 public int getInteger() throws IOException { 524 if (tag != tag_Integer) { 525 throw new IOException("DerValue.getInteger, not an int " + tag); 526 } 527 return buffer.getInteger(data.available()); 528 } 529 530 /** 531 * Returns an ASN.1 INTEGER value as a BigInteger. 532 * 533 * @return the integer held in this DER value as a BigInteger. 534 */ 535 public BigInteger getBigInteger() throws IOException { 536 if (tag != tag_Integer) 537 throw new IOException("DerValue.getBigInteger, not an int " + tag); 538 return buffer.getBigInteger(data.available(), false); 539 } 540 541 /** 542 * Returns an ASN.1 INTEGER value as a positive BigInteger. 543 * This is just to deal with implementations that incorrectly encode 544 * some values as negative. 545 * 546 * @return the integer held in this DER value as a BigInteger. 547 */ 548 public BigInteger getPositiveBigInteger() throws IOException { 549 if (tag != tag_Integer) 550 throw new IOException("DerValue.getBigInteger, not an int " + tag); 551 return buffer.getBigInteger(data.available(), true); 552 } 553 554 /** 555 * Returns an ASN.1 ENUMERATED value. 556 * 557 * @return the integer held in this DER value. 558 */ 559 public int getEnumerated() throws IOException { 560 if (tag != tag_Enumerated) { 561 throw new IOException("DerValue.getEnumerated, incorrect tag: " 562 + tag); 563 } 564 return buffer.getInteger(data.available()); 565 } 566 567 /** 568 * Returns an ASN.1 BIT STRING value. The bit string must be byte-aligned. 569 * 570 * @return the bit string held in this value 571 */ 572 public byte[] getBitString() throws IOException { 573 if (tag != tag_BitString) 574 throw new IOException( 575 "DerValue.getBitString, not a bit string " + tag); 576 577 return buffer.getBitString(); 578 } 579 580 /** 581 * Returns an ASN.1 BIT STRING value that need not be byte-aligned. 582 * 583 * @return a BitArray representing the bit string held in this value 584 */ 585 public BitArray getUnalignedBitString() throws IOException { 586 if (tag != tag_BitString) 587 throw new IOException( 588 "DerValue.getBitString, not a bit string " + tag); 589 590 return buffer.getUnalignedBitString(); 591 } 592 593 /** 594 * Returns the name component as a Java string, regardless of its 595 * encoding restrictions (ASCII, T61, Printable, IA5, BMP, UTF8). 596 */ 597 // TBD: Need encoder for UniversalString before it can be handled. 598 public String getAsString() throws IOException { 599 if (tag == tag_UTF8String) 600 return getUTF8String(); 601 else if (tag == tag_PrintableString) 602 return getPrintableString(); 603 else if (tag == tag_T61String) 604 return getT61String(); 605 else if (tag == tag_IA5String) 606 return getIA5String(); 607 /* 608 else if (tag == tag_UniversalString) 609 return getUniversalString(); 610 */ 611 else if (tag == tag_BMPString) 612 return getBMPString(); 613 else if (tag == tag_GeneralString) 614 return getGeneralString(); 615 else 616 return null; 617 } 618 619 /** 620 * Returns an ASN.1 BIT STRING value, with the tag assumed implicit 621 * based on the parameter. The bit string must be byte-aligned. 622 * 623 * @param tagImplicit if true, the tag is assumed implicit. 624 * @return the bit string held in this value 625 */ 626 public byte[] getBitString(boolean tagImplicit) throws IOException { 627 if (!tagImplicit) { 628 if (tag != tag_BitString) 629 throw new IOException("DerValue.getBitString, not a bit string " 630 + tag); 631 } 632 return buffer.getBitString(); 633 } 634 635 /** 636 * Returns an ASN.1 BIT STRING value, with the tag assumed implicit 637 * based on the parameter. The bit string need not be byte-aligned. 638 * 639 * @param tagImplicit if true, the tag is assumed implicit. 640 * @return the bit string held in this value 641 */ 642 public BitArray getUnalignedBitString(boolean tagImplicit) 643 throws IOException { 644 if (!tagImplicit) { 645 if (tag != tag_BitString) 646 throw new IOException("DerValue.getBitString, not a bit string " 647 + tag); 648 } 649 return buffer.getUnalignedBitString(); 650 } 651 652 /** 653 * Helper routine to return all the bytes contained in the 654 * DerInputStream associated with this object. 655 */ 656 public byte[] getDataBytes() throws IOException { 657 byte[] retVal = new byte[length]; 658 synchronized (data) { 659 data.reset(); 660 data.getBytes(retVal); 661 } 662 return retVal; 663 } 664 665 /** 666 * Returns an ASN.1 STRING value 667 * 668 * @return the printable string held in this value 669 */ 670 public String getPrintableString() 671 throws IOException { 672 if (tag != tag_PrintableString) 673 throw new IOException( 674 "DerValue.getPrintableString, not a string " + tag); 675 676 return new String(getDataBytes(), "ASCII"); 677 } 678 679 /** 680 * Returns an ASN.1 T61 (Teletype) STRING value 681 * 682 * @return the teletype string held in this value 683 */ 684 public String getT61String() throws IOException { 685 if (tag != tag_T61String) 686 throw new IOException( 687 "DerValue.getT61String, not T61 " + tag); 688 689 return new String(getDataBytes(), "ISO-8859-1"); 690 } 691 692 /** 693 * Returns an ASN.1 IA5 (ASCII) STRING value 694 * 695 * @return the ASCII string held in this value 696 */ 697 public String getIA5String() throws IOException { 698 if (tag != tag_IA5String) 699 throw new IOException( 700 "DerValue.getIA5String, not IA5 " + tag); 701 702 return new String(getDataBytes(), "ASCII"); 703 } 704 705 /** 706 * Returns the ASN.1 BMP (Unicode) STRING value as a Java string. 707 * 708 * @return a string corresponding to the encoded BMPString held in 709 * this value 710 */ 711 public String getBMPString() throws IOException { 712 if (tag != tag_BMPString) 713 throw new IOException( 714 "DerValue.getBMPString, not BMP " + tag); 715 716 // BMPString is the same as Unicode in big endian, unmarked 717 // format. 718 return new String(getDataBytes(), "UnicodeBigUnmarked"); 719 } 720 721 /** 722 * Returns the ASN.1 UTF-8 STRING value as a Java String. 723 * 724 * @return a string corresponding to the encoded UTF8String held in 725 * this value 726 */ 727 public String getUTF8String() throws IOException { 728 if (tag != tag_UTF8String) 729 throw new IOException( 730 "DerValue.getUTF8String, not UTF-8 " + tag); 731 732 return new String(getDataBytes(), "UTF8"); 733 } 734 735 /** 736 * Returns the ASN.1 GENERAL STRING value as a Java String. 737 * 738 * @return a string corresponding to the encoded GeneralString held in 739 * this value 740 */ 741 public String getGeneralString() throws IOException { 742 if (tag != tag_GeneralString) 743 throw new IOException( 744 "DerValue.getGeneralString, not GeneralString " + tag); 745 746 return new String(getDataBytes(), "ASCII"); 747 } 748 749 /** 750 * Returns a Date if the DerValue is UtcTime. 751 * 752 * @return the Date held in this DER value 753 */ 754 public Date getUTCTime() throws IOException { 755 if (tag != tag_UtcTime) { 756 throw new IOException("DerValue.getUTCTime, not a UtcTime: " + tag); 757 } 758 return buffer.getUTCTime(data.available()); 759 } 760 761 /** 762 * Returns a Date if the DerValue is GeneralizedTime. 763 * 764 * @return the Date held in this DER value 765 */ 766 public Date getGeneralizedTime() throws IOException { 767 if (tag != tag_GeneralizedTime) { 768 throw new IOException( 769 "DerValue.getGeneralizedTime, not a GeneralizedTime: " + tag); 770 } 771 return buffer.getGeneralizedTime(data.available()); 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 o the object being compared with this one 780 */ 781 @Override 782 public boolean equals(Object o) { 783 if (this == o) { 784 return true; 785 } 786 if (!(o instanceof DerValue)) { 787 return false; 788 } 789 DerValue other = (DerValue) o; 790 if (tag != other.tag) { 791 return false; 792 } 793 if (data == other.data) { 794 return true; 795 } 796 797 // make sure the order of lock is always consistent to avoid a deadlock 798 return (System.identityHashCode(this.data) 799 > System.identityHashCode(other.data)) ? 800 doEquals(this, other): 801 doEquals(other, this); 802 } 803 804 /** 805 * Helper for public method equals() 806 */ 807 private static boolean doEquals(DerValue d1, DerValue d2) { 808 synchronized (d1.data) { 809 synchronized (d2.data) { 810 d1.data.reset(); 811 d2.data.reset(); 812 return d1.buffer.equals(d2.buffer); 813 } 814 } 815 } 816 817 /** 818 * Returns a printable representation of the value. 819 * 820 * @return printable representation of the value 821 */ 822 @Override 823 public String toString() { 824 try { 825 826 String str = getAsString(); 827 if (str != null) 828 return "\"" + str + "\""; 829 if (tag == tag_Null) 830 return "[DerValue, null]"; 831 if (tag == tag_ObjectId) 832 return "OID." + getOID(); 833 834 // integers 835 else 836 return "[DerValue, tag = " + tag 837 + ", length = " + length + "]"; 838 } catch (IOException e) { 839 throw new IllegalArgumentException("misformatted DER value"); 840 } 841 } 842 843 /** 844 * Returns a DER-encoded value, such that if it's passed to the 845 * DerValue constructor, a value equivalent to "this" is returned. 846 * 847 * @return DER-encoded value, including tag and length. 848 */ 849 public byte[] toByteArray() throws IOException { 850 DerOutputStream out = new DerOutputStream(); 851 852 encode(out); 853 data.reset(); 854 return out.toByteArray(); 855 } 856 857 /** 858 * For "set" and "sequence" types, this function may be used 859 * to return a DER stream of the members of the set or sequence. 860 * This operation is not supported for primitive types such as 861 * integers or bit strings. 862 */ 863 public DerInputStream toDerInputStream() throws IOException { 864 if (tag == tag_Sequence || tag == tag_Set) 865 return new DerInputStream(buffer); 866 throw new IOException("toDerInputStream rejects tag type " + tag); 867 } 868 869 /** 870 * Get the length of the encoded value. 871 */ 872 public int length() { 873 return length; 874 } 875 876 /** 877 * Determine if a character is one of the permissible characters for 878 * PrintableString: 879 * A-Z, a-z, 0-9, space, apostrophe (39), left and right parentheses, 880 * plus sign, comma, hyphen, period, slash, colon, equals sign, 881 * and question mark. 882 * 883 * Characters that are *not* allowed in PrintableString include 884 * exclamation point, quotation mark, number sign, dollar sign, 885 * percent sign, ampersand, asterisk, semicolon, less than sign, 886 * greater than sign, at sign, left and right square brackets, 887 * backslash, circumflex (94), underscore, back quote (96), 888 * left and right curly brackets, vertical line, tilde, 889 * and the control codes (0-31 and 127). 890 * 891 * This list is based on X.680 (the ASN.1 spec). 892 */ 893 public static boolean isPrintableStringChar(char ch) { 894 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || 895 (ch >= '0' && ch <= '9')) { 896 return true; 897 } else { 898 switch (ch) { 899 case ' ': /* space */ 900 case '\'': /* apostrophe */ 901 case '(': /* left paren */ 902 case ')': /* right paren */ 903 case '+': /* plus */ 904 case ',': /* comma */ 905 case '-': /* hyphen */ 906 case '.': /* period */ 907 case '/': /* slash */ 908 case ':': /* colon */ 909 case '=': /* equals */ 910 case '?': /* question mark */ 911 return true; 912 default: 913 return false; 914 } 915 } 916 } 917 918 /** 919 * Create the tag of the attribute. 920 * 921 * @param tagClass the tag class type, one of UNIVERSAL, CONTEXT, 922 * APPLICATION or PRIVATE 923 * @param form if true, the value is constructed, otherwise it 924 * is primitive. 925 * @param val the tag value 926 */ 927 public static byte createTag(byte tagClass, boolean form, byte val) { 928 byte tag = (byte)(tagClass | val); 929 if (form) { 930 tag |= (byte)0x20; 931 } 932 return (tag); 933 } 934 935 /** 936 * Set the tag of the attribute. Commonly used to reset the 937 * tag value used for IMPLICIT encodings. 938 * 939 * @param tag the tag value 940 */ 941 public void resetTag(byte tag) { 942 this.tag = tag; 943 } 944 945 /** 946 * Returns a hashcode for this DerValue. 947 * 948 * @return a hashcode for this DerValue. 949 */ 950 @Override 951 public int hashCode() { 952 return toString().hashCode(); 953 } 954 }