Merge
diff --git a/make/rmic/Rmic-java.rmi.gmk b/make/rmic/Rmic-java.rmi.gmk
index c9b024e..7a7a464 100644
--- a/make/rmic/Rmic-java.rmi.gmk
+++ b/make/rmic/Rmic-java.rmi.gmk
@@ -40,16 +40,9 @@
     RUN_V12 := true))
 GENCLASSES += $(RMI_12)
 
-$(eval $(call SetupRMICompilation,RMI_11, \
-    CLASSES := sun.rmi.registry.RegistryImpl \
-        sun.rmi.transport.DGCImpl, \
-    CLASSES_DIR := $(CLASSES_DIR)/java.rmi, \
-    STUB_CLASSES_DIR := $(STUB_CLASSES_DIR)/java.rmi, \
-    RUN_V11 := true))
-GENCLASSES += $(RMI_11)
 
 ################################################################################
 
-all: $(RMI_11) $(RMI_12)
+all: $(RMI_12)
 
 .PHONY: all
diff --git a/src/java.base/share/classes/java/security/CodeSource.java b/src/java.base/share/classes/java/security/CodeSource.java
index 93d9983..818716f 100644
--- a/src/java.base/share/classes/java/security/CodeSource.java
+++ b/src/java.base/share/classes/java/security/CodeSource.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -560,6 +560,7 @@
     {
         CertificateFactory cf;
         Hashtable<String, CertificateFactory> cfs = null;
+        List<java.security.cert.Certificate> certList = null;
 
         ois.defaultReadObject(); // location
 
@@ -569,7 +570,7 @@
             // we know of 3 different cert types: X.509, PGP, SDSI, which
             // could all be present in the stream at the same time
             cfs = new Hashtable<>(3);
-            this.certs = new java.security.cert.Certificate[size];
+            certList = new ArrayList<>(size > 20 ? 20 : size);
         }
 
         for (int i = 0; i < size; i++) {
@@ -600,13 +601,17 @@
             ois.readFully(encoded);
             ByteArrayInputStream bais = new ByteArrayInputStream(encoded);
             try {
-                this.certs[i] = cf.generateCertificate(bais);
+                certList.add(cf.generateCertificate(bais));
             } catch (CertificateException ce) {
                 throw new IOException(ce.getMessage());
             }
             bais.close();
         }
 
+        if (certList != null) {
+            this.certs = certList.toArray(
+                    new java.security.cert.Certificate[size]);
+        }
         // Deserialize array of code signers (if any)
         try {
             this.signers = ((CodeSigner[])ois.readObject()).clone();
diff --git a/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java b/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java
index ceb9bf2..092b1b2 100644
--- a/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java
+++ b/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java
@@ -35,6 +35,9 @@
 
 package java.util.concurrent;
 
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.util.ArrayList;
 import java.util.ConcurrentModificationException;
 import java.util.HashSet;
@@ -584,6 +587,9 @@
     private static final RuntimePermission shutdownPerm =
         new RuntimePermission("modifyThread");
 
+    /* The context to be used when executing the finalizer, or null. */
+    private final AccessControlContext acc;
+
     /**
      * Class Worker mainly maintains interrupt control state for
      * threads running tasks, along with other minor bookkeeping.
@@ -1326,6 +1332,9 @@
             throw new IllegalArgumentException();
         if (workQueue == null || threadFactory == null || handler == null)
             throw new NullPointerException();
+        this.acc = System.getSecurityManager() == null ?
+                null :
+                AccessController.getContext();
         this.corePoolSize = corePoolSize;
         this.maximumPoolSize = maximumPoolSize;
         this.workQueue = workQueue;
@@ -1491,6 +1500,9 @@
      * Invokes {@code shutdown} when this executor is no longer
      * referenced and it has no threads.
      *
+     * <p>This method is invoked with privileges that are restricted by
+     * the security context of the caller that invokes the constructor.
+     *
      * @deprecated The {@code finalize} method has been deprecated.
      *     Subclasses that override {@code finalize} in order to perform cleanup
      *     should be modified to use alternative cleanup mechanisms and
@@ -1502,7 +1514,13 @@
      */
     @Deprecated(since="9")
     protected void finalize() {
-        shutdown();
+        SecurityManager sm = System.getSecurityManager();
+        if (sm == null || acc == null) {
+            shutdown();
+        } else {
+            PrivilegedAction<Void> pa = () -> { shutdown(); return null; };
+            AccessController.doPrivileged(pa, acc);
+        }
     }
 
     /**
diff --git a/src/java.base/share/classes/java/util/jar/JarVerifier.java b/src/java.base/share/classes/java/util/jar/JarVerifier.java
index 2d0f5eb..240b174 100644
--- a/src/java.base/share/classes/java/util/jar/JarVerifier.java
+++ b/src/java.base/share/classes/java/util/jar/JarVerifier.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -180,10 +180,12 @@
 
         // only set the jev object for entries that have a signature
         // (either verified or not)
-        if (sigFileSigners.get(name) != null ||
-                verifiedSigners.get(name) != null) {
-            mev.setEntry(name, je);
-            return;
+        if (!name.equals(JarFile.MANIFEST_NAME)) {
+            if (sigFileSigners.get(name) != null ||
+                    verifiedSigners.get(name) != null) {
+                mev.setEntry(name, je);
+                return;
+            }
         }
 
         // don't compute the digest for this entry
diff --git a/src/java.base/share/classes/sun/nio/ch/AsynchronousChannelGroupImpl.java b/src/java.base/share/classes/sun/nio/ch/AsynchronousChannelGroupImpl.java
index 117df24..8a88ddc 100644
--- a/src/java.base/share/classes/sun/nio/ch/AsynchronousChannelGroupImpl.java
+++ b/src/java.base/share/classes/sun/nio/ch/AsynchronousChannelGroupImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -246,13 +246,16 @@
     abstract void shutdownHandlerTasks();
 
     private void shutdownExecutors() {
-        AccessController.doPrivileged(new PrivilegedAction<>() {
-            public Void run() {
-                pool.executor().shutdown();
-                timeoutExecutor.shutdown();
-                return null;
-            }
-        });
+        AccessController.doPrivileged(
+            new PrivilegedAction<>() {
+                public Void run() {
+                    pool.executor().shutdown();
+                    timeoutExecutor.shutdown();
+                    return null;
+                }
+            },
+            null,
+            new RuntimePermission("modifyThread"));
     }
 
     @Override
diff --git a/src/java.base/share/classes/sun/security/pkcs/PKCS8Key.java b/src/java.base/share/classes/sun/security/pkcs/PKCS8Key.java
index 7cdc167..ee2c6e3 100644
--- a/src/java.base/share/classes/sun/security/pkcs/PKCS8Key.java
+++ b/src/java.base/share/classes/sun/security/pkcs/PKCS8Key.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,6 +32,7 @@
 import java.security.KeyRep;
 import java.security.PrivateKey;
 import java.security.KeyFactory;
+import java.security.MessageDigest;
 import java.security.Security;
 import java.security.Provider;
 import java.security.InvalidKeyException;
@@ -419,18 +420,9 @@
             // that encoding
             byte[] b2 = ((Key)object).getEncoded();
 
-            // do the comparison
-            int i;
-            if (b1.length != b2.length)
-                return false;
-            for (i = 0; i < b1.length; i++) {
-                if (b1[i] != b2[i]) {
-                    return false;
-                }
-            }
-            return true;
+            // time-constant comparison
+            return MessageDigest.isEqual(b1, b2);
         }
-
         return false;
     }
 
diff --git a/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java b/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java
index 6efd90d..18e32fc 100644
--- a/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java
+++ b/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java
@@ -323,6 +323,12 @@
                 data = content.getContentBytes();
             }
 
+            Timestamp timestamp = null;
+            try {
+                timestamp = getTimestamp();
+            } catch (Exception ignore) {
+            }
+
             ConstraintsParameters cparams =
                     new ConstraintsParameters(timestamp);
             String digestAlgname = getDigestAlgorithmId().getName();
diff --git a/src/java.base/share/classes/sun/security/provider/DSA.java b/src/java.base/share/classes/sun/security/provider/DSA.java
index 5763e65..9fc4785 100644
--- a/src/java.base/share/classes/sun/security/provider/DSA.java
+++ b/src/java.base/share/classes/sun/security/provider/DSA.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -64,6 +64,13 @@
     /* Are we debugging? */
     private static final boolean debug = false;
 
+    /* The number of bits used in exponent blinding */
+    private static final int BLINDING_BITS = 7;
+
+    /* The constant component of the exponent blinding value */
+    private static final BigInteger BLINDING_CONSTANT =
+        BigInteger.valueOf(1 << BLINDING_BITS);
+
     /* The parameter object */
     private DSAParams params;
 
@@ -368,8 +375,19 @@
         return null;
     }
 
+
     private BigInteger generateR(BigInteger p, BigInteger q, BigInteger g,
                          BigInteger k) {
+
+        // exponent blinding to hide information from timing channel
+        SecureRandom random = getSigningRandom();
+        // start with a random blinding component
+        BigInteger blindingValue = new BigInteger(BLINDING_BITS, random);
+        // add the fixed blinding component
+        blindingValue = blindingValue.add(BLINDING_CONSTANT);
+        // replace k with a blinded value that is congruent (mod q)
+        k = k.add(q.multiply(blindingValue));
+
         BigInteger temp = g.modPow(k, p);
         return temp.mod(q);
     }
@@ -434,43 +452,8 @@
         byte[] kValue = new byte[(q.bitLength() + 7)/8 + 8];
 
         random.nextBytes(kValue);
-        BigInteger k = new BigInteger(1, kValue).mod(
+        return new BigInteger(1, kValue).mod(
                 q.subtract(BigInteger.ONE)).add(BigInteger.ONE);
-
-        // Using an equivalent exponent of fixed length (same as q or 1 bit
-        // less than q) to keep the kG timing relatively constant.
-        //
-        // Note that this is an extra step on top of the approach defined in
-        // FIPS 186-4 AppendixB.2.1 so as to make a fixed length K.
-        k = k.add(q).divide(BigInteger.TWO);
-
-        // An alternative implementation based on FIPS 186-4 AppendixB2.2
-        // with fixed-length K.
-        //
-        // Please keep it here as we may need to switch to it in the future.
-        //
-        // SecureRandom random = getSigningRandom();
-        // byte[] kValue = new byte[(q.bitLength() + 7)/8];
-        // BigInteger d = q.subtract(BigInteger.TWO);
-        // BigInteger k;
-        // do {
-        //     random.nextBytes(kValue);
-        //     BigInteger c = new BigInteger(1, kValue);
-        //     if (c.compareTo(d) <= 0) {
-        //         k = c.add(BigInteger.ONE);
-        //         // Using an equivalent exponent of fixed length to keep
-        //         // the g^k timing relatively constant.
-        //         //
-        //         // Note that this is an extra step on top of the approach
-        //         // defined in FIPS 186-4 AppendixB.2.2 so as to make a
-        //         // fixed length K.
-        //         if (k.bitLength() >= q.bitLength()) {
-        //             break;
-        //         }
-        //     }
-        // } while (true);
-
-        return k;
     }
 
     // Use the application-specified SecureRandom Object if provided.
diff --git a/src/java.base/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java b/src/java.base/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java
index 11d8a06..5f825ff 100644
--- a/src/java.base/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java
+++ b/src/java.base/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java
@@ -344,7 +344,7 @@
 
                 // add the algorithm checker
                 checkers.add(new AlgorithmChecker(builder.trustAnchor,
-                        buildParams.date(), null));
+                        buildParams.date(), buildParams.variant()));
 
                 BasicChecker basicChecker = null;
                 if (nextState.keyParamsNeeded()) {
diff --git a/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java b/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java
index 9051b39..b763f7a 100644
--- a/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java
+++ b/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java
@@ -703,7 +703,6 @@
         private int minSize;            // the minimal available key size
         private int maxSize;            // the maximal available key size
         private int prohibitedSize = -1;    // unavailable key sizes
-        private int size;
 
         public KeySizeConstraint(String algo, Operator operator, int length) {
             algorithm = algo;
@@ -761,8 +760,9 @@
                     return;
                 }
                 throw new CertPathValidatorException(
-                        "Algorithm constraints check failed on keysize limits. "
-                        + algorithm + " " + size + "bit key" + extendedMsg(cp),
+                        "Algorithm constraints check failed on keysize limits. " +
+                        algorithm + " " + KeyUtil.getKeySize(key) + "bit key" +
+                        extendedMsg(cp),
                         null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
             }
         }
@@ -789,7 +789,7 @@
                 return true;
             }
 
