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/provider/certpath/OCSPChecker.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/security/provider/certpath/OCSPChecker.java+446−0
@@ -0,0 +1,446 @@
1+/*
2+ * Copyright (c) 2003, 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.provider.certpath;
27+
28+import java.math.BigInteger;
29+import java.util.*;
30+import java.security.AccessController;
31+import java.security.PrivilegedAction;
32+import java.security.Security;
33+import java.security.cert.*;
34+import java.security.cert.CertPathValidatorException.BasicReason;
35+import java.net.URI;
36+import java.net.URISyntaxException;
37+import javax.security.auth.x500.X500Principal;
38+
39+import static sun.security.provider.certpath.OCSP.*;
40+import sun.security.util.Debug;
41+import sun.security.x509.*;
42+
43+/**
44+ * OCSPChecker is a <code>PKIXCertPathChecker</code> that uses the
45+ * Online Certificate Status Protocol (OCSP) as specified in RFC 2560
46+ * <a href="http://www.ietf.org/rfc/rfc2560.txt">
47+ * http://www.ietf.org/rfc/rfc2560.txt</a>.
48+ *
49+ * @author Ram Marti
50+ */
51+class OCSPChecker extends PKIXCertPathChecker {
52+
53+ static final String OCSP_ENABLE_PROP = "ocsp.enable";
54+ static final String OCSP_URL_PROP = "ocsp.responderURL";
55+ static final String OCSP_CERT_SUBJECT_PROP =
56+ "ocsp.responderCertSubjectName";
57+ static final String OCSP_CERT_ISSUER_PROP = "ocsp.responderCertIssuerName";
58+ static final String OCSP_CERT_NUMBER_PROP =
59+ "ocsp.responderCertSerialNumber";
60+
61+ private static final String HEX_DIGITS = "0123456789ABCDEFabcdef";
62+ private static final Debug DEBUG = Debug.getInstance("certpath");
63+ private static final boolean dump = false;
64+
65+ private int remainingCerts;
66+
67+ private X509Certificate[] certs;
68+
69+ private CertPath cp;
70+
71+ private PKIXParameters pkixParams;
72+
73+ private boolean onlyEECert = false;
74+
75+ /**
76+ * Default Constructor
77+ *
78+ * @param certPath the X509 certification path
79+ * @param pkixParams the input PKIX parameter set
80+ * @throws CertPathValidatorException if OCSPChecker can not be created
81+ */
82+ OCSPChecker(CertPath certPath, PKIXParameters pkixParams)
83+ throws CertPathValidatorException {
84+ this(certPath, pkixParams, false);
85+ }
86+
87+ OCSPChecker(CertPath certPath, PKIXParameters pkixParams, boolean onlyEECert)
88+ throws CertPathValidatorException {
89+
90+ this.cp = certPath;
91+ this.pkixParams = pkixParams;
92+ this.onlyEECert = onlyEECert;
93+ List<? extends Certificate> tmp = cp.getCertificates();
94+ certs = tmp.toArray(new X509Certificate[tmp.size()]);
95+ init(false);
96+ }
97+
98+ /**
99+ * Initializes the internal state of the checker from parameters
100+ * specified in the constructor
101+ */
102+ @Override
103+ public void init(boolean forward) throws CertPathValidatorException {
104+ if (!forward) {
105+ remainingCerts = certs.length + 1;
106+ } else {
107+ throw new CertPathValidatorException(
108+ "Forward checking not supported");
109+ }
110+ }
111+
112+ @Override public boolean isForwardCheckingSupported() {
113+ return false;
114+ }
115+
116+ @Override public Set<String> getSupportedExtensions() {
117+ return Collections.<String>emptySet();
118+ }
119+
120+ /**
121+ * Sends an OCSPRequest for the certificate to the OCSP Server and
122+ * processes the response back from the OCSP Server.
123+ *
124+ * @param cert the Certificate
125+ * @param unresolvedCritExts the unresolved critical extensions
126+ * @exception CertPathValidatorException Exception is thrown if the
127+ * certificate has been revoked.
128+ */
129+ @Override
130+ public void check(Certificate cert, Collection<String> unresolvedCritExts)
131+ throws CertPathValidatorException {
132+
133+ // Decrement the certificate counter
134+ remainingCerts--;
135+
136+ X509CertImpl currCertImpl = null;
137+ try {
138+ currCertImpl = X509CertImpl.toImpl((X509Certificate)cert);
139+ } catch (CertificateException ce) {
140+ throw new CertPathValidatorException(ce);
141+ }
142+
143+ if (onlyEECert && currCertImpl.getBasicConstraints() != -1) {
144+ if (DEBUG != null) {
145+ DEBUG.println("Skipping revocation check, not end entity cert");
146+ }
147+ return;
148+ }
149+
150+ /*
151+ * OCSP security property values, in the following order:
152+ * 1. ocsp.responderURL
153+ * 2. ocsp.responderCertSubjectName
154+ * 3. ocsp.responderCertIssuerName
155+ * 4. ocsp.responderCertSerialNumber
156+ */
157+ // should cache these properties to avoid calling every time?
158+ String[] properties = getOCSPProperties();
159+
160+ // Check whether OCSP is feasible before seeking cert information
161+ URI uri = getOCSPServerURI(currCertImpl, properties[0]);
162+
163+ // When responder's subject name is set then the issuer/serial
164+ // properties are ignored
165+ X500Principal responderSubjectName = null;
166+ X500Principal responderIssuerName = null;
167+ BigInteger responderSerialNumber = null;
168+ if (properties[1] != null) {
169+ responderSubjectName = new X500Principal(properties[1]);
170+ } else if (properties[2] != null && properties[3] != null) {
171+ responderIssuerName = new X500Principal(properties[2]);
172+ // remove colon or space separators
173+ String value = stripOutSeparators(properties[3]);
174+ responderSerialNumber = new BigInteger(value, 16);
175+ } else if (properties[2] != null || properties[3] != null) {
176+ throw new CertPathValidatorException(
177+ "Must specify both ocsp.responderCertIssuerName and " +
178+ "ocsp.responderCertSerialNumber properties");
179+ }
180+
181+ // If the OCSP responder cert properties are set then the
182+ // identified cert must be located in the trust anchors or
183+ // in the cert stores.
184+ boolean seekResponderCert = false;
185+ if (responderSubjectName != null || responderIssuerName != null) {
186+ seekResponderCert = true;
187+ }
188+
189+ // Set the issuer certificate to the next cert in the chain
190+ // (unless we're processing the final cert).
191+ X509Certificate issuerCert = null;
192+ boolean seekIssuerCert = true;
193+ X509Certificate responderCert = null;
194+ if (remainingCerts < certs.length) {
195+ issuerCert = certs[remainingCerts];
196+ seekIssuerCert = false; // done
197+
198+ // By default, the OCSP responder's cert is the same as the
199+ // issuer of the cert being validated.
200+ if (!seekResponderCert) {
201+ responderCert = issuerCert;
202+ if (DEBUG != null) {
203+ DEBUG.println("Responder's certificate is the same " +
204+ "as the issuer of the certificate being validated");
205+ }
206+ }
207+ }
208+
209+ // Check anchor certs for:
210+ // - the issuer cert (of the cert being validated)
211+ // - the OCSP responder's cert
212+ if (seekIssuerCert || seekResponderCert) {
213+
214+ if (DEBUG != null && seekResponderCert) {
215+ DEBUG.println("Searching trust anchors for responder's " +
216+ "certificate");
217+ }
218+
219+ // Extract the anchor certs
220+ Iterator<TrustAnchor> anchors
221+ = pkixParams.getTrustAnchors().iterator();
222+ if (!anchors.hasNext()) {
223+ throw new CertPathValidatorException(
224+ "Must specify at least one trust anchor");
225+ }
226+
227+ X500Principal certIssuerName =
228+ currCertImpl.getIssuerX500Principal();
229+ while (anchors.hasNext() && (seekIssuerCert || seekResponderCert)) {
230+
231+ TrustAnchor anchor = anchors.next();
232+ X509Certificate anchorCert = anchor.getTrustedCert();
233+ X500Principal anchorSubjectName =
234+ anchorCert.getSubjectX500Principal();
235+
236+ if (dump) {
237+ System.out.println("Issuer DN is " + certIssuerName);
238+ System.out.println("Subject DN is " + anchorSubjectName);
239+ }
240+
241+ // Check if anchor cert is the issuer cert
242+ if (seekIssuerCert &&
243+ certIssuerName.equals(anchorSubjectName)) {
244+
245+ issuerCert = anchorCert;
246+ seekIssuerCert = false; // done
247+
248+ // By default, the OCSP responder's cert is the same as
249+ // the issuer of the cert being validated.
250+ if (!seekResponderCert && responderCert == null) {
251+ responderCert = anchorCert;
252+ if (DEBUG != null) {
253+ DEBUG.println("Responder's certificate is the" +
254+ " same as the issuer of the certificate " +
255+ "being validated");
256+ }
257+ }
258+ }
259+
260+ // Check if anchor cert is the responder cert
261+ if (seekResponderCert) {
262+ // Satisfy the responder subject name property only, or
263+ // satisfy the responder issuer name and serial number
264+ // properties only
265+ if ((responderSubjectName != null &&
266+ responderSubjectName.equals(anchorSubjectName)) ||
267+ (responderIssuerName != null &&
268+ responderSerialNumber != null &&
269+ responderIssuerName.equals(
270+ anchorCert.getIssuerX500Principal()) &&
271+ responderSerialNumber.equals(
272+ anchorCert.getSerialNumber()))) {
273+
274+ responderCert = anchorCert;
275+ seekResponderCert = false; // done
276+ }
277+ }
278+ }
279+ if (issuerCert == null) {
280+ throw new CertPathValidatorException(
281+ "No trusted certificate for " + currCertImpl.getIssuerDN());
282+ }
283+
284+ // Check cert stores if responder cert has not yet been found
285+ if (seekResponderCert) {
286+ if (DEBUG != null) {
287+ DEBUG.println("Searching cert stores for responder's " +
288+ "certificate");
289+ }
290+ X509CertSelector filter = null;
291+ if (responderSubjectName != null) {
292+ filter = new X509CertSelector();
293+ filter.setSubject(responderSubjectName);
294+ } else if (responderIssuerName != null &&
295+ responderSerialNumber != null) {
296+ filter = new X509CertSelector();
297+ filter.setIssuer(responderIssuerName);
298+ filter.setSerialNumber(responderSerialNumber);
299+ }
300+ if (filter != null) {
301+ List<CertStore> certStores = pkixParams.getCertStores();
302+ for (CertStore certStore : certStores) {
303+ Iterator i = null;
304+ try {
305+ i = certStore.getCertificates(filter).iterator();
306+ } catch (CertStoreException cse) {
307+ // ignore and try next certStore
308+ if (DEBUG != null) {
309+ DEBUG.println("CertStore exception:" + cse);
310+ }
311+ continue;
312+ }
313+ if (i.hasNext()) {
314+ responderCert = (X509Certificate) i.next();
315+ seekResponderCert = false; // done
316+ break;
317+ }
318+ }
319+ }
320+ }
321+ }
322+
323+ // Could not find the certificate identified in the OCSP properties
324+ if (seekResponderCert) {
325+ throw new CertPathValidatorException(
326+ "Cannot find the responder's certificate " +
327+ "(set using the OCSP security properties).");
328+ }
329+
330+ // The algorithm constraints of the OCSP trusted responder certificate
331+ // does not need to be checked in this code. The constraints will be
332+ // checked when the responder's certificate is validated.
333+
334+ CertId certId = null;
335+ OCSPResponse response = null;
336+ try {
337+ certId = new CertId
338+ (issuerCert, currCertImpl.getSerialNumberObject());
339+ response = OCSP.check(Collections.singletonList(certId), uri,
340+ responderCert, pkixParams.getDate());
341+ } catch (Exception e) {
342+ if (e instanceof CertPathValidatorException) {
343+ throw (CertPathValidatorException) e;
344+ } else {
345+ // Wrap exceptions in CertPathValidatorException so that
346+ // we can fallback to CRLs, if enabled.
347+ throw new CertPathValidatorException(e);
348+ }
349+ }
350+
351+ RevocationStatus rs = (RevocationStatus) response.getSingleResponse(certId);
352+ RevocationStatus.CertStatus certStatus = rs.getCertStatus();
353+ if (certStatus == RevocationStatus.CertStatus.REVOKED) {
354+ Throwable t = new CertificateRevokedException(
355+ rs.getRevocationTime(), rs.getRevocationReason(),
356+ responderCert.getSubjectX500Principal(),
357+ rs.getSingleExtensions());
358+ throw new CertPathValidatorException(t.getMessage(), t,
359+ null, -1, BasicReason.REVOKED);
360+ } else if (certStatus == RevocationStatus.CertStatus.UNKNOWN) {
361+ throw new CertPathValidatorException(
362+ "Certificate's revocation status is unknown", null, cp,
363+ remainingCerts, BasicReason.UNDETERMINED_REVOCATION_STATUS);
364+ }
365+ }
366+
367+ /*
368+ * The OCSP security property values are in the following order:
369+ * 1. ocsp.responderURL
370+ * 2. ocsp.responderCertSubjectName
371+ * 3. ocsp.responderCertIssuerName
372+ * 4. ocsp.responderCertSerialNumber
373+ */
374+ private static URI getOCSPServerURI(X509CertImpl currCertImpl,
375+ String responderURL) throws CertPathValidatorException {
376+
377+ if (responderURL != null) {
378+ try {
379+ return new URI(responderURL);
380+ } catch (URISyntaxException e) {
381+ throw new CertPathValidatorException(e);
382+ }
383+ }
384+
385+ // Examine the certificate's AuthorityInfoAccess extension
386+ AuthorityInfoAccessExtension aia =
387+ currCertImpl.getAuthorityInfoAccessExtension();
388+ if (aia == null) {
389+ throw new CertPathValidatorException(
390+ "Must specify the location of an OCSP Responder");
391+ }
392+
393+ List<AccessDescription> descriptions = aia.getAccessDescriptions();
394+ for (AccessDescription description : descriptions) {
395+ if (description.getAccessMethod().equals(
396+ AccessDescription.Ad_OCSP_Id)) {
397+
398+ GeneralName generalName = description.getAccessLocation();
399+ if (generalName.getType() == GeneralNameInterface.NAME_URI) {
400+ URIName uri = (URIName) generalName.getName();
401+ return uri.getURI();
402+ }
403+ }
404+ }
405+
406+ throw new CertPathValidatorException(
407+ "Cannot find the location of the OCSP Responder");
408+ }
409+
410+ /*
411+ * Retrieves the values of the OCSP security properties.
412+ */
413+ private static String[] getOCSPProperties() {
414+ final String[] properties = new String[4];
415+
416+ AccessController.doPrivileged(
417+ new PrivilegedAction<Void>() {
418+ public Void run() {
419+ properties[0] = Security.getProperty(OCSP_URL_PROP);
420+ properties[1] =
421+ Security.getProperty(OCSP_CERT_SUBJECT_PROP);
422+ properties[2] =
423+ Security.getProperty(OCSP_CERT_ISSUER_PROP);
424+ properties[3] =
425+ Security.getProperty(OCSP_CERT_NUMBER_PROP);
426+ return null;
427+ }
428+ });
429+
430+ return properties;
431+ }
432+
433+ /*
434+ * Removes any non-hexadecimal characters from a string.
435+ */
436+ private static String stripOutSeparators(String value) {
437+ char[] chars = value.toCharArray();
438+ StringBuilder hexNumber = new StringBuilder();
439+ for (int i = 0; i < chars.length; i++) {
440+ if (HEX_DIGITS.indexOf(chars[i]) != -1) {
441+ hexNumber.append(chars[i]);
442+ }
443+ }
444+ return hexNumber.toString();
445+ }
446+}