Home | History | Annotate | Download | only in certpath
      1 /*
      2  * Copyright (c) 2000, 2012, Oracle and/or its affiliates. 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.  Oracle designates this
      8  * particular file as subject to the "Classpath" exception as provided
      9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     22  * or visit www.oracle.com if you need additional information or have any
     23  * questions.
     24  */
     25 
     26 package sun.security.provider.certpath;
     27 
     28 import java.io.IOException;
     29 import java.security.cert.CertificateException;
     30 import java.security.cert.CertPathValidatorException;
     31 import java.security.cert.PKIXCertPathChecker;
     32 import java.security.cert.X509Certificate;
     33 import java.util.ArrayList;
     34 import java.util.HashSet;
     35 import java.util.List;
     36 import java.util.ListIterator;
     37 import javax.security.auth.x500.X500Principal;
     38 
     39 import sun.security.util.Debug;
     40 import sun.security.x509.SubjectAlternativeNameExtension;
     41 import sun.security.x509.GeneralNames;
     42 import sun.security.x509.GeneralName;
     43 import sun.security.x509.GeneralNameInterface;
     44 import sun.security.x509.X500Name;
     45 import sun.security.x509.X509CertImpl;
     46 
     47 /**
     48  * A specification of a forward PKIX validation state
     49  * which is initialized by each build and updated each time a
     50  * certificate is added to the current path.
     51  * @since       1.4
     52  * @author      Yassir Elley
     53  */
     54 class ForwardState implements State {
     55 
     56     private static final Debug debug = Debug.getInstance("certpath");
     57 
     58     /* The issuer DN of the last cert in the path */
     59     X500Principal issuerDN;
     60 
     61     /* The last cert in the path */
     62     X509CertImpl cert;
     63 
     64     /* The set of subjectDNs and subjectAltNames of all certs in the path */
     65     HashSet<GeneralNameInterface> subjectNamesTraversed;
     66 
     67     /*
     68      * The number of intermediate CA certs which have been traversed so
     69      * far in the path
     70      */
     71     int traversedCACerts;
     72 
     73     /* Flag indicating if state is initial (path is just starting) */
     74     private boolean init = true;
     75 
     76 
     77     /* the untrusted certificates checker */
     78     UntrustedChecker untrustedChecker;
     79 
     80     /* The list of user-defined checkers that support forward checking */
     81     ArrayList<PKIXCertPathChecker> forwardCheckers;
     82 
     83     /* Flag indicating if key needing to inherit key parameters has been
     84      * encountered.
     85      */
     86     boolean keyParamsNeededFlag = false;
     87 
     88     /**
     89      * Returns a boolean flag indicating if the state is initial
     90      * (just starting)
     91      *
     92      * @return boolean flag indicating if the state is initial (just starting)
     93      */
     94     @Override
     95     public boolean isInitial() {
     96         return init;
     97     }
     98 
     99     /**
    100      * Return boolean flag indicating whether a public key that needs to inherit
    101      * key parameters has been encountered.
    102      *
    103      * @return boolean true if key needing to inherit parameters has been
    104      * encountered; false otherwise.
    105      */
    106     @Override
    107     public boolean keyParamsNeeded() {
    108         return keyParamsNeededFlag;
    109     }
    110 
    111     /**
    112      * Display state for debugging purposes
    113      */
    114     @Override
    115     public String toString() {
    116         StringBuilder sb = new StringBuilder();
    117         sb.append("State [");
    118         sb.append("\n  issuerDN of last cert: ").append(issuerDN);
    119         sb.append("\n  traversedCACerts: ").append(traversedCACerts);
    120         sb.append("\n  init: ").append(String.valueOf(init));
    121         sb.append("\n  keyParamsNeeded: ").append
    122                  (String.valueOf(keyParamsNeededFlag));
    123         sb.append("\n  subjectNamesTraversed: \n").append
    124                  (subjectNamesTraversed);
    125         sb.append("]\n");
    126         return sb.toString();
    127     }
    128 
    129     /**
    130      * Initialize the state.
    131      *
    132      * @param certPathCheckers the list of user-defined PKIXCertPathCheckers
    133      */
    134     public void initState(List<PKIXCertPathChecker> certPathCheckers)
    135         throws CertPathValidatorException
    136     {
    137         subjectNamesTraversed = new HashSet<GeneralNameInterface>();
    138         traversedCACerts = 0;
    139 
    140         /*
    141          * Populate forwardCheckers with every user-defined checker
    142          * that supports forward checking and initialize the forwardCheckers
    143          */
    144         forwardCheckers = new ArrayList<PKIXCertPathChecker>();
    145         for (PKIXCertPathChecker checker : certPathCheckers) {
    146             if (checker.isForwardCheckingSupported()) {
    147                 checker.init(true);
    148                 forwardCheckers.add(checker);
    149             }
    150         }
    151 
    152         init = true;
    153     }
    154 
    155     /**
    156      * Update the state with the next certificate added to the path.
    157      *
    158      * @param cert the certificate which is used to update the state
    159      */
    160     @Override
    161     public void updateState(X509Certificate cert)
    162         throws CertificateException, IOException, CertPathValidatorException {
    163 
    164         if (cert == null)
    165             return;
    166 
    167         X509CertImpl icert = X509CertImpl.toImpl(cert);
    168 
    169         /* see if certificate key has null parameters */
    170         if (PKIX.isDSAPublicKeyWithoutParams(icert.getPublicKey())) {
    171             keyParamsNeededFlag = true;
    172         }
    173 
    174         /* update certificate */
    175         this.cert = icert;
    176 
    177         /* update issuer DN */
    178         issuerDN = cert.getIssuerX500Principal();
    179 
    180         if (!X509CertImpl.isSelfIssued(cert)) {
    181 
    182             /*
    183              * update traversedCACerts only if this is a non-self-issued
    184              * intermediate CA cert
    185              */
    186             if (!init && cert.getBasicConstraints() != -1) {
    187                 traversedCACerts++;
    188             }
    189         }
    190 
    191         /* update subjectNamesTraversed only if this is the EE cert or if
    192            this cert is not self-issued */
    193         if (init || !X509CertImpl.isSelfIssued(cert)){
    194             X500Principal subjName = cert.getSubjectX500Principal();
    195             subjectNamesTraversed.add(X500Name.asX500Name(subjName));
    196 
    197             try {
    198                 SubjectAlternativeNameExtension subjAltNameExt
    199                     = icert.getSubjectAlternativeNameExtension();
    200                 if (subjAltNameExt != null) {
    201                     GeneralNames gNames = subjAltNameExt.get(
    202                             SubjectAlternativeNameExtension.SUBJECT_NAME);
    203                     for (GeneralName gName : gNames.names()) {
    204                         subjectNamesTraversed.add(gName.getName());
    205                     }
    206                 }
    207             } catch (IOException e) {
    208                 if (debug != null) {
    209                     debug.println("ForwardState.updateState() unexpected "
    210                         + "exception");
    211                     e.printStackTrace();
    212                 }
    213                 throw new CertPathValidatorException(e);
    214             }
    215         }
    216 
    217         init = false;
    218     }
    219 
    220     /*
    221      * Clone current state. The state is cloned as each cert is
    222      * added to the path. This is necessary if backtracking occurs,
    223      * and a prior state needs to be restored.
    224      *
    225      * Note that this is a SMART clone. Not all fields are fully copied,
    226      * because some of them will
    227      * not have their contents modified by subsequent calls to updateState.
    228      */
    229     @Override
    230     @SuppressWarnings("unchecked") // Safe casts assuming clone() works correctly
    231     public Object clone() {
    232         try {
    233             ForwardState clonedState = (ForwardState) super.clone();
    234 
    235             /* clone checkers, if cloneable */
    236             clonedState.forwardCheckers = (ArrayList<PKIXCertPathChecker>)
    237                                                 forwardCheckers.clone();
    238             ListIterator<PKIXCertPathChecker> li =
    239                                 clonedState.forwardCheckers.listIterator();
    240             while (li.hasNext()) {
    241                 PKIXCertPathChecker checker = li.next();
    242                 if (checker instanceof Cloneable) {
    243                     li.set((PKIXCertPathChecker)checker.clone());
    244                 }
    245             }
    246 
    247             /*
    248              * Shallow copy traversed names. There is no need to
    249              * deep copy contents, since the elements of the Set
    250              * are never modified by subsequent calls to updateState().
    251              */
    252             clonedState.subjectNamesTraversed
    253                 = (HashSet<GeneralNameInterface>)subjectNamesTraversed.clone();
    254             return clonedState;
    255         } catch (CloneNotSupportedException e) {
    256             throw new InternalError(e.toString(), e);
    257         }
    258     }
    259 }
    260