# HG changeset patch # User xuelei # Date 1494459646 0 # Node ID b1b45177051bdd592718bc4fb28a370e87094d69 # Parent 0909d3bcbacb4a3022580bedaae9e2a6ea3ea27c 8140436: Negotiated Finite Field Diffie-Hellman Ephemeral Parameters for TLS Reviewed-by: valeriep, jnimeh, apetcher diff -r 0909d3bcbacb -r b1b45177051b jdk/src/java.base/share/classes/sun/security/ssl/CipherSuite.java --- a/jdk/src/java.base/share/classes/sun/security/ssl/CipherSuite.java Thu May 11 07:33:23 2017 +0800 +++ b/jdk/src/java.base/share/classes/sun/security/ssl/CipherSuite.java Wed May 10 23:40:46 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,6 +44,7 @@ import static sun.security.ssl.CipherSuite.MacAlg.*; import static sun.security.ssl.CipherSuite.BulkCipher.*; import static sun.security.ssl.JsseJce.*; +import static sun.security.ssl.NamedGroupType.*; /** * An SSL/TLS CipherSuite. Constants for the standard key exchange, cipher, @@ -376,38 +377,38 @@ static enum KeyExchange { // key exchange algorithms - K_NULL ("NULL", false, false), - K_RSA ("RSA", true, false), - K_RSA_EXPORT ("RSA_EXPORT", true, false), - K_DH_RSA ("DH_RSA", false, false), - K_DH_DSS ("DH_DSS", false, false), - K_DHE_DSS ("DHE_DSS", true, false), - K_DHE_RSA ("DHE_RSA", true, false), - K_DH_ANON ("DH_anon", true, false), + K_NULL ("NULL", false, NAMED_GROUP_NONE), + K_RSA ("RSA", true, NAMED_GROUP_NONE), + K_RSA_EXPORT ("RSA_EXPORT", true, NAMED_GROUP_NONE), + K_DH_RSA ("DH_RSA", false, NAMED_GROUP_NONE), + K_DH_DSS ("DH_DSS", false, NAMED_GROUP_NONE), + K_DHE_DSS ("DHE_DSS", true, NAMED_GROUP_FFDHE), + K_DHE_RSA ("DHE_RSA", true, NAMED_GROUP_FFDHE), + K_DH_ANON ("DH_anon", true, NAMED_GROUP_FFDHE), - K_ECDH_ECDSA ("ECDH_ECDSA", ALLOW_ECC, true), - K_ECDH_RSA ("ECDH_RSA", ALLOW_ECC, true), - K_ECDHE_ECDSA("ECDHE_ECDSA", ALLOW_ECC, true), - K_ECDHE_RSA ("ECDHE_RSA", ALLOW_ECC, true), - K_ECDH_ANON ("ECDH_anon", ALLOW_ECC, true), + K_ECDH_ECDSA ("ECDH_ECDSA", ALLOW_ECC, NAMED_GROUP_ECDHE), + K_ECDH_RSA ("ECDH_RSA", ALLOW_ECC, NAMED_GROUP_ECDHE), + K_ECDHE_ECDSA("ECDHE_ECDSA", ALLOW_ECC, NAMED_GROUP_ECDHE), + K_ECDHE_RSA ("ECDHE_RSA", ALLOW_ECC, NAMED_GROUP_ECDHE), + K_ECDH_ANON ("ECDH_anon", ALLOW_ECC, NAMED_GROUP_ECDHE), // Kerberos cipher suites - K_KRB5 ("KRB5", true, false), - K_KRB5_EXPORT("KRB5_EXPORT", true, false), + K_KRB5 ("KRB5", true, NAMED_GROUP_NONE), + K_KRB5_EXPORT("KRB5_EXPORT", true, NAMED_GROUP_NONE), // renegotiation protection request signaling cipher suite - K_SCSV ("SCSV", true, false); + K_SCSV ("SCSV", true, NAMED_GROUP_NONE); // name of the key exchange algorithm, e.g. DHE_DSS final String name; final boolean allowed; - final boolean isEC; + final NamedGroupType groupType; private final boolean alwaysAvailable; - KeyExchange(String name, boolean allowed, boolean isEC) { + KeyExchange(String name, boolean allowed, NamedGroupType groupType) { this.name = name; this.allowed = allowed; - this.isEC = isEC; + this.groupType = groupType; this.alwaysAvailable = allowed && (!name.startsWith("EC")) && (!name.startsWith("KRB")); } @@ -417,7 +418,7 @@ return true; } - if (isEC) { + if (groupType == NAMED_GROUP_ECDHE) { return (allowed && JsseJce.isEcAvailable()); } else if (name.startsWith("KRB")) { return (allowed && JsseJce.isKerberosAvailable()); diff -r 0909d3bcbacb -r b1b45177051b jdk/src/java.base/share/classes/sun/security/ssl/CipherSuiteList.java --- a/jdk/src/java.base/share/classes/sun/security/ssl/CipherSuiteList.java Thu May 11 07:33:23 2017 +0800 +++ b/jdk/src/java.base/share/classes/sun/security/ssl/CipherSuiteList.java Wed May 10 23:40:46 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ import java.util.*; import javax.net.ssl.SSLException; +import static sun.security.ssl.NamedGroupType.*; /** * A list of CipherSuites. Also maintains the lists of supported and @@ -42,15 +43,16 @@ private final Collection cipherSuites; private String[] suiteNames; - - // flag indicating whether this list contains any ECC ciphersuites. - // null if not yet checked. - private volatile Boolean containsEC; + private final EnumSet groupsTypes = + EnumSet.noneOf(NamedGroupType.class); // for use by buildAvailableCache() and // Handshaker.getKickstartMessage() only CipherSuiteList(Collection cipherSuites) { this.cipherSuites = cipherSuites; + for (CipherSuite suite : cipherSuites) { + updateGroupTypes(suite); + } } /** @@ -59,6 +61,7 @@ CipherSuiteList(CipherSuite suite) { cipherSuites = new ArrayList(1); cipherSuites.add(suite); + updateGroupTypes(suite); } /** @@ -82,6 +85,7 @@ + suiteName + " with currently installed providers"); } cipherSuites.add(suite); + updateGroupTypes(suite); } } @@ -97,7 +101,20 @@ } cipherSuites = new ArrayList(bytes.length >> 1); for (int i = 0; i < bytes.length; i += 2) { - cipherSuites.add(CipherSuite.valueOf(bytes[i], bytes[i+1])); + CipherSuite suite = CipherSuite.valueOf(bytes[i], bytes[i+1]); + cipherSuites.add(suite); + updateGroupTypes(suite); + } + } + + // Please don't use this method except constructors. + private void updateGroupTypes(CipherSuite cipherSuite) { + if (cipherSuite.keyExchange != null && (!cipherSuite.exportable)) { + NamedGroupType groupType = cipherSuite.keyExchange.groupType; + if ((groupType != NAMED_GROUP_NONE) && + (!groupsTypes.contains(groupType))) { + groupsTypes.add(groupType); + } } } @@ -108,20 +125,9 @@ return cipherSuites.contains(suite); } - // Return whether this list contains any ECC ciphersuites - boolean containsEC() { - if (containsEC == null) { - for (CipherSuite c : cipherSuites) { - if (c.keyExchange.isEC) { - containsEC = true; - return true; - } - } - - containsEC = false; - } - - return containsEC; + // Return whether this list contains cipher suites of a named group type. + boolean contains(NamedGroupType groupType) { + return groupsTypes.contains(groupType); } /** diff -r 0909d3bcbacb -r b1b45177051b jdk/src/java.base/share/classes/sun/security/ssl/ClientHandshaker.java --- a/jdk/src/java.base/share/classes/sun/security/ssl/ClientHandshaker.java Thu May 11 07:33:23 2017 +0800 +++ b/jdk/src/java.base/share/classes/sun/security/ssl/ClientHandshaker.java Wed May 10 23:40:46 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -148,6 +148,10 @@ private static final boolean enableMFLExtension = Debug.getBooleanProperty("jsse.enableMFLExtension", false); + // To switch off the supported_groups extension for DHE cipher suite. + private static final boolean enableFFDHE = + Debug.getBooleanProperty("jsse.enableFFDHE", true); + // Whether an ALPN extension was sent in the ClientHello private boolean alpnActive = false; @@ -767,13 +771,15 @@ fatalSE(Alerts.alert_unexpected_message, "Server set " + type + " extension when not requested by client"); } - } else if ((type != ExtensionType.EXT_ELLIPTIC_CURVES) + } else if ((type != ExtensionType.EXT_SUPPORTED_GROUPS) && (type != ExtensionType.EXT_EC_POINT_FORMATS) && (type != ExtensionType.EXT_SERVER_NAME) && (type != ExtensionType.EXT_ALPN) && (type != ExtensionType.EXT_RENEGOTIATION_INFO) && (type != ExtensionType.EXT_STATUS_REQUEST) && (type != ExtensionType.EXT_STATUS_REQUEST_V2)) { + // Note: Better to check client requested extensions rather + // than all supported extensions. fatalSE(Alerts.alert_unsupported_extension, "Server sent an unsupported extension: " + type); } @@ -823,6 +829,17 @@ * our own D-H algorithm object so we can defer key calculations * until after we've sent the client key exchange message (which * gives client and server some useful parallelism). + * + * Note per section 3 of RFC 7919, if the server is not compatible with + * FFDHE specification, the client MAY decide to continue the connection + * if the selected DHE group is acceptable under local policy, or it MAY + * decide to terminate the connection with a fatal insufficient_security + * (71) alert. The algorithm constraints mechanism is JDK local policy + * used for additional DHE parameters checking. So this implementation + * does not check the server compatibility and just pass to the local + * algorithm constraints checking. The client will continue the + * connection if the server selected DHE group is acceptable by the + * specified algorithm constraints. */ private void serverKeyExchange(DH_ServerKeyExchange mesg) throws IOException { @@ -1495,14 +1512,17 @@ sslContext.getSecureRandom(), maxProtocolVersion, sessionId, cipherSuites, isDTLS); - // add elliptic curves and point format extensions - if (cipherSuites.containsEC()) { - EllipticCurvesExtension ece = - EllipticCurvesExtension.createExtension(algorithmConstraints); - if (ece != null) { - clientHelloMessage.extensions.add(ece); + // Add named groups extension for ECDHE and FFDHE if necessary. + SupportedGroupsExtension sge = + SupportedGroupsExtension.createExtension( + algorithmConstraints, + cipherSuites, enableFFDHE); + if (sge != null) { + clientHelloMessage.extensions.add(sge); + // Add elliptic point format extensions + if (cipherSuites.contains(NamedGroupType.NAMED_GROUP_ECDHE)) { clientHelloMessage.extensions.add( - EllipticPointFormatsExtension.DEFAULT); + EllipticPointFormatsExtension.DEFAULT); } } diff -r 0909d3bcbacb -r b1b45177051b jdk/src/java.base/share/classes/sun/security/ssl/DHCrypt.java --- a/jdk/src/java.base/share/classes/sun/security/ssl/DHCrypt.java Thu May 11 07:33:23 2017 +0800 +++ b/jdk/src/java.base/share/classes/sun/security/ssl/DHCrypt.java Wed May 10 23:40:46 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,14 +26,8 @@ package sun.security.ssl; -import java.util.Map; -import java.util.HashMap; -import java.util.Collections; -import java.util.regex.Pattern; -import java.util.regex.Matcher; import java.math.BigInteger; import java.security.*; -import java.io.IOException; import javax.net.ssl.SSLHandshakeException; import javax.crypto.SecretKey; import javax.crypto.KeyAgreement; @@ -101,7 +95,7 @@ */ DHCrypt(int keyLength, SecureRandom random) { this(keyLength, - ParametersHolder.definedParams.get(keyLength), random); + PredefinedDHParameterSpecs.definedParams.get(keyLength), random); } /** @@ -116,6 +110,14 @@ } /** + * Generate a Diffie-Hellman keypair using the named group. + */ + DHCrypt(NamedGroup namedGroup, SecureRandom random) { + this(-1, // The length (-1) is not used in the implementation. + SupportedGroupsExtension.getDHParameterSpec(namedGroup), random); + } + + /** * Generate a Diffie-Hellman keypair using the specified size and * parameters. */ @@ -272,266 +274,5 @@ return null; } - - // lazy initialization holder class idiom for static default parameters - // - // See Effective Java Second Edition: Item 71. - private static class ParametersHolder { - private final static boolean debugIsOn = - (Debug.getInstance("ssl") != null) && Debug.isOn("sslctx"); - - // - // Default DH ephemeral parameters - // - private static final BigInteger p512 = new BigInteger( // generated - "D87780E15FF50B4ABBE89870188B049406B5BEA98AB23A02" + - "41D88EA75B7755E669C08093D3F0CA7FC3A5A25CF067DCB9" + - "A43DD89D1D90921C6328884461E0B6D3", 16); - private static final BigInteger p768 = new BigInteger( // RFC 2409 - "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + - "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + - "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + - "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF", 16); +} - private static final BigInteger p1024 = new BigInteger( // RFC 2409 - "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + - "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + - "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + - "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + - "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" + - "FFFFFFFFFFFFFFFF", 16); - private static final BigInteger p1536 = new BigInteger( // RFC 3526 - "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + - "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + - "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + - "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + - "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + - "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + - "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + - "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF", 16); - private static final BigInteger p2048 = new BigInteger( // TLS FFDHE - "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" + - "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + - "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" + - "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + - "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" + - "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + - "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" + - "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + - "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" + - "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + - "886B423861285C97FFFFFFFFFFFFFFFF", 16); - private static final BigInteger p3072 = new BigInteger( // TLS FFDHE - "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" + - "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + - "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" + - "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + - "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" + - "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + - "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" + - "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + - "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" + - "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + - "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238" + - "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" + - "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3" + - "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" + - "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF" + - "3C1B20EE3FD59D7C25E41D2B66C62E37FFFFFFFFFFFFFFFF", 16); - private static final BigInteger p4096 = new BigInteger( // TLS FFDHE - "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" + - "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + - "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" + - "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + - "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" + - "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + - "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" + - "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + - "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" + - "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + - "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238" + - "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" + - "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3" + - "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" + - "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF" + - "3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB" + - "7930E9E4E58857B6AC7D5F42D69F6D187763CF1D55034004" + - "87F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832" + - "A907600A918130C46DC778F971AD0038092999A333CB8B7A" + - "1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF" + - "8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E655F6A" + - "FFFFFFFFFFFFFFFF", 16); - private static final BigInteger p6144 = new BigInteger( // TLS FFDHE - "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" + - "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + - "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" + - "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + - "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" + - "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + - "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" + - "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + - "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" + - "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + - "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238" + - "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" + - "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3" + - "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" + - "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF" + - "3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB" + - "7930E9E4E58857B6AC7D5F42D69F6D187763CF1D55034004" + - "87F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832" + - "A907600A918130C46DC778F971AD0038092999A333CB8B7A" + - "1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF" + - "8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E0DD902" + - "0BFD64B645036C7A4E677D2C38532A3A23BA4442CAF53EA6" + - "3BB454329B7624C8917BDD64B1C0FD4CB38E8C334C701C3A" + - "CDAD0657FCCFEC719B1F5C3E4E46041F388147FB4CFDB477" + - "A52471F7A9A96910B855322EDB6340D8A00EF092350511E3" + - "0ABEC1FFF9E3A26E7FB29F8C183023C3587E38DA0077D9B4" + - "763E4E4B94B2BBC194C6651E77CAF992EEAAC0232A281BF6" + - "B3A739C1226116820AE8DB5847A67CBEF9C9091B462D538C" + - "D72B03746AE77F5E62292C311562A846505DC82DB854338A" + - "E49F5235C95B91178CCF2DD5CACEF403EC9D1810C6272B04" + - "5B3B71F9DC6B80D63FDD4A8E9ADB1E6962A69526D43161C1" + - "A41D570D7938DAD4A40E329CD0E40E65FFFFFFFFFFFFFFFF", 16); - private static final BigInteger p8192 = new BigInteger( // TLS FFDHE - "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" + - "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + - "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" + - "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + - "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" + - "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + - "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" + - "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + - "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" + - "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + - "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238" + - "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" + - "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3" + - "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" + - "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF" + - "3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB" + - "7930E9E4E58857B6AC7D5F42D69F6D187763CF1D55034004" + - "87F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832" + - "A907600A918130C46DC778F971AD0038092999A333CB8B7A" + - "1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF" + - "8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E0DD902" + - "0BFD64B645036C7A4E677D2C38532A3A23BA4442CAF53EA6" + - "3BB454329B7624C8917BDD64B1C0FD4CB38E8C334C701C3A" + - "CDAD0657FCCFEC719B1F5C3E4E46041F388147FB4CFDB477" + - "A52471F7A9A96910B855322EDB6340D8A00EF092350511E3" + - "0ABEC1FFF9E3A26E7FB29F8C183023C3587E38DA0077D9B4" + - "763E4E4B94B2BBC194C6651E77CAF992EEAAC0232A281BF6" + - "B3A739C1226116820AE8DB5847A67CBEF9C9091B462D538C" + - "D72B03746AE77F5E62292C311562A846505DC82DB854338A" + - "E49F5235C95B91178CCF2DD5CACEF403EC9D1810C6272B04" + - "5B3B71F9DC6B80D63FDD4A8E9ADB1E6962A69526D43161C1" + - "A41D570D7938DAD4A40E329CCFF46AAA36AD004CF600C838" + - "1E425A31D951AE64FDB23FCEC9509D43687FEB69EDD1CC5E" + - "0B8CC3BDF64B10EF86B63142A3AB8829555B2F747C932665" + - "CB2C0F1CC01BD70229388839D2AF05E454504AC78B758282" + - "2846C0BA35C35F5C59160CC046FD8251541FC68C9C86B022" + - "BB7099876A460E7451A8A93109703FEE1C217E6C3826E52C" + - "51AA691E0E423CFC99E9E31650C1217B624816CDAD9A95F9" + - "D5B8019488D9C0A0A1FE3075A577E23183F81D4A3F2FA457" + - "1EFC8CE0BA8A4FE8B6855DFE72B0A66EDED2FBABFBE58A30" + - "FAFABE1C5D71A87E2F741EF8C1FE86FEA6BBFDE530677F0D" + - "97D11D49F7A8443D0822E506A9F4614E011E2A94838FF88C" + - "D68C8BB7C5C6424CFFFFFFFFFFFFFFFF", 16); - - private static final BigInteger[] supportedPrimes = { - p512, p768, p1024, p1536, p2048, p3072, p4096, p6144, p8192}; - - // a measure of the uncertainty that prime modulus p is not a prime - // - // see BigInteger.isProbablePrime(int certainty) - private final static int PRIME_CERTAINTY = 120; - - // the known security property, jdk.tls.server.defaultDHEParameters - private final static String PROPERTY_NAME = - "jdk.tls.server.defaultDHEParameters"; - - private static final Pattern spacesPattern = Pattern.compile("\\s+"); - - private final static Pattern syntaxPattern = Pattern.compile( - "(\\{[0-9A-Fa-f]+,[0-9A-Fa-f]+\\})" + - "(,\\{[0-9A-Fa-f]+,[0-9A-Fa-f]+\\})*"); - - private static final Pattern paramsPattern = Pattern.compile( - "\\{([0-9A-Fa-f]+),([0-9A-Fa-f]+)\\}"); - - // cache of predefined default DH ephemeral parameters - private final static Map definedParams; - - static { - String property = AccessController.doPrivileged( - new PrivilegedAction() { - public String run() { - return Security.getProperty(PROPERTY_NAME); - } - }); - - if (property != null && !property.isEmpty()) { - // remove double quote marks from beginning/end of the property - if (property.length() >= 2 && property.charAt(0) == '"' && - property.charAt(property.length() - 1) == '"') { - property = property.substring(1, property.length() - 1); - } - - property = property.trim(); - } - - if (property != null && !property.isEmpty()) { - Matcher spacesMatcher = spacesPattern.matcher(property); - property = spacesMatcher.replaceAll(""); - - if (debugIsOn) { - System.out.println("The Security Property " + - PROPERTY_NAME + ": " + property); - } - } - - Map defaultParams = new HashMap<>(); - if (property != null && !property.isEmpty()) { - Matcher syntaxMatcher = syntaxPattern.matcher(property); - if (syntaxMatcher.matches()) { - Matcher paramsFinder = paramsPattern.matcher(property); - while(paramsFinder.find()) { - String primeModulus = paramsFinder.group(1); - BigInteger p = new BigInteger(primeModulus, 16); - if (!p.isProbablePrime(PRIME_CERTAINTY)) { - if (debugIsOn) { - System.out.println( - "Prime modulus p in Security Property, " + - PROPERTY_NAME + ", is not a prime: " + - primeModulus); - } - - continue; - } - - String baseGenerator = paramsFinder.group(2); - BigInteger g = new BigInteger(baseGenerator, 16); - - DHParameterSpec spec = new DHParameterSpec(p, g); - int primeLen = p.bitLength(); - defaultParams.put(primeLen, spec); - } - } else if (debugIsOn) { - System.out.println("Invalid Security Property, " + - PROPERTY_NAME + ", definition"); - } - } - - for (BigInteger p : supportedPrimes) { - int primeLen = p.bitLength(); - defaultParams.putIfAbsent(primeLen, - new DHParameterSpec(p, BigInteger.TWO)); - } - - definedParams = - Collections.unmodifiableMap( - defaultParams); - } - } -} diff -r 0909d3bcbacb -r b1b45177051b jdk/src/java.base/share/classes/sun/security/ssl/ECDHCrypt.java --- a/jdk/src/java.base/share/classes/sun/security/ssl/ECDHCrypt.java Thu May 11 07:33:23 2017 +0800 +++ b/jdk/src/java.base/share/classes/sun/security/ssl/ECDHCrypt.java Wed May 10 23:40:46 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,17 +56,17 @@ } // Called by ServerHandshaker for ephemeral ECDH - ECDHCrypt(int curveId, SecureRandom random) { + ECDHCrypt(NamedGroup namedGroup, SecureRandom random) { try { KeyPairGenerator kpg = JsseJce.getKeyPairGenerator("EC"); ECGenParameterSpec params = - EllipticCurvesExtension.getECGenParamSpec(curveId); + SupportedGroupsExtension.getECGenParamSpec(namedGroup); kpg.initialize(params, random); KeyPair kp = kpg.generateKeyPair(); privateKey = kp.getPrivate(); publicKey = (ECPublicKey)kp.getPublic(); } catch (GeneralSecurityException e) { - throw new RuntimeException("Could not generate DH keypair", e); + throw new RuntimeException("Could not generate ECDH keypair", e); } } @@ -79,7 +79,7 @@ privateKey = kp.getPrivate(); publicKey = (ECPublicKey)kp.getPublic(); } catch (GeneralSecurityException e) { - throw new RuntimeException("Could not generate DH keypair", e); + throw new RuntimeException("Could not generate ECDH keypair", e); } } diff -r 0909d3bcbacb -r b1b45177051b jdk/src/java.base/share/classes/sun/security/ssl/EllipticCurvesExtension.java --- a/jdk/src/java.base/share/classes/sun/security/ssl/EllipticCurvesExtension.java Thu May 11 07:33:23 2017 +0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,400 +0,0 @@ -/* - * Copyright (c) 2006, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.security.ssl; - -import java.io.IOException; -import java.security.spec.ECParameterSpec; -import java.security.spec.ECGenParameterSpec; -import java.security.spec.InvalidParameterSpecException; -import java.security.AlgorithmParameters; -import java.security.AlgorithmConstraints; -import java.security.CryptoPrimitive; -import java.security.AccessController; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.Map; -import java.util.ArrayList; -import javax.net.ssl.SSLProtocolException; - -import sun.security.action.GetPropertyAction; - -final class EllipticCurvesExtension extends HelloExtension { - - /* Class and subclass dynamic debugging support */ - private static final Debug debug = Debug.getInstance("ssl"); - - private static final int ARBITRARY_PRIME = 0xff01; - private static final int ARBITRARY_CHAR2 = 0xff02; - - // speed up the searching - private static final Map oidToIdMap = new HashMap<>(); - private static final Map idToOidMap = new HashMap<>(); - - // speed up the parameters construction - private static final Map idToParams = new HashMap<>(); - - // the supported elliptic curves - private static final int[] supportedCurveIds; - - // the curves of the extension - private final int[] curveIds; - - // See sun.security.util.CurveDB for the OIDs - private static enum NamedEllipticCurve { - T163_K1(1, "sect163k1", "1.3.132.0.1", true), // NIST K-163 - T163_R1(2, "sect163r1", "1.3.132.0.2", false), - T163_R2(3, "sect163r2", "1.3.132.0.15", true), // NIST B-163 - T193_R1(4, "sect193r1", "1.3.132.0.24", false), - T193_R2(5, "sect193r2", "1.3.132.0.25", false), - T233_K1(6, "sect233k1", "1.3.132.0.26", true), // NIST K-233 - T233_R1(7, "sect233r1", "1.3.132.0.27", true), // NIST B-233 - T239_K1(8, "sect239k1", "1.3.132.0.3", false), - T283_K1(9, "sect283k1", "1.3.132.0.16", true), // NIST K-283 - T283_R1(10, "sect283r1", "1.3.132.0.17", true), // NIST B-283 - T409_K1(11, "sect409k1", "1.3.132.0.36", true), // NIST K-409 - T409_R1(12, "sect409r1", "1.3.132.0.37", true), // NIST B-409 - T571_K1(13, "sect571k1", "1.3.132.0.38", true), // NIST K-571 - T571_R1(14, "sect571r1", "1.3.132.0.39", true), // NIST B-571 - - P160_K1(15, "secp160k1", "1.3.132.0.9", false), - P160_R1(16, "secp160r1", "1.3.132.0.8", false), - P160_R2(17, "secp160r2", "1.3.132.0.30", false), - P192_K1(18, "secp192k1", "1.3.132.0.31", false), - P192_R1(19, "secp192r1", "1.2.840.10045.3.1.1", true), // NIST P-192 - P224_K1(20, "secp224k1", "1.3.132.0.32", false), - P224_R1(21, "secp224r1", "1.3.132.0.33", true), // NIST P-224 - P256_K1(22, "secp256k1", "1.3.132.0.10", false), - P256_R1(23, "secp256r1", "1.2.840.10045.3.1.7", true), // NIST P-256 - P384_R1(24, "secp384r1", "1.3.132.0.34", true), // NIST P-384 - P521_R1(25, "secp521r1", "1.3.132.0.35", true); // NIST P-521 - - int id; - String name; - String oid; - boolean isFips; - - NamedEllipticCurve(int id, String name, String oid, boolean isFips) { - this.id = id; - this.name = name; - this.oid = oid; - this.isFips = isFips; - - if (oidToIdMap.put(oid, id) != null || - idToOidMap.put(id, oid) != null) { - - throw new RuntimeException( - "Duplicate named elliptic curve definition: " + name); - } - } - - static NamedEllipticCurve getCurve(String name, boolean requireFips) { - for (NamedEllipticCurve curve : NamedEllipticCurve.values()) { - if (curve.name.equals(name) && (!requireFips || curve.isFips)) { - return curve; - } - } - - return null; - } - } - - static { - boolean requireFips = SunJSSE.isFIPS(); - - // hack code to initialize NamedEllipticCurve - NamedEllipticCurve nec = - NamedEllipticCurve.getCurve("secp256r1", false); - - // The value of the System Property defines a list of enabled named - // curves in preference order, separated with comma. For example: - // - // jdk.tls.namedGroups="secp521r1, secp256r1, secp384r1" - // - // If the System Property is not defined or the value is empty, the - // default curves and preferences will be used. - String property = AccessController.doPrivileged( - new GetPropertyAction("jdk.tls.namedGroups")); - if (property != null && property.length() != 0) { - // remove double quote marks from beginning/end of the property - if (property.length() > 1 && property.charAt(0) == '"' && - property.charAt(property.length() - 1) == '"') { - property = property.substring(1, property.length() - 1); - } - } - - ArrayList idList; - if (property != null && property.length() != 0) { // customized curves - String[] curves = property.split(","); - idList = new ArrayList<>(curves.length); - for (String curve : curves) { - curve = curve.trim(); - if (!curve.isEmpty()) { - NamedEllipticCurve namedCurve = - NamedEllipticCurve.getCurve(curve, requireFips); - if (namedCurve != null) { - if (isAvailableCurve(namedCurve.id)) { - idList.add(namedCurve.id); - } - } // ignore unknown curves - } - } - if (idList.isEmpty() && JsseJce.isEcAvailable()) { - throw new IllegalArgumentException( - "System property jdk.tls.namedGroups(" + property + ") " + - "contains no supported elliptic curves"); - } - } else { // default curves - int[] ids; - if (requireFips) { - ids = new int[] { - // only NIST curves in FIPS mode - 23, 24, 25, 9, 10, 11, 12, 13, 14, - }; - } else { - ids = new int[] { - // NIST curves first - 23, 24, 25, 9, 10, 11, 12, 13, 14, - // non-NIST curves - 22, - }; - } - - idList = new ArrayList<>(ids.length); - for (int curveId : ids) { - if (isAvailableCurve(curveId)) { - idList.add(curveId); - } - } - } - - if (debug != null && idList.isEmpty()) { - Debug.log( - "Initialized [jdk.tls.namedGroups|default] list contains " + - "no available elliptic curves. " + - (property != null ? "(" + property + ")" : "[Default]")); - } - - supportedCurveIds = new int[idList.size()]; - int i = 0; - for (Integer id : idList) { - supportedCurveIds[i++] = id; - } - } - - // check whether the curve is supported by the underlying providers - private static boolean isAvailableCurve(int curveId) { - String oid = idToOidMap.get(curveId); - if (oid != null) { - AlgorithmParameters params = null; - try { - params = JsseJce.getAlgorithmParameters("EC"); - params.init(new ECGenParameterSpec(oid)); - } catch (Exception e) { - return false; - } - - // cache the parameters - idToParams.put(curveId, params); - - return true; - } - - return false; - } - - private EllipticCurvesExtension(int[] curveIds) { - super(ExtensionType.EXT_ELLIPTIC_CURVES); - - this.curveIds = curveIds; - } - - EllipticCurvesExtension(HandshakeInStream s, int len) - throws IOException { - super(ExtensionType.EXT_ELLIPTIC_CURVES); - - int k = s.getInt16(); - if (((len & 1) != 0) || (k + 2 != len)) { - throw new SSLProtocolException("Invalid " + type + " extension"); - } - - // Note: unknown curves will be ignored later. - curveIds = new int[k >> 1]; - for (int i = 0; i < curveIds.length; i++) { - curveIds[i] = s.getInt16(); - } - } - - // get the preferred active curve - static int getActiveCurves(AlgorithmConstraints constraints) { - return getPreferredCurve(supportedCurveIds, constraints); - } - - static boolean hasActiveCurves(AlgorithmConstraints constraints) { - return getActiveCurves(constraints) >= 0; - } - - static EllipticCurvesExtension createExtension( - AlgorithmConstraints constraints) { - - ArrayList idList = new ArrayList<>(supportedCurveIds.length); - for (int curveId : supportedCurveIds) { - if (constraints.permits( - EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), - "EC", idToParams.get(curveId))) { - idList.add(curveId); - } - } - - if (!idList.isEmpty()) { - int[] ids = new int[idList.size()]; - int i = 0; - for (Integer id : idList) { - ids[i++] = id; - } - - return new EllipticCurvesExtension(ids); - } - - return null; - } - - // get the preferred activated curve - int getPreferredCurve(AlgorithmConstraints constraints) { - return getPreferredCurve(curveIds, constraints); - } - - // get a preferred activated curve - private static int getPreferredCurve(int[] curves, - AlgorithmConstraints constraints) { - for (int curveId : curves) { - if (isSupported(curveId) && constraints.permits( - EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), - "EC", idToParams.get(curveId))) { - return curveId; - } - } - - return -1; - } - - boolean contains(int index) { - for (int curveId : curveIds) { - if (index == curveId) { - return true; - } - } - return false; - } - - @Override - int length() { - return 6 + (curveIds.length << 1); - } - - @Override - void send(HandshakeOutStream s) throws IOException { - s.putInt16(type.id); - int k = curveIds.length << 1; - s.putInt16(k + 2); - s.putInt16(k); - for (int curveId : curveIds) { - s.putInt16(curveId); - } - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("Extension " + type + ", curve names: {"); - boolean first = true; - for (int curveId : curveIds) { - if (first) { - first = false; - } else { - sb.append(", "); - } - // first check if it is a known named curve, then try other cases. - String curveName = getCurveName(curveId); - if (curveName != null) { - sb.append(curveName); - } else if (curveId == ARBITRARY_PRIME) { - sb.append("arbitrary_explicit_prime_curves"); - } else if (curveId == ARBITRARY_CHAR2) { - sb.append("arbitrary_explicit_char2_curves"); - } else { - sb.append("unknown curve " + curveId); - } - } - sb.append("}"); - return sb.toString(); - } - - // Test whether the given curve is supported. - static boolean isSupported(int index) { - for (int curveId : supportedCurveIds) { - if (index == curveId) { - return true; - } - } - - return false; - } - - static int getCurveIndex(ECParameterSpec params) { - String oid = JsseJce.getNamedCurveOid(params); - if (oid == null) { - return -1; - } - Integer n = oidToIdMap.get(oid); - return (n == null) ? -1 : n; - } - - static String getCurveOid(int index) { - return idToOidMap.get(index); - } - - static ECGenParameterSpec getECGenParamSpec(int index) { - AlgorithmParameters params = idToParams.get(index); - try { - return params.getParameterSpec(ECGenParameterSpec.class); - } catch (InvalidParameterSpecException ipse) { - // should be unlikely - String curveOid = getCurveOid(index); - return new ECGenParameterSpec(curveOid); - } - } - - private static String getCurveName(int index) { - for (NamedEllipticCurve namedCurve : NamedEllipticCurve.values()) { - if (namedCurve.id == index) { - return namedCurve.name; - } - } - - return null; - } -} diff -r 0909d3bcbacb -r b1b45177051b jdk/src/java.base/share/classes/sun/security/ssl/ExtensionType.java --- a/jdk/src/java.base/share/classes/sun/security/ssl/ExtensionType.java Thu May 11 07:33:23 2017 +0800 +++ b/jdk/src/java.base/share/classes/sun/security/ssl/ExtensionType.java Wed May 10 23:40:46 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -82,9 +82,9 @@ static final ExtensionType EXT_CERT_TYPE = e(0x0009, "cert_type"); // IANA registry value: 9 - // extensions defined in RFC 4492 (ECC) - static final ExtensionType EXT_ELLIPTIC_CURVES = - e(0x000A, "elliptic_curves"); // IANA registry value: 10 + // extensions defined in RFC 4492 (ECC) and RFC 7919 (FFDHE) + static final ExtensionType EXT_SUPPORTED_GROUPS = + e(0x000A, "supported_groups"); // IANA registry value: 10 static final ExtensionType EXT_EC_POINT_FORMATS = e(0x000B, "ec_point_formats"); // IANA registry value: 11 diff -r 0909d3bcbacb -r b1b45177051b jdk/src/java.base/share/classes/sun/security/ssl/HandshakeMessage.java --- a/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeMessage.java Thu May 11 07:33:23 2017 +0800 +++ b/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeMessage.java Wed May 10 23:40:46 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1369,8 +1369,9 @@ private static final int CURVE_EXPLICIT_CHAR2 = 2; private static final int CURVE_NAMED_CURVE = 3; - // id of the curve we are using - private int curveId; + // id of the named group we are using + private int groupId; + // encoded public point private byte[] pointBytes; @@ -1389,7 +1390,8 @@ ECDH_ServerKeyExchange(ECDHCrypt obj, PrivateKey privateKey, byte[] clntNonce, byte[] svrNonce, SecureRandom sr, SignatureAndHashAlgorithm signAlgorithm, - ProtocolVersion protocolVersion) throws GeneralSecurityException { + ProtocolVersion protocolVersion) + throws SSLHandshakeException, GeneralSecurityException { this.protocolVersion = protocolVersion; @@ -1397,7 +1399,14 @@ ECParameterSpec params = publicKey.getParams(); ECPoint point = publicKey.getW(); pointBytes = JsseJce.encodePoint(point, params.getCurve()); - curveId = EllipticCurvesExtension.getCurveIndex(params); + + NamedGroup namedGroup = NamedGroup.valueOf(params); + if ((namedGroup == null) || (namedGroup.oid == null) ){ + // unlikely + throw new SSLHandshakeException( + "Unnamed EC parameter spec: " + params); + } + groupId = namedGroup.id; if (privateKey == null) { // ECDH_anon @@ -1434,20 +1443,27 @@ // These parsing errors should never occur as we negotiated // the supported curves during the exchange of the Hello messages. if (curveType == CURVE_NAMED_CURVE) { - curveId = input.getInt16(); - if (!EllipticCurvesExtension.isSupported(curveId)) { + groupId = input.getInt16(); + NamedGroup namedGroup = NamedGroup.valueOf(groupId); + if (namedGroup == null) { throw new SSLHandshakeException( - "Unsupported curveId: " + curveId); + "Unknown named group ID: " + groupId); } - String curveOid = EllipticCurvesExtension.getCurveOid(curveId); - if (curveOid == null) { + + if (!SupportedGroupsExtension.supports(namedGroup)) { throw new SSLHandshakeException( - "Unknown named curve: " + curveId); + "Unsupported named group: " + namedGroup); } - parameters = JsseJce.getECParameterSpec(curveOid); + + if (namedGroup.oid == null) { + throw new SSLHandshakeException( + "Unknown named EC curve: " + namedGroup); + } + + parameters = JsseJce.getECParameterSpec(namedGroup.oid); if (parameters == null) { throw new SSLHandshakeException( - "Unsupported curve: " + curveOid); + "No supported EC parameter for named group: " + namedGroup); } } else { throw new SSLHandshakeException( @@ -1530,8 +1546,8 @@ sig.update(svrNonce); sig.update((byte)CURVE_NAMED_CURVE); - sig.update((byte)(curveId >> 8)); - sig.update((byte)curveId); + sig.update((byte)(groupId >> 8)); + sig.update((byte)groupId); sig.update((byte)pointBytes.length); sig.update(pointBytes); } @@ -1552,7 +1568,7 @@ @Override void send(HandshakeOutStream s) throws IOException { s.putInt8(CURVE_NAMED_CURVE); - s.putInt16(curveId); + s.putInt16(groupId); s.putBytes8(pointBytes); if (signatureBytes != null) { diff -r 0909d3bcbacb -r b1b45177051b jdk/src/java.base/share/classes/sun/security/ssl/Handshaker.java --- a/jdk/src/java.base/share/classes/sun/security/ssl/Handshaker.java Thu May 11 07:33:23 2017 +0800 +++ b/jdk/src/java.base/share/classes/sun/security/ssl/Handshaker.java Wed May 10 23:40:46 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,6 +52,7 @@ import static sun.security.ssl.CipherSuite.PRF.*; import static sun.security.ssl.CipherSuite.CipherType.*; +import static sun.security.ssl.NamedGroupType.*; /** * Handshaker ... processes handshake records from an SSL V3.0 @@ -685,42 +686,14 @@ ArrayList suites = new ArrayList<>(); if (!(activeProtocols.collection().isEmpty()) && activeProtocols.min.v != ProtocolVersion.NONE.v) { - boolean checkedCurves = false; - boolean hasCurves = false; + Map cachedStatus = + new EnumMap<>(NamedGroupType.class); for (CipherSuite suite : enabledCipherSuites.collection()) { - if (!activeProtocols.min.obsoletes(suite) && + if (suite.isAvailable() && + (!activeProtocols.min.obsoletes(suite)) && activeProtocols.max.supports(suite)) { - if (algorithmConstraints.permits( - EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), - suite.name, null)) { - - boolean available = true; - if (suite.keyExchange.isEC) { - if (!checkedCurves) { - hasCurves = EllipticCurvesExtension - .hasActiveCurves(algorithmConstraints); - checkedCurves = true; - - if (!hasCurves && debug != null && - Debug.isOn("verbose")) { - System.out.println( - "No available elliptic curves"); - } - } - - available = hasCurves; - - if (!available && debug != null && - Debug.isOn("verbose")) { - System.out.println( - "No active elliptic curves, ignore " + - suite); - } - } - - if (available) { - suites.add(suite); - } + if (isActivatable(suite, cachedStatus)) { + suites.add(suite); } } else if (debug != null && Debug.isOn("verbose")) { if (activeProtocols.min.obsoletes(suite)) { @@ -779,46 +752,15 @@ } boolean found = false; + Map cachedStatus = + new EnumMap<>(NamedGroupType.class); for (CipherSuite suite : enabledCipherSuites.collection()) { if (suite.isAvailable() && (!protocol.obsoletes(suite)) && protocol.supports(suite)) { - if (algorithmConstraints.permits( - EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), - suite.name, null)) { - - boolean available = true; - if (suite.keyExchange.isEC) { - if (!checkedCurves) { - hasCurves = EllipticCurvesExtension - .hasActiveCurves(algorithmConstraints); - checkedCurves = true; - - if (!hasCurves && debug != null && - Debug.isOn("verbose")) { - System.out.println( - "No activated elliptic curves"); - } - } - - available = hasCurves; - - if (!available && debug != null && - Debug.isOn("verbose")) { - System.out.println( - "No active elliptic curves, ignore " + - suite + " for " + protocol); - } - } - - if (available) { - protocols.add(protocol); - found = true; - break; - } - } else if (debug != null && Debug.isOn("verbose")) { - System.out.println( - "Ignoring disabled cipher suite: " + suite + - " for " + protocol); + if (isActivatable(suite, cachedStatus)) { + protocols.add(protocol); + found = true; + break; } } else if (debug != null && Debug.isOn("verbose")) { System.out.println( @@ -826,6 +768,7 @@ " for " + protocol); } } + if (!found && (debug != null) && Debug.isOn("handshake")) { System.out.println( "No available cipher suite for " + protocol); @@ -842,6 +785,43 @@ return activeProtocols; } + private boolean isActivatable(CipherSuite suite, + Map cachedStatus) { + + if (algorithmConstraints.permits( + EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), suite.name, null)) { + boolean available = true; + NamedGroupType groupType = suite.keyExchange.groupType; + if (groupType != NAMED_GROUP_NONE) { + Boolean checkedStatus = cachedStatus.get(groupType); + if (checkedStatus == null) { + available = SupportedGroupsExtension.isActivatable( + algorithmConstraints, groupType); + cachedStatus.put(groupType, available); + + if (!available && debug != null && Debug.isOn("verbose")) { + System.out.println("No activated named group"); + } + } else { + available = checkedStatus.booleanValue(); + } + + if (!available && debug != null && Debug.isOn("verbose")) { + System.out.println( + "No active named group, ignore " + suite); + } + + return available; + } else { + return true; + } + } else if (debug != null && Debug.isOn("verbose")) { + System.out.println("Ignoring disabled cipher suite: " + suite); + } + + return false; + } + /** * As long as handshaking has not activated, we can * change whether session creations are allowed. diff -r 0909d3bcbacb -r b1b45177051b jdk/src/java.base/share/classes/sun/security/ssl/HelloExtensions.java --- a/jdk/src/java.base/share/classes/sun/security/ssl/HelloExtensions.java Thu May 11 07:33:23 2017 +0800 +++ b/jdk/src/java.base/share/classes/sun/security/ssl/HelloExtensions.java Wed May 10 23:40:46 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,7 +49,7 @@ * explicitly support. * . ServerNameExtension: the server_name extension. * . SignatureAlgorithmsExtension: the signature_algorithms extension. - * . EllipticCurvesExtension: the ECC supported curves extension. + * . SupportedGroupsExtension: the supported groups extension. * . EllipticPointFormatsExtension: the ECC supported point formats * (compressed/uncompressed) extension. * . ALPNExtension: the application_layer_protocol_negotiation extension. @@ -79,8 +79,8 @@ extension = new ServerNameExtension(s, extlen); } else if (extType == ExtensionType.EXT_SIGNATURE_ALGORITHMS) { extension = new SignatureAlgorithmsExtension(s, extlen); - } else if (extType == ExtensionType.EXT_ELLIPTIC_CURVES) { - extension = new EllipticCurvesExtension(s, extlen); + } else if (extType == ExtensionType.EXT_SUPPORTED_GROUPS) { + extension = new SupportedGroupsExtension(s, extlen); } else if (extType == ExtensionType.EXT_EC_POINT_FORMATS) { extension = new EllipticPointFormatsExtension(s, extlen); } else if (extType == ExtensionType.EXT_RENEGOTIATION_INFO) { diff -r 0909d3bcbacb -r b1b45177051b jdk/src/java.base/share/classes/sun/security/ssl/NamedGroup.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/share/classes/sun/security/ssl/NamedGroup.java Wed May 10 23:40:46 2017 +0000 @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.ssl; + +import java.security.spec.ECParameterSpec; +import java.security.spec.ECGenParameterSpec; +import static sun.security.ssl.NamedGroupType.*; + +enum NamedGroup { + // Elliptic Curves (RFC 4492) + // + // See sun.security.util.CurveDB for the OIDs + + // NIST K-163 + SECT163_K1(1, NAMED_GROUP_ECDHE, "sect163k1", "1.3.132.0.1", true), + + SECT163_R1(2, NAMED_GROUP_ECDHE, "sect163r1", "1.3.132.0.2", false), + + // NIST B-163 + SECT163_R2(3, NAMED_GROUP_ECDHE, "sect163r2", "1.3.132.0.15", true), + + SECT193_R1(4, NAMED_GROUP_ECDHE, "sect193r1", "1.3.132.0.24", false), + SECT193_R2(5, NAMED_GROUP_ECDHE, "sect193r2", "1.3.132.0.25", false), + + // NIST K-233 + SECT233_K1(6, NAMED_GROUP_ECDHE, "sect233k1", "1.3.132.0.26", true), + + // NIST B-233 + SECT233_R1(7, NAMED_GROUP_ECDHE, "sect233r1", "1.3.132.0.27", true), + + SECT239_K1(8, NAMED_GROUP_ECDHE, "sect239k1", "1.3.132.0.3", false), + + // NIST K-283 + SECT283_K1(9, NAMED_GROUP_ECDHE, "sect283k1", "1.3.132.0.16", true), + + // NIST B-283 + SECT283_R1(10, NAMED_GROUP_ECDHE, "sect283r1", "1.3.132.0.17", true), + + // NIST K-409 + SECT409_K1(11, NAMED_GROUP_ECDHE, "sect409k1", "1.3.132.0.36", true), + + // NIST B-409 + SECT409_R1(12, NAMED_GROUP_ECDHE, "sect409r1", "1.3.132.0.37", true), + + // NIST K-571 + SECT571_K1(13, NAMED_GROUP_ECDHE, "sect571k1", "1.3.132.0.38", true), + + // NIST B-571 + SECT571_R1(14, NAMED_GROUP_ECDHE, "sect571r1", "1.3.132.0.39", true), + + SECP160_K1(15, NAMED_GROUP_ECDHE, "secp160k1", "1.3.132.0.9", false), + SECP160_R1(16, NAMED_GROUP_ECDHE, "secp160r1", "1.3.132.0.8", false), + SECP160_R2(17, NAMED_GROUP_ECDHE, "secp160r2", "1.3.132.0.30", false), + SECP192_K1(18, NAMED_GROUP_ECDHE, "secp192k1", "1.3.132.0.31", false), + + // NIST P-192 + SECP192_R1(19, NAMED_GROUP_ECDHE, "secp192r1", "1.2.840.10045.3.1.1", true), + + SECP224_K1(20, NAMED_GROUP_ECDHE, "secp224k1", "1.3.132.0.32", false), + // NIST P-224 + SECP224_R1(21, NAMED_GROUP_ECDHE, "secp224r1", "1.3.132.0.33", true), + + SECP256_K1(22, NAMED_GROUP_ECDHE, "secp256k1", "1.3.132.0.10", false), + + // NIST P-256 + SECP256_R1(23, NAMED_GROUP_ECDHE, "secp256r1", "1.2.840.10045.3.1.7", true), + + // NIST P-384 + SECP384_R1(24, NAMED_GROUP_ECDHE, "secp384r1", "1.3.132.0.34", true), + + // NIST P-521 + SECP521_R1(25, NAMED_GROUP_ECDHE, "secp521r1", "1.3.132.0.35", true), + + // Finite Field Diffie-Hellman Ephemeral Parameters (RFC 7919) + FFDHE_2048(256, NAMED_GROUP_FFDHE, "ffdhe2048", true), + FFDHE_3072(257, NAMED_GROUP_FFDHE, "ffdhe3072", true), + FFDHE_4096(258, NAMED_GROUP_FFDHE, "ffdhe4096", true), + FFDHE_6144(259, NAMED_GROUP_FFDHE, "ffdhe6144", true), + FFDHE_8192(260, NAMED_GROUP_FFDHE, "ffdhe8192", true); + + int id; + NamedGroupType type; + String name; + String oid; + String algorithm; + boolean isFips; + + // Constructor used for Elliptic Curve Groups (ECDHE) + NamedGroup(int id, NamedGroupType type, + String name, String oid, boolean isFips) { + this.id = id; + this.type = type; + this.name = name; + this.oid = oid; + this.algorithm = "EC"; + this.isFips = isFips; + } + + // Constructor used for Finite Field Diffie-Hellman Groups (FFDHE) + NamedGroup(int id, NamedGroupType type, String name, boolean isFips) { + this.id = id; + this.type = type; + this.name = name; + this.oid = null; + this.algorithm = "DiffieHellman"; + this.isFips = isFips; + } + + static NamedGroup valueOf(int id) { + for (NamedGroup group : NamedGroup.values()) { + if (group.id == id) { + return group; + } + } + + return null; + } + + static NamedGroup nameOf(String name) { + for (NamedGroup group : NamedGroup.values()) { + if (group.name.equals(name)) { + return group; + } + } + + return null; + } + + static NamedGroup valueOf(ECParameterSpec params) { + String oid = JsseJce.getNamedCurveOid(params); + if ((oid != null) && (!oid.isEmpty())) { + for (NamedGroup group : NamedGroup.values()) { + if (oid.equals(group.oid)) { + return group; + } + } + } + + return null; + } + + @Override + public String toString() { + return this.name; + } +} diff -r 0909d3bcbacb -r b1b45177051b jdk/src/java.base/share/classes/sun/security/ssl/NamedGroupType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/share/classes/sun/security/ssl/NamedGroupType.java Wed May 10 23:40:46 2017 +0000 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.ssl; + +enum NamedGroupType { + NAMED_GROUP_ECDHE, // Elliptic Curve Groups (ECDHE) + NAMED_GROUP_FFDHE, // Finite Field Groups (DHE) + NAMED_GROUP_NONE // No predefined named group +} diff -r 0909d3bcbacb -r b1b45177051b jdk/src/java.base/share/classes/sun/security/ssl/PredefinedDHParameterSpecs.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/share/classes/sun/security/ssl/PredefinedDHParameterSpecs.java Wed May 10 23:40:46 2017 +0000 @@ -0,0 +1,314 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.ssl; + +import java.security.*; +import java.math.BigInteger; +import java.util.regex.Pattern; +import java.util.regex.Matcher; +import java.util.Map; +import java.util.HashMap; +import java.util.Collections; +import javax.crypto.spec.DHParameterSpec; + +/** + * Predefined default DH ephemeral parameters. + */ +final class PredefinedDHParameterSpecs { + private final static boolean debugIsOn = + (Debug.getInstance("ssl") != null) && Debug.isOn("sslctx"); + + // + // Default DH ephemeral parameters + // + private static final BigInteger p512 = new BigInteger( // generated + "D87780E15FF50B4ABBE89870188B049406B5BEA98AB23A02" + + "41D88EA75B7755E669C08093D3F0CA7FC3A5A25CF067DCB9" + + "A43DD89D1D90921C6328884461E0B6D3", 16); + private static final BigInteger p768 = new BigInteger( // RFC 2409 + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF", 16); + + private static final BigInteger p1024 = new BigInteger( // RFC 2409 + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" + + "FFFFFFFFFFFFFFFF", 16); + private static final BigInteger p1536 = new BigInteger( // RFC 3526 + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF", 16); + private static final BigInteger p2048 = new BigInteger( // TLS FFDHE + "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" + + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" + + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" + + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" + + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" + + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + + "886B423861285C97FFFFFFFFFFFFFFFF", 16); + private static final BigInteger p3072 = new BigInteger( // TLS FFDHE + "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" + + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" + + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" + + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" + + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" + + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + + "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238" + + "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" + + "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3" + + "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" + + "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF" + + "3C1B20EE3FD59D7C25E41D2B66C62E37FFFFFFFFFFFFFFFF", 16); + private static final BigInteger p4096 = new BigInteger( // TLS FFDHE + "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" + + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" + + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" + + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" + + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" + + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + + "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238" + + "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" + + "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3" + + "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" + + "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF" + + "3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB" + + "7930E9E4E58857B6AC7D5F42D69F6D187763CF1D55034004" + + "87F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832" + + "A907600A918130C46DC778F971AD0038092999A333CB8B7A" + + "1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF" + + "8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E655F6A" + + "FFFFFFFFFFFFFFFF", 16); + private static final BigInteger p6144 = new BigInteger( // TLS FFDHE + "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" + + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" + + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" + + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" + + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" + + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + + "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238" + + "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" + + "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3" + + "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" + + "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF" + + "3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB" + + "7930E9E4E58857B6AC7D5F42D69F6D187763CF1D55034004" + + "87F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832" + + "A907600A918130C46DC778F971AD0038092999A333CB8B7A" + + "1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF" + + "8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E0DD902" + + "0BFD64B645036C7A4E677D2C38532A3A23BA4442CAF53EA6" + + "3BB454329B7624C8917BDD64B1C0FD4CB38E8C334C701C3A" + + "CDAD0657FCCFEC719B1F5C3E4E46041F388147FB4CFDB477" + + "A52471F7A9A96910B855322EDB6340D8A00EF092350511E3" + + "0ABEC1FFF9E3A26E7FB29F8C183023C3587E38DA0077D9B4" + + "763E4E4B94B2BBC194C6651E77CAF992EEAAC0232A281BF6" + + "B3A739C1226116820AE8DB5847A67CBEF9C9091B462D538C" + + "D72B03746AE77F5E62292C311562A846505DC82DB854338A" + + "E49F5235C95B91178CCF2DD5CACEF403EC9D1810C6272B04" + + "5B3B71F9DC6B80D63FDD4A8E9ADB1E6962A69526D43161C1" + + "A41D570D7938DAD4A40E329CD0E40E65FFFFFFFFFFFFFFFF", 16); + private static final BigInteger p8192 = new BigInteger( // TLS FFDHE + "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" + + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" + + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" + + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" + + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" + + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + + "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238" + + "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" + + "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3" + + "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" + + "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF" + + "3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB" + + "7930E9E4E58857B6AC7D5F42D69F6D187763CF1D55034004" + + "87F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832" + + "A907600A918130C46DC778F971AD0038092999A333CB8B7A" + + "1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF" + + "8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E0DD902" + + "0BFD64B645036C7A4E677D2C38532A3A23BA4442CAF53EA6" + + "3BB454329B7624C8917BDD64B1C0FD4CB38E8C334C701C3A" + + "CDAD0657FCCFEC719B1F5C3E4E46041F388147FB4CFDB477" + + "A52471F7A9A96910B855322EDB6340D8A00EF092350511E3" + + "0ABEC1FFF9E3A26E7FB29F8C183023C3587E38DA0077D9B4" + + "763E4E4B94B2BBC194C6651E77CAF992EEAAC0232A281BF6" + + "B3A739C1226116820AE8DB5847A67CBEF9C9091B462D538C" + + "D72B03746AE77F5E62292C311562A846505DC82DB854338A" + + "E49F5235C95B91178CCF2DD5CACEF403EC9D1810C6272B04" + + "5B3B71F9DC6B80D63FDD4A8E9ADB1E6962A69526D43161C1" + + "A41D570D7938DAD4A40E329CCFF46AAA36AD004CF600C838" + + "1E425A31D951AE64FDB23FCEC9509D43687FEB69EDD1CC5E" + + "0B8CC3BDF64B10EF86B63142A3AB8829555B2F747C932665" + + "CB2C0F1CC01BD70229388839D2AF05E454504AC78B758282" + + "2846C0BA35C35F5C59160CC046FD8251541FC68C9C86B022" + + "BB7099876A460E7451A8A93109703FEE1C217E6C3826E52C" + + "51AA691E0E423CFC99E9E31650C1217B624816CDAD9A95F9" + + "D5B8019488D9C0A0A1FE3075A577E23183F81D4A3F2FA457" + + "1EFC8CE0BA8A4FE8B6855DFE72B0A66EDED2FBABFBE58A30" + + "FAFABE1C5D71A87E2F741EF8C1FE86FEA6BBFDE530677F0D" + + "97D11D49F7A8443D0822E506A9F4614E011E2A94838FF88C" + + "D68C8BB7C5C6424CFFFFFFFFFFFFFFFF", 16); + + private static final BigInteger[] supportedPrimes = { + p512, p768, p1024, p1536, p2048, p3072, p4096, p6144, p8192}; + + private static final BigInteger[] ffdhePrimes = { + p2048, p3072, p4096, p6144, p8192}; + + // a measure of the uncertainty that prime modulus p is not a prime + // + // see BigInteger.isProbablePrime(int certainty) + private final static int PRIME_CERTAINTY = 120; + + // the known security property, jdk.tls.server.defaultDHEParameters + private final static String PROPERTY_NAME = + "jdk.tls.server.defaultDHEParameters"; + + private static final Pattern spacesPattern = Pattern.compile("\\s+"); + + private final static Pattern syntaxPattern = Pattern.compile( + "(\\{[0-9A-Fa-f]+,[0-9A-Fa-f]+\\})" + + "(,\\{[0-9A-Fa-f]+,[0-9A-Fa-f]+\\})*"); + + private static final Pattern paramsPattern = Pattern.compile( + "\\{([0-9A-Fa-f]+),([0-9A-Fa-f]+)\\}"); + + // cache of predefined default DH ephemeral parameters + final static Map definedParams; + + // cache of Finite Field DH Ephemeral parameters (RFC 7919/FFDHE) + final static Map ffdheParams; + + static { + String property = AccessController.doPrivileged( + new PrivilegedAction() { + public String run() { + return Security.getProperty(PROPERTY_NAME); + } + }); + + if (property != null && !property.isEmpty()) { + // remove double quote marks from beginning/end of the property + if (property.length() >= 2 && property.charAt(0) == '"' && + property.charAt(property.length() - 1) == '"') { + property = property.substring(1, property.length() - 1); + } + + property = property.trim(); + } + + if (property != null && !property.isEmpty()) { + Matcher spacesMatcher = spacesPattern.matcher(property); + property = spacesMatcher.replaceAll(""); + + if (debugIsOn) { + System.out.println("The Security Property " + + PROPERTY_NAME + ": " + property); + } + } + + Map defaultParams = new HashMap<>(); + if (property != null && !property.isEmpty()) { + Matcher syntaxMatcher = syntaxPattern.matcher(property); + if (syntaxMatcher.matches()) { + Matcher paramsFinder = paramsPattern.matcher(property); + while(paramsFinder.find()) { + String primeModulus = paramsFinder.group(1); + BigInteger p = new BigInteger(primeModulus, 16); + if (!p.isProbablePrime(PRIME_CERTAINTY)) { + if (debugIsOn) { + System.out.println( + "Prime modulus p in Security Property, " + + PROPERTY_NAME + ", is not a prime: " + + primeModulus); + } + + continue; + } + + String baseGenerator = paramsFinder.group(2); + BigInteger g = new BigInteger(baseGenerator, 16); + + DHParameterSpec spec = new DHParameterSpec(p, g); + int primeLen = p.bitLength(); + defaultParams.put(primeLen, spec); + } + } else if (debugIsOn) { + System.out.println("Invalid Security Property, " + + PROPERTY_NAME + ", definition"); + } + } + + Map tempFFDHEs = new HashMap<>(); + for (BigInteger p : ffdhePrimes) { + int primeLen = p.bitLength(); + DHParameterSpec dhps = new DHParameterSpec(p, BigInteger.TWO); + tempFFDHEs.put(primeLen, dhps); + defaultParams.putIfAbsent(primeLen, dhps); + } + + for (BigInteger p : supportedPrimes) { + int primeLen = p.bitLength(); + if (defaultParams.get(primeLen) == null) { + defaultParams.put(primeLen, + new DHParameterSpec(p, BigInteger.TWO)); + } + } + + ffdheParams = + Collections.unmodifiableMap(tempFFDHEs); + definedParams = + Collections.unmodifiableMap(defaultParams); + } +} diff -r 0909d3bcbacb -r b1b45177051b jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java --- a/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java Thu May 11 07:33:23 2017 +0800 +++ b/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java Wed May 10 23:40:46 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -96,7 +96,7 @@ private ProtocolVersion clientRequestedVersion; // client supported elliptic curves - private EllipticCurvesExtension requestedCurves; + private SupportedGroupsExtension requestedGroups; // the preferable signature algorithm used by ServerKeyExchange message SignatureAndHashAlgorithm preferableSignatureAlgorithm; @@ -751,8 +751,8 @@ throw new SSLException("Client did not resume a session"); } - requestedCurves = (EllipticCurvesExtension) - mesg.extensions.get(ExtensionType.EXT_ELLIPTIC_CURVES); + requestedGroups = (SupportedGroupsExtension) + mesg.extensions.get(ExtensionType.EXT_SUPPORTED_GROUPS); // We only need to handle the "signature_algorithm" extension // for full handshakes and TLS 1.2 or later. @@ -1341,6 +1341,8 @@ } } + // The named group used for ECDHE and FFDHE. + NamedGroup namedGroup = null; switch (keyExchange) { case K_RSA: // need RSA certs for authentication @@ -1366,6 +1368,37 @@ } break; case K_DHE_RSA: + // Is ephemeral DH cipher suite usable for the connection? + // + // [RFC 7919] If a compatible TLS server receives a Supported + // Groups extension from a client that includes any FFDHE group + // (i.e., any codepoint between 256 and 511, inclusive, even if + // unknown to the server), and if none of the client-proposed + // FFDHE groups are known and acceptable to the server, then + // the server MUST NOT select an FFDHE cipher suite. In this + // case, the server SHOULD select an acceptable non-FFDHE cipher + // suite from the client's offered list. If the extension is + // present with FFDHE groups, none of the client's offered + // groups are acceptable by the server, and none of the client's + // proposed non-FFDHE cipher suites are acceptable to the server, + // the server MUST end the connection with a fatal TLS alert + // of type insufficient_security(71). + // + // Note: For compatibility, if an application is customized to + // use legacy sizes (512 bits for exportable cipher suites and + // 768 bits for others), or the cipher suite is exportable, the + // FFDHE extension will not be used. + if ((!useLegacyEphemeralDHKeys) && (!suite.exportable) && + (requestedGroups != null) && requestedGroups.hasFFDHEGroup()) { + + namedGroup = requestedGroups.getPreferredGroup( + algorithmConstraints, NamedGroupType.NAMED_GROUP_FFDHE); + if (namedGroup == null) { + // no match found, cannot use this cipher suite. + return false; + } + } + // need RSA certs for authentication if (setupPrivateKeyAndChain("RSA") == false) { return false; @@ -1386,9 +1419,20 @@ } } - setupEphemeralDHKeys(suite.exportable, privateKey); + setupEphemeralDHKeys(namedGroup, suite.exportable, privateKey); break; case K_ECDHE_RSA: + // Is ECDHE cipher suite usable for the connection? + namedGroup = (requestedGroups != null) ? + requestedGroups.getPreferredGroup( + algorithmConstraints, NamedGroupType.NAMED_GROUP_ECDHE) : + SupportedGroupsExtension.getPreferredECGroup( + algorithmConstraints); + if (namedGroup == null) { + // no match found, cannot use this ciphersuite + return false; + } + // need RSA certs for authentication if (setupPrivateKeyAndChain("RSA") == false) { return false; @@ -1409,11 +1453,23 @@ } } - if (setupEphemeralECDHKeys() == false) { - return false; - } + setupEphemeralECDHKeys(namedGroup); break; case K_DHE_DSS: + // Is ephemeral DH cipher suite usable for the connection? + // + // See comment in K_DHE_RSA case. + if ((!useLegacyEphemeralDHKeys) && (!suite.exportable) && + (requestedGroups != null) && requestedGroups.hasFFDHEGroup()) { + + namedGroup = requestedGroups.getPreferredGroup( + algorithmConstraints, NamedGroupType.NAMED_GROUP_FFDHE); + if (namedGroup == null) { + // no match found, cannot use this cipher suite. + return false; + } + } + // get preferable peer signature algorithm for server key exchange if (protocolVersion.useTLS12PlusSpec()) { preferableSignatureAlgorithm = @@ -1434,9 +1490,20 @@ return false; } - setupEphemeralDHKeys(suite.exportable, privateKey); + setupEphemeralDHKeys(namedGroup, suite.exportable, privateKey); break; case K_ECDHE_ECDSA: + // Is ECDHE cipher suite usable for the connection? + namedGroup = (requestedGroups != null) ? + requestedGroups.getPreferredGroup( + algorithmConstraints, NamedGroupType.NAMED_GROUP_ECDHE) : + SupportedGroupsExtension.getPreferredECGroup( + algorithmConstraints); + if (namedGroup == null) { + // no match found, cannot use this ciphersuite + return false; + } + // get preferable peer signature algorithm for server key exchange if (protocolVersion.useTLS12PlusSpec()) { preferableSignatureAlgorithm = @@ -1456,9 +1523,8 @@ if (setupPrivateKeyAndChain("EC") == false) { return false; } - if (setupEphemeralECDHKeys() == false) { - return false; - } + + setupEphemeralECDHKeys(namedGroup); break; case K_ECDH_RSA: // need EC cert @@ -1475,14 +1541,36 @@ setupStaticECDHKeys(); break; case K_DH_ANON: + // Is ephemeral DH cipher suite usable for the connection? + // + // See comment in K_DHE_RSA case. + if ((!useLegacyEphemeralDHKeys) && (!suite.exportable) && + (requestedGroups != null) && requestedGroups.hasFFDHEGroup()) { + namedGroup = requestedGroups.getPreferredGroup( + algorithmConstraints, NamedGroupType.NAMED_GROUP_FFDHE); + if (namedGroup == null) { + // no match found, cannot use this cipher suite. + return false; + } + } + // no certs needed for anonymous - setupEphemeralDHKeys(suite.exportable, null); + setupEphemeralDHKeys(namedGroup, suite.exportable, null); break; case K_ECDH_ANON: - // no certs needed for anonymous - if (setupEphemeralECDHKeys() == false) { + // Is ECDHE cipher suite usable for the connection? + namedGroup = (requestedGroups != null) ? + requestedGroups.getPreferredGroup( + algorithmConstraints, NamedGroupType.NAMED_GROUP_ECDHE) : + SupportedGroupsExtension.getPreferredECGroup( + algorithmConstraints); + if (namedGroup == null) { + // no match found, cannot use this ciphersuite return false; } + + // no certs needed for anonymous + setupEphemeralECDHKeys(namedGroup); break; default: ClientKeyExchangeService p = @@ -1544,7 +1632,15 @@ * Acquire some "ephemeral" Diffie-Hellman keys for this handshake. * We don't reuse these, for improved forward secrecy. */ - private void setupEphemeralDHKeys(boolean export, Key key) { + private void setupEphemeralDHKeys( + NamedGroup namedGroup, boolean export, Key key) { + // Are the client and server willing to negotiate FFDHE groups? + if ((!useLegacyEphemeralDHKeys) && (!export) && (namedGroup != null)) { + dh = new DHCrypt(namedGroup, sslContext.getSecureRandom()); + + return; + } // Otherwise, the client is not compatible with FFDHE extension. + /* * 768 bits ephemeral DH private keys were used to be used in * ServerKeyExchange except that exportable ciphers max out at 512 @@ -1613,20 +1709,11 @@ dh = new DHCrypt(keySize, sslContext.getSecureRandom()); } - // Setup the ephemeral ECDH parameters. - // If we cannot continue because we do not support any of the curves that - // the client requested, return false. Otherwise (all is well), return true. - private boolean setupEphemeralECDHKeys() { - int index = (requestedCurves != null) ? - requestedCurves.getPreferredCurve(algorithmConstraints) : - EllipticCurvesExtension.getActiveCurves(algorithmConstraints); - if (index < 0) { - // no match found, cannot use this ciphersuite - return false; - } - - ecdh = new ECDHCrypt(index, sslContext.getSecureRandom()); - return true; + /** + * Setup the ephemeral ECDH parameters. + */ + private void setupEphemeralECDHKeys(NamedGroup namedGroup) { + ecdh = new ECDHCrypt(namedGroup, sslContext.getSecureRandom()); } private void setupStaticECDHKeys() { @@ -1674,9 +1761,11 @@ return false; } ECParameterSpec params = ((ECPublicKey)publicKey).getParams(); - int id = EllipticCurvesExtension.getCurveIndex(params); - if ((id <= 0) || !EllipticCurvesExtension.isSupported(id) || - ((requestedCurves != null) && !requestedCurves.contains(id))) { + NamedGroup namedGroup = NamedGroup.valueOf(params); + if ((namedGroup == null) || + (!SupportedGroupsExtension.supports(namedGroup)) || + ((requestedGroups != null) && + !requestedGroups.contains(namedGroup.id))) { return false; } } diff -r 0909d3bcbacb -r b1b45177051b jdk/src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java Wed May 10 23:40:46 2017 +0000 @@ -0,0 +1,491 @@ +/* + * Copyright (c) 2006, 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.ssl; + +import java.io.IOException; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.InvalidParameterSpecException; +import java.security.AlgorithmParameters; +import java.security.AlgorithmConstraints; +import java.security.CryptoPrimitive; +import java.security.AccessController; +import java.security.spec.AlgorithmParameterSpec; +import javax.crypto.spec.DHParameterSpec; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Map; +import java.util.ArrayList; +import javax.net.ssl.SSLProtocolException; + +import sun.security.action.GetPropertyAction; + +// +// Note: Since RFC 7919, the extension's semantics are expanded from +// "Supported Elliptic Curves" to "Supported Groups". The enum datatype +// used in the extension has been renamed from NamedCurve to NamedGroup. +// Its semantics are likewise expanded from "named curve" to "named group". +// +final class SupportedGroupsExtension extends HelloExtension { + + /* Class and subclass dynamic debugging support */ + private static final Debug debug = Debug.getInstance("ssl"); + + private static final int ARBITRARY_PRIME = 0xff01; + private static final int ARBITRARY_CHAR2 = 0xff02; + + // cache to speed up the parameters construction + private static final Map namedGroupParams = new HashMap<>(); + + // the supported named groups + private static final NamedGroup[] supportedNamedGroups; + + // the named group presented in the extension + private final int[] requestedNamedGroupIds; + + static { + boolean requireFips = SunJSSE.isFIPS(); + + // The value of the System Property defines a list of enabled named + // groups in preference order, separated with comma. For example: + // + // jdk.tls.namedGroups="secp521r1, secp256r1, ffdhe2048" + // + // If the System Property is not defined or the value is empty, the + // default groups and preferences will be used. + String property = AccessController.doPrivileged( + new GetPropertyAction("jdk.tls.namedGroups")); + if (property != null && property.length() != 0) { + // remove double quote marks from beginning/end of the property + if (property.length() > 1 && property.charAt(0) == '"' && + property.charAt(property.length() - 1) == '"') { + property = property.substring(1, property.length() - 1); + } + } + + ArrayList groupList; + if (property != null && property.length() != 0) { // customized groups + String[] groups = property.split(","); + groupList = new ArrayList<>(groups.length); + for (String group : groups) { + group = group.trim(); + if (!group.isEmpty()) { + NamedGroup namedGroup = NamedGroup.nameOf(group); + if (namedGroup != null && + (!requireFips || namedGroup.isFips)) { + if (isAvailableGroup(namedGroup)) { + groupList.add(namedGroup); + } + } // ignore unknown groups + } + } + + if (groupList.isEmpty() && JsseJce.isEcAvailable()) { + throw new IllegalArgumentException( + "System property jdk.tls.namedGroups(" + property + ") " + + "contains no supported elliptic curves"); + } + } else { // default groups + NamedGroup[] groups; + if (requireFips) { + groups = new NamedGroup[] { + // only NIST curves in FIPS mode + NamedGroup.SECP256_R1, + NamedGroup.SECP384_R1, + NamedGroup.SECP521_R1, + NamedGroup.SECT283_K1, + NamedGroup.SECT283_R1, + NamedGroup.SECT409_K1, + NamedGroup.SECT409_R1, + NamedGroup.SECT571_K1, + NamedGroup.SECT571_R1, + + // FFDHE 2048 + NamedGroup.FFDHE_2048, + NamedGroup.FFDHE_3072, + NamedGroup.FFDHE_4096, + NamedGroup.FFDHE_6144, + NamedGroup.FFDHE_8192, + }; + } else { + groups = new NamedGroup[] { + // NIST curves first + NamedGroup.SECP256_R1, + NamedGroup.SECP384_R1, + NamedGroup.SECP521_R1, + NamedGroup.SECT283_K1, + NamedGroup.SECT283_R1, + NamedGroup.SECT409_K1, + NamedGroup.SECT409_R1, + NamedGroup.SECT571_K1, + NamedGroup.SECT571_R1, + + // non-NIST curves + NamedGroup.SECP256_K1, + + // FFDHE 2048 + NamedGroup.FFDHE_2048, + NamedGroup.FFDHE_3072, + NamedGroup.FFDHE_4096, + NamedGroup.FFDHE_6144, + NamedGroup.FFDHE_8192, + }; + } + + groupList = new ArrayList<>(groups.length); + for (NamedGroup group : groups) { + if (isAvailableGroup(group)) { + groupList.add(group); + } + } + } + + if (debug != null && groupList.isEmpty()) { + Debug.log( + "Initialized [jdk.tls.namedGroups|default] list contains " + + "no available elliptic curves. " + + (property != null ? "(" + property + ")" : "[Default]")); + } + + supportedNamedGroups = new NamedGroup[groupList.size()]; + int i = 0; + for (NamedGroup namedGroup : groupList) { + supportedNamedGroups[i++] = namedGroup; + } + } + + // check whether the group is supported by the underlying providers + private static boolean isAvailableGroup(NamedGroup namedGroup) { + AlgorithmParameters params = null; + AlgorithmParameterSpec spec = null; + if ("EC".equals(namedGroup.algorithm)) { + if (namedGroup.oid != null) { + try { + params = JsseJce.getAlgorithmParameters("EC"); + spec = new ECGenParameterSpec(namedGroup.oid); + } catch (Exception e) { + return false; + } + } + } else if ("DiffieHellman".equals(namedGroup.algorithm)) { + try { + params = JsseJce.getAlgorithmParameters("DiffieHellman"); + spec = getFFDHEDHParameterSpec(namedGroup); + } catch (Exception e) { + return false; + } + } + + if ((params != null) && (spec != null)) { + try { + params.init(spec); + } catch (Exception e) { + return false; + } + + // cache the parameters + namedGroupParams.put(namedGroup, params); + + return true; + } + + return false; + } + + private static DHParameterSpec getFFDHEDHParameterSpec( + NamedGroup namedGroup) { + DHParameterSpec spec = null; + switch (namedGroup) { + case FFDHE_2048: + spec = PredefinedDHParameterSpecs.ffdheParams.get(2048); + break; + case FFDHE_3072: + spec = PredefinedDHParameterSpecs.ffdheParams.get(3072); + break; + case FFDHE_4096: + spec = PredefinedDHParameterSpecs.ffdheParams.get(4096); + break; + case FFDHE_6144: + spec = PredefinedDHParameterSpecs.ffdheParams.get(6144); + break; + case FFDHE_8192: + spec = PredefinedDHParameterSpecs.ffdheParams.get(8192); + } + + return spec; + } + + private static DHParameterSpec getPredefinedDHParameterSpec( + NamedGroup namedGroup) { + DHParameterSpec spec = null; + switch (namedGroup) { + case FFDHE_2048: + spec = PredefinedDHParameterSpecs.definedParams.get(2048); + break; + case FFDHE_3072: + spec = PredefinedDHParameterSpecs.definedParams.get(3072); + break; + case FFDHE_4096: + spec = PredefinedDHParameterSpecs.definedParams.get(4096); + break; + case FFDHE_6144: + spec = PredefinedDHParameterSpecs.definedParams.get(6144); + break; + case FFDHE_8192: + spec = PredefinedDHParameterSpecs.definedParams.get(8192); + } + + return spec; + } + + private SupportedGroupsExtension(int[] requestedNamedGroupIds) { + super(ExtensionType.EXT_SUPPORTED_GROUPS); + + this.requestedNamedGroupIds = requestedNamedGroupIds; + } + + SupportedGroupsExtension(HandshakeInStream s, int len) throws IOException { + super(ExtensionType.EXT_SUPPORTED_GROUPS); + + int k = s.getInt16(); + if (((len & 1) != 0) || (k == 0) || (k + 2 != len)) { + throw new SSLProtocolException("Invalid " + type + " extension"); + } + + // Note: unknown named group will be ignored later. + requestedNamedGroupIds = new int[k >> 1]; + for (int i = 0; i < requestedNamedGroupIds.length; i++) { + requestedNamedGroupIds[i] = s.getInt16(); + } + } + + // Get a local preferred supported ECDHE group permitted by the constraints. + static NamedGroup getPreferredECGroup(AlgorithmConstraints constraints) { + for (NamedGroup namedGroup : supportedNamedGroups) { + if ((namedGroup.type == NamedGroupType.NAMED_GROUP_ECDHE) && + constraints.permits(EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), + namedGroup.algorithm, namedGroupParams.get(namedGroup))) { + + return namedGroup; + } + } + + return null; + } + + // Is there any supported group permitted by the constraints? + static boolean isActivatable( + AlgorithmConstraints constraints, NamedGroupType type) { + + boolean hasFFDHEGroups = false; + for (NamedGroup namedGroup : supportedNamedGroups) { + if (namedGroup.type == type) { + if (constraints.permits( + EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), + namedGroup.algorithm, + namedGroupParams.get(namedGroup))) { + + return true; + } + + if (!hasFFDHEGroups && + (type == NamedGroupType.NAMED_GROUP_FFDHE)) { + + hasFFDHEGroups = true; + } + } + } + + // For compatibility, if no FFDHE groups are defined, the non-FFDHE + // compatible mode (using DHE cipher suite without FFDHE extension) + // is allowed. + // + // Note that the constraints checking on DHE parameters will be + // performed during key exchanging in a handshake. + if (!hasFFDHEGroups && (type == NamedGroupType.NAMED_GROUP_FFDHE)) { + return true; + } + + return false; + } + + // Create the default supported groups extension. + static SupportedGroupsExtension createExtension( + AlgorithmConstraints constraints, + CipherSuiteList cipherSuites, boolean enableFFDHE) { + + ArrayList groupList = + new ArrayList<>(supportedNamedGroups.length); + for (NamedGroup namedGroup : supportedNamedGroups) { + if ((!enableFFDHE) && + (namedGroup.type == NamedGroupType.NAMED_GROUP_FFDHE)) { + continue; + } + + if (cipherSuites.contains(namedGroup.type) && + constraints.permits(EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), + namedGroup.algorithm, namedGroupParams.get(namedGroup))) { + + groupList.add(namedGroup.id); + } + } + + if (!groupList.isEmpty()) { + int[] ids = new int[groupList.size()]; + int i = 0; + for (Integer id : groupList) { + ids[i++] = id; + } + + return new SupportedGroupsExtension(ids); + } + + return null; + } + + // get the preferred activated named group + NamedGroup getPreferredGroup( + AlgorithmConstraints constraints, NamedGroupType type) { + + for (int groupId : requestedNamedGroupIds) { + NamedGroup namedGroup = NamedGroup.valueOf(groupId); + if ((namedGroup != null) && (namedGroup.type == type) && + SupportedGroupsExtension.supports(namedGroup) && + constraints.permits(EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), + namedGroup.algorithm, namedGroupParams.get(namedGroup))) { + + return namedGroup; + } + } + + return null; + } + + boolean hasFFDHEGroup() { + for (int groupId : requestedNamedGroupIds) { + /* + * [RFC 7919] Codepoints in the "Supported Groups Registry" + * with a high byte of 0x01 (that is, between 256 and 511, + * inclusive) are set aside for FFDHE groups. + */ + if ((groupId >= 256) && (groupId <= 511)) { + return true; + } + } + + return false; + } + + boolean contains(int index) { + for (int groupId : requestedNamedGroupIds) { + if (index == groupId) { + return true; + } + } + return false; + } + + @Override + int length() { + return 6 + (requestedNamedGroupIds.length << 1); + } + + @Override + void send(HandshakeOutStream s) throws IOException { + s.putInt16(type.id); + int k = requestedNamedGroupIds.length << 1; + s.putInt16(k + 2); + s.putInt16(k); + for (int groupId : requestedNamedGroupIds) { + s.putInt16(groupId); + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("Extension " + type + ", group names: {"); + boolean first = true; + for (int groupId : requestedNamedGroupIds) { + if (first) { + first = false; + } else { + sb.append(", "); + } + // first check if it is a known named group, then try other cases. + NamedGroup namedGroup = NamedGroup.valueOf(groupId); + if (namedGroup != null) { + sb.append(namedGroup.name); + } else if (groupId == ARBITRARY_PRIME) { + sb.append("arbitrary_explicit_prime_curves"); + } else if (groupId == ARBITRARY_CHAR2) { + sb.append("arbitrary_explicit_char2_curves"); + } else { + sb.append("unknown named group " + groupId); + } + } + sb.append("}"); + return sb.toString(); + } + + static boolean supports(NamedGroup namedGroup) { + for (NamedGroup group : supportedNamedGroups) { + if (namedGroup.id == group.id) { + return true; + } + } + + return false; + } + + static ECGenParameterSpec getECGenParamSpec(NamedGroup namedGroup) { + if (namedGroup.type != NamedGroupType.NAMED_GROUP_ECDHE) { + throw new RuntimeException("Not a named EC group: " + namedGroup); + } + + AlgorithmParameters params = namedGroupParams.get(namedGroup); + try { + return params.getParameterSpec(ECGenParameterSpec.class); + } catch (InvalidParameterSpecException ipse) { + // should be unlikely + return new ECGenParameterSpec(namedGroup.oid); + } + } + + static DHParameterSpec getDHParameterSpec(NamedGroup namedGroup) { + if (namedGroup.type != NamedGroupType.NAMED_GROUP_FFDHE) { + throw new RuntimeException("Not a named DH group: " + namedGroup); + } + + AlgorithmParameters params = namedGroupParams.get(namedGroup); + try { + return params.getParameterSpec(DHParameterSpec.class); + } catch (InvalidParameterSpecException ipse) { + // should be unlikely + return getPredefinedDHParameterSpec(namedGroup); + } + } +} diff -r 0909d3bcbacb -r b1b45177051b jdk/test/sun/security/ssl/DHKeyExchange/DHEKeySizing.java --- a/jdk/test/sun/security/ssl/DHKeyExchange/DHEKeySizing.java Thu May 11 07:33:23 2017 +0800 +++ b/jdk/test/sun/security/ssl/DHKeyExchange/DHEKeySizing.java Wed May 10 23:40:46 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,33 +31,44 @@ * @bug 6956398 * @summary make ephemeral DH key match the length of the certificate key * @run main/othervm + * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1639 267 + * @run main/othervm -Djsse.enableFFDHE=false * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1255 75 - * @run main/othervm -Djdk.tls.ephemeralDHKeySize=matched + * @run main/othervm -Djsse.enableFFDHE=false + * -Djdk.tls.ephemeralDHKeySize=matched * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1255 75 - * @run main/othervm -Djdk.tls.ephemeralDHKeySize=legacy + * @run main/othervm -Djsse.enableFFDHE=false + * -Djdk.tls.ephemeralDHKeySize=legacy * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1255 75 - * @run main/othervm -Djdk.tls.ephemeralDHKeySize=1024 + * @run main/othervm -Djsse.enableFFDHE=false + * -Djdk.tls.ephemeralDHKeySize=1024 * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1255 75 * - * @run main/othervm + * @run main/othervm -Djsse.enableFFDHE=false * DHEKeySizing SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA true 229 75 * - * @run main/othervm + * @run main/othervm -Djsse.enableFFDHE=false * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1383 139 - * @run main/othervm -Djdk.tls.ephemeralDHKeySize=legacy + * @run main/othervm -Djsse.enableFFDHE=false + * -Djdk.tls.ephemeralDHKeySize=legacy * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1319 107 - * @run main/othervm -Djdk.tls.ephemeralDHKeySize=matched + * @run main/othervm -Djsse.enableFFDHE=false + * -Djdk.tls.ephemeralDHKeySize=matched * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1639 267 - * @run main/othervm -Djdk.tls.ephemeralDHKeySize=1024 + * @run main/othervm -Djsse.enableFFDHE=false + * -Djdk.tls.ephemeralDHKeySize=1024 * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1383 139 * - * @run main/othervm + * @run main/othervm -Djsse.enableFFDHE=false * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 false 357 139 - * @run main/othervm -Djdk.tls.ephemeralDHKeySize=legacy + * @run main/othervm -Djsse.enableFFDHE=false + * -Djdk.tls.ephemeralDHKeySize=legacy * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 false 293 107 - * @run main/othervm -Djdk.tls.ephemeralDHKeySize=matched + * @run main/othervm -Djsse.enableFFDHE=false + * -Djdk.tls.ephemeralDHKeySize=matched * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 false 357 139 - * @run main/othervm -Djdk.tls.ephemeralDHKeySize=1024 + * @run main/othervm -Djsse.enableFFDHE=false + * -Djdk.tls.ephemeralDHKeySize=1024 * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 false 357 139 */ diff -r 0909d3bcbacb -r b1b45177051b jdk/test/sun/security/ssl/DHKeyExchange/UseStrongDHSizes.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/security/ssl/DHKeyExchange/UseStrongDHSizes.java Wed May 10 23:40:46 2017 +0000 @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// +// SunJSSE does not support dynamic system properties, no way to re-use +// system properties in samevm/agentvm mode. +// + +/* + * @test + * @bug 8140436 + * @modules jdk.crypto.ec + * @library /javax/net/ssl/templates + * @summary Negotiated Finite Field Diffie-Hellman Ephemeral Parameters for TLS + * @run main/othervm UseStrongDHSizes 2048 + */ + +import java.io.InputStream; +import java.io.OutputStream; +import java.security.Security; +import javax.net.ssl.SSLSocket; + +public class UseStrongDHSizes extends SSLSocketTemplate { + /* + * Run the test case. + */ + public static void main(String[] args) throws Exception { + // reset the security property to make sure that the algorithms + // and keys used in this test are not disabled unexpectedly. + String constraint = "DH keySize < " + Integer.valueOf(args[0]); + Security.setProperty("jdk.tls.disabledAlgorithms", constraint); + Security.setProperty("jdk.certpath.disabledAlgorithms", ""); + + (new UseStrongDHSizes()).run(); + } + + @Override + protected void runServerApplication(SSLSocket socket) throws Exception { + String ciphers[] = { + "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", + "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", + "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", + "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA"}; + + socket.setEnabledCipherSuites(ciphers); + socket.setWantClientAuth(true); + + InputStream sslIS = socket.getInputStream(); + OutputStream sslOS = socket.getOutputStream(); + + sslIS.read(); + sslOS.write(85); + sslOS.flush(); + } + + @Override + protected void runClientApplication(SSLSocket socket) throws Exception { + String ciphers[] = { + "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", + "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", + "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", + "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA"}; + socket.setEnabledCipherSuites(ciphers); + socket.setUseClientMode(true); + + InputStream sslIS = socket.getInputStream(); + OutputStream sslOS = socket.getOutputStream(); + + sslOS.write(280); + sslOS.flush(); + sslIS.read(); + } +}