1 /* 2 * Copyright (c) 1996, 2021, 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 sun.nio.cs.UTF_32BE; 29 import sun.util.calendar.CalendarDate; 30 import sun.util.calendar.CalendarSystem; 31 32 import java.io.*; 33 import java.math.BigInteger; 34 import java.nio.charset.Charset; 35 import java.util.*; 36 37 import static java.nio.charset.StandardCharsets.*; 38 39 /** 40 * Represents a single DER-encoded value. DER encoding rules are a subset 41 * of the "Basic" Encoding Rules (BER), but they only support a single way 42 * ("Definite" encoding) to encode any given value. 43 * 44 * <P>All DER-encoded data are triples <em>{type, length, data}</em>. This 45 * class represents such tagged values as they have been read (or constructed), 46 * and provides structured access to the encoded data. 47 * 48 * <P>At this time, this class supports only a subset of the types of DER 49 * data encodings which are defined. That subset is sufficient for parsing 50 * most X.509 certificates, and working with selected additional formats 51 * (such as PKCS #10 certificate requests, and some kinds of PKCS #7 data). 52 * 53 * A note with respect to T61/Teletex strings: From RFC 1617, section 4.1.3 54 * and RFC 5280, section 8, we assume that this kind of string will contain 55 * ISO-8859-1 characters only. 56 * 57 * 58 * @author David Brownell 59 * @author Amit Kapoor 60 * @author Hemma Prafullchandra 61 */ 62 public class DerValue { 63 64 /** The tag class types */ 65 public static final byte TAG_UNIVERSAL = (byte)0x000; 66 public static final byte TAG_APPLICATION = (byte)0x040; 67 public static final byte TAG_CONTEXT = (byte)0x080; 68 public static final byte TAG_PRIVATE = (byte)0x0c0; 69 70 /* 71 * The type starts at the first byte of the encoding, and 72 * is one of these tag_* values. That may be all the type 73 * data that is needed. 74 */ 75 76 /* 77 * These tags are the "universal" tags ... they mean the same 78 * in all contexts. (Mask with 0x1f -- five bits.) 79 */ 80 81 /** Tag value indicating an ASN.1 "BOOLEAN" value. */ 82 public static final byte tag_Boolean = 0x01; 83 84 /** Tag value indicating an ASN.1 "INTEGER" value. */ 85 public static final byte tag_Integer = 0x02; 86 87 /** Tag value indicating an ASN.1 "BIT STRING" value. */ 88 public static final byte tag_BitString = 0x03; 89 90 /** Tag value indicating an ASN.1 "OCTET STRING" value. */ 91 public static final byte tag_OctetString = 0x04; 92 93 /** Tag value indicating an ASN.1 "NULL" value. */ 94 public static final byte tag_Null = 0x05; 95 96 /** Tag value indicating an ASN.1 "OBJECT IDENTIFIER" value. */ 97 public static final byte tag_ObjectId = 0x06; 98 99 /** Tag value including an ASN.1 "ENUMERATED" value */ 100 public static final byte tag_Enumerated = 0x0A; 101 102 /** Tag value indicating an ASN.1 "UTF8String" value. */ 103 public static final byte tag_UTF8String = 0x0C; 104 105 /** Tag value including a "printable" string */ 106 public static final byte tag_PrintableString = 0x13; 107 108 /** Tag value including a "teletype" string */ 109 public static final byte tag_T61String = 0x14; 110 111 /** Tag value including an ASCII string */ 112 public static final byte tag_IA5String = 0x16; 113 114 /** Tag value indicating an ASN.1 "UTCTime" value. */ 115 public static final byte tag_UtcTime = 0x17; 116 117 /** Tag value indicating an ASN.1 "GeneralizedTime" value. */ 118 public static final byte tag_GeneralizedTime = 0x18; 119 120 /** Tag value indicating an ASN.1 "GenerallString" value. */ 121 public static final byte tag_GeneralString = 0x1B; 122 123 /** Tag value indicating an ASN.1 "UniversalString" value. */ 124 public static final byte tag_UniversalString = 0x1C; 125 126 /** Tag value indicating an ASN.1 "BMPString" value. */ 127 public static final byte tag_BMPString = 0x1E; 128 129 // CONSTRUCTED seq/set 130 131 /** 132 * Tag value indicating an ASN.1 133 * "SEQUENCE" (zero to N elements, order is significant). 134 */ 135 public static final byte tag_Sequence = 0x30; 136 137 /** 138 * Tag value indicating an ASN.1 139 * "SEQUENCE OF" (one to N elements, order is significant). 140 */ 141 public static final byte tag_SequenceOf = 0x30; 142 143 /** 144 * Tag value indicating an ASN.1 145 * "SET" (zero to N members, order does not matter). 146 */ 147 public static final byte tag_Set = 0x31; 148 149 /** 150 * Tag value indicating an ASN.1 151 * "SET OF" (one to N members, order does not matter). 152 */ 153 public static final byte tag_SetOf = 0x31; 154 155 // This class is mostly immutable except that: 156 // 157 // 1. resetTag() modifies the tag 158 // 2. the data field is mutable 159 // 160 // For compatibility, data, getData() and resetTag() are preserved. 161 // A modern caller should call withTag() or data() instead. 162 // 163 // Also, some constructors have not cloned buffer, so the data could 164 // be modified externally. 165 166 public /*final*/ byte tag; 167 final byte[] buffer; 168 private final int start; 169 final int end; 170 private final boolean allowBER; 171 172 // Unsafe. Legacy. Never null. 173 public final DerInputStream data; 174 175 /* 176 * These values are the high order bits for the other kinds of tags. 177 */ 178 179 /** 180 * Returns true if the tag class is UNIVERSAL. 181 */ isUniversal()182 public boolean isUniversal() { return ((tag & 0x0c0) == 0x000); } 183 184 /** 185 * Returns true if the tag class is APPLICATION. 186 */ isApplication()187 public boolean isApplication() { return ((tag & 0x0c0) == 0x040); } 188 189 /** 190 * Returns true iff the CONTEXT SPECIFIC bit is set in the type tag. 191 * This is associated with the ASN.1 "DEFINED BY" syntax. 192 */ isContextSpecific()193 public boolean isContextSpecific() { return ((tag & 0x0c0) == 0x080); } 194 195 /** 196 * Returns true iff the CONTEXT SPECIFIC TAG matches the passed tag. 197 */ isContextSpecific(byte cntxtTag)198 public boolean isContextSpecific(byte cntxtTag) { 199 if (!isContextSpecific()) { 200 return false; 201 } 202 return ((tag & 0x01f) == cntxtTag); 203 } 204 isPrivate()205 boolean isPrivate() { return ((tag & 0x0c0) == 0x0c0); } 206 207 /** Returns true iff the CONSTRUCTED bit is set in the type tag. */ isConstructed()208 public boolean isConstructed() { return ((tag & 0x020) == 0x020); } 209 210 /** 211 * Returns true iff the CONSTRUCTED TAG matches the passed tag. 212 */ isConstructed(byte constructedTag)213 public boolean isConstructed(byte constructedTag) { 214 if (!isConstructed()) { 215 return false; 216 } 217 return ((tag & 0x01f) == constructedTag); 218 } 219 220 /** 221 * Creates a new DerValue by specifying all its fields. 222 */ DerValue(byte tag, byte[] buffer, int start, int end, boolean allowBER)223 DerValue(byte tag, byte[] buffer, int start, int end, boolean allowBER) { 224 if ((tag & 0x1f) == 0x1f) { 225 throw new IllegalArgumentException("Tag number over 30 is not supported"); 226 } 227 this.tag = tag; 228 this.buffer = buffer; 229 this.start = start; 230 this.end = end; 231 this.allowBER = allowBER; 232 this.data = data(); 233 } 234 235 /** 236 * Creates a PrintableString or UTF8string DER value from a string. 237 */ DerValue(String value)238 public DerValue(String value) { 239 this(isPrintableString(value) ? tag_PrintableString : tag_UTF8String, 240 value); 241 } 242 isPrintableString(String value)243 private static boolean isPrintableString(String value) { 244 for (int i = 0; i < value.length(); i++) { 245 if (!isPrintableStringChar(value.charAt(i))) { 246 return false; 247 } 248 } 249 return true; 250 } 251 252 /** 253 * Creates a string type DER value from a String object 254 * @param stringTag the tag for the DER value to create 255 * @param value the String object to use for the DER value 256 */ DerValue(byte stringTag, String value)257 public DerValue(byte stringTag, String value) { 258 this(stringTag, string2bytes(stringTag, value), false); 259 } 260 string2bytes(byte stringTag, String value)261 private static byte[] string2bytes(byte stringTag, String value) { 262 Charset charset = switch (stringTag) { 263 case tag_PrintableString, tag_IA5String, tag_GeneralString -> US_ASCII; 264 case tag_T61String -> ISO_8859_1; 265 case tag_BMPString -> UTF_16BE; 266 case tag_UTF8String -> UTF_8; 267 case tag_UniversalString -> Charset.forName("UTF_32BE"); 268 default -> throw new IllegalArgumentException("Unsupported DER string type"); 269 }; 270 return value.getBytes(charset); 271 } 272 DerValue(byte tag, byte[] buffer, boolean allowBER)273 DerValue(byte tag, byte[] buffer, boolean allowBER) { 274 this(tag, buffer, 0, buffer.length, allowBER); 275 } 276 277 /** 278 * Creates a DerValue from a tag and some DER-encoded data. 279 * 280 * This is a public constructor. 281 * 282 * @param tag the DER type tag 283 * @param buffer the DER-encoded data 284 */ DerValue(byte tag, byte[] buffer)285 public DerValue(byte tag, byte[] buffer) { 286 this(tag, buffer.clone(), true); 287 } 288 289 /** 290 * Wraps an DerOutputStream. All bytes currently written 291 * into the stream will become the content of the newly 292 * created DerValue. 293 * 294 * Attention: do not reset the DerOutputStream after this call. 295 * No array copying is made. 296 * 297 * @param tag the tag 298 * @param out the DerOutputStream 299 * @returns a new DerValue using out as its content 300 */ wrap(byte tag, DerOutputStream out)301 public static DerValue wrap(byte tag, DerOutputStream out) { 302 return new DerValue(tag, out.buf(), 0, out.size(), false); 303 } 304 305 /** 306 * Parse an ASN.1/BER encoded datum. The entire encoding must hold exactly 307 * one datum, including its tag and length. 308 * 309 * This is a public constructor. 310 */ DerValue(byte[] encoding)311 public DerValue(byte[] encoding) throws IOException { 312 this(encoding.clone(), 0, encoding.length, true, false); 313 } 314 315 /** 316 * Parse an ASN.1 encoded datum from a byte array. 317 * 318 * @param buf the byte array containing the DER-encoded datum 319 * @param offset where the encoded datum starts inside {@code buf} 320 * @param len length of bytes to parse inside {@code buf} 321 * @param allowBER whether BER is allowed 322 * @param allowMore whether extra bytes are allowed after the encoded datum. 323 * If true, {@code len} can be bigger than the length of 324 * the encoded datum. 325 * 326 * @throws IOException if it's an invalid encoding or there are extra bytes 327 * after the encoded datum and {@code allowMore} is false. 328 */ DerValue(byte[] buf, int offset, int len, boolean allowBER, boolean allowMore)329 DerValue(byte[] buf, int offset, int len, boolean allowBER, boolean allowMore) 330 throws IOException { 331 332 if (len < 2) { 333 throw new IOException("Too short"); 334 } 335 int pos = offset; 336 tag = buf[pos++]; 337 if ((tag & 0x1f) == 0x1f) { 338 throw new IOException("Tag number over 30 at " + offset + " is not supported"); 339 } 340 int lenByte = buf[pos++]; 341 342 int length; 343 if (lenByte == (byte) 0x80) { // indefinite length 344 if (!allowBER) { 345 throw new IOException("Indefinite length encoding " + 346 "not supported with DER"); 347 } 348 if (!isConstructed()) { 349 throw new IOException("Indefinite length encoding " + 350 "not supported with non-constructed data"); 351 } 352 353 // Reconstruct data source 354 buf = DerIndefLenConverter.convertStream( 355 new ByteArrayInputStream(buf, pos, len - (pos - offset)), tag); 356 offset = 0; 357 len = buf.length; 358 pos = 2; 359 360 if (tag != buf[0]) { 361 throw new IOException("Indefinite length encoding not supported"); 362 } 363 lenByte = buf[1]; 364 if (lenByte == (byte) 0x80) { 365 throw new IOException("Indefinite len conversion failed"); 366 } 367 } 368 369 if ((lenByte & 0x080) == 0x00) { // short form, 1 byte datum 370 length = lenByte; 371 } else { // long form 372 lenByte &= 0x07f; 373 if (lenByte > 4) { 374 throw new IOException("Invalid lenByte"); 375 } 376 if (len < 2 + lenByte) { 377 throw new IOException("Not enough length bytes"); 378 } 379 length = 0x0ff & buf[pos++]; 380 lenByte--; 381 if (length == 0 && !allowBER) { 382 // DER requires length value be encoded in minimum number of bytes 383 throw new IOException("Redundant length bytes found"); 384 } 385 while (lenByte-- > 0) { 386 length <<= 8; 387 length += 0x0ff & buf[pos++]; 388 } 389 if (length < 0) { 390 throw new IOException("Invalid length bytes"); 391 } else if (length <= 127 && !allowBER) { 392 throw new IOException("Should use short form for length"); 393 } 394 } 395 // pos is now at the beginning of the content 396 if (len - length < pos - offset) { 397 throw new EOFException("not enough content"); 398 } 399 if (len - length > pos - offset && !allowMore) { 400 throw new IOException("extra data at the end"); 401 } 402 this.buffer = buf; 403 this.start = pos; 404 this.end = pos + length; 405 this.allowBER = allowBER; 406 this.data = data(); 407 } 408 409 // Get an ASN1/DER encoded datum from an input stream w/ additional 410 // arg to control whether DER checks are enforced. DerValue(InputStream in, boolean allowBER)411 DerValue(InputStream in, boolean allowBER) throws IOException { 412 this.tag = (byte)in.read(); 413 if ((tag & 0x1f) == 0x1f) { 414 throw new IOException("Tag number over 30 is not supported"); 415 } 416 int length = DerInputStream.getLength(in); 417 if (length == -1) { // indefinite length encoding found 418 if (!allowBER) { 419 throw new IOException("Indefinite length encoding " + 420 "not supported with DER"); 421 } 422 if (!isConstructed()) { 423 throw new IOException("Indefinite length encoding " + 424 "not supported with non-constructed data"); 425 } 426 this.buffer = DerIndefLenConverter.convertStream(in, tag); 427 ByteArrayInputStream bin = new ByteArrayInputStream(this.buffer); 428 if (tag != bin.read()) { 429 throw new IOException 430 ("Indefinite length encoding not supported"); 431 } 432 length = DerInputStream.getDefiniteLength(bin); 433 this.start = this.buffer.length - bin.available(); 434 this.end = this.start + length; 435 // position of in is undetermined. Precisely, it might be n-bytes 436 // after DerValue, and these n bytes are at the end of this.buffer 437 // after this.end. 438 } else { 439 this.buffer = IOUtils.readExactlyNBytes(in, length); 440 this.start = 0; 441 this.end = length; 442 // position of in is right after the DerValue 443 } 444 this.allowBER = allowBER; 445 this.data = data(); 446 } 447 448 /** 449 * Get an ASN1/DER encoded datum from an input stream. The 450 * stream may have additional data following the encoded datum. 451 * In case of indefinite length encoded datum, the input stream 452 * must hold only one datum, i.e. all bytes in the stream might 453 * be consumed. Otherwise, only one DerValue will be consumed. 454 * 455 * @param in the input stream holding a single DER datum, 456 * which may be followed by additional data 457 */ DerValue(InputStream in)458 public DerValue(InputStream in) throws IOException { 459 this(in, true); 460 } 461 462 /** 463 * Encode an ASN1/DER encoded datum onto a DER output stream. 464 */ encode(DerOutputStream out)465 public void encode(DerOutputStream out) throws IOException { 466 out.write(tag); 467 out.putLength(end - start); 468 out.write(buffer, start, end - start); 469 data.pos = data.end; // Compatibility. Reach end. 470 } 471 472 /** 473 * Returns a new DerInputStream pointing at the start of this 474 * DerValue's content. 475 * 476 * @return the new DerInputStream value 477 */ data()478 public final DerInputStream data() { 479 return new DerInputStream(buffer, start, end - start, allowBER); 480 } 481 482 /** 483 * Returns the data field inside this class directly. 484 * 485 * Both this method and the {@link #data} field should be avoided. 486 * Consider using {@link #data()} instead. 487 */ getData()488 public final DerInputStream getData() { 489 return data; 490 } 491 getTag()492 public final byte getTag() { 493 return tag; 494 } 495 496 /** 497 * Returns an ASN.1 BOOLEAN 498 * 499 * @return the boolean held in this DER value 500 */ getBoolean()501 public boolean getBoolean() throws IOException { 502 if (tag != tag_Boolean) { 503 throw new IOException("DerValue.getBoolean, not a BOOLEAN " + tag); 504 } 505 if (end - start != 1) { 506 throw new IOException("DerValue.getBoolean, invalid length " 507 + (end - start)); 508 } 509 data.pos = data.end; // Compatibility. Reach end. 510 return buffer[start] != 0; 511 } 512 513 /** 514 * Returns an ASN.1 OBJECT IDENTIFIER. 515 * 516 * @return the OID held in this DER value 517 */ getOID()518 public ObjectIdentifier getOID() throws IOException { 519 if (tag != tag_ObjectId) { 520 throw new IOException("DerValue.getOID, not an OID " + tag); 521 } 522 data.pos = data.end; // Compatibility. Reach end. 523 return new ObjectIdentifier(Arrays.copyOfRange(buffer, start, end)); 524 } 525 526 /** 527 * Returns an ASN.1 OCTET STRING 528 * 529 * @return the octet string held in this DER value 530 */ getOctetString()531 public byte[] getOctetString() throws IOException { 532 533 if (tag != tag_OctetString && !isConstructed(tag_OctetString)) { 534 throw new IOException( 535 "DerValue.getOctetString, not an Octet String: " + tag); 536 } 537 // Note: do not attempt to call buffer.read(bytes) at all. There's a 538 // known bug that it returns -1 instead of 0. 539 if (end - start == 0) { 540 return new byte[0]; 541 } 542 543 data.pos = data.end; // Compatibility. Reach end. 544 if (!isConstructed()) { 545 return Arrays.copyOfRange(buffer, start, end); 546 } else { 547 ByteArrayOutputStream bout = new ByteArrayOutputStream(); 548 DerInputStream dis = data(); 549 while (dis.available() > 0) { 550 bout.write(dis.getDerValue().getOctetString()); 551 } 552 return bout.toByteArray(); 553 } 554 } 555 556 /** 557 * Returns an ASN.1 INTEGER value as an integer. 558 * 559 * @return the integer held in this DER value. 560 */ getInteger()561 public int getInteger() throws IOException { 562 return getIntegerInternal(tag_Integer); 563 } 564 getIntegerInternal(byte expectedTag)565 private int getIntegerInternal(byte expectedTag) throws IOException { 566 BigInteger result = getBigIntegerInternal(expectedTag, false); 567 if (result.compareTo(BigInteger.valueOf(Integer.MIN_VALUE)) < 0) { 568 throw new IOException("Integer below minimum valid value"); 569 } 570 if (result.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) > 0) { 571 throw new IOException("Integer exceeds maximum valid value"); 572 } 573 return result.intValue(); 574 } 575 576 /** 577 * Returns an ASN.1 INTEGER value as a BigInteger. 578 * 579 * @return the integer held in this DER value as a BigInteger. 580 */ getBigInteger()581 public BigInteger getBigInteger() throws IOException { 582 return getBigIntegerInternal(tag_Integer, false); 583 } 584 585 /** 586 * Returns an ASN.1 INTEGER value as a positive BigInteger. 587 * This is just to deal with implementations that incorrectly encode 588 * some values as negative. 589 * 590 * @return the integer held in this DER value as a BigInteger. 591 */ getPositiveBigInteger()592 public BigInteger getPositiveBigInteger() throws IOException { 593 return getBigIntegerInternal(tag_Integer, true); 594 } 595 596 /** 597 * Returns a BigInteger value 598 * 599 * @param makePositive whether to always return a positive value, 600 * irrespective of actual encoding 601 * @return the integer as a BigInteger. 602 */ getBigIntegerInternal(byte expectedTag, boolean makePositive)603 private BigInteger getBigIntegerInternal(byte expectedTag, boolean makePositive) throws IOException { 604 if (tag != expectedTag) { 605 throw new IOException("DerValue.getBigIntegerInternal, not expected " + tag); 606 } 607 if (end == start) { 608 throw new IOException("Invalid encoding: zero length Int value"); 609 } 610 data.pos = data.end; // Compatibility. Reach end. 611 if (!allowBER && (end - start >= 2 && (buffer[start] == 0) && (buffer[start + 1] >= 0))) { 612 throw new IOException("Invalid encoding: redundant leading 0s"); 613 } 614 return makePositive 615 ? new BigInteger(1, buffer, start, end - start) 616 : new BigInteger(buffer, start, end - start); 617 } 618 619 /** 620 * Returns an ASN.1 ENUMERATED value. 621 * 622 * @return the integer held in this DER value. 623 */ getEnumerated()624 public int getEnumerated() throws IOException { 625 return getIntegerInternal(tag_Enumerated); 626 } 627 628 /** 629 * Returns an ASN.1 BIT STRING value. The bit string must be byte-aligned. 630 * 631 * @return the bit string held in this value 632 */ getBitString()633 public byte[] getBitString() throws IOException { 634 return getBitString(false); 635 } 636 637 /** 638 * Returns an ASN.1 BIT STRING value that need not be byte-aligned. 639 * 640 * @return a BitArray representing the bit string held in this value 641 */ getUnalignedBitString()642 public BitArray getUnalignedBitString() throws IOException { 643 return getUnalignedBitString(false); 644 } 645 646 /** 647 * Returns the name component as a Java string, regardless of its 648 * encoding restrictions (ASCII, T61, Printable, IA5, BMP, UTF8). 649 */ 650 // TBD: Need encoder for UniversalString before it can be handled. getAsString()651 public String getAsString() throws IOException { 652 return switch (tag) { 653 case tag_UTF8String -> getUTF8String(); 654 case tag_PrintableString -> getPrintableString(); 655 case tag_T61String -> getT61String(); 656 case tag_IA5String -> getIA5String(); 657 case tag_UniversalString -> getUniversalString(); 658 case tag_BMPString -> getBMPString(); 659 case tag_GeneralString -> getGeneralString(); 660 default -> null; 661 }; 662 } 663 664 /** 665 * Returns an ASN.1 BIT STRING value, with the tag assumed implicit 666 * based on the parameter. The bit string must be byte-aligned. 667 * 668 * @param tagImplicit if true, the tag is assumed implicit. 669 * @return the bit string held in this value 670 */ getBitString(boolean tagImplicit)671 public byte[] getBitString(boolean tagImplicit) throws IOException { 672 if (!tagImplicit) { 673 if (tag != tag_BitString) { 674 throw new IOException("DerValue.getBitString, not a bit string " 675 + tag); 676 } 677 } 678 if (end == start) { 679 throw new IOException("Invalid encoding: zero length bit string"); 680 } 681 int numOfPadBits = buffer[start]; 682 if ((numOfPadBits < 0) || (numOfPadBits > 7)) { 683 throw new IOException("Invalid number of padding bits"); 684 } 685 // minus the first byte which indicates the number of padding bits 686 byte[] retval = Arrays.copyOfRange(buffer, start + 1, end); 687 if (numOfPadBits != 0) { 688 // get rid of the padding bits 689 retval[end - start - 2] &= (0xff << numOfPadBits); 690 } 691 data.pos = data.end; // Compatibility. Reach end. 692 return retval; 693 } 694 695 /** 696 * Returns an ASN.1 BIT STRING value, with the tag assumed implicit 697 * based on the parameter. The bit string need not be byte-aligned. 698 * 699 * @param tagImplicit if true, the tag is assumed implicit. 700 * @return the bit string held in this value 701 */ getUnalignedBitString(boolean tagImplicit)702 public BitArray getUnalignedBitString(boolean tagImplicit) 703 throws IOException { 704 if (!tagImplicit) { 705 if (tag != tag_BitString) { 706 throw new IOException("DerValue.getBitString, not a bit string " 707 + tag); 708 } 709 } 710 if (end == start) { 711 throw new IOException("Invalid encoding: zero length bit string"); 712 } 713 data.pos = data.end; // Compatibility. Reach end. 714 int numOfPadBits = buffer[start]; 715 if ((numOfPadBits < 0) || (numOfPadBits > 7)) { 716 throw new IOException("Invalid number of padding bits"); 717 } 718 if (end == start + 1) { 719 return new BitArray(0); 720 } else { 721 return new BitArray(((end - start - 1) << 3) - numOfPadBits, 722 Arrays.copyOfRange(buffer, start + 1, end)); 723 } 724 } 725 726 /** 727 * Helper routine to return all the bytes contained in the 728 * DerInputStream associated with this object. 729 */ getDataBytes()730 public byte[] getDataBytes() throws IOException { 731 data.pos = data.end; // Compatibility. Reach end. 732 return Arrays.copyOfRange(buffer, start, end); 733 } 734 readStringInternal(byte expectedTag, Charset cs)735 private String readStringInternal(byte expectedTag, Charset cs) throws IOException { 736 if (tag != expectedTag) { 737 throw new IOException("Incorrect string type " + tag + " is not " + expectedTag); 738 } 739 data.pos = data.end; // Compatibility. Reach end. 740 return new String(buffer, start, end - start, cs); 741 } 742 743 /** 744 * Returns an ASN.1 STRING value 745 * 746 * @return the printable string held in this value 747 */ getPrintableString()748 public String getPrintableString() throws IOException { 749 return readStringInternal(tag_PrintableString, US_ASCII); 750 } 751 752 /** 753 * Returns an ASN.1 T61 (Teletype) STRING value 754 * 755 * @return the teletype string held in this value 756 */ getT61String()757 public String getT61String() throws IOException { 758 return readStringInternal(tag_T61String, ISO_8859_1); 759 } 760 761 /** 762 * Returns an ASN.1 IA5 (ASCII) STRING value 763 * 764 * @return the ASCII string held in this value 765 */ getIA5String()766 public String getIA5String() throws IOException { 767 return readStringInternal(tag_IA5String, US_ASCII); 768 } 769 770 /** 771 * Returns the ASN.1 BMP (Unicode) STRING value as a Java string. 772 * 773 * @return a string corresponding to the encoded BMPString held in 774 * this value 775 */ getBMPString()776 public String getBMPString() throws IOException { 777 // BMPString is the same as Unicode in big endian, unmarked format. 778 return readStringInternal(tag_BMPString, UTF_16BE); 779 } 780 781 /** 782 * Returns the ASN.1 UTF-8 STRING value as a Java String. 783 * 784 * @return a string corresponding to the encoded UTF8String held in 785 * this value 786 */ getUTF8String()787 public String getUTF8String() throws IOException { 788 return readStringInternal(tag_UTF8String, UTF_8); 789 } 790 791 /** 792 * Returns the ASN.1 GENERAL STRING value as a Java String. 793 * 794 * @return a string corresponding to the encoded GeneralString held in 795 * this value 796 */ getGeneralString()797 public String getGeneralString() throws IOException { 798 return readStringInternal(tag_GeneralString, US_ASCII); 799 } 800 801 /** 802 * Returns the ASN.1 UNIVERSAL (UTF-32) STRING value as a Java String. 803 * 804 * @return a string corresponding to the encoded UniversalString held in 805 * this value 806 */ getUniversalString()807 public String getUniversalString() throws IOException { 808 return readStringInternal(tag_UniversalString, new UTF_32BE()); 809 } 810 811 /** 812 * Reads the ASN.1 NULL value 813 */ getNull()814 public void getNull() throws IOException { 815 if (tag != tag_Null) { 816 throw new IOException("DerValue.getNull, not NULL: " + tag); 817 } 818 if (end != start) { 819 throw new IOException("NULL should contain no data"); 820 } 821 } 822 823 /** 824 * Private helper routine to extract time from the der value. 825 * @param generalized true if Generalized Time is to be read, false 826 * if UTC Time is to be read. 827 */ getTimeInternal(boolean generalized)828 private Date getTimeInternal(boolean generalized) throws IOException { 829 830 /* 831 * UTC time encoded as ASCII chars: 832 * YYMMDDhhmmZ 833 * YYMMDDhhmmssZ 834 * YYMMDDhhmm+hhmm 835 * YYMMDDhhmm-hhmm 836 * YYMMDDhhmmss+hhmm 837 * YYMMDDhhmmss-hhmm 838 * UTC Time is broken in storing only two digits of year. 839 * If YY < 50, we assume 20YY; 840 * if YY >= 50, we assume 19YY, as per RFC 5280. 841 * 842 * Generalized time has a four-digit year and allows any 843 * precision specified in ISO 8601. However, for our purposes, 844 * we will only allow the same format as UTC time, except that 845 * fractional seconds (millisecond precision) are supported. 846 */ 847 848 int year, month, day, hour, minute, second, millis; 849 String type; 850 int pos = start; 851 int len = end - start; 852 853 if (generalized) { 854 type = "Generalized"; 855 year = 1000 * toDigit(buffer[pos++], type); 856 year += 100 * toDigit(buffer[pos++], type); 857 year += 10 * toDigit(buffer[pos++], type); 858 year += toDigit(buffer[pos++], type); 859 len -= 2; // For the two extra YY 860 } else { 861 type = "UTC"; 862 year = 10 * toDigit(buffer[pos++], type); 863 year += toDigit(buffer[pos++], type); 864 865 if (year < 50) { // origin 2000 866 year += 2000; 867 } else { 868 year += 1900; // origin 1900 869 } 870 } 871 872 month = 10 * toDigit(buffer[pos++], type); 873 month += toDigit(buffer[pos++], type); 874 875 day = 10 * toDigit(buffer[pos++], type); 876 day += toDigit(buffer[pos++], type); 877 878 hour = 10 * toDigit(buffer[pos++], type); 879 hour += toDigit(buffer[pos++], type); 880 881 minute = 10 * toDigit(buffer[pos++], type); 882 minute += toDigit(buffer[pos++], type); 883 884 len -= 10; // YYMMDDhhmm 885 886 /* 887 * We allow for non-encoded seconds, even though the 888 * IETF-PKIX specification says that the seconds should 889 * always be encoded even if it is zero. 890 */ 891 892 millis = 0; 893 if (len > 2) { 894 second = 10 * toDigit(buffer[pos++], type); 895 second += toDigit(buffer[pos++], type); 896 len -= 2; 897 // handle fractional seconds (if present) 898 if (generalized && (buffer[pos] == '.' || buffer[pos] == ',')) { 899 len --; 900 if (len == 0) { 901 throw new IOException("Parse " + type + 902 " time, empty fractional part"); 903 } 904 pos++; 905 int precision = 0; 906 while (buffer[pos] != 'Z' && 907 buffer[pos] != '+' && 908 buffer[pos] != '-') { 909 // Validate all digits in the fractional part but 910 // store millisecond precision only 911 int thisDigit = toDigit(buffer[pos], type); 912 precision++; 913 len--; 914 if (len == 0) { 915 throw new IOException("Parse " + type + 916 " time, invalid fractional part"); 917 } 918 pos++; 919 switch (precision) { 920 case 1 -> millis += 100 * thisDigit; 921 case 2 -> millis += 10 * thisDigit; 922 case 3 -> millis += thisDigit; 923 } 924 } 925 if (precision == 0) { 926 throw new IOException("Parse " + type + 927 " time, empty fractional part"); 928 } 929 } 930 } else 931 second = 0; 932 933 if (month == 0 || day == 0 934 || month > 12 || day > 31 935 || hour >= 24 || minute >= 60 || second >= 60) { 936 throw new IOException("Parse " + type + " time, invalid format"); 937 } 938 939 /* 940 * Generalized time can theoretically allow any precision, 941 * but we're not supporting that. 942 */ 943 CalendarSystem gcal = CalendarSystem.getGregorianCalendar(); 944 CalendarDate date = gcal.newCalendarDate(null); // no time zone 945 date.setDate(year, month, day); 946 date.setTimeOfDay(hour, minute, second, millis); 947 long time = gcal.getTime(date); 948 949 /* 950 * Finally, "Z" or "+hhmm" or "-hhmm" ... offsets change hhmm 951 */ 952 if (! (len == 1 || len == 5)) { 953 throw new IOException("Parse " + type + " time, invalid offset"); 954 } 955 956 int hr, min; 957 958 switch (buffer[pos++]) { 959 case '+': 960 if (len != 5) { 961 throw new IOException("Parse " + type + " time, invalid offset"); 962 } 963 hr = 10 * toDigit(buffer[pos++], type); 964 hr += toDigit(buffer[pos++], type); 965 min = 10 * toDigit(buffer[pos++], type); 966 min += toDigit(buffer[pos++], type); 967 968 if (hr >= 24 || min >= 60) { 969 throw new IOException("Parse " + type + " time, +hhmm"); 970 } 971 972 time -= ((hr * 60) + min) * 60 * 1000; 973 break; 974 975 case '-': 976 if (len != 5) { 977 throw new IOException("Parse " + type + " time, invalid offset"); 978 } 979 hr = 10 * toDigit(buffer[pos++], type); 980 hr += toDigit(buffer[pos++], type); 981 min = 10 * toDigit(buffer[pos++], type); 982 min += toDigit(buffer[pos++], type); 983 984 if (hr >= 24 || min >= 60) { 985 throw new IOException("Parse " + type + " time, -hhmm"); 986 } 987 988 time += ((hr * 60) + min) * 60 * 1000; 989 break; 990 991 case 'Z': 992 if (len != 1) { 993 throw new IOException("Parse " + type + " time, invalid format"); 994 } 995 break; 996 997 default: 998 throw new IOException("Parse " + type + " time, garbage offset"); 999 } 1000 return new Date(time); 1001 } 1002 1003 /** 1004 * Converts byte (represented as a char) to int. 1005 * @throws IOException if integer is not a valid digit in the specified 1006 * radix (10) 1007 */ toDigit(byte b, String type)1008 private static int toDigit(byte b, String type) throws IOException { 1009 if (b < '0' || b > '9') { 1010 throw new IOException("Parse " + type + " time, invalid format"); 1011 } 1012 return b - '0'; 1013 } 1014 1015 /** 1016 * Returns a Date if the DerValue is UtcTime. 1017 * 1018 * @return the Date held in this DER value 1019 */ getUTCTime()1020 public Date getUTCTime() throws IOException { 1021 if (tag != tag_UtcTime) { 1022 throw new IOException("DerValue.getUTCTime, not a UtcTime: " + tag); 1023 } 1024 if (end - start < 11 || end - start > 17) 1025 throw new IOException("DER UTC Time length error"); 1026 1027 data.pos = data.end; // Compatibility. Reach end. 1028 return getTimeInternal(false); 1029 } 1030 1031 /** 1032 * Returns a Date if the DerValue is GeneralizedTime. 1033 * 1034 * @return the Date held in this DER value 1035 */ getGeneralizedTime()1036 public Date getGeneralizedTime() throws IOException { 1037 if (tag != tag_GeneralizedTime) { 1038 throw new IOException( 1039 "DerValue.getGeneralizedTime, not a GeneralizedTime: " + tag); 1040 } 1041 if (end - start < 13) 1042 throw new IOException("DER Generalized Time length error"); 1043 1044 data.pos = data.end; // Compatibility. Reach end. 1045 return getTimeInternal(true); 1046 } 1047 1048 /** 1049 * Bitwise equality comparison. DER encoded values have a single 1050 * encoding, so that bitwise equality of the encoded values is an 1051 * efficient way to establish equivalence of the unencoded values. 1052 * 1053 * @param o the object being compared with this one 1054 */ 1055 @Override equals(Object o)1056 public boolean equals(Object o) { 1057 if (this == o) { 1058 return true; 1059 } 1060 if (!(o instanceof DerValue)) { 1061 return false; 1062 } 1063 DerValue other = (DerValue) o; 1064 if (tag != other.tag) { 1065 return false; 1066 } 1067 if (buffer == other.buffer && start == other.start && end == other.end) { 1068 return true; 1069 } 1070 return Arrays.equals(buffer, start, end, other.buffer, other.start, other.end); 1071 } 1072 1073 /** 1074 * Returns a printable representation of the value. 1075 * 1076 * @return printable representation of the value 1077 */ 1078 @Override toString()1079 public String toString() { 1080 return String.format("DerValue(%02x, %s, %d, %d)", 1081 0xff & tag, buffer, start, end); 1082 } 1083 1084 /** 1085 * Returns a DER-encoded value, such that if it's passed to the 1086 * DerValue constructor, a value equivalent to "this" is returned. 1087 * 1088 * @return DER-encoded value, including tag and length. 1089 */ toByteArray()1090 public byte[] toByteArray() throws IOException { 1091 data.pos = data.start; // Compatibility. At head. 1092 // Minimize content duplication by writing out tag and length only 1093 DerOutputStream out = new DerOutputStream(); 1094 out.write(tag); 1095 out.putLength(end - start); 1096 int headLen = out.size(); 1097 byte[] result = Arrays.copyOf(out.buf(), end - start + headLen); 1098 System.arraycopy(buffer, start, result, headLen, end - start); 1099 return result; 1100 } 1101 1102 /** 1103 * For "set" and "sequence" types, this function may be used 1104 * to return a DER stream of the members of the set or sequence. 1105 * This operation is not supported for primitive types such as 1106 * integers or bit strings. 1107 */ toDerInputStream()1108 public DerInputStream toDerInputStream() throws IOException { 1109 if (tag == tag_Sequence || tag == tag_Set) 1110 return data; 1111 throw new IOException("toDerInputStream rejects tag type " + tag); 1112 } 1113 1114 /** 1115 * Get the length of the encoded value. 1116 */ length()1117 public int length() { 1118 return end - start; 1119 } 1120 1121 /** 1122 * Determine if a character is one of the permissible characters for 1123 * PrintableString: 1124 * A-Z, a-z, 0-9, space, apostrophe (39), left and right parentheses, 1125 * plus sign, comma, hyphen, period, slash, colon, equals sign, 1126 * and question mark. 1127 * 1128 * Characters that are *not* allowed in PrintableString include 1129 * exclamation point, quotation mark, number sign, dollar sign, 1130 * percent sign, ampersand, asterisk, semicolon, less than sign, 1131 * greater than sign, at sign, left and right square brackets, 1132 * backslash, circumflex (94), underscore, back quote (96), 1133 * left and right curly brackets, vertical line, tilde, 1134 * and the control codes (0-31 and 127). 1135 * 1136 * This list is based on X.680 (the ASN.1 spec). 1137 */ isPrintableStringChar(char ch)1138 public static boolean isPrintableStringChar(char ch) { 1139 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || 1140 (ch >= '0' && ch <= '9')) { 1141 return true; 1142 } else { 1143 switch (ch) { 1144 case ' ': /* space */ 1145 case '\'': /* apostrophe */ 1146 case '(': /* left paren */ 1147 case ')': /* right paren */ 1148 case '+': /* plus */ 1149 case ',': /* comma */ 1150 case '-': /* hyphen */ 1151 case '.': /* period */ 1152 case '/': /* slash */ 1153 case ':': /* colon */ 1154 case '=': /* equals */ 1155 case '?': /* question mark */ 1156 return true; 1157 default: 1158 return false; 1159 } 1160 } 1161 } 1162 1163 /** 1164 * Create the tag of the attribute. 1165 * 1166 * @param tagClass the tag class type, one of UNIVERSAL, CONTEXT, 1167 * APPLICATION or PRIVATE 1168 * @param form if true, the value is constructed, otherwise it 1169 * is primitive. 1170 * @param val the tag value 1171 */ createTag(byte tagClass, boolean form, byte val)1172 public static byte createTag(byte tagClass, boolean form, byte val) { 1173 if (val < 0 || val > 30) { 1174 throw new IllegalArgumentException("Tag number over 30 is not supported"); 1175 } 1176 byte tag = (byte)(tagClass | val); 1177 if (form) { 1178 tag |= (byte)0x20; 1179 } 1180 return (tag); 1181 } 1182 1183 /** 1184 * Set the tag of the attribute. Commonly used to reset the 1185 * tag value used for IMPLICIT encodings. 1186 * 1187 * This method should be avoided, consider using withTag() instead. 1188 * 1189 * @param tag the tag value 1190 */ resetTag(byte tag)1191 public void resetTag(byte tag) { 1192 this.tag = tag; 1193 } 1194 1195 /** 1196 * Returns a new DerValue with a different tag. This method is used 1197 * to convert a DerValue decoded from an IMPLICIT encoding to its real 1198 * tag. The content is not checked against the tag in this method. 1199 * 1200 * @param newTag the new tag 1201 * @return a new DerValue 1202 */ withTag(byte newTag)1203 public DerValue withTag(byte newTag) { 1204 return new DerValue(newTag, buffer, start, end, allowBER); 1205 } 1206 1207 /** 1208 * Returns a hashcode for this DerValue. 1209 * 1210 * @return a hashcode for this DerValue. 1211 */ 1212 @Override hashCode()1213 public int hashCode() { 1214 int result = tag; 1215 for (int i = start; i < end; i++) { 1216 result = 31 * result + buffer[i]; 1217 } 1218 return result; 1219 } 1220 1221 /** 1222 * Reads the sub-values in a constructed DerValue. 1223 * 1224 * @param expectedTag the expected tag, or zero if we don't check. 1225 * This is useful when this DerValue is IMPLICIT. 1226 * @param startLen estimated number of sub-values 1227 * @return the sub-values in an array 1228 */ subs(byte expectedTag, int startLen)1229 DerValue[] subs(byte expectedTag, int startLen) throws IOException { 1230 if (expectedTag != 0 && expectedTag != tag) { 1231 throw new IOException("Not the correct tag"); 1232 } 1233 List<DerValue> result = new ArrayList<>(startLen); 1234 DerInputStream dis = data(); 1235 while (dis.available() > 0) { 1236 result.add(dis.getDerValue()); 1237 } 1238 return result.toArray(new DerValue[0]); 1239 } 1240 clear()1241 public void clear() { 1242 Arrays.fill(buffer, start, end, (byte)0); 1243 } 1244 } 1245