src/java.base/share/classes/sun/security/ssl/RenegoInfoExtension.java
changeset 50768 68fa3d4026ea
parent 47216 71c04702a3d5
child 53064 103ed9569fc8
equal deleted inserted replaced
50767:356eaea05bf0 50768:68fa3d4026ea
       
     1 /*
       
     2  * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package sun.security.ssl;
       
    27 
       
    28 import java.io.IOException;
       
    29 import java.nio.ByteBuffer;
       
    30 import java.text.MessageFormat;
       
    31 import java.util.Arrays;
       
    32 import java.util.Locale;
       
    33 import javax.net.ssl.SSLProtocolException;
       
    34 import sun.security.ssl.ClientHello.ClientHelloMessage;
       
    35 import static sun.security.ssl.SSLExtension.CH_RENEGOTIATION_INFO;
       
    36 import sun.security.ssl.SSLExtension.ExtensionConsumer;
       
    37 import static sun.security.ssl.SSLExtension.SH_RENEGOTIATION_INFO;
       
    38 import sun.security.ssl.SSLExtension.SSLExtensionSpec;
       
    39 import sun.security.ssl.SSLHandshake.HandshakeMessage;
       
    40 
       
    41 /**
       
    42  * Pack of the "renegotiation_info" extensions [RFC 5746].
       
    43  */
       
    44 final class RenegoInfoExtension {
       
    45     static final HandshakeProducer chNetworkProducer =
       
    46             new CHRenegotiationInfoProducer();
       
    47     static final ExtensionConsumer chOnLoadConsumer =
       
    48             new CHRenegotiationInfoConsumer();
       
    49     static final HandshakeAbsence chOnLoadAbsence =
       
    50             new CHRenegotiationInfoAbsence();
       
    51 
       
    52     static final HandshakeProducer shNetworkProducer =
       
    53             new SHRenegotiationInfoProducer();
       
    54     static final ExtensionConsumer shOnLoadConsumer =
       
    55             new SHRenegotiationInfoConsumer();
       
    56     static final HandshakeAbsence shOnLoadAbsence =
       
    57             new SHRenegotiationInfoAbsence();
       
    58 
       
    59     static final SSLStringizer rniStringizer =
       
    60             new RenegotiationInfoStringizer();
       
    61 
       
    62     /**
       
    63      * The "renegotiation_info" extension.
       
    64      */
       
    65     static final class RenegotiationInfoSpec implements SSLExtensionSpec {
       
    66         // A nominal object that does not holding any real renegotiation info.
       
    67         static final RenegotiationInfoSpec NOMINAL =
       
    68                 new RenegotiationInfoSpec(new byte[0]);
       
    69 
       
    70         private final byte[] renegotiatedConnection;
       
    71 
       
    72         private RenegotiationInfoSpec(byte[] renegotiatedConnection) {
       
    73             this.renegotiatedConnection = Arrays.copyOf(
       
    74                     renegotiatedConnection, renegotiatedConnection.length);
       
    75         }
       
    76 
       
    77         private RenegotiationInfoSpec(ByteBuffer m) throws IOException {
       
    78             // Parse the extension.
       
    79             if (!m.hasRemaining() || m.remaining() < 1) {
       
    80                 throw new SSLProtocolException(
       
    81                     "Invalid renegotiation_info extension data: " +
       
    82                     "insufficient data");
       
    83             }
       
    84             this.renegotiatedConnection = Record.getBytes8(m);
       
    85         }
       
    86 
       
    87         @Override
       
    88         public String toString() {
       
    89             MessageFormat messageFormat = new MessageFormat(
       
    90                 "\"renegotiated connection\": '['{0}']'", Locale.ENGLISH);
       
    91             if (renegotiatedConnection.length == 0) {
       
    92                 Object[] messageFields = {
       
    93                         "<no renegotiated connection>"
       
    94                     };
       
    95                 return messageFormat.format(messageFields);
       
    96             } else {
       
    97                 Object[] messageFields = {
       
    98                         Utilities.toHexString(renegotiatedConnection)
       
    99                     };
       
   100                 return messageFormat.format(messageFields);
       
   101             }
       
   102         }
       
   103     }
       
   104 
       
   105     private static final
       
   106             class RenegotiationInfoStringizer implements SSLStringizer {
       
   107         @Override
       
   108         public String toString(ByteBuffer buffer) {
       
   109             try {
       
   110                 return (new RenegotiationInfoSpec(buffer)).toString();
       
   111             } catch (IOException ioe) {
       
   112                 // For debug logging only, so please swallow exceptions.
       
   113                 return ioe.getMessage();
       
   114             }
       
   115         }
       
   116     }
       
   117 
       
   118     /**
       
   119      * Network data producer of a "renegotiation_info" extension in
       
   120      * the ClientHello handshake message.
       
   121      */
       
   122     private static final
       
   123             class CHRenegotiationInfoProducer implements HandshakeProducer {
       
   124         // Prevent instantiation of this class.
       
   125         private CHRenegotiationInfoProducer() {
       
   126             // blank
       
   127         }
       
   128 
       
   129         @Override
       
   130         public byte[] produce(ConnectionContext context,
       
   131                 HandshakeMessage message) throws IOException {
       
   132             // The producing happens in client side only.
       
   133             ClientHandshakeContext chc = (ClientHandshakeContext)context;
       
   134 
       
   135             // Is it a supported and enabled extension?
       
   136             if (!chc.sslConfig.isAvailable(CH_RENEGOTIATION_INFO)) {
       
   137                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   138                     SSLLogger.fine(
       
   139                             "Ignore unavailable renegotiation_info extension");
       
   140                 }
       
   141 
       
   142                 return null;
       
   143             }
       
   144 
       
   145             if (!chc.conContext.isNegotiated) {
       
   146                 if (chc.activeCipherSuites.contains(
       
   147                         CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)) {
       
   148                     // Using the the TLS_EMPTY_RENEGOTIATION_INFO_SCSV instead.
       
   149                     return null;
       
   150                 }
       
   151 
       
   152                 // initial handshaking.
       
   153                 //
       
   154                 // If this is the initial handshake for a connection, then the
       
   155                 // "renegotiated_connection" field is of zero length in both
       
   156                 // the ClientHello and the ServerHello. [RFC 5746]
       
   157                 byte[] extData = new byte[] { 0x00 };
       
   158                 chc.handshakeExtensions.put(
       
   159                         CH_RENEGOTIATION_INFO, RenegotiationInfoSpec.NOMINAL);
       
   160 
       
   161                 return extData;
       
   162             } else if (chc.conContext.secureRenegotiation) {
       
   163                 // secure renegotiation
       
   164                 //
       
   165                 // For ClientHello handshake message in renegotiation, this
       
   166                 // field contains the "client_verify_data".
       
   167                 byte[] extData =
       
   168                         new byte[chc.conContext.clientVerifyData.length + 1];
       
   169                 ByteBuffer m = ByteBuffer.wrap(extData);
       
   170                 Record.putBytes8(m, chc.conContext.clientVerifyData);
       
   171 
       
   172                 // The conContext.clientVerifyData will be used for further
       
   173                 // processing, so it does not matter to save whatever in the
       
   174                 // RenegotiationInfoSpec object.
       
   175                 chc.handshakeExtensions.put(
       
   176                         CH_RENEGOTIATION_INFO, RenegotiationInfoSpec.NOMINAL);
       
   177 
       
   178                 return extData;
       
   179             } else {    // not secure renegotiation
       
   180                 if (HandshakeContext.allowUnsafeRenegotiation) {
       
   181                     if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   182                         SSLLogger.warning("Using insecure renegotiation");
       
   183                     }
       
   184 
       
   185                     return null;
       
   186                 } else {
       
   187                     // terminate the session.
       
   188                     chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
   189                             "insecure renegotiation is not allowed");
       
   190                 }
       
   191             }
       
   192 
       
   193             return null;
       
   194         }
       
   195     }
       
   196 
       
   197     /**
       
   198      * Network data producer of a "renegotiation_info" extension in
       
   199      * the ServerHello handshake message.
       
   200      */
       
   201     private static final
       
   202             class CHRenegotiationInfoConsumer implements ExtensionConsumer {
       
   203         // Prevent instantiation of this class.
       
   204         private CHRenegotiationInfoConsumer() {
       
   205             // blank
       
   206         }
       
   207 
       
   208         @Override
       
   209         public void consume(ConnectionContext context,
       
   210             HandshakeMessage message, ByteBuffer buffer) throws IOException {
       
   211 
       
   212             // The consuming happens in server side only.
       
   213             ServerHandshakeContext shc = (ServerHandshakeContext)context;
       
   214 
       
   215             // Is it a supported and enabled extension?
       
   216             if (!shc.sslConfig.isAvailable(CH_RENEGOTIATION_INFO)) {
       
   217                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   218                     SSLLogger.fine("Ignore unavailable extension: " +
       
   219                             CH_RENEGOTIATION_INFO.name);
       
   220                 }
       
   221                 return;     // ignore the extension
       
   222             }
       
   223 
       
   224             // Parse the extension.
       
   225             RenegotiationInfoSpec spec;
       
   226             try {
       
   227                 spec = new RenegotiationInfoSpec(buffer);
       
   228             } catch (IOException ioe) {
       
   229                 shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe);
       
   230                 return;     // fatal() always throws, make the compiler happy.
       
   231             }
       
   232 
       
   233             if (!shc.conContext.isNegotiated) {
       
   234                 // initial handshaking.
       
   235                 if (spec.renegotiatedConnection.length != 0) {
       
   236                     shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
       
   237                         "Invalid renegotiation_info extension data: not empty");
       
   238                 }
       
   239                 shc.conContext.secureRenegotiation = true;
       
   240             } else {
       
   241                 if (!shc.conContext.secureRenegotiation) {
       
   242                     // Unexpected RI extension for insecure renegotiation,
       
   243                     // abort the handshake with a fatal handshake_failure alert.
       
   244                     shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
   245                             "The renegotiation_info is present in a insecure " +
       
   246                             "renegotiation");
       
   247                 } else {
       
   248                     // verify the client_verify_data value
       
   249                     if (!Arrays.equals(shc.conContext.clientVerifyData,
       
   250                             spec.renegotiatedConnection)) {
       
   251                         shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
       
   252                             "Invalid renegotiation_info extension data: " +
       
   253                             "incorrect verify data in ClientHello");
       
   254                     }
       
   255                 }
       
   256             }
       
   257 
       
   258             // Update the context.
       
   259             //
       
   260             // The conContext.clientVerifyData will be used for further
       
   261             // processing, so it does not matter to save whatever in the
       
   262             // RenegotiationInfoSpec object.
       
   263             shc.handshakeExtensions.put(
       
   264                     CH_RENEGOTIATION_INFO, RenegotiationInfoSpec.NOMINAL);
       
   265 
       
   266             // No impact on session resumption.
       
   267         }
       
   268     }
       
   269 
       
   270     /**
       
   271      * The absence processing if a "renegotiation_info" extension is
       
   272      * not present in the ClientHello handshake message.
       
   273      */
       
   274     private static final
       
   275             class CHRenegotiationInfoAbsence implements HandshakeAbsence {
       
   276         @Override
       
   277         public void absent(ConnectionContext context,
       
   278                 HandshakeMessage message) throws IOException {
       
   279             // The producing happens in server side only.
       
   280             ServerHandshakeContext shc = (ServerHandshakeContext)context;
       
   281             ClientHelloMessage clientHello = (ClientHelloMessage)message;
       
   282 
       
   283             if (!shc.conContext.isNegotiated) {
       
   284                 // initial handshaking.
       
   285                 for (int id : clientHello.cipherSuiteIds) {
       
   286                     if (id ==
       
   287                             CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV.id) {
       
   288                         if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   289                             SSLLogger.finest(
       
   290                                 "Safe renegotiation, using the SCSV signgling");
       
   291                         }
       
   292                         shc.conContext.secureRenegotiation = true;
       
   293                         return;
       
   294                     }
       
   295                 }
       
   296 
       
   297                 if (!HandshakeContext.allowLegacyHelloMessages) {
       
   298                     shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
   299                         "Failed to negotiate the use of secure renegotiation");
       
   300                 }   // otherwise, allow legacy hello message
       
   301 
       
   302                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   303                     SSLLogger.warning("Warning: No renegotiation " +
       
   304                         "indication in ClientHello, allow legacy ClientHello");
       
   305                 }
       
   306 
       
   307                 shc.conContext.secureRenegotiation = false;
       
   308             } else if (shc.conContext.secureRenegotiation) {
       
   309                 // Require secure renegotiation, terminate the connection.
       
   310                 shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
   311                         "Inconsistent secure renegotiation indication");
       
   312             } else {    // renegotiation, not secure
       
   313                 if (HandshakeContext.allowUnsafeRenegotiation) {
       
   314                     if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   315                         SSLLogger.warning("Using insecure renegotiation");
       
   316                     }
       
   317                 } else {
       
   318                     // Unsafe renegotiation should have been aborted in
       
   319                     // ealier processes.
       
   320                     if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   321                         SSLLogger.fine("Terminate insecure renegotiation");
       
   322                     }
       
   323                     shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
   324                         "Unsafe renegotiation is not allowed");
       
   325                 }
       
   326             }
       
   327         }
       
   328     }
       
   329 
       
   330     /**
       
   331      * Network data producer of a "renegotiation_info" extension in
       
   332      * the ServerHello handshake message.
       
   333      */
       
   334     private static final
       
   335             class SHRenegotiationInfoProducer implements HandshakeProducer {
       
   336         // Prevent instantiation of this class.
       
   337         private SHRenegotiationInfoProducer() {
       
   338             // blank
       
   339         }
       
   340 
       
   341         @Override
       
   342         public byte[] produce(ConnectionContext context,
       
   343                 HandshakeMessage message) throws IOException {
       
   344             // The producing happens in server side only.
       
   345             ServerHandshakeContext shc = (ServerHandshakeContext)context;
       
   346 
       
   347             // In response to "renegotiation_info" extension request only.
       
   348             RenegotiationInfoSpec requestedSpec = (RenegotiationInfoSpec)
       
   349                     shc.handshakeExtensions.get(CH_RENEGOTIATION_INFO);
       
   350             if (requestedSpec == null && !shc.conContext.secureRenegotiation) {
       
   351                 // Ignore, no renegotiation_info extension or SCSV signgling
       
   352                 // requested.
       
   353                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   354                     SSLLogger.finest(
       
   355                         "Ignore unavailable renegotiation_info extension");
       
   356                 }
       
   357                 return null;        // ignore the extension
       
   358             }
       
   359 
       
   360             if (!shc.conContext.secureRenegotiation) {
       
   361                 // Ignore, no secure renegotiation is negotiated.
       
   362                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   363                     SSLLogger.finest(
       
   364                         "No secure renegotiation has been negotiated");
       
   365                 }
       
   366                 return null;        // ignore the extension
       
   367             }
       
   368 
       
   369             if (!shc.conContext.isNegotiated) {
       
   370                 // initial handshaking.
       
   371                 //
       
   372                 // If this is the initial handshake for a connection, then the
       
   373                 // "renegotiated_connection" field is of zero length in both
       
   374                 // the ClientHello and the ServerHello. [RFC 5746]
       
   375                 byte[] extData = new byte[] { 0x00 };
       
   376 
       
   377                 // The conContext.client/serverVerifyData will be used for
       
   378                 // further processing, so it does not matter to save whatever
       
   379                 // in the RenegotiationInfoSpec object.
       
   380                 shc.handshakeExtensions.put(
       
   381                         SH_RENEGOTIATION_INFO, RenegotiationInfoSpec.NOMINAL);
       
   382 
       
   383                 return extData;
       
   384             } else {
       
   385                 // secure renegotiation
       
   386                 //
       
   387                 // For secure renegotiation, the server MUST include a
       
   388                 // "renegotiation_info" extension containing the saved
       
   389                 // client_verify_data and server_verify_data in the ServerHello.
       
   390                 int infoLen = shc.conContext.clientVerifyData.length +
       
   391                               shc.conContext.serverVerifyData.length;
       
   392                 byte[] extData = new byte[infoLen + 1];
       
   393                 ByteBuffer m = ByteBuffer.wrap(extData);
       
   394                 Record.putInt8(m, infoLen);
       
   395                 m.put(shc.conContext.clientVerifyData);
       
   396                 m.put(shc.conContext.serverVerifyData);
       
   397 
       
   398                 // The conContext.client/serverVerifyData will be used for
       
   399                 // further processing, so it does not matter to save whatever
       
   400                 // in the RenegotiationInfoSpec object.
       
   401                 shc.handshakeExtensions.put(
       
   402                         SH_RENEGOTIATION_INFO, RenegotiationInfoSpec.NOMINAL);
       
   403 
       
   404                 return extData;
       
   405             }
       
   406         }
       
   407     }
       
   408 
       
   409     /**
       
   410      * Network data consumer of a "renegotiation_info" extension in
       
   411      * the ServerHello handshake message.
       
   412      */
       
   413     private static final
       
   414             class SHRenegotiationInfoConsumer implements ExtensionConsumer {
       
   415         // Prevent instantiation of this class.
       
   416         private SHRenegotiationInfoConsumer() {
       
   417             // blank
       
   418         }
       
   419 
       
   420         @Override
       
   421         public void consume(ConnectionContext context,
       
   422             HandshakeMessage message, ByteBuffer buffer) throws IOException {
       
   423             // The producing happens in client side only.
       
   424             ClientHandshakeContext chc = (ClientHandshakeContext)context;
       
   425 
       
   426             // In response to the client renegotiation_info extension request
       
   427             // or SCSV signling, which is mandatory for ClientHello message.
       
   428             RenegotiationInfoSpec requestedSpec = (RenegotiationInfoSpec)
       
   429                     chc.handshakeExtensions.get(CH_RENEGOTIATION_INFO);
       
   430             if (requestedSpec == null &&
       
   431                     !chc.activeCipherSuites.contains(
       
   432                             CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)) {
       
   433                 chc.conContext.fatal(Alert.INTERNAL_ERROR,
       
   434                     "Missing renegotiation_info and SCSV detected in " +
       
   435                     "ClientHello");
       
   436             }
       
   437 
       
   438             // Parse the extension.
       
   439             RenegotiationInfoSpec spec;
       
   440             try {
       
   441                 spec = new RenegotiationInfoSpec(buffer);
       
   442             } catch (IOException ioe) {
       
   443                 chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe);
       
   444                 return;     // fatal() always throws, make the compiler happy.
       
   445             }
       
   446 
       
   447 
       
   448             if (!chc.conContext.isNegotiated) {     // initial handshake
       
   449                 // If the extension is present, set the secure_renegotiation
       
   450                 // flag to TRUE.  The client MUST then verify that the
       
   451                 // length of the "renegotiated_connection" field is zero,
       
   452                 // and if it is not, MUST abort the handshake (by sending
       
   453                 // a fatal handshake_failure alert). [RFC 5746]
       
   454                 if (spec.renegotiatedConnection.length != 0) {
       
   455                     chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
   456                         "Invalid renegotiation_info in ServerHello: " +
       
   457                         "not empty renegotiated_connection");
       
   458                 }
       
   459 
       
   460                 chc.conContext.secureRenegotiation = true;
       
   461             } else {        // renegotiation
       
   462                 // The client MUST then verify that the first half of the
       
   463                 // "renegotiated_connection" field is equal to the saved
       
   464                 // client_verify_data value, and the second half is equal to the
       
   465                 // saved server_verify_data value.  If they are not, the client
       
   466                 // MUST abort the handshake. [RFC 5746]
       
   467                 int infoLen = chc.conContext.clientVerifyData.length +
       
   468                               chc.conContext.serverVerifyData.length;
       
   469                 if (spec.renegotiatedConnection.length != infoLen) {
       
   470                     chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
   471                         "Invalid renegotiation_info in ServerHello: " +
       
   472                         "invalid renegotiated_connection length (" +
       
   473                         spec.renegotiatedConnection.length + ")");
       
   474                 }
       
   475 
       
   476                 byte[] cvd = chc.conContext.clientVerifyData;
       
   477                 if (!Arrays.equals(spec.renegotiatedConnection,
       
   478                         0, cvd.length, cvd, 0, cvd.length)) {
       
   479                     chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
   480                         "Invalid renegotiation_info in ServerHello: " +
       
   481                         "unmatched client_verify_data value");
       
   482                 }
       
   483                 byte[] svd = chc.conContext.serverVerifyData;
       
   484                 if (!Arrays.equals(spec.renegotiatedConnection,
       
   485                         cvd.length, infoLen, svd, 0, svd.length)) {
       
   486                     chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
   487                         "Invalid renegotiation_info in ServerHello: " +
       
   488                         "unmatched server_verify_data value");
       
   489                 }
       
   490             }
       
   491 
       
   492             // Update the context.
       
   493             chc.handshakeExtensions.put(
       
   494                     SH_RENEGOTIATION_INFO, RenegotiationInfoSpec.NOMINAL);
       
   495 
       
   496             // No impact on session resumption.
       
   497         }
       
   498     }
       
   499 
       
   500     /**
       
   501      * The absence processing if a "renegotiation_info" extension is
       
   502      * not present in the ServerHello handshake message.
       
   503      */
       
   504     private static final
       
   505             class SHRenegotiationInfoAbsence implements HandshakeAbsence {
       
   506         @Override
       
   507         public void absent(ConnectionContext context,
       
   508                 HandshakeMessage message) throws IOException {
       
   509             // The producing happens in client side only.
       
   510             ClientHandshakeContext chc = (ClientHandshakeContext)context;
       
   511 
       
   512             // In response to the client renegotiation_info extension request
       
   513             // or SCSV signling, which is mandatory for ClientHello message.
       
   514             RenegotiationInfoSpec requestedSpec = (RenegotiationInfoSpec)
       
   515                     chc.handshakeExtensions.get(CH_RENEGOTIATION_INFO);
       
   516             if (requestedSpec == null &&
       
   517                     !chc.activeCipherSuites.contains(
       
   518                             CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)) {
       
   519                 chc.conContext.fatal(Alert.INTERNAL_ERROR,
       
   520                     "Missing renegotiation_info and SCSV detected in " +
       
   521                     "ClientHello");
       
   522             }
       
   523 
       
   524             if (!chc.conContext.isNegotiated) {
       
   525                 // initial handshaking.
       
   526                 if (!HandshakeContext.allowLegacyHelloMessages) {
       
   527                     chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
   528                         "Failed to negotiate the use of secure renegotiation");
       
   529                 }   // otherwise, allow legacy hello message
       
   530 
       
   531                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   532                     SSLLogger.warning("Warning: No renegotiation " +
       
   533                         "indication in ServerHello, allow legacy ServerHello");
       
   534                 }
       
   535 
       
   536                 chc.conContext.secureRenegotiation = false;
       
   537             } else if (chc.conContext.secureRenegotiation) {
       
   538                 // Require secure renegotiation, terminate the connection.
       
   539                 chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
   540                         "Inconsistent secure renegotiation indication");
       
   541             } else {    // renegotiation, not secure
       
   542                 if (HandshakeContext.allowUnsafeRenegotiation) {
       
   543                     if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   544                         SSLLogger.warning("Using insecure renegotiation");
       
   545                     }
       
   546                 } else {
       
   547                     // Unsafe renegotiation should have been aborted in
       
   548                     // ealier processes.
       
   549                     if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   550                         SSLLogger.fine("Terminate insecure renegotiation");
       
   551                     }
       
   552                     chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
   553                         "Unsafe renegotiation is not allowed");
       
   554                 }
       
   555             }
       
   556         }
       
   557     }
       
   558 }