changeset 8836:1d98f0be7c8d tip

Merge from main OpenJDK repository
author Greg Lewis <glewis@eyesbeyond.com>
date Sat, 03 Feb 2018 21:37:28 -0800
parents 6b21d823f6e6 2a7d0883d64a
children
files .hgtags make/com/sun/java/pack/Makefile make/common/Defs.gmk make/common/Program.gmk make/java/jli/Makefile make/java/security/Makefile make/java/zip/Makefile make/sun/splashscreen/Makefile src/share/classes/sun/security/provider/certpath/CrlRevocationChecker.java src/share/classes/sun/security/provider/certpath/OCSPChecker.java src/share/native/java/util/zip/zlib-1.2.8/ChangeLog src/share/native/java/util/zip/zlib-1.2.8/README src/share/native/java/util/zip/zlib-1.2.8/compress.c src/share/native/java/util/zip/zlib-1.2.8/crc32.h src/share/native/java/util/zip/zlib-1.2.8/deflate.c src/share/native/java/util/zip/zlib-1.2.8/deflate.h src/share/native/java/util/zip/zlib-1.2.8/gzclose.c src/share/native/java/util/zip/zlib-1.2.8/gzguts.h src/share/native/java/util/zip/zlib-1.2.8/gzlib.c src/share/native/java/util/zip/zlib-1.2.8/gzread.c src/share/native/java/util/zip/zlib-1.2.8/gzwrite.c src/share/native/java/util/zip/zlib-1.2.8/infback.c src/share/native/java/util/zip/zlib-1.2.8/inffast.c src/share/native/java/util/zip/zlib-1.2.8/inffast.h src/share/native/java/util/zip/zlib-1.2.8/inffixed.h src/share/native/java/util/zip/zlib-1.2.8/inflate.c src/share/native/java/util/zip/zlib-1.2.8/inflate.h src/share/native/java/util/zip/zlib-1.2.8/inftrees.c src/share/native/java/util/zip/zlib-1.2.8/inftrees.h src/share/native/java/util/zip/zlib-1.2.8/patches/ChangeLog_java src/share/native/java/util/zip/zlib-1.2.8/trees.c src/share/native/java/util/zip/zlib-1.2.8/trees.h src/share/native/java/util/zip/zlib-1.2.8/uncompr.c src/share/native/java/util/zip/zlib-1.2.8/zadler32.c src/share/native/java/util/zip/zlib-1.2.8/zconf.h src/share/native/java/util/zip/zlib-1.2.8/zcrc32.c src/share/native/java/util/zip/zlib-1.2.8/zlib.h src/share/native/java/util/zip/zlib-1.2.8/zutil.c src/share/native/java/util/zip/zlib-1.2.8/zutil.h src/solaris/native/java/net/bsd_close.c src/solaris/native/java/net/net_util_md.c src/solaris/native/java/net/net_util_md.h test/sun/security/tools/keytool/autotest.sh test/sun/security/tools/keytool/standard.sh
diffstat 339 files changed, 33172 insertions(+), 21105 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Thu Sep 07 23:37:21 2017 -0700
+++ b/.hgtags	Sat Feb 03 21:37:28 2018 -0800
@@ -603,3 +603,5 @@
 19a085e656145471455d7fbd648717f94281a729 jdk7u141-b02
 871e3350966f67b95768a94c1854f1515cfa56ca jdk7u151-b00
 da1c09ab9b742fa77c0e667c2218b8d626432656 jdk7u151-b01
+18a07ae9631c8a06df924e3ff5b025cbf2295620 jdk7u161-b00
+48c4e54f7870bb2e6982ab946267f61e9d4f14d2 jdk7u161-b01
--- a/THIRD_PARTY_README	Thu Sep 07 23:37:21 2017 -0700
+++ b/THIRD_PARTY_README	Sat Feb 03 21:37:28 2018 -0800
@@ -3134,12 +3134,12 @@
 
 -------------------------------------------------------------------------------
 
-%% This notice is provided with respect to zlib v1.2.3, which is included 
+%% This notice is provided with respect to zlib v1.2.11, which may be included 
 with JRE 7, JDK 7, and OpenJDK 7
 
 --- begin of LICENSE ---
 
-  version 1.2.3, July 18th, 2005
+  version 1.2.11, January 15th, 2017
 
   Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
 
--- a/make/com/sun/java/pack/Makefile	Thu Sep 07 23:37:21 2017 -0700
+++ b/make/com/sun/java/pack/Makefile	Sat Feb 03 21:37:28 2018 -0800
@@ -72,7 +72,7 @@
 	     $(ZIPOBJDIR)/inftrees.$(OBJECT_SUFFIX) \
 	     $(ZIPOBJDIR)/inffast.$(OBJECT_SUFFIX)
 
-  ZINCLUDE=-I$(SHARE_SRC)/native/java/util/zip/zlib-$(ZLIB_VERSION)
+  ZINCLUDE=-I$(SHARE_SRC)/native/java/util/zip/zlib
   OTHER_CXXFLAGS += $(ZINCLUDE)
   LDDFLAGS += $(ZIPOBJS)
  else
--- a/make/common/Defs.gmk	Thu Sep 07 23:37:21 2017 -0700
+++ b/make/common/Defs.gmk	Sat Feb 03 21:37:28 2018 -0800
@@ -214,12 +214,6 @@
 endif
 
 #
-# zlib version
-#
-ZLIB_VERSION = 1.2.8
-
-
-#
 # Localizations for the different parts of the product beyond English
 #
 
--- a/make/common/Program.gmk	Thu Sep 07 23:37:21 2017 -0700
+++ b/make/common/Program.gmk	Sat Feb 03 21:37:28 2018 -0800
@@ -394,7 +394,7 @@
   OTHER_INCLUDES += -I$(LAUNCHER_SOLARIS_PLATFORM_SRC)/bin
 endif # PLATFORM !MACOSX
 ifneq ($(SYSTEM_ZLIB), true)
-  OTHER_INCLUDES += -I$(SHARE_SRC)/native/java/util/zip/zlib-1.2.8
+  OTHER_INCLUDES += -I$(SHARE_SRC)/native/java/util/zip/zlib
 endif # SYSTEM_ZLIB
 
 OTHER_CPPFLAGS  += -DPROGNAME='"$(PROGRAM)"'
--- a/make/java/jli/Makefile	Thu Sep 07 23:37:21 2017 -0700
+++ b/make/java/jli/Makefile	Sat Feb 03 21:37:28 2018 -0800
@@ -45,7 +45,7 @@
 include $(BUILDDIR)/common/Defs.gmk
 
 ifneq ($(SYSTEM_ZLIB),true)
-  ZIP_SRC = $(SHARE_SRC)/native/java/util/zip/zlib-$(ZLIB_VERSION)
+  ZIP_SRC = $(SHARE_SRC)/native/java/util/zip/zlib
 else # SYSTEM_ZLIB
   OTHER_CFLAGS += $(ZLIB_CFLAGS)
 endif #SYSTEM_ZLIB
--- a/make/java/security/Makefile	Thu Sep 07 23:37:21 2017 -0700
+++ b/make/java/security/Makefile	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,6 @@
 #
 # Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2017 Red Hat, Inc.
 # 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 +83,8 @@
 
 FILES_class = $(FILES_java:%.java=$(CLASSBINDIR)/%.class)
 
+CRYPTOLEVEL_JARFILE = $(BUILDTOOLJARDIR)/cryptolevel.jar
+
 #
 # Rules
 #
@@ -107,8 +110,16 @@
 
 trustedlibs: classes $(TRUSTEDLIBS_BUILD)
 
-$(PROPS_BUILD): $(PROPS_SRC)
-	$(install-file)
+$(PROPS_BUILD): $(PROPS_SRC) $(CRYPTOLEVEL_JARFILE)
+	$(prep-target)
+	$(RM) -f $@.tmp
+	$(CP) $< $@.tmp
+ifeq ($(UNLIMITED_CRYPTO), true)
+	  $(BOOT_JAVA_CMD) -jar $(CRYPTOLEVEL_JARFILE) \
+	    $@.tmp $@.tmp2 unlimited
+	  $(MV) $@.tmp2 $@.tmp
+endif
+	$(MV) $@.tmp $@
 
 $(POLICY_BUILD): $(POLICY_SRC)
 	$(install-file)
--- a/make/java/zip/Makefile	Thu Sep 07 23:37:21 2017 -0700
+++ b/make/java/zip/Makefile	Sat Feb 03 21:37:28 2018 -0800
@@ -31,10 +31,6 @@
 include $(BUILDDIR)/common/Defs.gmk
 
 #
-# ZLIB_VERSION is defined in make/common/Defs.gmk
-#
-
-#
 # Files to compile.
 #
 include FILES_c.gmk
@@ -92,12 +88,12 @@
 CPPFLAGS += -I$(PLATFORM_SRC)/native/java/io
 
 ifneq ($(SYSTEM_ZLIB),true)
-CPPFLAGS += -I$(SHARE_SRC)/native/java/util/zip/zlib-$(ZLIB_VERSION)
+CPPFLAGS += -I$(SHARE_SRC)/native/java/util/zip/zlib
 
 #
 # Add to ambient vpath so we pick up the library files
 #
-vpath %.c $(SHARE_SRC)/native/$(PKGDIR)/zlib-$(ZLIB_VERSION)
+vpath %.c $(SHARE_SRC)/native/$(PKGDIR)/zlib
 endif
 
 #
--- a/make/javax/crypto/Makefile	Thu Sep 07 23:37:21 2017 -0700
+++ b/make/javax/crypto/Makefile	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,6 @@
 #
 # Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2017 Red Hat, Inc.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -157,11 +158,7 @@
 #
 
 ifdef OPENJDK
-ifdef UNLIMITED_CRYPTO
-POLICY = install-unlimited
-else
-POLICY = install-limited
-endif
+POLICY = install-unlimited install-limited
 all: build-jar install-jar build-policy $(POLICY)
 else  # OPENJDK
 ifeq ($(strip $(FILES_java)),)
@@ -258,6 +255,8 @@
 #
 
 POLICY_DESTDIR			= $(LIBDIR)/security
+UNLIMITED_POLICY_DESTDIR	= $(POLICY_DESTDIR)/policy/unlimited
+LIMITED_POLICY_DESTDIR		= $(POLICY_DESTDIR)/policy/limited
 UNSIGNED_POLICY_BUILDDIR	= $(UNSIGNED_DIR)/policy
 
 build-policy: unlimited limited
@@ -432,11 +431,11 @@
 install-limited-jars: \
 	    $(INSTALL_POLICYDIR)/limited/US_export_policy.jar	\
 	    $(INSTALL_POLICYDIR)/limited/local_policy.jar
-	$(MKDIR) -p $(POLICY_DESTDIR)
+	$(MKDIR) -p $(LIMITED_POLICY_DESTDIR)
 	$(RM) \
-	    $(POLICY_DESTDIR)/US_export_policy.jar		\
-	    $(POLICY_DESTDIR)/local_policy.jar
-	$(CP) $^ $(POLICY_DESTDIR)
+	    $(LIMITED_POLICY_DESTDIR)/US_export_policy.jar		\
+	    $(LIMITED_POLICY_DESTDIR)/local_policy.jar
+	$(CP) $^ $(LIMITED_POLICY_DESTDIR)
 
 install-limited: install-limited-jars
 ifndef OPENJDK
@@ -446,11 +445,11 @@
 install-unlimited-jars: \
 	    $(INSTALL_POLICYDIR)/unlimited/US_export_policy.jar	\
 	    $(INSTALL_POLICYDIR)/unlimited/local_policy.jar 
-	$(MKDIR) -p $(POLICY_DESTDIR)
+	$(MKDIR) -p $(UNLIMITED_POLICY_DESTDIR)
 	$(RM) \
-	    $(POLICY_DESTDIR)/US_export_policy.jar		\
-	    $(POLICY_DESTDIR)/local_policy.jar
-	$(CP) $^ $(POLICY_DESTDIR)
+	    $(UNLIMITED_POLICY_DESTDIR)/US_export_policy.jar		\
+	    $(UNLIMITED_POLICY_DESTDIR)/local_policy.jar
+	$(CP) $^ $(UNLIMITED_POLICY_DESTDIR)
 
 install-unlimited: install-unlimited-jars
 ifndef OPENJDK
@@ -477,8 +476,11 @@
 #
 
 clobber clean::
-	$(RM) -r $(JAR_DESTFILE) $(POLICY_DESTDIR)/US_export_policy.jar \
-	    $(POLICY_DESTDIR)/local_policy.jar $(DELETE_DIRS) $(TEMPDIR) \
+	$(RM) -r $(JAR_DESTFILE) $(LIMITED_POLICY_DESTDIR)/US_export_policy.jar \
+	    $(LIMITED_POLICY_DESTDIR)/local_policy.jar \
+	    $(UNLIMITED_POLICY_DESTDIR)/US_export_policy.jar \
+	    $(UNLIMITED_POLICY_DESTDIR)/local_policy.jar \
+	    $(DELETE_DIRS) $(TEMPDIR) \
 	    $(JCE_BUILD_DIR)
 
 .PHONY: build-jar jar build-policy unlimited limited install-jar \
--- a/make/sun/splashscreen/Makefile	Thu Sep 07 23:37:21 2017 -0700
+++ b/make/sun/splashscreen/Makefile	Sat Feb 03 21:37:28 2018 -0800
@@ -122,7 +122,7 @@
 vpath %.c   $(SHARE_SRC)/native/$(PKGDIR)
 vpath %.c   $(SHARE_SRC)/native/$(PKGDIR)/giflib
 ifneq ($(SYSTEM_ZLIB),true)
-  vpath %.c   $(SHARE_SRC)/native/java/util/zip/zlib-$(ZLIB_VERSION)
+  vpath %.c   $(SHARE_SRC)/native/java/util/zip/zlib
 endif
 vpath %.c   $(SHARE_SRC)/native/$(PKGDIR)/libpng
 vpath %.c   $(SHARE_SRC)/native/$(PKGDIR)/image/jpeg
@@ -138,7 +138,11 @@
   CPPFLAGS += $(call NativeSrcDirList,-I,native/$(PKGDIR)/splashscreen)
   CPPFLAGS += $(call NativeSrcDirList,-I,/native/sun/osxapp)
 endif
-ifeq ($(SYSTEM_ZLIB),true)
+CPPFLAGS += -I$(SHARE_SRC)/native/$(PKGDIR)/splashscreen
+CPPFLAGS += -I$(SHARE_SRC)/native/$(PKGDIR)/image/jpeg
+ifneq ($(SYSTEM_ZLIB),true)
+  CPPFLAGS += -I$(SHARE_SRC)/native/java/util/zip/zlib
+else
   OTHER_CFLAGS += $(ZLIB_CFLAGS)
   OTHER_LDLIBS += $(ZLIB_LIBS)
 endif
--- a/make/tools/Makefile	Thu Sep 07 23:37:21 2017 -0700
+++ b/make/tools/Makefile	Sat Feb 03 21:37:28 2018 -0800
@@ -37,6 +37,7 @@
   commentchecker            \
   compile_font_config       \
   compile_properties        \
+  customizesecurityfile     \
   dir_diff                  \
   dtdbuilder                \
   generate_break_iterator   \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/tools/customizesecurityfile/Makefile	Sat Feb 03 21:37:28 2018 -0800
@@ -0,0 +1,43 @@
+#
+# Copyright 2017 Red Hat, Inc.
+# 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.
+#
+
+#
+# Makefile for building the CryptoLevel tool
+#
+
+BUILDDIR = ../..
+PACKAGE = build.tools.customizesecurityfile
+PRODUCT = tools
+PROGRAM = cryptolevel
+include $(BUILDDIR)/common/Defs.gmk
+
+BUILDTOOL_SOURCE_ROOT = $(BUILDDIR)/tools/src
+BUILDTOOL_MAIN        = $(PKGDIR)/CryptoLevel.java
+
+#
+# Build tool jar rules.
+#
+include $(BUILDDIR)/common/BuildToolJar.gmk
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/tools/src/build/tools/customizesecurityfile/CryptoLevel.java	Sat Feb 03 21:37:28 2018 -0800
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package build.tools.customizesecurityfile;
+
+import java.io.*;
+
+/**
+ * Alters the crypto.policy security property
+ * if --enable-unlimited-crypto is enabled.
+ */
+public class CryptoLevel {
+
+    private static final String PROP_NAME = "crypto.policy";
+
+    public static void main(String[] args) throws Exception {
+        boolean fileModified = false;
+
+        if (args.length < 3) {
+            System.err.println("Usage: java CryptoLevel" +
+                               "[input java.security file name] " +
+                               "[output java.security file name] " +
+                               "[unlimited|limited]");
+            System.exit(1);
+        }
+        if (!args[2].equals("unlimited") && !args[2].equals("limited")) {
+            System.err.println("CryptoLevel error: Unexpected " +
+                "input: " + args[2]);
+            System.exit(1);
+        }
+
+        FileReader fr = null;
+        BufferedReader br = null;
+        FileWriter fw = null;
+        BufferedWriter bw = null;
+        try {
+            fr = new FileReader(args[0]);
+            br = new BufferedReader(fr);
+            fw = new FileWriter(args[1]);
+            bw = new BufferedWriter(fw);
+            // parse the file line-by-line, looking for crypto.policy
+            String line = br.readLine();
+            while (line != null) {
+                if (line.startsWith('#' + PROP_NAME) ||
+                    line.startsWith(PROP_NAME)) {
+                    writeLine(bw, PROP_NAME + "=" + args[2]);
+                    fileModified = true;
+                } else {
+                    writeLine(bw, line);
+                }
+                line = br.readLine();
+            }
+            if (!fileModified) {
+                //no previous setting seen. Insert at end
+                writeLine(bw, PROP_NAME + "=" + args[2]);
+            }
+            bw.flush();
+        } finally {
+            if (br != null) { br.close(); }
+            if (bw != null) { bw.close(); }
+            if (fr != null) { fr.close(); }
+            if (fw != null) { fw.close(); }
+        }
+    }
+
+    private static void writeLine(BufferedWriter bw, String line)
+        throws IOException
+    {
+        bw.write(line);
+        bw.newLine();
+    }
+}
--- a/src/share/classes/com/sun/crypto/provider/AESCipher.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/com/sun/crypto/provider/AESCipher.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2012, 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
@@ -140,7 +140,7 @@
                 throw new InvalidKeyException("Key encoding must not be null");
             } else if (value.length != fixedKeySize) {
                 throw new InvalidKeyException("The key must be " +
-                    fixedKeySize*8 + " bits");
+                    fixedKeySize + " bytes");
             }
         }
     }
@@ -479,7 +479,7 @@
             throw new InvalidKeyException("Invalid AES key length: " +
                                           encoded.length + " bytes");
         }
-        return encoded.length * 8;
+        return CipherCore.multiplyExact(encoded.length, 8);
     }
 
     /**
--- a/src/share/classes/com/sun/crypto/provider/AESWrapCipher.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/com/sun/crypto/provider/AESWrapCipher.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 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
@@ -156,7 +156,7 @@
         if (decrypting) {
             result = inputLen - 8;
         } else {
-            result = inputLen + 8;
+            result = CipherCore.addExact(inputLen, 8);
         }
         return (result < 0? 0:result);
     }
@@ -378,7 +378,7 @@
             throw new InvalidKeyException("Invalid key length: " +
                                           encoded.length + " bytes");
         }
-        return encoded.length * 8;
+        return CipherCore.multiplyExact(encoded.length, 8);
     }
 
     /**
@@ -404,7 +404,7 @@
             throw new InvalidKeyException("Cannot get an encoding of " +
                                           "the key to be wrapped");
         }
-        byte[] out = new byte[keyVal.length + 8];
+        byte[] out = new byte[CipherCore.addExact(keyVal.length, 8)];
 
         if (keyVal.length == 8) {
             System.arraycopy(IV, 0, out, 0, IV.length);
--- a/src/share/classes/com/sun/crypto/provider/ARCFOURCipher.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/com/sun/crypto/provider/ARCFOURCipher.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -257,7 +257,7 @@
     // see JCE spec
     protected int engineGetKeySize(Key key) throws InvalidKeyException {
         byte[] encodedKey = getEncodedKey(key);
-        return encodedKey.length << 3;
+        return CipherCore.multiplyExact(encodedKey.length, 8);
     }
 
 }
--- a/src/share/classes/com/sun/crypto/provider/BlowfishCipher.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/com/sun/crypto/provider/BlowfishCipher.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 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
@@ -373,7 +373,7 @@
      * @exception InvalidKeyException if <code>key</code> is invalid.
      */
     protected int engineGetKeySize(Key key) throws InvalidKeyException {
-        return (key.getEncoded().length * 8);
+        return CipherCore.multiplyExact(key.getEncoded().length, 8);
     }
 
     /**
--- a/src/share/classes/com/sun/crypto/provider/CipherBlockChaining.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/com/sun/crypto/provider/CipherBlockChaining.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,8 @@
 package com.sun.crypto.provider;
 
 import java.security.InvalidKeyException;
+import java.security.ProviderException;
+
 
 /**
  * This class represents ciphers in cipher block chaining (CBC) mode.
@@ -122,34 +124,36 @@
      *
      * <p>The input plain text <code>plain</code>, starting at
      * <code>plainOffset</code> and ending at
-     * <code>(plainOffset + len - 1)</code>, is encrypted.
+     * <code>(plainOffset + plainLen - 1)</code>, is encrypted.
      * The result is stored in <code>cipher</code>, starting at
      * <code>cipherOffset</code>.
      *
-     * <p>It is the application's responsibility to make sure that
-     * <code>plainLen</code> is a multiple of the embedded cipher's block size,
-     * as any excess bytes are ignored.
-     *
      * @param plain the buffer with the input data to be encrypted
      * @param plainOffset the offset in <code>plain</code>
      * @param plainLen the length of the input data
      * @param cipher the buffer for the result
      * @param cipherOffset the offset in <code>cipher</code>
+     * @exception ProviderException if <code>len</code> is not
+     * a multiple of the block size
+     * @return the length of the encrypted data
      */
