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 SupportedGroupsSpec(int[] namedGroupsIds)78 private SupportedGroupsSpec(int[] namedGroupsIds) { 79 this.namedGroupsIds = namedGroupsIds; 80 } 81 SupportedGroupsSpec(List<NamedGroup> namedGroups)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 SupportedGroupsSpec(ByteBuffer m)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 toString()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 toString(ByteBuffer buffer)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 isSupported(List<CipherSuite> cipherSuites)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 final boolean isEcAvailable; 295 296 // Constructor used for Elliptic Curve Groups (ECDHE) NamedGroup(int id, String name, String oid, boolean isFips, ProtocolVersion[] supportedProtocols)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 this.isEcAvailable = JsseJce.isEcAvailable(); 307 } 308 309 // Constructor used for Elliptic Curve Groups (XDH) NamedGroup(int id, String name, boolean isFips, String algorithm, ProtocolVersion[] supportedProtocols)310 private NamedGroup(int id, String name, 311 boolean isFips, String algorithm, 312 ProtocolVersion[] supportedProtocols) { 313 this.id = id; 314 this.type = NamedGroupType.NAMED_GROUP_XDH; 315 this.name = name; 316 this.oid = null; 317 this.algorithm = algorithm; 318 this.isFips = isFips; 319 this.supportedProtocols = supportedProtocols; 320 this.isEcAvailable = true; // Don't care. 321 } 322 323 // Constructor used for Finite Field Diffie-Hellman Groups (FFDHE) NamedGroup(int id, String name, boolean isFips, ProtocolVersion[] supportedProtocols)324 private NamedGroup(int id, String name, boolean isFips, 325 ProtocolVersion[] supportedProtocols) { 326 this.id = id; 327 this.type = NamedGroupType.NAMED_GROUP_FFDHE; 328 this.name = name; 329 this.oid = null; 330 this.algorithm = "DiffieHellman"; 331 this.isFips = isFips; 332 this.supportedProtocols = supportedProtocols; 333 this.isEcAvailable = true; // Don't care. 334 } 335 336 // Constructor used for arbitrary prime and curves (ECDHE) NamedGroup(int id, String name, ProtocolVersion[] supportedProtocols)337 private NamedGroup(int id, String name, 338 ProtocolVersion[] supportedProtocols) { 339 this.id = id; 340 this.type = NamedGroupType.NAMED_GROUP_ARBITRARY; 341 this.name = name; 342 this.oid = null; 343 this.algorithm = "EC"; 344 this.isFips = false; 345 this.supportedProtocols = supportedProtocols; 346 this.isEcAvailable = true; // JsseJce.isEcAvailable(); 347 } 348 valueOf(int id)349 static NamedGroup valueOf(int id) { 350 for (NamedGroup group : NamedGroup.values()) { 351 if (group.id == id) { 352 return group; 353 } 354 } 355 356 return null; 357 } 358 valueOf(ECParameterSpec params)359 static NamedGroup valueOf(ECParameterSpec params) { 360 String oid = JsseJce.getNamedCurveOid(params); 361 if ((oid != null) && (!oid.isEmpty())) { 362 for (NamedGroup group : NamedGroup.values()) { 363 if ((group.type == NamedGroupType.NAMED_GROUP_ECDHE) && 364 oid.equals(group.oid)) { 365 return group; 366 } 367 } 368 } 369 370 return null; 371 } 372 valueOf(DHParameterSpec params)373 static NamedGroup valueOf(DHParameterSpec params) { 374 for (Map.Entry<NamedGroup, AlgorithmParameters> me : 375 SupportedGroups.namedGroupParams.entrySet()) { 376 NamedGroup ng = me.getKey(); 377 if (ng.type != NamedGroupType.NAMED_GROUP_FFDHE) { 378 continue; 379 } 380 381 DHParameterSpec ngParams = null; 382 AlgorithmParameters aps = me.getValue(); 383 try { 384 ngParams = aps.getParameterSpec(DHParameterSpec.class); 385 } catch (InvalidParameterSpecException ipse) { 386 // should be unlikely 387 } 388 389 if (ngParams == null) { 390 continue; 391 } 392 393 if (ngParams.getP().equals(params.getP()) && 394 ngParams.getG().equals(params.getG())) { 395 return ng; 396 } 397 } 398 399 return null; 400 } 401 nameOf(String name)402 static NamedGroup nameOf(String name) { 403 for (NamedGroup group : NamedGroup.values()) { 404 if (group.name.equals(name)) { 405 return group; 406 } 407 } 408 409 return null; 410 } 411 nameOf(int id)412 static String nameOf(int id) { 413 for (NamedGroup group : NamedGroup.values()) { 414 if (group.id == id) { 415 return group.name; 416 } 417 } 418 419 return "UNDEFINED-NAMED-GROUP(" + id + ")"; 420 } 421 isAvailable(List<ProtocolVersion> protocolVersions)422 boolean isAvailable(List<ProtocolVersion> protocolVersions) { 423 if (this.isEcAvailable) { 424 for (ProtocolVersion pv : supportedProtocols) { 425 if (protocolVersions.contains(pv)) { 426 return true; 427 } 428 } 429 } 430 return false; 431 } 432 isAvailable(ProtocolVersion protocolVersion)433 boolean isAvailable(ProtocolVersion protocolVersion) { 434 if (this.isEcAvailable) { 435 for (ProtocolVersion pv : supportedProtocols) { 436 if (protocolVersion == pv) { 437 return true; 438 } 439 } 440 } 441 return false; 442 } 443 isSupported(List<CipherSuite> cipherSuites)444 boolean isSupported(List<CipherSuite> cipherSuites) { 445 for (CipherSuite cs : cipherSuites) { 446 boolean isMatch = isAvailable(cs.supportedProtocols); 447 if (isMatch && (cs.keyExchange == null || 448 cs.keyExchange.groupType == type)) { 449 return true; 450 } 451 } 452 return false; 453 } 454 455 // lazy loading of parameters getParameters()456 AlgorithmParameters getParameters() { 457 return SupportedGroups.namedGroupParams.get(this); 458 } 459 getParameterSpec()460 AlgorithmParameterSpec getParameterSpec() { 461 if (this.type == NamedGroupType.NAMED_GROUP_ECDHE) { 462 return SupportedGroups.getECGenParamSpec(this); 463 } else if (this.type == NamedGroupType.NAMED_GROUP_FFDHE) { 464 return SupportedGroups.getDHParameterSpec(this); 465 } 466 467 return null; 468 } 469 } 470 471 static class SupportedGroups { 472 // To switch off the supported_groups extension for DHE cipher suite. 473 static final boolean enableFFDHE = 474 Utilities.getBooleanProperty("jsse.enableFFDHE", true); 475 476 // cache to speed up the parameters construction 477 static final Map<NamedGroup, 478 AlgorithmParameters> namedGroupParams = new HashMap<>(); 479 480 // the supported named groups 481 static final NamedGroup[] supportedNamedGroups; 482 483 static { 484 boolean requireFips = SunJSSE.isFIPS(); 485 486 // The value of the System Property defines a list of enabled named 487 // groups in preference order, separated with comma. For example: 488 // 489 // jdk.tls.namedGroups="secp521r1, secp256r1, ffdhe2048" 490 // 491 // If the System Property is not defined or the value is empty, the 492 // default groups and preferences will be used. 493 String property = GetPropertyAction 494 .privilegedGetProperty("jdk.tls.namedGroups"); 495 if (property != null && !property.isEmpty()) { 496 // remove double quote marks from beginning/end of the property 497 if (property.length() > 1 && property.charAt(0) == '"' && 498 property.charAt(property.length() - 1) == '"') { 499 property = property.substring(1, property.length() - 1); 500 } 501 } 502 503 ArrayList<NamedGroup> groupList; 504 if (property != null && !property.isEmpty()) { 505 String[] groups = property.split(","); 506 groupList = new ArrayList<>(groups.length); 507 for (String group : groups) { 508 group = group.trim(); 509 if (!group.isEmpty()) { 510 NamedGroup namedGroup = NamedGroup.nameOf(group); 511 if (namedGroup != null && 512 (!requireFips || namedGroup.isFips)) { 513 if (isAvailableGroup(namedGroup)) { 514 groupList.add(namedGroup); 515 } 516 } // ignore unknown groups 517 } 518 } 519 520 if (groupList.isEmpty()) { 521 throw new IllegalArgumentException( 522 "System property jdk.tls.namedGroups(" + 523 property + ") contains no supported named groups"); 524 } 525 } else { // default groups 526 NamedGroup[] groups; 527 if (requireFips) { 528 groups = new NamedGroup[] { 529 // only NIST curves in FIPS mode 530 NamedGroup.SECP256_R1, 531 NamedGroup.SECP384_R1, 532 NamedGroup.SECP521_R1, 533 534 // FFDHE 2048 535 NamedGroup.FFDHE_2048, 536 NamedGroup.FFDHE_3072, 537 NamedGroup.FFDHE_4096, 538 NamedGroup.FFDHE_6144, 539 NamedGroup.FFDHE_8192, 540 }; 541 } else { 542 groups = new NamedGroup[] { 543 // NIST curves first 544 NamedGroup.SECP256_R1, 545 NamedGroup.SECP384_R1, 546 NamedGroup.SECP521_R1, 547 548 // FFDHE 2048 549 NamedGroup.FFDHE_2048, 550 NamedGroup.FFDHE_3072, 551 NamedGroup.FFDHE_4096, 552 NamedGroup.FFDHE_6144, 553 NamedGroup.FFDHE_8192, 554 }; 555 } 556 557 groupList = new ArrayList<>(groups.length); 558 for (NamedGroup group : groups) { 559 if (isAvailableGroup(group)) { 560 groupList.add(group); 561 } 562 } 563 564 if (groupList.isEmpty() && 565 SSLLogger.isOn && SSLLogger.isOn("ssl")) { 566 SSLLogger.warning("No default named groups"); 567 } 568 } 569 570 supportedNamedGroups = new NamedGroup[groupList.size()]; 571 int i = 0; 572 for (NamedGroup namedGroup : groupList) { 573 supportedNamedGroups[i++] = namedGroup; 574 } 575 } 576 577 // check whether the group is supported by the underlying providers isAvailableGroup(NamedGroup namedGroup)578 private static boolean isAvailableGroup(NamedGroup namedGroup) { 579 AlgorithmParameters params = null; 580 AlgorithmParameterSpec spec = null; 581 if (namedGroup.type == NamedGroupType.NAMED_GROUP_ECDHE) { 582 if (namedGroup.oid != null) { 583 try { 584 params = JsseJce.getAlgorithmParameters("EC"); 585 spec = new ECGenParameterSpec(namedGroup.oid); 586 } catch (NoSuchAlgorithmException e) { 587 return false; 588 } 589 } 590 } else if (namedGroup.type == NamedGroupType.NAMED_GROUP_FFDHE) { 591 try { 592 params = JsseJce.getAlgorithmParameters("DiffieHellman"); 593 spec = getFFDHEDHParameterSpec(namedGroup); 594 } catch (NoSuchAlgorithmException e) { 595 return false; 596 } 597 } // Otherwise, unsupported. 598 599 if ((params != null) && (spec != null)) { 600 try { 601 params.init(spec); 602 } catch (InvalidParameterSpecException e) { 603 return false; 604 } 605 606 // cache the parameters 607 namedGroupParams.put(namedGroup, params); 608 609 return true; 610 } 611 612 return false; 613 } 614 getFFDHEDHParameterSpec( NamedGroup namedGroup)615 private static DHParameterSpec getFFDHEDHParameterSpec( 616 NamedGroup namedGroup) { 617 DHParameterSpec spec = null; 618 switch (namedGroup) { 619 case FFDHE_2048: 620 spec = PredefinedDHParameterSpecs.ffdheParams.get(2048); 621 break; 622 case FFDHE_3072: 623 spec = PredefinedDHParameterSpecs.ffdheParams.get(3072); 624 break; 625 case FFDHE_4096: 626 spec = PredefinedDHParameterSpecs.ffdheParams.get(4096); 627 break; 628 case FFDHE_6144: 629 spec = PredefinedDHParameterSpecs.ffdheParams.get(6144); 630 break; 631 case FFDHE_8192: 632 spec = PredefinedDHParameterSpecs.ffdheParams.get(8192); 633 } 634 635 return spec; 636 } 637 getPredefinedDHParameterSpec( NamedGroup namedGroup)638 private static DHParameterSpec getPredefinedDHParameterSpec( 639 NamedGroup namedGroup) { 640 DHParameterSpec spec = null; 641 switch (namedGroup) { 642 case FFDHE_2048: 643 spec = PredefinedDHParameterSpecs.definedParams.get(2048); 644 break; 645 case FFDHE_3072: 646 spec = PredefinedDHParameterSpecs.definedParams.get(3072); 647 break; 648 case FFDHE_4096: 649 spec = PredefinedDHParameterSpecs.definedParams.get(4096); 650 break; 651 case FFDHE_6144: 652 spec = PredefinedDHParameterSpecs.definedParams.get(6144); 653 break; 654 case FFDHE_8192: 655 spec = PredefinedDHParameterSpecs.definedParams.get(8192); 656 } 657 658 return spec; 659 } 660 getECGenParamSpec(NamedGroup namedGroup)661 static ECGenParameterSpec getECGenParamSpec(NamedGroup namedGroup) { 662 if (namedGroup.type != NamedGroupType.NAMED_GROUP_ECDHE) { 663 throw new RuntimeException( 664 "Not a named EC group: " + namedGroup); 665 } 666 667 AlgorithmParameters params = namedGroupParams.get(namedGroup); 668 if (params == null) { 669 throw new RuntimeException( 670 "Not a supported EC named group: " + namedGroup); 671 } 672 673 try { 674 return params.getParameterSpec(ECGenParameterSpec.class); 675 } catch (InvalidParameterSpecException ipse) { 676 // should be unlikely 677 return new ECGenParameterSpec(namedGroup.oid); 678 } 679 } 680 getDHParameterSpec(NamedGroup namedGroup)681 static DHParameterSpec getDHParameterSpec(NamedGroup namedGroup) { 682 if (namedGroup.type != NamedGroupType.NAMED_GROUP_FFDHE) { 683 throw new RuntimeException( 684 "Not a named DH group: " + namedGroup); 685 } 686 687 AlgorithmParameters params = namedGroupParams.get(namedGroup); 688 if (params == null) { 689 throw new RuntimeException( 690 "Not a supported DH named group: " + namedGroup); 691 } 692 693 try { 694 return params.getParameterSpec(DHParameterSpec.class); 695 } catch (InvalidParameterSpecException ipse) { 696 // should be unlikely 697 return getPredefinedDHParameterSpec(namedGroup); 698 } 699 } 700 701 // Is there any supported group permitted by the constraints? isActivatable( AlgorithmConstraints constraints, NamedGroupType type)702 static boolean isActivatable( 703 AlgorithmConstraints constraints, NamedGroupType type) { 704 705 boolean hasFFDHEGroups = false; 706 for (NamedGroup namedGroup : supportedNamedGroups) { 707 if (namedGroup.type == type) { 708 if (constraints.permits( 709 EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), 710 namedGroup.algorithm, 711 namedGroupParams.get(namedGroup))) { 712 713 return true; 714 } 715 716 if (!hasFFDHEGroups && 717 (type == NamedGroupType.NAMED_GROUP_FFDHE)) { 718 hasFFDHEGroups = true; 719 } 720 } 721 } 722 723 // For compatibility, if no FFDHE groups are defined, the non-FFDHE 724 // compatible mode (using DHE cipher suite without FFDHE extension) 725 // is allowed. 726 // 727 // Note that the constraints checking on DHE parameters will be 728 // performed during key exchanging in a handshake. 729 return !hasFFDHEGroups && type == NamedGroupType.NAMED_GROUP_FFDHE; 730 } 731 732 // Is the named group permitted by the constraints? isActivatable( AlgorithmConstraints constraints, NamedGroup namedGroup)733 static boolean isActivatable( 734 AlgorithmConstraints constraints, NamedGroup namedGroup) { 735 if (!isSupported(namedGroup)) { 736 return false; 737 } 738 739 return constraints.permits( 740 EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), 741 namedGroup.algorithm, 742 namedGroupParams.get(namedGroup)); 743 } 744 745 // Is the named group supported? isSupported(NamedGroup namedGroup)746 static boolean isSupported(NamedGroup namedGroup) { 747 for (NamedGroup group : supportedNamedGroups) { 748 if (namedGroup.id == group.id) { 749 return true; 750 } 751 } 752 753 return false; 754 } 755 getPreferredGroup( ProtocolVersion negotiatedProtocol, AlgorithmConstraints constraints, NamedGroupType type, List<NamedGroup> requestedNamedGroups)756 static NamedGroup getPreferredGroup( 757 ProtocolVersion negotiatedProtocol, 758 AlgorithmConstraints constraints, NamedGroupType type, 759 List<NamedGroup> requestedNamedGroups) { 760 for (NamedGroup namedGroup : requestedNamedGroups) { 761 if ((namedGroup.type == type) && 762 namedGroup.isAvailable(negotiatedProtocol) && 763 isSupported(namedGroup) && 764 constraints.permits( 765 EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), 766 namedGroup.algorithm, 767 namedGroupParams.get(namedGroup))) { 768 return namedGroup; 769 } 770 } 771 772 return null; 773 } 774 getPreferredGroup( ProtocolVersion negotiatedProtocol, AlgorithmConstraints constraints, NamedGroupType type)775 static NamedGroup getPreferredGroup( 776 ProtocolVersion negotiatedProtocol, 777 AlgorithmConstraints constraints, NamedGroupType type) { 778 for (NamedGroup namedGroup : supportedNamedGroups) { 779 if ((namedGroup.type == type) && 780 namedGroup.isAvailable(negotiatedProtocol) && 781 constraints.permits( 782 EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), 783 namedGroup.algorithm, 784 namedGroupParams.get(namedGroup))) { 785 return namedGroup; 786 } 787 } 788 789 return null; 790 } 791 } 792 793 /** 794 * Network data producer of a "supported_groups" extension in 795 * the ClientHello handshake message. 796 */ 797 private static final class CHSupportedGroupsProducer 798 extends SupportedGroups implements HandshakeProducer { 799 // Prevent instantiation of this class. CHSupportedGroupsProducer()800 private CHSupportedGroupsProducer() { 801 // blank 802 } 803 804 @Override produce(ConnectionContext context, HandshakeMessage message)805 public byte[] produce(ConnectionContext context, 806 HandshakeMessage message) throws IOException { 807 // The producing happens in client side only. 808 ClientHandshakeContext chc = (ClientHandshakeContext)context; 809 810 // Is it a supported and enabled extension? 811 if (!chc.sslConfig.isAvailable(CH_SUPPORTED_GROUPS)) { 812 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 813 SSLLogger.fine( 814 "Ignore unavailable supported_groups extension"); 815 } 816 return null; 817 } 818 819 // Produce the extension. 820 ArrayList<NamedGroup> namedGroups = 821 new ArrayList<>(SupportedGroups.supportedNamedGroups.length); 822 for (NamedGroup ng : SupportedGroups.supportedNamedGroups) { 823 if ((!SupportedGroups.enableFFDHE) && 824 (ng.type == NamedGroupType.NAMED_GROUP_FFDHE)) { 825 continue; 826 } 827 828 if (ng.isAvailable(chc.activeProtocols) && 829 ng.isSupported(chc.activeCipherSuites) && 830 chc.algorithmConstraints.permits( 831 EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), 832 ng.algorithm, namedGroupParams.get(ng))) { 833 namedGroups.add(ng); 834 } else if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 835 SSLLogger.fine( 836 "Ignore inactive or disabled named group: " + ng.name); 837 } 838 } 839 840 if (namedGroups.isEmpty()) { 841 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 842 SSLLogger.warning("no available named group"); 843 } 844 845 return null; 846 } 847 848 int vectorLen = namedGroups.size() << 1; 849 byte[] extData = new byte[vectorLen + 2]; 850 ByteBuffer m = ByteBuffer.wrap(extData); 851 Record.putInt16(m, vectorLen); 852 for (NamedGroup namedGroup : namedGroups) { 853 Record.putInt16(m, namedGroup.id); 854 } 855 856 // Update the context. 857 chc.clientRequestedNamedGroups = 858 Collections.<NamedGroup>unmodifiableList(namedGroups); 859 chc.handshakeExtensions.put(CH_SUPPORTED_GROUPS, 860 new SupportedGroupsSpec(namedGroups)); 861 862 return extData; 863 } 864 } 865 866 /** 867 * Network data producer of a "supported_groups" extension in 868 * the ClientHello handshake message. 869 */ 870 private static final 871 class CHSupportedGroupsConsumer implements ExtensionConsumer { 872 // Prevent instantiation of this class. CHSupportedGroupsConsumer()873 private CHSupportedGroupsConsumer() { 874 // blank 875 } 876 877 @Override consume(ConnectionContext context, HandshakeMessage message, ByteBuffer buffer)878 public void consume(ConnectionContext context, 879 HandshakeMessage message, ByteBuffer buffer) throws IOException { 880 // The consuming happens in server side only. 881 ServerHandshakeContext shc = (ServerHandshakeContext)context; 882 883 // Is it a supported and enabled extension? 884 if (!shc.sslConfig.isAvailable(CH_SUPPORTED_GROUPS)) { 885 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 886 SSLLogger.fine( 887 "Ignore unavailable supported_groups extension"); 888 } 889 return; // ignore the extension 890 } 891 892 // Parse the extension. 893 SupportedGroupsSpec spec; 894 try { 895 spec = new SupportedGroupsSpec(buffer); 896 } catch (IOException ioe) { 897 throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe); 898 } 899 900 // Update the context. 901 List<NamedGroup> knownNamedGroups = new LinkedList<>(); 902 for (int id : spec.namedGroupsIds) { 903 NamedGroup ng = NamedGroup.valueOf(id); 904 if (ng != null) { 905 knownNamedGroups.add(ng); 906 } 907 } 908 909 shc.clientRequestedNamedGroups = knownNamedGroups; 910 shc.handshakeExtensions.put(CH_SUPPORTED_GROUPS, spec); 911 912 // No impact on session resumption. 913 } 914 } 915 916 /** 917 * Network data producer of a "supported_groups" extension in 918 * the EncryptedExtensions handshake message. 919 */ 920 private static final class EESupportedGroupsProducer 921 extends SupportedGroups implements HandshakeProducer { 922 923 // Prevent instantiation of this class. EESupportedGroupsProducer()924 private EESupportedGroupsProducer() { 925 // blank 926 } 927 928 @Override produce(ConnectionContext context, HandshakeMessage message)929 public byte[] produce(ConnectionContext context, 930 HandshakeMessage message) throws IOException { 931 // The producing happens in server side only. 932 ServerHandshakeContext shc = (ServerHandshakeContext)context; 933 934 // Is it a supported and enabled extension? 935 if (!shc.sslConfig.isAvailable(EE_SUPPORTED_GROUPS)) { 936 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 937 SSLLogger.fine( 938 "Ignore unavailable supported_groups extension"); 939 } 940 return null; 941 } 942 943 // Produce the extension. 944 // 945 // Contains all groups the server supports, regardless of whether 946 // they are currently supported by the client. 947 ArrayList<NamedGroup> namedGroups = new ArrayList<>( 948 SupportedGroups.supportedNamedGroups.length); 949 for (NamedGroup ng : SupportedGroups.supportedNamedGroups) { 950 if ((!SupportedGroups.enableFFDHE) && 951 (ng.type == NamedGroupType.NAMED_GROUP_FFDHE)) { 952 continue; 953 } 954 955 if (ng.isAvailable(shc.activeProtocols) && 956 ng.isSupported(shc.activeCipherSuites) && 957 shc.algorithmConstraints.permits( 958 EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), 959 ng.algorithm, namedGroupParams.get(ng))) { 960 namedGroups.add(ng); 961 } else if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 962 SSLLogger.fine( 963 "Ignore inactive or disabled named group: " + ng.name); 964 } 965 } 966 967 if (namedGroups.isEmpty()) { 968 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 969 SSLLogger.warning("no available named group"); 970 } 971 972 return null; 973 } 974 975 int vectorLen = namedGroups.size() << 1; 976 byte[] extData = new byte[vectorLen + 2]; 977 ByteBuffer m = ByteBuffer.wrap(extData); 978 Record.putInt16(m, vectorLen); 979 for (NamedGroup namedGroup : namedGroups) { 980 Record.putInt16(m, namedGroup.id); 981 } 982 983 // Update the context. 984 shc.conContext.serverRequestedNamedGroups = 985 Collections.<NamedGroup>unmodifiableList(namedGroups); 986 SupportedGroupsSpec spec = new SupportedGroupsSpec(namedGroups); 987 shc.handshakeExtensions.put(EE_SUPPORTED_GROUPS, spec); 988 989 return extData; 990 } 991 } 992 993 private static final 994 class EESupportedGroupsConsumer implements ExtensionConsumer { 995 // Prevent instantiation of this class. EESupportedGroupsConsumer()996 private EESupportedGroupsConsumer() { 997 // blank 998 } 999 1000 @Override consume(ConnectionContext context, HandshakeMessage message, ByteBuffer buffer)1001 public void consume(ConnectionContext context, 1002 HandshakeMessage message, ByteBuffer buffer) throws IOException { 1003 // The consuming happens in client side only. 1004 ClientHandshakeContext chc = (ClientHandshakeContext)context; 1005 1006 // Is it a supported and enabled extension? 1007 if (!chc.sslConfig.isAvailable(EE_SUPPORTED_GROUPS)) { 1008 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 1009 SSLLogger.fine( 1010 "Ignore unavailable supported_groups extension"); 1011 } 1012 return; // ignore the extension 1013 } 1014 1015 // Parse the extension. 1016 SupportedGroupsSpec spec; 1017 try { 1018 spec = new SupportedGroupsSpec(buffer); 1019 } catch (IOException ioe) { 1020 throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe); 1021 } 1022 1023 // Update the context. 1024 List<NamedGroup> knownNamedGroups = 1025 new ArrayList<>(spec.namedGroupsIds.length); 1026 for (int id : spec.namedGroupsIds) { 1027 NamedGroup ng = NamedGroup.valueOf(id); 1028 if (ng != null) { 1029 knownNamedGroups.add(ng); 1030 } 1031 } 1032 1033 chc.conContext.serverRequestedNamedGroups = knownNamedGroups; 1034 chc.handshakeExtensions.put(EE_SUPPORTED_GROUPS, spec); 1035 1036 // No impact on session resumption. 1037 } 1038 } 1039 } 1040