< prev index next >

src/java.base/share/classes/sun/security/ssl/CertStatusExtension.java

Print this page


   1 /*
   2  * Copyright (c) 2015, 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.util.Objects;






















  30 
  31 /*








































  32  * RFC6066 defines the TLS extension,"status_request" (type 0x5),
  33  * which allows the client to request that the server perform OCSP
  34  * on the client's behalf.

  35  * The "extension data" field of this extension contains a
  36  * "CertificateStatusRequest" structure:
  37  *
  38  *      struct {
  39  *          CertificateStatusType status_type;
  40  *          select (status_type) {
  41  *              case ocsp: OCSPStatusRequest;
  42  *          } request;
  43  *      } CertificateStatusRequest;
  44  *
  45  *      enum { ocsp(1), (255) } CertificateStatusType;
  46  *
  47  *      struct {
  48  *          ResponderID responder_id_list<0..2^16-1>;
  49  *          Extensions  request_extensions;
  50  *      } OCSPStatusRequest;
  51  *
  52  *      opaque ResponderID<1..2^16-1>;
  53  *      opaque Extensions<0..2^16-1>;
  54  */



  55 
  56 final class CertStatusReqExtension extends HelloExtension {
  57 
  58     private final StatusRequestType statReqType;
  59     private final StatusRequest request;

  60 







  61 
  62     /**
  63      * Construct the default status request extension object.  The default
  64      * object results in a status_request extension where the extension
  65      * data segment is zero-length.  This is used primarily in ServerHello
  66      * messages where the server asserts it can do RFC 6066 status stapling.
  67      */
  68     CertStatusReqExtension() {
  69         super(ExtensionType.EXT_STATUS_REQUEST);
  70         statReqType = null;
  71         request = null;


















  72     }
  73 
  74     /**
  75      * Construct the status request extension object given a request type
  76      *      and {@code StatusRequest} object.
  77      *
  78      * @param reqType a {@code StatusRequestExtType object correspoding
  79      *      to the underlying {@code StatusRequest} object.  A value of
  80      *      {@code null} is not allowed.
  81      * @param statReq the {@code StatusRequest} object used to provide the
  82      *      encoding for the TLS extension.  A value of {@code null} is not
  83      *      allowed.
  84      *
  85      * @throws IllegalArgumentException if the provided {@code StatusRequest}
  86      *      does not match the type.
  87      * @throws NullPointerException if either the {@code reqType} or
  88      *      {@code statReq} arguments are {@code null}.


  89      */
  90     CertStatusReqExtension(StatusRequestType reqType, StatusRequest statReq) {
  91         super(ExtensionType.EXT_STATUS_REQUEST);



































  92 
  93         statReqType = Objects.requireNonNull(reqType,
  94                 "Unallowed null value for status_type");
  95         request = Objects.requireNonNull(statReq,
  96                 "Unallowed null value for request");








  97 
  98         // There is currently only one known status type (OCSP)
  99         // We can add more clauses to cover other types in the future
 100         if (statReqType == StatusRequestType.OCSP) {
 101             if (!(statReq instanceof OCSPStatusRequest)) {
 102                 throw new IllegalArgumentException("StatusRequest not " +
 103                         "of type OCSPStatusRequest");




 104             }
 105         }











 106     }
 107 
 108     /**
 109      * Construct the {@code CertStatusReqExtension} object from data read from
 110      *      a {@code HandshakeInputStream}























































 111      *
 112      * @param s the {@code HandshakeInputStream} providing the encoded data
 113      * @param len the length of the extension data
 114      *
 115      * @throws IOException if any decoding errors happen during object
 116      *      construction.


 117      */
 118     CertStatusReqExtension(HandshakeInStream s, int len) throws IOException {
 119         super(ExtensionType.EXT_STATUS_REQUEST);

 120 
 121         if (len > 0) {
 122             // Obtain the status type (first byte)
 123             statReqType = StatusRequestType.get(s.getInt8());
 124             if (statReqType == StatusRequestType.OCSP) {
 125                 request = new OCSPStatusRequest(s);
 126             } else {
 127                 // This is a status_type we don't understand.  Create
 128                 // an UnknownStatusRequest in order to preserve the data
 129                 request = new UnknownStatusRequest(s, len - 1);










 130             }





























































































 131         } else {
 132             // Treat this as a zero-length extension (i.e. from a ServerHello
 133             statReqType = null;
 134             request = null;





























































































 135         }
 136     }
 137 
 138     /**
 139      * Return the length of the encoded extension, including extension type,
 140      *      extension length and status_type fields.
 141      *
 142      * @return the length in bytes, including the extension type and
 143      *      length fields.
 144      */







 145     @Override
 146     int length() {
 147         return (statReqType != null ? 5 + request.length() : 4);




























 148     }
 149 
 150     /**
 151      * Send the encoded TLS extension through a {@code HandshakeOutputStream}
 152      *
 153      * @param s the {@code HandshakeOutputStream} used to send the encoded data
 154      *
 155      * @throws IOException tf any errors occur during the encoding process











































 156      */







 157     @Override
 158     void send(HandshakeOutStream s) throws IOException {
 159         s.putInt16(type.id);
 160         s.putInt16(this.length() - 4);


























 161 
 162         if (statReqType != null) {
 163             s.putInt8(statReqType.id);
 164             request.send(s);



















 165         }
 166     }
 167 
 168     /**
 169      * Create a string representation of this {@code CertStatusReqExtension}




































































 170      *
 171      * @return the string representation of this {@code CertStatusReqExtension}






 172      */















































































 173     @Override
 174     public String toString() {
 175         StringBuilder sb = new StringBuilder("Extension ").append(type);
 176         if (statReqType != null) {
 177             sb.append(": ").append(statReqType).append(", ").append(request);




















 178         }
 179 
 180         return sb.toString();










 181     }
 182 
 183     /**
 184      * Return the type field for this {@code CertStatusReqExtension}
 185      *
 186      * @return the {@code StatusRequestType} for this extension.  {@code null}
 187      *      will be returned if the default constructor is used to create
 188      *      a zero length status_request extension (found in ServerHello
 189      *      messages)









































 190      */
 191     StatusRequestType getType() {
 192         return statReqType;





































 193     }
 194 
 195     /**
 196      * Get the underlying {@code StatusRequest} for this
 197      *      {@code CertStatusReqExtension}
 198      *
 199      * @return the {@code StatusRequest} or {@code null} if the default
 200      * constructor was used to create this extension.






























































 201      */
 202     StatusRequest getRequest() {
 203         return request;




































































































































































 204     }
 205 }
   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 }
< prev index next >