1 /*
2  * Copyright (c) 1996, 2016, 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 import sun.misc.IOUtils;
32 
33 /**
34  * Represents a single DER-encoded value.  DER encoding rules are a subset
35  * of the "Basic" Encoding Rules (BER), but they only support a single way
36  * ("Definite" encoding) to encode any given value.
37  *
38  * <P>All DER-encoded data are triples <em>{type, length, data}</em>.  This
39  * class represents such tagged values as they have been read (or constructed),
40  * and provides structured access to the encoded data.
41  *
42  * <P>At this time, this class supports only a subset of the types of DER
43  * data encodings which are defined.  That subset is sufficient for parsing
44  * most X.509 certificates, and working with selected additional formats
45  * (such as PKCS #10 certificate requests, and some kinds of PKCS #7 data).
46  *
47  * A note with respect to T61/Teletex strings: From RFC 1617, section 4.1.3
48  * and RFC 3280, section 4.1.2.4., we assume that this kind of string will
49  * contain ISO-8859-1 characters only.
50  *
51  *
52  * @author David Brownell
53  * @author Amit Kapoor
54  * @author Hemma Prafullchandra
55  */
56 public class DerValue {
57     /** The tag class types */
58     public static final byte TAG_UNIVERSAL = (byte)0x000;
59     public static final byte TAG_APPLICATION = (byte)0x040;
60     public static final byte TAG_CONTEXT = (byte)0x080;
61     public static final byte TAG_PRIVATE = (byte)0x0c0;
62 
63     /** The DER tag of the value; one of the tag_ constants. */
64     public byte                 tag;
65 
66     protected DerInputBuffer    buffer;
67 
68     /**
69      * The DER-encoded data of the value, never null
70      */
71     public final DerInputStream data;
72 
73     private int                 length;
74 
75     // BEGIN Android-added: Original encoded form needed for APKs parsing/validation.
76     /**
77      * The original encoded form of the whole value (tag, length, and value)
78      * or null if the form was not provided or was not retained during parsing.
79      */
80     private byte[]              originalEncodedForm;
81     // END Android-added: Original encoded form needed for APKs parsing/validation.
82 
83     /*
84      * The type starts at the first byte of the encoding, and
85      * is one of these tag_* values.  That may be all the type
86      * data that is needed.
87      */
88 
89     /*
90      * These tags are the "universal" tags ... they mean the same
91      * in all contexts.  (Mask with 0x1f -- five bits.)
92      */
93 
94     /** Tag value indicating an ASN.1 "BOOLEAN" value. */
95     public final static byte    tag_Boolean = 0x01;
96 
97     /** Tag value indicating an ASN.1 "INTEGER" value. */
98     public final static byte    tag_Integer = 0x02;
99 
100     /** Tag value indicating an ASN.1 "BIT STRING" value. */
101     public final static byte    tag_BitString = 0x03;
102 
103     /** Tag value indicating an ASN.1 "OCTET STRING" value. */
104     public final static byte    tag_OctetString = 0x04;
105 
106     /** Tag value indicating an ASN.1 "NULL" value. */
107     public final static byte    tag_Null = 0x05;
108 
109     /** Tag value indicating an ASN.1 "OBJECT IDENTIFIER" value. */
110     public final static byte    tag_ObjectId = 0x06;
111 
112     /** Tag value including an ASN.1 "ENUMERATED" value */
113     public final static byte    tag_Enumerated = 0x0A;
114 
115     /** Tag value indicating an ASN.1 "UTF8String" value. */
116     public final static byte    tag_UTF8String = 0x0C;
117 
118     /** Tag value including a "printable" string */
119     public final static byte    tag_PrintableString = 0x13;
120 
121     /** Tag value including a "teletype" string */
122     public final static byte    tag_T61String = 0x14;
123 
124     /** Tag value including an ASCII string */
125     public final static byte    tag_IA5String = 0x16;
126 
127     /** Tag value indicating an ASN.1 "UTCTime" value. */
128     public final static byte    tag_UtcTime = 0x17;
129 
130     /** Tag value indicating an ASN.1 "GeneralizedTime" value. */
131     public final static byte    tag_GeneralizedTime = 0x18;
132 
133     /** Tag value indicating an ASN.1 "GenerallString" value. */
134     public final static byte    tag_GeneralString = 0x1B;
135 
136     /** Tag value indicating an ASN.1 "UniversalString" value. */
137     public final static byte    tag_UniversalString = 0x1C;
138 
139     /** Tag value indicating an ASN.1 "BMPString" value. */
140     public final static byte    tag_BMPString = 0x1E;
141 
142     // CONSTRUCTED seq/set
143 
144     /**
145      * Tag value indicating an ASN.1
146      * "SEQUENCE" (zero to N elements, order is significant).
147      */
148     public final static byte    tag_Sequence = 0x30;
149 
150     /**
151      * Tag value indicating an ASN.1
152      * "SEQUENCE OF" (one to N elements, order is significant).
153      */
154     public final static byte    tag_SequenceOf = 0x30;
155 
156     /**
157      * Tag value indicating an ASN.1
158      * "SET" (zero to N members, order does not matter).
159      */
160     public final static byte    tag_Set = 0x31;
161 
162     /**
163      * Tag value indicating an ASN.1
164      * "SET OF" (one to N members, order does not matter).
165      */
166     public final static byte    tag_SetOf = 0x31;
167 
168     /*
169      * These values are the high order bits for the other kinds of tags.
170      */
171 
172     /**
173      * Returns true if the tag class is UNIVERSAL.
174      */
isUniversal()175     public boolean isUniversal()      { return ((tag & 0x0c0) == 0x000); }
176 
177     /**
178      * Returns true if the tag class is APPLICATION.
179      */
isApplication()180     public boolean isApplication()    { return ((tag & 0x0c0) == 0x040); }
181 
182     /**
183      * Returns true iff the CONTEXT SPECIFIC bit is set in the type tag.
184      * This is associated with the ASN.1 "DEFINED BY" syntax.
185      */
isContextSpecific()186     public boolean isContextSpecific() { return ((tag & 0x0c0) == 0x080); }
187 
188     /**
189      * Returns true iff the CONTEXT SPECIFIC TAG matches the passed tag.
190      */
isContextSpecific(byte cntxtTag)191     public boolean isContextSpecific(byte cntxtTag) {
192         if (!isContextSpecific()) {
193             return false;
194         }
195         return ((tag & 0x01f) == cntxtTag);
196     }
197 
isPrivate()198     boolean isPrivate()        { return ((tag & 0x0c0) == 0x0c0); }
199 
200     /** Returns true iff the CONSTRUCTED bit is set in the type tag. */
isConstructed()201     public boolean isConstructed()    { return ((tag & 0x020) == 0x020); }
202 
203     /**
204      * Returns true iff the CONSTRUCTED TAG matches the passed tag.
205      */
isConstructed(byte constructedTag)206     public boolean isConstructed(byte constructedTag) {
207         if (!isConstructed()) {
208             return false;
209         }
210         return ((tag & 0x01f) == constructedTag);
211     }
212 
213     /**
214      * Creates a PrintableString or UTF8string DER value from a string
215      */
DerValue(String value)216     public DerValue(String value) throws IOException {
217         boolean isPrintableString = true;
218         for (int i = 0; i < value.length(); i++) {
219             if (!isPrintableStringChar(value.charAt(i))) {
220                 isPrintableString = false;
221                 break;
222             }
223         }
224 
225         data = init(isPrintableString ? tag_PrintableString : tag_UTF8String, value);
226     }
227 
228     /**
229      * Creates a string type DER value from a String object
230      * @param stringTag the tag for the DER value to create
231      * @param value the String object to use for the DER value
232      */
DerValue(byte stringTag, String value)233     public DerValue(byte stringTag, String value) throws IOException {
234         data = init(stringTag, value);
235     }
236 
237     /**
238      * Creates a DerValue from a tag and some DER-encoded data.
239      *
240      * @param tag the DER type tag
241      * @param data the DER-encoded data
242      */
DerValue(byte tag, byte[] data)243     public DerValue(byte tag, byte[] data) {
244         this.tag = tag;
245         buffer = new DerInputBuffer(data.clone());
246         length = data.length;
247         this.data = new DerInputStream(buffer);
248         this.data.mark(Integer.MAX_VALUE);
249     }
250 
251     /*
252      * package private
253      */
254     // BEGIN Android-changed: Original encoded form needed for APKs parsing/validation.
DerValue(DerInputBuffer in, boolean originalEncodedFormRetained)255     DerValue(DerInputBuffer in, boolean originalEncodedFormRetained)
256             throws IOException {
257         // XXX must also parse BER-encoded constructed
258         // values such as sequences, sets...
259 
260         int startPosInInput = in.getPos();
261         tag = (byte)in.read();
262         byte lenByte = (byte)in.read();
263         length = DerInputStream.getLength(lenByte, in);
264         if (length == -1) {  // indefinite length encoding found
265             DerInputBuffer inbuf = in.dup();
266             int readLen = inbuf.available();
267             int offset = 2;     // for tag and length bytes
268             byte[] indefData = new byte[readLen + offset];
269             indefData[0] = tag;
270             indefData[1] = lenByte;
271             DataInputStream dis = new DataInputStream(inbuf);
272             dis.readFully(indefData, offset, readLen);
273             dis.close();
274             DerIndefLenConverter derIn = new DerIndefLenConverter();
275             inbuf = new DerInputBuffer(derIn.convert(indefData));
276             if (tag != inbuf.read())
277                 throw new IOException
278                         ("Indefinite length encoding not supported");
279             length = DerInputStream.getLength(inbuf);
280             buffer = inbuf.dup();
281             buffer.truncate(length);
282             data = new DerInputStream(buffer);
283             // indefinite form is encoded by sending a length field with a
284             // length of 0. - i.e. [1000|0000].
285             // the object is ended by sending two zero bytes.
286             in.skip(length + offset);
287         } else {
288 
289             buffer = in.dup();
290             buffer.truncate(length);
291             data = new DerInputStream(buffer);
292 
293             in.skip(length);
294         }
295 
296         if (originalEncodedFormRetained) {
297             int consumed = in.getPos() - startPosInInput;
298             originalEncodedForm = in.getSlice(startPosInInput, consumed);
299         }
300     // END Android-changed: Original encoded form needed for APKs parsing/validation.
301     }
302 
303     /**
304      * Get an ASN.1/DER encoded datum from a buffer.  The
305      * entire buffer must hold exactly one datum, including
306      * its tag and length.
307      *
308      * @param buf buffer holding a single DER-encoded datum.
309      */
DerValue(byte[] buf)310     public DerValue(byte[] buf) throws IOException {
311         data = init(true, new ByteArrayInputStream(buf));
312     }
313 
314     /**
315      * Get an ASN.1/DER encoded datum from part of a buffer.
316      * That part of the buffer must hold exactly one datum, including
317      * its tag and length.
318      *
319      * @param buf the buffer
320      * @param offset start point of the single DER-encoded dataum
321      * @param length how many bytes are in the encoded datum
322      */
DerValue(byte[] buf, int offset, int len)323     public DerValue(byte[] buf, int offset, int len) throws IOException {
324         data = init(true, new ByteArrayInputStream(buf, offset, len));
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         data = init(false, in);
338     }
339 
init(byte stringTag, String value)340     private DerInputStream init(byte stringTag, String value) throws IOException {
341         String enc = null;
342 
343         tag = stringTag;
344 
345         switch (stringTag) {
346         case tag_PrintableString:
347         case tag_IA5String:
348         case tag_GeneralString:
349             enc = "ASCII";
350             break;
351         case tag_T61String:
352             enc = "ISO-8859-1";
353             break;
354         case tag_BMPString:
355             enc = "UnicodeBigUnmarked";
356             break;
357         case tag_UTF8String:
358             enc = "UTF8";
359             break;
360             // TBD: Need encoder for UniversalString before it can
361             // be handled.
362         default:
363             throw new IllegalArgumentException("Unsupported DER string type");
364         }
365 
366         byte[] buf = value.getBytes(enc);
367         length = buf.length;
368         buffer = new DerInputBuffer(buf);
369         DerInputStream result = new DerInputStream(buffer);
370         result.mark(Integer.MAX_VALUE);
371         return result;
372     }
373 
374     /*
375      * helper routine
376      */
init(boolean fullyBuffered, InputStream in)377     private DerInputStream init(boolean fullyBuffered, InputStream in)
378             throws IOException {
379 
380         tag = (byte)in.read();
381         byte lenByte = (byte)in.read();
382         length = DerInputStream.getLength(lenByte, in);
383         if (length == -1) { // indefinite length encoding found
384             int readLen = in.available();
385             int offset = 2;     // for tag and length bytes
386             byte[] indefData = new byte[readLen + offset];
387             indefData[0] = tag;
388             indefData[1] = lenByte;
389             DataInputStream dis = new DataInputStream(in);
390             dis.readFully(indefData, offset, readLen);
391             dis.close();
392             DerIndefLenConverter derIn = new DerIndefLenConverter();
393             in = new ByteArrayInputStream(derIn.convert(indefData));
394             if (tag != in.read())
395                 throw new IOException
396                         ("Indefinite length encoding not supported");
397             length = DerInputStream.getLength(in);
398         }
399 
400         if (fullyBuffered && in.available() != length)
401             throw new IOException("extra data given to DerValue constructor");
402 
403         byte[] bytes = IOUtils.readFully(in, length, true);
404 
405         buffer = new DerInputBuffer(bytes);
406         return new DerInputStream(buffer);
407     }
408 
409     /**
410      * Encode an ASN1/DER encoded datum onto a DER output stream.
411      */
encode(DerOutputStream out)412     public void encode(DerOutputStream out)
413     throws IOException {
414         out.write(tag);
415         out.putLength(length);
416         // XXX yeech, excess copies ... DerInputBuffer.write(OutStream)
417         if (length > 0) {
418             byte[] value = new byte[length];
419             // always synchronized on data
420             synchronized (data) {
421                 buffer.reset();
422                 if (buffer.read(value) != length) {
423                     throw new IOException("short DER value read (encode)");
424                 }
425                 out.write(value);
426             }
427         }
428     }
429 
getData()430     public final DerInputStream getData() {
431         return data;
432     }
433 
getTag()434     public final byte getTag() {
435         return tag;
436     }
437 
438     /**
439      * Returns an ASN.1 BOOLEAN
440      *
441      * @return the boolean held in this DER value
442      */
getBoolean()443     public boolean getBoolean() throws IOException {
444         if (tag != tag_Boolean) {
445             throw new IOException("DerValue.getBoolean, not a BOOLEAN " + tag);
446         }
447         if (length != 1) {
448             throw new IOException("DerValue.getBoolean, invalid length "
449                                         + length);
450         }
451         if (buffer.read() != 0) {
452             return true;
453         }
454         return false;
455     }
456 
457     /**
458      * Returns an ASN.1 OBJECT IDENTIFIER.
459      *
460      * @return the OID held in this DER value
461      */
getOID()462     public ObjectIdentifier getOID() throws IOException {
463         if (tag != tag_ObjectId)
464             throw new IOException("DerValue.getOID, not an OID " + tag);
465         return new ObjectIdentifier(buffer);
466     }
467 
append(byte[] a, byte[] b)468     private byte[] append(byte[] a, byte[] b) {
469         if (a == null)
470             return b;
471 
472         byte[] ret = new byte[a.length + b.length];
473         System.arraycopy(a, 0, ret, 0, a.length);
474         System.arraycopy(b, 0, ret, a.length, b.length);
475 
476         return ret;
477     }
478 
479     /**
480      * Returns an ASN.1 OCTET STRING
481      *
482      * @return the octet string held in this DER value
483      */
getOctetString()484     public byte[] getOctetString() throws IOException {
485         byte[] bytes;
486 
487         if (tag != tag_OctetString && !isConstructed(tag_OctetString)) {
488             throw new IOException(
489                 "DerValue.getOctetString, not an Octet String: " + tag);
490         }
491         bytes = new byte[length];
492         // Note: do not tempt to call buffer.read(bytes) at all. There's a
493         // known bug that it returns -1 instead of 0.
494         if (length == 0) {
495             return bytes;
496         }
497         if (buffer.read(bytes) != length)
498             throw new IOException("short read on DerValue buffer");
499         if (isConstructed()) {
500             DerInputStream in = new DerInputStream(bytes);
501             bytes = null;
502             while (in.available() != 0) {
503                 bytes = append(bytes, in.getOctetString());
504             }
505         }
506         return bytes;
507     }
508 
509     /**
510      * Returns an ASN.1 INTEGER value as an integer.
511      *
512      * @return the integer held in this DER value.
513      */
getInteger()514     public int getInteger() throws IOException {
515         if (tag != tag_Integer) {
516             throw new IOException("DerValue.getInteger, not an int " + tag);
517         }
518         return buffer.getInteger(data.available());
519     }
520 
521     /**
522      * Returns an ASN.1 INTEGER value as a BigInteger.
523      *
524      * @return the integer held in this DER value as a BigInteger.
525      */
getBigInteger()526     public BigInteger getBigInteger() throws IOException {
527         if (tag != tag_Integer)
528             throw new IOException("DerValue.getBigInteger, not an int " + tag);
529         return buffer.getBigInteger(data.available(), false);
530     }
531 
532     /**
533      * Returns an ASN.1 INTEGER value as a positive BigInteger.
534      * This is just to deal with implementations that incorrectly encode
535      * some values as negative.
536      *
537      * @return the integer held in this DER value as a BigInteger.
538      */
getPositiveBigInteger()539     public BigInteger getPositiveBigInteger() throws IOException {
540         if (tag != tag_Integer)
541             throw new IOException("DerValue.getBigInteger, not an int " + tag);
542         return buffer.getBigInteger(data.available(), true);
543     }
544 
545     /**
546      * Returns an ASN.1 ENUMERATED value.
547      *
548      * @return the integer held in this DER value.
549      */
getEnumerated()550     public int getEnumerated() throws IOException {
551         if (tag != tag_Enumerated) {
552             throw new IOException("DerValue.getEnumerated, incorrect tag: "
553                                   + tag);
554         }
555         return buffer.getInteger(data.available());
556     }
557 
558     /**
559      * Returns an ASN.1 BIT STRING value.  The bit string must be byte-aligned.
560      *
561      * @return the bit string held in this value
562      */
getBitString()563     public byte[] getBitString() throws IOException {
564         if (tag != tag_BitString)
565             throw new IOException(
566                 "DerValue.getBitString, not a bit string " + tag);
567 
568         return buffer.getBitString();
569     }
570 
571     /**
572      * Returns an ASN.1 BIT STRING value that need not be byte-aligned.
573      *
574      * @return a BitArray representing the bit string held in this value
575      */
getUnalignedBitString()576     public BitArray getUnalignedBitString() throws IOException {
577         if (tag != tag_BitString)
578             throw new IOException(
579                 "DerValue.getBitString, not a bit string " + tag);
580 
581         return buffer.getUnalignedBitString();
582     }
583 
584     /**
585      * Returns the name component as a Java string, regardless of its
586      * encoding restrictions (ASCII, T61, Printable, IA5, BMP, UTF8).
587      */
588     // TBD: Need encoder for UniversalString before it can be handled.
getAsString()589     public String getAsString() throws IOException {
590         if (tag == tag_UTF8String)
591             return getUTF8String();
592         else if (tag == tag_PrintableString)
593             return getPrintableString();
594         else if (tag == tag_T61String)
595             return getT61String();
596         else if (tag == tag_IA5String)
597             return getIA5String();
598         /*
599           else if (tag == tag_UniversalString)
600           return getUniversalString();
601         */
602         else if (tag == tag_BMPString)
603             return getBMPString();
604         else if (tag == tag_GeneralString)
605             return getGeneralString();
606         else
607             return null;
608     }
609 
610     /**
611      * Returns an ASN.1 BIT STRING value, with the tag assumed implicit
612      * based on the parameter.  The bit string must be byte-aligned.
613      *
614      * @params tagImplicit if true, the tag is assumed implicit.
615      * @return the bit string held in this value
616      */
getBitString(boolean tagImplicit)617     public byte[] getBitString(boolean tagImplicit) throws IOException {
618         if (!tagImplicit) {
619             if (tag != tag_BitString)
620                 throw new IOException("DerValue.getBitString, not a bit string "
621                                        + tag);
622             }
623         return buffer.getBitString();
624     }
625 
626     /**
627      * Returns an ASN.1 BIT STRING value, with the tag assumed implicit
628      * based on the parameter.  The bit string need not be byte-aligned.
629      *
630      * @params tagImplicit if true, the tag is assumed implicit.
631      * @return the bit string held in this value
632      */
getUnalignedBitString(boolean tagImplicit)633     public BitArray getUnalignedBitString(boolean tagImplicit)
634     throws IOException {
635         if (!tagImplicit) {
636             if (tag != tag_BitString)
637                 throw new IOException("DerValue.getBitString, not a bit string "
638                                        + tag);
639             }
640         return buffer.getUnalignedBitString();
641     }
642 
643     /**
644      * Helper routine to return all the bytes contained in the
645      * DerInputStream associated with this object.
646      */
getDataBytes()647     public byte[] getDataBytes() throws IOException {
648         byte[] retVal = new byte[length];
649         synchronized (data) {
650             data.reset();
651             data.getBytes(retVal);
652         }
653         return retVal;
654     }
655 
656     /**
657      * Returns an ASN.1 STRING value
658      *
659      * @return the printable string held in this value
660      */
getPrintableString()661     public String getPrintableString()
662     throws IOException {
663         if (tag != tag_PrintableString)
664             throw new IOException(
665                 "DerValue.getPrintableString, not a string " + tag);
666 
667         return new String(getDataBytes(), "ASCII");
668     }
669 
670     /**
671      * Returns an ASN.1 T61 (Teletype) STRING value
672      *
673      * @return the teletype string held in this value
674      */
getT61String()675     public String getT61String() throws IOException {
676         if (tag != tag_T61String)
677             throw new IOException(
678                 "DerValue.getT61String, not T61 " + tag);
679 
680         return new String(getDataBytes(), "ISO-8859-1");
681     }
682 
683     /**
684      * Returns an ASN.1 IA5 (ASCII) STRING value
685      *
686      * @return the ASCII string held in this value
687      */
getIA5String()688     public String getIA5String() throws IOException {
689         if (tag != tag_IA5String)
690             throw new IOException(
691                 "DerValue.getIA5String, not IA5 " + tag);
692 
693         return new String(getDataBytes(), "ASCII");
694     }
695 
696     /**
697      * Returns the ASN.1 BMP (Unicode) STRING value as a Java string.
698      *
699      * @return a string corresponding to the encoded BMPString held in
700      * this value
701      */
getBMPString()702     public String getBMPString() throws IOException {
703         if (tag != tag_BMPString)
704             throw new IOException(
705                 "DerValue.getBMPString, not BMP " + tag);
706 
707         // BMPString is the same as Unicode in big endian, unmarked
708         // format.
709         return new String(getDataBytes(), "UnicodeBigUnmarked");
710     }
711 
712     /**
713      * Returns the ASN.1 UTF-8 STRING value as a Java String.
714      *
715      * @return a string corresponding to the encoded UTF8String held in
716      * this value
717      */
getUTF8String()718     public String getUTF8String() throws IOException {
719         if (tag != tag_UTF8String)
720             throw new IOException(
721                 "DerValue.getUTF8String, not UTF-8 " + tag);
722 
723         return new String(getDataBytes(), "UTF8");
724     }
725 
726     /**
727      * Returns the ASN.1 GENERAL STRING value as a Java String.
728      *
729      * @return a string corresponding to the encoded GeneralString held in
730      * this value
731      */
getGeneralString()732     public String getGeneralString() throws IOException {
733         if (tag != tag_GeneralString)
734             throw new IOException(
735                 "DerValue.getGeneralString, not GeneralString " + tag);
736 
737         return new String(getDataBytes(), "ASCII");
738     }
739 
740     /**
741      * Returns a Date if the DerValue is UtcTime.
742      *
743      * @return the Date held in this DER value
744      */
getUTCTime()745     public Date getUTCTime() throws IOException {
746         if (tag != tag_UtcTime) {
747             throw new IOException("DerValue.getUTCTime, not a UtcTime: " + tag);
748         }
749         return buffer.getUTCTime(data.available());
750     }
751 
752     /**
753      * Returns a Date if the DerValue is GeneralizedTime.
754      *
755      * @return the Date held in this DER value
756      */
getGeneralizedTime()757     public Date getGeneralizedTime() throws IOException {
758         if (tag != tag_GeneralizedTime) {
759             throw new IOException(
760                 "DerValue.getGeneralizedTime, not a GeneralizedTime: " + tag);
761         }
762         return buffer.getGeneralizedTime(data.available());
763     }
764 
765     /**
766      * Returns true iff the other object is a DER value which
767      * is bitwise equal to this one.
768      *
769      * @param other the object being compared with this one
770      */
equals(Object other)771     public boolean equals(Object other) {
772         if (other instanceof DerValue)
773             return equals((DerValue)other);
774         else
775             return false;
776     }
777 
778     /**
779      * Bitwise equality comparison.  DER encoded values have a single
780      * encoding, so that bitwise equality of the encoded values is an
781      * efficient way to establish equivalence of the unencoded values.
782      *
783      * @param other the object being compared with this one
784      */
equals(DerValue other)785     public boolean equals(DerValue other) {
786         if (this == other) {
787             return true;
788         }
789         if (tag != other.tag) {
790             return false;
791         }
792         if (data == other.data) {
793             return true;
794         }
795 
796         // make sure the order of lock is always consistent to avoid a deadlock
797         return (System.identityHashCode(this.data)
798                 > System.identityHashCode(other.data)) ?
799                 doEquals(this, other):
800                 doEquals(other, this);
801     }
802 
803     /**
804      * Helper for public method equals()
805      */
doEquals(DerValue d1, DerValue d2)806     private static boolean doEquals(DerValue d1, DerValue d2) {
807         synchronized (d1.data) {
808             synchronized (d2.data) {
809                 d1.data.reset();
810                 d2.data.reset();
811                 return d1.buffer.equals(d2.buffer);
812             }
813         }
814     }
815 
816     /**
817      * Returns a printable representation of the value.
818      *
819      * @return printable representation of the value
820      */
toString()821     public String toString() {
822         try {
823 
824             String str = getAsString();
825             if (str != null)
826                 return "\"" + str + "\"";
827             if (tag == tag_Null)
828                 return "[DerValue, null]";
829             if (tag == tag_ObjectId)
830                 return "OID." + getOID();
831 
832             // integers
833             else
834                 return "[DerValue, tag = " + tag
835                         + ", length = " + length + "]";
836         } catch (IOException e) {
837             throw new IllegalArgumentException("misformatted DER value");
838         }
839     }
840 
841     // BEGIN Android-added: Original encoded form needed for APKs parsing/validation.
842     /**
843      * Returns the original encoded form or {@code null} if the form was not
844      * retained or is not available.
845      */
getOriginalEncodedForm()846     public byte[] getOriginalEncodedForm() {
847         return (originalEncodedForm != null)
848                 ? originalEncodedForm.clone() : null;
849     }
850     // END Android-added: Original encoded form needed for APKs parsing/validation.
851 
852     /**
853      * Returns a DER-encoded value, such that if it's passed to the
854      * DerValue constructor, a value equivalent to "this" is returned.
855      *
856      * @return DER-encoded value, including tag and length.
857      */
toByteArray()858     public byte[] toByteArray() throws IOException {
859         DerOutputStream out = new DerOutputStream();
860 
861         encode(out);
862         data.reset();
863         return out.toByteArray();
864     }
865 
866     /**
867      * For "set" and "sequence" types, this function may be used
868      * to return a DER stream of the members of the set or sequence.
869      * This operation is not supported for primitive types such as
870      * integers or bit strings.
871      */
toDerInputStream()872     public DerInputStream toDerInputStream() throws IOException {
873         if (tag == tag_Sequence || tag == tag_Set)
874             return new DerInputStream(buffer);
875         throw new IOException("toDerInputStream rejects tag type " + tag);
876     }
877 
878     /**
879      * Get the length of the encoded value.
880      */
length()881     public int length() {
882         return length;
883     }
884 
885     /**
886      * Determine if a character is one of the permissible characters for
887      * PrintableString:
888      * A-Z, a-z, 0-9, space, apostrophe (39), left and right parentheses,
889      * plus sign, comma, hyphen, period, slash, colon, equals sign,
890      * and question mark.
891      *
892      * Characters that are *not* allowed in PrintableString include
893      * exclamation point, quotation mark, number sign, dollar sign,
894      * percent sign, ampersand, asterisk, semicolon, less than sign,
895      * greater than sign, at sign, left and right square brackets,
896      * backslash, circumflex (94), underscore, back quote (96),
897      * left and right curly brackets, vertical line, tilde,
898      * and the control codes (0-31 and 127).
899      *
900      * This list is based on X.680 (the ASN.1 spec).
901      */
isPrintableStringChar(char ch)902     public static boolean isPrintableStringChar(char ch) {
903         if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
904             (ch >= '0' && ch <= '9')) {
905             return true;
906         } else {
907             switch (ch) {
908                 case ' ':       /* space */
909                 case '\'':      /* apostrophe */
910                 case '(':       /* left paren */
911                 case ')':       /* right paren */
912                 case '+':       /* plus */
913                 case ',':       /* comma */
914                 case '-':       /* hyphen */
915                 case '.':       /* period */
916                 case '/':       /* slash */
917                 case ':':       /* colon */
918                 case '=':       /* equals */
919                 case '?':       /* question mark */
920                     return true;
921                 default:
922                     return false;
923             }
924         }
925     }
926 
927     /**
928      * Create the tag of the attribute.
929      *
930      * @params class the tag class type, one of UNIVERSAL, CONTEXT,
931      *               APPLICATION or PRIVATE
932      * @params form if true, the value is constructed, otherwise it
933      * is primitive.
934      * @params val the tag value
935      */
createTag(byte tagClass, boolean form, byte val)936     public static byte createTag(byte tagClass, boolean form, byte val) {
937         byte tag = (byte)(tagClass | val);
938         if (form) {
939             tag |= (byte)0x20;
940         }
941         return (tag);
942     }
943 
944     /**
945      * Set the tag of the attribute. Commonly used to reset the
946      * tag value used for IMPLICIT encodings.
947      *
948      * @params tag the tag value
949      */
resetTag(byte tag)950     public void resetTag(byte tag) {
951         this.tag = tag;
952     }
953 
954     /**
955      * Returns a hashcode for this DerValue.
956      *
957      * @return a hashcode for this DerValue.
958      */
hashCode()959     public int hashCode() {
960         return toString().hashCode();
961     }
962 }
963