Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/util/DerOutputStream.java
38830 views
/*1* Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.util;2627import java.io.ByteArrayOutputStream;28import java.io.OutputStream;29import java.io.IOException;30import java.text.SimpleDateFormat;31import java.util.Date;32import java.util.TimeZone;33import java.util.Comparator;34import java.util.Arrays;35import java.math.BigInteger;36import java.util.Locale;373839/**40* Output stream marshaling DER-encoded data. This is eventually provided41* in the form of a byte array; there is no advance limit on the size of42* that byte array.43*44* <P>At this time, this class supports only a subset of the types of45* DER data encodings which are defined. That subset is sufficient for46* generating most X.509 certificates.47*48*49* @author David Brownell50* @author Amit Kapoor51* @author Hemma Prafullchandra52*/53public class DerOutputStream54extends ByteArrayOutputStream implements DerEncoder {55/**56* Construct an DER output stream.57*58* @param size how large a buffer to preallocate.59*/60public DerOutputStream(int size) { super(size); }6162/**63* Construct an DER output stream.64*/65public DerOutputStream() { }6667/**68* Writes tagged, pre-marshaled data. This calcuates and encodes69* the length, so that the output data is the standard triple of70* { tag, length, data } used by all DER values.71*72* @param tag the DER value tag for the data, such as73* <em>DerValue.tag_Sequence</em>74* @param buf buffered data, which must be DER-encoded75*/76public void write(byte tag, byte[] buf) throws IOException {77write(tag);78putLength(buf.length);79write(buf, 0, buf.length);80}8182/**83* Writes tagged data using buffer-to-buffer copy. As above,84* this writes a standard DER record. This is often used when85* efficiently encapsulating values in sequences.86*87* @param tag the DER value tag for the data, such as88* <em>DerValue.tag_Sequence</em>89* @param out buffered data90*/91public void write(byte tag, DerOutputStream out) throws IOException {92write(tag);93putLength(out.count);94write(out.buf, 0, out.count);95}9697/**98* Writes implicitly tagged data using buffer-to-buffer copy. As above,99* this writes a standard DER record. This is often used when100* efficiently encapsulating implicitly tagged values.101*102* @param tag the DER value of the context-specific tag that replaces103* original tag of the value in the output, such as in104* <pre>105* <em> <field> [N] IMPLICIT <type></em>106* </pre>107* For example, <em>FooLength [1] IMPLICIT INTEGER</em>, with value=4;108* would be encoded as "81 01 04" whereas in explicit109* tagging it would be encoded as "A1 03 02 01 04".110* Notice that the tag is A1 and not 81, this is because with111* explicit tagging the form is always constructed.112* @param value original value being implicitly tagged113*/114public void writeImplicit(byte tag, DerOutputStream value)115throws IOException {116write(tag);117write(value.buf, 1, value.count-1);118}119120/**121* Marshals pre-encoded DER value onto the output stream.122*/123public void putDerValue(DerValue val) throws IOException {124val.encode(this);125}126127/*128* PRIMITIVES -- these are "universal" ASN.1 simple types.129*130* BOOLEAN, INTEGER, BIT STRING, OCTET STRING, NULL131* OBJECT IDENTIFIER, SEQUENCE(OF), SET(OF)132* PrintableString, T61String, IA5String, UTCTime133*/134135/**136* Marshals a DER boolean on the output stream.137*/138public void putBoolean(boolean val) throws IOException {139write(DerValue.tag_Boolean);140putLength(1);141if (val) {142write(0xff);143} else {144write(0);145}146}147148/**149* Marshals a DER enumerated on the output stream.150* @param i the enumerated value.151*/152public void putEnumerated(int i) throws IOException {153write(DerValue.tag_Enumerated);154putIntegerContents(i);155}156157/**158* Marshals a DER integer on the output stream.159*160* @param i the integer in the form of a BigInteger.161*/162public void putInteger(BigInteger i) throws IOException {163write(DerValue.tag_Integer);164byte[] buf = i.toByteArray(); // least number of bytes165putLength(buf.length);166write(buf, 0, buf.length);167}168169/**170* Marshals a DER integer on the output stream.171* @param i the integer in the form of an Integer.172*/173public void putInteger(Integer i) throws IOException {174putInteger(i.intValue());175}176177/**178* Marshals a DER integer on the output stream.179* @param i the integer.180*/181public void putInteger(int i) throws IOException {182write(DerValue.tag_Integer);183putIntegerContents(i);184}185186private void putIntegerContents(int i) throws IOException {187188byte[] bytes = new byte[4];189int start = 0;190191// Obtain the four bytes of the int192193bytes[3] = (byte) (i & 0xff);194bytes[2] = (byte)((i & 0xff00) >>> 8);195bytes[1] = (byte)((i & 0xff0000) >>> 16);196bytes[0] = (byte)((i & 0xff000000) >>> 24);197198// Reduce them to the least number of bytes needed to199// represent this int200201if (bytes[0] == (byte)0xff) {202203// Eliminate redundant 0xff204205for (int j = 0; j < 3; j++) {206if ((bytes[j] == (byte)0xff) &&207((bytes[j+1] & 0x80) == 0x80))208start++;209else210break;211}212} else if (bytes[0] == 0x00) {213214// Eliminate redundant 0x00215216for (int j = 0; j < 3; j++) {217if ((bytes[j] == 0x00) &&218((bytes[j+1] & 0x80) == 0))219start++;220else221break;222}223}224225putLength(4 - start);226for (int k = start; k < 4; k++)227write(bytes[k]);228}229230/**231* Marshals a DER bit string on the output stream. The bit232* string must be byte-aligned.233*234* @param bits the bit string, MSB first235*/236public void putBitString(byte[] bits) throws IOException {237write(DerValue.tag_BitString);238putLength(bits.length + 1);239write(0); // all of last octet is used240write(bits);241}242243/**244* Marshals a DER bit string on the output stream.245* The bit strings need not be byte-aligned.246*247* @param bits the bit string, MSB first248*/249public void putUnalignedBitString(BitArray ba) throws IOException {250byte[] bits = ba.toByteArray();251252write(DerValue.tag_BitString);253putLength(bits.length + 1);254write(bits.length*8 - ba.length()); // excess bits in last octet255write(bits);256}257258/**259* Marshals a truncated DER bit string on the output stream.260* The bit strings need not be byte-aligned.261*262* @param bits the bit string, MSB first263*/264public void putTruncatedUnalignedBitString(BitArray ba) throws IOException {265putUnalignedBitString(ba.truncate());266}267268/**269* DER-encodes an ASN.1 OCTET STRING value on the output stream.270*271* @param octets the octet string272*/273public void putOctetString(byte[] octets) throws IOException {274write(DerValue.tag_OctetString, octets);275}276277/**278* Marshals a DER "null" value on the output stream. These are279* often used to indicate optional values which have been omitted.280*/281public void putNull() throws IOException {282write(DerValue.tag_Null);283putLength(0);284}285286/**287* Marshals an object identifier (OID) on the output stream.288* Corresponds to the ASN.1 "OBJECT IDENTIFIER" construct.289*/290public void putOID(ObjectIdentifier oid) throws IOException {291oid.encode(this);292}293294/**295* Marshals a sequence on the output stream. This supports both296* the ASN.1 "SEQUENCE" (zero to N values) and "SEQUENCE OF"297* (one to N values) constructs.298*/299public void putSequence(DerValue[] seq) throws IOException {300DerOutputStream bytes = new DerOutputStream();301int i;302303for (i = 0; i < seq.length; i++)304seq[i].encode(bytes);305306write(DerValue.tag_Sequence, bytes);307}308309/**310* Marshals the contents of a set on the output stream without311* ordering the elements. Ok for BER encoding, but not for DER312* encoding.313*314* For DER encoding, use orderedPutSet() or orderedPutSetOf().315*/316public void putSet(DerValue[] set) throws IOException {317DerOutputStream bytes = new DerOutputStream();318int i;319320for (i = 0; i < set.length; i++)321set[i].encode(bytes);322323write(DerValue.tag_Set, bytes);324}325326/**327* Marshals the contents of a set on the output stream. Sets328* are semantically unordered, but DER requires that encodings of329* set elements be sorted into ascending lexicographical order330* before being output. Hence sets with the same tags and331* elements have the same DER encoding.332*333* This method supports the ASN.1 "SET OF" construct, but not334* "SET", which uses a different order.335*/336public void putOrderedSetOf(byte tag, DerEncoder[] set) throws IOException {337putOrderedSet(tag, set, lexOrder);338}339340/**341* Marshals the contents of a set on the output stream. Sets342* are semantically unordered, but DER requires that encodings of343* set elements be sorted into ascending tag order344* before being output. Hence sets with the same tags and345* elements have the same DER encoding.346*347* This method supports the ASN.1 "SET" construct, but not348* "SET OF", which uses a different order.349*/350public void putOrderedSet(byte tag, DerEncoder[] set) throws IOException {351putOrderedSet(tag, set, tagOrder);352}353354/**355* Lexicographical order comparison on byte arrays, for ordering356* elements of a SET OF objects in DER encoding.357*/358private static ByteArrayLexOrder lexOrder = new ByteArrayLexOrder();359360/**361* Tag order comparison on byte arrays, for ordering elements of362* SET objects in DER encoding.363*/364private static ByteArrayTagOrder tagOrder = new ByteArrayTagOrder();365366/**367* Marshals a the contents of a set on the output stream with the368* encodings of its sorted in increasing order.369*370* @param order the order to use when sorting encodings of components.371*/372private void putOrderedSet(byte tag, DerEncoder[] set,373Comparator<byte[]> order) throws IOException {374DerOutputStream[] streams = new DerOutputStream[set.length];375376for (int i = 0; i < set.length; i++) {377streams[i] = new DerOutputStream();378set[i].derEncode(streams[i]);379}380381// order the element encodings382byte[][] bufs = new byte[streams.length][];383for (int i = 0; i < streams.length; i++) {384bufs[i] = streams[i].toByteArray();385}386Arrays.<byte[]>sort(bufs, order);387388DerOutputStream bytes = new DerOutputStream();389for (int i = 0; i < streams.length; i++) {390bytes.write(bufs[i]);391}392write(tag, bytes);393394}395396/**397* Marshals a string as a DER encoded UTF8String.398*/399public void putUTF8String(String s) throws IOException {400writeString(s, DerValue.tag_UTF8String, "UTF8");401}402403/**404* Marshals a string as a DER encoded PrintableString.405*/406public void putPrintableString(String s) throws IOException {407writeString(s, DerValue.tag_PrintableString, "ASCII");408}409410/**411* Marshals a string as a DER encoded T61String.412*/413public void putT61String(String s) throws IOException {414/*415* Works for characters that are defined in both ASCII and416* T61.417*/418writeString(s, DerValue.tag_T61String, "ISO-8859-1");419}420421/**422* Marshals a string as a DER encoded IA5String.423*/424public void putIA5String(String s) throws IOException {425writeString(s, DerValue.tag_IA5String, "ASCII");426}427428/**429* Marshals a string as a DER encoded BMPString.430*/431public void putBMPString(String s) throws IOException {432writeString(s, DerValue.tag_BMPString, "UnicodeBigUnmarked");433}434435/**436* Marshals a string as a DER encoded GeneralString.437*/438public void putGeneralString(String s) throws IOException {439writeString(s, DerValue.tag_GeneralString, "ASCII");440}441442/**443* Private helper routine for writing DER encoded string values.444* @param s the string to write445* @param stringTag one of the DER string tags that indicate which446* encoding should be used to write the string out.447* @param enc the name of the encoder that should be used corresponding448* to the above tag.449*/450private void writeString(String s, byte stringTag, String enc)451throws IOException {452453byte[] data = s.getBytes(enc);454write(stringTag);455putLength(data.length);456write(data);457}458459/**460* Marshals a DER UTC time/date value.461*462* <P>YYMMDDhhmmss{Z|+hhmm|-hhmm} ... emits only using Zulu time463* and with seconds (even if seconds=0) as per RFC 5280.464*/465public void putUTCTime(Date d) throws IOException {466putTime(d, DerValue.tag_UtcTime);467}468469/**470* Marshals a DER Generalized Time/date value.471*472* <P>YYYYMMDDhhmmss{Z|+hhmm|-hhmm} ... emits only using Zulu time473* and with seconds (even if seconds=0) as per RFC 5280.474*/475public void putGeneralizedTime(Date d) throws IOException {476putTime(d, DerValue.tag_GeneralizedTime);477}478479/**480* Private helper routine for marshalling a DER UTC/Generalized481* time/date value. If the tag specified is not that for UTC Time482* then it defaults to Generalized Time.483* @param d the date to be marshalled484* @param tag the tag for UTC Time or Generalized Time485*/486private void putTime(Date d, byte tag) throws IOException {487488/*489* Format the date.490*/491492TimeZone tz = TimeZone.getTimeZone("GMT");493String pattern = null;494495if (tag == DerValue.tag_UtcTime) {496pattern = "yyMMddHHmmss'Z'";497} else {498tag = DerValue.tag_GeneralizedTime;499pattern = "yyyyMMddHHmmss'Z'";500}501502SimpleDateFormat sdf = new SimpleDateFormat(pattern, Locale.US);503sdf.setTimeZone(tz);504byte[] time = (sdf.format(d)).getBytes("ISO-8859-1");505506/*507* Write the formatted date.508*/509510write(tag);511putLength(time.length);512write(time);513}514515/**516* Put the encoding of the length in the stream.517*518* @params len the length of the attribute.519* @exception IOException on writing errors.520*/521public void putLength(int len) throws IOException {522if (len < 128) {523write((byte)len);524525} else if (len < (1 << 8)) {526write((byte)0x081);527write((byte)len);528529} else if (len < (1 << 16)) {530write((byte)0x082);531write((byte)(len >> 8));532write((byte)len);533534} else if (len < (1 << 24)) {535write((byte)0x083);536write((byte)(len >> 16));537write((byte)(len >> 8));538write((byte)len);539540} else {541write((byte)0x084);542write((byte)(len >> 24));543write((byte)(len >> 16));544write((byte)(len >> 8));545write((byte)len);546}547}548549/**550* Put the tag of the attribute in the stream.551*552* @params class the tag class type, one of UNIVERSAL, CONTEXT,553* APPLICATION or PRIVATE554* @params form if true, the value is constructed, otherwise it is555* primitive.556* @params val the tag value557*/558public void putTag(byte tagClass, boolean form, byte val) {559byte tag = (byte)(tagClass | val);560if (form) {561tag |= (byte)0x20;562}563write(tag);564}565566/**567* Write the current contents of this <code>DerOutputStream</code>568* to an <code>OutputStream</code>.569*570* @exception IOException on output error.571*/572public void derEncode(OutputStream out) throws IOException {573out.write(toByteArray());574}575}576577578