-            size = KeyUtil.getKeySize(key);
+            int size = KeyUtil.getKeySize(key);
             if (size == 0) {
                 return false;    // we don't allow any key of size 0.
             } else if (size > 0) {
diff --git a/src/java.base/share/classes/sun/security/util/HostnameChecker.java b/src/java.base/share/classes/sun/security/util/HostnameChecker.java
index 145dff2..b14d36b 100644
--- a/src/java.base/share/classes/sun/security/util/HostnameChecker.java
+++ b/src/java.base/share/classes/sun/security/util/HostnameChecker.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,6 +32,7 @@
 import java.security.cert.*;
 import java.util.*;
 import javax.security.auth.x500.X500Principal;
+import javax.net.ssl.SNIHostName;
 
 import sun.net.util.IPAddressUtil;
 import sun.security.ssl.ClientKeyExchangeService;
@@ -201,6 +202,15 @@
     private void matchDNS(String expectedName, X509Certificate cert,
                           boolean chainsToPublicCA)
             throws CertificateException {
+        // Check that the expected name is a valid domain name.
+        try {
+            // Using the checking implemented in SNIHostName
+            SNIHostName sni = new SNIHostName(expectedName);
+        } catch (IllegalArgumentException iae) {
+            throw new CertificateException(
+                "Illegal given domain name: " + expectedName, iae);
+        }
+
         Collection<List<?>> subjAltNames = cert.getSubjectAlternativeNames();
         if (subjAltNames != null) {
             boolean foundDNS = false;
@@ -277,6 +287,19 @@
         if (hasIllegalWildcard(name, template, chainsToPublicCA)) {
             return false;
         }
+
+        // check the validity of the domain name template.
+        try {
+            // Replacing wildcard character '*' with 'x' so as to check
+            // the domain name template validity.
+            //
+            // Using the checking implemented in SNIHostName
+            SNIHostName sni = new SNIHostName(template.replace('*', 'x'));
+        } catch (IllegalArgumentException iae) {
+            // It would be nice to add debug log if not matching.
+            return false;
+        }
+
         if (checkType == TYPE_TLS) {
             return matchAllWildcards(name, template);
         } else if (checkType == TYPE_LDAP) {
diff --git a/src/java.base/share/classes/sun/security/util/ManifestEntryVerifier.java b/src/java.base/share/classes/sun/security/util/ManifestEntryVerifier.java
index 19cc730..6284047 100644
--- a/src/java.base/share/classes/sun/security/util/ManifestEntryVerifier.java
+++ b/src/java.base/share/classes/sun/security/util/ManifestEntryVerifier.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -107,6 +107,8 @@
         /* get the headers from the manifest for this entry */
         /* if there aren't any, we can't verify any digests for this entry */
 
+        skip = false;
+
         Attributes attr = man.getAttributes(name);
         if (attr == null) {
             // ugh. we should be able to remove this at some point.
@@ -141,7 +143,6 @@
                 }
 
                 if (digest != null) {
-                    skip = false;
                     digest.reset();
                     digests.add(digest);
                     manifestHashes.add(
@@ -197,6 +198,10 @@
             return null;
         }
 
+        if (digests.isEmpty()) {
+            throw new SecurityException("digest missing for " + name);
+        }
+
         if (signers != null)
             return signers;
 
diff --git a/src/java.base/share/conf/security/java.security b/src/java.base/share/conf/security/java.security
index a564f7c..5ddf619 100644
--- a/src/java.base/share/conf/security/java.security
+++ b/src/java.base/share/conf/security/java.security
@@ -545,21 +545,21 @@
 #     jdkCA
 #       This constraint 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.  If the jdkCA
-#       constraint is not set, then all chains using the specified algorithm
+#       trust anchor in the lib/security/cacerts keystore.  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"
+#       Example:  To apply this constraint to SHA-1 certificates, include
+#       the following:  "SHA1 jdkCA"
 #
 #   DenyAfterConstraint:
 #     denyAfter YYYY-MM-DD
 #       This constraint prohibits a certificate with the specified algorithm
 #       from being used after the date regardless of the certificate's
-#       validity.  JAR files that are signed and timestamped before the
+#       validity.  JAR files that are signed and timestamped before the
 #       constraint date with certificates containing the disabled algorithm
-#       will not be restricted.  The date is processed in the UTC timezone.
-#       This constraint can only be used once in a DisabledAlgorithm
+#       will not be restricted.  The date is processed in the UTC timezone.
+#       This constraint can only be used once in a DisabledAlgorithm
 #       expression.
 #       Example:  To deny usage of RSA 2048 bit certificates after Feb 3 2020,
 #       use the following:  "RSA keySize == 2048 & denyAfter 2020-02-03"
diff --git a/src/java.base/share/native/libverify/check_code.c b/src/java.base/share/native/libverify/check_code.c
index b278f25..e78627c 100644
--- a/src/java.base/share/native/libverify/check_code.c
+++ b/src/java.base/share/native/libverify/check_code.c
@@ -459,6 +459,8 @@
 
 static fullinfo_type cp_index_to_class_fullinfo(context_type *, int, int);
 
+static const char* get_result_signature(const char* signature);
+
 static char signature_to_fieldtype(context_type *context,
                                    const char **signature_p, fullinfo_type *info);
 
@@ -2789,7 +2791,7 @@
                                                                 operand);
             const char *result_signature;
             check_and_push(context, signature, VM_STRING_UTF);
-            result_signature = strchr(signature, JVM_SIGNATURE_ENDFUNC);
+            result_signature = get_result_signature(signature);
             if (result_signature++ == NULL) {
                 CCerror(context, "Illegal signature %s", signature);
             }
@@ -3712,6 +3714,42 @@
     longjmp(context->jump_buffer, 1);
 }
 
+/*
+ * Need to scan the entire signature to find the result type because
+ * types in the arg list and the result type could contain embedded ')'s.
+ */
+static const char* get_result_signature(const char* signature) {
+    const char *p;
+    for (p = signature; *p != JVM_SIGNATURE_ENDFUNC; p++) {
+        switch (*p) {
+          case JVM_SIGNATURE_BOOLEAN:
+          case JVM_SIGNATURE_BYTE:
+          case JVM_SIGNATURE_CHAR:
+          case JVM_SIGNATURE_SHORT:
+          case JVM_SIGNATURE_INT:
+          case JVM_SIGNATURE_FLOAT:
+          case JVM_SIGNATURE_DOUBLE:
+          case JVM_SIGNATURE_LONG:
+          case JVM_SIGNATURE_FUNC:  /* ignore initial (, if given */
+            break;
+          case JVM_SIGNATURE_CLASS:
+            while (*p != JVM_SIGNATURE_ENDCLASS) p++;
+            break;
+          case JVM_SIGNATURE_ARRAY:
+            while (*p == JVM_SIGNATURE_ARRAY) p++;
+            /* If an array of classes, skip over class name, too. */
+            if (*p == JVM_SIGNATURE_CLASS) {
+                while (*p != JVM_SIGNATURE_ENDCLASS) p++;
+            }
+            break;
+          default:
+            /* Indicate an error. */
+            return NULL;
+        }
+    }
+    return p++; /* skip over ')'. */
+}
+
 static char
 signature_to_fieldtype(context_type *context,
                        const char **signature_p, fullinfo_type *full_info_p)
diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java
index 3a1b4c1..e744095 100644
--- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java
+++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java
@@ -392,6 +392,17 @@
         }
     }
 
+    private void skipPastImage(int imageIndex) {
+        cbLock.lock();
+        try {
+            gotoImage(imageIndex);
+            skipImage();
+        } catch (IOException | IndexOutOfBoundsException e) {
+        } finally {
+            cbLock.unlock();
+        }
+    }
+
     @SuppressWarnings("fallthrough")
     private int getNumImagesOnThread(boolean allowSearch)
       throws IOException {
@@ -1340,7 +1351,8 @@
          * just a 1-line intermediate data transfer buffer that will not
          * affect the acceleration of the resulting image.
          */
-        boolean aborted = readImage(structPointer,
+        boolean aborted = readImage(imageIndex,
+                                    structPointer,
                                     buffer.getData(),
                                     numRasterBands,
                                     srcBands,
@@ -1502,7 +1514,8 @@
     /**
      * Returns {@code true} if the read was aborted.
      */
-    private native boolean readImage(long structPointer,
+    private native boolean readImage(int imageIndex,
+                                     long structPointer,
                                      byte [] buffer,
                                      int numRasterBands,
                                      int [] srcBands,
diff --git a/src/java.desktop/share/classes/javax/imageio/spi/ServiceRegistry.java b/src/java.desktop/share/classes/javax/imageio/spi/ServiceRegistry.java
index 0d87431..ae3b643 100644
--- a/src/java.desktop/share/classes/javax/imageio/spi/ServiceRegistry.java
+++ b/src/java.desktop/share/classes/javax/imageio/spi/ServiceRegistry.java
@@ -26,6 +26,9 @@
 package javax.imageio.spi;
 
 import java.io.File;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -755,13 +758,14 @@
 
     Class<?> category;
 
-    // Provider Objects organized by partial oridering
-    PartiallyOrderedSet<Object> poset = new PartiallyOrderedSet<>();
+    // Provider Objects organized by partial ordering
+    final PartiallyOrderedSet<Object> poset = new PartiallyOrderedSet<>();
 
     // Class -> Provider Object of that class
     // No way to express heterogeneous map, we want
     // Map<Class<T>, T>, where T is ?
-    Map<Class<?>, Object> map = new HashMap<>();
+    final Map<Class<?>, Object> map = new HashMap<>();
+    final Map<Class<?>, AccessControlContext> accMap = new HashMap<>();
 
     public SubRegistry(ServiceRegistry registry, Class<?> category) {
         this.registry = registry;
@@ -776,6 +780,7 @@
             deregisterServiceProvider(oprovider);
         }
         map.put(provider.getClass(), provider);
+        accMap.put(provider.getClass(), AccessController.getContext());
         poset.add(provider);
         if (provider instanceof RegisterableService) {
             RegisterableService rs = (RegisterableService)provider;
@@ -800,6 +805,7 @@
 
         if (provider == oprovider) {
             map.remove(provider.getClass());
+            accMap.remove(provider.getClass());
             poset.remove(provider);
             if (provider instanceof RegisterableService) {
                 RegisterableService rs = (RegisterableService)provider;
@@ -849,10 +855,17 @@
 
             if (provider instanceof RegisterableService) {
                 RegisterableService rs = (RegisterableService)provider;
-                rs.onDeregistration(registry, category);
+                AccessControlContext acc = accMap.get(provider.getClass());
+                if (acc != null || System.getSecurityManager() == null) {
+                    AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
+                    rs.onDeregistration(registry, category);
+                        return null;
+                    }, acc);
+                }
             }
         }
         poset.clear();
+        accMap.clear();
     }
 
     @SuppressWarnings("deprecation")
diff --git a/src/java.desktop/share/classes/sun/awt/image/ImageWatched.java b/src/java.desktop/share/classes/sun/awt/image/ImageWatched.java
index b740aa1..07d9646 100644
--- a/src/java.desktop/share/classes/sun/awt/image/ImageWatched.java
+++ b/src/java.desktop/share/classes/sun/awt/image/ImageWatched.java
@@ -29,6 +29,10 @@
 import java.awt.Image;
 import java.awt.image.ImageObserver;
 
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
 public abstract class ImageWatched {
     public static Link endlink = new Link();
 
@@ -85,16 +89,26 @@
         }
     }
 
+    static class AccWeakReference<T> extends WeakReference<T> {
+
+         private final AccessControlContext acc;
+
+         AccWeakReference(T ref) {
+             super(ref);
+             acc = AccessController.getContext();
+         }
+    }
+
     /*
      * Standard Link implementation to manage a Weak Reference
      * to an ImageObserver.
      */
     public static class WeakLink extends Link {
-        private WeakReference<ImageObserver> myref;
+        private final AccWeakReference<ImageObserver> myref;
         private Link next;
 
         public WeakLink(ImageObserver obs, Link next) {
-            myref = new WeakReference<ImageObserver>(obs);
+            myref = new AccWeakReference<ImageObserver>(obs);
             this.next = next;
         }
 
@@ -120,6 +134,19 @@
             return this;
         }
 
+        private static boolean update(ImageObserver iw, AccessControlContext acc,
+                                      Image img, int info,
+                                      int x, int y, int w, int h) {
+
+            if (acc != null || System.getSecurityManager() != null) {
+                return AccessController.doPrivileged(
+                       (PrivilegedAction<Boolean>) () -> {
+                            return iw.imageUpdate(img, info, x, y, w, h);
+                      }, acc);
+            }
+            return false;
+        }
+
         public boolean newInfo(Image img, int info,
                                int x, int y, int w, int h)
         {
@@ -129,7 +156,7 @@
             if (myiw == null) {
                 // My referent is null so we must prune in a second pass.
                 ret = true;
-            } else if (myiw.imageUpdate(img, info, x, y, w, h) == false) {
+            } else if (update(myiw, myref.acc, img, info, x, y, w, h) == false) {
                 // My referent has lost interest so clear it and ask
                 // for a pruning pass to remove it later.
                 myref.clear();
diff --git a/src/java.desktop/share/native/libjavajpeg/imageioJPEG.c b/src/java.desktop/share/native/libjavajpeg/imageioJPEG.c
index 7fe4bd9..d0c60b9 100644
--- a/src/java.desktop/share/native/libjavajpeg/imageioJPEG.c
+++ b/src/java.desktop/share/native/libjavajpeg/imageioJPEG.c
@@ -72,6 +72,7 @@
 static jmethodID JPEGImageReader_pushBackID;
 static jmethodID JPEGImageReader_passStartedID;
 static jmethodID JPEGImageReader_passCompleteID;
+static jmethodID JPEGImageReader_skipPastImageID;
 static jmethodID JPEGImageWriter_writeOutputDataID;
 static jmethodID JPEGImageWriter_warningOccurredID;
 static jmethodID JPEGImageWriter_warningWithMessageID;
@@ -1472,6 +1473,10 @@
                                                      cls,
                                                      "pushBack",
                                                      "(I)V"));
+    CHECK_NULL(JPEGImageReader_skipPastImageID = (*env)->GetMethodID(env,
+                                                     cls,
+                                                     "skipPastImage",
+                                                     "(I)V"));
     CHECK_NULL(JPEGQTable_tableID = (*env)->GetFieldID(env,
                                             qTableClass,
                                             "qTable",
@@ -1853,6 +1858,7 @@
 Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImage
     (JNIEnv *env,
      jobject this,
+     jint imageIndex,
      jlong ptr,
      jbyteArray buffer,
      jint numBands,
@@ -2181,12 +2187,23 @@
      * We are done, but we might not have read all the lines, or all
      * the passes, so use jpeg_abort instead of jpeg_finish_decompress.
      */
-    if (cinfo->output_scanline == cinfo->output_height) {
-        //    if ((cinfo->output_scanline == cinfo->output_height) &&
-        //(jpeg_input_complete(cinfo))) {  // We read the whole file
-        jpeg_finish_decompress(cinfo);
-    } else {
+    if ((cinfo->output_scanline != cinfo->output_height) ||
+        data->abortFlag == JNI_TRUE)
+     {
         jpeg_abort_decompress(cinfo);
+     } else if ((!jpeg_input_complete(cinfo)) &&
+                (progressive &&
+                 (cinfo->input_scan_number > maxProgressivePass))) {
+        /* We haven't reached EOI, but we need to skip to there */
+        (*cinfo->src->term_source) (cinfo);
+        /* We can use jpeg_abort to release memory and reset global_state */
+        jpeg_abort((j_common_ptr) cinfo);
+        (*env)->CallVoidMethod(env,
+                               this,
+                               JPEGImageReader_skipPastImageID,
+                               imageIndex);
+    } else {
+        jpeg_finish_decompress(cinfo);
     }
 
     free(scanLinePtr);
diff --git a/src/java.naming/share/classes/com/sun/jndi/ldap/LdapClient.java b/src/java.naming/share/classes/com/sun/jndi/ldap/LdapClient.java
index c615971..125530f 100644
--- a/src/java.naming/share/classes/com/sun/jndi/ldap/LdapClient.java
+++ b/src/java.naming/share/classes/com/sun/jndi/ldap/LdapClient.java
@@ -1234,6 +1234,7 @@
     static final int LDAP_REF_FOLLOW = 0x01;            // follow referrals
     static final int LDAP_REF_THROW = 0x02;             // throw referral ex.
     static final int LDAP_REF_IGNORE = 0x03;            // ignore referrals
+    static final int LDAP_REF_FOLLOW_SCHEME = 0x04;     // follow referrals of the same scheme
 
     static final String LDAP_URL = "ldap://";           // LDAPv3
     static final String LDAPS_URL = "ldaps://";         // LDAPv3
diff --git a/src/java.naming/share/classes/com/sun/jndi/ldap/LdapCtx.java b/src/java.naming/share/classes/com/sun/jndi/ldap/LdapCtx.java
index 6484c39..88185a0 100644
--- a/src/java.naming/share/classes/com/sun/jndi/ldap/LdapCtx.java
+++ b/src/java.naming/share/classes/com/sun/jndi/ldap/LdapCtx.java
@@ -2414,6 +2414,9 @@
         // First determine the referral mode
         if (ref != null) {
             switch (ref) {
+                case "follow-scheme":
+                    handleReferrals = LdapClient.LDAP_REF_FOLLOW_SCHEME;
+                    break;
                 case "follow":
                     handleReferrals = LdapClient.LDAP_REF_FOLLOW;
                     break;
@@ -2979,8 +2982,23 @@
             r = new LdapReferralException(resolvedName, resolvedObj, remainName,
                 msg, envprops, fullDN, handleReferrals, reqCtls);
             // only one set of URLs is present
-            r.setReferralInfo(res.referrals == null ? null :
-                    res.referrals.elementAt(0), false);
+            Vector<String> refs;
+            if (res.referrals == null) {
+                refs = null;
+            } else if (handleReferrals == LdapClient.LDAP_REF_FOLLOW_SCHEME) {
+                refs = new Vector<>();
+                for (String s : res.referrals.elementAt(0)) {
+                    if (s.startsWith("ldap:")) {
+                        refs.add(s);
+                    }
+                }
+                if (refs.isEmpty()) {
+                    refs = null;
+                }
+            } else {
+                refs = res.referrals.elementAt(0);
+            }
+            r.setReferralInfo(refs, false);
 
             if (hopCount > 1) {
                 r.setHopCount(hopCount);
diff --git a/src/java.naming/share/classes/com/sun/jndi/ldap/LdapReferralException.java b/src/java.naming/share/classes/com/sun/jndi/ldap/LdapReferralException.java
index 62437c7..eb74e63 100644
--- a/src/java.naming/share/classes/com/sun/jndi/ldap/LdapReferralException.java
+++ b/src/java.naming/share/classes/com/sun/jndi/ldap/LdapReferralException.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -117,7 +117,8 @@
 
         // If following referral, request controls are passed to referral ctx
         this.reqCtls =
-            (handleReferrals == LdapClient.LDAP_REF_FOLLOW ? reqCtls : null);
+            (handleReferrals == LdapClient.LDAP_REF_FOLLOW ||
+                    handleReferrals == LdapClient.LDAP_REF_FOLLOW_SCHEME ? reqCtls : null);
     }
 
     /**
diff --git a/src/java.naming/share/classes/javax/naming/directory/BasicAttribute.java b/src/java.naming/share/classes/javax/naming/directory/BasicAttribute.java
index 41ab918..868fac6 100644
--- a/src/java.naming/share/classes/javax/naming/directory/BasicAttribute.java
+++ b/src/java.naming/share/classes/javax/naming/directory/BasicAttribute.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -515,7 +515,7 @@
             throws java.io.IOException, ClassNotFoundException {
         s.defaultReadObject();  // read in the attrID
         int n = s.readInt();    // number of values
-        values = new Vector<>(n);
+        values = new Vector<>(Math.min(1024, n));
         while (--n >= 0) {
             values.addElement(s.readObject());
         }
diff --git a/src/java.naming/share/classes/sun/security/provider/certpath/ldap/LDAPCertStoreImpl.java b/src/java.naming/share/classes/sun/security/provider/certpath/ldap/LDAPCertStoreImpl.java
index 1b9a2b0..8813ff6 100644
--- a/src/java.naming/share/classes/sun/security/provider/certpath/ldap/LDAPCertStoreImpl.java
+++ b/src/java.naming/share/classes/sun/security/provider/certpath/ldap/LDAPCertStoreImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -186,7 +186,7 @@
              */
             Hashtable<?,?> currentEnv = ctx.getEnvironment();
             if (currentEnv.get(Context.REFERRAL) == null) {
-                ctx.addToEnvironment(Context.REFERRAL, "follow");
+                ctx.addToEnvironment(Context.REFERRAL, "follow-scheme");
             }
         } catch (NamingException e) {
             if (debug != null) {
diff --git a/src/java.rmi/share/classes/java/rmi/activation/ActivationID.java b/src/java.rmi/share/classes/java/rmi/activation/ActivationID.java
index 13b3a06..a7b2f99 100644
--- a/src/java.rmi/share/classes/java/rmi/activation/ActivationID.java
+++ b/src/java.rmi/share/classes/java/rmi/activation/ActivationID.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -40,6 +40,12 @@
 import java.rmi.server.RemoteObjectInvocationHandler;
 import java.rmi.server.RemoteRef;
 import java.rmi.server.UID;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.Permissions;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.security.ProtectionDomain;
 
 /**
  * Activation makes use of special identifiers to denote remote
@@ -81,6 +87,14 @@
     /** indicate compatibility with the Java 2 SDK v1.2 version of class */
     private static final long serialVersionUID = -4608673054848209235L;
 
+    /** an AccessControlContext with no permissions */
+    private static final AccessControlContext NOPERMS_ACC;
+    static {
+        Permissions perms = new Permissions();
+        ProtectionDomain[] pd = { new ProtectionDomain(null, perms) };
+        NOPERMS_ACC = new AccessControlContext(pd);
+    }
+
     /**
      * The constructor for <code>ActivationID</code> takes a single
      * argument, activator, that specifies a remote reference to the
@@ -116,13 +130,19 @@
         try {
             MarshalledObject<? extends Remote> mobj =
                 activator.activate(this, force);
-            return mobj.get();
-        } catch (RemoteException e) {
-            throw e;
-        } catch (IOException e) {
-            throw new UnmarshalException("activation failed", e);
-        } catch (ClassNotFoundException e) {
-            throw new UnmarshalException("activation failed", e);
+            return AccessController.doPrivileged(
+                new PrivilegedExceptionAction<Remote>() {
+                    public Remote run() throws IOException, ClassNotFoundException {
+                        return mobj.get();
+                    }
+                }, NOPERMS_ACC);
+        } catch (PrivilegedActionException pae) {
+            Exception ex = pae.getException();
+            if (ex instanceof RemoteException) {
+                throw (RemoteException) ex;
+            } else {
+                throw new UnmarshalException("activation failed", ex);
+            }
         }
 
     }
diff --git a/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl.java b/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl.java
index 6b75a2a..af012fa 100644
--- a/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl.java
+++ b/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl.java
@@ -75,6 +75,10 @@
  * registry.
  *
  * The LocateRegistry class is used to obtain registry for different hosts.
+ * <p>
+ * The default RegistryImpl exported restricts access to clients on the local host
+ * for the methods {@link #bind}, {@link #rebind}, {@link #unbind} by checking
+ * the client host in the skeleton.
  *
  * @see java.rmi.registry.LocateRegistry
  */
@@ -144,13 +148,27 @@
                         RMIServerSocketFactory ssf)
         throws RemoteException
     {
+        this(port, csf, ssf, RegistryImpl::registryFilter);
+    }
+
+
+    /**
+     * Construct a new RegistryImpl on the specified port with the
+     * given custom socket factory pair and ObjectInputFilter.
+     */
+    public RegistryImpl(int port,
+                        RMIClientSocketFactory csf,
+                        RMIServerSocketFactory ssf,
+                        ObjectInputFilter serialFilter)
+        throws RemoteException
+    {
         if (port == Registry.REGISTRY_PORT && System.getSecurityManager() != null) {
             // grant permission for default port only.
             try {
                 AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
                     public Void run() throws RemoteException {
                         LiveRef lref = new LiveRef(id, port, csf, ssf);
-                        setup(new UnicastServerRef2(lref, RegistryImpl::registryFilter));
+                        setup(new UnicastServerRef2(lref, serialFilter));
                         return null;
                     }
                 }, null, new SocketPermission("localhost:"+port, "listen,accept"));
@@ -226,7 +244,8 @@
     public void bind(String name, Remote obj)
         throws RemoteException, AlreadyBoundException, AccessException
     {
-        checkAccess("Registry.bind");
+        // The access check preventing remote access is done in the skeleton
+        // and is not applicable to local access.
         synchronized (bindings) {
             Remote curr = bindings.get(name);
             if (curr != null)
@@ -243,7 +262,8 @@
     public void unbind(String name)
         throws RemoteException, NotBoundException, AccessException
     {
-        checkAccess("Registry.unbind");
+        // The access check preventing remote access is done in the skeleton
+        // and is not applicable to local access.
         synchronized (bindings) {
             Remote obj = bindings.get(name);
             if (obj == null)
@@ -259,7 +279,8 @@
     public void rebind(String name, Remote obj)
         throws RemoteException, AccessException
     {
-        checkAccess("Registry.rebind");
+        // The access check preventing remote access is done in the skeleton
+        // and is not applicable to local access.
         bindings.put(name, obj);
     }
 
@@ -312,7 +333,7 @@
 
                 if (clientHost.isAnyLocalAddress()) {
                     throw new AccessException(
-                        "Registry." + op + " disallowed; origin unknown");
+                        op + " disallowed; origin unknown");
                 }
 
                 try {
@@ -335,7 +356,7 @@
                     // must have been an IOException
 
                     throw new AccessException(
-                        "Registry." + op + " disallowed; origin " +
+                        op + " disallowed; origin " +
                         clientHost + " is non-local host");
                 }
             }
@@ -344,8 +365,7 @@
              * Local call from this VM: allow access.
              */
         } catch (java.net.UnknownHostException ex) {
-            throw new AccessException("Registry." + op +
-                                      " disallowed; origin is unknown host");
+            throw new AccessException(op + " disallowed; origin is unknown host");
         }
     }
 
diff --git a/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Skel.java b/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Skel.java
new file mode 100644
index 0000000..842d477
--- /dev/null
+++ b/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Skel.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package sun.rmi.registry;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.rmi.AccessException;
+import java.rmi.server.RemoteCall;
+
+import sun.rmi.transport.Connection;
+import sun.rmi.transport.StreamRemoteCall;
+import sun.rmi.transport.tcp.TCPConnection;
+
+/**
+ * Skeleton to dispatch RegistryImpl methods.
+ * Originally generated by RMIC but frozen to match the stubs.
+ */
+@SuppressWarnings({"deprecation", "serial"})
+public final class RegistryImpl_Skel
+        implements java.rmi.server.Skeleton {
+    private static final java.rmi.server.Operation[] operations = {
+            new java.rmi.server.Operation("void bind(java.lang.String, java.rmi.Remote)"),
+            new java.rmi.server.Operation("java.lang.String list()[]"),
+            new java.rmi.server.Operation("java.rmi.Remote lookup(java.lang.String)"),
+            new java.rmi.server.Operation("void rebind(java.lang.String, java.rmi.Remote)"),
+            new java.rmi.server.Operation("void unbind(java.lang.String)")
+    };
+
+    private static final long interfaceHash = 4905912898345647071L;
+
+    public java.rmi.server.Operation[] getOperations() {
+        return operations.clone();
+    }
+
+    public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall call, int opnum, long hash)
+            throws java.lang.Exception {
+        if (hash != interfaceHash)
+            throw new java.rmi.server.SkeletonMismatchException("interface hash mismatch");
+
+        sun.rmi.registry.RegistryImpl server = (sun.rmi.registry.RegistryImpl) obj;
+        switch (opnum) {
+            case 0: // bind(String, Remote)
+            {
+                // Check access before reading the arguments
+                RegistryImpl.checkAccess("Registry.bind");
+
+                java.lang.String $param_String_1;
+                java.rmi.Remote $param_Remote_2;
+                try {
+                    java.io.ObjectInput in = call.getInputStream();
+                    $param_String_1 = (java.lang.String) in.readObject();
+                    $param_Remote_2 = (java.rmi.Remote) in.readObject();
+                } catch (java.io.IOException | java.lang.ClassNotFoundException e) {
+                    throw new java.rmi.UnmarshalException("error unmarshalling arguments", e);
+                } finally {
+                    call.releaseInputStream();
+                }
+                server.bind($param_String_1, $param_Remote_2);
+                try {
+                    call.getResultStream(true);
+                } catch (java.io.IOException e) {
+                    throw new java.rmi.MarshalException("error marshalling return", e);
+                }
+                break;
+            }
+
+            case 1: // list()
+            {
+                call.releaseInputStream();
+                java.lang.String[] $result = server.list();
+                try {
+                    java.io.ObjectOutput out = call.getResultStream(true);
+                    out.writeObject($result);
+                } catch (java.io.IOException e) {
+                    throw new java.rmi.MarshalException("error marshalling return", e);
+                }
+                break;
+            }
+
+            case 2: // lookup(String)
+            {
+                java.lang.String $param_String_1;
+                try {
+                    java.io.ObjectInput in = call.getInputStream();
+                    $param_String_1 = (java.lang.String) in.readObject();
+                } catch (java.io.IOException | java.lang.ClassNotFoundException e) {
+                    throw new java.rmi.UnmarshalException("error unmarshalling arguments", e);
+                } finally {
+                    call.releaseInputStream();
+                }
+                java.rmi.Remote $result = server.lookup($param_String_1);
+                try {
+                    java.io.ObjectOutput out = call.getResultStream(true);
+                    out.writeObject($result);
+                } catch (java.io.IOException e) {
+                    throw new java.rmi.MarshalException("error marshalling return", e);
+                }
+                break;
+            }
+
+            case 3: // rebind(String, Remote)
+            {
+                // Check access before reading the arguments
+                RegistryImpl.checkAccess("Registry.rebind");
+
+                java.lang.String $param_String_1;
+                java.rmi.Remote $param_Remote_2;
+                try {
+                    java.io.ObjectInput in = call.getInputStream();
+                    $param_String_1 = (java.lang.String) in.readObject();
+                    $param_Remote_2 = (java.rmi.Remote) in.readObject();
+                } catch (java.io.IOException | java.lang.ClassNotFoundException e) {
+                    throw new java.rmi.UnmarshalException("error unmarshalling arguments", e);
+                } finally {
+                    call.releaseInputStream();
+                }
+                server.rebind($param_String_1, $param_Remote_2);
+                try {
+                    call.getResultStream(true);
+                } catch (java.io.IOException e) {
+                    throw new java.rmi.MarshalException("error marshalling return", e);
+                }
+                break;
+            }
+
+            case 4: // unbind(String)
+            {
+                // Check access before reading the arguments
+                RegistryImpl.checkAccess("Registry.unbind");
+
+                java.lang.String $param_String_1;
+                try {
+                    java.io.ObjectInput in = call.getInputStream();
+                    $param_String_1 = (java.lang.String) in.readObject();
+                } catch (java.io.IOException | java.lang.ClassNotFoundException e) {
+                    throw new java.rmi.UnmarshalException("error unmarshalling arguments", e);
+                } finally {
+                    call.releaseInputStream();
+                }
+                server.unbind($param_String_1);
+                try {
+                    call.getResultStream(true);
+                } catch (java.io.IOException e) {
+                    throw new java.rmi.MarshalException("error marshalling return", e);
+                }
+                break;
+            }
+
+            default:
+                throw new java.rmi.UnmarshalException("invalid method number");
+        }
+    }
+}
diff --git a/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Stub.java b/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Stub.java
new file mode 100644
index 0000000..f857486
--- /dev/null
+++ b/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Stub.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.rmi.registry;
+/**
+ * Stubs to invoke RegistryImpl remote methods.
+ * Originally generated from RMIC but frozen to match RegistryImpl_Skel.
+ */
+@SuppressWarnings({"deprecation", "serial"})
+public final class RegistryImpl_Stub
+        extends java.rmi.server.RemoteStub
+        implements java.rmi.registry.Registry, java.rmi.Remote {
+    private static final java.rmi.server.Operation[] operations = {
+            new java.rmi.server.Operation("void bind(java.lang.String, java.rmi.Remote)"),
+            new java.rmi.server.Operation("java.lang.String list()[]"),
+            new java.rmi.server.Operation("java.rmi.Remote lookup(java.lang.String)"),
+            new java.rmi.server.Operation("void rebind(java.lang.String, java.rmi.Remote)"),
+            new java.rmi.server.Operation("void unbind(java.lang.String)")
+    };
+
+    private static final long interfaceHash = 4905912898345647071L;
+
+    // constructors
+    public RegistryImpl_Stub() {
+        super();
+    }
+
+    public RegistryImpl_Stub(java.rmi.server.RemoteRef ref) {
+        super(ref);
+    }
+
+    // methods from remote interfaces
+
+    // implementation of bind(String, Remote)
+    public void bind(java.lang.String $param_String_1, java.rmi.Remote $param_Remote_2)
+            throws java.rmi.AccessException, java.rmi.AlreadyBoundException, java.rmi.RemoteException {
+        try {
+            java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 0, interfaceHash);
+            try {
+                java.io.ObjectOutput out = call.getOutputStream();
+                out.writeObject($param_String_1);
+                out.writeObject($param_Remote_2);
+            } catch (java.io.IOException e) {
+                throw new java.rmi.MarshalException("error marshalling arguments", e);
+            }
+            ref.invoke(call);
+            ref.done(call);
+        } catch (java.lang.RuntimeException e) {
+            throw e;
+        } catch (java.rmi.RemoteException e) {
+            throw e;
+        } catch (java.rmi.AlreadyBoundException e) {
+            throw e;
+        } catch (java.lang.Exception e) {
+            throw new java.rmi.UnexpectedException("undeclared checked exception", e);
+        }
+    }
+
+    // implementation of list()
+    public java.lang.String[] list()
+            throws java.rmi.AccessException, java.rmi.RemoteException {
+        try {
+            java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 1, interfaceHash);
+            ref.invoke(call);
+            java.lang.String[] $result;
+            try {
+                java.io.ObjectInput in = call.getInputStream();
+                $result = (java.lang.String[]) in.readObject();
+            } catch (java.io.IOException e) {
+                throw new java.rmi.UnmarshalException("error unmarshalling return", e);
+            } catch (java.lang.ClassNotFoundException e) {
+                throw new java.rmi.UnmarshalException("error unmarshalling return", e);
+            } finally {
+                ref.done(call);
+            }
+            return $result;
+        } catch (java.lang.RuntimeException e) {
+            throw e;
+        } catch (java.rmi.RemoteException e) {
+            throw e;
+        } catch (java.lang.Exception e) {
+            throw new java.rmi.UnexpectedException("undeclared checked exception", e);
+        }
+    }
+
+    // implementation of lookup(String)
+    public java.rmi.Remote lookup(java.lang.String $param_String_1)
+            throws java.rmi.AccessException, java.rmi.NotBoundException, java.rmi.RemoteException {
+        try {
+            java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 2, interfaceHash);
+            try {
+                java.io.ObjectOutput out = call.getOutputStream();
+                out.writeObject($param_String_1);
+            } catch (java.io.IOException e) {
+                throw new java.rmi.MarshalException("error marshalling arguments", e);
+            }
+            ref.invoke(call);
+            java.rmi.Remote $result;
+            try {
+                java.io.ObjectInput in = call.getInputStream();
+                $result = (java.rmi.Remote) in.readObject();
+            } catch (java.io.IOException e) {
+                throw new java.rmi.UnmarshalException("error unmarshalling return", e);
+            } catch (java.lang.ClassNotFoundException e) {
+                throw new java.rmi.UnmarshalException("error unmarshalling return", e);
+            } finally {
+                ref.done(call);
+            }
+            return $result;
+        } catch (java.lang.RuntimeException e) {
+            throw e;
+        } catch (java.rmi.RemoteException e) {
+            throw e;
+        } catch (java.rmi.NotBoundException e) {
+            throw e;
+        } catch (java.lang.Exception e) {
+            throw new java.rmi.UnexpectedException("undeclared checked exception", e);
+        }
+    }
+
+    // implementation of rebind(String, Remote)
+    public void rebind(java.lang.String $param_String_1, java.rmi.Remote $param_Remote_2)
+            throws java.rmi.AccessException, java.rmi.RemoteException {
+        try {
+            java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 3, interfaceHash);
+            try {
+                java.io.ObjectOutput out = call.getOutputStream();
+                out.writeObject($param_String_1);
+                out.writeObject($param_Remote_2);
+            } catch (java.io.IOException e) {
+                throw new java.rmi.MarshalException("error marshalling arguments", e);
+            }
+            ref.invoke(call);
+            ref.done(call);
+        } catch (java.lang.RuntimeException e) {
+            throw e;
+        } catch (java.rmi.RemoteException e) {
+            throw e;
+        } catch (java.lang.Exception e) {
+            throw new java.rmi.UnexpectedException("undeclared checked exception", e);
+        }
+    }
+
+    // implementation of unbind(String)
+    public void unbind(java.lang.String $param_String_1)
+            throws java.rmi.AccessException, java.rmi.NotBoundException, java.rmi.RemoteException {
+        try {
+            java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 4, interfaceHash);
+            try {
+                java.io.ObjectOutput out = call.getOutputStream();
+                out.writeObject($param_String_1);
+            } catch (java.io.IOException e) {
+                throw new java.rmi.MarshalException("error marshalling arguments", e);
+            }
+            ref.invoke(call);
+            ref.done(call);
+        } catch (java.lang.RuntimeException e) {
+            throw e;
+        } catch (java.rmi.RemoteException e) {
+            throw e;
+        } catch (java.rmi.NotBoundException e) {
+            throw e;
+        } catch (java.lang.Exception e) {
+            throw new java.rmi.UnexpectedException("undeclared checked exception", e);
+        }
+    }
+}
diff --git a/src/java.rmi/share/classes/sun/rmi/server/Activation.java b/src/java.rmi/share/classes/sun/rmi/server/Activation.java
index a6ebbca..6c60f46 100644
--- a/src/java.rmi/share/classes/sun/rmi/server/Activation.java
+++ b/src/java.rmi/share/classes/sun/rmi/server/Activation.java
@@ -30,6 +30,7 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.ObjectInput;
 import java.io.ObjectInputStream;
 import java.io.OutputStream;
 import java.io.PrintStream;
@@ -105,7 +106,6 @@
 import sun.rmi.log.ReliableLog;
 import sun.rmi.registry.RegistryImpl;
 import sun.rmi.runtime.NewThreadAction;
-import sun.rmi.server.UnicastServerRef;
 import sun.rmi.transport.LiveRef;
 import sun.security.provider.PolicyFile;
 import com.sun.rmi.rmid.ExecPermission;
@@ -375,6 +375,7 @@
                 throw new AccessException(
                     "binding ActivationSystem is disallowed");
             } else {
+                RegistryImpl.checkAccess("ActivationSystem.bind");
                 super.bind(name, obj);
             }
         }
@@ -386,6 +387,7 @@
                 throw new AccessException(
                     "unbinding ActivationSystem is disallowed");
             } else {
+                RegistryImpl.checkAccess("ActivationSystem.unbind");
                 super.unbind(name);
             }
         }
@@ -398,6 +400,7 @@
                 throw new AccessException(
                     "binding ActivationSystem is disallowed");
             } else {
+                RegistryImpl.checkAccess("ActivationSystem.rebind");
                 super.rebind(name, obj);
             }
         }
