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+
26+package sun.security.validator;
27+
28+import java.util.*;
29+
30+import java.security.*;
31+import java.security.cert.*;
32+
33+import javax.security.auth.x500.X500Principal;
34+import sun.security.action.GetBooleanAction;
35+import 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+ */
52+public 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+}