History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/security/validator/PKIXValidator.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/security/validator/PKIXValidator.java+389−0
@@ -0,0 +1,389 @@
1/*
2 * Copyright (c) 2002, 2010, 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
26package sun.security.validator;
27
28import java.util.*;
29
30import java.security.*;
31import java.security.cert.*;
32
33import javax.security.auth.x500.X500Principal;
34import sun.security.action.GetBooleanAction;
35import sun.security.provider.certpath.AlgorithmChecker;
36
37/**
38 * Validator implementation built on the PKIX CertPath API. This
39 * implementation will be emphasized going forward.<p>
40 * <p>
41 * Note that the validate() implementation tries to use a PKIX validator
42 * if that appears possible and a PKIX builder otherwise. This increases
43 * performance and currently also leads to better exception messages
44 * in case of failures.
45 * <p>
46 * {@code PKIXValidator} objects are immutable once they have been created.
47 * Please DO NOT add methods that can change the state of an instance once
48 * it has been created.
49 *
50 * @author Andreas Sterbenz
51 */
52public final class PKIXValidator extends Validator {
53
54 /**
55 * Flag indicating whether to enable revocation check for the PKIX trust
56 * manager. Typically, this will only work if the PKIX implementation
57 * supports CRL distribution points as we do not manually setup CertStores.
58 */
59 private final static boolean checkTLSRevocation =
60 AccessController.doPrivileged
61 (new GetBooleanAction("com.sun.net.ssl.checkRevocation"));
62
63 // enable use of the validator if possible
64 private final static boolean TRY_VALIDATOR = true;
65
66 private final Set<X509Certificate> trustedCerts;
67 private final PKIXBuilderParameters parameterTemplate;
68 private int certPathLength = -1;
69
70 // needed only for the validator
71 private final Map<X500Principal, List<PublicKey>> trustedSubjects;
72 private final CertificateFactory factory;
73
74 private final boolean plugin;
75
76 PKIXValidator(String variant, Collection<X509Certificate> trustedCerts) {
77 super(TYPE_PKIX, variant);
78 if (trustedCerts instanceof Set) {
79 this.trustedCerts = (Set<X509Certificate>)trustedCerts;
80 } else {
81 this.trustedCerts = new HashSet<X509Certificate>(trustedCerts);
82 }
83 Set<TrustAnchor> trustAnchors = new HashSet<TrustAnchor>();
84 for (X509Certificate cert : trustedCerts) {
85 trustAnchors.add(new TrustAnchor(cert, null));
86 }
87 try {
88 parameterTemplate = new PKIXBuilderParameters(trustAnchors, null);
89 } catch (InvalidAlgorithmParameterException e) {
90 throw new RuntimeException("Unexpected error: " + e.toString(), e);
91 }
92 setDefaultParameters(variant);
93
94 // initCommon();
95 if (TRY_VALIDATOR) {
96 if (TRY_VALIDATOR == false) {
97 return;
98 }
99 trustedSubjects = new HashMap<X500Principal, List<PublicKey>>();
100 for (X509Certificate cert : trustedCerts) {
101 X500Principal dn = cert.getSubjectX500Principal();
102 List<PublicKey> keys;
103 if (trustedSubjects.containsKey(dn)) {
104 keys = trustedSubjects.get(dn);
105 } else {
106 keys = new ArrayList<PublicKey>();
107 trustedSubjects.put(dn, keys);
108 }
109 keys.add(cert.getPublicKey());
110 }
111 try {
112 factory = CertificateFactory.getInstance("X.509");
113 } catch (CertificateException e) {
114 throw new RuntimeException("Internal error", e);
115 }
116 plugin = variant.equals(VAR_PLUGIN_CODE_SIGNING);
117 } else {
118 plugin = false;
119 }
120 }
121
122 PKIXValidator(String variant, PKIXBuilderParameters params) {
123 super(TYPE_PKIX, variant);
124 trustedCerts = new HashSet<X509Certificate>();
125 for (TrustAnchor anchor : params.getTrustAnchors()) {
126 X509Certificate cert = anchor.getTrustedCert();
127 if (cert != null) {
128 trustedCerts.add(cert);
129 }
130 }
131 parameterTemplate = params;
132
133 // initCommon();
134 if (TRY_VALIDATOR) {
135 if (TRY_VALIDATOR == false) {
136 return;
137 }
138 trustedSubjects = new HashMap<X500Principal, List<PublicKey>>();
139 for (X509Certificate cert : trustedCerts) {
140 X500Principal dn = cert.getSubjectX500Principal();
141 List<PublicKey> keys;
142 if (trustedSubjects.containsKey(dn)) {
143 keys = trustedSubjects.get(dn);
144 } else {
145 keys = new ArrayList<PublicKey>();
146 trustedSubjects.put(dn, keys);
147 }
148 keys.add(cert.getPublicKey());
149 }
150 try {
151 factory = CertificateFactory.getInstance("X.509");
152 } catch (CertificateException e) {
153 throw new RuntimeException("Internal error", e);
154 }
155 plugin = variant.equals(VAR_PLUGIN_CODE_SIGNING);
156 } else {
157 plugin = false;
158 }
159 }
160
161 public Collection<X509Certificate> getTrustedCertificates() {
162 return trustedCerts;
163 }
164
165 /**
166 * Returns the length of the last certification path that is validated by
167 * CertPathValidator. This is intended primarily as a callback mechanism
168 * for PKIXCertPathCheckers to determine the length of the certification
169 * path that is being validated. It is necessary since engineValidate()
170 * may modify the length of the path.
171 *
172 * @return the length of the last certification path passed to
173 * CertPathValidator.validate, or -1 if it has not been invoked yet
174 */
175 public int getCertPathLength() { // mutable, should be private
176 return certPathLength;
177 }
178
179 /**
180 * Set J2SE global default PKIX parameters. Currently, hardcoded to disable
181 * revocation checking. In the future, this should be configurable.
182 */
183 private void setDefaultParameters(String variant) {
184 if ((variant == Validator.VAR_TLS_SERVER) ||
185 (variant == Validator.VAR_TLS_CLIENT)) {
186 parameterTemplate.setRevocationEnabled(checkTLSRevocation);
187 } else {
188 parameterTemplate.setRevocationEnabled(false);
189 }
190 }
191
192 /**
193 * Return the PKIX parameters used by this instance. An application may
194 * modify the parameters but must make sure not to perform any concurrent
195 * validations.
196 */
197 public PKIXBuilderParameters getParameters() { // mutable, should be private
198 return parameterTemplate;
199 }
200
201 @Override
202 X509Certificate[] engineValidate(X509Certificate[] chain,
203 Collection<X509Certificate> otherCerts,
204 AlgorithmConstraints constraints,
205 Object parameter) throws CertificateException {
206 if ((chain == null) || (chain.length == 0)) {
207 throw new CertificateException
208 ("null or zero-length certificate chain");
209 }
210
211 // add new algorithm constraints checker
212 PKIXBuilderParameters pkixParameters =
213 (PKIXBuilderParameters) parameterTemplate.clone();
214 AlgorithmChecker algorithmChecker = null;
215 if (constraints != null) {
216 algorithmChecker = new AlgorithmChecker(constraints);
217 pkixParameters.addCertPathChecker(algorithmChecker);
218 }
219
220 if (TRY_VALIDATOR) {
221 // check that chain is in correct order and check if chain contains
222 // trust anchor
223 X500Principal prevIssuer = null;
224 for (int i = 0; i < chain.length; i++) {
225 X509Certificate cert = chain[i];
226 X500Principal dn = cert.getSubjectX500Principal();
227 if (i != 0 &&
228 !dn.equals(prevIssuer)) {
229 // chain is not ordered correctly, call builder instead
230 return doBuild(chain, otherCerts, pkixParameters);
231 }
232
233 // Check if chain[i] is already trusted. It may be inside
234 // trustedCerts, or has the same dn and public key as a cert
235 // inside trustedCerts. The latter happens when a CA has
236 // updated its cert with a stronger signature algorithm in JRE
237 // but the weak one is still in circulation.
238
239 if (trustedCerts.contains(cert) || // trusted cert
240 (trustedSubjects.containsKey(dn) && // replacing ...
241 trustedSubjects.get(dn).contains( // ... weak cert
242 cert.getPublicKey()))) {
243 if (i == 0) {
244 return new X509Certificate[] {chain[0]};
245 }
246 // Remove and call validator on partial chain [0 .. i-1]
247 X509Certificate[] newChain = new X509Certificate[i];
248 System.arraycopy(chain, 0, newChain, 0, i);
249 return doValidate(newChain, pkixParameters);
250 }
251 prevIssuer = cert.getIssuerX500Principal();
252 }
253
254 // apparently issued by trust anchor?
255 X509Certificate last = chain[chain.length - 1];
256 X500Principal issuer = last.getIssuerX500Principal();
257 X500Principal subject = last.getSubjectX500Principal();
258 if (trustedSubjects.containsKey(issuer) &&
259 isSignatureValid(trustedSubjects.get(issuer), last)) {
260 return doValidate(chain, pkixParameters);
261 }
262
263 // don't fallback to builder if called from plugin/webstart
264 if (plugin) {
265 // Validate chain even if no trust anchor is found. This
266 // allows plugin/webstart to make sure the chain is
267 // otherwise valid
268 if (chain.length > 1) {
269 X509Certificate[] newChain =
270 new X509Certificate[chain.length-1];
271 System.arraycopy(chain, 0, newChain, 0, newChain.length);
272
273 // temporarily set last cert as sole trust anchor
274 try {
275 pkixParameters.setTrustAnchors
276 (Collections.singleton(new TrustAnchor
277 (chain[chain.length-1], null)));
278 } catch (InvalidAlgorithmParameterException iape) {
279 // should never occur, but ...
280 throw new CertificateException(iape);
281 }
282 doValidate(newChain, pkixParameters);
283 }
284 // if the rest of the chain is valid, throw exception
285 // indicating no trust anchor was found
286 throw new ValidatorException
287 (ValidatorException.T_NO_TRUST_ANCHOR);
288 }
289 // otherwise, fall back to builder
290 }
291
292 return doBuild(chain, otherCerts, pkixParameters);
293 }
294
295 private boolean isSignatureValid(List<PublicKey> keys,
296 X509Certificate sub) {
297 if (plugin) {
298 for (PublicKey key: keys) {
299 try {
300 sub.verify(key);
301 return true;
302 } catch (Exception ex) {
303 continue;
304 }
305 }
306 return false;
307 }
308 return true; // only check if PLUGIN is set
309 }
310
311 private static X509Certificate[] toArray(CertPath path, TrustAnchor anchor)
312 throws CertificateException {
313 List<? extends java.security.cert.Certificate> list =
314 path.getCertificates();
315 X509Certificate[] chain = new X509Certificate[list.size() + 1];
316 list.toArray(chain);
317 X509Certificate trustedCert = anchor.getTrustedCert();
318 if (trustedCert == null) {
319 throw new ValidatorException
320 ("TrustAnchor must be specified as certificate");
321 }
322 chain[chain.length - 1] = trustedCert;
323 return chain;
324 }
325
326 /**
327 * Set the check date (for debugging).
328 */
329 private void setDate(PKIXBuilderParameters params) {
330 Date date = validationDate;
331 if (date != null) {
332 params.setDate(date);
333 }
334 }
335
336 private X509Certificate[] doValidate(X509Certificate[] chain,
337 PKIXBuilderParameters params) throws CertificateException {
338 try {
339 setDate(params);
340
341 // do the validation
342 CertPathValidator validator = CertPathValidator.getInstance("PKIX");
343 CertPath path = factory.generateCertPath(Arrays.asList(chain));
344 certPathLength = chain.length;
345 PKIXCertPathValidatorResult result =
346 (PKIXCertPathValidatorResult)validator.validate(path, params);
347
348 return toArray(path, result.getTrustAnchor());
349 } catch (GeneralSecurityException e) {
350 throw new ValidatorException
351 ("PKIX path validation failed: " + e.toString(), e);
352 }
353 }
354
355 private X509Certificate[] doBuild(X509Certificate[] chain,
356 Collection<X509Certificate> otherCerts,
357 PKIXBuilderParameters params) throws CertificateException {
358
359 try {
360 setDate(params);
361
362 // setup target constraints
363 X509CertSelector selector = new X509CertSelector();
364 selector.setCertificate(chain[0]);
365 params.setTargetCertConstraints(selector);
366
367 // setup CertStores
368 Collection<X509Certificate> certs =
369 new ArrayList<X509Certificate>();
370 certs.addAll(Arrays.asList(chain));
371 if (otherCerts != null) {
372 certs.addAll(otherCerts);
373 }
374 CertStore store = CertStore.getInstance("Collection",
375 new CollectionCertStoreParameters(certs));
376 params.addCertStore(store);
377
378 // do the build
379 CertPathBuilder builder = CertPathBuilder.getInstance("PKIX");
380 PKIXCertPathBuilderResult result =
381 (PKIXCertPathBuilderResult)builder.build(params);
382
383 return toArray(result.getCertPath(), result.getTrustAnchor());
384 } catch (GeneralSecurityException e) {
385 throw new ValidatorException
386 ("PKIX path building failed: " + e.toString(), e);
387 }
388 }
389}