< prev index next >

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

Print this page

        

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.  Oracle designates this

@@ -24,116 +24,597 @@
  */
 
 package sun.security.ssl;
 
 import java.io.IOException;
+import java.nio.ByteBuffer;
 import javax.net.ssl.SSLProtocolException;
+import static sun.security.ssl.SSLExtension.CH_MAX_FRAGMENT_LENGTH;
+import static sun.security.ssl.SSLExtension.EE_MAX_FRAGMENT_LENGTH;
+import sun.security.ssl.SSLExtension.ExtensionConsumer;
+import static sun.security.ssl.SSLExtension.SH_MAX_FRAGMENT_LENGTH;
+import sun.security.ssl.SSLExtension.SSLExtensionSpec;
+import sun.security.ssl.SSLHandshake.HandshakeMessage;
 
-/*
- * [RFC6066] TLS specifies a fixed maximum plaintext fragment length of
- * 2^14 bytes.  It may be desirable for constrained clients to negotiate
- * a smaller maximum fragment length due to memory limitations or bandwidth
- * limitations.
- *
- * In order to negotiate smaller maximum fragment lengths, clients MAY
- * include an extension of type "max_fragment_length" in the (extended)
- * client hello.  The "extension_data" field of this extension SHALL
- * contain:
- *
- *    enum{
- *        2^9(1), 2^10(2), 2^11(3), 2^12(4), (255)
- *    } MaxFragmentLength;
- *
- * whose value is the desired maximum fragment length.
+/**
+ * Pack of the "max_fragment_length" extensions [RFC6066].
  */
