| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
 | 
 | 
package sun.security.x509;  | 
 | 
 | 
 | 
import java.io.*;  | 
 | 
import java.util.*;  | 
 | 
 | 
 | 
import sun.security.util.*;  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
public class GeneralSubtrees implements Cloneable { | 
 | 
 | 
 | 
    private final List<GeneralSubtree> trees;  | 
 | 
 | 
 | 
      | 
 | 
    private static final int NAME_DIFF_TYPE = GeneralNameInterface.NAME_DIFF_TYPE;  | 
 | 
    private static final int NAME_MATCH = GeneralNameInterface.NAME_MATCH;  | 
 | 
    private static final int NAME_NARROWS = GeneralNameInterface.NAME_NARROWS;  | 
 | 
    private static final int NAME_WIDENS = GeneralNameInterface.NAME_WIDENS;  | 
 | 
    private static final int NAME_SAME_TYPE = GeneralNameInterface.NAME_SAME_TYPE;  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    public GeneralSubtrees() { | 
 | 
        trees = new ArrayList<GeneralSubtree>();  | 
 | 
    }  | 
 | 
 | 
 | 
    private GeneralSubtrees(GeneralSubtrees source) { | 
 | 
        trees = new ArrayList<GeneralSubtree>(source.trees);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public GeneralSubtrees(DerValue val) throws IOException { | 
 | 
        this();  | 
 | 
        if (val.tag != DerValue.tag_Sequence) { | 
 | 
            throw new IOException("Invalid encoding of GeneralSubtrees."); | 
 | 
        }  | 
 | 
        while (val.data.available() != 0) { | 
 | 
            DerValue opt = val.data.getDerValue();  | 
 | 
            GeneralSubtree tree = new GeneralSubtree(opt);  | 
 | 
            add(tree);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    public GeneralSubtree get(int index) { | 
 | 
        return trees.get(index);  | 
 | 
    }  | 
 | 
 | 
 | 
    public void remove(int index) { | 
 | 
        trees.remove(index);  | 
 | 
    }  | 
 | 
 | 
 | 
    public void add(GeneralSubtree tree) { | 
 | 
        if (tree == null) { | 
 | 
            throw new NullPointerException();  | 
 | 
        }  | 
 | 
        trees.add(tree);  | 
 | 
    }  | 
 | 
 | 
 | 
    public boolean contains(GeneralSubtree tree) { | 
 | 
        if (tree == null) { | 
 | 
            throw new NullPointerException();  | 
 | 
        }  | 
 | 
        return trees.contains(tree);  | 
 | 
    }  | 
 | 
 | 
 | 
    public int size() { | 
 | 
        return trees.size();  | 
 | 
    }  | 
 | 
 | 
 | 
    public Iterator<GeneralSubtree> iterator() { | 
 | 
        return trees.iterator();  | 
 | 
    }  | 
 | 
 | 
 | 
    public List<GeneralSubtree> trees() { | 
 | 
        return trees;  | 
 | 
    }  | 
 | 
 | 
 | 
    public Object clone() { | 
 | 
        return new GeneralSubtrees(this);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    public String toString() { | 
 | 
        String s = "   GeneralSubtrees:\n" + trees.toString() + "\n";  | 
 | 
        return s;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public void encode(DerOutputStream out) throws IOException { | 
 | 
        DerOutputStream seq = new DerOutputStream();  | 
 | 
 | 
 | 
        for (int i = 0, n = size(); i < n; i++) { | 
 | 
            get(i).encode(seq);  | 
 | 
        }  | 
 | 
        out.write(DerValue.tag_Sequence, seq);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public boolean equals(Object obj) { | 
 | 
        if (this == obj) { | 
 | 
            return true;  | 
 | 
        }  | 
 | 
        if (obj instanceof GeneralSubtrees == false) { | 
 | 
            return false;  | 
 | 
        }  | 
 | 
        GeneralSubtrees other = (GeneralSubtrees)obj;  | 
 | 
        return this.trees.equals(other.trees);  | 
 | 
    }  | 
 | 
 | 
 | 
    public int hashCode() { | 
 | 
        return trees.hashCode();  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private GeneralNameInterface getGeneralNameInterface(int ndx) { | 
 | 
        return getGeneralNameInterface(get(ndx));  | 
 | 
    }  | 
 | 
 | 
 | 
    private static GeneralNameInterface getGeneralNameInterface(GeneralSubtree gs) { | 
 | 
        GeneralName gn = gs.getName();  | 
 | 
        GeneralNameInterface gni = gn.getName();  | 
 | 
        return gni;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private void minimize() { | 
 | 
 | 
 | 
        // Algorithm: compare each entry n to all subsequent entries in  | 
 | 
        // the list: if any subsequent entry matches or widens entry n,  | 
 | 
        // remove entry n. If any subsequent entries narrow entry n, remove  | 
 | 
          | 
 | 
        for (int i = 0; i < (size() - 1); i++) { | 
 | 
            GeneralNameInterface current = getGeneralNameInterface(i);  | 
 | 
            boolean remove1 = false;  | 
 | 
 | 
 | 
              | 
 | 
            for (int j = i + 1; j < size(); j++) { | 
 | 
                GeneralNameInterface subsequent = getGeneralNameInterface(j);  | 
 | 
                switch (current.constrains(subsequent)) { | 
 | 
                    case GeneralNameInterface.NAME_DIFF_TYPE:  | 
 | 
                          | 
 | 
                        continue;  | 
 | 
                    case GeneralNameInterface.NAME_MATCH:  | 
 | 
                          | 
 | 
                        remove1 = true;  | 
 | 
                        break;  | 
 | 
                    case GeneralNameInterface.NAME_NARROWS:  | 
 | 
                        /* subsequent narrows current */  | 
 | 
                          | 
 | 
                        remove(j);  | 
 | 
                        j--;   | 
 | 
                        continue;  | 
 | 
                    case GeneralNameInterface.NAME_WIDENS:  | 
 | 
                        /* subsequent widens current */  | 
 | 
                          | 
 | 
                        remove1 = true;  | 
 | 
                        break;  | 
 | 
                    case GeneralNameInterface.NAME_SAME_TYPE:  | 
 | 
                          | 
 | 
                        continue;  | 
 | 
                }  | 
 | 
                break;  | 
 | 
            } /* end of this pass of subsequent elements */  | 
 | 
 | 
 | 
            if (remove1) { | 
 | 
                remove(i);  | 
 | 
                i--; /* check the new i value */  | 
 | 
            }  | 
 | 
 | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private GeneralSubtree createWidestSubtree(GeneralNameInterface name) { | 
 | 
        try { | 
 | 
            GeneralName newName;  | 
 | 
            switch (name.getType()) { | 
 | 
            case GeneralNameInterface.NAME_ANY:  | 
 | 
                // Create new OtherName with same OID as baseName, but  | 
 | 
                  | 
 | 
                ObjectIdentifier otherOID = ((OtherName)name).getOID();  | 
 | 
                newName = new GeneralName(new OtherName(otherOID, null));  | 
 | 
                break;  | 
 | 
            case GeneralNameInterface.NAME_RFC822:  | 
 | 
                newName = new GeneralName(new RFC822Name("")); | 
 | 
                break;  | 
 | 
            case GeneralNameInterface.NAME_DNS:  | 
 | 
                newName = new GeneralName(new DNSName("")); | 
 | 
                break;  | 
 | 
            case GeneralNameInterface.NAME_X400:  | 
 | 
                newName = new GeneralName(new X400Address((byte[])null));  | 
 | 
                break;  | 
 | 
            case GeneralNameInterface.NAME_DIRECTORY:  | 
 | 
                newName = new GeneralName(new X500Name("")); | 
 | 
                break;  | 
 | 
            case GeneralNameInterface.NAME_EDI:  | 
 | 
                newName = new GeneralName(new EDIPartyName("")); | 
 | 
                break;  | 
 | 
            case GeneralNameInterface.NAME_URI:  | 
 | 
                newName = new GeneralName(new URIName("")); | 
 | 
                break;  | 
 | 
            case GeneralNameInterface.NAME_IP:  | 
 | 
                newName = new GeneralName(new IPAddressName((byte[])null));  | 
 | 
                break;  | 
 | 
            case GeneralNameInterface.NAME_OID:  | 
 | 
                newName = new GeneralName  | 
 | 
                    (new OIDName(new ObjectIdentifier((int[])null)));  | 
 | 
                break;  | 
 | 
            default:  | 
 | 
                throw new IOException  | 
 | 
                    ("Unsupported GeneralNameInterface type: " + name.getType()); | 
 | 
            }  | 
 | 
            return new GeneralSubtree(newName, 0, -1);  | 
 | 
        } catch (IOException e) { | 
 | 
            throw new RuntimeException("Unexpected error: " + e, e); | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public GeneralSubtrees intersect(GeneralSubtrees other) { | 
 | 
 | 
 | 
        if (other == null) { | 
 | 
            throw new NullPointerException("other GeneralSubtrees must not be null"); | 
 | 
        }  | 
 | 
 | 
 | 
        GeneralSubtrees newThis = new GeneralSubtrees();  | 
 | 
        GeneralSubtrees newExcluded = null;  | 
 | 
 | 
 | 
        // Step 1: If this is empty, just add everything in other to this and  | 
 | 
          | 
 | 
        if (size() == 0) { | 
 | 
            union(other);  | 
 | 
            return null;  | 
 | 
        }  | 
 | 
 | 
 | 
        // Step 2: For ease of checking the subtrees, minimize them by  | 
 | 
        // constructing versions that contain only the widest instance of  | 
 | 
          | 
 | 
        this.minimize();  | 
 | 
        other.minimize();  | 
 | 
 | 
 | 
        // Step 3: Check each entry in this to see whether we keep it or  | 
 | 
        // remove it, and whether we add anything to newExcluded or newThis.  | 
 | 
        // We keep an entry in this unless it is narrowed by all entries in  | 
 | 
        // other.  We add an entry to newExcluded if there is at least one  | 
 | 
        // entry of the same nameType in other, but this entry does  | 
 | 
        // not share the same subtree with any of the entries in other.  | 
 | 
        // We add an entry from other to newThis if there is no name of the  | 
 | 
          | 
 | 
        for (int i = 0; i < size(); i++) { | 
 | 
            GeneralNameInterface thisEntry = getGeneralNameInterface(i);  | 
 | 
            boolean removeThisEntry = false;  | 
 | 
 | 
 | 
            // Step 3a: If the widest name of this type in other narrows  | 
 | 
            // thisEntry, remove thisEntry and add widest other to newThis.  | 
 | 
            // Simultaneously, check for situation where there is a name of  | 
 | 
            // this type in other, but no name in other matches, narrows,  | 
 | 
              | 
 | 
            boolean sameType = false;  | 
 | 
            for (int j = 0; j < other.size(); j++) { | 
 | 
                GeneralSubtree otherEntryGS = other.get(j);  | 
 | 
                GeneralNameInterface otherEntry =  | 
 | 
                    getGeneralNameInterface(otherEntryGS);  | 
 | 
                switch (thisEntry.constrains(otherEntry)) { | 
 | 
                    case NAME_NARROWS:  | 
 | 
                        remove(i);  | 
 | 
                        i--;  | 
 | 
                        newThis.add(otherEntryGS);  | 
 | 
                        sameType = false;  | 
 | 
                        break;  | 
 | 
                    case NAME_SAME_TYPE:  | 
 | 
                        sameType = true;  | 
 | 
                        continue;  | 
 | 
                    case NAME_MATCH:  | 
 | 
                    case NAME_WIDENS:  | 
 | 
                        sameType = false;  | 
 | 
                        break;  | 
 | 
                    case NAME_DIFF_TYPE:  | 
 | 
                    default:  | 
 | 
                        continue;  | 
 | 
                }  | 
 | 
                break;  | 
 | 
            }  | 
 | 
 | 
 | 
            // Step 3b: If sameType is still true, we have the situation  | 
 | 
            // where there was a name of the same type as thisEntry in  | 
 | 
            // other, but no name in other widened, matched, or narrowed  | 
 | 
              | 
 | 
            if (sameType) { | 
 | 
 | 
 | 
                // Step 3b.1: See if there are any entries in this and other  | 
 | 
                // with this type that match, widen, or narrow each other.  | 
 | 
                // If not, then we need to add a "widest subtree" of this  | 
 | 
                  | 
 | 
                boolean intersection = false;  | 
 | 
                for (int j = 0; j < size(); j++) { | 
 | 
                    GeneralNameInterface thisAltEntry = getGeneralNameInterface(j);  | 
 | 
 | 
 | 
                    if (thisAltEntry.getType() == thisEntry.getType()) { | 
 | 
                        for (int k = 0; k < other.size(); k++) { | 
 | 
                            GeneralNameInterface othAltEntry =  | 
 | 
                                other.getGeneralNameInterface(k);  | 
 | 
 | 
 | 
                            int constraintType =  | 
 | 
                                thisAltEntry.constrains(othAltEntry);  | 
 | 
                            if (constraintType == NAME_MATCH ||  | 
 | 
                                constraintType == NAME_WIDENS ||  | 
 | 
                                constraintType == NAME_NARROWS) { | 
 | 
                                intersection = true;  | 
 | 
                                break;  | 
 | 
                            }  | 
 | 
                        }  | 
 | 
                    }  | 
 | 
                }  | 
 | 
                if (intersection == false) { | 
 | 
                    if (newExcluded == null) { | 
 | 
                        newExcluded = new GeneralSubtrees();  | 
 | 
                    }  | 
 | 
                    GeneralSubtree widestSubtree =  | 
 | 
                         createWidestSubtree(thisEntry);  | 
 | 
                    if (!newExcluded.contains(widestSubtree)) { | 
 | 
                        newExcluded.add(widestSubtree);  | 
 | 
                    }  | 
 | 
                }  | 
 | 
 | 
 | 
                  | 
 | 
                remove(i);  | 
 | 
                i--;  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
          | 
 | 
        if (newThis.size() > 0) { | 
 | 
            union(newThis);  | 
 | 
        }  | 
 | 
 | 
 | 
        // Step 5: Add all entries in other that do not have any entry of the  | 
 | 
          | 
 | 
        for (int i = 0; i < other.size(); i++) { | 
 | 
            GeneralSubtree otherEntryGS = other.get(i);  | 
 | 
            GeneralNameInterface otherEntry = getGeneralNameInterface(otherEntryGS);  | 
 | 
            boolean diffType = false;  | 
 | 
            for (int j = 0; j < size(); j++) { | 
 | 
                GeneralNameInterface thisEntry = getGeneralNameInterface(j);  | 
 | 
                switch (thisEntry.constrains(otherEntry)) { | 
 | 
                    case NAME_DIFF_TYPE:  | 
 | 
                        diffType = true;  | 
 | 
                        // continue to see if we find something later of the  | 
 | 
                          | 
 | 
                        continue;  | 
 | 
                    case NAME_NARROWS:  | 
 | 
                    case NAME_SAME_TYPE:  | 
 | 
                    case NAME_MATCH:  | 
 | 
                    case NAME_WIDENS:  | 
 | 
                        diffType = false;   | 
 | 
                        // break because we know we won't be adding it to  | 
 | 
                          | 
 | 
                        break;  | 
 | 
                    default:  | 
 | 
                        continue;  | 
 | 
                }  | 
 | 
                break;  | 
 | 
            }  | 
 | 
            if (diffType) { | 
 | 
                add(otherEntryGS);  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
          | 
 | 
        return newExcluded;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public void union(GeneralSubtrees other) { | 
 | 
        if (other != null) { | 
 | 
            for (int i = 0, n = other.size(); i < n; i++) { | 
 | 
                add(other.get(i));  | 
 | 
            }  | 
 | 
              | 
 | 
            minimize();  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public void reduce(GeneralSubtrees excluded) { | 
 | 
        if (excluded == null) { | 
 | 
            return;  | 
 | 
        }  | 
 | 
        for (int i = 0, n = excluded.size(); i < n; i++) { | 
 | 
            GeneralNameInterface excludedName = excluded.getGeneralNameInterface(i);  | 
 | 
            for (int j = 0; j < size(); j++) { | 
 | 
                GeneralNameInterface permitted = getGeneralNameInterface(j);  | 
 | 
                switch (excludedName.constrains(permitted)) { | 
 | 
                case GeneralNameInterface.NAME_DIFF_TYPE:  | 
 | 
                    break;  | 
 | 
                case GeneralNameInterface.NAME_MATCH:  | 
 | 
                    remove(j);  | 
 | 
                    j--;  | 
 | 
                    break;  | 
 | 
                case GeneralNameInterface.NAME_NARROWS:  | 
 | 
                      | 
 | 
                    remove(j);  | 
 | 
                    j--;  | 
 | 
                    break;  | 
 | 
                case GeneralNameInterface.NAME_WIDENS:  | 
 | 
                      | 
 | 
                    break;  | 
 | 
                case GeneralNameInterface.NAME_SAME_TYPE:  | 
 | 
                    break;  | 
 | 
                }  | 
 | 
            } /* end of this pass of permitted */  | 
 | 
        } /* end of pass of excluded */  | 
 | 
    }  | 
 | 
}  |