1 /* 2 * Copyright (c) 1996, 2010, 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.ByteArrayOutputStream; 29 import java.io.OutputStream; 30 import java.io.IOException; 31 import java.text.SimpleDateFormat; 32 import java.util.Date; 33 import java.util.TimeZone; 34 import java.util.Comparator; 35 import java.util.Arrays; 36 import java.math.BigInteger; 37 import java.util.Locale; 38 39 40 /** 41 * Output stream marshaling DER-encoded data. This is eventually provided 42 * in the form of a byte array; there is no advance limit on the size of 43 * that byte array. 44 * 45 * <P>At this time, this class supports only a subset of the types of 46 * DER data encodings which are defined. That subset is sufficient for 47 * generating most X.509 certificates. 48 * 49 * 50 * @author David Brownell 51 * @author Amit Kapoor 52 * @author Hemma Prafullchandra 53 */ 54 public class DerOutputStream 55 extends ByteArrayOutputStream implements DerEncoder { 56 /** 57 * Construct an DER output stream. 58 * 59 * @param size how large a buffer to preallocate. 60 */ DerOutputStream(int size)61 public DerOutputStream(int size) { super(size); } 62 63 /** 64 * Construct an DER output stream. 65 */ DerOutputStream()66 public DerOutputStream() { } 67 68 /** 69 * Writes tagged, pre-marshaled data. This calcuates and encodes 70 * the length, so that the output data is the standard triple of 71 * { tag, length, data } used by all DER values. 72 * 73 * @param tag the DER value tag for the data, such as 74 * <em>DerValue.tag_Sequence</em> 75 * @param buf buffered data, which must be DER-encoded 76 */ write(byte tag, byte[] buf)77 public void write(byte tag, byte[] buf) throws IOException { 78 write(tag); 79 putLength(buf.length); 80 write(buf, 0, buf.length); 81 } 82 83 /** 84 * Writes tagged data using buffer-to-buffer copy. As above, 85 * this writes a standard DER record. This is often used when 86 * efficiently encapsulating values in sequences. 87 * 88 * @param tag the DER value tag for the data, such as 89 * <em>DerValue.tag_Sequence</em> 90 * @param out buffered data 91 */ write(byte tag, DerOutputStream out)92 public void write(byte tag, DerOutputStream out) throws IOException { 93 write(tag); 94 putLength(out.count); 95 write(out.buf, 0, out.count); 96 } 97 98 /** 99 * Writes implicitly tagged data using buffer-to-buffer copy. As above, 100 * this writes a standard DER record. This is often used when 101 * efficiently encapsulating implicitly tagged values. 102 * 103 * @param tag the DER value of the context-specific tag that replaces 104 * original tag of the value in the output, such as in 105 * <pre> 106 * <em> <field> [N] IMPLICIT <type></em> 107 * </pre> 108 * For example, <em>FooLength [1] IMPLICIT INTEGER</em>, with value=4; 109 * would be encoded as "81 01 04" whereas in explicit 110 * tagging it would be encoded as "A1 03 02 01 04". 111 * Notice that the tag is A1 and not 81, this is because with 112 * explicit tagging the form is always constructed. 113 * @param value original value being implicitly tagged 114 */ writeImplicit(byte tag, DerOutputStream value)115 public void writeImplicit(byte tag, DerOutputStream value) 116 throws IOException { 117 write(tag); 118 write(value.buf, 1, value.count-1); 119 } 120 121 /** 122 * Marshals pre-encoded DER value onto the output stream. 123 */ putDerValue(DerValue val)124 public void putDerValue(DerValue val) throws IOException { 125 val.encode(this); 126 } 127 128 /* 129 * PRIMITIVES -- these are "universal" ASN.1 simple types. 130 * 131 * BOOLEAN, INTEGER, BIT STRING, OCTET STRING, NULL 132 * OBJECT IDENTIFIER, SEQUENCE(OF), SET(OF) 133 * PrintableString, T61String, IA5String, UTCTime 134 */ 135 136 /** 137 * Marshals a DER boolean on the output stream. 138 */ putBoolean(boolean val)139 public void putBoolean(boolean val) throws IOException { 140 write(DerValue.tag_Boolean); 141 putLength(1); 142 if (val) { 143 write(0xff); 144 } else { 145 write(0); 146 } 147 } 148 149 /** 150 * Marshals a DER enumerated on the output stream. 151 * @param i the enumerated value. 152 */ putEnumerated(int i)153 public void putEnumerated(int i) throws IOException { 154 write(DerValue.tag_Enumerated); 155 putIntegerContents(i); 156 } 157 158 /** 159 * Marshals a DER integer on the output stream. 160 * 161 * @param i the integer in the form of a BigInteger. 162 */ putInteger(BigInteger i)163 public void putInteger(BigInteger i) throws IOException { 164 write(DerValue.tag_Integer); 165 byte[] buf = i.toByteArray(); // least number of bytes 166 putLength(buf.length); 167 write(buf, 0, buf.length); 168 } 169 170 /** 171 * Marshals a DER integer on the output stream. 172 * @param i the integer in the form of an Integer. 173 */ putInteger(Integer i)174 public void putInteger(Integer i) throws IOException { 175 putInteger(i.intValue()); 176 } 177 178 /** 179 * Marshals a DER integer on the output stream. 180 * @param i the integer. 181 */ putInteger(int i)182 public void putInteger(int i) throws IOException { 183 write(DerValue.tag_Integer); 184 putIntegerContents(i); 185 } 186 putIntegerContents(int i)187 private void putIntegerContents(int i) throws IOException { 188 189 byte[] bytes = new byte[4]; 190 int start = 0; 191 192 // Obtain the four bytes of the int 193 194 bytes[3] = (byte) (i & 0xff); 195 bytes[2] = (byte)((i & 0xff00) >>> 8); 196 bytes[1] = (byte)((i & 0xff0000) >>> 16); 197 bytes[0] = (byte)((i & 0xff000000) >>> 24); 198 199 // Reduce them to the least number of bytes needed to 200 // represent this int 201 202 if (bytes[0] == (byte)0xff) { 203 204 // Eliminate redundant 0xff 205 206 for (int j = 0; j < 3; j++) { 207 if ((bytes[j] == (byte)0xff) && 208 ((bytes[j+1] & 0x80) == 0x80)) 209 start++; 210 else 211 break; 212 } 213 } else if (bytes[0] == 0x00) { 214 215 // Eliminate redundant 0x00 216 217 for (int j = 0; j < 3; j++) { 218 if ((bytes[j] == 0x00) && 219 ((bytes[j+1] & 0x80) == 0)) 220 start++; 221 else 222 break; 223 } 224 } 225 226 putLength(4 - start); 227 for (int k = start; k < 4; k++) 228 write(bytes[k]); 229 } 230 231 /** 232 * Marshals a DER bit string on the output stream. The bit 233 * string must be byte-aligned. 234 * 235 * @param bits the bit string, MSB first 236 */ putBitString(byte[] bits)237 public void putBitString(byte[] bits) throws IOException { 238 write(DerValue.tag_BitString); 239 putLength(bits.length + 1); 240 write(0); // all of last octet is used 241 write(bits); 242 } 243 244 /** 245 * Marshals a DER bit string on the output stream. 246 * The bit strings need not be byte-aligned. 247 * 248 * @param bits the bit string, MSB first 249 */ putUnalignedBitString(BitArray ba)250 public void putUnalignedBitString(BitArray ba) throws IOException { 251 byte[] bits = ba.toByteArray(); 252 253 write(DerValue.tag_BitString); 254 putLength(bits.length + 1); 255 write(bits.length*8 - ba.length()); // excess bits in last octet 256 write(bits); 257 } 258 259 /** 260 * Marshals a truncated DER bit string on the output stream. 261 * The bit strings need not be byte-aligned. 262 * 263 * @param bits the bit string, MSB first 264 */ putTruncatedUnalignedBitString(BitArray ba)265 public void putTruncatedUnalignedBitString(BitArray ba) throws IOException { 266 putUnalignedBitString(ba.truncate()); 267 } 268 269 /** 270 * DER-encodes an ASN.1 OCTET STRING value on the output stream. 271 * 272 * @param octets the octet string 273 */ putOctetString(byte[] octets)274 public void putOctetString(byte[] octets) throws IOException { 275 write(DerValue.tag_OctetString, octets); 276 } 277 278 /** 279 * Marshals a DER "null" value on the output stream. These are 280 * often used to indicate optional values which have been omitted. 281 */ putNull()282 public void putNull() throws IOException { 283 write(DerValue.tag_Null); 284 putLength(0); 285 } 286 287 /** 288 * Marshals an object identifier (OID) on the output stream. 289 * Corresponds to the ASN.1 "OBJECT IDENTIFIER" construct. 290 */ putOID(ObjectIdentifier oid)291 public void putOID(ObjectIdentifier oid) throws IOException { 292 oid.encode(this); 293 } 294 295 /** 296 * Marshals a sequence on the output stream. This supports both 297 * the ASN.1 "SEQUENCE" (zero to N values) and "SEQUENCE OF" 298 * (one to N values) constructs. 299 */ putSequence(DerValue[] seq)300 public void putSequence(DerValue[] seq) throws IOException { 301 DerOutputStream bytes = new DerOutputStream(); 302 int i; 303 304 for (i = 0; i < seq.length; i++) 305 seq[i].encode(bytes); 306 307 write(DerValue.tag_Sequence, bytes); 308 } 309 310 /** 311 * Marshals the contents of a set on the output stream without 312 * ordering the elements. Ok for BER encoding, but not for DER 313 * encoding. 314 * 315 * For DER encoding, use orderedPutSet() or orderedPutSetOf(). 316 */ putSet(DerValue[] set)317 public void putSet(DerValue[] set) throws IOException { 318 DerOutputStream bytes = new DerOutputStream(); 319 int i; 320 321 for (i = 0; i < set.length; i++) 322 set[i].encode(bytes); 323 324 write(DerValue.tag_Set, bytes); 325 } 326 327 /** 328 * Marshals the contents of a set on the output stream. Sets 329 * are semantically unordered, but DER requires that encodings of 330 * set elements be sorted into ascending lexicographical order 331 * before being output. Hence sets with the same tags and 332 * elements have the same DER encoding. 333 * 334 * This method supports the ASN.1 "SET OF" construct, but not 335 * "SET", which uses a different order. 336 */ putOrderedSetOf(byte tag, DerEncoder[] set)337 public void putOrderedSetOf(byte tag, DerEncoder[] set) throws IOException { 338 putOrderedSet(tag, set, lexOrder); 339 } 340 341 /** 342 * Marshals the contents of a set on the output stream. Sets 343 * are semantically unordered, but DER requires that encodings of 344 * set elements be sorted into ascending tag order 345 * before being output. Hence sets with the same tags and 346 * elements have the same DER encoding. 347 * 348 * This method supports the ASN.1 "SET" construct, but not 349 * "SET OF", which uses a different order. 350 */ putOrderedSet(byte tag, DerEncoder[] set)351 public void putOrderedSet(byte tag, DerEncoder[] set) throws IOException { 352 putOrderedSet(tag, set, tagOrder); 353 } 354 355 /** 356 * Lexicographical order comparison on byte arrays, for ordering 357 * elements of a SET OF objects in DER encoding. 358 */ 359 private static ByteArrayLexOrder lexOrder = new ByteArrayLexOrder(); 360 361 /** 362 * Tag order comparison on byte arrays, for ordering elements of 363 * SET objects in DER encoding. 364 */ 365 private static ByteArrayTagOrder tagOrder = new ByteArrayTagOrder(); 366 367 /** 368 * Marshals a the contents of a set on the output stream with the 369 * encodings of its sorted in increasing order. 370 * 371 * @param order the order to use when sorting encodings of components. 372 */ putOrderedSet(byte tag, DerEncoder[] set, Comparator<byte[]> order)373 private void putOrderedSet(byte tag, DerEncoder[] set, 374 Comparator<byte[]> order) throws IOException { 375 DerOutputStream[] streams = new DerOutputStream[set.length]; 376 377 for (int i = 0; i < set.length; i++) { 378 streams[i] = new DerOutputStream(); 379 set[i].derEncode(streams[i]); 380 } 381 382 // order the element encodings 383 byte[][] bufs = new byte[streams.length][]; 384 for (int i = 0; i < streams.length; i++) { 385 bufs[i] = streams[i].toByteArray(); 386 } 387 Arrays.<byte[]>sort(bufs, order); 388 389 DerOutputStream bytes = new DerOutputStream(); 390 for (int i = 0; i < streams.length; i++) { 391 bytes.write(bufs[i]); 392 } 393 write(tag, bytes); 394 395 } 396 397 /** 398 * Marshals a string as a DER encoded UTF8String. 399 */ putUTF8String(String s)400 public void putUTF8String(String s) throws IOException { 401 writeString(s, DerValue.tag_UTF8String, "UTF8"); 402 } 403 404 /** 405 * Marshals a string as a DER encoded PrintableString. 406 */ putPrintableString(String s)407 public void putPrintableString(String s) throws IOException { 408 writeString(s, DerValue.tag_PrintableString, "ASCII"); 409 } 410 411 /** 412 * Marshals a string as a DER encoded T61String. 413 */ putT61String(String s)414 public void putT61String(String s) throws IOException { 415 /* 416 * Works for characters that are defined in both ASCII and 417 * T61. 418 */ 419 writeString(s, DerValue.tag_T61String, "ISO-8859-1"); 420 } 421 422 /** 423 * Marshals a string as a DER encoded IA5String. 424 */ putIA5String(String s)425 public void putIA5String(String s) throws IOException { 426 writeString(s, DerValue.tag_IA5String, "ASCII"); 427 } 428 429 /** 430 * Marshals a string as a DER encoded BMPString. 431 */ putBMPString(String s)432 public void putBMPString(String s) throws IOException { 433 writeString(s, DerValue.tag_BMPString, "UnicodeBigUnmarked"); 434 } 435 436 /** 437 * Marshals a string as a DER encoded GeneralString. 438 */ putGeneralString(String s)439 public void putGeneralString(String s) throws IOException { 440 writeString(s, DerValue.tag_GeneralString, "ASCII"); 441 } 442 443 /** 444 * Private helper routine for writing DER encoded string values. 445 * @param s the string to write 446 * @param stringTag one of the DER string tags that indicate which 447 * encoding should be used to write the string out. 448 * @param enc the name of the encoder that should be used corresponding 449 * to the above tag. 450 */ writeString(String s, byte stringTag, String enc)451 private void writeString(String s, byte stringTag, String enc) 452 throws IOException { 453 454 byte[] data = s.getBytes(enc); 455 write(stringTag); 456 putLength(data.length); 457 write(data); 458 } 459 460 /** 461 * Marshals a DER UTC time/date value. 462 * 463 * <P>YYMMDDhhmmss{Z|+hhmm|-hhmm} ... emits only using Zulu time 464 * and with seconds (even if seconds=0) as per RFC 3280. 465 */ putUTCTime(Date d)466 public void putUTCTime(Date d) throws IOException { 467 putTime(d, DerValue.tag_UtcTime); 468 } 469 470 /** 471 * Marshals a DER Generalized Time/date value. 472 * 473 * <P>YYYYMMDDhhmmss{Z|+hhmm|-hhmm} ... emits only using Zulu time 474 * and with seconds (even if seconds=0) as per RFC 3280. 475 */ putGeneralizedTime(Date d)476 public void putGeneralizedTime(Date d) throws IOException { 477 putTime(d, DerValue.tag_GeneralizedTime); 478 } 479 480 /** 481 * Private helper routine for marshalling a DER UTC/Generalized 482 * time/date value. If the tag specified is not that for UTC Time 483 * then it defaults to Generalized Time. 484 * @param d the date to be marshalled 485 * @param tag the tag for UTC Time or Generalized Time 486 */ putTime(Date d, byte tag)487 private void putTime(Date d, byte tag) throws IOException { 488 489 /* 490 * Format the date. 491 */ 492 493 TimeZone tz = TimeZone.getTimeZone("GMT"); 494 String pattern = null; 495 496 if (tag == DerValue.tag_UtcTime) { 497 pattern = "yyMMddHHmmss'Z'"; 498 } else { 499 tag = DerValue.tag_GeneralizedTime; 500 pattern = "yyyyMMddHHmmss'Z'"; 501 } 502 503 SimpleDateFormat sdf = new SimpleDateFormat(pattern, Locale.US); 504 sdf.setTimeZone(tz); 505 byte[] time = (sdf.format(d)).getBytes("ISO-8859-1"); 506 507 /* 508 * Write the formatted date. 509 */ 510 511 write(tag); 512 putLength(time.length); 513 write(time); 514 } 515 516 /** 517 * Put the encoding of the length in the stream. 518 * 519 * @params len the length of the attribute. 520 * @exception IOException on writing errors. 521 */ putLength(int len)522 public void putLength(int len) throws IOException { 523 if (len < 128) { 524 write((byte)len); 525 526 } else if (len < (1 << 8)) { 527 write((byte)0x081); 528 write((byte)len); 529 530 } else if (len < (1 << 16)) { 531 write((byte)0x082); 532 write((byte)(len >> 8)); 533 write((byte)len); 534 535 } else if (len < (1 << 24)) { 536 write((byte)0x083); 537 write((byte)(len >> 16)); 538 write((byte)(len >> 8)); 539 write((byte)len); 540 541 } else { 542 write((byte)0x084); 543 write((byte)(len >> 24)); 544 write((byte)(len >> 16)); 545 write((byte)(len >> 8)); 546 write((byte)len); 547 } 548 } 549 550 /** 551 * Put the tag of the attribute in the stream. 552 * 553 * @params class the tag class type, one of UNIVERSAL, CONTEXT, 554 * APPLICATION or PRIVATE 555 * @params form if true, the value is constructed, otherwise it is 556 * primitive. 557 * @params val the tag value 558 */ putTag(byte tagClass, boolean form, byte val)559 public void putTag(byte tagClass, boolean form, byte val) { 560 byte tag = (byte)(tagClass | val); 561 if (form) { 562 tag |= (byte)0x20; 563 } 564 write(tag); 565 } 566 567 /** 568 * Write the current contents of this <code>DerOutputStream</code> 569 * to an <code>OutputStream</code>. 570 * 571 * @exception IOException on output error. 572 */ derEncode(OutputStream out)573 public void derEncode(OutputStream out) throws IOException { 574 out.write(toByteArray()); 575 } 576 } 577