-    void encrypt(byte[] plain, int plainOffset, int plainLen,
-                 byte[] cipher, int cipherOffset)
+    int encrypt(byte[] plain, int plainOffset, int plainLen,
+                byte[] cipher, int cipherOffset)
     {
-        int i;
+        if ((plainLen % blockSize) != 0) {
+            throw new ProviderException("Internal error in input buffering");
+        }
         int endIndex = plainOffset + plainLen;
 
         for (; plainOffset < endIndex;
              plainOffset+=blockSize, cipherOffset += blockSize) {
-            for (i=0; i<blockSize; i++) {
-                k[i] = (byte)(plain[i+plainOffset] ^ r[i]);
+            for (int i = 0; i < blockSize; i++) {
+                k[i] = (byte)(plain[i + plainOffset] ^ r[i]);
             }
             embeddedCipher.encryptBlock(k, 0, cipher, cipherOffset);
             System.arraycopy(cipher, cipherOffset, r, 0, blockSize);
         }
+        return plainLen;
     }
 
     /**
@@ -157,14 +161,10 @@
      *
      * <p>The input cipher text <code>cipher</code>, starting at
      * <code>cipherOffset</code> and ending at
-     * <code>(cipherOffset + len - 1)</code>, is decrypted.
+     * <code>(cipherOffset + cipherLen - 1)</code>, is decrypted.
      * The result is stored in <code>plain</code>, starting at
      * <code>plainOffset</code>.
      *
-     * <p>It is the application's responsibility to make sure that
-     * <code>cipherLen</code> is a multiple of the embedded cipher's block
-     * size, as any excess bytes are ignored.
-     *
      * <p>It is also the application's responsibility to make sure that
      * <code>init</code> has been called before this method is called.
      * (This check is omitted here, to avoid double checking.)
@@ -174,39 +174,26 @@
      * @param cipherLen the length of the input data
      * @param plain the buffer for the result
      * @param plainOffset the offset in <code>plain</code>
-     *
-     * @exception IllegalBlockSizeException if input data whose length does
-     * not correspond to the embedded cipher's block size is passed to the
-     * embedded cipher
+     * @exception ProviderException if <code>len</code> is not
+     * a multiple of the block size
+     * @return the length of the decrypted data
      */
-    void decrypt(byte[] cipher, int cipherOffset, int cipherLen,
-                 byte[] plain, int plainOffset)
+    int decrypt(byte[] cipher, int cipherOffset, int cipherLen,
+                byte[] plain, int plainOffset)
     {
-        int i;
-        byte[] cipherOrig=null;
+        if ((cipherLen % blockSize) != 0) {
+            throw new ProviderException("Internal error in input buffering");
+        }
         int endIndex = cipherOffset + cipherLen;
 
-        if (cipher==plain && (cipherOffset >= plainOffset)
-            && ((cipherOffset - plainOffset) < blockSize)) {
-            // Save the original ciphertext blocks, so they can be
-            // stored in the feedback register "r".
-            // This is necessary because in this constellation, a
-            // ciphertext block (or parts of it) will be overridden by
-            // the plaintext result.
-            cipherOrig = cipher.clone();
-        }
-
         for (; cipherOffset < endIndex;
              cipherOffset += blockSize, plainOffset += blockSize) {
             embeddedCipher.decryptBlock(cipher, cipherOffset, k, 0);
-            for (i = 0; i < blockSize; i++) {
-                plain[i+plainOffset] = (byte)(k[i] ^ r[i]);
+            for (int i = 0; i < blockSize; i++) {
+                plain[i + plainOffset] = (byte)(k[i] ^ r[i]);
             }
-            if (cipherOrig==null) {
-                System.arraycopy(cipher, cipherOffset, r, 0, blockSize);
-            } else {
-                System.arraycopy(cipherOrig, cipherOffset, r, 0, blockSize);
-            }
+            System.arraycopy(cipher, cipherOffset, r, 0, blockSize);
         }
+        return cipherLen;
     }
 }
--- a/src/share/classes/com/sun/crypto/provider/CipherCore.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/com/sun/crypto/provider/CipherCore.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2015, 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
@@ -25,6 +25,7 @@
 
 package com.sun.crypto.provider;
 
+import java.util.Arrays;
 import java.util.Locale;
 
 import java.security.*;
@@ -59,7 +60,7 @@
     private byte[] buffer = null;
 
     /*
-     * internal buffer
+     * block size of cipher in bytes
      */
     private int blockSize = 0;
 
@@ -76,7 +77,7 @@
     /*
      * minimum number of bytes in the buffer required for
      * FeedbackCipher.encryptFinal()/decryptFinal() call.
-     * update() must buffer this many bytes before before starting
+     * update() must buffer this many bytes before starting
      * to encrypt/decrypt data.
      * currently, only CTS mode has a non-zero value due to its special
      * handling on the last two blocks (the last one may be incomplete).
@@ -149,7 +150,7 @@
      * @param mode the cipher mode
      *
      * @exception NoSuchAlgorithmException if the requested cipher mode does
-     * not exist
+     * not exist for this cipher
      */
     void setMode(String mode) throws NoSuchAlgorithmException {
         if (mode == null)
@@ -165,30 +166,25 @@
         if (modeUpperCase.equals("CBC")) {
             cipherMode = CBC_MODE;
             cipher = new CipherBlockChaining(rawImpl);
-        }
-        else if (modeUpperCase.equals("CTS")) {
+        } else if (modeUpperCase.equals("CTS")) {
             cipherMode = CTS_MODE;
             cipher = new CipherTextStealing(rawImpl);
             minBytes = blockSize+1;
             padding = null;
-        }
-        else if (modeUpperCase.equals("CTR")) {
+        } else if (modeUpperCase.equals("CTR")) {
             cipherMode = CTR_MODE;
             cipher = new CounterMode(rawImpl);
             unitBytes = 1;
             padding = null;
-        }
-        else if (modeUpperCase.startsWith("CFB")) {
+        } else if (modeUpperCase.startsWith("CFB")) {
             cipherMode = CFB_MODE;
             unitBytes = getNumOfUnit(mode, "CFB".length(), blockSize);
             cipher = new CipherFeedback(rawImpl, unitBytes);
-        }
-        else if (modeUpperCase.startsWith("OFB")) {
+        } else if (modeUpperCase.startsWith("OFB")) {
             cipherMode = OFB_MODE;
             unitBytes = getNumOfUnit(mode, "OFB".length(), blockSize);
             cipher = new OutputFeedback(rawImpl, unitBytes);
-        }
-        else if (modeUpperCase.equals("PCBC")) {
+        } else if (modeUpperCase.equals("PCBC")) {
             cipherMode = PCBC_MODE;
             cipher = new PCBC(rawImpl);
         }
@@ -219,6 +215,7 @@
         return result;
     }
 
+
     /**
      * Sets the padding mechanism of this cipher.
      *
@@ -268,23 +265,30 @@
      * @return the required output buffer size (in bytes)
      */
     int getOutputSize(int inputLen) {
-        int totalLen = buffered + inputLen;
+        // estimate based on the maximum
+        return getOutputSizeByOperation(inputLen, true);
+    }
 
-        if (padding == null)
-            return totalLen;
-
-        if (decrypting)
-            return totalLen;
-
-        if (unitBytes != blockSize) {
-            if (totalLen < diffBlocksize)
-                return diffBlocksize;
-            else
-                return (totalLen + blockSize -
-                        ((totalLen - diffBlocksize) % blockSize));
-        } else {
-            return totalLen + padding.padLength(totalLen);
+    private int getOutputSizeByOperation(int inputLen, boolean isDoFinal) {
+        int totalLen = addExact(buffered, cipher.getBufferedLength());
+        totalLen = addExact(totalLen, inputLen);
+        switch (cipherMode) {
+        default:
+            if (padding != null && !decrypting) {
+                if (unitBytes != blockSize) {
+                    if (totalLen < diffBlocksize) {
+                        totalLen = diffBlocksize;
+                    } else {
+                        int residue = (totalLen - diffBlocksize) % blockSize;
+                        totalLen = addExact(totalLen, (blockSize - residue));
+                    }
+                } else {
+                    totalLen = addExact(totalLen, padding.padLength(totalLen));
+                }
+            }
+            break;
         }
+        return totalLen;
     }
 
     /**
@@ -318,34 +322,39 @@
      * does not use any parameters.
      */
     AlgorithmParameters getParameters(String algName) {
+        if (cipherMode == ECB_MODE) {
+            return null;
+        }
         AlgorithmParameters params = null;
-        if (cipherMode == ECB_MODE) return null;
+        AlgorithmParameterSpec spec;
         byte[] iv = getIV();
-        if (iv != null) {
-            AlgorithmParameterSpec ivSpec;
-            if (algName.equals("RC2")) {
-                RC2Crypt rawImpl = (RC2Crypt) cipher.getEmbeddedCipher();
-                ivSpec = new RC2ParameterSpec(rawImpl.getEffectiveKeyBits(),
-                                              iv);
-            } else {
-                ivSpec = new IvParameterSpec(iv);
-            }
-            try {
-                params = AlgorithmParameters.getInstance(algName, "SunJCE");
-            } catch (NoSuchAlgorithmException nsae) {
-                // should never happen
-                throw new RuntimeException("Cannot find " + algName +
-                    " AlgorithmParameters implementation in SunJCE provider");
-            } catch (NoSuchProviderException nspe) {
-                // should never happen
-                throw new RuntimeException("Cannot find SunJCE provider");
-            }
-            try {
-                params.init(ivSpec);
-            } catch (InvalidParameterSpecException ipse) {
-                // should never happen
-                throw new RuntimeException("IvParameterSpec not supported");
-            }
+        if (iv == null) {
+            // generate spec using default value
+            iv = new byte[blockSize];
+            SunJCE.RANDOM.nextBytes(iv);
+        }
+        if (algName.equals("RC2")) {
+            RC2Crypt rawImpl = (RC2Crypt) cipher.getEmbeddedCipher();
+            spec = new RC2ParameterSpec
+                (rawImpl.getEffectiveKeyBits(), iv);
+        } else {
+            spec = new IvParameterSpec(iv);
+        }
+        try {
+            params = AlgorithmParameters.getInstance(algName, "SunJCE");
+        } catch (NoSuchAlgorithmException nsae) {
+            // should never happen
+            throw new RuntimeException("Cannot find " + algName +
+                " AlgorithmParameters implementation in SunJCE provider");
+        } catch (NoSuchProviderException nspe) {
+            // should never happen
+            throw new RuntimeException("Cannot find SunJCE provider");
+        }
+        try {
+            params.init(spec);
+        } catch (InvalidParameterSpecException ipse) {
+            // should never happen
+            throw new RuntimeException(spec.getClass() + " not supported");
         }
         return params;
     }
@@ -420,40 +429,39 @@
                   || (opmode == Cipher.UNWRAP_MODE);
 
         byte[] keyBytes = getKeyBytes(key);
-
-        byte[] ivBytes;
-        if (params == null) {
-            ivBytes = null;
-        } else if (params instanceof IvParameterSpec) {
-            ivBytes = ((IvParameterSpec)params).getIV();
-            if ((ivBytes == null) || (ivBytes.length != blockSize)) {
+        int tagLen = -1;
+        byte[] ivBytes = null;
+        if (params != null) {
+            if (params instanceof IvParameterSpec) {
+                ivBytes = ((IvParameterSpec)params).getIV();
+                if ((ivBytes == null) || (ivBytes.length != blockSize)) {
+                    throw new InvalidAlgorithmParameterException
+                        ("Wrong IV length: must be " + blockSize +
+                         " bytes long");
+                }
+            } else if (params instanceof RC2ParameterSpec) {
+                ivBytes = ((RC2ParameterSpec)params).getIV();
+                if ((ivBytes != null) && (ivBytes.length != blockSize)) {
+                    throw new InvalidAlgorithmParameterException
+                        ("Wrong IV length: must be " + blockSize +
+                         " bytes long");
+                }
+            } else {
                 throw new InvalidAlgorithmParameterException
-                    ("Wrong IV length: must be " + blockSize +
-                    " bytes long");
+                    ("Unsupported parameter: " + params);
             }
-        } else if (params instanceof RC2ParameterSpec) {
-            ivBytes = ((RC2ParameterSpec)params).getIV();
-            if ((ivBytes != null) && (ivBytes.length != blockSize)) {
-                throw new InvalidAlgorithmParameterException
-                    ("Wrong IV length: must be " + blockSize +
-                    " bytes long");
-            }
-        } else {
-            throw new InvalidAlgorithmParameterException("Wrong parameter "
-                                                         + "type: IV "
-                                                         + "expected");
         }
-
         if (cipherMode == ECB_MODE) {
             if (ivBytes != null) {
                 throw new InvalidAlgorithmParameterException
                                                 ("ECB mode cannot use IV");
             }
-        } else if (ivBytes == null) {
+        } else if (ivBytes == null)  {
             if (decrypting) {
                 throw new InvalidAlgorithmParameterException("Parameters "
                                                              + "missing");
             }
+
             if (random == null) {
                 random = SunJCE.RANDOM;
             }
@@ -472,17 +480,21 @@
     void init(int opmode, Key key, AlgorithmParameters params,
               SecureRandom random)
         throws InvalidKeyException, InvalidAlgorithmParameterException {
-        IvParameterSpec ivSpec = null;
+        AlgorithmParameterSpec spec = null;
+        String paramType = null;
         if (params != null) {
             try {
-                ivSpec = params.getParameterSpec(IvParameterSpec.class);
+                // NOTE: RC2 parameters are always handled through
+                // init(..., AlgorithmParameterSpec,...) method, so
+                // we can assume IvParameterSpec type here.
+                paramType = "IV";
+                spec = params.getParameterSpec(IvParameterSpec.class);
             } catch (InvalidParameterSpecException ipse) {
-                throw new InvalidAlgorithmParameterException("Wrong parameter "
-                                                             + "type: IV "
-                                                             + "expected");
+                throw new InvalidAlgorithmParameterException
+                    ("Wrong parameter type: " + paramType + " expected");
             }
         }
-        init(opmode, key, ivSpec, random);
+        init(opmode, key, spec, random);
     }
 
     /**
@@ -504,6 +516,7 @@
         return keyBytes;
     }
 
+
     /**
      * Continues a multiple-part encryption or decryption operation
      * (depending on how this cipher was initialized), processing another data
@@ -525,21 +538,19 @@
      */
     byte[] update(byte[] input, int inputOffset, int inputLen) {
         byte[] output = null;
-        byte[] out = null;
         try {
-            output = new byte[getOutputSize(inputLen)];
+            output = new byte[getOutputSizeByOperation(inputLen, false)];
             int len = update(input, inputOffset, inputLen, output,
                              0);
             if (len == output.length) {
-                out = output;
+                return output;
             } else {
-                out = new byte[len];
-                System.arraycopy(output, 0, out, 0, len);
+                return Arrays.copyOf(output, len);
             }
         } catch (ShortBufferException e) {
-            // never thrown
+            // should never happen
+            throw new ProviderException("Unexpected exception", e);
         }
-        return out;
     }
 
     /**
@@ -568,72 +579,102 @@
     int update(byte[] input, int inputOffset, int inputLen, byte[] output,
                int outputOffset) throws ShortBufferException {
         // figure out how much can be sent to crypto function
-        int len = buffered + inputLen - minBytes;
+        int len = addExact(buffered, inputLen);
+        len -= minBytes;
         if (padding != null && decrypting) {
             // do not include the padding bytes when decrypting
             len -= blockSize;
         }
         // do not count the trailing bytes which do not make up a unit
-        len = (len > 0 ? (len - (len%unitBytes)) : 0);
+        len = (len > 0 ? (len - (len % unitBytes)) : 0);
 
         // check output buffer capacity
-        if ((output == null) || ((output.length - outputOffset) < len)) {
+        if ((output == null) ||
+            ((output.length - outputOffset) < len)) {
             throw new ShortBufferException("Output buffer must be "
                                            + "(at least) " + len
                                            + " bytes long");
         }
-        if (len != 0) {
-            // there is some work to do
-            byte[] in = new byte[len];
 
-            int inputConsumed = len - buffered;
-            int bufferedConsumed = buffered;
-            if (inputConsumed < 0) {
-                inputConsumed = 0;
-                bufferedConsumed = len;
+        int outLen = 0;
+        if (len != 0) { // there is some work to do
+            if ((input == output)
+                 && (outputOffset - inputOffset < inputLen)
+                 && (inputOffset - outputOffset < buffer.length)) {
+                // copy 'input' out to avoid its content being
+                // overwritten prematurely.
+                input = Arrays.copyOfRange(input, inputOffset,
+                    addExact(inputOffset, inputLen));
+                inputOffset = 0;
             }
-
-            if (buffered != 0) {
-                System.arraycopy(buffer, 0, in, 0, bufferedConsumed);
-            }
-            if (inputConsumed > 0) {
-                System.arraycopy(input, inputOffset, in,
-                                 bufferedConsumed, inputConsumed);
-            }
-
-            if (decrypting) {
-                cipher.decrypt(in, 0, len, output, outputOffset);
-            } else {
-                cipher.encrypt(in, 0, len, output, outputOffset);
+            if (len <= buffered) {
+                // all to-be-processed data are from 'buffer'
+                if (decrypting) {
+                    outLen = cipher.decrypt(buffer, 0, len, output, outputOffset);
+                } else {
+                    outLen = cipher.encrypt(buffer, 0, len, output, outputOffset);
+                }
+                buffered -= len;
+                if (buffered != 0) {
+                    System.arraycopy(buffer, len, buffer, 0, buffered);
+                }
+            } else { // len > buffered
+                int inputConsumed = len - buffered;
+                int temp;
+                if (buffered > 0) {
+                    int bufferCapacity = buffer.length - buffered;
+                    if (bufferCapacity != 0) {
+                        temp = Math.min(bufferCapacity, inputConsumed);
+                        if (unitBytes != blockSize) {
+                            temp -= (addExact(buffered, temp) % unitBytes);
+                        }
+                        System.arraycopy(input, inputOffset, buffer, buffered, temp);
+                        inputOffset = addExact(inputOffset, temp);
+                        inputConsumed -= temp;
+                        inputLen -= temp;
+                        buffered = addExact(buffered, temp);
+                    }
+                    // process 'buffer'
+                    if (decrypting) {
+                         outLen = cipher.decrypt(buffer, 0, buffered, output, outputOffset);
+                    } else {
+                         outLen = cipher.encrypt(buffer, 0, buffered, output, outputOffset);
+                    }
+                    outputOffset = addExact(outputOffset, outLen);
+                    buffered = 0;
+                }
+                if (inputConsumed > 0) { // still has input to process
+                    if (decrypting) {
+                        outLen += cipher.decrypt(input, inputOffset, inputConsumed,
+                            output, outputOffset);
+                    } else {
+                        outLen += cipher.encrypt(input, inputOffset, inputConsumed,
+                            output, outputOffset);
+                    }
+                    inputOffset += inputConsumed;
+                    inputLen -= inputConsumed;
+                }
             }
 
             // Let's keep track of how many bytes are needed to make
             // the total input length a multiple of blocksize when
             // padding is applied
             if (unitBytes != blockSize) {
-                if (len < diffBlocksize)
+                if (len < diffBlocksize) {
                     diffBlocksize -= len;
-                else
+                } else {
                     diffBlocksize = blockSize -
                         ((len - diffBlocksize) % blockSize);
-            }
-
-            inputLen -= inputConsumed;
-            inputOffset += inputConsumed;
-            outputOffset += len;
-            buffered -= bufferedConsumed;
-            if (buffered > 0) {
-                System.arraycopy(buffer, bufferedConsumed, buffer, 0,
-                                 buffered);
+                }
             }
         }
-        // left over again
+        // Store remaining input into 'buffer' again
         if (inputLen > 0) {
             System.arraycopy(input, inputOffset, buffer, buffered,
                              inputLen);
+            buffered = addExact(buffered, inputLen);
         }
-        buffered += inputLen;
-        return len;
+        return outLen;
     }
 
     /**
@@ -669,21 +710,18 @@
     byte[] doFinal(byte[] input, int inputOffset, int inputLen)
         throws IllegalBlockSizeException, BadPaddingException {
         byte[] output = null;
-        byte[] out = null;
         try {
-            output = new byte[getOutputSize(inputLen)];
+            output = new byte[getOutputSizeByOperation(inputLen, true)];
             int len = doFinal(input, inputOffset, inputLen, output, 0);
             if (len < output.length) {
-                out = new byte[len];
-                if (len != 0)
-                    System.arraycopy(output, 0, out, 0, len);
+                return Arrays.copyOf(output, len);
             } else {
-                out = output;
+                return output;
             }
         } catch (ShortBufferException e) {
             // never thrown
+            throw new ProviderException("Unexpected exception", e);
         }
-        return out;
     }
 
     /**
@@ -727,11 +765,24 @@
         throws IllegalBlockSizeException, ShortBufferException,
                BadPaddingException {
 
-        // calculate the total input length
-        int totalLen = buffered + inputLen;
-        int paddedLen = totalLen;
+        int estOutSize = getOutputSizeByOperation(inputLen, true);
+        // check output buffer capacity.
+        // if we are decrypting with padding applied, we can perform this
+        // check only after we have determined how many padding bytes there
+        // are.
+        int outputCapacity = output.length - outputOffset;
+        int minOutSize = (decrypting? (estOutSize - blockSize):estOutSize);
+        if ((output == null) || (outputCapacity < minOutSize)) {
+            throw new ShortBufferException("Output buffer must be "
+                + "(at least) " + minOutSize + " bytes long");
+        }
+
+        // calculate total input length
+        int len = addExact(buffered, inputLen);
+
+        // calculate padding length
+        int totalLen = addExact(len, cipher.getBufferedLength());
         int paddingLen = 0;
-
         // will the total input length be a multiple of blockSize?
         if (unitBytes != blockSize) {
             if (totalLen < diffBlocksize) {
@@ -744,39 +795,32 @@
             paddingLen = padding.padLength(totalLen);
         }
 
-        if ((paddingLen > 0) && (paddingLen != blockSize) &&
-            (padding != null) && decrypting) {
+        if (decrypting && (padding != null) &&
+            (paddingLen > 0) && (paddingLen != blockSize)) {
             throw new IllegalBlockSizeException
                 ("Input length must be multiple of " + blockSize +
                  " when decrypting with padded cipher");
         }
 
-        // if encrypting and padding not null, add padding
-        if (!decrypting && padding != null)
-            paddedLen += paddingLen;
-
-        // check output buffer capacity.
-        // if we are decrypting with padding applied, we can perform this
-        // check only after we have determined how many padding bytes there
-        // are.
-        if (output == null) {
-            throw new ShortBufferException("Output buffer is null");
-        }
-        int outputCapacity = output.length - outputOffset;
-        if (((!decrypting) || (padding == null)) &&
-            (outputCapacity < paddedLen) ||
-            (decrypting && (outputCapacity < (paddedLen - blockSize)))) {
-            throw new ShortBufferException("Output buffer too short: "
-                                           + outputCapacity + " bytes given, "
-                                           + paddedLen + " bytes needed");
-        }
-
-        // prepare the final input avoiding copying if possible
+        /*
+         * prepare the final input, assemble a new buffer if any
+         * of the following is true:
+         *  - 'input' and 'output' are the same buffer
+         *  - there are internally buffered bytes
+         *  - doing encryption and padding is needed
+         */
         byte[] finalBuf = input;
         int finalOffset = inputOffset;
-        if ((buffered != 0) || (!decrypting && padding != null)) {
+        int finalBufLen = inputLen;
+        if ((buffered != 0) || (!decrypting && padding != null) ||
+            ((input == output)
+              && (outputOffset - inputOffset < inputLen)
+              && (inputOffset - outputOffset < buffer.length))) {
+            if (decrypting || padding == null) {
+                paddingLen = 0;
+            }
+            finalBuf = new byte[addExact(len, paddingLen)];
             finalOffset = 0;
-            finalBuf = new byte[paddedLen];
             if (buffered != 0) {
                 System.arraycopy(buffer, 0, finalBuf, 0, buffered);
             }
@@ -784,48 +828,49 @@
                 System.arraycopy(input, inputOffset, finalBuf,
                                  buffered, inputLen);
             }
-            if (!decrypting && padding != null) {
-                padding.padWithLen(finalBuf, totalLen, paddingLen);
+            if (paddingLen != 0) {
+                padding.padWithLen(finalBuf, addExact(buffered, inputLen), paddingLen);
             }
+            finalBufLen = finalBuf.length;
         }
 
+        int outLen = 0;
         if (decrypting) {
             // if the size of specified output buffer is less than
             // the length of the cipher text, then the current
             // content of cipher has to be preserved in order for
             // users to retry the call with a larger buffer in the
             // case of ShortBufferException.
-            if (outputCapacity < paddedLen) {
+            if (outputCapacity < estOutSize) {
                 cipher.save();
             }
             // create temporary output buffer so that only "real"
             // data bytes are passed to user's output buffer.
-            byte[] outWithPadding = new byte[totalLen];
-            totalLen = finalNoPadding(finalBuf, finalOffset, outWithPadding,
-                                      0, totalLen);
+            byte[] outWithPadding = new byte[estOutSize];
+            outLen = finalNoPadding(finalBuf, finalOffset, outWithPadding,
+                                    0, finalBufLen);
 
             if (padding != null) {
-                int padStart = padding.unpad(outWithPadding, 0, totalLen);
+                int padStart = padding.unpad(outWithPadding, 0, outLen);
                 if (padStart < 0) {
                     throw new BadPaddingException("Given final block not "
                                                   + "properly padded");
                 }
-                totalLen = padStart;
+                outLen = padStart;
             }
-            if ((output.length - outputOffset) < totalLen) {
+            if (outputCapacity < outLen) {
                 // restore so users can retry with a larger buffer
                 cipher.restore();
                 throw new ShortBufferException("Output buffer too short: "
-                                               + (output.length-outputOffset)
-                                               + " bytes given, " + totalLen
+                                               + (outputCapacity)
+                                               + " bytes given, " + outLen
                                                + " bytes needed");
             }
-            for (int i = 0; i < totalLen; i++) {
-                output[outputOffset + i] = outWithPadding[i];
-            }
+            // copy the result into user-supplied output buffer
+            System.arraycopy(outWithPadding, 0, output, outputOffset, outLen);
         } else { // encrypting
-            totalLen = finalNoPadding(finalBuf, finalOffset, output,
-                                      outputOffset, paddedLen);
+                outLen = finalNoPadding(finalBuf, finalOffset, output,
+                                        outputOffset, finalBufLen);
         }
 
         buffered = 0;
@@ -833,12 +878,12 @@
         if (cipherMode != ECB_MODE) {
             cipher.reset();
         }
-        return totalLen;
+        return outLen;
     }
 
-    private int finalNoPadding(byte[] in, int inOff, byte[] out, int outOff,
+    private int finalNoPadding(byte[] in, int inOfs, byte[] out, int outOfs,
                                int len)
-        throws IllegalBlockSizeException
+        throws IllegalBlockSizeException, ShortBufferException
     {
         if (in == null || len == 0)
             return 0;
@@ -855,14 +900,13 @@
                      + " bytes");
             }
         }
-
+        int outLen = 0;
         if (decrypting) {
-            cipher.decryptFinal(in, inOff, len, out, outOff);
+            outLen = cipher.decryptFinal(in, inOfs, len, out, outOfs);
         } else {
-            cipher.encryptFinal(in, inOff, len, out, outOff);
+            outLen = cipher.encryptFinal(in, inOfs, len, out, outOfs);
         }
-
-        return len;
+        return outLen;
     }
 
     // Note: Wrap() and Unwrap() are the same in
@@ -939,4 +983,88 @@
         return ConstructKeys.constructKey(encodedKey, wrappedKeyAlgorithm,
                                           wrappedKeyType);
     }
+
+    /* Taken from java.lang.Math in OpenJDK 8 */
+
+    /**
+     * Returns the sum of its arguments,
+     * throwing an exception if the result overflows an {@code int}.
+     *
+     * @param x the first value
+     * @param y the second value
+     * @return the result
+     * @throws ArithmeticException if the result overflows an int
+     * @since 1.8
+     */
+    static int addExact(int x, int y) {
+        int r = x + y;
+        // HD 2-12 Overflow iff both arguments have the opposite sign of the result
+        if (((x ^ r) & (y ^ r)) < 0) {
+            throw new ArithmeticException("integer overflow");
+        }
+        return r;
+    }
+
+    /**
+     * Returns the sum of its arguments,
+     * throwing an exception if the result overflows a {@code long}.
+     *
+     * @param x the first value
+     * @param y the second value
+     * @return the result
+     * @throws ArithmeticException if the result overflows a long
+     * @since 1.8
+     */
+    static long addExact(long x, long y) {
+        long r = x + y;
+        // HD 2-12 Overflow iff both arguments have the opposite sign of the result
+        if (((x ^ r) & (y ^ r)) < 0) {
+            throw new ArithmeticException("long overflow");
+        }
+        return r;
+    }
+
+    /**
+     * Returns the product of the arguments,
+     * throwing an exception if the result overflows an {@code int}.
+     *
+     * @param x the first value
+     * @param y the second value
+     * @return the result
+     * @throws ArithmeticException if the result overflows an int
+     * @since 1.8
+     */
+    static int multiplyExact(int x, int y) {
+        long r = (long)x * (long)y;
+        if ((int)r != r) {
+            throw new ArithmeticException("integer overflow");
+        }
+        return (int)r;
+    }
+
+    /**
+     * Returns the product of the arguments,
+     * throwing an exception if the result overflows a {@code long}.
+     *
+     * @param x the first value
+     * @param y the second value
+     * @return the result
+     * @throws ArithmeticException if the result overflows a long
+     * @since 1.8
+     */
+    static long multiplyExact(long x, long y) {
+        long r = x * y;
+        long ax = Math.abs(x);
+        long ay = Math.abs(y);
+        if (((ax | ay) >>> 31 != 0)) {
+            // Some bits greater than 2^31 that might cause overflow
+            // Check the result using the divide operator
+            // and check for the special case of Long.MIN_VALUE * -1
+           if (((y != 0) && (r / y != x)) ||
+               (x == Long.MIN_VALUE && y == -1)) {
+                throw new ArithmeticException("long overflow");
+            }
+        }
+        return r;
+    }
 }
--- a/src/share/classes/com/sun/crypto/provider/CipherFeedback.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/com/sun/crypto/provider/CipherFeedback.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
 package com.sun.crypto.provider;
 
 import java.security.InvalidKeyException;
+import java.security.ProviderException;
 
 /**
  * This class represents ciphers in cipher-feedback (CFB) mode.
@@ -133,67 +134,75 @@
      *
      * <p>The input plain text <code>plain</code>, starting at
      * <code>plainOffset</code> and ending at
-     * <code>(plainOffset + len - 1)</code>, is encrypted.
+     * <code>(plainOffset + plainLen - 1)</code>, is encrypted.
      * The result is stored in <code>cipher</code>, starting at
      * <code>cipherOffset</code>.
      *
-     * <p>It is the application's responsibility to make sure that
-     * <code>plainLen</code> is a multiple of the stream unit size
-     * <code>numBytes</code>, as any excess bytes are ignored.
-     *
-     * <p>It is also the application's responsibility to make sure that
-     * <code>init</code> has been called before this method is called.
-     * (This check is omitted here, to avoid double checking.)
-     *
      * @param plain the buffer with the input data to be encrypted
      * @param plainOffset the offset in <code>plain</code>
      * @param plainLen the length of the input data
      * @param cipher the buffer for the result
      * @param cipherOffset the offset in <code>cipher</code>
+     * @exception ProviderException if <code>plainLen</code> is not
+     * a multiple of the <code>numBytes</code>
+     * @return the length of the encrypted data
      */
-    void encrypt(byte[] plain, int plainOffset, int plainLen,
-                        byte[] cipher, int cipherOffset)
-    {
-        int i, len;
-        len = blockSize - numBytes;
+    int encrypt(byte[] plain, int plainOffset, int plainLen,
+                byte[] cipher, int cipherOffset) {
+        if ((plainLen % numBytes) != 0) {
+            throw new ProviderException("Internal error in input buffering");
+        }
+
+        int nShift = blockSize - numBytes;
         int loopCount = plainLen / numBytes;
-        int oddBytes = plainLen % numBytes;
 
-        if (len == 0) {
-            for (; loopCount > 0 ;
-                 plainOffset += numBytes, cipherOffset += numBytes,
-                 loopCount--) {
-                embeddedCipher.encryptBlock(register, 0, k, 0);
-                for (i = 0; i < blockSize; i++)
-                    register[i] = cipher[i+cipherOffset] =
-                        (byte)(k[i] ^ plain[i+plainOffset]);
+        for (; loopCount > 0 ;
+             plainOffset += numBytes, cipherOffset += numBytes,
+             loopCount--) {
+            embeddedCipher.encryptBlock(register, 0, k, 0);
+            if (nShift != 0) {
+                System.arraycopy(register, numBytes, register, 0, nShift);
             }
-            if (oddBytes > 0) {
-                embeddedCipher.encryptBlock(register, 0, k, 0);
-                for (i=0; i<oddBytes; i++)
-                    register[i] = cipher[i+cipherOffset] =
-                        (byte)(k[i] ^ plain[i+plainOffset]);
-            }
-        } else {
-            for (; loopCount > 0 ;
-                 plainOffset += numBytes, cipherOffset += numBytes,
-                 loopCount--) {
-                embeddedCipher.encryptBlock(register, 0, k, 0);
-                System.arraycopy(register, numBytes, register, 0, len);
-                for (i=0; i<numBytes; i++)
-                    register[i+len] = cipher[i+cipherOffset] =
-                        (byte)(k[i] ^ plain[i+plainOffset]);
-
-            }
-            if (oddBytes != 0) {
-                embeddedCipher.encryptBlock(register, 0, k, 0);
-                System.arraycopy(register, numBytes, register, 0, len);
-                for (i=0; i<oddBytes; i++) {
-                    register[i+len] = cipher[i+cipherOffset] =
-                        (byte)(k[i] ^ plain[i+plainOffset]);
-                }
+            for (int i = 0; i < numBytes; i++) {
+                register[nShift + i] = cipher[i + cipherOffset] =
+                        (byte)(k[i] ^ plain[i + plainOffset]);
             }
         }
+        return plainLen;
+    }
+
+    /**
+     * Performs the last encryption operation.
+     *
+     * <p>The input plain text <code>plain</code>, starting at
+     * <code>plainOffset</code> and ending at
+     * <code>(plainOffset + plainLen - 1)</code>, is encrypted.
+     * The result is stored in <code>cipher</code>, starting at
+     * <code>cipherOffset</code>.
+     *
+     * @param plain the buffer with the input data to be encrypted
+     * @param plainOffset the offset in <code>plain</code>
+     * @param plainLen the length of the input data
+     * @param cipher the buffer for the result
+     * @param cipherOffset the offset in <code>cipher</code>
+     * @return the number of bytes placed into <code>cipher</code>
+     */
+    int encryptFinal(byte[] plain, int plainOffset, int plainLen,
+                     byte[] cipher, int cipherOffset) {
+
+        int oddBytes = plainLen % numBytes;
+        int len = encrypt(plain, plainOffset, (plainLen - oddBytes),
+                          cipher, cipherOffset);
+        plainOffset += len;
+        cipherOffset += len;
+        if (oddBytes != 0) {
+            embeddedCipher.encryptBlock(register, 0, k, 0);
+            for (int i = 0; i < oddBytes; i++) {
+                 cipher[i + cipherOffset] =
+                    (byte)(k[i] ^ plain[i + plainOffset]);
+            }
+        }
+        return plainLen;
     }
 
     /**
@@ -201,72 +210,75 @@
      *
      * <p>The input cipher text <code>cipher</code>, starting at
      * <code>cipherOffset</code> and ending at
-     * <code>(cipherOffset + len - 1)</code>, is decrypted.
+     * <code>(cipherOffset + cipherLen - 1)</code>, is decrypted.
      * The result is stored in <code>plain</code>, starting at
      * <code>plainOffset</code>.
      *
-     * <p>It is the application's responsibility to make sure that
-     * <code>cipherLen</code> is a multiple of the stream unit size
-     * <code>numBytes</code>, as any excess bytes are ignored.
-     *
-     * <p>It is also the application's responsibility to make sure that
-     * <code>init</code> has been called before this method is called.
-     * (This check is omitted here, to avoid double checking.)
-     *
      * @param cipher the buffer with the input data to be decrypted
      * @param cipherOffset the offset in <code>cipherOffset</code>
      * @param cipherLen the length of the input data
      * @param plain the buffer for the result
      * @param plainOffset the offset in <code>plain</code>
+     * @exception ProviderException if <code>cipherLen</code> is not
+     * a multiple of the <code>numBytes</code>
+     * @return the length of the decrypted data
      */
-    void decrypt(byte[] cipher, int cipherOffset, int cipherLen,
-                        byte[] plain, int plainOffset)
-    {
-        int i, len;
-        len = blockSize - numBytes;
+    int decrypt(byte[] cipher, int cipherOffset, int cipherLen,
+                byte[] plain, int plainOffset) {
+        if ((cipherLen % numBytes) != 0) {
+            throw new ProviderException("Internal error in input buffering");
+        }
+
+        int nShift = blockSize - numBytes;
         int loopCount = cipherLen / numBytes;
-        int oddBytes = cipherLen % numBytes;
 
-        if (len == 0) {
-            for (; loopCount > 0;
-                 plainOffset += numBytes, cipherOffset += numBytes,
-                 loopCount--) {
-                embeddedCipher.encryptBlock(register, 0, k, 0);
-                for (i = 0; i < blockSize; i++) {
-                    register[i] = cipher[i+cipherOffset];
-                    plain[i+plainOffset]
-                        = (byte)(cipher[i+cipherOffset] ^ k[i]);
-                }
+        for (; loopCount > 0;
+             plainOffset += numBytes, cipherOffset += numBytes,
+             loopCount--) {
+            embeddedCipher.encryptBlock(register, 0, k, 0);
+            if (nShift != 0) {
+                System.arraycopy(register, numBytes, register, 0, nShift);
             }
-            if (oddBytes > 0) {
-                embeddedCipher.encryptBlock(register, 0, k, 0);
-                for (i=0; i<oddBytes; i++) {
-                    register[i] = cipher[i+cipherOffset];
-                    plain[i+plainOffset]
-                        = (byte)(cipher[i+cipherOffset] ^ k[i]);
-                }
-            }
-        } else {
-            for (; loopCount > 0;
-                 plainOffset += numBytes, cipherOffset += numBytes,
-                 loopCount--) {
-                embeddedCipher.encryptBlock(register, 0, k, 0);
-                System.arraycopy(register, numBytes, register, 0, len);
-                for (i=0; i<numBytes; i++) {
-                    register[i+len] = cipher[i+cipherOffset];
-                    plain[i+plainOffset]
-                        = (byte)(cipher[i+cipherOffset] ^ k[i]);
-                }
-            }
-            if (oddBytes != 0) {
-                embeddedCipher.encryptBlock(register, 0, k, 0);
-                System.arraycopy(register, numBytes, register, 0, len);
-                for (i=0; i<oddBytes; i++) {
-                    register[i+len] = cipher[i+cipherOffset];
-                    plain[i+plainOffset]
-                        = (byte)(cipher[i+cipherOffset] ^ k[i]);
-                }
+            for (int i = 0; i < numBytes; i++) {
+                register[i + nShift] = cipher[i + cipherOffset];
+                plain[i + plainOffset]
+                    = (byte)(cipher[i + cipherOffset] ^ k[i]);
             }
         }
+        return cipherLen;
+    }
+
+    /**
+     * Performs the last decryption operation.
+     *
+     * <p>The input cipher text <code>cipher</code>, starting at
+     * <code>cipherOffset</code> and ending at
+     * <code>(cipherOffset + cipherLen - 1)</code>, is decrypted.
+     * The result is stored in <code>plain</code>, starting at
+     * <code>plainOffset</code>.
+     *
+     * @param cipher the buffer with the input data to be decrypted
+     * @param cipherOffset the offset in <code>cipherOffset</code>
+     * @param cipherLen the length of the input data
+     * @param plain the buffer for the result
+     * @param plainOffset the offset in <code>plain</code>
+     * @return the length of the decrypted data
+     */
+    int decryptFinal(byte[] cipher, int cipherOffset, int cipherLen,
+                byte[] plain, int plainOffset) {
+
+        int oddBytes = cipherLen % numBytes;
+        int len = decrypt(cipher, cipherOffset, (cipherLen - oddBytes),
+                          plain, plainOffset);
+        cipherOffset += len;
+        plainOffset += len;
+        if (oddBytes != 0) {
+            embeddedCipher.encryptBlock(register, 0, k, 0);
+            for (int i = 0; i < oddBytes; i++) {
+                plain[i + plainOffset]
+                    = (byte)(cipher[i + cipherOffset] ^ k[i]);
+            }
+        }
+        return cipherLen;
     }
 }
--- a/src/share/classes/com/sun/crypto/provider/CipherTextStealing.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/com/sun/crypto/provider/CipherTextStealing.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2013, 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
@@ -83,9 +83,10 @@
      * @param plainLen the length of the input data
      * @param cipher the buffer for the result
      * @param cipherOffset the offset in <code>cipher</code>
+     * @return the number of bytes placed into <code>cipher</code>
      */
-    void encryptFinal(byte[] plain, int plainOffset, int plainLen,
-                      byte[] cipher, int cipherOffset)
+    int encryptFinal(byte[] plain, int plainOffset, int plainLen,
+                     byte[] cipher, int cipherOffset)
         throws IllegalBlockSizeException {
 
         if (plainLen < blockSize) {
@@ -134,6 +135,7 @@
                 embeddedCipher.encryptBlock(tmp2, 0, cipher, cipherOffset);
             }
         }
+        return plainLen;
     }
 
     /**
@@ -158,9 +160,10 @@
      * @param cipherLen the length of the input data
      * @param plain the buffer for the result
      * @param plainOffset the offset in <code>plain</code>
+     * @return the number of bytes placed into <code>plain</code>
      */
-    void decryptFinal(byte[] cipher, int cipherOffset, int cipherLen,
-                      byte[] plain, int plainOffset)
+    int decryptFinal(byte[] cipher, int cipherOffset, int cipherLen,
+                     byte[] plain, int plainOffset)
         throws IllegalBlockSizeException {
         if (cipherLen < blockSize) {
             throw new IllegalBlockSizeException("input is too short!");
@@ -211,5 +214,6 @@
                 }
             }
         }
+        return cipherLen;
     }
 }
--- a/src/share/classes/com/sun/crypto/provider/CounterMode.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/com/sun/crypto/provider/CounterMode.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2014, 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
@@ -27,6 +27,7 @@
 
 import java.security.InvalidKeyException;
 
+
 /**
  * This class represents ciphers in counter (CTR) mode.
  *
@@ -136,49 +137,20 @@
      * The result is stored in <code>cipher</code>, starting at
      * <code>cipherOffset</code>.
      *
-     * <p>It is the application's responsibility to make sure that
-     * <code>plainLen</code> is a multiple of the embedded cipher's block size,
-     * as any excess bytes are ignored.
-     *
-     * <p>It is also the application's responsibility to make sure that
-     * <code>init</code> has been called before this method is called.
-     * (This check is omitted here, to avoid double checking.)
-     *
      * @param in the buffer with the input data to be encrypted
      * @param inOffset the offset in <code>plain</code>
      * @param len the length of the input data
      * @param out the buffer for the result
      * @param outOff the offset in <code>cipher</code>
+     * @return the length of the encrypted data
      */
-    void encrypt(byte[] in, int inOff, int len, byte[] out, int outOff) {
-        crypt(in, inOff, len, out, outOff);
+    int encrypt(byte[] in, int inOff, int len, byte[] out, int outOff) {
+        return crypt(in, inOff, len, out, outOff);
     }
 
-    /**
-     * Performs decryption operation.
-     *
-     * <p>The input cipher text <code>cipher</code>, starting at
-     * <code>cipherOffset</code> and ending at
-     * <code>(cipherOffset + len - 1)</code>, is decrypted.
-     * The result is stored in <code>plain</code>, starting at
-     * <code>plainOffset</code>.
-     *
-     * <p>It is the application's responsibility to make sure that
-     * <code>cipherLen</code> is a multiple of the embedded cipher's block
-     * size, as any excess bytes are ignored.
-     *
-     * <p>It is also the application's responsibility to make sure that
-     * <code>init</code> has been called before this method is called.
-     * (This check is omitted here, to avoid double checking.)
-     *
-     * @param in the buffer with the input data to be decrypted
-     * @param inOff the offset in <code>cipherOffset</code>
-     * @param len the length of the input data
-     * @param out the buffer for the result
-     * @param outOff the offset in <code>plain</code>
-     */
-    void decrypt(byte[] in, int inOff, int len, byte[] out, int outOff) {
-        crypt(in, inOff, len, out, outOff);
+    // CTR encrypt and decrypt are identical
+    int decrypt(byte[] in, int inOff, int len, byte[] out, int outOff) {
+        return crypt(in, inOff, len, out, outOff);
     }
 
     /**
@@ -197,7 +169,8 @@
      * keystream generated by encrypting the counter values. Counter values
      * are encrypted on demand.
      */
-    private void crypt(byte[] in, int inOff, int len, byte[] out, int outOff) {
+    private int crypt(byte[] in, int inOff, int len, byte[] out, int outOff) {
+        int result = len;
         while (len-- > 0) {
             if (used >= blockSize) {
                 embeddedCipher.encryptBlock(counter, 0, encryptedCounter, 0);
@@ -206,5 +179,6 @@
             }
             out[outOff++] = (byte)(in[inOff++] ^ encryptedCounter[used++]);
         }
+        return result;
     }
 }
--- a/src/share/classes/com/sun/crypto/provider/DESedeWrapCipher.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/com/sun/crypto/provider/DESedeWrapCipher.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 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
@@ -50,6 +50,9 @@
         (byte) 0x79, (byte) 0xe8, (byte) 0x21, (byte) 0x05
     };
 
+    private static final int CHECKSUM_LEN = 8;
+    private static final int IV_LEN = 8;
+
     /*
      * internal cipher object which does the real work.
      */
@@ -135,9 +138,9 @@
         // can only return an upper-limit if not initialized yet.
         int result = 0;
         if (decrypting) {
-            result = inputLen - 16;
+            result = inputLen - 16; // CHECKSUM_LEN + IV_LEN;
         } else {
-            result = inputLen + 16;
+            result = CipherCore.addExact(inputLen, 16);
         }
         return (result < 0? 0:result);
     }
@@ -215,7 +218,7 @@
         if (opmode == Cipher.WRAP_MODE) {
             decrypting = false;
             if (params == null) {
-                iv = new byte[8];
+                iv = new byte[IV_LEN];
                 if (random == null) {
                     random = SunJCE.RANDOM;
                 }
@@ -453,14 +456,15 @@
         }
 
         byte[] cks = getChecksum(keyVal);
-        byte[] out = new byte[iv.length + keyVal.length + cks.length];
+        byte[] in = new byte[CipherCore.addExact(keyVal.length, CHECKSUM_LEN)];
+        System.arraycopy(keyVal, 0, in, 0, keyVal.length);
+        System.arraycopy(cks, 0, in, keyVal.length, CHECKSUM_LEN);
 
-        System.arraycopy(keyVal, 0, out, iv.length, keyVal.length);
-        System.arraycopy(cks, 0, out, iv.length+keyVal.length, cks.length);
-        cipher.encrypt(out, iv.length, keyVal.length+cks.length,
-                       out, iv.length);
+        byte[] out = new byte[CipherCore.addExact(iv.length, in.length)];
+        System.arraycopy(iv, 0, out, 0, iv.length);
 
-        System.arraycopy(iv, 0, out, 0, iv.length);
+        cipher.encrypt(in, 0, in.length, out, iv.length);
+
         // reverse the array content
         for (int i = 0; i < out.length/2; i++) {
             byte temp = out[i];
@@ -474,7 +478,8 @@
             // should never happen
             throw new RuntimeException("Internal cipher key is corrupted");
         }
-        cipher.encrypt(out, 0, out.length, out, 0);
+        byte[] out2 = new byte[out.length];
+        cipher.encrypt(out, 0, out.length, out2, 0);
 
         // restore cipher state to prior to this call
         try {
@@ -484,7 +489,7 @@
             // should never happen
             throw new RuntimeException("Internal cipher key is corrupted");
         }
-        return out;
+        return out2;
     }
 
     /**
@@ -524,25 +529,26 @@
             buffer[i] = buffer[buffer.length-1-i];
             buffer[buffer.length-1-i] = temp;
         }
-        iv = new byte[IV2.length];
+        iv = new byte[IV_LEN];
         System.arraycopy(buffer, 0, iv, 0, iv.length);
         cipher.init(true, cipherKey.getAlgorithm(), cipherKey.getEncoded(),
                     iv);
-        cipher.decrypt(buffer, iv.length, buffer.length-iv.length,
-                       buffer, iv.length);
-        int origLen = buffer.length - iv.length - 8;
-        byte[] cks = getChecksum(buffer, iv.length, origLen);
-        int offset = iv.length + origLen;
-        for (int i = 0; i < cks.length; i++) {
-            if (buffer[offset + i] != cks[i]) {
+        byte[] buffer2 = new byte[buffer.length - iv.length];
+        cipher.decrypt(buffer, iv.length, buffer2.length,
+                       buffer2, 0);
+        int keyValLen = buffer2.length - CHECKSUM_LEN;
+        byte[] cks = getChecksum(buffer2, 0, keyValLen);
+        int offset = keyValLen;
+        for (int i = 0; i < CHECKSUM_LEN; i++) {
+            if (buffer2[offset + i] != cks[i]) {
                 throw new InvalidKeyException("Checksum comparison failed");
             }
         }
         // restore cipher state to prior to this call
         cipher.init(decrypting, cipherKey.getAlgorithm(),
                     cipherKey.getEncoded(), IV2);
-        byte[] out = new byte[origLen];
-        System.arraycopy(buffer, iv.length, out, 0, out.length);
+        byte[] out = new byte[keyValLen];
+        System.arraycopy(buffer2, 0, out, 0, keyValLen);
         return ConstructKeys.constructKey(out, wrappedKeyAlgorithm,
                                           wrappedKeyType);
     }
@@ -558,7 +564,7 @@
             throw new RuntimeException("SHA1 message digest not available");
         }
         md.update(in, offset, len);
-        byte[] cks = new byte[8];
+        byte[] cks = new byte[CHECKSUM_LEN];
         System.arraycopy(md.digest(), 0, cks, 0, cks.length);
         return cks;
     }
--- a/src/share/classes/com/sun/crypto/provider/DHKeyPairGenerator.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/com/sun/crypto/provider/DHKeyPairGenerator.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2012, 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
@@ -33,6 +33,7 @@
 import javax.crypto.spec.DHGenParameterSpec;
 
 import sun.security.provider.ParameterCache;
+import static sun.security.util.SecurityProviderConstants.DEF_DH_KEY_SIZE;
 
 /**
  * This class represents the key pair generator for Diffie-Hellman key pairs.
@@ -42,8 +43,7 @@
  * <ul>
  * <li>By providing the size in bits of the prime modulus -
  * This will be used to create a prime modulus and base generator, which will
- * then be used to create the Diffie-Hellman key pair. The default size of the
- * prime modulus is 1024 bits.
+ * then be used to create the Diffie-Hellman key pair.
  * <li>By providing a prime modulus and base generator
  * </ul>
  *
@@ -68,7 +68,7 @@
 
     public DHKeyPairGenerator() {
         super();
-        initialize(1024, null);
+        initialize(DEF_DH_KEY_SIZE, null);
     }
 
     /**
--- a/src/share/classes/com/sun/crypto/provider/DHParameterGenerator.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/com/sun/crypto/provider/DHParameterGenerator.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2012, 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
@@ -30,6 +30,8 @@
 import javax.crypto.spec.DHParameterSpec;
 import javax.crypto.spec.DHGenParameterSpec;
 
+import static sun.security.util.SecurityProviderConstants.DEF_DH_KEY_SIZE;
+
 /*
  * This class generates parameters for the Diffie-Hellman algorithm.
  * The parameters are a prime, a base, and optionally the length in bits of
@@ -37,7 +39,6 @@
  *
  * <p>The Diffie-Hellman parameter generation accepts the size in bits of the
  * prime modulus and the size in bits of the random exponent as input.
- * The size of the prime modulus defaults to 1024 bits.
  *
  * @author Jan Luehe
  *
@@ -50,7 +51,7 @@
 extends AlgorithmParameterGeneratorSpi {
 
     // The size in bits of the prime modulus
-    private int primeSize = 1024;
+    private int primeSize = DEF_DH_KEY_SIZE;
 
     // The size in bits of the random exponent (private value)
     private int exponentSize = 0;
@@ -58,6 +59,16 @@
     // The source of randomness
     private SecureRandom random = null;
 
+    private static void checkKeySize(int keysize)
+        throws InvalidAlgorithmParameterException {
+        if ((keysize != 2048) &&
+            ((keysize < 512) || (keysize > 1024) || (keysize % 64 != 0))) {
+            throw new InvalidAlgorithmParameterException(
+                "Keysize must be multiple of 64 ranging from "
+                + "512 to 1024 (inclusive), or 2048");
+        }
+    }
+
     /**
      * Initializes this parameter generator for a certain keysize
      * and source of randomness.
@@ -67,11 +78,11 @@
      * @param random the source of randomness
      */
     protected void engineInit(int keysize, SecureRandom random) {
-        if ((keysize < 512) || (keysize > 2048) || (keysize % 64 != 0)) {
-            throw new InvalidParameterException("Keysize must be multiple "
-                                                + "of 64, and can only range "
-                                                + "from 512 to 2048 "
-                                                + "(inclusive)");
+        // Re-uses DSA parameters and thus have the same range
+        try {
+            checkKeySize(keysize);
+        } catch (InvalidAlgorithmParameterException ex) {
+            throw new InvalidParameterException(ex.getMessage());
         }
         this.primeSize = keysize;
         this.random = random;
@@ -91,31 +102,29 @@
     protected void engineInit(AlgorithmParameterSpec genParamSpec,
                               SecureRandom random)
         throws InvalidAlgorithmParameterException {
-            if (!(genParamSpec instanceof DHGenParameterSpec)) {
-                throw new InvalidAlgorithmParameterException
-                    ("Inappropriate parameter type");
-            }
+        if (!(genParamSpec instanceof DHGenParameterSpec)) {
+            throw new InvalidAlgorithmParameterException
+                ("Inappropriate parameter type");
+        }
 
-            DHGenParameterSpec dhParamSpec = (DHGenParameterSpec)genParamSpec;
+        DHGenParameterSpec dhParamSpec = (DHGenParameterSpec)genParamSpec;
 
-            primeSize = dhParamSpec.getPrimeSize();
-            if ((primeSize<512) || (primeSize>2048) || (primeSize%64 != 0)) {
-                throw new InvalidAlgorithmParameterException
-                    ("Modulus size must be multiple of 64, and can only range "
-                     + "from 512 to 2048 (inclusive)");
-            }
+        primeSize = dhParamSpec.getPrimeSize();
 
-            exponentSize = dhParamSpec.getExponentSize();
-            if (exponentSize <= 0) {
-                throw new InvalidAlgorithmParameterException
-                    ("Exponent size must be greater than zero");
-            }
+        // Re-uses DSA parameters and thus have the same range
+        checkKeySize(primeSize);
 
-            // Require exponentSize < primeSize
-            if (exponentSize >= primeSize) {
-                throw new InvalidAlgorithmParameterException
-                    ("Exponent size must be less than modulus size");
-            }
+        exponentSize = dhParamSpec.getExponentSize();
+        if (exponentSize <= 0) {
+            throw new InvalidAlgorithmParameterException
+                ("Exponent size must be greater than zero");
+        }
+
+        // Require exponentSize < primeSize
+        if (exponentSize >= primeSize) {
+            throw new InvalidAlgorithmParameterException
+                ("Exponent size must be less than modulus size");
+        }
     }
 
     /**
--- a/src/share/classes/com/sun/crypto/provider/ElectronicCodeBook.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/com/sun/crypto/provider/ElectronicCodeBook.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
 package com.sun.crypto.provider;
 
 import java.security.InvalidKeyException;
+import java.security.ProviderException;
 
 /**
  * This class represents ciphers in electronic codebook (ECB) mode.
@@ -96,65 +97,58 @@
     /**
      * Performs encryption operation.
      *
-     * <p>The input plain text <code>plain</code>, starting at
-     * <code>plainOffset</code> and ending at
-     * <code>(plainOffset + len - 1)</code>, is encrypted.
-     * The result is stored in <code>cipher</code>, starting at
-     * <code>cipherOffset</code>.
-     *
-     * <p>It is the application's responsibility to make sure that
-     * <code>plainLen</code> is a multiple of the embedded cipher's block size,
-     * as any excess bytes are ignored.
-     *
-     * <p>It is also the application's responsibility to make sure that
-     * <code>init</code> has been called before this method is called.
-     * (This check is omitted here, to avoid double checking.)
+     * <p>The input plain text <code>in</code>, starting at
+     * <code>inOff</code> and ending at * <code>(inOff + len - 1)</code>,
+     * is encrypted. The result is stored in <code>out</code>, starting at
+     * <code>outOff</code>.
      *
      * @param in the buffer with the input data to be encrypted
-     * @param inOffset the offset in <code>plain</code>
+     * @param inOff the offset in <code>plain</code>
      * @param len the length of the input data
      * @param out the buffer for the result
      * @param outOff the offset in <code>cipher</code>
+     * @exception ProviderException if <code>len</code> is not
+     * a multiple of the block size
+     * @return the length of the encrypted data
      */
-    void encrypt(byte[] in, int inOff, int len, byte[] out, int outOff) {
-        while (len >= blockSize) {
+    int encrypt(byte[] in, int inOff, int len, byte[] out, int outOff) {
+        if ((len % blockSize) != 0) {
+             throw new ProviderException("Internal error in input buffering");
+        }
+        for (int i = len; i >= blockSize; i -= blockSize) {
             embeddedCipher.encryptBlock(in, inOff, out, outOff);
-            len -= blockSize;
             inOff += blockSize;
             outOff += blockSize;
         }
+        return len;
     }
 
     /**
      * Performs decryption operation.
      *
-     * <p>The input cipher text <code>cipher</code>, starting at
-     * <code>cipherOffset</code> and ending at
-     * <code>(cipherOffset + len - 1)</code>, is decrypted.
-     * The result is stored in <code>plain</code>, starting at
-     * <code>plainOffset</code>.
-     *
-     * <p>It is the application's responsibility to make sure that
-     * <code>cipherLen</code> is a multiple of the embedded cipher's block
-     * size, as any excess bytes are ignored.
-     *
-     * <p>It is also the application's responsibility to make sure that
-     * <code>init</code> has been called before this method is called.
-     * (This check is omitted here, to avoid double checking.)
+     * <p>The input cipher text <code>in</code>, starting at
+     * <code>inOff</code> and ending at * <code>(inOff + len - 1)</code>,
+     * is decrypted.The result is stored in <code>out</code>, starting at
+     * <code>outOff</code>.
      *
      * @param in the buffer with the input data to be decrypted
      * @param inOff the offset in <code>cipherOffset</code>
      * @param len the length of the input data
      * @param out the buffer for the result
      * @param outOff the offset in <code>plain</code>
+     * @exception ProviderException if <code>len</code> is not
+     * a multiple of the block size
+     * @return the length of the decrypted data
      */
-    void decrypt(byte[] in, int inOff, int len, byte[] out, int outOff) {
-        while (len >= blockSize) {
+    int decrypt(byte[] in, int inOff, int len, byte[] out, int outOff) {
+        if ((len % blockSize) != 0) {
+             throw new ProviderException("Internal error in input buffering");
+        }
+        for (int i = len; i >= blockSize; i -= blockSize) {
             embeddedCipher.decryptBlock(in, inOff, out, outOff);
-            len -= blockSize;
             inOff += blockSize;
             outOff += blockSize;
         }
+        return len;
     }
-
 }
--- a/src/share/classes/com/sun/crypto/provider/FeedbackCipher.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/com/sun/crypto/provider/FeedbackCipher.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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
@@ -27,6 +27,7 @@
 
 import java.security.InvalidKeyException;
 import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.ShortBufferException;
 
 /**
  * This class represents a block cipher in one of its modes. It wraps
@@ -111,6 +112,17 @@
     }
 
     /**
+     * @return the number of bytes that are buffered internally inside
+     * this FeedbackCipher instance.
+     * @since 1.8
+     */
+    int getBufferedLength() {
+        // Currently only AEAD cipher impl, e.g. GCM, buffers data
+        // internally during decryption mode
+        return 0;
+    }
+
+    /**
      * Resets the iv to its original value.
      * This is used when doFinal is called in the Cipher class, so that the
      * cipher can be reused (with its original iv).
@@ -133,9 +145,10 @@
      * @param plainLen the length of the input data
      * @param cipher the buffer for the encryption result
      * @param cipherOffset the offset in <code>cipher</code>
+     * @return the number of bytes placed into <code>cipher</code>
      */
-    abstract void encrypt(byte[] plain, int plainOffset, int plainLen,
-                          byte[] cipher, int cipherOffset);
+    abstract int encrypt(byte[] plain, int plainOffset, int plainLen,
+                         byte[] cipher, int cipherOffset);
     /**
      * Performs encryption operation for the last time.
      *
@@ -150,12 +163,13 @@
      * @param plainLen the length of the input data
      * @param cipher the buffer for the encryption result
      * @param cipherOffset the offset in <code>cipher</code>
+     * @return the number of bytes placed into <code>cipher</code>
      */
-     void encryptFinal(byte[] plain, int plainOffset, int plainLen,
-                       byte[] cipher, int cipherOffset)
-         throws IllegalBlockSizeException {
-         encrypt(plain, plainOffset, plainLen, cipher, cipherOffset);
-     }
+     int encryptFinal(byte[] plain, int plainOffset, int plainLen,
+                      byte[] cipher, int cipherOffset)
+         throws IllegalBlockSizeException, ShortBufferException {
+         return encrypt(plain, plainOffset, plainLen, cipher, cipherOffset);
+    }
     /**
      * Performs decryption operation.
      *
@@ -172,9 +186,10 @@
      * @param cipherLen the length of the input data
      * @param plain the buffer for the decryption result
      * @param plainOffset the offset in <code>plain</code>
+     * @return the number of bytes placed into <code>plain</code>
      */
-    abstract void decrypt(byte[] cipher, int cipherOffset, int cipherLen,
-                          byte[] plain, int plainOffset);
+    abstract int decrypt(byte[] cipher, int cipherOffset, int cipherLen,
+                         byte[] plain, int plainOffset);
 
     /**
      * Performs decryption operation for the last time.
@@ -190,10 +205,11 @@
      * @param cipherLen the length of the input data
      * @param plain the buffer for the decryption result
      * @param plainOffset the offset in <code>plain</code>
+     * @return the number of bytes placed into <code>plain</code>
      */
-     void decryptFinal(byte[] cipher, int cipherOffset, int cipherLen,
-                       byte[] plain, int plainOffset)
-         throws IllegalBlockSizeException {
-         decrypt(cipher, cipherOffset, cipherLen, plain, plainOffset);
+     int decryptFinal(byte[] cipher, int cipherOffset, int cipherLen,
+                      byte[] plain, int plainOffset)
+         throws IllegalBlockSizeException, ShortBufferException {
+         return decrypt(cipher, cipherOffset, cipherLen, plain, plainOffset);
      }
 }
--- a/src/share/classes/com/sun/crypto/provider/ISO10126Padding.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/com/sun/crypto/provider/ISO10126Padding.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -63,15 +63,16 @@
         if (in == null)
             return;
 
-        if ((off + len) > in.length) {
+        int idx = CipherCore.addExact(off, len);
+        if (idx > in.length) {
             throw new ShortBufferException("Buffer too small to hold padding");
         }
 
         byte paddingOctet = (byte) (len & 0xff);
-        byte[] padding = new byte[len];
+        byte[] padding = new byte[len - 1];
         SunJCE.RANDOM.nextBytes(padding);
-        padding[len-1] = paddingOctet;
-        System.arraycopy(padding, 0, in, off, len);
+        System.arraycopy(padding, 0, in, off, len - 1);
+        in[idx - 1] = paddingOctet;
         return;
     }
 
@@ -94,14 +95,15 @@
             return 0;
         }
 
-        byte lastByte = in[off + len - 1];
+        int idx = CipherCore.addExact(off, len);
+        byte lastByte = in[idx - 1];
         int padValue = (int)lastByte & 0x0ff;
         if ((padValue < 0x01)
             || (padValue > blockSize)) {
             return -1;
         }
 
-        int start = off + len - ((int)lastByte & 0x0ff);
+        int start = idx - padValue;
         if (start < off) {
             return -1;
         }
--- a/src/share/classes/com/sun/crypto/provider/JceKeyStore.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/com/sun/crypto/provider/JceKeyStore.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 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
@@ -27,12 +27,14 @@
 
 import java.io.*;
 import java.util.*;
+import java.security.AccessController;
 import java.security.DigestInputStream;
 import java.security.DigestOutputStream;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.security.Key;
 import java.security.PrivateKey;
+import java.security.PrivilegedAction;
 import java.security.KeyStoreSpi;
 import java.security.KeyStoreException;
 import java.security.UnrecoverableKeyException;
@@ -41,6 +43,8 @@
 import java.security.cert.CertificateException;
 import javax.crypto.SealedObject;
 
+import sun.misc.ObjectInputFilter;
+
 /**
  * This class provides the keystore implementation referred to as "jceks".
  * This implementation strongly protects the keystore private keys using
@@ -835,11 +839,23 @@
                         // read the sealed key
                         try {
                             ois = new ObjectInputStream(dis);
+                            final ObjectInputStream ois2 = ois;
+                            // Set a deserialization checker
+                            AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                                @Override
+                                public Void run() {
+                                    ObjectInputFilter.Config.setObjectInputFilter(
+                                        ois2, new DeserializationChecker());
+                                    return null;
+                                }
+                            });
                             entry.sealedKey = (SealedObject)ois.readObject();
                             // NOTE: don't close ois here since we are still
                             // using dis!!!
                         } catch (ClassNotFoundException cnfe) {
                             throw new IOException(cnfe.getMessage());
+                        } catch (InvalidClassException ice) {
+                            throw new IOException("Invalid secret key format");
                         }
 
                         // Add the entry to the list
@@ -898,4 +914,34 @@
         md.update("Mighty Aphrodite".getBytes("UTF8"));
         return md;
     }
+
+    /*
+     * An ObjectInputFilter that checks the format of the secret key being
+     * deserialized.
+     */
+    private static class DeserializationChecker implements ObjectInputFilter {
+        private static final int MAX_NESTED_DEPTH = 2;
+
+        @Override
+        public ObjectInputFilter.Status
+            checkInput(ObjectInputFilter.FilterInfo info) {
+
+            // First run a custom filter
+            long nestedDepth = info.depth();
+            if ((nestedDepth == 1 &&
+                info.serialClass() != SealedObjectForKeyProtector.class) ||
+                nestedDepth > MAX_NESTED_DEPTH) {
+                return Status.REJECTED;
+            }
+
+            // Next run the default filter, if available
+            ObjectInputFilter defaultFilter =
+                ObjectInputFilter.Config.getSerialFilter();
+            if (defaultFilter != null) {
+                return defaultFilter.checkInput(info);
+            }
+
+            return Status.UNDECIDED;
+        }
+    }
 }
--- a/src/share/classes/com/sun/crypto/provider/KeyProtector.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/com/sun/crypto/provider/KeyProtector.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 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
@@ -38,6 +38,7 @@
 import java.security.NoSuchProviderException;
 import java.security.UnrecoverableKeyException;
 import java.security.AlgorithmParameters;
+import java.security.spec.InvalidParameterSpecException;
 import java.security.spec.PKCS8EncodedKeySpec;
 
 import javax.crypto.Cipher;
@@ -74,6 +75,8 @@
     // keys in the keystore implementation that comes with JDK 1.2)
     private static final String KEY_PROTECTOR_OID = "1.3.6.1.4.1.42.2.17.1.1";
 
+    private static final int MAX_ITERATION_COUNT = 5000000;
+    private static final int ITERATION_COUNT = 200000;
     private static final int SALT_LEN = 20; // the salt length
     private static final int DIGEST_LEN = 20;
 
@@ -102,7 +105,7 @@
         SunJCE.RANDOM.nextBytes(salt);
 
         // create PBE parameters from salt and iteration count
-        PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, 20);
+        PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, ITERATION_COUNT);
 
         // create PBE key from password
         PBEKeySpec pbeKeySpec = new PBEKeySpec(this.password);
@@ -157,6 +160,9 @@
                 pbeParams.init(encodedParams);
                 PBEParameterSpec pbeSpec =
                         pbeParams.getParameterSpec(PBEParameterSpec.class);
+                if (pbeSpec.getIterationCount() > MAX_ITERATION_COUNT) {
+                    throw new IOException("PBE iteration count too large");
+                }
 
                 // create PBE key from password
                 PBEKeySpec pbeKeySpec = new PBEKeySpec(this.password);
@@ -287,7 +293,7 @@
         SunJCE.RANDOM.nextBytes(salt);
 
         // create PBE parameters from salt and iteration count
-        PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, 20);
+        PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, ITERATION_COUNT);
 
         // create PBE key from password
         PBEKeySpec pbeKeySpec = new PBEKeySpec(this.password);
@@ -328,6 +334,15 @@
                 throw new UnrecoverableKeyException("Cannot get " +
                                                     "algorithm parameters");
             }
+            PBEParameterSpec pbeSpec;
+            try {
+                pbeSpec = params.getParameterSpec(PBEParameterSpec.class);
+            } catch (InvalidParameterSpecException ipse) {
+                throw new IOException("Invalid PBE algorithm parameters");
+            }
+            if (pbeSpec.getIterationCount() > MAX_ITERATION_COUNT) {
+                throw new IOException("PBE iteration count too large");
+            }
             PBEWithMD5AndTripleDESCipher cipherSpi;
             cipherSpi = new PBEWithMD5AndTripleDESCipher();
             Cipher cipher = new CipherForKeyProtector(cipherSpi, PROV,
--- a/src/share/classes/com/sun/crypto/provider/OutputFeedback.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/com/sun/crypto/provider/OutputFeedback.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
 package com.sun.crypto.provider;
 
 import java.security.InvalidKeyException;
+import java.security.ProviderException;
 
 /**
  * This class represents ciphers in output-feedback (OFB) mode.
@@ -132,98 +133,88 @@
      *
      * <p>The input plain text <code>plain</code>, starting at
      * <code>plainOffset</code> and ending at
-     * <code>(plainOffset + len - 1)</code>, is encrypted.
+     * <code>(plainOffset + plainLen - 1)</code>, is encrypted.
      * The result is stored in <code>cipher</code>, starting at
      * <code>cipherOffset</code>.
      *
-     * <p>It is the application's responsibility to make sure that
-     * <code>plainLen</code> is a multiple of the stream unit size
-     * <code>numBytes</code>, as any excess bytes are ignored.
-     *
-     * <p>It is also the application's responsibility to make sure that
-     * <code>init</code> has been called before this method is called.
-     * (This check is omitted here, to avoid double checking.)
-     *
      * @param plain the buffer with the input data to be encrypted
      * @param plainOffset the offset in <code>plain</code>
      * @param plainLen the length of the input data
      * @param cipher the buffer for the result
      * @param cipherOffset the offset in <code>cipher</code>
+     * @exception ProviderException if <code>plainLen</code> is not
+     * a multiple of the <code>numBytes</code>
+     * @return the length of the encrypted data
      */
-    void encrypt(byte[] plain, int plainOffset, int plainLen,
-                        byte[] cipher, int cipherOffset)
-    {
-        int i;
-        int len = blockSize - numBytes;
+    int encrypt(byte[] plain, int plainOffset, int plainLen,
+                byte[] cipher, int cipherOffset) {
+
+        if ((plainLen % numBytes) != 0) {
+            throw new ProviderException("Internal error in input buffering");
+        }
+        int nShift = blockSize - numBytes;
         int loopCount = plainLen / numBytes;
-        int oddBytes = plainLen % numBytes;
 
-        if (len == 0) {
-            for (; loopCount > 0;
-                 plainOffset += numBytes, cipherOffset += numBytes,
-                 loopCount--) {
-                embeddedCipher.encryptBlock(register, 0, k, 0);
-                for (i=0; i<numBytes; i++)
-                    cipher[i+cipherOffset] =
-                        (byte)(k[i] ^ plain[i+plainOffset]);
-                System.arraycopy(k, 0, register, 0, numBytes);
-            }
-            if (oddBytes > 0) {
-                embeddedCipher.encryptBlock(register, 0, k, 0);
-                for (i=0; i<oddBytes; i++)
-                    cipher[i+cipherOffset] =
-                        (byte)(k[i] ^ plain[i+plainOffset]);
-                System.arraycopy(k, 0, register, 0, numBytes);
-            }
-        } else {
-            for (; loopCount > 0;
-                 plainOffset += numBytes, cipherOffset += numBytes,
-                 loopCount--) {
-                embeddedCipher.encryptBlock(register, 0, k, 0);
-                for (i=0; i<numBytes; i++)
-                    cipher[i+cipherOffset] =
-                        (byte)(k[i] ^ plain[i+plainOffset]);
-                System.arraycopy(register, numBytes, register, 0, len);
-                System.arraycopy(k, 0, register, len, numBytes);
-            }
-            if (oddBytes > 0) {
-                embeddedCipher.encryptBlock(register, 0, k, 0);
-                for (i=0; i<oddBytes; i++)
-                    cipher[i+cipherOffset] =
-                        (byte)(k[i] ^ plain[i+plainOffset]);
-                System.arraycopy(register, numBytes, register, 0, len);
-                System.arraycopy(k, 0, register, len, numBytes);
+        for (; loopCount > 0;
+             plainOffset += numBytes, cipherOffset += numBytes,
+             loopCount--) {
+            embeddedCipher.encryptBlock(register, 0, k, 0);
+            for (int i = 0; i < numBytes; i++) {
+                cipher[i + cipherOffset] =
+                    (byte)(k[i] ^ plain[i + plainOffset]);
+                if (nShift != 0) {
+                    System.arraycopy(register, numBytes, register, 0, nShift);
+                }
+                System.arraycopy(k, 0, register, nShift, numBytes);
             }
         }
+        return plainLen;
     }
 
     /**
-     * Performs decryption operation.
+     * Performs last encryption operation.
      *
-     * <p>The input cipher text <code>cipher</code>, starting at
-     * <code>cipherOffset</code> and ending at
-     * <code>(cipherOffset + len - 1)</code>, is decrypted.
-     * The result is stored in <code>plain</code>, starting at
-     * <code>plainOffset</code>.
+     * <p>The input plain text <code>plain</code>, starting at
+     * <code>plainOffset</code> and ending at
+     * <code>(plainOffset + plainLen - 1)</code>, is encrypted.
+     * The result is stored in <code>cipher</code>, starting at
+     * <code>cipherOffset</code>.
      *
-     * <p>It is the application's responsibility to make sure that
-     * <code>cipherLen</code> is a multiple of the stream unit size
-     * <code>numBytes</code>, as any excess bytes are ignored.
-     *
-     * <p>It is also the application's responsibility to make sure that
-     * <code>init</code> has been called before this method is called.
-     * (This check is omitted here, to avoid double checking.)
-     *
-     * @param cipher the buffer with the input data to be decrypted
-     * @param cipherOffset the offset in <code>cipherOffset</code>
-     * @param cipherLen the length of the input data
-     * @param plain the buffer for the result
+     * @param plain the buffer with the input data to be encrypted
      * @param plainOffset the offset in <code>plain</code>
+     * @param plainLen the length of the input data
+     * @param cipher the buffer for the result
+     * @param cipherOffset the offset in <code>cipher</code>
+     * @return the length of the encrypted data
      */
-    void decrypt(byte[] cipher, int cipherOffset, int cipherLen,
-                        byte[] plain, int plainOffset)
-    {
+    int encryptFinal(byte[] plain, int plainOffset, int plainLen,
+                     byte[] cipher, int cipherOffset) {
+        int oddBytes = plainLen % numBytes;
+        int len = encrypt(plain, plainOffset, (plainLen - oddBytes),
+                          cipher, cipherOffset);
+        plainOffset += len;
+        cipherOffset += len;
+
+        if (oddBytes != 0) {
+            embeddedCipher.encryptBlock(register, 0, k, 0);
+            for (int i = 0; i < oddBytes; i++) {
+                cipher[i + cipherOffset] =
+                    (byte)(k[i] ^ plain[ i + plainOffset]);
+            }
+        }
+        return plainLen;
+    }
+
+    // OFB encrypt and decrypt are identical
+    int decrypt(byte[] cipher, int cipherOffset, int cipherLen,
+                byte[] plain, int plainOffset) {
+        return encrypt(cipher, cipherOffset, cipherLen, plain, plainOffset);
+    }
+
+    // OFB encrypt and decrypt are identical
+    int decryptFinal(byte[] cipher, int cipherOffset, int cipherLen,
+                     byte[] plain, int plainOffset) {
         // OFB encrypt and decrypt are identical
-        encrypt(cipher, cipherOffset, cipherLen, plain, plainOffset);
+        return encryptFinal(cipher, cipherOffset, cipherLen, plain, plainOffset);
     }
 }
--- a/src/share/classes/com/sun/crypto/provider/PBECipherCore.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/com/sun/crypto/provider/PBECipherCore.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2011, 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
@@ -264,7 +264,7 @@
 
         if (algo.equals("DES")) {
             // P || S (password concatenated with salt)
-            byte[] concat = new byte[passwdBytes.length + salt.length];
+            byte[] concat = new byte[CipherCore.addExact(passwdBytes.length, salt.length)];
             System.arraycopy(passwdBytes, 0, concat, 0, passwdBytes.length);
             java.util.Arrays.fill(passwdBytes, (byte)0x00);
             System.arraycopy(salt, 0, concat, passwdBytes.length, salt.length);
@@ -288,7 +288,7 @@
                 for (i=0; i<2; i++) {
                     byte tmp = salt[i];
                     salt[i] = salt[3-i];
-                    salt[3-1] = tmp;
+                    salt[3-i] = tmp;
                 }
             }
 
--- a/src/share/classes/com/sun/crypto/provider/PCBC.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/com/sun/crypto/provider/PCBC.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,8 @@
 package com.sun.crypto.provider;
 
 import java.security.InvalidKeyException;
+import java.security.ProviderException;
+
 
 /**
  * This class represents ciphers in Plaintext Cipher Block Chaining (PCBC)
@@ -118,40 +120,39 @@
      *
      * <p>The input plain text <code>plain</code>, starting at
      * <code>plainOffset</code> and ending at
-     * <code>(plainOffset + len - 1)</code>, is encrypted.
+     * <code>(plainOffset + plainLen - 1)</code>, is encrypted.
      * The result is stored in <code>cipher</code>, starting at
      * <code>cipherOffset</code>.
      *
-     * <p>It is the application's responsibility to make sure that
-     * <code>plainLen</code> is a multiple of the embedded cipher's block size,
-     * as any excess bytes are ignored.
-     *
-     * <p>It is also the application's responsibility to make sure that
-     * <code>init</code> has been called before this method is called.
-     * (This check is omitted here, to avoid double checking.)
-     *
      * @param plain the buffer with the input data to be encrypted
      * @param plainOffset the offset in <code>plain</code>
      * @param plainLen the length of the input data
      * @param cipher the buffer for the result
      * @param cipherOffset the offset in <code>cipher</code>
+     * @exception ProviderException if <code>plainLen</code> is not
+     * a multiple of the block size
+     * @return the length of the encrypted data
      */
-    void encrypt(byte[] plain, int plainOffset, int plainLen,
-                        byte[] cipher, int cipherOffset)
+    int encrypt(byte[] plain, int plainOffset, int plainLen,
+                byte[] cipher, int cipherOffset)
     {
+        if ((plainLen % blockSize) != 0) {
+            throw new ProviderException("Internal error in input buffering");
+        }
         int i;
         int endIndex = plainOffset + plainLen;
 
         for (; plainOffset < endIndex;
              plainOffset += blockSize, cipherOffset += blockSize) {
-            for (i=0; i<blockSize; i++) {
-                k[i] ^= plain[i+plainOffset];
+            for (i = 0; i < blockSize; i++) {
+                k[i] ^= plain[i + plainOffset];
             }
             embeddedCipher.encryptBlock(k, 0, cipher, cipherOffset);
             for (i = 0; i < blockSize; i++) {
-                k[i] = (byte)(plain[i+plainOffset] ^ cipher[i+cipherOffset]);
+                k[i] = (byte)(plain[i + plainOffset] ^ cipher[i + cipherOffset]);
             }
         }
+        return plainLen;
     }
 
     /**
@@ -159,27 +160,25 @@
      *
      * <p>The input cipher text <code>cipher</code>, starting at
      * <code>cipherOffset</code> and ending at
-     * <code>(cipherOffset + len - 1)</code>, is decrypted.
+     * <code>(cipherOffset + cipherLen - 1)</code>, is decrypted.
      * The result is stored in <code>plain</code>, starting at
      * <code>plainOffset</code>.
      *
-     * <p>It is the application's responsibility to make sure that
-     * <code>cipherLen</code> is a multiple of the embedded cipher's block
-     * size, as any excess bytes are ignored.
-     *
-     * <p>It is also the application's responsibility to make sure that
-     * <code>init</code> has been called before this method is called.
-     * (This check is omitted here, to avoid double checking.)
-     *
      * @param cipher the buffer with the input data to be decrypted
      * @param cipherOffset the offset in <code>cipherOffset</code>
      * @param cipherLen the length of the input data
      * @param plain the buffer for the result
      * @param plainOffset the offset in <code>plain</code>
+     * @exception ProviderException if <code>cipherLen</code> is not
+     * a multiple of the block size
+     * @return the length of the decrypted data
      */
-    void decrypt(byte[] cipher, int cipherOffset, int cipherLen,
-                        byte[] plain, int plainOffset)
+    int decrypt(byte[] cipher, int cipherOffset, int cipherLen,
+                byte[] plain, int plainOffset)
     {
+        if ((cipherLen % blockSize) != 0) {
+             throw new ProviderException("Internal error in input buffering");
+        }
         int i;
         int endIndex = cipherOffset + cipherLen;
 
@@ -188,11 +187,12 @@
             embeddedCipher.decryptBlock(cipher, cipherOffset,
                                    plain, plainOffset);
             for (i = 0; i < blockSize; i++) {
-                plain[i+plainOffset] ^= k[i];
+                plain[i + plainOffset] ^= k[i];
             }
             for (i = 0; i < blockSize; i++) {
-                k[i] = (byte)(plain[i+plainOffset] ^ cipher[i+cipherOffset]);
+                k[i] = (byte)(plain[i + plainOffset] ^ cipher[i + cipherOffset]);
             }
         }
+        return cipherLen;
     }
 }
--- a/src/share/classes/com/sun/crypto/provider/PKCS5Padding.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/com/sun/crypto/provider/PKCS5Padding.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2007, 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
@@ -26,6 +26,7 @@
 package com.sun.crypto.provider;
 
 import javax.crypto.ShortBufferException;
+import java.util.Arrays;
 
 /**
  * This class implements padding as specified in the PKCS#5 standard.
@@ -63,14 +64,13 @@
         if (in == null)
             return;
 
-        if ((off + len) > in.length) {
+        int idx = CipherCore.addExact(off, len);
+        if (idx > in.length) {
             throw new ShortBufferException("Buffer too small to hold padding");
         }
 
         byte paddingOctet = (byte) (len & 0xff);
-        for (int i = 0; i < len; i++) {
-            in[i + off] = paddingOctet;
-        }
+        Arrays.fill(in, off, idx, paddingOctet);
         return;
     }
 
@@ -92,25 +92,24 @@
             (len == 0)) { // this can happen if input is really a padded buffer
             return 0;
         }
-
-        byte lastByte = in[off + len - 1];
+        int idx = CipherCore.addExact(off, len);
+        byte lastByte = in[idx - 1];
         int padValue = (int)lastByte & 0x0ff;
         if ((padValue < 0x01)
             || (padValue > blockSize)) {
             return -1;
         }
 
-        int start = off + len - ((int)lastByte & 0x0ff);
+        int start = idx - padValue;
         if (start < off) {
             return -1;
         }
 
-        for (int i = 0; i < ((int)lastByte & 0x0ff); i++) {
-            if (in[start+i] != lastByte) {
+        for (int i = start; i < idx; i++) {
+            if (in[i] != lastByte) {
                 return -1;
             }
         }
-
         return start;
     }
 
--- a/src/share/classes/com/sun/net/ssl/internal/www/protocol/https/HttpsURLConnectionOldImpl.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/com/sun/net/ssl/internal/www/protocol/https/HttpsURLConnectionOldImpl.java	Sat Feb 03 21:37:28 2018 -0800
@@ -38,6 +38,7 @@
 import java.net.URL;
 import java.net.Proxy;
 import java.net.ProtocolException;
+import java.net.MalformedURLException;
 import java.io.*;
 import javax.net.ssl.*;
 import java.security.Permission;
@@ -75,10 +76,18 @@
         this(u, null, handler);
     }
 
+    static URL checkURL(URL u) throws IOException {
+        if (u != null) {
+            if (u.toExternalForm().indexOf('\n') > -1) {
+                throw new MalformedURLException("Illegal character in URL");
+            }
+        }
+        return u;
+    }
 // For both copies of the file, uncomment one line and comment the other
 //    HttpsURLConnectionImpl(URL u, Handler handler) throws IOException {
     HttpsURLConnectionOldImpl(URL u, Proxy p, Handler handler) throws IOException {
-        super(u);
+        super(checkURL(u));
         delegate = new DelegateHttpsURLConnection(url, p, handler, this);
     }
 
--- a/src/share/classes/java/awt/MenuBar.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/java/awt/MenuBar.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2015, 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
@@ -181,7 +181,7 @@
      * removed from the menu bar, and replaced with the specified menu.
      * @param m    the menu to be set as the help menu
      */
-    public void setHelpMenu(Menu m) {
+    public void setHelpMenu(final Menu m) {
         synchronized (getTreeLock()) {
             if (helpMenu == m) {
                 return;
@@ -189,11 +189,11 @@
             if (helpMenu != null) {
                 remove(helpMenu);
             }
-            if (m.parent != this) {
-                add(m);
-            }
             helpMenu = m;
             if (m != null) {
+                if (m.parent != this) {
+                    add(m);
+                }
                 m.isHelpMenu = true;
                 m.parent = this;
                 MenuBarPeer peer = (MenuBarPeer)this.peer;
@@ -244,7 +244,7 @@
      * @param        index   the position of the menu to be removed.
      * @see          java.awt.MenuBar#add(java.awt.Menu)
      */
-    public void remove(int index) {
+    public void remove(final int index) {
         synchronized (getTreeLock()) {
             Menu m = getMenu(index);
             menus.removeElementAt(index);
@@ -254,6 +254,10 @@
                 m.removeNotify();
                 m.parent = null;
             }
+            if (helpMenu == m) {
+                helpMenu = null;
+                m.isHelpMenu = false;
+            }
         }
     }
 
--- a/src/share/classes/java/io/ObjectInputStream.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/java/io/ObjectInputStream.java	Sat Feb 03 21:37:28 2018 -0800
@@ -253,6 +253,12 @@
             public ObjectInputFilter getObjectInputFilter(ObjectInputStream stream) {
                 return stream.getInternalObjectInputFilter();
             }
+
+            public void checkArray(ObjectInputStream stream, Class<?> arrayType, int arrayLength)
+                throws InvalidClassException
+            {
+                stream.checkArray(arrayType, arrayLength);
+            }
         });
     }
 
@@ -1255,6 +1261,33 @@
     }
 
     /**
+     * Checks the given array type and length to ensure that creation of such
+     * an array is permitted by this ObjectInputStream. The arrayType argument
+     * must represent an actual array type.
+     *
+     * This private method is called via SharedSecrets.
+     *
+     * @param arrayType the array type
+     * @param arrayLength the array length
+     * @throws NullPointerException if arrayType is null
+     * @throws IllegalArgumentException if arrayType isn't actually an array type
+     * @throws NegativeArraySizeException if arrayLength is negative
+     * @throws InvalidClassException if the filter rejects creation
+     */
+    private void checkArray(Class<?> arrayType, int arrayLength) throws InvalidClassException {
+        Objects.requireNonNull(arrayType);
+        if (! arrayType.isArray()) {
+            throw new IllegalArgumentException("not an array type");
+        }
+
+        if (arrayLength < 0) {
+            throw new NegativeArraySizeException();
+        }
+
+        filterCheck(arrayType, arrayLength);
+    }
+
+    /**
      * Provide access to the persistent fields read from the input stream.
      */
     public static abstract class GetField {
@@ -1744,6 +1777,10 @@
         passHandle = NULL_HANDLE;
 
         int numIfaces = bin.readInt();
+        if (numIfaces > 65535) {
+            throw new InvalidObjectException("interface limit exceeded: "
+                    + numIfaces);
+        }
         String[] ifaces = new String[numIfaces];
         for (int i = 0; i < numIfaces; i++) {
             ifaces[i] = bin.readUTF();
--- a/src/share/classes/java/io/ObjectStreamClass.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/java/io/ObjectStreamClass.java	Sat Feb 03 21:37:28 2018 -0800
@@ -32,14 +32,19 @@
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.UndeclaredThrowableException;
 import java.lang.reflect.Member;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.Proxy;
+import java.security.AccessControlContext;
 import java.security.AccessController;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
+import java.security.PermissionCollection;
+import java.security.Permissions;
 import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -48,6 +53,8 @@
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
+import sun.misc.JavaSecurityAccess;
+import sun.misc.SharedSecrets;
 import sun.misc.Unsafe;
 import sun.reflect.CallerSensitive;
 import sun.reflect.Reflection;
@@ -173,6 +180,9 @@
 
     /** serialization-appropriate constructor, or null if none */
     private Constructor cons;
+    /** protection domains that need to be checked when calling the constructor */
+    private ProtectionDomain[] domains;
+
     /** class-defined writeObject method, or null if none */
     private Method writeObjectMethod;
     /** class-defined readObject method, or null if none */
@@ -505,6 +515,7 @@
                             cl, "readObjectNoData", null, Void.TYPE);
                         hasWriteObjectData = (writeObjectMethod != null);
                     }
+                    domains = getProtectionDomains(cons, cl);
                     writeReplaceMethod = getInheritableMethod(
                         cl, "writeReplace", null, Object.class);
                     readResolveMethod = getInheritableMethod(
@@ -548,6 +559,65 @@
     }
 
     /**
+     * Creates a PermissionDomain that grants no permission.
+     */
+    private ProtectionDomain noPermissionsDomain() {
+        PermissionCollection perms = new Permissions();
+        perms.setReadOnly();
+        return new ProtectionDomain(null, perms);
+    }
+
+    /**
+     * Aggregate the ProtectionDomains of all the classes that separate
+     * a concrete class {@code cl} from its ancestor's class declaring
+     * a constructor {@code cons}.
+     *
+     * If {@code cl} is defined by the boot loader, or the constructor
+     * {@code cons} is declared by {@code cl}, or if there is no security
+     * manager, then this method does nothing and {@code null} is returned.
+     *
+     * @param cons A constructor declared by {@code cl} or one of its
+     *             ancestors.
+     * @param cl A concrete class, which is either the class declaring
+     *           the constructor {@code cons}, or a serializable subclass
+     *           of that class.
+     * @return An array of ProtectionDomain representing the set of
+     *         ProtectionDomain that separate the concrete class {@code cl}
+     *         from its ancestor's declaring {@code cons}, or {@code null}.
+     */
+    private ProtectionDomain[] getProtectionDomains(Constructor<?> cons,
+                                                    Class<?> cl) {
+        ProtectionDomain[] domains = null;
+        if (cons != null && cl.getClassLoader() != null
+                && System.getSecurityManager() != null) {
+            Class<?> cls = cl;
+            Class<?> fnscl = cons.getDeclaringClass();
+            Set<ProtectionDomain> pds = null;
+            while (cls != fnscl) {
+                ProtectionDomain pd = cls.getProtectionDomain();
+                if (pd != null) {
+                    if (pds == null) pds = new HashSet<>();
+                    pds.add(pd);
+                }
+                cls = cls.getSuperclass();
+                if (cls == null) {
+                    // that's not supposed to happen
+                    // make a ProtectionDomain with no permission.
+                    // should we throw instead?
+                    if (pds == null) pds = new HashSet<>();
+                    else pds.clear();
+                    pds.add(noPermissionsDomain());
+                    break;
+                }
+            }
+            if (pds != null) {
+                domains = pds.toArray(new ProtectionDomain[0]);
+            }
+        }
+        return domains;
+    }
+
+    /**
      * Initializes class descriptor representing a proxy class.
      */
     void initProxy(Class<?> cl,
@@ -577,6 +647,7 @@
             writeReplaceMethod = localDesc.writeReplaceMethod;
             readResolveMethod = localDesc.readResolveMethod;
             deserializeEx = localDesc.deserializeEx;
+            domains = localDesc.domains;
             cons = localDesc.cons;
         }
         fieldRefl = getReflector(fields, localDesc);
@@ -663,6 +734,7 @@
             if (deserializeEx == null) {
                 deserializeEx = localDesc.deserializeEx;
             }
+            domains = localDesc.domains;
             cons = localDesc.cons;
         }
 
@@ -1003,7 +1075,38 @@
         requireInitialized();
         if (cons != null) {
             try {
-                return cons.newInstance();
+                if (domains == null || domains.length == 0) {
+                    return cons.newInstance();
+                } else {
+                    JavaSecurityAccess jsa = SharedSecrets.getJavaSecurityAccess();
+                    PrivilegedAction<Object> pea = new PrivilegedAction<Object>() {
+                        @Override
+                        public Object run() {
+                            try {
+                                return cons.newInstance();
+                            } catch (InstantiationException
+                                     | InvocationTargetException
+                                     | IllegalAccessException x) {
+                                throw new UndeclaredThrowableException(x);
+                            }
+                        }
+                    }; // Can't use PrivilegedExceptionAction with jsa
+                    try {
+                        return jsa.doIntersectionPrivilege(pea,
+                                   AccessController.getContext(),
+                                   new AccessControlContext(domains));
+                    } catch (UndeclaredThrowableException x) {
+                        Throwable cause = x.getCause();
+                        if (cause instanceof InstantiationException)
+                            throw (InstantiationException) cause;
+                        if (cause instanceof InvocationTargetException)
+                            throw (InvocationTargetException) cause;
+                        if (cause instanceof IllegalAccessException)
+                            throw (IllegalAccessException) cause;
+                        // not supposed to happen
+                        throw x;
+                    }
+                }
             } catch (IllegalAccessException ex) {
                 // should not occur, as access checks have been suppressed
                 throw new InternalError();
--- a/src/share/classes/java/security/CodeSource.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/java/security/CodeSource.java	Sat Feb 03 21:37:28 2018 -0800
@@ -34,6 +34,7 @@
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.security.cert.*;
+import sun.misc.IOUtils;
 
 /**
  *
@@ -540,6 +541,8 @@
             // could all be present in the stream at the same time
             cfs = new Hashtable<String, CertificateFactory>(3);
             certList = new ArrayList<>(size > 20 ? 20 : size);
+        } else if (size < 0) {
+            throw new IOException("size cannot be negative");
         }
 
         for (int i = 0; i < size; i++) {
@@ -561,13 +564,7 @@
                 cfs.put(certType, cf);
             }
             // parse the certificate
-            byte[] encoded = null;
-            try {
-                encoded = new byte[ois.readInt()];
-            } catch (OutOfMemoryError oome) {
-                throw new IOException("Certificate too big");
-            }
-            ois.readFully(encoded);
+            byte[] encoded = IOUtils.readNBytes(ois, ois.readInt());
             ByteArrayInputStream bais = new ByteArrayInputStream(encoded);
             try {
                 certList.add(cf.generateCertificate(bais));
--- a/src/share/classes/java/security/KeyStore.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/java/security/KeyStore.java	Sat Feb 03 21:37:28 2018 -0800
@@ -26,6 +26,7 @@
 package java.security;
 
 import java.io.*;
+import java.net.URI;
 import java.security.cert.Certificate;
 import java.security.cert.X509Certificate;
 import java.security.cert.CertificateException;
@@ -34,6 +35,10 @@
 
 import javax.security.auth.callback.*;
 
+import sun.misc.JavaSecurityKeyStoreAccess;
+import sun.misc.SharedSecrets;
+
+import sun.security.pkcs12.PKCS12Attribute;
 import sun.security.util.Debug;
 
 /**
@@ -182,6 +187,43 @@
     private static final boolean skipDebug =
         Debug.isOn("engine=") && !Debug.isOn("keystore");
 
+    // Set up JavaSecurityKeyStoreAccess in SharedSecrets
+    static {
+        SharedSecrets.setJavaSecurityKeyStoreAccess(new JavaSecurityKeyStoreAccess() {
+            public PrivateKeyEntry constructPrivateKeyEntry(PrivateKey privateKey,
+                                                            Certificate[] chain,
+                                                            Set<PKCS12Attribute> attributes) {
+                return new PrivateKeyEntry(privateKey, chain, attributes);
+            }
+
+            @Override
+            public Set<PKCS12Attribute> getPrivateKeyEntryAttributes(PrivateKeyEntry entry) {
+                return entry.getAttributes();
+            }
+
+            @Override
+            public SecretKeyEntry constructSecretKeyEntry(SecretKey secretKey,
+                                                          Set<PKCS12Attribute> attributes) {
+                return new SecretKeyEntry(secretKey, attributes);
+            }
+
+            @Override
+            public Set<PKCS12Attribute> getSecretKeyEntryAttributes(SecretKeyEntry entry) {
+                return entry.getAttributes();
+            }
+
+            public TrustedCertificateEntry constructTrustedCertificateEntry(Certificate trustedCert,
+                                                                            Set<PKCS12Attribute> attributes) {
+                return new TrustedCertificateEntry(trustedCert, attributes);
+            }
+
+            @Override
+            public Set<PKCS12Attribute> getTrustedCertificateEntryAttributes(TrustedCertificateEntry entry) {
+                return entry.getAttributes();
+            }
+            });
+    }
+
     /*
      * Constant to lookup in the Security properties file to determine
      * the default keystore type.
@@ -355,6 +397,7 @@
 
         private final PrivateKey privKey;
         private final Certificate[] chain;
+        private final Set<PKCS12Attribute> attributes;
 
         /**
          * Constructs a <code>PrivateKeyEntry</code> with a
@@ -381,7 +424,39 @@
          *      in the end entity <code>Certificate</code> (at index 0)
          */
         public PrivateKeyEntry(PrivateKey privateKey, Certificate[] chain) {
-            if (privateKey == null || chain == null) {
+            this(privateKey, chain, Collections.<PKCS12Attribute>emptySet());
+        }
+
+        /**
+         * Constructs a {@code PrivateKeyEntry} with a {@code PrivateKey} and
+         * corresponding certificate chain and associated entry attributes.
+         *
+         * <p> The specified {@code chain} and {@code attributes} are cloned
+         * before they are stored in the new {@code PrivateKeyEntry} object.
+         *
+         * @param privateKey the {@code PrivateKey}
+         * @param chain an array of {@code Certificate}s
+         *      representing the certificate chain.
+         *      The chain must be ordered and contain a
+         *      {@code Certificate} at index 0
+         *      corresponding to the private key.
+         * @param attributes the attributes
+         *
+         * @exception NullPointerException if {@code privateKey}, {@code chain}
+         *      or {@code attributes} is {@code null}
+         * @exception IllegalArgumentException if the specified chain has a
+         *      length of 0, if the specified chain does not contain
+         *      {@code Certificate}s of the same type,
+         *      or if the {@code PrivateKey} algorithm
+         *      does not match the algorithm of the {@code PublicKey}
+         *      in the end entity {@code Certificate} (at index 0)
+         *
+         * @since 1.8
+         */
+        private PrivateKeyEntry(PrivateKey privateKey, Certificate[] chain,
+           Set<PKCS12Attribute> attributes) {
+
+            if (privateKey == null || chain == null || attributes == null) {
                 throw new NullPointerException("invalid null input");
             }
             if (chain.length == 0) {
@@ -416,6 +491,9 @@
             } else {
                 this.chain = clonedChain;
             }
+
+            this.attributes =
+                Collections.unmodifiableSet(new HashSet<>(attributes));
         }
 
         /**
@@ -457,6 +535,18 @@
         }
 
         /**
+         * Retrieves the attributes associated with an entry.
+         * <p>
+         *
+         * @return an unmodifiable {@code Set} of attributes, possibly empty
+         *
+         * @since 1.8
+         */
+        private Set<PKCS12Attribute> getAttributes() {
+            return attributes;
+        }
+
+        /**
          * Returns a string representation of this PrivateKeyEntry.
          * @return a string representation of this PrivateKeyEntry.
          */
@@ -481,6 +571,7 @@
     public static final class SecretKeyEntry implements Entry {
 
         private final SecretKey sKey;
+        private final Set<PKCS12Attribute> attributes;
 
         /**
          * Constructs a <code>SecretKeyEntry</code> with a
@@ -496,6 +587,32 @@
                 throw new NullPointerException("invalid null input");
             }
             this.sKey = secretKey;
+            this.attributes = Collections.<PKCS12Attribute>emptySet();
+        }
+
+        /**
+         * Constructs a {@code SecretKeyEntry} with a {@code SecretKey} and
+         * associated entry attributes.
+         *
+         * <p> The specified {@code attributes} is cloned before it is stored
+         * in the new {@code SecretKeyEntry} object.
+         *
+         * @param secretKey the {@code SecretKey}
+         * @param attributes the attributes
+         *
+         * @exception NullPointerException if {@code secretKey} or
+         *     {@code attributes} is {@code null}
+         *
+         * @since 1.8
+         */
+        private SecretKeyEntry(SecretKey secretKey, Set<PKCS12Attribute> attributes) {
+
+            if (secretKey == null || attributes == null) {
+                throw new NullPointerException("invalid null input");
+            }
+            this.sKey = secretKey;
+            this.attributes =
+                Collections.unmodifiableSet(new HashSet<>(attributes));
         }
 
         /**
@@ -508,6 +625,18 @@
         }
 
         /**
+         * Retrieves the attributes associated with an entry.
+         * <p>
+         *
+         * @return an unmodifiable {@code Set} of attributes, possibly empty
+         *
+         * @since 1.8
+         */
+        private Set<PKCS12Attribute> getAttributes() {
+            return attributes;
+        }
+
+        /**
          * Returns a string representation of this SecretKeyEntry.
          * @return a string representation of this SecretKeyEntry.
          */
@@ -525,6 +654,7 @@
     public static final class TrustedCertificateEntry implements Entry {
 
         private final Certificate cert;
+        private final Set<PKCS12Attribute> attributes;
 
         /**
          * Constructs a <code>TrustedCertificateEntry</code> with a
@@ -540,6 +670,32 @@
                 throw new NullPointerException("invalid null input");
             }
             this.cert = trustedCert;
+            this.attributes = Collections.<PKCS12Attribute>emptySet();
+        }
+
+        /**
+         * Constructs a {@code TrustedCertificateEntry} with a
+         * trusted {@code Certificate} and associated entry attributes.
+         *
+         * <p> The specified {@code attributes} is cloned before it is stored
+         * in the new {@code TrustedCertificateEntry} object.
+         *
+         * @param trustedCert the trusted {@code Certificate}
+         * @param attributes the attributes
+         *
+         * @exception NullPointerException if {@code trustedCert} or
+         *     {@code attributes} is {@code null}
+         *
+         * @since 1.8
+         */
+        private TrustedCertificateEntry(Certificate trustedCert,
+           Set<PKCS12Attribute> attributes) {
+            if (trustedCert == null || attributes == null) {
+                throw new NullPointerException("invalid null input");
+            }
+            this.cert = trustedCert;
+            this.attributes =
+                Collections.unmodifiableSet(new HashSet<>(attributes));
         }
 
         /**
@@ -552,6 +708,18 @@
         }
 
         /**
+         * Retrieves the attributes associated with an entry.
+         * <p>
+         *
+         * @return an unmodifiable {@code Set} of attributes, possibly empty
+         *
+         * @since 1.8
+         */
+        private Set<PKCS12Attribute> getAttributes() {
+            return attributes;
+        }
+
+        /**
          * Returns a string representation of this TrustedCertificateEntry.
          * @return a string representation of this TrustedCertificateEntry.
          */
--- a/src/share/classes/java/security/Signature.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/java/security/Signature.java	Sat Feb 03 21:37:28 2018 -0800
@@ -437,6 +437,10 @@
         return this.provider;
     }
 
+    private String getProviderName() {
+        return (provider == null)  ? "(no provider)" : provider.getName();
+    }
+
     void chooseFirstProvider() {
         // empty, overridden in Delegate
     }
@@ -458,7 +462,7 @@
 
         if (!skipDebug && pdebug != null) {
             pdebug.println("Signature." + algorithm +
-                " verification algorithm from: " + this.provider.getName());
+                " verification algorithm from: " + getProviderName());
         }
     }
 
@@ -507,7 +511,7 @@
 
         if (!skipDebug && pdebug != null) {
             pdebug.println("Signature." + algorithm +
-                " verification algorithm from: " + this.provider.getName());
+                " verification algorithm from: " + getProviderName());
         }
     }
 
@@ -528,7 +532,7 @@
 
         if (!skipDebug && pdebug != null) {
             pdebug.println("Signature." + algorithm +
-                " signing algorithm from: " + this.provider.getName());
+                " signing algorithm from: " + getProviderName());
         }
     }
 
@@ -551,7 +555,7 @@
 
         if (!skipDebug && pdebug != null) {
             pdebug.println("Signature." + algorithm +
-                " signing algorithm from: " + this.provider.getName());
+                " signing algorithm from: " + getProviderName());
         }
     }
 
--- a/src/share/classes/java/security/UnresolvedPermission.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/java/security/UnresolvedPermission.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2011, 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
@@ -25,12 +25,16 @@
 
 package java.security;
 
+import sun.misc.IOUtils;
+
 import java.io.IOException;
 import java.io.ByteArrayInputStream;
+import java.security.cert.Certificate;
 import java.util.ArrayList;
 import java.util.Hashtable;
 import java.lang.reflect.*;
 import java.security.cert.*;
+import java.util.List;
 
 /**
  * The UnresolvedPermission class is used to hold Permissions that
@@ -549,6 +553,7 @@
     {
         CertificateFactory cf;
         Hashtable<String, CertificateFactory> cfs = null;
+        List<Certificate> certList = null;
 
         ois.defaultReadObject();
 
@@ -560,8 +565,10 @@
         if (size > 0) {
             // 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<String, CertificateFactory>(3);
-            this.certs = new java.security.cert.Certificate[size];
+            cfs = new Hashtable<>(3);
+            certList = new ArrayList<>(size > 20 ? 20 : size);
+        } else if (size < 0) {
+            throw new IOException("size cannot be negative");
         }
 
         for (int i=0; i<size; i++) {
@@ -583,20 +590,18 @@
                 cfs.put(certType, cf);
             }
             // parse the certificate
-            byte[] encoded=null;
-            try {
-                encoded = new byte[ois.readInt()];
-            } catch (OutOfMemoryError oome) {
-                throw new IOException("Certificate too big");
-            }
-            ois.readFully(encoded);
+            byte[] encoded = IOUtils.readNBytes(ois, ois.readInt());
             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]);
+        }
     }
 }
--- a/src/share/classes/java/security/cert/CertificateRevokedException.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/java/security/cert/CertificateRevokedException.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -34,6 +34,7 @@
 import java.util.Map;
 import javax.security.auth.x500.X500Principal;
 
+import sun.misc.IOUtils;
 import sun.security.util.ObjectIdentifier;
 import sun.security.x509.InvalidityDateExtension;
 
@@ -228,17 +229,17 @@
         int size = ois.readInt();
         if (size == 0) {
             extensions = Collections.emptyMap();
+        } else if (size < 0) {
+            throw new IOException("size cannot be negative");
         } else {
-            extensions = new HashMap<String, Extension>(size);
+            extensions = new HashMap<>(size > 20 ? 20 : size);
         }
 
         // Read in the extensions and put the mappings in the extensions map
         for (int i = 0; i < size; i++) {
             String oid = (String) ois.readObject();
             boolean critical = ois.readBoolean();
-            int length = ois.readInt();
-            byte[] extVal = new byte[length];
-            ois.readFully(extVal);
+            byte[] extVal = IOUtils.readNBytes(ois, ois.readInt());
             Extension ext = sun.security.x509.Extension.newExtension
                 (new ObjectIdentifier(oid), critical, extVal);
             extensions.put(oid, ext);
--- a/src/share/classes/java/util/ArrayDeque.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/java/util/ArrayDeque.java	Sat Feb 03 21:37:28 2018 -0800
@@ -33,7 +33,13 @@
  */
 
 package java.util;
-import java.io.*;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+
+import sun.misc.SharedSecrets;
 
 /**
  * Resizable-array implementation of the {@link Deque} interface.  Array
@@ -44,16 +50,16 @@
  * {@link Stack} when used as a stack, and faster than {@link LinkedList}
  * when used as a queue.
  *
- * <p>Most <tt>ArrayDeque</tt> operations run in amortized constant time.
+ * <p>Most {@code ArrayDeque} operations run in amortized constant time.
  * Exceptions include {@link #remove(Object) remove}, {@link
  * #removeFirstOccurrence removeFirstOccurrence}, {@link #removeLastOccurrence
  * removeLastOccurrence}, {@link #contains contains}, {@link #iterator
  * iterator.remove()}, and the bulk operations, all of which run in linear
  * time.
  *
- * <p>The iterators returned by this class's <tt>iterator</tt> method are
+ * <p>The iterators returned by this class's {@code iterator} method are
  * <i>fail-fast</i>: If the deque is modified at any time after the iterator
- * is created, in any way except through the iterator's own <tt>remove</tt>
+ * is created, in any way except through the iterator's own {@code remove}
  * method, the iterator will generally throw a {@link
  * ConcurrentModificationException}.  Thus, in the face of concurrent
  * modification, the iterator fails quickly and cleanly, rather than risking
@@ -63,7 +69,7 @@
  * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
  * as it is, generally speaking, impossible to make any hard guarantees in the
  * presence of unsynchronized concurrent modification.  Fail-fast iterators
- * throw <tt>ConcurrentModificationException</tt> on a best-effort basis.
+ * throw {@code ConcurrentModificationException} on a best-effort basis.
  * Therefore, it would be wrong to write a program that depended on this
  * exception for its correctness: <i>the fail-fast behavior of iterators
  * should be used only to detect bugs.</i>
@@ -93,7 +99,7 @@
      * other.  We also guarantee that all array cells not holding
      * deque elements are always null.
      */
-    private transient E[] elements;
+    private transient Object[] elements;
 
     /**
      * The index of the element at the head of the deque (which is the
@@ -116,12 +122,7 @@
 
     // ******  Array allocation and resizing utilities ******
 
-    /**
-     * Allocate empty array to hold the given number of elements.
-     *
-     * @param numElements  the number of elements to hold
-     */
-    private void allocateElements(int numElements) {
+    private static int calculateSize(int numElements) {
         int initialCapacity = MIN_INITIAL_CAPACITY;
         // Find the best power of two to hold elements.
         // Tests "<=" because arrays aren't kept full.
@@ -137,11 +138,20 @@
             if (initialCapacity < 0)   // Too many elements, must back off
                 initialCapacity >>>= 1;// Good luck allocating 2 ^ 30 elements
         }
-        elements = (E[]) new Object[initialCapacity];
+        return initialCapacity;
     }
 
     /**
-     * Double the capacity of this deque.  Call only when full, i.e.,
+     * Allocates empty array to hold the given number of elements.
+     *
+     * @param numElements  the number of elements to hold
+     */
+    private void allocateElements(int numElements) {
+        elements = new Object[calculateSize(numElements)];
+    }
+
+    /**
+     * Doubles the capacity of this deque.  Call only when full, i.e.,
      * when head and tail have wrapped around to become equal.
      */
     private void doubleCapacity() {
@@ -183,7 +193,7 @@
      * sufficient to hold 16 elements.
      */
     public ArrayDeque() {
-        elements = (E[]) new Object[16];
+        elements = new Object[16];
     }
 
     /**
@@ -249,7 +259,7 @@
      * Inserts the specified element at the front of this deque.
      *
      * @param e the element to add
-     * @return <tt>true</tt> (as specified by {@link Deque#offerFirst})
+     * @return {@code true} (as specified by {@link Deque#offerFirst})
      * @throws NullPointerException if the specified element is null
      */
     public boolean offerFirst(E e) {
@@ -261,7 +271,7 @@
      * Inserts the specified element at the end of this deque.
      *
      * @param e the element to add
-     * @return <tt>true</tt> (as specified by {@link Deque#offerLast})
+     * @return {@code true} (as specified by {@link Deque#offerLast})
      * @throws NullPointerException if the specified element is null
      */
     public boolean offerLast(E e) {
@@ -291,7 +301,9 @@
 
     public E pollFirst() {
         int h = head;
-        E result = elements[h]; // Element is null if deque empty
+        @SuppressWarnings("unchecked")
+        E result = (E) elements[h];
+        // Element is null if deque empty
         if (result == null)
             return null;
         elements[h] = null;     // Must null out slot
@@ -301,7 +313,8 @@
 
     public E pollLast() {
         int t = (tail - 1) & (elements.length - 1);
-        E result = elements[t];
+        @SuppressWarnings("unchecked")
+        E result = (E) elements[t];
         if (result == null)
             return null;
         elements[t] = null;
@@ -313,48 +326,53 @@
      * @throws NoSuchElementException {@inheritDoc}
      */
     public E getFirst() {
-        E x = elements[head];
-        if (x == null)
+        @SuppressWarnings("unchecked")
+        E result = (E) elements[head];
+        if (result == null)
             throw new NoSuchElementException();
-        return x;
+        return result;
     }
 
     /**
      * @throws NoSuchElementException {@inheritDoc}
      */
     public E getLast() {
-        E x = elements[(tail - 1) & (elements.length - 1)];
-        if (x == null)
+        @SuppressWarnings("unchecked")
+        E result = (E) elements[(tail - 1) & (elements.length - 1)];
+        if (result == null)
             throw new NoSuchElementException();
-        return x;
+        return result;
     }
 
+    @SuppressWarnings("unchecked")
     public E peekFirst() {
-        return elements[head]; // elements[head] is null if deque empty
+        // elements[head] is null if deque empty
+        return (E) elements[head];
     }
 
+    @SuppressWarnings("unchecked")
     public E peekLast() {
-        return elements[(tail - 1) & (elements.length - 1)];
+        return (E) elements[(tail - 1) & (elements.length - 1)];
     }
 
     /**
      * Removes the first occurrence of the specified element in this
      * deque (when traversing the deque from head to tail).
      * If the deque does not contain the element, it is unchanged.
-     * More formally, removes the first element <tt>e</tt> such that
-     * <tt>o.equals(e)</tt> (if such an element exists).
-     * Returns <tt>true</tt> if this deque contained the specified element
+     * More formally, removes the first element {@code e} such that
+     * {@code o.equals(e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
      * (or equivalently, if this deque changed as a result of the call).
      *
      * @param o element to be removed from this deque, if present
-     * @return <tt>true</tt> if the deque contained the specified element
+     * @return {@code true} if the deque contained the specified element
      */
     public boolean removeFirstOccurrence(Object o) {
         if (o == null)
             return false;
         int mask = elements.length - 1;
         int i = head;
-        E x;
+        Object x;
         while ( (x = elements[i]) != null) {
             if (o.equals(x)) {
                 delete(i);
@@ -369,20 +387,20 @@
      * Removes the last occurrence of the specified element in this
      * deque (when traversing the deque from head to tail).
      * If the deque does not contain the element, it is unchanged.
-     * More formally, removes the last element <tt>e</tt> such that
-     * <tt>o.equals(e)</tt> (if such an element exists).
-     * Returns <tt>true</tt> if this deque contained the specified element
+     * More formally, removes the last element {@code e} such that
+     * {@code o.equals(e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
      * (or equivalently, if this deque changed as a result of the call).
      *
      * @param o element to be removed from this deque, if present
-     * @return <tt>true</tt> if the deque contained the specified element
+     * @return {@code true} if the deque contained the specified element
      */
     public boolean removeLastOccurrence(Object o) {
         if (o == null)
             return false;
         int mask = elements.length - 1;
         int i = (tail - 1) & mask;
-        E x;
+        Object x;
         while ( (x = elements[i]) != null) {
             if (o.equals(x)) {
                 delete(i);
@@ -401,7 +419,7 @@
      * <p>This method is equivalent to {@link #addLast}.
      *
      * @param e the element to add
-     * @return <tt>true</tt> (as specified by {@link Collection#add})
+     * @return {@code true} (as specified by {@link Collection#add})
      * @throws NullPointerException if the specified element is null
      */
     public boolean add(E e) {
@@ -415,7 +433,7 @@
      * <p>This method is equivalent to {@link #offerLast}.
      *
      * @param e the element to add
-     * @return <tt>true</tt> (as specified by {@link Queue#offer})
+     * @return {@code true} (as specified by {@link Queue#offer})
      * @throws NullPointerException if the specified element is null
      */
     public boolean offer(E e) {
@@ -440,12 +458,12 @@
     /**
      * Retrieves and removes the head of the queue represented by this deque
      * (in other words, the first element of this deque), or returns
-     * <tt>null</tt> if this deque is empty.
+     * {@code null} if this deque is empty.
      *
      * <p>This method is equivalent to {@link #pollFirst}.
      *
      * @return the head of the queue represented by this deque, or
-     *         <tt>null</tt> if this deque is empty
+     *         {@code null} if this deque is empty
      */
     public E poll() {
         return pollFirst();
@@ -467,12 +485,12 @@
 
     /**
      * Retrieves, but does not remove, the head of the queue represented by
-     * this deque, or returns <tt>null</tt> if this deque is empty.
+     * this deque, or returns {@code null} if this deque is empty.
      *
      * <p>This method is equivalent to {@link #peekFirst}.
      *
      * @return the head of the queue represented by this deque, or
-     *         <tt>null</tt> if this deque is empty
+     *         {@code null} if this deque is empty
      */
     public E peek() {
         return peekFirst();
@@ -527,7 +545,7 @@
      */
     private boolean delete(int i) {
         checkInvariants();
-        final E[] elements = this.elements;
+        final Object[] elements = this.elements;
         final int mask = elements.length - 1;
         final int h = head;
         final int t = tail;
@@ -576,9 +594,9 @@
     }
 
     /**
-     * Returns <tt>true</tt> if this deque contains no elements.
+     * Returns {@code true} if this deque contains no elements.
      *
-     * @return <tt>true</tt> if this deque contains no elements
+     * @return {@code true} if this deque contains no elements
      */
     public boolean isEmpty() {
         return head == tail;
@@ -625,7 +643,8 @@
         public E next() {
             if (cursor == fence)
                 throw new NoSuchElementException();
-            E result = elements[cursor];
+            @SuppressWarnings("unchecked")
+            E result = (E) elements[cursor];
             // This check doesn't catch all possible comodifications,
             // but does catch the ones that corrupt traversal
             if (tail != fence || result == null)
@@ -664,7 +683,8 @@
             if (cursor == fence)
                 throw new NoSuchElementException();
             cursor = (cursor - 1) & (elements.length - 1);
-            E result = elements[cursor];
+            @SuppressWarnings("unchecked")
+            E result = (E) elements[cursor];
             if (head != fence || result == null)
                 throw new ConcurrentModificationException();
             lastRet = cursor;
@@ -683,19 +703,19 @@
     }
 
     /**
-     * Returns <tt>true</tt> if this deque contains the specified element.
-     * More formally, returns <tt>true</tt> if and only if this deque contains
-     * at least one element <tt>e</tt> such that <tt>o.equals(e)</tt>.
+     * Returns {@code true} if this deque contains the specified element.
+     * More formally, returns {@code true} if and only if this deque contains
+     * at least one element {@code e} such that {@code o.equals(e)}.
      *
      * @param o object to be checked for containment in this deque
-     * @return <tt>true</tt> if this deque contains the specified element
+     * @return {@code true} if this deque contains the specified element
      */
     public boolean contains(Object o) {
         if (o == null)
             return false;
         int mask = elements.length - 1;
         int i = head;
-        E x;
+        Object x;
         while ( (x = elements[i]) != null) {
             if (o.equals(x))
                 return true;
@@ -707,15 +727,15 @@
     /**
      * Removes a single instance of the specified element from this deque.
      * If the deque does not contain the element, it is unchanged.
-     * More formally, removes the first element <tt>e</tt> such that
-     * <tt>o.equals(e)</tt> (if such an element exists).
-     * Returns <tt>true</tt> if this deque contained the specified element
+     * More formally, removes the first element {@code e} such that
+     * {@code o.equals(e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
      * (or equivalently, if this deque changed as a result of the call).
      *
-     * <p>This method is equivalent to {@link #removeFirstOccurrence}.
+     * <p>This method is equivalent to {@link #removeFirstOccurrence(Object)}.
      *
      * @param o element to be removed from this deque, if present
-     * @return <tt>true</tt> if this deque contained the specified element
+     * @return {@code true} if this deque contained the specified element
      */
     public boolean remove(Object o) {
         return removeFirstOccurrence(o);
@@ -767,22 +787,21 @@
      * <p>If this deque fits in the specified array with room to spare
      * (i.e., the array has more elements than this deque), the element in
      * the array immediately following the end of the deque is set to
-     * <tt>null</tt>.
+     * {@code null}.
      *
      * <p>Like the {@link #toArray()} method, this method acts as bridge between
      * array-based and collection-based APIs.  Further, this method allows
      * precise control over the runtime type of the output array, and may,
      * under certain circumstances, be used to save allocation costs.
      *
-     * <p>Suppose <tt>x</tt> is a deque known to contain only strings.
+     * <p>Suppose {@code x} is a deque known to contain only strings.
      * The following code can be used to dump the deque into a newly
-     * allocated array of <tt>String</tt>:
+     * allocated array of {@code String}:
      *
-     * <pre>
-     *     String[] y = x.toArray(new String[0]);</pre>
+     *  <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
      *
-     * Note that <tt>toArray(new Object[0])</tt> is identical in function to
-     * <tt>toArray()</tt>.
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
      *
      * @param a the array into which the elements of the deque are to
      *          be stored, if it is big enough; otherwise, a new array of the
@@ -813,10 +832,10 @@
      */
     public ArrayDeque<E> clone() {
         try {
+            @SuppressWarnings("unchecked")
             ArrayDeque<E> result = (ArrayDeque<E>) super.clone();
             result.elements = Arrays.copyOf(elements, elements.length);
             return result;
-
         } catch (CloneNotSupportedException e) {
             throw new AssertionError();
         }
@@ -828,9 +847,9 @@
     private static final long serialVersionUID = 2340985798034038923L;
 
     /**
-     * Serialize this deque.
+     * Saves this deque to a stream (that is, serializes it).
      *
-     * @serialData The current size (<tt>int</tt>) of the deque,
+     * @serialData The current size ({@code int}) of the deque,
      * followed by all of its elements (each an object reference) in
      * first-to-last order.
      */
@@ -847,7 +866,7 @@
     }
 
     /**
-     * Deserialize this deque.
+     * Reconstitutes this deque from a stream (that is, deserializes it).
      */
     private void readObject(ObjectInputStream s)
             throws IOException, ClassNotFoundException {
@@ -855,12 +874,14 @@
 
         // Read in size and allocate array
         int size = s.readInt();
+        int capacity = calculateSize(size);
+        SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, capacity);
         allocateElements(size);
         head = 0;
         tail = size;
 
         // Read in all elements in the proper order.
         for (int i = 0; i < size; i++)
-            elements[i] = (E)s.readObject();
+            elements[i] = s.readObject();
     }
 }
--- a/src/share/classes/java/util/ArrayList.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/java/util/ArrayList.java	Sat Feb 03 21:37:28 2018 -0800
@@ -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
@@ -25,6 +25,8 @@
 
 package java.util;
 
+import sun.misc.SharedSecrets;
+
 /**
  * Resizable-array implementation of the <tt>List</tt> interface.  Implements
  * all optional list operations, and permits all elements, including
@@ -200,12 +202,15 @@
         }
     }
 
+    private static int calculateCapacity(Object[] elementData, int minCapacity) {
+        if (elementData == EMPTY_ELEMENTDATA) {
+            return Math.max(DEFAULT_CAPACITY, minCapacity);
+        }
+        return minCapacity;
+    }
+
     private void ensureCapacityInternal(int minCapacity) {
-        if (elementData == EMPTY_ELEMENTDATA) {
-            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
-        }
-
-        ensureExplicitCapacity(minCapacity);
+        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
     }
 
     private void ensureExplicitCapacity(int minCapacity) {
@@ -763,6 +768,8 @@
 
         if (size > 0) {
             // be like clone(), allocate array based upon size not capacity
+            int capacity = calculateCapacity(elementData, size);
+            SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, capacity);
             ensureCapacityInternal(size);
 
             Object[] a = elementData;
--- a/src/share/classes/java/util/GregorianCalendar.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/java/util/GregorianCalendar.java	Sat Feb 03 21:37:28 2018 -0800
@@ -508,6 +508,18 @@
     // The default value of gregorianCutover.
     static final long DEFAULT_GREGORIAN_CUTOVER = -12219292800000L;
 
+    // Set up JavaUtilCalendarAccess in SharedSecrets
+    static {
+       sun.misc.SharedSecrets.setJavaUtilCalendarAccess(new sun.misc.JavaUtilCalendarAccess() {
+               public GregorianCalendar createCalendar(TimeZone zone, Locale locale) {
+                   return new GregorianCalendar(zone, locale, true);
+               }
+               public void complete(Calendar cal) {
+                   cal.complete();
+               }
+        });
+    }
+
 /////////////////////
 // Instance Variables
 /////////////////////
@@ -722,6 +734,18 @@
         this.internalSet(MILLISECOND, millis);
     }
 
+    /**
+     * Constructs an empty GregorianCalendar.
+     *
+     * @param zone    the given time zone
+     * @param aLocale the given locale
+     * @param flag    the flag requesting an empty instance
+     */
+    GregorianCalendar(TimeZone zone, Locale locale, boolean flag) {
+        super(zone, locale);
+        gdate = (BaseCalendar.Date) gcal.newCalendarDate(getZone());
+    }
+
 /////////////////
 // Public methods
 /////////////////
--- a/src/share/classes/java/util/HashMap.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/java/util/HashMap.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2010, 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
@@ -25,6 +25,7 @@
 
 package java.util;
 import java.io.*;
+import sun.misc.SharedSecrets;
 
 /**
  * Hash table based implementation of the <tt>Map</tt> interface.  This
@@ -298,7 +299,7 @@
         putAllForCreate(m);
     }
 
-    private static int roundUpToPowerOf2(int number) {
+    static int roundUpToPowerOf2(int number) {
         // assert number >= 0 : "number must be non-negative";
         return number >= MAXIMUM_CAPACITY
                 ? MAXIMUM_CAPACITY
@@ -1174,6 +1175,11 @@
 
         init();  // Give subclass a chance to do its thing.
 
+
+        // Check Map.Entry[].class since it's the nearest public type to
+        // what we're actually creating.
+        SharedSecrets.getJavaOISAccess().checkArray(s, Map.Entry[].class, capacity);
+
         // Read the keys and values, and put the mappings in the HashMap
         for (int i = 0; i < mappings; i++) {
             K key = (K) s.readObject();
--- a/src/share/classes/java/util/HashSet.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/java/util/HashSet.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2010, 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
@@ -25,6 +25,10 @@
 
 package java.util;
 
+import java.io.InvalidObjectException;
+
+import sun.misc.SharedSecrets;
+
 /**
  * This class implements the <tt>Set</tt> interface, backed by a hash table
  * (actually a <tt>HashMap</tt> instance).  It makes no guarantees as to the
@@ -293,16 +297,44 @@
         // Read in any hidden serialization magic
         s.defaultReadObject();
 
-        // Read in HashMap capacity and load factor and create backing HashMap
+        // Read capacity and verify non-negative.
         int capacity = s.readInt();
+        if (capacity < 0) {
+            throw new InvalidObjectException("Illegal capacity: " +
+                                             capacity);
+        }
+
+        // Read load factor and verify positive and non NaN.
         float loadFactor = s.readFloat();
+        if (loadFactor <= 0 || Float.isNaN(loadFactor)) {
+            throw new InvalidObjectException("Illegal load factor: " +
+                                             loadFactor);
+        }
+
+        // Read size and verify non-negative.
+        int size = s.readInt();
+        if (size < 0) {
+            throw new InvalidObjectException("Illegal size: " +
+                                             size);
+        }
+        // Set the capacity according to the size and load factor ensuring that
+        // the HashMap is at least 25% full but clamping to maximum capacity.
+        capacity = (int) Math.min(size * Math.min(1 / loadFactor, 4.0f),
+                HashMap.MAXIMUM_CAPACITY);
+
+        // Constructing the backing map will lazily create an array when the first element is
+        // added, so check it before construction. Call HashMap.roundUpToPowerOf2 to compute the
+        // actual allocation size. Check Map.Entry[].class since it's the nearest public type to
+        // what is actually created.
+
+        SharedSecrets.getJavaOISAccess()
+                     .checkArray(s, Map.Entry[].class, HashMap.roundUpToPowerOf2(capacity));
+
+        // Create backing HashMap
         map = (((HashSet)this) instanceof LinkedHashSet ?
                new LinkedHashMap<E,Object>(capacity, loadFactor) :
                new HashMap<E,Object>(capacity, loadFactor));
 
-        // Read in size
-        int size = s.readInt();
-
         // Read in all elements in the proper order.
         for (int i=0; i<size; i++) {
             E e = (E) s.readObject();
--- a/src/share/classes/java/util/Hashtable.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/java/util/Hashtable.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 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
@@ -25,6 +25,7 @@
 
 package java.util;
 import java.io.*;
+import sun.misc.SharedSecrets;
 
 /**
  * This class implements a hash table, which maps keys to values. Any
@@ -935,10 +936,10 @@
         Entry<K, V> entryStack = null;
 
         synchronized (this) {
-            // Write out the length, threshold, loadfactor
+            // Write out the threshold and loadFactor
             s.defaultWriteObject();
 
-            // Write out length, count of elements
+            // Write out the length and count of elements
             s.writeInt(table.length);
             s.writeInt(count);
 
@@ -968,22 +969,37 @@
     private void readObject(java.io.ObjectInputStream s)
          throws IOException, ClassNotFoundException
     {
-        // Read in the length, threshold, and loadfactor
+        // Read in the threshold and loadFactor
         s.defaultReadObject();
 
+        // Validate loadFactor (ignore threshold - it will be re-computed)
+        if (loadFactor <= 0 || Float.isNaN(loadFactor))
+            throw new StreamCorruptedException("Illegal Load: " + loadFactor);
+
         // Read the original length of the array and number of elements
         int origlength = s.readInt();
         int elements = s.readInt();
 
-        // Compute new size with a bit of room 5% to grow but
-        // no larger than the original size.  Make the length
+        // Validate # of elements
+        if (elements < 0)
+            throw new StreamCorruptedException("Illegal # of Elements: " + elements);
+
+        // Clamp original length to be more than elements / loadFactor
+        // (this is the invariant enforced with auto-growth)
+        origlength = Math.max(origlength, (int)(elements / loadFactor) + 1);
+
+        // Compute new length with a bit of room 5% + 3 to grow but
+        // no larger than the clamped original length.  Make the length
         // odd if it's large enough, this helps distribute the entries.
         // Guard against the length ending up zero, that's not valid.
-        int length = (int)(elements * loadFactor) + (elements / 20) + 3;
+        int length = (int)((elements + elements / 20) / loadFactor) + 3;
         if (length > elements && (length & 1) == 0)
             length--;
-        if (origlength > 0 && length > origlength)
-            length = origlength;
+        length = Math.min(length, origlength);
+
+        // Check Map.Entry[].class since it's the nearest public type to
+        // what we're actually creating.
+        SharedSecrets.getJavaOISAccess().checkArray(s, Map.Entry[].class, length);
 
         Entry<K,V>[] newTable = new Entry[length];
         threshold = (int) Math.min(length * loadFactor, MAX_ARRAY_SIZE + 1);
@@ -994,7 +1010,7 @@
         for (; elements > 0; elements--) {
             K key = (K)s.readObject();
             V value = (V)s.readObject();
-            // synch could be eliminated for performance
+            // sync is eliminated for performance
             reconstitutionPut(newTable, key, value);
         }
         this.table = newTable;
@@ -1007,9 +1023,9 @@
      *
      * <p>This differs from the regular put method in several ways. No
      * checking for rehashing is necessary since the number of elements
-     * initially in the table is known. The modCount is not incremented
-     * because we are creating a new instance. Also, no return value
-     * is needed.
+     * initially in the table is known. The modCount is not incremented and
+     * there's no synchronization because we are creating a new instance.
+     * Also, no return value is needed.
      */
     private void reconstitutionPut(Entry<K,V>[] tab, K key, V value)
         throws StreamCorruptedException
--- a/src/share/classes/java/util/IdentityHashMap.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/java/util/IdentityHashMap.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -24,7 +24,8 @@
  */
 
 package java.util;
-import java.io.*;
+
+import sun.misc.SharedSecrets;
 
 /**
  * This class implements the <tt>Map</tt> interface with a hash table, using
@@ -69,7 +70,7 @@
  * maximum size and the number of buckets is unspecified.
  *
  * <p>If the size of the map (the number of key-value mappings) sufficiently
- * exceeds the expected maximum size, the number of buckets is increased
+ * exceeds the expected maximum size, the number of buckets is increased.
  * Increasing the number of buckets ("rehashing") may be fairly expensive, so
  * it pays to create identity hash maps with a sufficiently large expected
  * maximum size.  On the other hand, iteration over collection views requires
@@ -155,6 +156,10 @@
      * The maximum capacity, used if a higher value is implicitly specified
      * by either of the constructors with arguments.
      * MUST be a power of two <= 1<<29.
+     *
+     * In fact, the map can hold no more than MAXIMUM_CAPACITY-1 items
+     * because it has to have at least one slot with the key == null
+     * in order to avoid infinite loops in get(), put(), remove()
      */
     private static final int MAXIMUM_CAPACITY = 1 << 29;
 
@@ -176,11 +181,6 @@
     private transient int modCount;
 
     /**
-     * The next size value at which to resize (capacity * load factor).
-     */
-    private transient int threshold;
-
-    /**
      * Value representing null keys inside tables.
      */
     private static final Object NULL_KEY = new Object();
@@ -224,27 +224,18 @@
     }
 
     /**
-     * Returns the appropriate capacity for the specified expected maximum
-     * size.  Returns the smallest power of two between MINIMUM_CAPACITY
-     * and MAXIMUM_CAPACITY, inclusive, that is greater than
-     * (3 * expectedMaxSize)/2, if such a number exists.  Otherwise
-     * returns MAXIMUM_CAPACITY.  If (3 * expectedMaxSize)/2 is negative, it
-     * is assumed that overflow has occurred, and MAXIMUM_CAPACITY is returned.
+     * Returns the appropriate capacity for the given expected maximum size.
+     * Returns the smallest power of two between MINIMUM_CAPACITY and
+     * MAXIMUM_CAPACITY, inclusive, that is greater than (3 *
+     * expectedMaxSize)/2, if such a number exists.  Otherwise returns
+     * MAXIMUM_CAPACITY.
      */
-    private int capacity(int expectedMaxSize) {
-        // Compute min capacity for expectedMaxSize given a load factor of 2/3
-        int minCapacity = (3 * expectedMaxSize)/2;
-
-        // Compute the appropriate capacity
-        int result;
-        if (minCapacity > MAXIMUM_CAPACITY || minCapacity < 0) {
-            result = MAXIMUM_CAPACITY;
-        } else {
-            result = MINIMUM_CAPACITY;
-            while (result < minCapacity)
-                result <<= 1;
-        }
-        return result;
+    private static int capacity(int expectedMaxSize) {
+        // assert expectedMaxSize >= 0;
+        return
+            (expectedMaxSize > MAXIMUM_CAPACITY / 3) ? MAXIMUM_CAPACITY :
+            (expectedMaxSize <= 2 * MINIMUM_CAPACITY / 3) ? MINIMUM_CAPACITY :
+            Integer.highestOneBit(expectedMaxSize + (expectedMaxSize << 1));
     }
 
     /**
@@ -257,7 +248,6 @@
         // assert initCapacity >= MINIMUM_CAPACITY;
         // assert initCapacity <= MAXIMUM_CAPACITY;
 
-        threshold = (initCapacity * 2)/3;
         table = new Object[2 * initCapacity];
     }
 
@@ -423,51 +413,58 @@
      * @see     #containsKey(Object)
      */
     public V put(K key, V value) {
-        Object k = maskNull(key);
-        Object[] tab = table;
-        int len = tab.length;
-        int i = hash(k, len);
+        final Object k = maskNull(key);
 
-        Object item;
-        while ( (item = tab[i]) != null) {
-            if (item == k) {
-                V oldValue = (V) tab[i + 1];
-                tab[i + 1] = value;
-                return oldValue;
+        retryAfterResize: for (;;) {
+            final Object[] tab = table;
+            final int len = tab.length;
+            int i = hash(k, len);
+
+            for (Object item; (item = tab[i]) != null;
+                 i = nextKeyIndex(i, len)) {
+                if (item == k) {
+                    @SuppressWarnings("unchecked")
+                        V oldValue = (V) tab[i + 1];
+                    tab[i + 1] = value;
+                    return oldValue;
+                }
             }
-            i = nextKeyIndex(i, len);
+
+            final int s = size + 1;
+            // Use optimized form of 3 * s.
+            // Next capacity is len, 2 * current capacity.
+            if (s + (s << 1) > len && resize(len))
+                continue retryAfterResize;
+
+            modCount++;
+            tab[i] = k;
+            tab[i + 1] = value;
+            size = s;
+            return null;
         }
-
-        modCount++;
-        tab[i] = k;
-        tab[i + 1] = value;
-        if (++size >= threshold)
-            resize(len); // len == 2 * current capacity.
-        return null;
     }
 
     /**
-     * Resize the table to hold given capacity.
+     * Resizes the table if necessary to hold given capacity.
      *
      * @param newCapacity the new capacity, must be a power of two.
+     * @return whether a resize did in fact take place
      */
-    private void resize(int newCapacity) {
+    private boolean resize(int newCapacity) {
         // assert (newCapacity & -newCapacity) == newCapacity; // power of 2
         int newLength = newCapacity * 2;
 
         Object[] oldTable = table;
         int oldLength = oldTable.length;
-        if (oldLength == 2*MAXIMUM_CAPACITY) { // can't expand any further
-            if (threshold == MAXIMUM_CAPACITY-1)
+        if (oldLength == 2 * MAXIMUM_CAPACITY) { // can't expand any further
+            if (size == MAXIMUM_CAPACITY - 1)
                 throw new IllegalStateException("Capacity exhausted.");
-            threshold = MAXIMUM_CAPACITY-1;  // Gigantic map!
-            return;
+            return false;
         }
         if (oldLength >= newLength)
-            return;
+            return false;
 
         Object[] newTable = new Object[newLength];
-        threshold = newLength / 3;
 
         for (int j = 0; j < oldLength; j += 2) {
             Object key = oldTable[j];
@@ -483,6 +480,7 @@
             }
         }
         table = newTable;
+        return true;
     }
 
     /**
@@ -497,8 +495,8 @@
         int n = m.size();
         if (n == 0)
             return;
-        if (n > threshold) // conservatively pre-expand
-            resize(capacity(n));
+        if (n > size)
+            resize(capacity(n)); // conservatively pre-expand
 
         for (Entry<? extends K, ? extends V> e : m.entrySet())
             put(e.getKey(), e.getValue());
@@ -534,7 +532,6 @@
                 return null;
             i = nextKeyIndex(i, len);
         }
-
     }
 
     /**
@@ -1168,8 +1165,8 @@
     private static final long serialVersionUID = 8188218128353913216L;
 
     /**
-     * Save the state of the <tt>IdentityHashMap</tt> instance to a stream
-     * (i.e., serialize it).
+     * Saves the state of the <tt>IdentityHashMap</tt> instance to a stream
+     * (i.e., serializes it).
      *
      * @serialData The <i>size</i> of the HashMap (the number of key-value
      *          mappings) (<tt>int</tt>), followed by the key (Object) and
@@ -1197,8 +1194,8 @@
     }
 
     /**
-     * Reconstitute the <tt>IdentityHashMap</tt> instance from a stream (i.e.,
-     * deserialize it).
+     * Reconstitutes the <tt>IdentityHashMap</tt> instance from a stream (i.e.,
+     * deserializes it).
      */
     private void readObject(java.io.ObjectInputStream s)
         throws java.io.IOException, ClassNotFoundException  {
@@ -1207,9 +1204,12 @@
 
         // Read in size (number of Mappings)
         int size = s.readInt();
-
-        // Allow for 33% growth (i.e., capacity is >= 2* size()).
-        init(capacity((size*4)/3));
+        if (size < 0)
+            throw new java.io.StreamCorruptedException
+                ("Illegal mappings count: " + size);
+        int cap = capacity(size);
+        SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, cap);
+        init(cap);
 
         // Read the keys and values, and put the mappings in the table
         for (int i=0; i<size; i++) {
@@ -1224,7 +1224,7 @@
      * update modCount, etc.
      */
     private void putForCreate(K key, V value)
-        throws IOException
+        throws java.io.StreamCorruptedException
     {
         K k = (K)maskNull(key);
         Object[] tab = table;
--- a/src/share/classes/java/util/PriorityQueue.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/java/util/PriorityQueue.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -25,6 +25,8 @@
 
 package java.util;
 
+import sun.misc.SharedSecrets;
+
 /**
  * An unbounded priority {@linkplain Queue queue} based on a priority heap.
  * The elements of the priority queue are ordered according to their
@@ -762,6 +764,7 @@
         // Read in (and discard) array length
         s.readInt();
 
+        SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, size);
         queue = new Object[size];
 
         // Read in all elements.
--- a/src/share/classes/java/util/SimpleTimeZone.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/java/util/SimpleTimeZone.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2011, 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
@@ -41,6 +41,7 @@
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
 import java.io.IOException;
+import java.io.InvalidObjectException;
 import sun.util.calendar.CalendarSystem;
 import sun.util.calendar.CalendarUtils;
 import sun.util.calendar.BaseCalendar;
@@ -1278,6 +1279,9 @@
      */
     private int serialVersionOnStream = currentSerialVersion;
 
+    // Maximum number of rules.
+    private static final int MAX_RULE_NUM = 6;
+
     synchronized private void invalidateCache() {
         cacheYear = startYear - 1;
         cacheStart = cacheEnd = 0;
@@ -1569,7 +1573,7 @@
      */
     private byte[] packRules()
     {
-        byte[] rules = new byte[6];
+        byte[] rules = new byte[MAX_RULE_NUM];
         rules[0] = (byte)startDay;
         rules[1] = (byte)startDayOfWeek;
         rules[2] = (byte)endDay;
@@ -1594,7 +1598,7 @@
         endDayOfWeek   = rules[3];
 
         // As of serial version 2, include time modes
-        if (rules.length >= 6) {
+        if (rules.length >= MAX_RULE_NUM) {
             startTimeMode = rules[4];
             endTimeMode   = rules[5];
         }
@@ -1691,9 +1695,13 @@
             // store the actual rules (which have not be made compatible with 1.1)
             // in the optional area.  Read them in here and parse them.
             int length = stream.readInt();
-            byte[] rules = new byte[length];
-            stream.readFully(rules);
-            unpackRules(rules);
+            if (length <= MAX_RULE_NUM) {
+                byte[] rules = new byte[length];
+                stream.readFully(rules);
+                unpackRules(rules);
+            } else {
+                throw new InvalidObjectException("Too many rules: " + length);
+            }
         }
 
         if (serialVersionOnStream >= 2) {
--- a/src/share/classes/java/util/concurrent/CopyOnWriteArrayList.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/java/util/concurrent/CopyOnWriteArrayList.java	Sat Feb 03 21:37:28 2018 -0800
@@ -36,6 +36,7 @@
 package java.util.concurrent;
 import java.util.*;
 import java.util.concurrent.locks.*;
+import sun.misc.SharedSecrets;
 import sun.misc.Unsafe;
 
 /**
@@ -872,6 +873,7 @@
 
         // Read in array length and allocate array
         int len = s.readInt();
+        SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, len);
         Object[] elements = new Object[len];
 
         // Read in all elements in the proper order.
--- a/src/share/classes/javax/crypto/CipherSpi.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/javax/crypto/CipherSpi.java	Sat Feb 03 21:37:28 2018 -0800
@@ -777,7 +777,9 @@
             int total = 0;
             do {
                 int chunk = Math.min(inLen, inArray.length);
-                input.get(inArray, 0, chunk);
+                if (chunk > 0) {
+                    input.get(inArray, 0, chunk);
+                }
                 int n;
                 if (isUpdate || (inLen != chunk)) {
                     n = engineUpdate(inArray, 0, chunk, outArray, outOfs);
@@ -805,8 +807,9 @@
             int total = 0;
             boolean resized = false;
             do {
-                int chunk = Math.min(inLen, outSize);
-                if ((a1 == false) && (resized == false)) {
+                int chunk =
+                    Math.min(inLen, (outSize == 0? inArray.length : outSize));
+                if (!a1 && !resized && chunk > 0) {
                     input.get(inArray, 0, chunk);
                     inOfs = 0;
                 }
@@ -820,8 +823,10 @@
                     resized = false;
                     inOfs += chunk;
                     inLen -= chunk;
-                    output.put(outArray, 0, n);
-                    total += n;
+                    if (n > 0) {
+                        output.put(outArray, 0, n);
+                        total += n;
+                    }
                 } catch (ShortBufferException e) {
                     if (resized) {
                         // we just resized the output buffer, but it still
@@ -831,11 +836,13 @@
                     }
                     // output buffer is too small, realloc and try again
                     resized = true;
-                    int newOut = engineGetOutputSize(chunk);
-                    outArray = new byte[newOut];
+                    outSize = engineGetOutputSize(chunk);
+                    outArray = new byte[outSize];
                 }
             } while (inLen > 0);
-            input.position(inLimit);
+            if (a1) {
+                input.position(inLimit);
+            }
             return total;
         }
     }
--- a/src/share/classes/javax/crypto/JceSecurity.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/javax/crypto/JceSecurity.java	Sat Feb 03 21:37:28 2018 -0800
@@ -29,12 +29,14 @@
 import java.util.jar.*;
 import java.io.*;
 import java.net.URL;
+import java.nio.file.*;
 import java.security.*;
 
 import java.security.Provider.Service;
 
 import sun.security.jca.*;
 import sun.security.jca.GetInstance.Instance;
+import sun.security.util.Debug;
 
 /**
  * This class instantiates implementations of JCE engine classes from
@@ -67,6 +69,9 @@
     // Set the default value. May be changed in the static initializer.
     private static boolean isRestricted = true;
 
+    private static final Debug debug =
+                        Debug.getInstance("jca", "Cipher");
+
     /*
      * Don't let anyone instantiate this.
      */
@@ -205,7 +210,7 @@
 
     static {
         try {
-            NULL_URL = new URL("http://null.sun.com/");
+            NULL_URL = new URL("http://null.oracle.com/");
         } catch (Exception e) {
             throw new RuntimeException(e);
         }
@@ -240,14 +245,70 @@
         }
     }
 
+    /*
+     * This is called from within an doPrivileged block.
+     *
+     * Following logic is used to decide what policy files are selected.
+     *
+     * If the new Security property (crypto.policy) is set in the
+     * java.security file, or has been set dynamically using the
+     * Security.setProperty() call before the JCE framework has
+     * been initialized, that setting will be used.
+     * Remember - this property is not defined by default. A conscious
+     * user edit or an application call is required.
+     *
+     * Otherwise, if user has policy jar files installed in the legacy
+     * jre/lib/security/ directory, the JDK will honor whatever
+     * setting is set by those policy files. (legacy/current behavior)
+     *
+     * If none of the above 2 conditions are met, the JDK will default
+     * to using the limited crypto policy files found in the
+     * jre/lib/security/policy/limited/ directory
+     */
     private static void setupJurisdictionPolicies() throws Exception {
-        String javaHomeDir = System.getProperty("java.home");
-        String sep = File.separator;
-        String pathToPolicyJar = javaHomeDir + sep + "lib" + sep +
-            "security" + sep;
+        // Sanity check the crypto.policy Security property.  Single
+        // directory entry, no pseudo-directories (".", "..", leading/trailing
+        // path separators). normalize()/getParent() will help later.
+        String javaHomeProperty = System.getProperty("java.home");
+        String cryptoPolicyProperty = Security.getProperty("crypto.policy");
+        Path cpPath = (cryptoPolicyProperty == null) ? null :
+                Paths.get(cryptoPolicyProperty);
 
-        File exportJar = new File(pathToPolicyJar, "US_export_policy.jar");
-        File importJar = new File(pathToPolicyJar, "local_policy.jar");
+        if ((cpPath != null) && ((cpPath.getNameCount() != 1) ||
+                (cpPath.compareTo(cpPath.getFileName())) != 0)) {
+            throw new SecurityException(
+                    "Invalid policy directory name format: " +
+                            cryptoPolicyProperty);
+        }
+
+        if (cpPath == null) {
+            // Security property is not set, use default path
+            cpPath = Paths.get(javaHomeProperty, "lib", "security");
+        } else {
+            // populate with java.home
+            cpPath = Paths.get(javaHomeProperty, "lib", "security",
+                    "policy", cryptoPolicyProperty);
+        }
+
+        if (debug != null) {
+            debug.println("crypto policy directory: " + cpPath);
+        }
+
+        File exportJar = new File(cpPath.toFile(),"US_export_policy.jar");
+        File importJar = new File(cpPath.toFile(),"local_policy.jar");
+
+        if (cryptoPolicyProperty == null && (!exportJar.exists() ||
+                !importJar.exists())) {
+            // Compatibility set up. If crypto.policy is not defined.
+            // check to see if legacy jars exist in lib directory. If
+            // they don't exist, we default to limited policy mode.
+            cpPath = Paths.get(
+                    javaHomeProperty, "lib", "security", "policy", "limited");
+            // point to the new jar files in limited directory
+            exportJar = new File(cpPath.toFile(),"US_export_policy.jar");
+            importJar = new File(cpPath.toFile(),"local_policy.jar");
+        }
+
         URL jceCipherURL = ClassLoader.getSystemResource
                 ("javax/crypto/Cipher.class");
 
--- a/src/share/classes/sun/awt/CustomCursor.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/sun/awt/CustomCursor.java	Sat Feb 03 21:37:28 2018 -0800
@@ -65,7 +65,8 @@
 
         // Scale image to nearest supported size.
         Dimension nativeSize = toolkit.getBestCursorSize(width, height);
-        if (nativeSize.width != width || nativeSize.height != height) {
+        if ((nativeSize.width != width || nativeSize.height != height) &&
+            (nativeSize.width != 0 && nativeSize.height != 0)) {
             cursor = cursor.getScaledInstance(nativeSize.width,
                                               nativeSize.height,
                                               Image.SCALE_DEFAULT);
--- a/src/share/classes/sun/awt/resources/awt_ko.properties	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/sun/awt/resources/awt_ko.properties	Sat Feb 03 21:37:28 2018 -0800
@@ -14,7 +14,7 @@
 AWT.enter=Enter
 AWT.backSpace=Backspace
 AWT.tab=Tab
-AWT.cancel=Cancel
+AWT.cancel=\uCDE8\uC18C
 AWT.clear=Clear
 AWT.pause=Pause
 AWT.capsLock=Caps Lock
--- a/src/share/classes/sun/misc/IOUtils.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/sun/misc/IOUtils.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 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
@@ -37,9 +37,9 @@
 public class IOUtils {
 
     /**
-     * Read up to <code>length</code> of bytes from <code>in</code>
+     * Read up to {@code length} of bytes from {@code in}
      * until EOF is detected.
-     * @param in input stream, must not be null
+     * @param is input stream, must not be null
      * @param length number of bytes to read, -1 or Integer.MAX_VALUE means
      *        read as much as possible
      * @param readAll if true, an EOFException will be thrown if not enough
@@ -77,4 +77,22 @@
         }
         return output;
     }
+
+    /**
+     * Read {@code length} of bytes from {@code in}. An exception is
+     * thrown if there are not enough bytes in the stream.
+     *
+     * @param is input stream, must not be null
+     * @param length number of bytes to read, must not be negative
+     * @return bytes read
+     * @throws IOException if any IO error or a premature EOF is detected, or
+     *      if {@code length} is negative since this length is usually also
+     *      read from {@code is}.
+     */
+    public static byte[] readNBytes(InputStream is, int length) throws IOException {
+        if (length < 0) {
+            throw new IOException("length cannot be negative: " + length);
+        }
+        return readFully(is, length, true);
+    }
 }
--- a/src/share/classes/sun/misc/JavaOISAccess.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/sun/misc/JavaOISAccess.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -25,9 +25,12 @@
 
 package sun.misc;
 
+import java.io.InvalidClassException;
 import java.io.ObjectInputStream;
 
 public interface JavaOISAccess {
     void setObjectInputFilter(ObjectInputStream stream, ObjectInputFilter filter);
     ObjectInputFilter getObjectInputFilter(ObjectInputStream stream);
+    void checkArray(ObjectInputStream stream, Class<?> arrayType, int arrayLength)
+        throws InvalidClassException;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/misc/JavaSecurityKeyStoreAccess.java	Sat Feb 03 21:37:28 2018 -0800
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2017 Red Hat, Inc.
+ * 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.misc;
+
+import java.security.cert.Certificate;
+import java.security.KeyStore.PrivateKeyEntry;
+import java.security.KeyStore.SecretKeyEntry;
+import java.security.KeyStore.TrustedCertificateEntry;
+import java.security.PrivateKey;
+
+import javax.crypto.SecretKey;
+
+import java.util.Set;
+
+import sun.security.pkcs12.PKCS12Attribute;
+
+/**
+ * Shared secret interface to allow us
+ * to create key entries which hold a set of
+ * PKCS12Attribute objects.
+ */
+public interface JavaSecurityKeyStoreAccess {
+
+    /**
+     * Constructs a {@code PrivateKeyEntry} with a {@code PrivateKey} and
+     * corresponding certificate chain and associated entry attributes.
+     *
+     * <p> The specified {@code chain} and {@code attributes} are cloned
+     * before they are stored in the new {@code PrivateKeyEntry} object.
+     *
+     * @param privateKey the {@code PrivateKey}
+     * @param chain an array of {@code Certificate}s
+     *      representing the certificate chain.
+     *      The chain must be ordered and contain a
+     *      {@code Certificate} at index 0
+     *      corresponding to the private key.
+     * @param attributes the attributes
+     *
+     * @exception NullPointerException if {@code privateKey}, {@code chain}
+     *      or {@code attributes} is {@code null}
+     * @exception IllegalArgumentException if the specified chain has a
+     *      length of 0, if the specified chain does not contain
+     *      {@code Certificate}s of the same type,
+     *      or if the {@code PrivateKey} algorithm
+     *      does not match the algorithm of the {@code PublicKey}
+     *      in the end entity {@code Certificate} (at index 0)
+     *
+     * @since 1.8
+     */
+    PrivateKeyEntry constructPrivateKeyEntry(PrivateKey privateKey, Certificate[] chain,
+                                             Set<PKCS12Attribute> attributes);
+
+    /**
+     * Retrieves the attributes associated with a {@code PrivateKeyEntry}.
+     * <p>
+     *
+     * @return an unmodifiable {@code Set} of attributes, possibly empty
+     *
+     * @since 1.8
+     */
+    Set<PKCS12Attribute> getPrivateKeyEntryAttributes(PrivateKeyEntry entry);
+
+    /**
+     * Constructs a {@code SecretKeyEntry} with a {@code SecretKey} and
+     * associated entry attributes.
+     *
+     * <p> The specified {@code attributes} is cloned before it is stored
+     * in the new {@code SecretKeyEntry} object.
+     *
+     * @param secretKey the {@code SecretKey}
+     * @param attributes the attributes
+     *
+     * @exception NullPointerException if {@code secretKey} or
+     *     {@code attributes} is {@code null}
+     *
+     * @since 1.8
+     */
+    SecretKeyEntry constructSecretKeyEntry(SecretKey secretKey, Set<PKCS12Attribute> attributes);
+
+    /**
+     * Retrieves the attributes associated with a {@code SecretKeyEntry}.
+     * <p>
+     *
+     * @return an unmodifiable {@code Set} of attributes, possibly empty
+     *
+     * @since 1.8
+     */
+    Set<PKCS12Attribute> getSecretKeyEntryAttributes(SecretKeyEntry entry);
+
+    /**
+     * Constructs a {@code TrustedCertificateEntry} with a
+     * trusted {@code Certificate} and associated entry attributes.
+     *
+     * <p> The specified {@code attributes} is cloned before it is stored
+     * in the new {@code TrustedCertificateEntry} object.
+     *
+     * @param trustedCert the trusted {@code Certificate}
+     * @param attributes the attributes
+     *
+     * @exception NullPointerException if {@code trustedCert} or
+     *     {@code attributes} is {@code null}
+     *
+     * @since 1.8
+     */
+    TrustedCertificateEntry constructTrustedCertificateEntry(Certificate trustedCert,
+                                                             Set<PKCS12Attribute> attributes);
+
+    /**
+     * Retrieves the attributes associated with a {@code TrustedCertificateEntry}.
+     * <p>
+     *
+     * @return an unmodifiable {@code Set} of attributes, possibly empty
+     *
+     * @since 1.8
+     */
+    Set<PKCS12Attribute> getTrustedCertificateEntryAttributes(TrustedCertificateEntry entry);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/misc/JavaUtilCalendarAccess.java	Sat Feb 03 21:37:28 2018 -0800
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2017 Red Hat, Inc.
+ * 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.misc;
+
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.Locale;
+import java.util.TimeZone;
+
+public interface JavaUtilCalendarAccess {
+
+    /**
+     * Create an empty GregorianCalendar instance.
+     */
+    GregorianCalendar createCalendar(TimeZone zone, Locale locale);
+
+    /**
+     * Fills in any unset fields in the calendar fields. First, the {@link
+     * #computeTime()} method is called if the time value (millisecond offset
+     * from the <a href="#Epoch">Epoch</a>) has not been calculated from
+     * calendar field values. Then, the {@link #computeFields()} method is
+     * called to calculate all calendar field values.
+     *
+     * @param cal the calendar to complete.
+     */
+    void complete(Calendar cal);
+}
--- a/src/share/classes/sun/misc/SharedSecrets.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/sun/misc/SharedSecrets.java	Sat Feb 03 21:37:28 2018 -0800
@@ -25,17 +25,18 @@
 
 package sun.misc;
 
-import java.io.ObjectInputStream;
-import java.util.jar.JarFile;
 import java.io.Console;
 import java.io.FileDescriptor;
 import java.io.ObjectInputStream;
+import java.security.AccessController;
+import java.security.KeyStore;
 import java.security.ProtectionDomain;
+import java.util.GregorianCalendar;
+import java.util.jar.JarFile;
 import java.util.zip.Adler32;
+
 import javax.security.auth.kerberos.KeyTab;
 
-import java.security.AccessController;
-
 /** A repository of "shared secrets", which are a mechanism for
     calling implementation-private methods in another package without
     using reflection. A package-private class implements a public
@@ -62,6 +63,8 @@
     private static JavaAWTAccess javaAWTAccess;
     private static JavaOISAccess javaOISAccess;
     private static JavaObjectInputStreamAccess javaObjectInputStreamAccess;
+    private static JavaUtilCalendarAccess javaUtilCalendarAccess;
+    private static JavaSecurityKeyStoreAccess javaSecurityKeyStoreAccess;
 
     public static JavaUtilJarAccess javaUtilJarAccess() {
         if (javaUtilJarAccess == null) {
@@ -226,4 +229,25 @@
     public static void setJavaObjectInputStreamAccess(JavaObjectInputStreamAccess access) {
         javaObjectInputStreamAccess = access;
     }
+
+    public static JavaUtilCalendarAccess getJavaUtilCalendarAccess() {
+        if (javaUtilCalendarAccess == null) {
+            unsafe.ensureClassInitialized(GregorianCalendar.class);
+        }
+        return javaUtilCalendarAccess;
+    }
+
+    public static void setJavaUtilCalendarAccess(JavaUtilCalendarAccess access) {
+        javaUtilCalendarAccess = access;
+    }
+
+    public static void setJavaSecurityKeyStoreAccess(JavaSecurityKeyStoreAccess jsksa) {
+            javaSecurityKeyStoreAccess = jsksa;
+    }
+
+    public static JavaSecurityKeyStoreAccess getJavaSecurityKeyStoreAccess() {
+            if (javaSecurityKeyStoreAccess == null)
+                unsafe.ensureClassInitialized(KeyStore.class);
+            return javaSecurityKeyStoreAccess;
+    }
 }
--- a/src/share/classes/sun/net/ftp/impl/FtpClient.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/sun/net/ftp/impl/FtpClient.java	Sat Feb 03 21:37:28 2018 -0800
@@ -117,8 +117,8 @@
                 new PrivilegedAction<Object>() {
 
                     public Object run() {
-                        vals[0] = Integer.getInteger("sun.net.client.defaultReadTimeout", 0).intValue();
-                        vals[1] = Integer.getInteger("sun.net.client.defaultConnectTimeout", 0).intValue();
+                        vals[0] = Integer.getInteger("sun.net.client.defaultReadTimeout", 300_000).intValue();
+                        vals[1] = Integer.getInteger("sun.net.client.defaultConnectTimeout", 300_000).intValue();
                         encs[0] = System.getProperty("file.encoding", "ISO8859_1");
                         return null;
                     }
--- a/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java	Sat Feb 03 21:37:28 2018 -0800
@@ -761,18 +761,36 @@
         this(u, null, handler);
     }
 
-    public HttpURLConnection(URL u, String host, int port) {
-        this(u, new Proxy(Proxy.Type.HTTP, InetSocketAddress.createUnresolved(host, port)));
+    private static String checkHost(String h) throws IOException {
+        if (h != null) {
+            if (h.indexOf('\n') > -1) {
+                throw new MalformedURLException("Illegal character in host");
+            }
+        }
+        return h;
+    }
+    public HttpURLConnection(URL u, String host, int port) throws IOException {
+        this(u, new Proxy(Proxy.Type.HTTP,
+                InetSocketAddress.createUnresolved(checkHost(host), port)));
     }
 
     /** this constructor is used by other protocol handlers such as ftp
         that want to use http to fetch urls on their behalf.*/
-    public HttpURLConnection(URL u, Proxy p) {
+    public HttpURLConnection(URL u, Proxy p) throws IOException {
         this(u, p, new Handler());
     }
 
-    protected HttpURLConnection(URL u, Proxy p, Handler handler) {
-        super(u);
+    private static URL checkURL(URL u) throws IOException {
+        if (u != null) {
+            if (u.toExternalForm().indexOf('\n') > -1) {
+                throw new MalformedURLException("Illegal character in URL");
+            }
+        }
+        return u;
+    }
+    protected HttpURLConnection(URL u, Proxy p, Handler handler)
+            throws IOException {
+        super(checkURL(u));
         requests = new MessageHeader();
         responses = new MessageHeader();
         this.handler = handler;
--- a/src/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java	Sat Feb 03 21:37:28 2018 -0800
@@ -38,6 +38,7 @@
 import java.net.URL;
 import java.net.Proxy;
 import java.net.ProtocolException;
+import java.net.MalformedURLException;
 import java.io.*;
 import javax.net.ssl.*;
 import java.security.Permission;
@@ -79,10 +80,18 @@
         this(u, null, handler);
     }
 
+    static URL checkURL(URL u) throws IOException {
+        if (u != null) {
+            if (u.toExternalForm().indexOf('\n') > -1) {
+                throw new MalformedURLException("Illegal character in URL");
+            }
+        }
+        return u;
+    }
 // For both copies of the file, uncomment one line and comment the other
     HttpsURLConnectionImpl(URL u, Proxy p, Handler handler) throws IOException {
 //    HttpsURLConnectionOldImpl(URL u, Proxy p, Handler handler) throws IOException {
-        super(u);
+        super(checkURL(u));
         delegate = new DelegateHttpsURLConnection(url, p, handler, this);
     }
 
--- a/src/share/classes/sun/rmi/transport/Target.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/sun/rmi/transport/Target.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2008, 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
@@ -31,6 +31,7 @@
 import java.rmi.server.Unreferenced;
 import java.security.AccessControlContext;
 import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.util.*;
 import sun.rmi.runtime.Log;
 import sun.rmi.runtime.NewThreadAction;
@@ -322,25 +323,21 @@
             Remote obj = getImpl();
             if (obj instanceof Unreferenced) {
                 final Unreferenced unrefObj = (Unreferenced) obj;
-                final Thread t =
-                    java.security.AccessController.doPrivileged(
-                        new NewThreadAction(new Runnable() {
+                final Thread t = AccessController.doPrivileged(
+                     new NewThreadAction(new Runnable() {
+                            @Override
                             public void run() {
-                                unrefObj.unreferenced();
+                                Thread.currentThread().setContextClassLoader(ccl);
+                                AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                                    @Override
+                                    public Void run() {
+                                        unrefObj.unreferenced();
+                                        return null;
+                                    }
+                                }, acc);
                             }
-                        }, "Unreferenced-" + nextThreadNum++, false, true));
-                // REMIND: access to nextThreadNum not synchronized; you care?
-                /*
-                 * We must manually set the context class loader appropriately
-                 * for threads that may invoke user code (see bugid 4171278).
-                 */
-                java.security.AccessController.doPrivileged(
-                    new java.security.PrivilegedAction<Void>() {
-                        public Void run() {
-                        t.setContextClassLoader(ccl);
-                        return null;
-                    }
-                });
+                    }, "Unreferenced-" + nextThreadNum++, false, true));
+                    // REMIND: access to nextThreadNum not synchronized; you care?
 
                 t.start();
             }
--- a/src/share/classes/sun/security/action/GetPropertyAction.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/sun/security/action/GetPropertyAction.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 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
@@ -25,6 +25,9 @@
 
 package sun.security.action;
 
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
 /**
  * A convenience class for retrieving the string value of a system
  * property as a privileged action.
@@ -46,8 +49,7 @@
  * @since 1.2
  */
 
-public class GetPropertyAction
-        implements java.security.PrivilegedAction<String> {
+public class GetPropertyAction implements PrivilegedAction<String> {
     private String theProp;
     private String defaultVal;
 
@@ -84,4 +86,26 @@
         String value = System.getProperty(theProp);
         return (value == null) ? defaultVal : value;
     }
+
+    /**
+     * Convenience method to get a property without going through doPrivileged
+     * if no security manager is present. This is unsafe for inclusion in a
+     * public API but allowable here since this class is by default restricted
+     * by the package.access security property.
+     *
+     * Note that this method performs a privileged action using caller-provided
+     * inputs. The caller of this method should take care to ensure that the
+     * inputs are not tainted and the returned property is not made accessible
+     * to untrusted code if it contains sensitive information.
+     *
+     * @param theProp the name of the system property.
+     */
+    public static String privilegedGetProperty(String theProp) {
+        if (System.getSecurityManager() == null) {
+            return System.getProperty(theProp);
+        } else {
+            return AccessController.doPrivileged(
+                    new GetPropertyAction(theProp));
+        }
+    }
 }
--- a/src/share/classes/sun/security/ec/ECKeyPairGenerator.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/sun/security/ec/ECKeyPairGenerator.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, 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
@@ -37,6 +37,7 @@
 import sun.security.ec.ECPrivateKeyImpl;
 import sun.security.ec.ECPublicKeyImpl;
 import sun.security.jca.JCAUtil;
+import static sun.security.util.SecurityProviderConstants.DEF_EC_KEY_SIZE;
 
 /**
  * EC keypair generator.
@@ -48,7 +49,6 @@
 
     private static final int KEY_SIZE_MIN = 112; // min bits (see ecc_impl.h)
     private static final int KEY_SIZE_MAX = 571; // max bits (see ecc_impl.h)
-    private static final int KEY_SIZE_DEFAULT = 256;
 
     // used to seed the keypair generator
     private SecureRandom random;
@@ -64,7 +64,7 @@
      */
     public ECKeyPairGenerator() {
         // initialize to default in case the app does not call initialize()
-        initialize(KEY_SIZE_DEFAULT, null);
+        initialize(DEF_EC_KEY_SIZE, null);
     }
 
     // initialize the generator. See JCA doc
--- a/src/share/classes/sun/security/krb5/KdcComm.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/sun/security/krb5/KdcComm.java	Sat Feb 03 21:37:28 2018 -0800
@@ -369,37 +369,36 @@
 
             for (int i=1; i <= retries; i++) {
                 String proto = useTCP?"TCP":"UDP";
-                NetClient kdcClient = NetClient.getInstance(
-                        proto, kdc, port, timeout);
-                if (DEBUG) {
-                    System.out.println(">>> KDCCommunication: kdc=" + kdc
-                           + " " + proto + ":"
-                           +  port +  ", timeout="
-                           + timeout
-                           + ",Attempt =" + i
-                           + ", #bytes=" + obuf.length);
-                }
-                try {
-                    /*
-                     * Send the data to the kdc.
-                     */
-                    kdcClient.send(obuf);
-                    /*
-                     * And get a response.
-                     */
-                    ibuf = kdcClient.receive();
-                    break;
-                } catch (SocketTimeoutException se) {
+                try (NetClient kdcClient = NetClient.getInstance(
+                        proto, kdc, port, timeout)) {
                     if (DEBUG) {
-                        System.out.println ("SocketTimeOutException with " +
-                                            "attempt: " + i);
+                        System.out.println(">>> KDCCommunication: kdc=" + kdc
+                            + " " + proto + ":"
+                            +  port +  ", timeout="
+                            + timeout
+                            + ",Attempt =" + i
+                            + ", #bytes=" + obuf.length);
                     }
-                    if (i == retries) {
-                        ibuf = null;
-                        throw se;
+                    try {
+                        /*
+                        * Send the data to the kdc.
+                        */
+                        kdcClient.send(obuf);
+                        /*
+                        * And get a response.
+                        */
+                        ibuf = kdcClient.receive();
+                        break;
+                    } catch (SocketTimeoutException se) {
+                        if (DEBUG) {
+                            System.out.println ("SocketTimeOutException with " +
+                                                "attempt: " + i);
+                        }
+                        if (i == retries) {
+                            ibuf = null;
+                            throw se;
+                        }
                     }
-                } finally {
-                    kdcClient.close();
                 }
             }
             return ibuf;
--- a/src/share/classes/sun/security/krb5/KrbAsRep.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/sun/security/krb5/KrbAsRep.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -160,7 +160,7 @@
         creds = new Credentials(
                                 rep.ticket,
                                 req.reqBody.cname,
-                                rep.ticket.sname,
+                                enc_part.sname,
                                 enc_part.key,
                                 enc_part.flags,
                                 enc_part.authtime,
--- a/src/share/classes/sun/security/krb5/KrbTgsRep.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/sun/security/krb5/KrbTgsRep.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -88,7 +88,7 @@
 
         this.creds = new Credentials(rep.ticket,
                                 req.reqBody.cname,
-                                rep.ticket.sname,
+                                enc_part.sname,
                                 enc_part.key,
                                 enc_part.flags,
                                 enc_part.authtime,
--- a/src/share/classes/sun/security/krb5/internal/NetClient.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/sun/security/krb5/internal/NetClient.java	Sat Feb 03 21:37:28 2018 -0800
@@ -36,7 +36,7 @@
 import java.io.*;
 import java.net.*;
 
-public abstract class NetClient {
+public abstract class NetClient implements AutoCloseable {
     public static NetClient getInstance(String protocol, String hostname, int port,
             int timeout) throws IOException {
         if (protocol.equals("TCP")) {
@@ -47,9 +47,7 @@
     }
 
     abstract public void send(byte[] data) throws IOException;
-
     abstract public byte[] receive() throws IOException;
-
     abstract public void close() throws IOException;
 }
 
@@ -190,6 +188,7 @@
         iport = port;
         dgSocket = new DatagramSocket();
         dgSocket.setSoTimeout(timeout);
+        dgSocket.connect(iaddr, iport);
     }
 
     @Override
@@ -207,6 +206,9 @@
             dgSocket.receive(dgPacketIn);
         }
         catch (SocketException e) {
+            if (e instanceof PortUnreachableException) {
+                throw e;
+            }
             dgSocket.receive(dgPacketIn);
         }
         byte[] data = new byte[dgPacketIn.getLength()];
--- a/src/share/classes/sun/security/pkcs/SignerInfo.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/sun/security/pkcs/SignerInfo.java	Sat Feb 03 21:37:28 2018 -0800
@@ -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
@@ -37,6 +37,7 @@
 import java.security.Signature;
 import java.security.SignatureException;
 import java.security.Timestamp;
+import java.security.cert.CertPathValidatorException;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
 import java.security.cert.CertPath;
@@ -49,6 +50,7 @@
 
 import sun.misc.HexDumpEncoder;
 import sun.security.timestamp.TimestampToken;
+import sun.security.util.ConstraintsParameters;
 import sun.security.util.Debug;
 import sun.security.util.DerEncoder;
 import sun.security.util.DerInputStream;
@@ -209,7 +211,7 @@
 
     /**
      * DER encode this object onto an output stream.
-     * Implements the <code>DerEncoder</code> interface.
+     * Implements the {@code DerEncoder} interface.
      *
      * @param out
      * the output stream on which to write the DER encoding.
@@ -266,7 +268,7 @@
         if (userCert == null)
             return null;
 
-        ArrayList<X509Certificate> certList = new ArrayList<X509Certificate>();
+        ArrayList<X509Certificate> certList = new ArrayList<>();
         certList.add(userCert);
 
         X509Certificate[] pkcsCerts = block.getCertificates();
@@ -321,6 +323,14 @@
                 data = content.getContentBytes();
             }
 
+            Timestamp timestamp = null;
+            try {
+                timestamp = getTimestamp();
+            } catch (Exception ignore) {
+            }
+
+            ConstraintsParameters cparams =
+                    new ConstraintsParameters(timestamp);
             String digestAlgname = getDigestAlgorithmId().getName();
 
             byte[] dataSigned;
@@ -347,11 +357,11 @@
                 if (messageDigest == null) // fail if there is no message digest
                     return null;
 
-                // check that algorithm is not restricted
-                if (!JAR_DISABLED_CHECK.permits(DIGEST_PRIMITIVE_SET,
-                        digestAlgname, null)) {
-                    throw new SignatureException("Digest check failed. " +
-                            "Disabled algorithm used: " + digestAlgname);
+                // check that digest algorithm is not restricted
+                try {
+                    JAR_DISABLED_CHECK.permits(digestAlgname, cparams);
+                } catch (CertPathValidatorException e) {
+                    throw new SignatureException(e.getMessage(), e);
                 }
 
                 MessageDigest md = MessageDigest.getInstance(
@@ -386,17 +396,18 @@
             String algname = AlgorithmId.makeSigAlg(
                     digestAlgname, encryptionAlgname);
 
-            // check that algorithm is not restricted
-            if (!JAR_DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, algname, null)) {
-                throw new SignatureException("Signature check failed. " +
-                        "Disabled algorithm used: " + algname);
+            // check that jar signature algorithm is not restricted
+            try {
+                JAR_DISABLED_CHECK.permits(algname, cparams);
+            } catch (CertPathValidatorException e) {
+                throw new SignatureException(e.getMessage(), e);
             }
 
             X509Certificate cert = getCertificate(block);
-            PublicKey key = cert.getPublicKey();
             if (cert == null) {
                 return null;
             }
+            PublicKey key = cert.getPublicKey();
 
             // check if the public key is restricted
             if (!JAR_DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, key)) {
@@ -520,7 +531,7 @@
      * Extracts a timestamp from a PKCS7 SignerInfo.
      *
      * Examines the signer's unsigned attributes for a
-     * <tt>signatureTimestampToken</tt> attribute. If present,
+     * {@code signatureTimestampToken} attribute. If present,
      * then it is parsed to extract the date and time at which the
      * timestamp was generated.
      *
--- a/src/share/classes/sun/security/pkcs10/PKCS10.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/sun/security/pkcs10/PKCS10.java	Sat Feb 03 21:37:28 2018 -0800
@@ -167,7 +167,8 @@
         // key and signature algorithm we found.
         //
         try {
-            sig = Signature.getInstance(id.getName());
+            sigAlg = id.getName();
+            sig = Signature.getInstance(sigAlg);
             sig.initVerify(subjectPublicKeyInfo);
             sig.update(data);
             if (!sig.verify(sigData))
@@ -218,6 +219,7 @@
         signature.update(certificateRequestInfo, 0,
                 certificateRequestInfo.length);
         sig = signature.sign();
+        sigAlg = signature.getAlgorithm();
 
         /*
          * Build guts of SIGNED macro
@@ -251,6 +253,11 @@
         { return subjectPublicKeyInfo; }
 
     /**
+     * Returns the signature algorithm.
+     */
+    public String getSigAlg() { return sigAlg; }
+
+    /**
      * Returns the additional attributes requested.
      */
     public PKCS10Attributes getAttributes()
@@ -348,6 +355,7 @@
 
     private X500Name            subject;
     private PublicKey           subjectPublicKeyInfo;
+    private String              sigAlg;
     private PKCS10Attributes    attributeSet;
     private byte[]              encoded;        // signed
 }
--- a/src/share/classes/sun/security/pkcs11/P11KeyPairGenerator.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/sun/security/pkcs11/P11KeyPairGenerator.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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,11 +33,13 @@
 import javax.crypto.spec.DHParameterSpec;
 
 import sun.security.provider.ParameterCache;
+import static sun.security.util.SecurityProviderConstants.*;
 
 import static sun.security.pkcs11.TemplateManager.*;
 import sun.security.pkcs11.wrapper.*;
 import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
 
+
 import sun.security.rsa.RSAKeyFactory;
 
 /**
@@ -70,20 +72,72 @@
     // for RSA, selected or default value of public exponent, always valid
     private BigInteger rsaPublicExponent = RSAKeyGenParameterSpec.F4;
 
+    // the supported keysize range of the native PKCS11 library
+    // if the value cannot be retrieved or unspecified, -1 is used.
+    private final int minKeySize;
+    private final int maxKeySize;
+
     // SecureRandom instance, if specified in init
     private SecureRandom random;
 
     P11KeyPairGenerator(Token token, String algorithm, long mechanism)
             throws PKCS11Exception {
         super();
+        int minKeyLen = -1;
+        int maxKeyLen = -1;
+        try {
+            CK_MECHANISM_INFO mechInfo = token.getMechanismInfo(mechanism);
+            if (mechInfo != null) {
+                minKeyLen = (int) mechInfo.ulMinKeySize;
+                maxKeyLen = (int) mechInfo.ulMaxKeySize;
+            }
+        } catch (PKCS11Exception p11e) {
+            // Should never happen
+            throw new ProviderException
+                        ("Unexpected error while getting mechanism info", p11e);
+        }
+        // set default key sizes and apply our own algorithm-specific limits
+        // override lower limit to disallow unsecure keys being generated
+        // override upper limit to deter DOS attack
+        if (algorithm.equals("EC")) {
+            keySize = DEF_EC_KEY_SIZE;
+            if ((minKeyLen == -1) || (minKeyLen < 112)) {
+                minKeyLen = 112;
+            }
+            if ((maxKeyLen == -1) || (maxKeyLen > 2048)) {
+                maxKeyLen = 2048;
+            }
+        } else {
+            if (algorithm.equals("DSA")) {
+                keySize = DEF_DSA_KEY_SIZE;
+            } else if (algorithm.equals("RSA")) {
+                keySize = DEF_RSA_KEY_SIZE;
+            } else {
+                keySize = DEF_DH_KEY_SIZE;
+            }
+            if ((minKeyLen == -1) || (minKeyLen < 512)) {
+                minKeyLen = 512;
+            }
+            if (algorithm.equals("RSA")) {
+                if ((maxKeyLen == -1) || (maxKeyLen > 64 * 1024)) {
+                    maxKeyLen = 64 * 1024;
+                }
+            }
+        }
+
+        // auto-adjust default keysize in case it's out-of-range
+        if ((minKeyLen != -1) && (keySize < minKeyLen)) {
+            keySize = minKeyLen;
+        }
+        if ((maxKeyLen != -1) && (keySize > maxKeyLen)) {
+            keySize = maxKeyLen;
+        }
         this.token = token;
         this.algorithm = algorithm;
         this.mechanism = mechanism;
-        if (algorithm.equals("EC")) {
-            initialize(256, null);
-        } else {
-            initialize(1024, null);
-        }
+        this.minKeySize = minKeyLen;
+        this.maxKeySize = maxKeyLen;
+        initialize(keySize, null);
     }
 
     // see JCA spec
@@ -94,9 +148,7 @@
         } catch (InvalidAlgorithmParameterException e) {
             throw new InvalidParameterException(e.getMessage());
         }
-        this.keySize = keySize;
         this.params = null;
-        this.random = random;
         if (algorithm.equals("EC")) {
             params = P11ECKeyFactory.getECParameterSpec(keySize);
             if (params == null) {
@@ -105,33 +157,35 @@
                     + keySize + " bits");
             }
         }
+        this.keySize = keySize;
+        this.random = random;
     }
 
     // see JCA spec
     public void initialize(AlgorithmParameterSpec params, SecureRandom random)
             throws InvalidAlgorithmParameterException {
         token.ensureValid();
+        int tmpKeySize;
         if (algorithm.equals("DH")) {
             if (params instanceof DHParameterSpec == false) {
                 throw new InvalidAlgorithmParameterException
                         ("DHParameterSpec required for Diffie-Hellman");
             }
-            DHParameterSpec dhParams = (DHParameterSpec)params;
-            int tmpKeySize = dhParams.getP().bitLength();
-            checkKeySize(tmpKeySize, dhParams);
-            this.keySize = tmpKeySize;
-            this.params = dhParams;
+            DHParameterSpec dhParams = (DHParameterSpec) params;
+            tmpKeySize = dhParams.getP().bitLength();
+            checkKeySize(tmpKeySize, null);
             // XXX sanity check params
         } else if (algorithm.equals("RSA")) {
             if (params instanceof RSAKeyGenParameterSpec == false) {
                 throw new InvalidAlgorithmParameterException
                         ("RSAKeyGenParameterSpec required for RSA");
             }
-            RSAKeyGenParameterSpec rsaParams = (RSAKeyGenParameterSpec)params;
-            int tmpKeySize = rsaParams.getKeysize();
+            RSAKeyGenParameterSpec rsaParams =
+                (RSAKeyGenParameterSpec) params;
+            tmpKeySize = rsaParams.getKeysize();
             checkKeySize(tmpKeySize, rsaParams);
-            this.keySize = tmpKeySize;
-            this.params = null;
+            // override the supplied params to null
+            params = null;
             this.rsaPublicExponent = rsaParams.getPublicExponent();
             // XXX sanity check params
         } else if (algorithm.equals("DSA")) {
@@ -139,11 +193,9 @@
                 throw new InvalidAlgorithmParameterException
                         ("DSAParameterSpec required for DSA");
             }
-            DSAParameterSpec dsaParams = (DSAParameterSpec)params;
-            int tmpKeySize = dsaParams.getP().bitLength();
-            checkKeySize(tmpKeySize, dsaParams);
-            this.keySize = tmpKeySize;
-            this.params = dsaParams;
+            DSAParameterSpec dsaParams = (DSAParameterSpec) params;
+            tmpKeySize = dsaParams.getP().bitLength();
+            checkKeySize(tmpKeySize, null);
             // XXX sanity check params
         } else if (algorithm.equals("EC")) {
             ECParameterSpec ecParams;
@@ -155,28 +207,42 @@
                         ("Unsupported curve: " + params);
                 }
             } else if (params instanceof ECGenParameterSpec) {
-                String name = ((ECGenParameterSpec)params).getName();
+                String name = ((ECGenParameterSpec) params).getName();
                 ecParams = P11ECKeyFactory.getECParameterSpec(name);
                 if (ecParams == null) {
                     throw new InvalidAlgorithmParameterException
                         ("Unknown curve name: " + name);
                 }
+                // override the supplied params with the derived one
+                params = ecParams;
             } else {
                 throw new InvalidAlgorithmParameterException
                     ("ECParameterSpec or ECGenParameterSpec required for EC");
             }
-            int tmpKeySize = ecParams.getCurve().getField().getFieldSize();
-            checkKeySize(tmpKeySize, ecParams);
-            this.keySize = tmpKeySize;
-            this.params = ecParams;
+            tmpKeySize = ecParams.getCurve().getField().getFieldSize();
+            checkKeySize(tmpKeySize, null);
         } else {
             throw new ProviderException("Unknown algorithm: " + algorithm);
         }
+        this.keySize = tmpKeySize;
+        this.params = params;
         this.random = random;
     }
 
-    private void checkKeySize(int keySize, AlgorithmParameterSpec params)
-            throws InvalidAlgorithmParameterException {
+    // NOTE: 'params' is only used for checking RSA keys currently.
+    private void checkKeySize(int keySize, RSAKeyGenParameterSpec params)
+        throws InvalidAlgorithmParameterException {
+        // check native range first
+        if ((minKeySize != -1) && (keySize < minKeySize)) {
+            throw new InvalidAlgorithmParameterException(algorithm +
+                " key must be at least " + minKeySize + " bits");
+        }
+        if ((maxKeySize != -1) && (keySize > maxKeySize)) {
+            throw new InvalidAlgorithmParameterException(algorithm +
+                " key must be at most " + maxKeySize + " bits");
+        }
+
+        // check our own algorithm-specific limits also
         if (algorithm.equals("EC")) {
             if (keySize < 112) {
                 throw new InvalidAlgorithmParameterException
@@ -187,41 +253,45 @@
                 throw new InvalidAlgorithmParameterException
                     ("Key size must be at most 2048 bit");
             }
-            return;
-        } else if (algorithm.equals("RSA")) {
-            BigInteger tmpExponent = rsaPublicExponent;
-            if (params != null) {
-                // Already tested for instanceof RSAKeyGenParameterSpec above
-                tmpExponent =
-                    ((RSAKeyGenParameterSpec)params).getPublicExponent();
+        } else {
+            // RSA, DH, DSA
+            if (keySize < 512) {
+                throw new InvalidAlgorithmParameterException
+                    ("Key size must be at least 512 bit");
             }
-            try {
-                // This provider supports 64K or less.
-                RSAKeyFactory.checkKeyLengths(keySize, tmpExponent,
-                    512, 64 * 1024);
-            } catch (InvalidKeyException e) {
-                throw new InvalidAlgorithmParameterException(e.getMessage());
-            }
-            return;
-        }
-
-        if (keySize < 512) {
-            throw new InvalidAlgorithmParameterException
-                ("Key size must be at least 512 bit");
-        }
-        if (algorithm.equals("DH") && (params != null)) {
-            // sanity check, nobody really wants keys this large
-            if (keySize > 64 * 1024) {
-                throw new InvalidAlgorithmParameterException
-                    ("Key size must be at most 65536 bit");
-            }
-        } else {
-            // this restriction is in the spec for DSA
-            // since we currently use DSA parameters for DH as well,
-            // it also applies to DH if no parameters are specified
-            if ((keySize > 1024) || ((keySize & 0x3f) != 0)) {
-                throw new InvalidAlgorithmParameterException
-                    ("Key size must be a multiple of 64 and at most 1024 bit");
+            if (algorithm.equals("RSA")) {
+                BigInteger tmpExponent = rsaPublicExponent;
+                if (params != null) {
+                    tmpExponent = params.getPublicExponent();
+                }
+                try {
+                    // Reuse the checking in SunRsaSign provider.
+                    // If maxKeySize is -1, then replace it with
+                    // Integer.MAX_VALUE to indicate no limit.
+                    RSAKeyFactory.checkKeyLengths(keySize, tmpExponent,
+                        minKeySize,
+                        (maxKeySize==-1? Integer.MAX_VALUE:maxKeySize));
+                } catch (InvalidKeyException e) {
+                    throw new InvalidAlgorithmParameterException(e.getMessage());
+                }
+            } else {
+                if (algorithm.equals("DH") && (params != null)) {
+                    // sanity check, nobody really wants keys this large
+                    if (keySize > 64 * 1024) {
+                        throw new InvalidAlgorithmParameterException
+                            ("Key size must be at most 65536 bit");
+                    }
+                } else {
+                    // this restriction is in the spec for DSA
+                    // since we currently use DSA parameters for DH as well,
+                    // it also applies to DH if no parameters are specified
+                    if ((keySize != 2048) &&
+                        ((keySize > 1024) || ((keySize & 0x3f) != 0))) {
+                        throw new InvalidAlgorithmParameterException(algorithm +
+                            " key must be multiples of 64 if less than 1024 bits" +
+                            ", or 2048 bits");
+                    }
+                }
             }
         }
     }
@@ -325,5 +395,4 @@
             token.releaseSession(session);
         }
     }
-
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/security/pkcs12/PKCS12Attribute.java	Sat Feb 03 21:37:28 2018 -0800
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.pkcs12;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.regex.Pattern;
+import sun.security.util.*;
+
+/**
+ * An attribute associated with a PKCS12 keystore entry.
+ * The attribute name is an ASN.1 Object Identifier and the attribute
+ * value is a set of ASN.1 types.
+ *
+ * @since 1.8
+ */
+public final class PKCS12Attribute {
+
+    private static final Pattern COLON_SEPARATED_HEX_PAIRS =
+        Pattern.compile("^[0-9a-fA-F]{2}(:[0-9a-fA-F]{2})+$");
+    private String name;
+    private String value;
+    private byte[] encoded;
+    private int hashValue = -1;
+
+    /**
+     * Constructs a PKCS12 attribute from its name and value.
+     * The name is an ASN.1 Object Identifier represented as a list of
+     * dot-separated integers.
+     * A string value is represented as the string itself.
+     * A binary value is represented as a string of colon-separated
+     * pairs of hexadecimal digits.
+     * Multi-valued attributes are represented as a comma-separated
+     * list of values, enclosed in square brackets. See
+     * {@link Arrays#toString(java.lang.Object[])}.
+     * <p>
+     * A string value will be DER-encoded as an ASN.1 UTF8String and a
+     * binary value will be DER-encoded as an ASN.1 Octet String.
+     *
+     * @param name the attribute's identifier
+     * @param value the attribute's value
+     *
+     * @exception NullPointerException if {@code name} or {@code value}
+     *     is {@code null}
+     * @exception IllegalArgumentException if {@code name} or
+     *     {@code value} is incorrectly formatted
+     */
+    public PKCS12Attribute(String name, String value) {
+        if (name == null || value == null) {
+            throw new NullPointerException();
+        }
+        // Validate name
+        ObjectIdentifier type;
+        try {
+            type = new ObjectIdentifier(name);
+        } catch (IOException e) {
+            throw new IllegalArgumentException("Incorrect format: name", e);
+        }
+        this.name = name;
+
+        // Validate value
+        int length = value.length();
+        String[] values;
+        if (value.charAt(0) == '[' && value.charAt(length - 1) == ']') {
+            values = value.substring(1, length - 1).split(", ");
+        } else {
+            values = new String[]{ value };
+        }
+        this.value = value;
+
+        try {
+            this.encoded = encode(type, values);
+        } catch (IOException e) {
+            throw new IllegalArgumentException("Incorrect format: value", e);
+        }
+    }
+
+    /**
+     * Constructs a PKCS12 attribute from its ASN.1 DER encoding.
+     * The DER encoding is specified by the following ASN.1 definition:
+     * <pre>
+     *
+     * Attribute ::= SEQUENCE {
+     *     type   AttributeType,
+     *     values SET OF AttributeValue
+     * }
+     * AttributeType ::= OBJECT IDENTIFIER
+     * AttributeValue ::= ANY defined by type
+     *
+     * </pre>
+     *
+     * @param encoded the attribute's ASN.1 DER encoding. It is cloned
+     *     to prevent subsequent modificaion.
+     *
+     * @exception NullPointerException if {@code encoded} is
+     *     {@code null}
+     * @exception IllegalArgumentException if {@code encoded} is
+     *     incorrectly formatted
+     */
+    public PKCS12Attribute(byte[] encoded) {
+        if (encoded == null) {
+            throw new NullPointerException();
+        }
+        this.encoded = encoded.clone();
+
+        try {
+            parse(encoded);
+        } catch (IOException e) {
+            throw new IllegalArgumentException("Incorrect format: encoded", e);
+        }
+    }
+
+    /**
+     * Returns the attribute's ASN.1 Object Identifier represented as a
+     * list of dot-separated integers.
+     *
+     * @return the attribute's identifier
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Returns the attribute's ASN.1 DER-encoded value as a string.
+     * An ASN.1 DER-encoded value is returned in one of the following
+     * {@code String} formats:
+     * <ul>
+     * <li> the DER encoding of a basic ASN.1 type that has a natural
+     *      string representation is returned as the string itself.
+     *      Such types are currently limited to BOOLEAN, INTEGER,
+     *      OBJECT IDENTIFIER, UTCTime, GeneralizedTime and the
+     *      following six ASN.1 string types: UTF8String,
+     *      PrintableString, T61String, IA5String, BMPString and
+     *      GeneralString.
+     * <li> the DER encoding of any other ASN.1 type is not decoded but
+     *      returned as a binary string of colon-separated pairs of
+     *      hexadecimal digits.
+     * </ul>
+     * Multi-valued attributes are represented as a comma-separated
+     * list of values, enclosed in square brackets. See
+     * {@link Arrays#toString(java.lang.Object[])}.
+     *
+     * @return the attribute value's string encoding
+     */
+    public String getValue() {
+        return value;
+    }
+
+    /**
+     * Returns the attribute's ASN.1 DER encoding.
+     *
+     * @return a clone of the attribute's DER encoding
+     */
+    public byte[] getEncoded() {
+        return encoded.clone();
+    }
+
+    /**
+     * Compares this {@code PKCS12Attribute} and a specified object for
+     * equality.
+     *
+     * @param obj the comparison object
+     *
+     * @return true if {@code obj} is a {@code PKCS12Attribute} and
+     * their DER encodings are equal.
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof PKCS12Attribute)) {
+            return false;
+        }
+        return Arrays.equals(encoded, ((PKCS12Attribute) obj).getEncoded());
+    }
+
+    /**
+     * Returns the hashcode for this {@code PKCS12Attribute}.
+     * The hash code is computed from its DER encoding.
+     *
+     * @return the hash code
+     */
+    @Override
+    public int hashCode() {
+        if (hashValue == -1) {
+            Arrays.hashCode(encoded);
+        }
+        return hashValue;
+    }
+
+    /**
+     * Returns a string representation of this {@code PKCS12Attribute}.
+     *
+     * @return a name/value pair separated by an 'equals' symbol
+     */
+    @Override
+    public String toString() {
+        return (name + "=" + value);
+    }
+
+    private byte[] encode(ObjectIdentifier type, String[] values)
+            throws IOException {
+        DerOutputStream attribute = new DerOutputStream();
+        attribute.putOID(type);
+        DerOutputStream attrContent = new DerOutputStream();
+        for (String value : values) {
+            if (COLON_SEPARATED_HEX_PAIRS.matcher(value).matches()) {
+                byte[] bytes =
+                    new BigInteger(value.replace(":", ""), 16).toByteArray();
+                if (bytes[0] == 0) {
+                    bytes = Arrays.copyOfRange(bytes, 1, bytes.length);
+                }
+                attrContent.putOctetString(bytes);
+            } else {
+                attrContent.putUTF8String(value);
+            }
+        }
+        attribute.write(DerValue.tag_Set, attrContent);
+        DerOutputStream attributeValue = new DerOutputStream();
+        attributeValue.write(DerValue.tag_Sequence, attribute);
+
+        return attributeValue.toByteArray();
+    }
+
+    private void parse(byte[] encoded) throws IOException {
+        DerInputStream attributeValue = new DerInputStream(encoded);
+        DerValue[] attrSeq = attributeValue.getSequence(2);
+        ObjectIdentifier type = attrSeq[0].getOID();
+        DerInputStream attrContent =
+            new DerInputStream(attrSeq[1].toByteArray());
+        DerValue[] attrValueSet = attrContent.getSet(1);
+        String[] values = new String[attrValueSet.length];
+        String printableString;
+        for (int i = 0; i < attrValueSet.length; i++) {
+            if (attrValueSet[i].tag == DerValue.tag_OctetString) {
+                values[i] = Debug.toString(attrValueSet[i].getOctetString());
+            } else if ((printableString = attrValueSet[i].getAsString())
+                != null) {
+                values[i] = printableString;
+            } else if (attrValueSet[i].tag == DerValue.tag_ObjectId) {
+                values[i] = attrValueSet[i].getOID().toString();
+            } else if (attrValueSet[i].tag == DerValue.tag_GeneralizedTime) {
+                values[i] = attrValueSet[i].getGeneralizedTime().toString();
+            } else if (attrValueSet[i].tag == DerValue.tag_UtcTime) {
+                values[i] = attrValueSet[i].getUTCTime().toString();
+            } else if (attrValueSet[i].tag == DerValue.tag_Integer) {
+                values[i] = attrValueSet[i].getBigInteger().toString();
+            } else if (attrValueSet[i].tag == DerValue.tag_Boolean) {
+                values[i] = String.valueOf(attrValueSet[i].getBoolean());
+            } else {
+                values[i] = Debug.toString(attrValueSet[i].getDataBytes());
+            }
+        }
+
+        this.name = type.toString();
+        this.value = values.length == 1 ? values[0] : Arrays.toString(values);
+    }
+}
--- a/src/share/classes/sun/security/pkcs12/PKCS12KeyStore.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/sun/security/pkcs12/PKCS12KeyStore.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2015, 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
@@ -30,27 +30,37 @@
 import java.security.NoSuchAlgorithmException;
 import java.security.Key;
 import java.security.KeyFactory;
-import java.security.PrivateKey;
+import java.security.KeyStore;
 import java.security.KeyStoreSpi;
 import java.security.KeyStoreException;
+import java.security.PrivateKey;
+import java.security.UnrecoverableEntryException;
 import java.security.UnrecoverableKeyException;
 import java.security.SecureRandom;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
 import java.security.cert.CertificateException;
+import java.security.spec.InvalidParameterSpecException;
+import java.security.spec.KeySpec;
 import java.security.spec.PKCS8EncodedKeySpec;
 import java.util.*;
 
 import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
 import javax.crypto.spec.PBEParameterSpec;
 import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.SecretKeySpec;
 import javax.crypto.SecretKeyFactory;
 import javax.crypto.SecretKey;
 import javax.crypto.Cipher;
 import javax.crypto.Mac;
+import javax.security.auth.DestroyFailedException;
 import javax.security.auth.x500.X500Principal;
 
+import sun.misc.JavaSecurityKeyStoreAccess;
+import sun.misc.SharedSecrets;
+
 import sun.security.util.Debug;
 import sun.security.util.DerInputStream;
 import sun.security.util.DerOutputStream;
@@ -100,11 +110,12 @@
  * OpenSSL PKCS#12 code.      All.                   All.
  * ---------------------------------------------------------------------
  *
- * NOTE: Currently PKCS12 KeyStore does not support TrustedCertEntries.
+ * NOTE: PKCS12 KeyStore supports PrivateKeyEntry and TrustedCertficateEntry.
  * PKCS#12 is mainly used to deliver private keys with their associated
  * certificate chain and aliases. In a PKCS12 keystore, entries are
  * identified by the alias, and a localKeyId is required to match the
- * private key with the certificate.
+ * private key with the certificate. Trusted certificate entries are identified
+ * by the presence of an trustedKeyUsage attribute.
  *
  * @author Seema Malkani
  * @author Jeff Nisewanger
@@ -120,10 +131,23 @@
 
     public static final int VERSION_3 = 3;
 
+    private static final int MAX_ITERATION_COUNT = 5000000;
+    private static final int PBE_ITERATION_COUNT = 50000; // default
+    private static final int MAC_ITERATION_COUNT = 100000; // default
+    private static final int SALT_LEN = 20;
+
+    // friendlyName, localKeyId, trustedKeyUsage
+    private static final String[] CORE_ATTRIBUTES = {
+        "1.2.840.113549.1.9.20",
+        "1.2.840.113549.1.9.21",
+        "2.16.840.1.113894.746875.1.1"
+    };
+
     private static final Debug debug = Debug.getInstance("pkcs12");
 
     private static final int keyBag[]  = {1, 2, 840, 113549, 1, 12, 10, 1, 2};
     private static final int certBag[] = {1, 2, 840, 113549, 1, 12, 10, 1, 3};
+    private static final int secretBag[] = {1, 2, 840, 113549, 1, 12, 10, 1, 5};
 
     private static final int pkcs9Name[]  = {1, 2, 840, 113549, 1, 9, 20};
     private static final int pkcs9KeyId[] = {1, 2, 840, 113549, 1, 9, 21};
@@ -134,24 +158,39 @@
                                         {1, 2, 840, 113549, 1, 12, 1, 6};
     private static final int pbeWithSHAAnd3KeyTripleDESCBC[] =
                                         {1, 2, 840, 113549, 1, 12, 1, 3};
+    // TODO: temporary Oracle OID
+    /*
+     * { joint-iso-itu-t(2) country(16) us(840) organization(1) oracle(113894)
+     *   jdk(746875) crypto(1) id-at-trustedKeyUsage(1) }
+     */
+    private static final int TrustedKeyUsage[] =
+                                        {2, 16, 840, 1, 113894, 746875, 1, 1};
+    private static final int AnyExtendedKeyUsage[] = {2, 5, 29, 37, 0};
 
     private static ObjectIdentifier PKCS8ShroudedKeyBag_OID;
     private static ObjectIdentifier CertBag_OID;
+    private static ObjectIdentifier SecretBag_OID;
     private static ObjectIdentifier PKCS9FriendlyName_OID;
     private static ObjectIdentifier PKCS9LocalKeyId_OID;
     private static ObjectIdentifier PKCS9CertType_OID;
     private static ObjectIdentifier pbeWithSHAAnd40BitRC2CBC_OID;
     private static ObjectIdentifier pbeWithSHAAnd3KeyTripleDESCBC_OID;
+    private static ObjectIdentifier TrustedKeyUsage_OID;
+    private static ObjectIdentifier[] AnyUsage;
 
     private int counter = 0;
-    private static final int iterationCount = 1024;
-    private static final int SALT_LEN = 20;
 
     // private key count
     // Note: This is a workaround to allow null localKeyID attribute
     // in pkcs12 with one private key entry and associated cert-chain
     private int privateKeyCount = 0;
 
+    // secret key count
+    private int secretKeyCount = 0;
+
+    // certificate count
+    private int certificateCount = 0;
+
     // the source of randomness
     private SecureRandom random;
 
@@ -159,6 +198,7 @@
         try {
             PKCS8ShroudedKeyBag_OID = new ObjectIdentifier(keyBag);
             CertBag_OID = new ObjectIdentifier(certBag);
+            SecretBag_OID = new ObjectIdentifier(secretBag);
             PKCS9FriendlyName_OID = new ObjectIdentifier(pkcs9Name);
             PKCS9LocalKeyId_OID = new ObjectIdentifier(pkcs9KeyId);
             PKCS9CertType_OID = new ObjectIdentifier(pkcs9certType);
@@ -166,38 +206,67 @@
                         new ObjectIdentifier(pbeWithSHAAnd40BitRC2CBC);
             pbeWithSHAAnd3KeyTripleDESCBC_OID =
                         new ObjectIdentifier(pbeWithSHAAnd3KeyTripleDESCBC);
+            TrustedKeyUsage_OID = new ObjectIdentifier(TrustedKeyUsage);
+            AnyUsage = new ObjectIdentifier[]{
+                new ObjectIdentifier(AnyExtendedKeyUsage)};
         } catch (IOException ioe) {
             // should not happen
         }
     }
 
-    // Private keys and their supporting certificate chains
-    private static class KeyEntry {
+    // A keystore entry and associated attributes
+    private static class Entry {
         Date date; // the creation date of this entry
+        String alias;
+        byte[] keyId;
+        Set<PKCS12Attribute> attributes;
+    }
+
+    // A key entry
+    private static class KeyEntry extends Entry {
+    }
+
+    // A private key entry and its supporting certificate chain
+    private static class PrivateKeyEntry extends KeyEntry {
         byte[] protectedPrivKey;
         Certificate chain[];
-        byte[] keyId;
-        String alias;
     };
 
-    // A certificate with its PKCS #9 attributes
-    private static class CertEntry {
+    // A secret key
+    private static class SecretKeyEntry extends KeyEntry {
+        byte[] protectedSecretKey;
+    };
+
+    // A certificate entry
+    private static class CertEntry extends Entry {
         final X509Certificate cert;
-        final byte[] keyId;
-        final String alias;
+        ObjectIdentifier[] trustedKeyUsage;
+
         CertEntry(X509Certificate cert, byte[] keyId, String alias) {
+            this(cert, keyId, alias, null, null);
+        }
+
+        CertEntry(X509Certificate cert, byte[] keyId, String alias,
+                ObjectIdentifier[] trustedKeyUsage,
+                Set<? extends PKCS12Attribute> attributes) {
+            this.date = new Date();
             this.cert = cert;
             this.keyId = keyId;
             this.alias = alias;
+            this.trustedKeyUsage = trustedKeyUsage;
+            this.attributes = new HashSet<>();
+            if (attributes != null) {
+                this.attributes.addAll(attributes);
+            }
         }
     }
 
     /**
-     * Private keys and certificates are stored in a hashtable.
-     * Hash entries are keyed by alias names.
+     * Private keys and certificates are stored in a map.
+     * Map entries are keyed by alias names.
      */
-    private Hashtable<String, KeyEntry> entries =
-                                new Hashtable<String, KeyEntry>();
+    private Map<String, Entry> entries =
+        Collections.synchronizedMap(new LinkedHashMap<String, Entry>());
 
     private ArrayList<KeyEntry> keyList = new ArrayList<KeyEntry>();
     private LinkedHashMap<X500Principal, X509Certificate> certsMap =
@@ -222,19 +291,27 @@
     public Key engineGetKey(String alias, char[] password)
         throws NoSuchAlgorithmException, UnrecoverableKeyException
     {
-        KeyEntry entry = entries.get(alias.toLowerCase(Locale.ENGLISH));
+        Entry entry = entries.get(alias.toLowerCase(Locale.ENGLISH));
         Key key = null;
 
-        if (entry == null) {
+        if (entry == null || (!(entry instanceof KeyEntry))) {
             return null;
         }
 
-        // get the encoded private key
-        byte[] encrBytes = entry.protectedPrivKey;
+        // get the encoded private key or secret key
+        byte[] encrBytes = null;
+        if (entry instanceof PrivateKeyEntry) {
+            encrBytes = ((PrivateKeyEntry) entry).protectedPrivKey;
+        } else if (entry instanceof SecretKeyEntry) {
+            encrBytes = ((SecretKeyEntry) entry).protectedSecretKey;
+        } else {
+            throw new UnrecoverableKeyException("Error locating key");
+        }
 
         byte[] encryptedKey;
         AlgorithmParameters algParams;
         ObjectIdentifier algOid;
+
         try {
             // get the encrypted private key
             EncryptedPrivateKeyInfo encrInfo =
@@ -255,15 +332,32 @@
             throw uke;
         }
 
-        try {
-            byte[] privateKeyInfo;
+       try {
+            PBEParameterSpec pbeSpec;
+            int ic = 0;
+
+            if (algParams != null) {
+                try {
+                    pbeSpec =
+                        algParams.getParameterSpec(PBEParameterSpec.class);
+                } catch (InvalidParameterSpecException ipse) {
+                    throw new IOException("Invalid PBE algorithm parameters");
+                }
+                ic = pbeSpec.getIterationCount();
+
+                if (ic > MAX_ITERATION_COUNT) {
+                    throw new IOException("PBE iteration count too large");
+                }
+            }
+
+            byte[] keyInfo;
             while (true) {
                 try {
                     // Use JCE
                     SecretKey skey = getPBEKey(password);
                     Cipher cipher = Cipher.getInstance(algOid.toString());
                     cipher.init(Cipher.DECRYPT_MODE, skey, algParams);
-                    privateKeyInfo = cipher.doFinal(encryptedKey);
+                    keyInfo = cipher.doFinal(encryptedKey);
                     break;
                 } catch (Exception e) {
                     if (password.length == 0) {
@@ -276,21 +370,54 @@
                 }
             }
 
-            PKCS8EncodedKeySpec kspec = new PKCS8EncodedKeySpec(privateKeyInfo);
-
             /*
              * Parse the key algorithm and then use a JCA key factory
-             * to create the private key.
+             * to re-create the key.
              */
-            DerValue val = new DerValue(privateKeyInfo);
+            DerValue val = new DerValue(keyInfo);
             DerInputStream in = val.toDerInputStream();
             int i = in.getInteger();
             DerValue[] value = in.getSequence(2);
             AlgorithmId algId = new AlgorithmId(value[0].getOID());
-            String algName = algId.getName();
+            String keyAlgo = algId.getName();
 
-            KeyFactory kfac = KeyFactory.getInstance(algName);
-            key =  kfac.generatePrivate(kspec);
+            // decode private key
+            if (entry instanceof PrivateKeyEntry) {
+                KeyFactory kfac = KeyFactory.getInstance(keyAlgo);
+                PKCS8EncodedKeySpec kspec = new PKCS8EncodedKeySpec(keyInfo);
+                key = kfac.generatePrivate(kspec);
+
+                if (debug != null) {
+                    debug.println("Retrieved a protected private key at alias" +
+                        " '" + alias + "' (" +
+                        new AlgorithmId(algOid).getName() +
+                        " iterations: " + ic + ")");
+                }
+
+            // decode secret key
+            } else {
+                byte[] keyBytes = in.getOctetString();
+                SecretKeySpec secretKeySpec =
+                    new SecretKeySpec(keyBytes, keyAlgo);
+
+                // Special handling required for PBE: needs a PBEKeySpec
+                if (keyAlgo.startsWith("PBE")) {
+                    SecretKeyFactory sKeyFactory =
+                        SecretKeyFactory.getInstance(keyAlgo);
+                    KeySpec pbeKeySpec =
+                        sKeyFactory.getKeySpec(secretKeySpec, PBEKeySpec.class);
+                    key = sKeyFactory.generateSecret(pbeKeySpec);
+                } else {
+                    key = secretKeySpec;
+                }
+
+                if (debug != null) {
+                    debug.println("Retrieved a protected secret key at alias " +
+                        "'" + alias + "' (" +
+                        new AlgorithmId(algOid).getName() +
+                        " iterations: " + ic + ")");
+                }
+            }
         } catch (Exception e) {
             UnrecoverableKeyException uke =
                 new UnrecoverableKeyException("Get Key failed: " +
@@ -313,12 +440,19 @@
      * <i>key entry</i> without a certificate chain).
      */
     public Certificate[] engineGetCertificateChain(String alias) {
-        KeyEntry entry = entries.get(alias.toLowerCase(Locale.ENGLISH));
-        if (entry != null) {
-            if (entry.chain == null) {
+        Entry entry = entries.get(alias.toLowerCase(Locale.ENGLISH));
+        if (entry != null && entry instanceof PrivateKeyEntry) {
+            if (((PrivateKeyEntry) entry).chain == null) {
                 return null;
             } else {
-                return entry.chain.clone();
+
+                 if (debug != null) {
+                     debug.println("Retrieved a " +
+                        ((PrivateKeyEntry) entry).chain.length +
+                         "-certificate chain at alias '" + alias + "'");
+                 }
+
+                return ((PrivateKeyEntry) entry).chain.clone();
             }
         } else {
             return null;
@@ -341,13 +475,39 @@
      * does not contain a certificate.
      */
     public Certificate engineGetCertificate(String alias) {
-        KeyEntry entry = entries.get(alias.toLowerCase(Locale.ENGLISH));
-        if (entry != null) {
-            if (entry.chain == null) {
+        Entry entry = entries.get(alias.toLowerCase(Locale.ENGLISH));
+        if (entry == null) {
+            return null;
+        }
+        if (entry instanceof CertEntry &&
+            ((CertEntry) entry).trustedKeyUsage != null) {
+
+            if (debug != null) {
+                if (Arrays.equals(AnyUsage,
+                    ((CertEntry) entry).trustedKeyUsage)) {
+                    debug.println("Retrieved a certificate at alias '" + alias +
+                        "' (trusted for any purpose)");
+                } else {
+                    debug.println("Retrieved a certificate at alias '" + alias +
+                        "' (trusted for limited purposes)");
+                }
+            }
+
+            return ((CertEntry) entry).cert;
+
+        } else if (entry instanceof PrivateKeyEntry) {
+            if (((PrivateKeyEntry) entry).chain == null) {
                 return null;
             } else {
-                return entry.chain[0];
+
+                if (debug != null) {
+                    debug.println("Retrieved a certificate at alias '" + alias +
+                        "'");
+                }
+
+                return ((PrivateKeyEntry) entry).chain[0];
             }
+
         } else {
             return null;
         }
@@ -362,7 +522,7 @@
      * not exist
      */
     public Date engineGetCreationDate(String alias) {
-        KeyEntry entry = entries.get(alias.toLowerCase(Locale.ENGLISH));
+        Entry entry = entries.get(alias.toLowerCase(Locale.ENGLISH));
         if (entry != null) {
             return new Date(entry.date.getTime());
         } else {
@@ -396,40 +556,97 @@
                         char[] password, Certificate[] chain)
         throws KeyStoreException
     {
+        setKeyEntry(alias, key, password, chain, null);
+    }
+
+    /*
+     * Sets a key entry (with attributes, when present)
+     */
+    private void setKeyEntry(String alias, Key key,
+        char[] password, Certificate[] chain,
+        Set<PKCS12Attribute> attributes)
+            throws KeyStoreException
+    {
         try {
-            KeyEntry entry = new KeyEntry();
-            entry.date = new Date();
+            Entry entry;
 
             if (key instanceof PrivateKey) {
+                PrivateKeyEntry keyEntry = new PrivateKeyEntry();
+                keyEntry.date = new Date();
+
                 if ((key.getFormat().equals("PKCS#8")) ||
                     (key.getFormat().equals("PKCS8"))) {
+
+                    if (debug != null) {
+                        debug.println(
+                            "Setting a protected private key at alias '" +
+                            alias + "'");
+                    }
+
                     // Encrypt the private key
-                    entry.protectedPrivKey =
+                    keyEntry.protectedPrivKey =
                         encryptPrivateKey(key.getEncoded(), password);
                 } else {
                     throw new KeyStoreException("Private key is not encoded" +
                                 "as PKCS#8");
                 }
+
+                // clone the chain
+                if (chain != null) {
+                    // validate cert-chain
+                    if ((chain.length > 1) && (!validateChain(chain)))
+                       throw new KeyStoreException("Certificate chain is " +
+                                                "not valid");
+                    keyEntry.chain = chain.clone();
+                    certificateCount += chain.length;
+
+                    if (debug != null) {
+                        debug.println("Setting a " + chain.length +
+                            "-certificate chain at alias '" + alias + "'");
+                    }
+                }
+                privateKeyCount++;
+                entry = keyEntry;
+
+            } else if (key instanceof SecretKey) {
+                SecretKeyEntry keyEntry = new SecretKeyEntry();
+                keyEntry.date = new Date();
+
+                // Encode secret key in a PKCS#8
+                DerOutputStream pkcs8 = new DerOutputStream();
+                DerOutputStream secretKeyInfo = new DerOutputStream();
+                secretKeyInfo.putInteger(0);
+                AlgorithmId algId = AlgorithmId.get(key.getAlgorithm());
+                algId.encode(secretKeyInfo);
+                secretKeyInfo.putOctetString(key.getEncoded());
+                pkcs8.write(DerValue.tag_Sequence, secretKeyInfo);
+
+                // Encrypt the secret key (using same PBE as for private keys)
+                keyEntry.protectedSecretKey =
+                    encryptPrivateKey(pkcs8.toByteArray(), password);
+
+                if (debug != null) {
+                    debug.println("Setting a protected secret key at alias '" +
+                        alias + "'");
+                }
+                secretKeyCount++;
+                entry = keyEntry;
+
             } else {
-                throw new KeyStoreException("Key is not a PrivateKey");
+                throw new KeyStoreException("Unsupported Key type");
             }
 
-            // clone the chain
-            if (chain != null) {
-                // validate cert-chain
-                if ((chain.length > 1) && (!validateChain(chain)))
-                   throw new KeyStoreException("Certificate chain is " +
-                                                "not validate");
-                entry.chain = chain.clone();
+            entry.attributes = new HashSet<>();
+            if (attributes != null) {
+                entry.attributes.addAll(attributes);
             }
-
             // set the keyId to current date
             entry.keyId = ("Time " + (entry.date).getTime()).getBytes("UTF8");
             // set the alias
             entry.alias = alias.toLowerCase(Locale.ENGLISH);
-
             // add the entry
             entries.put(alias.toLowerCase(Locale.ENGLISH), entry);
+
         } catch (Exception nsae) {
             throw new KeyStoreException("Key protection " +
                        " algorithm not found: " + nsae, nsae);
@@ -463,7 +680,7 @@
                                   Certificate[] chain)
         throws KeyStoreException
     {
-        // key must be encoded as EncryptedPrivateKeyInfo
+        // Private key must be encoded as EncryptedPrivateKeyInfo
         // as defined in PKCS#8
         try {
             new EncryptedPrivateKeyInfo(key);
@@ -472,9 +689,14 @@
                     + " as PKCS#8 EncryptedPrivateKeyInfo: " + ioe, ioe);
         }
 
-        KeyEntry entry = new KeyEntry();
+        PrivateKeyEntry entry = new PrivateKeyEntry();
         entry.date = new Date();
 
+        if (debug != null) {
+            debug.println("Setting a protected private key at alias '" +
+                alias + "'");
+        }
+
         try {
             // set the keyId to current date
             entry.keyId = ("Time " + (entry.date).getTime()).getBytes("UTF8");
@@ -491,10 +713,17 @@
                throw new KeyStoreException("Certificate chain is "
                        + "not valid");
            }
-           entry.chain = chain.clone();
+            entry.chain = chain.clone();
+            certificateCount += chain.length;
+
+            if (debug != null) {
+                debug.println("Setting a " + entry.chain.length +
+                    "-certificate chain at alias '" + alias + "'");
+            }
         }
 
         // add the entry
+        privateKeyCount++;
         entries.put(alias.toLowerCase(Locale.ENGLISH), entry);
     }
 
@@ -516,19 +745,19 @@
     /*
      * Generate PBE Algorithm Parameters
      */
-    private AlgorithmParameters getAlgorithmParameters(String algorithm)
+    private AlgorithmParameters getPBEAlgorithmParameters(String algorithm)
         throws IOException
     {
         AlgorithmParameters algParams = null;
 
         // create PBE parameters from salt and iteration count
         PBEParameterSpec paramSpec =
-                new PBEParameterSpec(getSalt(), iterationCount);
+                new PBEParameterSpec(getSalt(), PBE_ITERATION_COUNT);
         try {
            algParams = AlgorithmParameters.getInstance(algorithm);
            algParams.init(paramSpec);
         } catch (Exception e) {
-           throw new IOException("getAlgorithmParameters failed: " +
+           throw new IOException("getPBEAlgorithmParameters failed: " +
                                  e.getMessage(), e);
         }
         return algParams;
@@ -573,6 +802,7 @@
             PBEKeySpec keySpec = new PBEKeySpec(password);
             SecretKeyFactory skFac = SecretKeyFactory.getInstance("PBE");
             skey = skFac.generateSecret(keySpec);
+            keySpec.clearPassword();
         } catch (Exception e) {
            throw new IOException("getSecretKey failed: " +
                                  e.getMessage(), e);
@@ -597,7 +827,7 @@
         try {
             // create AlgorithmParameters
             AlgorithmParameters algParams =
-                getAlgorithmParameters("PBEWithSHA1AndDESede");
+                getPBEAlgorithmParameters("PBEWithSHA1AndDESede");
 
             // Use JCE
             SecretKey skey = getPBEKey(password);
@@ -605,6 +835,11 @@
             cipher.init(Cipher.ENCRYPT_MODE, skey, algParams);
             byte[] encryptedKey = cipher.doFinal(data);
 
+            if (debug != null) {
+                debug.println("  (Cipher algorithm: " + cipher.getAlgorithm() +
+                    ")");
+            }
+
             // wrap encrypted private key in EncryptedPrivateKeyInfo
             // as defined in PKCS#8
             AlgorithmId algid =
@@ -634,17 +869,36 @@
      * @param cert the certificate
      *
      * @exception KeyStoreException if the given alias already exists and does
-     * identify a <i>key entry</i>, or on an attempt to create a
-     * <i>trusted cert entry</i> which is currently not supported.
+     * not identify a <i>trusted certificate entry</i>, or this operation fails
+     * for some other reason.
      */
     public synchronized void engineSetCertificateEntry(String alias,
         Certificate cert) throws KeyStoreException
     {
-        KeyEntry entry = entries.get(alias.toLowerCase(Locale.ENGLISH));
-        if (entry != null) {
+        setCertEntry(alias, cert, null);
+    }
+
+    /*
+     * Sets a trusted cert entry (with attributes, when present)
+     */
+    private void setCertEntry(String alias, Certificate cert,
+        Set<PKCS12Attribute> attributes) throws KeyStoreException {
+
+        Entry entry = entries.get(alias.toLowerCase(Locale.ENGLISH));
+        if (entry != null && entry instanceof KeyEntry) {
             throw new KeyStoreException("Cannot overwrite own certificate");
-        } else
-            throw new KeyStoreException("TrustedCertEntry not supported");
+        }
+
+        CertEntry certEntry =
+            new CertEntry((X509Certificate) cert, null, alias, AnyUsage,
+                attributes);
+        certificateCount++;
+        entries.put(alias, certEntry);
+
+        if (debug != null) {
+            debug.println("Setting a trusted certificate at alias '" + alias +
+                "'");
+        }
     }
 
     /**
@@ -657,6 +911,22 @@
     public synchronized void engineDeleteEntry(String alias)
         throws KeyStoreException
     {
+        if (debug != null) {
+            debug.println("Removing entry at alias '" + alias + "'");
+        }
+
+        Entry entry = entries.get(alias.toLowerCase(Locale.ENGLISH));
+        if (entry instanceof PrivateKeyEntry) {
+            PrivateKeyEntry keyEntry = (PrivateKeyEntry) entry;
+            if (keyEntry.chain != null) {
+                certificateCount -= keyEntry.chain.length;
+            }
+            privateKeyCount--;
+        } else if (entry instanceof CertEntry) {
+            certificateCount--;
+        } else if (entry instanceof SecretKeyEntry) {
+            secretKeyCount--;
+        }
         entries.remove(alias.toLowerCase(Locale.ENGLISH));
     }
 
@@ -666,7 +936,7 @@
      * @return enumeration of the alias names
      */
     public Enumeration<String> engineAliases() {
-        return entries.keys();
+        return Collections.enumeration(entries.keySet());
     }
 
     /**
@@ -697,8 +967,8 @@
      * <i>key entry</i>, false otherwise.
      */
     public boolean engineIsKeyEntry(String alias) {
-        KeyEntry entry = entries.get(alias.toLowerCase(Locale.ENGLISH));
-        if (entry != null) {
+        Entry entry = entries.get(alias.toLowerCase(Locale.ENGLISH));
+        if (entry != null && entry instanceof KeyEntry) {
             return true;
         } else {
             return false;
@@ -713,7 +983,45 @@
      * <i>trusted certificate entry</i>, false otherwise.
      */
     public boolean engineIsCertificateEntry(String alias) {
-        // TrustedCertEntry is not supported
+        Entry entry = entries.get(alias.toLowerCase(Locale.ENGLISH));
+        if (entry != null && entry instanceof CertEntry &&
+            ((CertEntry) entry).trustedKeyUsage != null) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Determines if the keystore {@code Entry} for the specified
+     * {@code alias} is an instance or subclass of the specified
+     * {@code entryClass}.
+     *
+     * @param alias the alias name
+     * @param entryClass the entry class
+     *
+     * @return true if the keystore {@code Entry} for the specified
+     *          {@code alias} is an instance or subclass of the
+     *          specified {@code entryClass}, false otherwise
+     *
+     * @since 1.5
+     */
+    @Override
+    public boolean
+        engineEntryInstanceOf(String alias,
+                              Class<? extends KeyStore.Entry> entryClass)
+    {
+        if (entryClass == KeyStore.TrustedCertificateEntry.class) {
+            return engineIsCertificateEntry(alias);
+        }
+
+        Entry entry = entries.get(alias.toLowerCase(Locale.ENGLISH));
+        if (entryClass == KeyStore.PrivateKeyEntry.class) {
+            return (entry != null && entry instanceof PrivateKeyEntry);
+        }
+        if (entryClass == KeyStore.SecretKeyEntry.class) {
+            return (entry != null && entry instanceof SecretKeyEntry);
+        }
         return false;
     }
 
@@ -736,13 +1044,20 @@
     public String engineGetCertificateAlias(Certificate cert) {
         Certificate certElem = null;
 
-        for (Enumeration<String> e = entries.keys(); e.hasMoreElements(); ) {
+        for (Enumeration<String> e = engineAliases(); e.hasMoreElements(); ) {
             String alias = e.nextElement();
-            KeyEntry entry = entries.get(alias);
-            if (entry.chain != null) {
-                certElem = entry.chain[0];
+            Entry entry = entries.get(alias);
+            if (entry instanceof PrivateKeyEntry) {
+                if (((PrivateKeyEntry) entry).chain != null) {
+                    certElem = ((PrivateKeyEntry) entry).chain[0];
+                }
+            } else if (entry instanceof CertEntry &&
+                    ((CertEntry) entry).trustedKeyUsage != null) {
+                certElem = ((CertEntry) entry).cert;
+            } else {
+                continue;
             }
-            if (certElem.equals(cert)) {
+            if (certElem != null && certElem.equals(cert)) {
                 return alias;
             }
         }
@@ -786,16 +1101,32 @@
         DerOutputStream authSafeContentInfo = new DerOutputStream();
 
         // -- create safeContent Data ContentInfo
-        byte[] safeContentData = createSafeContent();
-        ContentInfo dataContentInfo = new ContentInfo(safeContentData);
-        dataContentInfo.encode(authSafeContentInfo);
+        if (privateKeyCount > 0 || secretKeyCount > 0) {
+
+            if (debug != null) {
+                debug.println("Storing " + (privateKeyCount + secretKeyCount) +
+                    " protected key(s) in a PKCS#7 data");
+            }
+
+            byte[] safeContentData = createSafeContent();
+            ContentInfo dataContentInfo = new ContentInfo(safeContentData);
+            dataContentInfo.encode(authSafeContentInfo);
+        }
 
         // -- create EncryptedContentInfo
-        byte[] encrData = createEncryptedData(password);
-        ContentInfo encrContentInfo =
+        if (certificateCount > 0) {
+
+            if (debug != null) {
+                debug.println("Storing " + certificateCount +
+                    " certificate(s) in a PKCS#7 encryptedData");
+            }
+
+            byte[] encrData = createEncryptedData(password);
+            ContentInfo encrContentInfo =
                 new ContentInfo(ContentInfo.ENCRYPTED_DATA_OID,
                                 new DerValue(encrData));
-        encrContentInfo.encode(authSafeContentInfo);
+            encrContentInfo.encode(authSafeContentInfo);
+        }
 
         // wrap as SequenceOf ContentInfos
         DerOutputStream cInfo = new DerOutputStream();
@@ -821,6 +1152,211 @@
     }
 
 
+    /**
+     * Gets a <code>KeyStore.Entry</code> for the specified alias
+     * with the specified protection parameter.
+     *
+     * @param alias get the <code>KeyStore.Entry</code> for this alias
+     * @param protParam the <code>ProtectionParameter</code>
+     *          used to protect the <code>Entry</code>,
+     *          which may be <code>null</code>
+     *
+     * @return the <code>KeyStore.Entry</code> for the specified alias,
+     *          or <code>null</code> if there is no such entry
+     *
+     * @exception KeyStoreException if the operation failed
+     * @exception NoSuchAlgorithmException if the algorithm for recovering the
+     *          entry cannot be found
+     * @exception UnrecoverableEntryException if the specified
+     *          <code>protParam</code> were insufficient or invalid
+     * @exception UnrecoverableKeyException if the entry is a
+     *          <code>PrivateKeyEntry</code> or <code>SecretKeyEntry</code>
+     *          and the specified <code>protParam</code> does not contain
+     *          the information needed to recover the key (e.g. wrong password)
+     *
+     * @since 1.5
+     */
+    @Override
+    public KeyStore.Entry engineGetEntry(String alias,
+                        KeyStore.ProtectionParameter protParam)
+                throws KeyStoreException, NoSuchAlgorithmException,
+                UnrecoverableEntryException {
+
+        if (!engineContainsAlias(alias)) {
+            return null;
+        }
+
+        Entry entry = entries.get(alias.toLowerCase(Locale.ENGLISH));
+        JavaSecurityKeyStoreAccess jsksa = SharedSecrets.getJavaSecurityKeyStoreAccess();
+        if (protParam == null) {
+            if (engineIsCertificateEntry(alias)) {
+                if (entry instanceof CertEntry &&
+                    ((CertEntry) entry).trustedKeyUsage != null) {
+
+                    if (debug != null) {
+                        debug.println("Retrieved a trusted certificate at " +
+                            "alias '" + alias + "'");
+                    }
+
+                    return jsksa.constructTrustedCertificateEntry(
+                        ((CertEntry)entry).cert, getAttributes(entry));
+                }
+            } else {
+                throw new UnrecoverableKeyException
+                        ("requested entry requires a password");
+            }
+        }
+
+        if (protParam instanceof KeyStore.PasswordProtection) {
+            if (engineIsCertificateEntry(alias)) {
+                throw new UnsupportedOperationException
+                    ("trusted certificate entries are not password-protected");
+            } else if (engineIsKeyEntry(alias)) {
+                KeyStore.PasswordProtection pp =
+                        (KeyStore.PasswordProtection)protParam;
+                char[] password = pp.getPassword();
+
+                Key key = engineGetKey(alias, password);
+                if (key instanceof PrivateKey) {
+                    Certificate[] chain = engineGetCertificateChain(alias);
+
+                    return jsksa.constructPrivateKeyEntry((PrivateKey)key, chain,
+                        getAttributes(entry));
+
+                } else if (key instanceof SecretKey) {
+
+                    return jsksa.constructSecretKeyEntry((SecretKey)key,
+                        getAttributes(entry));
+                }
+            } else if (!engineIsKeyEntry(alias)) {
+                throw new UnsupportedOperationException
+                    ("untrusted certificate entries are not " +
+                        "password-protected");
+            }
+        }
+
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Saves a <code>KeyStore.Entry</code> under the specified alias.
+     * The specified protection parameter is used to protect the
+     * <code>Entry</code>.
+     *
+     * <p> If an entry already exists for the specified alias,
+     * it is overridden.
+     *
+     * @param alias save the <code>KeyStore.Entry</code> under this alias
+     * @param entry the <code>Entry</code> to save
+     * @param protParam the <code>ProtectionParameter</code>
+     *          used to protect the <code>Entry</code>,
+     *          which may be <code>null</code>
+     *
+     * @exception KeyStoreException if this operation fails
+     *
+     * @since 1.5
+     */
+    @Override
+    public synchronized void engineSetEntry(String alias, KeyStore.Entry entry,
+        KeyStore.ProtectionParameter protParam) throws KeyStoreException {
+
+        // get password
+        if (protParam != null &&
+            !(protParam instanceof KeyStore.PasswordProtection)) {
+            throw new KeyStoreException("unsupported protection parameter");
+        }
+        KeyStore.PasswordProtection pProtect = null;
+        if (protParam != null) {
+            pProtect = (KeyStore.PasswordProtection)protParam;
+        }
+
+        // set entry
+        JavaSecurityKeyStoreAccess jsksa = SharedSecrets.getJavaSecurityKeyStoreAccess();
+        if (entry instanceof KeyStore.TrustedCertificateEntry) {
+            if (protParam != null && pProtect.getPassword() != null) {
+                // pre-1.5 style setCertificateEntry did not allow password
+                throw new KeyStoreException
+                    ("trusted certificate entries are not password-protected");
+            } else {
+                KeyStore.TrustedCertificateEntry tce =
+                        (KeyStore.TrustedCertificateEntry)entry;
+                setCertEntry(alias, tce.getTrustedCertificate(),
+                    jsksa.getTrustedCertificateEntryAttributes(tce));
+
+                return;
+            }
+        } else if (entry instanceof KeyStore.PrivateKeyEntry) {
+            if (pProtect == null || pProtect.getPassword() == null) {
+                // pre-1.5 style setKeyEntry required password
+                throw new KeyStoreException
+                    ("non-null password required to create PrivateKeyEntry");
+            } else {
+                KeyStore.PrivateKeyEntry pke = (KeyStore.PrivateKeyEntry)entry;
+                setKeyEntry(alias, pke.getPrivateKey(), pProtect.getPassword(),
+                    pke.getCertificateChain(),
+                    jsksa.getPrivateKeyEntryAttributes(pke));
+
+                return;
+            }
+        } else if (entry instanceof KeyStore.SecretKeyEntry) {
+            if (pProtect == null || pProtect.getPassword() == null) {
+                // pre-1.5 style setKeyEntry required password
+                throw new KeyStoreException
+                    ("non-null password required to create SecretKeyEntry");
+            } else {
+                KeyStore.SecretKeyEntry ske = (KeyStore.SecretKeyEntry)entry;
+                setKeyEntry(alias, ske.getSecretKey(), pProtect.getPassword(),
+                    (Certificate[])null,
+                    jsksa.getSecretKeyEntryAttributes(ske));
+
+                return;
+            }
+        }
+
+        throw new KeyStoreException
+                ("unsupported entry type: " + entry.getClass().getName());
+    }
+
+    /*
+     * Assemble the entry attributes
+     */
+    private Set<PKCS12Attribute> getAttributes(Entry entry) {
+
+        if (entry.attributes == null) {
+            entry.attributes = new HashSet<>();
+        }
+
+        // friendlyName
+        entry.attributes.add(new PKCS12Attribute(
+            PKCS9FriendlyName_OID.toString(), entry.alias));
+
+        // localKeyID
+        byte[] keyIdValue = entry.keyId;
+        if (keyIdValue != null) {
+            entry.attributes.add(new PKCS12Attribute(
+                PKCS9LocalKeyId_OID.toString(), Debug.toString(keyIdValue)));
+        }
+
+        // trustedKeyUsage
+        if (entry instanceof CertEntry) {
+            ObjectIdentifier[] trustedKeyUsageValue =
+                ((CertEntry) entry).trustedKeyUsage;
+            if (trustedKeyUsageValue != null) {
+                if (trustedKeyUsageValue.length == 1) { // omit brackets
+                    entry.attributes.add(new PKCS12Attribute(
+                        TrustedKeyUsage_OID.toString(),
+                        trustedKeyUsageValue[0].toString()));
+                } else { // multi-valued
+                    entry.attributes.add(new PKCS12Attribute(
+                        TrustedKeyUsage_OID.toString(),
+                        Arrays.toString(trustedKeyUsageValue)));
+                }
+            }
+        }
+
+        return entry.attributes;
+    }
+
     /*
      * Generate Hash.
      */
@@ -858,7 +1394,7 @@
             // generate MAC (MAC key is generated within JCE)
             Mac m = Mac.getInstance("HmacPBESHA1");
             PBEParameterSpec params =
-                        new PBEParameterSpec(salt, iterationCount);
+                        new PBEParameterSpec(salt, MAC_ITERATION_COUNT);
             SecretKey key = getPBEKey(passwd);
             m.init(key, params);
             m.update(data);
@@ -866,7 +1402,7 @@
 
             // encode as MacData
             MacData macData = new MacData(algName, macResult, salt,
-                                                iterationCount);
+                                                MAC_ITERATION_COUNT);
             DerOutputStream bytes = new DerOutputStream();
             bytes.write(macData.getEncoded());
             mData = bytes.toByteArray();
@@ -900,11 +1436,12 @@
 
 
     /*
-     * Create PKCS#12 Attributes, friendlyName and localKeyId.
+     * Create PKCS#12 Attributes, friendlyName, localKeyId and trustedKeyUsage.
      *
      * Although attributes are optional, they could be required.
      * For e.g. localKeyId attribute is required to match the
      * private key with the associated end-entity certificate.
+     * The trustedKeyUsage attribute is used to denote a trusted certificate.
      *
      * PKCS8ShroudedKeyBags include unique localKeyID and friendlyName.
      * CertBags may or may not include attributes depending on the type
@@ -926,20 +1463,28 @@
      * friendlyName            unique        same/    same/     unique
      *                                       unique   unique/
      *                                                null
+     * trustedKeyUsage         -             -        -         true
      *
      * Note: OpenSSL adds friendlyName for end-entity cert only, and
      * removes the localKeyID and friendlyName for CA certs.
      * If the CertBag did not have a friendlyName, most vendors will
      * add it, and assign it to the DN of the cert.
      */
-    private byte[] getBagAttributes(String alias, byte[] keyId)
-        throws IOException {
+    private byte[] getBagAttributes(String alias, byte[] keyId,
+        Set<PKCS12Attribute> attributes) throws IOException {
+        return getBagAttributes(alias, keyId, null, attributes);
+    }
+
+    private byte[] getBagAttributes(String alias, byte[] keyId,
+        ObjectIdentifier[] trustedUsage,
+        Set<PKCS12Attribute> attributes) throws IOException {
 
         byte[] localKeyID = null;
         byte[] friendlyName = null;
+        byte[] trustedKeyUsage = null;
 
-        // return null if both attributes are null
-        if ((alias == null) && (keyId == null)) {
+        // return null if all three attributes are null
+        if ((alias == null) && (keyId == null) && (trustedKeyUsage == null)) {
             return null;
         }
 
@@ -970,6 +1515,20 @@
             localKeyID = bagAttrValue2.toByteArray();
         }
 
+        // Encode the trustedKeyUsage oid.
+        if (trustedUsage != null) {
+            DerOutputStream bagAttr3 = new DerOutputStream();
+            bagAttr3.putOID(TrustedKeyUsage_OID);
+            DerOutputStream bagAttrContent3 = new DerOutputStream();
+            DerOutputStream bagAttrValue3 = new DerOutputStream();
+            for (ObjectIdentifier usage : trustedUsage) {
+                bagAttrContent3.putOID(usage);
+            }
+            bagAttr3.write(DerValue.tag_Set, bagAttrContent3);
+            bagAttrValue3.write(DerValue.tag_Sequence, bagAttr3);
+            trustedKeyUsage = bagAttrValue3.toByteArray();
+        }
+
         DerOutputStream attrs = new DerOutputStream();
         if (friendlyName != null) {
             attrs.write(friendlyName);
@@ -977,11 +1536,27 @@
         if (localKeyID != null) {
             attrs.write(localKeyID);
         }
+        if (trustedKeyUsage != null) {
+            attrs.write(trustedKeyUsage);
+        }
+
+        if (attributes != null) {
+            for (PKCS12Attribute attribute : attributes) {
+                String attributeName = attribute.getName();
+                // skip friendlyName, localKeyId and trustedKeyUsage
+                if (CORE_ATTRIBUTES[0].equals(attributeName) ||
+                    CORE_ATTRIBUTES[1].equals(attributeName) ||
+                    CORE_ATTRIBUTES[2].equals(attributeName)) {
+                    continue;
+                }
+                attrs.write(attribute.getEncoded());
+            }
+        }
+
         bagAttrs.write(DerValue.tag_Set, attrs);
         return bagAttrs.toByteArray();
     }
 
-
     /*
      * Create EncryptedData content type, that contains EncryptedContentInfo.
      * Includes certificates in individual SafeBags of type CertBag.
@@ -992,20 +1567,28 @@
         throws CertificateException, IOException
     {
         DerOutputStream out = new DerOutputStream();
-        for (Enumeration<String> e = entries.keys(); e.hasMoreElements(); ) {
+        for (Enumeration<String> e = engineAliases(); e.hasMoreElements(); ) {
 
             String alias = e.nextElement();
-            KeyEntry entry = entries.get(alias);
+            Entry entry = entries.get(alias);
 
             // certificate chain
-            int chainLen;
-            if (entry.chain == null) {
-                chainLen = 0;
+            Certificate[] certs;
+
+            if (entry instanceof PrivateKeyEntry) {
+                PrivateKeyEntry keyEntry = (PrivateKeyEntry) entry;
+                if (keyEntry.chain != null) {
+                    certs = keyEntry.chain;
+                } else {
+                    certs = new Certificate[0];
+                }
+            } else if (entry instanceof CertEntry) {
+                certs = new Certificate[]{((CertEntry) entry).cert};
             } else {
-                chainLen = entry.chain.length;
+                certs = new Certificate[0];
             }
 
-            for (int i = 0; i < chainLen; i++) {
+            for (int i = 0; i < certs.length; i++) {
                 // create SafeBag of Type CertBag
                 DerOutputStream safeBag = new DerOutputStream();
                 safeBag.putOID(CertBag_OID);
@@ -1016,7 +1599,7 @@
 
                 // write encoded certs in a context-specific tag
                 DerOutputStream certValue = new DerOutputStream();
-                X509Certificate cert = (X509Certificate)entry.chain[i];
+                X509Certificate cert = (X509Certificate) certs[i];
                 certValue.putOctetString(cert.getEncoded());
                 certBag.write(DerValue.createTag(DerValue.TAG_CONTEXT,
                                         true, (byte) 0), certValue);
@@ -1039,7 +1622,18 @@
                 byte[] bagAttrs = null;
                 if (i == 0) {
                     // Only End-Entity Cert should have a localKeyId.
-                    bagAttrs = getBagAttributes(entry.alias, entry.keyId);
+                    if (entry instanceof KeyEntry) {
+                        KeyEntry keyEntry = (KeyEntry) entry;
+                        bagAttrs =
+                            getBagAttributes(keyEntry.alias, keyEntry.keyId,
+                                keyEntry.attributes);
+                    } else {
+                        CertEntry certEntry = (CertEntry) entry;
+                        bagAttrs =
+                            getBagAttributes(certEntry.alias, certEntry.keyId,
+                                certEntry.trustedKeyUsage,
+                                certEntry.attributes);
+                    }
                 } else {
                     // Trusted root CA certs and Intermediate CA certs do not
                     // need to have a localKeyId, and hence localKeyId is null
@@ -1048,7 +1642,8 @@
                     // certificate chain to have unique or null localKeyID.
                     // However, IE/OpenSSL do not impose this restriction.
                     bagAttrs = getBagAttributes(
-                            cert.getSubjectX500Principal().getName(), null);
+                            cert.getSubjectX500Principal().getName(), null,
+                            entry.attributes);
                 }
                 if (bagAttrs != null) {
                     safeBag.write(bagAttrs);
@@ -1078,6 +1673,7 @@
 
     /*
      * Create SafeContent Data content type.
+     * Includes encrypted secret key in a SafeBag of type SecretBag.
      * Includes encrypted private key in a SafeBag of type PKCS8ShroudedKeyBag.
      * Each PKCS8ShroudedKeyBag includes pkcs12 attributes
      * (see comments in getBagAttributes)
@@ -1086,33 +1682,74 @@
         throws CertificateException, IOException {
 
         DerOutputStream out = new DerOutputStream();
-        for (Enumeration<String> e = entries.keys(); e.hasMoreElements(); ) {
+        for (Enumeration<String> e = engineAliases(); e.hasMoreElements(); ) {
 
             String alias = e.nextElement();
-            KeyEntry entry = entries.get(alias);
+            Entry entry = entries.get(alias);
+            if (entry == null || (!(entry instanceof KeyEntry))) {
+                continue;
+            }
+            DerOutputStream safeBag = new DerOutputStream();
+            KeyEntry keyEntry = (KeyEntry) entry;
 
-            // Create SafeBag of type pkcs8ShroudedKeyBag
-            DerOutputStream safeBag = new DerOutputStream();
-            safeBag.putOID(PKCS8ShroudedKeyBag_OID);
+            // DER encode the private key
+            if (keyEntry instanceof PrivateKeyEntry) {
+                // Create SafeBag of type pkcs8ShroudedKeyBag
+                safeBag.putOID(PKCS8ShroudedKeyBag_OID);
 
-            // get the encrypted private key
-            byte[] encrBytes = entry.protectedPrivKey;
-            EncryptedPrivateKeyInfo encrInfo = null;
-            try {
-                encrInfo = new EncryptedPrivateKeyInfo(encrBytes);
-            } catch (IOException ioe) {
-                throw new IOException("Private key not stored as "
-                        + "PKCS#8 EncryptedPrivateKeyInfo" + ioe.getMessage());
+                // get the encrypted private key
+                byte[] encrBytes = ((PrivateKeyEntry)keyEntry).protectedPrivKey;
+                EncryptedPrivateKeyInfo encrInfo = null;
+                try {
+                    encrInfo = new EncryptedPrivateKeyInfo(encrBytes);
+
+                } catch (IOException ioe) {
+                    throw new IOException("Private key not stored as "
+                            + "PKCS#8 EncryptedPrivateKeyInfo"
+                            + ioe.getMessage());
+                }
+
+                // Wrap the EncryptedPrivateKeyInfo in a context-specific tag.
+                DerOutputStream bagValue = new DerOutputStream();
+                bagValue.write(encrInfo.getEncoded());
+                safeBag.write(DerValue.createTag(DerValue.TAG_CONTEXT,
+                                true, (byte) 0), bagValue);
+
+            // DER encode the secret key
+            } else if (keyEntry instanceof SecretKeyEntry) {
+                // Create SafeBag of type SecretBag
+                safeBag.putOID(SecretBag_OID);
+
+                // Create a SecretBag
+                DerOutputStream secretBag = new DerOutputStream();
+                secretBag.putOID(PKCS8ShroudedKeyBag_OID);
+
+                // Write secret key in a context-specific tag
+                DerOutputStream secretKeyValue = new DerOutputStream();
+                secretKeyValue.putOctetString(
+                    ((SecretKeyEntry) keyEntry).protectedSecretKey);
+                secretBag.write(DerValue.createTag(DerValue.TAG_CONTEXT,
+                                        true, (byte) 0), secretKeyValue);
+
+                // Wrap SecretBag in a Sequence
+                DerOutputStream secretBagSeq = new DerOutputStream();
+                secretBagSeq.write(DerValue.tag_Sequence, secretBag);
+                byte[] secretBagValue = secretBagSeq.toByteArray();
+
+                // Wrap the secret bag in a context-specific tag.
+                DerOutputStream bagValue = new DerOutputStream();
+                bagValue.write(secretBagValue);
+
+                // Write SafeBag value
+                safeBag.write(DerValue.createTag(DerValue.TAG_CONTEXT,
+                                    true, (byte) 0), bagValue);
+            } else {
+                continue; // skip this entry
             }
 
-            // Wrap the EncryptedPrivateKeyInfo in a context-specific tag.
-            DerOutputStream bagValue = new DerOutputStream();
-            bagValue.write(encrInfo.getEncoded());
-            safeBag.write(DerValue.createTag(DerValue.TAG_CONTEXT,
-                                true, (byte) 0), bagValue);
-
             // write SafeBag Attributes
-            byte[] bagAttrs = getBagAttributes(alias, entry.keyId);
+            byte[] bagAttrs =
+                getBagAttributes(alias, entry.keyId, entry.attributes);
             safeBag.write(bagAttrs);
 
             // wrap as Sequence
@@ -1142,7 +1779,7 @@
 
         // create AlgorithmParameters
         AlgorithmParameters algParams =
-                getAlgorithmParameters("PBEWithSHA1AndRC2_40");
+                getPBEAlgorithmParameters("PBEWithSHA1AndRC2_40");
         DerOutputStream bytes = new DerOutputStream();
         AlgorithmId algId =
                 new AlgorithmId(pbeWithSHAAnd40BitRC2CBC_OID, algParams);
@@ -1156,6 +1793,11 @@
             cipher.init(Cipher.ENCRYPT_MODE, skey, algParams);
             encryptedData = cipher.doFinal(data);
 
+            if (debug != null) {
+                debug.println("  (Cipher algorithm: " + cipher.getAlgorithm() +
+                    ")");
+            }
+
         } catch (Exception e) {
             throw new IOException("Failed to encrypt" +
                     " safe contents entry: " + e, e);
@@ -1227,6 +1869,11 @@
         ObjectIdentifier contentType = authSafe.getContentType();
 
         if (contentType.equals((Object)ContentInfo.DATA_OID)) {
+
+                if (debug != null) {
+                    debug.println("Loading PKCS#7 data");
+                }
+
            authSafeData = authSafe.getData();
         } else /* signed data */ {
            throw new IOException("public key protected PKCS12 not supported");
@@ -1236,8 +1883,10 @@
         DerValue[] safeContentsArray = as.getSequence(2);
         int count = safeContentsArray.length;
 
-        // reset the count at the start
+        // reset the counters at the start
         privateKeyCount = 0;
+        secretKeyCount = 0;
+        certificateCount = 0;
 
         /*
          * Spin over the ContentInfos.
@@ -1256,7 +1905,12 @@
                 safeContentsData = safeContents.getData();
             } else if (contentType.equals(ContentInfo.ENCRYPTED_DATA_OID)) {
                 if (password == null) {
-                   continue;
+
+                    if (debug != null) {
+                        debug.println("Warning: skipping PKCS#7 encryptedData" +
+                            " - no password was supplied");
+                    }
+                    continue;
                 }
                 DerInputStream edi =
                                 safeContents.getContent().toDerInputStream();
@@ -1278,6 +1932,30 @@
                 ObjectIdentifier algOid = in.getOID();
                 AlgorithmParameters algParams = parseAlgParameters(in);
 
+                PBEParameterSpec pbeSpec;
+                int ic = 0;
+
+                if (algParams != null) {
+                    try {
+                        pbeSpec =
+                            algParams.getParameterSpec(PBEParameterSpec.class);
+                    } catch (InvalidParameterSpecException ipse) {
+                        throw new IOException(
+                            "Invalid PBE algorithm parameters");
+                    }
+                    ic = pbeSpec.getIterationCount();
+
+                    if (ic > MAX_ITERATION_COUNT) {
+                        throw new IOException("PBE iteration count too large");
+                    }
+                }
+
+                if (debug != null) {
+                    debug.println("Loading PKCS#7 encryptedData " +
+                        "(" + new AlgorithmId(algOid).getName() +
+                        " iterations: " + ic + ")");
+                }
+
                 while (true) {
                     try {
                         // Use JCE
@@ -1293,8 +1971,9 @@
                             password = new char[1];
                             continue;
                         }
-                        throw new IOException(
-                                "failed to decrypt safe contents entry: " + e, e);
+                        throw new IOException("keystore password was incorrect",
+                            new UnrecoverableKeyException(
+                                "failed to decrypt safe contents entry: " + e));
                     }
                 }
             } else {
@@ -1307,8 +1986,15 @@
 
         // The MacData is optional.
         if (password != null && s.available() > 0) {
-           MacData macData = new MacData(s);
-           try {
+            MacData macData = new MacData(s);
+            int ic = macData.getIterations();
+
+            try {
+                if (ic > MAX_ITERATION_COUNT) {
+                    throw new InvalidAlgorithmParameterException(
+                        "MAC iteration count too large: " + ic);
+                }
+
                 String algName =
                         macData.getDigestAlgName().toUpperCase(Locale.ENGLISH);
 
@@ -1318,28 +2004,33 @@
                 // generate MAC (MAC key is created within JCE)
                 Mac m = Mac.getInstance("HmacPBE" + algName);
                 PBEParameterSpec params =
-                        new PBEParameterSpec(macData.getSalt(),
-                                        macData.getIterations());
+                        new PBEParameterSpec(macData.getSalt(), ic);
                 SecretKey key = getPBEKey(password);
                 m.init(key, params);
                 m.update(authSafeData);
                 byte[] macResult = m.doFinal();
 
+                if (debug != null) {
+                    debug.println("Checking keystore integrity " +
+                        "(" + m.getAlgorithm() + " iterations: " + ic + ")");
+                }
+
                 if (!MessageDigest.isEqual(macData.getDigest(), macResult)) {
                    throw new SecurityException("Failed PKCS12" +
                                         " integrity checking");
                 }
-           } catch (Exception e) {
+            } catch (Exception e) {
                 throw new IOException("Integrity check failed: " + e, e);
-           }
+            }
         }
 
         /*
          * Match up private keys with certificate chains.
          */
-        KeyEntry[] list = keyList.toArray(new KeyEntry[keyList.size()]);
+        PrivateKeyEntry[] list =
+            keyList.toArray(new PrivateKeyEntry[keyList.size()]);
         for (int m = 0; m < list.length; m++) {
-            KeyEntry entry = list[m];
+            PrivateKeyEntry entry = list[m];
             if (entry.keyId != null) {
                 ArrayList<X509Certificate> chain =
                                 new ArrayList<X509Certificate>();
@@ -1374,6 +2065,22 @@
                     entry.chain = chain.toArray(new Certificate[chain.size()]);
             }
         }
+
+        if (debug != null) {
+            if (privateKeyCount > 0) {
+                debug.println("Loaded " + privateKeyCount +
+                    " protected private key(s)");
+            }
+            if (secretKeyCount > 0) {
+                debug.println("Loaded " + secretKeyCount +
+                    " protected secret key(s)");
+            }
+            if (certificateCount > 0) {
+                debug.println("Loaded " + certificateCount +
+                    " certificate(s)");
+            }
+        }
+
         certEntries.clear();
         certsMap.clear();
         keyList.clear();
@@ -1384,7 +2091,7 @@
      * @param entry the KeyEntry to match
      * @return a certificate, null if not found
      */
-    private X509Certificate findMatchedCertificate(KeyEntry entry) {
+    private X509Certificate findMatchedCertificate(PrivateKeyEntry entry) {
         CertEntry keyIdMatch = null;
         CertEntry aliasMatch = null;
         for (CertEntry ce: certEntries) {
@@ -1428,7 +2135,7 @@
             }
             bagValue = bagValue.data.getDerValue();
             if (bagId.equals((Object)PKCS8ShroudedKeyBag_OID)) {
-                KeyEntry kEntry = new KeyEntry();
+                PrivateKeyEntry kEntry = new PrivateKeyEntry();
                 kEntry.protectedPrivKey = bagValue.toByteArray();
                 bagItem = kEntry;
                 privateKeyCount++;
@@ -1446,13 +2153,31 @@
                 cert = (X509Certificate)cf.generateCertificate
                         (new ByteArrayInputStream(certValue.getOctetString()));
                 bagItem = cert;
+                certificateCount++;
+            } else if (bagId.equals((Object)SecretBag_OID)) {
+                DerInputStream ss = new DerInputStream(bagValue.toByteArray());
+                DerValue[] secretValues = ss.getSequence(2);
+                ObjectIdentifier secretId = secretValues[0].getOID();
+                if (!secretValues[1].isContextSpecific((byte)0)) {
+                    throw new IOException(
+                        "unsupported PKCS12 secret value type "
+                                        + secretValues[1].tag);
+                }
+                DerValue secretValue = secretValues[1].data.getDerValue();
+                SecretKeyEntry kEntry = new SecretKeyEntry();
+                kEntry.protectedSecretKey = secretValue.getOctetString();
+                bagItem = kEntry;
+                secretKeyCount++;
             } else {
-                // log error message for "unsupported PKCS12 bag type"
+
+                if (debug != null) {
+                    debug.println("Unsupported PKCS12 bag type: " + bagId);
+                }
             }
 
             DerValue[] attrSet;
             try {
-                attrSet = sbi.getSet(2);
+                attrSet = sbi.getSet(3);
             } catch (IOException e) {
                 // entry does not have attributes
                 // Note: CA certs can have no attributes
@@ -1462,11 +2187,13 @@
 
             String alias = null;
             byte[] keyId = null;
+            ObjectIdentifier[] trustedKeyUsage = null;
+            Set<PKCS12Attribute> attributes = new HashSet<>();
 
             if (attrSet != null) {
                 for (int j = 0; j < attrSet.length; j++) {
-                    DerInputStream as =
-                        new DerInputStream(attrSet[j].toByteArray());
+                    byte[] encoded = attrSet[j].toByteArray();
+                    DerInputStream as = new DerInputStream(encoded);
                     DerValue[] attrSeq = as.getSequence(2);
                     ObjectIdentifier attrId = attrSeq[0].getOID();
                     DerInputStream vs =
@@ -1482,8 +2209,15 @@
                         alias = valSet[0].getBMPString();
                     } else if (attrId.equals((Object)PKCS9LocalKeyId_OID)) {
                         keyId = valSet[0].getOctetString();
+                    } else if
+                        (attrId.equals((Object)TrustedKeyUsage_OID)) {
+                        trustedKeyUsage = new ObjectIdentifier[valSet.length];
+                        for (int k = 0; k < valSet.length; k++) {
+                            trustedKeyUsage[k] = valSet[k].getOID();
+                        }
                     } else {
-                        // log error message for "unknown attr"
+
+                        attributes.add(new PKCS12Attribute(encoded));
                     }
                 }
             }
@@ -1499,16 +2233,19 @@
              */
             if (bagItem instanceof KeyEntry) {
                 KeyEntry entry = (KeyEntry)bagItem;
-                if (keyId == null) {
-                   // Insert a localKeyID for the privateKey
-                   // Note: This is a workaround to allow null localKeyID
-                   // attribute in pkcs12 with one private key entry and
-                   // associated cert-chain
-                   if (privateKeyCount == 1) {
-                        keyId = "01".getBytes("UTF8");
-                   } else {
-                        continue;
-                   }
+
+                if (bagItem instanceof PrivateKeyEntry) {
+                    if (keyId == null) {
+                       // Insert a localKeyID for the privateKey
+                       // Note: This is a workaround to allow null localKeyID
+                       // attribute in pkcs12 with one private key entry and
+                       // associated cert-chain
+                       if (privateKeyCount == 1) {
+                            keyId = "01".getBytes("UTF8");
+                       } else {
+                            continue;
+                       }
+                    }
                 }
                 entry.keyId = keyId;
                 // restore date if it exists
@@ -1526,11 +2263,20 @@
                     date = new Date();
                 }
                 entry.date = date;
-                keyList.add(entry);
-                if (alias == null)
+
+                if (bagItem instanceof PrivateKeyEntry) {
+                    keyList.add((PrivateKeyEntry) entry);
+                }
+                if (entry.attributes == null) {
+                    entry.attributes = new HashSet<>();
+                }
+                entry.attributes.addAll(attributes);
+                if (alias == null) {
                    alias = getUnfriendlyName();
+                }
                 entry.alias = alias;
                 entries.put(alias.toLowerCase(Locale.ENGLISH), entry);
+
             } else if (bagItem instanceof X509Certificate) {
                 X509Certificate cert = (X509Certificate)bagItem;
                 // Insert a localKeyID for the corresponding cert
@@ -1543,7 +2289,18 @@
                         keyId = "01".getBytes("UTF8");
                     }
                 }
-                certEntries.add(new CertEntry(cert, keyId, alias));
+                // Trusted certificate
+                if (trustedKeyUsage != null) {
+                    if (alias == null) {
+                        alias = getUnfriendlyName();
+                    }
+                    CertEntry certEntry =
+                        new CertEntry(cert, keyId, alias, trustedKeyUsage,
+                            attributes);
+                    entries.put(alias.toLowerCase(Locale.ENGLISH), certEntry);
+                } else {
+                    certEntries.add(new CertEntry(cert, keyId, alias));
+                }
                 X500Principal subjectDN = cert.getSubjectX500Principal();
                 if (subjectDN != null) {
                     if (!certsMap.containsKey(subjectDN)) {
--- a/src/share/classes/sun/security/provider/DSAKeyPairGenerator.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/sun/security/provider/DSAKeyPairGenerator.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2012, 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
@@ -35,6 +35,8 @@
 import java.security.spec.DSAParameterSpec;
 
 import sun.security.jca.JCAUtil;
+import static sun.security.util.SecurityProviderConstants.DEF_DSA_KEY_SIZE;
+import static sun.security.util.SecurityProviderConstants.getDefDSASubprimeSize;
 
 /**
  * This class generates DSA key parameters and public/private key
@@ -45,15 +47,14 @@
  * @author Andreas Sterbenz
  *
  */
-public class DSAKeyPairGenerator extends KeyPairGenerator
-implements java.security.interfaces.DSAKeyPairGenerator {
+class DSAKeyPairGenerator extends KeyPairGenerator {
 
     /* Length for prime P and subPrime Q in bits */
     private int plen;
     private int qlen;
 
     /* whether to force new parameters to be generated for each KeyPair */
-    private boolean forceNewParameters;
+    boolean forceNewParameters;
 
     /* preset algorithm parameters. */
     private DSAParameterSpec params;
@@ -61,9 +62,9 @@
     /* The source of random bits to use */
     private SecureRandom random;
 
-    public DSAKeyPairGenerator() {
+    DSAKeyPairGenerator(int defaultKeySize) {
         super("DSA");
-        initialize(1024, null);
+        initialize(defaultKeySize, null);
     }
 
     private static void checkStrength(int sizeP, int sizeQ) {
@@ -82,51 +83,7 @@
     }
 
     public void initialize(int modlen, SecureRandom random) {
-        initialize(modlen, false, random);
-    }
-
-    /**
-     * Initializes the DSA key pair generator. If <code>genParams</code>
-     * is false, a set of pre-computed parameters is used.
-     */
-    public void initialize(int modlen, boolean genParams, SecureRandom random) {
-        int subPrimeLen = -1;
-        if (modlen <= 1024) {
-            subPrimeLen = 160;
-        } else if (modlen == 2048) {
-            subPrimeLen = 224;
-        }
-        checkStrength(modlen, subPrimeLen);
-        if (genParams) {
-            params = null;
-        } else {
-            params = ParameterCache.getCachedDSAParameterSpec(modlen,
-                subPrimeLen);
-            if (params == null) {
-                throw new InvalidParameterException
-                    ("No precomputed parameters for requested modulus size "
-                     + "available");
-            }
-
-        }
-        this.plen = modlen;
-        this.qlen = subPrimeLen;
-        this.random = random;
-        this.forceNewParameters = genParams;
-    }
-
-    /**
-     * Initializes the DSA object using a DSA parameter object.
-     *
-     * @param params a fully initialized DSA parameter object.
-     */
-    public void initialize(DSAParams params, SecureRandom random) {
-        if (params == null) {
-            throw new InvalidParameterException("Params must not be null");
-        }
-        DSAParameterSpec spec = new DSAParameterSpec
-                                (params.getP(), params.getQ(), params.getG());
-        initialize0(spec, random);
+        init(modlen, random, false);
     }
 
     /**
@@ -145,10 +102,21 @@
             throw new InvalidAlgorithmParameterException
                 ("Inappropriate parameter");
         }
-        initialize0((DSAParameterSpec)params, random);
+        init((DSAParameterSpec)params, random, false);
     }
 
-    private void initialize0(DSAParameterSpec params, SecureRandom random) {
+    void init(int modlen, SecureRandom random, boolean forceNew) {
+        int subPrimeLen = getDefDSASubprimeSize(modlen);
+        checkStrength(modlen, subPrimeLen);
+        this.plen = modlen;
+        this.qlen = subPrimeLen;
+        this.params = null;
+        this.random = random;
+        this.forceNewParameters = forceNew;
+    }
+
+    void init(DSAParameterSpec params, SecureRandom random,
+        boolean forceNew) {
         int sizeP = params.getP().bitLength();
         int sizeQ = params.getQ().bitLength();
         checkStrength(sizeP, sizeQ);
@@ -156,7 +124,7 @@
         this.qlen = sizeQ;
         this.params = params;
         this.random = random;
-        this.forceNewParameters = false;
+        this.forceNewParameters = forceNew;
     }
 
     /**
@@ -185,7 +153,7 @@
         return generateKeyPair(spec.getP(), spec.getQ(), spec.getG(), random);
     }
 
-    public KeyPair generateKeyPair(BigInteger p, BigInteger q, BigInteger g,
+    private KeyPair generateKeyPair(BigInteger p, BigInteger q, BigInteger g,
                                    SecureRandom random) {
 
         BigInteger x = generateX(random, q);
@@ -240,4 +208,55 @@
         return y;
     }
 
+    public static final class Current extends DSAKeyPairGenerator {
+        public Current() {
+            super(DEF_DSA_KEY_SIZE);
+        }
+    }
+
+    public static final class Legacy extends DSAKeyPairGenerator
+        implements java.security.interfaces.DSAKeyPairGenerator {
+
+        public Legacy() {
+            super(1024);
+        }
+
+        /**
+         * Initializes the DSA key pair generator. If <code>genParams</code>
+         * is false, a set of pre-computed parameters is used.
+         */
+        @Override
+        public void initialize(int modlen, boolean genParams,
+            SecureRandom random) throws InvalidParameterException {
+            if (genParams) {
+                super.init(modlen, random, true);
+            } else {
+                DSAParameterSpec cachedParams =
+                    ParameterCache.getCachedDSAParameterSpec(modlen,
+                        getDefDSASubprimeSize(modlen));
+                if (cachedParams == null) {
+                    throw new InvalidParameterException
+                        ("No precomputed parameters for requested modulus" +
+                         " size available");
+                }
+                super.init(cachedParams, random, false);
+            }
+        }
+
+        /**
+         * Initializes the DSA object using a DSA parameter object.
+         *
+         * @param params a fully initialized DSA parameter object.
+         */
+        @Override
+        public void initialize(DSAParams params, SecureRandom random)
+            throws InvalidParameterException {
+            if (params == null) {
+                throw new InvalidParameterException("Params must not be null");
+             }
+             DSAParameterSpec spec = new DSAParameterSpec
+                 (params.getP(), params.getQ(), params.getG());
+             super.init(spec, random, false);
+        }
+    }
 }
--- a/src/share/classes/sun/security/provider/DSAParameterGenerator.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/sun/security/provider/DSAParameterGenerator.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2012, 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
@@ -34,16 +34,19 @@
 import java.security.InvalidParameterException;
 import java.security.MessageDigest;
 import java.security.SecureRandom;
+import java.security.ProviderException;
 import java.security.spec.AlgorithmParameterSpec;
 import java.security.spec.InvalidParameterSpecException;
 import java.security.spec.DSAParameterSpec;
 
 import sun.security.spec.DSAGenParameterSpec;
 
+import static sun.security.util.SecurityProviderConstants.DEF_DSA_KEY_SIZE;
+import static sun.security.util.SecurityProviderConstants.getDefDSASubprimeSize;
+
+
 /**
- * This class generates parameters for the DSA algorithm. It uses a default
- * prime modulus size of 1024 bits, which can be overwritten during
- * initialization.
+ * This class generates parameters for the DSA algorithm.
  *
  * @author Jan Luehe
  *
@@ -57,10 +60,6 @@
 
 public class DSAParameterGenerator extends AlgorithmParameterGeneratorSpi {
 
-    // the default parameters
-    private static final DSAGenParameterSpec DEFAULTS =
-        new DSAGenParameterSpec(1024, 160, 160);
-
     // the length of prime P, subPrime Q, and seed in bits
     private int valueL = -1;
     private int valueN = -1;
@@ -84,18 +83,16 @@
      * @param strength the strength (size of prime) in bits
      * @param random the source of randomness
      */
+    @Override
     protected void engineInit(int strength, SecureRandom random) {
-        if ((strength >= 512) && (strength <= 1024) && (strength % 64 == 0)) {
-            this.valueN = 160;
-        } else if (strength == 2048) {
-            this.valueN = 224;
-//      } else if (strength == 3072) {
-//          this.valueN = 256;
-        } else {
-            throw new InvalidParameterException
-                ("Prime size should be 512 - 1024, or 2048");
+        if ((strength != 2048) &&
+            ((strength < 512) || (strength > 1024) || (strength % 64 != 0))) {
+            throw new InvalidParameterException(
+                "Unexpected strength (size of prime): " + strength +
+                ". Prime size should be 512-1024, or 2048");
         }
         this.valueL = strength;
+        this.valueN = getDefDSASubprimeSize(strength);
         this.seedLen = valueN;
         this.random = random;
     }
@@ -104,25 +101,27 @@
      * Initializes this parameter generator with a set of
      * algorithm-specific parameter generation values.
      *
-     * @param genParamSpec the set of algorithm-specific parameter generation values
+     * @param genParamSpec the set of algorithm-specific parameter
+     *        generation values
      * @param random the source of randomness
      *
      * @exception InvalidAlgorithmParameterException if the given parameter
      * generation values are inappropriate for this parameter generator
      */
+    @Override
     protected void engineInit(AlgorithmParameterSpec genParamSpec,
-                              SecureRandom random)
-        throws InvalidAlgorithmParameterException {
+            SecureRandom random) throws InvalidAlgorithmParameterException {
         if (!(genParamSpec instanceof DSAGenParameterSpec)) {
             throw new InvalidAlgorithmParameterException("Invalid parameter");
         }
-        DSAGenParameterSpec dsaGenParams = (DSAGenParameterSpec) genParamSpec;
-        if (dsaGenParams.getPrimePLength() > 2048) {
+        DSAGenParameterSpec dsaGenParams = (DSAGenParameterSpec)genParamSpec;
+        int primePLen = dsaGenParams.getPrimePLength();
+        if (primePLen > 2048) {
             throw new InvalidParameterException
-                ("Prime size should be 512 - 1024, or 2048");
+                ("No support for prime size " + primePLen);
         }
         // directly initialize using the already validated values
-        this.valueL = dsaGenParams.getPrimePLength();
+        this.valueL = primePLen;
         this.valueN = dsaGenParams.getSubprimeQLength();
         this.seedLen = dsaGenParams.getSeedLength();
         this.random = random;
@@ -140,11 +139,7 @@
                 this.random = new SecureRandom();
             }
             if (valueL == -1) {
-                try {
-                    engineInit(DEFAULTS, this.random);
-                } catch (InvalidAlgorithmParameterException iape) {
-                    // should never happen
-                }
+                engineInit(DEF_DSA_KEY_SIZE, this.random);
             }
             BigInteger[] pAndQ = generatePandQ(this.random, valueL,
                                                valueN, seedLen);
@@ -210,13 +205,16 @@
         int b = (valueL - 1) % outLen;
         byte[] seedBytes = new byte[seedLen/8];
         BigInteger twoSl = TWO.pow(seedLen);
-        int primeCertainty = 80; // for 1024-bit prime P
-        if (valueL == 2048) {
+        int primeCertainty = -1;
+        if (valueL <= 1024) {
+            primeCertainty = 80;
+        } else if (valueL == 2048) {
             primeCertainty = 112;
-            //} else if (valueL == 3072) {
-            //    primeCertainty = 128;
         }
 
+        if (primeCertainty < 0) {
+            throw new ProviderException("Invalid valueL: " + valueL);
+        }
         BigInteger resultP, resultQ, seed = null;
         int counter;
         while (true) {
--- a/src/share/classes/sun/security/provider/JavaKeyStore.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/sun/security/provider/JavaKeyStore.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,9 +31,10 @@
 import java.security.cert.CertificateFactory;
 import java.security.cert.CertificateException;
 import java.util.*;
+
 import sun.misc.IOUtils;
-
 import sun.security.pkcs.EncryptedPrivateKeyInfo;
+import sun.security.pkcs12.PKCS12KeyStore;
 
 /**
  * This class provides the keystore implementation referred to as "JKS".
@@ -65,6 +66,13 @@
         }
     }
 
+    // special JKS that supports JKS and PKCS12 file formats
+    public static final class DualFormatJKS extends KeyStoreDelegator {
+        public DualFormatJKS() {
+            super("JKS", JKS.class, "PKCS12", PKCS12KeyStore.class);
+        }
+    }
+
     private static final int MAGIC = 0xfeedfeed;
     private static final int VERSION_1 = 0x01;
     private static final int VERSION_2 = 0x02;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/security/provider/KeyStoreDelegator.java	Sat Feb 03 21:37:28 2018 -0800
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.provider;
+
+import java.io.*;
+import java.security.*;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.cert.CertificateException;
+import java.util.*;
+
+import sun.security.util.Debug;
+
+/**
+ * This class delegates to a primary or secondary keystore implementation.
+ *
+ * @since 1.8
+ */
+
+class KeyStoreDelegator extends KeyStoreSpi {
+
+    private static final String KEYSTORE_TYPE_COMPAT = "keystore.type.compat";
+    private static final Debug debug = Debug.getInstance("keystore");
+
+    private final String primaryType;   // the primary keystore's type
+    private final String secondaryType; // the secondary keystore's type
+    private final Class<? extends KeyStoreSpi> primaryKeyStore;
+                                        // the primary keystore's class
+    private final Class<? extends KeyStoreSpi> secondaryKeyStore;
+                                        // the secondary keystore's class
+    private String type; // the delegate's type
+    private KeyStoreSpi keystore; // the delegate
+    private boolean compatModeEnabled = true;
+
+    public KeyStoreDelegator(
+        String primaryType,
+        Class<? extends KeyStoreSpi> primaryKeyStore,
+        String secondaryType,
+        Class<? extends KeyStoreSpi> secondaryKeyStore) {
+
+        // Check whether compatibility mode has been disabled
+        // (Use inner-class instead of lambda to avoid init/ClassLoader problem)
+        compatModeEnabled = "true".equalsIgnoreCase(
+            AccessController.doPrivileged(
+                new PrivilegedAction<String>() {
+                    public String run() {
+                        return Security.getProperty(KEYSTORE_TYPE_COMPAT);
+                    }
+                }
+            ));
+
+        if (compatModeEnabled) {
+            this.primaryType = primaryType;
+            this.secondaryType = secondaryType;
+            this.primaryKeyStore = primaryKeyStore;
+            this.secondaryKeyStore = secondaryKeyStore;
+        } else {
+            this.primaryType = primaryType;
+            this.secondaryType = null;
+            this.primaryKeyStore = primaryKeyStore;
+            this.secondaryKeyStore = null;
+
+            if (debug != null) {
+                debug.println("WARNING: compatibility mode disabled for " +
+                    primaryType + " and " + secondaryType + " keystore types");
+            }
+        }
+    }
+
+    @Override
+    public Key engineGetKey(String alias, char[] password)
+        throws NoSuchAlgorithmException, UnrecoverableKeyException {
+        return keystore.engineGetKey(alias, password);
+    }
+
+    @Override
+    public Certificate[] engineGetCertificateChain(String alias) {
+        return keystore.engineGetCertificateChain(alias);
+    }
+
+    @Override
+    public Certificate engineGetCertificate(String alias) {
+        return keystore.engineGetCertificate(alias);
+    }
+
+    @Override
+    public Date engineGetCreationDate(String alias) {
+        return keystore.engineGetCreationDate(alias);
+    }
+
+    @Override
+    public void engineSetKeyEntry(String alias, Key key, char[] password,
+        Certificate[] chain) throws KeyStoreException {
+        keystore.engineSetKeyEntry(alias, key, password, chain);
+    }
+
+    @Override
+    public void engineSetKeyEntry(String alias, byte[] key, Certificate[] chain)
+        throws KeyStoreException {
+        keystore.engineSetKeyEntry(alias, key, chain);
+    }
+
+    @Override
+    public void engineSetCertificateEntry(String alias, Certificate cert)
+        throws KeyStoreException {
+        keystore.engineSetCertificateEntry(alias, cert);
+    }
+
+    @Override
+    public void engineDeleteEntry(String alias) throws KeyStoreException {
+        keystore.engineDeleteEntry(alias);
+    }
+
+    @Override
+    public Enumeration<String> engineAliases() {
+        return keystore.engineAliases();
+    }
+
+    @Override
+    public boolean engineContainsAlias(String alias) {
+        return keystore.engineContainsAlias(alias);
+    }
+
+    @Override
+    public int engineSize() {
+        return keystore.engineSize();
+    }
+
+    @Override
+    public boolean engineIsKeyEntry(String alias) {
+        return keystore.engineIsKeyEntry(alias);
+    }
+
+    @Override
+    public boolean engineIsCertificateEntry(String alias) {
+        return keystore.engineIsCertificateEntry(alias);
+    }
+
+    @Override
+    public String engineGetCertificateAlias(Certificate cert) {
+        return keystore.engineGetCertificateAlias(cert);
+    }
+
+    @Override
+    public KeyStore.Entry engineGetEntry(String alias,
+        KeyStore.ProtectionParameter protParam)
+            throws KeyStoreException, NoSuchAlgorithmException,
+                UnrecoverableEntryException {
+        return keystore.engineGetEntry(alias, protParam);
+    }
+
+    @Override
+    public void engineSetEntry(String alias, KeyStore.Entry entry,
+        KeyStore.ProtectionParameter protParam)
+            throws KeyStoreException {
+        keystore.engineSetEntry(alias, entry, protParam);
+    }
+
+    @Override
+    public boolean engineEntryInstanceOf(String alias,
+        Class<? extends KeyStore.Entry> entryClass) {
+        return keystore.engineEntryInstanceOf(alias, entryClass);
+    }
+
+    @Override
+    public void engineStore(OutputStream stream, char[] password)
+        throws IOException, NoSuchAlgorithmException, CertificateException {
+
+        if (debug != null) {
+            debug.println("Storing keystore in " + type + " format");
+        }
+        keystore.engineStore(stream, password);
+    }
+
+    @Override
+    public void engineLoad(InputStream stream, char[] password)
+        throws IOException, NoSuchAlgorithmException, CertificateException {
+
+        // A new keystore is always created in the primary keystore format
+        if (stream == null || !compatModeEnabled) {
+            try {
+                keystore = primaryKeyStore.newInstance();
+
+            } catch (InstantiationException | IllegalAccessException e) {
+                // can safely ignore
+            }
+            type = primaryType;
+
+            if (debug != null && stream == null) {
+                debug.println("Creating a new keystore in " + type + " format");
+            }
+            keystore.engineLoad(stream, password);
+
+        } else {
+            // First try the primary keystore then try the secondary keystore
+            InputStream bufferedStream = new BufferedInputStream(stream);
+            bufferedStream.mark(Integer.MAX_VALUE);
+            try {
+                keystore = primaryKeyStore.newInstance();
+                type = primaryType;
+                keystore.engineLoad(bufferedStream, password);
+
+            } catch (Exception e) {
+
+                // incorrect password
+                if (e instanceof IOException &&
+                    e.getCause() instanceof UnrecoverableKeyException) {
+                    throw (IOException)e;
+                }
+
+                try {
+                    keystore = secondaryKeyStore.newInstance();
+                    type = secondaryType;
+                    bufferedStream.reset();
+                    keystore.engineLoad(bufferedStream, password);
+
+                    if (debug != null) {
+                        debug.println("WARNING: switching from " +
+                          primaryType + " to " + secondaryType +
+                          " keystore file format has altered the " +
+                          "keystore security level");
+                    }
+
+                } catch (InstantiationException |
+                    IllegalAccessException e2) {
+                    // can safely ignore
+
+                } catch (IOException |
+                    NoSuchAlgorithmException |
+                    CertificateException e3) {
+
+                    // incorrect password
+                    if (e3 instanceof IOException &&
+                        e3.getCause() instanceof
+                            UnrecoverableKeyException) {
+                        throw (IOException)e3;
+                    }
+                    // rethrow the outer exception
+                    if (e instanceof IOException) {
+                        throw (IOException)e;
+                    } else if (e instanceof CertificateException) {
+                        throw (CertificateException)e;
+                    } else if (e instanceof NoSuchAlgorithmException) {
+                        throw (NoSuchAlgorithmException)e;
+                    }
+                }
+            }
+
+            if (debug != null) {
+                debug.println("Loaded a keystore in " + type + " format");
+            }
+        }
+    }
+}
--- a/src/share/classes/sun/security/provider/ParameterCache.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/sun/security/provider/ParameterCache.java	Sat Feb 03 21:37:28 2018 -0800
@@ -148,9 +148,14 @@
                    InvalidAlgorithmParameterException {
         AlgorithmParameterGenerator gen =
                 AlgorithmParameterGenerator.getInstance("DSA");
-        DSAGenParameterSpec genParams =
-            new DSAGenParameterSpec(primeLen, subprimeLen);
-        gen.init(genParams, random);
+        // Use init(int size, SecureRandom random) for legacy DSA key sizes
+        if (primeLen < 1024) {
+            gen.init(primeLen, random);
+        } else {
+            DSAGenParameterSpec genParams =
+                new DSAGenParameterSpec(primeLen, subprimeLen);
+            gen.init(genParams, random);
+        }
         AlgorithmParameters params = gen.generateParameters();
         DSAParameterSpec spec = params.getParameterSpec(DSAParameterSpec.class);
         return spec;
@@ -161,8 +166,9 @@
         dsaCache = new ConcurrentHashMap<Integer,DSAParameterSpec>();
 
         /*
-         * We support precomputed parameter for 512, 768 and 1024 bit
-         * moduli. In this file we provide both the seed and counter
+         * We support precomputed parameter for legacy 512, 768 bit moduli,
+         * and (L, N) combinations of (1024, 160), (2048, 224), (2048, 256).
+         * In this file we provide both the seed and counter
          * value of the generation process for each of these seeds,
          * for validation purposes. We also include the test vectors
          * from the DSA specification, FIPS 186, and the FIPS 186
--- a/src/share/classes/sun/security/provider/SunEntries.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/sun/security/provider/SunEntries.java	Sat Feb 03 21:37:28 2018 -0800
@@ -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
@@ -27,6 +27,7 @@
 
 import java.util.Map;
 import java.security.*;
+import sun.security.action.GetPropertyAction;
 
 /**
  * Defines the entries of the SUN provider.
@@ -76,6 +77,10 @@
 
 final class SunEntries {
 
+    private static final boolean useLegacyDSA =
+        Boolean.parseBoolean(GetPropertyAction.privilegedGetProperty
+            ("jdk.security.legacyDSAKeyPairGenerator"));
+
     private SunEntries() {
         // empty
     }
@@ -140,8 +145,9 @@
         /*
          *  Key Pair Generator engines
          */
-        map.put("KeyPairGenerator.DSA",
-            "sun.security.provider.DSAKeyPairGenerator");
+        String dsaKPGImplClass = "sun.security.provider.DSAKeyPairGenerator$";
+        dsaKPGImplClass += (useLegacyDSA? "Legacy" : "Current");
+        map.put("KeyPairGenerator.DSA", dsaKPGImplClass);
         map.put("Alg.Alias.KeyPairGenerator.OID.1.2.840.10040.4.1", "DSA");
         map.put("Alg.Alias.KeyPairGenerator.1.2.840.10040.4.1", "DSA");
         map.put("Alg.Alias.KeyPairGenerator.1.3.14.3.2.12", "DSA");
@@ -205,7 +211,8 @@
         /*
          * KeyStore
          */
-        map.put("KeyStore.JKS", "sun.security.provider.JavaKeyStore$JKS");
+        map.put("KeyStore.JKS",
+                        "sun.security.provider.JavaKeyStore$DualFormatJKS");
         map.put("KeyStore.CaseExactJKS",
                         "sun.security.provider.JavaKeyStore$CaseExactJKS");
 
--- a/src/share/classes/sun/security/provider/certpath/AdjacencyList.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/sun/security/provider/certpath/AdjacencyList.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2012, 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
@@ -24,13 +24,11 @@
  */
 package sun.security.provider.certpath;
 
-
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 
-
 /**
  * An AdjacencyList is used to store the history of certification paths
  * attempted in constructing a path from an initiator to a target. The
@@ -123,124 +121,117 @@
      * at the start.
      */
     private boolean buildList(List<List<Vertex>> theList, int index,
-        BuildStep follow) {
+                              BuildStep follow) {
 
         // Each time this method is called, we're examining a new list
         // from the global list. So, we have to start by getting the list
         // that contains the set of Vertexes we're considering.
         List<Vertex> l = theList.get(index);
 
-        try {
-            // we're interested in the case where all indexes are -1...
-            boolean allNegOne = true;
-            // ...and in the case where every entry has a Throwable
-            boolean allXcps = true;
+        // we're interested in the case where all indexes are -1...
+        boolean allNegOne = true;
+        // ...and in the case where every entry has a Throwable
+        boolean allXcps = true;
+
+        for (Vertex v : l) {
+            if (v.getIndex() != -1) {
+                // count an empty list the same as an index of -1...this
+                // is to patch a bug somewhere in the builder
+                if (theList.get(v.getIndex()).size() != 0)
+                    allNegOne = false;
+            } else {
+                if (v.getThrowable() == null)
+                    allXcps = false;
+            }
+            // every entry, regardless of the final use for it, is always
+            // entered as a possible step before we take any actions
+            mStepList.add(new BuildStep(v, BuildStep.POSSIBLE));
+        }
+
+        if (allNegOne) {
+            // There are two cases that we could be looking at here. We
+            // may need to back up, or the build may have succeeded at
+            // this point. This is based on whether or not any
+            // exceptions were found in the list.
+            if (allXcps) {
+                // we need to go back...see if this is the last one
+                if (follow == null)
+                    mStepList.add(new BuildStep(null, BuildStep.FAIL));
+                else
+                    mStepList.add(new BuildStep(follow.getVertex(),
+                                                BuildStep.BACK));
+
+                return false;
+            } else {
+                // we succeeded...now the only question is which is the
+                // successful step? If there's only one entry without
+                // a throwable, then that's the successful step. Otherwise,
+                // we'll have to make some guesses...
+                List<Vertex> possibles = new ArrayList<>();
+                for (Vertex v : l) {
+                    if (v.getThrowable() == null)
+                        possibles.add(v);
+                }
+
+                if (possibles.size() == 1) {
+                    // real easy...we've found the final Vertex
+                    mStepList.add(new BuildStep(possibles.get(0),
+                                                BuildStep.SUCCEED));
+                } else {
+                    // ok...at this point, there is more than one Cert
+                    // which might be the succeed step...how do we know
+                    // which it is? I'm going to assume that our builder
+                    // algorithm is good enough to know which is the
+                    // correct one, and put it first...but a FIXME goes
+                    // here anyway, and we should be comparing to the
+                    // target/initiator Cert...
+                    mStepList.add(new BuildStep(possibles.get(0),
+                                                BuildStep.SUCCEED));
+                }
+
+                return true;
+            }
+        } else {
+            // There's at least one thing that we can try before we give
+            // up and go back. Run through the list now, and enter a new
+            // BuildStep for each path that we try to follow. If none of
+            // the paths we try produce a successful end, we're going to
+            // have to back out ourselves.
+            boolean success = false;
 
             for (Vertex v : l) {
+
+                // Note that we'll only find a SUCCEED case when we're
+                // looking at the last possible path, so we don't need to
+                // consider success in the while loop
+
                 if (v.getIndex() != -1) {
-                    // count an empty list the same as an index of -1...this
-                    // is to patch a bug somewhere in the builder
-                    if (theList.get(v.getIndex()).size() != 0)
-                        allNegOne = false;
+                    if (theList.get(v.getIndex()).size() != 0) {
+                        // If the entry we're looking at doesn't have an
+                        // index of -1, and doesn't lead to an empty list,
+                        // then it's something we follow!
+                        BuildStep bs = new BuildStep(v, BuildStep.FOLLOW);
+                        mStepList.add(bs);
+                        success = buildList(theList, v.getIndex(), bs);
+                    }
                 }
-                else
-                    if (v.getThrowable() == null)
-                        allXcps = false;
-
-                // every entry, regardless of the final use for it, is always
-                // entered as a possible step before we take any actions
-                mStepList.add(new BuildStep(v, BuildStep.POSSIBLE));
             }
 
-            if (allNegOne) {
-                // There are two cases that we could be looking at here. We
-                // may need to back up, or the build may have succeeded at
-                // this point. This is based on whether or not any
-                // exceptions were found in the list.
-                if (allXcps) {
-                    // we need to go back...see if this is the last one
-                    if (follow == null)
-                        mStepList.add(new BuildStep(null, BuildStep.FAIL));
-                    else
-                        mStepList.add(new BuildStep(follow.getVertex(),
-                                                    BuildStep.BACK));
+            if (success) {
+                // We're already finished!
+                return true;
+            } else {
+                // We failed, and we've exhausted all the paths that we
+                // could take. The only choice is to back ourselves out.
+                if (follow == null)
+                    mStepList.add(new BuildStep(null, BuildStep.FAIL));
+                else
+                    mStepList.add(new BuildStep(follow.getVertex(),
+                                                BuildStep.BACK));
 
-                    return false;
-                } else {
-                    // we succeeded...now the only question is which is the
-                    // successful step? If there's only one entry without
-                    // a throwable, then that's the successful step. Otherwise,
-                    // we'll have to make some guesses...
-                    List<Vertex> possibles = new ArrayList<Vertex>();
-                    for (Vertex v : l) {
-                        if (v.getThrowable() == null)
-                            possibles.add(v);
-                    }
-
-                    if (possibles.size() == 1) {
-                        // real easy...we've found the final Vertex
-                        mStepList.add(new BuildStep(possibles.get(0),
-                                                    BuildStep.SUCCEED));
-                    } else {
-                        // ok...at this point, there is more than one Cert
-                        // which might be the succeed step...how do we know
-                        // which it is? I'm going to assume that our builder
-                        // algorithm is good enough to know which is the
-                        // correct one, and put it first...but a FIXME goes
-                        // here anyway, and we should be comparing to the
-                        // target/initiator Cert...
-                        mStepList.add(new BuildStep(possibles.get(0),
-                                                    BuildStep.SUCCEED));
-                    }
-
-                    return true;
-                }
-            } else {
-                // There's at least one thing that we can try before we give
-                // up and go back. Run through the list now, and enter a new
-                // BuildStep for each path that we try to follow. If none of
-                // the paths we try produce a successful end, we're going to
-                // have to back out ourselves.
-                boolean success = false;
-
-                for (Vertex v : l) {
-
-                    // Note that we'll only find a SUCCEED case when we're
-                    // looking at the last possible path, so we don't need to
-                    // consider success in the while loop
-
-                    if (v.getIndex() != -1) {
-                        if (theList.get(v.getIndex()).size() != 0) {
-                            // If the entry we're looking at doesn't have an
-                            // index of -1, and doesn't lead to an empty list,
-                            // then it's something we follow!
-                            BuildStep bs = new BuildStep(v, BuildStep.FOLLOW);
-                            mStepList.add(bs);
-                            success = buildList(theList, v.getIndex(), bs);
-                        }
-                    }
-                }
-
-                if (success) {
-                    // We're already finished!
-                    return true;
-                } else {
-                    // We failed, and we've exhausted all the paths that we
-                    // could take. The only choice is to back ourselves out.
-                    if (follow == null)
-                        mStepList.add(new BuildStep(null, BuildStep.FAIL));
-                    else
-                        mStepList.add(new BuildStep(follow.getVertex(),
-                                                    BuildStep.BACK));
-
-                    return false;
-                }
+                return false;
             }
         }
-        catch (Exception e) {}
-
-        // we'll never get here, but you know java...
-        return false;
     }