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 javax.net.ssl.SSLProtocolException; 31 import static sun.security.ssl.SSLExtension.CH_MAX_FRAGMENT_LENGTH; 32 import static sun.security.ssl.SSLExtension.EE_MAX_FRAGMENT_LENGTH; 33 import sun.security.ssl.SSLExtension.ExtensionConsumer; 34 import static sun.security.ssl.SSLExtension.SH_MAX_FRAGMENT_LENGTH; 35 import sun.security.ssl.SSLExtension.SSLExtensionSpec; 36 import sun.security.ssl.SSLHandshake.HandshakeMessage; 37 38 /** 39 * Pack of the "max_fragment_length" extensions [RFC6066]. 40 */ 41 final class MaxFragExtension { 42 static final HandshakeProducer chNetworkProducer = 43 new CHMaxFragmentLengthProducer(); 44 static final ExtensionConsumer chOnLoadConcumer = 45 new CHMaxFragmentLengthConsumer(); 46 47 static final HandshakeProducer shNetworkProducer = 48 new SHMaxFragmentLengthProducer(); 49 static final ExtensionConsumer shOnLoadConcumer = 50 new SHMaxFragmentLengthConsumer(); 51 static final HandshakeConsumer shOnTradeConsumer = 52 new SHMaxFragmentLengthUpdate(); 53 54 static final HandshakeProducer eeNetworkProducer = 55 new EEMaxFragmentLengthProducer(); 56 static final ExtensionConsumer eeOnLoadConcumer = 57 new EEMaxFragmentLengthConsumer(); 58 static final HandshakeConsumer eeOnTradeConsumer = 59 new EEMaxFragmentLengthUpdate(); 60 61 static final SSLStringize maxFragLenStringize = 62 new MaxFragLenStringize(); 63 64 /** 65 * The "max_fragment_length" extension [RFC 6066]. 66 */ 67 static final class MaxFragLenSpec implements SSLExtensionSpec { 68 byte id; 69 70 private MaxFragLenSpec(byte id) { 71 this.id = id; 72 } 73 74 private MaxFragLenSpec(ByteBuffer buffer) throws IOException { 75 if (buffer.remaining() != 1) { 76 throw new SSLProtocolException( 77 "Invalid max_fragment_length extension data"); 78 } 79 80 this.id = buffer.get(); 81 } 82 83 @Override 84 public String toString() { 85 return MaxFragLenEnum.nameOf(id); 86 } 87 } 88 89 private static final class MaxFragLenStringize implements SSLStringize { 90 @Override 91 public String toString(ByteBuffer buffer) { 92 try { 93 return (new MaxFragLenSpec(buffer)).toString(); 94 } catch (IOException ioe) { 95 // For debug logging only, so please swallow exceptions. 96 return ioe.getMessage(); 97 } 98 } 99 } 100 101 static enum MaxFragLenEnum { 102 MFL_512 ((byte)0x01, 512, "2^9"), 103 MFL_1024 ((byte)0x02, 1024, "2^10"), 104 MFL_2048 ((byte)0x03, 2048, "2^11"), 105 MFL_4096 ((byte)0x04, 4096, "2^12"); 106 107 final byte id; 108 final int fragmentSize; 109 final String description; 110 111 private MaxFragLenEnum(byte id, int fragmentSize, String description) { 112 this.id = id; 113 this.fragmentSize = fragmentSize; 114 this.description = description; 115 } 116 117 private static MaxFragLenEnum valueOf(byte id) { 118 for (MaxFragLenEnum mfl : MaxFragLenEnum.values()) { 119 if (mfl.id == id) { 120 return mfl; 121 } 122 } 123 124 return null; 125 } 126 127 private static String nameOf(byte id) { 128 for (MaxFragLenEnum mfl : MaxFragLenEnum.values()) { 129 if (mfl.id == id) { 130 return mfl.description; 131 } 132 } 133 134 return "UNDEFINED-MAX-FRAGMENT-LENGTH(" + id + ")"; 135 } 136 137 /** 138 * Returns the best match enum constant of the specified 139 * fragment size. 140 */ 141 static MaxFragLenEnum valueOf(int fragmentSize) { 142 if (fragmentSize <= 0) { 143 return null; 144 } else if (fragmentSize < 1024) { 145 return MFL_512; 146 } else if (fragmentSize < 2048) { 147 return MFL_1024; 148 } else if (fragmentSize < 4096) { 149 return MFL_2048; 150 } else if (fragmentSize == 4096) { 151 return MFL_4096; 152 } 153 154 return null; 155 } 156 } 157 158 /** 159 * Network data producer of a "max_fragment_length" extension in 160 * the ClientHello handshake message. 161 */ 162 private static final 163 class CHMaxFragmentLengthProducer implements HandshakeProducer { 164 // Prevent instantiation of this class. 165 private CHMaxFragmentLengthProducer() { 166 // blank 167 } 168 169 @Override 170 public byte[] produce(ConnectionContext context, 171 HandshakeMessage message) throws IOException { 172 // The producing happens in client side only. 173 ClientHandshakeContext chc = (ClientHandshakeContext)context; 174 175 // Is it a supported and enabled extension? 176 if (!chc.sslConfig.isAvailable(CH_MAX_FRAGMENT_LENGTH)) { 177 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 178 SSLLogger.fine( 179 "Ignore unavailable max_fragment_length extension"); 180 } 181 return null; 182 } 183 184 // Produce the extension and update the context. 185 int requestedMFLength; 186 if (chc.isResumption && (chc.resumingSession != null)) { 187 // The same extension should be sent for resumption. 188 requestedMFLength = 189 chc.resumingSession.getNegotiatedMaxFragSize(); 190 } else if (chc.sslConfig.maximumPacketSize != 0) { 191 // Maybe we can calculate the fragment size more accurate 192 // by condering the enabled cipher suites in the future. 193 requestedMFLength = chc.sslConfig.maximumPacketSize; 194 if (chc.sslContext.isDTLS()) { 195 requestedMFLength -= DTLSRecord.maxPlaintextPlusSize; 196 } else { 197 requestedMFLength -= SSLRecord.maxPlaintextPlusSize; 198 } 199 } else { 200 // Need no max_fragment_length extension. 201 requestedMFLength = -1; 202 } 203 204 MaxFragLenEnum mfl = MaxFragLenEnum.valueOf(requestedMFLength); 205 if (mfl != null) { 206 // update the context. 207 chc.handshakeExtensions.put( 208 CH_MAX_FRAGMENT_LENGTH, new MaxFragLenSpec(mfl.id)); 209 210 return new byte[] { mfl.id }; 211 } else { 212 // log and ignore, no MFL extension. 213 chc.maxFragmentLength = -1; 214 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 215 SSLLogger.fine( 216 "No available max_fragment_length extension can " + 217 "be used for fragment size of " + 218 requestedMFLength + "bytes"); 219 } 220 } 221 222 return null; 223 } 224 } 225 226 /** 227 * Network data consumer of a "max_fragment_length" extension in 228 * the ClientHello handshake message. 229 */ 230 private static final 231 class CHMaxFragmentLengthConsumer implements ExtensionConsumer { 232 // Prevent instantiation of this class. 233 private CHMaxFragmentLengthConsumer() { 234 // blank 235 } 236 237 @Override 238 public void consume(ConnectionContext context, 239 HandshakeMessage message, ByteBuffer buffer) throws IOException { 240 // The comsuming happens in server side only. 241 ServerHandshakeContext shc = (ServerHandshakeContext)context; 242 243 if (!shc.sslConfig.isAvailable(CH_MAX_FRAGMENT_LENGTH)) { 244 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 245 SSLLogger.fine( 246 "Ignore unavailable max_fragment_length extension"); 247 } 248 return; // ignore the extension 249 } 250 251 // Parse the extension. 252 MaxFragLenSpec spec; 253 try { 254 spec = new MaxFragLenSpec(buffer); 255 } catch (IOException ioe) { 256 shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe); 257 return; // fatal() always throws, make the compiler happy. 258 } 259 260 MaxFragLenEnum mfle = MaxFragLenEnum.valueOf(spec.id); 261 if (mfle == null) { 262 shc.conContext.fatal(Alert.ILLEGAL_PARAMETER, 263 "the requested maximum fragment length is other " + 264 "than the allowed values"); 265 } 266 267 // Update the context. 268 shc.maxFragmentLength = mfle.fragmentSize; 269 shc.handshakeExtensions.put(CH_MAX_FRAGMENT_LENGTH, spec); 270 271 // No impact on session resumption. 272 } 273 } 274 275 /** 276 * Network data producer of a "max_fragment_length" extension in 277 * the ServerHello handshake message. 278 */ 279 private static final 280 class SHMaxFragmentLengthProducer implements HandshakeProducer { 281 // Prevent instantiation of this class. 282 private SHMaxFragmentLengthProducer() { 283 // blank 284 } 285 286 @Override 287 public byte[] produce(ConnectionContext context, 288 HandshakeMessage message) throws IOException { 289 // The producing happens in server side only. 290 ServerHandshakeContext shc = (ServerHandshakeContext)context; 291 292 // In response to "max_fragment_length" extension request only 293 MaxFragLenSpec spec = (MaxFragLenSpec) 294 shc.handshakeExtensions.get(CH_MAX_FRAGMENT_LENGTH); 295 if (spec == null) { 296 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 297 SSLLogger.finest( 298 "Ignore unavailable max_fragment_length extension"); 299 } 300 return null; // ignore the extension 301 } 302 303 if ((shc.maxFragmentLength > 0) && 304 (shc.sslConfig.maximumPacketSize != 0)) { 305 int estimatedMaxFragSize = 306 shc.negotiatedCipherSuite.calculatePacketSize( 307 shc.maxFragmentLength, shc.negotiatedProtocol, 308 shc.sslContext.isDTLS()); 309 if (estimatedMaxFragSize > shc.sslConfig.maximumPacketSize) { 310 // For better interoperability, abort the maximum 311 // fragment length negotiation, rather than terminate 312 // the connection with a fatal alert. 313 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 314 SSLLogger.fine( 315 "Abort the maximum fragment length negotiation, " + 316 "may overflow the maximum packet size limit."); 317 } 318 shc.maxFragmentLength = -1; 319 } 320 } 321 322 // update the context 323 if (shc.maxFragmentLength > 0) { 324 shc.handshakeSession.setNegotiatedMaxFragSize( 325 shc.maxFragmentLength); 326 shc.conContext.inputRecord.changeFragmentSize( 327 shc.maxFragmentLength); 328 shc.conContext.outputRecord.changeFragmentSize( 329 shc.maxFragmentLength); 330 331 // The response extension data is the same as the requested one. 332 shc.handshakeExtensions.put(SH_MAX_FRAGMENT_LENGTH, spec); 333 return new byte[] { spec.id }; 334 } 335 336 return null; 337 } 338 } 339 340 /** 341 * Network data consumer of a "max_fragment_length" extension in 342 * the ServerHello handshake message. 343 */ 344 private static final 345 class SHMaxFragmentLengthConsumer implements ExtensionConsumer { 346 // Prevent instantiation of this class. 347 private SHMaxFragmentLengthConsumer() { 348 // blank 349 } 350 351 @Override 352 public void consume(ConnectionContext context, 353 HandshakeMessage message, ByteBuffer buffer) throws IOException { 354 355 // The comsuming happens in client side only. 356 ClientHandshakeContext chc = (ClientHandshakeContext)context; 357 358 // In response to "max_fragment_length" extension request only 359 MaxFragLenSpec requestedSpec = (MaxFragLenSpec) 360 chc.handshakeExtensions.get(CH_MAX_FRAGMENT_LENGTH); 361 if (requestedSpec == null) { 362 chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, 363 "Unexpected max_fragment_length extension in ServerHello"); 364 } 365 366 // Parse the extension. 367 MaxFragLenSpec spec; 368 try { 369 spec = new MaxFragLenSpec(buffer); 370 } catch (IOException ioe) { 371 chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe); 372 return; // fatal() always throws, make the compiler happy. 373 } 374 375 if (spec.id != requestedSpec.id) { 376 chc.conContext.fatal(Alert.ILLEGAL_PARAMETER, 377 "The maximum fragment length response is not requested"); 378 } 379 380 MaxFragLenEnum mfle = MaxFragLenEnum.valueOf(spec.id); 381 if (mfle == null) { 382 chc.conContext.fatal(Alert.ILLEGAL_PARAMETER, 383 "the requested maximum fragment length is other " + 384 "than the allowed values"); 385 } 386 387 // update the context 388 chc.maxFragmentLength = mfle.fragmentSize; 389 chc.handshakeExtensions.put(SH_MAX_FRAGMENT_LENGTH, spec); 390 } 391 } 392 393 /** 394 * After session creation consuming of a "max_fragment_length" 395 * extension in the ClientHello handshake message. 396 */ 397 private static final class SHMaxFragmentLengthUpdate 398 implements HandshakeConsumer { 399 400 // Prevent instantiation of this class. 401 private SHMaxFragmentLengthUpdate() { 402 // blank 403 } 404 405 @Override 406 public void consume(ConnectionContext context, 407 HandshakeMessage message) throws IOException { 408 // The comsuming happens in client side only. 409 ClientHandshakeContext chc = (ClientHandshakeContext)context; 410 411 MaxFragLenSpec spec = (MaxFragLenSpec) 412 chc.handshakeExtensions.get(SH_MAX_FRAGMENT_LENGTH); 413 if (spec == null) { 414 // Ignore, no "max_fragment_length" extension response. 415 return; 416 } 417 418 if ((chc.maxFragmentLength > 0) && 419 (chc.sslConfig.maximumPacketSize != 0)) { 420 int estimatedMaxFragSize = 421 chc.negotiatedCipherSuite.calculatePacketSize( 422 chc.maxFragmentLength, chc.negotiatedProtocol, 423 chc.sslContext.isDTLS()); 424 if (estimatedMaxFragSize > chc.sslConfig.maximumPacketSize) { 425 // For better interoperability, abort the maximum 426 // fragment length negotiation, rather than terminate 427 // the connection with a fatal alert. 428 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 429 SSLLogger.fine( 430 "Abort the maximum fragment length negotiation, " + 431 "may overflow the maximum packet size limit."); 432 } 433 chc.maxFragmentLength = -1; 434 } 435 } 436 437 // update the context 438 if (chc.maxFragmentLength > 0) { 439 chc.handshakeSession.setNegotiatedMaxFragSize( 440 chc.maxFragmentLength); 441 chc.conContext.inputRecord.changeFragmentSize( 442 chc.maxFragmentLength); 443 chc.conContext.outputRecord.changeFragmentSize( 444 chc.maxFragmentLength); 445 } 446 } 447 } 448 449 /** 450 * Network data producer of a "max_fragment_length" extension in 451 * the EncryptedExtensions handshake message. 452 */ 453 private static final 454 class EEMaxFragmentLengthProducer implements HandshakeProducer { 455 // Prevent instantiation of this class. 456 private EEMaxFragmentLengthProducer() { 457 // blank 458 } 459 460 @Override 461 public byte[] produce(ConnectionContext context, 462 HandshakeMessage message) throws IOException { 463 // The producing happens in server side only. 464 ServerHandshakeContext shc = (ServerHandshakeContext)context; 465 466 // In response to "max_fragment_length" extension request only 467 MaxFragLenSpec spec = (MaxFragLenSpec) 468 shc.handshakeExtensions.get(CH_MAX_FRAGMENT_LENGTH); 469 if (spec == null) { 470 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 471 SSLLogger.finest( 472 "Ignore unavailable max_fragment_length extension"); 473 } 474 return null; // ignore the extension 475 } 476 477 if ((shc.maxFragmentLength > 0) && 478 (shc.sslConfig.maximumPacketSize != 0)) { 479 int estimatedMaxFragSize = 480 shc.negotiatedCipherSuite.calculatePacketSize( 481 shc.maxFragmentLength, shc.negotiatedProtocol, 482 shc.sslContext.isDTLS()); 483 if (estimatedMaxFragSize > shc.sslConfig.maximumPacketSize) { 484 // For better interoperability, abort the maximum 485 // fragment length negotiation, rather than terminate 486 // the connection with a fatal alert. 487 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 488 SSLLogger.fine( 489 "Abort the maximum fragment length negotiation, " + 490 "may overflow the maximum packet size limit."); 491 } 492 shc.maxFragmentLength = -1; 493 } 494 } 495 496 // update the context 497 if (shc.maxFragmentLength > 0) { 498 shc.handshakeSession.setNegotiatedMaxFragSize( 499 shc.maxFragmentLength); 500 shc.conContext.inputRecord.changeFragmentSize( 501 shc.maxFragmentLength); 502 shc.conContext.outputRecord.changeFragmentSize( 503 shc.maxFragmentLength); 504 505 // The response extension data is the same as the requested one. 506 shc.handshakeExtensions.put(EE_MAX_FRAGMENT_LENGTH, spec); 507 return new byte[] { spec.id }; 508 } 509 510 return null; 511 } 512 } 513 514 /** 515 * Network data consumer of a "max_fragment_length" extension in the 516 * EncryptedExtensions handshake message. 517 */ 518 private static final 519 class EEMaxFragmentLengthConsumer implements ExtensionConsumer { 520 // Prevent instantiation of this class. 521 private EEMaxFragmentLengthConsumer() { 522 // blank 523 } 524 525 @Override 526 public void consume(ConnectionContext context, 527 HandshakeMessage message, ByteBuffer buffer) throws IOException { 528 // The comsuming happens in client side only. 529 ClientHandshakeContext chc = (ClientHandshakeContext)context; 530 531 // In response to "max_fragment_length" extension request only 532 MaxFragLenSpec requestedSpec = (MaxFragLenSpec) 533 chc.handshakeExtensions.get(CH_MAX_FRAGMENT_LENGTH); 534 if (requestedSpec == null) { 535 chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, 536 "Unexpected max_fragment_length extension in ServerHello"); 537 } 538 539 // Parse the extension. 540 MaxFragLenSpec spec; 541 try { 542 spec = new MaxFragLenSpec(buffer); 543 } catch (IOException ioe) { 544 chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe); 545 return; // fatal() always throws, make the compiler happy. 546 } 547 548 if (spec.id != requestedSpec.id) { 549 chc.conContext.fatal(Alert.ILLEGAL_PARAMETER, 550 "The maximum fragment length response is not requested"); 551 } 552 553 MaxFragLenEnum mfle = MaxFragLenEnum.valueOf(spec.id); 554 if (mfle == null) { 555 chc.conContext.fatal(Alert.ILLEGAL_PARAMETER, 556 "the requested maximum fragment length is other " + 557 "than the allowed values"); 558 } 559 560 // update the context 561 chc.maxFragmentLength = mfle.fragmentSize; 562 chc.handshakeExtensions.put(EE_MAX_FRAGMENT_LENGTH, spec); 563 } 564 } 565 566 /** 567 * After session creation consuming of a "max_fragment_length" 568 * extension in the EncryptedExtensions handshake message. 569 */ 570 private static final 571 class EEMaxFragmentLengthUpdate implements HandshakeConsumer { 572 // Prevent instantiation of this class. 573 private EEMaxFragmentLengthUpdate() { 574 // blank 575 } 576 577 @Override 578 public void consume(ConnectionContext context, 579 HandshakeMessage message) throws IOException { 580 // The comsuming happens in client side only. 581 ClientHandshakeContext chc = (ClientHandshakeContext)context; 582 583 MaxFragLenSpec spec = (MaxFragLenSpec) 584 chc.handshakeExtensions.get(EE_MAX_FRAGMENT_LENGTH); 585 if (spec == null) { 586 // Ignore, no "max_fragment_length" extension response. 587 return; 588 } 589 590 if ((chc.maxFragmentLength > 0) && 591 (chc.sslConfig.maximumPacketSize != 0)) { 592 int estimatedMaxFragSize = 593 chc.negotiatedCipherSuite.calculatePacketSize( 594 chc.maxFragmentLength, chc.negotiatedProtocol, 595 chc.sslContext.isDTLS()); 596 if (estimatedMaxFragSize > chc.sslConfig.maximumPacketSize) { 597 // For better interoperability, abort the maximum 598 // fragment length negotiation, rather than terminate 599 // the connection with a fatal alert. 600 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 601 SSLLogger.fine( 602 "Abort the maximum fragment length negotiation, " + 603 "may overflow the maximum packet size limit."); 604 } 605 chc.maxFragmentLength = -1; 606 } 607 } 608 609 // update the context 610 if (chc.maxFragmentLength > 0) { 611 chc.handshakeSession.setNegotiatedMaxFragSize( 612 chc.maxFragmentLength); 613 chc.conContext.inputRecord.changeFragmentSize( 614 chc.maxFragmentLength); 615 chc.conContext.outputRecord.changeFragmentSize( 616 chc.maxFragmentLength); 617 } 618 } 619 } 620 }