src/java.base/share/classes/sun/security/ssl/CertStatusExtension.java
branchJDK-8145252-TLS13-branch
changeset 56542 56aaa6cb3693
parent 47216 71c04702a3d5
child 56651 0c13b82d3274
equal deleted inserted replaced
56541:92cbbfc996f3 56542:56aaa6cb3693
       
     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 SSLStringize certStatusReqStringize =
       
    73             new CertStatusRequestStringize();
       
    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 SSLStringize certStatusReqV2Stringize =
       
    86             new CertStatusRequestsStringize();
       
    87 
       
    88     static final SSLStringize certStatusRespStringize =
       
    89             new CertStatusRespStringize();
       
    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 CertStatusRequestStringize implements SSLStringize {
       
   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 CertStatusRespStringize implements SSLStringize {
       
   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 encodedLen;
       
   327         private final int ridListLen;
       
   328         private final int extListLen;
       
   329 
       
   330         static {
       
   331             OCSPStatusRequest ocspReq = null;
       
   332             OCSPStatusRequest multiReq = null;
       
   333 
       
   334             try {
       
   335                 ocspReq = new OCSPStatusRequest(
       
   336                         CertStatusRequestType.OCSP.id,
       
   337                         new byte[] {0x00, 0x00, 0x00, 0x00});
       
   338                 multiReq = new OCSPStatusRequest(
       
   339                     CertStatusRequestType.OCSP_MULTI.id,
       
   340                     new byte[] {0x00, 0x00, 0x00, 0x00});
       
   341             } catch (IOException ioe) {
       
   342                 // unlikely
       
   343             }
       
   344 
       
   345             EMPTY_OCSP = ocspReq;
       
   346             EMPTY_OCSP_MULTI = multiReq;
       
   347         }
       
   348 
       
   349         private OCSPStatusRequest(byte statusType,
       
   350                 byte[] encoded) throws IOException {
       
   351             super(statusType, encoded);
       
   352 
       
   353             if (encoded == null || encoded.length < 4) {
       
   354                                         //  2: length of responder_id_list
       
   355                                         // +2: length of request_extensions
       
   356                 throw new SSLProtocolException(
       
   357                         "Invalid OCSP status request: insufficient data");
       
   358             }
       
   359             this.encodedLen = encoded.length;
       
   360 
       
   361             List<ResponderId> rids = new ArrayList<>();
       
   362             List<Extension> exts = new ArrayList<>();
       
   363             ByteBuffer m = ByteBuffer.wrap(encoded);
       
   364 
       
   365             this.ridListLen = Record.getInt16(m);
       
   366             if (m.remaining() < (ridListLen + 2)) {
       
   367                 throw new SSLProtocolException(
       
   368                         "Invalid OCSP status request: insufficient data");
       
   369             }
       
   370 
       
   371             int ridListBytesRemaining = ridListLen;
       
   372             while (ridListBytesRemaining >= 2) {    // 2: length of responder_id
       
   373                 byte[] ridBytes = Record.getBytes16(m);
       
   374                 try {
       
   375                     rids.add(new ResponderId(ridBytes));
       
   376                 } catch (IOException ioe) {
       
   377                     throw new SSLProtocolException(
       
   378                         "Invalid OCSP status request: invalid responder ID");
       
   379                 }
       
   380                 ridListBytesRemaining -= ridBytes.length + 2;
       
   381             }
       
   382 
       
   383             if (ridListBytesRemaining != 0) {
       
   384                     throw new SSLProtocolException(
       
   385                         "Invalid OCSP status request: incomplete data");
       
   386             }
       
   387 
       
   388             byte[] extListBytes = Record.getBytes16(m);
       
   389             this.extListLen = extListBytes.length;
       
   390             if (extListLen > 0) {
       
   391                 try {
       
   392                     DerInputStream dis = new DerInputStream(extListBytes);
       
   393                     DerValue[] extSeqContents =
       
   394                             dis.getSequence(extListBytes.length);
       
   395                     for (DerValue extDerVal : extSeqContents) {
       
   396                         exts.add(new sun.security.x509.Extension(extDerVal));
       
   397                     }
       
   398                 } catch (IOException ioe) {
       
   399                     throw new SSLProtocolException(
       
   400                         "Invalid OCSP status request: invalid extension");
       
   401                 }
       
   402             }
       
   403 
       
   404             this.responderIds = rids;
       
   405             this.extensions = exts;
       
   406         }
       
   407 
       
   408         @Override
       
   409         public String toString() {
       
   410             MessageFormat messageFormat = new MessageFormat(
       
   411                 "\"certificate status type\": {0}\n" +
       
   412                 "\"OCSP status request\": '{'\n" +
       
   413                 "{1}\n" +
       
   414                 "'}'",
       
   415                 Locale.ENGLISH);
       
   416 
       
   417             MessageFormat requestFormat = new MessageFormat(
       
   418                 "\"responder_id\": {0}\n" +
       
   419                 "\"request extensions\": '{'\n" +
       
   420                 "{1}\n" +
       
   421                 "'}'",
       
   422                 Locale.ENGLISH);
       
   423 
       
   424             String ridStr = "<empty>";
       
   425             if (!responderIds.isEmpty()) {
       
   426                 ridStr = responderIds.toString();
       
   427 
       
   428             }
       
   429 
       
   430             String extsStr = "<empty>";
       
   431             if (!extensions.isEmpty()) {
       
   432                 StringBuilder extBuilder = new StringBuilder(512);
       
   433                 boolean isFirst = true;
       
   434                 for (Extension ext : this.extensions) {
       
   435                     if (isFirst) {
       
   436                         isFirst = false;
       
   437                     } else {
       
   438                         extBuilder.append(",\n");
       
   439                     }
       
   440                     extBuilder.append(
       
   441                             "{\n" + Utilities.indent(ext.toString()) + "}");
       
   442                 }
       
   443 
       
   444                 extsStr = extBuilder.toString();
       
   445             }
       
   446 
       
   447             Object[] requestFields = {
       
   448                     ridStr,
       
   449                     Utilities.indent(extsStr)
       
   450                 };
       
   451             String ocspStatusRequest = requestFormat.format(requestFields);
       
   452 
       
   453             Object[] messageFields = {
       
   454                     CertStatusRequestType.nameOf(statusType),
       
   455                     Utilities.indent(ocspStatusRequest)
       
   456                 };
       
   457 
       
   458             return messageFormat.format(messageFields);
       
   459         }
       
   460     }
       
   461 
       
   462     static class CertStatusResponse {
       
   463         final byte statusType;
       
   464         final byte[] encodedResponse;
       
   465 
       
   466         protected CertStatusResponse(byte statusType, byte[] respDer) {
       
   467             this.statusType = statusType;
       
   468             this.encodedResponse = respDer;
       
   469         }
       
   470 
       
   471         byte[] toByteArray() throws IOException {
       
   472             // Create a byte array large enough to handle the status_type
       
   473             // field (1) + OCSP length (3) + OCSP data (variable)
       
   474             byte[] outData = new byte[encodedResponse.length + 4];
       
   475             ByteBuffer buf = ByteBuffer.wrap(outData);
       
   476             Record.putInt8(buf, statusType);
       
   477             Record.putBytes24(buf, encodedResponse);
       
   478             return buf.array();
       
   479         }
       
   480 
       
   481         @Override
       
   482         public String toString() {
       
   483             MessageFormat messageFormat = new MessageFormat(
       
   484                 "\"certificate status response type\": {0}\n" +
       
   485                 "\"encoded certificate status\": '{'\n" +
       
   486                 "{1}\n" +
       
   487                 "'}'",
       
   488                 Locale.ENGLISH);
       
   489 
       
   490             HexDumpEncoder hexEncoder = new HexDumpEncoder();
       
   491             String encoded = hexEncoder.encodeBuffer(encodedResponse);
       
   492 
       
   493             Object[] messageFields = {
       
   494                 CertStatusRequestType.nameOf(statusType),
       
   495                 Utilities.indent(encoded)
       
   496             };
       
   497 
       
   498             return messageFormat.format(messageFields);
       
   499         }
       
   500     }
       
   501 
       
   502     static final class OCSPStatusResponse extends CertStatusResponse {
       
   503         final OCSPResponse ocspResponse;
       
   504 
       
   505         private OCSPStatusResponse(byte statusType,
       
   506                 byte[] encoded) throws IOException {
       
   507             super(statusType, encoded);
       
   508 
       
   509             // The DER-encoded OCSP response must not be zero length
       
   510             if (encoded == null || encoded.length < 1) {
       
   511                 throw new SSLProtocolException(
       
   512                         "Invalid OCSP status response: insufficient data");
       
   513             }
       
   514 
       
   515             // Otherwise, make an OCSPResponse object from the data
       
   516             ocspResponse = new OCSPResponse(encoded);
       
   517         }
       
   518 
       
   519         @Override
       
   520         public String toString() {
       
   521             MessageFormat messageFormat = new MessageFormat(
       
   522                 "\"certificate status response type\": {0}\n" +
       
   523                 "\"OCSP status response\": '{'\n" +
       
   524                 "{1}\n" +
       
   525                 "'}'",
       
   526                 Locale.ENGLISH);
       
   527 
       
   528             Object[] messageFields = {
       
   529                 CertStatusRequestType.nameOf(statusType),
       
   530                 Utilities.indent(ocspResponse.toString())
       
   531             };
       
   532 
       
   533             return messageFormat.format(messageFields);
       
   534         }
       
   535     }
       
   536 
       
   537     /**
       
   538      * Network data producer of a "status_request" extension in the
       
   539      * ClientHello handshake message.
       
   540      */
       
   541     private static final
       
   542             class CHCertStatusReqProducer implements HandshakeProducer {
       
   543         // Prevent instantiation of this class.
       
   544         private CHCertStatusReqProducer() {
       
   545             // blank
       
   546         }
       
   547 
       
   548         @Override
       
   549         public byte[] produce(ConnectionContext context,
       
   550                 HandshakeMessage message) throws IOException {
       
   551             // The producing happens in client side only.
       
   552             ClientHandshakeContext chc = (ClientHandshakeContext)context;
       
   553 
       
   554             if (!chc.sslContext.isStaplingEnabled(true)) {
       
   555                 return null;
       
   556             }
       
   557 
       
   558             if (!chc.sslConfig.isAvailable(CH_STATUS_REQUEST)) {
       
   559                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   560                     SSLLogger.fine(
       
   561                         "Ignore unavailable extension: " +
       
   562                         CH_STATUS_REQUEST.name);
       
   563                 }
       
   564                 return null;
       
   565             }
       
   566 
       
   567             // Produce the extension.
       
   568             //
       
   569             // We are using empty OCSPStatusRequest at present. May extend to
       
   570             // support specific responder or extensions later.
       
   571             byte[] extData = new byte[] {0x01, 0x00, 0x00, 0x00, 0x00};
       
   572 
       
   573             // Update the context.
       
   574             chc.handshakeExtensions.put(
       
   575                     CH_STATUS_REQUEST, CertStatusRequestSpec.DEFAULT);
       
   576 
       
   577             return extData;
       
   578         }
       
   579     }
       
   580 
       
   581     /**
       
   582      * Network data consumer of a "status_request" extension in the
       
   583      * ClientHello handshake message.
       
   584      */
       
   585     private static final
       
   586             class CHCertStatusReqConsumer implements ExtensionConsumer {
       
   587         // Prevent instantiation of this class.
       
   588         private CHCertStatusReqConsumer() {
       
   589             // blank
       
   590         }
       
   591 
       
   592         @Override
       
   593         public void consume(ConnectionContext context,
       
   594             HandshakeMessage message, ByteBuffer buffer) throws IOException {
       
   595 
       
   596             // The comsuming happens in server side only.
       
   597             ServerHandshakeContext shc = (ServerHandshakeContext)context;
       
   598 
       
   599             if (!shc.sslConfig.isAvailable(CH_STATUS_REQUEST)) {
       
   600                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   601                     SSLLogger.fine("Ignore unavailable extension: " +
       
   602                         CH_STATUS_REQUEST.name);
       
   603                 }
       
   604                 return;     // ignore the extension
       
   605             }
       
   606 
       
   607             // Parse the extension.
       
   608             CertStatusRequestSpec spec;
       
   609             try {
       
   610                 spec = new CertStatusRequestSpec(buffer);
       
   611             } catch (IOException ioe) {
       
   612                 shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe);
       
   613                 return;     // fatal() always throws, make the compiler happy.
       
   614             }
       
   615 
       
   616             // Update the context.
       
   617             shc.handshakeExtensions.put(CH_STATUS_REQUEST, spec);
       
   618             if (!shc.negotiatedProtocol.useTLS13PlusSpec()) {
       
   619                 shc.handshakeProducers.put(SSLHandshake.CERTIFICATE_STATUS.id,
       
   620                     SSLHandshake.CERTIFICATE_STATUS);
       
   621             }   // Otherwise, the certificate status presents in server cert.
       
   622 
       
   623             // No impact on session resumption.
       
   624         }
       
   625     }
       
   626 
       
   627     /**
       
   628      * Network data producer of a "status_request" extension in the
       
   629      * ServerHello handshake message.
       
   630      */
       
   631     private static final
       
   632             class SHCertStatusReqProducer implements HandshakeProducer {
       
   633         // Prevent instantiation of this class.
       
   634         private SHCertStatusReqProducer() {
       
   635             // blank
       
   636         }
       
   637 
       
   638         @Override
       
   639         public byte[] produce(ConnectionContext context,
       
   640                 HandshakeMessage message) throws IOException {
       
   641             // The producing happens in client side only.
       
   642             ServerHandshakeContext shc = (ServerHandshakeContext)context;
       
   643 
       
   644             // The StaplingParameters in the ServerHandshakeContext will
       
   645             // contain the info about what kind of stapling (if any) to
       
   646             // perform and whether this status_request extension should be
       
   647             // produced or the status_request_v2 (found in a different producer)
       
   648             // No explicit check is required for isStaplingEnabled here.  If
       
   649             // it is false then stapleParams will be null.  If it is true
       
   650             // then stapleParams may or may not be false and the check below
       
   651             // is sufficient.
       
   652             if ((shc.stapleParams == null) ||
       
   653                     (shc.stapleParams.statusRespExt !=
       
   654                     SSLExtension.CH_STATUS_REQUEST)) {
       
   655                 return null;    // Do not produce status_request in ServerHello
       
   656             }
       
   657 
       
   658             // In response to "status_request" extension request only.
       
   659             CertStatusRequestSpec spec = (CertStatusRequestSpec)
       
   660                     shc.handshakeExtensions.get(CH_STATUS_REQUEST);
       
   661             if (spec == null) {
       
   662                 // Ignore, no status_request extension requested.
       
   663                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   664                     SSLLogger.finest(
       
   665                         "Ignore unavailable extension: " +
       
   666                         CH_STATUS_REQUEST.name);
       
   667                 }
       
   668 
       
   669                 return null;        // ignore the extension
       
   670             }
       
   671 
       
   672             // Is it a session resuming?
       
   673             if (shc.isResumption) {
       
   674                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   675                     SSLLogger.finest(
       
   676                         "No status_request response for session resuming");
       
   677                 }
       
   678 
       
   679                 return null;        // ignore the extension
       
   680             }
       
   681 
       
   682             // The "extension_data" in the extended ServerHello handshake
       
   683             // message MUST be empty.
       
   684             byte[] extData = new byte[0];
       
   685 
       
   686             // Update the context.
       
   687             shc.handshakeExtensions.put(
       
   688                     SH_STATUS_REQUEST, CertStatusRequestSpec.DEFAULT);
       
   689 
       
   690             return extData;
       
   691         }
       
   692     }
       
   693 
       
   694     /**
       
   695      * Network data consumer of a "status_request" extension in the
       
   696      * ServerHello handshake message.
       
   697      */
       
   698     private static final
       
   699             class SHCertStatusReqConsumer implements ExtensionConsumer {
       
   700         // Prevent instantiation of this class.
       
   701         private SHCertStatusReqConsumer() {
       
   702             // blank
       
   703         }
       
   704 
       
   705         @Override
       
   706         public void consume(ConnectionContext context,
       
   707             HandshakeMessage message, ByteBuffer buffer) throws IOException {
       
   708 
       
   709             // The producing happens in client side only.
       
   710             ClientHandshakeContext chc = (ClientHandshakeContext)context;
       
   711 
       
   712             // In response to "status_request" extension request only.
       
   713             CertStatusRequestSpec requestedCsr = (CertStatusRequestSpec)
       
   714                     chc.handshakeExtensions.get(CH_STATUS_REQUEST);
       
   715             if (requestedCsr == null) {
       
   716                 chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
       
   717                     "Unexpected status_request extension in ServerHello");
       
   718             }
       
   719 
       
   720             // Parse the extension.
       
   721             if (buffer.hasRemaining()) {
       
   722                 chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
       
   723                   "Invalid status_request extension in ServerHello message: " +
       
   724                   "the extension data must be empty");
       
   725             }
       
   726 
       
   727             // Update the context.
       
   728             chc.handshakeExtensions.put(
       
   729                     SH_STATUS_REQUEST, CertStatusRequestSpec.DEFAULT);
       
   730             chc.handshakeConsumers.put(SSLHandshake.CERTIFICATE_STATUS.id,
       
   731                     SSLHandshake.CERTIFICATE_STATUS);
       
   732 
       
   733             // Since we've received a legitimate status_request in the
       
   734             // ServerHello, stapling is active if it's been enabled.
       
   735             chc.staplingActive = chc.sslContext.isStaplingEnabled(true);
       
   736 
       
   737             // No impact on session resumption.
       
   738         }
       
   739     }
       
   740 
       
   741     /**
       
   742      * The "status_request_v2" extension.
       
   743      *
       
   744      * RFC6961 defines the TLS extension,"status_request_v2" (type 0x5),
       
   745      * which allows the client to request that the server perform OCSP
       
   746      * on the client's behalf.
       
   747      *
       
   748      * The RFC defines an CertStatusReqItemV2 structure:
       
   749      *
       
   750      *      struct {
       
   751      *          CertificateStatusType status_type;
       
   752      *          uint16 request_length;
       
   753      *          select (status_type) {
       
   754      *              case ocsp: OCSPStatusRequest;
       
   755      *              case ocsp_multi: OCSPStatusRequest;
       
   756      *          } request;
       
   757      *      } CertificateStatusRequestItemV2;
       
   758      *
       
   759      *      enum { ocsp(1), ocsp_multi(2), (255) } CertificateStatusType;
       
   760      *      struct {
       
   761      *        ResponderID responder_id_list<0..2^16-1>;
       
   762      *        Extensions request_extensions;
       
   763      *      } OCSPStatusRequest;
       
   764      *
       
   765      *      opaque ResponderID<1..2^16-1>;
       
   766      *      opaque Extensions<0..2^16-1>;
       
   767      *
       
   768      *      struct {
       
   769      *        CertificateStatusRequestItemV2
       
   770      *                         certificate_status_req_list<1..2^16-1>;
       
   771      *      } CertificateStatusRequestListV2;
       
   772      */
       
   773     static final class CertStatusRequestV2Spec implements SSLExtensionSpec {
       
   774         static final CertStatusRequestV2Spec DEFAULT =
       
   775                 new CertStatusRequestV2Spec(new CertStatusRequest[] {
       
   776                         OCSPStatusRequest.EMPTY_OCSP_MULTI});
       
   777 
       
   778         final CertStatusRequest[] certStatusRequests;
       
   779 
       
   780         private CertStatusRequestV2Spec(CertStatusRequest[] certStatusRequests) {
       
   781             this.certStatusRequests = certStatusRequests;
       
   782         }
       
   783 
       
   784         private CertStatusRequestV2Spec(ByteBuffer message) throws IOException {
       
   785             // Is it a empty extension_data?
       
   786             if (message.remaining() == 0) {
       
   787                 // server response
       
   788                 this.certStatusRequests = new CertStatusRequest[0];
       
   789                 return;
       
   790             }
       
   791 
       
   792             if (message.remaining() < 5) {  //  2: certificate_status_req_list
       
   793                                             // +1: status_type
       
   794                                             // +2: request_length
       
   795                 throw new SSLProtocolException(
       
   796                     "Invalid status_request_v2 extension: insufficient data");
       
   797             }
       
   798 
       
   799             int listLen = Record.getInt16(message);
       
   800             if (listLen <= 0) {
       
   801                 throw new SSLProtocolException(
       
   802                     "certificate_status_req_list length must be positive " +
       
   803                     "(received length: " + listLen + ")");
       
   804             }
       
   805 
       
   806             int remaining = listLen;
       
   807             List<CertStatusRequest> statusRequests = new ArrayList<>();
       
   808             while (remaining > 0) {
       
   809                 byte statusType = (byte)Record.getInt8(message);
       
   810                 int requestLen = Record.getInt16(message);
       
   811 
       
   812                 if (message.remaining() < requestLen) {
       
   813                     throw new SSLProtocolException(
       
   814                             "Invalid status_request_v2 extension: " +
       
   815                             "insufficient data (request_length=" + requestLen +
       
   816                             ", remining=" + message.remaining() + ")");
       
   817                 }
       
   818 
       
   819                 byte[] encoded = new byte[requestLen];
       
   820                 if (encoded.length != 0) {
       
   821                     message.get(encoded);
       
   822                 }
       
   823                 remaining -= 3;     // 1(status type) + 2(request_length) bytes
       
   824                 remaining -= requestLen;
       
   825 
       
   826                 if (statusType == CertStatusRequestType.OCSP.id ||
       
   827                         statusType == CertStatusRequestType.OCSP_MULTI.id) {
       
   828                     if (encoded.length < 4) {
       
   829                                         //  2: length of responder_id_list
       
   830                                         // +2: length of request_extensions
       
   831                         throw new SSLProtocolException(
       
   832                             "Invalid status_request_v2 extension: " +
       
   833                             "insufficient data");
       
   834                     }
       
   835                     statusRequests.add(
       
   836                             new OCSPStatusRequest(statusType, encoded));
       
   837                 } else {
       
   838                     if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   839                         SSLLogger.info(
       
   840                                 "Unknown certificate status request " +
       
   841                                 "(status type: " + statusType + ")");
       
   842                     }
       
   843                     statusRequests.add(
       
   844                             new CertStatusRequest(statusType, encoded));
       
   845                 }
       
   846             }
       
   847 
       
   848             certStatusRequests =
       
   849                     statusRequests.toArray(new CertStatusRequest[0]);
       
   850         }
       
   851 
       
   852         @Override
       
   853         public String toString() {
       
   854             if (certStatusRequests == null || certStatusRequests.length == 0) {
       
   855                 return "<empty>";
       
   856             } else {
       
   857                 MessageFormat messageFormat = new MessageFormat(
       
   858                     "\"cert status request\": '{'\n{0}\n'}'", Locale.ENGLISH);
       
   859 
       
   860                 StringBuilder builder = new StringBuilder(512);
       
   861                 boolean isFirst = true;
       
   862                 for (CertStatusRequest csr : certStatusRequests) {
       
   863                     if (isFirst) {
       
   864                         isFirst = false;
       
   865                     } else {
       
   866                         builder.append(", ");
       
   867                     }
       
   868                     Object[] messageFields = {
       
   869                             Utilities.indent(csr.toString())
       
   870                         };
       
   871                     builder.append(messageFormat.format(messageFields));
       
   872                 }
       
   873 
       
   874                 return builder.toString();
       
   875             }
       
   876         }
       
   877     }
       
   878 
       
   879     private static final
       
   880             class CertStatusRequestsStringize implements SSLStringize {
       
   881         @Override
       
   882         public String toString(ByteBuffer buffer) {
       
   883             try {
       
   884                 return (new CertStatusRequestV2Spec(buffer)).toString();
       
   885             } catch (IOException ioe) {
       
   886                 // For debug logging only, so please swallow exceptions.
       
   887                 return ioe.getMessage();
       
   888             }
       
   889         }
       
   890     }
       
   891 
       
   892     /**
       
   893      * Network data producer of a "status_request_v2" extension in the
       
   894      * ClientHello handshake message.
       
   895      */
       
   896     private static final
       
   897             class CHCertStatusReqV2Producer implements HandshakeProducer {
       
   898         // Prevent instantiation of this class.
       
   899         private CHCertStatusReqV2Producer() {
       
   900             // blank
       
   901         }
       
   902 
       
   903         @Override
       
   904         public byte[] produce(ConnectionContext context,
       
   905                 HandshakeMessage message) throws IOException {
       
   906             // The producing happens in client side only.
       
   907             ClientHandshakeContext chc = (ClientHandshakeContext)context;
       
   908 
       
   909             if (!chc.sslContext.isStaplingEnabled(true)) {
       
   910                 return null;
       
   911             }
       
   912 
       
   913             if (!chc.sslConfig.isAvailable(CH_STATUS_REQUEST_V2)) {
       
   914                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   915                     SSLLogger.finest(
       
   916                         "Ignore unavailable status_request_v2 extension");
       
   917                 }
       
   918 
       
   919                 return null;
       
   920             }
       
   921 
       
   922             // Produce the extension.
       
   923             //
       
   924             // We are using empty OCSPStatusRequest at present. May extend to
       
   925             // support specific responder or extensions later.
       
   926             byte[] extData = new byte[] {
       
   927                 0x00, 0x07, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00};
       
   928 
       
   929             // Update the context.
       
   930             chc.handshakeExtensions.put(
       
   931                     CH_STATUS_REQUEST_V2, CertStatusRequestV2Spec.DEFAULT);
       
   932 
       
   933             return extData;
       
   934         }
       
   935     }
       
   936 
       
   937     /**
       
   938      * Network data consumer of a "status_request_v2" extension in the
       
   939      * ClientHello handshake message.
       
   940      */
       
   941     private static final
       
   942             class CHCertStatusReqV2Consumer implements ExtensionConsumer {
       
   943         // Prevent instantiation of this class.
       
   944         private CHCertStatusReqV2Consumer() {
       
   945             // blank
       
   946         }
       
   947 
       
   948         @Override
       
   949         public void consume(ConnectionContext context,
       
   950             HandshakeMessage message, ByteBuffer buffer) throws IOException {
       
   951 
       
   952             // The comsuming happens in server side only.
       
   953             ServerHandshakeContext shc = (ServerHandshakeContext)context;
       
   954 
       
   955             if (!shc.sslConfig.isAvailable(CH_STATUS_REQUEST_V2)) {
       
   956                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   957                     SSLLogger.finest(
       
   958                         "Ignore unavailable status_request_v2 extension");
       
   959                 }
       
   960 
       
   961                 return;     // ignore the extension
       
   962             }
       
   963 
       
   964             // Parse the extension.
       
   965             CertStatusRequestV2Spec spec;
       
   966             try {
       
   967                 spec = new CertStatusRequestV2Spec(buffer);
       
   968             } catch (IOException ioe) {
       
   969                 shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe);
       
   970                 return;     // fatal() always throws, make the compiler happy.
       
   971             }
       
   972 
       
   973             // Update the context.
       
   974             shc.handshakeExtensions.put(CH_STATUS_REQUEST_V2, spec);
       
   975             shc.handshakeProducers.putIfAbsent(
       
   976                     SSLHandshake.CERTIFICATE_STATUS.id,
       
   977                     SSLHandshake.CERTIFICATE_STATUS);
       
   978             // No impact on session resumption.
       
   979         }
       
   980     }
       
   981 
       
   982     /**
       
   983      * Network data producer of a "status_request_v2" extension in the
       
   984      * ServerHello handshake message.
       
   985      */
       
   986     private static final
       
   987             class SHCertStatusReqV2Producer implements HandshakeProducer {
       
   988         // Prevent instantiation of this class.
       
   989         private SHCertStatusReqV2Producer() {
       
   990             // blank
       
   991         }
       
   992 
       
   993         @Override
       
   994         public byte[] produce(ConnectionContext context,
       
   995                 HandshakeMessage message) throws IOException {
       
   996             // The producing happens in client side only.
       
   997 
       
   998             ServerHandshakeContext shc = (ServerHandshakeContext)context;
       
   999             // The StaplingParameters in the ServerHandshakeContext will
       
  1000             // contain the info about what kind of stapling (if any) to
       
  1001             // perform and whether this status_request extension should be
       
  1002             // produced or the status_request_v2 (found in a different producer)
       
  1003             // No explicit check is required for isStaplingEnabled here.  If
       
  1004             // it is false then stapleParams will be null.  If it is true
       
  1005             // then stapleParams may or may not be false and the check below
       
  1006             // is sufficient.
       
  1007             if ((shc.stapleParams == null) ||
       
  1008                     (shc.stapleParams.statusRespExt !=
       
  1009                     SSLExtension.CH_STATUS_REQUEST_V2)) {
       
  1010                 return null;    // Do not produce status_request_v2 in SH
       
  1011             }
       
  1012 
       
  1013             // In response to "status_request_v2" extension request only
       
  1014             CertStatusRequestV2Spec spec = (CertStatusRequestV2Spec)
       
  1015                     shc.handshakeExtensions.get(CH_STATUS_REQUEST_V2);
       
  1016             if (spec == null) {
       
  1017                 // Ignore, no status_request_v2 extension requested.
       
  1018                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
  1019                     SSLLogger.finest(
       
  1020                         "Ignore unavailable status_request_v2 extension");
       
  1021                 }
       
  1022 
       
  1023                 return null;        // ignore the extension
       
  1024             }
       
  1025 
       
  1026             // Is it a session resuming?
       
  1027             if (shc.isResumption) {
       
  1028                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
  1029                     SSLLogger.finest(
       
  1030                         "No status_request_v2 response for session resumption");
       
  1031                 }
       
  1032                 return null;        // ignore the extension
       
  1033             }
       
  1034 
       
  1035             // The "extension_data" in the extended ServerHello handshake
       
  1036             // message MUST be empty.
       
  1037             byte[] extData = new byte[0];
       
  1038 
       
  1039             // Update the context.
       
  1040             shc.handshakeExtensions.put(
       
  1041                     SH_STATUS_REQUEST_V2, CertStatusRequestV2Spec.DEFAULT);
       
  1042 
       
  1043             return extData;
       
  1044         }
       
  1045     }
       
  1046 
       
  1047     /**
       
  1048      * Network data consumer of a "status_request_v2" extension in the
       
  1049      * ServerHello handshake message.
       
  1050      */
       
  1051     private static final
       
  1052             class SHCertStatusReqV2Consumer implements ExtensionConsumer {
       
  1053         // Prevent instantiation of this class.
       
  1054         private SHCertStatusReqV2Consumer() {
       
  1055             // blank
       
  1056         }
       
  1057 
       
  1058         @Override
       
  1059         public void consume(ConnectionContext context,
       
  1060             HandshakeMessage message, ByteBuffer buffer) throws IOException {
       
  1061 
       
  1062             // The consumption happens in client side only.
       
  1063             ClientHandshakeContext chc = (ClientHandshakeContext)context;
       
  1064 
       
  1065             // In response to "status_request" extension request only
       
  1066             CertStatusRequestV2Spec requestedCsr = (CertStatusRequestV2Spec)
       
  1067                     chc.handshakeExtensions.get(CH_STATUS_REQUEST_V2);
       
  1068             if (requestedCsr == null) {
       
  1069                 chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
       
  1070                     "Unexpected status_request_v2 extension in ServerHello");
       
  1071             }
       
  1072 
       
  1073             // Parse the extension.
       
  1074             if (buffer.hasRemaining()) {
       
  1075                 chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
       
  1076                   "Invalid status_request_v2 extension in ServerHello: " +
       
  1077                   "the extension data must be empty");
       
  1078             }
       
  1079 
       
  1080             // Update the context.
       
  1081             chc.handshakeExtensions.put(
       
  1082                     SH_STATUS_REQUEST_V2, CertStatusRequestV2Spec.DEFAULT);
       
  1083             chc.handshakeConsumers.put(SSLHandshake.CERTIFICATE_STATUS.id,
       
  1084                     SSLHandshake.CERTIFICATE_STATUS);
       
  1085 
       
  1086             // Since we've received a legitimate status_request in the
       
  1087             // ServerHello, stapling is active if it's been enabled.
       
  1088             chc.staplingActive = chc.sslContext.isStaplingEnabled(true);
       
  1089 
       
  1090             // No impact on session resumption.
       
  1091         }
       
  1092     }
       
  1093 
       
  1094     private static final
       
  1095             class CTCertStatusResponseProducer implements HandshakeProducer {
       
  1096         // Prevent instantiation of this class.
       
  1097         private CTCertStatusResponseProducer() {
       
  1098             // blank
       
  1099         }
       
  1100 
       
  1101         @Override
       
  1102         public byte[] produce(ConnectionContext context,
       
  1103                 HandshakeMessage message) throws IOException {
       
  1104             ServerHandshakeContext shc = (ServerHandshakeContext)context;
       
  1105             byte[] producedData = null;
       
  1106 
       
  1107             // Stapling needs to be active and have valid data to proceed
       
  1108             if (shc.stapleParams == null) {
       
  1109                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
  1110                     SSLLogger.finest(
       
  1111                         "Stapling is disabled for this connection");
       
  1112                 }
       
  1113                 return null;
       
  1114             }
       
  1115 
       
  1116             // There needs to be a non-null CertificateEntry to proceed
       
  1117             if (shc.currentCertEntry == null) {
       
  1118                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
  1119                     SSLLogger.finest("Found null CertificateEntry in context");
       
  1120                 }
       
  1121                 return null;
       
  1122             }
       
  1123 
       
  1124             // Pull the certificate from the CertificateEntry and find
       
  1125             // a response from the response map.  If one exists we will
       
  1126             // staple it.
       
  1127             try {
       
  1128                 CertificateFactory cf = CertificateFactory.getInstance("X.509");
       
  1129                 X509Certificate x509Cert =
       
  1130                         (X509Certificate)cf.generateCertificate(
       
  1131                                 new ByteArrayInputStream(
       
  1132                                         shc.currentCertEntry.encoded));
       
  1133                 byte[] respBytes = shc.stapleParams.responseMap.get(x509Cert);
       
  1134                 if (respBytes == null) {
       
  1135                     // We're done with this entry.  Clear it from the context
       
  1136                     if (SSLLogger.isOn &&
       
  1137                             SSLLogger.isOn("ssl,handshake,verbose")) {
       
  1138                         SSLLogger.finest("No status response found for " +
       
  1139                                 x509Cert.getSubjectX500Principal());
       
  1140                     }
       
  1141                     shc.currentCertEntry = null;
       
  1142                     return null;
       
  1143                 }
       
  1144 
       
  1145                 // Build a proper response buffer from the stapling information
       
  1146                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake,verbose")) {
       
  1147                     SSLLogger.finest("Found status response for " +
       
  1148                             x509Cert.getSubjectX500Principal() +
       
  1149                             ", response length: " + respBytes.length);
       
  1150                 }
       
  1151                 CertStatusResponse certResp = (shc.stapleParams.statReqType ==
       
  1152                         CertStatusRequestType.OCSP) ?
       
  1153                         new OCSPStatusResponse(shc.stapleParams.statReqType.id,
       
  1154                                 respBytes) :
       
  1155                         new CertStatusResponse(shc.stapleParams.statReqType.id,
       
  1156                                 respBytes);
       
  1157                 producedData = certResp.toByteArray();
       
  1158             } catch (CertificateException ce) {
       
  1159                 shc.conContext.fatal(Alert.BAD_CERTIFICATE,
       
  1160                         "Failed to parse server certificates", ce);
       
  1161             } catch (IOException ioe) {
       
  1162                 shc.conContext.fatal(Alert.BAD_CERT_STATUS_RESPONSE,
       
  1163                         "Failed to parse certificate status response", ioe);
       
  1164             }
       
  1165 
       
  1166             // Clear the pinned CertificateEntry from the context
       
  1167             shc.currentCertEntry = null;
       
  1168             return producedData;
       
  1169         }
       
  1170     }
       
  1171 
       
  1172     private static final
       
  1173         class CTCertStatusResponseConsumer implements ExtensionConsumer {
       
  1174         // Prevent instantiation of this class.
       
  1175         private CTCertStatusResponseConsumer() {
       
  1176             // blank
       
  1177         }
       
  1178 
       
  1179         @Override
       
  1180         public void consume(ConnectionContext context,
       
  1181                 HandshakeMessage message, ByteBuffer buffer) throws IOException {
       
  1182             // The consumption happens in client side only.
       
  1183             ClientHandshakeContext chc = (ClientHandshakeContext)context;
       
  1184 
       
  1185             // Parse the extension.
       
  1186             CertStatusResponseSpec spec;
       
  1187             try {
       
  1188                 spec = new CertStatusResponseSpec(buffer);
       
  1189             } catch (IOException ioe) {
       
  1190                 chc.conContext.fatal(Alert.DECODE_ERROR, ioe);
       
  1191                 return;     // fatal() always throws, make the compiler happy.
       
  1192             }
       
  1193 
       
  1194             if (chc.sslContext.isStaplingEnabled(true)) {
       
  1195                 // Activate stapling
       
  1196                 chc.staplingActive = true;
       
  1197             } else {
       
  1198                 // Do no further processing of stapled responses
       
  1199                 return;
       
  1200             }
       
  1201 
       
  1202             // Get response list from the session.  This is unmodifiable
       
  1203             // so we need to create a new list.  Then add this new response
       
  1204             // to the end and submit it back to the session object.
       
  1205             if ((chc.handshakeSession != null) && (!chc.isResumption)) {
       
  1206                 List<byte[]> respList = new ArrayList<>(
       
  1207                         chc.handshakeSession.getStatusResponses());
       
  1208                 respList.add(spec.statusResponse.encodedResponse);
       
  1209                 chc.handshakeSession.setStatusResponses(respList);
       
  1210             } else {
       
  1211                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake,verbose")) {
       
  1212                     SSLLogger.finest(
       
  1213                             "Ignoring stapled data on resumed session");
       
  1214                 }
       
  1215             }
       
  1216         }
       
  1217     }
       
  1218 }