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