@@ -488,6 +491,33 @@
     }
 
 
+    /**
+     * SameHostOnlyServerRef checks that access is from a local client
+     * before the parameters are deserialized.  The unmarshalCustomCallData
+     * hook is used to check the network address of the caller
+     * with RegistryImpl.checkAccess().
+     * The kind of access is retained for an exception if one is thrown.
+     */
+    static class SameHostOnlyServerRef extends UnicastServerRef {
+        private static final long serialVersionUID = 1234L;
+        private String accessKind;      // an exception message
+
+        /**
+         * Construct a new SameHostOnlyServerRef from a LiveRef.
+         * @param lref a LiveRef
+         */
+        SameHostOnlyServerRef(LiveRef lref, String accessKind) {
+            super(lref);
+            this.accessKind = accessKind;
+        }
+
+        @Override
+        protected void unmarshalCustomCallData(ObjectInput in) throws IOException, ClassNotFoundException {
+            RegistryImpl.checkAccess(accessKind);
+            super.unmarshalCustomCallData(in);
+        }
+    }
+
     class ActivationSystemImpl
         extends RemoteServer
         implements ActivationSystem
@@ -505,7 +535,8 @@
              * 'this' can be exported.
              */
             LiveRef lref = new LiveRef(new ObjID(4), port, null, ssf);
-            UnicastServerRef uref = new UnicastServerRef(lref);
+            UnicastServerRef uref = new SameHostOnlyServerRef(lref,
+                    "ActivationSystem.nonLocalAccess");
             ref = uref;
             uref.exportObject(this, null);
         }
