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