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
26package sun.security.provider.certpath;
27
28import java.math.BigInteger;
29import java.util.*;
30import java.security.AccessController;
31import java.security.PrivilegedAction;
32import java.security.Security;
33import java.security.cert.*;
34import java.security.cert.CertPathValidatorException.BasicReason;
35import java.net.URI;
36import java.net.URISyntaxException;
37import javax.security.auth.x500.X500Principal;
38
39import static sun.security.provider.certpath.OCSP.*;
40import sun.security.util.Debug;
41import 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 */
51class 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}