Path: blob/master/src/java.base/share/classes/sun/security/provider/certpath/ConstraintsChecker.java
41161 views
/*1* Copyright (c) 2000, 2015, 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.provider.certpath;2627import java.io.IOException;28import java.security.cert.Certificate;29import java.security.cert.CertificateException;30import java.security.cert.CertPathValidatorException;31import java.security.cert.PKIXCertPathChecker;32import java.security.cert.PKIXReason;33import java.security.cert.X509Certificate;34import java.util.Collection;35import java.util.Collections;36import java.util.HashSet;37import java.util.Set;3839import sun.security.util.Debug;40import static sun.security.x509.PKIXExtensions.*;41import sun.security.x509.NameConstraintsExtension;42import sun.security.x509.X509CertImpl;4344/**45* ConstraintsChecker is a <code>PKIXCertPathChecker</code> that checks46* constraints information on a PKIX certificate, namely basic constraints47* and name constraints.48*49* @since 1.450* @author Yassir Elley51*/52class ConstraintsChecker extends PKIXCertPathChecker {5354private static final Debug debug = Debug.getInstance("certpath");55/* length of cert path */56private final int certPathLength;57/* current maximum path length (as defined in PKIX) */58private int maxPathLength;59/* current index of cert */60private int i;61private NameConstraintsExtension prevNC;6263private Set<String> supportedExts;6465/**66* Creates a ConstraintsChecker.67*68* @param certPathLength the length of the certification path69*/70ConstraintsChecker(int certPathLength) {71this.certPathLength = certPathLength;72}7374@Override75public void init(boolean forward) throws CertPathValidatorException {76if (!forward) {77i = 0;78maxPathLength = certPathLength;79prevNC = null;80} else {81throw new CertPathValidatorException82("forward checking not supported");83}84}8586@Override87public boolean isForwardCheckingSupported() {88return false;89}9091@Override92public Set<String> getSupportedExtensions() {93if (supportedExts == null) {94supportedExts = new HashSet<String>(2);95supportedExts.add(BasicConstraints_Id.toString());96supportedExts.add(NameConstraints_Id.toString());97supportedExts = Collections.unmodifiableSet(supportedExts);98}99return supportedExts;100}101102/**103* Performs the basic constraints and name constraints104* checks on the certificate using its internal state.105*106* @param cert the <code>Certificate</code> to be checked107* @param unresCritExts a <code>Collection</code> of OID strings108* representing the current set of unresolved critical extensions109* @throws CertPathValidatorException if the specified certificate110* does not pass the check111*/112@Override113public void check(Certificate cert, Collection<String> unresCritExts)114throws CertPathValidatorException115{116X509Certificate currCert = (X509Certificate)cert;117118i++;119// MUST run NC check second, since it depends on BC check to120// update remainingCerts121checkBasicConstraints(currCert);122verifyNameConstraints(currCert);123124if (unresCritExts != null && !unresCritExts.isEmpty()) {125unresCritExts.remove(BasicConstraints_Id.toString());126unresCritExts.remove(NameConstraints_Id.toString());127}128}129130/**131* Internal method to check the name constraints against a cert132*/133private void verifyNameConstraints(X509Certificate currCert)134throws CertPathValidatorException135{136String msg = "name constraints";137if (debug != null) {138debug.println("---checking " + msg + "...");139}140141// check name constraints only if there is a previous name constraint142// and either the currCert is the final cert or the currCert is not143// self-issued144if (prevNC != null && ((i == certPathLength) ||145!X509CertImpl.isSelfIssued(currCert))) {146if (debug != null) {147debug.println("prevNC = " + prevNC +148", currDN = " + currCert.getSubjectX500Principal());149}150151try {152if (!prevNC.verify(currCert)) {153throw new CertPathValidatorException(msg + " check failed",154null, null, -1, PKIXReason.INVALID_NAME);155}156} catch (IOException ioe) {157throw new CertPathValidatorException(ioe);158}159}160161// merge name constraints regardless of whether cert is self-issued162prevNC = mergeNameConstraints(currCert, prevNC);163164if (debug != null)165debug.println(msg + " verified.");166}167168/**169* Helper to fold sets of name constraints together170*/171static NameConstraintsExtension mergeNameConstraints(172X509Certificate currCert, NameConstraintsExtension prevNC)173throws CertPathValidatorException174{175X509CertImpl currCertImpl;176try {177currCertImpl = X509CertImpl.toImpl(currCert);178} catch (CertificateException ce) {179throw new CertPathValidatorException(ce);180}181182NameConstraintsExtension newConstraints =183currCertImpl.getNameConstraintsExtension();184185if (debug != null) {186debug.println("prevNC = " + prevNC +187", newNC = " + String.valueOf(newConstraints));188}189190// if there are no previous name constraints, we just return the191// new name constraints.192if (prevNC == null) {193if (debug != null) {194debug.println("mergedNC = " + String.valueOf(newConstraints));195}196if (newConstraints == null) {197return newConstraints;198} else {199// Make sure we do a clone here, because we're probably200// going to modify this object later and we don't want to201// be sharing it with a Certificate object!202return (NameConstraintsExtension)newConstraints.clone();203}204} else {205try {206// after merge, prevNC should contain the merged constraints207prevNC.merge(newConstraints);208} catch (IOException ioe) {209throw new CertPathValidatorException(ioe);210}211if (debug != null) {212debug.println("mergedNC = " + prevNC);213}214return prevNC;215}216}217218/**219* Internal method to check that a given cert meets basic constraints.220*/221private void checkBasicConstraints(X509Certificate currCert)222throws CertPathValidatorException223{224String msg = "basic constraints";225if (debug != null) {226debug.println("---checking " + msg + "...");227debug.println("i = " + i +228", maxPathLength = " + maxPathLength);229}230231/* check if intermediate cert */232if (i < certPathLength) {233// RFC5280: If certificate i is a version 3 certificate, verify234// that the basicConstraints extension is present and that cA is235// set to TRUE. (If certificate i is a version 1 or version 2236// certificate, then the application MUST either verify that237// certificate i is a CA certificate through out-of-band means238// or reject the certificate. Conforming implementations may239// choose to reject all version 1 and version 2 intermediate240// certificates.)241//242// We choose to reject all version 1 and version 2 intermediate243// certificates except that it is self issued by the trust244// anchor in order to support key rollover or changes in245// certificate policies.246int pathLenConstraint = -1;247if (currCert.getVersion() < 3) { // version 1 or version 2248if (i == 1) { // issued by a trust anchor249if (X509CertImpl.isSelfIssued(currCert)) {250pathLenConstraint = Integer.MAX_VALUE;251}252}253} else {254pathLenConstraint = currCert.getBasicConstraints();255}256257if (pathLenConstraint == -1) {258throw new CertPathValidatorException259(msg + " check failed: this is not a CA certificate",260null, null, -1, PKIXReason.NOT_CA_CERT);261}262263if (!X509CertImpl.isSelfIssued(currCert)) {264if (maxPathLength <= 0) {265throw new CertPathValidatorException266(msg + " check failed: pathLenConstraint violated - "267+ "this cert must be the last cert in the "268+ "certification path", null, null, -1,269PKIXReason.PATH_TOO_LONG);270}271maxPathLength--;272}273if (pathLenConstraint < maxPathLength)274maxPathLength = pathLenConstraint;275}276277if (debug != null) {278debug.println("after processing, maxPathLength = " + maxPathLength);279debug.println(msg + " verified.");280}281}282283/**284* Merges the specified maxPathLength with the pathLenConstraint285* obtained from the certificate.286*287* @param cert the <code>X509Certificate</code>288* @param maxPathLength the previous maximum path length289* @return the new maximum path length constraint (-1 means no more290* certificates can follow, Integer.MAX_VALUE means path length is291* unconstrained)292*/293static int mergeBasicConstraints(X509Certificate cert, int maxPathLength) {294295int pathLenConstraint = cert.getBasicConstraints();296297if (!X509CertImpl.isSelfIssued(cert)) {298maxPathLength--;299}300301if (pathLenConstraint < maxPathLength) {302maxPathLength = pathLenConstraint;303}304305return maxPathLength;306}307}308309310