@@ -514,8 +545,8 @@
             throws ActivationException, UnknownGroupException, RemoteException
         {
             checkShutdown();
-            RegistryImpl.checkAccess("ActivationSystem.registerObject");
-
+            // RegistryImpl.checkAccess() is done in the SameHostOnlyServerRef
+            // during unmarshallCustomData and is not applicable to local access.
             ActivationGroupID groupID = desc.getGroupID();
             ActivationID id = new ActivationID(activatorStub);
             getGroupEntry(groupID).registerObject(id, desc, true);
@@ -526,7 +557,8 @@
             throws ActivationException, UnknownObjectException, RemoteException
         {
             checkShutdown();
-            RegistryImpl.checkAccess("ActivationSystem.unregisterObject");
+            // RegistryImpl.checkAccess() is done in the SameHostOnlyServerRef
+            // during unmarshallCustomData and is not applicable to local access.
             getGroupEntry(id).unregisterObject(id, true);
         }
 
@@ -534,7 +566,8 @@
             throws ActivationException, RemoteException
         {
             checkShutdown();
-            RegistryImpl.checkAccess("ActivationSystem.registerGroup");
+            // RegistryImpl.checkAccess() is done in the SameHostOnlyServerRef
+            // during unmarshallCustomData and is not applicable to local access.
             checkArgs(desc, null);
 
             ActivationGroupID id = new ActivationGroupID(systemStub);
@@ -551,7 +584,8 @@
             throws ActivationException, UnknownGroupException, RemoteException
         {
             checkShutdown();
-            RegistryImpl.checkAccess("ActivationSystem.activeGroup");
+            // RegistryImpl.checkAccess() is done in the SameHostOnlyServerRef
+            // during unmarshallCustomData and is not applicable to local access.
 
             getGroupEntry(id).activeGroup(group, incarnation);
             return monitor;
@@ -561,7 +595,8 @@
             throws ActivationException, UnknownGroupException, RemoteException
         {
             checkShutdown();
-            RegistryImpl.checkAccess("ActivationSystem.unregisterGroup");
+            // RegistryImpl.checkAccess() is done in the SameHostOnlyServerRef
+            // during unmarshallCustomData and is not applicable to local access.
 
             // remove entry before unregister so state is updated before
             // logged
@@ -573,7 +608,8 @@
             throws ActivationException, UnknownObjectException, RemoteException
         {
             checkShutdown();
-            RegistryImpl.checkAccess("ActivationSystem.setActivationDesc");
+            // RegistryImpl.checkAccess() is done in the SameHostOnlyServerRef
+            // during unmarshallCustomData and is not applicable to local access.
 
             if (!getGroupID(id).equals(desc.getGroupID())) {
                 throw new ActivationException(
@@ -587,8 +623,8 @@
             throws ActivationException, UnknownGroupException, RemoteException
         {
             checkShutdown();
-            RegistryImpl.checkAccess(
-                "ActivationSystem.setActivationGroupDesc");
+            // RegistryImpl.checkAccess() is done in the SameHostOnlyServerRef
+            // during unmarshallCustomData and is not applicable to local access.
 
             checkArgs(desc, null);
             return getGroupEntry(id).setActivationGroupDesc(id, desc, true);
@@ -598,7 +634,8 @@
             throws ActivationException, UnknownObjectException, RemoteException
         {
             checkShutdown();
-            RegistryImpl.checkAccess("ActivationSystem.getActivationDesc");
+            // RegistryImpl.checkAccess() is done in the SameHostOnlyServerRef
+            // during unmarshallCustomData and is not applicable to local access.
 
             return getGroupEntry(id).getActivationDesc(id);
         }
@@ -607,8 +644,8 @@
             throws ActivationException, UnknownGroupException, RemoteException
         {
             checkShutdown();
-            RegistryImpl.checkAccess
-                ("ActivationSystem.getActivationGroupDesc");
+            // RegistryImpl.checkAccess() is done in the SameHostOnlyServerRef
+            // during unmarshallCustomData and is not applicable to local access.
 
             return getGroupEntry(id).desc;
         }
@@ -618,7 +655,8 @@
          * the activation daemon and exits the activation daemon.
          */
         public void shutdown() throws AccessException {
-            RegistryImpl.checkAccess("ActivationSystem.shutdown");
+            // RegistryImpl.checkAccess() is done in the SameHostOnlyServerRef
+            // during unmarshallCustomData and is not applicable to local access.
 
             Object lock = startupLock;
             if (lock != null) {
diff --git a/src/java.rmi/share/classes/sun/rmi/server/UnicastRef.java b/src/java.rmi/share/classes/sun/rmi/server/UnicastRef.java
index a581235..6b9aec5 100644
--- a/src/java.rmi/share/classes/sun/rmi/server/UnicastRef.java
+++ b/src/java.rmi/share/classes/sun/rmi/server/UnicastRef.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,7 +32,6 @@
 import java.rmi.MarshalException;
 import java.rmi.Remote;
 import java.rmi.RemoteException;
-import java.rmi.ServerException;
 import java.rmi.UnmarshalException;
 import java.rmi.server.Operation;
 import java.rmi.server.RemoteCall;
@@ -187,14 +186,11 @@
 
                 return returnValue;
 
-            } catch (IOException e) {
+            } catch (IOException | ClassNotFoundException e) {
+                // disable saving any refs in the inputStream for GC
+                ((StreamRemoteCall)call).discardPendingRefs();
                 clientRefLog.log(Log.BRIEF,
-                                 "IOException unmarshalling return: ", e);
-                throw new UnmarshalException("error unmarshalling return", e);
-            } catch (ClassNotFoundException e) {
-                clientRefLog.log(Log.BRIEF,
-                    "ClassNotFoundException unmarshalling return: ", e);
-
+                                 e.getClass().getName() + " unmarshalling return: ", e);
                 throw new UnmarshalException("error unmarshalling return", e);
             } finally {
                 try {
diff --git a/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java b/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java
index 65437b7..f0a4e0f 100644
--- a/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java
+++ b/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,6 +33,7 @@
 import java.io.ObjectStreamClass;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.rmi.AccessException;
 import java.rmi.MarshalException;
 import java.rmi.Remote;
 import java.rmi.RemoteException;
@@ -57,6 +58,7 @@
 import java.util.concurrent.atomic.AtomicInteger;
 import sun.rmi.runtime.Log;
 import sun.rmi.transport.LiveRef;
+import sun.rmi.transport.StreamRemoteCall;
 import sun.rmi.transport.Target;
 import sun.rmi.transport.tcp.TCPTransport;
 
@@ -287,21 +289,26 @@
             try {
                 in = call.getInputStream();
                 num = in.readInt();
-                if (num >= 0) {
-                    if (skel != null) {
-                        oldDispatch(obj, call, num);
-                        return;
-                    } else {
-                        throw new UnmarshalException(
-                            "skeleton class not found but required " +
-                            "for client version");
-                    }
-                }
-                op = in.readLong();
             } catch (Exception readEx) {
                 throw new UnmarshalException("error unmarshalling call header",
                                              readEx);
             }
+            if (num >= 0) {
+                if (skel != null) {
+                    oldDispatch(obj, call, num);
+                    return;
+                } else {
+                    throw new UnmarshalException(
+                        "skeleton class not found but required " +
+                        "for client version");
+                }
+            }
+            try {
+                op = in.readLong();
+            } catch (Exception readEx) {
+                throw new UnmarshalException("error unmarshalling call header",
+                        readEx);
+            }
 
             /*
              * Since only system classes (with null class loaders) will be on
@@ -328,10 +335,14 @@
             try {
                 unmarshalCustomCallData(in);
                 params = unmarshalParameters(obj, method, marshalStream);
-            } catch (java.io.IOException e) {
-                throw new UnmarshalException(
-                    "error unmarshalling arguments", e);
-            } catch (ClassNotFoundException e) {
+            } catch (AccessException aex) {
+                // For compatibility, AccessException is not wrapped in UnmarshalException
+                // disable saving any refs in the inputStream for GC
+                ((StreamRemoteCall) call).discardPendingRefs();
+                throw aex;
+            } catch (java.io.IOException | ClassNotFoundException e) {
+                // disable saving any refs in the inputStream for GC
+                ((StreamRemoteCall) call).discardPendingRefs();
                 throw new UnmarshalException(
                     "error unmarshalling arguments", e);
             } finally {
@@ -365,6 +376,7 @@
                  */
             }
         } catch (Throwable e) {
+            Throwable origEx = e;
             logCallException(e);
 
             ObjectOutput out = call.getResultStream(false);
@@ -380,6 +392,12 @@
                 clearStackTraces(e);
             }
             out.writeObject(e);
+
+            // AccessExceptions should cause Transport.serviceCall
+            // to flag the connection as unusable.
+            if (origEx instanceof AccessException) {
+                throw new IOException("Connection is not reusable", origEx);
+            }
         } finally {
             call.releaseInputStream(); // in case skeleton doesn't
             call.releaseOutputStream();
@@ -408,62 +426,41 @@
      * Handle server-side dispatch using the RMI 1.1 stub/skeleton
      * protocol, given a non-negative operation number that has
      * already been read from the call stream.
+     * Exceptions are handled by the caller to be sent to the remote client.
      *
      * @param obj the target remote object for the call
      * @param call the "remote call" from which operation and
      * method arguments can be obtained.
      * @param op the operation number
-     * @exception IOException if unable to marshal return result or
+     * @throws Exception if unable to marshal return result or
      * release input or output streams
      */
-    public void oldDispatch(Remote obj, RemoteCall call, int op)
-        throws IOException
+    private void oldDispatch(Remote obj, RemoteCall call, int op)
+        throws Exception
     {
         long hash;              // hash for matching stub with skeleton
 
+        // read remote call header
+        ObjectInput in;
+        in = call.getInputStream();
         try {
-            // read remote call header
-            ObjectInput in;
-            try {
-                in = call.getInputStream();
-                try {
-                    Class<?> clazz = Class.forName("sun.rmi.transport.DGCImpl_Skel");
-                    if (clazz.isAssignableFrom(skel.getClass())) {
-                        ((MarshalInputStream)in).useCodebaseOnly();
-                    }
-                } catch (ClassNotFoundException ignore) { }
-                hash = in.readLong();
-            } catch (Exception readEx) {
-                throw new UnmarshalException("error unmarshalling call header",
-                                             readEx);
+            Class<?> clazz = Class.forName("sun.rmi.transport.DGCImpl_Skel");
+            if (clazz.isAssignableFrom(skel.getClass())) {
+                ((MarshalInputStream)in).useCodebaseOnly();
             }
+        } catch (ClassNotFoundException ignore) { }
 
-            // if calls are being logged, write out object id and operation
-            logCall(obj, skel.getOperations()[op]);
-            unmarshalCustomCallData(in);
-            // dispatch to skeleton for remote object
-            skel.dispatch(obj, call, op, hash);
-
-        } catch (Throwable e) {
-            logCallException(e);
-
-            ObjectOutput out = call.getResultStream(false);
-            if (e instanceof Error) {
-                e = new ServerError(
-                    "Error occurred in server thread", (Error) e);
-            } else if (e instanceof RemoteException) {
-                e = new ServerException(
-                    "RemoteException occurred in server thread",
-                    (Exception) e);
-            }
-            if (suppressStackTraces) {
-                clearStackTraces(e);
-            }
-            out.writeObject(e);
-        } finally {
-            call.releaseInputStream(); // in case skeleton doesn't
-            call.releaseOutputStream();
+        try {
+            hash = in.readLong();
+        } catch (Exception ioe) {
+            throw new UnmarshalException("error unmarshalling call header", ioe);
         }
+
+        // if calls are being logged, write out object id and operation
+        logCall(obj, skel.getOperations()[op]);
+        unmarshalCustomCallData(in);
+        // dispatch to skeleton for remote object
+        skel.dispatch(obj, call, op, hash);
     }
 
     /**
diff --git a/src/java.rmi/share/classes/sun/rmi/transport/ConnectionInputStream.java b/src/java.rmi/share/classes/sun/rmi/transport/ConnectionInputStream.java
index c0ff825..e6917f7 100644
--- a/src/java.rmi/share/classes/sun/rmi/transport/ConnectionInputStream.java
+++ b/src/java.rmi/share/classes/sun/rmi/transport/ConnectionInputStream.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -82,6 +82,14 @@
     }
 
     /**
+     * Discard the saved incoming refs so there is nothing to register
+     * when {@code registerRefs} is called.
+     */
+    void discardRefs() {
+        incomingRefTable.clear();
+    }
+
+    /**
      * Add references to DGC table (and possibly send dirty call).
      * RegisterRefs now calls DGCClient.referenced on all
      * refs with the same endpoint at once to achieve batching of
diff --git a/src/java.rmi/share/classes/sun/rmi/transport/DGCClient.java b/src/java.rmi/share/classes/sun/rmi/transport/DGCClient.java
index 71fc403..89144a2 100644
--- a/src/java.rmi/share/classes/sun/rmi/transport/DGCClient.java
+++ b/src/java.rmi/share/classes/sun/rmi/transport/DGCClient.java
@@ -24,9 +24,11 @@
  */
 package sun.rmi.transport;
 
+import java.io.InvalidClassException;
 import java.lang.ref.PhantomReference;
 import java.lang.ref.ReferenceQueue;
 import java.net.SocketPermission;
+import java.rmi.UnmarshalException;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.HashMap;
@@ -41,6 +43,8 @@
 import java.rmi.dgc.Lease;
 import java.rmi.dgc.VMID;
 import java.rmi.server.ObjID;
+
+import sun.rmi.runtime.Log;
 import sun.rmi.runtime.NewThreadAction;
 import sun.rmi.server.UnicastRef;
 import sun.rmi.server.Util;
@@ -388,6 +392,12 @@
                 synchronized (this) {
                     dirtyFailures++;
 
+                    if (e instanceof UnmarshalException
+                            && e.getCause() instanceof InvalidClassException) {
+                        DGCImpl.dgcLog.log(Log.BRIEF, "InvalidClassException exception in DGC dirty call", e);
+                        return;             // protocol error, do not register these refs
+                    }
+
                     if (dirtyFailures == 1) {
                         /*
                          * If this was the first recent failed dirty call,
diff --git a/src/java.rmi/share/classes/sun/rmi/transport/DGCImpl_Skel.java b/src/java.rmi/share/classes/sun/rmi/transport/DGCImpl_Skel.java
new file mode 100644
index 0000000..f991a6e
--- /dev/null
+++ b/src/java.rmi/share/classes/sun/rmi/transport/DGCImpl_Skel.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.rmi.transport;
+
+/**
+ * Skeleton to dispatch DGC methods.
+ * Originally generated by RMIC but frozen to match the stubs.
+ */
+@SuppressWarnings({"deprecation", "serial"})
+public final class DGCImpl_Skel
+        implements java.rmi.server.Skeleton {
+    private static final java.rmi.server.Operation[] operations = {
+            new java.rmi.server.Operation("void clean(java.rmi.server.ObjID[], long, java.rmi.dgc.VMID, boolean)"),
+            new java.rmi.server.Operation("java.rmi.dgc.Lease dirty(java.rmi.server.ObjID[], long, java.rmi.dgc.Lease)")
+    };
+
+    private static final long interfaceHash = -669196253586618813L;
+
+    public java.rmi.server.Operation[] getOperations() {
+        return operations.clone();
+    }
+
+    public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall call, int opnum, long hash)
+            throws java.lang.Exception {
+        if (hash != interfaceHash)
+            throw new java.rmi.server.SkeletonMismatchException("interface hash mismatch");
+
+        sun.rmi.transport.DGCImpl server = (sun.rmi.transport.DGCImpl) obj;
+        switch (opnum) {
+            case 0: // clean(ObjID[], long, VMID, boolean)
+            {
+                java.rmi.server.ObjID[] $param_arrayOf_ObjID_1;
+                long $param_long_2;
+                java.rmi.dgc.VMID $param_VMID_3;
+                boolean $param_boolean_4;
+                try {
+                    java.io.ObjectInput in = call.getInputStream();
+                    $param_arrayOf_ObjID_1 = (java.rmi.server.ObjID[]) in.readObject();
+                    $param_long_2 = in.readLong();
+                    $param_VMID_3 = (java.rmi.dgc.VMID) in.readObject();
+                    $param_boolean_4 = in.readBoolean();
+                } catch (java.io.IOException e) {
+                    throw new java.rmi.UnmarshalException("error unmarshalling arguments", e);
+                } catch (java.lang.ClassNotFoundException e) {
+                    throw new java.rmi.UnmarshalException("error unmarshalling arguments", e);
+                } finally {
+                    call.releaseInputStream();
+                }
+                server.clean($param_arrayOf_ObjID_1, $param_long_2, $param_VMID_3, $param_boolean_4);
+                try {
+                    call.getResultStream(true);
+                } catch (java.io.IOException e) {
+                    throw new java.rmi.MarshalException("error marshalling return", e);
+                }
+                break;
+            }
+
+            case 1: // dirty(ObjID[], long, Lease)
+            {
+                java.rmi.server.ObjID[] $param_arrayOf_ObjID_1;
+                long $param_long_2;
+                java.rmi.dgc.Lease $param_Lease_3;
+                try {
+                    java.io.ObjectInput in = call.getInputStream();
+                    $param_arrayOf_ObjID_1 = (java.rmi.server.ObjID[]) in.readObject();
+                    $param_long_2 = in.readLong();
+                    $param_Lease_3 = (java.rmi.dgc.Lease) in.readObject();
+                } catch (java.io.IOException e) {
+                    throw new java.rmi.UnmarshalException("error unmarshalling arguments", e);
+                } catch (java.lang.ClassNotFoundException e) {
+                    throw new java.rmi.UnmarshalException("error unmarshalling arguments", e);
+                } finally {
+                    call.releaseInputStream();
+                }
+                java.rmi.dgc.Lease $result = server.dirty($param_arrayOf_ObjID_1, $param_long_2, $param_Lease_3);
+                try {
+                    java.io.ObjectOutput out = call.getResultStream(true);
+                    out.writeObject($result);
+                } catch (java.io.IOException e) {
+                    throw new java.rmi.MarshalException("error marshalling return", e);
+                }
+                break;
+            }
+
+            default:
+                throw new java.rmi.UnmarshalException("invalid method number");
+        }
+    }
+}
diff --git a/src/java.rmi/share/classes/sun/rmi/transport/DGCImpl_Stub.java b/src/java.rmi/share/classes/sun/rmi/transport/DGCImpl_Stub.java
new file mode 100644
index 0000000..cc44ff8
--- /dev/null
+++ b/src/java.rmi/share/classes/sun/rmi/transport/DGCImpl_Stub.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.rmi.transport;
+
+import java.io.ObjectInputFilter;
+import java.io.ObjectInputStream;
+import java.rmi.dgc.Lease;
+import java.rmi.dgc.VMID;
+import java.rmi.server.UID;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+import sun.rmi.server.UnicastRef;
+import sun.rmi.transport.tcp.TCPConnection;
+
+/**
+ * Stubs to invoke DGC remote methods.
+ * Originally generated from RMIC but frozen to insert serialFilter.
+ */
+@SuppressWarnings({"deprecation", "serial"})
+public final class DGCImpl_Stub
+        extends java.rmi.server.RemoteStub
+        implements java.rmi.dgc.DGC {
+    private static final java.rmi.server.Operation[] operations = {
+            new java.rmi.server.Operation("void clean(java.rmi.server.ObjID[], long, java.rmi.dgc.VMID, boolean)"),
+            new java.rmi.server.Operation("java.rmi.dgc.Lease dirty(java.rmi.server.ObjID[], long, java.rmi.dgc.Lease)")
+    };
+
+    private static final long interfaceHash = -669196253586618813L;
+
+    /** Registry max depth of remote invocations. **/
+    private static int DGCCLIENT_MAX_DEPTH = 6;
+
+    /** Registry maximum array size in remote invocations. **/
+    private static int DGCCLIENT_MAX_ARRAY_SIZE = 10000;
+
+    // constructors
+    public DGCImpl_Stub() {
+        super();
+    }
+
+    public DGCImpl_Stub(java.rmi.server.RemoteRef ref) {
+        super(ref);
+    }
+
+    // methods from remote interfaces
+
+    // implementation of clean(ObjID[], long, VMID, boolean)
+    public void clean(java.rmi.server.ObjID[] $param_arrayOf_ObjID_1, long $param_long_2, java.rmi.dgc.VMID $param_VMID_3, boolean $param_boolean_4)
+            throws java.rmi.RemoteException {
+        try {
+            java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 0, interfaceHash);
+            try {
+                java.io.ObjectOutput out = call.getOutputStream();
+                out.writeObject($param_arrayOf_ObjID_1);
+                out.writeLong($param_long_2);
+                out.writeObject($param_VMID_3);
+                out.writeBoolean($param_boolean_4);
+            } catch (java.io.IOException e) {
+                throw new java.rmi.MarshalException("error marshalling arguments", e);
+            }
+            ref.invoke(call);
+            ref.done(call);
+        } catch (java.lang.RuntimeException e) {
+            throw e;
+        } catch (java.rmi.RemoteException e) {
+            throw e;
+        } catch (java.lang.Exception e) {
+            throw new java.rmi.UnexpectedException("undeclared checked exception", e);
+        }
+    }
+
+    // implementation of dirty(ObjID[], long, Lease)
+    public java.rmi.dgc.Lease dirty(java.rmi.server.ObjID[] $param_arrayOf_ObjID_1, long $param_long_2, java.rmi.dgc.Lease $param_Lease_3)
+            throws java.rmi.RemoteException {
+        try {
+            java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 1, interfaceHash);
+            try {
+                java.io.ObjectOutput out = call.getOutputStream();
+                out.writeObject($param_arrayOf_ObjID_1);
+                out.writeLong($param_long_2);
+                out.writeObject($param_Lease_3);
+            } catch (java.io.IOException e) {
+                throw new java.rmi.MarshalException("error marshalling arguments", e);
+            }
+            ref.invoke(call);
+            java.rmi.dgc.Lease $result;
+            Connection connection = ((StreamRemoteCall) call).getConnection();
+            try {
+                java.io.ObjectInput in = call.getInputStream();
+
+                if (in instanceof ObjectInputStream) {
+                    /**
+                     * Set a filter on the stream for the return value.
+                     */
+                    ObjectInputStream ois = (ObjectInputStream) in;
+                    AccessController.doPrivileged((PrivilegedAction<Void>)() -> {
+                        ois.setObjectInputFilter(DGCImpl_Stub::leaseFilter);
+                        return null;
+                    });
+                }
+                $result = (java.rmi.dgc.Lease) in.readObject();
+            } catch (java.io.IOException | java.lang.ClassNotFoundException e) {
+                if (connection instanceof TCPConnection) {
+                    // Modified to prevent re-use of the connection after an exception
+                    ((TCPConnection) connection).getChannel().free(connection, false);
+                }
+                throw new java.rmi.UnmarshalException("error unmarshalling return", e);
+            } finally {
+                ref.done(call);
+            }
+            return $result;
+        } catch (java.lang.RuntimeException e) {
+            throw e;
+        } catch (java.rmi.RemoteException e) {
+            throw e;
+        } catch (java.lang.Exception e) {
+            throw new java.rmi.UnexpectedException("undeclared checked exception", e);
+        }
+    }
+
+    /**
+     * ObjectInputFilter to filter DGCClient return value (a Lease).
+     * The list of acceptable classes is very short and explicit.
+     * The depth and array sizes are limited.
+     *
+     * @param filterInfo access to class, arrayLength, etc.
+     * @return  {@link ObjectInputFilter.Status#ALLOWED} if allowed,
+     *          {@link ObjectInputFilter.Status#REJECTED} if rejected,
+     *          otherwise {@link ObjectInputFilter.Status#UNDECIDED}
+     */
+    private static ObjectInputFilter.Status leaseFilter(ObjectInputFilter.FilterInfo filterInfo) {
+
+        if (filterInfo.depth() > DGCCLIENT_MAX_DEPTH) {
+            return ObjectInputFilter.Status.REJECTED;
+        }
+        Class<?> clazz = filterInfo.serialClass();
+        if (clazz != null) {
+            while (clazz.isArray()) {
+                if (filterInfo.arrayLength() >= 0 && filterInfo.arrayLength() > DGCCLIENT_MAX_ARRAY_SIZE) {
+                    return ObjectInputFilter.Status.REJECTED;
+                }
+                // Arrays are allowed depending on the component type
+                clazz = clazz.getComponentType();
+            }
+            if (clazz.isPrimitive()) {
+                // Arrays of primitives are allowed
+                return ObjectInputFilter.Status.ALLOWED;
+            }
+            return (clazz == UID.class ||
+                    clazz == VMID.class ||
+                    clazz == Lease.class)
+                    ? ObjectInputFilter.Status.ALLOWED
+                    : ObjectInputFilter.Status.REJECTED;
+        }
+        // Not a class, not size limited
+        return ObjectInputFilter.Status.UNDECIDED;
+    }
+
+}
diff --git a/src/java.rmi/share/classes/sun/rmi/transport/StreamRemoteCall.java b/src/java.rmi/share/classes/sun/rmi/transport/StreamRemoteCall.java
index 915ed6f..d0a0ced 100644
--- a/src/java.rmi/share/classes/sun/rmi/transport/StreamRemoteCall.java
+++ b/src/java.rmi/share/classes/sun/rmi/transport/StreamRemoteCall.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -168,6 +168,13 @@
     }
 
     /**
+     * Discard any post-processing of refs the InputStream.
+     */
+    public void discardPendingRefs() {
+        in.discardRefs();
+    }
+
+    /**
      * Returns an output stream (may put out header information
      * relating to the success of the call).
      * @param success If true, indicates normal return, else indicates
diff --git a/src/jdk.crypto.ec/share/classes/sun/security/ec/ECDSASignature.java b/src/jdk.crypto.ec/share/classes/sun/security/ec/ECDSASignature.java
index 3b74338..f2ac544 100644
--- a/src/jdk.crypto.ec/share/classes/sun/security/ec/ECDSASignature.java
+++ b/src/jdk.crypto.ec/share/classes/sun/security/ec/ECDSASignature.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -370,9 +370,15 @@
         }
         random.nextBytes(seed);
 
+        // random bits needed for timing countermeasures
+        int timingArgument = random.nextInt();
+        // values must be non-zero to enable countermeasures
+        timingArgument |= 1;
+
         byte[] sig;
         try {
-            sig = signDigest(getDigestValue(), s, encodedParams, seed);
+            sig = signDigest(getDigestValue(), s, encodedParams, seed,
+                timingArgument);
         } catch (GeneralSecurityException e) {
             throw new SignatureException("Could not sign data", e);
         }
@@ -509,11 +515,19 @@
      * @param s the private key's S value.
      * @param encodedParams the curve's DER encoded object identifier.
      * @param seed the random seed.
+     * @param timing When non-zero, the implmentation will use timing
+     *     countermeasures to hide secrets from timing channels. The EC
+     *     implementation will disable the countermeasures when this value is
+     *     zero, because the underlying EC functions are shared by several
+     *     crypto operations, some of which do not use the countermeasures.
+     *     The high-order 31 bits must be uniformly random. The entropy from
+     *     these bits is used by the countermeasures.
      *
      * @return byte[] the signature.
      */
     private static native byte[] signDigest(byte[] digest, byte[] s,
-        byte[] encodedParams, byte[] seed) throws GeneralSecurityException;
+        byte[] encodedParams, byte[] seed, int timing)
+            throws GeneralSecurityException;
 
     /**
      * Verifies the signed digest using the public key.
diff --git a/src/jdk.crypto.ec/share/native/libsunec/ECC_JNI.cpp b/src/jdk.crypto.ec/share/native/libsunec/ECC_JNI.cpp
index 31c2d07..1cec783 100644
--- a/src/jdk.crypto.ec/share/native/libsunec/ECC_JNI.cpp
+++ b/src/jdk.crypto.ec/share/native/libsunec/ECC_JNI.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -196,7 +196,7 @@
  */
 JNIEXPORT jbyteArray
 JNICALL Java_sun_security_ec_ECDSASignature_signDigest
-  (JNIEnv *env, jclass clazz, jbyteArray digest, jbyteArray privateKey, jbyteArray encodedParams, jbyteArray seed)
+  (JNIEnv *env, jclass clazz, jbyteArray digest, jbyteArray privateKey, jbyteArray encodedParams, jbyteArray seed, jint timing)
 {
     jbyte* pDigestBuffer = NULL;
     jint jDigestLength = env->GetArrayLength(digest);
@@ -256,7 +256,7 @@
 
     // Sign the digest (using the supplied seed)
     if (ECDSA_SignDigest(&privKey, &signature_item, &digest_item,
-        (unsigned char *) pSeedBuffer, jSeedLength, 0) != SECSuccess) {
+        (unsigned char *) pSeedBuffer, jSeedLength, 0, timing) != SECSuccess) {
         ThrowException(env, KEY_EXCEPTION);
         goto cleanup;
     }
diff --git a/src/jdk.crypto.ec/share/native/libsunec/impl/ec.c b/src/jdk.crypto.ec/share/native/libsunec/impl/ec.c
index 4f3cab3..c439eb7 100644
--- a/src/jdk.crypto.ec/share/native/libsunec/impl/ec.c
+++ b/src/jdk.crypto.ec/share/native/libsunec/impl/ec.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
  * Use is subject to license terms.
  *
  * This library is free software; you can redistribute it and/or
@@ -34,7 +34,7 @@
  *   Dr Vipul Gupta <vipul.gupta@sun.com> and
  *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
  *
- * Last Modified Date from the Original Code: November 2016
+ * Last Modified Date from the Original Code: May 2017
  *********************************************************************** */
 
 #include "mplogic.h"
@@ -87,7 +87,7 @@
  */
 SECStatus
 ec_points_mul(const ECParams *params, const mp_int *k1, const mp_int *k2,
-             const SECItem *pointP, SECItem *pointQ, int kmflag)
+             const SECItem *pointP, SECItem *pointQ, int kmflag, int timing)
 {
     mp_int Px, Py, Qx, Qy;
     mp_int Gx, Gy, order, irreducible, a, b;
@@ -199,9 +199,9 @@
                 goto cleanup;
 
         if ((k2 != NULL) && (pointP != NULL)) {
-                CHECK_MPI_OK( ECPoints_mul(group, k1, k2, &Px, &Py, &Qx, &Qy) );
+                CHECK_MPI_OK( ECPoints_mul(group, k1, k2, &Px, &Py, &Qx, &Qy, timing) );
         } else {
-                CHECK_MPI_OK( ECPoints_mul(group, k1, NULL, NULL, NULL, &Qx, &Qy) );
+                CHECK_MPI_OK( ECPoints_mul(group, k1, NULL, NULL, NULL, &Qx, &Qy, timing) );
     }
 
     /* Construct the SECItem representation of point Q */
@@ -333,7 +333,8 @@
     CHECK_MPI_OK( mp_read_unsigned_octets(&k, key->privateValue.data,
         (mp_size) len) );
 
-    rv = ec_points_mul(ecParams, &k, NULL, NULL, &(key->publicValue), kmflag);
+    /* key generation does not support timing mitigation */
+    rv = ec_points_mul(ecParams, &k, NULL, NULL, &(key->publicValue), kmflag, /*timing*/ 0);
     if (rv != SECSuccess) goto cleanup;
     *privKey = key;
 
@@ -610,7 +611,8 @@
     }
 
     /* Multiply our private key and peer's public point */
-    if ((ec_points_mul(ecParams, NULL, &k, publicValue, &pointQ, kmflag) != SECSuccess) ||
+    /* ECDH doesn't support timing mitigation */
+    if ((ec_points_mul(ecParams, NULL, &k, publicValue, &pointQ, kmflag, /*timing*/ 0) != SECSuccess) ||
         ec_point_at_infinity(&pointQ))
         goto cleanup;
 
@@ -645,7 +647,8 @@
  */
 SECStatus
 ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature,
-    const SECItem *digest, const unsigned char *kb, const int kblen, int kmflag)
+    const SECItem *digest, const unsigned char *kb, const int kblen, int kmflag,
+    int timing)
 {
     SECStatus rv = SECFailure;
     mp_int x1;
@@ -715,16 +718,6 @@
     }
 
     /*
-     * Using an equivalent exponent of fixed length (same as n or 1 bit less
-     * than n) to keep the kG timing relatively constant.
-     *
-     * Note that this is an extra step on top of the approach defined in
-     * ANSI X9.62 so as to make a fixed length K.
-     */
-    CHECK_MPI_OK( mp_add(&k, &n, &k) );
-    CHECK_MPI_OK( mp_div_2(&k, &k) );
-
-    /*
     ** ANSI X9.62, Section 5.3.2, Step 2
     **
     ** Compute kG
@@ -732,7 +725,7 @@
     kGpoint.len = 2*flen + 1;
     kGpoint.data = PORT_Alloc(2*flen + 1, kmflag);
     if ((kGpoint.data == NULL) ||
-        (ec_points_mul(ecParams, &k, NULL, NULL, &kGpoint, kmflag)
+        (ec_points_mul(ecParams, &k, NULL, NULL, &kGpoint, kmflag, timing)
             != SECSuccess))
         goto cleanup;
 
@@ -854,7 +847,7 @@
 */
 SECStatus
 ECDSA_SignDigest(ECPrivateKey *key, SECItem *signature, const SECItem *digest,
-    const unsigned char* random, int randomLen, int kmflag)
+    const unsigned char* random, int randomLen, int kmflag, int timing)
 {
     SECStatus rv = SECFailure;
     int len;
@@ -872,7 +865,7 @@
     if (kBytes == NULL) goto cleanup;
 
     /* Generate ECDSA signature with the specified k value */
-    rv = ECDSA_SignDigestWithSeed(key, signature, digest, kBytes, len, kmflag);
+    rv = ECDSA_SignDigestWithSeed(key, signature, digest, kBytes, len, kmflag, timing);
 
 cleanup:
     if (kBytes) {
@@ -1018,7 +1011,8 @@
     ** Here, A = u1.G     B = u2.Q    and   C = A + B
     ** If the result, C, is the point at infinity, reject the signature
     */
-    if (ec_points_mul(ecParams, &u1, &u2, &key->publicValue, &pointC, kmflag)
+    /* verification does not support timing mitigation */
+    if (ec_points_mul(ecParams, &u1, &u2, &key->publicValue, &pointC, kmflag, /*timing*/ 0)
         != SECSuccess) {
         rv = SECFailure;
         goto cleanup;
diff --git a/src/jdk.crypto.ec/share/native/libsunec/impl/ec2.h b/src/jdk.crypto.ec/share/native/libsunec/impl/ec2.h
index aa5f2bb..72df04e 100644
--- a/src/jdk.crypto.ec/share/native/libsunec/impl/ec2.h
+++ b/src/jdk.crypto.ec/share/native/libsunec/impl/ec2.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
  * Use is subject to license terms.
  *
  * This library is free software; you can redistribute it and/or
@@ -33,6 +33,7 @@
  * Contributor(s):
  *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
  *
+ * Last Modified Date from the Original Code: May 2017
  *********************************************************************** */
 
 #ifndef _EC2_H
@@ -79,7 +80,7 @@
  * determines the field GF2m.  Uses Montgomery projective coordinates. */
 mp_err ec_GF2m_pt_mul_mont(const mp_int *n, const mp_int *px,
                                                    const mp_int *py, mp_int *rx, mp_int *ry,
-                                                   const ECGroup *group);
+                                                   const ECGroup *group, int timing);
 
 #ifdef ECL_ENABLE_GF2M_PROJ
 /* Converts a point P(px, py) from affine coordinates to projective
diff --git a/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_aff.c b/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_aff.c
index 5a546c0..8d0f546 100644
--- a/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_aff.c
+++ b/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_aff.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
  * Use is subject to license terms.
  *
  * This library is free software; you can redistribute it and/or
@@ -33,6 +33,7 @@
  * Contributor(s):
  *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
  *
+ * Last Modified Date from the Original Code: May 2017
  *********************************************************************** */
 
 #include "ec2.h"
@@ -329,7 +330,8 @@
     /* 4: Verify that the order of the curve times the publicValue
      *    is the point at infinity.
      */
-        MP_CHECKOK( ECPoint_mul(group, &group->order, px, py, &pxt, &pyt) );
+        /* timing mitigation is not supported */
+        MP_CHECKOK( ECPoint_mul(group, &group->order, px, py, &pxt, &pyt, /*timing*/ 0) );
         if (ec_GF2m_pt_is_inf_aff(&pxt, &pyt) != MP_YES) {
                 res = MP_NO;
                 goto CLEANUP;
diff --git a/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_mont.c b/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_mont.c
index b91e65e..bb60553 100644
--- a/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_mont.c
+++ b/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_mont.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
  * Use is subject to license terms.
  *
  * This library is free software; you can redistribute it and/or
@@ -35,6 +35,7 @@
  *   Stephen Fung <fungstep@hotmail.com>, and
  *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories.
  *
+ *  Last Modified Date from the Original Code: May 2017
  *********************************************************************** */
 
 #include "ec2.h"
@@ -181,10 +182,12 @@
 /* Computes R = nP based on algorithm 2P of Lopex, J. and Dahab, R.  "Fast
  * multiplication on elliptic curves over GF(2^m) without
  * precomputation". Elliptic curve points P and R can be identical. Uses
- * Montgomery projective coordinates. */
+ * Montgomery projective coordinates. The timing parameter is ignored
+ * because this algorithm resists timing attacks by default. */
 mp_err
 ec_GF2m_pt_mul_mont(const mp_int *n, const mp_int *px, const mp_int *py,
-                                        mp_int *rx, mp_int *ry, const ECGroup *group)
+                                        mp_int *rx, mp_int *ry, const ECGroup *group,
+                                        int timing)
 {
         mp_err res = MP_OKAY;
         mp_int x1, x2, z1, z2;
diff --git a/src/jdk.crypto.ec/share/native/libsunec/impl/ecc_impl.h b/src/jdk.crypto.ec/share/native/libsunec/impl/ecc_impl.h
index 0739f4c..48aa13a 100644
--- a/src/jdk.crypto.ec/share/native/libsunec/impl/ecc_impl.h
+++ b/src/jdk.crypto.ec/share/native/libsunec/impl/ecc_impl.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
  * Use is subject to license terms.
  *
  * This library is free software; you can redistribute it and/or
@@ -34,7 +34,7 @@
  *   Dr Vipul Gupta <vipul.gupta@sun.com> and
  *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
  *
- * Last Modified Date from the Original Code: November 2013
+ * Last Modified Date from the Original Code: May 2017
  *********************************************************************** */
 
 #ifndef _ECC_IMPL_H
@@ -258,7 +258,7 @@
     const unsigned char* random, int randomlen, int);
 /* This function has been modified to accept an array of random bytes */
 extern SECStatus ECDSA_SignDigest(ECPrivateKey *, SECItem *, const SECItem *,
-    const unsigned char* random, int randomlen, int);
+    const unsigned char* random, int randomlen, int, int timing);
 extern SECStatus ECDSA_VerifyDigest(ECPublicKey *, const SECItem *,
     const SECItem *, int);
 extern SECStatus ECDH_Derive(SECItem *, ECParams *, SECItem *, boolean_t,
diff --git a/src/jdk.crypto.ec/share/native/libsunec/impl/ecl-priv.h b/src/jdk.crypto.ec/share/native/libsunec/impl/ecl-priv.h
index fa232dd..bdfe615 100644
--- a/src/jdk.crypto.ec/share/native/libsunec/impl/ecl-priv.h
+++ b/src/jdk.crypto.ec/share/native/libsunec/impl/ecl-priv.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
  * Use is subject to license terms.
  *
  * This library is free software; you can redistribute it and/or
@@ -34,6 +34,7 @@
  *   Stephen Fung <fungstep@hotmail.com> and
  *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
  *
+ * Last Modified Date from the Original Code: May 2017
  *********************************************************************** */
 
 #ifndef _ECL_PRIV_H
@@ -193,12 +194,13 @@
                                                  mp_int *ry, const ECGroup *group);
         mp_err (*point_mul) (const mp_int *n, const mp_int *px,
                                                  const mp_int *py, mp_int *rx, mp_int *ry,
-                                                 const ECGroup *group);
+                                                 const ECGroup *group, int timing);
         mp_err (*base_point_mul) (const mp_int *n, mp_int *rx, mp_int *ry,
                                                           const ECGroup *group);
         mp_err (*points_mul) (const mp_int *k1, const mp_int *k2,
                                                   const mp_int *px, const mp_int *py, mp_int *rx,
-                                                  mp_int *ry, const ECGroup *group);
+                                                  mp_int *ry, const ECGroup *group,
+                                                  int timing);
         mp_err (*validate_point) (const mp_int *px, const mp_int *py, const ECGroup *group);
         /* Extra storage for implementation-specific data.  Any memory
          * allocated to these extra fields will be cleared by extra_free. */
@@ -262,10 +264,12 @@
 /* point multiplication */
 mp_err ec_pts_mul_basic(const mp_int *k1, const mp_int *k2,
                                                 const mp_int *px, const mp_int *py, mp_int *rx,
-                                                mp_int *ry, const ECGroup *group);
+                                                mp_int *ry, const ECGroup *group,
+                                                int timing);
 mp_err ec_pts_mul_simul_w2(const mp_int *k1, const mp_int *k2,
                                                    const mp_int *px, const mp_int *py, mp_int *rx,
-                                                   mp_int *ry, const ECGroup *group);
+                                                   mp_int *ry, const ECGroup *group,
+                                                   int timing);
 
 /* Computes the windowed non-adjacent-form (NAF) of a scalar. Out should
  * be an array of signed char's to output to, bitsize should be the number
diff --git a/src/jdk.crypto.ec/share/native/libsunec/impl/ecl.h b/src/jdk.crypto.ec/share/native/libsunec/impl/ecl.h
index 3a83a9e..deff0aa 100644
--- a/src/jdk.crypto.ec/share/native/libsunec/impl/ecl.h
+++ b/src/jdk.crypto.ec/share/native/libsunec/impl/ecl.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
  * Use is subject to license terms.
  *
  * This library is free software; you can redistribute it and/or
@@ -33,6 +33,7 @@
  * Contributor(s):
  *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
  *
+ * Last Modified Date from the Original Code: May 2017
  *********************************************************************** */
 
 #ifndef _ECL_H
@@ -70,7 +71,8 @@
  * of the group of points on the elliptic curve. Input and output values
  * are assumed to be NOT field-encoded. */
 mp_err ECPoint_mul(const ECGroup *group, const mp_int *k, const mp_int *px,
-                                   const mp_int *py, mp_int *qx, mp_int *qy);
+                                   const mp_int *py, mp_int *qx, mp_int *qy,
+                                   int timing);
 
 /* Elliptic curve scalar-point multiplication. Computes Q(x, y) = k1 * G +
  * k2 * P(x, y), where G is the generator (base point) of the group of
@@ -78,7 +80,7 @@
  * be NOT field-encoded. */
 mp_err ECPoints_mul(const ECGroup *group, const mp_int *k1,
                                         const mp_int *k2, const mp_int *px, const mp_int *py,
-                                        mp_int *qx, mp_int *qy);
+                                        mp_int *qx, mp_int *qy, int timing);
 
 /* Validates an EC public key as described in Section 5.2.2 of X9.62.
  * Returns MP_YES if the public key is valid, MP_NO if the public key
diff --git a/src/jdk.crypto.ec/share/native/libsunec/impl/ecl_mult.c b/src/jdk.crypto.ec/share/native/libsunec/impl/ecl_mult.c
index 92dd0ec..16f2592 100644
--- a/src/jdk.crypto.ec/share/native/libsunec/impl/ecl_mult.c
+++ b/src/jdk.crypto.ec/share/native/libsunec/impl/ecl_mult.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
  * Use is subject to license terms.
  *
  * This library is free software; you can redistribute it and/or
@@ -33,7 +33,7 @@
  * Contributor(s):
  *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
  *
- * Last Modified Date from the Original Code: Nov 2016
+ * Last Modified Date from the Original Code: May 2017
  *********************************************************************** */
 
 #include "mpi.h"
