• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2000, 2013, 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.PublicKey;
30 import java.security.cert.CertificateException;
31 import java.security.cert.CertPathValidatorException;
32 import java.security.cert.PKIXCertPathChecker;
33 import java.security.cert.PKIXRevocationChecker;
34 import java.security.cert.TrustAnchor;
35 import java.security.cert.X509Certificate;
36 import java.util.ArrayList;
37 import java.util.HashSet;
38 import java.util.List;
39 import java.util.ListIterator;
40 import java.util.Set;
41 import javax.security.auth.x500.X500Principal;
42 
43 import sun.security.provider.certpath.PKIX.BuilderParams;
44 import sun.security.util.Debug;
45 import sun.security.x509.NameConstraintsExtension;
46 import sun.security.x509.SubjectKeyIdentifierExtension;
47 import sun.security.x509.X509CertImpl;
48 
49 /**
50  * A specification of a reverse PKIX validation state
51  * which is initialized by each build and updated each time a
52  * certificate is added to the current path.
53  * @since       1.4
54  * @author      Sean Mullan
55  * @author      Yassir Elley
56  */
57 
58 class ReverseState implements State {
59 
60     private static final Debug debug = Debug.getInstance("certpath");
61 
62     /* The subject DN of the last cert in the path */
63     X500Principal subjectDN;
64 
65     /* The subject public key of the last cert */
66     PublicKey pubKey;
67 
68     /* The subject key identifier extension (if any) of the last cert */
69     SubjectKeyIdentifierExtension subjKeyId;
70 
71     /* The PKIX constrained/excluded subtrees state variable */
72     NameConstraintsExtension nc;
73 
74     /* The PKIX explicit policy, policy mapping, and inhibit_any-policy
75        state variables */
76     int explicitPolicy;
77     int policyMapping;
78     int inhibitAnyPolicy;
79     int certIndex;
80     PolicyNodeImpl rootNode;
81 
82     /* The number of remaining CA certs which may follow in the path.
83      * -1: previous cert was an EE cert
84      * 0: only EE certs may follow.
85      * >0 and <Integer.MAX_VALUE:no more than this number of CA certs may follow
86      * Integer.MAX_VALUE: unlimited
87      */
88     int remainingCACerts;
89 
90     /* The list of user-defined checkers retrieved from the PKIXParameters
91      * instance */
92     ArrayList<PKIXCertPathChecker> userCheckers;
93 
94     /* Flag indicating if state is initial (path is just starting) */
95     private boolean init = true;
96 
97     /* the checker used for revocation status */
98     RevocationChecker revChecker;
99 
100     /* the algorithm checker */
101     AlgorithmChecker algorithmChecker;
102 
103     /* the untrusted certificates checker */
104     UntrustedChecker untrustedChecker;
105 
106     /* the trust anchor used to validate the path */
107     TrustAnchor trustAnchor;
108 
109     /* Flag indicating if current cert can vouch for the CRL for
110      * the next cert
111      */
112     boolean crlSign = true;
113 
114     /**
115      * Returns a boolean flag indicating if the state is initial
116      * (just starting)
117      *
118      * @return boolean flag indicating if the state is initial (just starting)
119      */
120     @Override
isInitial()121     public boolean isInitial() {
122         return init;
123     }
124 
125     /**
126      * Display state for debugging purposes
127      */
128     @Override
toString()129     public String toString() {
130         StringBuilder sb = new StringBuilder();
131         sb.append("State [");
132         sb.append("\n  subjectDN of last cert: ").append(subjectDN);
133         sb.append("\n  subjectKeyIdentifier: ").append
134                  (String.valueOf(subjKeyId));
135         sb.append("\n  nameConstraints: ").append(String.valueOf(nc));
136         sb.append("\n  certIndex: ").append(certIndex);
137         sb.append("\n  explicitPolicy: ").append(explicitPolicy);
138         sb.append("\n  policyMapping:  ").append(policyMapping);
139         sb.append("\n  inhibitAnyPolicy:  ").append(inhibitAnyPolicy);
140         sb.append("\n  rootNode: ").append(rootNode);
141         sb.append("\n  remainingCACerts: ").append(remainingCACerts);
142         sb.append("\n  crlSign: ").append(crlSign);
143         sb.append("\n  init: ").append(init);
144         sb.append("\n]\n");
145         return sb.toString();
146     }
147 
148     /**
149      * Initialize the state.
150      *
151      * @param buildParams builder parameters
152      */
initState(BuilderParams buildParams)153     public void initState(BuilderParams buildParams)
154         throws CertPathValidatorException
155     {
156         /*
157          * Initialize number of remainingCACerts.
158          * Note that -1 maxPathLen implies unlimited.
159          * 0 implies only an EE cert is acceptable.
160          */
161         int maxPathLen = buildParams.maxPathLength();
162         remainingCACerts = (maxPathLen == -1) ? Integer.MAX_VALUE
163                                               : maxPathLen;
164 
165         /* Initialize explicit policy state variable */
166         if (buildParams.explicitPolicyRequired()) {
167             explicitPolicy = 0;
168         } else {
169             // unconstrained if maxPathLen is -1,
170             // otherwise, we want to initialize this to the value of the
171             // longest possible path + 1 (i.e. maxpathlen + finalcert + 1)
172             explicitPolicy = (maxPathLen == -1) ? maxPathLen : maxPathLen + 2;
173         }
174 
175         /* Initialize policy mapping state variable */
176         if (buildParams.policyMappingInhibited()) {
177             policyMapping = 0;
178         } else {
179             policyMapping = (maxPathLen == -1) ? maxPathLen : maxPathLen + 2;
180         }
181 
182         /* Initialize inhibit any policy state variable */
183         if (buildParams.anyPolicyInhibited()) {
184             inhibitAnyPolicy = 0;
185         } else {
186             inhibitAnyPolicy = (maxPathLen == -1) ? maxPathLen : maxPathLen + 2;
187         }
188 
189         /* Initialize certIndex */
190         certIndex = 1;
191 
192         /* Initialize policy tree */
193         Set<String> initExpPolSet = new HashSet<>(1);
194         initExpPolSet.add(PolicyChecker.ANY_POLICY);
195 
196         rootNode = new PolicyNodeImpl(null, PolicyChecker.ANY_POLICY, null,
197                                       false, initExpPolSet, false);
198 
199         /*
200          * Initialize each user-defined checker
201          * Shallow copy the checkers
202          */
203         userCheckers = new ArrayList<>(buildParams.certPathCheckers());
204         /* initialize each checker (just in case) */
205         for (PKIXCertPathChecker checker : userCheckers) {
206             checker.init(false);
207         }
208 
209         /* Start by trusting the cert to sign CRLs */
210         crlSign = true;
211 
212         init = true;
213     }
214 
215     /**
216      * Update the state with the specified trust anchor.
217      *
218      * @param anchor the most-trusted CA
219      * @param buildParams builder parameters
220      */
updateState(TrustAnchor anchor, BuilderParams buildParams)221     public void updateState(TrustAnchor anchor, BuilderParams buildParams)
222         throws CertificateException, IOException, CertPathValidatorException
223     {
224         trustAnchor = anchor;
225         X509Certificate trustedCert = anchor.getTrustedCert();
226         if (trustedCert != null) {
227             updateState(trustedCert);
228         } else {
229             X500Principal caName = anchor.getCA();
230             updateState(anchor.getCAPublicKey(), caName);
231         }
232 
233         // The user specified AlgorithmChecker and RevocationChecker may not be
234         // able to set the trust anchor until now.
235         boolean revCheckerAdded = false;
236         for (PKIXCertPathChecker checker : userCheckers) {
237             if (checker instanceof AlgorithmChecker) {
238                 ((AlgorithmChecker)checker).trySetTrustAnchor(anchor);
239             } else if (checker instanceof PKIXRevocationChecker) {
240                 if (revCheckerAdded) {
241                     throw new CertPathValidatorException(
242                         "Only one PKIXRevocationChecker can be specified");
243                 }
244                 // if it's our own, initialize it
245                 if (checker instanceof RevocationChecker) {
246                     ((RevocationChecker)checker).init(anchor, buildParams);
247                 }
248                 ((PKIXRevocationChecker)checker).init(false);
249                 revCheckerAdded = true;
250             }
251         }
252 
253         // only create a RevocationChecker if revocation is enabled and
254         // a PKIXRevocationChecker has not already been added
255         if (buildParams.revocationEnabled() && !revCheckerAdded) {
256             revChecker = new RevocationChecker(anchor, buildParams);
257             revChecker.init(false);
258         }
259 
260         init = false;
261     }
262 
263     /**
264      * Update the state. This method is used when the most-trusted CA is
265      * a trusted public-key and caName, instead of a trusted cert.
266      *
267      * @param pubKey the public key of the trusted CA
268      * @param subjectDN the subject distinguished name of the trusted CA
269      */
updateState(PublicKey pubKey, X500Principal subjectDN)270     private void updateState(PublicKey pubKey, X500Principal subjectDN) {
271 
272         /* update subject DN */
273         this.subjectDN = subjectDN;
274 
275         /* update subject public key */
276         this.pubKey = pubKey;
277     }
278 
279     /**
280      * Update the state with the next certificate added to the path.
281      *
282      * @param cert the certificate which is used to update the state
283      */
updateState(X509Certificate cert)284     public void updateState(X509Certificate cert)
285         throws CertificateException, IOException, CertPathValidatorException {
286 
287         if (cert == null) {
288             return;
289         }
290 
291         /* update subject DN */
292         subjectDN = cert.getSubjectX500Principal();
293 
294         /* check for key needing to inherit alg parameters */
295         X509CertImpl icert = X509CertImpl.toImpl(cert);
296         PublicKey newKey = cert.getPublicKey();
297         if (PKIX.isDSAPublicKeyWithoutParams(newKey)) {
298             newKey = BasicChecker.makeInheritedParamsKey(newKey, pubKey);
299         }
300 
301         /* update subject public key */
302         pubKey = newKey;
303 
304         /*
305          * if this is a trusted cert (init == true), then we
306          * don't update any of the remaining fields
307          */
308         if (init) {
309             init = false;
310             return;
311         }
312 
313         /* update subject key identifier */
314         subjKeyId = icert.getSubjectKeyIdentifierExtension();
315 
316         /* update crlSign */
317         crlSign = RevocationChecker.certCanSignCrl(cert);
318 
319         /* update current name constraints */
320         if (nc != null) {
321             nc.merge(icert.getNameConstraintsExtension());
322         } else {
323             nc = icert.getNameConstraintsExtension();
324             if (nc != null) {
325                 // Make sure we do a clone here, because we're probably
326                 // going to modify this object later and we don't want to
327                 // be sharing it with a Certificate object!
328                 nc = (NameConstraintsExtension) nc.clone();
329             }
330         }
331 
332         /* update policy state variables */
333         explicitPolicy =
334             PolicyChecker.mergeExplicitPolicy(explicitPolicy, icert, false);
335         policyMapping =
336             PolicyChecker.mergePolicyMapping(policyMapping, icert);
337         inhibitAnyPolicy =
338             PolicyChecker.mergeInhibitAnyPolicy(inhibitAnyPolicy, icert);
339         certIndex++;
340 
341         /*
342          * Update remaining CA certs
343          */
344         remainingCACerts =
345             ConstraintsChecker.mergeBasicConstraints(cert, remainingCACerts);
346 
347         init = false;
348     }
349 
350     /**
351      * Returns a boolean flag indicating if a key lacking necessary key
352      * algorithm parameters has been encountered.
353      *
354      * @return boolean flag indicating if key lacking parameters encountered.
355      */
356     @Override
keyParamsNeeded()357     public boolean keyParamsNeeded() {
358         /* when building in reverse, we immediately get parameters needed
359          * or else throw an exception
360          */
361         return false;
362     }
363 
364     /*
365      * Clone current state. The state is cloned as each cert is
366      * added to the path. This is necessary if backtracking occurs,
367      * and a prior state needs to be restored.
368      *
369      * Note that this is a SMART clone. Not all fields are fully copied,
370      * because some of them (e.g., subjKeyId) will
371      * not have their contents modified by subsequent calls to updateState.
372      */
373     @Override
374     @SuppressWarnings("unchecked") // Safe casts assuming clone() works correctly
clone()375     public Object clone() {
376         try {
377             ReverseState clonedState = (ReverseState) super.clone();
378 
379             /* clone checkers, if cloneable */
380             clonedState.userCheckers =
381                         (ArrayList<PKIXCertPathChecker>)userCheckers.clone();
382             ListIterator<PKIXCertPathChecker> li =
383                         clonedState.userCheckers.listIterator();
384             while (li.hasNext()) {
385                 PKIXCertPathChecker checker = li.next();
386                 if (checker instanceof Cloneable) {
387                     li.set((PKIXCertPathChecker)checker.clone());
388                 }
389             }
390 
391             /* make copy of name constraints */
392             if (nc != null) {
393                 clonedState.nc = (NameConstraintsExtension) nc.clone();
394             }
395 
396             /* make copy of policy tree */
397             if (rootNode != null) {
398                 clonedState.rootNode = rootNode.copyTree();
399             }
400 
401             return clonedState;
402         } catch (CloneNotSupportedException e) {
403             throw new InternalError(e.toString(), e);
404         }
405     }
406 }
407