Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/sun/security/x509/GeneralSubtrees.java
41159 views
1
/*
2
* Copyright (c) 1997, 2020, 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.x509;
27
28
import java.io.*;
29
import java.util.*;
30
31
import sun.security.util.*;
32
33
/**
34
* Represent the GeneralSubtrees ASN.1 object.
35
* <p>
36
* The ASN.1 for this is
37
* <pre>
38
* GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
39
* </pre>
40
*
41
*
42
* @author Amit Kapoor
43
* @author Hemma Prafullchandra
44
* @author Andreas Sterbenz
45
*/
46
public class GeneralSubtrees implements Cloneable {
47
48
private final List<GeneralSubtree> trees;
49
50
// Private variables
51
private static final int NAME_DIFF_TYPE = GeneralNameInterface.NAME_DIFF_TYPE;
52
private static final int NAME_MATCH = GeneralNameInterface.NAME_MATCH;
53
private static final int NAME_NARROWS = GeneralNameInterface.NAME_NARROWS;
54
private static final int NAME_WIDENS = GeneralNameInterface.NAME_WIDENS;
55
private static final int NAME_SAME_TYPE = GeneralNameInterface.NAME_SAME_TYPE;
56
57
/**
58
* The default constructor for the class.
59
*/
60
public GeneralSubtrees() {
61
trees = new ArrayList<>();
62
}
63
64
private GeneralSubtrees(GeneralSubtrees source) {
65
trees = new ArrayList<>(source.trees);
66
}
67
68
/**
69
* Create the object from the passed DER encoded form.
70
*
71
* @param val the DER encoded form of the same.
72
*/
73
public GeneralSubtrees(DerValue val) throws IOException {
74
this();
75
if (val.tag != DerValue.tag_Sequence) {
76
throw new IOException("Invalid encoding of GeneralSubtrees.");
77
}
78
while (val.data.available() != 0) {
79
DerValue opt = val.data.getDerValue();
80
GeneralSubtree tree = new GeneralSubtree(opt);
81
add(tree);
82
}
83
}
84
85
public GeneralSubtree get(int index) {
86
return trees.get(index);
87
}
88
89
public void remove(int index) {
90
trees.remove(index);
91
}
92
93
public void add(GeneralSubtree tree) {
94
if (tree == null) {
95
throw new NullPointerException();
96
}
97
trees.add(tree);
98
}
99
100
public boolean contains(GeneralSubtree tree) {
101
if (tree == null) {
102
throw new NullPointerException();
103
}
104
return trees.contains(tree);
105
}
106
107
public int size() {
108
return trees.size();
109
}
110
111
public Iterator<GeneralSubtree> iterator() {
112
return trees.iterator();
113
}
114
115
public List<GeneralSubtree> trees() {
116
return trees;
117
}
118
119
public Object clone() {
120
return new GeneralSubtrees(this);
121
}
122
123
/**
124
* Return a printable string of the GeneralSubtree.
125
*/
126
public String toString() {
127
return " GeneralSubtrees:\n" + trees + '\n';
128
}
129
130
/**
131
* Encode the GeneralSubtrees.
132
*
133
* @param out the DerOutputStrean to encode this object to.
134
*/
135
public void encode(DerOutputStream out) throws IOException {
136
DerOutputStream seq = new DerOutputStream();
137
138
for (int i = 0, n = size(); i < n; i++) {
139
get(i).encode(seq);
140
}
141
out.write(DerValue.tag_Sequence, seq);
142
}
143
144
/**
145
* Compare two general subtrees by comparing the subtrees
146
* of each.
147
*
148
* @param obj GeneralSubtrees to compare to this
149
* @return true if match
150
*/
151
public boolean equals(Object obj) {
152
if (this == obj) {
153
return true;
154
}
155
if (obj instanceof GeneralSubtrees == false) {
156
return false;
157
}
158
GeneralSubtrees other = (GeneralSubtrees)obj;
159
return this.trees.equals(other.trees);
160
}
161
162
public int hashCode() {
163
return trees.hashCode();
164
}
165
166
/**
167
* Return the GeneralNameInterface form of the GeneralName in one of
168
* the GeneralSubtrees.
169
*
170
* @param ndx index of the GeneralSubtree from which to obtain the name
171
*/
172
private GeneralNameInterface getGeneralNameInterface(int ndx) {
173
return getGeneralNameInterface(get(ndx));
174
}
175
176
private static GeneralNameInterface getGeneralNameInterface(GeneralSubtree gs) {
177
GeneralName gn = gs.getName();
178
GeneralNameInterface gni = gn.getName();
179
return gni;
180
}
181
182
/**
183
* minimize this GeneralSubtrees by removing all redundant entries.
184
* Internal method used by intersect and reduce.
185
*/
186
private void minimize() {
187
188
// Algorithm: compare each entry n to all subsequent entries in
189
// the list: if any subsequent entry matches or widens entry n,
190
// remove entry n. If any subsequent entries narrow entry n, remove
191
// the subsequent entries.
192
for (int i = 0; i < (size() - 1); i++) {
193
GeneralNameInterface current = getGeneralNameInterface(i);
194
boolean remove1 = false;
195
196
/* compare current to subsequent elements */
197
for (int j = i + 1; j < size(); j++) {
198
GeneralNameInterface subsequent = getGeneralNameInterface(j);
199
switch (current.constrains(subsequent)) {
200
case GeneralNameInterface.NAME_DIFF_TYPE:
201
/* not comparable; different name types; keep checking */
202
continue;
203
case GeneralNameInterface.NAME_MATCH:
204
/* delete one of the duplicates */
205
remove1 = true;
206
break;
207
case GeneralNameInterface.NAME_NARROWS:
208
/* subsequent narrows current */
209
/* remove narrower name (subsequent) */
210
remove(j);
211
j--; /* continue check with new subsequent */
212
continue;
213
case GeneralNameInterface.NAME_WIDENS:
214
/* subsequent widens current */
215
/* remove narrower name current */
216
remove1 = true;
217
break;
218
case GeneralNameInterface.NAME_SAME_TYPE:
219
/* keep both for now; keep checking */
220
continue;
221
}
222
break;
223
} /* end of this pass of subsequent elements */
224
225
if (remove1) {
226
remove(i);
227
i--; /* check the new i value */
228
}
229
230
}
231
}
232
233
/**
234
* create a subtree containing an instance of the input
235
* name type that widens all other names of that type.
236
*
237
* @param name GeneralNameInterface name
238
* @return GeneralSubtree containing widest name of that type
239
* @throws RuntimeException on error (should not occur)
240
*/
241
private GeneralSubtree createWidestSubtree(GeneralNameInterface name) {
242
try {
243
GeneralName newName;
244
switch (name.getType()) {
245
case GeneralNameInterface.NAME_ANY:
246
// Create new OtherName with same OID as baseName, but
247
// empty value
248
ObjectIdentifier otherOID = ((OtherName)name).getOID();
249
newName = new GeneralName(new OtherName(otherOID, null));
250
break;
251
case GeneralNameInterface.NAME_RFC822:
252
newName = new GeneralName(new RFC822Name(""));
253
break;
254
case GeneralNameInterface.NAME_DNS:
255
newName = new GeneralName(new DNSName(""));
256
break;
257
case GeneralNameInterface.NAME_X400:
258
newName = new GeneralName(new X400Address((byte[])null));
259
break;
260
case GeneralNameInterface.NAME_DIRECTORY:
261
newName = new GeneralName(new X500Name(""));
262
break;
263
case GeneralNameInterface.NAME_EDI:
264
newName = new GeneralName(new EDIPartyName(""));
265
break;
266
case GeneralNameInterface.NAME_URI:
267
newName = new GeneralName(new URIName(""));
268
break;
269
case GeneralNameInterface.NAME_IP:
270
newName = new GeneralName(new IPAddressName((byte[])null));
271
break;
272
case GeneralNameInterface.NAME_OID:
273
newName = new GeneralName(new OIDName(""));
274
break;
275
default:
276
throw new IOException
277
("Unsupported GeneralNameInterface type: " + name.getType());
278
}
279
return new GeneralSubtree(newName, 0, -1);
280
} catch (IOException e) {
281
throw new RuntimeException("Unexpected error: " + e, e);
282
}
283
}
284
285
/**
286
* intersect this GeneralSubtrees with other. This function
287
* is used in merging permitted NameConstraints. The operation
288
* is performed as follows:
289
* <ul>
290
* <li>If a name in other narrows all names of the same type in this,
291
* the result will contain the narrower name and none of the
292
* names it narrows.
293
* <li>If a name in other widens all names of the same type in this,
294
* the result will not contain the wider name.
295
* <li>If a name in other does not share the same subtree with any name
296
* of the same type in this, then the name is added to the list
297
* of GeneralSubtrees returned. These names should be added to
298
* the list of names that are specifically excluded. The reason
299
* is that, if the intersection is empty, then no names of that
300
* type are permitted, and the only way to express this in
301
* NameConstraints is to include the name in excludedNames.
302
* <li>If a name in this has no name of the same type in other, then
303
* the result contains the name in this. No name of a given type
304
* means the name type is completely permitted.
305
* <li>If a name in other has no name of the same type in this, then
306
* the result contains the name in other. This means that
307
* the name is now constrained in some way, whereas before it was
308
* completely permitted.
309
* </ul>
310
*
311
* @param other GeneralSubtrees to be intersected with this
312
* @return GeneralSubtrees to be merged with excluded; these are
313
* empty-valued name types corresponding to entries that were
314
* of the same type but did not share the same subtree between
315
* this and other. Returns null if no such.
316
*/
317
public GeneralSubtrees intersect(GeneralSubtrees other) {
318
319
if (other == null) {
320
throw new NullPointerException("other GeneralSubtrees must not be null");
321
}
322
323
GeneralSubtrees newThis = new GeneralSubtrees();
324
GeneralSubtrees newExcluded = null;
325
326
// Step 1: If this is empty, just add everything in other to this and
327
// return no new excluded entries
328
if (size() == 0) {
329
union(other);
330
return null;
331
}
332
333
// Step 2: For ease of checking the subtrees, minimize them by
334
// constructing versions that contain only the widest instance of
335
// each type
336
this.minimize();
337
other.minimize();
338
339
// Step 3: Check each entry in this to see whether we keep it or
340
// remove it, and whether we add anything to newExcluded or newThis.
341
// We keep an entry in this unless it is narrowed by all entries in
342
// other. We add an entry to newExcluded if there is at least one
343
// entry of the same nameType in other, but this entry does
344
// not share the same subtree with any of the entries in other.
345
// We add an entry from other to newThis if there is no name of the
346
// same type in this.
347
for (int i = 0; i < size(); i++) {
348
GeneralNameInterface thisEntry = getGeneralNameInterface(i);
349
boolean removeThisEntry = false;
350
351
// Step 3a: If the widest name of this type in other narrows
352
// thisEntry, remove thisEntry and add widest other to newThis.
353
// Simultaneously, check for situation where there is a name of
354
// this type in other, but no name in other matches, narrows,
355
// or widens thisEntry.
356
boolean sameType = false;
357
for (int j = 0; j < other.size(); j++) {
358
GeneralSubtree otherEntryGS = other.get(j);
359
GeneralNameInterface otherEntry =
360
getGeneralNameInterface(otherEntryGS);
361
switch (thisEntry.constrains(otherEntry)) {
362
case NAME_NARROWS:
363
remove(i);
364
i--;
365
newThis.add(otherEntryGS);
366
sameType = false;
367
break;
368
case NAME_SAME_TYPE:
369
sameType = true;
370
continue;
371
case NAME_MATCH:
372
case NAME_WIDENS:
373
sameType = false;
374
break;
375
case NAME_DIFF_TYPE:
376
default:
377
continue;
378
}
379
break;
380
}
381
382
// Step 3b: If sameType is still true, we have the situation
383
// where there was a name of the same type as thisEntry in
384
// other, but no name in other widened, matched, or narrowed
385
// thisEntry.
386
if (sameType) {
387
388
// Step 3b.1: See if there are any entries in this and other
389
// with this type that match, widen, or narrow each other.
390
// If not, then we need to add a "widest subtree" of this
391
// type to excluded.
392
boolean intersection = false;
393
for (int j = 0; j < size(); j++) {
394
GeneralNameInterface thisAltEntry = getGeneralNameInterface(j);
395
396
if (thisAltEntry.getType() == thisEntry.getType()) {
397
for (int k = 0; k < other.size(); k++) {
398
GeneralNameInterface othAltEntry =
399
other.getGeneralNameInterface(k);
400
401
int constraintType =
402
thisAltEntry.constrains(othAltEntry);
403
if (constraintType == NAME_MATCH ||
404
constraintType == NAME_WIDENS ||
405
constraintType == NAME_NARROWS) {
406
intersection = true;
407
break;
408
}
409
}
410
}
411
}
412
if (intersection == false) {
413
if (newExcluded == null) {
414
newExcluded = new GeneralSubtrees();
415
}
416
GeneralSubtree widestSubtree =
417
createWidestSubtree(thisEntry);
418
if (!newExcluded.contains(widestSubtree)) {
419
newExcluded.add(widestSubtree);
420
}
421
}
422
423
// Step 3b.2: Remove thisEntry from this
424
remove(i);
425
i--;
426
}
427
}
428
429
// Step 4: Add all entries in newThis to this
430
if (newThis.size() > 0) {
431
union(newThis);
432
}
433
434
// Step 5: Add all entries in other that do not have any entry of the
435
// same type in this to this
436
for (int i = 0; i < other.size(); i++) {
437
GeneralSubtree otherEntryGS = other.get(i);
438
GeneralNameInterface otherEntry = getGeneralNameInterface(otherEntryGS);
439
boolean diffType = false;
440
for (int j = 0; j < size(); j++) {
441
GeneralNameInterface thisEntry = getGeneralNameInterface(j);
442
switch (thisEntry.constrains(otherEntry)) {
443
case NAME_DIFF_TYPE:
444
diffType = true;
445
// continue to see if we find something later of the
446
// same type
447
continue;
448
case NAME_NARROWS:
449
case NAME_SAME_TYPE:
450
case NAME_MATCH:
451
case NAME_WIDENS:
452
diffType = false; // we found an entry of the same type
453
// break because we know we won't be adding it to
454
// this now
455
break;
456
default:
457
continue;
458
}
459
break;
460
}
461
if (diffType) {
462
add(otherEntryGS);
463
}
464
}
465
466
// Step 6: Return the newExcluded GeneralSubtrees
467
return newExcluded;
468
}
469
470
/**
471
* construct union of this GeneralSubtrees with other.
472
*
473
* @param other GeneralSubtrees to be united with this
474
*/
475
public void union(GeneralSubtrees other) {
476
if (other != null) {
477
for (int i = 0, n = other.size(); i < n; i++) {
478
add(other.get(i));
479
}
480
// Minimize this
481
minimize();
482
}
483
}
484
485
/**
486
* reduce this GeneralSubtrees by contents of another. This function
487
* is used in merging excluded NameConstraints with permitted NameConstraints
488
* to obtain a minimal form of permitted NameConstraints. It is an
489
* optimization, and does not affect correctness of the results.
490
*
491
* @param excluded GeneralSubtrees
492
*/
493
public void reduce(GeneralSubtrees excluded) {
494
if (excluded == null) {
495
return;
496
}
497
for (int i = 0, n = excluded.size(); i < n; i++) {
498
GeneralNameInterface excludedName = excluded.getGeneralNameInterface(i);
499
for (int j = 0; j < size(); j++) {
500
GeneralNameInterface permitted = getGeneralNameInterface(j);
501
switch (excludedName.constrains(permitted)) {
502
case GeneralNameInterface.NAME_DIFF_TYPE:
503
break;
504
case GeneralNameInterface.NAME_MATCH:
505
remove(j);
506
j--;
507
break;
508
case GeneralNameInterface.NAME_NARROWS:
509
/* permitted narrows excluded */
510
remove(j);
511
j--;
512
break;
513
case GeneralNameInterface.NAME_WIDENS:
514
/* permitted widens excluded */
515
break;
516
case GeneralNameInterface.NAME_SAME_TYPE:
517
break;
518
}
519
} /* end of this pass of permitted */
520
} /* end of pass of excluded */
521
}
522
}
523
524