• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
isInitial()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
keyParamsNeeded()107     public boolean keyParamsNeeded() {
108         return keyParamsNeededFlag;
109     }
110 
111     /**
112      * Display state for debugging purposes
113      */
114     @Override
toString()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      */
initState(List<PKIXCertPathChecker> certPathCheckers)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
updateState(X509Certificate cert)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
clone()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