src/java.base/share/classes/sun/security/ssl/StatusResponseManager.java
changeset 50768 68fa3d4026ea
parent 47216 71c04702a3d5
child 51398 3c389a284345
equal deleted inserted replaced
50767:356eaea05bf0 50768:68fa3d4026ea
     1 /*
     1 /*
     2  * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     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
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     7  * published by the Free Software Foundation.  Oracle designates this
    20  *
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    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
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    23  * questions.
    24  */
    24  */
    25 
       
    26 package sun.security.ssl;
    25 package sun.security.ssl;
    27 
    26 
    28 import java.io.IOException;
    27 import java.io.IOException;
    29 import java.net.URI;
    28 import java.net.URI;
    30 import java.net.URISyntaxException;
    29 import java.net.URISyntaxException;
    31 import java.security.AccessController;
    30 import java.security.AccessController;
       
    31 import java.security.cert.Extension;
    32 import java.security.cert.X509Certificate;
    32 import java.security.cert.X509Certificate;
    33 import java.security.cert.Extension;
    33 import java.util.ArrayList;
    34 import java.util.*;
    34 import java.util.Collections;
    35 import java.util.concurrent.*;
    35 import java.util.Date;
    36 
    36 import java.util.HashMap;
       
    37 import java.util.List;
       
    38 import java.util.Map;
       
    39 import java.util.Objects;
       
    40 import java.util.concurrent.Callable;
       
    41 import java.util.concurrent.ExecutionException;
       
    42 import java.util.concurrent.Executors;
       
    43 import java.util.concurrent.Future;
       
    44 import java.util.concurrent.ScheduledThreadPoolExecutor;
       
    45 import java.util.concurrent.ThreadFactory;
       
    46 import java.util.concurrent.ThreadPoolExecutor;
       
    47 import java.util.concurrent.TimeUnit;
       
    48 import sun.security.action.GetBooleanAction;
       
    49 import sun.security.action.GetIntegerAction;
       
    50 import sun.security.action.GetPropertyAction;
    37 import sun.security.provider.certpath.CertId;
    51 import sun.security.provider.certpath.CertId;
    38 import sun.security.provider.certpath.OCSP;
    52 import sun.security.provider.certpath.OCSP;
    39 import sun.security.provider.certpath.OCSPResponse;
    53 import sun.security.provider.certpath.OCSPResponse;
    40 import sun.security.provider.certpath.ResponderId;
    54 import sun.security.provider.certpath.ResponderId;
    41 import sun.security.util.Cache;
    55 import sun.security.util.Cache;
    42 import sun.security.x509.PKIXExtensions;
    56 import sun.security.x509.PKIXExtensions;
    43 import sun.security.x509.SerialNumber;
    57 import sun.security.x509.SerialNumber;
    44 import sun.security.action.GetBooleanAction;
    58 import sun.security.ssl.X509Authentication.X509Possession;
    45 import sun.security.action.GetIntegerAction;
    59 import static sun.security.ssl.CertStatusExtension.*;
    46 import sun.security.action.GetPropertyAction;
       
    47 
    60 
    48 final class StatusResponseManager {
    61 final class StatusResponseManager {
    49     private static final int DEFAULT_CORE_THREADS = 8;
    62     private static final int DEFAULT_CORE_THREADS = 8;
    50     private static final int DEFAULT_CACHE_SIZE = 256;
    63     private static final int DEFAULT_CACHE_SIZE = 256;
    51     private static final int DEFAULT_CACHE_LIFETIME = 3600;         // seconds
    64     private static final int DEFAULT_CACHE_LIFETIME = 3600;     // seconds
    52     private static final Debug debug = Debug.getInstance("ssl");
       
    53 
    65 
    54     private final ScheduledThreadPoolExecutor threadMgr;
    66     private final ScheduledThreadPoolExecutor threadMgr;
    55     private final Cache<CertId, ResponseCacheEntry> responseCache;
    67     private final Cache<CertId, ResponseCacheEntry> responseCache;
    56     private final URI defaultResponder;
    68     private final URI defaultResponder;
    57     private final boolean respOverride;
    69     private final boolean respOverride;
    97                 t.setDaemon(true);
   109                 t.setDaemon(true);
    98                 return t;
   110                 return t;
    99             }
   111             }
   100         }, new ThreadPoolExecutor.DiscardPolicy());
   112         }, new ThreadPoolExecutor.DiscardPolicy());
   101         threadMgr.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
   113         threadMgr.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
   102         threadMgr.setContinueExistingPeriodicTasksAfterShutdownPolicy(false);
   114         threadMgr.setContinueExistingPeriodicTasksAfterShutdownPolicy(
       
   115                 false);
   103         threadMgr.setKeepAliveTime(5000, TimeUnit.MILLISECONDS);
   116         threadMgr.setKeepAliveTime(5000, TimeUnit.MILLISECONDS);
   104         threadMgr.allowCoreThreadTimeOut(true);
   117         threadMgr.allowCoreThreadTimeOut(true);
   105         responseCache = Cache.newSoftMemoryCache(cacheCapacity, cacheLifetime);
   118         responseCache = Cache.newSoftMemoryCache(
       
   119                 cacheCapacity, cacheLifetime);
   106     }
   120     }
   107 
   121 
   108     /**
   122     /**
   109      * Get the current cache lifetime setting
   123      * Get the current cache lifetime setting
   110      *
   124      *
   145 
   159 
   146     /**
   160     /**
   147      * Get the ignore extensions setting.
   161      * Get the ignore extensions setting.
   148      *
   162      *
   149      * @return {@code true} if the {@code StatusResponseManager} will not
   163      * @return {@code true} if the {@code StatusResponseManager} will not
   150      * pass OCSP Extensions in the TLS {@code status_request[_v2]} extensions,
   164      * pass OCSP Extensions in the TLS {@code status_request[_v2]}
   151      * {@code false} if extensions will be passed (the default).
   165      * extensions, {@code false} if extensions will be passed (the default).
   152      */
   166      */
   153     boolean getIgnoreExtensions() {
   167     boolean getIgnoreExtensions() {
   154         return ignoreExtensions;
   168         return ignoreExtensions;
   155     }
   169     }
   156 
   170 
   157     /**
   171     /**
   158      * Clear the status response cache
   172      * Clear the status response cache
   159      */
   173      */
   160     void clear() {
   174     void clear() {
   161         debugLog("Clearing response cache");
   175         if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) {
       
   176             SSLLogger.fine("Clearing response cache");
       
   177         }
   162         responseCache.clear();
   178         responseCache.clear();
   163     }
   179     }
   164 
   180 
   165     /**
   181     /**
   166      * Returns the number of currently valid objects in the response cache.
   182      * Returns the number of currently valid objects in the response cache.
   170     int size() {
   186     int size() {
   171         return responseCache.size();
   187         return responseCache.size();
   172     }
   188     }
   173 
   189 
   174     /**
   190     /**
   175      * Obtain the URI use by the {@code StatusResponseManager} during lookups.
   191      * Obtain the URI use by the {@code StatusResponseManager} during
       
   192      * lookups.
       
   193      *
   176      * This method takes into account not only the AIA extension from a
   194      * This method takes into account not only the AIA extension from a
   177      * certificate to be checked, but also any default URI and possible
   195      * certificate to be checked, but also any default URI and possible
   178      * override settings for the response manager.
   196      * override settings for the response manager.
   179      *
   197      *
   180      * @param cert the subject to get the responder URI from
   198      * @param cert the subject to get the responder URI from
   181      *
   199      *
   182      * @return a {@code URI} containing the address to the OCSP responder, or
   200      * @return a {@code URI} containing the address to the OCSP responder,
   183      *      {@code null} if no AIA extension exists in the certificate and no
   201      *      or {@code null} if no AIA extension exists in the certificate
   184      *      default responder has been configured.
   202      *      and no default responder has been configured.
   185      *
   203      *
   186      * @throws NullPointerException if {@code cert} is {@code null}.
   204      * @throws NullPointerException if {@code cert} is {@code null}.
   187      */
   205      */
   188     URI getURI(X509Certificate cert) {
   206     URI getURI(X509Certificate cert) {
   189         Objects.requireNonNull(cert);
   207         Objects.requireNonNull(cert);
   190 
   208 
   191         if (cert.getExtensionValue(
   209         if (cert.getExtensionValue(
   192                 PKIXExtensions.OCSPNoCheck_Id.toString()) != null) {
   210                 PKIXExtensions.OCSPNoCheck_Id.toString()) != null) {
   193             debugLog("OCSP NoCheck extension found.  OCSP will be skipped");
   211             if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) {
       
   212                 SSLLogger.fine(
       
   213                     "OCSP NoCheck extension found.  OCSP will be skipped");
       
   214             }
   194             return null;
   215             return null;
   195         } else if (defaultResponder != null && respOverride) {
   216         } else if (defaultResponder != null && respOverride) {
   196             debugLog("Responder override: URI is " + defaultResponder);
   217             if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) {
       
   218               SSLLogger.fine(
       
   219                     "Responder override: URI is " + defaultResponder);
       
   220             }
   197             return defaultResponder;
   221             return defaultResponder;
   198         } else {
   222         } else {
   199             URI certURI = OCSP.getResponderURI(cert);
   223             URI certURI = OCSP.getResponderURI(cert);
   200             return (certURI != null ? certURI : defaultResponder);
   224             return (certURI != null ? certURI : defaultResponder);
   201         }
   225         }
   203 
   227 
   204     /**
   228     /**
   205      * Shutdown the thread pool
   229      * Shutdown the thread pool
   206      */
   230      */
   207     void shutdown() {
   231     void shutdown() {
   208         debugLog("Shutting down " + threadMgr.getActiveCount() +
   232         if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) {
   209                 " active threads");
   233             SSLLogger.fine("Shutting down " + threadMgr.getActiveCount() +
       
   234                     " active threads");
       
   235         }
   210         threadMgr.shutdown();
   236         threadMgr.shutdown();
   211     }
   237     }
   212 
   238 
   213     /**
   239     /**
   214      * Get a list of responses for a chain of certificates.
   240      * Get a list of responses for a chain of certificates.
   215      * This will find OCSP responses from the cache, or failing that, directly
   241      *
   216      * contact the OCSP responder.  It is assumed that the certificates in
   242      * This will find OCSP responses from the cache, or failing that,
   217      * the provided chain are in their proper order (from end-entity to
   243      * directly contact the OCSP responder.  It is assumed that the
   218      * trust anchor).
   244      * certificates in the provided chain are in their proper order
       
   245      * (from end-entity to trust anchor).
   219      *
   246      *
   220      * @param type the type of request being made of the
   247      * @param type the type of request being made of the
   221      *      {@code StatusResponseManager}
   248      *      {@code StatusResponseManager}
   222      * @param request the {@code StatusRequest} from the status_request or
   249      * @param request the {@code CertStatusRequest} from the
   223      *      status_request_v2 ClientHello extension.  A value of {@code null}
   250      *      status_request or status_request_v2 ClientHello extension.
   224      *      is interpreted as providing no responder IDs or extensions.
   251      *      A value of {@code null} is interpreted as providing no
   225      * @param chain an array of 2 or more certificates.  Each certificate must
   252      *      responder IDs or extensions.
   226      *      be issued by the next certificate in the chain.
   253      * @param chain an array of 2 or more certificates.  Each certificate
       
   254      *      must be issued by the next certificate in the chain.
   227      * @param delay the number of time units to delay before returning
   255      * @param delay the number of time units to delay before returning
   228      *      responses.
   256      *      responses.
   229      * @param unit the unit of time applied to the {@code delay} parameter
   257      * @param unit the unit of time applied to the {@code delay} parameter
   230      *
   258      *
   231      * @return an unmodifiable {@code Map} containing the certificate and
   259      * @return an unmodifiable {@code Map} containing the certificate and
   232      *      its usually
   260      *      its usually
   233      *
   261      *
   234      * @throws SSLHandshakeException if an unsupported {@code StatusRequest}
   262      * @throws SSLHandshakeException if an unsupported
   235      *      is provided.
   263      *      {@code CertStatusRequest} is provided.
   236      */
   264      */
   237     Map<X509Certificate, byte[]> get(StatusRequestType type,
   265     Map<X509Certificate, byte[]> get(CertStatusRequestType type,
   238             StatusRequest request, X509Certificate[] chain, long delay,
   266             CertStatusRequest request, X509Certificate[] chain, long delay,
   239             TimeUnit unit) {
   267             TimeUnit unit) {
   240         Map<X509Certificate, byte[]> responseMap = new HashMap<>();
   268         Map<X509Certificate, byte[]> responseMap = new HashMap<>();
   241         List<OCSPFetchCall> requestList = new ArrayList<>();
   269         List<OCSPFetchCall> requestList = new ArrayList<>();
   242 
   270 
   243         debugLog("Beginning check: Type = " + type + ", Chain length = " +
   271         if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) {
       
   272             SSLLogger.fine(
       
   273                 "Beginning check: Type = " + type + ", Chain length = " +
   244                 chain.length);
   274                 chain.length);
       
   275         }
   245 
   276 
   246         // It is assumed that the caller has ordered the certs in the chain
   277         // It is assumed that the caller has ordered the certs in the chain
   247         // in the proper order (each certificate is issued by the next entry
   278         // in the proper order (each certificate is issued by the next entry
   248         // in the provided chain).
   279         // in the provided chain).
   249         if (chain.length < 2) {
   280         if (chain.length < 2) {
   250             return Collections.emptyMap();
   281             return Collections.emptyMap();
   251         }
   282         }
   252 
   283 
   253         if (type == StatusRequestType.OCSP) {
   284         if (type == CertStatusRequestType.OCSP) {
   254             try {
   285             try {
   255                 // For type OCSP, we only check the end-entity certificate
   286                 // For type OCSP, we only check the end-entity certificate
   256                 OCSPStatusRequest ocspReq = (OCSPStatusRequest)request;
   287                 OCSPStatusRequest ocspReq = (OCSPStatusRequest)request;
   257                 CertId cid = new CertId(chain[1],
   288                 CertId cid = new CertId(chain[1],
   258                         new SerialNumber(chain[0].getSerialNumber()));
   289                         new SerialNumber(chain[0].getSerialNumber()));
   262                 } else {
   293                 } else {
   263                     StatusInfo sInfo = new StatusInfo(chain[0], cid);
   294                     StatusInfo sInfo = new StatusInfo(chain[0], cid);
   264                     requestList.add(new OCSPFetchCall(sInfo, ocspReq));
   295                     requestList.add(new OCSPFetchCall(sInfo, ocspReq));
   265                 }
   296                 }
   266             } catch (IOException exc) {
   297             } catch (IOException exc) {
   267                 debugLog("Exception during CertId creation: " + exc);
   298                 if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) {
   268             }
   299                     SSLLogger.fine(
   269         } else if (type == StatusRequestType.OCSP_MULTI) {
   300                         "Exception during CertId creation: ", exc);
       
   301                 }
       
   302             }
       
   303         } else if (type == CertStatusRequestType.OCSP_MULTI) {
   270             // For type OCSP_MULTI, we check every cert in the chain that
   304             // For type OCSP_MULTI, we check every cert in the chain that
   271             // has a direct issuer at the next index.  We won't have an issuer
   305             // has a direct issuer at the next index.  We won't have an
   272             // certificate for the last certificate in the chain and will
   306             // issuer certificate for the last certificate in the chain
   273             // not be able to create a CertId because of that.
   307             // and will not be able to create a CertId because of that.
   274             OCSPStatusRequest ocspReq = (OCSPStatusRequest)request;
   308             OCSPStatusRequest ocspReq = (OCSPStatusRequest)request;
   275             int ctr;
   309             int ctr;
   276             for (ctr = 0; ctr < chain.length - 1; ctr++) {
   310             for (ctr = 0; ctr < chain.length - 1; ctr++) {
   277                 try {
   311                 try {
   278                     // The cert at "ctr" is the subject cert, "ctr + 1" is the
   312                     // The cert at "ctr" is the subject cert, "ctr + 1"
   279                     // issuer certificate.
   313                     // is the issuer certificate.
   280                     CertId cid = new CertId(chain[ctr + 1],
   314                     CertId cid = new CertId(chain[ctr + 1],
   281                             new SerialNumber(chain[ctr].getSerialNumber()));
   315                         new SerialNumber(chain[ctr].getSerialNumber()));
   282                     ResponseCacheEntry cacheEntry = getFromCache(cid, ocspReq);
   316                     ResponseCacheEntry cacheEntry =
       
   317                         getFromCache(cid, ocspReq);
   283                     if (cacheEntry != null) {
   318                     if (cacheEntry != null) {
   284                         responseMap.put(chain[ctr], cacheEntry.ocspBytes);
   319                         responseMap.put(chain[ctr], cacheEntry.ocspBytes);
   285                     } else {
   320                     } else {
   286                         StatusInfo sInfo = new StatusInfo(chain[ctr], cid);
   321                         StatusInfo sInfo = new StatusInfo(chain[ctr], cid);
   287                         requestList.add(new OCSPFetchCall(sInfo, ocspReq));
   322                         requestList.add(new OCSPFetchCall(sInfo, ocspReq));
   288                     }
   323                     }
   289                 } catch (IOException exc) {
   324                 } catch (IOException exc) {
   290                     debugLog("Exception during CertId creation: " + exc);
   325                     if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) {
       
   326                         SSLLogger.fine(
       
   327                             "Exception during CertId creation: ", exc);
       
   328                     }
   291                 }
   329                 }
   292             }
   330             }
   293         } else {
   331         } else {
   294             debugLog("Unsupported status request type: " + type);
   332             if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) {
       
   333                 SSLLogger.fine("Unsupported status request type: " + type);
       
   334             }
   295         }
   335         }
   296 
   336 
   297         // If we were able to create one or more Fetches, go and run all
   337         // If we were able to create one or more Fetches, go and run all
   298         // of them in separate threads.  For all the threads that completed
   338         // of them in separate threads.  For all the threads that completed
   299         // in the allotted time, put those status responses into the returned
   339         // in the allotted time, put those status responses into the
   300         // Map.
   340         // returned Map.
   301         if (!requestList.isEmpty()) {
   341         if (!requestList.isEmpty()) {
   302             try {
   342             try {
   303                 // Set a bunch of threads to go do the fetching
   343                 // Set a bunch of threads to go do the fetching
   304                 List<Future<StatusInfo>> resultList =
   344                 List<Future<StatusInfo>> resultList =
   305                         threadMgr.invokeAll(requestList, delay, unit);
   345                         threadMgr.invokeAll(requestList, delay, unit);
   306 
   346 
   307                 // Go through the Futures and from any non-cancelled task,
   347                 // Go through the Futures and from any non-cancelled task,
   308                 // get the bytes and attach them to the responseMap.
   348                 // get the bytes and attach them to the responseMap.
   309                 for (Future<StatusInfo> task : resultList) {
   349                 for (Future<StatusInfo> task : resultList) {
   310                     if (task.isDone()) {
   350                     if (!task.isDone()) {
   311                         if (!task.isCancelled()) {
   351                         continue;
   312                             StatusInfo info = task.get();
   352                     }
   313                             if (info != null && info.responseData != null) {
   353 
   314                                 responseMap.put(info.cert,
   354                     if (!task.isCancelled()) {
   315                                         info.responseData.ocspBytes);
   355                         StatusInfo info = task.get();
   316                             } else {
   356                         if (info != null && info.responseData != null) {
   317                                 debugLog("Completed task had no response data");
   357                             responseMap.put(info.cert,
   318                             }
   358                                     info.responseData.ocspBytes);
   319                         } else {
   359                         } else if (SSLLogger.isOn &&
   320                             debugLog("Found cancelled task");
   360                                 SSLLogger.isOn("respmgr")) {
       
   361                             SSLLogger.fine(
       
   362                                 "Completed task had no response data");
       
   363                         }
       
   364                     } else {
       
   365                         if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) {
       
   366                             SSLLogger.fine("Found cancelled task");
   321                         }
   367                         }
   322                     }
   368                     }
   323                 }
   369                 }
   324             } catch (InterruptedException | ExecutionException exc) {
   370             } catch (InterruptedException | ExecutionException exc) {
   325                 // Not sure what else to do here
   371                 // Not sure what else to do here
   326                 debugLog("Exception when getting data: " + exc);
   372                 if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) {
       
   373                     SSLLogger.fine("Exception when getting data: ", exc);
       
   374                 }
   327             }
   375             }
   328         }
   376         }
   329 
   377 
   330         return Collections.unmodifiableMap(responseMap);
   378         return Collections.unmodifiableMap(responseMap);
   331     }
   379     }
   343      */
   391      */
   344     private ResponseCacheEntry getFromCache(CertId cid,
   392     private ResponseCacheEntry getFromCache(CertId cid,
   345             OCSPStatusRequest ocspRequest) {
   393             OCSPStatusRequest ocspRequest) {
   346         // Determine if the nonce extension is present in the request.  If
   394         // Determine if the nonce extension is present in the request.  If
   347         // so, then do not attempt to retrieve the response from the cache.
   395         // so, then do not attempt to retrieve the response from the cache.
   348         for (Extension ext : ocspRequest.getExtensions()) {
   396         for (Extension ext : ocspRequest.extensions) {
   349             if (ext.getId().equals(PKIXExtensions.OCSPNonce_Id.toString())) {
   397             if (ext.getId().equals(
   350                 debugLog("Nonce extension found, skipping cache check");
   398                     PKIXExtensions.OCSPNonce_Id.toString())) {
       
   399                 if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) {
       
   400                     SSLLogger.fine(
       
   401                             "Nonce extension found, skipping cache check");
       
   402                 }
   351                 return null;
   403                 return null;
   352             }
   404             }
   353         }
   405         }
   354 
   406 
   355         ResponseCacheEntry respEntry = responseCache.get(cid);
   407         ResponseCacheEntry respEntry = responseCache.get(cid);
   357         // If the response entry has a nextUpdate and it has expired
   409         // If the response entry has a nextUpdate and it has expired
   358         // before the cache expiration, purge it from the cache
   410         // before the cache expiration, purge it from the cache
   359         // and do not return it as a cache hit.
   411         // and do not return it as a cache hit.
   360         if (respEntry != null && respEntry.nextUpdate != null &&
   412         if (respEntry != null && respEntry.nextUpdate != null &&
   361                 respEntry.nextUpdate.before(new Date())) {
   413                 respEntry.nextUpdate.before(new Date())) {
   362             debugLog("nextUpdate threshold exceeded, purging from cache");
   414             if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) {
       
   415                 SSLLogger.fine(
       
   416                     "nextUpdate threshold exceeded, purging from cache");
       
   417             }
   363             respEntry = null;
   418             respEntry = null;
   364         }
   419         }
   365 
   420 
   366         debugLog("Check cache for SN" + cid.getSerialNumber() + ": " +
   421         if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) {
   367                 (respEntry != null ? "HIT" : "MISS"));
   422             SSLLogger.fine(
       
   423                     "Check cache for SN" + cid.getSerialNumber() + ": " +
       
   424                     (respEntry != null ? "HIT" : "MISS"));
       
   425         }
   368         return respEntry;
   426         return respEntry;
   369     }
   427     }
   370 
   428 
   371     @Override
   429     @Override
   372     public String toString() {
   430     public String toString() {
   396 
   454 
   397         return sb.toString();
   455         return sb.toString();
   398     }
   456     }
   399 
   457 
   400     /**
   458     /**
   401      * Log messages through the SSL Debug facility.
       
   402      *
       
   403      * @param message the message to be displayed
       
   404      */
       
   405     static void debugLog(String message) {
       
   406         if (debug != null && Debug.isOn("respmgr")) {
       
   407             StringBuilder sb = new StringBuilder();
       
   408             sb.append("[").append(Thread.currentThread().getName());
       
   409             sb.append("] ").append(message);
       
   410             System.out.println(sb.toString());
       
   411         }
       
   412     }
       
   413 
       
   414     /**
       
   415      * Inner class used to group request and response data.
   459      * Inner class used to group request and response data.
   416      */
   460      */
   417     class StatusInfo {
   461     class StatusInfo {
   418         final X509Certificate cert;
   462         final X509Certificate cert;
   419         final CertId cid;
   463         final CertId cid;
   424          * Create a StatusInfo object from certificate data.
   468          * Create a StatusInfo object from certificate data.
   425          *
   469          *
   426          * @param subjectCert the certificate to be checked for revocation
   470          * @param subjectCert the certificate to be checked for revocation
   427          * @param issuerCert the issuer of the {@code subjectCert}
   471          * @param issuerCert the issuer of the {@code subjectCert}
   428          *
   472          *
   429          * @throws IOException if CertId creation from the certificates fails
   473          * @throws IOException if CertId creation from the certificate fails
   430          */
   474          */
   431         StatusInfo(X509Certificate subjectCert, X509Certificate issuerCert)
   475         StatusInfo(X509Certificate subjectCert, X509Certificate issuerCert)
   432                 throws IOException {
   476                 throws IOException {
   433             this(subjectCert, new CertId(issuerCert,
   477             this(subjectCert, new CertId(issuerCert,
   434                     new SerialNumber(subjectCert.getSerialNumber())));
   478                     new SerialNumber(subjectCert.getSerialNumber())));
   469          * @return a {@code String} representation of this object
   513          * @return a {@code String} representation of this object
   470          */
   514          */
   471         @Override
   515         @Override
   472         public String toString() {
   516         public String toString() {
   473             StringBuilder sb = new StringBuilder("StatusInfo:");
   517             StringBuilder sb = new StringBuilder("StatusInfo:");
   474             sb.append("\n\tCert: ").append(this.cert.getSubjectX500Principal());
   518             sb.append("\n\tCert: ").append(
       
   519                     this.cert.getSubjectX500Principal());
   475             sb.append("\n\tSerial: ").append(this.cert.getSerialNumber());
   520             sb.append("\n\tSerial: ").append(this.cert.getSerialNumber());
   476             sb.append("\n\tResponder: ").append(this.responder);
   521             sb.append("\n\tResponder: ").append(this.responder);
   477             sb.append("\n\tResponse data: ").append(this.responseData != null ?
   522             sb.append("\n\tResponse data: ").append(
   478                     (this.responseData.ocspBytes.length + " bytes") : "<NULL>");
   523                     this.responseData != null ?
       
   524                         (this.responseData.ocspBytes.length + " bytes") :
       
   525                         "<NULL>");
   479             return sb.toString();
   526             return sb.toString();
   480         }
   527         }
   481     }
   528     }
   482 
   529 
   483     /**
   530     /**
   484      * Static nested class used as the data kept in the response cache.
   531      * Static nested class used as the data kept in the response cache.
   485      */
   532      */
   486     static class ResponseCacheEntry {
   533     class ResponseCacheEntry {
   487         final OCSPResponse.ResponseStatus status;
   534         final OCSPResponse.ResponseStatus status;
   488         final byte[] ocspBytes;
   535         final byte[] ocspBytes;
   489         final Date nextUpdate;
   536         final Date nextUpdate;
   490         final OCSPResponse.SingleResponse singleResp;
   537         final OCSPResponse.SingleResponse singleResp;
   491         final ResponderId respId;
   538         final ResponderId respId;
   493         /**
   540         /**
   494          * Create a new cache entry from the raw bytes of the response
   541          * Create a new cache entry from the raw bytes of the response
   495          *
   542          *
   496          * @param responseBytes the DER encoding for the OCSP response
   543          * @param responseBytes the DER encoding for the OCSP response
   497          *
   544          *
   498          * @throws IOException if an {@code OCSPResponse} cannot be created from
   545          * @throws IOException if an {@code OCSPResponse} cannot be
   499          *      the encoded bytes.
   546          *         created from the encoded bytes.
   500          */
   547          */
   501         ResponseCacheEntry(byte[] responseBytes, CertId cid)
   548         ResponseCacheEntry(byte[] responseBytes, CertId cid)
   502                 throws IOException {
   549                 throws IOException {
   503             Objects.requireNonNull(responseBytes,
   550             Objects.requireNonNull(responseBytes,
   504                     "Non-null responseBytes required");
   551                     "Non-null responseBytes required");
   513                 if (singleResp != null) {
   560                 if (singleResp != null) {
   514                     // Pull out the nextUpdate field in advance because the
   561                     // Pull out the nextUpdate field in advance because the
   515                     // Date is cloned.
   562                     // Date is cloned.
   516                     nextUpdate = singleResp.getNextUpdate();
   563                     nextUpdate = singleResp.getNextUpdate();
   517                 } else {
   564                 } else {
   518                     throw new IOException("Unable to find SingleResponse for " +
   565                     throw new IOException(
   519                             "SN " + cid.getSerialNumber());
   566                             "Unable to find SingleResponse for SN " +
       
   567                             cid.getSerialNumber());
   520                 }
   568                 }
   521             } else {
   569             } else {
   522                 nextUpdate = null;
   570                 nextUpdate = null;
   523             }
   571             }
   524         }
   572         }
   535         List<Extension> extensions;
   583         List<Extension> extensions;
   536         List<ResponderId> responderIds;
   584         List<ResponderId> responderIds;
   537 
   585 
   538         /**
   586         /**
   539          * A constructor that builds the OCSPFetchCall from the provided
   587          * A constructor that builds the OCSPFetchCall from the provided
   540          * StatusInfo and information from the status_request[_v2] extension.
   588          * StatusInfo and information from the status_request[_v2]
       
   589          * extension.
   541          *
   590          *
   542          * @param info the {@code StatusInfo} containing the subject
   591          * @param info the {@code StatusInfo} containing the subject
   543          * certificate, CertId, and other supplemental info.
   592          * certificate, CertId, and other supplemental info.
   544          * @param request the {@code OCSPStatusRequest} containing any
   593          * @param request the {@code OCSPStatusRequest} containing any
   545          * responder IDs and extensions.
   594          * responder IDs and extensions.
   547         public OCSPFetchCall(StatusInfo info, OCSPStatusRequest request) {
   596         public OCSPFetchCall(StatusInfo info, OCSPStatusRequest request) {
   548             statInfo = Objects.requireNonNull(info,
   597             statInfo = Objects.requireNonNull(info,
   549                     "Null StatusInfo not allowed");
   598                     "Null StatusInfo not allowed");
   550             ocspRequest = Objects.requireNonNull(request,
   599             ocspRequest = Objects.requireNonNull(request,
   551                     "Null OCSPStatusRequest not allowed");
   600                     "Null OCSPStatusRequest not allowed");
   552             extensions = ocspRequest.getExtensions();
   601             extensions = ocspRequest.extensions;
   553             responderIds = ocspRequest.getResponderIds();
   602             responderIds = ocspRequest.responderIds;
   554         }
   603         }
   555 
   604 
   556         /**
   605         /**
   557          * Get an OCSP response, either from the cache or from a responder.
   606          * Get an OCSP response, either from the cache or from a responder.
   558          *
   607          *
   559          * @return The StatusInfo object passed into the {@code OCSPFetchCall}
   608          * @return The StatusInfo object passed into the
   560          * constructor, with the {@code responseData} field filled in with the
   609          *         {@code OCSPFetchCall} constructor, with the
   561          * response or {@code null} if no response can be obtained.
   610          *         {@code responseData} field filled in with the response
       
   611          *         or {@code null} if no response can be obtained.
   562          */
   612          */
   563         @Override
   613         @Override
   564         public StatusInfo call() {
   614         public StatusInfo call() {
   565             debugLog("Starting fetch for SN " + statInfo.cid.getSerialNumber());
   615             if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) {
       
   616                 SSLLogger.fine(
       
   617                     "Starting fetch for SN " +
       
   618                     statInfo.cid.getSerialNumber());
       
   619             }
   566             try {
   620             try {
   567                 ResponseCacheEntry cacheEntry;
   621                 ResponseCacheEntry cacheEntry;
   568                 List<Extension> extsToSend;
   622                 List<Extension> extsToSend;
   569 
   623 
   570                 if (statInfo.responder == null) {
   624                 if (statInfo.responder == null) {
   571                     // If we have no URI then there's nothing to do but return
   625                     // If we have no URI then there's nothing to do
   572                     debugLog("Null URI detected, OCSP fetch aborted.");
   626                     // but return.
       
   627                     if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) {
       
   628                         SSLLogger.fine(
       
   629                             "Null URI detected, OCSP fetch aborted");
       
   630                     }
   573                     return statInfo;
   631                     return statInfo;
   574                 } else {
   632                 } else {
   575                     debugLog("Attempting fetch from " + statInfo.responder);
   633                     if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) {
       
   634                         SSLLogger.fine(
       
   635                             "Attempting fetch from " + statInfo.responder);
       
   636                     }
   576                 }
   637                 }
   577 
   638 
   578                 // If the StatusResponseManager has been configured to not
   639                 // If the StatusResponseManager has been configured to not
   579                 // forward extensions, then set extensions to an empty list.
   640                 // forward extensions, then set extensions to an empty
   580                 // We will forward the extensions unless one of two conditions
   641                 // list.
   581                 // occur: (1) The jdk.tls.stapling.ignoreExtensions property is
   642                 //
   582                 // true or (2) There is a non-empty ResponderId list.
   643                 // We will forward the extensions unless one of two
       
   644                 // conditions occur:
       
   645                 // (1) The jdk.tls.stapling.ignoreExtensions property is
       
   646                 //     true, or
       
   647                 // (2) There is a non-empty ResponderId list.
       
   648                 //
   583                 // ResponderId selection is a feature that will be
   649                 // ResponderId selection is a feature that will be
   584                 // supported in the future.
   650                 // supported in the future.
   585                 extsToSend = (ignoreExtensions || !responderIds.isEmpty()) ?
   651                 extsToSend = (ignoreExtensions || !responderIds.isEmpty()) ?
   586                         Collections.emptyList() : extensions;
   652                         Collections.emptyList() : extensions;
   587 
   653 
   593                     // Place the data into the response cache
   659                     // Place the data into the response cache
   594                     cacheEntry = new ResponseCacheEntry(respBytes,
   660                     cacheEntry = new ResponseCacheEntry(respBytes,
   595                             statInfo.cid);
   661                             statInfo.cid);
   596 
   662 
   597                     // Get the response status and act on it appropriately
   663                     // Get the response status and act on it appropriately
   598                     debugLog("OCSP Status: " + cacheEntry.status +
   664                     if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) {
       
   665                         SSLLogger.fine("OCSP Status: " + cacheEntry.status +
   599                             " (" + respBytes.length + " bytes)");
   666                             " (" + respBytes.length + " bytes)");
       
   667                     }
   600                     if (cacheEntry.status ==
   668                     if (cacheEntry.status ==
   601                             OCSPResponse.ResponseStatus.SUCCESSFUL) {
   669                             OCSPResponse.ResponseStatus.SUCCESSFUL) {
   602                         // Set the response in the returned StatusInfo
   670                         // Set the response in the returned StatusInfo
   603                         statInfo.responseData = cacheEntry;
   671                         statInfo.responseData = cacheEntry;
   604 
   672 
   605                         // Add the response to the cache (if applicable)
   673                         // Add the response to the cache (if applicable)
   606                         addToCache(statInfo.cid, cacheEntry);
   674                         addToCache(statInfo.cid, cacheEntry);
   607                     }
   675                     }
   608                 } else {
   676                 } else {
   609                     debugLog("No data returned from OCSP Responder");
   677                     if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) {
       
   678                         SSLLogger.fine(
       
   679                             "No data returned from OCSP Responder");
       
   680                     }
   610                 }
   681                 }
   611             } catch (IOException ioe) {
   682             } catch (IOException ioe) {
   612                 debugLog("Caught exception: " + ioe);
   683                 if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) {
       
   684                     SSLLogger.fine("Caught exception: ", ioe);
       
   685                 }
   613             }
   686             }
   614 
   687 
   615             return statInfo;
   688             return statInfo;
   616         }
   689         }
   617 
   690 
   624          */
   697          */
   625         private void addToCache(CertId certId, ResponseCacheEntry entry) {
   698         private void addToCache(CertId certId, ResponseCacheEntry entry) {
   626             // If no cache lifetime has been set on entries then
   699             // If no cache lifetime has been set on entries then
   627             // don't cache this response if there is no nextUpdate field
   700             // don't cache this response if there is no nextUpdate field
   628             if (entry.nextUpdate == null && cacheLifetime == 0) {
   701             if (entry.nextUpdate == null && cacheLifetime == 0) {
   629                 debugLog("Not caching this OCSP response");
   702                 if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) {
       
   703                     SSLLogger.fine("Not caching this OCSP response");
       
   704                 }
   630             } else {
   705             } else {
   631                 responseCache.put(certId, entry);
   706                 responseCache.put(certId, entry);
   632                 debugLog("Added response for SN " + certId.getSerialNumber() +
   707                 if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) {
       
   708                     SSLLogger.fine(
       
   709                         "Added response for SN " +
       
   710                         certId.getSerialNumber() +
   633                         " to cache");
   711                         " to cache");
       
   712                 }
   634             }
   713             }
   635         }
   714         }
   636 
   715 
   637         /**
   716         /**
   638          * Determine the delay to use when scheduling the task that will
   717          * Determine the delay to use when scheduling the task that will
   639          * update the OCSP response.  This is the shorter time between the
   718          * update the OCSP response.  This is the shorter time between the
   640          * cache lifetime and the nextUpdate.  If no nextUpdate is present in
   719          * cache lifetime and the nextUpdate.  If no nextUpdate is present
   641          * the response, then only the cache lifetime is used.
   720          * in the response, then only the cache lifetime is used.
   642          * If cache timeouts are disabled (a zero value) and there's no
   721          * If cache timeouts are disabled (a zero value) and there's no
   643          * nextUpdate, then the entry is not cached and no rescheduling will
   722          * nextUpdate, then the entry is not cached and no rescheduling
   644          * take place.
   723          * will take place.
   645          *
   724          *
   646          * @param nextUpdate a {@code Date} object corresponding to the
   725          * @param nextUpdate a {@code Date} object corresponding to the
   647          *      next update time from a SingleResponse.
   726          *      next update time from a SingleResponse.
   648          *
   727          *
   649          * @return the number of seconds of delay before the next fetch
   728          * @return the number of seconds of delay before the next fetch
   665             }
   744             }
   666 
   745 
   667             return delaySec;
   746             return delaySec;
   668         }
   747         }
   669     }
   748     }
       
   749 
       
   750     static final StaplingParameters processStapling(
       
   751             ServerHandshakeContext shc) {
       
   752         StaplingParameters params = null;
       
   753         SSLExtension ext = null;
       
   754         CertStatusRequestType type = null;
       
   755         CertStatusRequest req = null;
       
   756         Map<X509Certificate, byte[]> responses;
       
   757 
       
   758         // If this feature has not been enabled, then no more processing
       
   759         // is necessary.  Also we will only staple if we're doing a full
       
   760         // handshake.
       
   761         if (!shc.sslContext.isStaplingEnabled(false) || shc.isResumption) {
       
   762             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   763                 SSLLogger.fine("Staping disabled or is a resumed session");
       
   764             }
       
   765             return null;
       
   766         }
       
   767 
       
   768         // Check if the client has asserted the status_request[_v2] extension(s)
       
   769         Map<SSLExtension, SSLExtension.SSLExtensionSpec> exts =
       
   770                 shc.handshakeExtensions;
       
   771         CertStatusRequestSpec statReq = (CertStatusRequestSpec)exts.get(
       
   772                 SSLExtension.CH_STATUS_REQUEST);
       
   773         CertStatusRequestV2Spec statReqV2 = (CertStatusRequestV2Spec)
       
   774                 exts.get(SSLExtension.CH_STATUS_REQUEST_V2);
       
   775 
       
   776         // Determine which type of stapling we are doing and assert the
       
   777         // proper extension in the server hello.
       
   778         // Favor status_request_v2 over status_request and ocsp_multi
       
   779         // over ocsp.
       
   780         // If multiple ocsp or ocsp_multi types exist, select the first
       
   781         // instance of a given type.  Also since we don't support ResponderId
       
   782         // selection yet, only accept a request if the ResponderId field
       
   783         // is empty.  Finally, we'll only do this in (D)TLS 1.2 or earlier.
       
   784         if (statReqV2 != null && !shc.negotiatedProtocol.useTLS13PlusSpec()) {
       
   785             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake,verbose")) {
       
   786                 SSLLogger.fine("SH Processing status_request_v2 extension");
       
   787             }
       
   788             // RFC 6961 stapling
       
   789             ext = SSLExtension.CH_STATUS_REQUEST_V2;
       
   790             int ocspIdx = -1;
       
   791             int ocspMultiIdx = -1;
       
   792             CertStatusRequest[] reqItems = statReqV2.certStatusRequests;
       
   793             for (int pos = 0; (pos < reqItems.length &&
       
   794                     (ocspIdx == -1 || ocspMultiIdx == -1)); pos++) {
       
   795                 CertStatusRequest item = reqItems[pos];
       
   796                 CertStatusRequestType curType =
       
   797                         CertStatusRequestType.valueOf(item.statusType);
       
   798                 if (ocspIdx < 0 && curType == CertStatusRequestType.OCSP) {
       
   799                     OCSPStatusRequest ocspReq = (OCSPStatusRequest)item;
       
   800                     // We currently only accept empty responder ID lists
       
   801                     // but may support them in the future
       
   802                     if (ocspReq.responderIds.isEmpty()) {
       
   803                         ocspIdx = pos;
       
   804                     }
       
   805                 } else if (ocspMultiIdx < 0 &&
       
   806                         curType == CertStatusRequestType.OCSP_MULTI) {
       
   807                     OCSPStatusRequest ocspReq = (OCSPStatusRequest)item;
       
   808                     // We currently only accept empty responder ID lists
       
   809                     // but may support them in the future
       
   810                     if (ocspReq.responderIds.isEmpty()) {
       
   811                         ocspMultiIdx = pos;
       
   812                     }
       
   813                 }
       
   814             }
       
   815             if (ocspMultiIdx >= 0) {
       
   816                 req = reqItems[ocspMultiIdx];
       
   817                 type = CertStatusRequestType.valueOf(req.statusType);
       
   818             } else if (ocspIdx >= 0) {
       
   819                 req = reqItems[ocspIdx];
       
   820                 type = CertStatusRequestType.valueOf(req.statusType);
       
   821             } else {
       
   822                 if (SSLLogger.isOn &&
       
   823                         SSLLogger.isOn("ssl,handshake")) {
       
   824                     SSLLogger.finest("Warning: No suitable request " +
       
   825                             "found in the status_request_v2 extension.");
       
   826                 }
       
   827             }
       
   828         }
       
   829 
       
   830         // Only attempt to process a status_request extension if:
       
   831         // * The status_request extension is set AND
       
   832         // * either the status_request_v2 extension is not present OR
       
   833         // * none of the underlying OCSPStatusRequest structures is
       
   834         // suitable for stapling.
       
   835         // If either of the latter two bullet items is true the ext,
       
   836         // type and req variables should all be null.  If any are null
       
   837         // we will try processing an asserted status_request.
       
   838         if ((statReq != null) &&
       
   839                 (ext == null || type == null || req == null)) {
       
   840             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake,verbose")) {
       
   841                 SSLLogger.fine("SH Processing status_request extension");
       
   842             }
       
   843             ext = SSLExtension.CH_STATUS_REQUEST;
       
   844             type = CertStatusRequestType.valueOf(
       
   845                     statReq.statusRequest.statusType);
       
   846             if (type == CertStatusRequestType.OCSP) {
       
   847                 // If the type is OCSP, then the request is guaranteed
       
   848                 // to be OCSPStatusRequest
       
   849                 OCSPStatusRequest ocspReq =
       
   850                         (OCSPStatusRequest)statReq.statusRequest;
       
   851                 if (ocspReq.responderIds.isEmpty()) {
       
   852                     req = ocspReq;
       
   853                 } else {
       
   854                     if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   855                         SSLLogger.finest("Warning: No suitable request " +
       
   856                             "found in the status_request extension.");
       
   857                     }
       
   858                 }
       
   859             }
       
   860         }
       
   861 
       
   862         // If, after walking through the extensions we were unable to
       
   863         // find a suitable StatusRequest, then stapling is disabled.
       
   864         // The ext, type and req variables must have been set to continue.
       
   865         if (type == null || req == null || ext == null) {
       
   866             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   867                 SSLLogger.fine("No suitable status_request or " +
       
   868                         "status_request_v2, stapling is disabled");
       
   869             }
       
   870             return null;
       
   871         }
       
   872 
       
   873         // Get the cert chain since we'll need it for OCSP checking
       
   874         X509Possession x509Possession = null;
       
   875         for (SSLPossession possession : shc.handshakePossessions) {
       
   876             if (possession instanceof X509Possession) {
       
   877                 x509Possession = (X509Possession)possession;
       
   878                 break;
       
   879             }
       
   880         }
       
   881 
       
   882         if (x509Possession == null) {       // unlikely
       
   883             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   884                 SSLLogger.finest("Warning: no X.509 certificates found.  " +
       
   885                         "Stapling is disabled.");
       
   886             }
       
   887             return null;
       
   888         }
       
   889 
       
   890         // Get the OCSP responses from the StatusResponseManager
       
   891         X509Certificate[] certs = x509Possession.popCerts;
       
   892         StatusResponseManager statRespMgr =
       
   893                 shc.sslContext.getStatusResponseManager();
       
   894         if (statRespMgr != null) {
       
   895             // For the purposes of the fetch from the SRM, override the
       
   896             // type when it is TLS 1.3 so it always gets responses for
       
   897             // all certs it can.  This should not change the type field
       
   898             // in the StaplingParameters though.
       
   899             CertStatusRequestType fetchType =
       
   900                     shc.negotiatedProtocol.useTLS13PlusSpec() ?
       
   901                     CertStatusRequestType.OCSP_MULTI : type;
       
   902             responses = statRespMgr.get(fetchType, req, certs,
       
   903                     shc.statusRespTimeout, TimeUnit.MILLISECONDS);
       
   904             if (!responses.isEmpty()) {
       
   905                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   906                     SSLLogger.finest("Response manager returned " +
       
   907                             responses.size() + " entries.");
       
   908                 }
       
   909                 // If this RFC 6066-style stapling (SSL cert only) then the
       
   910                 // response cannot be zero length
       
   911                 if (type == CertStatusRequestType.OCSP) {
       
   912                     byte[] respDER = responses.get(certs[0]);
       
   913                     if (respDER == null || respDER.length <= 0) {
       
   914                         if (SSLLogger.isOn &&
       
   915                                 SSLLogger.isOn("ssl,handshake")) {
       
   916                             SSLLogger.finest("Warning: Null or zero-length " +
       
   917                                     "response found for leaf certificate. " +
       
   918                                     "Stapling is disabled.");
       
   919                         }
       
   920                         return null;
       
   921                     }
       
   922                 }
       
   923                 params = new StaplingParameters(ext, type, req, responses);
       
   924             } else {
       
   925                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   926                     SSLLogger.finest("Warning: no OCSP responses obtained.  " +
       
   927                             "Stapling is disabled.");
       
   928                 }
       
   929             }
       
   930         } else {
       
   931             // This should not happen, but if lazy initialization of the
       
   932             // StatusResponseManager doesn't occur we should turn off stapling.
       
   933             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   934                 SSLLogger.finest("Warning: lazy initialization " +
       
   935                         "of the StatusResponseManager failed.  " +
       
   936                         "Stapling is disabled.");
       
   937             }
       
   938             params = null;
       
   939         }
       
   940 
       
   941         return params;
       
   942     }
       
   943 
       
   944     /**
       
   945      * Inner class used to hold stapling parameters needed by the handshaker
       
   946      * when stapling is active.
       
   947      */
       
   948     static final class StaplingParameters {
       
   949         final SSLExtension statusRespExt;
       
   950         final CertStatusRequestType statReqType;
       
   951         final CertStatusRequest statReqData;
       
   952         final Map<X509Certificate, byte[]> responseMap;
       
   953 
       
   954         StaplingParameters(SSLExtension ext, CertStatusRequestType type,
       
   955                 CertStatusRequest req, Map<X509Certificate, byte[]> responses) {
       
   956             statusRespExt = ext;
       
   957             statReqType = type;
       
   958             statReqData = req;
       
   959             responseMap = responses;
       
   960         }
       
   961     }
   670 }
   962 }
       
   963