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.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 56 /** 57 * Pack of the "supported_groups" extensions [RFC 4492/7919]. 58 */ 59 final class SupportedGroupsExtension { 60 static final HandshakeProducer chNetworkProducer = 61 new CHSupportedGroupsProducer(); 62 static final ExtensionConsumer chOnLoadConsumer = 63 new CHSupportedGroupsConsumer(); 64 static final SSLStringizer sgsStringizer = 65 new SupportedGroupsStringizer(); 66 67 static final HandshakeProducer eeNetworkProducer = 68 new EESupportedGroupsProducer(); 69 static final ExtensionConsumer eeOnLoadConsumer = 70 new EESupportedGroupsConsumer(); 71 72 /** 73 * The "supported_groups" extension. 74 */ 75 static final class SupportedGroupsSpec implements SSLExtensionSpec { 76 final int[] namedGroupsIds; 77 78 private SupportedGroupsSpec(int[] namedGroupsIds) { 79 this.namedGroupsIds = namedGroupsIds; 80 } 81 82 private SupportedGroupsSpec(List<NamedGroup> namedGroups) { 83 this.namedGroupsIds = new int[namedGroups.size()]; 84 int i = 0; 85 for (NamedGroup ng : namedGroups) { 86 namedGroupsIds[i++] = ng.id; 87 } 88 } 89 90 private SupportedGroupsSpec(ByteBuffer m) throws IOException { 91 if (m.remaining() < 2) { // 2: the length of the list 92 throw new SSLProtocolException( 93 "Invalid supported_groups extension: insufficient data"); 94 } 95 96 byte[] ngs = Record.getBytes16(m); 97 if (m.hasRemaining()) { 98 throw new SSLProtocolException( 99 "Invalid supported_groups extension: unknown extra data"); 100 } 101 102 if ((ngs == null) || (ngs.length == 0) || (ngs.length % 2 != 0)) { 103 throw new SSLProtocolException( 104 "Invalid supported_groups extension: incomplete data"); 105 } 106 107 int[] ids = new int[ngs.length / 2]; 108 for (int i = 0, j = 0; i < ngs.length;) { 109 ids[j++] = ((ngs[i++] & 0xFF) << 8) | (ngs[i++] & 0xFF); 110 } 111 112 this.namedGroupsIds = ids; 113 } 114 115 @Override 116 public String toString() { 117 MessageFormat messageFormat = new MessageFormat( 118 "\"versions\": '['{0}']'", Locale.ENGLISH); 119 120 if (namedGroupsIds == null || namedGroupsIds.length == 0) { 121 Object[] messageFields = { 122 "<no supported named group specified>" 123 }; 124 return messageFormat.format(messageFields); 125 } else { 126 StringBuilder builder = new StringBuilder(512); 127 boolean isFirst = true; 128 for (int ngid : namedGroupsIds) { 129 if (isFirst) { 130 isFirst = false; 131 } else { 132 builder.append(", "); 133 } 134 135 builder.append(NamedGroup.nameOf(ngid)); 136 } 137 138 Object[] messageFields = { 139 builder.toString() 140 }; 141 142 return messageFormat.format(messageFields); 143 } 144 } 145 } 146 147 private static final 148 class SupportedGroupsStringizer implements SSLStringizer { 149 @Override 150 public String toString(ByteBuffer buffer) { 151 try { 152 return (new SupportedGroupsSpec(buffer)).toString(); 153 } catch (IOException ioe) { 154 // For debug logging only, so please swallow exceptions. 155 return ioe.getMessage(); 156 } 157 } 158 } 159 160 static enum NamedGroupType { 161 NAMED_GROUP_ECDHE, // Elliptic Curve Groups (ECDHE) 162 NAMED_GROUP_FFDHE, // Finite Field Groups (DHE) 163 NAMED_GROUP_XDH, // Finite Field Groups (XDH) 164 NAMED_GROUP_ARBITRARY, // arbitrary prime and curves (ECDHE) 165 NAMED_GROUP_NONE; // Not predefined named group 166 167 boolean isSupported(List<CipherSuite> cipherSuites) { 168 for (CipherSuite cs : cipherSuites) { 169 if (cs.keyExchange == null || cs.keyExchange.groupType == this) { 170 return true; 171 } 172 } 173 174 return false; 175 } 176 } 177 178 static enum NamedGroup { 179 // Elliptic Curves (RFC 4492) 180 // 181 // See sun.security.util.CurveDB for the OIDs 182 // NIST K-163 183 SECT163_K1 (0x0001, "sect163k1", "1.3.132.0.1", true, 184 ProtocolVersion.PROTOCOLS_TO_12), 185 SECT163_R1 (0x0002, "sect163r1", "1.3.132.0.2", false, 186 ProtocolVersion.PROTOCOLS_TO_12), 187 188 // NIST B-163 189 SECT163_R2 (0x0003, "sect163r2", "1.3.132.0.15", true, 190 ProtocolVersion.PROTOCOLS_TO_12), 191 SECT193_R1 (0x0004, "sect193r1", "1.3.132.0.24", false, 192 ProtocolVersion.PROTOCOLS_TO_12), 193 SECT193_R2 (0x0005, "sect193r2", "1.3.132.0.25", false, 194 ProtocolVersion.PROTOCOLS_TO_12), 195 196 // NIST K-233 197 SECT233_K1 (0x0006, "sect233k1", "1.3.132.0.26", true, 198 ProtocolVersion.PROTOCOLS_TO_12), 199 200 // NIST B-233 201 SECT233_R1 (0x0007, "sect233r1", "1.3.132.0.27", true, 202 ProtocolVersion.PROTOCOLS_TO_12), 203 SECT239_K1 (0x0008, "sect239k1", "1.3.132.0.3", false, 204 ProtocolVersion.PROTOCOLS_TO_12), 205 206 // NIST K-283 207 SECT283_K1 (0x0009, "sect283k1", "1.3.132.0.16", true, 208 ProtocolVersion.PROTOCOLS_TO_12), 209 210 // NIST B-283 211 SECT283_R1 (0x000A, "sect283r1", "1.3.132.0.17", true, 212 ProtocolVersion.PROTOCOLS_TO_12), 213 214 // NIST K-409 215 SECT409_K1 (0x000B, "sect409k1", "1.3.132.0.36", true, 216 ProtocolVersion.PROTOCOLS_TO_12), 217 218 // NIST B-409 219 SECT409_R1 (0x000C, "sect409r1", "1.3.132.0.37", true, 220 ProtocolVersion.PROTOCOLS_TO_12), 221 222 // NIST K-571 223 SECT571_K1 (0x000D, "sect571k1", "1.3.132.0.38", true, 224 ProtocolVersion.PROTOCOLS_TO_12), 225 226 // NIST B-571 227 SECT571_R1 (0x000E, "sect571r1", "1.3.132.0.39", true, 228 ProtocolVersion.PROTOCOLS_TO_12), 229 SECP160_K1 (0x000F, "secp160k1", "1.3.132.0.9", false, 230 ProtocolVersion.PROTOCOLS_TO_12), 231 SECP160_R1 (0x0010, "secp160r1", "1.3.132.0.8", false, 232 ProtocolVersion.PROTOCOLS_TO_12), 233 SECP160_R2 (0x0011, "secp160r2", "1.3.132.0.30", false, 234 ProtocolVersion.PROTOCOLS_TO_12), 235 SECP192_K1 (0x0012, "secp192k1", "1.3.132.0.31", false, 236 ProtocolVersion.PROTOCOLS_TO_12), 237 238 // NIST P-192 239 SECP192_R1 (0x0013, "secp192r1", "1.2.840.10045.3.1.1", true, 240 ProtocolVersion.PROTOCOLS_TO_12), 241 SECP224_K1 (0x0014, "secp224k1", "1.3.132.0.32", false, 242 ProtocolVersion.PROTOCOLS_TO_12), 243 // NIST P-224 244 SECP224_R1 (0x0015, "secp224r1", "1.3.132.0.33", true, 245 ProtocolVersion.PROTOCOLS_TO_12), 246 SECP256_K1 (0x0016, "secp256k1", "1.3.132.0.10", false, 247 ProtocolVersion.PROTOCOLS_TO_12), 248 249 // NIST P-256 250 SECP256_R1 (0x0017, "secp256r1", "1.2.840.10045.3.1.7", true, 251 ProtocolVersion.PROTOCOLS_TO_13), 252 253 // NIST P-384 254 SECP384_R1 (0x0018, "secp384r1", "1.3.132.0.34", true, 255 ProtocolVersion.PROTOCOLS_TO_13), 256 257 // NIST P-521 258 SECP521_R1 (0x0019, "secp521r1", "1.3.132.0.35", true, 259 ProtocolVersion.PROTOCOLS_TO_13), 260 261 // x25519 and x448 262 X25519 (0x001D, "x25519", true, "x25519", 263 ProtocolVersion.PROTOCOLS_TO_13), 264 X448 (0x001E, "x448", true, "x448", 265 ProtocolVersion.PROTOCOLS_TO_13), 266 267 // Finite Field Diffie-Hellman Ephemeral Parameters (RFC 7919) 268 FFDHE_2048 (0x0100, "ffdhe2048", true, 269 ProtocolVersion.PROTOCOLS_TO_13), 270 FFDHE_3072 (0x0101, "ffdhe3072", true, 271 ProtocolVersion.PROTOCOLS_TO_13), 272 FFDHE_4096 (0x0102, "ffdhe4096", true, 273 ProtocolVersion.PROTOCOLS_TO_13), 274 FFDHE_6144 (0x0103, "ffdhe6144", true, 275 ProtocolVersion.PROTOCOLS_TO_13), 276 FFDHE_8192 (0x0104, "ffdhe8192", true, 277 ProtocolVersion.PROTOCOLS_TO_13), 278 279 // Elliptic Curves (RFC 4492) 280 // 281 // arbitrary prime and characteristic-2 curves 282 ARBITRARY_PRIME (0xFF01, "arbitrary_explicit_prime_curves", 283 ProtocolVersion.PROTOCOLS_TO_12), 284 ARBITRARY_CHAR2 (0xFF02, "arbitrary_explicit_char2_curves", 285 ProtocolVersion.PROTOCOLS_TO_12); 286 287 final int id; // hash + signature 288 final NamedGroupType type; // group type 289 final String name; // literal name 290 final String oid; // object identifier of the named group 291 final String algorithm; // signature algorithm 292 final boolean isFips; // can be used in FIPS mode? 293 final ProtocolVersion[] supportedProtocols; 294 295 // Constructor used for Elliptic Curve Groups (ECDHE) 296 private NamedGroup(int id, String name, String oid, boolean isFips, 297 ProtocolVersion[] supportedProtocols) { 298 this.id = id; 299 this.type = NamedGroupType.NAMED_GROUP_ECDHE; 300 this.name = name; 301 this.oid = oid; 302 this.algorithm = "EC"; 303 this.isFips = isFips; 304 this.supportedProtocols = supportedProtocols; 305 } 306 307 // Constructor used for Elliptic Curve Groups (XDH) 308 private NamedGroup(int id, String name, 309 boolean isFips, String algorithm, 310 ProtocolVersion[] supportedProtocols) { 311 this.id = id; 312 this.type = NamedGroupType.NAMED_GROUP_XDH; 313 this.name = name; 314 this.oid = null; 315 this.algorithm = algorithm; 316 this.isFips = isFips; 317 this.supportedProtocols = supportedProtocols; 318 } 319 320 // Constructor used for Finite Field Diffie-Hellman Groups (FFDHE) 321 private NamedGroup(int id, String name, boolean isFips, 322 ProtocolVersion[] supportedProtocols) { 323 this.id = id; 324 this.type = NamedGroupType.NAMED_GROUP_FFDHE; 325 this.name = name; 326 this.oid = null; 327 this.algorithm = "DiffieHellman"; 328 this.isFips = isFips; 329 this.supportedProtocols = supportedProtocols; 330 } 331 332 // Constructor used for arbitrary prime and curves (ECDHE) 333 private NamedGroup(int id, String name, 334 ProtocolVersion[] supportedProtocols) { 335 this.id = id; 336 this.type = NamedGroupType.NAMED_GROUP_ARBITRARY; 337 this.name = name; 338 this.oid = null; 339 this.algorithm = "EC"; 340 this.isFips = false; 341 this.supportedProtocols = supportedProtocols; 342 } 343 344 static NamedGroup valueOf(int id) { 345 for (NamedGroup group : NamedGroup.values()) { 346 if (group.id == id) { 347 return group; 348 } 349 } 350 351 return null; 352 } 353 354 static NamedGroup valueOf(ECParameterSpec params) { 355 String oid = JsseJce.getNamedCurveOid(params); 356 if ((oid != null) && (!oid.isEmpty())) { 357 for (NamedGroup group : NamedGroup.values()) { 358 if ((group.type == NamedGroupType.NAMED_GROUP_ECDHE) && 359 oid.equals(group.oid)) { 360 return group; 361 } 362 } 363 } 364 365 return null; 366 } 367 368 static NamedGroup valueOf(DHParameterSpec params) { 369 for (Map.Entry<NamedGroup, AlgorithmParameters> me : 370 SupportedGroups.namedGroupParams.entrySet()) { 371 NamedGroup ng = me.getKey(); 372 if (ng.type != NamedGroupType.NAMED_GROUP_FFDHE) { 373 continue; 374 } 375 376 DHParameterSpec ngParams = null; 377 AlgorithmParameters aps = me.getValue(); 378 try { 379 ngParams = aps.getParameterSpec(DHParameterSpec.class); 380 } catch (InvalidParameterSpecException ipse) { 381 // should be unlikely 382 } 383 384 if (ngParams == null) { 385 continue; 386 } 387 388 if (ngParams.getP().equals(params.getP()) && 389 ngParams.getG().equals(params.getG())) { 390 return ng; 391 } 392 } 393 394 return null; 395 } 396 397 static NamedGroup nameOf(String name) { 398 for (NamedGroup group : NamedGroup.values()) { 399 if (group.name.equals(name)) { 400 return group; 401 } 402 } 403 404 return null; 405 } 406 407 static String nameOf(int id) { 408 for (NamedGroup group : NamedGroup.values()) { 409 if (group.id == id) { 410 return group.name; 411 } 412 } 413 414 return "UNDEFINED-NAMED-GROUP(" + id + ")"; 415 } 416 417 boolean isAvailable(List<ProtocolVersion> protocolVersions) { 418 for (ProtocolVersion pv : supportedProtocols) { 419 if (protocolVersions.contains(pv)) { 420 return true; 421 } 422 } 423 return false; 424 } 425 426 boolean isAvailable(ProtocolVersion protocolVersion) { 427 for (ProtocolVersion pv : supportedProtocols) { 428 if (protocolVersion == pv) { 429 return true; 430 } 431 } 432 return false; 433 } 434 435 boolean isSupported(List<CipherSuite> cipherSuites) { 436 for (CipherSuite cs : cipherSuites) { 437 boolean isMatch = isAvailable(cs.supportedProtocols); 438 if (isMatch && (cs.keyExchange == null || 439 cs.keyExchange.groupType == type)) { 440 return true; 441 } 442 } 443 return false; 444 } 445 446 // lazy loading of parameters 447 AlgorithmParameters getParameters() { 448 return SupportedGroups.namedGroupParams.get(this); 449 } 450 451 AlgorithmParameterSpec getParameterSpec() { 452 if (this.type == NamedGroupType.NAMED_GROUP_ECDHE) { 453 return SupportedGroups.getECGenParamSpec(this); 454 } else if (this.type == NamedGroupType.NAMED_GROUP_FFDHE) { 455 return SupportedGroups.getDHParameterSpec(this); 456 } 457 458 return null; 459 } 460 } 461 462 static class SupportedGroups { 463 // To switch off the supported_groups extension for DHE cipher suite. 464 static final boolean enableFFDHE = 465 Utilities.getBooleanProperty("jsse.enableFFDHE", true); 466 467 // cache to speed up the parameters construction 468 static final Map<NamedGroup, 469 AlgorithmParameters> namedGroupParams = new HashMap<>(); 470 471 // the supported named groups 472 static final NamedGroup[] supportedNamedGroups; 473 474 static { 475 boolean requireFips = SunJSSE.isFIPS(); 476 477 // The value of the System Property defines a list of enabled named 478 // groups in preference order, separated with comma. For example: 479 // 480 // jdk.tls.namedGroups="secp521r1, secp256r1, ffdhe2048" 481 // 482 // If the System Property is not defined or the value is empty, the 483 // default groups and preferences will be used. 484 String property = GetPropertyAction 485 .privilegedGetProperty("jdk.tls.namedGroups"); 486 if (property != null && property.length() != 0) { 487 // remove double quote marks from beginning/end of the property 488 if (property.length() > 1 && property.charAt(0) == '"' && 489 property.charAt(property.length() - 1) == '"') { 490 property = property.substring(1, property.length() - 1); 491 } 492 } 493 494 ArrayList<NamedGroup> groupList; 495 if (property != null && property.length() != 0) { 496 String[] groups = property.split(","); 497 groupList = new ArrayList<>(groups.length); 498 for (String group : groups) { 499 group = group.trim(); 500 if (!group.isEmpty()) { 501 NamedGroup namedGroup = NamedGroup.nameOf(group); 502 if (namedGroup != null && 503 (!requireFips || namedGroup.isFips)) { 504 if (isAvailableGroup(namedGroup)) { 505 groupList.add(namedGroup); 506 } 507 } // ignore unknown groups 508 } 509 } 510 511 if (groupList.isEmpty()) { 512 throw new IllegalArgumentException( 513 "System property jdk.tls.namedGroups(" + 514 property + ") contains no supported named groups"); 515 } 516 } else { // default groups 517 NamedGroup[] groups; 518 if (requireFips) { 519 groups = new NamedGroup[] { 520 // only NIST curves in FIPS mode 521 NamedGroup.SECP256_R1, 522 NamedGroup.SECP384_R1, 523 NamedGroup.SECP521_R1, 524 NamedGroup.SECT283_K1, 525 NamedGroup.SECT283_R1, 526 NamedGroup.SECT409_K1, 527 NamedGroup.SECT409_R1, 528 NamedGroup.SECT571_K1, 529 NamedGroup.SECT571_R1, 530 531 // FFDHE 2048 532 NamedGroup.FFDHE_2048, 533 NamedGroup.FFDHE_3072, 534 NamedGroup.FFDHE_4096, 535 NamedGroup.FFDHE_6144, 536 NamedGroup.FFDHE_8192, 537 }; 538 } else { 539 groups = new NamedGroup[] { 540 // NIST curves first 541 NamedGroup.SECP256_R1, 542 NamedGroup.SECP384_R1, 543 NamedGroup.SECP521_R1, 544 NamedGroup.SECT283_K1, 545 NamedGroup.SECT283_R1, 546 NamedGroup.SECT409_K1, 547 NamedGroup.SECT409_R1, 548 NamedGroup.SECT571_K1, 549 NamedGroup.SECT571_R1, 550 551 // non-NIST curves 552 NamedGroup.SECP256_K1, 553 554 // FFDHE 2048 555 NamedGroup.FFDHE_2048, 556 NamedGroup.FFDHE_3072, 557 NamedGroup.FFDHE_4096, 558 NamedGroup.FFDHE_6144, 559 NamedGroup.FFDHE_8192, 560 }; 561 } 562 563 groupList = new ArrayList<>(groups.length); 564 for (NamedGroup group : groups) { 565 if (isAvailableGroup(group)) { 566 groupList.add(group); 567 } 568 } 569 570 if (groupList.isEmpty() && 571 SSLLogger.isOn && SSLLogger.isOn("ssl")) { 572 SSLLogger.warning("No default named groups"); 573 } 574 } 575 576 supportedNamedGroups = new NamedGroup[groupList.size()]; 577 int i = 0; 578 for (NamedGroup namedGroup : groupList) { 579 supportedNamedGroups[i++] = namedGroup; 580 } 581 } 582 583 // check whether the group is supported by the underlying providers 584 private static boolean isAvailableGroup(NamedGroup namedGroup) { 585 AlgorithmParameters params = null; 586 AlgorithmParameterSpec spec = null; 587 if (namedGroup.type == NamedGroupType.NAMED_GROUP_ECDHE) { 588 if (namedGroup.oid != null) { 589 try { 590 params = JsseJce.getAlgorithmParameters("EC"); 591 spec = new ECGenParameterSpec(namedGroup.oid); 592 } catch (NoSuchAlgorithmException e) { 593 return false; 594 } 595 } 596 } else if (namedGroup.type == NamedGroupType.NAMED_GROUP_FFDHE) { 597 try { 598 params = JsseJce.getAlgorithmParameters("DiffieHellman"); 599 spec = getFFDHEDHParameterSpec(namedGroup); 600 } catch (NoSuchAlgorithmException e) { 601 return false; 602 } 603 } // Otherwise, unsupported. 604 605 if ((params != null) && (spec != null)) { 606 try { 607 params.init(spec); 608 } catch (InvalidParameterSpecException e) { 609 return false; 610 } 611 612 // cache the parameters 613 namedGroupParams.put(namedGroup, params); 614 615 return true; 616 } 617 618 return false; 619 } 620 621 private static DHParameterSpec getFFDHEDHParameterSpec( 622 NamedGroup namedGroup) { 623 DHParameterSpec spec = null; 624 switch (namedGroup) { 625 case FFDHE_2048: 626 spec = PredefinedDHParameterSpecs.ffdheParams.get(2048); 627 break; 628 case FFDHE_3072: 629 spec = PredefinedDHParameterSpecs.ffdheParams.get(3072); 630 break; 631 case FFDHE_4096: 632 spec = PredefinedDHParameterSpecs.ffdheParams.get(4096); 633 break; 634 case FFDHE_6144: 635 spec = PredefinedDHParameterSpecs.ffdheParams.get(6144); 636 break; 637 case FFDHE_8192: 638 spec = PredefinedDHParameterSpecs.ffdheParams.get(8192); 639 } 640 641 return spec; 642 } 643 644 private static DHParameterSpec getPredefinedDHParameterSpec( 645 NamedGroup namedGroup) { 646 DHParameterSpec spec = null; 647 switch (namedGroup) { 648 case FFDHE_2048: 649 spec = PredefinedDHParameterSpecs.definedParams.get(2048); 650 break; 651 case FFDHE_3072: 652 spec = PredefinedDHParameterSpecs.definedParams.get(3072); 653 break; 654 case FFDHE_4096: 655 spec = PredefinedDHParameterSpecs.definedParams.get(4096); 656 break; 657 case FFDHE_6144: 658 spec = PredefinedDHParameterSpecs.definedParams.get(6144); 659 break; 660 case FFDHE_8192: 661 spec = PredefinedDHParameterSpecs.definedParams.get(8192); 662 } 663 664 return spec; 665 } 666 667 static ECGenParameterSpec getECGenParamSpec(NamedGroup namedGroup) { 668 if (namedGroup.type != NamedGroupType.NAMED_GROUP_ECDHE) { 669 throw new RuntimeException( 670 "Not a named EC group: " + namedGroup); 671 } 672 673 AlgorithmParameters params = namedGroupParams.get(namedGroup); 674 if (params == null) { 675 throw new RuntimeException( 676 "Not a supported EC named group: " + namedGroup); 677 } 678 679 try { 680 return params.getParameterSpec(ECGenParameterSpec.class); 681 } catch (InvalidParameterSpecException ipse) { 682 // should be unlikely 683 return new ECGenParameterSpec(namedGroup.oid); 684 } 685 } 686 687 static DHParameterSpec getDHParameterSpec(NamedGroup namedGroup) { 688 if (namedGroup.type != NamedGroupType.NAMED_GROUP_FFDHE) { 689 throw new RuntimeException( 690 "Not a named DH group: " + namedGroup); 691 } 692 693 AlgorithmParameters params = namedGroupParams.get(namedGroup); 694 if (params == null) { 695 throw new RuntimeException( 696 "Not a supported DH named group: " + namedGroup); 697 } 698 699 try { 700 return params.getParameterSpec(DHParameterSpec.class); 701 } catch (InvalidParameterSpecException ipse) { 702 // should be unlikely 703 return getPredefinedDHParameterSpec(namedGroup); 704 } 705 } 706 707 // Is there any supported group permitted by the constraints? 708 static boolean isActivatable( 709 AlgorithmConstraints constraints, NamedGroupType type) { 710 711 boolean hasFFDHEGroups = false; 712 for (NamedGroup namedGroup : supportedNamedGroups) { 713 if (namedGroup.type == type) { 714 if (constraints.permits( 715 EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), 716 namedGroup.algorithm, 717 namedGroupParams.get(namedGroup))) { 718 719 return true; 720 } 721 722 if (!hasFFDHEGroups && 723 (type == NamedGroupType.NAMED_GROUP_FFDHE)) { 724 hasFFDHEGroups = true; 725 } 726 } 727 } 728 729 // For compatibility, if no FFDHE groups are defined, the non-FFDHE 730 // compatible mode (using DHE cipher suite without FFDHE extension) 731 // is allowed. 732 // 733 // Note that the constraints checking on DHE parameters will be 734 // performed during key exchanging in a handshake. 735 return !hasFFDHEGroups && type == NamedGroupType.NAMED_GROUP_FFDHE; 736 } 737 738 // Is the named group permitted by the constraints? 739 static boolean isActivatable( 740 AlgorithmConstraints constraints, NamedGroup namedGroup) { 741 if (!isSupported(namedGroup)) { 742 return false; 743 } 744 745 return constraints.permits( 746 EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), 747 namedGroup.algorithm, 748 namedGroupParams.get(namedGroup)); 749 } 750 751 // Is the named group supported? 752 static boolean isSupported(NamedGroup namedGroup) { 753 for (NamedGroup group : supportedNamedGroups) { 754 if (namedGroup.id == group.id) { 755 return true; 756 } 757 } 758 759 return false; 760 } 761 762 static NamedGroup getPreferredGroup( 763 ProtocolVersion negotiatedProtocol, 764 AlgorithmConstraints constraints, NamedGroupType type, 765 List<NamedGroup> requestedNamedGroups) { 766 for (NamedGroup namedGroup : requestedNamedGroups) { 767 if ((namedGroup.type == type) && 768 namedGroup.isAvailable(negotiatedProtocol) && 769 isSupported(namedGroup) && 770 constraints.permits( 771 EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), 772 namedGroup.algorithm, 773 namedGroupParams.get(namedGroup))) { 774 return namedGroup; 775 } 776 } 777 778 return null; 779 } 780 781 static NamedGroup getPreferredGroup( 782 ProtocolVersion negotiatedProtocol, 783 AlgorithmConstraints constraints, NamedGroupType type) { 784 for (NamedGroup namedGroup : supportedNamedGroups) { 785 if ((namedGroup.type == type) && 786 namedGroup.isAvailable(negotiatedProtocol) && 787 constraints.permits( 788 EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), 789 namedGroup.algorithm, 790 namedGroupParams.get(namedGroup))) { 791 return namedGroup; 792 } 793 } 794 795 return null; 796 } 797 } 798 799 /** 800 * Network data producer of a "supported_groups" extension in 801 * the ClientHello handshake message. 802 */ 803 private static final class CHSupportedGroupsProducer 804 extends SupportedGroups implements HandshakeProducer { 805 // Prevent instantiation of this class. 806 private CHSupportedGroupsProducer() { 807 // blank 808 } 809 810 @Override 811 public byte[] produce(ConnectionContext context, 812 HandshakeMessage message) throws IOException { 813 // The producing happens in client side only. 814 ClientHandshakeContext chc = (ClientHandshakeContext)context; 815 816 // Is it a supported and enabled extension? 817 if (!chc.sslConfig.isAvailable(CH_SUPPORTED_GROUPS)) { 818 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 819 SSLLogger.fine( 820 "Ignore unavailable supported_groups extension"); 821 } 822 return null; 823 } 824 825 // Produce the extension. 826 ArrayList<NamedGroup> namedGroups = 827 new ArrayList<>(SupportedGroups.supportedNamedGroups.length); 828 for (NamedGroup ng : SupportedGroups.supportedNamedGroups) { 829 if ((!SupportedGroups.enableFFDHE) && 830 (ng.type == NamedGroupType.NAMED_GROUP_FFDHE)) { 831 continue; 832 } 833 834 if (ng.isAvailable(chc.activeProtocols) && 835 ng.isSupported(chc.activeCipherSuites) && 836 chc.algorithmConstraints.permits( 837 EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), 838 ng.algorithm, namedGroupParams.get(ng))) { 839 namedGroups.add(ng); 840 } else if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 841 SSLLogger.fine( 842 "Ignore inactive or disabled named group: " + ng.name); 843 } 844 } 845 846 if (namedGroups.isEmpty()) { 847 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 848 SSLLogger.warning("no available named group"); 849 } 850 851 return null; 852 } 853 854 int vectorLen = namedGroups.size() << 1; 855 byte[] extData = new byte[vectorLen + 2]; 856 ByteBuffer m = ByteBuffer.wrap(extData); 857 Record.putInt16(m, vectorLen); 858 for (NamedGroup namedGroup : namedGroups) { 859 Record.putInt16(m, namedGroup.id); 860 } 861 862 // Update the context. 863 chc.clientRequestedNamedGroups = 864 Collections.<NamedGroup>unmodifiableList(namedGroups); 865 chc.handshakeExtensions.put(CH_SUPPORTED_GROUPS, 866 new SupportedGroupsSpec(namedGroups)); 867 868 return extData; 869 } 870 } 871 872 /** 873 * Network data producer of a "supported_groups" extension in 874 * the ClientHello handshake message. 875 */ 876 private static final 877 class CHSupportedGroupsConsumer implements ExtensionConsumer { 878 // Prevent instantiation of this class. 879 private CHSupportedGroupsConsumer() { 880 // blank 881 } 882 883 @Override 884 public void consume(ConnectionContext context, 885 HandshakeMessage message, ByteBuffer buffer) throws IOException { 886 // The consuming happens in server side only. 887 ServerHandshakeContext shc = (ServerHandshakeContext)context; 888 889 // Is it a supported and enabled extension? 890 if (!shc.sslConfig.isAvailable(CH_SUPPORTED_GROUPS)) { 891 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 892 SSLLogger.fine( 893 "Ignore unavailable supported_groups extension"); 894 } 895 return; // ignore the extension 896 } 897 898 // Parse the extension. 899 SupportedGroupsSpec spec; 900 try { 901 spec = new SupportedGroupsSpec(buffer); 902 } catch (IOException ioe) { 903 shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe); 904 return; // fatal() always throws, make the compiler happy. 905 } 906 907 // Update the context. 908 List<NamedGroup> knownNamedGroups = new LinkedList<>(); 909 for (int id : spec.namedGroupsIds) { 910 NamedGroup ng = NamedGroup.valueOf(id); 911 if (ng != null) { 912 knownNamedGroups.add(ng); 913 } 914 } 915 916 shc.clientRequestedNamedGroups = knownNamedGroups; 917 shc.handshakeExtensions.put(CH_SUPPORTED_GROUPS, spec); 918 919 // No impact on session resumption. 920 } 921 } 922 923 /** 924 * Network data producer of a "supported_groups" extension in 925 * the EncryptedExtensions handshake message. 926 */ 927 private static final class EESupportedGroupsProducer 928 extends SupportedGroups implements HandshakeProducer { 929 930 // Prevent instantiation of this class. 931 private EESupportedGroupsProducer() { 932 // blank 933 } 934 935 @Override 936 public byte[] produce(ConnectionContext context, 937 HandshakeMessage message) throws IOException { 938 // The producing happens in server side only. 939 ServerHandshakeContext shc = (ServerHandshakeContext)context; 940 941 // Is it a supported and enabled extension? 942 if (!shc.sslConfig.isAvailable(EE_SUPPORTED_GROUPS)) { 943 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 944 SSLLogger.fine( 945 "Ignore unavailable supported_groups extension"); 946 } 947 return null; 948 } 949 950 // Produce the extension. 951 // 952 // Contains all groups the server supports, regardless of whether 953 // they are currently supported by the client. 954 ArrayList<NamedGroup> namedGroups = new ArrayList<>( 955 SupportedGroups.supportedNamedGroups.length); 956 for (NamedGroup ng : SupportedGroups.supportedNamedGroups) { 957 if ((!SupportedGroups.enableFFDHE) && 958 (ng.type == NamedGroupType.NAMED_GROUP_FFDHE)) { 959 continue; 960 } 961 962 if (ng.isAvailable(shc.activeProtocols) && 963 ng.isSupported(shc.activeCipherSuites) && 964 shc.algorithmConstraints.permits( 965 EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), 966 ng.algorithm, namedGroupParams.get(ng))) { 967 namedGroups.add(ng); 968 } else if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 969 SSLLogger.fine( 970 "Ignore inactive or disabled named group: " + ng.name); 971 } 972 } 973 974 if (namedGroups.isEmpty()) { 975 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 976 SSLLogger.warning("no available named group"); 977 } 978 979 return null; 980 } 981 982 int vectorLen = namedGroups.size() << 1; 983 byte[] extData = new byte[vectorLen + 2]; 984 ByteBuffer m = ByteBuffer.wrap(extData); 985 Record.putInt16(m, vectorLen); 986 for (NamedGroup namedGroup : namedGroups) { 987 Record.putInt16(m, namedGroup.id); 988 } 989 990 // Update the context. 991 shc.conContext.serverRequestedNamedGroups = 992 Collections.<NamedGroup>unmodifiableList(namedGroups); 993 SupportedGroupsSpec spec = new SupportedGroupsSpec(namedGroups); 994 shc.handshakeExtensions.put(EE_SUPPORTED_GROUPS, spec); 995 996 return extData; 997 } 998 } 999 1000 private static final 1001 class EESupportedGroupsConsumer implements ExtensionConsumer { 1002 // Prevent instantiation of this class. 1003 private EESupportedGroupsConsumer() { 1004 // blank 1005 } 1006 1007 @Override 1008 public void consume(ConnectionContext context, 1009 HandshakeMessage message, ByteBuffer buffer) throws IOException { 1010 // The consuming happens in client side only. 1011 ClientHandshakeContext chc = (ClientHandshakeContext)context; 1012 1013 // Is it a supported and enabled extension? 1014 if (!chc.sslConfig.isAvailable(EE_SUPPORTED_GROUPS)) { 1015 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 1016 SSLLogger.fine( 1017 "Ignore unavailable supported_groups extension"); 1018 } 1019 return; // ignore the extension 1020 } 1021 1022 // Parse the extension. 1023 SupportedGroupsSpec spec; 1024 try { 1025 spec = new SupportedGroupsSpec(buffer); 1026 } catch (IOException ioe) { 1027 chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe); 1028 return; // fatal() always throws, make the compiler happy. 1029 } 1030 1031 // Update the context. 1032 List<NamedGroup> knownNamedGroups = 1033 new ArrayList<>(spec.namedGroupsIds.length); 1034 for (int id : spec.namedGroupsIds) { 1035 NamedGroup ng = NamedGroup.valueOf(id); 1036 if (ng != null) { 1037 knownNamedGroups.add(ng); 1038 } 1039 } 1040 1041 chc.conContext.serverRequestedNamedGroups = knownNamedGroups; 1042 chc.handshakeExtensions.put(EE_SUPPORTED_GROUPS, spec); 1043 1044 // No impact on session resumption. 1045 } 1046 } 1047 }