src/java.base/share/classes/sun/security/ssl/CertStatusExtension.java
changeset 50768 68fa3d4026ea
parent 47216 71c04702a3d5
child 53064 103ed9569fc8
equal deleted inserted replaced
50767:356eaea05bf0 50768:68fa3d4026ea
       
     1 /*
       
     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.
       
     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.ssl;
       
    27 
       
    28 import java.io.IOException;
       
    29 import java.io.ByteArrayInputStream;
       
    30 import java.nio.ByteBuffer;
       
    31 import java.security.cert.Extension;
       
    32 import java.security.cert.CertificateFactory;
       
    33 import java.security.cert.CertificateException;
       
    34 import java.security.cert.X509Certificate;
       
    35 import java.text.MessageFormat;
       
    36 import java.util.ArrayList;
       
    37 import java.util.List;
       
    38 import java.util.Locale;
       
    39 import javax.net.ssl.SSLProtocolException;
       
    40 import sun.security.provider.certpath.OCSPResponse;
       
    41 import sun.security.provider.certpath.ResponderId;
       
    42 import static sun.security.ssl.SSLExtension.CH_STATUS_REQUEST;
       
    43 import static sun.security.ssl.SSLExtension.CH_STATUS_REQUEST_V2;
       
    44 import sun.security.ssl.SSLExtension.ExtensionConsumer;
       
    45 import static sun.security.ssl.SSLExtension.SH_STATUS_REQUEST;
       
    46 import static sun.security.ssl.SSLExtension.SH_STATUS_REQUEST_V2;
       
    47 import sun.security.ssl.SSLExtension.SSLExtensionSpec;
       
    48 import sun.security.ssl.SSLHandshake.HandshakeMessage;
       
    49 import sun.security.util.DerInputStream;
       
    50 import sun.security.util.DerValue;
       
    51 import sun.security.util.HexDumpEncoder;
       
    52 
       
    53 /**
       
    54  * Pack of "status_request" and "status_request_v2" extensions.
       
    55  */
       
    56 final class CertStatusExtension {
       
    57     static final HandshakeProducer chNetworkProducer =
       
    58             new CHCertStatusReqProducer();
       
    59     static final ExtensionConsumer chOnLoadConsumer =
       
    60             new CHCertStatusReqConsumer();
       
    61 
       
    62     static final HandshakeProducer shNetworkProducer =
       
    63             new SHCertStatusReqProducer();
       
    64     static final ExtensionConsumer shOnLoadConsumer =
       
    65             new SHCertStatusReqConsumer();
       
    66 
       
    67     static final HandshakeProducer ctNetworkProducer =
       
    68             new CTCertStatusResponseProducer();
       
    69     static final ExtensionConsumer ctOnLoadConsumer =
       
    70             new CTCertStatusResponseConsumer();
       
    71 
       
    72     static final SSLStringizer certStatusReqStringizer =
       
    73             new CertStatusRequestStringizer();
       
    74 
       
    75     static final HandshakeProducer chV2NetworkProducer =
       
    76             new CHCertStatusReqV2Producer();
       
    77     static final ExtensionConsumer chV2OnLoadConsumer =
       
    78             new CHCertStatusReqV2Consumer();
       
    79 
       
    80     static final HandshakeProducer shV2NetworkProducer =
       
    81             new SHCertStatusReqV2Producer();
       
    82     static final ExtensionConsumer shV2OnLoadConsumer =
       
    83             new SHCertStatusReqV2Consumer();
       
    84 
       
    85     static final SSLStringizer certStatusReqV2Stringizer =
       
    86             new CertStatusRequestsStringizer();
       
    87 
       
    88     static final SSLStringizer certStatusRespStringizer =
       
    89             new CertStatusRespStringizer();
       
    90 
       
    91     /**
       
    92      * The "status_request" extension.
       
    93      *
       
    94      * RFC6066 defines the TLS extension,"status_request" (type 0x5),
       
    95      * which allows the client to request that the server perform OCSP
       
    96      * on the client's behalf.
       
    97      *
       
    98      * The "extension data" field of this extension contains a
       
    99      * "CertificateStatusRequest" structure:
       
   100      *
       
   101      *      struct {
       
   102      *          CertificateStatusType status_type;
       
   103      *          select (status_type) {
       
   104      *              case ocsp: OCSPStatusRequest;
       
   105      *          } request;
       
   106      *      } CertificateStatusRequest;
       
   107      *
       
   108      *      enum { ocsp(1), (255) } CertificateStatusType;
       
   109      *
       
   110      *      struct {
       
   111      *          ResponderID responder_id_list<0..2^16-1>;
       
   112      *          Extensions  request_extensions;
       
   113      *      } OCSPStatusRequest;
       
   114      *
       
   115      *      opaque ResponderID<1..2^16-1>;
       
   116      *      opaque Extensions<0..2^16-1>;
       
   117      */
       
   118     static final class CertStatusRequestSpec implements SSLExtensionSpec {
       
   119         static final CertStatusRequestSpec DEFAULT =
       
   120                 new CertStatusRequestSpec(OCSPStatusRequest.EMPTY_OCSP);
       
   121 
       
   122         final CertStatusRequest statusRequest;
       
   123 
       
   124         private CertStatusRequestSpec(CertStatusRequest statusRequest) {
       
   125             this.statusRequest = statusRequest;
       
   126         }
       
   127 
       
   128         private CertStatusRequestSpec(ByteBuffer buffer) throws IOException {
       
   129             // Is it a empty extension_data?
       
   130             if (buffer.remaining() == 0) {
       
   131                 // server response
       
   132                 this.statusRequest = null;
       
   133                 return;
       
   134             }
       
   135 
       
   136             if (buffer.remaining() < 1) {
       
   137                 throw new SSLProtocolException(
       
   138                     "Invalid status_request extension: insufficient data");
       
   139             }
       
   140 
       
   141             byte statusType = (byte)Record.getInt8(buffer);
       
   142             byte[] encoded = new byte[buffer.remaining()];
       
   143             if (encoded.length != 0) {
       
   144                 buffer.get(encoded);
       
   145             }
       
   146             if (statusType == CertStatusRequestType.OCSP.id) {
       
   147                 this.statusRequest = new OCSPStatusRequest(statusType, encoded);
       
   148             } else {
       
   149                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   150                     SSLLogger.info(
       
   151                         "Unknown certificate status request " +
       
   152                         "(status type: " + statusType + ")");
       
   153                 }
       
   154 
       
   155                 this.statusRequest = new CertStatusRequest(statusType, encoded);
       
   156             }
       
   157         }
       
   158 
       
   159         @Override
       
   160         public String toString() {
       
   161             return statusRequest == null ?
       
   162                         "<empty>" : statusRequest.toString();
       
   163         }
       
   164     }
       
   165 
       
   166     /**
       
   167      * Defines the CertificateStatus response structure as outlined in
       
   168      * RFC 6066.  This will contain a status response type, plus a single,
       
   169      * non-empty OCSP response in DER-encoded form.
       
   170      *
       
   171      * struct {
       
   172      *     CertificateStatusType status_type;
       
   173      *     select (status_type) {
       
   174      *         case ocsp: OCSPResponse;
       
   175      *     } response;
       
   176      * } CertificateStatus;
       
   177      */
       
   178     static final class CertStatusResponseSpec implements SSLExtensionSpec {
       
   179         final CertStatusResponse statusResponse;
       
   180 
       
   181         private CertStatusResponseSpec(CertStatusResponse resp) {
       
   182             this.statusResponse = resp;
       
   183         }
       
   184 
       
   185         private CertStatusResponseSpec(ByteBuffer buffer) throws IOException {
       
   186             if (buffer.remaining() < 2) {
       
   187                 throw new SSLProtocolException(
       
   188                     "Invalid status_request extension: insufficient data");
       
   189             }
       
   190 
       
   191             // Get the status type (1 byte) and response data (vector)
       
   192             byte type = (byte)Record.getInt8(buffer);
       
   193             byte[] respData = Record.getBytes24(buffer);
       
   194 
       
   195             // Create the CertStatusResponse based on the type
       
   196             if (type == CertStatusRequestType.OCSP.id) {
       
   197                 this.statusResponse = new OCSPStatusResponse(type, respData);
       
   198             } else {
       
   199                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   200                     SSLLogger.info(
       
   201                         "Unknown certificate status response " +
       
   202                         "(status type: " + type + ")");
       
   203                 }
       
   204 
       
   205                 this.statusResponse = new CertStatusResponse(type, respData);
       
   206             }
       
   207         }
       
   208 
       
   209         @Override
       
   210         public String toString() {
       
   211             return statusResponse == null ?
       
   212                         "<empty>" : statusResponse.toString();
       
   213         }
       
   214     }
       
   215 
       
   216     private static final
       
   217             class CertStatusRequestStringizer implements SSLStringizer {
       
   218         @Override
       
   219         public String toString(ByteBuffer buffer) {
       
   220             try {
       
   221                 return (new CertStatusRequestSpec(buffer)).toString();
       
   222             } catch (IOException ioe) {
       
   223                 // For debug logging only, so please swallow exceptions.
       
   224                 return ioe.getMessage();
       
   225             }
       
   226         }
       
   227     }
       
   228 
       
   229     private static final
       
   230             class CertStatusRespStringizer implements SSLStringizer {
       
   231         @Override
       
   232         public String toString(ByteBuffer buffer) {
       
   233             try {
       
   234                 return (new CertStatusResponseSpec(buffer)).toString();
       
   235             } catch (IOException ioe) {
       
   236                  // For debug logging only, so please swallow exceptions.
       
   237                 return ioe.getMessage();
       
   238             }
       
   239         }
       
   240     }
       
   241 
       
   242     static enum CertStatusRequestType {
       
   243         OCSP        ((byte)0x01,    "ocsp"),        // RFC 6066/6961
       
   244         OCSP_MULTI  ((byte)0x02,    "ocsp_multi");  // RFC 6961
       
   245 
       
   246         final byte id;
       
   247         final String name;
       
   248 
       
   249         private CertStatusRequestType(byte id, String name) {
       
   250             this.id = id;
       
   251             this.name = name;
       
   252         }
       
   253 
       
   254         /**
       
   255          * Returns the enum constant of the specified id (see RFC 6066).
       
   256          */
       
   257         static CertStatusRequestType valueOf(byte id) {
       
   258             for (CertStatusRequestType srt : CertStatusRequestType.values()) {
       
   259                 if (srt.id == id) {
       
   260                     return srt;
       
   261                 }
       
   262             }
       
   263 
       
   264             return null;
       
   265         }
       
   266 
       
   267         static String nameOf(byte id) {
       
   268             for (CertStatusRequestType srt : CertStatusRequestType.values()) {
       
   269                 if (srt.id == id) {
       
   270                     return srt.name;
       
   271                 }
       
   272             }
       
   273 
       
   274             return "UNDEFINED-CERT-STATUS-TYPE(" + id + ")";
       
   275         }
       
   276     }
       
   277 
       
   278     static class CertStatusRequest {
       
   279         final byte statusType;
       
   280         final byte[] encodedRequest;
       
   281 
       
   282         protected CertStatusRequest(byte statusType, byte[] encodedRequest) {
       
   283             this.statusType = statusType;
       
   284             this.encodedRequest = encodedRequest;
       
   285         }
       
   286 
       
   287         @Override
       
   288         public String toString() {
       
   289             MessageFormat messageFormat = new MessageFormat(
       
   290                 "\"certificate status type\": {0}\n" +
       
   291                 "\"encoded certificate status\": '{'\n" +
       
   292                 "{1}\n" +
       
   293                 "'}'",
       
   294                 Locale.ENGLISH);
       
   295 
       
   296             HexDumpEncoder hexEncoder = new HexDumpEncoder();
       
   297             String encoded = hexEncoder.encodeBuffer(encodedRequest);
       
   298 
       
   299             Object[] messageFields = {
       
   300                 CertStatusRequestType.nameOf(statusType),
       
   301                 Utilities.indent(encoded)
       
   302             };
       
   303 
       
   304             return messageFormat.format(messageFields);
       
   305         }
       
   306     }
       
   307 
       
   308     /*
       
   309      * RFC6066 defines the TLS extension,"status_request" (type 0x5),
       
   310      * which allows the client to request that the server perform OCSP
       
   311      * on the client's behalf.
       
   312      *
       
   313      * The RFC defines an OCSPStatusRequest structure:
       
   314      *
       
   315      *      struct {
       
   316      *          ResponderID responder_id_list<0..2^16-1>;
       
   317      *          Extensions  request_extensions;
       
   318      *      } OCSPStatusRequest;
       
   319      */
       
   320     static final class OCSPStatusRequest extends CertStatusRequest {
       
   321         static final OCSPStatusRequest EMPTY_OCSP;
       
   322         static final OCSPStatusRequest EMPTY_OCSP_MULTI;
       
   323 
       
   324         final List<ResponderId> responderIds;
       
   325         final List<Extension> extensions;
       
   326         private final int ridListLen;
       
   327         private final int extListLen;
       
   328 
       
   329         static {
       
   330             OCSPStatusRequest ocspReq = null;
       
   331             OCSPStatusRequest multiReq = null;
       
   332 
       
   333             try {
       
   334                 ocspReq = new OCSPStatusRequest(
       
   335                         CertStatusRequestType.OCSP.id,
       
   336                         new byte[] {0x00, 0x00, 0x00, 0x00});
       
   337                 multiReq = new OCSPStatusRequest(
       
   338                     CertStatusRequestType.OCSP_MULTI.id,
       
   339                     new byte[] {0x00, 0x00, 0x00, 0x00});
       
   340             } catch (IOException ioe) {
       
   341                 // unlikely
       
   342             }
       
   343 
       
   344             EMPTY_OCSP = ocspReq;
       
   345             EMPTY_OCSP_MULTI = multiReq;
       
   346         }
       
   347 
       
   348         private OCSPStatusRequest(byte statusType,
       
   349                 byte[] encoded) throws IOException {
       
   350             super(statusType, encoded);
       
   351 
       
   352             if (encoded == null || encoded.length < 4) {
       
   353                                         //  2: length of responder_id_list
       
   354                                         // +2: length of request_extensions
       
   355                 throw new SSLProtocolException(
       
   356                         "Invalid OCSP status request: insufficient data");
       
   357             }
       
   358 
       
   359             List<ResponderId> rids = new ArrayList<>();
       
   360             List<Extension> exts = new ArrayList<>();
       
   361             ByteBuffer m = ByteBuffer.wrap(encoded);
       
   362 
       
   363             this.ridListLen = Record.getInt16(m);
       
   364             if (m.remaining() < (ridListLen + 2)) {
       
   365                 throw new SSLProtocolException(
       
   366                         "Invalid OCSP status request: insufficient data");
       
   367             }
       
   368 
       
   369             int ridListBytesRemaining = ridListLen;
       
   370             while (ridListBytesRemaining >= 2) {    // 2: length of responder_id
       
   371                 byte[] ridBytes = Record.getBytes16(m);
       
   372                 try {
       
   373                     rids.add(new ResponderId(ridBytes));
       
   374                 } catch (IOException ioe) {
       
   375                     throw new SSLProtocolException(
       
   376                         "Invalid OCSP status request: invalid responder ID");
       
   377                 }
       
   378                 ridListBytesRemaining -= ridBytes.length + 2;
       
   379             }
       
   380 
       
   381             if (ridListBytesRemaining != 0) {
       
   382                     throw new SSLProtocolException(
       
   383                         "Invalid OCSP status request: incomplete data");
       
   384             }
       
   385 
       
   386             byte[] extListBytes = Record.getBytes16(m);
       
   387             this.extListLen = extListBytes.length;
       
   388             if (extListLen > 0) {
       
   389                 try {
       
   390                     DerInputStream dis = new DerInputStream(extListBytes);
       
   391                     DerValue[] extSeqContents =
       
   392                             dis.getSequence(extListBytes.length);
       
   393                     for (DerValue extDerVal : extSeqContents) {
       
   394                         exts.add(new sun.security.x509.Extension(extDerVal));
       
   395                     }
       
   396                 } catch (IOException ioe) {
       
   397                     throw new SSLProtocolException(
       
   398                         "Invalid OCSP status request: invalid extension");
       
   399                 }
       
   400             }
       
   401 
       
   402             this.responderIds = rids;
       
   403             this.extensions = exts;
       
   404         }
       
   405 
       
   406         @Override
       
   407         public String toString() {
       
   408             MessageFormat messageFormat = new MessageFormat(
       
   409                 "\"certificate status type\": {0}\n" +
       
   410                 "\"OCSP status request\": '{'\n" +
       
   411                 "{1}\n" +
       
   412                 "'}'",
       
   413                 Locale.ENGLISH);
       
   414 
       
   415             MessageFormat requestFormat = new MessageFormat(
       
   416                 "\"responder_id\": {0}\n" +
       
   417                 "\"request extensions\": '{'\n" +
       
   418                 "{1}\n" +
       
   419                 "'}'",
       
   420                 Locale.ENGLISH);
       
   421 
       
   422             String ridStr = "<empty>";
       
   423             if (!responderIds.isEmpty()) {
       
   424                 ridStr = responderIds.toString();
       
   425             }
       
   426 
       
   427             String extsStr = "<empty>";
       
   428             if (!extensions.isEmpty()) {
       
   429                 StringBuilder extBuilder = new StringBuilder(512);
       
   430                 boolean isFirst = true;
       
   431                 for (Extension ext : this.extensions) {
       
   432                     if (isFirst) {
       
   433                         isFirst = false;
       
   434                     } else {
       
   435                         extBuilder.append(",\n");
       
   436                     }
       
   437                     extBuilder.append(
       
   438                             "{\n" + Utilities.indent(ext.toString()) + "}");
       
   439                 }
       
   440 
       
   441                 extsStr = extBuilder.toString();
       
   442             }
       
   443 
       
   444             Object[] requestFields = {
       
   445                     ridStr,
       
   446                     Utilities.indent(extsStr)
       
   447                 };
       
   448             String ocspStatusRequest = requestFormat.format(requestFields);
       
   449 
       
   450             Object[] messageFields = {
       
   451                     CertStatusRequestType.nameOf(statusType),
       
   452                     Utilities.indent(ocspStatusRequest)
       
   453                 };
       
   454 
       
   455             return messageFormat.format(messageFields);
       
   456         }
       
   457     }
       
   458 
       
   459     static class CertStatusResponse {
       
   460         final byte statusType;
       
   461         final byte[] encodedResponse;
       
   462 
       
   463         protected CertStatusResponse(byte statusType, byte[] respDer) {
       
   464             this.statusType = statusType;
       
   465             this.encodedResponse = respDer;
       
   466         }
       
   467 
       
   468         byte[] toByteArray() throws IOException {
       
   469             // Create a byte array large enough to handle the status_type
       
   470             // field (1) + OCSP length (3) + OCSP data (variable)
       
   471             byte[] outData = new byte[encodedResponse.length + 4];
       
   472             ByteBuffer buf = ByteBuffer.wrap(outData);
       
   473             Record.putInt8(buf, statusType);
       
   474             Record.putBytes24(buf, encodedResponse);
       
   475             return buf.array();
       
   476         }
       
   477 
       
   478         @Override
       
   479         public String toString() {
       
   480             MessageFormat messageFormat = new MessageFormat(
       
   481                 "\"certificate status response type\": {0}\n" +
       
   482                 "\"encoded certificate status\": '{'\n" +
       
   483                 "{1}\n" +
       
   484                 "'}'",
       
   485                 Locale.ENGLISH);
       
   486 
       
   487             HexDumpEncoder hexEncoder = new HexDumpEncoder();
       
   488             String encoded = hexEncoder.encodeBuffer(encodedResponse);
       
   489 
       
   490             Object[] messageFields = {
       
   491                 CertStatusRequestType.nameOf(statusType),
       
   492                 Utilities.indent(encoded)
       
   493             };
       
   494 
       
   495             return messageFormat.format(messageFields);
       
   496         }
       
   497     }
       
   498 
       
   499     static final class OCSPStatusResponse extends CertStatusResponse {
       
   500         final OCSPResponse ocspResponse;
       
   501 
       
   502         private OCSPStatusResponse(byte statusType,
       
   503                 byte[] encoded) throws IOException {
       
   504             super(statusType, encoded);
       
   505 
       
   506             // The DER-encoded OCSP response must not be zero length
       
   507             if (encoded == null || encoded.length < 1) {
       
   508                 throw new SSLProtocolException(
       
   509                         "Invalid OCSP status response: insufficient data");
       
   510             }
       
   511 
       
   512             // Otherwise, make an OCSPResponse object from the data
       
   513             ocspResponse = new OCSPResponse(encoded);
       
   514         }
       
   515 
       
   516         @Override
       
   517         public String toString() {
       
   518             MessageFormat messageFormat = new MessageFormat(
       
   519                 "\"certificate status response type\": {0}\n" +
       
   520                 "\"OCSP status response\": '{'\n" +
       
   521                 "{1}\n" +
       
   522                 "'}'",
       
   523                 Locale.ENGLISH);
       
   524 
       
   525             Object[] messageFields = {
       
   526                 CertStatusRequestType.nameOf(statusType),
       
   527                 Utilities.indent(ocspResponse.toString())
       
   528             };
       
   529 
       
   530             return messageFormat.format(messageFields);
       
   531         }
       
   532     }
       
   533 
       
   534     /**
       
   535      * Network data producer of a "status_request" extension in the
       
   536      * ClientHello handshake message.
       
   537      */
       
   538     private static final
       
   539             class CHCertStatusReqProducer implements HandshakeProducer {
       
   540         // Prevent instantiation of this class.
       
   541         private CHCertStatusReqProducer() {
       
   542             // blank
       
   543         }
       
   544 
       
   545         @Override
       
   546         public byte[] produce(ConnectionContext context,
       
   547                 HandshakeMessage message) throws IOException {
       
   548             // The producing happens in client side only.
       
   549             ClientHandshakeContext chc = (ClientHandshakeContext)context;
       
   550 
       
   551             if (!chc.sslContext.isStaplingEnabled(true)) {
       
   552                 return null;
       
   553             }
       
   554 
       
   555             if (!chc.sslConfig.isAvailable(CH_STATUS_REQUEST)) {
       
   556                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   557                     SSLLogger.fine(
       
   558                         "Ignore unavailable extension: " +
       
   559                         CH_STATUS_REQUEST.name);
       
   560                 }
       
   561                 return null;
       
   562             }
       
   563 
       
   564             // Produce the extension.
       
   565             //
       
   566             // We are using empty OCSPStatusRequest at present. May extend to
       
   567             // support specific responder or extensions later.
       
   568             byte[] extData = new byte[] {0x01, 0x00, 0x00, 0x00, 0x00};
       
   569 
       
   570             // Update the context.
       
   571             chc.handshakeExtensions.put(
       
   572                     CH_STATUS_REQUEST, CertStatusRequestSpec.DEFAULT);
       
   573 
       
   574             return extData;
       
   575         }
       
   576     }
       
   577 
       
   578     /**
       
   579      * Network data consumer of a "status_request" extension in the
       
   580      * ClientHello handshake message.
       
   581      */
       
   582     private static final
       
   583             class CHCertStatusReqConsumer implements ExtensionConsumer {
       
   584         // Prevent instantiation of this class.
       
   585         private CHCertStatusReqConsumer() {
       
   586             // blank
       
   587         }
       
   588 
       
   589         @Override
       
   590         public void consume(ConnectionContext context,
       
   591             HandshakeMessage message, ByteBuffer buffer) throws IOException {
       
   592 
       
   593             // The consuming happens in server side only.
       
   594             ServerHandshakeContext shc = (ServerHandshakeContext)context;
       
   595 
       
   596             if (!shc.sslConfig.isAvailable(CH_STATUS_REQUEST)) {
       
   597                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   598                     SSLLogger.fine("Ignore unavailable extension: " +
       
   599                         CH_STATUS_REQUEST.name);
       
   600                 }
       
   601                 return;     // ignore the extension
       
   602             }
       
   603 
       
   604             // Parse the extension.
       
   605             CertStatusRequestSpec spec;
       
   606             try {
       
   607                 spec = new CertStatusRequestSpec(buffer);
       
   608             } catch (IOException ioe) {
       
   609                 shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe);
       
   610                 return;     // fatal() always throws, make the compiler happy.
       
   611             }
       
   612 
       
   613             // Update the context.
       
   614             shc.handshakeExtensions.put(CH_STATUS_REQUEST, spec);
       
   615             if (!shc.isResumption &&
       
   616                     !shc.negotiatedProtocol.useTLS13PlusSpec()) {
       
   617                 shc.handshakeProducers.put(SSLHandshake.CERTIFICATE_STATUS.id,
       
   618                     SSLHandshake.CERTIFICATE_STATUS);
       
   619             }   // Otherwise, the certificate status presents in server cert.
       
   620 
       
   621             // No impact on session resumption.
       
   622         }
       
   623     }
       
   624 
       
   625     /**
       
   626      * Network data producer of a "status_request" extension in the
       
   627      * ServerHello handshake message.
       
   628      */
       
   629     private static final
       
   630             class SHCertStatusReqProducer implements HandshakeProducer {
       
   631         // Prevent instantiation of this class.
       
   632         private SHCertStatusReqProducer() {
       
   633             // blank
       
   634         }
       
   635 
       
   636         @Override
       
   637         public byte[] produce(ConnectionContext context,
       
   638                 HandshakeMessage message) throws IOException {
       
   639             // The producing happens in client side only.
       
   640             ServerHandshakeContext shc = (ServerHandshakeContext)context;
       
   641 
       
   642             // The StaplingParameters in the ServerHandshakeContext will
       
   643             // contain the info about what kind of stapling (if any) to
       
   644             // perform and whether this status_request extension should be
       
   645             // produced or the status_request_v2 (found in a different producer)
       
   646             // No explicit check is required for isStaplingEnabled here.  If
       
   647             // it is false then stapleParams will be null.  If it is true
       
   648             // then stapleParams may or may not be false and the check below
       
   649             // is sufficient.
       
   650             if ((shc.stapleParams == null) ||
       
   651                     (shc.stapleParams.statusRespExt !=
       
   652                     SSLExtension.CH_STATUS_REQUEST)) {
       
   653                 return null;    // Do not produce status_request in ServerHello
       
   654             }
       
   655 
       
   656             // In response to "status_request" extension request only.
       
   657             CertStatusRequestSpec spec = (CertStatusRequestSpec)
       
   658                     shc.handshakeExtensions.get(CH_STATUS_REQUEST);
       
   659             if (spec == null) {
       
   660                 // Ignore, no status_request extension requested.
       
   661                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   662                     SSLLogger.finest(
       
   663                         "Ignore unavailable extension: " +
       
   664                         CH_STATUS_REQUEST.name);
       
   665                 }
       
   666 
       
   667                 return null;        // ignore the extension
       
   668             }
       
   669 
       
   670             // Is it a session resuming?
       
   671             if (shc.isResumption) {
       
   672                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   673                     SSLLogger.finest(
       
   674                         "No status_request response for session resuming");
       
   675                 }
       
   676 
       
   677                 return null;        // ignore the extension
       
   678             }
       
   679 
       
   680             // The "extension_data" in the extended ServerHello handshake
       
   681             // message MUST be empty.
       
   682             byte[] extData = new byte[0];
       
   683 
       
   684             // Update the context.
       
   685             shc.handshakeExtensions.put(
       
   686                     SH_STATUS_REQUEST, CertStatusRequestSpec.DEFAULT);
       
   687 
       
   688             return extData;
       
   689         }
       
   690     }
       
   691 
       
   692     /**
       
   693      * Network data consumer of a "status_request" extension in the
       
   694      * ServerHello handshake message.
       
   695      */
       
   696     private static final
       
   697             class SHCertStatusReqConsumer implements ExtensionConsumer {
       
   698         // Prevent instantiation of this class.
       
   699         private SHCertStatusReqConsumer() {
       
   700             // blank
       
   701         }
       
   702 
       
   703         @Override
       
   704         public void consume(ConnectionContext context,
       
   705             HandshakeMessage message, ByteBuffer buffer) throws IOException {
       
   706 
       
   707             // The producing happens in client side only.
       
   708             ClientHandshakeContext chc = (ClientHandshakeContext)context;
       
   709 
       
   710             // In response to "status_request" extension request only.
       
   711             CertStatusRequestSpec requestedCsr = (CertStatusRequestSpec)
       
   712                     chc.handshakeExtensions.get(CH_STATUS_REQUEST);
       
   713             if (requestedCsr == null) {
       
   714                 chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
       
   715                     "Unexpected status_request extension in ServerHello");
       
   716             }
       
   717 
       
   718             // Parse the extension.
       
   719             if (buffer.hasRemaining()) {
       
   720                 chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
       
   721                   "Invalid status_request extension in ServerHello message: " +
       
   722                   "the extension data must be empty");
       
   723             }
       
   724 
       
   725             // Update the context.
       
   726             chc.handshakeExtensions.put(
       
   727                     SH_STATUS_REQUEST, CertStatusRequestSpec.DEFAULT);
       
   728             chc.handshakeConsumers.put(SSLHandshake.CERTIFICATE_STATUS.id,
       
   729                     SSLHandshake.CERTIFICATE_STATUS);
       
   730 
       
   731             // Since we've received a legitimate status_request in the
       
   732             // ServerHello, stapling is active if it's been enabled.
       
   733             chc.staplingActive = chc.sslContext.isStaplingEnabled(true);
       
   734 
       
   735             // No impact on session resumption.
       
   736         }
       
   737     }
       
   738 
       
   739     /**
       
   740      * The "status_request_v2" extension.
       
   741      *
       
   742      * RFC6961 defines the TLS extension,"status_request_v2" (type 0x5),
       
   743      * which allows the client to request that the server perform OCSP
       
   744      * on the client's behalf.
       
   745      *
       
   746      * The RFC defines an CertStatusReqItemV2 structure:
       
   747      *
       
   748      *      struct {
       
   749      *          CertificateStatusType status_type;
       
   750      *          uint16 request_length;
       
   751      *          select (status_type) {
       
   752      *              case ocsp: OCSPStatusRequest;
       
   753      *              case ocsp_multi: OCSPStatusRequest;
       
   754      *          } request;
       
   755      *      } CertificateStatusRequestItemV2;
       
   756      *
       
   757      *      enum { ocsp(1), ocsp_multi(2), (255) } CertificateStatusType;
       
   758      *      struct {
       
   759      *        ResponderID responder_id_list<0..2^16-1>;
       
   760      *        Extensions request_extensions;
       
   761      *      } OCSPStatusRequest;
       
   762      *
       
   763      *      opaque ResponderID<1..2^16-1>;
       
   764      *      opaque Extensions<0..2^16-1>;
       
   765      *
       
   766      *      struct {
       
   767      *        CertificateStatusRequestItemV2
       
   768      *                         certificate_status_req_list<1..2^16-1>;
       
   769      *      } CertificateStatusRequestListV2;
       
   770      */
       
   771     static final class CertStatusRequestV2Spec implements SSLExtensionSpec {
       
   772         static final CertStatusRequestV2Spec DEFAULT =
       
   773                 new CertStatusRequestV2Spec(new CertStatusRequest[] {
       
   774                         OCSPStatusRequest.EMPTY_OCSP_MULTI});
       
   775 
       
   776         final CertStatusRequest[] certStatusRequests;
       
   777 
       
   778         private CertStatusRequestV2Spec(CertStatusRequest[] certStatusRequests) {
       
   779             this.certStatusRequests = certStatusRequests;
       
   780         }
       
   781 
       
   782         private CertStatusRequestV2Spec(ByteBuffer message) throws IOException {
       
   783             // Is it a empty extension_data?
       
   784             if (message.remaining() == 0) {
       
   785                 // server response
       
   786                 this.certStatusRequests = new CertStatusRequest[0];
       
   787                 return;
       
   788             }
       
   789 
       
   790             if (message.remaining() < 5) {  //  2: certificate_status_req_list
       
   791                                             // +1: status_type
       
   792                                             // +2: request_length
       
   793                 throw new SSLProtocolException(
       
   794                     "Invalid status_request_v2 extension: insufficient data");
       
   795             }
       
   796 
       
   797             int listLen = Record.getInt16(message);
       
   798             if (listLen <= 0) {
       
   799                 throw new SSLProtocolException(
       
   800                     "certificate_status_req_list length must be positive " +
       
   801                     "(received length: " + listLen + ")");
       
   802             }
       
   803 
       
   804             int remaining = listLen;
       
   805             List<CertStatusRequest> statusRequests = new ArrayList<>();
       
   806             while (remaining > 0) {
       
   807                 byte statusType = (byte)Record.getInt8(message);
       
   808                 int requestLen = Record.getInt16(message);
       
   809 
       
   810                 if (message.remaining() < requestLen) {
       
   811                     throw new SSLProtocolException(
       
   812                             "Invalid status_request_v2 extension: " +
       
   813                             "insufficient data (request_length=" + requestLen +
       
   814                             ", remining=" + message.remaining() + ")");
       
   815                 }
       
   816 
       
   817                 byte[] encoded = new byte[requestLen];
       
   818                 if (encoded.length != 0) {
       
   819                     message.get(encoded);
       
   820                 }
       
   821                 remaining -= 3;     // 1(status type) + 2(request_length) bytes
       
   822                 remaining -= requestLen;
       
   823 
       
   824                 if (statusType == CertStatusRequestType.OCSP.id ||
       
   825                         statusType == CertStatusRequestType.OCSP_MULTI.id) {
       
   826                     if (encoded.length < 4) {
       
   827                                         //  2: length of responder_id_list
       
   828                                         // +2: length of request_extensions
       
   829                         throw new SSLProtocolException(
       
   830                             "Invalid status_request_v2 extension: " +
       
   831                             "insufficient data");
       
   832                     }
       
   833                     statusRequests.add(
       
   834                             new OCSPStatusRequest(statusType, encoded));
       
   835                 } else {
       
   836                     if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   837                         SSLLogger.info(
       
   838                                 "Unknown certificate status request " +
       
   839                                 "(status type: " + statusType + ")");
       
   840                     }
       
   841                     statusRequests.add(
       
   842                             new CertStatusRequest(statusType, encoded));
       
   843                 }
       
   844             }
       
   845 
       
   846             certStatusRequests =
       
   847                     statusRequests.toArray(new CertStatusRequest[0]);
       
   848         }
       
   849 
       
   850         @Override
       
   851         public String toString() {
       
   852             if (certStatusRequests == null || certStatusRequests.length == 0) {
       
   853                 return "<empty>";
       
   854             } else {
       
   855                 MessageFormat messageFormat = new MessageFormat(
       
   856                     "\"cert status request\": '{'\n{0}\n'}'", Locale.ENGLISH);
       
   857 
       
   858                 StringBuilder builder = new StringBuilder(512);
       
   859                 boolean isFirst = true;
       
   860                 for (CertStatusRequest csr : certStatusRequests) {
       
   861                     if (isFirst) {
       
   862                         isFirst = false;
       
   863                     } else {
       
   864                         builder.append(", ");
       
   865                     }
       
   866                     Object[] messageFields = {
       
   867                             Utilities.indent(csr.toString())
       
   868                         };
       
   869                     builder.append(messageFormat.format(messageFields));
       
   870                 }
       
   871 
       
   872                 return builder.toString();
       
   873             }
       
   874         }
       
   875     }
       
   876 
       
   877     private static final
       
   878             class CertStatusRequestsStringizer implements SSLStringizer {
       
   879         @Override
       
   880         public String toString(ByteBuffer buffer) {
       
   881             try {
       
   882                 return (new CertStatusRequestV2Spec(buffer)).toString();
       
   883             } catch (IOException ioe) {
       
   884                 // For debug logging only, so please swallow exceptions.
       
   885                 return ioe.getMessage();
       
   886             }
       
   887         }
       
   888     }
       
   889 
       
   890     /**
       
   891      * Network data producer of a "status_request_v2" extension in the
       
   892      * ClientHello handshake message.
       
   893      */
       
   894     private static final
       
   895             class CHCertStatusReqV2Producer implements HandshakeProducer {
       
   896         // Prevent instantiation of this class.
       
   897         private CHCertStatusReqV2Producer() {
       
   898             // blank
       
   899         }
       
   900 
       
   901         @Override
       
   902         public byte[] produce(ConnectionContext context,
       
   903                 HandshakeMessage message) throws IOException {
       
   904             // The producing happens in client side only.
       
   905             ClientHandshakeContext chc = (ClientHandshakeContext)context;
       
   906 
       
   907             if (!chc.sslContext.isStaplingEnabled(true)) {
       
   908                 return null;
       
   909             }
       
   910 
       
   911             if (!chc.sslConfig.isAvailable(CH_STATUS_REQUEST_V2)) {
       
   912                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   913                     SSLLogger.finest(
       
   914                         "Ignore unavailable status_request_v2 extension");
       
   915                 }
       
   916 
       
   917                 return null;
       
   918             }
       
   919 
       
   920             // Produce the extension.
       
   921             //
       
   922             // We are using empty OCSPStatusRequest at present. May extend to
       
   923             // support specific responder or extensions later.
       
   924             byte[] extData = new byte[] {
       
   925                 0x00, 0x07, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00};
       
   926 
       
   927             // Update the context.
       
   928             chc.handshakeExtensions.put(
       
   929                     CH_STATUS_REQUEST_V2, CertStatusRequestV2Spec.DEFAULT);
       
   930 
       
   931             return extData;
       
   932         }
       
   933     }
       
   934 
       
   935     /**
       
   936      * Network data consumer of a "status_request_v2" extension in the
       
   937      * ClientHello handshake message.
       
   938      */
       
   939     private static final
       
   940             class CHCertStatusReqV2Consumer implements ExtensionConsumer {
       
   941         // Prevent instantiation of this class.
       
   942         private CHCertStatusReqV2Consumer() {
       
   943             // blank
       
   944         }
       
   945 
       
   946         @Override
       
   947         public void consume(ConnectionContext context,
       
   948             HandshakeMessage message, ByteBuffer buffer) throws IOException {
       
   949 
       
   950             // The consuming happens in server side only.
       
   951             ServerHandshakeContext shc = (ServerHandshakeContext)context;
       
   952 
       
   953             if (!shc.sslConfig.isAvailable(CH_STATUS_REQUEST_V2)) {
       
   954                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   955                     SSLLogger.finest(
       
   956                         "Ignore unavailable status_request_v2 extension");
       
   957                 }
       
   958 
       
   959                 return;     // ignore the extension
       
   960             }
       
   961 
       
   962             // Parse the extension.
       
   963             CertStatusRequestV2Spec spec;
       
   964             try {
       
   965                 spec = new CertStatusRequestV2Spec(buffer);
       
   966             } catch (IOException ioe) {
       
   967                 shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe);
       
   968                 return;     // fatal() always throws, make the compiler happy.
       
   969             }
       
   970 
       
   971             // Update the context.
       
   972             shc.handshakeExtensions.put(CH_STATUS_REQUEST_V2, spec);
       
   973             if (!shc.isResumption) {
       
   974                 shc.handshakeProducers.putIfAbsent(
       
   975                         SSLHandshake.CERTIFICATE_STATUS.id,
       
   976                         SSLHandshake.CERTIFICATE_STATUS);
       
   977             }
       
   978 
       
   979             // No impact on session resumption.
       
   980         }
       
   981     }
       
   982 
       
   983     /**
       
   984      * Network data producer of a "status_request_v2" extension in the
       
   985      * ServerHello handshake message.
       
   986      */
       
   987     private static final
       
   988             class SHCertStatusReqV2Producer implements HandshakeProducer {
       
   989         // Prevent instantiation of this class.
       
   990         private SHCertStatusReqV2Producer() {
       
   991             // blank
       
   992         }
       
   993 
       
   994         @Override
       
   995         public byte[] produce(ConnectionContext context,
       
   996                 HandshakeMessage message) throws IOException {
       
   997             // The producing happens in client side only.
       
   998 
       
   999             ServerHandshakeContext shc = (ServerHandshakeContext)context;
       
  1000             // The StaplingParameters in the ServerHandshakeContext will
       
  1001             // contain the info about what kind of stapling (if any) to
       
  1002             // perform and whether this status_request extension should be
       
  1003             // produced or the status_request_v2 (found in a different producer)
       
  1004             // No explicit check is required for isStaplingEnabled here.  If
       
  1005             // it is false then stapleParams will be null.  If it is true
       
  1006             // then stapleParams may or may not be false and the check below
       
  1007             // is sufficient.
       
  1008             if ((shc.stapleParams == null) ||
       
  1009                     (shc.stapleParams.statusRespExt !=
       
  1010                     SSLExtension.CH_STATUS_REQUEST_V2)) {
       
  1011                 return null;    // Do not produce status_request_v2 in SH
       
  1012             }
       
  1013 
       
  1014             // In response to "status_request_v2" extension request only
       
  1015             CertStatusRequestV2Spec spec = (CertStatusRequestV2Spec)
       
  1016                     shc.handshakeExtensions.get(CH_STATUS_REQUEST_V2);
       
  1017             if (spec == null) {
       
  1018                 // Ignore, no status_request_v2 extension requested.
       
  1019                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
  1020                     SSLLogger.finest(
       
  1021                         "Ignore unavailable status_request_v2 extension");
       
  1022                 }
       
  1023 
       
  1024                 return null;        // ignore the extension
       
  1025             }
       
  1026 
       
  1027             // Is it a session resuming?
       
  1028             if (shc.isResumption) {
       
  1029                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
  1030                     SSLLogger.finest(
       
  1031                         "No status_request_v2 response for session resumption");
       
  1032                 }
       
  1033                 return null;        // ignore the extension
       
  1034             }
       
  1035 
       
  1036             // The "extension_data" in the extended ServerHello handshake
       
  1037             // message MUST be empty.
       
  1038             byte[] extData = new byte[0];
       
  1039 
       
  1040             // Update the context.
       
  1041             shc.handshakeExtensions.put(
       
  1042                     SH_STATUS_REQUEST_V2, CertStatusRequestV2Spec.DEFAULT);
       
  1043 
       
  1044             return extData;
       
  1045         }
       
  1046     }
       
  1047 
       
  1048     /**
       
  1049      * Network data consumer of a "status_request_v2" extension in the
       
  1050      * ServerHello handshake message.
       
  1051      */
       
  1052     private static final
       
  1053             class SHCertStatusReqV2Consumer implements ExtensionConsumer {
       
  1054         // Prevent instantiation of this class.
       
  1055         private SHCertStatusReqV2Consumer() {
       
  1056             // blank
       
  1057         }
       
  1058 
       
  1059         @Override
       
  1060         public void consume(ConnectionContext context,
       
  1061             HandshakeMessage message, ByteBuffer buffer) throws IOException {
       
  1062 
       
  1063             // The consumption happens in client side only.
       
  1064             ClientHandshakeContext chc = (ClientHandshakeContext)context;
       
  1065 
       
  1066             // In response to "status_request" extension request only
       
  1067             CertStatusRequestV2Spec requestedCsr = (CertStatusRequestV2Spec)
       
  1068                     chc.handshakeExtensions.get(CH_STATUS_REQUEST_V2);
       
  1069             if (requestedCsr == null) {
       
  1070                 chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
       
  1071                     "Unexpected status_request_v2 extension in ServerHello");
       
  1072             }
       
  1073 
       
  1074             // Parse the extension.
       
  1075             if (buffer.hasRemaining()) {
       
  1076                 chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
       
  1077                   "Invalid status_request_v2 extension in ServerHello: " +
       
  1078                   "the extension data must be empty");
       
  1079             }
       
  1080 
       
  1081             // Update the context.
       
  1082             chc.handshakeExtensions.put(
       
  1083                     SH_STATUS_REQUEST_V2, CertStatusRequestV2Spec.DEFAULT);
       
  1084             chc.handshakeConsumers.put(SSLHandshake.CERTIFICATE_STATUS.id,
       
  1085                     SSLHandshake.CERTIFICATE_STATUS);
       
  1086 
       
  1087             // Since we've received a legitimate status_request in the
       
  1088             // ServerHello, stapling is active if it's been enabled.
       
  1089             chc.staplingActive = chc.sslContext.isStaplingEnabled(true);
       
  1090 
       
  1091             // No impact on session resumption.
       
  1092         }
       
  1093     }
       
  1094 
       
  1095     private static final
       
  1096             class CTCertStatusResponseProducer implements HandshakeProducer {
       
  1097         // Prevent instantiation of this class.
       
  1098         private CTCertStatusResponseProducer() {
       
  1099             // blank
       
  1100         }
       
  1101 
       
  1102         @Override
       
  1103         public byte[] produce(ConnectionContext context,
       
  1104                 HandshakeMessage message) throws IOException {
       
  1105             ServerHandshakeContext shc = (ServerHandshakeContext)context;
       
  1106             byte[] producedData = null;
       
  1107 
       
  1108             // Stapling needs to be active and have valid data to proceed
       
  1109             if (shc.stapleParams == null) {
       
  1110                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
  1111                     SSLLogger.finest(
       
  1112                         "Stapling is disabled for this connection");
       
  1113                 }
       
  1114                 return null;
       
  1115             }
       
  1116 
       
  1117             // There needs to be a non-null CertificateEntry to proceed
       
  1118             if (shc.currentCertEntry == null) {
       
  1119                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
  1120                     SSLLogger.finest("Found null CertificateEntry in context");
       
  1121                 }
       
  1122                 return null;
       
  1123             }
       
  1124 
       
  1125             // Pull the certificate from the CertificateEntry and find
       
  1126             // a response from the response map.  If one exists we will
       
  1127             // staple it.
       
  1128             try {
       
  1129                 CertificateFactory cf = CertificateFactory.getInstance("X.509");
       
  1130                 X509Certificate x509Cert =
       
  1131                         (X509Certificate)cf.generateCertificate(
       
  1132                                 new ByteArrayInputStream(
       
  1133                                         shc.currentCertEntry.encoded));
       
  1134                 byte[] respBytes = shc.stapleParams.responseMap.get(x509Cert);
       
  1135                 if (respBytes == null) {
       
  1136                     // We're done with this entry.  Clear it from the context
       
  1137                     if (SSLLogger.isOn &&
       
  1138                             SSLLogger.isOn("ssl,handshake,verbose")) {
       
  1139                         SSLLogger.finest("No status response found for " +
       
  1140                                 x509Cert.getSubjectX500Principal());
       
  1141                     }
       
  1142                     shc.currentCertEntry = null;
       
  1143                     return null;
       
  1144                 }
       
  1145 
       
  1146                 // Build a proper response buffer from the stapling information
       
  1147                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake,verbose")) {
       
  1148                     SSLLogger.finest("Found status response for " +
       
  1149                             x509Cert.getSubjectX500Principal() +
       
  1150                             ", response length: " + respBytes.length);
       
  1151                 }
       
  1152                 CertStatusResponse certResp = (shc.stapleParams.statReqType ==
       
  1153                         CertStatusRequestType.OCSP) ?
       
  1154                         new OCSPStatusResponse(shc.stapleParams.statReqType.id,
       
  1155                                 respBytes) :
       
  1156                         new CertStatusResponse(shc.stapleParams.statReqType.id,
       
  1157                                 respBytes);
       
  1158                 producedData = certResp.toByteArray();
       
  1159             } catch (CertificateException ce) {
       
  1160                 shc.conContext.fatal(Alert.BAD_CERTIFICATE,
       
  1161                         "Failed to parse server certificates", ce);
       
  1162             } catch (IOException ioe) {
       
  1163                 shc.conContext.fatal(Alert.BAD_CERT_STATUS_RESPONSE,
       
  1164                         "Failed to parse certificate status response", ioe);
       
  1165             }
       
  1166 
       
  1167             // Clear the pinned CertificateEntry from the context
       
  1168             shc.currentCertEntry = null;
       
  1169             return producedData;
       
  1170         }
       
  1171     }
       
  1172 
       
  1173     private static final
       
  1174         class CTCertStatusResponseConsumer implements ExtensionConsumer {
       
  1175         // Prevent instantiation of this class.
       
  1176         private CTCertStatusResponseConsumer() {
       
  1177             // blank
       
  1178         }
       
  1179 
       
  1180         @Override
       
  1181         public void consume(ConnectionContext context,
       
  1182                 HandshakeMessage message, ByteBuffer buffer) throws IOException {
       
  1183             // The consumption happens in client side only.
       
  1184             ClientHandshakeContext chc = (ClientHandshakeContext)context;
       
  1185 
       
  1186             // Parse the extension.
       
  1187             CertStatusResponseSpec spec;
       
  1188             try {
       
  1189                 spec = new CertStatusResponseSpec(buffer);
       
  1190             } catch (IOException ioe) {
       
  1191                 chc.conContext.fatal(Alert.DECODE_ERROR, ioe);
       
  1192                 return;     // fatal() always throws, make the compiler happy.
       
  1193             }
       
  1194 
       
  1195             if (chc.sslContext.isStaplingEnabled(true)) {
       
  1196                 // Activate stapling
       
  1197                 chc.staplingActive = true;
       
  1198             } else {
       
  1199                 // Do no further processing of stapled responses
       
  1200                 return;
       
  1201             }
       
  1202 
       
  1203             // Get response list from the session.  This is unmodifiable
       
  1204             // so we need to create a new list.  Then add this new response
       
  1205             // to the end and submit it back to the session object.
       
  1206             if ((chc.handshakeSession != null) && (!chc.isResumption)) {
       
  1207                 List<byte[]> respList = new ArrayList<>(
       
  1208                         chc.handshakeSession.getStatusResponses());
       
  1209                 respList.add(spec.statusResponse.encodedResponse);
       
  1210                 chc.handshakeSession.setStatusResponses(respList);
       
  1211             } else {
       
  1212                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake,verbose")) {
       
  1213                     SSLLogger.finest(
       
  1214                             "Ignoring stapled data on resumed session");
       
  1215                 }
       
  1216             }
       
  1217         }
       
  1218     }
       
  1219 }