@@ -50,7 +50,8 @@
  * are assumed to be NOT field-encoded. */
 mp_err
 ECPoint_mul(const ECGroup *group, const mp_int *k, const mp_int *px,
-                        const mp_int *py, mp_int *rx, mp_int *ry)
+                        const mp_int *py, mp_int *rx, mp_int *ry,
+                        int timing)
 {
         mp_err res = MP_OKAY;
         mp_int kt;
@@ -76,16 +77,16 @@
                         kt.flag = (mp_sign)0;
                         MP_CHECKOK(group->
                                            point_mul(&kt, &group->genx, &group->geny, rx, ry,
-                                                                 group));
+                                                                 group, timing));
                 }
         } else {
                 if (group->meth->field_enc) {
                         MP_CHECKOK(group->meth->field_enc(px, rx, group->meth));
                         MP_CHECKOK(group->meth->field_enc(py, ry, group->meth));
-                        MP_CHECKOK(group->point_mul(&kt, rx, ry, rx, ry, group));
+                        MP_CHECKOK(group->point_mul(&kt, rx, ry, rx, ry, group, timing));
                 } else {
                         kt.flag = (mp_sign)0;
-                        MP_CHECKOK(group->point_mul(&kt, px, py, rx, ry, group));
+                        MP_CHECKOK(group->point_mul(&kt, px, py, rx, ry, group, timing));
                 }
         }
         if (group->meth->field_dec) {
@@ -107,7 +108,7 @@
 mp_err
 ec_pts_mul_basic(const mp_int *k1, const mp_int *k2, const mp_int *px,
                                  const mp_int *py, mp_int *rx, mp_int *ry,
-                                 const ECGroup *group)
+                                 const ECGroup *group, int timing)
 {
         mp_err res = MP_OKAY;
         mp_int sx, sy;
@@ -119,9 +120,9 @@
 
         /* if some arguments are not defined used ECPoint_mul */
         if (k1 == NULL) {
-                return ECPoint_mul(group, k2, px, py, rx, ry);
+                return ECPoint_mul(group, k2, px, py, rx, ry, timing);
         } else if ((k2 == NULL) || (px == NULL) || (py == NULL)) {
-                return ECPoint_mul(group, k1, NULL, NULL, rx, ry);
+                return ECPoint_mul(group, k1, NULL, NULL, rx, ry, timing);
         }
 
         MP_DIGITS(&sx) = 0;
@@ -129,8 +130,8 @@
         MP_CHECKOK(mp_init(&sx, FLAG(k1)));
         MP_CHECKOK(mp_init(&sy, FLAG(k1)));
 
-        MP_CHECKOK(ECPoint_mul(group, k1, NULL, NULL, &sx, &sy));
-        MP_CHECKOK(ECPoint_mul(group, k2, px, py, rx, ry));
+        MP_CHECKOK(ECPoint_mul(group, k1, NULL, NULL, &sx, &sy, timing));
+        MP_CHECKOK(ECPoint_mul(group, k2, px, py, rx, ry, timing));
 
         if (group->meth->field_enc) {
                 MP_CHECKOK(group->meth->field_enc(&sx, &sx, group->meth));
@@ -162,7 +163,7 @@
 mp_err
 ec_pts_mul_simul_w2(const mp_int *k1, const mp_int *k2, const mp_int *px,
                                         const mp_int *py, mp_int *rx, mp_int *ry,
-                                        const ECGroup *group)
+                                        const ECGroup *group, int timing)
 {
         mp_err res = MP_OKAY;
         mp_int precomp[4][4][2];
@@ -177,9 +178,9 @@
 
         /* if some arguments are not defined used ECPoint_mul */
         if (k1 == NULL) {
-                return ECPoint_mul(group, k2, px, py, rx, ry);
+                return ECPoint_mul(group, k2, px, py, rx, ry, timing);
         } else if ((k2 == NULL) || (px == NULL) || (py == NULL)) {
-                return ECPoint_mul(group, k1, NULL, NULL, rx, ry);
+                return ECPoint_mul(group, k1, NULL, NULL, rx, ry, timing);
         }
 
         /* initialize precomputation table */
@@ -311,7 +312,8 @@
  * Input and output values are assumed to be NOT field-encoded. */
 mp_err
 ECPoints_mul(const ECGroup *group, const mp_int *k1, const mp_int *k2,
-                         const mp_int *px, const mp_int *py, mp_int *rx, mp_int *ry)
+                         const mp_int *px, const mp_int *py, mp_int *rx, mp_int *ry,
+                         int timing)
 {
         mp_err res = MP_OKAY;
         mp_int k1t, k2t;
@@ -348,9 +350,9 @@
 
         /* if points_mul is defined, then use it */
         if (group->points_mul) {
-                res = group->points_mul(k1p, k2p, px, py, rx, ry, group);
+                res = group->points_mul(k1p, k2p, px, py, rx, ry, group, timing);
         } else {
-                res = ec_pts_mul_simul_w2(k1p, k2p, px, py, rx, ry, group);
+                res = ec_pts_mul_simul_w2(k1p, k2p, px, py, rx, ry, group, timing);
         }
 
   CLEANUP:
diff --git a/src/jdk.crypto.ec/share/native/libsunec/impl/ecp.h b/src/jdk.crypto.ec/share/native/libsunec/impl/ecp.h
index c2aad8e..b367b90 100644
--- a/src/jdk.crypto.ec/share/native/libsunec/impl/ecp.h
+++ b/src/jdk.crypto.ec/share/native/libsunec/impl/ecp.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
  * Use is subject to license terms.
  *
  * This library is free software; you can redistribute it and/or
@@ -33,6 +33,7 @@
  * Contributor(s):
  *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
  *
+ * Last Modified Date from the Original Code: May 2017
  *********************************************************************** */
 
 #ifndef _ECP_H
@@ -122,7 +123,7 @@
 mp_err
  ec_GFp_pts_mul_jac(const mp_int *k1, const mp_int *k2, const mp_int *px,
                                         const mp_int *py, mp_int *rx, mp_int *ry,
-                                        const ECGroup *group);
+                                        const ECGroup *group, int timing);
 
 /* Computes R = nP where R is (rx, ry) and P is the base point. Elliptic
  * curve points P and R can be identical. Uses mixed Modified-Jacobian
@@ -131,9 +132,13 @@
  * returns output that is still field-encoded. Uses 5-bit window NAF
  * method (algorithm 11) for scalar-point multiplication from Brown,
  * Hankerson, Lopez, Menezes. Software Implementation of the NIST Elliptic
- * Curves Over Prime Fields. */
+ * Curves Over Prime Fields. The implementation includes a countermeasure
+ * that attempts to hide the size of n from timing channels. This counter-
+ * measure is enabled using the timing argument. The high-rder bits of timing
+ * must be uniformly random in order for this countermeasure to work. */
 mp_err
  ec_GFp_pt_mul_jm_wNAF(const mp_int *n, const mp_int *px, const mp_int *py,
-                                           mp_int *rx, mp_int *ry, const ECGroup *group);
+                                           mp_int *rx, mp_int *ry, const ECGroup *group,
+                                           int timing);
 
 #endif /* _ECP_H */