-final class MaxFragmentLengthExtension extends HelloExtension {
+final class MaxFragExtension {
+    static final HandshakeProducer chNetworkProducer =
+            new CHMaxFragmentLengthProducer();
+    static final ExtensionConsumer chOnLoadConcumer =
+            new CHMaxFragmentLengthConsumer();
+
+    static final HandshakeProducer shNetworkProducer =
+            new SHMaxFragmentLengthProducer();
+    static final ExtensionConsumer shOnLoadConcumer =
+            new SHMaxFragmentLengthConsumer();
+    static final HandshakeConsumer shOnTradeConsumer =
+            new SHMaxFragmentLengthUpdate();
+
+    static final HandshakeProducer eeNetworkProducer =
+            new EEMaxFragmentLengthProducer();
+    static final ExtensionConsumer eeOnLoadConcumer =
+            new EEMaxFragmentLengthConsumer();
+    static final HandshakeConsumer eeOnTradeConsumer =
+            new EEMaxFragmentLengthUpdate();
+
+    static final SSLStringize maxFragLenStringize =
+            new MaxFragLenStringize();
+
+    /**
+     * The "max_fragment_length" extension [RFC 6066].
+     */
+    static final class MaxFragLenSpec implements SSLExtensionSpec {
+        byte id;
+
+        private MaxFragLenSpec(byte id) {
+            this.id = id;
+        }
+
+        private MaxFragLenSpec(ByteBuffer buffer) throws IOException {
+            if (buffer.remaining() != 1) {
+                throw new SSLProtocolException(
+                    "Invalid max_fragment_length extension data");
+            }
+
+            this.id = buffer.get();
+        }
+
+        @Override
+        public String toString() {
+            return MaxFragLenEnum.nameOf(id);
+        }
+    }
+
+    private static final class MaxFragLenStringize implements SSLStringize {
+        @Override
+        public String toString(ByteBuffer buffer) {
+            try {
+                return (new MaxFragLenSpec(buffer)).toString();
+            } catch (IOException ioe) {
+                // For debug logging only, so please swallow exceptions.
+                return ioe.getMessage();
+            }
+        }
+    }
+
+    static enum MaxFragLenEnum {
+        MFL_512     ((byte)0x01,  512,  "2^9"),
+        MFL_1024    ((byte)0x02, 1024,  "2^10"),
+        MFL_2048    ((byte)0x03, 2048,  "2^11"),
+        MFL_4096    ((byte)0x04, 4096,  "2^12");
 
-    private static final int MAX_FRAGMENT_LENGTH_512  = 1;      // 2^9
-    private static final int MAX_FRAGMENT_LENGTH_1024 = 2;      // 2^10
-    private static final int MAX_FRAGMENT_LENGTH_2048 = 3;      // 2^11
-    private static final int MAX_FRAGMENT_LENGTH_4096 = 4;      // 2^12
+        final byte id;
+        final int fragmentSize;
+        final String description;
 
-    final int maxFragmentLength;
+        private MaxFragLenEnum(byte id, int fragmentSize, String description) {
+            this.id = id;
+            this.fragmentSize = fragmentSize;
+            this.description = description;
+        }
+
+        private static MaxFragLenEnum valueOf(byte id) {
+            for (MaxFragLenEnum mfl : MaxFragLenEnum.values()) {
+                if (mfl.id == id) {
+                    return mfl;
+                }
+            }
+
+            return null;
+        }
+
+        private static String nameOf(byte id) {
+            for (MaxFragLenEnum mfl : MaxFragLenEnum.values()) {
+                if (mfl.id == id) {
+                    return mfl.description;
+                }
+            }
 
-    MaxFragmentLengthExtension(int fragmentSize) {
-        super(ExtensionType.EXT_MAX_FRAGMENT_LENGTH);
+            return "UNDEFINED-MAX-FRAGMENT-LENGTH(" + id + ")";
+        }
 
-        if (fragmentSize < 1024) {
-            maxFragmentLength = MAX_FRAGMENT_LENGTH_512;
+        /**
+         * Returns the best match enum constant of the specified
+         * fragment size.
+         */
+        static MaxFragLenEnum valueOf(int fragmentSize) {
+            if (fragmentSize <= 0) {
+                return null;
+            } else if (fragmentSize < 1024) {
+                return MFL_512;
         } else if (fragmentSize < 2048) {
-            maxFragmentLength = MAX_FRAGMENT_LENGTH_1024;
+                return MFL_1024;
         } else if (fragmentSize < 4096) {
-            maxFragmentLength = MAX_FRAGMENT_LENGTH_2048;
+                return MFL_2048;
+            } else if (fragmentSize == 4096) {
+                return MFL_4096;
+            }
+
+            return null;
+        }
+    }
+
+    /**
+     * Network data producer of a "max_fragment_length" extension in
+     * the ClientHello handshake message.
+     */
+    private static final
+            class CHMaxFragmentLengthProducer implements HandshakeProducer {
+        // Prevent instantiation of this class.
+        private CHMaxFragmentLengthProducer() {
+            // blank
+        }
+
+        @Override
+        public byte[] produce(ConnectionContext context,
+                HandshakeMessage message) throws IOException {
+            // The producing happens in client side only.
+            ClientHandshakeContext chc = (ClientHandshakeContext)context;
+
+            // Is it a supported and enabled extension?
+            if (!chc.sslConfig.isAvailable(CH_MAX_FRAGMENT_LENGTH)) {
+                if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
+                    SSLLogger.fine(
+                        "Ignore unavailable max_fragment_length extension");
+                }
+                return null;
+            }
+
+            // Produce the extension and update the context.
+            int requestedMFLength;
+            if (chc.isResumption && (chc.resumingSession != null)) {
+                // The same extension should be sent for resumption.
+                requestedMFLength =
+                    chc.resumingSession.getNegotiatedMaxFragSize();
+            } else if (chc.sslConfig.maximumPacketSize != 0) {
+                // Maybe we can calculate the fragment size more accurate
+                // by condering the enabled cipher suites in the future.
+                requestedMFLength = chc.sslConfig.maximumPacketSize;
+                if (chc.sslContext.isDTLS()) {
+                    requestedMFLength -= DTLSRecord.maxPlaintextPlusSize;
         } else {
-            maxFragmentLength = MAX_FRAGMENT_LENGTH_4096;
+                    requestedMFLength -= SSLRecord.maxPlaintextPlusSize;
         }
+            } else {
+                // Need no max_fragment_length extension.
+                requestedMFLength = -1;
     }
 
-    MaxFragmentLengthExtension(HandshakeInStream s, int len)
-                throws IOException {
-        super(ExtensionType.EXT_MAX_FRAGMENT_LENGTH);
+            MaxFragLenEnum mfl = MaxFragLenEnum.valueOf(requestedMFLength);
+            if (mfl != null) {
+                // update the context.
+                chc.handshakeExtensions.put(
+                        CH_MAX_FRAGMENT_LENGTH, new MaxFragLenSpec(mfl.id));
 
-        // check the extension length
-        if (len != 1) {
-            throw new SSLProtocolException("Invalid " + type + " extension");
+                return new byte[] { mfl.id };
+            } else {
+                // log and ignore, no MFL extension.
+                chc.maxFragmentLength = -1;
+                if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
+                    SSLLogger.fine(
+                        "No available max_fragment_length extension can " +
+                        "be used for fragment size of " +
+                        requestedMFLength + "bytes");
+                }
         }
 
-        maxFragmentLength = s.getInt8();
-        if ((maxFragmentLength > 4) || (maxFragmentLength < 1)) {
-            throw new SSLProtocolException("Invalid " + type + " extension");
+            return null;
         }
     }
 
-    // Length of the encoded extension, including the type and length fields
+    /**
+     * Network data consumer of a "max_fragment_length" extension in
+     * the ClientHello handshake message.
+     */
+    private static final
+            class CHMaxFragmentLengthConsumer implements ExtensionConsumer {
+        // Prevent instantiation of this class.
+        private CHMaxFragmentLengthConsumer() {
+            // blank
+        }
+
     @Override
-    int length() {
-        return 5;               // 4: extension type and length fields
-                                // 1: MaxFragmentLength field
+        public void consume(ConnectionContext context,
+            HandshakeMessage message, ByteBuffer buffer) throws IOException {
+            // The comsuming happens in server side only.
+            ServerHandshakeContext shc = (ServerHandshakeContext)context;
+
+            if (!shc.sslConfig.isAvailable(CH_MAX_FRAGMENT_LENGTH)) {
+                if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
+                    SSLLogger.fine(
+                        "Ignore unavailable max_fragment_length extension");
+                }
+                return;     // ignore the extension
+            }
+
+            // Parse the extension.
+            MaxFragLenSpec spec;
+            try {
+                spec = new MaxFragLenSpec(buffer);
+            } catch (IOException ioe) {
+                shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe);
+                return;     // fatal() always throws, make the compiler happy.
+            }
+
+            MaxFragLenEnum mfle = MaxFragLenEnum.valueOf(spec.id);
+            if (mfle == null) {
+                shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
+                    "the requested maximum fragment length is other " +
+                    "than the allowed values");
+            }
+
+            // Update the context.
+            shc.maxFragmentLength = mfle.fragmentSize;
+            shc.handshakeExtensions.put(CH_MAX_FRAGMENT_LENGTH, spec);
+
+            // No impact on session resumption.
+        }
+    }
+
+    /**
+     * Network data producer of a "max_fragment_length" extension in
+     * the ServerHello handshake message.
+     */
+    private static final
+            class SHMaxFragmentLengthProducer implements HandshakeProducer {
+        // Prevent instantiation of this class.
+        private SHMaxFragmentLengthProducer() {
+            // blank
     }
 
     @Override
-    void send(HandshakeOutStream s) throws IOException {
-        s.putInt16(type.id);
-        s.putInt16(1);
-        s.putInt8(maxFragmentLength);
+        public byte[] produce(ConnectionContext context,
+                HandshakeMessage message) throws IOException {
+            // The producing happens in server side only.
+            ServerHandshakeContext shc = (ServerHandshakeContext)context;
+
+            // In response to "max_fragment_length" extension request only
+            MaxFragLenSpec spec = (MaxFragLenSpec)
+                    shc.handshakeExtensions.get(CH_MAX_FRAGMENT_LENGTH);
+            if (spec == null) {
+                if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
+                    SSLLogger.finest(
+                        "Ignore unavailable max_fragment_length extension");
+                }
+                return null;        // ignore the extension
+            }
+
+            if ((shc.maxFragmentLength > 0) &&
+                    (shc.sslConfig.maximumPacketSize != 0)) {
+                int estimatedMaxFragSize =
+                        shc.negotiatedCipherSuite.calculatePacketSize(
+                                shc.maxFragmentLength, shc.negotiatedProtocol,
+                                shc.sslContext.isDTLS());
+                if (estimatedMaxFragSize > shc.sslConfig.maximumPacketSize) {
+                    // For better interoperability, abort the maximum
+                    // fragment length negotiation, rather than terminate
+                    // the connection with a fatal alert.
+                    if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
+                        SSLLogger.fine(
+                            "Abort the maximum fragment length negotiation, " +
+                            "may overflow the maximum packet size limit.");
+                    }
+                    shc.maxFragmentLength = -1;
+                }
     }
 
-    int getMaxFragLen() {
-        switch (maxFragmentLength) {
-            case MAX_FRAGMENT_LENGTH_512:
-                return 512;
-            case MAX_FRAGMENT_LENGTH_1024:
-                return 1024;
-            case MAX_FRAGMENT_LENGTH_2048:
-                return 2048;
-            case MAX_FRAGMENT_LENGTH_4096:
-                return 4096;
+            // update the context
+            if (shc.maxFragmentLength > 0) {
+                shc.handshakeSession.setNegotiatedMaxFragSize(
+                        shc.maxFragmentLength);
+                shc.conContext.inputRecord.changeFragmentSize(
+                        shc.maxFragmentLength);
+                shc.conContext.outputRecord.changeFragmentSize(
+                        shc.maxFragmentLength);
+
+                // The response extension data is the same as the requested one.
+                shc.handshakeExtensions.put(SH_MAX_FRAGMENT_LENGTH, spec);
+                return new byte[] { spec.id };
+            }
+
+            return null;
+        }
         }
 
-        // unlikely to happen
-        return -1;
+    /**
+     * Network data consumer of a "max_fragment_length" extension in
+     * the ServerHello handshake message.
+     */
+    private static final
+            class SHMaxFragmentLengthConsumer implements ExtensionConsumer {
+        // Prevent instantiation of this class.
+        private SHMaxFragmentLengthConsumer() {
+            // blank
     }
 
-    static boolean needFragLenNego(int fragmentSize) {
-        return (fragmentSize > 0) && (fragmentSize <= 4096);
+        @Override
+        public void consume(ConnectionContext context,
+            HandshakeMessage message, ByteBuffer buffer) throws IOException {
+
+            // The comsuming happens in client side only.
+            ClientHandshakeContext chc = (ClientHandshakeContext)context;
+
+            // In response to "max_fragment_length" extension request only
+            MaxFragLenSpec requestedSpec = (MaxFragLenSpec)
+                    chc.handshakeExtensions.get(CH_MAX_FRAGMENT_LENGTH);
+            if (requestedSpec == null) {
+                chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
+                    "Unexpected max_fragment_length extension in ServerHello");
     }
 
-    static int getValidMaxFragLen(int fragmentSize) {
-        if (fragmentSize < 1024) {
-            return 512;
-        } else if (fragmentSize < 2048) {
-            return 1024;
-        } else if (fragmentSize < 4096) {
-            return 2048;
-        } else if (fragmentSize == 4096) {
-            return 4096;
-        } else {
-            return 16384;
+            // Parse the extension.
+            MaxFragLenSpec spec;
+            try {
+                spec = new MaxFragLenSpec(buffer);
+            } catch (IOException ioe) {
+                chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe);
+                return;     // fatal() always throws, make the compiler happy.
+            }
+
+            if (spec.id != requestedSpec.id) {
+                chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
+                    "The maximum fragment length response is not requested");
+            }
+
+            MaxFragLenEnum mfle = MaxFragLenEnum.valueOf(spec.id);
+            if (mfle == null) {
+                chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
+                    "the requested maximum fragment length is other " +
+                    "than the allowed values");
+            }
+
+            // update the context
+            chc.maxFragmentLength = mfle.fragmentSize;
+            chc.handshakeExtensions.put(SH_MAX_FRAGMENT_LENGTH, spec);
         }
     }
 
+    /**
+     * After session creation consuming of a "max_fragment_length"
+     * extension in the ClientHello handshake message.
+     */
+    private static final class SHMaxFragmentLengthUpdate
+            implements HandshakeConsumer {
+
+        // Prevent instantiation of this class.
+        private SHMaxFragmentLengthUpdate() {
+            // blank
+        }
+
     @Override
-    public String toString() {
-        return "Extension " + type + ", max_fragment_length: " +
-                "(2^" + (maxFragmentLength + 8) + ")";
+        public void consume(ConnectionContext context,
+                HandshakeMessage message) throws IOException {
+            // The comsuming happens in client side only.
+            ClientHandshakeContext chc = (ClientHandshakeContext)context;
+
+            MaxFragLenSpec spec = (MaxFragLenSpec)
+                    chc.handshakeExtensions.get(SH_MAX_FRAGMENT_LENGTH);
+            if (spec == null) {
+                // Ignore, no "max_fragment_length" extension response.
+                return;
+            }
+
+            if ((chc.maxFragmentLength > 0) &&
+                    (chc.sslConfig.maximumPacketSize != 0)) {
+                int estimatedMaxFragSize =
+                        chc.negotiatedCipherSuite.calculatePacketSize(
+                                chc.maxFragmentLength, chc.negotiatedProtocol,
+                                chc.sslContext.isDTLS());
+                if (estimatedMaxFragSize > chc.sslConfig.maximumPacketSize) {
+                    // For better interoperability, abort the maximum
+                    // fragment length negotiation, rather than terminate
+                    // the connection with a fatal alert.
+                    if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
+                        SSLLogger.fine(
+                            "Abort the maximum fragment length negotiation, " +
+                            "may overflow the maximum packet size limit.");
+                    }
+                    chc.maxFragmentLength = -1;
+                }
+            }
+
+            // update the context
+            if (chc.maxFragmentLength > 0) {
+                chc.handshakeSession.setNegotiatedMaxFragSize(
+                        chc.maxFragmentLength);
+                chc.conContext.inputRecord.changeFragmentSize(
+                        chc.maxFragmentLength);
+                chc.conContext.outputRecord.changeFragmentSize(
+                        chc.maxFragmentLength);
+            }
+        }
+    }
+
+    /**
+     * Network data producer of a "max_fragment_length" extension in
+     * the EncryptedExtensions handshake message.
+     */
+    private static final
+            class EEMaxFragmentLengthProducer implements HandshakeProducer {
+        // Prevent instantiation of this class.
+        private EEMaxFragmentLengthProducer() {
+            // blank
+        }
+
+        @Override
+        public byte[] produce(ConnectionContext context,
+                HandshakeMessage message) throws IOException {
+            // The producing happens in server side only.
+            ServerHandshakeContext shc = (ServerHandshakeContext)context;
+
+            // In response to "max_fragment_length" extension request only
+            MaxFragLenSpec spec = (MaxFragLenSpec)
+                    shc.handshakeExtensions.get(CH_MAX_FRAGMENT_LENGTH);
+            if (spec == null) {
+                if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
+                    SSLLogger.finest(
+                        "Ignore unavailable max_fragment_length extension");
+                }
+                return null;        // ignore the extension
+            }
+
+            if ((shc.maxFragmentLength > 0) &&
+                    (shc.sslConfig.maximumPacketSize != 0)) {
+                int estimatedMaxFragSize =
+                        shc.negotiatedCipherSuite.calculatePacketSize(
+                                shc.maxFragmentLength, shc.negotiatedProtocol,
+                                shc.sslContext.isDTLS());
+                if (estimatedMaxFragSize > shc.sslConfig.maximumPacketSize) {
+                    // For better interoperability, abort the maximum
+                    // fragment length negotiation, rather than terminate
+                    // the connection with a fatal alert.
+                    if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
+                        SSLLogger.fine(
+                            "Abort the maximum fragment length negotiation, " +
+                            "may overflow the maximum packet size limit.");
+                    }
+                    shc.maxFragmentLength = -1;
+                }
+            }
+
+            // update the context
+            if (shc.maxFragmentLength > 0) {
+                shc.handshakeSession.setNegotiatedMaxFragSize(
+                        shc.maxFragmentLength);
+                shc.conContext.inputRecord.changeFragmentSize(
+                        shc.maxFragmentLength);
+                shc.conContext.outputRecord.changeFragmentSize(
+                        shc.maxFragmentLength);
+
+                // The response extension data is the same as the requested one.
+                shc.handshakeExtensions.put(EE_MAX_FRAGMENT_LENGTH, spec);
+                return new byte[] { spec.id };
+            }
+
+            return null;
+        }
+    }
+
+    /**
+     * Network data consumer of a "max_fragment_length" extension in the
+     * EncryptedExtensions handshake message.
+     */
+    private static final
+            class EEMaxFragmentLengthConsumer implements ExtensionConsumer {
+        // Prevent instantiation of this class.
+        private EEMaxFragmentLengthConsumer() {
+            // blank
+        }
+
+        @Override
+        public void consume(ConnectionContext context,
+            HandshakeMessage message, ByteBuffer buffer) throws IOException {
+            // The comsuming happens in client side only.
+            ClientHandshakeContext chc = (ClientHandshakeContext)context;
+
+            // In response to "max_fragment_length" extension request only
+            MaxFragLenSpec requestedSpec = (MaxFragLenSpec)
+                    chc.handshakeExtensions.get(CH_MAX_FRAGMENT_LENGTH);
+            if (requestedSpec == null) {
+                chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
+                    "Unexpected max_fragment_length extension in ServerHello");
+            }
+
+            // Parse the extension.
+            MaxFragLenSpec spec;
+            try {
+                spec = new MaxFragLenSpec(buffer);
+            } catch (IOException ioe) {
+                chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe);
+                return;     // fatal() always throws, make the compiler happy.
+            }
+
+            if (spec.id != requestedSpec.id) {
+                chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
+                    "The maximum fragment length response is not requested");
+            }
+
+            MaxFragLenEnum mfle = MaxFragLenEnum.valueOf(spec.id);
+            if (mfle == null) {
+                chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
+                    "the requested maximum fragment length is other " +
+                    "than the allowed values");
+            }
+
+            // update the context
+            chc.maxFragmentLength = mfle.fragmentSize;
+            chc.handshakeExtensions.put(EE_MAX_FRAGMENT_LENGTH, spec);
+        }
+    }
+
+    /**
+     * After session creation consuming of a "max_fragment_length"
+     * extension in the EncryptedExtensions handshake message.
+     */
+    private static final
+            class EEMaxFragmentLengthUpdate implements HandshakeConsumer {
+        // Prevent instantiation of this class.
+        private EEMaxFragmentLengthUpdate() {
+            // blank
+        }
+
+        @Override
+        public void consume(ConnectionContext context,
+                HandshakeMessage message) throws IOException {
+            // The comsuming happens in client side only.
+            ClientHandshakeContext chc = (ClientHandshakeContext)context;
+
+            MaxFragLenSpec spec = (MaxFragLenSpec)
+                    chc.handshakeExtensions.get(EE_MAX_FRAGMENT_LENGTH);
+            if (spec == null) {
+                // Ignore, no "max_fragment_length" extension response.
+                return;
+            }
+
+            if ((chc.maxFragmentLength > 0) &&
+                    (chc.sslConfig.maximumPacketSize != 0)) {
+                int estimatedMaxFragSize =
+                        chc.negotiatedCipherSuite.calculatePacketSize(
+                                chc.maxFragmentLength, chc.negotiatedProtocol,
+                                chc.sslContext.isDTLS());
+                if (estimatedMaxFragSize > chc.sslConfig.maximumPacketSize) {
+                    // For better interoperability, abort the maximum
+                    // fragment length negotiation, rather than terminate
+                    // the connection with a fatal alert.
+                    if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
+                        SSLLogger.fine(
+                            "Abort the maximum fragment length negotiation, " +
+                            "may overflow the maximum packet size limit.");
+                    }
+                    chc.maxFragmentLength = -1;
+                }
+            }
+
+            // update the context
+            if (chc.maxFragmentLength > 0) {
+                chc.handshakeSession.setNegotiatedMaxFragSize(
+                        chc.maxFragmentLength);
+                chc.conContext.inputRecord.changeFragmentSize(
+                        chc.maxFragmentLength);
+                chc.conContext.outputRecord.changeFragmentSize(
+                        chc.maxFragmentLength);
+            }
+        }
     }
 }
< prev index next >