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