diff --git a/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_aff.c b/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_aff.c
index f150ca1..c9d9232 100644
--- a/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_aff.c
+++ b/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_aff.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
  * Use is subject to license terms.
  *
  * This library is free software; you can redistribute it and/or
@@ -38,6 +38,7 @@
  *   Nils Larsch <nla@trustcenter.de>, and
  *   Lenka Fibikova <fibikova@exp-math.uni-essen.de>, the OpenSSL Project
  *
+ * Last Modified Date from the Original Code: May 2017
  *********************************************************************** */
 
 #include "ecp.h"
@@ -340,7 +341,8 @@
     /* 4: Verify that the order of the curve times the publicValue
      *    is the point at infinity.
      */
-        MP_CHECKOK( ECPoint_mul(group, &group->order, px, py, &pxt, &pyt) );
+        /* timing mitigation is not supported */
+        MP_CHECKOK( ECPoint_mul(group, &group->order, px, py, &pxt, &pyt, /*timing*/ 0) );
         if (ec_GFp_pt_is_inf_aff(&pxt, &pyt) != MP_YES) {
                 res = MP_NO;
                 goto CLEANUP;
diff --git a/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_jac.c b/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_jac.c
index 12410be..9e1bdf2 100644
--- a/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_jac.c
+++ b/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_jac.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
  * Use is subject to license terms.
  *
  * This library is free software; you can redistribute it and/or
@@ -38,6 +38,7 @@
  *   Nils Larsch <nla@trustcenter.de>, and
  *   Lenka Fibikova <fibikova@exp-math.uni-essen.de>, the OpenSSL Project
  *
+ * Last Modified Date from the Original Code: May 2017
  *********************************************************************** */
 
 #include "ecp.h"
@@ -180,6 +181,15 @@
         MP_CHECKOK(group->meth->field_mul(&A, qx, &A, group->meth));
         MP_CHECKOK(group->meth->field_mul(&B, qy, &B, group->meth));
 
+        /*
+         * Additional checks for point equality and point at infinity
+         */
+        if (mp_cmp(px, &A) == 0 && mp_cmp(py, &B) == 0) {
+            /* POINT_DOUBLE(P) */
+            MP_CHECKOK(ec_GFp_pt_dbl_jac(px, py, pz, rx, ry, rz, group));
+            goto CLEANUP;
+        }
+
         /* C = A - px, D = B - py */
         MP_CHECKOK(group->meth->field_sub(&A, px, &C, group->meth));
         MP_CHECKOK(group->meth->field_sub(&B, py, &D, group->meth));
@@ -406,7 +416,7 @@
 mp_err
 ec_GFp_pts_mul_jac(const mp_int *k1, const mp_int *k2, const mp_int *px,
                                    const mp_int *py, mp_int *rx, mp_int *ry,
-                                   const ECGroup *group)
+                                   const ECGroup *group, int timing)
 {
         mp_err res = MP_OKAY;
         mp_int precomp[4][4][2];
@@ -430,9 +440,9 @@
 
         /* if some arguments are not defined used ECPoint_mul */
         if (k1 == NULL) {
-                return ECPoint_mul(group, k2, px, py, rx, ry);
+                return ECPoint_mul(group, k2, px, py, rx, ry, timing);
         } else if ((k2 == NULL) || (px == NULL) || (py == NULL)) {
-                return ECPoint_mul(group, k1, NULL, NULL, rx, ry);
+                return ECPoint_mul(group, k1, NULL, NULL, rx, ry, timing);
         }
 
         /* initialize precomputation table */
diff --git a/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_jm.c b/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_jm.c
index cdee87a..c5cdef9 100644
--- a/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_jm.c
+++ b/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_jm.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
  * Use is subject to license terms.
  *
  * This library is free software; you can redistribute it and/or
@@ -33,6 +33,7 @@
  * Contributor(s):
  *   Stephen Fung <fungstep@hotmail.com>, Sun Microsystems Laboratories
  *
+ * Last Modified Date from the Original Code: May 2017
  *********************************************************************** */
 
 #include "ecp.h"
@@ -165,6 +166,16 @@
         MP_CHECKOK(group->meth->field_mul(A, qx, A, group->meth));
         MP_CHECKOK(group->meth->field_mul(B, qy, B, group->meth));
 
+        /*
+         * Additional checks for point equality and point at infinity
+         */
+        if (mp_cmp(px, A) == 0 && mp_cmp(py, B) == 0) {
+            /* POINT_DOUBLE(P) */
+            MP_CHECKOK(ec_GFp_pt_dbl_jm(px, py, pz, paz4, rx, ry, rz, raz4,
+                                        scratch, group));
+            goto CLEANUP;
+        }
+
         /* C = A - px, D = B - py */
         MP_CHECKOK(group->meth->field_sub(A, px, C, group->meth));
         MP_CHECKOK(group->meth->field_sub(B, py, D, group->meth));
@@ -213,19 +224,23 @@
  * Curves Over Prime Fields. */
 mp_err
 ec_GFp_pt_mul_jm_wNAF(const mp_int *n, const mp_int *px, const mp_int *py,
-                                          mp_int *rx, mp_int *ry, const ECGroup *group)
+                                          mp_int *rx, mp_int *ry, const ECGroup *group,
+                                          int timing)
 {
         mp_err res = MP_OKAY;
-        mp_int precomp[16][2], rz, tpx, tpy;
-        mp_int raz4;
+        mp_int precomp[16][2], rz, tpx, tpy, tpz;
+        mp_int raz4, tpaz4;
         mp_int scratch[MAX_SCRATCH];
         signed char *naf = NULL;
         int i, orderBitSize;
+        int numDoubles, numAdds, extraDoubles, extraAdds;
 
         MP_DIGITS(&rz) = 0;
         MP_DIGITS(&raz4) = 0;
         MP_DIGITS(&tpx) = 0;
         MP_DIGITS(&tpy) = 0;
+        MP_DIGITS(&tpz) = 0;
+        MP_DIGITS(&tpaz4) = 0;
         for (i = 0; i < 16; i++) {
                 MP_DIGITS(&precomp[i][0]) = 0;
                 MP_DIGITS(&precomp[i][1]) = 0;
@@ -239,7 +254,9 @@
 
         /* initialize precomputation table */
         MP_CHECKOK(mp_init(&tpx, FLAG(n)));
-        MP_CHECKOK(mp_init(&tpy, FLAG(n)));;
+        MP_CHECKOK(mp_init(&tpy, FLAG(n)));
+        MP_CHECKOK(mp_init(&tpz, FLAG(n)));
+        MP_CHECKOK(mp_init(&tpaz4, FLAG(n)));
         MP_CHECKOK(mp_init(&rz, FLAG(n)));
         MP_CHECKOK(mp_init(&raz4, FLAG(n)));
 
@@ -295,19 +312,64 @@
         /* Compute 5NAF */
         ec_compute_wNAF(naf, orderBitSize, n, 5);
 
+        numAdds = 0;
+        numDoubles = orderBitSize;
         /* wNAF method */
         for (i = orderBitSize; i >= 0; i--) {
+
+                if (ec_GFp_pt_is_inf_jac(rx, ry, &rz) == MP_YES) {
+                  numDoubles--;
+                }
+
                 /* R = 2R */
                 ec_GFp_pt_dbl_jm(rx, ry, &rz, &raz4, rx, ry, &rz,
                                              &raz4, scratch, group);
+
                 if (naf[i] != 0) {
                         ec_GFp_pt_add_jm_aff(rx, ry, &rz, &raz4,
                                                                  &precomp[(naf[i] + 15) / 2][0],
                                                                  &precomp[(naf[i] + 15) / 2][1], rx, ry,
                                                                  &rz, &raz4, scratch, group);
+                        numAdds++;
                 }
         }
 
+        /* extra operations to make timing less dependent on secrets */
+        if (timing) {
+                /* low-order bit of timing argument contains no entropy */
+                timing >>= 1;
+
+                MP_CHECKOK(ec_GFp_pt_set_inf_jac(&tpx, &tpy, &tpz));
+                mp_zero(&tpaz4);
+
+                /* Set the temp value to a non-infinite point */
+                ec_GFp_pt_add_jm_aff(&tpx, &tpy, &tpz, &tpaz4,
+                                                                 &precomp[8][0],
+                                                                 &precomp[8][1], &tpx, &tpy,
+                                                                 &tpz, &tpaz4, scratch, group);
+
+                /* two bits of extra adds */
+                extraAdds = timing & 0x3;
+                timing >>= 2;
+                /* Window size is 5, so the maximum number of additions is ceil(orderBitSize/5) */
+                /* This is the same as (orderBitSize + 4) / 5 */
+                for(i = numAdds; i <= (orderBitSize + 4) / 5 + extraAdds; i++) {
+                        ec_GFp_pt_add_jm_aff(&tpx, &tpy, &tpz, &tpaz4,
+                                                                 &precomp[9 + (i % 3)][0],
+                                                                 &precomp[9 + (i % 3)][1], &tpx, &tpy,
+                                                                 &tpz, &tpaz4, scratch, group);
+                }
+
+                /* two bits of extra doubles */
+                extraDoubles = timing & 0x3;
+                timing >>= 2;
+                for(i = numDoubles; i <= orderBitSize + extraDoubles; i++) {
+                        ec_GFp_pt_dbl_jm(&tpx, &tpy, &tpz, &tpaz4, &tpx, &tpy, &tpz,
+                                             &tpaz4, scratch, group);
+                }
+
+        }
+
         /* convert result S to affine coordinates */
         MP_CHECKOK(ec_GFp_pt_jac2aff(rx, ry, &rz, rx, ry, group));
 
@@ -321,6 +383,8 @@
         }
         mp_clear(&tpx);
         mp_clear(&tpy);
+        mp_clear(&tpz);
+        mp_clear(&tpaz4);
         mp_clear(&rz);
         mp_clear(&raz4);
 #ifdef _KERNEL
diff --git a/src/jdk.management.agent/share/classes/sun/management/jmxremote/SingleEntryRegistry.java b/src/jdk.management.agent/share/classes/sun/management/jmxremote/SingleEntryRegistry.java
index 998b00a..c29df19 100644
--- a/src/jdk.management.agent/share/classes/sun/management/jmxremote/SingleEntryRegistry.java
+++ b/src/jdk.management.agent/share/classes/sun/management/jmxremote/SingleEntryRegistry.java
@@ -32,6 +32,7 @@
 
 package sun.management.jmxremote;
 
+import java.io.ObjectInputFilter;
 import java.rmi.AccessException;
 import java.rmi.NotBoundException;
 import java.rmi.Remote;
@@ -56,7 +57,7 @@
                         String name,
                         Remote object)
             throws RemoteException {
-        super(port, csf, ssf);
+        super(port, csf, ssf, SingleEntryRegistry::singleRegistryFilter);
         this.name = name;
         this.object = object;
     }
