Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/util/DerOutputStream.java
38830 views
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
*/
61
public DerOutputStream(int size) { super(size); }
62
63
/**
64
* Construct an DER output stream.
65
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
182
public void putInteger(int i) throws IOException {
183
write(DerValue.tag_Integer);
184
putIntegerContents(i);
185
}
186
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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 5280.
465
*/
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 5280.
475
*/
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
*/
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
*/
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
*/
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
*/
573
public void derEncode(OutputStream out) throws IOException {
574
out.write(toByteArray());
575
}
576
}
577
578