< prev index next >

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

Print this page




  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.security.AlgorithmConstraints;
  31 import java.security.AlgorithmParameters;
  32 import java.security.CryptoPrimitive;


  33 import java.security.spec.ECGenParameterSpec;

  34 import java.security.spec.InvalidParameterSpecException;
  35 import java.text.MessageFormat;
  36 import java.util.ArrayList;
  37 import java.util.Collections;
  38 import java.util.EnumSet;

  39 import java.util.LinkedList;
  40 import java.util.List;
  41 import java.util.Locale;


  42 import javax.net.ssl.SSLProtocolException;
  43 import sun.security.action.GetPropertyAction;
  44 import sun.security.ssl.NamedGroup.NamedGroupType;
  45 import static sun.security.ssl.SSLExtension.CH_SUPPORTED_GROUPS;
  46 import static sun.security.ssl.SSLExtension.EE_SUPPORTED_GROUPS;
  47 import sun.security.ssl.SSLExtension.ExtensionConsumer;
  48 import sun.security.ssl.SSLExtension.SSLExtensionSpec;
  49 import sun.security.ssl.SSLHandshake.HandshakeMessage;
  50 
  51 
  52 /**
  53  * Pack of the "supported_groups" extensions [RFC 4492/7919].
  54  */
  55 final class SupportedGroupsExtension {
  56     static final HandshakeProducer chNetworkProducer =
  57             new CHSupportedGroupsProducer();
  58     static final ExtensionConsumer chOnLoadConsumer =
  59             new CHSupportedGroupsConsumer();
  60     static final SSLStringizer sgsStringizer =
  61             new SupportedGroupsStringizer();
  62 
  63     static final HandshakeProducer eeNetworkProducer =
  64             new EESupportedGroupsProducer();
  65     static final ExtensionConsumer eeOnLoadConsumer =
  66             new EESupportedGroupsConsumer();
  67 
  68     /**
  69      * The "supported_groups" extension.
  70      */


 136                     };
 137 
 138                 return messageFormat.format(messageFields);
 139             }
 140         }
 141     }
 142 
 143     private static final
 144             class SupportedGroupsStringizer implements SSLStringizer {
 145         @Override
 146         public String toString(ByteBuffer buffer) {
 147             try {
 148                 return (new SupportedGroupsSpec(buffer)).toString();
 149             } catch (IOException ioe) {
 150                 // For debug logging only, so please swallow exceptions.
 151                 return ioe.getMessage();
 152             }
 153         }
 154     }
 155 

















































































































































































































































































































 156     static class SupportedGroups {
 157         // To switch off the supported_groups extension for DHE cipher suite.
 158         static final boolean enableFFDHE =
 159                 Utilities.getBooleanProperty("jsse.enableFFDHE", true);
 160 




 161         // the supported named groups
 162         static final NamedGroup[] supportedNamedGroups;
 163 
 164         static {
 165             // The value of the System Property defines a list of enabled named
 166             // groups in preference order, separated with comma.  For example:
 167             //
 168             //      jdk.tls.namedGroups="secp521r1, secp256r1, ffdhe2048"
 169             //
 170             // If the System Property is not defined or the value is empty, the
 171             // default groups and preferences will be used.
 172             String property = GetPropertyAction
 173                     .privilegedGetProperty("jdk.tls.namedGroups");
 174             if (property != null && !property.isEmpty()) {
 175                 // remove double quote marks from beginning/end of the property
 176                 if (property.length() > 1 && property.charAt(0) == '"' &&
 177                         property.charAt(property.length() - 1) == '"') {
 178                     property = property.substring(1, property.length() - 1);
 179                 }
 180             }


 185                 groupList = new ArrayList<>(groups.length);
 186                 for (String group : groups) {
 187                     group = group.trim();
 188                     if (!group.isEmpty()) {
 189                         NamedGroup namedGroup = NamedGroup.nameOf(group);
 190                         if (namedGroup != null) {
 191                             if (isAvailableGroup(namedGroup)) {
 192                                 groupList.add(namedGroup);
 193                             }
 194                         }   // ignore unknown groups
 195                     }
 196                 }
 197 
 198                 if (groupList.isEmpty()) {
 199                     throw new IllegalArgumentException(
 200                             "System property jdk.tls.namedGroups(" +
 201                             property + ") contains no supported named groups");
 202                 }
 203             } else {        // default groups
 204                 NamedGroup[] groups = new NamedGroup[] {
 205 
 206                         // Primary XDH (RFC 7748) curves
 207                         NamedGroup.X25519,
 208 
 209                         // Primary NIST curves (e.g. used in TLSv1.3)
 210                         NamedGroup.SECP256_R1,
 211                         NamedGroup.SECP384_R1,
 212                         NamedGroup.SECP521_R1,
 213 
 214                         // Secondary XDH curves
 215                         NamedGroup.X448,
 216 
 217                         // Secondary NIST curves
 218                         NamedGroup.SECT283_K1,
 219                         NamedGroup.SECT283_R1,
 220                         NamedGroup.SECT409_K1,
 221                         NamedGroup.SECT409_R1,
 222                         NamedGroup.SECT571_K1,
 223                         NamedGroup.SECT571_R1,
 224 
 225                         // non-NIST curves
 226                         NamedGroup.SECP256_K1,
 227 
 228                         // FFDHE (RFC 7919)
 229                         NamedGroup.FFDHE_2048,
 230                         NamedGroup.FFDHE_3072,
 231                         NamedGroup.FFDHE_4096,
 232                         NamedGroup.FFDHE_6144,
 233                         NamedGroup.FFDHE_8192,
 234                     };
 235 
 236                 groupList = new ArrayList<>(groups.length);
 237                 for (NamedGroup group : groups) {
 238                     if (isAvailableGroup(group)) {
 239                         groupList.add(group);
 240                     }
 241                 }
 242 
 243                 if (groupList.isEmpty() &&
 244                         SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 245                     SSLLogger.warning("No default named groups");
 246                 }
 247             }
 248 
 249             supportedNamedGroups = new NamedGroup[groupList.size()];
 250             int i = 0;
 251             for (NamedGroup namedGroup : groupList) {
 252                 supportedNamedGroups[i++] = namedGroup;
 253             }
 254         }
 255 
 256         // check whether the group is supported by the underlying providers
 257         private static boolean isAvailableGroup(NamedGroup namedGroup) {
 258             return namedGroup.isAvailableGroup();

































 259         }
 260 
 261         static ECGenParameterSpec getECGenParamSpec(NamedGroup ng) {
 262             if (ng.type != NamedGroupType.NAMED_GROUP_ECDHE) {
 263                  throw new RuntimeException(
 264                          "Not a named EC group: " + ng);




















































 265             }
 266 
 267             // parameters are non-null
 268             AlgorithmParameters params = ng.getParameters();
 269             try {
 270                 return params.getParameterSpec(ECGenParameterSpec.class);
 271             } catch (InvalidParameterSpecException ipse) {
 272                 // should be unlikely
 273                 return new ECGenParameterSpec(ng.oid);
 274             }
 275         }
 276 
 277         static AlgorithmParameters getParameters(NamedGroup ng) {
 278             return ng.getParameters();
















 279         }
 280 
 281         // Is there any supported group permitted by the constraints?
 282         static boolean isActivatable(
 283                 AlgorithmConstraints constraints, NamedGroupType type) {
 284 
 285             boolean hasFFDHEGroups = false;
 286             for (NamedGroup namedGroup : supportedNamedGroups) {
 287                 if (namedGroup.type == type) {
 288                     if (constraints.permits(
 289                             EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
 290                             namedGroup.algorithm,
 291                             getParameters(namedGroup))) {
 292 
 293                         return true;
 294                     }
 295 
 296                     if (!hasFFDHEGroups &&
 297                             (type == NamedGroupType.NAMED_GROUP_FFDHE)) {
 298                         hasFFDHEGroups = true;
 299                     }
 300                 }
 301             }
 302 
 303             // For compatibility, if no FFDHE groups are defined, the non-FFDHE
 304             // compatible mode (using DHE cipher suite without FFDHE extension)
 305             // is allowed.
 306             //
 307             // Note that the constraints checking on DHE parameters will be
 308             // performed during key exchanging in a handshake.
 309             return !hasFFDHEGroups && type == NamedGroupType.NAMED_GROUP_FFDHE;
 310         }
 311 
 312         // Is the named group permitted by the constraints?
 313         static boolean isActivatable(
 314                 AlgorithmConstraints constraints, NamedGroup namedGroup) {
 315             if (!isSupported(namedGroup)) {
 316                 return false;
 317             }
 318 
 319             return constraints.permits(
 320                             EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
 321                             namedGroup.algorithm,
 322                             getParameters(namedGroup));
 323         }
 324 
 325         // Is the named group supported?
 326         static boolean isSupported(NamedGroup namedGroup) {
 327             for (NamedGroup group : supportedNamedGroups) {
 328                 if (namedGroup.id == group.id) {
 329                     return true;
 330                 }
 331             }
 332 
 333             return false;
 334         }
 335 
 336         static NamedGroup getPreferredGroup(
 337                 ProtocolVersion negotiatedProtocol,
 338                 AlgorithmConstraints constraints, NamedGroupType[] types,
 339                 List<NamedGroup> requestedNamedGroups) {
 340             for (NamedGroup namedGroup : requestedNamedGroups) {
 341                 if ((NamedGroupType.arrayContains(types, namedGroup.type)) &&
 342                         namedGroup.isAvailable(negotiatedProtocol) &&
 343                         isSupported(namedGroup) &&
 344                         constraints.permits(
 345                                 EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
 346                                 namedGroup.algorithm,
 347                                 getParameters(namedGroup))) {
 348                     return namedGroup;
 349                 }
 350             }
 351 
 352             return null;
 353         }
 354 
 355         static NamedGroup getPreferredGroup(
 356                 ProtocolVersion negotiatedProtocol,
 357                 AlgorithmConstraints constraints, NamedGroupType[] types) {
 358             for (NamedGroup namedGroup : supportedNamedGroups) {
 359                 if ((NamedGroupType.arrayContains(types, namedGroup.type)) &&
 360                         namedGroup.isAvailable(negotiatedProtocol) &&
 361                         constraints.permits(
 362                                 EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
 363                                 namedGroup.algorithm,
 364                                 getParameters(namedGroup))) {
 365                     return namedGroup;
 366                 }
 367             }
 368 
 369             return null;
 370         }
 371     }
 372 
 373     /**
 374      * Network data producer of a "supported_groups" extension in
 375      * the ClientHello handshake message.
 376      */
 377     private static final class CHSupportedGroupsProducer
 378             extends SupportedGroups implements HandshakeProducer {
 379         // Prevent instantiation of this class.
 380         private CHSupportedGroupsProducer() {
 381             // blank
 382         }
 383 
 384         @Override


 392                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 393                     SSLLogger.fine(
 394                         "Ignore unavailable supported_groups extension");
 395                 }
 396                 return null;
 397             }
 398 
 399             // Produce the extension.
 400             ArrayList<NamedGroup> namedGroups =
 401                 new ArrayList<>(SupportedGroups.supportedNamedGroups.length);
 402             for (NamedGroup ng : SupportedGroups.supportedNamedGroups) {
 403                 if ((!SupportedGroups.enableFFDHE) &&
 404                     (ng.type == NamedGroupType.NAMED_GROUP_FFDHE)) {
 405                     continue;
 406                 }
 407 
 408                 if (ng.isAvailable(chc.activeProtocols) &&
 409                         ng.isSupported(chc.activeCipherSuites) &&
 410                         chc.algorithmConstraints.permits(
 411                             EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
 412                             ng.algorithm, getParameters(ng))) {
 413                     namedGroups.add(ng);
 414                 } else if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 415                     SSLLogger.fine(
 416                         "Ignore inactive or disabled named group: " + ng.name);
 417                 }
 418             }
 419 
 420             if (namedGroups.isEmpty()) {
 421                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 422                     SSLLogger.warning("no available named group");
 423                 }
 424 
 425                 return null;
 426             }
 427 
 428             int vectorLen = namedGroups.size() << 1;
 429             byte[] extData = new byte[vectorLen + 2];
 430             ByteBuffer m = ByteBuffer.wrap(extData);
 431             Record.putInt16(m, vectorLen);
 432             for (NamedGroup namedGroup : namedGroups) {


 519                 }
 520                 return null;
 521             }
 522 
 523             // Produce the extension.
 524             //
 525             // Contains all groups the server supports, regardless of whether
 526             // they are currently supported by the client.
 527             ArrayList<NamedGroup> namedGroups = new ArrayList<>(
 528                     SupportedGroups.supportedNamedGroups.length);
 529             for (NamedGroup ng : SupportedGroups.supportedNamedGroups) {
 530                 if ((!SupportedGroups.enableFFDHE) &&
 531                     (ng.type == NamedGroupType.NAMED_GROUP_FFDHE)) {
 532                     continue;
 533                 }
 534 
 535                 if (ng.isAvailable(shc.activeProtocols) &&
 536                         ng.isSupported(shc.activeCipherSuites) &&
 537                         shc.algorithmConstraints.permits(
 538                             EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
 539                             ng.algorithm, getParameters(ng))) {
 540                     namedGroups.add(ng);
 541                 } else if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 542                     SSLLogger.fine(
 543                         "Ignore inactive or disabled named group: " + ng.name);
 544                 }
 545             }
 546 
 547             if (namedGroups.isEmpty()) {
 548                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 549                     SSLLogger.warning("no available named group");
 550                 }
 551 
 552                 return null;
 553             }
 554 
 555             int vectorLen = namedGroups.size() << 1;
 556             byte[] extData = new byte[vectorLen + 2];
 557             ByteBuffer m = ByteBuffer.wrap(extData);
 558             Record.putInt16(m, vectorLen);
 559             for (NamedGroup namedGroup : namedGroups) {




  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.security.AlgorithmConstraints;
  31 import java.security.AlgorithmParameters;
  32 import java.security.CryptoPrimitive;
  33 import java.security.NoSuchAlgorithmException;
  34 import java.security.spec.AlgorithmParameterSpec;
  35 import java.security.spec.ECGenParameterSpec;
  36 import java.security.spec.ECParameterSpec;
  37 import java.security.spec.InvalidParameterSpecException;
  38 import java.text.MessageFormat;
  39 import java.util.ArrayList;
  40 import java.util.Collections;
  41 import java.util.EnumSet;
  42 import java.util.HashMap;
  43 import java.util.LinkedList;
  44 import java.util.List;
  45 import java.util.Locale;
  46 import java.util.Map;
  47 import javax.crypto.spec.DHParameterSpec;
  48 import javax.net.ssl.SSLProtocolException;
  49 import sun.security.action.GetPropertyAction;

  50 import static sun.security.ssl.SSLExtension.CH_SUPPORTED_GROUPS;
  51 import static sun.security.ssl.SSLExtension.EE_SUPPORTED_GROUPS;
  52 import sun.security.ssl.SSLExtension.ExtensionConsumer;
  53 import sun.security.ssl.SSLExtension.SSLExtensionSpec;
  54 import sun.security.ssl.SSLHandshake.HandshakeMessage;
  55 import sun.security.util.ECUtil;
  56 
  57 /**
  58  * Pack of the "supported_groups" extensions [RFC 4492/7919].
  59  */
  60 final class SupportedGroupsExtension {
  61     static final HandshakeProducer chNetworkProducer =
  62             new CHSupportedGroupsProducer();
  63     static final ExtensionConsumer chOnLoadConsumer =
  64             new CHSupportedGroupsConsumer();
  65     static final SSLStringizer sgsStringizer =
  66             new SupportedGroupsStringizer();
  67 
  68     static final HandshakeProducer eeNetworkProducer =
  69             new EESupportedGroupsProducer();
  70     static final ExtensionConsumer eeOnLoadConsumer =
  71             new EESupportedGroupsConsumer();
  72 
  73     /**
  74      * The "supported_groups" extension.
  75      */


 141                     };
 142 
 143                 return messageFormat.format(messageFields);
 144             }
 145         }
 146     }
 147 
 148     private static final
 149             class SupportedGroupsStringizer implements SSLStringizer {
 150         @Override
 151         public String toString(ByteBuffer buffer) {
 152             try {
 153                 return (new SupportedGroupsSpec(buffer)).toString();
 154             } catch (IOException ioe) {
 155                 // For debug logging only, so please swallow exceptions.
 156                 return ioe.getMessage();
 157             }
 158         }
 159     }
 160 
 161     static enum NamedGroupType {
 162         NAMED_GROUP_ECDHE     ("EC"),
 163         NAMED_GROUP_FFDHE     ("DiffieHellman"),
 164         NAMED_GROUP_X25519    ("x25519"),
 165         NAMED_GROUP_X448      ("x448"),
 166         NAMED_GROUP_ARBITRARY ("EC"),
 167         NAMED_GROUP_NONE      ("");
 168 
 169         private final String algorithm;
 170 
 171         private NamedGroupType(String algorithm) {
 172             this.algorithm = algorithm;
 173         }
 174 
 175         boolean isSupported(List<CipherSuite> cipherSuites) {
 176             for (CipherSuite cs : cipherSuites) {
 177                 if (cs.keyExchange == null ||
 178                         cs.keyExchange.groupType == this) {
 179                     return true;
 180                 }
 181             }
 182 
 183             return false;
 184         }
 185     }
 186 
 187     static enum NamedGroup {
 188         // Elliptic Curves (RFC 4492)
 189         //
 190         // See sun.security.util.CurveDB for the OIDs
 191         // NIST K-163
 192         SECT163_K1  (0x0001, "sect163k1", "1.3.132.0.1",
 193                             NamedGroupType.NAMED_GROUP_ECDHE,
 194                             ProtocolVersion.PROTOCOLS_TO_12),
 195         SECT163_R1  (0x0002, "sect163r1", "1.3.132.0.2",
 196                             NamedGroupType.NAMED_GROUP_ECDHE,
 197                             ProtocolVersion.PROTOCOLS_TO_12),
 198 
 199         // NIST B-163
 200         SECT163_R2  (0x0003, "sect163r2", "1.3.132.0.15",
 201                             NamedGroupType.NAMED_GROUP_ECDHE,
 202                             ProtocolVersion.PROTOCOLS_TO_12),
 203         SECT193_R1  (0x0004, "sect193r1", "1.3.132.0.24",
 204                             NamedGroupType.NAMED_GROUP_ECDHE,
 205                             ProtocolVersion.PROTOCOLS_TO_12),
 206         SECT193_R2  (0x0005, "sect193r2", "1.3.132.0.25",
 207                             NamedGroupType.NAMED_GROUP_ECDHE,
 208                             ProtocolVersion.PROTOCOLS_TO_12),
 209 
 210         // NIST K-233
 211         SECT233_K1  (0x0006, "sect233k1", "1.3.132.0.26",
 212                             NamedGroupType.NAMED_GROUP_ECDHE,
 213                             ProtocolVersion.PROTOCOLS_TO_12),
 214 
 215         // NIST B-233
 216         SECT233_R1  (0x0007, "sect233r1", "1.3.132.0.27",
 217                             NamedGroupType.NAMED_GROUP_ECDHE,
 218                             ProtocolVersion.PROTOCOLS_TO_12),
 219         SECT239_K1  (0x0008, "sect239k1", "1.3.132.0.3",
 220                             NamedGroupType.NAMED_GROUP_ECDHE,
 221                             ProtocolVersion.PROTOCOLS_TO_12),
 222 
 223         // NIST K-283
 224         SECT283_K1  (0x0009, "sect283k1", "1.3.132.0.16",
 225                             NamedGroupType.NAMED_GROUP_ECDHE,
 226                             ProtocolVersion.PROTOCOLS_TO_12),
 227 
 228         // NIST B-283
 229         SECT283_R1  (0x000A, "sect283r1", "1.3.132.0.17",
 230                             NamedGroupType.NAMED_GROUP_ECDHE,
 231                             ProtocolVersion.PROTOCOLS_TO_12),
 232 
 233         // NIST K-409
 234         SECT409_K1  (0x000B, "sect409k1", "1.3.132.0.36",
 235                             NamedGroupType.NAMED_GROUP_ECDHE,
 236                             ProtocolVersion.PROTOCOLS_TO_12),
 237 
 238         // NIST B-409
 239         SECT409_R1  (0x000C, "sect409r1", "1.3.132.0.37",
 240                             NamedGroupType.NAMED_GROUP_ECDHE,
 241                             ProtocolVersion.PROTOCOLS_TO_12),
 242 
 243         // NIST K-571
 244         SECT571_K1  (0x000D, "sect571k1", "1.3.132.0.38",
 245                             NamedGroupType.NAMED_GROUP_ECDHE,
 246                             ProtocolVersion.PROTOCOLS_TO_12),
 247 
 248         // NIST B-571
 249         SECT571_R1  (0x000E, "sect571r1", "1.3.132.0.39",
 250                             NamedGroupType.NAMED_GROUP_ECDHE,
 251                             ProtocolVersion.PROTOCOLS_TO_12),
 252         SECP160_K1  (0x000F, "secp160k1", "1.3.132.0.9",
 253                             NamedGroupType.NAMED_GROUP_ECDHE,
 254                             ProtocolVersion.PROTOCOLS_TO_12),
 255         SECP160_R1  (0x0010, "secp160r1", "1.3.132.0.8",
 256                             NamedGroupType.NAMED_GROUP_ECDHE,
 257                             ProtocolVersion.PROTOCOLS_TO_12),
 258         SECP160_R2  (0x0011, "secp160r2", "1.3.132.0.30",
 259                             NamedGroupType.NAMED_GROUP_ECDHE,
 260                             ProtocolVersion.PROTOCOLS_TO_12),
 261         SECP192_K1  (0x0012, "secp192k1", "1.3.132.0.31",
 262                             NamedGroupType.NAMED_GROUP_ECDHE,
 263                             ProtocolVersion.PROTOCOLS_TO_12),
 264 
 265         // NIST P-192
 266         SECP192_R1  (0x0013, "secp192r1", "1.2.840.10045.3.1.1",
 267                             NamedGroupType.NAMED_GROUP_ECDHE,
 268                             ProtocolVersion.PROTOCOLS_TO_12),
 269         SECP224_K1  (0x0014, "secp224k1", "1.3.132.0.32",
 270                             NamedGroupType.NAMED_GROUP_ECDHE,
 271                             ProtocolVersion.PROTOCOLS_TO_12),
 272         // NIST P-224
 273         SECP224_R1  (0x0015, "secp224r1", "1.3.132.0.33",
 274                             NamedGroupType.NAMED_GROUP_ECDHE,
 275                             ProtocolVersion.PROTOCOLS_TO_12),
 276         SECP256_K1  (0x0016, "secp256k1", "1.3.132.0.10",
 277                             NamedGroupType.NAMED_GROUP_ECDHE,
 278                             ProtocolVersion.PROTOCOLS_TO_12),
 279 
 280         // NIST P-256
 281         SECP256_R1  (0x0017, "secp256r1", "1.2.840.10045.3.1.7",
 282                             NamedGroupType.NAMED_GROUP_ECDHE,
 283                             ProtocolVersion.PROTOCOLS_TO_13),
 284 
 285         // NIST P-384
 286         SECP384_R1  (0x0018, "secp384r1", "1.3.132.0.34",
 287                             NamedGroupType.NAMED_GROUP_ECDHE,
 288                             ProtocolVersion.PROTOCOLS_TO_13),
 289 
 290         // NIST P-521
 291         SECP521_R1  (0x0019, "secp521r1", "1.3.132.0.35",
 292                             NamedGroupType.NAMED_GROUP_ECDHE,
 293                             ProtocolVersion.PROTOCOLS_TO_13),
 294 
 295         // x25519 and x448
 296         X25519      (0x001D, "x25519", null,
 297                             NamedGroupType.NAMED_GROUP_X25519,
 298                             ProtocolVersion.PROTOCOLS_TO_13),
 299         X448        (0x001E, "x448", null,
 300                             NamedGroupType.NAMED_GROUP_X448,
 301                             ProtocolVersion.PROTOCOLS_TO_13),
 302 
 303         // Finite Field Diffie-Hellman Ephemeral Parameters (RFC 7919)
 304         FFDHE_2048  (0x0100, "ffdhe2048", null,
 305                             NamedGroupType.NAMED_GROUP_FFDHE,
 306                             ProtocolVersion.PROTOCOLS_TO_13),
 307         FFDHE_3072  (0x0101, "ffdhe3072", null,
 308                             NamedGroupType.NAMED_GROUP_FFDHE,
 309                             ProtocolVersion.PROTOCOLS_TO_13),
 310         FFDHE_4096  (0x0102, "ffdhe4096", null,
 311                             NamedGroupType.NAMED_GROUP_FFDHE,
 312                             ProtocolVersion.PROTOCOLS_TO_13),
 313         FFDHE_6144  (0x0103, "ffdhe6144", null,
 314                             NamedGroupType.NAMED_GROUP_FFDHE,
 315                             ProtocolVersion.PROTOCOLS_TO_13),
 316         FFDHE_8192  (0x0104, "ffdhe8192", null,
 317                             NamedGroupType.NAMED_GROUP_FFDHE,
 318                             ProtocolVersion.PROTOCOLS_TO_13),
 319 
 320         // Elliptic Curves (RFC 4492)
 321         //
 322         // arbitrary prime and characteristic-2 curves
 323         ARBITRARY_PRIME  (0xFF01, "arbitrary_explicit_prime_curves", null,
 324                             NamedGroupType.NAMED_GROUP_ARBITRARY,
 325                             ProtocolVersion.PROTOCOLS_TO_12),
 326         ARBITRARY_CHAR2  (0xFF02, "arbitrary_explicit_char2_curves", null,
 327                             NamedGroupType.NAMED_GROUP_ARBITRARY,
 328                             ProtocolVersion.PROTOCOLS_TO_12);
 329 
 330         final int id;               // hash + signature
 331         final NamedGroupType type;  // group type
 332         final String name;          // literal name
 333         final String oid;           // object identifier of the named group
 334         final String algorithm;     // signature algorithm
 335         final ProtocolVersion[] supportedProtocols;
 336 
 337         private NamedGroup(int id, String name, String oid,
 338                 NamedGroupType namedGroupType,
 339                 ProtocolVersion[] supportedProtocols) {
 340             this.id = id;
 341             this.type = namedGroupType;
 342             this.name = name;
 343             this.oid = oid;
 344             this.algorithm = namedGroupType.algorithm;
 345             this.supportedProtocols = supportedProtocols;
 346         }
 347 
 348         static NamedGroup valueOf(int id) {
 349             for (NamedGroup group : NamedGroup.values()) {
 350                 if (group.id == id) {
 351                     return group;
 352                 }
 353             }
 354 
 355             return null;
 356         }
 357 
 358         static NamedGroup valueOf(ECParameterSpec params) {
 359             String oid = ECUtil.getCurveName(null, params);
 360             if ((oid != null) && (!oid.isEmpty())) {
 361                 for (NamedGroup group : NamedGroup.values()) {
 362                     if ((group.type == NamedGroupType.NAMED_GROUP_ECDHE) &&
 363                             oid.equals(group.oid)) {
 364                         return group;
 365                     }
 366                 }
 367             }
 368 
 369             return null;
 370         }
 371 
 372         static NamedGroup valueOf(DHParameterSpec params) {
 373             for (Map.Entry<NamedGroup, AlgorithmParameters> me :
 374                     SupportedGroups.namedGroupParams.entrySet()) {
 375                 NamedGroup ng = me.getKey();
 376                 if (ng.type != NamedGroupType.NAMED_GROUP_FFDHE) {
 377                     continue;
 378                 }
 379 
 380                 DHParameterSpec ngParams = null;
 381                 AlgorithmParameters aps = me.getValue();
 382                 try {
 383                     ngParams = aps.getParameterSpec(DHParameterSpec.class);
 384                 } catch (InvalidParameterSpecException ipse) {
 385                     // should be unlikely
 386                 }
 387 
 388                 if (ngParams == null) {
 389                     continue;
 390                 }
 391 
 392                 if (ngParams.getP().equals(params.getP()) &&
 393                         ngParams.getG().equals(params.getG())) {
 394                     return ng;
 395                 }
 396             }
 397 
 398             return null;
 399         }
 400 
 401         static NamedGroup nameOf(String name) {
 402             for (NamedGroup group : NamedGroup.values()) {
 403                 if (group.name.equals(name)) {
 404                     return group;
 405                 }
 406             }
 407 
 408             return null;
 409         }
 410 
 411         static String nameOf(int id) {
 412             for (NamedGroup group : NamedGroup.values()) {
 413                 if (group.id == id) {
 414                     return group.name;
 415                 }
 416             }
 417 
 418             return "UNDEFINED-NAMED-GROUP(" + id + ")";
 419         }
 420 
 421         boolean isAvailable(List<ProtocolVersion> protocolVersions) {
 422             for (ProtocolVersion pv : supportedProtocols) {
 423                 if (protocolVersions.contains(pv)) {
 424                     return true;
 425                 }
 426             }
 427             return false;
 428         }
 429 
 430         boolean isAvailable(ProtocolVersion protocolVersion) {
 431             for (ProtocolVersion pv : supportedProtocols) {
 432                 if (protocolVersion == pv) {
 433                     return true;
 434                 }
 435             }
 436             return false;
 437         }
 438 
 439         boolean isSupported(List<CipherSuite> cipherSuites) {
 440             for (CipherSuite cs : cipherSuites) {
 441                 boolean isMatch = isAvailable(cs.supportedProtocols);
 442                 if (isMatch && (cs.keyExchange == null ||
 443                         cs.keyExchange.groupType == type)) {
 444                     return true;
 445                 }
 446             }
 447             return false;
 448         }
 449 
 450         // lazy loading of parameters
 451         AlgorithmParameters getParameters() {
 452             return SupportedGroups.namedGroupParams.get(this);
 453         }
 454 
 455         AlgorithmParameterSpec getParameterSpec() {
 456             if (this.type == NamedGroupType.NAMED_GROUP_ECDHE) {
 457                 return SupportedGroups.getECGenParamSpec(this);
 458             } else if (this.type == NamedGroupType.NAMED_GROUP_FFDHE) {
 459                 return SupportedGroups.getDHParameterSpec(this);
 460             }
 461 
 462             return null;
 463         }
 464     }
 465 
 466     static class SupportedGroups {
 467         // To switch off the supported_groups extension for DHE cipher suite.
 468         static final boolean enableFFDHE =
 469                 Utilities.getBooleanProperty("jsse.enableFFDHE", true);
 470 
 471         // cache to speed up the parameters construction
 472         static final Map<NamedGroup,
 473                     AlgorithmParameters> namedGroupParams = new HashMap<>();
 474 
 475         // the supported named groups
 476         static final NamedGroup[] supportedNamedGroups;
 477 
 478         static {
 479             // The value of the System Property defines a list of enabled named
 480             // groups in preference order, separated with comma.  For example:
 481             //
 482             //      jdk.tls.namedGroups="secp521r1, secp256r1, ffdhe2048"
 483             //
 484             // If the System Property is not defined or the value is empty, the
 485             // default groups and preferences will be used.
 486             String property = GetPropertyAction
 487                     .privilegedGetProperty("jdk.tls.namedGroups");
 488             if (property != null && !property.isEmpty()) {
 489                 // remove double quote marks from beginning/end of the property
 490                 if (property.length() > 1 && property.charAt(0) == '"' &&
 491                         property.charAt(property.length() - 1) == '"') {
 492                     property = property.substring(1, property.length() - 1);
 493                 }
 494             }


 499                 groupList = new ArrayList<>(groups.length);
 500                 for (String group : groups) {
 501                     group = group.trim();
 502                     if (!group.isEmpty()) {
 503                         NamedGroup namedGroup = NamedGroup.nameOf(group);
 504                         if (namedGroup != null) {
 505                             if (isAvailableGroup(namedGroup)) {
 506                                 groupList.add(namedGroup);
 507                             }
 508                         }   // ignore unknown groups
 509                     }
 510                 }
 511 
 512                 if (groupList.isEmpty()) {
 513                     throw new IllegalArgumentException(
 514                             "System property jdk.tls.namedGroups(" +
 515                             property + ") contains no supported named groups");
 516                 }
 517             } else {        // default groups
 518                 NamedGroup[] groups = new NamedGroup[] {
 519                         // NIST curves first




 520                         NamedGroup.SECP256_R1,
 521                         NamedGroup.SECP384_R1,
 522                         NamedGroup.SECP521_R1,





 523                         NamedGroup.SECT283_K1,
 524                         NamedGroup.SECT283_R1,
 525                         NamedGroup.SECT409_K1,
 526                         NamedGroup.SECT409_R1,
 527                         NamedGroup.SECT571_K1,
 528                         NamedGroup.SECT571_R1,
 529 
 530                         // non-NIST curves
 531                         NamedGroup.SECP256_K1,
 532 
 533                         // FFDHE 2048
 534                         NamedGroup.FFDHE_2048,
 535                         NamedGroup.FFDHE_3072,
 536                         NamedGroup.FFDHE_4096,
 537                         NamedGroup.FFDHE_6144,
 538                         NamedGroup.FFDHE_8192,
 539                     };
 540 
 541                 groupList = new ArrayList<>(groups.length);
 542                 for (NamedGroup group : groups) {
 543                     if (isAvailableGroup(group)) {
 544                         groupList.add(group);
 545                     }
 546                 }
 547 
 548                 if (groupList.isEmpty() &&
 549                         SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 550                     SSLLogger.warning("No default named groups");
 551                 }
 552             }
 553 
 554             supportedNamedGroups = new NamedGroup[groupList.size()];
 555             int i = 0;
 556             for (NamedGroup namedGroup : groupList) {
 557                 supportedNamedGroups[i++] = namedGroup;
 558             }
 559         }
 560 
 561         // check whether the group is supported by the underlying providers
 562         private static boolean isAvailableGroup(NamedGroup namedGroup) {
 563             AlgorithmParameters params = null;
 564             AlgorithmParameterSpec spec = null;
 565             if (namedGroup.type == NamedGroupType.NAMED_GROUP_ECDHE) {
 566                 if (namedGroup.oid != null) {
 567                     try {
 568                         params = AlgorithmParameters.getInstance("EC");
 569                         spec = new ECGenParameterSpec(namedGroup.oid);
 570                     } catch (NoSuchAlgorithmException e) {
 571                         return false;
 572                     }
 573                 }
 574             } else if (namedGroup.type == NamedGroupType.NAMED_GROUP_FFDHE) {
 575                 try {
 576                     params = AlgorithmParameters.getInstance("DiffieHellman");
 577                     spec = getFFDHEDHParameterSpec(namedGroup);
 578                 } catch (NoSuchAlgorithmException e) {
 579                     return false;
 580                 }
 581             }   // Otherwise, unsupported.
 582 
 583             if ((params != null) && (spec != null)) {
 584                 try {
 585                     params.init(spec);
 586                 } catch (InvalidParameterSpecException e) {
 587                     return false;
 588                 }
 589 
 590                 // cache the parameters
 591                 namedGroupParams.put(namedGroup, params);
 592 
 593                 return true;
 594             }
 595 
 596             return false;
 597         }
 598 
 599         private static DHParameterSpec getFFDHEDHParameterSpec(
 600                 NamedGroup namedGroup) {
 601             DHParameterSpec spec = null;
 602             switch (namedGroup) {
 603                 case FFDHE_2048:
 604                     spec = PredefinedDHParameterSpecs.ffdheParams.get(2048);
 605                     break;
 606                 case FFDHE_3072:
 607                     spec = PredefinedDHParameterSpecs.ffdheParams.get(3072);
 608                     break;
 609                 case FFDHE_4096:
 610                     spec = PredefinedDHParameterSpecs.ffdheParams.get(4096);
 611                     break;
 612                 case FFDHE_6144:
 613                     spec = PredefinedDHParameterSpecs.ffdheParams.get(6144);
 614                     break;
 615                 case FFDHE_8192:
 616                     spec = PredefinedDHParameterSpecs.ffdheParams.get(8192);
 617             }
 618 
 619             return spec;
 620         }
 621 
 622         private static DHParameterSpec getPredefinedDHParameterSpec(
 623                 NamedGroup namedGroup) {
 624             DHParameterSpec spec = null;
 625             switch (namedGroup) {
 626                 case FFDHE_2048:
 627                     spec = PredefinedDHParameterSpecs.definedParams.get(2048);
 628                     break;
 629                 case FFDHE_3072:
 630                     spec = PredefinedDHParameterSpecs.definedParams.get(3072);
 631                     break;
 632                 case FFDHE_4096:
 633                     spec = PredefinedDHParameterSpecs.definedParams.get(4096);
 634                     break;
 635                 case FFDHE_6144:
 636                     spec = PredefinedDHParameterSpecs.definedParams.get(6144);
 637                     break;
 638                 case FFDHE_8192:
 639                     spec = PredefinedDHParameterSpecs.definedParams.get(8192);
 640             }
 641 
 642             return spec;
 643         }
 644 
 645         static ECGenParameterSpec getECGenParamSpec(NamedGroup namedGroup) {
 646             if (namedGroup.type != NamedGroupType.NAMED_GROUP_ECDHE) {
 647                 throw new RuntimeException(
 648                         "Not a named EC group: " + namedGroup);
 649             }
 650 
 651             AlgorithmParameters params = namedGroupParams.get(namedGroup);
 652             if (params == null) {
 653                 throw new RuntimeException(
 654                         "Not a supported EC named group: " + namedGroup);
 655             }
 656 


 657             try {
 658                 return params.getParameterSpec(ECGenParameterSpec.class);
 659             } catch (InvalidParameterSpecException ipse) {
 660                 // should be unlikely
 661                 return new ECGenParameterSpec(namedGroup.oid);
 662             }
 663         }
 664 
 665         static DHParameterSpec getDHParameterSpec(NamedGroup namedGroup) {
 666             if (namedGroup.type != NamedGroupType.NAMED_GROUP_FFDHE) {
 667                 throw new RuntimeException(
 668                         "Not a named DH group: " + namedGroup);
 669             }
 670 
 671             AlgorithmParameters params = namedGroupParams.get(namedGroup);
 672             if (params == null) {
 673                 throw new RuntimeException(
 674                         "Not a supported DH named group: " + namedGroup);
 675             }
 676 
 677             try {
 678                 return params.getParameterSpec(DHParameterSpec.class);
 679             } catch (InvalidParameterSpecException ipse) {
 680                 // should be unlikely
 681                 return getPredefinedDHParameterSpec(namedGroup);
 682             }
 683         }
 684 
 685         // Is there any supported group permitted by the constraints?
 686         static boolean isActivatable(
 687                 AlgorithmConstraints constraints, NamedGroupType type) {
 688 
 689             boolean hasFFDHEGroups = false;
 690             for (NamedGroup namedGroup : supportedNamedGroups) {
 691                 if (namedGroup.type == type) {
 692                     if (constraints.permits(
 693                             EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
 694                             namedGroup.algorithm,
 695                             namedGroupParams.get(namedGroup))) {
 696 
 697                         return true;
 698                     }
 699 
 700                     if (!hasFFDHEGroups &&
 701                             (type == NamedGroupType.NAMED_GROUP_FFDHE)) {
 702                         hasFFDHEGroups = true;
 703                     }
 704                 }
 705             }
 706 
 707             // For compatibility, if no FFDHE groups are defined, the non-FFDHE
 708             // compatible mode (using DHE cipher suite without FFDHE extension)
 709             // is allowed.
 710             //
 711             // Note that the constraints checking on DHE parameters will be
 712             // performed during key exchanging in a handshake.
 713             return !hasFFDHEGroups && type == NamedGroupType.NAMED_GROUP_FFDHE;
 714         }
 715 
 716         // Is the named group permitted by the constraints?
 717         static boolean isActivatable(
 718                 AlgorithmConstraints constraints, NamedGroup namedGroup) {
 719             if (!isSupported(namedGroup)) {
 720                 return false;
 721             }
 722 
 723             return constraints.permits(
 724                             EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
 725                             namedGroup.algorithm,
 726                             namedGroupParams.get(namedGroup));
 727         }
 728 
 729         // Is the named group supported?
 730         static boolean isSupported(NamedGroup namedGroup) {
 731             for (NamedGroup group : supportedNamedGroups) {
 732                 if (namedGroup.id == group.id) {
 733                     return true;
 734                 }
 735             }
 736 
 737             return false;
 738         }
 739 
 740         static NamedGroup getPreferredGroup(
 741                 ProtocolVersion negotiatedProtocol,
 742                 AlgorithmConstraints constraints, NamedGroupType type,
 743                 List<NamedGroup> requestedNamedGroups) {
 744             for (NamedGroup namedGroup : requestedNamedGroups) {
 745                 if ((namedGroup.type == type) &&
 746                         namedGroup.isAvailable(negotiatedProtocol) &&
 747                         isSupported(namedGroup) &&
 748                         constraints.permits(
 749                                 EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
 750                                 namedGroup.algorithm,
 751                                 namedGroupParams.get(namedGroup))) {
 752                     return namedGroup;
 753                 }
 754             }
 755 
 756             return null;
 757         }
 758 
 759         static NamedGroup getPreferredGroup(
 760                 ProtocolVersion negotiatedProtocol,
 761                 AlgorithmConstraints constraints, NamedGroupType type) {
 762             for (NamedGroup namedGroup : supportedNamedGroups) {
 763                 if ((namedGroup.type == type) &&
 764                         namedGroup.isAvailable(negotiatedProtocol) &&
 765                         constraints.permits(
 766                                 EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
 767                                 namedGroup.algorithm,
 768                                 namedGroupParams.get(namedGroup))) {
 769                     return namedGroup;
 770                 }
 771             }
 772 
 773             return null;
 774         }
 775     }
 776 
 777     /**
 778      * Network data producer of a "supported_groups" extension in
 779      * the ClientHello handshake message.
 780      */
 781     private static final class CHSupportedGroupsProducer
 782             extends SupportedGroups implements HandshakeProducer {
 783         // Prevent instantiation of this class.
 784         private CHSupportedGroupsProducer() {
 785             // blank
 786         }
 787 
 788         @Override


 796                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 797                     SSLLogger.fine(
 798                         "Ignore unavailable supported_groups extension");
 799                 }
 800                 return null;
 801             }
 802 
 803             // Produce the extension.
 804             ArrayList<NamedGroup> namedGroups =
 805                 new ArrayList<>(SupportedGroups.supportedNamedGroups.length);
 806             for (NamedGroup ng : SupportedGroups.supportedNamedGroups) {
 807                 if ((!SupportedGroups.enableFFDHE) &&
 808                     (ng.type == NamedGroupType.NAMED_GROUP_FFDHE)) {
 809                     continue;
 810                 }
 811 
 812                 if (ng.isAvailable(chc.activeProtocols) &&
 813                         ng.isSupported(chc.activeCipherSuites) &&
 814                         chc.algorithmConstraints.permits(
 815                             EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
 816                             ng.algorithm, namedGroupParams.get(ng))) {
 817                     namedGroups.add(ng);
 818                 } else if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 819                     SSLLogger.fine(
 820                         "Ignore inactive or disabled named group: " + ng.name);
 821                 }
 822             }
 823 
 824             if (namedGroups.isEmpty()) {
 825                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 826                     SSLLogger.warning("no available named group");
 827                 }
 828 
 829                 return null;
 830             }
 831 
 832             int vectorLen = namedGroups.size() << 1;
 833             byte[] extData = new byte[vectorLen + 2];
 834             ByteBuffer m = ByteBuffer.wrap(extData);
 835             Record.putInt16(m, vectorLen);
 836             for (NamedGroup namedGroup : namedGroups) {


 923                 }
 924                 return null;
 925             }
 926 
 927             // Produce the extension.
 928             //
 929             // Contains all groups the server supports, regardless of whether
 930             // they are currently supported by the client.
 931             ArrayList<NamedGroup> namedGroups = new ArrayList<>(
 932                     SupportedGroups.supportedNamedGroups.length);
 933             for (NamedGroup ng : SupportedGroups.supportedNamedGroups) {
 934                 if ((!SupportedGroups.enableFFDHE) &&
 935                     (ng.type == NamedGroupType.NAMED_GROUP_FFDHE)) {
 936                     continue;
 937                 }
 938 
 939                 if (ng.isAvailable(shc.activeProtocols) &&
 940                         ng.isSupported(shc.activeCipherSuites) &&
 941                         shc.algorithmConstraints.permits(
 942                             EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
 943                             ng.algorithm, namedGroupParams.get(ng))) {
 944                     namedGroups.add(ng);
 945                 } else if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 946                     SSLLogger.fine(
 947                         "Ignore inactive or disabled named group: " + ng.name);
 948                 }
 949             }
 950 
 951             if (namedGroups.isEmpty()) {
 952                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 953                     SSLLogger.warning("no available named group");
 954                 }
 955 
 956                 return null;
 957             }
 958 
 959             int vectorLen = namedGroups.size() << 1;
 960             byte[] extData = new byte[vectorLen + 2];
 961             ByteBuffer m = ByteBuffer.wrap(extData);
 962             Record.putInt16(m, vectorLen);
 963             for (NamedGroup namedGroup : namedGroups) {


< prev index next >