@@ -84,6 +85,23 @@
         throw new AccessException("Cannot modify this registry");
     }
 
+    /**
+     * ObjectInputFilter to check parameters to SingleEntryRegistry.
+     * Since it is a read-only Registry, no classes are accepted.
+     * String arguments are accepted without passing them to the serialFilter.
+     *
+     * @param info a reference to the serialization filter information
+     * @return Status.REJECTED if parameters are out of range
+     */
+    private static ObjectInputFilter.Status singleRegistryFilter(ObjectInputFilter.FilterInfo info) {
+        return (info.serialClass() != null ||
+                info.depth() > 2 ||
+                info.references() > 4 ||
+                info.arrayLength() >= 0)
+        ? ObjectInputFilter.Status.REJECTED
+        : ObjectInputFilter.Status.ALLOWED;
+    }
+
     private final String name;
     private final Remote object;
 
diff --git a/src/jdk.management/share/classes/com/sun/management/HotSpotDiagnosticMXBean.java b/src/jdk.management/share/classes/com/sun/management/HotSpotDiagnosticMXBean.java
index 40d79a2..c79d511 100644
--- a/src/jdk.management/share/classes/com/sun/management/HotSpotDiagnosticMXBean.java
+++ b/src/jdk.management/share/classes/com/sun/management/HotSpotDiagnosticMXBean.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -61,9 +61,10 @@
      * @param  outputFile the system-dependent filename
      * @param  live if {@code true} dump only <i>live</i> objects
      *         i.e. objects that are reachable from others
-     * @throws IOException if the {@code outputFile}
+     * @throws IOException if the {@code outputFile} already exists,
      *                     cannot be created, opened, or written to.
      * @throws UnsupportedOperationException if this operation is not supported.
