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