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