| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
 | 
 | 
package sun.security.provider.certpath;  | 
 | 
 | 
 | 
import java.io.IOException;  | 
 | 
import java.security.cert.Certificate;  | 
 | 
import java.security.cert.CertificateException;  | 
 | 
import java.security.cert.CertPathValidatorException;  | 
 | 
import java.security.cert.PKIXCertPathChecker;  | 
 | 
import java.security.cert.PKIXReason;  | 
 | 
import java.security.cert.X509Certificate;  | 
 | 
import java.util.Collection;  | 
 | 
import java.util.Collections;  | 
 | 
import java.util.HashSet;  | 
 | 
import java.util.Set;  | 
 | 
 | 
 | 
import sun.security.util.Debug;  | 
 | 
import static sun.security.x509.PKIXExtensions.*;  | 
 | 
import sun.security.x509.NameConstraintsExtension;  | 
 | 
import sun.security.x509.X509CertImpl;  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
class ConstraintsChecker extends PKIXCertPathChecker { | 
 | 
 | 
 | 
    private static final Debug debug = Debug.getInstance("certpath"); | 
 | 
      | 
 | 
    private final int certPathLength;  | 
 | 
      | 
 | 
    private int maxPathLength;  | 
 | 
      | 
 | 
    private int i;  | 
 | 
    private NameConstraintsExtension prevNC;  | 
 | 
 | 
 | 
    private Set<String> supportedExts;  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    ConstraintsChecker(int certPathLength) { | 
 | 
        this.certPathLength = certPathLength;  | 
 | 
    }  | 
 | 
 | 
 | 
    @Override  | 
 | 
    public void init(boolean forward) throws CertPathValidatorException { | 
 | 
        if (!forward) { | 
 | 
            i = 0;  | 
 | 
            maxPathLength = certPathLength;  | 
 | 
            prevNC = null;  | 
 | 
        } else { | 
 | 
            throw new CertPathValidatorException  | 
 | 
                ("forward checking not supported"); | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    @Override  | 
 | 
    public boolean isForwardCheckingSupported() { | 
 | 
        return false;  | 
 | 
    }  | 
 | 
 | 
 | 
    @Override  | 
 | 
    public Set<String> getSupportedExtensions() { | 
 | 
        if (supportedExts == null) { | 
 | 
            supportedExts = new HashSet<String>(2);  | 
 | 
            supportedExts.add(BasicConstraints_Id.toString());  | 
 | 
            supportedExts.add(NameConstraints_Id.toString());  | 
 | 
            supportedExts = Collections.unmodifiableSet(supportedExts);  | 
 | 
        }  | 
 | 
        return supportedExts;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    @Override  | 
 | 
    public void check(Certificate cert, Collection<String> unresCritExts)  | 
 | 
        throws CertPathValidatorException  | 
 | 
    { | 
 | 
        X509Certificate currCert = (X509Certificate)cert;  | 
 | 
 | 
 | 
        i++;  | 
 | 
        // MUST run NC check second, since it depends on BC check to  | 
 | 
          | 
 | 
        checkBasicConstraints(currCert);  | 
 | 
        verifyNameConstraints(currCert);  | 
 | 
 | 
 | 
        if (unresCritExts != null && !unresCritExts.isEmpty()) { | 
 | 
            unresCritExts.remove(BasicConstraints_Id.toString());  | 
 | 
            unresCritExts.remove(NameConstraints_Id.toString());  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private void verifyNameConstraints(X509Certificate currCert)  | 
 | 
        throws CertPathValidatorException  | 
 | 
    { | 
 | 
        String msg = "name constraints";  | 
 | 
        if (debug != null) { | 
 | 
            debug.println("---checking " + msg + "..."); | 
 | 
        }  | 
 | 
 | 
 | 
        // check name constraints only if there is a previous name constraint  | 
 | 
        // and either the currCert is the final cert or the currCert is not  | 
 | 
          | 
 | 
        if (prevNC != null && ((i == certPathLength) ||  | 
 | 
                !X509CertImpl.isSelfIssued(currCert))) { | 
 | 
            if (debug != null) { | 
 | 
                debug.println("prevNC = " + prevNC + | 
 | 
                    ", currDN = " + currCert.getSubjectX500Principal());  | 
 | 
            }  | 
 | 
 | 
 | 
            try { | 
 | 
                if (!prevNC.verify(currCert)) { | 
 | 
                    throw new CertPathValidatorException(msg + " check failed",  | 
 | 
                        null, null, -1, PKIXReason.INVALID_NAME);  | 
 | 
                }  | 
 | 
            } catch (IOException ioe) { | 
 | 
                throw new CertPathValidatorException(ioe);  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
          | 
 | 
        prevNC = mergeNameConstraints(currCert, prevNC);  | 
 | 
 | 
 | 
        if (debug != null)  | 
 | 
            debug.println(msg + " verified.");  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    static NameConstraintsExtension mergeNameConstraints(  | 
 | 
        X509Certificate currCert, NameConstraintsExtension prevNC)  | 
 | 
        throws CertPathValidatorException  | 
 | 
    { | 
 | 
        X509CertImpl currCertImpl;  | 
 | 
        try { | 
 | 
            currCertImpl = X509CertImpl.toImpl(currCert);  | 
 | 
        } catch (CertificateException ce) { | 
 | 
            throw new CertPathValidatorException(ce);  | 
 | 
        }  | 
 | 
 | 
 | 
        NameConstraintsExtension newConstraints =  | 
 | 
            currCertImpl.getNameConstraintsExtension();  | 
 | 
 | 
 | 
        if (debug != null) { | 
 | 
            debug.println("prevNC = " + prevNC + | 
 | 
                        ", newNC = " + String.valueOf(newConstraints));  | 
 | 
        }  | 
 | 
 | 
 | 
        // if there are no previous name constraints, we just return the  | 
 | 
          | 
 | 
        if (prevNC == null) { | 
 | 
            if (debug != null) { | 
 | 
                debug.println("mergedNC = " + String.valueOf(newConstraints)); | 
 | 
            }  | 
 | 
            if (newConstraints == null) { | 
 | 
                return newConstraints;  | 
 | 
            } else { | 
 | 
                // Make sure we do a clone here, because we're probably  | 
 | 
                // going to modify this object later and we don't want to  | 
 | 
                  | 
 | 
                return (NameConstraintsExtension)newConstraints.clone();  | 
 | 
            }  | 
 | 
        } else { | 
 | 
            try { | 
 | 
                  | 
 | 
                prevNC.merge(newConstraints);  | 
 | 
            } catch (IOException ioe) { | 
 | 
                throw new CertPathValidatorException(ioe);  | 
 | 
            }  | 
 | 
            if (debug != null) { | 
 | 
                debug.println("mergedNC = " + prevNC); | 
 | 
            }  | 
 | 
            return prevNC;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private void checkBasicConstraints(X509Certificate currCert)  | 
 | 
        throws CertPathValidatorException  | 
 | 
    { | 
 | 
        String msg = "basic constraints";  | 
 | 
        if (debug != null) { | 
 | 
            debug.println("---checking " + msg + "..."); | 
 | 
            debug.println("i = " + i + | 
 | 
                        ", maxPathLength = " + maxPathLength);  | 
 | 
        }  | 
 | 
 | 
 | 
          | 
 | 
        if (i < certPathLength) { | 
 | 
            // RFC5280: If certificate i is a version 3 certificate, verify  | 
 | 
            // that the basicConstraints extension is present and that cA is  | 
 | 
            // set to TRUE.  (If certificate i is a version 1 or version 2  | 
 | 
            // certificate, then the application MUST either verify that  | 
 | 
            // certificate i is a CA certificate through out-of-band means  | 
 | 
            // or reject the certificate.  Conforming implementations may  | 
 | 
            // choose to reject all version 1 and version 2 intermediate  | 
 | 
            // certificates.)  | 
 | 
            //  | 
 | 
            // We choose to reject all version 1 and version 2 intermediate  | 
 | 
            // certificates except that it is self issued by the trust  | 
 | 
            // anchor in order to support key rollover or changes in  | 
 | 
              | 
 | 
            int pathLenConstraint = -1;  | 
 | 
            if (currCert.getVersion() < 3) {     | 
 | 
                if (i == 1) {                    | 
 | 
                    if (X509CertImpl.isSelfIssued(currCert)) { | 
 | 
                        pathLenConstraint = Integer.MAX_VALUE;  | 
 | 
                    }  | 
 | 
                }  | 
 | 
            } else { | 
 | 
                pathLenConstraint = currCert.getBasicConstraints();  | 
 | 
            }  | 
 | 
 | 
 | 
            if (pathLenConstraint == -1) { | 
 | 
                throw new CertPathValidatorException  | 
 | 
                    (msg + " check failed: this is not a CA certificate",  | 
 | 
                     null, null, -1, PKIXReason.NOT_CA_CERT);  | 
 | 
            }  | 
 | 
 | 
 | 
            if (!X509CertImpl.isSelfIssued(currCert)) { | 
 | 
                if (maxPathLength <= 0) { | 
 | 
                   throw new CertPathValidatorException  | 
 | 
                        (msg + " check failed: pathLenConstraint violated - "  | 
 | 
                         + "this cert must be the last cert in the "  | 
 | 
                         + "certification path", null, null, -1,  | 
 | 
                         PKIXReason.PATH_TOO_LONG);  | 
 | 
                }  | 
 | 
                maxPathLength--;  | 
 | 
            }  | 
 | 
            if (pathLenConstraint < maxPathLength)  | 
 | 
                maxPathLength = pathLenConstraint;  | 
 | 
        }  | 
 | 
 | 
 | 
        if (debug != null) { | 
 | 
            debug.println("after processing, maxPathLength = " + maxPathLength); | 
 | 
            debug.println(msg + " verified.");  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    static int mergeBasicConstraints(X509Certificate cert, int maxPathLength) { | 
 | 
 | 
 | 
        int pathLenConstraint = cert.getBasicConstraints();  | 
 | 
 | 
 | 
        if (!X509CertImpl.isSelfIssued(cert)) { | 
 | 
            maxPathLength--;  | 
 | 
        }  | 
 | 
 | 
 | 
        if (pathLenConstraint < maxPathLength) { | 
 | 
            maxPathLength = pathLenConstraint;  | 
 | 
        }  | 
 | 
 | 
 | 
        return maxPathLength;  | 
 | 
    }  | 
 | 
}  |