jdk/src/share/classes/sun/security/provider/certpath/ConstraintsChecker.java
changeset 2 90ce3da70b43
child 790 b91742db13e2
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Copyright 2000-2006 Sun Microsystems, Inc.  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.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 package sun.security.provider.certpath;
       
    27 
       
    28 import java.util.Collection;
       
    29 import java.util.Collections;
       
    30 import java.util.Set;
       
    31 import java.util.HashSet;
       
    32 import java.io.IOException;
       
    33 import java.security.cert.Certificate;
       
    34 import java.security.cert.CertificateException;
       
    35 import java.security.cert.X509Certificate;
       
    36 import java.security.cert.PKIXCertPathChecker;
       
    37 import java.security.cert.CertPathValidatorException;
       
    38 import sun.security.util.Debug;
       
    39 import sun.security.x509.PKIXExtensions;
       
    40 import sun.security.x509.NameConstraintsExtension;
       
    41 import sun.security.x509.X509CertImpl;
       
    42 
       
    43 /**
       
    44  * ConstraintsChecker is a <code>PKIXCertPathChecker</code> that checks
       
    45  * constraints information on a PKIX certificate, namely basic constraints
       
    46  * and name constraints.
       
    47  *
       
    48  * @since       1.4
       
    49  * @author      Yassir Elley
       
    50  */
       
    51 class ConstraintsChecker extends PKIXCertPathChecker {
       
    52 
       
    53     private static final Debug debug = Debug.getInstance("certpath");
       
    54     /* length of cert path */
       
    55     private final int certPathLength;
       
    56     /* current maximum path length (as defined in PKIX) */
       
    57     private int maxPathLength;
       
    58     /* current index of cert */
       
    59     private int i;
       
    60     private NameConstraintsExtension prevNC;
       
    61 
       
    62     private static Set<String> supportedExts;
       
    63 
       
    64     /**
       
    65      * Creates a ConstraintsChecker.
       
    66      *
       
    67      * @param certPathLength the length of the certification path
       
    68      * @throws CertPathValidatorException if the checker cannot be initialized
       
    69      */
       
    70     ConstraintsChecker(int certPathLength) throws CertPathValidatorException {
       
    71         this.certPathLength = certPathLength;
       
    72         init(false);
       
    73     }
       
    74 
       
    75     public void init(boolean forward) throws CertPathValidatorException {
       
    76         if (!forward) {
       
    77             i = 0;
       
    78             maxPathLength = certPathLength;
       
    79             prevNC = null;
       
    80         } else {
       
    81             throw new CertPathValidatorException
       
    82                 ("forward checking not supported");
       
    83         }
       
    84     }
       
    85 
       
    86     public boolean isForwardCheckingSupported() {
       
    87         return false;
       
    88     }
       
    89 
       
    90     public Set<String> getSupportedExtensions() {
       
    91         if (supportedExts == null) {
       
    92             supportedExts = new HashSet<String>();
       
    93             supportedExts.add(PKIXExtensions.BasicConstraints_Id.toString());
       
    94             supportedExts.add(PKIXExtensions.NameConstraints_Id.toString());
       
    95             supportedExts = Collections.unmodifiableSet(supportedExts);
       
    96         }
       
    97         return supportedExts;
       
    98     }
       
    99 
       
   100     /**
       
   101      * Performs the basic constraints and name constraints
       
   102      * checks on the certificate using its internal state.
       
   103      *
       
   104      * @param cert the <code>Certificate</code> to be checked
       
   105      * @param unresCritExts a <code>Collection</code> of OID strings
       
   106      * representing the current set of unresolved critical extensions
       
   107      * @throws CertPathValidatorException if the specified certificate
       
   108      * does not pass the check
       
   109      */
       
   110     public void check(Certificate cert, Collection<String> unresCritExts)
       
   111         throws CertPathValidatorException
       
   112     {
       
   113         X509Certificate currCert = (X509Certificate) cert;
       
   114 
       
   115         i++;
       
   116         // MUST run NC check second, since it depends on BC check to
       
   117         // update remainingCerts
       
   118         checkBasicConstraints(currCert);
       
   119         verifyNameConstraints(currCert);
       
   120 
       
   121         if (unresCritExts != null && !unresCritExts.isEmpty()) {
       
   122             unresCritExts.remove(PKIXExtensions.BasicConstraints_Id.toString());
       
   123             unresCritExts.remove(PKIXExtensions.NameConstraints_Id.toString());
       
   124         }
       
   125     }
       
   126 
       
   127     /**
       
   128      * Internal method to check the name constraints against a cert
       
   129      */
       
   130     private void verifyNameConstraints(X509Certificate currCert)
       
   131         throws CertPathValidatorException
       
   132     {
       
   133         String msg = "name constraints";
       
   134         if (debug != null) {
       
   135             debug.println("---checking " + msg + "...");
       
   136         }
       
   137 
       
   138         // check name constraints only if there is a previous name constraint
       
   139         // and either the currCert is the final cert or the currCert is not
       
   140         // self-issued
       
   141         if (prevNC != null && ((i == certPathLength) ||
       
   142                 !X509CertImpl.isSelfIssued(currCert))) {
       
   143             if (debug != null) {
       
   144                 debug.println("prevNC = " + prevNC);
       
   145                 debug.println("currDN = " + currCert.getSubjectX500Principal());
       
   146             }
       
   147 
       
   148             try {
       
   149                 if (!prevNC.verify(currCert)) {
       
   150                     throw new CertPathValidatorException(msg + " check failed");
       
   151                 }
       
   152             } catch (IOException ioe) {
       
   153                 throw new CertPathValidatorException(ioe);
       
   154             }
       
   155         }
       
   156 
       
   157         // merge name constraints regardless of whether cert is self-issued
       
   158         prevNC = mergeNameConstraints(currCert, prevNC);
       
   159 
       
   160         if (debug != null)
       
   161             debug.println(msg + " verified.");
       
   162     }
       
   163 
       
   164     /**
       
   165      * Helper to fold sets of name constraints together
       
   166      */
       
   167     static NameConstraintsExtension
       
   168         mergeNameConstraints(X509Certificate currCert,
       
   169             NameConstraintsExtension prevNC) throws CertPathValidatorException
       
   170     {
       
   171         X509CertImpl currCertImpl;
       
   172         try {
       
   173             currCertImpl = X509CertImpl.toImpl(currCert);
       
   174         } catch (CertificateException ce) {
       
   175             throw new CertPathValidatorException(ce);
       
   176         }
       
   177 
       
   178         NameConstraintsExtension newConstraints =
       
   179             currCertImpl.getNameConstraintsExtension();
       
   180 
       
   181         if (debug != null) {
       
   182             debug.println("prevNC = " + prevNC);
       
   183             debug.println("newNC = " + String.valueOf(newConstraints));
       
   184         }
       
   185 
       
   186         // if there are no previous name constraints, we just return the
       
   187         // new name constraints.
       
   188         if (prevNC == null) {
       
   189             if (debug != null) {
       
   190                 debug.println("mergedNC = " + String.valueOf(newConstraints));
       
   191             }
       
   192             if (newConstraints == null) {
       
   193                 return newConstraints;
       
   194             } else {
       
   195                 // Make sure we do a clone here, because we're probably
       
   196                 // going to modify this object later and we don't want to
       
   197                 // be sharing it with a Certificate object!
       
   198                 return (NameConstraintsExtension) newConstraints.clone();
       
   199             }
       
   200         } else {
       
   201             try {
       
   202                 // after merge, prevNC should contain the merged constraints
       
   203                 prevNC.merge(newConstraints);
       
   204             } catch (IOException ioe) {
       
   205                 throw new CertPathValidatorException(ioe);
       
   206             }
       
   207             if (debug != null) {
       
   208                 debug.println("mergedNC = " + prevNC);
       
   209             }
       
   210             return prevNC;
       
   211         }
       
   212     }
       
   213 
       
   214     /**
       
   215      * Internal method to check that a given cert meets basic constraints.
       
   216      */
       
   217     private void checkBasicConstraints(X509Certificate currCert)
       
   218         throws CertPathValidatorException
       
   219     {
       
   220         String msg = "basic constraints";
       
   221         if (debug != null) {
       
   222             debug.println("---checking " + msg + "...");
       
   223             debug.println("i = " + i);
       
   224             debug.println("maxPathLength = " + maxPathLength);
       
   225         }
       
   226 
       
   227         /* check if intermediate cert */
       
   228         if (i < certPathLength) {
       
   229             int pathLenConstraint = currCert.getBasicConstraints();
       
   230             if (pathLenConstraint == -1) {
       
   231                 throw new CertPathValidatorException(msg + " check failed: "
       
   232                     + "this is not a CA certificate");
       
   233             }
       
   234 
       
   235             if (!X509CertImpl.isSelfIssued(currCert)) {
       
   236                 if (maxPathLength <= 0) {
       
   237                    throw new CertPathValidatorException
       
   238                         (msg + " check failed: pathLenConstraint violated - "
       
   239                          + "this cert must be the last cert in the "
       
   240                          + "certification path");
       
   241                 }
       
   242                 maxPathLength--;
       
   243             }
       
   244             if (pathLenConstraint < maxPathLength)
       
   245                 maxPathLength = pathLenConstraint;
       
   246         }
       
   247 
       
   248         if (debug != null) {
       
   249             debug.println("after processing, maxPathLength = " + maxPathLength);
       
   250             debug.println(msg + " verified.");
       
   251         }
       
   252     }
       
   253 
       
   254     /**
       
   255      * Merges the specified maxPathLength with the pathLenConstraint
       
   256      * obtained from the certificate.
       
   257      *
       
   258      * @param cert the <code>X509Certificate</code>
       
   259      * @param maxPathLength the previous maximum path length
       
   260      * @return the new maximum path length constraint (-1 means no more
       
   261      * certificates can follow, Integer.MAX_VALUE means path length is
       
   262      * unconstrained)
       
   263      */
       
   264     static int mergeBasicConstraints(X509Certificate cert, int maxPathLength) {
       
   265 
       
   266         int pathLenConstraint = cert.getBasicConstraints();
       
   267 
       
   268         if (!X509CertImpl.isSelfIssued(cert)) {
       
   269             maxPathLength--;
       
   270         }
       
   271 
       
   272         if (pathLenConstraint < maxPathLength) {
       
   273             maxPathLength = pathLenConstraint;
       
   274         }
       
   275 
       
   276         return maxPathLength;
       
   277     }
       
   278 }