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