< prev index next >

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

Print this page


   1 /*
   2  * Copyright (c) 2006, 2017, 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.security.spec.ECGenParameterSpec;
  30 import java.security.spec.InvalidParameterSpecException;
  31 import java.security.AlgorithmParameters;
  32 import java.security.AlgorithmConstraints;

  33 import java.security.CryptoPrimitive;
  34 import java.security.AccessController;
  35 import java.security.spec.AlgorithmParameterSpec;
  36 import javax.crypto.spec.DHParameterSpec;





  37 import java.util.EnumSet;
  38 import java.util.HashMap;



  39 import java.util.Map;
  40 import java.util.ArrayList;
  41 import javax.net.ssl.SSLProtocolException;
  42 
  43 import sun.security.action.GetPropertyAction;



























  44 
  45 //
  46 // Note: Since RFC 7919, the extension's semantics are expanded from
  47 // "Supported Elliptic Curves" to "Supported Groups".  The enum datatype
  48 // used in the extension has been renamed from NamedCurve to NamedGroup.
  49 // Its semantics are likewise expanded from "named curve" to "named group".
  50 //
  51 final class SupportedGroupsExtension extends HelloExtension {
















  52 
  53     /* Class and subclass dynamic debugging support */
  54     private static final Debug debug = Debug.getInstance("ssl");















  55 
  56     private static final int ARBITRARY_PRIME = 0xff01;
  57     private static final int ARBITRARY_CHAR2 = 0xff02;
























































































































































































































































































































































  58 
  59     // cache to speed up the parameters construction
  60     private static final Map<NamedGroup,
  61                 AlgorithmParameters> namedGroupParams = new HashMap<>();
  62 
  63     // the supported named groups
  64     private static final NamedGroup[] supportedNamedGroups;
  65 
  66     // the named group presented in the extension
  67     private final int[] requestedNamedGroupIds;
  68 
  69     static {
  70         boolean requireFips = SunJSSE.isFIPS();
  71 
  72         // The value of the System Property defines a list of enabled named
  73         // groups in preference order, separated with comma.  For example:
  74         //
  75         //      jdk.tls.namedGroups="secp521r1, secp256r1, ffdhe2048"
  76         //
  77         // If the System Property is not defined or the value is empty, the
  78         // default groups and preferences will be used.
  79         String property = AccessController.doPrivileged(
  80                     new GetPropertyAction("jdk.tls.namedGroups"));
  81         if (property != null && property.length() != 0) {
  82             // remove double quote marks from beginning/end of the property
  83             if (property.length() > 1 && property.charAt(0) == '"' &&
  84                     property.charAt(property.length() - 1) == '"') {
  85                 property = property.substring(1, property.length() - 1);
  86             }
  87         }
  88 
  89         ArrayList<NamedGroup> groupList;
  90         if (property != null && property.length() != 0) {   // customized groups
  91             String[] groups = property.split(",");
  92             groupList = new ArrayList<>(groups.length);
  93             for (String group : groups) {
  94                 group = group.trim();
  95                 if (!group.isEmpty()) {
  96                     NamedGroup namedGroup = NamedGroup.nameOf(group);
  97                     if (namedGroup != null &&
  98                             (!requireFips || namedGroup.isFips)) {
  99                         if (isAvailableGroup(namedGroup)) {
 100                             groupList.add(namedGroup);
 101                         }
 102                     }   // ignore unknown groups
 103                 }
 104             }
 105 
 106             if (groupList.isEmpty() && JsseJce.isEcAvailable()) {
 107                 throw new IllegalArgumentException(
 108                     "System property jdk.tls.namedGroups(" + property + ") " +
 109                     "contains no supported elliptic curves");
 110             }
 111         } else {        // default groups
 112             NamedGroup[] groups;
 113             if (requireFips) {
 114                 groups = new NamedGroup[] {
 115                     // only NIST curves in FIPS mode
 116                     NamedGroup.SECP256_R1,
 117                     NamedGroup.SECP384_R1,
 118                     NamedGroup.SECP521_R1,
 119                     NamedGroup.SECT283_K1,
 120                     NamedGroup.SECT283_R1,
 121                     NamedGroup.SECT409_K1,
 122                     NamedGroup.SECT409_R1,
 123                     NamedGroup.SECT571_K1,
 124                     NamedGroup.SECT571_R1,
 125 
 126                     // FFDHE 2048
 127                     NamedGroup.FFDHE_2048,
 128                     NamedGroup.FFDHE_3072,
 129                     NamedGroup.FFDHE_4096,


 144                     NamedGroup.SECT571_R1,
 145 
 146                     // non-NIST curves
 147                     NamedGroup.SECP256_K1,
 148 
 149                     // FFDHE 2048
 150                     NamedGroup.FFDHE_2048,
 151                     NamedGroup.FFDHE_3072,
 152                     NamedGroup.FFDHE_4096,
 153                     NamedGroup.FFDHE_6144,
 154                     NamedGroup.FFDHE_8192,
 155                 };
 156             }
 157 
 158             groupList = new ArrayList<>(groups.length);
 159             for (NamedGroup group : groups) {
 160                 if (isAvailableGroup(group)) {
 161                     groupList.add(group);
 162                 }
 163             }
 164         }
 165 
 166         if (debug != null && groupList.isEmpty()) {
 167             Debug.log(
 168                 "Initialized [jdk.tls.namedGroups|default] list contains " +
 169                 "no available elliptic curves. " +
 170                 (property != null ? "(" + property + ")" : "[Default]"));
 171         }
 172 
 173         supportedNamedGroups = new NamedGroup[groupList.size()];
 174         int i = 0;
 175         for (NamedGroup namedGroup : groupList) {
 176             supportedNamedGroups[i++] = namedGroup;
 177         }
 178     }
 179 
 180     // check whether the group is supported by the underlying providers
 181     private static boolean isAvailableGroup(NamedGroup namedGroup) {
 182         AlgorithmParameters params = null;
 183         AlgorithmParameterSpec spec = null;
 184         if ("EC".equals(namedGroup.algorithm)) {
 185             if (namedGroup.oid != null) {
 186                 try {
 187                     params = JsseJce.getAlgorithmParameters("EC");
 188                     spec = new ECGenParameterSpec(namedGroup.oid);
 189                 } catch (Exception e) {
 190                     return false;
 191                 }
 192             }
 193         } else if ("DiffieHellman".equals(namedGroup.algorithm)) {
 194             try {
 195                 params = JsseJce.getAlgorithmParameters("DiffieHellman");
 196                 spec = getFFDHEDHParameterSpec(namedGroup);
 197             } catch (Exception e) {
 198                 return false;
 199             }
 200         }
 201 
 202         if ((params != null) && (spec != null)) {
 203             try {
 204                 params.init(spec);
 205             } catch (Exception e) {
 206                 return false;
 207             }
 208 
 209             // cache the parameters
 210             namedGroupParams.put(namedGroup, params);
 211 
 212             return true;
 213         }
 214 
 215         return false;
 216     }
 217 
 218     private static DHParameterSpec getFFDHEDHParameterSpec(
 219             NamedGroup namedGroup) {
 220         DHParameterSpec spec = null;
 221         switch (namedGroup) {
 222             case FFDHE_2048:
 223                 spec = PredefinedDHParameterSpecs.ffdheParams.get(2048);
 224                 break;
 225             case FFDHE_3072:


 244         switch (namedGroup) {
 245             case FFDHE_2048:
 246                 spec = PredefinedDHParameterSpecs.definedParams.get(2048);
 247                 break;
 248             case FFDHE_3072:
 249                 spec = PredefinedDHParameterSpecs.definedParams.get(3072);
 250                 break;
 251             case FFDHE_4096:
 252                 spec = PredefinedDHParameterSpecs.definedParams.get(4096);
 253                 break;
 254             case FFDHE_6144:
 255                 spec = PredefinedDHParameterSpecs.definedParams.get(6144);
 256                 break;
 257             case FFDHE_8192:
 258                 spec = PredefinedDHParameterSpecs.definedParams.get(8192);
 259         }
 260 
 261         return spec;
 262     }
 263 
 264     private SupportedGroupsExtension(int[] requestedNamedGroupIds) {
 265         super(ExtensionType.EXT_SUPPORTED_GROUPS);
 266 
 267         this.requestedNamedGroupIds = requestedNamedGroupIds;
 268     }
 269 
 270     SupportedGroupsExtension(HandshakeInStream s, int len) throws IOException {
 271         super(ExtensionType.EXT_SUPPORTED_GROUPS);
 272 
 273         int k = s.getInt16();
 274         if (((len & 1) != 0) || (k == 0) || (k + 2 != len)) {
 275             throw new SSLProtocolException("Invalid " + type + " extension");
 276         }
 277 
 278         // Note: unknown named group will be ignored later.
 279         requestedNamedGroupIds = new int[k >> 1];
 280         for (int i = 0; i < requestedNamedGroupIds.length; i++) {
 281             requestedNamedGroupIds[i] = s.getInt16();


 282         }
 283     }
 284 
 285     // Get a local preferred supported ECDHE group permitted by the constraints.
 286     static NamedGroup getPreferredECGroup(AlgorithmConstraints constraints) {
 287         for (NamedGroup namedGroup : supportedNamedGroups) {
 288             if ((namedGroup.type == NamedGroupType.NAMED_GROUP_ECDHE) &&
 289                 constraints.permits(EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
 290                     namedGroup.algorithm, namedGroupParams.get(namedGroup))) {
 291 
 292                 return namedGroup;
 293             }
 294         }
 295 
 296         return null;






 297     }
 298 
 299     // Is there any supported group permitted by the constraints?
 300     static boolean isActivatable(
 301             AlgorithmConstraints constraints, NamedGroupType type) {
 302 
 303         boolean hasFFDHEGroups = false;
 304         for (NamedGroup namedGroup : supportedNamedGroups) {
 305             if (namedGroup.type == type) {
 306                 if (constraints.permits(
 307                         EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
 308                         namedGroup.algorithm,
 309                         namedGroupParams.get(namedGroup))) {
 310 
 311                     return true;
 312                 }
 313 
 314                 if (!hasFFDHEGroups &&
 315                         (type == NamedGroupType.NAMED_GROUP_FFDHE)) {
 316 
 317                     hasFFDHEGroups = true;
 318                 }
 319             }
 320         }
 321 
 322         // For compatibility, if no FFDHE groups are defined, the non-FFDHE
 323         // compatible mode (using DHE cipher suite without FFDHE extension)
 324         // is allowed.
 325         //
 326         // Note that the constraints checking on DHE parameters will be
 327         // performed during key exchanging in a handshake.
 328         if (!hasFFDHEGroups && (type == NamedGroupType.NAMED_GROUP_FFDHE)) {
 329             return true;
 330         }
 331 




 332         return false;
 333     }
 334 
 335     // Create the default supported groups extension.
 336     static SupportedGroupsExtension createExtension(
 337             AlgorithmConstraints constraints,
 338             CipherSuiteList cipherSuites, boolean enableFFDHE) {

 339 
 340         ArrayList<Integer> groupList =
 341                 new ArrayList<>(supportedNamedGroups.length);
 342         for (NamedGroup namedGroup : supportedNamedGroups) {
 343             if ((!enableFFDHE) &&
 344                 (namedGroup.type == NamedGroupType.NAMED_GROUP_FFDHE)) {
 345                 continue;
 346             }
 347 
 348             if (cipherSuites.contains(namedGroup.type) &&
 349                 constraints.permits(EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
 350                     namedGroup.algorithm, namedGroupParams.get(namedGroup))) {
 351 
 352                 groupList.add(namedGroup.id);











 353             }
 354         }
 355 
 356         if (!groupList.isEmpty()) {
 357             int[] ids = new int[groupList.size()];
 358             int i = 0;
 359             for (Integer id : groupList) {
 360                 ids[i++] = id;
 361             }
 362 
 363             return new SupportedGroupsExtension(ids);











 364         }
 365 
 366         return null;
 367     }

 368 
 369     // get the preferred activated named group
 370     NamedGroup getPreferredGroup(
 371             AlgorithmConstraints constraints, NamedGroupType type) {







 372 
 373         for (int groupId : requestedNamedGroupIds) {
 374             NamedGroup namedGroup = NamedGroup.valueOf(groupId);
 375             if ((namedGroup != null) && (namedGroup.type == type) &&
 376                 SupportedGroupsExtension.supports(namedGroup) &&
 377                 constraints.permits(EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
 378                     namedGroup.algorithm, namedGroupParams.get(namedGroup))) {








 379 
 380                 return namedGroup;

















 381             }
 382         }
 383 





 384         return null;
 385     }
 386 
 387     boolean hasFFDHEGroup() {
 388         for (int groupId : requestedNamedGroupIds) {
 389             /*
 390              * [RFC 7919] Codepoints in the "Supported Groups Registry"
 391              * with a high byte of 0x01 (that is, between 256 and 511,
 392              * inclusive) are set aside for FFDHE groups.















 393              */
 394             if ((groupId >= 256) && (groupId <= 511)) {
 395                 return true;



 396             }














 397         }
 398 
 399         return false;






 400     }
 401 
 402     boolean contains(int index) {
 403         for (int groupId : requestedNamedGroupIds) {
 404             if (index == groupId) {
 405                 return true;


 406             }
 407         }
 408         return false;





 409     }
 410 
 411     @Override
 412     int length() {
 413         return 6 + (requestedNamedGroupIds.length << 1);







 414     }
 415 
 416     @Override
 417     void send(HandshakeOutStream s) throws IOException {
 418         s.putInt16(type.id);
 419         int k = requestedNamedGroupIds.length << 1;
 420         s.putInt16(k + 2);
 421         s.putInt16(k);
 422         for (int groupId : requestedNamedGroupIds) {
 423             s.putInt16(groupId);



 424         }

 425     }
 426 
 427     @Override
 428     public String toString() {
 429         StringBuilder sb = new StringBuilder();
 430         sb.append("Extension " + type + ", group names: {");
 431         boolean first = true;
 432         for (int groupId : requestedNamedGroupIds) {
 433             if (first) {
 434                 first = false;
 435             } else {
 436                 sb.append(", ");
 437             }
 438             // first check if it is a known named group, then try other cases.
 439             NamedGroup namedGroup = NamedGroup.valueOf(groupId);
 440             if (namedGroup != null) {
 441                 sb.append(namedGroup.name);
 442             } else if (groupId == ARBITRARY_PRIME) {
 443                 sb.append("arbitrary_explicit_prime_curves");
 444             } else if (groupId == ARBITRARY_CHAR2) {
 445                 sb.append("arbitrary_explicit_char2_curves");
 446             } else {
 447                 sb.append("unknown named group " + groupId);
 448             }
 449         }
 450         sb.append("}");
 451         return sb.toString();


 452     }
 453 
 454     static boolean supports(NamedGroup namedGroup) {
 455         for (NamedGroup group : supportedNamedGroups) {
 456             if (namedGroup.id == group.id) {
 457                 return true;
 458             }







 459         }
 460 
 461         return false;







 462     }
 463 
 464     static ECGenParameterSpec getECGenParamSpec(NamedGroup namedGroup) {
 465         if (namedGroup.type != NamedGroupType.NAMED_GROUP_ECDHE) {
 466             throw new RuntimeException("Not a named EC group: " + namedGroup);


 467         }
 468 
 469         AlgorithmParameters params = namedGroupParams.get(namedGroup);
 470         try {
 471             return params.getParameterSpec(ECGenParameterSpec.class);
 472         } catch (InvalidParameterSpecException ipse) {
 473             // should be unlikely
 474             return new ECGenParameterSpec(namedGroup.oid);





 475         }

 476     }
 477 
 478     static DHParameterSpec getDHParameterSpec(NamedGroup namedGroup) {
 479         if (namedGroup.type != NamedGroupType.NAMED_GROUP_FFDHE) {
 480             throw new RuntimeException("Not a named DH group: " + namedGroup);




 481         }
 482 
 483         AlgorithmParameters params = namedGroupParams.get(namedGroup);
 484         try {
 485             return params.getParameterSpec(DHParameterSpec.class);
 486         } catch (InvalidParameterSpecException ipse) {
 487             // should be unlikely
 488             return getPredefinedDHParameterSpec(namedGroup);








 489         }
 490     }
 491 }
   1 /*
   2  * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.security.ssl;
  27 
  28 import java.io.IOException;
  29 import java.nio.ByteBuffer;
  30 import java.security.AccessController;

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

  50 import sun.security.action.GetPropertyAction;
  51 import static sun.security.ssl.SSLExtension.CH_SUPPORTED_GROUPS;
  52 import static sun.security.ssl.SSLExtension.EE_SUPPORTED_GROUPS;
  53 import sun.security.ssl.SSLExtension.ExtensionConsumer;
  54 import sun.security.ssl.SSLExtension.SSLExtensionSpec;
  55 import sun.security.ssl.SSLHandshake.HandshakeMessage;
  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 chOnLoadConcumer =
  64             new CHSupportedGroupsConsumer();
  65     static final SSLStringize sgsStringize =
  66             new SupportedGroupsStringize();
  67 
  68     static final HandshakeProducer eeNetworkProducer =
  69             new EESupportedGroupsProducer();
  70     static final ExtensionConsumer eeOnLoadConcumer =
  71             new EESupportedGroupsConsumer();
  72 
  73     /**
  74      * The "supported_groups" extension.
  75      */
  76     static final class SupportedGroupsSpec implements SSLExtensionSpec {
  77         final int[] namedGroupsIds;
  78 
  79         private SupportedGroupsSpec(int[] namedGroupsIds) {
  80             this.namedGroupsIds = namedGroupsIds;
  81         }
  82 
  83         private SupportedGroupsSpec(List<NamedGroup> namedGroups) {
  84             this.namedGroupsIds = new int[namedGroups.size()];
  85             int i = 0;
  86             for (NamedGroup ng : namedGroups) {
  87                 namedGroupsIds[i++] = ng.id;
  88             }
  89         }
  90 
  91         private SupportedGroupsSpec(ByteBuffer m) throws IOException  {
  92             if (m.remaining() < 2) {      // 2: the length of the list
  93                 throw new SSLProtocolException(
  94                     "Invalid supported_groups extension: insufficient data");
  95             }
  96 
  97             byte[] ngs = Record.getBytes16(m);
  98             if (m.hasRemaining()) {
  99                 throw new SSLProtocolException(
 100                     "Invalid supported_groups extension: unknown extra data");
 101             }
 102 
 103             if ((ngs == null) || (ngs.length == 0) || (ngs.length % 2 != 0)) {
 104                 throw new SSLProtocolException(
 105                     "Invalid supported_groups extension: incomplete data");
 106             }
 107 
 108             int[] ids = new int[ngs.length / 2];
 109             for (int i = 0, j = 0; i < ngs.length;) {
 110                 ids[j++] = ((ngs[i++] & 0xFF) << 8) | (ngs[i++] & 0xFF);
 111             }
 112 
 113             this.namedGroupsIds = ids;
 114         }
 115 
 116         @Override
 117         public String toString() {
 118             MessageFormat messageFormat = new MessageFormat(
 119                 "\"versions\": '['{0}']'", Locale.ENGLISH);
 120 
 121             if (namedGroupsIds == null || namedGroupsIds.length == 0) {
 122                 Object[] messageFields = {
 123                         "<no supported named group specified>"
 124                     };
 125                 return messageFormat.format(messageFields);
 126             } else {
 127                 StringBuilder builder = new StringBuilder(512);
 128                 boolean isFirst = true;
 129                 for (int ngid : namedGroupsIds) {
 130                     if (isFirst) {
 131                         isFirst = false;
 132                     } else {
 133                         builder.append(", ");
 134                     }
 135 
 136                     builder.append(NamedGroup.nameOf(ngid));
 137                 }
 138 
 139                 Object[] messageFields = {
 140                         builder.toString()
 141                     };
 142 
 143                 return messageFormat.format(messageFields);
 144             }
 145         }
 146     }
 147 
 148     private static final
 149             class SupportedGroupsStringize implements SSLStringize {
 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,          // Elliptic Curve Groups (ECDHE)
 163         NAMED_GROUP_FFDHE,          // Finite Field Groups (DHE)
 164         NAMED_GROUP_XDH,            // Finite Field Groups (XDH)
 165         NAMED_GROUP_ARBITRARY,      // arbitrary prime and curves (ECDHE)
 166         NAMED_GROUP_NONE;           // Not predefined named group
 167 
 168         boolean isSupported(List<CipherSuite> cipherSuites) {
 169             for (CipherSuite cs : cipherSuites) {
 170                 if (cs.keyExchange == null || cs.keyExchange.groupType == this) {
 171                     return true;
 172                 }
 173             }
 174 
 175             return false;
 176         }
 177     }
 178 
 179     static enum NamedGroup {
 180         // Elliptic Curves (RFC 4492)
 181         //
 182         // See sun.security.util.CurveDB for the OIDs
 183         // NIST K-163
 184         SECT163_K1  (0x0001, "sect163k1", "1.3.132.0.1", true,
 185                             ProtocolVersion.PROTOCOLS_TO_12),
 186         SECT163_R1  (0x0002, "sect163r1", "1.3.132.0.2", false,
 187                             ProtocolVersion.PROTOCOLS_TO_12),
 188 
 189         // NIST B-163
 190         SECT163_R2  (0x0003, "sect163r2", "1.3.132.0.15", true,
 191                             ProtocolVersion.PROTOCOLS_TO_12),
 192         SECT193_R1  (0x0004, "sect193r1", "1.3.132.0.24", false,
 193                             ProtocolVersion.PROTOCOLS_TO_12),
 194         SECT193_R2  (0x0005, "sect193r2", "1.3.132.0.25", false,
 195                             ProtocolVersion.PROTOCOLS_TO_12),
 196 
 197         // NIST K-233
 198         SECT233_K1  (0x0006, "sect233k1", "1.3.132.0.26", true,
 199                             ProtocolVersion.PROTOCOLS_TO_12),
 200 
 201         // NIST B-233
 202         SECT233_R1  (0x0007, "sect233r1", "1.3.132.0.27", true,
 203                             ProtocolVersion.PROTOCOLS_TO_12),
 204         SECT239_K1  (0x0008, "sect239k1", "1.3.132.0.3", false,
 205                             ProtocolVersion.PROTOCOLS_TO_12),
 206 
 207         // NIST K-283
 208         SECT283_K1  (0x0009, "sect283k1", "1.3.132.0.16", true,
 209                             ProtocolVersion.PROTOCOLS_TO_12),
 210 
 211         // NIST B-283
 212         SECT283_R1  (0x000A, "sect283r1", "1.3.132.0.17", true,
 213                             ProtocolVersion.PROTOCOLS_TO_12),
 214 
 215         // NIST K-409
 216         SECT409_K1  (0x000B, "sect409k1", "1.3.132.0.36", true,
 217                             ProtocolVersion.PROTOCOLS_TO_12),
 218 
 219         // NIST B-409
 220         SECT409_R1  (0x000C, "sect409r1", "1.3.132.0.37", true,
 221                             ProtocolVersion.PROTOCOLS_TO_12),
 222 
 223         // NIST K-571
 224         SECT571_K1  (0x000D, "sect571k1", "1.3.132.0.38", true,
 225                             ProtocolVersion.PROTOCOLS_TO_12),
 226 
 227         // NIST B-571
 228         SECT571_R1  (0x000E, "sect571r1", "1.3.132.0.39", true,
 229                             ProtocolVersion.PROTOCOLS_TO_12),
 230         SECP160_K1  (0x000F, "secp160k1", "1.3.132.0.9", false,
 231                             ProtocolVersion.PROTOCOLS_TO_12),
 232         SECP160_R1  (0x0010, "secp160r1", "1.3.132.0.8", false,
 233                             ProtocolVersion.PROTOCOLS_TO_12),
 234         SECP160_R2  (0x0011, "secp160r2", "1.3.132.0.30", false,
 235                             ProtocolVersion.PROTOCOLS_TO_12),
 236         SECP192_K1  (0x0012, "secp192k1", "1.3.132.0.31", false,
 237                             ProtocolVersion.PROTOCOLS_TO_12),
 238 
 239         // NIST P-192
 240         SECP192_R1  (0x0013, "secp192r1", "1.2.840.10045.3.1.1", true,
 241                             ProtocolVersion.PROTOCOLS_TO_12),
 242         SECP224_K1  (0x0014, "secp224k1", "1.3.132.0.32", false,
 243                             ProtocolVersion.PROTOCOLS_TO_12),
 244         // NIST P-224
 245         SECP224_R1  (0x0015, "secp224r1", "1.3.132.0.33", true,
 246                             ProtocolVersion.PROTOCOLS_TO_12),
 247         SECP256_K1  (0x0016, "secp256k1", "1.3.132.0.10", false,
 248                             ProtocolVersion.PROTOCOLS_TO_12),
 249 
 250         // NIST P-256
 251         SECP256_R1  (0x0017, "secp256r1", "1.2.840.10045.3.1.7", true,
 252                             ProtocolVersion.PROTOCOLS_TO_13),
 253 
 254         // NIST P-384
 255         SECP384_R1  (0x0018, "secp384r1", "1.3.132.0.34", true,
 256                             ProtocolVersion.PROTOCOLS_TO_13),
 257 
 258         // NIST P-521
 259         SECP521_R1  (0x0019, "secp521r1", "1.3.132.0.35", true,
 260                             ProtocolVersion.PROTOCOLS_TO_13),
 261 
 262         // x25519 and x448
 263         X25519      (0x001D, "x25519", true, "x25519",
 264                             ProtocolVersion.PROTOCOLS_TO_13),
 265         X448        (0x001E, "x448", true, "x448",
 266                             ProtocolVersion.PROTOCOLS_TO_13),
 267 
 268         // Finite Field Diffie-Hellman Ephemeral Parameters (RFC 7919)
 269         FFDHE_2048  (0x0100, "ffdhe2048",  true,
 270                             ProtocolVersion.PROTOCOLS_TO_13),
 271         FFDHE_3072  (0x0101, "ffdhe3072",  true,
 272                             ProtocolVersion.PROTOCOLS_TO_13),
 273         FFDHE_4096  (0x0102, "ffdhe4096",  true,
 274                             ProtocolVersion.PROTOCOLS_TO_13),
 275         FFDHE_6144  (0x0103, "ffdhe6144",  true,
 276                             ProtocolVersion.PROTOCOLS_TO_13),
 277         FFDHE_8192  (0x0104, "ffdhe8192",  true,
 278                             ProtocolVersion.PROTOCOLS_TO_13),
 279 
 280         // Elliptic Curves (RFC 4492)
 281         //
 282         // arbitrary prime and characteristic-2 curves
 283         ARBITRARY_PRIME  (0xFF01, "arbitrary_explicit_prime_curves",
 284                             ProtocolVersion.PROTOCOLS_TO_12),
 285         ARBITRARY_CHAR2  (0xFF02, "arbitrary_explicit_char2_curves",
 286                             ProtocolVersion.PROTOCOLS_TO_12);
 287 
 288         final int id;               // hash + signature
 289         final NamedGroupType type;  // group type
 290         final String name;          // literal name
 291         final String oid;           // object identifier of the named group
 292         final String algorithm;     // signature algorithm
 293         final boolean isFips;       // can be used in FIPS mode?
 294         final ProtocolVersion[] supportedProtocols;
 295 
 296         // Constructor used for Elliptic Curve Groups (ECDHE)
 297         private NamedGroup(int id, String name, String oid, boolean isFips,
 298                 ProtocolVersion[] supportedProtocols) {
 299             this.id = id;
 300             this.type = NamedGroupType.NAMED_GROUP_ECDHE;
 301             this.name = name;
 302             this.oid = oid;
 303             this.algorithm = "EC";
 304             this.isFips = isFips;
 305             this.supportedProtocols = supportedProtocols;
 306         }
 307 
 308         // Constructor used for Elliptic Curve Groups (XDH)
 309         private NamedGroup(int id, String name,
 310                 boolean isFips, String algorithm,
 311                 ProtocolVersion[] supportedProtocols) {
 312             this.id = id;
 313             this.type = NamedGroupType.NAMED_GROUP_XDH;
 314             this.name = name;
 315             this.oid = null;
 316             this.algorithm = algorithm;
 317             this.isFips = isFips;
 318             this.supportedProtocols = supportedProtocols;
 319         }
 320 
 321         // Constructor used for Finite Field Diffie-Hellman Groups (FFDHE)
 322         private NamedGroup(int id, String name, boolean isFips,
 323                 ProtocolVersion[] supportedProtocols) {
 324             this.id = id;
 325             this.type = NamedGroupType.NAMED_GROUP_FFDHE;
 326             this.name = name;
 327             this.oid = null;
 328             this.algorithm = "DiffieHellman";
 329             this.isFips = isFips;
 330             this.supportedProtocols = supportedProtocols;
 331         }
 332 
 333         // Constructor used for arbitrary prime and curves (ECDHE)
 334         private NamedGroup(int id, String name,
 335                 ProtocolVersion[] supportedProtocols) {
 336             this.id = id;
 337             this.type = NamedGroupType.NAMED_GROUP_ARBITRARY;
 338             this.name = name;
 339             this.oid = null;
 340             this.algorithm = "EC";
 341             this.isFips = false;
 342             this.supportedProtocols = supportedProtocols;
 343         }
 344 
 345         static NamedGroup valueOf(int id) {
 346             for (NamedGroup group : NamedGroup.values()) {
 347                 if (group.id == id) {
 348                     return group;
 349                 }
 350             }
 351 
 352             return null;
 353         }
 354 
 355         static NamedGroup valueOf(ECParameterSpec params) {
 356             String oid = JsseJce.getNamedCurveOid(params);
 357             if ((oid != null) && (!oid.isEmpty())) {
 358                 for (NamedGroup group : NamedGroup.values()) {
 359                     if ((group.type == NamedGroupType.NAMED_GROUP_ECDHE) &&
 360                             oid.equals(group.oid)) {
 361                         return group;
 362                     }
 363                 }
 364             }
 365 
 366             return null;
 367         }
 368 
 369         static NamedGroup valueOf(DHParameterSpec params) {
 370             for (Map.Entry<NamedGroup, AlgorithmParameters> me :
 371                     SupportedGroups.namedGroupParams.entrySet()) {
 372                 NamedGroup ng = me.getKey();
 373                 if (ng.type != NamedGroupType.NAMED_GROUP_FFDHE) {
 374                     continue;
 375                 }
 376 
 377                 DHParameterSpec ngParams = null;
 378                 AlgorithmParameters aps = me.getValue();
 379                 try {
 380                     ngParams = aps.getParameterSpec(DHParameterSpec.class);
 381                 } catch (InvalidParameterSpecException ipse) {
 382                     // should be unlikely
 383                 }
 384 
 385                 if (ngParams == null) {
 386                     continue;
 387                 }
 388 
 389                 if (ngParams.getP().equals(params.getP()) &&
 390                         ngParams.getG().equals(params.getG())) {
 391                     return ng;
 392                 }
 393             }
 394 
 395             return null;
 396         }
 397 
 398         static NamedGroup nameOf(String name) {
 399             for (NamedGroup group : NamedGroup.values()) {
 400                 if (group.name.equals(name)) {
 401                     return group;
 402                 }
 403             }
 404 
 405             return null;
 406         }
 407 
 408         static String nameOf(int id) {
 409             for (NamedGroup group : NamedGroup.values()) {
 410                 if (group.id == id) {
 411                     return group.name;
 412                 }
 413             }
 414 
 415             return "UNDEFINED-NAMED-GROUP(" + id + ")";
 416         }
 417 
 418         boolean isAvailable(List<ProtocolVersion> protocolVersions) {
 419             for (ProtocolVersion pv : supportedProtocols) {
 420                 if (protocolVersions.contains(pv)) {
 421                     return true;
 422                 }
 423             }
 424             return false;
 425         }
 426 
 427         boolean isAvailable(ProtocolVersion protocolVersion) {
 428             for (ProtocolVersion pv : supportedProtocols) {
 429                 if (protocolVersion == pv) {
 430                     return true;
 431                 }
 432             }
 433             return false;
 434         }
 435 
 436         boolean isSupported(List<CipherSuite> cipherSuites) {
 437             for (CipherSuite cs : cipherSuites) {
 438                 boolean isMatch = isAvailable(cs.supportedProtocols);
 439                 if (isMatch && (cs.keyExchange == null ||
 440                         cs.keyExchange.groupType == type)) {
 441                     return true;
 442                 }
 443             }
 444             return false;
 445         }
 446 
 447         // lazy loading of parameters
 448         AlgorithmParameters getParameters() {
 449             return SupportedGroups.namedGroupParams.get(this);
 450         }
 451 
 452         AlgorithmParameterSpec getParameterSpec() {
 453             if (this.type == NamedGroupType.NAMED_GROUP_ECDHE) {
 454                 return SupportedGroups.getECGenParamSpec(this);
 455             } else if (this.type == NamedGroupType.NAMED_GROUP_FFDHE) {
 456                 return SupportedGroups.getDHParameterSpec(this);
 457             }
 458 
 459             return null;
 460         }
 461     }
 462 
 463     static class SupportedGroups {
 464         // To switch off the supported_groups extension for DHE cipher suite.
 465         static final boolean enableFFDHE =
 466                 Utilities.getBooleanProperty("jsse.enableFFDHE", true);
 467 
 468         // cache to speed up the parameters construction
 469         static final Map<NamedGroup,
 470                     AlgorithmParameters> namedGroupParams = new HashMap<>();
 471 
 472         // the supported named groups
 473         static final NamedGroup[] supportedNamedGroups;



 474 
 475         static {
 476             boolean requireFips = SunJSSE.isFIPS();
 477 
 478             // The value of the System Property defines a list of enabled named
 479             // groups in preference order, separated with comma.  For example:
 480             //
 481             //      jdk.tls.namedGroups="secp521r1, secp256r1, ffdhe2048"
 482             //
 483             // If the System Property is not defined or the value is empty, the
 484             // default groups and preferences will be used.
 485             String property = AccessController.doPrivileged(
 486                         new GetPropertyAction("jdk.tls.namedGroups"));
 487             if (property != null && property.length() != 0) {
 488                 // remove double quote marks from beginning/end of the property
 489                 if (property.length() > 1 && property.charAt(0) == '"' &&
 490                         property.charAt(property.length() - 1) == '"') {
 491                     property = property.substring(1, property.length() - 1);
 492                 }
 493             }
 494 
 495             ArrayList<NamedGroup> groupList;
 496             if (property != null && property.length() != 0) {
 497                 String[] groups = property.split(",");
 498                 groupList = new ArrayList<>(groups.length);
 499                 for (String group : groups) {
 500                     group = group.trim();
 501                     if (!group.isEmpty()) {
 502                         NamedGroup namedGroup = NamedGroup.nameOf(group);
 503                         if (namedGroup != null &&
 504                                 (!requireFips || namedGroup.isFips)) {
 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;
 519                 if (requireFips) {
 520                     groups = new NamedGroup[] {
 521                         // only NIST curves in FIPS mode
 522                         NamedGroup.SECP256_R1,
 523                         NamedGroup.SECP384_R1,
 524                         NamedGroup.SECP521_R1,
 525                         NamedGroup.SECT283_K1,
 526                         NamedGroup.SECT283_R1,
 527                         NamedGroup.SECT409_K1,
 528                         NamedGroup.SECT409_R1,
 529                         NamedGroup.SECT571_K1,
 530                         NamedGroup.SECT571_R1,
 531 
 532                         // FFDHE 2048
 533                         NamedGroup.FFDHE_2048,
 534                         NamedGroup.FFDHE_3072,
 535                         NamedGroup.FFDHE_4096,


 550                         NamedGroup.SECT571_R1,
 551 
 552                         // non-NIST curves
 553                         NamedGroup.SECP256_K1,
 554 
 555                         // FFDHE 2048
 556                         NamedGroup.FFDHE_2048,
 557                         NamedGroup.FFDHE_3072,
 558                         NamedGroup.FFDHE_4096,
 559                         NamedGroup.FFDHE_6144,
 560                         NamedGroup.FFDHE_8192,
 561                     };
 562                 }
 563 
 564                 groupList = new ArrayList<>(groups.length);
 565                 for (NamedGroup group : groups) {
 566                     if (isAvailableGroup(group)) {
 567                         groupList.add(group);
 568                     }
 569                 }

 570 
 571                 if (groupList.isEmpty() &&
 572                         SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 573                     SSLLogger.warning("No default named groups");
 574                 }

 575             }
 576 
 577             supportedNamedGroups = new NamedGroup[groupList.size()];
 578             int i = 0;
 579             for (NamedGroup namedGroup : groupList) {
 580                 supportedNamedGroups[i++] = namedGroup;
 581             }
 582         }
 583 
 584         // check whether the group is supported by the underlying providers
 585         private static boolean isAvailableGroup(NamedGroup namedGroup) {
 586             AlgorithmParameters params = null;
 587             AlgorithmParameterSpec spec = null;
 588             if (namedGroup.type == NamedGroupType.NAMED_GROUP_ECDHE) {
 589                 if (namedGroup.oid != null) {
 590                     try {
 591                         params = JsseJce.getAlgorithmParameters("EC");
 592                         spec = new ECGenParameterSpec(namedGroup.oid);
 593                     } catch (NoSuchAlgorithmException e) {
 594                         return false;
 595                     }
 596                 }
 597             } else if (namedGroup.type == NamedGroupType.NAMED_GROUP_FFDHE) {
 598                 try {
 599                     params = JsseJce.getAlgorithmParameters("DiffieHellman");
 600                     spec = getFFDHEDHParameterSpec(namedGroup);
 601                 } catch (NoSuchAlgorithmException e) {
 602                     return false;
 603                 }
 604             }   // Otherwise, unsupported.
 605 
 606             if ((params != null) && (spec != null)) {
 607                 try {
 608                     params.init(spec);
 609                 } catch (InvalidParameterSpecException e) {
 610                     return false;
 611                 }
 612 
 613                 // cache the parameters
 614                 namedGroupParams.put(namedGroup, params);
 615 
 616                 return true;
 617             }
 618 
 619             return false;
 620         }
 621 
 622         private static DHParameterSpec getFFDHEDHParameterSpec(
 623                 NamedGroup namedGroup) {
 624             DHParameterSpec spec = null;
 625             switch (namedGroup) {
 626                 case FFDHE_2048:
 627                     spec = PredefinedDHParameterSpecs.ffdheParams.get(2048);
 628                     break;
 629                 case FFDHE_3072:


 648             switch (namedGroup) {
 649                 case FFDHE_2048:
 650                     spec = PredefinedDHParameterSpecs.definedParams.get(2048);
 651                     break;
 652                 case FFDHE_3072:
 653                     spec = PredefinedDHParameterSpecs.definedParams.get(3072);
 654                     break;
 655                 case FFDHE_4096:
 656                     spec = PredefinedDHParameterSpecs.definedParams.get(4096);
 657                     break;
 658                 case FFDHE_6144:
 659                     spec = PredefinedDHParameterSpecs.definedParams.get(6144);
 660                     break;
 661                 case FFDHE_8192:
 662                     spec = PredefinedDHParameterSpecs.definedParams.get(8192);
 663             }
 664 
 665             return spec;
 666         }
 667 
 668         static ECGenParameterSpec getECGenParamSpec(NamedGroup namedGroup) {
 669             if (namedGroup.type != NamedGroupType.NAMED_GROUP_ECDHE) {
 670                 throw new RuntimeException(
 671                         "Not a named EC group: " + namedGroup);








 672             }
 673 
 674             AlgorithmParameters params = namedGroupParams.get(namedGroup);
 675             try {
 676                 return params.getParameterSpec(ECGenParameterSpec.class);
 677             } catch (InvalidParameterSpecException ipse) {
 678                 // should be unlikely
 679                 return new ECGenParameterSpec(namedGroup.oid);
 680             }
 681         }
 682 
 683         static DHParameterSpec getDHParameterSpec(NamedGroup namedGroup) {
 684             if (namedGroup.type != NamedGroupType.NAMED_GROUP_FFDHE) {
 685                 throw new RuntimeException(
 686                         "Not a named DH group: " + namedGroup);





 687             }
 688 
 689             AlgorithmParameters params = namedGroupParams.get(namedGroup);
 690             try {
 691                 return params.getParameterSpec(DHParameterSpec.class);
 692             } catch (InvalidParameterSpecException ipse) {
 693                 // should be unlikely
 694                 return getPredefinedDHParameterSpec(namedGroup);
 695             }
 696         }
 697 
 698         // Is there any supported group permitted by the constraints?
 699         static boolean isActivatable(
 700                 AlgorithmConstraints constraints, NamedGroupType type) {
 701 
 702             boolean hasFFDHEGroups = false;
 703             for (NamedGroup namedGroup : supportedNamedGroups) {
 704                 if (namedGroup.type == type) {
 705                     if (constraints.permits(
 706                             EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
 707                             namedGroup.algorithm,
 708                             namedGroupParams.get(namedGroup))) {
 709 
 710                         return true;
 711                     }
 712 
 713                     if (!hasFFDHEGroups &&
 714                             (type == NamedGroupType.NAMED_GROUP_FFDHE)) {

 715                         hasFFDHEGroups = true;
 716                     }
 717                 }
 718             }
 719 
 720             // For compatibility, if no FFDHE groups are defined, the non-FFDHE
 721             // compatible mode (using DHE cipher suite without FFDHE extension)
 722             // is allowed.
 723             //
 724             // Note that the constraints checking on DHE parameters will be
 725             // performed during key exchanging in a handshake.
 726             return !hasFFDHEGroups && type == NamedGroupType.NAMED_GROUP_FFDHE;

 727         }
 728 
 729         // Is the named group permitted by the constraints?
 730         static boolean isActivatable(
 731                 AlgorithmConstraints constraints, NamedGroup namedGroup) {
 732             if (!isSupported(namedGroup)) {
 733                 return false;
 734             }
 735 
 736             return constraints.permits(
 737                             EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
 738                             namedGroup.algorithm,
 739                             namedGroupParams.get(namedGroup));
 740         }
 741 
 742         // Is there any supported group permitted by the constraints?
 743         static boolean isSupported(NamedGroup namedGroup) {
 744             for (NamedGroup group : supportedNamedGroups) {
 745                 if (namedGroup.id == group.id) {
 746                     return true;
 747                 }
 748             }
 749 
 750             return false;
 751         }

 752 
 753         static NamedGroup getPreferredGroup(
 754                 ProtocolVersion negotiatedProtocol,
 755                 AlgorithmConstraints constraints, NamedGroupType type,
 756                 List<NamedGroup> requestedNamedGroups) {
 757             for (NamedGroup namedGroup : requestedNamedGroups) {
 758                 if ((namedGroup.type == type) &&
 759                         namedGroup.isAvailable(negotiatedProtocol) &&
 760                         constraints.permits(
 761                                 EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
 762                                 namedGroup.algorithm,
 763                                 namedGroupParams.get(namedGroup))) {
 764                     return namedGroup;
 765                 }
 766             }
 767 
 768             return null;




 769         }
 770 
 771         static NamedGroup getPreferredGroup(
 772                 ProtocolVersion negotiatedProtocol,
 773                 AlgorithmConstraints constraints, NamedGroupType type) {
 774             for (NamedGroup namedGroup : supportedNamedGroups) {
 775                 if ((namedGroup.type == type) &&
 776                         namedGroup.isAvailable(negotiatedProtocol) &&
 777                         constraints.permits(
 778                                 EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
 779                                 namedGroup.algorithm,
 780                                 namedGroupParams.get(namedGroup))) {
 781                     return namedGroup;
 782                 }
 783             }
 784 
 785             return null;
 786         }
 787     }
 788 
 789     /**
 790      * Network data producer of a "supported_groups" extension in
 791      * the ClientHello handshake message.
 792      */
 793     private static final class CHSupportedGroupsProducer
 794             extends SupportedGroups implements HandshakeProducer {
 795         // Prevent instantiation of this class.
 796         private CHSupportedGroupsProducer() {
 797             // blank
 798         }
 799 
 800         @Override
 801         public byte[] produce(ConnectionContext context,
 802                 HandshakeMessage message) throws IOException {
 803             // The producing happens in client side only.
 804             ClientHandshakeContext chc = (ClientHandshakeContext)context;
 805 
 806             // Is it a supported and enabled extension?
 807             if (!chc.sslConfig.isAvailable(CH_SUPPORTED_GROUPS)) {
 808                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 809                     SSLLogger.fine(
 810                         "Ignore unavailable supported_groups extension");
 811                 }
 812                 return null;
 813             }
 814 
 815             // Produce the extension.
 816             ArrayList<NamedGroup> namedGroups =
 817                 new ArrayList<>(SupportedGroups.supportedNamedGroups.length);
 818             for (NamedGroup ng : SupportedGroups.supportedNamedGroups) {
 819                 if ((!SupportedGroups.enableFFDHE) &&
 820                     (ng.type == NamedGroupType.NAMED_GROUP_FFDHE)) {
 821                     continue;
 822                 }
 823 
 824                 if (ng.isAvailable(chc.activeProtocols) &&
 825                         ng.isSupported(chc.activeCipherSuites) &&
 826                         chc.algorithmConstraints.permits(
 827                             EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
 828                             ng.algorithm, namedGroupParams.get(ng))) {
 829                     namedGroups.add(ng);
 830                 } else if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 831                     SSLLogger.fine(
 832                         "Ignore inactive or disabled named group: " + ng.name);
 833                 }
 834             }
 835 
 836             if (namedGroups.isEmpty()) {
 837                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 838                     SSLLogger.warning("no available named group");
 839                 }
 840 
 841                 return null;
 842             }
 843 
 844             int vectorLen = namedGroups.size() << 1;
 845             byte[] extData = new byte[vectorLen + 2];
 846             ByteBuffer m = ByteBuffer.wrap(extData);
 847             Record.putInt16(m, vectorLen);
 848             for (NamedGroup namedGroup : namedGroups) {
 849                     Record.putInt16(m, namedGroup.id);
 850             }
 851 
 852             // Update the context.
 853             chc.clientRequestedNamedGroups =
 854                     Collections.<NamedGroup>unmodifiableList(namedGroups);
 855             chc.handshakeExtensions.put(CH_SUPPORTED_GROUPS,
 856                     new SupportedGroupsSpec(namedGroups));
 857 
 858             return extData;
 859         }
 860     }
 861 
 862     /**
 863      * Network data producer of a "supported_groups" extension in
 864      * the ClientHello handshake message.
 865      */
 866     private static final
 867             class CHSupportedGroupsConsumer implements ExtensionConsumer {
 868         // Prevent instantiation of this class.
 869         private CHSupportedGroupsConsumer() {
 870             // blank
 871         }
 872 
 873         @Override
 874         public void consume(ConnectionContext context,
 875             HandshakeMessage message, ByteBuffer buffer) throws IOException {
 876             // The comsuming happens in server side only.
 877             ServerHandshakeContext shc = (ServerHandshakeContext)context;
 878 
 879             // Is it a supported and enabled extension?
 880             if (!shc.sslConfig.isAvailable(CH_SUPPORTED_GROUPS)) {
 881                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 882                     SSLLogger.fine(
 883                         "Ignore unavailable supported_groups extension");
 884                 }
 885                 return;     // ignore the extension
 886             }
 887 
 888             // Parse the extension.
 889             SupportedGroupsSpec spec;
 890             try {
 891                 spec = new SupportedGroupsSpec(buffer);
 892             } catch (IOException ioe) {
 893                 shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe);
 894                 return;     // fatal() always throws, make the compiler happy.
 895             }
 896 
 897             // Update the context.
 898             List<NamedGroup> knownNamedGroups = new LinkedList<>();
 899             for (int id : spec.namedGroupsIds) {
 900                 NamedGroup ng = NamedGroup.valueOf(id);
 901                 if (ng != null) {
 902                     knownNamedGroups.add(ng);
 903                 }
 904             }
 905 
 906             shc.clientRequestedNamedGroups = knownNamedGroups;
 907             shc.handshakeExtensions.put(CH_SUPPORTED_GROUPS, spec);
 908 
 909             // No impact on session resumption.
 910         }
 911     }
 912 
 913     /**
 914      * Network data producer of a "supported_groups" extension in
 915      * the EncryptedExtensions handshake message.
 916      */
 917     private static final class EESupportedGroupsProducer
 918             extends SupportedGroups implements HandshakeProducer {
 919 
 920         // Prevent instantiation of this class.
 921         private EESupportedGroupsProducer() {
 922             // blank
 923         }
 924 
 925         @Override
 926         public byte[] produce(ConnectionContext context,
 927                 HandshakeMessage message) throws IOException {
 928             // The producing happens in server side only.
 929             ServerHandshakeContext shc = (ServerHandshakeContext)context;
 930 
 931             // Is it a supported and enabled extension?
 932             if (!shc.sslConfig.isAvailable(EE_SUPPORTED_GROUPS)) {
 933                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 934                     SSLLogger.fine(
 935                         "Ignore unavailable supported_groups extension");
 936                 }
 937                 return null;
 938             }
 939 
 940             // Produce the extension.
 941             //
 942             // Contains all groups the server supports, regardless of whether
 943             // they are currently supported by the client.
 944             ArrayList<NamedGroup> namedGroups = new ArrayList<>(
 945                     SupportedGroups.supportedNamedGroups.length);
 946             for (NamedGroup ng : SupportedGroups.supportedNamedGroups) {
 947                 if ((!SupportedGroups.enableFFDHE) &&
 948                     (ng.type == NamedGroupType.NAMED_GROUP_FFDHE)) {
 949                     continue;
 950                 }
 951 
 952                 if (ng.isAvailable(shc.activeProtocols) &&
 953                         ng.isSupported(shc.activeCipherSuites) &&
 954                         shc.algorithmConstraints.permits(
 955                             EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
 956                             ng.algorithm, namedGroupParams.get(ng))) {
 957                     namedGroups.add(ng);
 958                 } else if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 959                     SSLLogger.fine(
 960                         "Ignore inactive or disabled named group: " + ng.name);
 961                 }
 962             }
 963 
 964             if (namedGroups.isEmpty()) {
 965                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 966                     SSLLogger.warning("no available named group");
 967                 }
 968 
 969                 return null;



 970             }
 971 
 972             int vectorLen = namedGroups.size() << 1;
 973             byte[] extData = new byte[vectorLen + 2];
 974             ByteBuffer m = ByteBuffer.wrap(extData);
 975             Record.putInt16(m, vectorLen);
 976             for (NamedGroup namedGroup : namedGroups) {
 977                     Record.putInt16(m, namedGroup.id);
 978             }
 979 
 980             // Update the context.
 981             shc.conContext.serverRequestedNamedGroups =
 982                     Collections.<NamedGroup>unmodifiableList(namedGroups);
 983             SupportedGroupsSpec spec = new SupportedGroupsSpec(namedGroups);
 984             shc.handshakeExtensions.put(EE_SUPPORTED_GROUPS, spec);
 985 
 986             return extData;
 987         }
 988     }
 989 
 990     private static final
 991             class EESupportedGroupsConsumer implements ExtensionConsumer {
 992         // Prevent instantiation of this class.
 993         private EESupportedGroupsConsumer() {
 994             // blank
 995         }
 996 
 997         @Override
 998         public void consume(ConnectionContext context,
 999             HandshakeMessage message, ByteBuffer buffer) throws IOException {
1000             // The comsuming happens in client side only.
1001             ClientHandshakeContext chc = (ClientHandshakeContext)context;
1002 
1003             // Is it a supported and enabled extension?
1004             if (!chc.sslConfig.isAvailable(EE_SUPPORTED_GROUPS)) {
1005                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
1006                     SSLLogger.fine(
1007                         "Ignore unavailable supported_groups extension");
1008                 }
1009                 return;     // ignore the extension
1010             }
1011 
1012             // Parse the extension.
1013             SupportedGroupsSpec spec;
1014             try {
1015                 spec = new SupportedGroupsSpec(buffer);
1016             } catch (IOException ioe) {
1017                 chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe);
1018                 return;     // fatal() always throws, make the compiler happy.
1019             }
1020 
1021             // Update the context.
1022             List<NamedGroup> knownNamedGroups =
1023                     new ArrayList<>(spec.namedGroupsIds.length);
1024             for (int id : spec.namedGroupsIds) {
1025                 NamedGroup ng = NamedGroup.valueOf(id);
1026                 if (ng != null) {
1027                     knownNamedGroups.add(ng);
1028                 }
1029             }
1030 
1031             chc.conContext.serverRequestedNamedGroups = knownNamedGroups;
1032             chc.handshakeExtensions.put(EE_SUPPORTED_GROUPS, spec);
1033 
1034             // No impact on session resumption.
1035         }
1036     }
1037 }
< prev index next >