View Javadoc
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 }