jdk/src/share/classes/sun/security/util/DerValue.java
changeset 2 90ce3da70b43
child 2065 d0bafa066816
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Copyright 1996-2006 Sun Microsystems, Inc.  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.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 package sun.security.util;
       
    27 
       
    28 import java.io.*;
       
    29 import java.math.BigInteger;
       
    30 import java.util.Date;
       
    31 
       
    32 /**
       
    33  * Represents a single DER-encoded value.  DER encoding rules are a subset
       
    34  * of the "Basic" Encoding Rules (BER), but they only support a single way
       
    35  * ("Definite" encoding) to encode any given value.
       
    36  *
       
    37  * <P>All DER-encoded data are triples <em>{type, length, data}</em>.  This
       
    38  * class represents such tagged values as they have been read (or constructed),
       
    39  * and provides structured access to the encoded data.
       
    40  *
       
    41  * <P>At this time, this class supports only a subset of the types of DER
       
    42  * data encodings which are defined.  That subset is sufficient for parsing
       
    43  * most X.509 certificates, and working with selected additional formats
       
    44  * (such as PKCS #10 certificate requests, and some kinds of PKCS #7 data).
       
    45  *
       
    46  * A note with respect to T61/Teletex strings: From RFC 1617, section 4.1.3
       
    47  * and RFC 3280, section 4.1.2.4., we assume that this kind of string will
       
    48  * contain ISO-8859-1 characters only.
       
    49  *
       
    50  *
       
    51  * @author David Brownell
       
    52  * @author Amit Kapoor
       
    53  * @author Hemma Prafullchandra
       
    54  */
       
    55 public class DerValue {
       
    56     /** The tag class types */
       
    57     public static final byte TAG_UNIVERSAL = (byte)0x000;
       
    58     public static final byte TAG_APPLICATION = (byte)0x040;
       
    59     public static final byte TAG_CONTEXT = (byte)0x080;
       
    60     public static final byte TAG_PRIVATE = (byte)0x0c0;
       
    61 
       
    62     /** The DER tag of the value; one of the tag_ constants. */
       
    63     public byte                 tag;
       
    64 
       
    65     protected DerInputBuffer    buffer;
       
    66 
       
    67     /**
       
    68      * The DER-encoded data of the value.
       
    69      */
       
    70     public final DerInputStream data;
       
    71 
       
    72     private int                 length;
       
    73 
       
    74     /*
       
    75      * The type starts at the first byte of the encoding, and
       
    76      * is one of these tag_* values.  That may be all the type
       
    77      * data that is needed.
       
    78      */
       
    79 
       
    80     /*
       
    81      * These tags are the "universal" tags ... they mean the same
       
    82      * in all contexts.  (Mask with 0x1f -- five bits.)
       
    83      */
       
    84 
       
    85     /** Tag value indicating an ASN.1 "BOOLEAN" value. */
       
    86     public final static byte    tag_Boolean = 0x01;
       
    87 
       
    88     /** Tag value indicating an ASN.1 "INTEGER" value. */
       
    89     public final static byte    tag_Integer = 0x02;
       
    90 
       
    91     /** Tag value indicating an ASN.1 "BIT STRING" value. */
       
    92     public final static byte    tag_BitString = 0x03;
       
    93 
       
    94     /** Tag value indicating an ASN.1 "OCTET STRING" value. */
       
    95     public final static byte    tag_OctetString = 0x04;
       
    96 
       
    97     /** Tag value indicating an ASN.1 "NULL" value. */
       
    98     public final static byte    tag_Null = 0x05;
       
    99 
       
   100     /** Tag value indicating an ASN.1 "OBJECT IDENTIFIER" value. */
       
   101     public final static byte    tag_ObjectId = 0x06;
       
   102 
       
   103     /** Tag value including an ASN.1 "ENUMERATED" value */
       
   104     public final static byte    tag_Enumerated = 0x0A;
       
   105 
       
   106     /** Tag value indicating an ASN.1 "UTF8String" value. */
       
   107     public final static byte    tag_UTF8String = 0x0C;
       
   108 
       
   109     /** Tag value including a "printable" string */
       
   110     public final static byte    tag_PrintableString = 0x13;
       
   111 
       
   112     /** Tag value including a "teletype" string */
       
   113     public final static byte    tag_T61String = 0x14;
       
   114 
       
   115     /** Tag value including an ASCII string */
       
   116     public final static byte    tag_IA5String = 0x16;
       
   117 
       
   118     /** Tag value indicating an ASN.1 "UTCTime" value. */
       
   119     public final static byte    tag_UtcTime = 0x17;
       
   120 
       
   121     /** Tag value indicating an ASN.1 "GeneralizedTime" value. */
       
   122     public final static byte    tag_GeneralizedTime = 0x18;
       
   123 
       
   124     /** Tag value indicating an ASN.1 "GenerallString" value. */
       
   125     public final static byte    tag_GeneralString = 0x1B;
       
   126 
       
   127     /** Tag value indicating an ASN.1 "UniversalString" value. */
       
   128     public final static byte    tag_UniversalString = 0x1C;
       
   129 
       
   130     /** Tag value indicating an ASN.1 "BMPString" value. */
       
   131     public final static byte    tag_BMPString = 0x1E;
       
   132 
       
   133     // CONSTRUCTED seq/set
       
   134 
       
   135     /**
       
   136      * Tag value indicating an ASN.1
       
   137      * "SEQUENCE" (zero to N elements, order is significant).
       
   138      */
       
   139     public final static byte    tag_Sequence = 0x30;
       
   140 
       
   141     /**
       
   142      * Tag value indicating an ASN.1
       
   143      * "SEQUENCE OF" (one to N elements, order is significant).
       
   144      */
       
   145     public final static byte    tag_SequenceOf = 0x30;
       
   146 
       
   147     /**
       
   148      * Tag value indicating an ASN.1
       
   149      * "SET" (zero to N members, order does not matter).
       
   150      */
       
   151     public final static byte    tag_Set = 0x31;
       
   152 
       
   153     /**
       
   154      * Tag value indicating an ASN.1
       
   155      * "SET OF" (one to N members, order does not matter).
       
   156      */
       
   157     public final static byte    tag_SetOf = 0x31;
       
   158 
       
   159     /*
       
   160      * These values are the high order bits for the other kinds of tags.
       
   161      */
       
   162 
       
   163     /**
       
   164      * Returns true if the tag class is UNIVERSAL.
       
   165      */
       
   166     public boolean isUniversal()      { return ((tag & 0x0c0) == 0x000); }
       
   167 
       
   168     /**
       
   169      * Returns true if the tag class is APPLICATION.
       
   170      */
       
   171     public boolean isApplication()    { return ((tag & 0x0c0) == 0x040); }
       
   172 
       
   173     /**
       
   174      * Returns true iff the CONTEXT SPECIFIC bit is set in the type tag.
       
   175      * This is associated with the ASN.1 "DEFINED BY" syntax.
       
   176      */
       
   177     public boolean isContextSpecific() { return ((tag & 0x0c0) == 0x080); }
       
   178 
       
   179     /**
       
   180      * Returns true iff the CONTEXT SPECIFIC TAG matches the passed tag.
       
   181      */
       
   182     public boolean isContextSpecific(byte cntxtTag) {
       
   183         if (!isContextSpecific()) {
       
   184             return false;
       
   185         }
       
   186         return ((tag & 0x01f) == cntxtTag);
       
   187     }
       
   188 
       
   189     boolean isPrivate()        { return ((tag & 0x0c0) == 0x0c0); }
       
   190 
       
   191     /** Returns true iff the CONSTRUCTED bit is set in the type tag. */
       
   192     public boolean isConstructed()    { return ((tag & 0x020) == 0x020); }
       
   193 
       
   194     /**
       
   195      * Returns true iff the CONSTRUCTED TAG matches the passed tag.
       
   196      */
       
   197     public boolean isConstructed(byte constructedTag) {
       
   198         if (!isConstructed()) {
       
   199             return false;
       
   200         }
       
   201         return ((tag & 0x01f) == constructedTag);
       
   202     }
       
   203 
       
   204     /**
       
   205      * Creates a PrintableString or UTF8string DER value from a string
       
   206      */
       
   207     public DerValue(String value) throws IOException {
       
   208         boolean isPrintableString = true;
       
   209         for (int i = 0; i < value.length(); i++) {
       
   210             if (!isPrintableStringChar(value.charAt(i))) {
       
   211                 isPrintableString = false;
       
   212                 break;
       
   213             }
       
   214         }
       
   215 
       
   216         data = init(isPrintableString ? tag_PrintableString : tag_UTF8String, value);
       
   217     }
       
   218 
       
   219     /**
       
   220      * Creates a string type DER value from a String object
       
   221      * @param stringTag the tag for the DER value to create
       
   222      * @param value the String object to use for the DER value
       
   223      */
       
   224     public DerValue(byte stringTag, String value) throws IOException {
       
   225         data = init(stringTag, value);
       
   226     }
       
   227 
       
   228     /**
       
   229      * Creates a DerValue from a tag and some DER-encoded data.
       
   230      *
       
   231      * @param tag the DER type tag
       
   232      * @param data the DER-encoded data
       
   233      */
       
   234     public DerValue(byte tag, byte[] data) {
       
   235         this.tag = tag;
       
   236         buffer = new DerInputBuffer(data.clone());
       
   237         length = data.length;
       
   238         this.data = new DerInputStream(buffer);
       
   239         this.data.mark(Integer.MAX_VALUE);
       
   240     }
       
   241 
       
   242     /*
       
   243      * package private
       
   244      */
       
   245     DerValue(DerInputBuffer in) throws IOException {
       
   246         // XXX must also parse BER-encoded constructed
       
   247         // values such as sequences, sets...
       
   248 
       
   249         tag = (byte)in.read();
       
   250         byte lenByte = (byte)in.read();
       
   251         length = DerInputStream.getLength((lenByte & 0xff), in);
       
   252         if (length == -1) {  // indefinite length encoding found
       
   253             DerInputBuffer inbuf = in.dup();
       
   254             int readLen = inbuf.available();
       
   255             int offset = 2;     // for tag and length bytes
       
   256             byte[] indefData = new byte[readLen + offset];
       
   257             indefData[0] = tag;
       
   258             indefData[1] = lenByte;
       
   259             DataInputStream dis = new DataInputStream(inbuf);
       
   260             dis.readFully(indefData, offset, readLen);
       
   261             dis.close();
       
   262             DerIndefLenConverter derIn = new DerIndefLenConverter();
       
   263             inbuf = new DerInputBuffer(derIn.convert(indefData));
       
   264             if (tag != inbuf.read())
       
   265                 throw new IOException
       
   266                         ("Indefinite length encoding not supported");
       
   267             length = DerInputStream.getLength(inbuf);
       
   268             buffer = inbuf.dup();
       
   269             buffer.truncate(length);
       
   270             data = new DerInputStream(buffer);
       
   271             // indefinite form is encoded by sending a length field with a
       
   272             // length of 0. - i.e. [1000|0000].
       
   273             // the object is ended by sending two zero bytes.
       
   274             in.skip(length + offset);
       
   275         } else {
       
   276 
       
   277             buffer = in.dup();
       
   278             buffer.truncate(length);
       
   279             data = new DerInputStream(buffer);
       
   280 
       
   281             in.skip(length);
       
   282         }
       
   283     }
       
   284 
       
   285     /**
       
   286      * Get an ASN.1/DER encoded datum from a buffer.  The
       
   287      * entire buffer must hold exactly one datum, including
       
   288      * its tag and length.
       
   289      *
       
   290      * @param buf buffer holding a single DER-encoded datum.
       
   291      */
       
   292     public DerValue(byte[] buf) throws IOException {
       
   293         data = init(true, new ByteArrayInputStream(buf));
       
   294     }
       
   295 
       
   296     /**
       
   297      * Get an ASN.1/DER encoded datum from part of a buffer.
       
   298      * That part of the buffer must hold exactly one datum, including
       
   299      * its tag and length.
       
   300      *
       
   301      * @param buf the buffer
       
   302      * @param offset start point of the single DER-encoded dataum
       
   303      * @param length how many bytes are in the encoded datum
       
   304      */
       
   305     public DerValue(byte[] buf, int offset, int len) throws IOException {
       
   306         data = init(true, new ByteArrayInputStream(buf, offset, len));
       
   307     }
       
   308 
       
   309     /**
       
   310      * Get an ASN1/DER encoded datum from an input stream.  The
       
   311      * stream may have additional data following the encoded datum.
       
   312      * In case of indefinite length encoded datum, the input stream
       
   313      * must hold only one datum.
       
   314      *
       
   315      * @param in the input stream holding a single DER datum,
       
   316      *  which may be followed by additional data
       
   317      */
       
   318     public DerValue(InputStream in) throws IOException {
       
   319         data = init(false, in);
       
   320     }
       
   321 
       
   322     private DerInputStream init(byte stringTag, String value) throws IOException {
       
   323         String enc = null;
       
   324 
       
   325         tag = stringTag;
       
   326 
       
   327         switch (stringTag) {
       
   328         case tag_PrintableString:
       
   329         case tag_IA5String:
       
   330         case tag_GeneralString:
       
   331             enc = "ASCII";
       
   332             break;
       
   333         case tag_T61String:
       
   334             enc = "ISO-8859-1";
       
   335             break;
       
   336         case tag_BMPString:
       
   337             enc = "UnicodeBigUnmarked";
       
   338             break;
       
   339         case tag_UTF8String:
       
   340             enc = "UTF8";
       
   341             break;
       
   342             // TBD: Need encoder for UniversalString before it can
       
   343             // be handled.
       
   344         default:
       
   345             throw new IllegalArgumentException("Unsupported DER string type");
       
   346         }
       
   347 
       
   348         byte[] buf = value.getBytes(enc);
       
   349         length = buf.length;
       
   350         buffer = new DerInputBuffer(buf);
       
   351         DerInputStream result = new DerInputStream(buffer);
       
   352         result.mark(Integer.MAX_VALUE);
       
   353         return result;
       
   354     }
       
   355 
       
   356     /*
       
   357      * helper routine
       
   358      */
       
   359     private DerInputStream init(boolean fullyBuffered, InputStream in)
       
   360             throws IOException {
       
   361 
       
   362         tag = (byte)in.read();
       
   363         byte lenByte = (byte)in.read();
       
   364         length = DerInputStream.getLength((lenByte & 0xff), in);
       
   365         if (length == -1) { // indefinite length encoding found
       
   366             int readLen = in.available();
       
   367             int offset = 2;     // for tag and length bytes
       
   368             byte[] indefData = new byte[readLen + offset];
       
   369             indefData[0] = tag;
       
   370             indefData[1] = lenByte;
       
   371             DataInputStream dis = new DataInputStream(in);
       
   372             dis.readFully(indefData, offset, readLen);
       
   373             dis.close();
       
   374             DerIndefLenConverter derIn = new DerIndefLenConverter();
       
   375             in = new ByteArrayInputStream(derIn.convert(indefData));
       
   376             if (tag != in.read())
       
   377                 throw new IOException
       
   378                         ("Indefinite length encoding not supported");
       
   379             length = DerInputStream.getLength(in);
       
   380         }
       
   381         if (length == 0)
       
   382             return null;
       
   383 
       
   384         if (fullyBuffered && in.available() != length)
       
   385             throw new IOException("extra data given to DerValue constructor");
       
   386 
       
   387         byte[] bytes = new byte[length];
       
   388 
       
   389         // n.b. readFully not needed in normal fullyBuffered case
       
   390         DataInputStream dis = new DataInputStream(in);
       
   391 
       
   392         dis.readFully(bytes);
       
   393         buffer = new DerInputBuffer(bytes);
       
   394         return new DerInputStream(buffer);
       
   395     }
       
   396 
       
   397     /**
       
   398      * Encode an ASN1/DER encoded datum onto a DER output stream.
       
   399      */
       
   400     public void encode(DerOutputStream out)
       
   401     throws IOException {
       
   402         out.write(tag);
       
   403         out.putLength(length);
       
   404         // XXX yeech, excess copies ... DerInputBuffer.write(OutStream)
       
   405         if (length > 0) {
       
   406             byte[] value = new byte[length];
       
   407             // always synchronized on data
       
   408             synchronized (data) {
       
   409                 buffer.reset();
       
   410                 if (buffer.read(value) != length) {
       
   411                     throw new IOException("short DER value read (encode)");
       
   412                 }
       
   413                 out.write(value);
       
   414             }
       
   415         }
       
   416     }
       
   417 
       
   418     public final DerInputStream getData() {
       
   419         return data;
       
   420     }
       
   421 
       
   422     public final byte getTag() {
       
   423         return tag;
       
   424     }
       
   425 
       
   426     /**
       
   427      * Returns an ASN.1 BOOLEAN
       
   428      *
       
   429      * @return the boolean held in this DER value
       
   430      */
       
   431     public boolean getBoolean() throws IOException {
       
   432         if (tag != tag_Boolean) {
       
   433             throw new IOException("DerValue.getBoolean, not a BOOLEAN " + tag);
       
   434         }
       
   435         if (length != 1) {
       
   436             throw new IOException("DerValue.getBoolean, invalid length "
       
   437                                         + length);
       
   438         }
       
   439         if (buffer.read() != 0) {
       
   440             return true;
       
   441         }
       
   442         return false;
       
   443     }
       
   444 
       
   445     /**
       
   446      * Returns an ASN.1 OBJECT IDENTIFIER.
       
   447      *
       
   448      * @return the OID held in this DER value
       
   449      */
       
   450     public ObjectIdentifier getOID() throws IOException {
       
   451         if (tag != tag_ObjectId)
       
   452             throw new IOException("DerValue.getOID, not an OID " + tag);
       
   453         return new ObjectIdentifier(buffer);
       
   454     }
       
   455 
       
   456     private byte[] append(byte[] a, byte[] b) {
       
   457         if (a == null)
       
   458             return b;
       
   459 
       
   460         byte[] ret = new byte[a.length + b.length];
       
   461         System.arraycopy(a, 0, ret, 0, a.length);
       
   462         System.arraycopy(b, 0, ret, a.length, b.length);
       
   463 
       
   464         return ret;
       
   465     }
       
   466 
       
   467     /**
       
   468      * Returns an ASN.1 OCTET STRING
       
   469      *
       
   470      * @return the octet string held in this DER value
       
   471      */
       
   472     public byte[] getOctetString() throws IOException {
       
   473         byte[] bytes;
       
   474 
       
   475         if (tag != tag_OctetString && !isConstructed(tag_OctetString)) {
       
   476             throw new IOException(
       
   477                 "DerValue.getOctetString, not an Octet String: " + tag);
       
   478         }
       
   479         bytes = new byte[length];
       
   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 }