changeset 12107:5f0839ac7e0d jdk8u121-b01

Merge
author asaha
date Mon, 19 Sep 2016 11:21:02 -0700
parents 1f5412ac6bd8 8dc49b3c8953
children 17a829050ae5
files
diffstat 38 files changed, 1826 insertions(+), 524 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/java/net/SocketInputStream.java	Thu Sep 08 15:00:00 2016 -0700
+++ b/src/share/classes/java/net/SocketInputStream.java	Mon Sep 19 11:21:02 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2016, 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
@@ -155,11 +155,12 @@
         }
 
         // bounds check
-        if (length <= 0 || off < 0 || off + length > b.length) {
+        if (length <= 0 || off < 0 || length > b.length - off) {
             if (length == 0) {
                 return 0;
             }
-            throw new ArrayIndexOutOfBoundsException();
+            throw new ArrayIndexOutOfBoundsException("length == " + length
+                    + " off == " + off + " buffer length == " + b.length);
         }
 
         boolean gotReset = false;
--- a/src/share/classes/java/net/SocketOutputStream.java	Thu Sep 08 15:00:00 2016 -0700
+++ b/src/share/classes/java/net/SocketOutputStream.java	Mon Sep 19 11:21:02 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2016, 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
@@ -97,11 +97,13 @@
      */
     private void socketWrite(byte b[], int off, int len) throws IOException {
 
-        if (len <= 0 || off < 0 || off + len > b.length) {
+
+        if (len <= 0 || off < 0 || len > b.length - off) {
             if (len == 0) {
                 return;
             }
-            throw new ArrayIndexOutOfBoundsException();
+            throw new ArrayIndexOutOfBoundsException("len == " + len
+                    + " off == " + off + " buffer length == " + b.length);
         }
 
         FileDescriptor fd = impl.acquireFD();
--- a/src/share/classes/sun/security/pkcs/SignerInfo.java	Thu Sep 08 15:00:00 2016 -0700
+++ b/src/share/classes/sun/security/pkcs/SignerInfo.java	Mon Sep 19 11:21:02 2016 -0700
@@ -55,6 +55,7 @@
 import sun.security.util.DerOutputStream;
 import sun.security.util.DerValue;
 import sun.security.util.DisabledAlgorithmConstraints;
+import sun.security.util.KeyUtil;
 import sun.security.util.ObjectIdentifier;
 import sun.security.x509.AlgorithmId;
 import sun.security.x509.X500Name;
@@ -399,7 +400,9 @@
             // check if the public key is restricted
             if (!JAR_DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, key)) {
                 throw new SignatureException("Public key check failed. " +
-                        "Disabled algorithm used: " + key.getAlgorithm());
+                        "Disabled key used: " +
+                        KeyUtil.getKeySize(key) + " bit " +
+                        key.getAlgorithm());
             }
 
             if (cert.hasUnsupportedCriticalExtension()) {
--- a/src/share/classes/sun/security/provider/certpath/AlgorithmChecker.java	Thu Sep 08 15:00:00 2016 -0700
+++ b/src/share/classes/sun/security/provider/certpath/AlgorithmChecker.java	Mon Sep 19 11:21:02 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2016, 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,12 +31,10 @@
 import java.util.Collections;
 import java.util.Set;
 import java.util.EnumSet;
-import java.util.HashSet;
 import java.math.BigInteger;
 import java.security.PublicKey;
 import java.security.KeyFactory;
 import java.security.AlgorithmParameters;
-import java.security.NoSuchAlgorithmException;
 import java.security.GeneralSecurityException;
 import java.security.cert.Certificate;
 import java.security.cert.X509CRL;
@@ -48,10 +46,13 @@
 import java.security.cert.CertPathValidatorException;
 import java.security.cert.CertPathValidatorException.BasicReason;
 import java.security.cert.PKIXReason;
-import java.io.IOException;
-import java.security.interfaces.*;
-import java.security.spec.*;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPublicKey;
+import java.security.spec.DSAPublicKeySpec;
 
+import sun.security.util.AnchorCertificates;
+import sun.security.util.CertConstraintParameters;
+import sun.security.util.Debug;
 import sun.security.util.DisabledAlgorithmConstraints;
 import sun.security.x509.X509CertImpl;
 import sun.security.x509.X509CRLImpl;
@@ -69,6 +70,7 @@
  * @see PKIXParameters
  */
 final public class AlgorithmChecker extends PKIXCertPathChecker {
+    private static final Debug debug = Debug.getInstance("certpath");
 
     private final AlgorithmConstraints constraints;
     private final PublicKey trustedPubKey;
@@ -88,6 +90,14 @@
         certPathDefaultConstraints = new DisabledAlgorithmConstraints(
             DisabledAlgorithmConstraints.PROPERTY_CERTPATH_DISABLED_ALGS);
 
+    // If there is no "cacerts" keyword, then disable anchor checking
+    private static final boolean publicCALimits =
+            certPathDefaultConstraints.checkProperty("jdkCA");
+
+    // If anchor checking enabled, this will be true if the trust anchor
+    // has a match in the cacerts file
+    private boolean trustedMatch = false;
+
     /**
      * Create a new <code>AlgorithmChecker</code> with the algorithm
      * constraints specified in security property
@@ -136,6 +146,11 @@
 
         if (anchor.getTrustedCert() != null) {
             this.trustedPubKey = anchor.getTrustedCert().getPublicKey();
+            // Check for anchor certificate restrictions
+            trustedMatch = checkFingerprint(anchor.getTrustedCert());
+            if (trustedMatch && debug != null) {
+                debug.println("trustedMatch = true");
+            }
         } else {
             this.trustedPubKey = anchor.getCAPublicKey();
         }
@@ -144,6 +159,19 @@
         this.constraints = constraints;
     }
 
+    // Check this 'cert' for restrictions in the AnchorCertificates
+    // trusted certificates list
+    private static boolean checkFingerprint(X509Certificate cert) {
+        if (!publicCALimits) {
+            return false;
+        }
+
+        if (debug != null) {
+            debug.println("AlgorithmChecker.contains: " + cert.getSigAlgName());
+        }
+        return AnchorCertificates.contains(cert);
+    }
+
     @Override
     public void init(boolean forward) throws CertPathValidatorException {
         //  Note that this class does not support forward mode.
@@ -181,36 +209,8 @@
             return;
         }
 
-        X509CertImpl x509Cert = null;
-        try {
-            x509Cert = X509CertImpl.toImpl((X509Certificate)cert);
-        } catch (CertificateException ce) {
-            throw new CertPathValidatorException(ce);
-        }
-
-        PublicKey currPubKey = x509Cert.getPublicKey();
-        String currSigAlg = x509Cert.getSigAlgName();
-
-        AlgorithmId algorithmId = null;
-        try {
-            algorithmId = (AlgorithmId)x509Cert.get(X509CertImpl.SIG_ALG);
-        } catch (CertificateException ce) {
-            throw new CertPathValidatorException(ce);
-        }
-
-        AlgorithmParameters currSigAlgParams = algorithmId.getParameters();
-
-        // Check the current signature algorithm
-        if (!constraints.permits(
-                SIGNATURE_PRIMITIVE_SET,
-                currSigAlg, currSigAlgParams)) {
-            throw new CertPathValidatorException(
-                "Algorithm constraints check failed: " + currSigAlg,
-                null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
-        }
-
         // check the key usage and key size
-        boolean[] keyUsage = x509Cert.getKeyUsage();
+        boolean[] keyUsage = ((X509Certificate) cert).getKeyUsage();
         if (keyUsage != null && keyUsage.length < 9) {
             throw new CertPathValidatorException(
                 "incorrect KeyUsage extension",
@@ -248,28 +248,68 @@
 
             if (primitives.isEmpty()) {
                 throw new CertPathValidatorException(
-                    "incorrect KeyUsage extension",
+                    "incorrect KeyUsage extension bits",
                     null, null, -1, PKIXReason.INVALID_KEY_USAGE);
             }
         }
 
+        PublicKey currPubKey = cert.getPublicKey();
+
+        // Check against DisabledAlgorithmConstraints certpath constraints.
+        // permits() will throw exception on failure.
+        certPathDefaultConstraints.permits(primitives,
+                new CertConstraintParameters((X509Certificate)cert,
+                        trustedMatch));
+                // new CertConstraintParameters(x509Cert, trustedMatch));
+        // If there is no previous key, set one and exit
+        if (prevPubKey == null) {
+            prevPubKey = currPubKey;
+            return;
+        }
+
+        X509CertImpl x509Cert;
+        AlgorithmId algorithmId;
+        try {
+            x509Cert = X509CertImpl.toImpl((X509Certificate)cert);
+            algorithmId = (AlgorithmId)x509Cert.get(X509CertImpl.SIG_ALG);
+        } catch (CertificateException ce) {
+            throw new CertPathValidatorException(ce);
+        }
+
+        AlgorithmParameters currSigAlgParams = algorithmId.getParameters();
+        String currSigAlg = x509Cert.getSigAlgName();
+
+        // If 'constraints' is not of DisabledAlgorithmConstraints, check all
+        // everything individually
+        if (!(constraints instanceof DisabledAlgorithmConstraints)) {
+            // Check the current signature algorithm
+            if (!constraints.permits(
+                    SIGNATURE_PRIMITIVE_SET,
+                    currSigAlg, currSigAlgParams)) {
+                throw new CertPathValidatorException(
+                        "Algorithm constraints check failed on signature " +
+                                "algorithm: " + currSigAlg, null, null, -1,
+                        BasicReason.ALGORITHM_CONSTRAINED);
+            }
+
         if (!constraints.permits(primitives, currPubKey)) {
             throw new CertPathValidatorException(
-                "algorithm constraints check failed",
+                        "Algorithm constraints check failed on keysize: " +
+                                sun.security.util.KeyUtil.getKeySize(currPubKey),
                 null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
         }
+        }
 
         // Check with previous cert for signature algorithm and public key
         if (prevPubKey != null) {
-            if (currSigAlg != null) {
                 if (!constraints.permits(
                         SIGNATURE_PRIMITIVE_SET,
                         currSigAlg, prevPubKey, currSigAlgParams)) {
                     throw new CertPathValidatorException(
-                        "Algorithm constraints check failed: " + currSigAlg,
+                    "Algorithm constraints check failed on " +
+                            "signature algorithm: " + currSigAlg,
                         null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
                 }
-            }
 
             // Inherit key parameters from previous key
             if (PKIX.isDSAPublicKeyWithoutParams(currPubKey)) {
@@ -282,7 +322,7 @@
                 DSAParams params = ((DSAPublicKey)prevPubKey).getParams();
                 if (params == null) {
                     throw new CertPathValidatorException(
-                                    "Key parameters missing");
+                        "Key parameters missing from public key.");
                 }
 
                 try {
@@ -330,6 +370,11 @@
             // Don't bother to change the trustedPubKey.
             if (anchor.getTrustedCert() != null) {
                 prevPubKey = anchor.getTrustedCert().getPublicKey();
+                // Check for anchor certificate restrictions
+                trustedMatch = checkFingerprint(anchor.getTrustedCert());
+                if (trustedMatch && debug != null) {
+                    debug.println("trustedMatch = true");
+                }
             } else {
                 prevPubKey = anchor.getCAPublicKey();
             }
@@ -370,7 +415,8 @@
         if (!certPathDefaultConstraints.permits(
                 SIGNATURE_PRIMITIVE_SET, sigAlgName, key, sigAlgParams)) {
             throw new CertPathValidatorException(
-                "algorithm check failed: " + sigAlgName + " is disabled",
+                "Algorithm constraints check failed on signature algorithm: " +
+                sigAlgName + " is disabled",
                 null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
         }
     }
--- a/src/share/classes/sun/security/provider/certpath/PKIXMasterCertPathValidator.java	Thu Sep 08 15:00:00 2016 -0700
+++ b/src/share/classes/sun/security/provider/certpath/PKIXMasterCertPathValidator.java	Mon Sep 19 11:21:02 2016 -0700
@@ -131,8 +131,8 @@
 
                 } catch (CertPathValidatorException cpve) {
                     throw new CertPathValidatorException(cpve.getMessage(),
-                        cpve.getCause(), cpOriginal, cpSize - (i + 1),
-                        cpve.getReason());
+                        (cpve.getCause() != null) ? cpve.getCause() : cpve,
+                            cpOriginal, cpSize - (i + 1), cpve.getReason());
                 }
             }
 
--- a/src/share/classes/sun/security/ssl/CipherSuite.java	Thu Sep 08 15:00:00 2016 -0700
+++ b/src/share/classes/sun/security/ssl/CipherSuite.java	Mon Sep 19 11:21:02 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2016, 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
@@ -326,36 +326,38 @@
     static enum KeyExchange {
 
         // key exchange algorithms
-        K_NULL       ("NULL",       false),
-        K_RSA        ("RSA",        true),
-        K_RSA_EXPORT ("RSA_EXPORT", true),
-        K_DH_RSA     ("DH_RSA",     false),
-        K_DH_DSS     ("DH_DSS",     false),
-        K_DHE_DSS    ("DHE_DSS",    true),
-        K_DHE_RSA    ("DHE_RSA",    true),
-        K_DH_ANON    ("DH_anon",    true),
+        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_ECDH_ECDSA ("ECDH_ECDSA",  ALLOW_ECC),
-        K_ECDH_RSA   ("ECDH_RSA",    ALLOW_ECC),
-        K_ECDHE_ECDSA("ECDHE_ECDSA", ALLOW_ECC),
-        K_ECDHE_RSA  ("ECDHE_RSA",   ALLOW_ECC),
-        K_ECDH_ANON  ("ECDH_anon",   ALLOW_ECC),
+        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),
 
         // Kerberos cipher suites
-        K_KRB5       ("KRB5", true),
-        K_KRB5_EXPORT("KRB5_EXPORT", true),
+        K_KRB5       ("KRB5", true,             false),
+        K_KRB5_EXPORT("KRB5_EXPORT", true,      false),
 
         // renegotiation protection request signaling cipher suite
-        K_SCSV       ("SCSV",        true);
+        K_SCSV       ("SCSV",        true,      false);
 
         // name of the key exchange algorithm, e.g. DHE_DSS
         final String name;
         final boolean allowed;
+        final boolean isEC;
         private final boolean alwaysAvailable;
 
-        KeyExchange(String name, boolean allowed) {
+        KeyExchange(String name, boolean allowed, boolean isEC) {
             this.name = name;
             this.allowed = allowed;
+            this.isEC = isEC;
             this.alwaysAvailable = allowed &&
                 (!name.startsWith("EC")) && (!name.startsWith("KRB"));
         }
@@ -365,7 +367,7 @@
                 return true;
             }
 
-            if (name.startsWith("EC")) {
+            if (isEC) {
                 return (allowed && JsseJce.isEcAvailable());
             } else if (name.startsWith("KRB")) {
                 return (allowed && JsseJce.isKerberosAvailable());
--- a/src/share/classes/sun/security/ssl/CipherSuiteList.java	Thu Sep 08 15:00:00 2016 -0700
+++ b/src/share/classes/sun/security/ssl/CipherSuiteList.java	Mon Sep 19 11:21:02 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2016, 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
@@ -112,20 +112,15 @@
     boolean containsEC() {
         if (containsEC == null) {
             for (CipherSuite c : cipherSuites) {
-                switch (c.keyExchange) {
-                case K_ECDH_ECDSA:
-                case K_ECDH_RSA:
-                case K_ECDHE_ECDSA:
-                case K_ECDHE_RSA:
-                case K_ECDH_ANON:
+                if (c.keyExchange.isEC) {
                     containsEC = true;
                     return true;
-                default:
-                    break;
                 }
             }
+
             containsEC = false;
         }
+
         return containsEC;
     }
 
--- a/src/share/classes/sun/security/ssl/ClientHandshaker.java	Thu Sep 08 15:00:00 2016 -0700
+++ b/src/share/classes/sun/security/ssl/ClientHandshaker.java	Mon Sep 19 11:21:02 2016 -0700
@@ -762,30 +762,33 @@
                 String typeName;
 
                 switch (certRequest.types[i]) {
-                case CertificateRequest.cct_rsa_sign:
-                    typeName = "RSA";
-                    break;
+                    case CertificateRequest.cct_rsa_sign:
+                        typeName = "RSA";
+                        break;
 
-                case CertificateRequest.cct_dss_sign:
-                    typeName = "DSA";
-                    break;
+                    case CertificateRequest.cct_dss_sign:
+                        typeName = "DSA";
+                            break;
 
-                case CertificateRequest.cct_ecdsa_sign:
-                    // ignore if we do not have EC crypto available
-                    typeName = JsseJce.isEcAvailable() ? "EC" : null;
-                    break;
+                    case CertificateRequest.cct_ecdsa_sign:
+                        // ignore if we do not have EC crypto available
+                        typeName = JsseJce.isEcAvailable() ? "EC" : null;
+                        break;
 
-                // Fixed DH/ECDH client authentication not supported
-                case CertificateRequest.cct_rsa_fixed_dh:
-                case CertificateRequest.cct_dss_fixed_dh:
-                case CertificateRequest.cct_rsa_fixed_ecdh:
-                case CertificateRequest.cct_ecdsa_fixed_ecdh:
-                // Any other values (currently not used in TLS)
-                case CertificateRequest.cct_rsa_ephemeral_dh:
-                case CertificateRequest.cct_dss_ephemeral_dh:
-                default:
-                    typeName = null;
-                    break;
+                    // Fixed DH/ECDH client authentication not supported
+                    //
+                    // case CertificateRequest.cct_rsa_fixed_dh:
+                    // case CertificateRequest.cct_dss_fixed_dh:
+                    // case CertificateRequest.cct_rsa_fixed_ecdh:
+                    // case CertificateRequest.cct_ecdsa_fixed_ecdh:
+                    //
+                    // Any other values (currently not used in TLS)
+                    //
+                    // case CertificateRequest.cct_rsa_ephemeral_dh:
+                    // case CertificateRequest.cct_dss_ephemeral_dh:
+                    default:
+                        typeName = null;
+                        break;
                 }
 
                 if ((typeName != null) && (!keytypesTmp.contains(typeName))) {
@@ -813,18 +816,6 @@
                 X509Certificate[] certs = km.getCertificateChain(alias);
                 if ((certs != null) && (certs.length != 0)) {
                     PublicKey publicKey = certs[0].getPublicKey();
-                    // for EC, make sure we use a supported named curve
-                    if (publicKey instanceof ECPublicKey) {
-                        ECParameterSpec params =
-                            ((ECPublicKey)publicKey).getParams();
-                        int index =
-                            SupportedEllipticCurvesExtension.getCurveIndex(
-                                params);
-                        if (!SupportedEllipticCurvesExtension.isSupported(
-                                index)) {
-                            publicKey = null;
-                        }
-                    }
                     if (publicKey != null) {
                         m1 = new CertificateMsg(certs);
                         signingKey = km.getPrivateKey(alias);
@@ -1385,6 +1376,17 @@
                 sslContext.getSecureRandom(), maxProtocolVersion,
                 sessionId, cipherSuites);
 
+        // add elliptic curves and point format extensions
+        if (cipherSuites.containsEC()) {
+            SupportedEllipticCurvesExtension ece =
+                SupportedEllipticCurvesExtension.createExtension(algorithmConstraints);
+            if (ece != null) {
+                clientHelloMessage.extensions.add(ece);
+                clientHelloMessage.extensions.add(
+                   SupportedEllipticPointFormatsExtension.DEFAULT);
+            }
+        }
+
         // add signature_algorithm extension
         if (maxProtocolVersion.v >= ProtocolVersion.TLS12.v) {
             // we will always send the signature_algorithm extension
--- a/src/share/classes/sun/security/ssl/ECDHCrypt.java	Thu Sep 08 15:00:00 2016 -0700
+++ b/src/share/classes/sun/security/ssl/ECDHCrypt.java	Mon Sep 19 11:21:02 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2016, 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,10 +56,11 @@
     }
 
     // Called by ServerHandshaker for ephemeral ECDH
-    ECDHCrypt(String curveName, SecureRandom random) {
+    ECDHCrypt(int curveId, SecureRandom random) {
         try {
             KeyPairGenerator kpg = JsseJce.getKeyPairGenerator("EC");
-            ECGenParameterSpec params = new ECGenParameterSpec(curveName);
+            ECGenParameterSpec params =
+                    SupportedEllipticCurvesExtension.getECGenParamSpec(curveId);
             kpg.initialize(params, random);
             KeyPair kp = kpg.generateKeyPair();
             privateKey = kp.getPrivate();
--- a/src/share/classes/sun/security/ssl/HandshakeMessage.java	Thu Sep 08 15:00:00 2016 -0700
+++ b/src/share/classes/sun/security/ssl/HandshakeMessage.java	Mon Sep 19 11:21:02 2016 -0700
@@ -230,11 +230,6 @@
         this.sessionId = sessionId;
         this.cipherSuites = cipherSuites;
 
-        if (cipherSuites.containsEC()) {
-            extensions.add(SupportedEllipticCurvesExtension.DEFAULT);
-            extensions.add(SupportedEllipticPointFormatsExtension.DEFAULT);
-        }
-
         clnt_random = new RandomCookie(generator);
         compression_methods = NULL_COMPRESSION;
     }
--- a/src/share/classes/sun/security/ssl/Handshaker.java	Thu Sep 08 15:00:00 2016 -0700
+++ b/src/share/classes/sun/security/ssl/Handshaker.java	Mon Sep 19 11:21:02 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2016, 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
@@ -636,13 +636,41 @@
             ArrayList<CipherSuite> suites = new ArrayList<>();
             if (!(activeProtocols.collection().isEmpty()) &&
                     activeProtocols.min.v != ProtocolVersion.NONE.v) {
+                boolean checkedCurves = false;
+                boolean hasCurves = false;
                 for (CipherSuite suite : enabledCipherSuites.collection()) {
                     if (suite.obsoleted > activeProtocols.min.v &&
                             suite.supported <= activeProtocols.max.v) {
                         if (algorithmConstraints.permits(
                                 EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
                                 suite.name, null)) {
-                            suites.add(suite);
+                            boolean available = true;
+                            if (suite.keyExchange.isEC) {
+                                if (!checkedCurves) {
+                                    hasCurves = SupportedEllipticCurvesExtension
+                                        .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);
+                            }
                         }
                     } else if (debug != null && Debug.isOn("verbose")) {
                         if (suite.obsoleted <= activeProtocols.min.v) {
@@ -679,18 +707,10 @@
     ProtocolList getActiveProtocols() {
         if (activeProtocols == null) {
             boolean enabledSSL20Hello = false;
+            boolean checkedCurves = false;
+            boolean hasCurves = false;
             ArrayList<ProtocolVersion> protocols = new ArrayList<>(4);
             for (ProtocolVersion protocol : enabledProtocols.collection()) {
-                if (!algorithmConstraints.permits(
-                        EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
-                        protocol.name, null)) {
-                    if (debug != null && Debug.isOn("verbose")) {
-                        System.out.println(
-                            "Ignoring disabled protocol: " + protocol);
-                    }
-
-                    continue;
-                }
                 // Need not to check the SSL20Hello protocol.
                 if (protocol.v == ProtocolVersion.SSL20Hello.v) {
                     enabledSSL20Hello = true;
@@ -714,9 +734,36 @@
                         if (algorithmConstraints.permits(
                                 EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
                                 suite.name, null)) {
-                            protocols.add(protocol);
-                            found = true;
-                            break;
+
+                            boolean available = true;
+                            if (suite.keyExchange.isEC) {
+                                if (!checkedCurves) {
+                                    hasCurves = SupportedEllipticCurvesExtension
+                                        .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 +
--- a/src/share/classes/sun/security/ssl/JsseJce.java	Thu Sep 08 15:00:00 2016 -0700
+++ b/src/share/classes/sun/security/ssl/JsseJce.java	Mon Sep 19 11:21:02 2016 -0700
@@ -290,6 +290,15 @@
         }
     }
 
+    static AlgorithmParameters getAlgorithmParameters(String algorithm)
+            throws NoSuchAlgorithmException {
+        if (cryptoProvider == null) {
+            return AlgorithmParameters.getInstance(algorithm);
+        } else {
+            return AlgorithmParameters.getInstance(algorithm, cryptoProvider);
+        }
+    }
+
     static SecureRandom getSecureRandom() throws KeyManagementException {
         if (cryptoProvider == null) {
             return new SecureRandom();
@@ -409,6 +418,7 @@
                 JsseJce.getKeyAgreement("ECDH");
                 JsseJce.getKeyFactory("EC");
                 JsseJce.getKeyPairGenerator("EC");
+                JsseJce.getAlgorithmParameters("EC");
             } catch (Exception e) {
                 mediator = false;
             }
--- a/src/share/classes/sun/security/ssl/ServerHandshaker.java	Thu Sep 08 15:00:00 2016 -0700
+++ b/src/share/classes/sun/security/ssl/ServerHandshaker.java	Mon Sep 19 11:21:02 2016 -0700
@@ -92,7 +92,8 @@
     // we remember it for the RSA premaster secret version check
     private ProtocolVersion clientRequestedVersion;
 
-    private SupportedEllipticCurvesExtension supportedCurves;
+    // client supported elliptic curves
+    private SupportedEllipticCurvesExtension requestedCurves;
 
     // the preferable signature algorithm used by ServerKeyExchange message
     SignatureAndHashAlgorithm preferableSignatureAlgorithm;
@@ -682,7 +683,7 @@
                 throw new SSLException("Client did not resume a session");
             }
 
-            supportedCurves = (SupportedEllipticCurvesExtension)
+            requestedCurves = (SupportedEllipticCurvesExtension)
                         mesg.extensions.get(ExtensionType.EXT_ELLIPTIC_CURVES);
 
             // We only need to handle the "signature_algorithm" extension
@@ -1412,26 +1413,15 @@
     // 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 = -1;
-        if (supportedCurves != null) {
-            // if the client sent the supported curves extension, pick the
-            // first one that we support;
-            for (int curveId : supportedCurves.curveIds()) {
-                if (SupportedEllipticCurvesExtension.isSupported(curveId)) {
-                    index = curveId;
-                    break;
-                }
-            }
-            if (index < 0) {
-                // no match found, cannot use this ciphersuite
-                return false;
-            }
-        } else {
-            // pick our preference
-            index = SupportedEllipticCurvesExtension.DEFAULT.curveIds()[0];
+        int index = (requestedCurves != null) ?
+                requestedCurves.getPreferredCurve(algorithmConstraints) :
+                SupportedEllipticCurvesExtension.getActiveCurves(algorithmConstraints);
+        if (index < 0) {
+            // no match found, cannot use this ciphersuite
+            return false;
         }
-        String oid = SupportedEllipticCurvesExtension.getCurveOid(index);
-        ecdh = new ECDHCrypt(oid, sslContext.getSecureRandom());
+
+        ecdh = new ECDHCrypt(index, sslContext.getSecureRandom());
         return true;
     }
 
@@ -1480,11 +1470,9 @@
                 return false;
             }
             ECParameterSpec params = ((ECPublicKey)publicKey).getParams();
-            int index = SupportedEllipticCurvesExtension.getCurveIndex(params);
-            if (SupportedEllipticCurvesExtension.isSupported(index) == false) {
-                return false;
-            }
-            if ((supportedCurves != null) && !supportedCurves.contains(index)) {
+            int id = SupportedEllipticCurvesExtension.getCurveIndex(params);
+            if ((id <= 0) || !SupportedEllipticCurvesExtension.isSupported(id) ||
+                ((requestedCurves != null) && !requestedCurves.contains(id))) {
                 return false;
             }
         }
--- a/src/share/classes/sun/security/ssl/SupportedEllipticCurvesExtension.java	Thu Sep 08 15:00:00 2016 -0700
+++ b/src/share/classes/sun/security/ssl/SupportedEllipticCurvesExtension.java	Mon Sep 19 11:21:02 2016 -0700
@@ -27,39 +27,195 @@
 
 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 javax.net.ssl.SSLProtocolException;
+import sun.security.action.GetPropertyAction;
 
 final class SupportedEllipticCurvesExtension extends HelloExtension {
 
-    // the extension value to send in the ClientHello message
-    static final SupportedEllipticCurvesExtension DEFAULT;
+    private static final int ARBITRARY_PRIME = 0xff01;
+    private static final int ARBITRARY_CHAR2 = 0xff02;
 
-    private static final boolean fips;
+    // speed up the searching
+    private static final Map<String, Integer> oidToIdMap = new HashMap<>();
+    private static final Map<Integer, String> idToOidMap = new HashMap<>();
+
+    // speed up the parameters construction
+    private static final Map<Integer,
+                AlgorithmParameters> 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 {
-        int[] ids;
-        fips = SunJSSE.isFIPS();
-        if (fips == false) {
-            ids = new int[] {
-                // NIST curves first
-                // prefer NIST P-256, rest in order of increasing key length
-                23, 1, 3, 19, 21, 6, 7, 9, 10, 24, 11, 12, 25, 13, 14,
-                // non-NIST curves
-                15, 16, 17, 2, 18, 4, 5, 20, 8, 22,
-            };
+        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<Integer> 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
+                }
+            }
+        } 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 (idList.isEmpty()) {
+            throw new IllegalArgumentException(
+                "System property jdk.tls.namedGroups(" + property + ") " +
+                "contains no supported elliptic curves");
         } else {
-            ids = new int[] {
-                // same as above, but allow only NIST curves in FIPS mode
-                23, 1, 3, 19, 21, 6, 7, 9, 10, 24, 11, 12, 25, 13, 14,
-            };
+            supportedCurveIds = new int[idList.size()];
+            int i = 0;
+            for (Integer id : idList) {
+                supportedCurveIds[i++] = id;
+            }
         }
-        DEFAULT = new SupportedEllipticCurvesExtension(ids);
     }
 
-    private final int[] curveIds;
+    // 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 SupportedEllipticCurvesExtension(int[] curveIds) {
         super(ExtensionType.EXT_ELLIPTIC_CURVES);
@@ -73,12 +229,67 @@
         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 SupportedEllipticCurvesExtension createExtension(
+                AlgorithmConstraints constraints) {
+
+        ArrayList<Integer> 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 SupportedEllipticCurvesExtension(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 (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) {
@@ -88,12 +299,6 @@
         return false;
     }
 
-    // Return a reference to the internal curveIds array.
-    // The caller must NOT modify the contents.
-    int[] curveIds() {
-        return curveIds;
-    }
-
     @Override
     int length() {
         return 6 + (curveIds.length << 1);
@@ -121,18 +326,9 @@
             } else {
                 sb.append(", ");
             }
-            // first check if it is a known named curve, then try other cases.
-            String oid = getCurveOid(curveId);
-            if (oid != null) {
-                ECParameterSpec spec = JsseJce.getECParameterSpec(oid);
-                // this toString() output will look nice for the current
-                // implementation of the ECParameterSpec class in the Sun
-                // provider, but may not look good for other implementations.
-                if (spec != null) {
-                    sb.append(spec.toString().split(" ")[0]);
-                } else {
-                    sb.append(oid);
-                }
+            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) {
@@ -145,16 +341,15 @@
         return sb.toString();
     }
 
-    // Test whether we support the curve with the given index.
+    // Test whether the given curve is supported.
     static boolean isSupported(int index) {
-        if ((index <= 0) || (index >= NAMED_CURVE_OID_TABLE.length)) {
-            return false;
+        for (int curveId : supportedCurveIds) {
+            if (index == curveId) {
+                return true;
+            }
         }
-        if (fips == false) {
-            // in non-FIPS mode, we support all valid indices
-            return true;
-        }
-        return DEFAULT.contains(index);
+
+        return false;
     }
 
     static int getCurveIndex(ECParameterSpec params) {
@@ -162,57 +357,32 @@
         if (oid == null) {
             return -1;
         }
-        Integer n = curveIndices.get(oid);
+        Integer n = oidToIdMap.get(oid);
         return (n == null) ? -1 : n;
     }
 
     static String getCurveOid(int index) {
-        if ((index > 0) && (index < NAMED_CURVE_OID_TABLE.length)) {
-            return NAMED_CURVE_OID_TABLE[index];
-        }
-        return null;
+        return idToOidMap.get(index);
     }
 
-    private final static int ARBITRARY_PRIME = 0xff01;
-    private final static int ARBITRARY_CHAR2 = 0xff02;
-
-    // See sun.security.ec.NamedCurve for the OIDs
-    private final static String[] NAMED_CURVE_OID_TABLE = new String[] {
-        null,                   //  (0) unused
-        "1.3.132.0.1",          //  (1) sect163k1, NIST K-163
-        "1.3.132.0.2",          //  (2) sect163r1
-        "1.3.132.0.15",         //  (3) sect163r2, NIST B-163
-        "1.3.132.0.24",         //  (4) sect193r1
-        "1.3.132.0.25",         //  (5) sect193r2
-        "1.3.132.0.26",         //  (6) sect233k1, NIST K-233
-        "1.3.132.0.27",         //  (7) sect233r1, NIST B-233
-        "1.3.132.0.3",          //  (8) sect239k1
-        "1.3.132.0.16",         //  (9) sect283k1, NIST K-283
-        "1.3.132.0.17",         // (10) sect283r1, NIST B-283
-        "1.3.132.0.36",         // (11) sect409k1, NIST K-409
-        "1.3.132.0.37",         // (12) sect409r1, NIST B-409
-        "1.3.132.0.38",         // (13) sect571k1, NIST K-571
-        "1.3.132.0.39",         // (14) sect571r1, NIST B-571
-        "1.3.132.0.9",          // (15) secp160k1
-        "1.3.132.0.8",          // (16) secp160r1
-        "1.3.132.0.30",         // (17) secp160r2
-        "1.3.132.0.31",         // (18) secp192k1
-        "1.2.840.10045.3.1.1",  // (19) secp192r1, NIST P-192
-        "1.3.132.0.32",         // (20) secp224k1
-        "1.3.132.0.33",         // (21) secp224r1, NIST P-224
-        "1.3.132.0.10",         // (22) secp256k1
-        "1.2.840.10045.3.1.7",  // (23) secp256r1, NIST P-256
-        "1.3.132.0.34",         // (24) secp384r1, NIST P-384
-        "1.3.132.0.35",         // (25) secp521r1, NIST P-521
-    };
-
-    private final static Map<String,Integer> curveIndices;
-
-    static {
-        curveIndices = new HashMap<String,Integer>();
-        for (int i = 1; i < NAMED_CURVE_OID_TABLE.length; i++) {
-            curveIndices.put(NAMED_CURVE_OID_TABLE[i], i);
+    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;
+    }
 }
--- a/src/share/classes/sun/security/tools/jarsigner/Main.java	Thu Sep 08 15:00:00 2016 -0700
+++ b/src/share/classes/sun/security/tools/jarsigner/Main.java	Mon Sep 19 11:21:02 2016 -0700
@@ -603,6 +603,7 @@
             }
 
             Manifest man = jf.getManifest();
+            boolean hasSignature = false;
 
             // The map to record display info, only used when -verbose provided
             //      key: signer info string
@@ -618,6 +619,10 @@
                 while (e.hasMoreElements()) {
                     JarEntry je = e.nextElement();
                     String name = je.getName();
+
+                    hasSignature = hasSignature
+                            || SignatureFileVerifier.isBlockOrSF(name);
+
                     CodeSigner[] signers = je.getCodeSigners();
                     boolean isSigned = (signers != null);
                     anySigned |= isSigned;
@@ -757,8 +762,11 @@
                 System.out.println(rb.getString("no.manifest."));
 
             if (!anySigned) {
-                System.out.println(rb.getString(
-                      "jar.is.unsigned.signatures.missing.or.not.parsable."));
+                if (hasSignature) {
+                    System.out.println(rb.getString("jar.treated.unsigned"));
+                } else {
+                    System.out.println(rb.getString("jar.is.unsigned"));
+                }
             } else {
                 boolean warningAppeared = false;
                 boolean errorAppeared = false;
--- a/src/share/classes/sun/security/tools/jarsigner/Resources.java	Thu Sep 08 15:00:00 2016 -0700
+++ b/src/share/classes/sun/security/tools/jarsigner/Resources.java	Mon Sep 19 11:21:02 2016 -0700
@@ -135,8 +135,10 @@
         {"no.manifest.", "no manifest."},
         {".Signature.related.entries.","(Signature related entries)"},
         {".Unsigned.entries.", "(Unsigned entries)"},
-        {"jar.is.unsigned.signatures.missing.or.not.parsable.",
-                "jar is unsigned. (signatures missing or not parsable)"},
+        {"jar.is.unsigned",
+                "jar is unsigned."},
+        {"jar.treated.unsigned",
+                "Signature not parsable or verifiable. The jar will be treated as unsigned. The jar may have been signed with a weak algorithm that is now disabled. For more information, rerun jarsigner with debug enabled (-J-Djava.security.debug=jar)."},
         {"jar.signed.", "jar signed."},
         {"jar.signed.with.signer.errors.", "jar signed, with signer errors."},
         {"jar.verified.", "jar verified."},
--- a/src/share/classes/sun/security/util/AbstractAlgorithmConstraints.java	Thu Sep 08 15:00:00 2016 -0700
+++ b/src/share/classes/sun/security/util/AbstractAlgorithmConstraints.java	Mon Sep 19 11:21:02 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016 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
@@ -29,7 +29,6 @@
 import java.security.AlgorithmConstraints;
 import java.security.PrivilegedAction;
 import java.security.Security;
-import java.util.Map;
 import java.util.Set;
 
 /**
@@ -45,8 +44,7 @@
     }
 
     // Get algorithm constraints from the specified security property.
-    private static void loadAlgorithmsMap(Map<String, String[]> algorithmsMap,
-            String propertyName) {
+    static String[] getAlgorithms(String propertyName) {
         String property = AccessController.doPrivileged(
                 new PrivilegedAction<String>() {
                     @Override
@@ -72,18 +70,7 @@
         if (algorithmsInProperty == null) {
             algorithmsInProperty = new String[0];
         }
-        algorithmsMap.put(propertyName, algorithmsInProperty);
-    }
-
-    static String[] getAlgorithms(Map<String, String[]> algorithmsMap,
-            String propertyName) {
-        synchronized (algorithmsMap) {
-            if (!algorithmsMap.containsKey(propertyName)) {
-                loadAlgorithmsMap(algorithmsMap, propertyName);
-            }
-
-            return algorithmsMap.get(propertyName);
-        }
+        return algorithmsInProperty;
     }
 
     static boolean checkAlgorithm(String[] algorithms, String algorithm,
--- a/src/share/classes/sun/security/util/AlgorithmDecomposer.java	Thu Sep 08 15:00:00 2016 -0700
+++ b/src/share/classes/sun/security/util/AlgorithmDecomposer.java	Mon Sep 19 11:21:02 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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
@@ -38,19 +38,7 @@
     private static final Pattern pattern =
                     Pattern.compile("with|and", Pattern.CASE_INSENSITIVE);
 
-    /**
-     * Decompose the standard algorithm name into sub-elements.
-     * <p>
-     * For example, we need to decompose "SHA1WithRSA" into "SHA1" and "RSA"
-     * so that we can check the "SHA1" and "RSA" algorithm constraints
-     * separately.
-     * <p>
-     * Please override the method if need to support more name pattern.
-     */
-    public Set<String> decompose(String algorithm) {
-        if (algorithm == null || algorithm.length() == 0) {
-            return new HashSet<>();
-        }
+    private static Set<String> decomposeImpl(String algorithm) {
 
         // algorithm/mode/padding
         String[] transTockens = transPattern.split(algorithm);
@@ -76,6 +64,24 @@
                 elements.add(token);
             }
         }
+        return elements;
+    }
+
+    /**
+     * Decompose the standard algorithm name into sub-elements.
+     * <p>
+     * For example, we need to decompose "SHA1WithRSA" into "SHA1" and "RSA"
+     * so that we can check the "SHA1" and "RSA" algorithm constraints
+     * separately.
+     * <p>
+     * Please override the method if need to support more name pattern.
+     */
+    public Set<String> decompose(String algorithm) {
+        if (algorithm == null || algorithm.length() == 0) {
+            return new HashSet<>();
+        }
+
+        Set<String> elements = decomposeImpl(algorithm);
 
         // In Java standard algorithm name specification, for different
         // purpose, the SHA-1 and SHA-2 algorithm names are different. For
@@ -127,4 +133,40 @@
         return elements;
     }
 
+    private static void hasLoop(Set<String> elements, String find, String replace) {
+        if (elements.contains(find)) {
+            if (!elements.contains(replace)) {
+                elements.add(replace);
 }
+            elements.remove(find);
+        }
+    }
+
+    /*
+     * This decomposes a standard name into sub-elements with a consistent
+     * message digest algorithm name to avoid overly complicated checking.
+     */
+    public static Set<String> decomposeOneHash(String algorithm) {
+        if (algorithm == null || algorithm.length() == 0) {
+            return new HashSet<>();
+        }
+
+        Set<String> elements = decomposeImpl(algorithm);
+
+        hasLoop(elements, "SHA-1", "SHA1");
+        hasLoop(elements, "SHA-224", "SHA224");
+        hasLoop(elements, "SHA-256", "SHA256");
+        hasLoop(elements, "SHA-384", "SHA384");
+        hasLoop(elements, "SHA-512", "SHA512");
+
+        return elements;
+    }
+
+    /*
+     * The provided message digest algorithm name will return a consistent
+     * naming scheme.
+     */
+    public static String hashName(String algorithm) {
+        return algorithm.replace("-", "");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/security/util/AnchorCertificates.java	Mon Sep 19 11:21:02 2016 -0700
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2016, 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.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.security.AccessController;
+import java.security.KeyStore;
+import java.security.PrivilegedAction;
+import java.security.cert.X509Certificate;
+import java.util.Enumeration;
+import java.util.HashSet;
+
+import sun.security.x509.X509CertImpl;
+
+/**
+ * The purpose of this class is to determine the trust anchor certificates is in
+ * the cacerts file.  This is used for PKIX CertPath checking.
+ */
+public class AnchorCertificates {
+
+    private static final Debug debug = Debug.getInstance("certpath");
+    private static final String HASH = "SHA-256";
+    private static HashSet<String> certs;
+
+    static  {
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            @Override
+            public Void run() {
+                File f = new File(System.getProperty("java.home"),
+                        "lib/security/cacerts");
+                KeyStore cacerts;
+                try {
+                    cacerts = KeyStore.getInstance("JKS");
+                    try (FileInputStream fis = new FileInputStream(f)) {
+                        cacerts.load(fis, "changeit".toCharArray());
+                        certs = new HashSet<>();
+                        Enumeration<String> list = cacerts.aliases();
+                        String alias;
+                        while (list.hasMoreElements()) {
+                            alias = list.nextElement();
+                            // Check if this cert is labeled a trust anchor.
+                            if (alias.contains(" [jdk")) {
+                                X509Certificate cert = (X509Certificate) cacerts
+                                        .getCertificate(alias);
+                                certs.add(X509CertImpl.getFingerprint(HASH, cert));
+                            }
+                        }
+                    }
+                } catch (Exception e) {
+                    if (debug != null) {
+                        debug.println("Error parsing cacerts");
+                    }
+                    e.printStackTrace();
+                }
+                return null;
+            }
+        });
+    }
+
+    /**
+     * Checks if a certificate is a trust anchor.
+     *
+     * @param cert the certificate to check
+     * @return true if the certificate is trusted.
+     */
+    public static boolean contains(X509Certificate cert) {
+        String key = X509CertImpl.getFingerprint(HASH, cert);
+        boolean result = certs.contains(key);
+        if (result && debug != null) {
+            debug.println("AnchorCertificate.contains: matched " +
+                    cert.getSubjectDN());
+        }
+        return result;
+    }
+
+    private AnchorCertificates() {}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/security/util/CertConstraintParameters.java	Mon Sep 19 11:21:02 2016 -0700
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2016, 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.util;
+
+import java.security.cert.X509Certificate;
+
+/**
+ * This class is a wrapper for keeping state and passing objects between PKIX,
+ * AlgorithmChecker, and DisabledAlgorithmConstraints.
+ */
+public class CertConstraintParameters {
+    // A certificate being passed to check against constraints.
+    private final X509Certificate cert;
+
+    // This is true if the trust anchor in the certificate chain matches a cert
+    // in AnchorCertificates
+    private final boolean trustedMatch;
+
+    public CertConstraintParameters(X509Certificate c, boolean match) {
+        cert = c;
+        trustedMatch = match;
+    }
+
+    public CertConstraintParameters(X509Certificate c) {
+        this(c, false);
+    }
+
+    // Returns if the trust anchor has a match if anchor checking is enabled.
+    public boolean isTrustedMatch() {
+        return trustedMatch;
+    }
+
+    public X509Certificate getCertificate() {
+        return cert;
+    }
+}
--- a/src/share/classes/sun/security/util/DisabledAlgorithmConstraints.java	Thu Sep 08 15:00:00 2016 -0700
+++ b/src/share/classes/sun/security/util/DisabledAlgorithmConstraints.java	Mon Sep 19 11:21:02 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2016, 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
@@ -28,12 +28,14 @@
 import java.security.CryptoPrimitive;
 import java.security.AlgorithmParameters;
 import java.security.Key;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertPathValidatorException.BasicReason;
+import java.security.cert.X509Certificate;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Locale;
+import java.util.Map;
 import java.util.Set;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.HashMap;
 import java.util.regex.Pattern;
 import java.util.regex.Matcher;
 
@@ -44,6 +46,7 @@
  * for the syntax of the disabled algorithm string.
  */
 public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
+    private static final Debug debug = Debug.getInstance("certpath");
 
     // the known security property, jdk.certpath.disabledAlgorithms
     public final static String PROPERTY_CERTPATH_DISABLED_ALGS =
@@ -53,17 +56,12 @@
     public final static String PROPERTY_TLS_DISABLED_ALGS =
             "jdk.tls.disabledAlgorithms";
 
-    private final static Map<String, String[]> disabledAlgorithmsMap =
-                                                            new HashMap<>();
-    private final static Map<String, KeySizeConstraints> keySizeConstraintsMap =
-                                                            new HashMap<>();
-
     // the known security property, jdk.jar.disabledAlgorithms
     public static final String PROPERTY_JAR_DISABLED_ALGS =
             "jdk.jar.disabledAlgorithms";
 
     private final String[] disabledAlgorithms;
-    private final KeySizeConstraints keySizeConstraints;
+    private final Constraints algorithmConstraints;
 
     /**
      * Initialize algorithm constraints with the specified security property.
@@ -86,11 +84,14 @@
     public DisabledAlgorithmConstraints(String propertyName,
             AlgorithmDecomposer decomposer) {
         super(decomposer);
-        disabledAlgorithms = getAlgorithms(disabledAlgorithmsMap, propertyName);
-        keySizeConstraints = getKeySizeConstraints(disabledAlgorithms,
-                propertyName);
+        disabledAlgorithms = getAlgorithms(propertyName);
+        algorithmConstraints = new Constraints(disabledAlgorithms);
     }
 
+    /*
+     * This only checks if the algorithm has been completely disabled.  If
+     * there are keysize or other limit, this method allow the algorithm.
+     */
     @Override
     final public boolean permits(Set<CryptoPrimitive> primitives,
             String algorithm, AlgorithmParameters parameters) {
@@ -103,11 +104,19 @@
         return checkAlgorithm(disabledAlgorithms, algorithm, decomposer);
     }
 
+    /*
+     * Checks if the key algorithm has been disabled or constraints have been
+     * placed on the key.
+     */
     @Override
     final public boolean permits(Set<CryptoPrimitive> primitives, Key key) {
         return checkConstraints(primitives, "", key, null);
     }
 
+    /*
+     * Checks if the key algorithm has been disabled or if constraints have
+     * been placed on the key.
+     */
     @Override
     final public boolean permits(Set<CryptoPrimitive> primitives,
             String algorithm, Key key, AlgorithmParameters parameters) {
@@ -119,7 +128,39 @@
         return checkConstraints(primitives, algorithm, key, parameters);
     }
 
-    // Check algorithm constraints
+    /*
+     * Check if a x509Certificate object is permitted.  Check if all
+     * algorithms are allowed, certificate constraints, and the
+     * public key against key constraints.
+     *
+     * Uses new style permit() which throws exceptions.
+     */
+    public final void permits(Set<CryptoPrimitive> primitives,
+            CertConstraintParameters cp) throws CertPathValidatorException {
+        checkConstraints(primitives, cp);
+    }
+
+    /*
+     * Check if Certificate object is within the constraints.
+     * Uses new style permit() which throws exceptions.
+     */
+    public final void permits(Set<CryptoPrimitive> primitives,
+            X509Certificate cert) throws CertPathValidatorException {
+        checkConstraints(primitives, new CertConstraintParameters(cert));
+    }
+
+    // Check if a string is contained inside the property
+    public boolean checkProperty(String param) {
+        param = param.toLowerCase(Locale.ENGLISH);
+        for (String block : disabledAlgorithms) {
+            if (block.toLowerCase(Locale.ENGLISH).indexOf(param) >= 0) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    // Check algorithm constraints with key and algorithm
     private boolean checkConstraints(Set<CryptoPrimitive> primitives,
             String algorithm, Key key, AlgorithmParameters parameters) {
 
@@ -128,7 +169,7 @@
             throw new IllegalArgumentException("The key cannot be null");
         }
 
-        // check the target algorithm
+        // check the signature algorithm
         if (algorithm != null && algorithm.length() != 0) {
             if (!permits(primitives, algorithm, parameters)) {
                 return false;
@@ -141,97 +182,203 @@
         }
 
         // check the key constraints
-        if (keySizeConstraints.disables(key)) {
-            return false;
+        return algorithmConstraints.permits(key);
+    }
+
+    /*
+     * Check algorithm constraints with Certificate
+     * Uses new style permit() which throws exceptions.
+     */
+    private void checkConstraints(Set<CryptoPrimitive> primitives,
+            CertConstraintParameters cp) throws CertPathValidatorException {
+
+        X509Certificate cert = cp.getCertificate();
+        String algorithm = cert.getSigAlgName();
+
+        // Check signature algorithm is not disabled
+        if (!permits(primitives, algorithm, null)) {
+            throw new CertPathValidatorException(
+                    "Algorithm constraints check failed on disabled "+
+                            "signature algorithm: " + algorithm,
+                    null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
         }
 
-        return true;
-    }
+        // Check key algorithm is not disabled
+        if (!permits(primitives, cert.getPublicKey().getAlgorithm(), null)) {
+            throw new CertPathValidatorException(
+                    "Algorithm constraints check failed on disabled "+
+                            "public key algorithm: " + algorithm,
+                    null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
+        }
 
-    private static KeySizeConstraints getKeySizeConstraints(
-            String[] disabledAlgorithms, String propertyName) {
-        synchronized (keySizeConstraintsMap) {
-            if(!keySizeConstraintsMap.containsKey(propertyName)) {
-                // map the key constraints
-                KeySizeConstraints keySizeConstraints =
-                        new KeySizeConstraints(disabledAlgorithms);
-                keySizeConstraintsMap.put(propertyName, keySizeConstraints);
-            }
+        // Check the certificate and key constraints
+        algorithmConstraints.permits(cp);
 
-            return keySizeConstraintsMap.get(propertyName);
-        }
     }
 
     /**
-     * key constraints
+     * Key and Certificate Constraints
+     *
+     * The complete disabling of an algorithm is not handled by Constraints or
+     * Constraint classes.  That is addressed with
+     *   permit(Set<CryptoPrimitive>, String, AlgorithmParameters)
+     *
+     * When passing a Key to permit(), the boolean return values follow the
+     * same as the interface class AlgorithmConstraints.permit().  This is to
+     * maintain compatibility:
+     * 'true' means the operation is allowed.
+     * 'false' means it failed the constraints and is disallowed.
+     *
+     * When passing CertConstraintParameters through permit(), an exception
+     * will be thrown on a failure to better identify why the operation was
+     * disallowed.
      */
-    private static class KeySizeConstraints {
-        private static final Pattern pattern = Pattern.compile(
-                "(\\S+)\\s+keySize\\s*(<=|<|==|!=|>|>=)\\s*(\\d+)");
 
-        private Map<String, Set<KeySizeConstraint>> constraintsMap =
-            Collections.synchronizedMap(
-                        new HashMap<String, Set<KeySizeConstraint>>());
+    private static class Constraints {
+        private Map<String, Set<Constraint>> constraintsMap = new HashMap<>();
+        private static final Pattern keySizePattern = Pattern.compile(
+                "keySize\\s*(<=|<|==|!=|>|>=)\\s*(\\d+)");
 
-        public KeySizeConstraints(String[] restrictions) {
-            for (String restriction : restrictions) {
-                if (restriction == null || restriction.isEmpty()) {
+        public Constraints(String[] constraintArray) {
+            for (String constraintEntry : constraintArray) {
+                if (constraintEntry == null || constraintEntry.isEmpty()) {
                     continue;
                 }
 
-                Matcher matcher = pattern.matcher(restriction);
-                if (matcher.matches()) {
-                    String algorithm = matcher.group(1);
+                constraintEntry = constraintEntry.trim();
+                if (debug != null) {
+                    debug.println("Constraints: " + constraintEntry);
+                }
 
-                    KeySizeConstraint.Operator operator =
-                             KeySizeConstraint.Operator.of(matcher.group(2));
-                    int length = Integer.parseInt(matcher.group(3));
+                // Check if constraint is a complete disabling of an
+                // algorithm or has conditions.
+                String algorithm;
+                String policy;
+                int space = constraintEntry.indexOf(' ');
+                if (space > 0) {
+                    algorithm = AlgorithmDecomposer.hashName(
+                            constraintEntry.substring(0, space).
+                                    toUpperCase(Locale.ENGLISH));
+                    policy = constraintEntry.substring(space + 1);
+                } else {
+                    constraintsMap.computeIfAbsent(
+                            constraintEntry.toUpperCase(Locale.ENGLISH),
+                            k -> new HashSet<>());
+                    continue;
+                }
 
-                    algorithm = algorithm.toLowerCase(Locale.ENGLISH);
+                // Convert constraint conditions into Constraint classes
+                Constraint c, lastConstraint = null;
+                // Allow only one jdkCA entry per constraint entry
+                boolean jdkCALimit = false;
 
-                    synchronized (constraintsMap) {
+                for (String entry : policy.split("&")) {
+                    entry = entry.trim();
+
+                    Matcher matcher = keySizePattern.matcher(entry);
+                    if (matcher.matches()) {
+                        if (debug != null) {
+                            debug.println("Constraints set to keySize: " +
+                                    entry);
+                        }
+                        c = new KeySizeConstraint(algorithm,
+                                KeySizeConstraint.Operator.of(matcher.group(1)),
+                                Integer.parseInt(matcher.group(2)));
+
+                    } else if (entry.equalsIgnoreCase("jdkCA")) {
+                        if (debug != null) {
+                            debug.println("Constraints set to jdkCA.");
+                        }
+                        if (jdkCALimit) {
+                            throw new IllegalArgumentException("Only one " +
+                                    "jdkCA entry allowed in property. " +
+                                    "Constraint: " + constraintEntry);
+                        }
+                        c = new jdkCAConstraint(algorithm);
+                        jdkCALimit = true;
+                    } else {
+                        throw new IllegalArgumentException("Error in security" +
+                                " property. Constraint unknown: " + entry);
+                    }
+
+                    // Link multiple conditions for a single constraint
+                    // into a linked list.
+                    if (lastConstraint == null) {
                         if (!constraintsMap.containsKey(algorithm)) {
-                            constraintsMap.put(algorithm,
-                                new HashSet<KeySizeConstraint>());
+                            constraintsMap.putIfAbsent(algorithm,
+                                    new HashSet<>());
                         }
-
-                        Set<KeySizeConstraint> constraintSet =
-                            constraintsMap.get(algorithm);
-                        KeySizeConstraint constraint =
-                            new KeySizeConstraint(operator, length);
-                        constraintSet.add(constraint);
+                        constraintsMap.get(algorithm).add(c);
+                    } else {
+                        lastConstraint.nextConstraint = c;
                     }
+                    lastConstraint = c;
                 }
             }
         }
 
-        // Does this KeySizeConstraints disable the specified key?
-        public boolean disables(Key key) {
-            String algorithm = key.getAlgorithm().toLowerCase(Locale.ENGLISH);
-            synchronized (constraintsMap) {
-                if (constraintsMap.containsKey(algorithm)) {
-                    Set<KeySizeConstraint> constraintSet =
-                                        constraintsMap.get(algorithm);
-                    for (KeySizeConstraint constraint : constraintSet) {
-                        if (constraint.disables(key)) {
-                            return true;
-                        }
+        // Get applicable constraints based off the signature algorithm
+        private Set<Constraint> getConstraints(String algorithm) {
+            return constraintsMap.get(algorithm);
+        }
+
+        // Check if KeySizeConstraints permit the specified key
+        public boolean permits(Key key) {
+            Set<Constraint> set = getConstraints(key.getAlgorithm());
+            if (set == null) {
+                return true;
+            }
+            for (Constraint constraint : set) {
+                if (!constraint.permits(key)) {
+                    if (debug != null) {
+                        debug.println("keySizeConstraint: failed key " +
+                                "constraint check " + KeyUtil.getKeySize(key));
                     }
+            return false;
+        }
+            }
+        return true;
+    }
+
+        // Check if constraints permit this cert.
+        public void permits(CertConstraintParameters cp)
+                throws CertPathValidatorException {
+            X509Certificate cert = cp.getCertificate();
+
+            if (debug != null) {
+                debug.println("Constraints.permits(): " + cert.getSigAlgName());
+            }
+
+            // Get all signature algorithms to check for constraints
+            Set<String> algorithms =
+                    AlgorithmDecomposer.decomposeOneHash(cert.getSigAlgName());
+            if (algorithms == null || algorithms.isEmpty()) {
+                return;
+    }
+
+            // Attempt to add the public key algorithm to the set
+            algorithms.add(cert.getPublicKey().getAlgorithm());
+
+            // Check all applicable constraints
+            for (String algorithm : algorithms) {
+                Set<Constraint> set = getConstraints(algorithm);
+                if (set == null) {
+                    continue;
+                }
+                for (Constraint constraint : set) {
+                    constraint.permits(cp);
                 }
             }
+        }
+                        }
 
-            return false;
-        }
-    }
+    // Abstract class for algorithm constraint checking
+    private abstract static class Constraint {
+        String algorithm;
+        Constraint nextConstraint = null;
 
-    /**
-     * Key size constraint.
-     *
-     * e.g.  "keysize <= 1024"
-     */
-    private static class KeySizeConstraint {
         // operator
-        static enum Operator {
+        enum Operator {
             EQ,         // "=="
             NE,         // "!="
             LT,         // "<"
@@ -255,16 +402,77 @@
                         return GE;
                 }
 
-                throw new IllegalArgumentException(
-                        s + " is not a legal Operator");
+                throw new IllegalArgumentException("Error in security " +
+                        "property. " + s + " is not a legal Operator");
             }
         }
 
+        /**
+         * Check if an algorithm constraint permit this key to be used.
+         * @param key Public key
+         * @return true if constraints do not match
+         */
+        public boolean permits(Key key) {
+            return true;
+        }
+
+        /**
+         * Check if an algorithm constraint is permit this certificate to
+         * be used.
+         * @param cp CertificateParameter containing certificate and state info
+         * @return true if constraints do not match
+         */
+        public abstract void permits(CertConstraintParameters cp)
+                throws CertPathValidatorException;
+    }
+
+    /*
+     * This class contains constraints dealing with the certificate chain
+     * of the certificate.
+     */
+    private static class jdkCAConstraint extends Constraint {
+        jdkCAConstraint(String algo) {
+            algorithm = algo;
+        }
+
+        /*
+         * Check if each constraint fails and check if there is a linked
+         * constraint  Any permitted constraint will exit the linked list
+         * to allow the operation.
+         */
+        public void permits(CertConstraintParameters cp)
+                throws CertPathValidatorException {
+            if (debug != null) {
+                debug.println("jdkCAConstraints.permits(): " + algorithm);
+            }
+
+            // Return false if the chain has a trust anchor in cacerts
+            if (cp.isTrustedMatch()) {
+                if (nextConstraint != null) {
+                    nextConstraint.permits(cp);
+                    return;
+                }
+                throw new CertPathValidatorException(
+                        "Algorithm constraints check failed on certificate " +
+                                "anchor limits",
+                        null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
+            }
+        }
+    }
+
+
+    /*
+     * This class contains constraints dealing with the key size
+     * support limits per algorithm.   e.g.  "keySize <= 1024"
+     */
+    private static class KeySizeConstraint extends Constraint {
+
         private int minSize;            // the minimal available key size
         private int maxSize;            // the maximal available key size
         private int prohibitedSize = -1;    // unavailable key sizes
 
-        public KeySizeConstraint(Operator operator, int length) {
+        public KeySizeConstraint(String algo, Operator operator, int length) {
+            algorithm = algo;
             switch (operator) {
                 case EQ:      // an unavailable key size
                     this.minSize = 0;
@@ -298,21 +506,59 @@
             }
         }
 
-        // Does this key constraint disable the specified key?
-        public boolean disables(Key key) {
+        /*
+         * If we are passed a certificate, extract the public key and use it.
+         *
+         * Check if each constraint fails and check if there is a linked
+         * constraint  Any permitted constraint will exit the linked list
+         * to allow the operation.
+         */
+        public void permits(CertConstraintParameters cp)
+                throws CertPathValidatorException {
+            if (!permitsImpl(cp.getCertificate().getPublicKey())) {
+                if (nextConstraint != null) {
+                    nextConstraint.permits(cp);
+                    return;
+                }
+                throw new CertPathValidatorException(
+                        "Algorithm constraints check failed on keysize limits",
+                        null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
+            }
+        }
+
+
+        // Check if key constraint disable the specified key
+        // Uses old style permit()
+        public boolean permits(Key key) {
+            // If we recursively find a constraint that permits us to use
+            // this key, return true and skip any other constraint checks.
+            if (nextConstraint != null && nextConstraint.permits(key)) {
+                return true;
+            }
+            if (debug != null) {
+                debug.println("KeySizeConstraints.permits(): " + algorithm);
+            }
+
+            return permitsImpl(key);
+        }
+
+        private boolean permitsImpl(Key key) {
+            // Verify this constraint is for this public key algorithm
+            if (algorithm.compareToIgnoreCase(key.getAlgorithm()) != 0) {
+                return true;
+            }
+
             int size = KeyUtil.getKeySize(key);
-
             if (size == 0) {
-                return true;    // we don't allow any key of size 0.
+                return false;    // we don't allow any key of size 0.
             } else if (size > 0) {
-                return ((size < minSize) || (size > maxSize) ||
+                return !((size < minSize) || (size > maxSize) ||
                     (prohibitedSize == size));
             }   // Otherwise, the key size is not accessible. Conservatively,
                 // please don't disable such keys.
 
-            return false;
+            return true;
+        }
         }
     }
 
-}
-
--- a/src/share/classes/sun/security/util/LegacyAlgorithmConstraints.java	Thu Sep 08 15:00:00 2016 -0700
+++ b/src/share/classes/sun/security/util/LegacyAlgorithmConstraints.java	Mon Sep 19 11:21:02 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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
@@ -28,8 +28,6 @@
 import java.security.AlgorithmParameters;
 import java.security.CryptoPrimitive;
 import java.security.Key;
-import java.util.HashMap;
-import java.util.Map;
 import java.util.Set;
 import static sun.security.util.AbstractAlgorithmConstraints.getAlgorithms;
 
@@ -42,15 +40,12 @@
     public final static String PROPERTY_TLS_LEGACY_ALGS =
             "jdk.tls.legacyAlgorithms";
 
-    private final static Map<String, String[]> legacyAlgorithmsMap =
-                                                          new HashMap<>();
-
     private final String[] legacyAlgorithms;
 
     public LegacyAlgorithmConstraints(String propertyName,
             AlgorithmDecomposer decomposer) {
         super(decomposer);
-        legacyAlgorithms = getAlgorithms(legacyAlgorithmsMap, propertyName);
+        legacyAlgorithms = getAlgorithms(propertyName);
     }
 
     @Override
--- a/src/share/classes/sun/security/x509/X509CertImpl.java	Thu Sep 08 15:00:00 2016 -0700
+++ b/src/share/classes/sun/security/x509/X509CertImpl.java	Mon Sep 19 11:21:02 2016 -0700
@@ -1932,18 +1932,19 @@
 
     public String getFingerprint(String algorithm) {
         return fingerprints.computeIfAbsent(algorithm,
-                x -> getCertificateFingerPrint(x));
+                x -> getFingerprint(x, this));
     }
 
     /**
      * Gets the requested finger print of the certificate. The result
      * only contains 0-9 and A-F. No small case, no colon.
      */
-    private String getCertificateFingerPrint(String mdAlg) {
+    public static String getFingerprint(String algorithm,
+            X509Certificate cert) {
         String fingerPrint = "";
         try {
-            byte[] encCertInfo = getEncoded();
-            MessageDigest md = MessageDigest.getInstance(mdAlg);
+            byte[] encCertInfo = cert.getEncoded();
+            MessageDigest md = MessageDigest.getInstance(algorithm);
             byte[] digest = md.digest(encCertInfo);
             StringBuffer buf = new StringBuffer();
             for (int i = 0; i < digest.length; i++) {
--- a/src/share/lib/security/java.security-aix	Thu Sep 08 15:00:00 2016 -0700
+++ b/src/share/lib/security/java.security-aix	Mon Sep 19 11:21:02 2016 -0700
@@ -429,13 +429,13 @@
 #       " DisabledAlgorithm { , DisabledAlgorithm } "
 #
 #   DisabledAlgorithm:
-#       AlgorithmName [Constraint]
+#       AlgorithmName [Constraint] { '&' Constraint }
 #
 #   AlgorithmName:
 #       (see below)
 #
 #   Constraint:
-#       KeySizeConstraint
+#       KeySizeConstraint, CertConstraint
 #
 #   KeySizeConstraint:
 #       keySize Operator DecimalInteger
@@ -452,6 +452,9 @@
 #   DecimalDigit: one of
 #       1 2 3 4 5 6 7 8 9 0
 #
+#   CertConstraint
+#       jdkCA
+#
 # The "AlgorithmName" is the standard algorithm name of the disabled
 # algorithm. See "Java Cryptography Architecture Standard Algorithm Name
 # Documentation" for information about Standard Algorithm Names.  Matching
@@ -474,6 +477,29 @@
 # be disabled. Note that the "KeySizeConstraint" only makes sense to key
 # algorithms.
 #
+# "CertConstraint" specifies additional constraints for
+# certificates that contain algorithms that are restricted:
+#
+#   "jdkCA" prohibits the specified algorithm only if the algorithm is used
+#     in a certificate chain that terminates at a marked trust anchor in the
+#     lib/security/cacerts keystore.  All other chains are not affected.
+#     If the jdkCA constraint is not set, then all chains using the
+#     specified algorithm are restricted.  jdkCA may only be used once in
+#     a DisabledAlgorithm expression.
+#     Example:  To apply this constraint to SHA-1 certificates, include
+#     the following  "SHA1 jdkCA"
+#
+# When an algorithm must satisfy more than one constraint, it must be
+# delimited by an ampersand '&'.  For example, to restrict certificates in a
+# chain that terminate at a distribution provided trust anchor and contain
+# RSA keys that are less than or equal to 1024 bits, add the following
+# constraint:  "RSA keySize <= 1024 & jdkCA".
+#
+# All DisabledAlgorithms expressions are processed in the order defined in the
+# property.  This requires lower keysize constraints to be specified
+# before larger keysize constraints of the same algorithm.  For example:
+# "RSA keySize < 1024 & jdkCA, RSA keySize < 2048".
+#
 # Note: This property is currently used by Oracle's PKIX implementation. It
 # is not guaranteed to be examined and used by other implementations.
 #
@@ -482,7 +508,7 @@
 #
 #
 jdk.certpath.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, \
-    DSA keySize < 1024
+    DSA keySize < 1024, EC keySize < 224
 
 # Algorithm restrictions for Secure Socket Layer/Transport Layer Security
 # (SSL/TLS) processing
@@ -505,12 +531,13 @@
 # See the specification of "jdk.certpath.disabledAlgorithms" for the
 # syntax of the disabled algorithm string.
 #
-# Note: This property is currently used by Oracle's JSSE implementation.
+# Note: This property is currently used by the JDK Reference implementation.
 # It is not guaranteed to be examined and used by other implementations.
 #
 # Example:
 #   jdk.tls.disabledAlgorithms=MD5, SSLv3, DSA, RSA keySize < 2048
-jdk.tls.disabledAlgorithms=SSLv3, RC4, MD5withRSA, DH keySize < 768
+jdk.tls.disabledAlgorithms=SSLv3, RC4, MD5withRSA, DH keySize < 768, \
+    EC keySize < 224
 
 # Legacy algorithms for Secure Socket Layer/Transport Layer Security (SSL/TLS)
 # processing in JSSE implementation.
@@ -524,7 +551,7 @@
 # During SSL/TLS security parameters negotiation, legacy algorithms will
 # not be negotiated unless there are no other candidates.
 #
-# The syntax of the disabled algorithm string is described as this Java
+# The syntax of the legacy algorithms string is described as this Java
 # BNF-style:
 #   LegacyAlgorithms:
 #       " LegacyAlgorithm { , LegacyAlgorithm } "
@@ -554,7 +581,7 @@
 # See SSL/TLS specifications and "Java Cryptography Architecture Standard
 # Algorithm Name Documentation" for information about the algorithm names.
 #
-# Note: This property is currently used by Oracle's JSSE implementation.
+# Note: This property is currently used by the JDK Reference implementation.
 # It is not guaranteed to be examined and used by other implementations.
 # There is no guarantee the property will continue to exist or be of the
 # same syntax in future releases.
@@ -567,7 +594,8 @@
         DHE_DSS_EXPORT, DHE_RSA_EXPORT, DH_anon_EXPORT, DH_DSS_EXPORT, \
         DH_RSA_EXPORT, RSA_EXPORT, \
         DH_anon, ECDH_anon, \
-        RC4_128, RC4_40, DES_CBC, DES40_CBC
+        RC4_128, RC4_40, DES_CBC, DES40_CBC, \
+        3DES_EDE_CBC
 
 # The pre-defined default finite field Diffie-Hellman ephemeral (DHE)
 # parameters for Transport Layer Security (SSL/TLS/DTLS) processing.
--- a/src/share/lib/security/java.security-linux	Thu Sep 08 15:00:00 2016 -0700
+++ b/src/share/lib/security/java.security-linux	Mon Sep 19 11:21:02 2016 -0700
@@ -429,13 +429,13 @@
 #       " DisabledAlgorithm { , DisabledAlgorithm } "
 #
 #   DisabledAlgorithm:
-#       AlgorithmName [Constraint]
+#       AlgorithmName [Constraint] { '&' Constraint }
 #
 #   AlgorithmName:
 #       (see below)
 #
 #   Constraint:
-#       KeySizeConstraint
+#       KeySizeConstraint, CertConstraint
 #
 #   KeySizeConstraint:
 #       keySize Operator DecimalInteger
@@ -452,6 +452,9 @@
 #   DecimalDigit: one of
 #       1 2 3 4 5 6 7 8 9 0
 #
+#   CertConstraint
+#       jdkCA
+#
 # The "AlgorithmName" is the standard algorithm name of the disabled
 # algorithm. See "Java Cryptography Architecture Standard Algorithm Name
 # Documentation" for information about Standard Algorithm Names.  Matching
@@ -474,6 +477,29 @@
 # be disabled. Note that the "KeySizeConstraint" only makes sense to key
 # algorithms.
 #
+# "CertConstraint" specifies additional constraints for
+# certificates that contain algorithms that are restricted:
+#
+#   "jdkCA" prohibits the specified algorithm only if the algorithm is used
+#     in a certificate chain that terminates at a marked trust anchor in the
+#     lib/security/cacerts keystore.  All other chains are not affected.
+#     If the jdkCA constraint is not set, then all chains using the
+#     specified algorithm are restricted.  jdkCA may only be used once in
+#     a DisabledAlgorithm expression.
+#     Example:  To apply this constraint to SHA-1 certificates, include
+#     the following:  "SHA1 jdkCA"
+#
+# When an algorithm must satisfy more than one constraint, it must be
+# delimited by an ampersand '&'.  For example, to restrict certificates in a
+# chain that terminate at a distribution provided trust anchor and contain
+# RSA keys that are less than or equal to 1024 bits, add the following
+# constraint:  "RSA keySize <= 1024 & jdkCA".
+#
+# All DisabledAlgorithms expressions are processed in the order defined in the
+# property.  This requires lower keysize constraints to be specified
+# before larger keysize constraints of the same algorithm.  For example:
+# "RSA keySize < 1024 & jdkCA, RSA keySize < 2048".
+#
 # Note: This property is currently used by Oracle's PKIX implementation. It
 # is not guaranteed to be examined and used by other implementations.
 #
@@ -482,7 +508,7 @@
 #
 #
 jdk.certpath.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, \
-    DSA keySize < 1024
+    DSA keySize < 1024, EC keySize < 224
 
 # Algorithm restrictions for Secure Socket Layer/Transport Layer Security
 # (SSL/TLS) processing
@@ -505,12 +531,13 @@
 # See the specification of "jdk.certpath.disabledAlgorithms" for the
 # syntax of the disabled algorithm string.
 #
-# Note: This property is currently used by Oracle's JSSE implementation.
+# Note: This property is currently used by the JDK Reference implementation.
 # It is not guaranteed to be examined and used by other implementations.
 #
 # Example:
 #   jdk.tls.disabledAlgorithms=MD5, SSLv3, DSA, RSA keySize < 2048
-jdk.tls.disabledAlgorithms=SSLv3, RC4, MD5withRSA, DH keySize < 768
+jdk.tls.disabledAlgorithms=SSLv3, RC4, MD5withRSA, DH keySize < 768, \
+    EC keySize < 224
 
 # Legacy algorithms for Secure Socket Layer/Transport Layer Security (SSL/TLS)
 # processing in JSSE implementation.
@@ -524,7 +551,7 @@
 # During SSL/TLS security parameters negotiation, legacy algorithms will
 # not be negotiated unless there are no other candidates.
 #
-# The syntax of the disabled algorithm string is described as this Java
+# The syntax of the legacy algorithms string is described as this Java
 # BNF-style:
 #   LegacyAlgorithms:
 #       " LegacyAlgorithm { , LegacyAlgorithm } "
@@ -554,7 +581,7 @@
 # See SSL/TLS specifications and "Java Cryptography Architecture Standard
 # Algorithm Name Documentation" for information about the algorithm names.
 #
-# Note: This property is currently used by Oracle's JSSE implementation.
+# Note: This property is currently used by the JDK Reference implementation.
 # It is not guaranteed to be examined and used by other implementations.
 # There is no guarantee the property will continue to exist or be of the
 # same syntax in future releases.
@@ -567,7 +594,8 @@
         DHE_DSS_EXPORT, DHE_RSA_EXPORT, DH_anon_EXPORT, DH_DSS_EXPORT, \
         DH_RSA_EXPORT, RSA_EXPORT, \
         DH_anon, ECDH_anon, \
-        RC4_128, RC4_40, DES_CBC, DES40_CBC
+        RC4_128, RC4_40, DES_CBC, DES40_CBC, \
+        3DES_EDE_CBC
 
 # The pre-defined default finite field Diffie-Hellman ephemeral (DHE)
 # parameters for Transport Layer Security (SSL/TLS/DTLS) processing.
--- a/src/share/lib/security/java.security-macosx	Thu Sep 08 15:00:00 2016 -0700
+++ b/src/share/lib/security/java.security-macosx	Mon Sep 19 11:21:02 2016 -0700
@@ -432,13 +432,13 @@
 #       " DisabledAlgorithm { , DisabledAlgorithm } "
 #
 #   DisabledAlgorithm:
-#       AlgorithmName [Constraint]
+#       AlgorithmName [Constraint] { '&' Constraint }
 #
 #   AlgorithmName:
 #       (see below)
 #
 #   Constraint:
-#       KeySizeConstraint
+#       KeySizeConstraint, CertConstraint
 #
 #   KeySizeConstraint:
 #       keySize Operator DecimalInteger
@@ -455,6 +455,9 @@
 #   DecimalDigit: one of
 #       1 2 3 4 5 6 7 8 9 0
 #
+#   CertConstraint
+#       jdkCA
+#
 # The "AlgorithmName" is the standard algorithm name of the disabled
 # algorithm. See "Java Cryptography Architecture Standard Algorithm Name
 # Documentation" for information about Standard Algorithm Names.  Matching
@@ -477,6 +480,29 @@
 # be disabled. Note that the "KeySizeConstraint" only makes sense to key
 # algorithms.
 #
+# "CertConstraint" specifies additional constraints for
+# certificates that contain algorithms that are restricted:
+#
+#   "jdkCA" prohibits the specified algorithm only if the algorithm is used
+#     in a certificate chain that terminates at a marked trust anchor in the
+#     lib/security/cacerts keystore.  All other chains are not affected.
+#     If the jdkCA constraint is not set, then all chains using the
+#     specified algorithm are restricted. jdkCA may only be used once in
+#     a DisabledAlgorithm expression.
+#     Example:  To apply this constraint to SHA-1 certificates, include
+#     the following:  "SHA1 jdkCA"
+#
+# When an algorithm must satisfy more than one constraint, it must be
+# delimited by an ampersand '&'.  For example, to restrict certificates in a
+# chain that terminate at a distribution provided trust anchor and contain
+# RSA keys that are less than or equal to 1024 bits, add the following
+# constraint:  "RSA keySize <= 1024 & jdkCA".
+#
+# All DisabledAlgorithms expressions are processed in the order defined in the
+# property.  This requires lower keysize constraints to be specified
+# before larger keysize constraints of the same algorithm.  For example:
+# "RSA keySize < 1024 & jdkCA, RSA keySize < 2048".
+#
 # Note: This property is currently used by Oracle's PKIX implementation. It
 # is not guaranteed to be examined and used by other implementations.
 #
@@ -485,7 +511,7 @@
 #
 #
 jdk.certpath.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, \
-    DSA keySize < 1024
+    DSA keySize < 1024, EC keySize < 224
 
 # Algorithm restrictions for Secure Socket Layer/Transport Layer Security
 # (SSL/TLS) processing
@@ -508,12 +534,13 @@
 # See the specification of "jdk.certpath.disabledAlgorithms" for the
 # syntax of the disabled algorithm string.
 #
-# Note: This property is currently used by Oracle's JSSE implementation.
+# Note: This property is currently used by the JDK Reference implementation.
 # It is not guaranteed to be examined and used by other implementations.
 #
 # Example:
 #   jdk.tls.disabledAlgorithms=MD5, SSLv3, DSA, RSA keySize < 2048
-jdk.tls.disabledAlgorithms=SSLv3, RC4, MD5withRSA, DH keySize < 768
+jdk.tls.disabledAlgorithms=SSLv3, RC4, MD5withRSA, DH keySize < 768, \
+    EC keySize < 224
 
 # Legacy algorithms for Secure Socket Layer/Transport Layer Security (SSL/TLS)
 # processing in JSSE implementation.
@@ -527,7 +554,7 @@
 # During SSL/TLS security parameters negotiation, legacy algorithms will
 # not be negotiated unless there are no other candidates.
 #
-# The syntax of the disabled algorithm string is described as this Java
+# The syntax of the legacy algorithms string is described as this Java
 # BNF-style:
 #   LegacyAlgorithms:
 #       " LegacyAlgorithm { , LegacyAlgorithm } "
@@ -557,7 +584,7 @@
 # See SSL/TLS specifications and "Java Cryptography Architecture Standard
 # Algorithm Name Documentation" for information about the algorithm names.
 #
-# Note: This property is currently used by Oracle's JSSE implementation.
+# Note: This property is currently used by the JDK Reference implementation.
 # It is not guaranteed to be examined and used by other implementations.
 # There is no guarantee the property will continue to exist or be of the
 # same syntax in future releases.
@@ -570,7 +597,8 @@
         DHE_DSS_EXPORT, DHE_RSA_EXPORT, DH_anon_EXPORT, DH_DSS_EXPORT, \
         DH_RSA_EXPORT, RSA_EXPORT, \
         DH_anon, ECDH_anon, \
-        RC4_128, RC4_40, DES_CBC, DES40_CBC
+        RC4_128, RC4_40, DES_CBC, DES40_CBC, \
+        3DES_EDE_CBC
 
 # The pre-defined default finite field Diffie-Hellman ephemeral (DHE)
 # parameters for Transport Layer Security (SSL/TLS/DTLS) processing.
--- a/src/share/lib/security/java.security-solaris	Thu Sep 08 15:00:00 2016 -0700
+++ b/src/share/lib/security/java.security-solaris	Mon Sep 19 11:21:02 2016 -0700
@@ -431,13 +431,13 @@
 #       " DisabledAlgorithm { , DisabledAlgorithm } "
 #
 #   DisabledAlgorithm:
-#       AlgorithmName [Constraint]
+#       AlgorithmName [Constraint] { '&' Constraint }
 #
 #   AlgorithmName:
 #       (see below)
 #
 #   Constraint:
-#       KeySizeConstraint
+#       KeySizeConstraint, CertConstraint
 #
 #   KeySizeConstraint:
 #       keySize Operator DecimalInteger
@@ -454,6 +454,9 @@
 #   DecimalDigit: one of
 #       1 2 3 4 5 6 7 8 9 0
 #
+#   CertConstraint
+#       jdkCA
+#
 # The "AlgorithmName" is the standard algorithm name of the disabled
 # algorithm. See "Java Cryptography Architecture Standard Algorithm Name
 # Documentation" for information about Standard Algorithm Names.  Matching
@@ -476,6 +479,29 @@
 # be disabled. Note that the "KeySizeConstraint" only makes sense to key
 # algorithms.
 #
+# "CertConstraint" specifies additional constraints for
+# certificates that contain algorithms that are restricted:
+#
+#   "jdkCA" prohibits the specified algorithm only if the algorithm is used
+#     in a certificate chain that terminates at a marked trust anchor in the
+#     lib/security/cacerts keystore.  All other chains are not affected.
+#     If the jdkCA constraint is not set, then all chains using the
+#     specified algorithm are restricted. jdkCA may only be used once in
+#     a DisabledAlgorithm expression.
+#     Example:  To apply this constraint to SHA-1 certificates, include
+#     the following:  "SHA1 jdkCA"
+#
+# When an algorithm must satisfy more than one constraint, it must be
+# delimited by an ampersand '&'.  For example, to restrict certificates in a
+# chain that terminate at a distribution provided trust anchor and contain
+# RSA keys that are less than or equal to 1024 bits, add the following
+# constraint:  "RSA keySize <= 1024 & jdkCA".
+#
+# All DisabledAlgorithms expressions are processed in the order defined in the
+# property.  This requires lower keysize constraints to be specified
+# before larger keysize constraints of the same algorithm.  For example:
+# "RSA keySize < 1024 & jdkCA, RSA keySize < 2048".
+#
 # Note: This property is currently used by Oracle's PKIX implementation. It
 # is not guaranteed to be examined and used by other implementations.
 #
@@ -484,7 +510,7 @@
 #
 #
 jdk.certpath.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, \
-    DSA keySize < 1024
+    DSA keySize < 1024, EC keySize < 224
 
 # Algorithm restrictions for Secure Socket Layer/Transport Layer Security
 # (SSL/TLS) processing
@@ -507,12 +533,13 @@
 # See the specification of "jdk.certpath.disabledAlgorithms" for the
 # syntax of the disabled algorithm string.
 #
-# Note: This property is currently used by Oracle's JSSE implementation.
+# Note: This property is currently used by the JDK Reference implementation.
 # It is not guaranteed to be examined and used by other implementations.
 #
 # Example:
 #   jdk.tls.disabledAlgorithms=MD5, SSLv3, DSA, RSA keySize < 2048
-jdk.tls.disabledAlgorithms=SSLv3, RC4, MD5withRSA, DH keySize < 768
+jdk.tls.disabledAlgorithms=SSLv3, RC4, MD5withRSA, DH keySize < 768, \
+    EC keySize < 224
 
 # Legacy algorithms for Secure Socket Layer/Transport Layer Security (SSL/TLS)
 # processing in JSSE implementation.
@@ -526,7 +553,7 @@
 # During SSL/TLS security parameters negotiation, legacy algorithms will
 # not be negotiated unless there are no other candidates.
 #
-# The syntax of the disabled algorithm string is described as this Java
+# The syntax of the legacy algorithms string is described as this Java
 # BNF-style:
 #   LegacyAlgorithms:
 #       " LegacyAlgorithm { , LegacyAlgorithm } "
@@ -556,7 +583,7 @@
 # See SSL/TLS specifications and "Java Cryptography Architecture Standard
 # Algorithm Name Documentation" for information about the algorithm names.
 #
-# Note: This property is currently used by Oracle's JSSE implementation.
+# Note: This property is currently used by the JDK Reference implementation.
 # It is not guaranteed to be examined and used by other implementations.
 # There is no guarantee the property will continue to exist or be of the
 # same syntax in future releases.
@@ -569,7 +596,8 @@
         DHE_DSS_EXPORT, DHE_RSA_EXPORT, DH_anon_EXPORT, DH_DSS_EXPORT, \
         DH_RSA_EXPORT, RSA_EXPORT, \
         DH_anon, ECDH_anon, \
-        RC4_128, RC4_40, DES_CBC, DES40_CBC
+        RC4_128, RC4_40, DES_CBC, DES40_CBC, \
+        3DES_EDE_CBC
 
 # The pre-defined default finite field Diffie-Hellman ephemeral (DHE)
 # parameters for Transport Layer Security (SSL/TLS/DTLS) processing.
--- a/src/share/lib/security/java.security-windows	Thu Sep 08 15:00:00 2016 -0700
+++ b/src/share/lib/security/java.security-windows	Mon Sep 19 11:21:02 2016 -0700
@@ -432,13 +432,13 @@
 #       " DisabledAlgorithm { , DisabledAlgorithm } "
 #
 #   DisabledAlgorithm:
-#       AlgorithmName [Constraint]
+#       AlgorithmName [Constraint] { '&' Constraint }
 #
 #   AlgorithmName:
 #       (see below)
 #
 #   Constraint:
-#       KeySizeConstraint
+#       KeySizeConstraint, CertConstraint
 #
 #   KeySizeConstraint:
 #       keySize Operator DecimalInteger
@@ -455,6 +455,9 @@
 #   DecimalDigit: one of
 #       1 2 3 4 5 6 7 8 9 0
 #
+#   CertConstraint
+#       jdkCA
+#
 # The "AlgorithmName" is the standard algorithm name of the disabled
 # algorithm. See "Java Cryptography Architecture Standard Algorithm Name
 # Documentation" for information about Standard Algorithm Names.  Matching
@@ -477,6 +480,29 @@
 # be disabled. Note that the "KeySizeConstraint" only makes sense to key
 # algorithms.
 #
+# "CertConstraint" specifies additional constraints for
+# certificates that contain algorithms that are restricted:
+#
+#   "jdkCA" prohibits the specified algorithm only if the algorithm is used
+#     in a certificate chain that terminates at a marked trust anchor in the
+#     lib/security/cacerts keystore.  All other chains are not affected.
+#     If the jdkCA constraint is not set, then all chains using the
+#     specified algorithm are restricted.  jdkCA may only be used once in
+#     a DisabledAlgorithm expression.
+#     Example:  To apply this constraint to SHA-1 certificates, include
+#     the following:  "SHA1 jdkCA"
+#
+# When an algorithm must satisfy more than one constraint, it must be
+# delimited by an ampersand '&'.  For example, to restrict certificates in a
+# chain that terminate at a distribution provided trust anchor and contain
+# RSA keys that are less than or equal to 1024 bits, add the following
+# constraint:  "RSA keySize <= 1024 & jdkCA".
+#
+# All DisabledAlgorithms expressions are processed in the order defined in the
+# property.  This requires lower keysize constraints to be specified
+# before larger keysize constraints of the same algorithm.  For example:
+# "RSA keySize < 1024 & jdkCA, RSA keySize < 2048".
+#
 # Note: This property is currently used by Oracle's PKIX implementation. It
 # is not guaranteed to be examined and used by other implementations.
 #
@@ -485,7 +511,7 @@
 #
 #
 jdk.certpath.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, \
-    DSA keySize < 1024
+    DSA keySize < 1024, EC keySize < 224
 
 # Algorithm restrictions for Secure Socket Layer/Transport Layer Security
 # (SSL/TLS) processing
@@ -508,12 +534,13 @@
 # See the specification of "jdk.certpath.disabledAlgorithms" for the
 # syntax of the disabled algorithm string.
 #
-# Note: This property is currently used by Oracle's JSSE implementation.
+# Note: This property is currently used by the JDK Reference implementation.
 # It is not guaranteed to be examined and used by other implementations.
 #
 # Example:
 #   jdk.tls.disabledAlgorithms=MD5, SSLv3, DSA, RSA keySize < 2048
-jdk.tls.disabledAlgorithms=SSLv3, RC4, MD5withRSA, DH keySize < 768
+jdk.tls.disabledAlgorithms=SSLv3, RC4, MD5withRSA, DH keySize < 768, \
+    EC keySize < 224
 
 # Legacy algorithms for Secure Socket Layer/Transport Layer Security (SSL/TLS)
 # processing in JSSE implementation.
@@ -527,7 +554,7 @@
 # During SSL/TLS security parameters negotiation, legacy algorithms will
 # not be negotiated unless there are no other candidates.
 #
-# The syntax of the disabled algorithm string is described as this Java
+# The syntax of the legacy algorithms string is described as this Java
 # BNF-style:
 #   LegacyAlgorithms:
 #       " LegacyAlgorithm { , LegacyAlgorithm } "
@@ -557,7 +584,7 @@
 # See SSL/TLS specifications and "Java Cryptography Architecture Standard
 # Algorithm Name Documentation" for information about the algorithm names.
 #
-# Note: This property is currently used by Oracle's JSSE implementation.
+# Note: This property is currently used by the JDK Reference implementation.
 # It is not guaranteed to be examined and used by other implementations.
 # There is no guarantee the property will continue to exist or be of the
 # same syntax in future releases.
@@ -570,7 +597,8 @@
         DHE_DSS_EXPORT, DHE_RSA_EXPORT, DH_anon_EXPORT, DH_DSS_EXPORT, \
         DH_RSA_EXPORT, RSA_EXPORT, \
         DH_anon, ECDH_anon, \
-        RC4_128, RC4_40, DES_CBC, DES40_CBC
+        RC4_128, RC4_40, DES_CBC, DES40_CBC, \
+        3DES_EDE_CBC
 
 # The pre-defined default finite field Diffie-Hellman ephemeral (DHE)
 # parameters for Transport Layer Security (SSL/TLS/DTLS) processing.
--- a/src/solaris/native/java/net/SocketOutputStream.c	Thu Sep 08 15:00:00 2016 -0700
+++ b/src/solaris/native/java/net/SocketOutputStream.c	Mon Sep 19 11:21:02 2016 -0700
@@ -103,31 +103,35 @@
         int llen = chunkLen;
         (*env)->GetByteArrayRegion(env, data, off, chunkLen, (jbyte *)bufP);
 
-        while(llen > 0) {
-            int n = NET_Send(fd, bufP + loff, llen, 0);
-            if (n > 0) {
-                llen -= n;
-                loff += n;
-                continue;
+        if ((*env)->ExceptionCheck(env)) {
+            break;
+        } else {
+            while(llen > 0) {
+                int n = NET_Send(fd, bufP + loff, llen, 0);
+                if (n > 0) {
+                    llen -= n;
+                    loff += n;
+                    continue;
+                }
+                if (n == JVM_IO_INTR) {
+                    JNU_ThrowByName(env, "java/io/InterruptedIOException", 0);
+                } else {
+                    if (errno == ECONNRESET) {
+                        JNU_ThrowByName(env, "sun/net/ConnectionResetException",
+                            "Connection reset");
+                    } else {
+                        NET_ThrowByNameWithLastError(env, "java/net/SocketException",
+                            "Write failed");
+                    }
+                }
+                if (bufP != BUF) {
+                    free(bufP);
+                }
+                return;
             }
-            if (n == JVM_IO_INTR) {
-                JNU_ThrowByName(env, "java/io/InterruptedIOException", 0);
-            } else {
-                if (errno == ECONNRESET) {
-                    JNU_ThrowByName(env, "sun/net/ConnectionResetException",
-                        "Connection reset");
-                } else {
-                    NET_ThrowByNameWithLastError(env, "java/net/SocketException",
-                        "Write failed");
-                }
-            }
-            if (bufP != BUF) {
-                free(bufP);
-            }
-            return;
+            len -= chunkLen;
+            off += chunkLen;
         }
-        len -= chunkLen;
-        off += chunkLen;
     }
 
     if (bufP != BUF) {
--- a/src/windows/native/java/net/SocketOutputStream.c	Thu Sep 08 15:00:00 2016 -0700
+++ b/src/windows/native/java/net/SocketOutputStream.c	Mon Sep 19 11:21:02 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -100,66 +100,69 @@
         int retry = 0;
 
         (*env)->GetByteArrayRegion(env, data, off, chunkLen, (jbyte *)bufP);
-
-        while(llen > 0) {
-            int n = send(fd, bufP + loff, llen, 0);
-            if (n > 0) {
-                llen -= n;
-                loff += n;
-                continue;
-            }
-
-            /*
-             * Due to a bug in Windows Sockets (observed on NT and Windows
-             * 2000) it may be necessary to retry the send. The issue is that
-             * on blocking sockets send/WSASend is supposed to block if there
-             * is insufficient buffer space available. If there are a large
-             * number of threads blocked on write due to congestion then it's
-             * possile to hit the NT/2000 bug whereby send returns WSAENOBUFS.
-             * The workaround we use is to retry the send. If we have a
-             * large buffer to send (>2k) then we retry with a maximum of
-             * 2k buffer. If we hit the issue with <=2k buffer then we backoff
-             * for 1 second and retry again. We repeat this up to a reasonable
-             * limit before bailing out and throwing an exception. In load
-             * conditions we've observed that the send will succeed after 2-3
-             * attempts but this depends on network buffers associated with
-             * other sockets draining.
-             */
-            if (WSAGetLastError() == WSAENOBUFS) {
-                if (llen > MAX_BUFFER_LEN) {
-                    buflen = MAX_BUFFER_LEN;
-                    chunkLen = MAX_BUFFER_LEN;
-                    llen = MAX_BUFFER_LEN;
+        if ((*env)->ExceptionCheck(env)) {
+            break;
+        } else {
+            while(llen > 0) {
+                int n = send(fd, bufP + loff, llen, 0);
+                if (n > 0) {
+                    llen -= n;
+                    loff += n;
                     continue;
                 }
-                if (retry >= 30) {
-                    JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
-                        "No buffer space available - exhausted attempts to queue buffer");
-                    if (bufP != BUF) {
-                        free(bufP);
+
+                /*
+                 * Due to a bug in Windows Sockets (observed on NT and Windows
+                 * 2000) it may be necessary to retry the send. The issue is that
+                 * on blocking sockets send/WSASend is supposed to block if there
+                 * is insufficient buffer space available. If there are a large
+                 * number of threads blocked on write due to congestion then it's
+                 * possile to hit the NT/2000 bug whereby send returns WSAENOBUFS.
+                 * The workaround we use is to retry the send. If we have a
+                 * large buffer to send (>2k) then we retry with a maximum of
+                 * 2k buffer. If we hit the issue with <=2k buffer then we backoff
+                 * for 1 second and retry again. We repeat this up to a reasonable
+                 * limit before bailing out and throwing an exception. In load
+                 * conditions we've observed that the send will succeed after 2-3
+                 * attempts but this depends on network buffers associated with
+                 * other sockets draining.
+                 */
+                if (WSAGetLastError() == WSAENOBUFS) {
+                    if (llen > MAX_BUFFER_LEN) {
+                        buflen = MAX_BUFFER_LEN;
+                        chunkLen = MAX_BUFFER_LEN;
+                        llen = MAX_BUFFER_LEN;
+                        continue;
                     }
-                    return;
+                    if (retry >= 30) {
+                        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
+                            "No buffer space available - exhausted attempts to queue buffer");
+                        if (bufP != BUF) {
+                            free(bufP);
+                        }
+                        return;
+                    }
+                    Sleep(1000);
+                    retry++;
+                    continue;
                 }
-                Sleep(1000);
-                retry++;
-                continue;
+
+                /*
+                 * Send failed - can be caused by close or write error.
+                 */
+                if (WSAGetLastError() == WSAENOTSOCK) {
+                    JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
+                } else {
+                    NET_ThrowCurrent(env, "socket write error");
+                }
+                if (bufP != BUF) {
+                    free(bufP);
+                }
+                return;
             }
-
-            /*
-             * Send failed - can be caused by close or write error.
-             */
-            if (WSAGetLastError() == WSAENOTSOCK) {
-                JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
-            } else {
-                NET_ThrowCurrent(env, "socket write error");
-            }
-            if (bufP != BUF) {
-                free(bufP);
-            }
-            return;
+            len -= chunkLen;
+            off += chunkLen;
         }
-        len -= chunkLen;
-        off += chunkLen;
     }
 
     if (bufP != BUF) {
--- a/test/javax/net/ssl/ciphersuites/DisabledAlgorithms.java	Thu Sep 08 15:00:00 2016 -0700
+++ b/test/javax/net/ssl/ciphersuites/DisabledAlgorithms.java	Mon Sep 19 11:21:02 2016 -0700
@@ -41,7 +41,8 @@
  * @bug 8076221
  * @summary Check if weak cipher suites are disabled
  * @run main/othervm DisabledAlgorithms default
- * @run main/othervm DisabledAlgorithms empty
+ * @run main/othervm -Djdk.tls.namedGroups="secp256r1,secp192r1"
+ *     DisabledAlgorithms empty
  */
 public class DisabledAlgorithms {
 
@@ -97,6 +98,11 @@
                 System.out.println("jdk.tls.disabledAlgorithms = "
                         + Security.getProperty("jdk.tls.disabledAlgorithms"));
 
+                // some of the certs in our test are weak; disable
+                Security.setProperty("jdk.certpath.disabledAlgorithms", "");
+                System.out.println("jdk.certpath.disabledAlgorithms = "
+                        + Security.getProperty("jdk.cerpath.disabledAlgorithms"));
+
                 // check if RC4 cipher suites can be used
                 // if jdk.tls.disabledAlgorithms is empty
                 checkSuccess(rc4_ciphersuites);
@@ -224,6 +230,7 @@
                     socket.getSession().invalidate();
                 } catch (SSLHandshakeException e) {
                     System.out.println("Server: run: " + e);
+                    e.printStackTrace();
                     sslError = true;
                     stopped = true;
                 } catch (IOException e) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/ciphersuites/ECCurvesconstraints.java	Mon Sep 19 11:21:02 2016 -0700
@@ -0,0 +1,408 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 8148516
+ * @summary Improve the default strength of EC in JDK
+ * @run main/othervm ECCurvesconstraints PKIX
+ * @run main/othervm ECCurvesconstraints SunX509
+ */
+
+import java.net.*;
+import java.util.*;
+import java.io.*;
+import javax.net.ssl.*;
+import java.security.Security;
+import java.security.KeyStore;
+import java.security.KeyFactory;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.spec.*;
+import java.security.interfaces.*;
+import java.util.Base64;
+
+
+public class ECCurvesconstraints {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = false;
+
+    /*
+     * Where do we find the keystores?
+     */
+    // Certificates and key used in the test.
+    //
+    // EC curve: secp224k1
+    static String trustedCertStr =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIBCzCBugIEVz2lcjAKBggqhkjOPQQDAjAaMRgwFgYDVQQDDA93d3cuZXhhbXBs\n" +
+        "ZS5vcmcwHhcNMTYwNTE5MTEzNzM5WhcNMTcwNTE5MTEzNzM5WjAaMRgwFgYDVQQD\n" +
+        "DA93d3cuZXhhbXBsZS5vcmcwTjAQBgcqhkjOPQIBBgUrgQQAIAM6AAT68uovMZ8f\n" +
+        "KARn5NOjvieJaq6h8zHYkM9w5DuN0kkOo4KBhke06EkQj0nvQQcSvppTV6RoDLY4\n" +
+        "djAKBggqhkjOPQQDAgNAADA9AhwMNIujM0R0llpPH6d89d1S3VRGH/78ovc+zw51\n" +
+        "Ah0AuZ1YlQkUbrJIzkuPSICxz5UfCWPe+7w4as+wiA==\n" +
+        "-----END CERTIFICATE-----";
+
+    // Private key in the format of PKCS#8
+    static String targetPrivateKey =
+        "MIGCAgEAMBAGByqGSM49AgEGBSuBBAAgBGswaQIBAQQdAPbckc86mgW/zexB1Ajq\n" +
+        "38HntWOjdxL6XSoiAsWgBwYFK4EEACChPAM6AAT68uovMZ8fKARn5NOjvieJaq6h\n" +
+        "8zHYkM9w5DuN0kkOo4KBhke06EkQj0nvQQcSvppTV6RoDLY4dg==";
+
+    static String[] serverCerts = {trustedCertStr};
+    static String[] serverKeys  = {targetPrivateKey};
+    static String[] clientCerts = {trustedCertStr};
+    static String[] clientKeys  = {targetPrivateKey};
+
+    static char passphrase[] = "passphrase".toCharArray();
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide() throws Exception {
+        SSLContext context = generateSSLContext(false);
+        SSLServerSocketFactory sslssf = context.getServerSocketFactory();
+        SSLServerSocket sslServerSocket =
+            (SSLServerSocket)sslssf.createServerSocket(serverPort);
+        serverPort = sslServerSocket.getLocalPort();
+
+        /*
+         * Signal Client, we're ready for his connect.
+         */
+        serverReady = true;
+
+        SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept();
+        try {
+            sslSocket.setSoTimeout(5000);
+            sslSocket.setSoLinger(true, 5);
+
+            InputStream sslIS = sslSocket.getInputStream();
+            OutputStream sslOS = sslSocket.getOutputStream();
+
+            sslIS.read();
+            sslOS.write('A');
+            sslOS.flush();
+
+            throw new Exception("EC curve secp224k1 should be disabled");
+        } catch (SSLHandshakeException she) {
+            // expected exception: no cipher suites in common
+            System.out.println("Expected exception: " + she);
+        } finally {
+            sslSocket.close();
+            sslServerSocket.close();
+        }
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        SSLContext context = generateSSLContext(true);
+        SSLSocketFactory sslsf = context.getSocketFactory();
+
+        SSLSocket sslSocket =
+            (SSLSocket)sslsf.createSocket("localhost", serverPort);
+
+        try {
+            sslSocket.setSoTimeout(5000);
+            sslSocket.setSoLinger(true, 5);
+
+            InputStream sslIS = sslSocket.getInputStream();
+            OutputStream sslOS = sslSocket.getOutputStream();
+
+            sslOS.write('B');
+            sslOS.flush();
+            sslIS.read();
+
+            throw new Exception("EC curve secp224k1 should be disabled");
+        } catch (SSLHandshakeException she) {
+            // expected exception: Received fatal alert
+            System.out.println("Expected exception: " + she);
+        } finally {
+            sslSocket.close();
+        }
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+    private static String tmAlgorithm;             // trust manager
+
+    private static void parseArguments(String[] args) {
+        tmAlgorithm = args[0];
+    }
+
+    private static SSLContext generateSSLContext(boolean isClient)
+            throws Exception {
+
+        // generate certificate from cert string
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+
+        // create a key store
+        KeyStore ks = KeyStore.getInstance("JKS");
+        ks.load(null, null);
+
+        // import the trused cert
+        ByteArrayInputStream is =
+                    new ByteArrayInputStream(trustedCertStr.getBytes());
+        Certificate trusedCert = cf.generateCertificate(is);
+        is.close();
+
+        ks.setCertificateEntry("Export Signer", trusedCert);
+
+        String[] certStrs = null;
+        String[] keyStrs = null;
+        if (isClient) {
+            certStrs = clientCerts;
+            keyStrs = clientKeys;
+        } else {
+            certStrs = serverCerts;
+            keyStrs = serverKeys;
+        }
+
+        for (int i = 0; i < certStrs.length; i++) {
+            // generate the private key.
+            String keySpecStr = keyStrs[i];
+            PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
+                                Base64.getMimeDecoder().decode(keySpecStr));
+            KeyFactory kf = KeyFactory.getInstance("EC");
+            ECPrivateKey priKey =
+                    (ECPrivateKey)kf.generatePrivate(priKeySpec);
+
+            // generate certificate chain
+            String keyCertStr = certStrs[i];
+            is = new ByteArrayInputStream(keyCertStr.getBytes());
+            Certificate keyCert = cf.generateCertificate(is);
+            is.close();
+
+            Certificate[] chain = new Certificate[2];
+            chain[0] = keyCert;
+            chain[1] = trusedCert;
+
+            // import the key entry.
+            ks.setKeyEntry("key-entry-" + i, priKey, passphrase, chain);
+        }
+
+        // create SSL context
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm);
+        tmf.init(ks);
+
+        SSLContext ctx = SSLContext.getInstance("TLS");
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
+        kmf.init(ks, passphrase);
+
+        ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+        ks = null;
+
+        return ctx;
+    }
+
+    // use any free port by default
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    public static void main(String[] args) throws Exception {
+        if (debug) {
+            System.setProperty("javax.net.debug", "all");
+        }
+
+        /*
+         * Get the customized arguments.
+         */
+        parseArguments(args);
+
+        /*
+         * Start the tests.
+         */
+        new ECCurvesconstraints();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    ECCurvesconstraints() throws Exception {
+        try {
+            if (separateServerThread) {
+                startServer(true);
+                startClient(false);
+            } else {
+                startClient(true);
+                startServer(false);
+            }
+        } catch (Exception e) {
+            // swallow for now.  Show later
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            serverThread.join();
+        } else {
+            clientThread.join();
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         * Which side threw the error?
+         */
+        Exception local;
+        Exception remote;
+        String whichRemote;
+
+        if (separateServerThread) {
+            remote = serverException;
+            local = clientException;
+            whichRemote = "server";
+        } else {
+            remote = clientException;
+            local = serverException;
+            whichRemote = "client";
+        }
+
+        /*
+         * If both failed, return the curthread's exception, but also
+         * print the remote side Exception
+         */
+        if ((local != null) && (remote != null)) {
+            System.out.println(whichRemote + " also threw:");
+            remote.printStackTrace();
+            System.out.println();
+            throw local;
+        }
+
+        if (remote != null) {
+            throw remote;
+        }
+
+        if (local != null) {
+            throw local;
+        }
+    }
+
+    void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died, because of " + e);
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            try {
+                doServerSide();
+            } catch (Exception e) {
+                serverException = e;
+            } finally {
+                serverReady = true;
+            }
+        }
+    }
+
+    void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died, because of " + e);
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            try {
+                doClientSide();
+            } catch (Exception e) {
+                clientException = e;
+            }
+        }
+    }
+}
--- a/test/lib/testlibrary/jdk/testlibrary/OutputAnalyzer.java	Thu Sep 08 15:00:00 2016 -0700
+++ b/test/lib/testlibrary/jdk/testlibrary/OutputAnalyzer.java	Mon Sep 19 11:21:02 2016 -0700
@@ -90,13 +90,14 @@
      * @throws RuntimeException
      *             If the string was not found
      */
-    public void shouldContain(String expectedString) {
+    public OutputAnalyzer shouldContain(String expectedString) {
         if (!stdout.contains(expectedString)
                 && !stderr.contains(expectedString)) {
             reportDiagnosticSummary();
             throw new RuntimeException("'" + expectedString
                     + "' missing from stdout/stderr \n");
         }
+        return this;
     }
 
     /**
@@ -107,12 +108,13 @@
      * @throws RuntimeException
      *             If the string was not found
      */
-    public void stdoutShouldContain(String expectedString) {
+    public OutputAnalyzer stdoutShouldContain(String expectedString) {
         if (!stdout.contains(expectedString)) {
             reportDiagnosticSummary();
             throw new RuntimeException("'" + expectedString
                     + "' missing from stdout \n");
         }
+        return this;
     }
 
     /**
@@ -123,24 +125,25 @@
      * @throws RuntimeException
      *             If the string was not found
      */
-    public void stderrShouldContain(String expectedString) {
+    public OutputAnalyzer stderrShouldContain(String expectedString) {
         if (!stderr.contains(expectedString)) {
             reportDiagnosticSummary();
             throw new RuntimeException("'" + expectedString
                     + "' missing from stderr \n");
         }
+        return this;
     }
 
     /**
      * Verify that the stdout and stderr contents of output buffer does not
      * contain the string
      *
-     * @param expectedString
+     * @param notExpectedString
      *            String that the buffer should not contain
      * @throws RuntimeException
      *             If the string was found
      */
-    public void shouldNotContain(String notExpectedString) {
+    public OutputAnalyzer shouldNotContain(String notExpectedString) {
         if (stdout.contains(notExpectedString)) {
             reportDiagnosticSummary();
             throw new RuntimeException("'" + notExpectedString
@@ -151,23 +154,25 @@
             throw new RuntimeException("'" + notExpectedString
                     + "' found in stderr \n");
         }
+        return this;
     }
 
     /**
      * Verify that the stdout contents of output buffer does not contain the
      * string
      *
-     * @param expectedString
+     * @param notExpectedString
      *            String that the buffer should not contain
      * @throws RuntimeException
      *             If the string was found
      */
-    public void stdoutShouldNotContain(String notExpectedString) {
+    public OutputAnalyzer stdoutShouldNotContain(String notExpectedString) {
         if (stdout.contains(notExpectedString)) {
             reportDiagnosticSummary();
             throw new RuntimeException("'" + notExpectedString
                     + "' found in stdout \n");
         }
+        return this;
     }
 
     /**
@@ -195,7 +200,7 @@
      * @throws RuntimeException
      *             If the pattern was not found
      */
-    public void shouldMatch(String pattern) {
+    public OutputAnalyzer shouldMatch(String pattern) {
         Matcher stdoutMatcher = Pattern.compile(pattern, Pattern.MULTILINE)
                 .matcher(stdout);
         Matcher stderrMatcher = Pattern.compile(pattern, Pattern.MULTILINE)
@@ -205,6 +210,7 @@
             throw new RuntimeException("'" + pattern
                     + "' missing from stdout/stderr \n");
         }
+        return this;
     }
 
     /**
@@ -214,7 +220,7 @@
      * @throws RuntimeException
      *             If the pattern was not found
      */
-    public void stdoutShouldMatch(String pattern) {
+    public OutputAnalyzer stdoutShouldMatch(String pattern) {
         Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(
                 stdout);
         if (!matcher.find()) {
@@ -222,6 +228,7 @@
             throw new RuntimeException("'" + pattern
                     + "' missing from stdout \n");
         }
+        return this;
     }
 
     /**
@@ -231,7 +238,7 @@
      * @throws RuntimeException
      *             If the pattern was not found
      */
-    public void stderrShouldMatch(String pattern) {
+    public OutputAnalyzer stderrShouldMatch(String pattern) {
         Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(
                 stderr);
         if (!matcher.find()) {
@@ -239,6 +246,7 @@
             throw new RuntimeException("'" + pattern
                     + "' missing from stderr \n");
         }
+        return this;
     }
 
     /**
@@ -249,7 +257,7 @@
      * @throws RuntimeException
      *             If the pattern was found
      */
-    public void shouldNotMatch(String pattern) {
+    public OutputAnalyzer shouldNotMatch(String pattern) {
         Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(
                 stdout);
         if (matcher.find()) {
@@ -263,6 +271,7 @@
             throw new RuntimeException("'" + pattern + "' found in stderr: '"
                     + matcher.group() + "' \n");
         }
+        return this;
     }
 
     /**
@@ -273,13 +282,14 @@
      * @throws RuntimeException
      *             If the pattern was found
      */
-    public void stdoutShouldNotMatch(String pattern) {
+    public OutputAnalyzer stdoutShouldNotMatch(String pattern) {
         Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(
                 stdout);
         if (matcher.find()) {
             reportDiagnosticSummary();
             throw new RuntimeException("'" + pattern + "' found in stdout \n");
         }
+        return this;
     }
 
     /**
@@ -290,13 +300,14 @@
      * @throws RuntimeException
      *             If the pattern was found
      */
-    public void stderrShouldNotMatch(String pattern) {
+    public OutputAnalyzer stderrShouldNotMatch(String pattern) {
         Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(
                 stderr);
         if (matcher.find()) {
             reportDiagnosticSummary();
             throw new RuntimeException("'" + pattern + "' found in stderr \n");
         }
+        return this;
     }
 
     /**
@@ -344,12 +355,13 @@
      *             If the exit value from the process did not match the expected
      *             value
      */
-    public void shouldHaveExitValue(int expectedExitValue) {
+    public OutputAnalyzer shouldHaveExitValue(int expectedExitValue) {
         if (getExitValue() != expectedExitValue) {
             reportDiagnosticSummary();
             throw new RuntimeException("Expected to get exit value of ["
                     + expectedExitValue + "]\n");
         }
+        return this;
     }
 
     /**
@@ -357,11 +369,12 @@
      * - standard input produced by the process under test - standard output -
      * exit code Note: the command line is printed by the ProcessTools
      */
-    private void reportDiagnosticSummary() {
+    private OutputAnalyzer reportDiagnosticSummary() {
         String msg = " stdout: [" + stdout + "];\n" + " stderr: [" + stderr
                 + "]\n" + " exitValue = " + getExitValue() + "\n";
 
         System.err.println(msg);
+        return this;
     }
 
     /**
--- a/test/sun/security/ec/TestEC.java	Thu Sep 08 15:00:00 2016 -0700
+++ b/test/sun/security/ec/TestEC.java	Mon Sep 19 11:21:02 2016 -0700
@@ -35,7 +35,7 @@
  * @library ../pkcs11/sslecc
  * @library ../../../java/security/testlibrary
  * @compile -XDignore.symbol.file TestEC.java
- * @run main/othervm TestEC
+ * @run main/othervm -Djdk.tls.namedGroups="secp256r1,sect193r1" TestEC
  */
 
 import java.security.NoSuchProviderException;
--- a/test/sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java	Thu Sep 08 15:00:00 2016 -0700
+++ b/test/sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java	Mon Sep 19 11:21:02 2016 -0700
@@ -33,7 +33,8 @@
  * @author Andreas Sterbenz
  * @library ..
  * @library ../../../../java/security/testlibrary
- * @run main/othervm ClientJSSEServerJSSE
+ * @run main/othervm -Djdk.tls.namedGroups="secp256r1,sect193r1"
+ *      ClientJSSEServerJSSE
  */
 
 import java.security.*;
--- a/test/sun/security/ssl/javax/net/ssl/SSLParameters/UseCipherSuitesOrder.java	Thu Sep 08 15:00:00 2016 -0700
+++ b/test/sun/security/ssl/javax/net/ssl/SSLParameters/UseCipherSuitesOrder.java	Mon Sep 19 11:21:02 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, 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,7 +31,7 @@
  * @bug 7188657
  * @summary There should be a way to reorder the JSSE ciphers
  * @run main/othervm UseCipherSuitesOrder
- *     TLS_RSA_WITH_AES_128_CBC_SHA,SSL_RSA_WITH_3DES_EDE_CBC_SHA
+ *     TLS_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_RSA_WITH_AES_128_CBC_SHA
  */
 
 import java.io.*;
--- a/test/sun/security/ssl/sanity/interop/ClientJSSEServerJSSE.java	Thu Sep 08 15:00:00 2016 -0700
+++ b/test/sun/security/ssl/sanity/interop/ClientJSSEServerJSSE.java	Mon Sep 19 11:21:02 2016 -0700
@@ -26,7 +26,8 @@
  * @bug 4496785
  * @summary Verify that all ciphersuites work in all configurations
  * @author Andreas Sterbenz
- * @run main/othervm/timeout=300 ClientJSSEServerJSSE
+ * @run main/othervm/timeout=300 -Djdk.tls.namedGroups="secp256r1,secp192r1"
+ *      ClientJSSEServerJSSE
  */
 
 import java.security.Security;
--- a/test/sun/security/tools/jarsigner/warnings/Test.java	Thu Sep 08 15:00:00 2016 -0700
+++ b/test/sun/security/tools/jarsigner/warnings/Test.java	Mon Sep 19 11:21:02 2016 -0700
@@ -22,6 +22,11 @@
  */
 
 import jdk.testlibrary.OutputAnalyzer;
+import jdk.testlibrary.ProcessTools;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 
 /**
  * Base class.
@@ -175,4 +180,21 @@
         }
         analyzer.shouldContain(JAR_SIGNED);
     }
+
+    protected OutputAnalyzer keytool(String... cmd) throws Throwable {
+        return tool(KEYTOOL, cmd);
+    }
+
+    protected OutputAnalyzer jarsigner(String... cmd) throws Throwable {
+        return tool(JARSIGNER, cmd);
+    }
+
+    private OutputAnalyzer tool(String tool, String... args) throws Throwable {
+        List<String> cmd = new ArrayList<>();
+        cmd.add(tool);
+        cmd.add("-J-Duser.language=en");
+        cmd.add("-J-Duser.country=US");
+        cmd.addAll(Arrays.asList(args));
+        return ProcessTools.executeCommand(cmd.toArray(new String[cmd.size()]));
+    }
 }