1 /* 2 * Copyright (c) 2017, Red Hat, Inc. and/or its affiliates. 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 javax.net.ssl.SSLProtocolException; 30 31 /** 32 * Extended Master Secret TLS extension (TLS 1.0+). This extension 33 * defines how to calculate the TLS connection master secret and 34 * mitigates some types of man-in-the-middle attacks. 35 * 36 * See further information in 37 * <a href="https://tools.ietf.org/html/rfc7627">RFC 7627</a>. 38 * 39 * @author Martin Balao (mbalao@redhat.com) 40 */ 41 final class ExtendedMasterSecretExtension extends HelloExtension { 42 ExtendedMasterSecretExtension() { 43 super(ExtensionType.EXT_EXTENDED_MASTER_SECRET); 44 } 45 46 ExtendedMasterSecretExtension(HandshakeInStream s, 47 int len) throws IOException { 48 super(ExtensionType.EXT_EXTENDED_MASTER_SECRET); 49 50 if (len != 0) { 51 throw new SSLProtocolException("Invalid " + type + " extension"); 52 } 53 } 54 55 @Override 56 int length() { 57 return 4; // 4: extension type and length fields 58 } 59 60 @Override 61 void send(HandshakeOutStream s) throws IOException { 62 s.putInt16(type.id); // ExtensionType extension_type; 63 s.putInt16(0); // extension_data length 64 } 65 66 @Override 67 public String toString() { 68 return "Extension " + type; 69 } 70 } 71 | 1 /* 2 * Copyright (c) 2017, 2018, Red Hat, Inc. and/or its affiliates. 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 javax.net.ssl.SSLProtocolException; 31 import static sun.security.ssl.SSLConfiguration.allowLegacyMasterSecret; 32 import static sun.security.ssl.SSLConfiguration.allowLegacyResumption; 33 import static sun.security.ssl.SSLExtension.CH_EXTENDED_MASTER_SECRET; 34 import sun.security.ssl.SSLExtension.ExtensionConsumer; 35 import static sun.security.ssl.SSLExtension.SH_EXTENDED_MASTER_SECRET; 36 import sun.security.ssl.SSLExtension.SSLExtensionSpec; 37 import sun.security.ssl.SSLHandshake.HandshakeMessage; 38 39 /** 40 * Pack of the "extended_master_secret" extensions [RFC 5746]. 41 */ 42 final class ExtendedMasterSecretExtension { 43 static final HandshakeProducer chNetworkProducer = 44 new CHExtendedMasterSecretProducer(); 45 static final ExtensionConsumer chOnLoadConcumer = 46 new CHExtendedMasterSecretConsumer(); 47 static final HandshakeAbsence chOnLoadAbsence = 48 new CHExtendedMasterSecretAbsence(); 49 50 static final HandshakeProducer shNetworkProducer = 51 new SHExtendedMasterSecretProducer(); 52 static final ExtensionConsumer shOnLoadConcumer = 53 new SHExtendedMasterSecretConsumer(); 54 static final HandshakeAbsence shOnLoadAbsence = 55 new SHExtendedMasterSecretAbsence(); 56 57 static final SSLStringize emsStringize = 58 new ExtendedMasterSecretStringize(); 59 60 /** 61 * The "extended_master_secret" extension. 62 */ 63 static final class ExtendedMasterSecretSpec implements SSLExtensionSpec { 64 // A nominal object that does not holding any real renegotiation info. 65 static final ExtendedMasterSecretSpec NOMINAL = 66 new ExtendedMasterSecretSpec(); 67 68 private ExtendedMasterSecretSpec() { 69 // blank 70 } 71 72 private ExtendedMasterSecretSpec(ByteBuffer m) throws IOException { 73 // Parse the extension. 74 if (m.hasRemaining()) { 75 throw new SSLProtocolException( 76 "Invalid extended_master_secret extension data: " + 77 "not empty"); 78 } 79 } 80 81 @Override 82 public String toString() { 83 return "<empty>"; 84 } 85 } 86 87 private static final 88 class ExtendedMasterSecretStringize implements SSLStringize { 89 @Override 90 public String toString(ByteBuffer buffer) { 91 try { 92 return (new ExtendedMasterSecretSpec(buffer)).toString(); 93 } catch (IOException ioe) { 94 // For debug logging only, so please swallow exceptions. 95 return ioe.getMessage(); 96 } 97 } 98 } 99 100 /** 101 * Network data producer of a "extended_master_secret" extension in 102 * the ClientHello handshake message. 103 */ 104 private static final 105 class CHExtendedMasterSecretProducer implements HandshakeProducer { 106 // Prevent instantiation of this class. 107 private CHExtendedMasterSecretProducer() { 108 // blank 109 } 110 111 @Override 112 public byte[] produce(ConnectionContext context, 113 HandshakeMessage message) throws IOException { 114 // The producing happens in client side only. 115 ClientHandshakeContext chc = (ClientHandshakeContext)context; 116 117 // Is it a supported and enabled extension? 118 if (!chc.sslConfig.isAvailable(CH_EXTENDED_MASTER_SECRET)) { 119 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 120 SSLLogger.fine( 121 "Ignore unavailable extended_master_secret extension"); 122 } 123 124 return null; 125 } 126 127 if (chc.handshakeSession == null || 128 chc.handshakeSession.useExtendedMasterSecret) { 129 byte[] extData = new byte[0]; 130 chc.handshakeExtensions.put(CH_EXTENDED_MASTER_SECRET, 131 ExtendedMasterSecretSpec.NOMINAL); 132 133 return extData; 134 } 135 136 return null; 137 } 138 } 139 140 /** 141 * Network data producer of a "extended_master_secret" extension in 142 * the ServerHello handshake message. 143 */ 144 private static final 145 class CHExtendedMasterSecretConsumer implements ExtensionConsumer { 146 // Prevent instantiation of this class. 147 private CHExtendedMasterSecretConsumer() { 148 // blank 149 } 150 151 @Override 152 public void consume(ConnectionContext context, 153 HandshakeMessage message, ByteBuffer buffer) throws IOException { 154 155 // The comsuming happens in server side only. 156 ServerHandshakeContext shc = (ServerHandshakeContext)context; 157 158 // Is it a supported and enabled extension? 159 if (!shc.sslConfig.isAvailable(CH_EXTENDED_MASTER_SECRET)) { 160 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 161 SSLLogger.fine("Ignore unavailable extension: " + 162 CH_EXTENDED_MASTER_SECRET.name); 163 } 164 return; // ignore the extension 165 } 166 167 // Parse the extension. 168 ExtendedMasterSecretSpec spec; 169 try { 170 spec = new ExtendedMasterSecretSpec(buffer); 171 } catch (IOException ioe) { 172 shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe); 173 return; // fatal() always throws, make the compiler happy. 174 } 175 176 if (shc.isResumption && shc.resumingSession != null && 177 !shc.resumingSession.useExtendedMasterSecret) { 178 // For abbreviated handshake request, If the original 179 // session did not use the "extended_master_secret" 180 // extension but the new ClientHello contains the 181 // extension, then the server MUST NOT perform the 182 // abbreviated handshake. Instead, it SHOULD continue 183 // with a full handshake. 184 shc.isResumption = false; 185 shc.resumingSession = null; 186 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 187 SSLLogger.fine( 188 "abort session resumption which did not use " + 189 "Extended Master Secret extension"); 190 } 191 } 192 193 // Update the context. 194 // 195 shc.handshakeExtensions.put( 196 CH_EXTENDED_MASTER_SECRET, ExtendedMasterSecretSpec.NOMINAL); 197 198 // No impact on session resumption. 199 } 200 } 201 202 /** 203 * The absence processing if a "extended_master_secret" extension is 204 * not present in the ClientHello handshake message. 205 */ 206 private static final 207 class CHExtendedMasterSecretAbsence implements HandshakeAbsence { 208 @Override 209 public void absent(ConnectionContext context, 210 HandshakeMessage message) throws IOException { 211 // The producing happens in server side only. 212 ServerHandshakeContext shc = (ServerHandshakeContext)context; 213 214 // Is it a supported and enabled extension? 215 if (!shc.sslConfig.isAvailable(CH_EXTENDED_MASTER_SECRET)) { 216 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 217 SSLLogger.fine("Ignore unavailable extension: " + 218 CH_EXTENDED_MASTER_SECRET.name); 219 } 220 return; // ignore the extension 221 } 222 223 if (!allowLegacyMasterSecret) { 224 // For full handshake, if the server receives a ClientHello 225 // without the extension, it SHOULD abort the handshake if 226 // it does not wish to interoperate with legacy clients. 227 // 228 // As if extended master extension is required for full 229 // handshake, it MUST be used in abbreviated handshake too. 230 shc.conContext.fatal(Alert.HANDSHAKE_FAILURE, 231 "Extended Master Secret extension is required"); 232 } 233 234 if (shc.isResumption && shc.resumingSession != null) { 235 if (shc.resumingSession.useExtendedMasterSecret) { 236 // For abbreviated handshake request, if the original 237 // session used the "extended_master_secret" extension 238 // but the new ClientHello does not contain it, the 239 // server MUST abort the abbreviated handshake. 240 shc.conContext.fatal(Alert.HANDSHAKE_FAILURE, 241 "Missing Extended Master Secret extension " + 242 "on session resumption"); 243 } else { 244 // For abbreviated handshake request, if neither the 245 // original session nor the new ClientHello uses the 246 // extension, the server SHOULD abort the handshake. 247 if (!allowLegacyResumption) { 248 shc.conContext.fatal(Alert.HANDSHAKE_FAILURE, 249 "Missing Extended Master Secret extension " + 250 "on session resumption"); 251 } else { // Otherwise, continue with a full handshake. 252 shc.isResumption = false; 253 shc.resumingSession = null; 254 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 255 SSLLogger.fine( 256 "abort session resumption, " + 257 "missing Extended Master Secret extension"); 258 } 259 } 260 } 261 } 262 } 263 } 264 265 /** 266 * Network data producer of a "extended_master_secret" extension in 267 * the ServerHello handshake message. 268 */ 269 private static final 270 class SHExtendedMasterSecretProducer implements HandshakeProducer { 271 // Prevent instantiation of this class. 272 private SHExtendedMasterSecretProducer() { 273 // blank 274 } 275 276 @Override 277 public byte[] produce(ConnectionContext context, 278 HandshakeMessage message) throws IOException { 279 // The producing happens in server side only. 280 ServerHandshakeContext shc = (ServerHandshakeContext)context; 281 282 if (shc.handshakeSession.useExtendedMasterSecret) { 283 byte[] extData = new byte[0]; 284 shc.handshakeExtensions.put(SH_EXTENDED_MASTER_SECRET, 285 ExtendedMasterSecretSpec.NOMINAL); 286 287 return extData; 288 } 289 290 return null; 291 } 292 } 293 294 /** 295 * Network data consumer of a "extended_master_secret" extension in 296 * the ServerHello handshake message. 297 */ 298 private static final 299 class SHExtendedMasterSecretConsumer implements ExtensionConsumer { 300 // Prevent instantiation of this class. 301 private SHExtendedMasterSecretConsumer() { 302 // blank 303 } 304 305 @Override 306 public void consume(ConnectionContext context, 307 HandshakeMessage message, ByteBuffer buffer) throws IOException { 308 // The producing happens in client side only. 309 ClientHandshakeContext chc = (ClientHandshakeContext)context; 310 311 // In response to the client extended_master_secret extension 312 // request, which is mandatory for ClientHello message. 313 ExtendedMasterSecretSpec requstedSpec = (ExtendedMasterSecretSpec) 314 chc.handshakeExtensions.get(CH_EXTENDED_MASTER_SECRET); 315 if (requstedSpec == null) { 316 chc.conContext.fatal(Alert.UNSUPPORTED_EXTENSION, 317 "Server sent the extended_master_secret " + 318 "extension improperly"); 319 } 320 321 // Parse the extension. 322 ExtendedMasterSecretSpec spec; 323 try { 324 spec = new ExtendedMasterSecretSpec(buffer); 325 } catch (IOException ioe) { 326 chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe); 327 return; // fatal() always throws, make the compiler happy. 328 } 329 330 if (chc.isResumption && chc.resumingSession != null && 331 !chc.resumingSession.useExtendedMasterSecret) { 332 chc.conContext.fatal(Alert.UNSUPPORTED_EXTENSION, 333 "Server sent an unexpected extended_master_secret " + 334 "extension on session resumption"); 335 } 336 337 // Update the context. 338 chc.handshakeExtensions.put( 339 SH_EXTENDED_MASTER_SECRET, ExtendedMasterSecretSpec.NOMINAL); 340 341 // No impact on session resumption. 342 } 343 } 344 345 /** 346 * The absence processing if a "extended_master_secret" extension is 347 * not present in the ServerHello handshake message. 348 */ 349 private static final 350 class SHExtendedMasterSecretAbsence implements HandshakeAbsence { 351 @Override 352 public void absent(ConnectionContext context, 353 HandshakeMessage message) throws IOException { 354 // The producing happens in client side only. 355 ClientHandshakeContext chc = (ClientHandshakeContext)context; 356 357 if (SSLConfiguration.useExtendedMasterSecret 358 && !SSLConfiguration.allowLegacyMasterSecret) { 359 // For full handshake, if a client receives a ServerHello 360 // without the extension, it SHOULD abort the handshake if 361 // it does not wish to interoperate with legacy servers. 362 chc.conContext.fatal(Alert.HANDSHAKE_FAILURE, 363 "Extended Master Secret extension is required"); 364 } 365 366 if (chc.isResumption && chc.resumingSession != null) { 367 if (chc.resumingSession.useExtendedMasterSecret) { 368 // For abbreviated handshake, if the original session used 369 // the "extended_master_secret" extension but the new 370 // ServerHello does not contain the extension, the client 371 // MUST abort the handshake. 372 chc.conContext.fatal(Alert.HANDSHAKE_FAILURE, 373 "Missing Extended Master Secret extension " + 374 "on session resumption"); 375 } else if (SSLConfiguration.useExtendedMasterSecret && 376 !SSLConfiguration.allowLegacyResumption) { 377 // Unlikely, abbreviated handshake should be discarded. 378 chc.conContext.fatal(Alert.HANDSHAKE_FAILURE, 379 "Extended Master Secret extension is required"); 380 } 381 } 382 } 383 } 384 } 385 |