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     // Android-removed: Android doesn't use this mechanism for checking untrusted certificates.
     79     // UntrustedChecker untrustedChecker;
     80 
     81     /* The list of user-defined checkers that support forward checking */
     82     ArrayList<PKIXCertPathChecker> forwardCheckers;
     83 
     84     /* Flag indicating if key needing to inherit key parameters has been
     85      * encountered.
     86      */
     87     boolean keyParamsNeededFlag = false;
     88 
     89     /**
     90      * Returns a boolean flag indicating if the state is initial
     91      * (just starting)
     92      *
     93      * @return boolean flag indicating if the state is initial (just starting)
     94      */
     95     @Override
     96     public boolean isInitial() {
     97         return init;
     98     }
     99 
    100     /**
    101      * Return boolean flag indicating whether a public key that needs to inherit
    102      * key parameters has been encountered.
    103      *
    104      * @return boolean true if key needing to inherit parameters has been
    105      * encountered; false otherwise.
    106      */
    107     @Override
    108     public boolean keyParamsNeeded() {
    109         return keyParamsNeededFlag;
    110     }
    111 
    112     /**
    113      * Display state for debugging purposes
    114      */
    115     @Override
    116     public String toString() {
    117         StringBuilder sb = new StringBuilder();
    118         sb.append("State [");
    119         sb.append("\n  issuerDN of last cert: ").append(issuerDN);
    120         sb.append("\n  traversedCACerts: ").append(traversedCACerts);
    121         sb.append("\n  init: ").append(String.valueOf(init));
    122         sb.append("\n  keyParamsNeeded: ").append
    123                  (String.valueOf(keyParamsNeededFlag));
    124         sb.append("\n  subjectNamesTraversed: \n").append
    125                  (subjectNamesTraversed);
    126         sb.append("]\n");
    127         return sb.toString();
    128     }
    129 
    130     /**
    131      * Initialize the state.
    132      *
    133      * @param certPathCheckers the list of user-defined PKIXCertPathCheckers
    134      */
    135     public void initState(List<PKIXCertPathChecker> certPathCheckers)
    136         throws CertPathValidatorException
    137     {
    138         subjectNamesTraversed = new HashSet<GeneralNameInterface>();
    139         traversedCACerts = 0;
    140 
    141         /*
    142          * Populate forwardCheckers with every user-defined checker
    143          * that supports forward checking and initialize the forwardCheckers
    144          */
    145         forwardCheckers = new ArrayList<PKIXCertPathChecker>();
    146         for (PKIXCertPathChecker checker : certPathCheckers) {
    147             if (checker.isForwardCheckingSupported()) {
    148                 checker.init(true);
    149                 forwardCheckers.add(checker);
    150             }
    151         }
    152 
    153         init = true;
    154     }
    155 
    156     /**
    157      * Update the state with the next certificate added to the path.
    158      *
    159      * @param cert the certificate which is used to update the state
    160      */
    161     @Override
    162     public void updateState(X509Certificate cert)
    163         throws CertificateException, IOException, CertPathValidatorException {
    164 
    165         if (cert == null)
    166             return;
    167 
    168         X509CertImpl icert = X509CertImpl.toImpl(cert);
    169 
    170         /* see if certificate key has null parameters */
    171         if (PKIX.isDSAPublicKeyWithoutParams(icert.getPublicKey())) {
    172             keyParamsNeededFlag = true;
    173         }
    174 
    175         /* update certificate */
    176         this.cert = icert;
    177 
    178         /* update issuer DN */
    179         issuerDN = cert.getIssuerX500Principal();
    180 
    181         if (!X509CertImpl.isSelfIssued(cert)) {
    182 
    183             /*
    184              * update traversedCACerts only if this is a non-self-issued
    185              * intermediate CA cert
    186              */
    187             if (!init && cert.getBasicConstraints() != -1) {
    188                 traversedCACerts++;
    189             }
    190         }
    191 
    192         /* update subjectNamesTraversed only if this is the EE cert or if
    193            this cert is not self-issued */
    194         if (init || !X509CertImpl.isSelfIssued(cert)){
    195             X500Principal subjName = cert.getSubjectX500Principal();
    196             subjectNamesTraversed.add(X500Name.asX500Name(subjName));
    197 
    198             try {
    199                 SubjectAlternativeNameExtension subjAltNameExt
    200                     = icert.getSubjectAlternativeNameExtension();
    201                 if (subjAltNameExt != null) {
    202                     GeneralNames gNames = subjAltNameExt.get(
    203                             SubjectAlternativeNameExtension.SUBJECT_NAME);
    204                     for (GeneralName gName : gNames.names()) {
    205                         subjectNamesTraversed.add(gName.getName());
    206                     }
    207                 }
    208             } catch (IOException e) {
    209                 if (debug != null) {
    210                     debug.println("ForwardState.updateState() unexpected "
    211                         + "exception");
    212                     e.printStackTrace();
    213                 }
    214                 throw new CertPathValidatorException(e);
    215             }
    216         }
    217 
    218         init = false;
    219     }
    220 
    221     /*
    222      * Clone current state. The state is cloned as each cert is
    223      * added to the path. This is necessary if backtracking occurs,
    224      * and a prior state needs to be restored.
    225      *
    226      * Note that this is a SMART clone. Not all fields are fully copied,
    227      * because some of them will
    228      * not have their contents modified by subsequent calls to updateState.
    229      */
    230     @Override
    231     @SuppressWarnings("unchecked") // Safe casts assuming clone() works correctly
    232     public Object clone() {
    233         try {
    234             ForwardState clonedState = (ForwardState) super.clone();
    235 
    236             /* clone checkers, if cloneable */
    237             clonedState.forwardCheckers = (ArrayList<PKIXCertPathChecker>)
    238                                                 forwardCheckers.clone();
    239             ListIterator<PKIXCertPathChecker> li =
    240                                 clonedState.forwardCheckers.listIterator();
    241             while (li.hasNext()) {
    242                 PKIXCertPathChecker checker = li.next();
    243                 if (checker instanceof Cloneable) {
    244                     li.set((PKIXCertPathChecker)checker.clone());
    245                 }
    246             }
    247 
    248             /*
    249              * Shallow copy traversed names. There is no need to
    250              * deep copy contents, since the elements of the Set
    251              * are never modified by subsequent calls to updateState().
    252              */
    253             clonedState.subjectNamesTraversed
    254                 = (HashSet<GeneralNameInterface>)subjectNamesTraversed.clone();
    255             return clonedState;
    256         } catch (CloneNotSupportedException e) {
    257             throw new InternalError(e.toString(), e);
    258         }
    259     }
    260 }
    261