+     * @throws IllegalArgumentException if {@code outputFile} does not end with ".hprof" suffix.
      * @throws NullPointerException if {@code outputFile} is {@code null}.
      * @throws SecurityException
      *         If a security manager exists and its {@link
diff --git a/src/jdk.management/share/classes/com/sun/management/internal/HotSpotDiagnostic.java b/src/jdk.management/share/classes/com/sun/management/internal/HotSpotDiagnostic.java
index 5b9d8ef..4edf6ad 100644
--- a/src/jdk.management/share/classes/com/sun/management/internal/HotSpotDiagnostic.java
+++ b/src/jdk.management/share/classes/com/sun/management/internal/HotSpotDiagnostic.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,7 +22,6 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-
 package com.sun.management.internal;
 
 import java.io.IOException;
@@ -32,6 +31,8 @@
 
 import com.sun.management.HotSpotDiagnosticMXBean;
 import com.sun.management.VMOption;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import sun.management.Util;
 
 /**
@@ -43,6 +44,14 @@
 
     @Override
     public void dumpHeap(String outputFile, boolean live) throws IOException {
+
+        String propertyName = "jdk.management.heapdump.allowAnyFileSuffix";
+        PrivilegedAction<Boolean> pa = () -> Boolean.parseBoolean(System.getProperty(propertyName, "false"));
+        boolean allowAnyFileSuffix = AccessController.doPrivileged(pa);
+        if (!allowAnyFileSuffix && !outputFile.endsWith(".hprof")) {
+            throw new IllegalArgumentException("heapdump file must have .hprof extention");
+        }
+
         SecurityManager security = System.getSecurityManager();
         if (security != null) {
             security.checkWrite(outputFile);
diff --git a/test/java/rmi/activation/nonLocalActivation/NonLocalActivationTest.java b/test/java/rmi/activation/nonLocalActivation/NonLocalActivationTest.java
new file mode 100644
index 0000000..55cea96
--- /dev/null
+++ b/test/java/rmi/activation/nonLocalActivation/NonLocalActivationTest.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.net.InetAddress;
+import java.rmi.AccessException;
+import java.rmi.activation.ActivationSystem;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import java.util.Set;
+
+/*
+ * @test
+ * @bug 8174770
+ * @summary Verify that ActivationSystem rejects non-local access.
+ *    The test is manual because the (non-local) host running rmid must be supplied as a property.
+ * @run main/manual/othervm -Dactivation.host=rmid-host NonLocalActivationTest
+ */
+
+/**
+ * Lookup the ActivationSystem on a different host and invoke its remote interface methods.
+ * They should all throw an exception, non-local access is prohibited.
+ *
+ * This test is a manual test and uses rmid running on a *different* host.
+ * The default port (1098) for the Activation System is ok and expected.
+ * Login or ssh to the different host and invoke {@code $JDK_HOME/bin/rmid}.
+ * It will not show any output.
+ *
+ * On the first host modify the @run command above to replace "rmid-host"
+ * with the hostname or IP address of the different host and run the test with jtreg.
+ */
+public class NonLocalActivationTest
+{
+    public static void main(String[] args) throws Exception {
+
+        String host = System.getProperty("activation.host");
+        if (host == null || host.isEmpty()) {
+            throw new RuntimeException("Specify host with system property: -Dactivation.host=<host>");
+        }
+
+        // Check if running the test on a local system; it only applies to remote
+        String myHostName = InetAddress.getLocalHost().getHostName();
+        Set<InetAddress> myAddrs = Set.of(InetAddress.getAllByName(myHostName));
+        Set<InetAddress> hostAddrs = Set.of(InetAddress.getAllByName(host));
+        if (hostAddrs.stream().anyMatch(i -> myAddrs.contains(i))
+                || hostAddrs.stream().anyMatch(h -> h.isLoopbackAddress())) {
+            throw new RuntimeException("Error: property 'activation.host' must not be the local host%n");
+        }
+
+        // Locate the registry operated by the ActivationSystem
+        // Test SystemRegistryImpl
+        Registry registry = LocateRegistry.getRegistry(host, ActivationSystem.SYSTEM_PORT);
+        try {
+            // Verify it is an ActivationSystem registry
+            registry.lookup("java.rmi.activation.ActivationSystem");
+        } catch (Exception nf) {
+            throw new RuntimeException("Not a ActivationSystem registry, does not contain java.rmi.activation.ActivationSystem", nf);
+        }
+
+        try {
+            registry.bind("foo", null);
+            throw new RuntimeException("Remote access should not succeed for method: bind");
+        } catch (Exception e) {
+            assertIsAccessException(e, "Registry.bind");
+        }
+
+        try {
+            registry.rebind("foo", null);
+            throw new RuntimeException("Remote access should not succeed for method: rebind");
+        } catch (Exception e) {
+            assertIsAccessException(e, "Registry.rebind");
+        }
+
+        try {
+            registry.unbind("foo");
+            throw new RuntimeException("Remote access should not succeed for method: unbind");
+        } catch (Exception e) {
+            assertIsAccessException(e, "Registry.unbind");
+        }
+
+
+        // Locate the ActivationSystem on the specified host and default port.
+        // Test each of the ActivationSystem methods
+        ActivationSystem as = (ActivationSystem) registry.lookup("java.rmi.activation.ActivationSystem");
+
+        // Argument is not material, access check is before arg processing
+
+        try {
+            as.registerGroup(null);
+        } catch (Exception aex) {
+            assertIsAccessException(aex, "ActivationSystem.nonLocalAccess");
+        }
+
+        try {
+            as.getActivationDesc(null);
+        } catch (Exception aex) {
+            assertIsAccessException(aex, "ActivationSystem.nonLocalAccess");
+        }
+
+        try {
+            as.getActivationGroupDesc(null);
+        } catch (Exception aex) {
+            assertIsAccessException(aex, "ActivationSystem.nonLocalAccess");
+        }
+
+        try {
+            as.registerObject(null);
+        } catch (Exception aex) {
+            assertIsAccessException(aex, "ActivationSystem.nonLocalAccess");
+        }
+
+        try {
+            as.unregisterGroup(null);
+        } catch (Exception aex) {
+            assertIsAccessException(aex, "ActivationSystem.nonLocalAccess");
+        }
+
+        try {
+            as.unregisterObject(null);
+        } catch (Exception aex) {
+            assertIsAccessException(aex, "ActivationSystem.nonLocalAccess");
+        }
+
+        try {
+            as.setActivationDesc(null, null);
+        } catch (Exception aex) {
+            assertIsAccessException(aex, "ActivationSystem.nonLocalAccess");
+        }
+
+        try {
+            as.setActivationGroupDesc(null, null);
+        } catch (Exception aex) {
+            assertIsAccessException(aex, "ActivationSystem.nonLocalAccess");
+        }
+    }
+
+    /**
+     * Check the exception chain for the expected AccessException and message.
+     * @param ex the exception from the remote invocation.
+     */
+    private static void assertIsAccessException(Exception ex, String msg1) {
+        Throwable t = ex;
+        System.out.println();
+        while (!(t instanceof AccessException) && t.getCause() != null) {
+            t = t.getCause();
+        }
+        if (t instanceof AccessException) {
+            String msg = t.getMessage();
+            int asIndex = msg.indexOf(msg1);
+            int disallowIndex = msg.indexOf("disallowed");
+            int nonLocalHostIndex = msg.indexOf("non-local host");
+            if (asIndex < 0 ||
+                    disallowIndex < 0 ||
+                    nonLocalHostIndex < 0 ) {
+                throw new RuntimeException("exception message is malformed", t);
+            }
+            System.out.printf("Found expected AccessException: %s%n", t);
+        } else {
+            throw new RuntimeException("AccessException did not occur", ex);
+        }
+    }
+}
diff --git a/test/java/rmi/registry/nonLocalRegistry/NonLocalRegistryTest.java b/test/java/rmi/registry/nonLocalRegistry/NonLocalRegistryTest.java
new file mode 100644
index 0000000..7dd1476
--- /dev/null
+++ b/test/java/rmi/registry/nonLocalRegistry/NonLocalRegistryTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.net.InetAddress;
+import java.rmi.AccessException;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import java.util.Set;
+
+/* @test
+ * @bug 8174770
+ * @summary Verify that Registry rejects non-local access for bind, unbind, rebind.
+ *    The test is manual because the (non-local) host running rmiregistry must be supplied as a property.
+ * @run main/othervm/manual -Dregistry.host=rmi-registry-host NonLocalRegistryTest
+ */
+
+/**
+ * Verify that access checks for Registry.bind(), .rebind(), and .unbind()
+ * are prevented on remote access to the registry.
+ *
+ * This test is a manual test and uses a standard rmiregistry running
+ * on a *different* host.
+ * The test verifies that the access check is performed *before* the object to be
+ * bound or rebound is deserialized.
+ *
+ * Login or ssh to the different host and invoke {@code $JDK_HOME/bin/rmiregistry}.
+ * It will not show any output.
+ *
+ * On the first host modify the @run command above to replace "rmi-registry-host"
+ * with the hostname or IP address of the different host and run the test with jtreg.
+ */
+public class NonLocalRegistryTest {
+
+    public static void main(String[] args) throws Exception {
+
+        String host = System.getProperty("registry.host");
+        if (host == null || host.isEmpty()) {
+            throw new RuntimeException("Specify host with system property: -Dregistry.host=<host>");
+        }
+
+        // Check if running the test on a local system; it only applies to remote
+        String myHostName = InetAddress.getLocalHost().getHostName();
+        Set<InetAddress> myAddrs = Set.of(InetAddress.getAllByName(myHostName));
+        Set<InetAddress> hostAddrs = Set.of(InetAddress.getAllByName(host));
+        if (hostAddrs.stream().anyMatch(i -> myAddrs.contains(i))
+                || hostAddrs.stream().anyMatch(h -> h.isLoopbackAddress())) {
+            throw new RuntimeException("Error: property 'registry.host' must not be the local host%n");
+        }
+
+        Registry registry = LocateRegistry.getRegistry(host, Registry.REGISTRY_PORT);
+
+        try {
+            registry.bind("foo", null);
+            throw new RuntimeException("Remote access should not succeed for method: bind");
+        } catch (Exception e) {
+            assertIsAccessException(e);
+        }
+
+        try {
+            registry.rebind("foo", null);
+            throw new RuntimeException("Remote access should not succeed for method: rebind");
+        } catch (Exception e) {
+            assertIsAccessException(e);
+        }
+
+        try {
+            registry.unbind("foo");
+            throw new RuntimeException("Remote access should not succeed for method: unbind");
+        } catch (Exception e) {
+            assertIsAccessException(e);
+        }
+    }
+
+    /**
+     * Check the exception chain for the expected AccessException and message.
+     * @param ex the exception from the remote invocation.
+     */
+    private static void assertIsAccessException(Throwable ex) {
+        Throwable t = ex;
+        while (!(t instanceof AccessException) && t.getCause() != null) {
+            t = t.getCause();
+        }
+        if (t instanceof AccessException) {
+            String msg = t.getMessage();
+            int asIndex = msg.indexOf("Registry");
+            int rrIndex = msg.indexOf("Registry.Registry");     // Obsolete error text
+            int disallowIndex = msg.indexOf("disallowed");
+            int nonLocalHostIndex = msg.indexOf("non-local host");
+            if (asIndex < 0 ||
+                    rrIndex != -1 ||
+                    disallowIndex < 0 ||
+                    nonLocalHostIndex < 0 ) {
+                throw new RuntimeException("exception message is malformed", t);
+            }
+            System.out.printf("Found expected AccessException: %s%n%n", t);
+        } else {
+            throw new RuntimeException("AccessException did not occur when expected", ex);
+        }
+    }
+}
diff --git a/test/java/rmi/testlibrary/TestSocketFactory.java b/test/java/rmi/testlibrary/TestSocketFactory.java
new file mode 100644
index 0000000..b320ef0
--- /dev/null
+++ b/test/java/rmi/testlibrary/TestSocketFactory.java
@@ -0,0 +1,602 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.ByteArrayOutputStream;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.net.SocketOption;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.rmi.server.RMIClientSocketFactory;
+import java.rmi.server.RMIServerSocketFactory;
+import java.rmi.server.RMISocketFactory;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+import org.testng.Assert;
+import org.testng.TestNG;
+import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+
+
+/**
+ * A RMISocketFactory utility factory to log RMI stream contents and to
+ * match and replace output stream contents to simulate failures.
+ */
+public class TestSocketFactory extends RMISocketFactory
+        implements RMIClientSocketFactory, RMIServerSocketFactory, Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private volatile transient byte[] matchBytes;
+
+    private volatile transient byte[] replaceBytes;
+
+    private transient final List<InterposeSocket> sockets = new ArrayList<>();
+
+    private transient final List<InterposeServerSocket> serverSockets = new ArrayList<>();
+
+    public static final boolean DEBUG = false;
+
+    /**
+     * Debugging output can be synchronized with logging of RMI actions.
+     *
+     * @param format a printf format
+     * @param args   any args
+     */
+    private static void DEBUG(String format, Object... args) {
+        if (DEBUG) {
+            System.err.printf(format, args);
+        }
+    }
+
+    /**
+     * Create a socket factory that creates InputStreams that log
+     * and OutputStreams that log .
+     */
+    public TestSocketFactory() {
+        this.matchBytes = new byte[0];
+        this.replaceBytes = this.matchBytes;
+        System.out.printf("Creating TestSocketFactory()%n");
+    }
+
+    public void setMatchReplaceBytes(byte[] matchBytes, byte[] replaceBytes) {
+        this.matchBytes = Objects.requireNonNull(matchBytes, "matchBytes");
+        this.replaceBytes = Objects.requireNonNull(replaceBytes, "replaceBytes");
+        sockets.forEach( s -> s.setMatchReplaceBytes(matchBytes, replaceBytes));
+        serverSockets.forEach( s -> s.setMatchReplaceBytes(matchBytes, replaceBytes));
+
+    }
+
+    @Override
+    public Socket createSocket(String host, int port) throws IOException {
+        Socket socket = RMISocketFactory.getDefaultSocketFactory()
+                .createSocket(host, port);
+        InterposeSocket s = new InterposeSocket(socket, matchBytes, replaceBytes);
+        sockets.add(s);
+        return s;
+    }
+
+    /**
+     * Return the current list of sockets.
+     * @return Return a snapshot of the current list of sockets
+     */
+    public List<InterposeSocket> getSockets() {
+        List<InterposeSocket> snap = new ArrayList<>(sockets);
+        return snap;
+    }
+
+    @Override
+    public ServerSocket createServerSocket(int port) throws IOException {
+
+        ServerSocket serverSocket = RMISocketFactory.getDefaultSocketFactory()
+                .createServerSocket(port);
+        InterposeServerSocket ss = new InterposeServerSocket(serverSocket, matchBytes, replaceBytes);
+        serverSockets.add(ss);
+        return ss;
+    }
+
+    /**
+     * Return the current list of server sockets.
+     * @return Return a snapshot of the current list of server sockets
+     */
+    public List<InterposeServerSocket> getServerSockets() {
+        List<InterposeServerSocket> snap = new ArrayList<>(serverSockets);
+        return snap;
+    }
+
+    /**
+     * An InterposeSocket wraps a socket that produces InputStreams
+     * and OutputStreams that log the traffic.
+     * The OutputStreams it produces match an array of bytes and replace them.
+     * Useful for injecting protocol and content errors.
+     */
+    public static class InterposeSocket extends Socket {
+        private final Socket socket;
+        private InputStream in;
+        private MatchReplaceOutputStream out;
+        private volatile byte[] matchBytes;
+        private volatile byte[] replaceBytes;
+        private final ByteArrayOutputStream inLogStream;
+        private final ByteArrayOutputStream outLogStream;
+        private final String name;
+        private static volatile int num = 0;    // index for created InterposeSockets
+
+        public InterposeSocket(Socket socket, byte[] matchBytes, byte[] replaceBytes) {
+            this.socket = socket;
+            this.matchBytes = Objects.requireNonNull(matchBytes, "matchBytes");
+            this.replaceBytes = Objects.requireNonNull(replaceBytes, "replaceBytes");
+            this.inLogStream = new ByteArrayOutputStream();
+            this.outLogStream = new ByteArrayOutputStream();
+            this.name = "IS" + ++num + "::"
+                    + Thread.currentThread().getName() + ": "
+                    + socket.getLocalPort() + " <  " + socket.getPort();
+        }
+
+        public void setMatchReplaceBytes(byte[] matchBytes, byte[] replaceBytes) {
+            this.matchBytes = matchBytes;
+            this.replaceBytes = replaceBytes;
+            out.setMatchReplaceBytes(matchBytes, replaceBytes);
+        }
+
+        @Override
+        public void connect(SocketAddress endpoint) throws IOException {
+            socket.connect(endpoint);
+        }
+
+        @Override
+        public void connect(SocketAddress endpoint, int timeout) throws IOException {
+            socket.connect(endpoint, timeout);
+        }
+
+        @Override
+        public void bind(SocketAddress bindpoint) throws IOException {
+            socket.bind(bindpoint);
+        }
+
+        @Override
+        public InetAddress getInetAddress() {
+            return socket.getInetAddress();
+        }
+
+        @Override
+        public InetAddress getLocalAddress() {
+            return socket.getLocalAddress();
+        }
+
+        @Override
+        public int getPort() {
+            return socket.getPort();
+        }
+
+        @Override
+        public int getLocalPort() {
+            return socket.getLocalPort();
+        }
+
+        @Override
+        public SocketAddress getRemoteSocketAddress() {
+            return socket.getRemoteSocketAddress();
+        }
+
+        @Override
+        public SocketAddress getLocalSocketAddress() {
+            return socket.getLocalSocketAddress();
+        }
+
+        @Override
+        public SocketChannel getChannel() {
+            return socket.getChannel();
+        }
+
+        @Override
+        public synchronized void close() throws IOException {
+            socket.close();
+        }
+
+        @Override
+        public String toString() {
+            return "InterposeSocket " + name + ": " + socket.toString();
+        }
+
+        @Override
+        public boolean isConnected() {
+            return socket.isConnected();
+        }
+
+        @Override
+        public boolean isBound() {
+            return socket.isBound();
+        }
+
+        @Override
+        public boolean isClosed() {
+            return socket.isClosed();
+        }
+
+        @Override
+        public <T> Socket setOption(SocketOption<T> name, T value) throws IOException {
+            return socket.setOption(name, value);
+        }
+
+        @Override
+        public <T> T getOption(SocketOption<T> name) throws IOException {
+            return socket.getOption(name);
+        }
+
+        @Override
+        public Set<SocketOption<?>> supportedOptions() {
+            return socket.supportedOptions();
+        }
+
+        @Override
+        public synchronized InputStream getInputStream() throws IOException {
+            if (in == null) {
+                in = socket.getInputStream();
+                String name = Thread.currentThread().getName() + ": "
+                        + socket.getLocalPort() + " <  " + socket.getPort();
+                in = new LoggingInputStream(in, name, inLogStream);
+                DEBUG("Created new InterposeInputStream: %s%n", name);
+            }
+            return in;
+        }
+
+        @Override
+        public synchronized OutputStream getOutputStream() throws IOException {
+            if (out == null) {
+                OutputStream o = socket.getOutputStream();
+                String name = Thread.currentThread().getName() + ": "
+                        + socket.getLocalPort() + "  > " + socket.getPort();
+                out = new MatchReplaceOutputStream(o, name, outLogStream, matchBytes, replaceBytes);
+                DEBUG("Created new MatchReplaceOutputStream: %s%n", name);
+            }
+            return out;
+        }
+
+        /**
+         * Return the bytes logged from the input stream.
+         * @return Return the bytes logged from the input stream.
+         */
+        public byte[] getInLogBytes() {
+            return inLogStream.toByteArray();
+        }
+
+        /**
+         * Return the bytes logged from the output stream.
+         * @return Return the bytes logged from the output stream.
+         */
+        public byte[] getOutLogBytes() {
+            return outLogStream.toByteArray();
+        }
+
+    }
+
+    /**
+     * InterposeServerSocket is a ServerSocket that wraps each Socket it accepts
+     * with an InterposeSocket so that its input and output streams can be monitored.
+     */
+    public static class InterposeServerSocket extends ServerSocket {
+        private final ServerSocket socket;
+        private volatile byte[] matchBytes;
+        private volatile byte[] replaceBytes;
+        private final List<InterposeSocket> sockets = new ArrayList<>();
+
+        public InterposeServerSocket(ServerSocket socket, byte[] matchBytes, byte[] replaceBytes) throws IOException {
+            this.socket = socket;
+            this.matchBytes = Objects.requireNonNull(matchBytes, "matchBytes");
+            this.replaceBytes = Objects.requireNonNull(replaceBytes, "replaceBytes");
+        }
+
+        public void setMatchReplaceBytes(byte[] matchBytes, byte[] replaceBytes) {
+            this.matchBytes = matchBytes;
+            this.replaceBytes = replaceBytes;
+            sockets.forEach(s -> s.setMatchReplaceBytes(matchBytes, replaceBytes));
+        }
+        /**
+         * Return a snapshot of the current list of sockets created from this server socket.
+         * @return Return a snapshot of the current list of sockets
+         */
+        public List<InterposeSocket> getSockets() {
+            List<InterposeSocket> snap = new ArrayList<>(sockets);
+            return snap;
+        }
+
+        @Override
+        public void bind(SocketAddress endpoint) throws IOException {
+            socket.bind(endpoint);
+        }
+
+        @Override
+        public void bind(SocketAddress endpoint, int backlog) throws IOException {
+            socket.bind(endpoint, backlog);
+        }
+
+        @Override
+        public InetAddress getInetAddress() {
+            return socket.getInetAddress();
+        }
+
+        @Override
+        public int getLocalPort() {
+            return socket.getLocalPort();
+        }
+
+        @Override
+        public SocketAddress getLocalSocketAddress() {
+            return socket.getLocalSocketAddress();
+        }
+
+        @Override
+        public Socket accept() throws IOException {
+            Socket s = socket.accept();
+            InterposeSocket socket = new InterposeSocket(s, matchBytes, replaceBytes);
+            sockets.add(socket);
+            return socket;
+        }
+
+        @Override
+        public void close() throws IOException {
+            socket.close();
+        }
+
+        @Override
+        public ServerSocketChannel getChannel() {
+            return socket.getChannel();
+        }
+
+        @Override
+        public boolean isClosed() {
+            return socket.isClosed();
+        }
+
+        @Override
+        public String toString() {
+            return socket.toString();
+        }
+
+        @Override
+        public <T> ServerSocket setOption(SocketOption<T> name, T value) throws IOException {
+            return socket.setOption(name, value);
+        }
+
+        @Override
+        public <T> T getOption(SocketOption<T> name) throws IOException {
+            return socket.getOption(name);
+        }
+
+        @Override
+        public Set<SocketOption<?>> supportedOptions() {
+            return socket.supportedOptions();
+        }
+
+        @Override
+        public synchronized void setSoTimeout(int timeout) throws SocketException {
+            socket.setSoTimeout(timeout);
+        }
+
+        @Override
+        public synchronized int getSoTimeout() throws IOException {
+            return socket.getSoTimeout();
+        }
+    }
+
+    /**
+     * LoggingInputStream is a stream and logs all bytes read to it.
+     * For identification it is given a name.
+     */
+    public static class LoggingInputStream extends FilterInputStream {
+        private int bytesIn = 0;
+        private final String name;
+        private final OutputStream log;
+
+        public LoggingInputStream(InputStream in, String name, OutputStream log) {
+            super(in);
+            this.name = name;
+            this.log = log;
+        }
+
+        @Override
+        public int read() throws IOException {
+            int b = super.read();
+            if (b >= 0) {
+                log.write(b);
+                bytesIn++;
+            }
+            return b;
+        }
+
+        @Override
+        public int read(byte[] b, int off, int len) throws IOException {
+            int bytes = super.read(b, off, len);
+            if (bytes > 0) {
+                log.write(b, off, bytes);
+                bytesIn += bytes;
+            }
+            return bytes;
+        }
+
+        @Override
+        public int read(byte[] b) throws IOException {
+            return read(b, 0, b.length);
+        }
+
+        @Override
+        public void close() throws IOException {
+            super.close();
+        }
+
+        @Override
+        public String toString() {
+            return String.format("%s: In: (%d)", name, bytesIn);
+        }
+    }
+
+    /**
+     * An OutputStream that replaces one string of bytes with another.
+     * If any range matches, the match starts after the partial match.
+     */
+    static class MatchReplaceOutputStream extends OutputStream {
+        private final OutputStream out;
+        private final String name;
+        private volatile byte[] matchBytes;
+        private volatile byte[] replaceBytes;
+        int matchIndex;
+        private int bytesOut = 0;
+        private final OutputStream log;
+
+        MatchReplaceOutputStream(OutputStream out, String name, OutputStream log,
+                                 byte[] matchBytes, byte[] replaceBytes) {
+            this.out = out;
+            this.name = name;
+            this.matchBytes = Objects.requireNonNull(matchBytes, "matchBytes");
+            this.replaceBytes = Objects.requireNonNull(replaceBytes, "replaceBytes");
+            matchIndex = 0;
+            this.log = log;
+        }
+
+        public void setMatchReplaceBytes(byte[] matchBytes, byte[] replaceBytes) {
+            this.matchBytes = matchBytes;
+            this.replaceBytes = replaceBytes;
+            matchIndex = 0;
+        }
+
+
+        public void write(int b) throws IOException {
+            b = b & 0xff;
+            if (matchBytes.length == 0) {
+                out.write(b);
+                log.write(b);
+                bytesOut++;
+                return;
+            }
+            if (b == (matchBytes[matchIndex] & 0xff)) {
+                if (++matchIndex >= matchBytes.length) {
+                    matchIndex = 0;
+                    DEBUG( "TestSocketFactory MatchReplace %s replaced %d bytes at offset: %d (x%04x)%n",
+                            name, replaceBytes.length, bytesOut, bytesOut);
+                    out.write(replaceBytes);
+                    log.write(replaceBytes);
+                    bytesOut += replaceBytes.length;
+                }
+            } else {
+                if (matchIndex > 0) {
+                    // mismatch, write out any that matched already
+                    if (matchIndex > 0) // Only non-trivial matches
+                        DEBUG( "Partial match %s matched %d bytes at offset: %d (0x%04x), expected: x%02x, actual: x%02x%n",
+                                name, matchIndex, bytesOut, bytesOut,  matchBytes[matchIndex], b);
+                    out.write(matchBytes, 0, matchIndex);
+                    log.write(matchBytes, 0, matchIndex);
+                    bytesOut += matchIndex;
+                    matchIndex = 0;
+                }
+                if (b == (matchBytes[matchIndex] & 0xff)) {
+                    matchIndex++;
+                } else {
+                    out.write(b);
+                    log.write(b);
+                    bytesOut++;
+                }
+            }
+        }
+
+        @Override
+        public String toString() {
+            return String.format("%s: Out: (%d)", name, bytesOut);
+        }
+    }
+
+    private static byte[] orig = new byte[]{
+            (byte) 0x80, 0x05,
+            0x73, 0x72, 0x00, 0x12, // TC_OBJECT, TC_CLASSDESC, length = 18
+            0x6A, 0x61, 0x76, 0x61, 0x2E, 0x72, 0x6D, 0x69, 0x2E, // "java.rmi."
+            0x64, 0x67, 0x63, 0x2E, 0x4C, 0x65, 0x61, 0x73, 0x65  // "dgc.Lease"
+    };
+    private static byte[] repl = new byte[]{
+            (byte) 0x80, 0x05,
+            0x73, 0x72, 0x00, 0x12, // TC_OBJECT, TC_CLASSDESC, length = 18
+            0x6A, 0x61, 0x76, 0x61, 0x2E, (byte) 'l', (byte) 'a', (byte) 'n', (byte) 'g',
+            0x2E, (byte) 'R', (byte) 'u', (byte) 'n', (byte) 'n', (byte) 'a', (byte) 'b', (byte) 'l',
+            (byte) 'e'
+    };
+
+    @DataProvider(name = "MatchReplaceData")
+    static Object[][] matchReplaceData() {
+        byte[] empty = new byte[0];
+        byte[] byte1 = new byte[]{1, 2, 3, 4, 5, 6};
+        byte[] bytes2 = new byte[]{1, 2, 4, 3, 5, 6};
+        byte[] bytes3 = new byte[]{6, 5, 4, 3, 2, 1};
+        byte[] bytes4 = new byte[]{1, 2, 0x10, 0x20, 0x30, 0x40, 5, 6};
+        byte[] bytes4a = new byte[]{1, 2, 0x10, 0x20, 0x30, 0x40, 5, 7};  // mostly matches bytes4
+        byte[] bytes5 = new byte[]{0x30, 0x40, 5, 6};
+        byte[] bytes6 = new byte[]{1, 2, 0x10, 0x20, 0x30};
+
+        return new Object[][]{
+                {new byte[]{}, new byte[]{}, empty, empty},
+                {new byte[]{}, new byte[]{}, byte1, byte1},
+                {new byte[]{3, 4}, new byte[]{4, 3}, byte1, bytes2}, //swap bytes
+                {new byte[]{3, 4}, new byte[]{0x10, 0x20, 0x30, 0x40}, byte1, bytes4}, // insert
+                {new byte[]{1, 2, 0x10, 0x20}, new byte[]{}, bytes4, bytes5}, // delete head
+                {new byte[]{0x40, 5, 6}, new byte[]{}, bytes4, bytes6},   // delete tail
+                {new byte[]{0x40, 0x50}, new byte[]{0x60, 0x50}, bytes4, bytes4}, // partial match, replace nothing
+                {bytes4a, bytes3, bytes4, bytes4}, // long partial match, not replaced
+                {orig, repl, orig, repl},
+        };
+    }
+
+    @Test(enabled = true, dataProvider = "MatchReplaceData")
+    static void test3(byte[] match, byte[] replace,
+                      byte[] input, byte[] expected) {
+        System.out.printf("match: %s, replace: %s%n", Arrays.toString(match), Arrays.toString(replace));
+        try (ByteArrayOutputStream output = new ByteArrayOutputStream();
+        ByteArrayOutputStream log = new ByteArrayOutputStream();
+             OutputStream out = new MatchReplaceOutputStream(output, "test3",
+                     log, match, replace)) {
+            out.write(input);
+            byte[] actual = output.toByteArray();
+            long index = Arrays.mismatch(actual, expected);
+
+            if (index >= 0) {
+                System.out.printf("array mismatch, offset: %d%n", index);
+                System.out.printf("actual: %s%n", Arrays.toString(actual));
+                System.out.printf("expected: %s%n", Arrays.toString(expected));
+            }
+            Assert.assertEquals(actual, expected, "match/replace fail");
+        } catch (IOException ioe) {
+            Assert.fail("unexpected exception", ioe);
+        }
+    }
+
+
+
+}
diff --git a/test/javax/management/remote/nonLocalAccess/NonLocalJMXRemoteTest.java b/test/javax/management/remote/nonLocalAccess/NonLocalJMXRemoteTest.java
new file mode 100644
index 0000000..d05aff1
--- /dev/null
+++ b/test/javax/management/remote/nonLocalAccess/NonLocalJMXRemoteTest.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.net.InetAddress;
+import java.rmi.AccessException;
+import java.rmi.NotBoundException;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import java.util.Set;
+
+/* @test
+ * @bug 8174770
+ * @summary Verify that JMX Registry rejects non-local access for bind, unbind, rebind.
+ *    The test is manual because the (non-local) host and port running JMX must be supplied as properties.
+ * @run main/othervm/manual -Djmx-registry.host=jmx-registry-host -Djmx-registry.port=jmx-registry-port NonLocalJMXRemoteTest
+ */
+
+/**
+ * Verify that access checks for the Registry exported by JMX Registry.bind(),
+ * .rebind(), and .unbind() are prevented on remote access to the registry.
+ * The test verifies that the access check is performed *before* the object to be
+ * bound or rebound is deserialized.
+ * This tests the SingleEntryRegistry implemented by JMX.
+ * This test is a manual test and uses JMX running on a *different* host.
+ * JMX can be enabled in any Java runtime; for example:
+ * login or ssh to the different host and invoke rmiregistry with arguments below.
+ * It will not show any output.
+ * {@code $JDK_HOME/bin/rmiregistry \
+ *         -J-Dcom.sun.management.jmxremote.port=8888 \
+ *         -J-Dcom.sun.management.jmxremote.local.only=false \
+ *         -J-Dcom.sun.management.jmxremote.ssl=false \
+ *         -J-Dcom.sun.management.jmxremote.authenticate=false
+ * }
+ * On the first host modify the @run command above to replace "jmx-registry-host"
+ * with the hostname or IP address of the different host and run the test with jtreg.
+ */
+public class NonLocalJMXRemoteTest {
+
+    public static void main(String[] args) throws Exception {
+
+        String host = System.getProperty("jmx-registry.host");
+        if (host == null || host.isEmpty()) {
+            throw new RuntimeException("Specify host with system property: -Djmx-registry.host=<host>");
+        }
+        int port = Integer.getInteger("jmx-registry.port", -1);
+        if (port <= 0) {
+            throw new RuntimeException("Specify port with system property: -Djmx-registry.port=<port>");
+        }
+
+        // Check if running the test on a local system; it only applies to remote
+        String myHostName = InetAddress.getLocalHost().getHostName();
+        Set<InetAddress> myAddrs = Set.of(InetAddress.getAllByName(myHostName));
+        Set<InetAddress> hostAddrs = Set.of(InetAddress.getAllByName(host));
+        if (hostAddrs.stream().anyMatch(i -> myAddrs.contains(i))
+                || hostAddrs.stream().anyMatch(h -> h.isLoopbackAddress())) {
+            throw new RuntimeException("Error: property 'jmx-registry.host' must not be the local host%n");
+        }
+
+        Registry registry = LocateRegistry.getRegistry(host, port);
+        try {
+            // Verify it is a JMX Registry
+            registry.lookup("jmxrmi");
+        } catch (NotBoundException nf) {
+            throw new RuntimeException("Not a JMX registry, jmxrmi is not bound", nf);
+        }
+
+        try {
+            registry.bind("foo", null);
+            throw new RuntimeException("Remote access should not succeed for method: bind");
+        } catch (Exception e) {
+            assertIsAccessException(e);
+        }
+
+        try {
+            registry.rebind("foo", null);
+            throw new RuntimeException("Remote access should not succeed for method: rebind");
+        } catch (Exception e) {
+            assertIsAccessException(e);
+        }
+
+        try {
+            registry.unbind("foo");
+            throw new RuntimeException("Remote access should not succeed for method: unbind");
+        } catch (Exception e) {
+            assertIsAccessException(e);
+        }
+    }
+
+    /**
+     * Check the exception chain for the expected AccessException and message.
+     * @param ex the exception from the remote invocation.
+     */
+    private static void assertIsAccessException(Throwable ex) {
+        Throwable t = ex;
+        while (!(t instanceof AccessException) && t.getCause() != null) {
+            t = t.getCause();
+        }
+        if (t instanceof AccessException) {
+            String msg = t.getMessage();
+            int asIndex = msg.indexOf("Registry");
+            int disallowIndex = msg.indexOf("disallowed");
+            int nonLocalHostIndex = msg.indexOf("non-local host");
+            if (asIndex < 0 ||
+                    disallowIndex < 0 ||
+                    nonLocalHostIndex < 0 ) {
+                throw new RuntimeException("exception message is malformed", t);
+            }
+            System.out.printf("Found expected AccessException: %s%n%n", t);
+        } else {
+            throw new RuntimeException("AccessException did not occur when expected", ex);
+        }
+    }
+}