History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/security/util/DerValue.java (1 of 18352 files). Show all

Unified · Split

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