< prev index next >

src/java.base/share/classes/sun/security/util/DerValue.java

Print this page


   1 /*
   2  * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any


 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, 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.getDefiniteLength(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 len 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, 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.getDefiniteLength(in);
 380         }
 381 
 382         if (fullyBuffered && in.available() != length)
 383             throw new IOException("extra data given to DerValue constructor");
 384 
 385         byte[] bytes = IOUtils.readFully(in, length, true);
 386 
 387         buffer = new DerInputBuffer(bytes);
 388         return new DerInputStream(buffer);
 389     }
 390 
 391     /**
 392      * Encode an ASN1/DER encoded datum onto a DER output stream.
 393      */
 394     public void encode(DerOutputStream out)
 395     throws IOException {
 396         out.write(tag);
 397         out.putLength(length);
 398         // XXX yeech, excess copies ... DerInputBuffer.write(OutStream)
 399         if (length > 0) {
 400             byte[] value = new byte[length];
 401             // always synchronized on data
 402             synchronized (data) {
 403                 buffer.reset();
 404                 if (buffer.read(value) != length) {
 405                     throw new IOException("short DER value read (encode)");
 406                 }
 407                 out.write(value);


 462      * Returns an ASN.1 OCTET STRING
 463      *
 464      * @return the octet string held in this DER value
 465      */
 466     public byte[] getOctetString() throws IOException {
 467         byte[] bytes;
 468 
 469         if (tag != tag_OctetString && !isConstructed(tag_OctetString)) {
 470             throw new IOException(
 471                 "DerValue.getOctetString, not an Octet String: " + tag);
 472         }
 473         bytes = new byte[length];
 474         // Note: do not tempt to call buffer.read(bytes) at all. There's a
 475         // known bug that it returns -1 instead of 0.
 476         if (length == 0) {
 477             return bytes;
 478         }
 479         if (buffer.read(bytes) != length)
 480             throw new IOException("short read on DerValue buffer");
 481         if (isConstructed()) {
 482             DerInputStream in = new DerInputStream(bytes);

 483             bytes = null;
 484             while (in.available() != 0) {
 485                 bytes = append(bytes, in.getOctetString());
 486             }
 487         }
 488         return bytes;
 489     }
 490 
 491     /**
 492      * Returns an ASN.1 INTEGER value as an integer.
 493      *
 494      * @return the integer held in this DER value.
 495      */
 496     public int getInteger() throws IOException {
 497         if (tag != tag_Integer) {
 498             throw new IOException("DerValue.getInteger, not an int " + tag);
 499         }
 500         return buffer.getInteger(data.available());
 501     }
 502 


   1 /**
   2  * Copyright (c) 1996, 2017, 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


 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     // Creates a DerValue from a tag and some DER-encoded data w/ additional
 229     // arg to control whether DER checks are enforced.
 230     DerValue(byte tag, byte[] data, boolean allowBER) {
 231         this.tag = tag;
 232         buffer = new DerInputBuffer(data.clone(), allowBER);
 233         length = data.length;
 234         this.data = new DerInputStream(buffer);
 235         this.data.mark(Integer.MAX_VALUE);
 236     }
 237 
 238     /**
 239      * Creates a DerValue from a tag and some DER-encoded data.
 240      *
 241      * @param tag the DER type tag
 242      * @param data the DER-encoded data
 243      */
 244     public DerValue(byte tag, byte[] data) {
 245         this(tag, data, true);




 246     }
 247 
 248     /*
 249      * package private
 250      */
 251     DerValue(DerInputBuffer in) throws IOException {
 252 
 253         // XXX must also parse BER-encoded constructed
 254         // values such as sequences, sets...

 255         tag = (byte)in.read();
 256         byte lenByte = (byte)in.read();
 257         length = DerInputStream.getLength(lenByte, in);
 258         if (length == -1) {  // indefinite length encoding found
 259             DerInputBuffer inbuf = in.dup();
 260             int readLen = inbuf.available();
 261             int offset = 2;     // for tag and length bytes
 262             byte[] indefData = new byte[readLen + offset];
 263             indefData[0] = tag;
 264             indefData[1] = lenByte;
 265             DataInputStream dis = new DataInputStream(inbuf);
 266             dis.readFully(indefData, offset, readLen);
 267             dis.close();
 268             DerIndefLenConverter derIn = new DerIndefLenConverter();
 269             inbuf = new DerInputBuffer(derIn.convert(indefData), in.allowBER);
 270             if (tag != inbuf.read())
 271                 throw new IOException
 272                         ("Indefinite length encoding not supported");
 273             length = DerInputStream.getDefiniteLength(inbuf);
 274             buffer = inbuf.dup();
 275             buffer.truncate(length);
 276             data = new DerInputStream(buffer);
 277             // indefinite form is encoded by sending a length field with a
 278             // length of 0. - i.e. [1000|0000].
 279             // the object is ended by sending two zero bytes.
 280             in.skip(length + offset);
 281         } else {
 282 
 283             buffer = in.dup();
 284             buffer.truncate(length);
 285             data = new DerInputStream(buffer);
 286 
 287             in.skip(length);
 288         }
 289     }
 290 
 291     // Get an ASN.1/DER encoded datum from a buffer w/ additional
 292     // arg to control whether DER checks are enforced.
 293     DerValue(byte[] buf, boolean allowBER) throws IOException {
 294         data = init(true, new ByteArrayInputStream(buf), allowBER);
 295     }
 296 
 297     /**
 298      * Get an ASN.1/DER encoded datum from a buffer.  The
 299      * entire buffer must hold exactly one datum, including
 300      * its tag and length.
 301      *
 302      * @param buf buffer holding a single DER-encoded datum.
 303      */
 304     public DerValue(byte[] buf) throws IOException {
 305         this(buf, true);
 306     }
 307 
 308     // Get an ASN.1/DER encoded datum from part of a buffer w/ additional
 309     // arg to control whether DER checks are enforced.
 310     DerValue(byte[] buf, int offset, int len, boolean allowBER)
 311         throws IOException {
 312         data = init(true, new ByteArrayInputStream(buf, offset, len), allowBER);
 313     }
 314 
 315     /**
 316      * Get an ASN.1/DER encoded datum from part of a buffer.
 317      * That part of the buffer must hold exactly one datum, including
 318      * its tag and length.
 319      *
 320      * @param buf the buffer
 321      * @param offset start point of the single DER-encoded dataum
 322      * @param len how many bytes are in the encoded datum
 323      */
 324     public DerValue(byte[] buf, int offset, int len) throws IOException {
 325         this(buf, offset, len, true);
 326     }
 327 
 328     // Get an ASN1/DER encoded datum from an input stream w/ additional
 329     // arg to control whether DER checks are enforced.
 330     DerValue(InputStream in, boolean allowBER) throws IOException {
 331         data = init(false, in, allowBER);
 332     }
 333 
 334     /**
 335      * Get an ASN1/DER encoded datum from an input stream.  The
 336      * stream may have additional data following the encoded datum.
 337      * In case of indefinite length encoded datum, the input stream
 338      * must hold only one datum.
 339      *
 340      * @param in the input stream holding a single DER datum,
 341      *  which may be followed by additional data
 342      */
 343     public DerValue(InputStream in) throws IOException {
 344         this(in, true);
 345     }
 346 
 347     private DerInputStream init(byte stringTag, String value)
 348         throws IOException {
 349         String enc = null;
 350 
 351         tag = stringTag;
 352 
 353         switch (stringTag) {
 354         case tag_PrintableString:
 355         case tag_IA5String:
 356         case tag_GeneralString:
 357             enc = "ASCII";
 358             break;
 359         case tag_T61String:
 360             enc = "ISO-8859-1";
 361             break;
 362         case tag_BMPString:
 363             enc = "UnicodeBigUnmarked";
 364             break;
 365         case tag_UTF8String:
 366             enc = "UTF8";
 367             break;
 368             // TBD: Need encoder for UniversalString before it can
 369             // be handled.
 370         default:
 371             throw new IllegalArgumentException("Unsupported DER string type");
 372         }
 373 
 374         byte[] buf = value.getBytes(enc);
 375         length = buf.length;
 376         buffer = new DerInputBuffer(buf, true);
 377         DerInputStream result = new DerInputStream(buffer);
 378         result.mark(Integer.MAX_VALUE);
 379         return result;
 380     }
 381 
 382     /*
 383      * helper routine
 384      */
 385     private DerInputStream init(boolean fullyBuffered, InputStream in,
 386         boolean allowBER) throws IOException {
 387 
 388         tag = (byte)in.read();
 389         byte lenByte = (byte)in.read();
 390         length = DerInputStream.getLength(lenByte, in);
 391         if (length == -1) { // indefinite length encoding found
 392             int readLen = in.available();
 393             int offset = 2;     // for tag and length bytes
 394             byte[] indefData = new byte[readLen + offset];
 395             indefData[0] = tag;
 396             indefData[1] = lenByte;
 397             DataInputStream dis = new DataInputStream(in);
 398             dis.readFully(indefData, offset, readLen);
 399             dis.close();
 400             DerIndefLenConverter derIn = new DerIndefLenConverter();
 401             in = new ByteArrayInputStream(derIn.convert(indefData));
 402             if (tag != in.read())
 403                 throw new IOException
 404                         ("Indefinite length encoding not supported");
 405             length = DerInputStream.getDefiniteLength(in);
 406         }
 407 
 408         if (fullyBuffered && in.available() != length)
 409             throw new IOException("extra data given to DerValue constructor");
 410 
 411         byte[] bytes = IOUtils.readFully(in, length, true);
 412 
 413         buffer = new DerInputBuffer(bytes, allowBER);
 414         return new DerInputStream(buffer);
 415     }
 416 
 417     /**
 418      * Encode an ASN1/DER encoded datum onto a DER output stream.
 419      */
 420     public void encode(DerOutputStream out)
 421     throws IOException {
 422         out.write(tag);
 423         out.putLength(length);
 424         // XXX yeech, excess copies ... DerInputBuffer.write(OutStream)
 425         if (length > 0) {
 426             byte[] value = new byte[length];
 427             // always synchronized on data
 428             synchronized (data) {
 429                 buffer.reset();
 430                 if (buffer.read(value) != length) {
 431                     throw new IOException("short DER value read (encode)");
 432                 }
 433                 out.write(value);


 488      * Returns an ASN.1 OCTET STRING
 489      *
 490      * @return the octet string held in this DER value
 491      */
 492     public byte[] getOctetString() throws IOException {
 493         byte[] bytes;
 494 
 495         if (tag != tag_OctetString && !isConstructed(tag_OctetString)) {
 496             throw new IOException(
 497                 "DerValue.getOctetString, not an Octet String: " + tag);
 498         }
 499         bytes = new byte[length];
 500         // Note: do not tempt to call buffer.read(bytes) at all. There's a
 501         // known bug that it returns -1 instead of 0.
 502         if (length == 0) {
 503             return bytes;
 504         }
 505         if (buffer.read(bytes) != length)
 506             throw new IOException("short read on DerValue buffer");
 507         if (isConstructed()) {
 508             DerInputStream in = new DerInputStream(bytes, 0, bytes.length,
 509                 buffer.allowBER);
 510             bytes = null;
 511             while (in.available() != 0) {
 512                 bytes = append(bytes, in.getOctetString());
 513             }
 514         }
 515         return bytes;
 516     }
 517 
 518     /**
 519      * Returns an ASN.1 INTEGER value as an integer.
 520      *
 521      * @return the integer held in this DER value.
 522      */
 523     public int getInteger() throws IOException {
 524         if (tag != tag_Integer) {
 525             throw new IOException("DerValue.getInteger, not an int " + tag);
 526         }
 527         return buffer.getInteger(data.available());
 528     }
 529 


< prev index next >