Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/x509/GeneralSubtrees.java
38831 views
/*1* Copyright (c) 1997, 2003, 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.x509;2627import java.io.*;28import java.util.*;2930import sun.security.util.*;3132/**33* Represent the GeneralSubtrees ASN.1 object.34* <p>35* The ASN.1 for this is36* <pre>37* GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree38* </pre>39* </p>40*41*42* @author Amit Kapoor43* @author Hemma Prafullchandra44* @author Andreas Sterbenz45*/46public class GeneralSubtrees implements Cloneable {4748private final List<GeneralSubtree> trees;4950// Private variables51private static final int NAME_DIFF_TYPE = GeneralNameInterface.NAME_DIFF_TYPE;52private static final int NAME_MATCH = GeneralNameInterface.NAME_MATCH;53private static final int NAME_NARROWS = GeneralNameInterface.NAME_NARROWS;54private static final int NAME_WIDENS = GeneralNameInterface.NAME_WIDENS;55private static final int NAME_SAME_TYPE = GeneralNameInterface.NAME_SAME_TYPE;5657/**58* The default constructor for the class.59*/60public GeneralSubtrees() {61trees = new ArrayList<GeneralSubtree>();62}6364private GeneralSubtrees(GeneralSubtrees source) {65trees = new ArrayList<GeneralSubtree>(source.trees);66}6768/**69* Create the object from the passed DER encoded form.70*71* @param val the DER encoded form of the same.72*/73public GeneralSubtrees(DerValue val) throws IOException {74this();75if (val.tag != DerValue.tag_Sequence) {76throw new IOException("Invalid encoding of GeneralSubtrees.");77}78while (val.data.available() != 0) {79DerValue opt = val.data.getDerValue();80GeneralSubtree tree = new GeneralSubtree(opt);81add(tree);82}83}8485public GeneralSubtree get(int index) {86return trees.get(index);87}8889public void remove(int index) {90trees.remove(index);91}9293public void add(GeneralSubtree tree) {94if (tree == null) {95throw new NullPointerException();96}97trees.add(tree);98}99100public boolean contains(GeneralSubtree tree) {101if (tree == null) {102throw new NullPointerException();103}104return trees.contains(tree);105}106107public int size() {108return trees.size();109}110111public Iterator<GeneralSubtree> iterator() {112return trees.iterator();113}114115public List<GeneralSubtree> trees() {116return trees;117}118119public Object clone() {120return new GeneralSubtrees(this);121}122123/**124* Return a printable string of the GeneralSubtree.125*/126public String toString() {127String s = " GeneralSubtrees:\n" + trees.toString() + "\n";128return s;129}130131/**132* Encode the GeneralSubtrees.133*134* @params out the DerOutputStrean to encode this object to.135*/136public void encode(DerOutputStream out) throws IOException {137DerOutputStream seq = new DerOutputStream();138139for (int i = 0, n = size(); i < n; i++) {140get(i).encode(seq);141}142out.write(DerValue.tag_Sequence, seq);143}144145/**146* Compare two general subtrees by comparing the subtrees147* of each.148*149* @param other GeneralSubtrees to compare to this150* @returns true if match151*/152public boolean equals(Object obj) {153if (this == obj) {154return true;155}156if (obj instanceof GeneralSubtrees == false) {157return false;158}159GeneralSubtrees other = (GeneralSubtrees)obj;160return this.trees.equals(other.trees);161}162163public int hashCode() {164return trees.hashCode();165}166167/**168* Return the GeneralNameInterface form of the GeneralName in one of169* the GeneralSubtrees.170*171* @param ndx index of the GeneralSubtree from which to obtain the name172*/173private GeneralNameInterface getGeneralNameInterface(int ndx) {174return getGeneralNameInterface(get(ndx));175}176177private static GeneralNameInterface getGeneralNameInterface(GeneralSubtree gs) {178GeneralName gn = gs.getName();179GeneralNameInterface gni = gn.getName();180return gni;181}182183/**184* minimize this GeneralSubtrees by removing all redundant entries.185* Internal method used by intersect and reduce.186*/187private void minimize() {188189// Algorithm: compare each entry n to all subsequent entries in190// the list: if any subsequent entry matches or widens entry n,191// remove entry n. If any subsequent entries narrow entry n, remove192// the subsequent entries.193for (int i = 0; i < (size() - 1); i++) {194GeneralNameInterface current = getGeneralNameInterface(i);195boolean remove1 = false;196197/* compare current to subsequent elements */198for (int j = i + 1; j < size(); j++) {199GeneralNameInterface subsequent = getGeneralNameInterface(j);200switch (current.constrains(subsequent)) {201case GeneralNameInterface.NAME_DIFF_TYPE:202/* not comparable; different name types; keep checking */203continue;204case GeneralNameInterface.NAME_MATCH:205/* delete one of the duplicates */206remove1 = true;207break;208case GeneralNameInterface.NAME_NARROWS:209/* subsequent narrows current */210/* remove narrower name (subsequent) */211remove(j);212j--; /* continue check with new subsequent */213continue;214case GeneralNameInterface.NAME_WIDENS:215/* subsequent widens current */216/* remove narrower name current */217remove1 = true;218break;219case GeneralNameInterface.NAME_SAME_TYPE:220/* keep both for now; keep checking */221continue;222}223break;224} /* end of this pass of subsequent elements */225226if (remove1) {227remove(i);228i--; /* check the new i value */229}230231}232}233234/**235* create a subtree containing an instance of the input236* name type that widens all other names of that type.237*238* @params name GeneralNameInterface name239* @returns GeneralSubtree containing widest name of that type240* @throws RuntimeException on error (should not occur)241*/242private GeneralSubtree createWidestSubtree(GeneralNameInterface name) {243try {244GeneralName newName;245switch (name.getType()) {246case GeneralNameInterface.NAME_ANY:247// Create new OtherName with same OID as baseName, but248// empty value249ObjectIdentifier otherOID = ((OtherName)name).getOID();250newName = new GeneralName(new OtherName(otherOID, null));251break;252case GeneralNameInterface.NAME_RFC822:253newName = new GeneralName(new RFC822Name(""));254break;255case GeneralNameInterface.NAME_DNS:256newName = new GeneralName(new DNSName(""));257break;258case GeneralNameInterface.NAME_X400:259newName = new GeneralName(new X400Address((byte[])null));260break;261case GeneralNameInterface.NAME_DIRECTORY:262newName = new GeneralName(new X500Name(""));263break;264case GeneralNameInterface.NAME_EDI:265newName = new GeneralName(new EDIPartyName(""));266break;267case GeneralNameInterface.NAME_URI:268newName = new GeneralName(new URIName(""));269break;270case GeneralNameInterface.NAME_IP:271newName = new GeneralName(new IPAddressName((byte[])null));272break;273case GeneralNameInterface.NAME_OID:274newName = new GeneralName275(new OIDName(new ObjectIdentifier((int[])null)));276break;277default:278throw new IOException279("Unsupported GeneralNameInterface type: " + name.getType());280}281return new GeneralSubtree(newName, 0, -1);282} catch (IOException e) {283throw new RuntimeException("Unexpected error: " + e, e);284}285}286287/**288* intersect this GeneralSubtrees with other. This function289* is used in merging permitted NameConstraints. The operation290* is performed as follows:291* <ul>292* <li>If a name in other narrows all names of the same type in this,293* the result will contain the narrower name and none of the294* names it narrows.295* <li>If a name in other widens all names of the same type in this,296* the result will not contain the wider name.297* <li>If a name in other does not share the same subtree with any name298* of the same type in this, then the name is added to the list299* of GeneralSubtrees returned. These names should be added to300* the list of names that are specifically excluded. The reason301* is that, if the intersection is empty, then no names of that302* type are permitted, and the only way to express this in303* NameConstraints is to include the name in excludedNames.304* <li>If a name in this has no name of the same type in other, then305* the result contains the name in this. No name of a given type306* means the name type is completely permitted.307* <li>If a name in other has no name of the same type in this, then308* the result contains the name in other. This means that309* the name is now constrained in some way, whereas before it was310* completely permitted.311* <ul>312*313* @param other GeneralSubtrees to be intersected with this314* @returns GeneralSubtrees to be merged with excluded; these are315* empty-valued name types corresponding to entries that were316* of the same type but did not share the same subtree between317* this and other. Returns null if no such.318*/319public GeneralSubtrees intersect(GeneralSubtrees other) {320321if (other == null) {322throw new NullPointerException("other GeneralSubtrees must not be null");323}324325GeneralSubtrees newThis = new GeneralSubtrees();326GeneralSubtrees newExcluded = null;327328// Step 1: If this is empty, just add everything in other to this and329// return no new excluded entries330if (size() == 0) {331union(other);332return null;333}334335// Step 2: For ease of checking the subtrees, minimize them by336// constructing versions that contain only the widest instance of337// each type338this.minimize();339other.minimize();340341// Step 3: Check each entry in this to see whether we keep it or342// remove it, and whether we add anything to newExcluded or newThis.343// We keep an entry in this unless it is narrowed by all entries in344// other. We add an entry to newExcluded if there is at least one345// entry of the same nameType in other, but this entry does346// not share the same subtree with any of the entries in other.347// We add an entry from other to newThis if there is no name of the348// same type in this.349for (int i = 0; i < size(); i++) {350GeneralNameInterface thisEntry = getGeneralNameInterface(i);351boolean removeThisEntry = false;352353// Step 3a: If the widest name of this type in other narrows354// thisEntry, remove thisEntry and add widest other to newThis.355// Simultaneously, check for situation where there is a name of356// this type in other, but no name in other matches, narrows,357// or widens thisEntry.358boolean sameType = false;359for (int j = 0; j < other.size(); j++) {360GeneralSubtree otherEntryGS = other.get(j);361GeneralNameInterface otherEntry =362getGeneralNameInterface(otherEntryGS);363switch (thisEntry.constrains(otherEntry)) {364case NAME_NARROWS:365remove(i);366i--;367newThis.add(otherEntryGS);368sameType = false;369break;370case NAME_SAME_TYPE:371sameType = true;372continue;373case NAME_MATCH:374case NAME_WIDENS:375sameType = false;376break;377case NAME_DIFF_TYPE:378default:379continue;380}381break;382}383384// Step 3b: If sameType is still true, we have the situation385// where there was a name of the same type as thisEntry in386// other, but no name in other widened, matched, or narrowed387// thisEntry.388if (sameType) {389390// Step 3b.1: See if there are any entries in this and other391// with this type that match, widen, or narrow each other.392// If not, then we need to add a "widest subtree" of this393// type to excluded.394boolean intersection = false;395for (int j = 0; j < size(); j++) {396GeneralNameInterface thisAltEntry = getGeneralNameInterface(j);397398if (thisAltEntry.getType() == thisEntry.getType()) {399for (int k = 0; k < other.size(); k++) {400GeneralNameInterface othAltEntry =401other.getGeneralNameInterface(k);402403int constraintType =404thisAltEntry.constrains(othAltEntry);405if (constraintType == NAME_MATCH ||406constraintType == NAME_WIDENS ||407constraintType == NAME_NARROWS) {408intersection = true;409break;410}411}412}413}414if (intersection == false) {415if (newExcluded == null) {416newExcluded = new GeneralSubtrees();417}418GeneralSubtree widestSubtree =419createWidestSubtree(thisEntry);420if (!newExcluded.contains(widestSubtree)) {421newExcluded.add(widestSubtree);422}423}424425// Step 3b.2: Remove thisEntry from this426remove(i);427i--;428}429}430431// Step 4: Add all entries in newThis to this432if (newThis.size() > 0) {433union(newThis);434}435436// Step 5: Add all entries in other that do not have any entry of the437// same type in this to this438for (int i = 0; i < other.size(); i++) {439GeneralSubtree otherEntryGS = other.get(i);440GeneralNameInterface otherEntry = getGeneralNameInterface(otherEntryGS);441boolean diffType = false;442for (int j = 0; j < size(); j++) {443GeneralNameInterface thisEntry = getGeneralNameInterface(j);444switch (thisEntry.constrains(otherEntry)) {445case NAME_DIFF_TYPE:446diffType = true;447// continue to see if we find something later of the448// same type449continue;450case NAME_NARROWS:451case NAME_SAME_TYPE:452case NAME_MATCH:453case NAME_WIDENS:454diffType = false; // we found an entry of the same type455// break because we know we won't be adding it to456// this now457break;458default:459continue;460}461break;462}463if (diffType) {464add(otherEntryGS);465}466}467468// Step 6: Return the newExcluded GeneralSubtrees469return newExcluded;470}471472/**473* construct union of this GeneralSubtrees with other.474*475* @param other GeneralSubtrees to be united with this476*/477public void union(GeneralSubtrees other) {478if (other != null) {479for (int i = 0, n = other.size(); i < n; i++) {480add(other.get(i));481}482// Minimize this483minimize();484}485}486487/**488* reduce this GeneralSubtrees by contents of another. This function489* is used in merging excluded NameConstraints with permitted NameConstraints490* to obtain a minimal form of permitted NameConstraints. It is an491* optimization, and does not affect correctness of the results.492*493* @param excluded GeneralSubtrees494*/495public void reduce(GeneralSubtrees excluded) {496if (excluded == null) {497return;498}499for (int i = 0, n = excluded.size(); i < n; i++) {500GeneralNameInterface excludedName = excluded.getGeneralNameInterface(i);501for (int j = 0; j < size(); j++) {502GeneralNameInterface permitted = getGeneralNameInterface(j);503switch (excludedName.constrains(permitted)) {504case GeneralNameInterface.NAME_DIFF_TYPE:505break;506case GeneralNameInterface.NAME_MATCH:507remove(j);508j--;509break;510case GeneralNameInterface.NAME_NARROWS:511/* permitted narrows excluded */512remove(j);513j--;514break;515case GeneralNameInterface.NAME_WIDENS:516/* permitted widens excluded */517break;518case GeneralNameInterface.NAME_SAME_TYPE:519break;520}521} /* end of this pass of permitted */522} /* end of pass of excluded */523}524}525526527