# HG changeset patch # User Greg Lewis # Date 1517722648 28800 # Node ID 1d98f0be7c8d530688a8fb12d59f2cbd1d8dee45 # Parent 6b21d823f6e607cce705a631353eb6d2fbda2aeb# Parent 2a7d0883d64a457d0b631a712d0bf31501402370 Merge from main OpenJDK repository diff -r 6b21d823f6e6 -r 1d98f0be7c8d .hgtags --- 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 diff -r 6b21d823f6e6 -r 1d98f0be7c8d THIRD_PARTY_README --- 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 diff -r 6b21d823f6e6 -r 1d98f0be7c8d make/com/sun/java/pack/Makefile --- 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 diff -r 6b21d823f6e6 -r 1d98f0be7c8d make/common/Defs.gmk --- 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 # diff -r 6b21d823f6e6 -r 1d98f0be7c8d make/common/Program.gmk --- 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)"' diff -r 6b21d823f6e6 -r 1d98f0be7c8d make/java/jli/Makefile --- 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 diff -r 6b21d823f6e6 -r 1d98f0be7c8d make/java/security/Makefile --- 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) diff -r 6b21d823f6e6 -r 1d98f0be7c8d make/java/zip/Makefile --- 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 # diff -r 6b21d823f6e6 -r 1d98f0be7c8d make/javax/crypto/Makefile --- 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 \ diff -r 6b21d823f6e6 -r 1d98f0be7c8d make/sun/splashscreen/Makefile --- 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 diff -r 6b21d823f6e6 -r 1d98f0be7c8d make/tools/Makefile --- 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 \ diff -r 6b21d823f6e6 -r 1d98f0be7c8d make/tools/customizesecurityfile/Makefile --- /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 + diff -r 6b21d823f6e6 -r 1d98f0be7c8d make/tools/src/build/tools/customizesecurityfile/CryptoLevel.java --- /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(); + } +} diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/com/sun/crypto/provider/AESCipher.java --- 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); } /** diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/com/sun/crypto/provider/AESWrapCipher.java --- 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); diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/com/sun/crypto/provider/ARCFOURCipher.java --- 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); } } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/com/sun/crypto/provider/BlowfishCipher.java --- 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 key is invalid. */ protected int engineGetKeySize(Key key) throws InvalidKeyException { - return (key.getEncoded().length * 8); + return CipherCore.multiplyExact(key.getEncoded().length, 8); } /** diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/com/sun/crypto/provider/CipherBlockChaining.java --- 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 @@ * *

The input plain text plain, starting at * plainOffset and ending at - * (plainOffset + len - 1), is encrypted. + * (plainOffset + plainLen - 1), is encrypted. * The result is stored in cipher, starting at * cipherOffset. * - *

It is the application's responsibility to make sure that - * plainLen 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 plain * @param plainLen the length of the input data * @param cipher the buffer for the result * @param cipherOffset the offset in cipher + * @exception ProviderException if len 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; iThe input cipher text cipher, starting at * cipherOffset and ending at - * (cipherOffset + len - 1), is decrypted. + * (cipherOffset + cipherLen - 1), is decrypted. * The result is stored in plain, starting at * plainOffset. * - *

It is the application's responsibility to make sure that - * cipherLen is a multiple of the embedded cipher's block - * size, as any excess bytes are ignored. - * *

It is also the application's responsibility to make sure that * init 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 plain - * - * @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 len 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; } } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/com/sun/crypto/provider/CipherCore.java --- 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; - - if (padding == null) - return totalLen; - - if (decrypting) - return totalLen; + // estimate based on the maximum + return getOutputSizeByOperation(inputLen, true); + } - 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; + } } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/com/sun/crypto/provider/CipherFeedback.java --- 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 @@ * *

The input plain text plain, starting at * plainOffset and ending at - * (plainOffset + len - 1), is encrypted. + * (plainOffset + plainLen - 1), is encrypted. * The result is stored in cipher, starting at * cipherOffset. * - *

It is the application's responsibility to make sure that - * plainLen is a multiple of the stream unit size - * numBytes, as any excess bytes are ignored. - * - *

It is also the application's responsibility to make sure that - * init 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 plain * @param plainLen the length of the input data * @param cipher the buffer for the result * @param cipherOffset the offset in cipher + * @exception ProviderException if plainLen is not + * a multiple of the numBytes + * @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 loopCount = plainLen / numBytes; - int oddBytes = plainLen % 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"); + } - 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]); + int nShift = blockSize - numBytes; + int loopCount = plainLen / numBytes; + + 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 0 ; - plainOffset += numBytes, cipherOffset += numBytes, - loopCount--) { - embeddedCipher.encryptBlock(register, 0, k, 0); - System.arraycopy(register, numBytes, register, 0, len); - for (i=0; iThe input plain text plain, starting at + * plainOffset and ending at + * (plainOffset + plainLen - 1), is encrypted. + * The result is stored in cipher, starting at + * cipherOffset. + * + * @param plain the buffer with the input data to be encrypted + * @param plainOffset the offset in plain + * @param plainLen the length of the input data + * @param cipher the buffer for the result + * @param cipherOffset the offset in cipher + * @return the number of bytes placed into cipher + */ + 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 @@ * *

The input cipher text cipher, starting at * cipherOffset and ending at - * (cipherOffset + len - 1), is decrypted. + * (cipherOffset + cipherLen - 1), is decrypted. * The result is stored in plain, starting at * plainOffset. * - *

It is the application's responsibility to make sure that - * cipherLen is a multiple of the stream unit size - * numBytes, as any excess bytes are ignored. - * - *

It is also the application's responsibility to make sure that - * init 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 cipherOffset * @param cipherLen the length of the input data * @param plain the buffer for the result * @param plainOffset the offset in plain + * @exception ProviderException if cipherLen is not + * a multiple of the numBytes + * @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 loopCount = cipherLen / numBytes; - int oddBytes = cipherLen % 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"); + } - 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]); - } + int nShift = blockSize - numBytes; + int loopCount = cipherLen / numBytes; + + 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 0; - plainOffset += numBytes, cipherOffset += numBytes, - loopCount--) { - embeddedCipher.encryptBlock(register, 0, k, 0); - System.arraycopy(register, numBytes, register, 0, len); - for (i=0; iThe input cipher text cipher, starting at + * cipherOffset and ending at + * (cipherOffset + cipherLen - 1), is decrypted. + * The result is stored in plain, starting at + * plainOffset. + * + * @param cipher the buffer with the input data to be decrypted + * @param cipherOffset the offset in cipherOffset + * @param cipherLen the length of the input data + * @param plain the buffer for the result + * @param plainOffset the offset in plain + * @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; } } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/com/sun/crypto/provider/CipherTextStealing.java --- 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 cipher + * @return the number of bytes placed into cipher */ - 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 plain + * @return the number of bytes placed into plain */ - 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; } } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/com/sun/crypto/provider/CounterMode.java --- 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 cipher, starting at * cipherOffset. * - *

It is the application's responsibility to make sure that - * plainLen is a multiple of the embedded cipher's block size, - * as any excess bytes are ignored. - * - *

It is also the application's responsibility to make sure that - * init 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 plain * @param len the length of the input data * @param out the buffer for the result * @param outOff the offset in cipher + * @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. - * - *

The input cipher text cipher, starting at - * cipherOffset and ending at - * (cipherOffset + len - 1), is decrypted. - * The result is stored in plain, starting at - * plainOffset. - * - *

It is the application's responsibility to make sure that - * cipherLen is a multiple of the embedded cipher's block - * size, as any excess bytes are ignored. - * - *

It is also the application's responsibility to make sure that - * init 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 cipherOffset - * @param len the length of the input data - * @param out the buffer for the result - * @param outOff the offset in plain - */ - 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; } } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/com/sun/crypto/provider/DESedeWrapCipher.java --- 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; } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/com/sun/crypto/provider/DHKeyPairGenerator.java --- 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 @@ *

* @@ -68,7 +68,7 @@ public DHKeyPairGenerator() { super(); - initialize(1024, null); + initialize(DEF_DH_KEY_SIZE, null); } /** diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/com/sun/crypto/provider/DHParameterGenerator.java --- 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 @@ * *

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(); + + // Re-uses DSA parameters and thus have the same range + checkKeySize(primeSize); - 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)"); - } + exponentSize = dhParamSpec.getExponentSize(); + if (exponentSize <= 0) { + throw new InvalidAlgorithmParameterException + ("Exponent size must be greater than zero"); + } - 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"); - } + // Require exponentSize < primeSize + if (exponentSize >= primeSize) { + throw new InvalidAlgorithmParameterException + ("Exponent size must be less than modulus size"); + } } /** diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/com/sun/crypto/provider/ElectronicCodeBook.java --- 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. * - *

The input plain text plain, starting at - * plainOffset and ending at - * (plainOffset + len - 1), is encrypted. - * The result is stored in cipher, starting at - * cipherOffset. - * - *

It is the application's responsibility to make sure that - * plainLen is a multiple of the embedded cipher's block size, - * as any excess bytes are ignored. - * - *

It is also the application's responsibility to make sure that - * init has been called before this method is called. - * (This check is omitted here, to avoid double checking.) + *

The input plain text in, starting at + * inOff and ending at * (inOff + len - 1), + * is encrypted. The result is stored in out, starting at + * outOff. * * @param in the buffer with the input data to be encrypted - * @param inOffset the offset in plain + * @param inOff the offset in plain * @param len the length of the input data * @param out the buffer for the result * @param outOff the offset in cipher + * @exception ProviderException if len 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. * - *

The input cipher text cipher, starting at - * cipherOffset and ending at - * (cipherOffset + len - 1), is decrypted. - * The result is stored in plain, starting at - * plainOffset. - * - *

It is the application's responsibility to make sure that - * cipherLen is a multiple of the embedded cipher's block - * size, as any excess bytes are ignored. - * - *

It is also the application's responsibility to make sure that - * init has been called before this method is called. - * (This check is omitted here, to avoid double checking.) + *

The input cipher text in, starting at + * inOff and ending at * (inOff + len - 1), + * is decrypted.The result is stored in out, starting at + * outOff. * * @param in the buffer with the input data to be decrypted * @param inOff the offset in cipherOffset * @param len the length of the input data * @param out the buffer for the result * @param outOff the offset in plain + * @exception ProviderException if len 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; } - } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/com/sun/crypto/provider/FeedbackCipher.java --- 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 cipher + * @return the number of bytes placed into cipher */ - 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 cipher + * @return the number of bytes placed into cipher */ - 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 plain + * @return the number of bytes placed into plain */ - 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 plain + * @return the number of bytes placed into plain */ - 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); } } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/com/sun/crypto/provider/ISO10126Padding.java --- 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; } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/com/sun/crypto/provider/JceKeyStore.java --- 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() { + @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; + } + } } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/com/sun/crypto/provider/KeyProtector.java --- 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, diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/com/sun/crypto/provider/OutputFeedback.java --- 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 @@ * *

The input plain text plain, starting at * plainOffset and ending at - * (plainOffset + len - 1), is encrypted. + * (plainOffset + plainLen - 1), is encrypted. * The result is stored in cipher, starting at * cipherOffset. * - *

It is the application's responsibility to make sure that - * plainLen is a multiple of the stream unit size - * numBytes, as any excess bytes are ignored. - * - *

It is also the application's responsibility to make sure that - * init 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 plain * @param plainLen the length of the input data * @param cipher the buffer for the result * @param cipherOffset the offset in cipher + * @exception ProviderException if plainLen is not + * a multiple of the numBytes + * @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 loopCount = plainLen / numBytes; - int oddBytes = plainLen % numBytes; + int encrypt(byte[] plain, int plainOffset, int plainLen, + byte[] cipher, int cipherOffset) { - if (len == 0) { - for (; loopCount > 0; - plainOffset += numBytes, cipherOffset += numBytes, - loopCount--) { - embeddedCipher.encryptBlock(register, 0, k, 0); - for (i=0; i 0) { - embeddedCipher.encryptBlock(register, 0, k, 0); - for (i=0; i 0; - plainOffset += numBytes, cipherOffset += numBytes, - loopCount--) { - embeddedCipher.encryptBlock(register, 0, k, 0); - for (i=0; i 0) { - embeddedCipher.encryptBlock(register, 0, k, 0); - for (i=0; i 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. * - *

The input cipher text cipher, starting at - * cipherOffset and ending at - * (cipherOffset + len - 1), is decrypted. - * The result is stored in plain, starting at - * plainOffset. - * - *

It is the application's responsibility to make sure that - * cipherLen is a multiple of the stream unit size - * numBytes, as any excess bytes are ignored. + *

The input plain text plain, starting at + * plainOffset and ending at + * (plainOffset + plainLen - 1), is encrypted. + * The result is stored in cipher, starting at + * cipherOffset. * - *

It is also the application's responsibility to make sure that - * init 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 cipherOffset - * @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 plain + * @param plainLen the length of the input data + * @param cipher the buffer for the result + * @param cipherOffset the offset in cipher + * @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); } } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/com/sun/crypto/provider/PBECipherCore.java --- 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; } } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/com/sun/crypto/provider/PCBC.java --- 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 @@ * *

The input plain text plain, starting at * plainOffset and ending at - * (plainOffset + len - 1), is encrypted. + * (plainOffset + plainLen - 1), is encrypted. * The result is stored in cipher, starting at * cipherOffset. * - *

It is the application's responsibility to make sure that - * plainLen is a multiple of the embedded cipher's block size, - * as any excess bytes are ignored. - * - *

It is also the application's responsibility to make sure that - * init 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 plain * @param plainLen the length of the input data * @param cipher the buffer for the result * @param cipherOffset the offset in cipher + * @exception ProviderException if plainLen 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; iThe input cipher text cipher, starting at * cipherOffset and ending at - * (cipherOffset + len - 1), is decrypted. + * (cipherOffset + cipherLen - 1), is decrypted. * The result is stored in plain, starting at * plainOffset. * - *

It is the application's responsibility to make sure that - * cipherLen is a multiple of the embedded cipher's block - * size, as any excess bytes are ignored. - * - *

It is also the application's responsibility to make sure that - * init 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 cipherOffset * @param cipherLen the length of the input data * @param plain the buffer for the result * @param plainOffset the offset in plain + * @exception ProviderException if cipherLen 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; } } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/com/sun/crypto/provider/PKCS5Padding.java --- 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; } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/com/sun/net/ssl/internal/www/protocol/https/HttpsURLConnectionOldImpl.java --- 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); } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/java/awt/MenuBar.java --- 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; + } } } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/java/io/ObjectInputStream.java --- 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(); diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/java/io/ObjectStreamClass.java --- 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 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 pea = new PrivilegedAction() { + @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(); diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/java/security/CodeSource.java --- 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(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)); diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/java/security/KeyStore.java --- 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 attributes) { + return new PrivateKeyEntry(privateKey, chain, attributes); + } + + @Override + public Set getPrivateKeyEntryAttributes(PrivateKeyEntry entry) { + return entry.getAttributes(); + } + + @Override + public SecretKeyEntry constructSecretKeyEntry(SecretKey secretKey, + Set attributes) { + return new SecretKeyEntry(secretKey, attributes); + } + + @Override + public Set getSecretKeyEntryAttributes(SecretKeyEntry entry) { + return entry.getAttributes(); + } + + public TrustedCertificateEntry constructTrustedCertificateEntry(Certificate trustedCert, + Set attributes) { + return new TrustedCertificateEntry(trustedCert, attributes); + } + + @Override + public Set 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 attributes; /** * Constructs a PrivateKeyEntry with a @@ -381,7 +424,39 @@ * in the end entity Certificate (at index 0) */ public PrivateKeyEntry(PrivateKey privateKey, Certificate[] chain) { - if (privateKey == null || chain == null) { + this(privateKey, chain, Collections.emptySet()); + } + + /** + * Constructs a {@code PrivateKeyEntry} with a {@code PrivateKey} and + * corresponding certificate chain and associated entry attributes. + * + *

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 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. + *

+ * + * @return an unmodifiable {@code Set} of attributes, possibly empty + * + * @since 1.8 + */ + private Set 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 attributes; /** * Constructs a SecretKeyEntry with a @@ -496,6 +587,32 @@ throw new NullPointerException("invalid null input"); } this.sKey = secretKey; + this.attributes = Collections.emptySet(); + } + + /** + * Constructs a {@code SecretKeyEntry} with a {@code SecretKey} and + * associated entry attributes. + * + *

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 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. + *

+ * + * @return an unmodifiable {@code Set} of attributes, possibly empty + * + * @since 1.8 + */ + private Set 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 attributes; /** * Constructs a TrustedCertificateEntry with a @@ -540,6 +670,32 @@ throw new NullPointerException("invalid null input"); } this.cert = trustedCert; + this.attributes = Collections.emptySet(); + } + + /** + * Constructs a {@code TrustedCertificateEntry} with a + * trusted {@code Certificate} and associated entry attributes. + * + *

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 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. + *

+ * + * @return an unmodifiable {@code Set} of attributes, possibly empty + * + * @since 1.8 + */ + private Set getAttributes() { + return attributes; + } + + /** * Returns a string representation of this TrustedCertificateEntry. * @return a string representation of this TrustedCertificateEntry. */ diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/java/security/Signature.java --- 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()); } } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/java/security/UnresolvedPermission.java --- 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 cfs = null; + List 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(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); + 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); diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/java/util/ArrayDeque.java --- 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. * - *

Most ArrayDeque operations run in amortized constant time. + *

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. * - *

The iterators returned by this class's iterator method are + *

The iterators returned by this class's {@code iterator} method are * fail-fast: If the deque is modified at any time after the iterator - * is created, in any way except through the iterator's own remove + * 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 @@ *

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 ConcurrentModificationException 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: the fail-fast behavior of iterators * should be used only to detect bugs. @@ -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 true (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 true (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 e such that - * o.equals(e) (if such an element exists). - * Returns true 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 true 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 e such that - * o.equals(e) (if such an element exists). - * Returns true 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 true 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 @@ *

This method is equivalent to {@link #addLast}. * * @param e the element to add - * @return true (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 @@ *

This method is equivalent to {@link #offerLast}. * * @param e the element to add - * @return true (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 - * null if this deque is empty. + * {@code null} if this deque is empty. * *

This method is equivalent to {@link #pollFirst}. * * @return the head of the queue represented by this deque, or - * null 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 null if this deque is empty. + * this deque, or returns {@code null} if this deque is empty. * *

This method is equivalent to {@link #peekFirst}. * * @return the head of the queue represented by this deque, or - * null 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 true if this deque contains no elements. + * Returns {@code true} if this deque contains no elements. * - * @return true 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 true if this deque contains the specified element. - * More formally, returns true if and only if this deque contains - * at least one element e such that o.equals(e). + * 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 true 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 e such that - * o.equals(e) (if such an element exists). - * Returns true 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). * - *

This method is equivalent to {@link #removeFirstOccurrence}. + *

This method is equivalent to {@link #removeFirstOccurrence(Object)}. * * @param o element to be removed from this deque, if present - * @return true 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 @@ *

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 - * null. + * {@code null}. * *

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. * - *

Suppose x is a deque known to contain only strings. + *

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 String: + * allocated array of {@code String}: * - *

-     *     String[] y = x.toArray(new String[0]);
+ *
 {@code String[] y = x.toArray(new String[0]);}
* - * Note that toArray(new Object[0]) is identical in function to - * toArray(). + * 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 clone() { try { + @SuppressWarnings("unchecked") ArrayDeque result = (ArrayDeque) 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 (int) 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(); } } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/java/util/ArrayList.java --- 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 List interface. Implements * all optional list operations, and permits all elements, including @@ -200,12 +202,15 @@ } } - private void ensureCapacityInternal(int minCapacity) { + private static int calculateCapacity(Object[] elementData, int minCapacity) { if (elementData == EMPTY_ELEMENTDATA) { - minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); + return Math.max(DEFAULT_CAPACITY, minCapacity); } + return minCapacity; + } - ensureExplicitCapacity(minCapacity); + private void ensureCapacityInternal(int 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; diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/java/util/GregorianCalendar.java --- 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 ///////////////// diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/java/util/HashMap.java --- 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 Map 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(); diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/java/util/HashSet.java --- 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 Set interface, backed by a hash table * (actually a HashMap 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(capacity, loadFactor) : new HashMap(capacity, loadFactor)); - // Read in size - int size = s.readInt(); - // Read in all elements in the proper order. for (int i=0; i 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[] 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 @@ * *

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[] tab, K key, V value) throws StreamCorruptedException diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/java/util/IdentityHashMap.java --- 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 Map interface with a hash table, using @@ -69,7 +70,7 @@ * maximum size and the number of buckets is unspecified. * *

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); + + retryAfterResize: for (;;) { + final Object[] tab = table; + final int len = tab.length; + int i = hash(k, len); - Object item; - while ( (item = tab[i]) != null) { - if (item == k) { - V oldValue = (V) tab[i + 1]; - tab[i + 1] = value; - return oldValue; + 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; - if (++size >= threshold) - resize(len); // len == 2 * current capacity. - return null; + modCount++; + tab[i] = k; + tab[i + 1] = value; + size = s; + 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 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 IdentityHashMap instance to a stream - * (i.e., serialize it). + * Saves the state of the IdentityHashMap instance to a stream + * (i.e., serializes it). * * @serialData The size of the HashMap (the number of key-value * mappings) (int), followed by the key (Object) and @@ -1197,8 +1194,8 @@ } /** - * Reconstitute the IdentityHashMap instance from a stream (i.e., - * deserialize it). + * Reconstitutes the IdentityHashMap 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= 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) { diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/java/util/concurrent/CopyOnWriteArrayList.java --- 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. diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/javax/crypto/CipherSpi.java --- 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; } } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/javax/crypto/JceSecurity.java --- 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); + + if ((cpPath != null) && ((cpPath.getNameCount() != 1) || + (cpPath.compareTo(cpPath.getFileName())) != 0)) { + throw new SecurityException( + "Invalid policy directory name format: " + + cryptoPolicyProperty); + } - File exportJar = new File(pathToPolicyJar, "US_export_policy.jar"); - File importJar = new File(pathToPolicyJar, "local_policy.jar"); + 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"); diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/awt/CustomCursor.java --- 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); diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/awt/resources/awt_ko.properties --- 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 diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/misc/IOUtils.java --- 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 length of bytes from in + * 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); + } } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/misc/JavaOISAccess.java --- 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; } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/misc/JavaSecurityKeyStoreAccess.java --- /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. + * + *

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 attributes); + + /** + * Retrieves the attributes associated with a {@code PrivateKeyEntry}. + *

+ * + * @return an unmodifiable {@code Set} of attributes, possibly empty + * + * @since 1.8 + */ + Set getPrivateKeyEntryAttributes(PrivateKeyEntry entry); + + /** + * Constructs a {@code SecretKeyEntry} with a {@code SecretKey} and + * associated entry attributes. + * + *

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 attributes); + + /** + * Retrieves the attributes associated with a {@code SecretKeyEntry}. + *

+ * + * @return an unmodifiable {@code Set} of attributes, possibly empty + * + * @since 1.8 + */ + Set getSecretKeyEntryAttributes(SecretKeyEntry entry); + + /** + * Constructs a {@code TrustedCertificateEntry} with a + * trusted {@code Certificate} and associated entry attributes. + * + *

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 attributes); + + /** + * Retrieves the attributes associated with a {@code TrustedCertificateEntry}. + *

+ * + * @return an unmodifiable {@code Set} of attributes, possibly empty + * + * @since 1.8 + */ + Set getTrustedCertificateEntryAttributes(TrustedCertificateEntry entry); +} diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/misc/JavaUtilCalendarAccess.java --- /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 Epoch) 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); +} diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/misc/SharedSecrets.java --- 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; + } } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/net/ftp/impl/FtpClient.java --- 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() { 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; } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java --- 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; diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java --- 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); } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/rmi/transport/Target.java --- 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() { + @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() { - public Void run() { - t.setContextClassLoader(ccl); - return null; - } - }); + }, "Unreferenced-" + nextThreadNum++, false, true)); + // REMIND: access to nextThreadNum not synchronized; you care? t.start(); } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/action/GetPropertyAction.java --- 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 { +public class GetPropertyAction implements PrivilegedAction { 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)); + } + } } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/ec/ECKeyPairGenerator.java --- 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 diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/krb5/KdcComm.java --- 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; diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/krb5/KrbAsRep.java --- 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, diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/krb5/KrbTgsRep.java --- 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, diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/krb5/internal/NetClient.java --- 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()]; diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/pkcs/SignerInfo.java --- 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 DerEncoder 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 certList = new ArrayList(); + ArrayList 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 - * signatureTimestampToken attribute. If present, + * {@code signatureTimestampToken} attribute. If present, * then it is parsed to extract the date and time at which the * timestamp was generated. * diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/pkcs10/PKCS10.java --- 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 } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/pkcs11/P11KeyPairGenerator.java --- 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(); - } - try { - // This provider supports 64K or less. - RSAKeyFactory.checkKeyLengths(keySize, tmpExponent, - 512, 64 * 1024); - } catch (InvalidKeyException e) { - throw new InvalidAlgorithmParameterException(e.getMessage()); + } else { + // RSA, DH, DSA + if (keySize < 512) { + throw new InvalidAlgorithmParameterException + ("Key size must be at least 512 bit"); } - 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); } } - } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/pkcs12/PKCS12Attribute.java --- /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[])}. + *

+ * 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: + *

+     *
+     * Attribute ::= SEQUENCE {
+     *     type   AttributeType,
+     *     values SET OF AttributeValue
+     * }
+     * AttributeType ::= OBJECT IDENTIFIER
+     * AttributeValue ::= ANY defined by type
+     *
+     * 
+ * + * @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: + *
    + *
  • 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. + *
  • 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. + *
+ * 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); + } +} diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/pkcs12/PKCS12KeyStore.java --- 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 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 secret key + private static class SecretKeyEntry extends KeyEntry { + byte[] protectedSecretKey; }; - // A certificate with its PKCS #9 attributes - private static class CertEntry { + // 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 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 entries = - new Hashtable(); + private Map entries = + Collections.synchronizedMap(new LinkedHashMap()); private ArrayList keyList = new ArrayList(); private LinkedHashMap 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(); + + // 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 + ")"); + } - KeyFactory kfac = KeyFactory.getInstance(algName); - key = kfac.generatePrivate(kspec); + // 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 @@ * key entry 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 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 key entry, or on an attempt to create a - * trusted cert entry which is currently not supported. + * not identify a trusted certificate entry, 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 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 engineAliases() { - return entries.keys(); + return Collections.enumeration(entries.keySet()); } /** @@ -697,8 +967,8 @@ * key entry, 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 @@ * trusted certificate entry, 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 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 e = entries.keys(); e.hasMoreElements(); ) { + for (Enumeration 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 KeyStore.Entry for the specified alias + * with the specified protection parameter. + * + * @param alias get the KeyStore.Entry for this alias + * @param protParam the ProtectionParameter + * used to protect the Entry, + * which may be null + * + * @return the KeyStore.Entry for the specified alias, + * or null 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 + * protParam were insufficient or invalid + * @exception UnrecoverableKeyException if the entry is a + * PrivateKeyEntry or SecretKeyEntry + * and the specified protParam 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 KeyStore.Entry under the specified alias. + * The specified protection parameter is used to protect the + * Entry. + * + *

If an entry already exists for the specified alias, + * it is overridden. + * + * @param alias save the KeyStore.Entry under this alias + * @param entry the Entry to save + * @param protParam the ProtectionParameter + * used to protect the Entry, + * which may be null + * + * @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 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 attributes) throws IOException { + return getBagAttributes(alias, keyId, null, attributes); + } + + private byte[] getBagAttributes(String alias, byte[] keyId, + ObjectIdentifier[] trustedUsage, + Set 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 e = entries.keys(); e.hasMoreElements(); ) { + for (Enumeration 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 e = entries.keys(); e.hasMoreElements(); ) { + for (Enumeration 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; + + // DER encode the private key + if (keyEntry instanceof PrivateKeyEntry) { + // Create SafeBag of type pkcs8ShroudedKeyBag + safeBag.putOID(PKCS8ShroudedKeyBag_OID); - // Create SafeBag of type pkcs8ShroudedKeyBag - DerOutputStream safeBag = new DerOutputStream(); - safeBag.putOID(PKCS8ShroudedKeyBag_OID); + // 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); - // 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()); + // 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 chain = new ArrayList(); @@ -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 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)) { diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/DSAKeyPairGenerator.java --- 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 genParams - * 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 genParams + * 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); + } + } } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/DSAParameterGenerator.java --- 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) { diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/JavaKeyStore.java --- 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; diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/KeyStoreDelegator.java --- /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 primaryKeyStore; + // the primary keystore's class + private final Class 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 primaryKeyStore, + String secondaryType, + Class 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() { + 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 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 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"); + } + } + } +} diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/ParameterCache.java --- 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(); /* - * 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 diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/SunEntries.java --- 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"); diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/certpath/AdjacencyList.java --- 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> 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 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 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)); - - 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 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)); - } + 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 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; } /** @@ -248,23 +239,20 @@ * * @return String representation */ + @Override public String toString() { - String out = "[\n"; + StringBuilder sb = new StringBuilder("[\n"); int i = 0; for (List l : mOrigList) { - out = out + "LinkedList[" + i++ + "]:\n"; + sb.append("LinkedList[").append(i++).append("]:\n"); for (Vertex step : l) { - try { - out = out + step.toString(); - out = out + "\n"; - } - catch (Exception e) { out = out + "No Such Element\n"; } + sb.append(step.toString()).append("\n"); } } - out = out + "]\n"; + sb.append("]\n"); - return out; + return sb.toString(); } } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/certpath/AlgorithmChecker.java --- a/src/share/classes/sun/security/provider/certpath/AlgorithmChecker.java Thu Sep 07 23:37:21 2017 -0700 +++ b/src/share/classes/sun/security/provider/certpath/AlgorithmChecker.java Sat Feb 03 21:37:28 2018 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,8 +27,11 @@ import java.security.AlgorithmConstraints; import java.security.CryptoPrimitive; +import java.security.Timestamp; +import java.security.cert.CertPathValidator; import java.util.Collection; import java.util.Collections; +import java.util.Date; import java.util.Set; import java.util.EnumSet; import java.math.BigInteger; @@ -51,15 +54,16 @@ import java.security.spec.DSAPublicKeySpec; import sun.security.util.AnchorCertificates; -import sun.security.util.CertConstraintParameters; +import sun.security.util.ConstraintsParameters; import sun.security.util.Debug; import sun.security.util.DisabledAlgorithmConstraints; +import sun.security.validator.Validator; import sun.security.x509.X509CertImpl; import sun.security.x509.X509CRLImpl; import sun.security.x509.AlgorithmId; /** - * A PKIXCertPathChecker implementation to check whether a + * A {@code PKIXCertPathChecker} implementation to check whether a * specified certificate contains the required algorithm constraints. *

* Certificate fields such as the subject public key, the signature @@ -69,24 +73,27 @@ * @see PKIXCertPathChecker * @see PKIXParameters */ -final public class AlgorithmChecker extends PKIXCertPathChecker { +public final class AlgorithmChecker extends PKIXCertPathChecker { private static final Debug debug = Debug.getInstance("certpath"); private final AlgorithmConstraints constraints; private final PublicKey trustedPubKey; + private final Date pkixdate; private PublicKey prevPubKey; + private final Timestamp jarTimestamp; + private final String variant; - private final static Set SIGNATURE_PRIMITIVE_SET = + private static final Set SIGNATURE_PRIMITIVE_SET = Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE)); - private final static Set KU_PRIMITIVE_SET = + private static final Set KU_PRIMITIVE_SET = Collections.unmodifiableSet(EnumSet.of( CryptoPrimitive.SIGNATURE, CryptoPrimitive.KEY_ENCAPSULATION, CryptoPrimitive.PUBLIC_KEY_ENCRYPTION, CryptoPrimitive.KEY_AGREEMENT)); - private final static DisabledAlgorithmConstraints + private static final DisabledAlgorithmConstraints certPathDefaultConstraints = new DisabledAlgorithmConstraints( DisabledAlgorithmConstraints.PROPERTY_CERTPATH_DISABLED_ALGS); @@ -99,64 +106,99 @@ private boolean trustedMatch = false; /** - * Create a new AlgorithmChecker with the algorithm - * constraints specified in security property - * "jdk.certpath.disabledAlgorithms". + * Create a new {@code AlgorithmChecker} with the given algorithm + * given {@code TrustAnchor} and {@code String} variant. * * @param anchor the trust anchor selected to validate the target * certificate + * @param variant is the Validator variants of the operation. A null value + * passed will set it to Validator.GENERIC. */ - public AlgorithmChecker(TrustAnchor anchor) { - this(anchor, certPathDefaultConstraints); + public AlgorithmChecker(TrustAnchor anchor, String variant) { + this(anchor, certPathDefaultConstraints, null, null, variant); } /** - * Create a new AlgorithmChecker with the - * given {@code AlgorithmConstraints}. - *

- * Note that this constructor will be used to check a certification - * path where the trust anchor is unknown, or a certificate list which may - * contain the trust anchor. This constructor is used by SunJSSE. + * Create a new {@code AlgorithmChecker} with the given + * {@code AlgorithmConstraints}, {@code Timestamp}, and {@code String} + * variant. + * + * Note that this constructor can initialize a variation of situations where + * the AlgorithmConstraints, Timestamp, or Variant maybe known. * * @param constraints the algorithm constraints (or null) + * @param jarTimestamp Timestamp passed for JAR timestamp constraint + * checking. Set to null if not applicable. + * @param variant is the Validator variants of the operation. A null value + * passed will set it to Validator.GENERIC. */ - public AlgorithmChecker(AlgorithmConstraints constraints) { - this.prevPubKey = null; - this.trustedPubKey = null; - this.constraints = constraints; + public AlgorithmChecker(AlgorithmConstraints constraints, + Timestamp jarTimestamp, String variant) { + this(null, constraints, null, jarTimestamp, variant); } /** - * Create a new AlgorithmChecker with the - * given TrustAnchor and AlgorithmConstraints. + * Create a new {@code AlgorithmChecker} with the + * given {@code TrustAnchor}, {@code AlgorithmConstraints}, + * {@code Timestamp}, and {@code String} variant. * * @param anchor the trust anchor selected to validate the target * certificate * @param constraints the algorithm constraints (or null) - * - * @throws IllegalArgumentException if the anchor is null + * @param pkixdate The date specified by the PKIXParameters date. If the + * PKIXParameters is null, the current date is used. This + * should be null when jar files are being checked. + * @param jarTimestamp Timestamp passed for JAR timestamp constraint + * checking. Set to null if not applicable. + * @param variant is the Validator variants of the operation. A null value + * passed will set it to Validator.GENERIC. */ public AlgorithmChecker(TrustAnchor anchor, - AlgorithmConstraints constraints) { + AlgorithmConstraints constraints, Date pkixdate, + Timestamp jarTimestamp, String variant) { - if (anchor == null) { - throw new IllegalArgumentException( - "The trust anchor cannot be null"); + if (anchor != null) { + if (anchor.getTrustedCert() != null) { + this.trustedPubKey = anchor.getTrustedCert().getPublicKey(); + // Check for anchor certificate restrictions + trustedMatch = checkFingerprint(anchor.getTrustedCert()); + if (trustedMatch && debug != null) { + debug.println("trustedMatch = true"); + } + } else { + this.trustedPubKey = anchor.getCAPublicKey(); + } + } else { + this.trustedPubKey = null; + if (debug != null) { + debug.println("TrustAnchor is null, trustedMatch is false."); + } } - if (anchor.getTrustedCert() != null) { - this.trustedPubKey = anchor.getTrustedCert().getPublicKey(); - // Check for anchor certificate restrictions - trustedMatch = checkFingerprint(anchor.getTrustedCert()); - if (trustedMatch && debug != null) { - debug.println("trustedMatch = true"); - } - } else { - this.trustedPubKey = anchor.getCAPublicKey(); - } + this.prevPubKey = this.trustedPubKey; + this.constraints = (constraints == null ? certPathDefaultConstraints : + constraints); + // If we are checking jar files, set pkixdate the same as the timestamp + // for certificate checking + this.pkixdate = (jarTimestamp != null ? jarTimestamp.getTimestamp() : + pkixdate); + this.jarTimestamp = jarTimestamp; + this.variant = (variant == null ? Validator.VAR_GENERIC : variant); + } - this.prevPubKey = trustedPubKey; - this.constraints = constraints; + /** + * Create a new {@code AlgorithmChecker} with the given {@code TrustAnchor}, + * {@code PKIXParameter} date, and {@code varient} + * + * @param anchor the trust anchor selected to validate the target + * certificate + * @param pkixdate Date the constraints are checked against. The value is + * either the PKIXParameters date or null for the current date. + * @param variant is the Validator variants of the operation. A null value + * passed will set it to Validator.GENERIC. + */ + public AlgorithmChecker(TrustAnchor anchor, Date pkixdate, String variant) { + this(anchor, certPathDefaultConstraints, pkixdate, null, variant); } // Check this 'cert' for restrictions in the AnchorCertificates @@ -217,6 +259,28 @@ null, null, -1, PKIXReason.INVALID_KEY_USAGE); } + X509CertImpl x509Cert; + AlgorithmId algorithmId; + try { + x509Cert = X509CertImpl.toImpl((X509Certificate)cert); + algorithmId = (AlgorithmId)x509Cert.get(X509CertImpl.SIG_ALG); + } catch (CertificateException ce) { + throw new CertPathValidatorException(ce); + } + + AlgorithmParameters currSigAlgParams = algorithmId.getParameters(); + PublicKey currPubKey = cert.getPublicKey(); + String currSigAlg = x509Cert.getSigAlgName(); + + // Check the signature algorithm and parameters against constraints. + if (!constraints.permits(SIGNATURE_PRIMITIVE_SET, currSigAlg, + currSigAlgParams)) { + throw new CertPathValidatorException( + "Algorithm constraints check failed on signature " + + "algorithm: " + currSigAlg, null, null, -1, + BasicReason.ALGORITHM_CONSTRAINED); + } + // Assume all key usage bits are set if key usage is not present Set primitives = KU_PRIMITIVE_SET; @@ -253,102 +317,74 @@ } } - PublicKey currPubKey = cert.getPublicKey(); + ConstraintsParameters cp = + new ConstraintsParameters((X509Certificate)cert, + trustedMatch, pkixdate, jarTimestamp, variant); + // Check against local constraints if it is DisabledAlgorithmConstraints if (constraints instanceof DisabledAlgorithmConstraints) { - // Check against DisabledAlgorithmConstraints certpath constraints. - // permits() will throw exception on failure. - ((DisabledAlgorithmConstraints)constraints).permits(primitives, - new CertConstraintParameters((X509Certificate)cert, - trustedMatch)); - // If there is no previous key, set one and exit - if (prevPubKey == null) { - prevPubKey = currPubKey; - return; + ((DisabledAlgorithmConstraints)constraints).permits(currSigAlg, cp); + // DisabledAlgorithmsConstraints does not check primitives, so key + // additional key check. + + } else { + // Perform the default constraints checking anyway. + certPathDefaultConstraints.permits(currSigAlg, cp); + // Call locally set constraints to check key with primitives. + if (!constraints.permits(primitives, currPubKey)) { + throw new CertPathValidatorException( + "Algorithm constraints check failed on key " + + currPubKey.getAlgorithm() + " with size of " + + sun.security.util.KeyUtil.getKeySize(currPubKey) + + "bits", + null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); } } - X509CertImpl x509Cert; - AlgorithmId algorithmId; - try { - x509Cert = X509CertImpl.toImpl((X509Certificate)cert); - algorithmId = (AlgorithmId)x509Cert.get(X509CertImpl.SIG_ALG); - } catch (CertificateException ce) { - throw new CertPathValidatorException(ce); - } - - AlgorithmParameters currSigAlgParams = algorithmId.getParameters(); - String currSigAlg = x509Cert.getSigAlgName(); - - // If 'constraints' is not of DisabledAlgorithmConstraints, check all - // everything individually - if (!(constraints instanceof DisabledAlgorithmConstraints)) { - // Check the current signature algorithm - if (!constraints.permits( - SIGNATURE_PRIMITIVE_SET, - currSigAlg, currSigAlgParams)) { - throw new CertPathValidatorException( - "Algorithm constraints check failed on signature " + - "algorithm: " + currSigAlg, null, null, -1, - BasicReason.ALGORITHM_CONSTRAINED); - } - - if (!constraints.permits(primitives, currPubKey)) { - throw new CertPathValidatorException( - "Algorithm constraints check failed on keysize: " + - sun.security.util.KeyUtil.getKeySize(currPubKey), - null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); - } + // If there is no previous key, set one and exit + if (prevPubKey == null) { + prevPubKey = currPubKey; + return; } // Check with previous cert for signature algorithm and public key - if (prevPubKey != null) { - if (!constraints.permits( - SIGNATURE_PRIMITIVE_SET, - currSigAlg, prevPubKey, currSigAlgParams)) { - throw new CertPathValidatorException( + if (!constraints.permits( + SIGNATURE_PRIMITIVE_SET, + currSigAlg, prevPubKey, currSigAlgParams)) { + throw new CertPathValidatorException( "Algorithm constraints check failed on " + "signature algorithm: " + currSigAlg, - null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); - } + null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); + } - // Inherit key parameters from previous key - if (currPubKey instanceof DSAPublicKey && - ((DSAPublicKey)currPubKey).getParams() == null) { - // Inherit DSA parameters from previous key - if (!(prevPubKey instanceof DSAPublicKey)) { - throw new CertPathValidatorException("Input key is not " + + // Inherit key parameters from previous key + if (PKIX.isDSAPublicKeyWithoutParams(currPubKey)) { + // Inherit DSA parameters from previous key + if (!(prevPubKey instanceof DSAPublicKey)) { + throw new CertPathValidatorException("Input key is not " + "of a appropriate type for inheriting parameters"); - } + } - DSAParams params = ((DSAPublicKey)prevPubKey).getParams(); - if (params == null) { - throw new CertPathValidatorException( + DSAParams params = ((DSAPublicKey)prevPubKey).getParams(); + if (params == null) { + throw new CertPathValidatorException( "Key parameters missing from public key."); - } + } - try { - BigInteger y = ((DSAPublicKey)currPubKey).getY(); - KeyFactory kf = KeyFactory.getInstance("DSA"); - DSAPublicKeySpec ks = new DSAPublicKeySpec(y, - params.getP(), - params.getQ(), - params.getG()); - currPubKey = kf.generatePublic(ks); - } catch (GeneralSecurityException e) { - throw new CertPathValidatorException("Unable to generate " + + try { + BigInteger y = ((DSAPublicKey)currPubKey).getY(); + KeyFactory kf = KeyFactory.getInstance("DSA"); + DSAPublicKeySpec ks = new DSAPublicKeySpec(y, params.getP(), + params.getQ(), params.getG()); + currPubKey = kf.generatePublic(ks); + } catch (GeneralSecurityException e) { + throw new CertPathValidatorException("Unable to generate " + "key with inherited parameters: " + e.getMessage(), e); - } } } // reset the previous public key prevPubKey = currPubKey; - - // check the extended key usage, ignore the check now - // List extendedKeyUsages = x509Cert.getExtendedKeyUsage(); - - // DO NOT remove any unresolved critical extensions } /** @@ -388,8 +424,10 @@ * * @param key the public key to verify the CRL signature * @param crl the target CRL + * @param variant is the Validator variants of the operation. A null value + * passed will set it to Validator.GENERIC. */ - static void check(PublicKey key, X509CRL crl) + static void check(PublicKey key, X509CRL crl, String variant) throws CertPathValidatorException { X509CRLImpl x509CRLImpl = null; @@ -400,28 +438,23 @@ } AlgorithmId algorithmId = x509CRLImpl.getSigAlgId(); - check(key, algorithmId); + check(key, algorithmId, variant); } /** * Check the signature algorithm with the specified public key. * * @param key the public key to verify the CRL signature - * @param crl the target CRL + * @param algorithmId signature algorithm Algorithm ID + * @param variant is the Validator variants of the operation. A null value + * passed will set it to Validator.GENERIC. */ - static void check(PublicKey key, AlgorithmId algorithmId) + static void check(PublicKey key, AlgorithmId algorithmId, String variant) throws CertPathValidatorException { String sigAlgName = algorithmId.getName(); AlgorithmParameters sigAlgParams = algorithmId.getParameters(); - if (!certPathDefaultConstraints.permits( - SIGNATURE_PRIMITIVE_SET, sigAlgName, key, sigAlgParams)) { - throw new CertPathValidatorException( - "Algorithm constraints check failed on signature algorithm: " + - sigAlgName + " is disabled", - null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); - } + certPathDefaultConstraints.permits(new ConstraintsParameters( + sigAlgName, sigAlgParams, key, variant)); } - } - diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/certpath/BasicChecker.java --- a/src/share/classes/sun/security/provider/certpath/BasicChecker.java Thu Sep 07 23:37:21 2017 -0700 +++ b/src/share/classes/sun/security/provider/certpath/BasicChecker.java Sat Feb 03 21:37:28 2018 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2008, 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 @@ -51,7 +51,7 @@ /** * BasicChecker is a PKIXCertPathChecker that checks the basic information - * on a PKIX certificate, namely the signature, timestamp, and subject/issuer + * on a PKIX certificate, namely the signature, validity, and subject/issuer * name chaining. * * @since 1.4 @@ -62,7 +62,7 @@ private static final Debug debug = Debug.getInstance("certpath"); private final PublicKey trustedPubKey; private final X500Principal caName; - private final Date testDate; + private final Date date; private final String sigProvider; private final boolean sigOnly; private X500Principal prevSubject; @@ -73,14 +73,13 @@ * * @param anchor the anchor selected to validate the target certificate * @param testDate the time for which the validity of the certificate - * should be determined + * should be determined * @param sigProvider the name of the signature provider * @param sigOnly true if only signature checking is to be done; * if false, all checks are done */ - BasicChecker(TrustAnchor anchor, Date testDate, String sigProvider, - boolean sigOnly) throws CertPathValidatorException - { + BasicChecker(TrustAnchor anchor, Date date, String sigProvider, + boolean sigOnly) { if (anchor.getTrustedCert() != null) { this.trustedPubKey = anchor.getTrustedCert().getPublicKey(); this.caName = anchor.getTrustedCert().getSubjectX500Principal(); @@ -88,10 +87,9 @@ this.trustedPubKey = anchor.getCAPublicKey(); this.caName = anchor.getCA(); } - this.testDate = testDate; + this.date = date; this.sigProvider = sigProvider; this.sigOnly = sigOnly; - init(false); } /** @@ -117,40 +115,37 @@ } /** - * Performs the signature, timestamp, and subject/issuer name chaining + * Performs the signature, validity, and subject/issuer name chaining * checks on the certificate using its internal state. This method does * not remove any critical extensions from the Collection. * * @param cert the Certificate * @param unresolvedCritExts a Collection of the unresolved critical * extensions - * @exception CertPathValidatorException Exception thrown if certificate - * does not verify. + * @throws CertPathValidatorException if certificate does not verify */ public void check(Certificate cert, Collection unresolvedCritExts) throws CertPathValidatorException { - X509Certificate currCert = (X509Certificate) cert; + X509Certificate currCert = (X509Certificate)cert; if (!sigOnly) { - verifyTimestamp(currCert, testDate); - verifyNameChaining(currCert, prevSubject); + verifyValidity(currCert); + verifyNameChaining(currCert); } - verifySignature(currCert, prevPubKey, sigProvider); + verifySignature(currCert); updateState(currCert); } /** - * Verifies the signature on the certificate using the previous public key - * @param cert the Certificate - * @param prevPubKey the previous PublicKey - * @param sigProvider a String containing the signature provider - * @exception CertPathValidatorException Exception thrown if certificate - * does not verify. + * Verifies the signature on the certificate using the previous public key. + * + * @param cert the X509Certificate + * @throws CertPathValidatorException if certificate does not verify */ - private void verifySignature(X509Certificate cert, PublicKey prevPubKey, - String sigProvider) throws CertPathValidatorException + private void verifySignature(X509Certificate cert) + throws CertPathValidatorException { String msg = "signature"; if (debug != null) @@ -162,7 +157,7 @@ throw new CertPathValidatorException (msg + " check failed", e, null, -1, BasicReason.INVALID_SIGNATURE); - } catch (Exception e) { + } catch (GeneralSecurityException e) { throw new CertPathValidatorException(msg + " check failed", e); } @@ -171,12 +166,12 @@ } /** - * Internal method to verify the timestamp on a certificate + * Internal method to verify the validity on a certificate */ - private void verifyTimestamp(X509Certificate cert, Date date) + private void verifyValidity(X509Certificate cert) throws CertPathValidatorException { - String msg = "timestamp"; + String msg = "validity"; if (debug != null) debug.println("---checking " + msg + ":" + date.toString() + "..."); @@ -197,8 +192,8 @@ /** * Internal method to check that cert has a valid DN to be next in a chain */ - private void verifyNameChaining(X509Certificate cert, - X500Principal prevSubject) throws CertPathValidatorException + private void verifyNameChaining(X509Certificate cert) + throws CertPathValidatorException { if (prevSubject != null) { @@ -207,8 +202,8 @@ debug.println("---checking " + msg + "..."); X500Principal currIssuer = cert.getIssuerX500Principal(); + // reject null or empty issuer DNs - if (X500Name.asX500Name(currIssuer).isEmpty()) { throw new CertPathValidatorException (msg + " check failed: " + @@ -240,8 +235,7 @@ currCert.getSubjectX500Principal() + "; serial#: " + currCert.getSerialNumber().toString()); } - if (cKey instanceof DSAPublicKey && - ((DSAPublicKey)cKey).getParams() == null) { + if (PKIX.isDSAPublicKeyWithoutParams(cKey)) { //cKey needs to inherit DSA parameters from prev key cKey = makeInheritedParamsKey(cKey, prevPubKey); if (debug != null) debug.println("BasicChecker.updateState Made " + diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/certpath/BuildStep.java --- a/src/share/classes/sun/security/provider/certpath/BuildStep.java Thu Sep 07 23:37:21 2017 -0700 +++ b/src/share/classes/sun/security/provider/certpath/BuildStep.java Sat Feb 03 21:37:28 2018 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2005, 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 @@ -25,7 +25,6 @@ package sun.security.provider.certpath; -import sun.security.util.Debug; import java.security.cert.X509Certificate; /** @@ -39,7 +38,6 @@ */ public class BuildStep { - private static final Debug debug = Debug.getInstance("certpath"); private Vertex vertex; private X509Certificate cert; private Throwable throwable; @@ -86,7 +84,7 @@ public BuildStep(Vertex vtx, int res) { vertex = vtx; if (vertex != null) { - cert = (X509Certificate)vertex.getCertificate(); + cert = vertex.getCertificate(); throwable = vertex.getThrowable(); } result = res; @@ -117,7 +115,7 @@ * @returns String form of issuer name or null, if no certificate. */ public String getIssuerName() { - return (cert == null ? null : cert.getIssuerX500Principal().toString()); + return getIssuerName(null); } /** @@ -142,7 +140,7 @@ * @returns String form of subject name or null, if no certificate. */ public String getSubjectName() { - return (cert == null ? null : cert.getSubjectX500Principal().toString()); + return getSubjectName(null); } /** @@ -191,21 +189,21 @@ public String resultToString(int res) { String resultString = ""; switch (res) { - case BuildStep.POSSIBLE: + case POSSIBLE: resultString = "Certificate to be tried.\n"; break; - case BuildStep.BACK: + case BACK: resultString = "Certificate backed out since path does not " + "satisfy build requirements.\n"; break; - case BuildStep.FOLLOW: + case FOLLOW: resultString = "Certificate satisfies conditions.\n"; break; - case BuildStep.FAIL: + case FAIL: resultString = "Certificate backed out since path does not " + "satisfy conditions.\n"; break; - case BuildStep.SUCCEED: + case SUCCEED: resultString = "Certificate satisfies conditions.\n"; break; default: @@ -220,6 +218,7 @@ * * @returns String */ + @Override public String toString() { String out = "Internal Error\n"; switch (result) { @@ -273,8 +272,6 @@ * @returns String */ public String fullToString() { - String out = resultToString(getResult()); - out = out + vertex.toString(); - return out; + return resultToString(getResult()) + vertex.toString(); } } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/certpath/Builder.java --- a/src/share/classes/sun/security/provider/certpath/Builder.java Thu Sep 07 23:37:21 2017 -0700 +++ b/src/share/classes/sun/security/provider/certpath/Builder.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, 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 @@ -31,9 +31,8 @@ import java.security.cert.*; import java.util.*; -import javax.security.auth.x500.X500Principal; - import sun.security.action.GetBooleanAction; +import sun.security.provider.certpath.PKIX.BuilderParams; import sun.security.util.Debug; import sun.security.x509.GeneralNames; import sun.security.x509.GeneralNameInterface; @@ -56,9 +55,7 @@ private static final Debug debug = Debug.getInstance("certpath"); private Set matchingPolicies; - final PKIXBuilderParameters buildParams; - final X500Principal targetSubjectDN; - final Date date; + final BuilderParams buildParams; final X509CertSelector targetCertConstraints; /** @@ -74,14 +71,10 @@ * * @param params the parameter set used to build a certification path */ - Builder(PKIXBuilderParameters buildParams, X500Principal targetSubjectDN) { + Builder(BuilderParams buildParams) { this.buildParams = buildParams; - this.targetSubjectDN = targetSubjectDN; - // Initialize date if not specified - Date paramsDate = buildParams.getDate(); - this.date = paramsDate != null ? paramsDate : new Date(); this.targetCertConstraints = - (X509CertSelector) buildParams.getTargetCertConstraints(); + (X509CertSelector)buildParams.targetCertConstraints(); } /** @@ -104,7 +97,8 @@ * @param certPathList the certPathList generated thus far */ abstract void verifyCert(X509Certificate cert, State currentState, - List certPathList) throws GeneralSecurityException; + List certPathList) + throws GeneralSecurityException; /** * Verifies whether the input certificate completes the path. @@ -123,7 +117,7 @@ * @param certPathList the certification path list */ abstract void addCertToPath(X509Certificate cert, - LinkedList certPathList); + LinkedList certPathList); /** * Removes final certificate from the certPathList @@ -147,7 +141,8 @@ * is a grandparent, etc. */ static int distance(GeneralNameInterface base, - GeneralNameInterface test, int incomparable) { + GeneralNameInterface test, int incomparable) + { switch (base.constrains(test)) { case GeneralNameInterface.NAME_DIFF_TYPE: if (debug != null) { @@ -192,7 +187,8 @@ * some number of down hops. */ static int hops(GeneralNameInterface base, GeneralNameInterface test, - int incomparable) { + int incomparable) + { int baseRtest = base.constrains(test); switch (baseRtest) { case GeneralNameInterface.NAME_DIFF_TYPE: @@ -282,9 +278,9 @@ * @throws IOException if certificate does not get closer */ static int targetDistance(NameConstraintsExtension constraints, - X509Certificate cert, GeneralNameInterface target) - throws IOException { - + X509Certificate cert, GeneralNameInterface target) + throws IOException + { /* ensure that certificate satisfies existing name constraints */ if (constraints != null && !constraints.verify(cert)) { throw new IOException("certificate does not satisfy existing name " @@ -295,7 +291,7 @@ try { certImpl = X509CertImpl.toImpl(cert); } catch (CertificateException e) { - throw (IOException)new IOException("Invalid certificate").initCause(e); + throw new IOException("Invalid certificate", e); } /* see if certificate subject matches target */ X500Name subject = X500Name.asX500Name(certImpl.getSubjectX500Principal()); @@ -398,13 +394,13 @@ */ Set getMatchingPolicies() { if (matchingPolicies != null) { - Set initialPolicies = buildParams.getInitialPolicies(); + Set initialPolicies = buildParams.initialPolicies(); if ((!initialPolicies.isEmpty()) && (!initialPolicies.contains(PolicyChecker.ANY_POLICY)) && - (buildParams.isPolicyMappingInhibited())) + (buildParams.policyMappingInhibited())) { - initialPolicies.add(PolicyChecker.ANY_POLICY); - matchingPolicies = initialPolicies; + matchingPolicies = new HashSet<>(initialPolicies); + matchingPolicies.add(PolicyChecker.ANY_POLICY); } else { // we just return an empty set to make sure that there is // at least a certificate policies extension in the cert @@ -429,13 +425,15 @@ * Returns true iff resultCerts changed (a cert was added to the collection) */ boolean addMatchingCerts(X509CertSelector selector, - Collection certStores, - Collection resultCerts, boolean checkAll) { + Collection certStores, + Collection resultCerts, + boolean checkAll) + { X509Certificate targetCert = selector.getCertificate(); if (targetCert != null) { // no need to search CertStores if (selector.match(targetCert) && !X509CertImpl.isSelfSigned - (targetCert, buildParams.getSigProvider())) { + (targetCert, buildParams.sigProvider())) { if (debug != null) { debug.println("Builder.addMatchingCerts: adding target cert"); } @@ -450,7 +448,7 @@ store.getCertificates(selector); for (Certificate cert : certs) { if (!X509CertImpl.isSelfSigned - ((X509Certificate)cert, buildParams.getSigProvider())) { + ((X509Certificate)cert, buildParams.sigProvider())) { if (resultCerts.add((X509Certificate)cert)) { add = true; } @@ -471,16 +469,4 @@ } return add; } - - /** - * Returns true if CertStore is local. Currently, returns true if - * type is Collection or if it has been initialized with - * CollectionCertStoreParameters. A new API method should be added - * to CertStore that returns local or remote. - */ - static boolean isLocalCertStore(CertStore certStore) { - return (certStore.getType().equals("Collection") || - certStore.getCertStoreParameters() instanceof - CollectionCertStoreParameters); - } } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/certpath/CertId.java --- a/src/share/classes/sun/security/provider/certpath/CertId.java Thu Sep 07 23:37:21 2017 -0700 +++ b/src/share/classes/sun/security/provider/certpath/CertId.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, 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 @@ -29,8 +29,10 @@ import java.math.BigInteger; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; import java.security.cert.X509Certificate; import java.util.Arrays; +import javax.security.auth.x500.X500Principal; import sun.misc.HexDumpEncoder; import sun.security.x509.*; import sun.security.util.*; @@ -70,6 +72,13 @@ public CertId(X509Certificate issuerCert, SerialNumber serialNumber) throws IOException { + this(issuerCert.getSubjectX500Principal(), + issuerCert.getPublicKey(), serialNumber); + } + + public CertId(X500Principal issuerName, PublicKey issuerKey, + SerialNumber serialNumber) throws IOException { + // compute issuerNameHash MessageDigest md = null; try { @@ -78,11 +87,11 @@ throw new IOException("Unable to create CertId", nsae); } hashAlgId = SHA1_ALGID; - md.update(issuerCert.getSubjectX500Principal().getEncoded()); + md.update(issuerName.getEncoded()); issuerNameHash = md.digest(); // compute issuerKeyHash (remove the tag and length) - byte[] pubKey = issuerCert.getPublicKey().getEncoded(); + byte[] pubKey = issuerKey.getEncoded(); DerValue val = new DerValue(pubKey); DerValue[] seq = new DerValue[2]; seq[0] = val.data.getDerValue(); // AlgorithmID @@ -94,7 +103,7 @@ if (debug) { HexDumpEncoder encoder = new HexDumpEncoder(); - System.out.println("Issuer Certificate is " + issuerCert); + System.out.println("Issuer Name is " + issuerName); System.out.println("issuerNameHash is " + encoder.encodeBuffer(issuerNameHash)); System.out.println("issuerKeyHash is " + diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/certpath/CertPathChecker.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/sun/security/provider/certpath/CertPathChecker.java Sat Feb 03 21:37:28 2018 -0800 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 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 + * 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.certpath; + +import java.security.cert.Certificate; +import java.security.cert.CertPathValidatorException; + +/** + *

Performs one or more checks on each {@code Certificate} of a + * {@code CertPath}. + * + *

A {@code CertPathChecker} implementation is typically created to extend + * a certification path validation algorithm. For example, an implementation + * may check for and process a critical private extension of each certificate + * in a certification path. + * + * @since 1.8 + */ +public interface CertPathChecker { + + /** + * Initializes the internal state of this {@code CertPathChecker}. + * + *

The {@code forward} flag specifies the order that certificates will + * be passed to the {@link #check check} method (forward or reverse). + * + * @param forward the order that certificates are presented to the + * {@code check} method. If {@code true}, certificates are + * presented from target to trust anchor (forward); if + * {@code false}, from trust anchor to target (reverse). + * @throws CertPathValidatorException if this {@code CertPathChecker} is + * unable to check certificates in the specified order + */ + void init(boolean forward) throws CertPathValidatorException; + + /** + * Indicates if forward checking is supported. Forward checking refers + * to the ability of the {@code CertPathChecker} to perform its checks + * when certificates are presented to the {@code check} method in the + * forward direction (from target to trust anchor). + * + * @return {@code true} if forward checking is supported, {@code false} + * otherwise + */ + boolean isForwardCheckingSupported(); + + /** + * Performs the check(s) on the specified certificate using its internal + * state. The certificates are presented in the order specified by the + * {@code init} method. + * + * @param cert the {@code Certificate} to be checked + * @throws CertPathValidatorException if the specified certificate does + * not pass the check + */ + void check(Certificate cert) throws CertPathValidatorException; +} diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/certpath/CertStoreHelper.java --- a/src/share/classes/sun/security/provider/certpath/CertStoreHelper.java Thu Sep 07 23:37:21 2017 -0700 +++ b/src/share/classes/sun/security/provider/certpath/CertStoreHelper.java Sat Feb 03 21:37:28 2018 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 @@ -35,6 +35,7 @@ import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.security.cert.CertStore; +import java.security.cert.CertStoreException; import java.security.cert.X509CertSelector; import java.security.cert.X509CRLSelector; import javax.security.auth.x500.X500Principal; @@ -82,9 +83,8 @@ = (CertStoreHelper)c.newInstance(); cache.put(type, csh); return csh; - } catch (InstantiationException e) { - throw new AssertionError(e); - } catch (IllegalAccessException e) { + } catch (InstantiationException | + IllegalAccessException e) { throw new AssertionError(e); } } @@ -96,6 +96,25 @@ } } + static boolean isCausedByNetworkIssue(String type, CertStoreException cse) { + switch (type) { + case "LDAP": + case "SSLServer": + try { + CertStoreHelper csh = CertStoreHelper.getInstance(type); + return csh.isCausedByNetworkIssue(cse); + } catch (NoSuchAlgorithmException nsae) { + return false; + } + case "URI": + Throwable t = cse.getCause(); + return (t != null && t instanceof IOException); + default: + // we don't know about any other remote CertStore types + return false; + } + } + /** * Returns a CertStore using the given URI as parameters. */ @@ -119,4 +138,10 @@ Collection certIssuers, String dn) throws IOException; + + /** + * Returns true if the cause of the CertStoreException is a network + * related issue. + */ + public abstract boolean isCausedByNetworkIssue(CertStoreException e); } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/certpath/CollectionCertStore.java --- a/src/share/classes/sun/security/provider/certpath/CollectionCertStore.java Thu Sep 07 23:37:21 2017 -0700 +++ b/src/share/classes/sun/security/provider/certpath/CollectionCertStore.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 @@ -31,7 +31,6 @@ import java.util.Collection; import java.util.ConcurrentModificationException; import java.util.HashSet; -import java.util.Iterator; import java.security.cert.CertSelector; import java.security.cert.CertStore; import java.security.cert.CertStoreException; @@ -114,6 +113,7 @@ * match the specified selector * @throws CertStoreException if an exception occurs */ + @Override public Collection engineGetCertificates (CertSelector selector) throws CertStoreException { if (coll == null) { @@ -122,18 +122,15 @@ // Tolerate a few ConcurrentModificationExceptions for (int c = 0; c < 10; c++) { try { - HashSet result = new HashSet(); - Iterator i = coll.iterator(); + HashSet result = new HashSet<>(); if (selector != null) { - while (i.hasNext()) { - Object o = i.next(); + for (Object o : coll) { if ((o instanceof Certificate) && selector.match((Certificate) o)) result.add((Certificate)o); } } else { - while (i.hasNext()) { - Object o = i.next(); + for (Object o : coll) { if (o instanceof Certificate) result.add((Certificate)o); } @@ -157,6 +154,7 @@ * match the specified selector * @throws CertStoreException if an exception occurs */ + @Override public Collection engineGetCRLs(CRLSelector selector) throws CertStoreException { @@ -166,22 +164,19 @@ // Tolerate a few ConcurrentModificationExceptions for (int c = 0; c < 10; c++) { try { - HashSet result = new HashSet(); - Iterator i = coll.iterator(); + HashSet result = new HashSet<>(); if (selector != null) { - while (i.hasNext()) { - Object o = i.next(); + for (Object o : coll) { if ((o instanceof CRL) && selector.match((CRL) o)) result.add((CRL)o); } } else { - while (i.hasNext()) { - Object o = i.next(); + for (Object o : coll) { if (o instanceof CRL) result.add((CRL)o); } } - return(result); + return result; } catch (ConcurrentModificationException e) { } } throw new ConcurrentModificationException("Too many " diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/certpath/ConstraintsChecker.java --- a/src/share/classes/sun/security/provider/certpath/ConstraintsChecker.java Thu Sep 07 23:37:21 2017 -0700 +++ b/src/share/classes/sun/security/provider/certpath/ConstraintsChecker.java Sat Feb 03 21:37:28 2018 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2008, 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 @@ -25,19 +25,20 @@ package sun.security.provider.certpath; -import java.util.Collection; -import java.util.Collections; -import java.util.Set; -import java.util.HashSet; import java.io.IOException; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.CertPathValidatorException; -import java.security.cert.X509Certificate; import java.security.cert.PKIXCertPathChecker; import java.security.cert.PKIXReason; +import java.security.cert.X509Certificate; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + import sun.security.util.Debug; -import sun.security.x509.PKIXExtensions; +import static sun.security.x509.PKIXExtensions.*; import sun.security.x509.NameConstraintsExtension; import sun.security.x509.X509CertImpl; @@ -66,13 +67,12 @@ * Creates a ConstraintsChecker. * * @param certPathLength the length of the certification path - * @throws CertPathValidatorException if the checker cannot be initialized */ - ConstraintsChecker(int certPathLength) throws CertPathValidatorException { + ConstraintsChecker(int certPathLength) { this.certPathLength = certPathLength; - init(false); } + @Override public void init(boolean forward) throws CertPathValidatorException { if (!forward) { i = 0; @@ -84,15 +84,17 @@ } } + @Override public boolean isForwardCheckingSupported() { return false; } + @Override public Set getSupportedExtensions() { if (supportedExts == null) { - supportedExts = new HashSet(); - supportedExts.add(PKIXExtensions.BasicConstraints_Id.toString()); - supportedExts.add(PKIXExtensions.NameConstraints_Id.toString()); + supportedExts = new HashSet(2); + supportedExts.add(BasicConstraints_Id.toString()); + supportedExts.add(NameConstraints_Id.toString()); supportedExts = Collections.unmodifiableSet(supportedExts); } return supportedExts; @@ -104,14 +106,15 @@ * * @param cert the Certificate to be checked * @param unresCritExts a Collection of OID strings - * representing the current set of unresolved critical extensions + * representing the current set of unresolved critical extensions * @throws CertPathValidatorException if the specified certificate - * does not pass the check + * does not pass the check */ + @Override public void check(Certificate cert, Collection unresCritExts) throws CertPathValidatorException { - X509Certificate currCert = (X509Certificate) cert; + X509Certificate currCert = (X509Certificate)cert; i++; // MUST run NC check second, since it depends on BC check to @@ -120,8 +123,8 @@ verifyNameConstraints(currCert); if (unresCritExts != null && !unresCritExts.isEmpty()) { - unresCritExts.remove(PKIXExtensions.BasicConstraints_Id.toString()); - unresCritExts.remove(PKIXExtensions.NameConstraints_Id.toString()); + unresCritExts.remove(BasicConstraints_Id.toString()); + unresCritExts.remove(NameConstraints_Id.toString()); } } @@ -166,9 +169,9 @@ /** * Helper to fold sets of name constraints together */ - static NameConstraintsExtension - mergeNameConstraints(X509Certificate currCert, - NameConstraintsExtension prevNC) throws CertPathValidatorException + static NameConstraintsExtension mergeNameConstraints( + X509Certificate currCert, NameConstraintsExtension prevNC) + throws CertPathValidatorException { X509CertImpl currCertImpl; try { @@ -197,7 +200,7 @@ // Make sure we do a clone here, because we're probably // going to modify this object later and we don't want to // be sharing it with a Certificate object! - return (NameConstraintsExtension) newConstraints.clone(); + return (NameConstraintsExtension)newConstraints.clone(); } } else { try { diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/certpath/CrlRevocationChecker.java --- a/src/share/classes/sun/security/provider/certpath/CrlRevocationChecker.java Thu Sep 07 23:37:21 2017 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,800 +0,0 @@ -/* - * Copyright (c) 2000, 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.provider.certpath; - -import java.math.BigInteger; -import java.util.Arrays; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import java.util.HashSet; -import java.util.Set; -import java.util.Iterator; -import java.security.InvalidAlgorithmParameterException; -import java.security.NoSuchAlgorithmException; -import java.security.PublicKey; -import java.security.cert.Certificate; -import java.security.cert.CertificateException; -import java.security.cert.CertificateRevokedException; -import java.security.cert.CertPathBuilder; -import java.security.cert.CertPathBuilderException; -import java.security.cert.CertPathValidatorException; -import java.security.cert.CertPathValidatorException.BasicReason; -import java.security.cert.CertStore; -import java.security.cert.CollectionCertStoreParameters; -import java.security.cert.CRLException; -import java.security.cert.CRLReason; -import java.security.cert.PKIXBuilderParameters; -import java.security.cert.PKIXCertPathBuilderResult; -import java.security.cert.PKIXCertPathChecker; -import java.security.cert.PKIXParameters; -import java.security.cert.TrustAnchor; -import java.security.cert.X509Certificate; -import java.security.cert.X509CertSelector; -import java.security.cert.X509CRL; -import java.security.cert.X509CRLEntry; -import java.security.cert.X509CRLSelector; -import java.security.interfaces.DSAPublicKey; -import sun.security.util.Debug; -import sun.security.x509.AccessDescription; -import sun.security.x509.AuthorityInfoAccessExtension; -import sun.security.x509.CRLDistributionPointsExtension; -import sun.security.x509.DistributionPoint; -import sun.security.x509.GeneralName; -import sun.security.x509.GeneralNames; -import sun.security.x509.PKIXExtensions; -import sun.security.x509.X500Name; -import sun.security.x509.X509CertImpl; -import sun.security.x509.X509CRLEntryImpl; - -/** - * CrlRevocationChecker is a PKIXCertPathChecker that checks - * revocation status information on a PKIX certificate using CRLs obtained - * from one or more CertStores. This is based on section 6.3 - * of RFC 3280 (http://www.ietf.org/rfc/rfc3280.txt). - * - * @since 1.4 - * @author Seth Proctor - * @author Steve Hanna - */ -class CrlRevocationChecker extends PKIXCertPathChecker { - - private static final Debug debug = Debug.getInstance("certpath"); - private final TrustAnchor mAnchor; - private final List mStores; - private final String mSigProvider; - private final Date mCurrentTime; - private PublicKey mPrevPubKey; - private boolean mCRLSignFlag; - private HashSet mPossibleCRLs; - private HashSet mApprovedCRLs; - private final PKIXParameters mParams; - private static final boolean [] mCrlSignUsage = - { false, false, false, false, false, false, true }; - private static final boolean[] ALL_REASONS = - {true, true, true, true, true, true, true, true, true}; - private boolean mOnlyEECert = false; - - // Maximum clock skew in milliseconds (15 minutes) allowed when checking - // validity of CRLs - private static final long MAX_CLOCK_SKEW = 900000; - - /** - * Creates a CrlRevocationChecker. - * - * @param anchor anchor selected to validate the target certificate - * @param params PKIXParameters to be used for - * finding certificates and CRLs, etc. - */ - CrlRevocationChecker(TrustAnchor anchor, PKIXParameters params) - throws CertPathValidatorException - { - this(anchor, params, null); - } - - /** - * Creates a CrlRevocationChecker, allowing - * extra certificates to be supplied beyond those contained - * in the PKIXParameters. - * - * @param anchor anchor selected to validate the target certificate - * @param params PKIXParameters to be used for - * finding certificates and CRLs, etc. - * @param certs a Collection of certificates - * that may be useful, beyond those available - * through params (null - * if none) - */ - CrlRevocationChecker(TrustAnchor anchor, PKIXParameters params, - Collection certs) throws CertPathValidatorException - { - this(anchor, params, certs, false); - } - - CrlRevocationChecker(TrustAnchor anchor, PKIXParameters params, - Collection certs, boolean onlyEECert) - throws CertPathValidatorException { - mAnchor = anchor; - mParams = params; - mStores = new ArrayList(params.getCertStores()); - mSigProvider = params.getSigProvider(); - if (certs != null) { - try { - mStores.add(CertStore.getInstance("Collection", - new CollectionCertStoreParameters(certs))); - } catch (Exception e) { - // should never occur but not necessarily fatal, so log it, - // ignore and continue - if (debug != null) { - debug.println("CrlRevocationChecker: " + - "error creating Collection CertStore: " + e); - } - } - } - Date testDate = params.getDate(); - mCurrentTime = (testDate != null ? testDate : new Date()); - mOnlyEECert = onlyEECert; - init(false); - } - - /** - * Initializes the internal state of the checker from parameters - * specified in the constructor - */ - public void init(boolean forward) throws CertPathValidatorException - { - if (!forward) { - if (mAnchor != null) { - if (mAnchor.getCAPublicKey() != null) { - mPrevPubKey = mAnchor.getCAPublicKey(); - } else { - mPrevPubKey = mAnchor.getTrustedCert().getPublicKey(); - } - } else { - mPrevPubKey = null; - } - mCRLSignFlag = true; - } else { - throw new CertPathValidatorException("forward checking " - + "not supported"); - } - } - - public boolean isForwardCheckingSupported() { - return false; - } - - public Set getSupportedExtensions() { - return null; - } - - /** - * Performs the revocation status check on the certificate using - * its internal state. - * - * @param cert the Certificate - * @param unresolvedCritExts a Collection of the unresolved critical - * extensions - * @exception CertPathValidatorException Exception thrown if - * certificate does not verify - */ - public void check(Certificate cert, Collection unresolvedCritExts) - throws CertPathValidatorException - { - X509Certificate currCert = (X509Certificate) cert; - verifyRevocationStatus(currCert, mPrevPubKey, mCRLSignFlag, true); - - // Make new public key if parameters are missing - PublicKey cKey = currCert.getPublicKey(); - if (cKey instanceof DSAPublicKey && - ((DSAPublicKey)cKey).getParams() == null) { - // cKey needs to inherit DSA parameters from prev key - cKey = BasicChecker.makeInheritedParamsKey(cKey, mPrevPubKey); - } - mPrevPubKey = cKey; - mCRLSignFlag = certCanSignCrl(currCert); - } - - /** - * Performs the revocation status check on the certificate using - * the provided state variables, as well as the constant internal - * data. - * - * @param currCert the Certificate - * @param prevKey the previous PublicKey in the chain - * @param signFlag a boolean as returned from the last call, or true - * if this is the first cert in the chain - * @return a boolean specifying if the cert is allowed to vouch for the - * validity of a CRL for the next iteration - * @exception CertPathValidatorException Exception thrown if - * certificate does not verify. - */ - public boolean check(X509Certificate currCert, PublicKey prevKey, - boolean signFlag) throws CertPathValidatorException - { - verifyRevocationStatus(currCert, prevKey, signFlag, true); - return certCanSignCrl(currCert); - } - - /** - * Checks that a cert can be used to verify a CRL. - * - * @param currCert an X509Certificate to check - * @return a boolean specifying if the cert is allowed to vouch for the - * validity of a CRL - */ - static boolean certCanSignCrl(X509Certificate currCert) { - // if the cert doesn't include the key usage ext, or - // the key usage ext asserts cRLSigning, return true, - // otherwise return false. - boolean[] kbools = currCert.getKeyUsage(); - if (kbools != null) { - return kbools[6]; - } - return false; - } - - /** - * Internal method to start the verification of a cert - */ - private void verifyRevocationStatus(X509Certificate currCert, - PublicKey prevKey, boolean signFlag, boolean allowSeparateKey) - throws CertPathValidatorException - { - verifyRevocationStatus(currCert, prevKey, signFlag, - allowSeparateKey, null, mParams.getTrustAnchors()); - } - - /** - * Internal method to start the verification of a cert - * @param stackedCerts a Set of X509Certificates> - * whose revocation status depends on the - * non-revoked status of this cert. To avoid - * circular dependencies, we assume they're - * revoked while checking the revocation - * status of this cert. - * @param trustAnchors a Set of TrustAnchors - */ - private void verifyRevocationStatus(X509Certificate currCert, - PublicKey prevKey, boolean signFlag, boolean allowSeparateKey, - Set stackedCerts, - Set trustAnchors) throws CertPathValidatorException { - - String msg = "revocation status"; - if (debug != null) { - debug.println("CrlRevocationChecker.verifyRevocationStatus()" + - " ---checking " + msg + "..."); - } - - if (mOnlyEECert && currCert.getBasicConstraints() != -1) { - if (debug != null) { - debug.println("Skipping revocation check, not end entity cert"); - } - return; - } - - // reject circular dependencies - RFC 3280 is not explicit on how - // to handle this, so we feel it is safest to reject them until - // the issue is resolved in the PKIX WG. - if ((stackedCerts != null) && stackedCerts.contains(currCert)) { - if (debug != null) { - debug.println("CrlRevocationChecker.verifyRevocationStatus()" + - " circular dependency"); - } - throw new CertPathValidatorException - ("Could not determine revocation status", null, null, -1, - BasicReason.UNDETERMINED_REVOCATION_STATUS); - } - - // init the state for this run - mPossibleCRLs = new HashSet(); - mApprovedCRLs = new HashSet(); - boolean[] reasonsMask = new boolean[9]; - - try { - X509CRLSelector sel = new X509CRLSelector(); - sel.setCertificateChecking(currCert); - CertPathHelper.setDateAndTime(sel, mCurrentTime, MAX_CLOCK_SKEW); - - for (CertStore mStore : mStores) { - for (java.security.cert.CRL crl : mStore.getCRLs(sel)) { - mPossibleCRLs.add((X509CRL)crl); - } - } - // all CRLs returned by the DP Fetcher have also been verified - mApprovedCRLs.addAll(DistributionPointFetcher.getCRLs(sel, signFlag, - prevKey, mSigProvider, mStores, reasonsMask, trustAnchors, - mParams.getDate())); - } catch (Exception e) { - if (debug != null) { - debug.println("CrlRevocationChecker.verifyRevocationStatus() " - + "unexpected exception: " + e.getMessage()); - } - throw new CertPathValidatorException(e); - } - - if (debug != null) { - debug.println("CrlRevocationChecker.verifyRevocationStatus() " + - "crls.size() = " + mPossibleCRLs.size()); - } - if (!mPossibleCRLs.isEmpty()) { - // Now that we have a list of possible CRLs, see which ones can - // be approved - mApprovedCRLs.addAll(verifyPossibleCRLs(mPossibleCRLs, currCert, - signFlag, prevKey, reasonsMask, trustAnchors)); - } - if (debug != null) { - debug.println("CrlRevocationChecker.verifyRevocationStatus() " + - "approved crls.size() = " + mApprovedCRLs.size()); - } - - // make sure that we have at least one CRL that _could_ cover - // the certificate in question and all reasons are covered - if (mApprovedCRLs.isEmpty() || - !Arrays.equals(reasonsMask, ALL_REASONS)) { - if (allowSeparateKey) { - verifyWithSeparateSigningKey(currCert, prevKey, signFlag, - stackedCerts); - return; - } else { - throw new CertPathValidatorException - ("Could not determine revocation status", null, null, -1, - BasicReason.UNDETERMINED_REVOCATION_STATUS); - } - } - - // See if the cert is in the set of approved crls. - if (debug != null) { - BigInteger sn = currCert.getSerialNumber(); - debug.println("CrlRevocationChecker.verifyRevocationStatus() " + - "starting the final sweep..."); - debug.println("CrlRevocationChecker.verifyRevocationStatus" + - " cert SN: " + sn.toString()); - } - - CRLReason reasonCode = CRLReason.UNSPECIFIED; - X509CRLEntryImpl entry = null; - for (X509CRL crl : mApprovedCRLs) { - X509CRLEntry e = crl.getRevokedCertificate(currCert); - if (e != null) { - try { - entry = X509CRLEntryImpl.toImpl(e); - } catch (CRLException ce) { - throw new CertPathValidatorException(ce); - } - if (debug != null) { - debug.println("CrlRevocationChecker.verifyRevocationStatus" - + " CRL entry: " + entry.toString()); - } - - /* - * Abort CRL validation and throw exception if there are any - * unrecognized critical CRL entry extensions (see section - * 5.3 of RFC 3280). - */ - Set unresCritExts = entry.getCriticalExtensionOIDs(); - if (unresCritExts != null && !unresCritExts.isEmpty()) { - /* remove any that we will process */ - unresCritExts.remove - (PKIXExtensions.ReasonCode_Id.toString()); - unresCritExts.remove - (PKIXExtensions.CertificateIssuer_Id.toString()); - if (!unresCritExts.isEmpty()) { - if (debug != null) { - debug.println("Unrecognized " - + "critical extension(s) in revoked CRL entry: " - + unresCritExts); - } - throw new CertPathValidatorException - ("Could not determine revocation status", null, null, - -1, BasicReason.UNDETERMINED_REVOCATION_STATUS); - } - } - - reasonCode = entry.getRevocationReason(); - if (reasonCode == null) { - reasonCode = CRLReason.UNSPECIFIED; - } - Throwable t = new CertificateRevokedException - (entry.getRevocationDate(), reasonCode, - crl.getIssuerX500Principal(), entry.getExtensions()); - throw new CertPathValidatorException(t.getMessage(), t, - null, -1, BasicReason.REVOKED); - } - } - } - - /** - * We have a cert whose revocation status couldn't be verified by - * a CRL issued by the cert that issued the CRL. See if we can - * find a valid CRL issued by a separate key that can verify the - * revocation status of this certificate. - *

- * Note that this does not provide support for indirect CRLs, - * only CRLs signed with a different key (but the same issuer - * name) as the certificate being checked. - * - * @param currCert the X509Certificate to be checked - * @param prevKey the PublicKey that failed - * @param signFlag true if that key was trusted to sign CRLs - * @param stackedCerts a Set of X509Certificates> - * whose revocation status depends on the - * non-revoked status of this cert. To avoid - * circular dependencies, we assume they're - * revoked while checking the revocation - * status of this cert. - * @throws CertPathValidatorException if the cert's revocation status - * cannot be verified successfully with another key - */ - private void verifyWithSeparateSigningKey(X509Certificate currCert, - PublicKey prevKey, boolean signFlag, Set stackedCerts) - throws CertPathValidatorException { - String msg = "revocation status"; - if (debug != null) { - debug.println( - "CrlRevocationChecker.verifyWithSeparateSigningKey()" + - " ---checking " + msg + "..."); - } - - // reject circular dependencies - RFC 3280 is not explicit on how - // to handle this, so we feel it is safest to reject them until - // the issue is resolved in the PKIX WG. - if ((stackedCerts != null) && stackedCerts.contains(currCert)) { - if (debug != null) { - debug.println( - "CrlRevocationChecker.verifyWithSeparateSigningKey()" + - " circular dependency"); - } - throw new CertPathValidatorException - ("Could not determine revocation status", null, null, - -1, BasicReason.UNDETERMINED_REVOCATION_STATUS); - } - - // If prevKey wasn't trusted, maybe we just didn't have the right - // path to it. Don't rule that key out. - if (!signFlag) { - prevKey = null; - } - - // Try to find another key that might be able to sign - // CRLs vouching for this cert. - buildToNewKey(currCert, prevKey, stackedCerts); - } - - /** - * Tries to find a CertPath that establishes a key that can be - * used to verify the revocation status of a given certificate. - * Ignores keys that have previously been tried. Throws a - * CertPathValidatorException if no such key could be found. - * - * @param currCert the X509Certificate to be checked - * @param prevKey the PublicKey of the certificate whose key - * cannot be used to vouch for the CRL and should be ignored - * @param stackedCerts a Set of X509Certificates> - * whose revocation status depends on the - * establishment of this path. - * @throws CertPathValidatorException on failure - */ - private void buildToNewKey(X509Certificate currCert, - PublicKey prevKey, Set stackedCerts) - throws CertPathValidatorException { - - if (debug != null) { - debug.println("CrlRevocationChecker.buildToNewKey()" + - " starting work"); - } - Set badKeys = new HashSet(); - if (prevKey != null) { - badKeys.add(prevKey); - } - X509CertSelector certSel = new RejectKeySelector(badKeys); - certSel.setSubject(currCert.getIssuerX500Principal()); - certSel.setKeyUsage(mCrlSignUsage); - - Set newAnchors = - (mAnchor == null ? mParams.getTrustAnchors() : - Collections.singleton(mAnchor)); - - PKIXBuilderParameters builderParams; - if (mParams instanceof PKIXBuilderParameters) { - builderParams = (PKIXBuilderParameters) mParams.clone(); - builderParams.setTargetCertConstraints(certSel); - // Policy qualifiers must be rejected, since we don't have - // any way to convey them back to the application. - builderParams.setPolicyQualifiersRejected(true); - try { - builderParams.setTrustAnchors(newAnchors); - } catch (InvalidAlgorithmParameterException iape) { - throw new RuntimeException(iape); // should never occur - } - } else { - // It's unfortunate that there's no easy way to make a - // PKIXBuilderParameters object from a PKIXParameters - // object. This might miss some things if parameters - // are added in the future or the validatorParams object - // is a custom class derived from PKIXValidatorParameters. - try { - builderParams = new PKIXBuilderParameters(newAnchors, certSel); - } catch (InvalidAlgorithmParameterException iape) { - throw new RuntimeException(iape); // should never occur - } - builderParams.setInitialPolicies(mParams.getInitialPolicies()); - builderParams.setCertStores(mStores); - builderParams.setExplicitPolicyRequired - (mParams.isExplicitPolicyRequired()); - builderParams.setPolicyMappingInhibited - (mParams.isPolicyMappingInhibited()); - builderParams.setAnyPolicyInhibited(mParams.isAnyPolicyInhibited()); - // Policy qualifiers must be rejected, since we don't have - // any way to convey them back to the application. - // That's the default, so no need to write code. - builderParams.setDate(mParams.getDate()); - builderParams.setCertPathCheckers(mParams.getCertPathCheckers()); - builderParams.setSigProvider(mParams.getSigProvider()); - } - - // Skip revocation during this build to detect circular - // references. But check revocation afterwards, using the - // key (or any other that works). - builderParams.setRevocationEnabled(false); - - // check for AuthorityInformationAccess extension - if (Builder.USE_AIA == true) { - X509CertImpl currCertImpl = null; - try { - currCertImpl = X509CertImpl.toImpl(currCert); - } catch (CertificateException ce) { - // ignore but log it - if (debug != null) { - debug.println("CrlRevocationChecker.buildToNewKey: " + - "error decoding cert: " + ce); - } - } - AuthorityInfoAccessExtension aiaExt = null; - if (currCertImpl != null) { - aiaExt = currCertImpl.getAuthorityInfoAccessExtension(); - } - if (aiaExt != null) { - List adList = aiaExt.getAccessDescriptions(); - if (adList != null) { - for (AccessDescription ad : adList) { - CertStore cs = URICertStore.getInstance(ad); - if (cs != null) { - if (debug != null) { - debug.println("adding AIAext CertStore"); - } - builderParams.addCertStore(cs); - } - } - } - } - } - - CertPathBuilder builder = null; - try { - builder = CertPathBuilder.getInstance("PKIX"); - } catch (NoSuchAlgorithmException nsae) { - throw new CertPathValidatorException(nsae); - } - while (true) { - try { - if (debug != null) { - debug.println("CrlRevocationChecker.buildToNewKey()" + - " about to try build ..."); - } - PKIXCertPathBuilderResult cpbr = - (PKIXCertPathBuilderResult) builder.build(builderParams); - - if (debug != null) { - debug.println("CrlRevocationChecker.buildToNewKey()" + - " about to check revocation ..."); - } - // Now check revocation of all certs in path, assuming that - // the stackedCerts are revoked. - if (stackedCerts == null) { - stackedCerts = new HashSet(); - } - stackedCerts.add(currCert); - TrustAnchor ta = cpbr.getTrustAnchor(); - PublicKey prevKey2 = ta.getCAPublicKey(); - if (prevKey2 == null) { - prevKey2 = ta.getTrustedCert().getPublicKey(); - } - boolean signFlag = true; - List cpList = - cpbr.getCertPath().getCertificates(); - try { - for (int i = cpList.size()-1; i >= 0; i-- ) { - X509Certificate cert = (X509Certificate) cpList.get(i); - - if (debug != null) { - debug.println("CrlRevocationChecker.buildToNewKey()" - + " index " + i + " checking " + cert); - } - verifyRevocationStatus(cert, prevKey2, signFlag, true, - stackedCerts, newAnchors); - signFlag = certCanSignCrl(cert); - prevKey2 = cert.getPublicKey(); - } - } catch (CertPathValidatorException cpve) { - // ignore it and try to get another key - badKeys.add(cpbr.getPublicKey()); - continue; - } - - if (debug != null) { - debug.println("CrlRevocationChecker.buildToNewKey()" + - " got key " + cpbr.getPublicKey()); - } - // Now check revocation on the current cert using that key. - // If it doesn't check out, try to find a different key. - // And if we can't find a key, then return false. - PublicKey newKey = cpbr.getPublicKey(); - try { - verifyRevocationStatus(currCert, newKey, true, false); - // If that passed, the cert is OK! - return; - } catch (CertPathValidatorException cpve) { - // If it is revoked, rethrow exception - if (cpve.getReason() == BasicReason.REVOKED) { - throw cpve; - } - // Otherwise, ignore the exception and - // try to get another key. - } - badKeys.add(newKey); - } catch (InvalidAlgorithmParameterException iape) { - throw new CertPathValidatorException(iape); - } catch (CertPathBuilderException cpbe) { - throw new CertPathValidatorException - ("Could not determine revocation status", null, null, - -1, BasicReason.UNDETERMINED_REVOCATION_STATUS); - } - } - } - - /* - * This inner class extends the X509CertSelector to add an additional - * check to make sure the subject public key isn't on a particular list. - * This class is used by buildToNewKey() to make sure the builder doesn't - * end up with a CertPath to a public key that has already been rejected. - */ - private static class RejectKeySelector extends X509CertSelector { - private final Set badKeySet; - - /** - * Creates a new RejectKeySelector. - * - * @param badPublicKeys a Set of - * PublicKeys that - * should be rejected (or null - * if no such check should be done) - */ - RejectKeySelector(Set badPublicKeys) { - this.badKeySet = badPublicKeys; - } - - /** - * Decides whether a Certificate should be selected. - * - * @param cert the Certificate to be checked - * @return true if the Certificate should be - * selected, false otherwise - */ - public boolean match(Certificate cert) { - if (!super.match(cert)) - return(false); - - if (badKeySet.contains(cert.getPublicKey())) { - if (debug != null) - debug.println("RejectCertSelector.match: bad key"); - return false; - } - - if (debug != null) - debug.println("RejectCertSelector.match: returning true"); - return true; - } - - /** - * Return a printable representation of the CertSelector. - * - * @return a String describing the contents of the - * CertSelector - */ - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("RejectCertSelector: [\n"); - sb.append(super.toString()); - sb.append(badKeySet); - sb.append("]"); - return sb.toString(); - } - } - - /** - * Internal method that verifies a set of possible_crls, - * and sees if each is approved, based on the cert. - * - * @param crls a set of possible CRLs to test for acceptability - * @param cert the certificate whose revocation status is being checked - * @param signFlag true if prevKey was trusted to sign CRLs - * @param prevKey the public key of the issuer of cert - * @param reasonsMask the reason code mask - * @param trustAnchors a Set of TrustAnchors> - * @return a collection of approved crls (or an empty collection) - */ - private Collection verifyPossibleCRLs(Set crls, - X509Certificate cert, boolean signFlag, PublicKey prevKey, - boolean[] reasonsMask, - Set trustAnchors) throws CertPathValidatorException { - - try { - X509CertImpl certImpl = X509CertImpl.toImpl(cert); - if (debug != null) { - debug.println("CRLRevocationChecker.verifyPossibleCRLs: " + - "Checking CRLDPs for " - + certImpl.getSubjectX500Principal()); - } - CRLDistributionPointsExtension ext = - certImpl.getCRLDistributionPointsExtension(); - List points = null; - if (ext == null) { - // assume a DP with reasons and CRLIssuer fields omitted - // and a DP name of the cert issuer. - // TODO add issuerAltName too - X500Name certIssuer = (X500Name)certImpl.getIssuerDN(); - DistributionPoint point = new DistributionPoint - (new GeneralNames().add(new GeneralName(certIssuer)), - null, null); - points = Collections.singletonList(point); - } else { - points = ext.get(CRLDistributionPointsExtension.POINTS); - } - Set results = new HashSet(); - for (Iterator t = points.iterator(); - t.hasNext() && !Arrays.equals(reasonsMask, ALL_REASONS); ) { - DistributionPoint point = t.next(); - for (X509CRL crl : crls) { - if (DistributionPointFetcher.verifyCRL(certImpl, point, crl, - reasonsMask, signFlag, prevKey, mSigProvider, - trustAnchors, mStores, mParams.getDate())) { - results.add(crl); - } - } - } - return results; - } catch (Exception e) { - if (debug != null) { - debug.println("Exception while verifying CRL: "+e.getMessage()); - e.printStackTrace(); - } - return Collections.emptySet(); - } - } -} diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java --- a/src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java Thu Sep 07 23:37:21 2017 -0700 +++ b/src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.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 @@ -27,14 +27,16 @@ import java.io.*; import java.net.URI; -import java.util.*; import java.security.*; import java.security.cert.*; import javax.security.auth.x500.X500Principal; +import java.util.*; import sun.security.action.GetBooleanAction; import sun.security.util.Debug; +import sun.security.validator.Validator; import sun.security.util.DerOutputStream; +import static sun.security.x509.PKIXExtensions.*; import sun.security.x509.*; /** @@ -78,6 +80,20 @@ * empty set. */ public static Collection getCRLs(X509CRLSelector selector, + boolean signFlag, PublicKey prevKey, String provider, + List certStores, boolean[] reasonsMask, + Set trustAnchors, Date validity, String variant) + throws CertStoreException + { + return getCRLs(selector, signFlag, prevKey, null, provider, certStores, + reasonsMask, trustAnchors, validity, variant); + } + /** + * Return the X509CRLs matching this selector. The selector must be + * an X509CRLSelector with certificateChecking set. + */ + // Called by com.sun.deploy.security.RevocationChecker + public static Collection getCRLs(X509CRLSelector selector, boolean signFlag, PublicKey prevKey, String provider, @@ -87,6 +103,26 @@ Date validity) throws CertStoreException { + return getCRLs(selector, signFlag, prevKey, null, provider, certStores, + reasonsMask, trustAnchors, validity, Validator.VAR_GENERIC); + } + + /** + * Return the X509CRLs matching this selector. The selector must be + * an X509CRLSelector with certificateChecking set. + */ + public static Collection getCRLs(X509CRLSelector selector, + boolean signFlag, + PublicKey prevKey, + X509Certificate prevCert, + String provider, + List certStores, + boolean[] reasonsMask, + Set trustAnchors, + Date validity, + String variant) + throws CertStoreException + { if (USE_CRLDP == false) { return Collections.emptySet(); } @@ -110,22 +146,20 @@ } List points = ext.get(CRLDistributionPointsExtension.POINTS); - Set results = new HashSet(); + Set results = new HashSet<>(); for (Iterator t = points.iterator(); t.hasNext() && !Arrays.equals(reasonsMask, ALL_REASONS); ) { DistributionPoint point = t.next(); Collection crls = getCRLs(selector, certImpl, - point, reasonsMask, signFlag, prevKey, provider, - certStores, trustAnchors, validity); + point, reasonsMask, signFlag, prevKey, prevCert, provider, + certStores, trustAnchors, validity, variant); results.addAll(crls); } if (debug != null) { debug.println("Returning " + results.size() + " CRLs"); } return results; - } catch (CertificateException e) { - return Collections.emptySet(); - } catch (IOException e) { + } catch (CertificateException | IOException e) { return Collections.emptySet(); } } @@ -133,12 +167,18 @@ /** * Download CRLs from the given distribution point, verify and return them. * See the top of the class for current limitations. + * + * @throws CertStoreException if there is an error retrieving the CRLs + * from one of the GeneralNames and no other CRLs are retrieved from + * the other GeneralNames. If more than one GeneralName throws an + * exception then the one from the last GeneralName is thrown. */ private static Collection getCRLs(X509CRLSelector selector, X509CertImpl certImpl, DistributionPoint point, boolean[] reasonsMask, - boolean signFlag, PublicKey prevKey, String provider, - List certStores, Set trustAnchors, - Date validity) { + boolean signFlag, PublicKey prevKey, X509Certificate prevCert, + String provider, List certStores, + Set trustAnchors, Date validity, String variant) + throws CertStoreException { // check for full name GeneralNames fullName = point.getFullName(); @@ -166,35 +206,44 @@ return Collections.emptySet(); } } - Collection possibleCRLs = new ArrayList(); - Collection crls = new ArrayList(2); + Collection possibleCRLs = new ArrayList<>(); + CertStoreException savedCSE = null; for (Iterator t = fullName.iterator(); t.hasNext(); ) { - GeneralName name = t.next(); - if (name.getType() == GeneralNameInterface.NAME_DIRECTORY) { - X500Name x500Name = (X500Name) name.getName(); - possibleCRLs.addAll( - getCRLs(x500Name, certImpl.getIssuerX500Principal(), - certStores)); - } else if (name.getType() == GeneralNameInterface.NAME_URI) { - URIName uriName = (URIName)name.getName(); - X509CRL crl = getCRL(uriName); - if (crl != null) { - possibleCRLs.add(crl); + try { + GeneralName name = t.next(); + if (name.getType() == GeneralNameInterface.NAME_DIRECTORY) { + X500Name x500Name = (X500Name) name.getName(); + possibleCRLs.addAll( + getCRLs(x500Name, certImpl.getIssuerX500Principal(), + certStores)); + } else if (name.getType() == GeneralNameInterface.NAME_URI) { + URIName uriName = (URIName)name.getName(); + X509CRL crl = getCRL(uriName); + if (crl != null) { + possibleCRLs.add(crl); + } } + } catch (CertStoreException cse) { + savedCSE = cse; } } + // only throw CertStoreException if no CRLs are retrieved + if (possibleCRLs.isEmpty() && savedCSE != null) { + throw savedCSE; + } + Collection crls = new ArrayList<>(2); for (X509CRL crl : possibleCRLs) { try { // make sure issuer is not set // we check the issuer in verifyCRLs method selector.setIssuerNames(null); if (selector.match(crl) && verifyCRL(certImpl, point, crl, - reasonsMask, signFlag, prevKey, provider, trustAnchors, - certStores, validity)) { + reasonsMask, signFlag, prevKey, prevCert, provider, + trustAnchors, certStores, validity, variant)) { crls.add(crl); } - } catch (Exception e) { + } catch (IOException | CRLException e) { // don't add the CRL if (debug != null) { debug.println("Exception verifying CRL: " + e.getMessage()); @@ -208,34 +257,43 @@ /** * Download CRL from given URI. */ - private static X509CRL getCRL(URIName name) { + private static X509CRL getCRL(URIName name) throws CertStoreException { URI uri = name.getURI(); if (debug != null) { debug.println("Trying to fetch CRL from DP " + uri); } + CertStore ucs = null; try { - CertStore ucs = URICertStore.getInstance + ucs = URICertStore.getInstance (new URICertStore.URICertStoreParameters(uri)); - Collection crls = ucs.getCRLs(null); - if (crls.isEmpty()) { - return null; - } else { - return (X509CRL) crls.iterator().next(); + } catch (InvalidAlgorithmParameterException | + NoSuchAlgorithmException e) { + if (debug != null) { + debug.println("Can't create URICertStore: " + e.getMessage()); } - } catch (Exception e) { - if (debug != null) { - debug.println("Exception getting CRL from CertStore: " + e); - e.printStackTrace(); - } + return null; } - return null; + + Collection crls = ucs.getCRLs(null); + if (crls.isEmpty()) { + return null; + } else { + return (X509CRL) crls.iterator().next(); + } } /** * Fetch CRLs from certStores. + * + * @throws CertStoreException if there is an error retrieving the CRLs from + * one of the CertStores and no other CRLs are retrieved from + * the other CertStores. If more than one CertStore throws an + * exception then the one from the last CertStore is thrown. */ private static Collection getCRLs(X500Name name, - X500Principal certIssuer, List certStores) + X500Principal certIssuer, + List certStores) + throws CertStoreException { if (debug != null) { debug.println("Trying to fetch CRL from DP " + name); @@ -243,22 +301,28 @@ X509CRLSelector xcs = new X509CRLSelector(); xcs.addIssuer(name.asX500Principal()); xcs.addIssuer(certIssuer); - Collection crls = new ArrayList(); + Collection crls = new ArrayList<>(); + CertStoreException savedCSE = null; for (CertStore store : certStores) { try { for (CRL crl : store.getCRLs(xcs)) { crls.add((X509CRL)crl); } } catch (CertStoreException cse) { - // don't add the CRL if (debug != null) { - debug.println("Non-fatal exception while retrieving " + + debug.println("Exception while retrieving " + "CRLs: " + cse); cse.printStackTrace(); } + savedCSE = new PKIX.CertStoreTypeException(store.getType(),cse); } } - return crls; + // only throw CertStoreException if no CRLs are retrieved + if (crls.isEmpty() && savedCSE != null) { + throw savedCSE; + } else { + return crls; + } } /** @@ -271,6 +335,8 @@ * @param reasonsMask the interim reasons mask * @param signFlag true if prevKey can be used to verify the CRL * @param prevKey the public key that verifies the certificate's signature + * @param prevCert the certificate whose public key verifies + * {@code certImpl}'s signature * @param provider the Signature provider to use * @param trustAnchors a {@code Set} of {@code TrustAnchor}s * @param certStores a {@code List} of {@code CertStore}s to be used in @@ -281,9 +347,17 @@ */ static boolean verifyCRL(X509CertImpl certImpl, DistributionPoint point, X509CRL crl, boolean[] reasonsMask, boolean signFlag, - PublicKey prevKey, String provider, + PublicKey prevKey, X509Certificate prevCert, String provider, Set trustAnchors, List certStores, - Date validity) throws CRLException, IOException { + Date validity, String variant) throws CRLException, IOException { + + if (debug != null) { + debug.println("DistributionPointFetcher.verifyCRL: " + + "checking revocation status for" + + "\n SN: " + Debug.toHexString(certImpl.getSerialNumber()) + + "\n Subject: " + certImpl.getSubjectX500Principal() + + "\n Issuer: " + certImpl.getIssuerX500Principal()); + } boolean indirectCRL = false; X509CRLImpl crlImpl = X509CRLImpl.toImpl(crl); @@ -328,15 +402,15 @@ } } else if (crlIssuer.equals(certIssuer) == false) { if (debug != null) { - debug.println("crl issuer does not equal cert issuer"); + debug.println("crl issuer does not equal cert issuer.\n" + + "crl issuer: " + crlIssuer + "\n" + + "cert issuer: " + certIssuer); } return false; } else { // in case of self-issued indirect CRL issuer. - byte[] certAKID = certImpl.getExtensionValue( - PKIXExtensions.AuthorityKey_Id.toString()); - byte[] crlAKID = crlImpl.getExtensionValue( - PKIXExtensions.AuthorityKey_Id.toString()); + KeyIdentifier certAKID = certImpl.getAuthKeyId(); + KeyIdentifier crlAKID = crlImpl.getAuthKeyId(); if (certAKID == null || crlAKID == null) { // cannot recognize indirect CRL without AKID @@ -347,7 +421,7 @@ // reset the public key used to verify the CRL's signature prevKey = certImpl.getPublicKey(); } - } else if (!Arrays.equals(certAKID, crlAKID)) { + } else if (!certAKID.equals(crlAKID)) { // we accept the case that a CRL issuer provide status // information for itself. if (issues(certImpl, crlImpl, provider)) { @@ -401,7 +475,7 @@ } if (indirectCRL) { if (pointCrlIssuers.size() != 1) { - // RFC 3280: there must be only 1 CRL issuer + // RFC 5280: there must be only 1 CRL issuer // name when relativeName is present if (debug != null) { debug.println("must only be one CRL " + @@ -581,18 +655,26 @@ // the subject criterion will be set by builder automatically. } - // by far, we have validated the previous certificate, we can - // trust it during validating the CRL issuer. - // Except the performance improvement, another benefit is to break - // the dead loop while looking for the issuer back and forth + // By now, we have validated the previous certificate, so we can + // trust it during the validation of the CRL issuer. + // In addition to the performance improvement, another benefit is to + // break the dead loop while looking for the issuer back and forth // between the delegated self-issued certificate and its issuer. Set newTrustAnchors = new HashSet<>(trustAnchors); if (prevKey != null) { // Add the previous certificate as a trust anchor. - X500Principal principal = certImpl.getIssuerX500Principal(); - TrustAnchor temporary = - new TrustAnchor(principal, prevKey, null); + // If prevCert is not null, we want to construct a TrustAnchor + // using the cert object because when the certpath for the CRL + // is built later, the CertSelector will make comparisons with + // the TrustAnchor's trustedCert member rather than its pubKey. + TrustAnchor temporary; + if (prevCert != null) { + temporary = new TrustAnchor(prevCert, null); + } else { + X500Principal principal = certImpl.getIssuerX500Principal(); + temporary = new TrustAnchor(principal, prevKey, null); + } newTrustAnchors.add(temporary); } @@ -610,14 +692,14 @@ PKIXCertPathBuilderResult result = (PKIXCertPathBuilderResult) builder.build(params); prevKey = result.getPublicKey(); - } catch (Exception e) { + } catch (GeneralSecurityException e) { throw new CRLException(e); } } // check the crl signature algorithm try { - AlgorithmChecker.check(prevKey, crl); + AlgorithmChecker.check(prevKey, crl, variant); } catch (CertPathValidatorException cpve) { if (debug != null) { debug.println("CRL signature algorithm check failed: " + cpve); @@ -628,7 +710,7 @@ // validate the signature on the CRL try { crl.verify(prevKey, provider); - } catch (Exception e) { + } catch (GeneralSecurityException e) { if (debug != null) { debug.println("CRL signature failed to verify"); } @@ -639,15 +721,14 @@ Set unresCritExts = crl.getCriticalExtensionOIDs(); // remove any that we have processed if (unresCritExts != null) { - unresCritExts.remove - (PKIXExtensions.IssuingDistributionPoint_Id.toString()); + unresCritExts.remove(IssuingDistributionPoint_Id.toString()); if (!unresCritExts.isEmpty()) { if (debug != null) { debug.println("Unrecognized critical extension(s) in CRL: " + unresCritExts); - Iterator i = unresCritExts.iterator(); - while (i.hasNext()) - debug.println(i.next()); + for (String ext : unresCritExts) { + debug.println(ext); + } } return false; } @@ -667,8 +748,9 @@ * GeneralNames object. */ private static GeneralNames getFullNames(X500Name issuer, RDN rdn) - throws IOException { - List rdns = new ArrayList(issuer.rdns()); + throws IOException + { + List rdns = new ArrayList<>(issuer.rdns()); rdns.add(rdn); X500Name fullName = new X500Name(rdns.toArray(new RDN[0])); GeneralNames fullNames = new GeneralNames(); @@ -676,15 +758,16 @@ return fullNames; } - /** Verifies whether a CRL is issued by a certain certificate + /** + * Verifies whether a CRL is issued by a certain certificate * * @param cert the certificate * @param crl the CRL to be verified * @param provider the name of the signature provider */ private static boolean issues(X509CertImpl cert, X509CRLImpl crl, - String provider) throws IOException { - + String provider) throws IOException + { boolean matched = false; AdaptableX509CertSelector issuerSelector = @@ -722,7 +805,7 @@ try { crl.verify(cert.getPublicKey(), provider); matched = true; - } catch (Exception e) { + } catch (GeneralSecurityException e) { matched = false; } } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/certpath/ForwardBuilder.java --- a/src/share/classes/sun/security/provider/certpath/ForwardBuilder.java Thu Sep 07 23:37:21 2017 -0700 +++ b/src/share/classes/sun/security/provider/certpath/ForwardBuilder.java Sat Feb 03 21:37:28 2018 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -26,10 +26,9 @@ package sun.security.provider.certpath; import java.io.IOException; -import java.util.*; - import java.security.GeneralSecurityException; import java.security.InvalidKeyException; +import java.security.PublicKey; import java.security.cert.CertificateException; import java.security.cert.CertPathValidatorException; import java.security.cert.PKIXReason; @@ -40,15 +39,15 @@ import java.security.cert.TrustAnchor; import java.security.cert.X509Certificate; import java.security.cert.X509CertSelector; +import java.util.*; import javax.security.auth.x500.X500Principal; +import sun.security.provider.certpath.PKIX.BuilderParams; import sun.security.util.Debug; import sun.security.x509.AccessDescription; import sun.security.x509.AuthorityInfoAccessExtension; -import sun.security.x509.PKIXExtensions; -import sun.security.x509.PolicyMappingsExtension; +import static sun.security.x509.PKIXExtensions.*; import sun.security.x509.X500Name; -import sun.security.x509.X509CertImpl; import sun.security.x509.AuthorityKeyIdentifierExtension; /** @@ -72,21 +71,17 @@ TrustAnchor trustAnchor; private Comparator comparator; private boolean searchAllCertStores = true; - private boolean onlyEECert = false; /** * Initialize the builder with the input parameters. * * @param params the parameter set used to build a certification path */ - ForwardBuilder(PKIXBuilderParameters buildParams, - X500Principal targetSubjectDN, boolean searchAllCertStores, - boolean onlyEECert) - { - super(buildParams, targetSubjectDN); + ForwardBuilder(BuilderParams buildParams, boolean searchAllCertStores) { + super(buildParams); // populate sets of trusted certificates and subject DNs - trustAnchors = buildParams.getTrustAnchors(); + trustAnchors = buildParams.trustAnchors(); trustedCerts = new HashSet(trustAnchors.size()); trustedSubjectDNs = new HashSet(trustAnchors.size()); for (TrustAnchor anchor : trustAnchors) { @@ -100,7 +95,6 @@ } comparator = new PKIXCertComparator(trustedSubjectDNs); this.searchAllCertStores = searchAllCertStores; - this.onlyEECert = onlyEECert; } /** @@ -112,9 +106,10 @@ * Must be an instance of ForwardState * @param certStores list of CertStores */ - Collection getMatchingCerts - (State currentState, List certStores) - throws CertStoreException, CertificateException, IOException + @Override + Collection getMatchingCerts(State currentState, + List certStores) + throws CertStoreException, CertificateException, IOException { if (debug != null) { debug.println("ForwardBuilder.getMatchingCerts()..."); @@ -127,7 +122,7 @@ * As each cert is added, it is sorted based on the PKIXCertComparator * algorithm. */ - Set certs = new TreeSet(comparator); + Set certs = new TreeSet<>(comparator); /* * Only look for EE certs if search has just started. @@ -145,9 +140,10 @@ * and requirements specified in the parameters and PKIX state. */ private void getMatchingEECerts(ForwardState currentState, - List certStores, Collection eeCerts) - throws IOException { - + List certStores, + Collection eeCerts) + throws IOException + { if (debug != null) { debug.println("ForwardBuilder.getMatchingEECerts()..."); } @@ -165,12 +161,12 @@ /* * Match on certificate validity date */ - eeSelector.setCertificateValid(date); + eeSelector.setCertificateValid(buildParams.date()); /* * Policy processing optimizations */ - if (buildParams.isExplicitPolicyRequired()) { + if (buildParams.explicitPolicyRequired()) { eeSelector.setPolicy(getMatchingPolicies()); } /* @@ -188,9 +184,10 @@ * and requirements specified in the parameters and PKIX state. */ private void getMatchingCACerts(ForwardState currentState, - List certStores, Collection caCerts) - throws IOException { - + List certStores, + Collection caCerts) + throws IOException + { if (debug != null) { debug.println("ForwardBuilder.getMatchingCACerts()..."); } @@ -216,8 +213,8 @@ } if (caTargetSelector == null) { - caTargetSelector = (X509CertSelector) - targetCertConstraints.clone(); + caTargetSelector = + (X509CertSelector) targetCertConstraints.clone(); /* * Since we don't check the validity period of trusted @@ -229,7 +226,7 @@ /* * Policy processing optimizations */ - if (buildParams.isExplicitPolicyRequired()) + if (buildParams.explicitPolicyRequired()) caTargetSelector.setPolicy(getMatchingPolicies()); } @@ -249,7 +246,7 @@ /* * Policy processing optimizations */ - if (buildParams.isExplicitPolicyRequired()) + if (buildParams.explicitPolicyRequired()) caSelector.setPolicy(getMatchingPolicies()); } @@ -278,7 +275,7 @@ * check the validity period */ caSelector.setValidityPeriod(currentState.cert.getNotBefore(), - currentState.cert.getNotAfter()); + currentState.cert.getNotAfter()); sel = caSelector; } @@ -307,7 +304,7 @@ * The trusted certificate matching is completed. We need to match * on certificate validity date. */ - sel.setCertificateValid(date); + sel.setCertificateValid(buildParams.date()); /* * Require CA certs with a pathLenConstraint that allows @@ -323,11 +320,12 @@ * certificate pairs. */ if (currentState.isInitial() || - (buildParams.getMaxPathLength() == -1) || - (buildParams.getMaxPathLength() > currentState.traversedCACerts)) + (buildParams.maxPathLength() == -1) || + (buildParams.maxPathLength() > currentState.traversedCACerts)) { if (addMatchingCerts(sel, certStores, - caCerts, searchAllCertStores) && !searchAllCertStores) { + caCerts, searchAllCertStores) + && !searchAllCertStores) { return; } } @@ -356,7 +354,8 @@ // because of the selector, so the cast is safe @SuppressWarnings("unchecked") private boolean getCerts(AuthorityInfoAccessExtension aiaExt, - Collection certs) { + Collection certs) + { if (Builder.USE_AIA == false) { return false; } @@ -451,6 +450,7 @@ * @throws ClassCastException if either argument is not of type * X509Certificate */ + @Override public int compare(X509Certificate oCert1, X509Certificate oCert2) { // if certs are the same, return 0 @@ -653,8 +653,10 @@ * @param currentState the current state against which the cert is verified * @param certPathList the certPathList generated thus far */ + @Override void verifyCert(X509Certificate cert, State currentState, - List certPathList) throws GeneralSecurityException + List certPathList) + throws GeneralSecurityException { if (debug != null) { debug.println("ForwardBuilder.verifyCert(SN: " @@ -669,32 +671,16 @@ currState.untrustedChecker.check(cert, Collections.emptySet()); /* - * check for looping - abort a loop if - * ((we encounter the same certificate twice) AND - * ((policyMappingInhibited = true) OR (no policy mapping - * extensions can be found between the occurrences of the same - * certificate))) + * check for looping - abort a loop if we encounter the same + * certificate twice */ if (certPathList != null) { - boolean policyMappingFound = false; for (X509Certificate cpListCert : certPathList) { - X509CertImpl cpListCertImpl = X509CertImpl.toImpl(cpListCert); - PolicyMappingsExtension policyMappingsExt - = cpListCertImpl.getPolicyMappingsExtension(); - if (policyMappingsExt != null) { - policyMappingFound = true; - } - if (debug != null) { - debug.println("policyMappingFound = " + policyMappingFound); - } if (cert.equals(cpListCert)) { - if ((buildParams.isPolicyMappingInhibited()) || - (!policyMappingFound)) { - if (debug != null) { - debug.println("loop detected!!"); - } - throw new CertPathValidatorException("loop detected"); + if (debug != null) { + debug.println("loop detected!!"); } + throw new CertPathValidatorException("loop detected"); } } } @@ -723,7 +709,7 @@ * all extensions that all user checkers are capable of * processing. */ - for (PKIXCertPathChecker checker : buildParams.getCertPathCheckers()) { + for (PKIXCertPathChecker checker : buildParams.certPathCheckers()) { if (!checker.isForwardCheckingSupported()) { Set supportedExts = checker.getSupportedExtensions(); if (supportedExts != null) { @@ -737,23 +723,15 @@ * to check. If there are any left, throw an exception! */ if (!unresCritExts.isEmpty()) { - unresCritExts.remove( - PKIXExtensions.BasicConstraints_Id.toString()); - unresCritExts.remove( - PKIXExtensions.NameConstraints_Id.toString()); - unresCritExts.remove( - PKIXExtensions.CertificatePolicies_Id.toString()); - unresCritExts.remove( - PKIXExtensions.PolicyMappings_Id.toString()); - unresCritExts.remove( - PKIXExtensions.PolicyConstraints_Id.toString()); - unresCritExts.remove( - PKIXExtensions.InhibitAnyPolicy_Id.toString()); - unresCritExts.remove( - PKIXExtensions.SubjectAlternativeName_Id.toString()); - unresCritExts.remove(PKIXExtensions.KeyUsage_Id.toString()); - unresCritExts.remove( - PKIXExtensions.ExtendedKeyUsage_Id.toString()); + unresCritExts.remove(BasicConstraints_Id.toString()); + unresCritExts.remove(NameConstraints_Id.toString()); + unresCritExts.remove(CertificatePolicies_Id.toString()); + unresCritExts.remove(PolicyMappings_Id.toString()); + unresCritExts.remove(PolicyConstraints_Id.toString()); + unresCritExts.remove(InhibitAnyPolicy_Id.toString()); + unresCritExts.remove(SubjectAlternativeName_Id.toString()); + unresCritExts.remove(KeyUsage_Id.toString()); + unresCritExts.remove(ExtendedKeyUsage_Id.toString()); if (!unresCritExts.isEmpty()) throw new CertPathValidatorException @@ -791,31 +769,12 @@ */ /* - * Check revocation for the previous cert - */ - if (buildParams.isRevocationEnabled()) { - - // first off, see if this cert can authorize revocation... - if (CrlRevocationChecker.certCanSignCrl(cert)) { - // And then check to be sure no key requiring key parameters - // has been encountered - if (!currState.keyParamsNeeded()) - // If all that checks out, we can check the - // revocation status of the cert. Otherwise, - // we'll just wait until the end. - currState.crlChecker.check(currState.cert, - cert.getPublicKey(), - true); - } - } - - /* * Check signature only if no key requiring key parameters has been * encountered. */ if (!currState.keyParamsNeeded()) { (currState.cert).verify(cert.getPublicKey(), - buildParams.getSigProvider()); + buildParams.sigProvider()); } } @@ -831,6 +790,7 @@ * @param cert the certificate to test * @return a boolean value indicating whether the cert completes the path. */ + @Override boolean isPathCompleted(X509Certificate cert) { for (TrustAnchor anchor : trustAnchors) { if (anchor.getTrustedCert() != null) { @@ -840,62 +800,46 @@ } else { continue; } - } else { - X500Principal principal = anchor.getCA(); - java.security.PublicKey publicKey = anchor.getCAPublicKey(); + } + X500Principal principal = anchor.getCA(); + PublicKey publicKey = anchor.getCAPublicKey(); - if (principal != null && publicKey != null && - principal.equals(cert.getSubjectX500Principal())) { - if (publicKey.equals(cert.getPublicKey())) { - // the cert itself is a trust anchor - this.trustAnchor = anchor; - return true; - } - // else, it is a self-issued certificate of the anchor + if (principal != null && publicKey != null && + principal.equals(cert.getSubjectX500Principal())) { + if (publicKey.equals(cert.getPublicKey())) { + // the cert itself is a trust anchor + this.trustAnchor = anchor; + return true; } - - // Check subject/issuer name chaining - if (principal == null || - !principal.equals(cert.getIssuerX500Principal())) { - continue; - } + // else, it is a self-issued certificate of the anchor } - /* Check revocation if it is enabled */ - if (buildParams.isRevocationEnabled()) { - try { - CrlRevocationChecker crlChecker = new CrlRevocationChecker - (anchor, buildParams, null, onlyEECert); - crlChecker.check(cert, anchor.getCAPublicKey(), true); - } catch (CertPathValidatorException cpve) { - if (debug != null) { - debug.println("ForwardBuilder.isPathCompleted() cpve"); - cpve.printStackTrace(); - } - continue; - } + // Check subject/issuer name chaining + if (principal == null || + !principal.equals(cert.getIssuerX500Principal())) { + continue; + } + + // skip anchor if it contains a DSA key with no DSA params + if (PKIX.isDSAPublicKeyWithoutParams(publicKey)) { + continue; } /* * Check signature */ try { - // NOTE: the DSA public key in the buildParams may lack - // parameters, yet there is no key to inherit the parameters - // from. This is probably such a rare case that it is not worth - // trying to detect the situation earlier. - cert.verify(anchor.getCAPublicKey(), - buildParams.getSigProvider()); + cert.verify(publicKey, buildParams.sigProvider()); } catch (InvalidKeyException ike) { if (debug != null) { debug.println("ForwardBuilder.isPathCompleted() invalid " - + "DSA key found"); + + "DSA key found"); } continue; - } catch (Exception e){ + } catch (GeneralSecurityException e){ if (debug != null) { debug.println("ForwardBuilder.isPathCompleted() " + - "unexpected exception"); + "unexpected exception"); e.printStackTrace(); } continue; @@ -913,8 +857,10 @@ * @param cert the certificate to be added * @param certPathList the certification path list */ + @Override void addCertToPath(X509Certificate cert, - LinkedList certPathList) { + LinkedList certPathList) + { certPathList.addFirst(cert); } @@ -922,6 +868,7 @@ * * @param certPathList the certification path list */ + @Override void removeFinalCertFromPath(LinkedList certPathList) { certPathList.removeFirst(); } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/certpath/ForwardState.java --- a/src/share/classes/sun/security/provider/certpath/ForwardState.java Thu Sep 07 23:37:21 2017 -0700 +++ b/src/share/classes/sun/security/provider/certpath/ForwardState.java Sat Feb 03 21:37:28 2018 -0800 @@ -26,15 +26,12 @@ package sun.security.provider.certpath; import java.io.IOException; -import java.security.PublicKey; import java.security.cert.CertificateException; import java.security.cert.CertPathValidatorException; import java.security.cert.PKIXCertPathChecker; import java.security.cert.X509Certificate; -import java.security.interfaces.DSAPublicKey; import java.util.ArrayList; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.ListIterator; import javax.security.auth.x500.X500Principal; @@ -76,9 +73,6 @@ /* Flag indicating if state is initial (path is just starting) */ private boolean init = true; - /* the checker used for revocation status */ - public CrlRevocationChecker crlChecker; - /* the untrusted certificates checker */ UntrustedChecker untrustedChecker; @@ -96,6 +90,7 @@ * * @return boolean flag indicating if the state is initial (just starting) */ + @Override public boolean isInitial() { return init; } @@ -107,6 +102,7 @@ * @return boolean true if key needing to inherit parameters has been * encountered; false otherwise. */ + @Override public boolean keyParamsNeeded() { return keyParamsNeededFlag; } @@ -114,23 +110,18 @@ /** * Display state for debugging purposes */ + @Override public String toString() { - StringBuffer sb = new StringBuffer(); - try { - sb.append("State ["); - sb.append("\n issuerDN of last cert: " + issuerDN); - sb.append("\n traversedCACerts: " + traversedCACerts); - sb.append("\n init: " + String.valueOf(init)); - sb.append("\n keyParamsNeeded: " - + String.valueOf(keyParamsNeededFlag)); - sb.append("\n subjectNamesTraversed: \n" + subjectNamesTraversed); - sb.append("]\n"); - } catch (Exception e) { - if (debug != null) { - debug.println("ForwardState.toString() unexpected exception"); - e.printStackTrace(); - } - } + StringBuilder sb = new StringBuilder(); + sb.append("State ["); + sb.append("\n issuerDN of last cert: ").append(issuerDN); + sb.append("\n traversedCACerts: ").append(traversedCACerts); + sb.append("\n init: ").append(String.valueOf(init)); + sb.append("\n keyParamsNeeded: ").append + (String.valueOf(keyParamsNeededFlag)); + sb.append("\n subjectNamesTraversed: \n").append + (subjectNamesTraversed); + sb.append("]\n"); return sb.toString(); } @@ -150,12 +141,10 @@ * that supports forward checking and initialize the forwardCheckers */ forwardCheckers = new ArrayList(); - if (certPathCheckers != null) { - for (PKIXCertPathChecker checker : certPathCheckers) { - if (checker.isForwardCheckingSupported()) { - checker.init(true); - forwardCheckers.add(checker); - } + for (PKIXCertPathChecker checker : certPathCheckers) { + if (checker.isForwardCheckingSupported()) { + checker.init(true); + forwardCheckers.add(checker); } } @@ -167,6 +156,7 @@ * * @param cert the certificate which is used to update the state */ + @Override public void updateState(X509Certificate cert) throws CertificateException, IOException, CertPathValidatorException { @@ -176,9 +166,7 @@ X509CertImpl icert = X509CertImpl.toImpl(cert); /* see if certificate key has null parameters */ - PublicKey newKey = icert.getPublicKey(); - if (newKey instanceof DSAPublicKey && - ((DSAPublicKey)newKey).getParams() == null) { + if (PKIX.isDSAPublicKeyWithoutParams(icert.getPublicKey())) { keyParamsNeededFlag = true; } @@ -211,13 +199,11 @@ if (subjAltNameExt != null) { GeneralNames gNames = subjAltNameExt.get( SubjectAlternativeNameExtension.SUBJECT_NAME); - for (Iterator t = gNames.iterator(); - t.hasNext(); ) { - GeneralNameInterface gName = t.next().getName(); - subjectNamesTraversed.add(gName); + for (GeneralName gName : gNames.names()) { + subjectNamesTraversed.add(gName.getName()); } } - } catch (Exception e) { + } catch (IOException e) { if (debug != null) { debug.println("ForwardState.updateState() unexpected " + "exception"); @@ -239,6 +225,7 @@ * because some of them will * not have their contents modified by subsequent calls to updateState. */ + @Override @SuppressWarnings("unchecked") // Safe casts assuming clone() works correctly public Object clone() { try { diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/certpath/IndexedCollectionCertStore.java --- a/src/share/classes/sun/security/provider/certpath/IndexedCollectionCertStore.java Thu Sep 07 23:37:21 2017 -0700 +++ b/src/share/classes/sun/security/provider/certpath/IndexedCollectionCertStore.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, 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 @@ -180,7 +180,7 @@ if (cert.equals(oldEntry)) { return; } - List list = new ArrayList(2); + List list = new ArrayList<>(2); list.add(cert); list.add((X509Certificate)oldEntry); certSubjects.put(subject, list); @@ -206,7 +206,7 @@ if (crl.equals(oldEntry)) { return; } - List list = new ArrayList(2); + List list = new ArrayList<>(2); list.add(crl); list.add((X509CRL)oldEntry); crlIssuers.put(issuer, list); @@ -234,19 +234,20 @@ * match the specified selector * @throws CertStoreException if an exception occurs */ + @Override public Collection engineGetCertificates(CertSelector selector) throws CertStoreException { // no selector means match all if (selector == null) { - Set matches = new HashSet(); + Set matches = new HashSet<>(); matchX509Certs(new X509CertSelector(), matches); matches.addAll(otherCertificates); return matches; } if (selector instanceof X509CertSelector == false) { - Set matches = new HashSet(); + Set matches = new HashSet<>(); matchX509Certs(selector, matches); for (Certificate cert : otherCertificates) { if (selector.match(cert)) { @@ -285,7 +286,7 @@ // See certSubjects javadoc. @SuppressWarnings("unchecked") List list = (List)entry; - Set matches = new HashSet(16); + Set matches = new HashSet<>(16); for (X509Certificate cert : list) { if (x509Selector.match(cert)) { matches.add(cert); @@ -295,7 +296,7 @@ } } // cannot use index, iterate all - Set matches = new HashSet(16); + Set matches = new HashSet<>(16); matchX509Certs(x509Selector, matches); return matches; } @@ -338,18 +339,19 @@ * match the specified selector * @throws CertStoreException if an exception occurs */ + @Override public Collection engineGetCRLs(CRLSelector selector) throws CertStoreException { if (selector == null) { - Set matches = new HashSet(); + Set matches = new HashSet<>(); matchX509CRLs(new X509CRLSelector(), matches); matches.addAll(otherCRLs); return matches; } if (selector instanceof X509CRLSelector == false) { - Set matches = new HashSet(); + Set matches = new HashSet<>(); matchX509CRLs(selector, matches); for (CRL crl : otherCRLs) { if (selector.match(crl)) { @@ -366,7 +368,7 @@ // see if the issuer is specified Collection issuers = x509Selector.getIssuers(); if (issuers != null) { - HashSet matches = new HashSet(16); + HashSet matches = new HashSet<>(16); for (X500Principal issuer : issuers) { Object entry = crlIssuers.get(issuer); if (entry == null) { @@ -390,7 +392,7 @@ return matches; } // cannot use index, iterate all - Set matches = new HashSet(16); + Set matches = new HashSet<>(16); matchX509CRLs(x509Selector, matches); return matches; } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/certpath/KeyChecker.java --- a/src/share/classes/sun/security/provider/certpath/KeyChecker.java Thu Sep 07 23:37:21 2017 -0700 +++ b/src/share/classes/sun/security/provider/certpath/KeyChecker.java Sat Feb 03 21:37:28 2018 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2008, 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 @@ -30,7 +30,7 @@ import java.security.cert.PKIXReason; import sun.security.util.Debug; -import sun.security.x509.PKIXExtensions; +import static sun.security.x509.PKIXExtensions.*; /** * KeyChecker is a PKIXCertPathChecker that checks that the @@ -45,33 +45,29 @@ class KeyChecker extends PKIXCertPathChecker { private static final Debug debug = Debug.getInstance("certpath"); - // the index of keyCertSign in the boolean KeyUsage array - private static final int keyCertSign = 5; private final int certPathLen; - private CertSelector targetConstraints; + private final CertSelector targetConstraints; private int remainingCerts; private Set supportedExts; /** - * Default Constructor + * Creates a KeyChecker. * * @param certPathLen allowable cert path length * @param targetCertSel a CertSelector object specifying the constraints * on the target certificate */ - KeyChecker(int certPathLen, CertSelector targetCertSel) - throws CertPathValidatorException - { + KeyChecker(int certPathLen, CertSelector targetCertSel) { this.certPathLen = certPathLen; this.targetConstraints = targetCertSel; - init(false); } /** * Initializes the internal state of the checker from parameters * specified in the constructor */ + @Override public void init(boolean forward) throws CertPathValidatorException { if (!forward) { remainingCerts = certPathLen; @@ -81,16 +77,18 @@ } } - public final boolean isForwardCheckingSupported() { + @Override + public boolean isForwardCheckingSupported() { return false; } + @Override public Set getSupportedExtensions() { if (supportedExts == null) { - supportedExts = new HashSet(); - supportedExts.add(PKIXExtensions.KeyUsage_Id.toString()); - supportedExts.add(PKIXExtensions.ExtendedKeyUsage_Id.toString()); - supportedExts.add(PKIXExtensions.SubjectAlternativeName_Id.toString()); + supportedExts = new HashSet(3); + supportedExts.add(KeyUsage_Id.toString()); + supportedExts.add(ExtendedKeyUsage_Id.toString()); + supportedExts.add(SubjectAlternativeName_Id.toString()); supportedExts = Collections.unmodifiableSet(supportedExts); } return supportedExts; @@ -102,20 +100,20 @@ * * @param cert the Certificate * @param unresolvedCritExts the unresolved critical extensions - * @exception CertPathValidatorException Exception thrown if certificate - * does not verify + * @throws CertPathValidatorException if certificate does not verify */ + @Override public void check(Certificate cert, Collection unresCritExts) throws CertPathValidatorException { - X509Certificate currCert = (X509Certificate) cert; + X509Certificate currCert = (X509Certificate)cert; remainingCerts--; // if final certificate, check that target constraints are satisfied if (remainingCerts == 0) { - if ((targetConstraints != null) && - (targetConstraints.match(currCert) == false)) { + if (targetConstraints != null && + targetConstraints.match(currCert) == false) { throw new CertPathValidatorException("target certificate " + "constraints check failed"); } @@ -126,25 +124,26 @@ // remove the extensions that we have checked if (unresCritExts != null && !unresCritExts.isEmpty()) { - unresCritExts.remove(PKIXExtensions.KeyUsage_Id.toString()); - unresCritExts.remove(PKIXExtensions.ExtendedKeyUsage_Id.toString()); - unresCritExts.remove( - PKIXExtensions.SubjectAlternativeName_Id.toString()); + unresCritExts.remove(KeyUsage_Id.toString()); + unresCritExts.remove(ExtendedKeyUsage_Id.toString()); + unresCritExts.remove(SubjectAlternativeName_Id.toString()); } } + // the index of keyCertSign in the boolean KeyUsage array + private static final int KEY_CERT_SIGN = 5; /** - * Static method to verify that the key usage and extended key usage - * extension in a CA cert. The key usage extension, if present, must - * assert the keyCertSign bit. The extended key usage extension, if - * present, must include anyExtendedKeyUsage. + * Verifies the key usage extension in a CA cert. + * The key usage extension, if present, must assert the keyCertSign bit. + * The extended key usage extension is not checked (see CR 4776794 for + * more information). */ static void verifyCAKeyUsage(X509Certificate cert) throws CertPathValidatorException { String msg = "CA key usage"; if (debug != null) { debug.println("KeyChecker.verifyCAKeyUsage() ---checking " + msg - + "..."); + + "..."); } boolean[] keyUsageBits = cert.getKeyUsage(); @@ -156,7 +155,7 @@ } // throw an exception if the keyCertSign bit is not set - if (!keyUsageBits[keyCertSign]) { + if (!keyUsageBits[KEY_CERT_SIGN]) { throw new CertPathValidatorException (msg + " check failed: keyCertSign bit is not set", null, null, -1, PKIXReason.INVALID_KEY_USAGE); @@ -164,7 +163,7 @@ if (debug != null) { debug.println("KeyChecker.verifyCAKeyUsage() " + msg - + " verified."); + + " verified."); } } } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/certpath/OCSP.java --- a/src/share/classes/sun/security/provider/certpath/OCSP.java Thu Sep 07 23:37:21 2017 -0700 +++ b/src/share/classes/sun/security/provider/certpath/OCSP.java Sat Feb 03 21:37:28 2018 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2013, 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 @@ -32,8 +32,10 @@ import java.net.HttpURLConnection; import java.security.cert.CertificateException; import java.security.cert.CertPathValidatorException; +import java.security.cert.CertPathValidatorException.BasicReason; import java.security.cert.CRLReason; import java.security.cert.Extension; +import java.security.cert.TrustAnchor; import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.Collections; @@ -41,13 +43,14 @@ import java.util.List; import java.util.Map; -import static sun.security.provider.certpath.OCSPResponse.*; import sun.security.action.GetIntegerAction; import sun.security.util.Debug; +import sun.security.validator.Validator; import sun.security.x509.AccessDescription; import sun.security.x509.AuthorityInfoAccessExtension; import sun.security.x509.GeneralName; import sun.security.x509.GeneralNameInterface; +import sun.security.x509.PKIXExtensions; import sun.security.x509.URIName; import sun.security.x509.X509CertImpl; @@ -92,44 +95,6 @@ private OCSP() {} - /** - * Obtains the revocation status of a certificate using OCSP using the most - * common defaults. The OCSP responder URI is retrieved from the - * certificate's AIA extension. The OCSP responder certificate is assumed - * to be the issuer's certificate (or issued by the issuer CA). - * - * @param cert the certificate to be checked - * @param issuerCert the issuer certificate - * @return the RevocationStatus - * @throws IOException if there is an exception connecting to or - * communicating with the OCSP responder - * @throws CertPathValidatorException if an exception occurs while - * encoding the OCSP Request or validating the OCSP Response - */ - public static RevocationStatus check(X509Certificate cert, - X509Certificate issuerCert) - throws IOException, CertPathValidatorException { - CertId certId = null; - URI responderURI = null; - try { - X509CertImpl certImpl = X509CertImpl.toImpl(cert); - responderURI = getResponderURI(certImpl); - if (responderURI == null) { - throw new CertPathValidatorException - ("No OCSP Responder URI in certificate"); - } - certId = new CertId(issuerCert, certImpl.getSerialNumberObject()); - } catch (CertificateException ce) { - throw new CertPathValidatorException - ("Exception while encoding OCSPRequest", ce); - } catch (IOException ioe) { - throw new CertPathValidatorException - ("Exception while encoding OCSPRequest", ioe); - } - OCSPResponse ocspResponse = check(Collections.singletonList(certId), - responderURI, Collections.singletonList(issuerCert), null); - return (RevocationStatus) ocspResponse.getSingleResponse(certId); - } /** * Obtains the revocation status of a certificate using OCSP. @@ -146,59 +111,62 @@ * @throws CertPathValidatorException if an exception occurs while * encoding the OCSP Request or validating the OCSP Response */ + + // Called by com.sun.deploy.security.TrustDecider public static RevocationStatus check(X509Certificate cert, - X509Certificate issuerCert, URI responderURI, - X509Certificate responderCert, Date date) - throws IOException, CertPathValidatorException { - - return check(cert, issuerCert, responderURI, - Collections.singletonList(responderCert), date); + X509Certificate issuerCert, + URI responderURI, + X509Certificate responderCert, + Date date) + throws IOException, CertPathValidatorException + { + return check(cert, issuerCert, responderURI, responderCert, date, + Collections.emptyList(), Validator.VAR_GENERIC); } - /** - * Obtains the revocation status of a certificate using OCSP. - * - * @param cert the certificate to be checked - * @param issuerCert the issuer certificate - * @param responderURI the URI of the OCSP responder - * @param responderCerts the OCSP responder's certificates - * @param date the time the validity of the OCSP responder's certificate - * should be checked against. If null, the current time is used. - * @return the RevocationStatus - * @throws IOException if there is an exception connecting to or - * communicating with the OCSP responder - * @throws CertPathValidatorException if an exception occurs while - * encoding the OCSP Request or validating the OCSP Response - */ + public static RevocationStatus check(X509Certificate cert, - X509Certificate issuerCert, URI responderURI, - List responderCerts, Date date) - throws IOException, CertPathValidatorException { + X509Certificate issuerCert, URI responderURI, + X509Certificate responderCert, Date date, List extensions, + String variant) + throws IOException, CertPathValidatorException + { + return check(cert, responderURI, null, issuerCert, responderCert, date, + extensions, variant); + } - CertId certId = null; + public static RevocationStatus check(X509Certificate cert, + URI responderURI, TrustAnchor anchor, X509Certificate issuerCert, + X509Certificate responderCert, Date date, + List extensions, String variant) + throws IOException, CertPathValidatorException + { + CertId certId; try { X509CertImpl certImpl = X509CertImpl.toImpl(cert); certId = new CertId(issuerCert, certImpl.getSerialNumberObject()); - } catch (CertificateException ce) { + } catch (CertificateException | IOException e) { throw new CertPathValidatorException - ("Exception while encoding OCSPRequest", ce); - } catch (IOException ioe) { - throw new CertPathValidatorException - ("Exception while encoding OCSPRequest", ioe); + ("Exception while encoding OCSPRequest", e); } OCSPResponse ocspResponse = check(Collections.singletonList(certId), - responderURI, responderCerts, date); + responderURI, new OCSPResponse.IssuerInfo(anchor, issuerCert), + responderCert, date, extensions, variant); return (RevocationStatus) ocspResponse.getSingleResponse(certId); } /** * Checks the revocation status of a list of certificates using OCSP. * - * @param certs the CertIds to be checked + * @param certIds the CertIds to be checked * @param responderURI the URI of the OCSP responder - * @param responderCerts the OCSP responder's certificates + * @param issuerInfo the issuer's certificate and/or subject and public key + * @param responderCert the OCSP responder's certificate * @param date the time the validity of the OCSP responder's certificate * should be checked against. If null, the current time is used. + * @param extensions zero or more OCSP extensions to be included in the + * request. If no extensions are requested, an empty {@code List} must + * be used. A {@code null} value is not allowed. * @return the OCSPResponse * @throws IOException if there is an exception connecting to or * communicating with the OCSP responder @@ -206,21 +174,59 @@ * encoding the OCSP Request or validating the OCSP Response */ static OCSPResponse check(List certIds, URI responderURI, - List responderCerts, Date date) - throws IOException, CertPathValidatorException { + OCSPResponse.IssuerInfo issuerInfo, + X509Certificate responderCert, Date date, + List extensions, String variant) + throws IOException, CertPathValidatorException + { + byte[] nonce = null; + for (Extension ext : extensions) { + if (ext.getId().equals(PKIXExtensions.OCSPNonce_Id.toString())) { + nonce = ext.getValue(); + } + } - byte[] bytes = null; + OCSPResponse ocspResponse = null; try { - OCSPRequest request = new OCSPRequest(certIds); - bytes = request.encodeBytes(); + byte[] response = getOCSPBytes(certIds, responderURI, extensions); + ocspResponse = new OCSPResponse(response); + + // verify the response + ocspResponse.verify(certIds, issuerInfo, responderCert, date, + nonce, variant); } catch (IOException ioe) { - throw new CertPathValidatorException - ("Exception while encoding OCSPRequest", ioe); + throw new CertPathValidatorException( + "Unable to determine revocation status due to network error", + ioe, null, -1, BasicReason.UNDETERMINED_REVOCATION_STATUS); } + return ocspResponse; + } + + + /** + * Send an OCSP request, then read and return the OCSP response bytes. + * + * @param certIds the CertIds to be checked + * @param responderURI the URI of the OCSP responder + * @param extensions zero or more OCSP extensions to be included in the + * request. If no extensions are requested, an empty {@code List} must + * be used. A {@code null} value is not allowed. + * + * @return the OCSP response bytes + * + * @throws IOException if there is an exception connecting to or + * communicating with the OCSP responder + */ + public static byte[] getOCSPBytes(List certIds, URI responderURI, + List extensions) throws IOException { + OCSPRequest request = new OCSPRequest(certIds, extensions); + byte[] bytes = request.encodeBytes(); + InputStream in = null; OutputStream out = null; byte[] response = null; + try { URL url = responderURI.toURL(); if (debug != null) { @@ -279,37 +285,7 @@ } } } - - OCSPResponse ocspResponse = null; - try { - ocspResponse = new OCSPResponse(response, date, responderCerts); - } catch (IOException ioe) { - // response decoding exception - throw new CertPathValidatorException(ioe); - } - if (ocspResponse.getResponseStatus() != ResponseStatus.SUCCESSFUL) { - throw new CertPathValidatorException - ("OCSP response error: " + ocspResponse.getResponseStatus()); - } - - // Check that the response includes a response for all of the - // certs that were supplied in the request - for (CertId certId : certIds) { - SingleResponse sr = ocspResponse.getSingleResponse(certId); - if (sr == null) { - if (debug != null) { - debug.println("No response found for CertId: " + certId); - } - throw new CertPathValidatorException( - "OCSP response does not include a response for a " + - "certificate supplied in the OCSP request"); - } - if (debug != null) { - debug.println("Status of certificate (with serial number " + - certId.getSerialNumber() + ") is: " + sr.getCertStatus()); - } - } - return ocspResponse; + return response; } /** @@ -320,6 +296,7 @@ * @param cert the certificate * @return the URI of the OCSP Responder, or null if not specified */ + // Called by com.sun.deploy.security.TrustDecider public static URI getResponderURI(X509Certificate cert) { try { return getResponderURI(X509CertImpl.toImpl(cert)); @@ -340,7 +317,7 @@ List descriptions = aia.getAccessDescriptions(); for (AccessDescription description : descriptions) { - if (description.getAccessMethod().equals((Object) + if (description.getAccessMethod().equals( AccessDescription.Ad_OCSP_Id)) { GeneralName generalName = description.getAccessLocation(); @@ -379,4 +356,12 @@ */ Map getSingleExtensions(); } + + static class NetworkFailureException extends CertPathValidatorException { + private static final long serialVersionUID = 0l; + + NetworkFailureException(Throwable t) { + super(t); + } + } } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/certpath/OCSPChecker.java --- a/src/share/classes/sun/security/provider/certpath/OCSPChecker.java Thu Sep 07 23:37:21 2017 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,522 +0,0 @@ -/* - * Copyright (c) 2003, 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 - * 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.certpath; - -import java.io.IOException; -import java.math.BigInteger; -import java.util.*; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.security.Security; -import java.security.cert.Certificate; -import java.security.cert.CertificateException; -import java.security.cert.CertificateRevokedException; -import java.security.cert.CertPath; -import java.security.cert.CertPathValidatorException; -import java.security.cert.CertPathValidatorException.BasicReason; -import java.security.cert.CertStore; -import java.security.cert.CertStoreException; -import java.security.cert.PKIXCertPathChecker; -import java.security.cert.PKIXParameters; -import java.security.cert.TrustAnchor; -import java.security.cert.X509Certificate; -import java.security.cert.X509CertSelector; -import java.net.URI; -import java.net.URISyntaxException; -import javax.security.auth.x500.X500Principal; - -import static sun.security.provider.certpath.OCSP.*; -import sun.security.util.Debug; -import sun.security.x509.*; - -/** - * OCSPChecker is a PKIXCertPathChecker that uses the - * Online Certificate Status Protocol (OCSP) as specified in RFC 2560 - * - * http://www.ietf.org/rfc/rfc2560.txt. - * - * @author Ram Marti - */ -class OCSPChecker extends PKIXCertPathChecker { - - static final String OCSP_ENABLE_PROP = "ocsp.enable"; - static final String OCSP_URL_PROP = "ocsp.responderURL"; - static final String OCSP_CERT_SUBJECT_PROP = - "ocsp.responderCertSubjectName"; - static final String OCSP_CERT_ISSUER_PROP = "ocsp.responderCertIssuerName"; - static final String OCSP_CERT_NUMBER_PROP = - "ocsp.responderCertSerialNumber"; - - private static final String HEX_DIGITS = "0123456789ABCDEFabcdef"; - private static final Debug DEBUG = Debug.getInstance("certpath"); - private static final boolean dump = false; - - private int remainingCerts; - - private X509Certificate[] certs; - - private CertPath cp; - - private PKIXParameters pkixParams; - - private boolean onlyEECert = false; - - /** - * Default Constructor - * - * @param certPath the X509 certification path - * @param pkixParams the input PKIX parameter set - * @throws CertPathValidatorException if OCSPChecker can not be created - */ - OCSPChecker(CertPath certPath, PKIXParameters pkixParams) - throws CertPathValidatorException { - this(certPath, pkixParams, false); - } - - OCSPChecker(CertPath certPath, PKIXParameters pkixParams, boolean onlyEECert) - throws CertPathValidatorException { - - this.cp = certPath; - this.pkixParams = pkixParams; - this.onlyEECert = onlyEECert; - List tmp = cp.getCertificates(); - certs = tmp.toArray(new X509Certificate[tmp.size()]); - init(false); - } - - /** - * Initializes the internal state of the checker from parameters - * specified in the constructor - */ - @Override - public void init(boolean forward) throws CertPathValidatorException { - if (!forward) { - remainingCerts = certs.length + 1; - } else { - throw new CertPathValidatorException( - "Forward checking not supported"); - } - } - - @Override public boolean isForwardCheckingSupported() { - return false; - } - - @Override public Set getSupportedExtensions() { - return Collections.emptySet(); - } - - /** - * Sends an OCSPRequest for the certificate to the OCSP Server and - * processes the response back from the OCSP Server. - * - * @param cert the Certificate - * @param unresolvedCritExts the unresolved critical extensions - * @exception CertPathValidatorException Exception is thrown if the - * certificate has been revoked. - */ - @Override - public void check(Certificate cert, Collection unresolvedCritExts) - throws CertPathValidatorException { - - // Decrement the certificate counter - remainingCerts--; - - X509CertImpl currCertImpl = null; - try { - currCertImpl = X509CertImpl.toImpl((X509Certificate)cert); - } catch (CertificateException ce) { - throw new CertPathValidatorException(ce); - } - - if (onlyEECert && currCertImpl.getBasicConstraints() != -1) { - if (DEBUG != null) { - DEBUG.println("Skipping revocation check, not end entity cert"); - } - return; - } - - /* - * OCSP security property values, in the following order: - * 1. ocsp.responderURL - * 2. ocsp.responderCertSubjectName - * 3. ocsp.responderCertIssuerName - * 4. ocsp.responderCertSerialNumber - */ - // should cache these properties to avoid calling every time? - String[] properties = getOCSPProperties(); - - // Check whether OCSP is feasible before seeking cert information - URI uri = getOCSPServerURI(currCertImpl, properties[0]); - - // When responder's subject name is set then the issuer/serial - // properties are ignored - X500Principal responderSubjectName = null; - X500Principal responderIssuerName = null; - BigInteger responderSerialNumber = null; - if (properties[1] != null) { - responderSubjectName = new X500Principal(properties[1]); - } else if (properties[2] != null && properties[3] != null) { - responderIssuerName = new X500Principal(properties[2]); - // remove colon or space separators - String value = stripOutSeparators(properties[3]); - responderSerialNumber = new BigInteger(value, 16); - } else if (properties[2] != null || properties[3] != null) { - throw new CertPathValidatorException( - "Must specify both ocsp.responderCertIssuerName and " + - "ocsp.responderCertSerialNumber properties"); - } - - // If the OCSP responder cert properties are set then the - // identified cert must be located in the trust anchors or - // in the cert stores. - boolean seekResponderCert = false; - if (responderSubjectName != null || responderIssuerName != null) { - seekResponderCert = true; - } - - // Set the issuer certificate to the next cert in the chain - // (unless we're processing the final cert). - X509Certificate issuerCert = null; - boolean seekIssuerCert = true; - List responderCerts = new ArrayList(); - - if (remainingCerts < certs.length) { - issuerCert = certs[remainingCerts]; - seekIssuerCert = false; // done - - // By default, the OCSP responder's cert is the same as the - // issuer of the cert being validated. - if (!seekResponderCert) { - responderCerts.add(issuerCert); - if (DEBUG != null) { - DEBUG.println("Responder's certificate is the same " + - "as the issuer of the certificate being validated"); - } - } - } - - // Check anchor certs for: - // - the issuer cert (of the cert being validated) - // - the OCSP responder's cert - if (seekIssuerCert || seekResponderCert) { - - if (DEBUG != null && seekResponderCert) { - DEBUG.println("Searching trust anchors for issuer or " + - "responder certificate"); - } - - // Extract the anchor certs - Iterator anchors - = pkixParams.getTrustAnchors().iterator(); - if (!anchors.hasNext()) { - throw new CertPathValidatorException( - "Must specify at least one trust anchor"); - } - - X500Principal certIssuerName = - currCertImpl.getIssuerX500Principal(); - byte[] certIssuerKeyId = null; - - while (anchors.hasNext() && (seekIssuerCert || seekResponderCert)) { - - TrustAnchor anchor = anchors.next(); - X509Certificate anchorCert = anchor.getTrustedCert(); - X500Principal anchorSubjectName = - anchorCert.getSubjectX500Principal(); - - if (dump) { - System.out.println("Issuer DN is " + certIssuerName); - System.out.println("Subject DN is " + anchorSubjectName); - } - - // Check if anchor cert is the issuer cert - if (seekIssuerCert && - certIssuerName.equals(anchorSubjectName)) { - - // Retrieve the issuer's key identifier - if (certIssuerKeyId == null) { - certIssuerKeyId = currCertImpl.getIssuerKeyIdentifier(); - if (certIssuerKeyId == null) { - if (DEBUG != null) { - DEBUG.println("No issuer key identifier (AKID) " - + "in the certificate being validated"); - } - } - } - - // Check that the key identifiers match, if both are present - byte[] anchorKeyId = null; - if (certIssuerKeyId != null && - (anchorKeyId = - OCSPChecker.getKeyId(anchorCert)) != null) { - if (!Arrays.equals(certIssuerKeyId, anchorKeyId)) { - continue; // try next cert - } - - if (DEBUG != null) { - DEBUG.println("Issuer certificate key ID: " + - String.format("0x%0" + - (certIssuerKeyId.length * 2) + "x", - new BigInteger(1, certIssuerKeyId))); - } - } - - issuerCert = anchorCert; - seekIssuerCert = false; // done - - // By default, the OCSP responder's cert is the same as - // the issuer of the cert being validated. - if (!seekResponderCert && responderCerts.isEmpty()) { - responderCerts.add(anchorCert); - if (DEBUG != null) { - DEBUG.println("Responder's certificate is the" + - " same as the issuer of the certificate " + - "being validated"); - } - } - } - - // Check if anchor cert is the responder cert - if (seekResponderCert) { - // Satisfy the responder subject name property only, or - // satisfy the responder issuer name and serial number - // properties only - if ((responderSubjectName != null && - responderSubjectName.equals(anchorSubjectName)) || - (responderIssuerName != null && - responderSerialNumber != null && - responderIssuerName.equals( - anchorCert.getIssuerX500Principal()) && - responderSerialNumber.equals( - anchorCert.getSerialNumber()))) { - - responderCerts.add(anchorCert); - } - } - } - if (issuerCert == null) { - throw new CertPathValidatorException( - "No trusted certificate for " + currCertImpl.getIssuerDN()); - } - - // Check cert stores if responder cert has not yet been found - if (seekResponderCert) { - if (DEBUG != null) { - DEBUG.println("Searching cert stores for responder's " + - "certificate"); - } - X509CertSelector filter = null; - if (responderSubjectName != null) { - filter = new X509CertSelector(); - filter.setSubject(responderSubjectName); - } else if (responderIssuerName != null && - responderSerialNumber != null) { - filter = new X509CertSelector(); - filter.setIssuer(responderIssuerName); - filter.setSerialNumber(responderSerialNumber); - } - if (filter != null) { - List certStores = pkixParams.getCertStores(); - for (CertStore certStore : certStores) { - try { - for (Certificate storeCert : certStore.getCertificates(filter)) { - if (storeCert instanceof X509Certificate) { - responderCerts.add((X509Certificate) storeCert); - } - } - } catch (CertStoreException cse) { - // ignore and try next certStore - if (DEBUG != null) { - DEBUG.println("CertStore exception:" + cse); - } - continue; - } - } - } - } - } - - // Could not find the certificate identified in the OCSP properties - if (seekResponderCert && responderCerts.isEmpty()) { - throw new CertPathValidatorException( - "Cannot find the responder's certificate " + - "(set using the OCSP security properties)."); - } - - if (DEBUG != null) { - DEBUG.println("Located " + responderCerts.size() + - " trusted responder certificate(s)"); - } - - // The algorithm constraints of the OCSP trusted responder certificate - // does not need to be checked in this code. The constraints will be - // checked when the responder's certificate is validated. - - CertId certId = null; - OCSPResponse response = null; - try { - certId = new CertId - (issuerCert, currCertImpl.getSerialNumberObject()); - response = OCSP.check(Collections.singletonList(certId), uri, - responderCerts, pkixParams.getDate()); - } catch (Exception e) { - if (e instanceof CertPathValidatorException) { - throw (CertPathValidatorException) e; - } else { - // Wrap exceptions in CertPathValidatorException so that - // we can fallback to CRLs, if enabled. - throw new CertPathValidatorException(e); - } - } - - RevocationStatus rs = (RevocationStatus) response.getSingleResponse(certId); - RevocationStatus.CertStatus certStatus = rs.getCertStatus(); - if (certStatus == RevocationStatus.CertStatus.REVOKED) { - Throwable t = new CertificateRevokedException( - rs.getRevocationTime(), rs.getRevocationReason(), - responderCerts.get(0).getSubjectX500Principal(), - rs.getSingleExtensions()); - throw new CertPathValidatorException(t.getMessage(), t, - null, -1, BasicReason.REVOKED); - } else if (certStatus == RevocationStatus.CertStatus.UNKNOWN) { - throw new CertPathValidatorException( - "Certificate's revocation status is unknown", null, cp, - (remainingCerts - 1), - BasicReason.UNDETERMINED_REVOCATION_STATUS); - } - } - - /* - * The OCSP security property values are in the following order: - * 1. ocsp.responderURL - * 2. ocsp.responderCertSubjectName - * 3. ocsp.responderCertIssuerName - * 4. ocsp.responderCertSerialNumber - */ - private static URI getOCSPServerURI(X509CertImpl currCertImpl, - String responderURL) throws CertPathValidatorException { - - if (responderURL != null) { - try { - return new URI(responderURL); - } catch (URISyntaxException e) { - throw new CertPathValidatorException(e); - } - } - - // Examine the certificate's AuthorityInfoAccess extension - AuthorityInfoAccessExtension aia = - currCertImpl.getAuthorityInfoAccessExtension(); - if (aia == null) { - throw new CertPathValidatorException( - "Must specify the location of an OCSP Responder"); - } - - List descriptions = aia.getAccessDescriptions(); - for (AccessDescription description : descriptions) { - if (description.getAccessMethod().equals((Object) - AccessDescription.Ad_OCSP_Id)) { - - GeneralName generalName = description.getAccessLocation(); - if (generalName.getType() == GeneralNameInterface.NAME_URI) { - URIName uri = (URIName) generalName.getName(); - return uri.getURI(); - } - } - } - - throw new CertPathValidatorException( - "Cannot find the location of the OCSP Responder"); - } - - /* - * Retrieves the values of the OCSP security properties. - */ - private static String[] getOCSPProperties() { - final String[] properties = new String[4]; - - AccessController.doPrivileged( - new PrivilegedAction() { - public Void run() { - properties[0] = Security.getProperty(OCSP_URL_PROP); - properties[1] = - Security.getProperty(OCSP_CERT_SUBJECT_PROP); - properties[2] = - Security.getProperty(OCSP_CERT_ISSUER_PROP); - properties[3] = - Security.getProperty(OCSP_CERT_NUMBER_PROP); - return null; - } - }); - - return properties; - } - - /* - * Removes any non-hexadecimal characters from a string. - */ - private static String stripOutSeparators(String value) { - char[] chars = value.toCharArray(); - StringBuilder hexNumber = new StringBuilder(); - for (int i = 0; i < chars.length; i++) { - if (HEX_DIGITS.indexOf(chars[i]) != -1) { - hexNumber.append(chars[i]); - } - } - return hexNumber.toString(); - } - - /* - * Returns the subject key identifier for the supplied certificate, or null - */ - static byte[] getKeyId(X509Certificate cert) { - X509CertImpl certImpl = null; - byte[] certSubjectKeyId = null; - - try { - certImpl = X509CertImpl.toImpl(cert); - certSubjectKeyId = certImpl.getSubjectKeyIdentifier(); - - if (certSubjectKeyId == null) { - if (DEBUG != null) { - DEBUG.println("No subject key identifier (SKID) in the " + - "certificate (Subject: " + - cert.getSubjectX500Principal() + ")"); - } - } - - } catch (CertificateException e) { - // Ignore certificate - if (DEBUG != null) { - DEBUG.println("Error parsing X.509 certificate (Subject: " + - cert.getSubjectX500Principal() + ") " + e); - } - } - - return certSubjectKeyId; - } -} diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/certpath/OCSPRequest.java --- a/src/share/classes/sun/security/provider/certpath/OCSPRequest.java Thu Sep 07 23:37:21 2017 -0700 +++ b/src/share/classes/sun/security/provider/certpath/OCSPRequest.java Sat Feb 03 21:37:28 2018 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2009, 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 @@ -26,14 +26,17 @@ package sun.security.provider.certpath; import java.io.IOException; +import java.security.cert.Extension; import java.util.Collections; import java.util.List; + import sun.misc.HexDumpEncoder; import sun.security.util.*; +import sun.security.x509.PKIXExtensions; /** * This class can be used to generate an OCSP request and send it over - * an outputstream. Currently we do not support signing requests + * an output stream. Currently we do not support signing requests. * The OCSP Request is specified in RFC 2560 and * the ASN.1 definition is as follows: *

@@ -75,21 +78,29 @@
 class OCSPRequest {
 
     private static final Debug debug = Debug.getInstance("certpath");
-    private static final boolean dump = Debug.isOn("ocsp");
+    private static final boolean dump = debug != null && Debug.isOn("ocsp");
 
     // List of request CertIds
     private final List certIds;
+    private final List extensions;
+    private byte[] nonce;
 
     /*
      * Constructs an OCSPRequest. This constructor is used
      * to construct an unsigned OCSP Request for a single user cert.
      */
     OCSPRequest(CertId certId) {
-        this.certIds = Collections.singletonList(certId);
+        this(Collections.singletonList(certId));
     }
 
     OCSPRequest(List certIds) {
         this.certIds = certIds;
+        this.extensions = Collections.emptyList();
+    }
+
+    OCSPRequest(List certIds, List extensions) {
+        this.certIds = certIds;
+        this.extensions = extensions;
     }
 
     byte[] encodeBytes() throws IOException {
@@ -104,7 +115,21 @@
         }
 
         tmp.write(DerValue.tag_Sequence, requestsOut);
-        // No extensions supported
+        if (!extensions.isEmpty()) {
+            DerOutputStream extOut = new DerOutputStream();
+            for (Extension ext : extensions) {
+                ext.encode(extOut);
+                if (ext.getId().equals(
+                        PKIXExtensions.OCSPNonce_Id.toString())) {
+                    nonce = ext.getValue();
+                }
+            }
+            DerOutputStream extsOut = new DerOutputStream();
+            extsOut.write(DerValue.tag_Sequence, extOut);
+            tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT,
+                                         true, (byte)2), extsOut);
+        }
+
         DerOutputStream tbsRequest = new DerOutputStream();
         tbsRequest.write(DerValue.tag_Sequence, tmp);
 
@@ -116,8 +141,8 @@
 
         if (dump) {
             HexDumpEncoder hexEnc = new HexDumpEncoder();
-            debug.println("\nOCSPRequest bytes... ");
-            debug.println(hexEnc.encode(bytes) + "\n");
+            debug.println("OCSPRequest bytes...\n\n" +
+                hexEnc.encode(bytes) + "\n");
         }
 
         return bytes;
@@ -126,4 +151,8 @@
     List getCertIds() {
         return certIds;
     }
+
+    byte[] getNonce() {
+        return nonce;
+    }
 }
diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/certpath/OCSPResponse.java
--- a/src/share/classes/sun/security/provider/certpath/OCSPResponse.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/sun/security/provider/certpath/OCSPResponse.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2015, 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
@@ -34,12 +34,16 @@
 import java.security.cert.CRLReason;
 import java.security.cert.TrustAnchor;
 import java.security.cert.X509Certificate;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
+import javax.security.auth.x500.X500Principal;
+
 import sun.misc.HexDumpEncoder;
 import sun.security.action.GetIntegerAction;
 import sun.security.x509.*;
@@ -126,15 +130,12 @@
         SIG_REQUIRED,          // Must sign the request
         UNAUTHORIZED           // Request unauthorized
     };
-    private static ResponseStatus[] rsvalues = ResponseStatus.values();
+    private static final ResponseStatus[] rsvalues = ResponseStatus.values();
 
-    private static final Debug DEBUG = Debug.getInstance("certpath");
-    private static final boolean dump = Debug.isOn("ocsp");
+    private static final Debug debug = Debug.getInstance("certpath");
+    private static final boolean dump = debug != null && Debug.isOn("ocsp");
     private static final ObjectIdentifier OCSP_BASIC_RESPONSE_OID =
         ObjectIdentifier.newInternal(new int[] { 1, 3, 6, 1, 5, 5, 7, 48, 1, 1});
-    private static final ObjectIdentifier OCSP_NONCE_EXTENSION_OID =
-        ObjectIdentifier.newInternal(new int[] { 1, 3, 6, 1, 5, 5, 7, 48, 1, 2});
-
     private static final int CERT_STATUS_GOOD = 0;
     private static final int CERT_STATUS_REVOKED = 1;
     private static final int CERT_STATUS_UNKNOWN = 2;
@@ -146,9 +147,6 @@
     // Object identifier for the OCSPSigning key purpose
     private static final String KP_OCSP_SIGNING_OID = "1.3.6.1.5.5.7.3.9";
 
-    private final ResponseStatus responseStatus;
-    private final Map singleResponseMap;
-
     // Default maximum clock skew in milliseconds (15 minutes)
     // allowed when checking validity of OCSP responses
     private static final int DEFAULT_MAX_CLOCK_SKEW = 900000;
@@ -176,20 +174,30 @@
     }
 
     // an array of all of the CRLReasons (used in SingleResponse)
-    private static CRLReason[] values = CRLReason.values();
+    private static final CRLReason[] values = CRLReason.values();
+
+    private final ResponseStatus responseStatus;
+    private final Map singleResponseMap;
+    private final AlgorithmId sigAlgId;
+    private final byte[] signature;
+    private final byte[] tbsResponseData;
+    private final byte[] responseNonce;
+    private List certs;
+    private X509CertImpl signerCert = null;
+    private final ResponderId respId;
+    private Date producedAtDate = null;
+    private final Map responseExtensions;
 
     /*
      * Create an OCSP response from its ASN.1 DER encoding.
+     *
+     * @param bytes The DER-encoded bytes for an OCSP response
      */
-    OCSPResponse(byte[] bytes, Date dateCheckedAgainst,
-        List responderCerts)
-        throws IOException, CertPathValidatorException {
-
-        // OCSPResponse
+    public OCSPResponse(byte[] bytes) throws IOException {
         if (dump) {
             HexDumpEncoder hexEnc = new HexDumpEncoder();
-            DEBUG.println("\nOCSPResponse bytes...");
-            DEBUG.println(hexEnc.encode(bytes) + "\n");
+            debug.println("OCSPResponse bytes...\n\n" +
+                hexEnc.encode(bytes) + "\n");
         }
         DerValue der = new DerValue(bytes);
         if (der.tag != DerValue.tag_Sequence) {
@@ -206,12 +214,19 @@
             // unspecified responseStatus
             throw new IOException("Unknown OCSPResponse status: " + status);
         }
-        if (DEBUG != null) {
-            DEBUG.println("OCSP response status: " + responseStatus);
+        if (debug != null) {
+            debug.println("OCSP response status: " + responseStatus);
         }
         if (responseStatus != ResponseStatus.SUCCESSFUL) {
             // no need to continue, responseBytes are not set.
             singleResponseMap = Collections.emptyMap();
+            certs = new ArrayList();
+            sigAlgId = null;
+            signature = null;
+            tbsResponseData = null;
+            responseNonce = null;
+            responseExtensions = Collections.emptyMap();
+            respId = null;
             return;
         }
 
@@ -231,15 +246,15 @@
         derIn = tmp.data;
         ObjectIdentifier responseType = derIn.getOID();
         if (responseType.equals((Object)OCSP_BASIC_RESPONSE_OID)) {
-            if (DEBUG != null) {
-                DEBUG.println("OCSP response type: basic");
+            if (debug != null) {
+                debug.println("OCSP response type: basic");
             }
         } else {
-            if (DEBUG != null) {
-                DEBUG.println("OCSP response type: " + responseType);
+            if (debug != null) {
+                debug.println("OCSP response type: " + responseType);
             }
             throw new IOException("Unsupported OCSP response type: " +
-                responseType);
+                                  responseType);
         }
 
         // BasicOCSPResponse
@@ -254,7 +269,7 @@
         DerValue responseData = seqTmp[0];
 
         // Need the DER encoded ResponseData to verify the signature later
-        byte[] responseDataDer = seqTmp[0].toByteArray();
+        tbsResponseData = seqTmp[0].toByteArray();
 
         // tbsResponseData
         if (responseData.tag != DerValue.tag_Sequence) {
@@ -280,79 +295,54 @@
         }
 
         // responderID
-        short tag = (byte)(seq.tag & 0x1f);
-        if (tag == NAME_TAG) {
-            if (DEBUG != null) {
-                X500Name responderName = new X500Name(seq.getData());
-                DEBUG.println("OCSP Responder name: " + responderName);
-            }
-        } else if (tag == KEY_TAG) {
-            seq = seq.data.getDerValue(); // consume tag and length
-            if (DEBUG != null) {
-                byte[] responderKeyId = seq.getOctetString();
-                DEBUG.println("OCSP Responder key ID: " +
-                    String.format("0x%0" +
-                        (responderKeyId.length * 2) + "x",
-                            new BigInteger(1, responderKeyId)));
-            }
-        } else {
-            throw new IOException("Bad encoding in responderID element of " +
-                "OCSP response: expected ASN.1 context specific tag 1 or 2");
+        respId = new ResponderId(seq.toByteArray());
+        if (debug != null) {
+            debug.println("Responder ID: " + respId);
         }
 
         // producedAt
         seq = seqDerIn.getDerValue();
-        if (DEBUG != null) {
-            Date producedAtDate = seq.getGeneralizedTime();
-            DEBUG.println("OCSP response produced at: " + producedAtDate);
+        producedAtDate = seq.getGeneralizedTime();
+        if (debug != null) {
+            debug.println("OCSP response produced at: " + producedAtDate);
         }
 
         // responses
         DerValue[] singleResponseDer = seqDerIn.getSequence(1);
-        singleResponseMap
-            = new HashMap(singleResponseDer.length);
-        if (DEBUG != null) {
-            DEBUG.println("OCSP number of SingleResponses: "
-                + singleResponseDer.length);
+        singleResponseMap = new HashMap<>(singleResponseDer.length);
+        if (debug != null) {
+            debug.println("OCSP number of SingleResponses: "
+                          + singleResponseDer.length);
         }
-        for (int i = 0; i < singleResponseDer.length; i++) {
-            SingleResponse singleResponse
-                = new SingleResponse(singleResponseDer[i], dateCheckedAgainst);
+        for (DerValue srDer : singleResponseDer) {
+            SingleResponse singleResponse = new SingleResponse(srDer);
             singleResponseMap.put(singleResponse.getCertId(), singleResponse);
         }
 
         // responseExtensions
+        Map tmpExtMap = new HashMap<>();
         if (seqDerIn.available() > 0) {
             seq = seqDerIn.getDerValue();
             if (seq.isContextSpecific((byte)1)) {
-                DerValue[] responseExtDer = seq.data.getSequence(3);
-                for (int i = 0; i < responseExtDer.length; i++) {
-                    Extension responseExtension
-                        = new Extension(responseExtDer[i]);
-                    if (DEBUG != null) {
-                        DEBUG.println("OCSP extension: " + responseExtension);
-                    }
-                    if (responseExtension.getExtensionId().equals((Object)
-                        OCSP_NONCE_EXTENSION_OID)) {
-                        /*
-                        ocspNonce =
-                            responseExtension[i].getExtensionValue();
-                         */
-                    } else if (responseExtension.isCritical())  {
-                        throw new IOException(
-                            "Unsupported OCSP critical extension: " +
-                            responseExtension.getExtensionId());
-                    }
-                }
+                tmpExtMap = parseExtensions(seq);
             }
         }
+        responseExtensions = tmpExtMap;
+
+        // Attach the nonce value if found in the extension map
+        Extension nonceExt = (Extension)tmpExtMap.get(
+                PKIXExtensions.OCSPNonce_Id.toString());
+        responseNonce = (nonceExt != null) ?
+                nonceExt.getExtensionValue() : null;
+        if (debug != null && responseNonce != null) {
+            debug.println("Response nonce: " + Arrays.toString(responseNonce));
+        }
 
         // signatureAlgorithmId
-        AlgorithmId sigAlgId = AlgorithmId.parse(seqTmp[1]);
+        sigAlgId = AlgorithmId.parse(seqTmp[1]);
 
         // signature
-        byte[] signature = seqTmp[2].getBitString();
-        X509CertImpl[] x509Certs = null;
+        signature = seqTmp[2].getBitString();
 
         // if seq[3] is available , then it is a sequence of certificates
         if (seqTmp.length > 3) {
@@ -362,234 +352,413 @@
                 throw new IOException("Bad encoding in certs element of " +
                     "OCSP response: expected ASN.1 context specific tag 0.");
             }
-            DerValue[] certs = seqCert.getData().getSequence(3);
-            x509Certs = new X509CertImpl[certs.length];
+            DerValue[] derCerts = seqCert.getData().getSequence(3);
+            certs = new ArrayList(derCerts.length);
             try {
-                for (int i = 0; i < certs.length; i++) {
-                    x509Certs[i] = new X509CertImpl(certs[i].toByteArray());
+                for (int i = 0; i < derCerts.length; i++) {
+                    X509CertImpl cert =
+                        new X509CertImpl(derCerts[i].toByteArray());
+                    certs.add(cert);
+
+                    if (debug != null) {
+                        debug.println("OCSP response cert #" + (i + 1) + ": " +
+                            cert.getSubjectX500Principal());
+                    }
                 }
             } catch (CertificateException ce) {
                 throw new IOException("Bad encoding in X509 Certificate", ce);
             }
+        } else {
+            certs = Collections.emptyList();
+        }
+    }
+
+    void verify(List certIds, IssuerInfo issuerInfo,
+            X509Certificate responderCert, Date date, byte[] nonce,
+            String variant)
+        throws CertPathValidatorException
+    {
+        if (responseStatus != ResponseStatus.SUCCESSFUL) {
+            throw new CertPathValidatorException
+                ("OCSP response error: " + responseStatus);
         }
 
-        // By default, the OCSP responder's cert is the same as the issuer of
-        // the cert being validated. The issuer cert is the first in the list.
-        X509Certificate trustedResponderCert = responderCerts.get(0);
-
-        // Check whether the signer cert returned by the responder is trusted
-        if (x509Certs != null && x509Certs[0] != null) {
-            X509CertImpl signerCert = x509Certs[0];
+        // Check that the response includes a response for all of the
+        // certs that were supplied in the request
+        for (CertId certId : certIds) {
+            SingleResponse sr = getSingleResponse(certId);
+            if (sr == null) {
+                if (debug != null) {
+                    debug.println("No response found for CertId: " + certId);
+                }
+                throw new CertPathValidatorException(
+                    "OCSP response does not include a response for a " +
+                    "certificate supplied in the OCSP request");
+            }
+            if (debug != null) {
+                debug.println("Status of certificate (with serial number " +
+                    certId.getSerialNumber() + ") is: " + sr.getCertStatus());
+            }
+        }
 
-            if (DEBUG != null) {
-                DEBUG.println("Signer certificate name: " +
-                    signerCert.getSubjectX500Principal());
-
-                byte[] signerKeyId = signerCert.getSubjectKeyIdentifier();
-                if (signerKeyId != null) {
-                    DEBUG.println("Signer certificate key ID: " +
-                        String.format("0x%0" + (signerKeyId.length * 2) + "x",
-                                new BigInteger(1, signerKeyId)));
+        // Locate the signer cert
+        if (signerCert == null) {
+            // Add the Issuing CA cert and/or Trusted Responder cert to the list
+            // of certs from the OCSP response
+            try {
+                if (issuerInfo.getCertificate() != null) {
+                    certs.add(X509CertImpl.toImpl(issuerInfo.getCertificate()));
                 }
+                if (responderCert != null) {
+                    certs.add(X509CertImpl.toImpl(responderCert));
+                }
+            } catch (CertificateException ce) {
+                throw new CertPathValidatorException(
+                    "Invalid issuer or trusted responder certificate", ce);
             }
 
-            byte[] certIssuerKeyId = null;
-
-            for (X509Certificate responderCert : responderCerts) {
-
-                // First check if signer cert matches a trusted responder cert
-                if (signerCert.equals(responderCert)) {
-
-                    // signer cert is trusted, now verify the signed response
-                    trustedResponderCert = responderCert;
-                    if (DEBUG != null) {
-                        DEBUG.println("Signer certificate is a trusted " +
-                            "responder");
+            if (respId.getType() == ResponderId.Type.BY_NAME) {
+                X500Principal rName = respId.getResponderName();
+                for (X509CertImpl cert : certs) {
+                    if (cert.getSubjectX500Principal().equals(rName)) {
+                        signerCert = cert;
+                        break;
                     }
-                    break;
-
-                // Next check if signer cert was issued by a trusted responder
-                // cert
-                } else if (signerCert.getIssuerX500Principal().equals(
-                    responderCert.getSubjectX500Principal())) {
-
-                    // Retrieve the issuer's key identifier
-                    if (certIssuerKeyId == null) {
-                        certIssuerKeyId = signerCert.getIssuerKeyIdentifier();
-                        if (certIssuerKeyId == null) {
-                            if (DEBUG != null) {
-                                DEBUG.println("No issuer key identifier (AKID) "
-                                    + "in the signer certificate");
-                            }
-                        }
-                    }
-
-                    // Check that the key identifiers match, if both are present
-                    byte[] responderKeyId = null;
-                    if (certIssuerKeyId != null &&
-                        (responderKeyId =
-                            OCSPChecker.getKeyId(responderCert)) != null) {
-                        if (!Arrays.equals(certIssuerKeyId, responderKeyId)) {
-                            continue; // try next cert
-                        }
-
-                        if (DEBUG != null) {
-                            DEBUG.println("Issuer certificate key ID: " +
-                                String.format("0x%0" +
-                                    (certIssuerKeyId.length * 2) + "x",
-                                        new BigInteger(1, certIssuerKeyId)));
-                        }
-                    }
-
-                    // Check for the OCSPSigning key purpose
-                    try {
-                        List keyPurposes =
-                            signerCert.getExtendedKeyUsage();
-                        if (keyPurposes == null ||
-                            !keyPurposes.contains(KP_OCSP_SIGNING_OID)) {
-
-                            continue; // try next cert
+                }
+            } else if (respId.getType() == ResponderId.Type.BY_KEY) {
+                KeyIdentifier ridKeyId = respId.getKeyIdentifier();
+                for (X509CertImpl cert : certs) {
+                    // Match responder's key identifier against the cert's SKID
+                    // This will match if the SKID is encoded using the 160-bit
+                    // SHA-1 hash method as defined in RFC 5280.
+                    KeyIdentifier certKeyId = cert.getSubjectKeyId();
+                    if (certKeyId != null && ridKeyId.equals(certKeyId)) {
+                        signerCert = cert;
+                        break;
+                    } else {
+                        // The certificate does not have a SKID or may have
+                        // been using a different algorithm (ex: see RFC 7093).
+                        // Check if the responder's key identifier matches
+                        // against a newly generated key identifier of the
+                        // cert's public key using the 160-bit SHA-1 method.
+                        try {
+                            certKeyId = new KeyIdentifier(cert.getPublicKey());
+                        } catch (IOException e) {
+                            // ignore
                         }
-                    } catch (CertificateParsingException cpe) {
-
-                        continue; // try next cert
-                    }
-
-                    // Check algorithm constraints specified in security
-                    // property "jdk.certpath.disabledAlgorithms".
-                    AlgorithmChecker algChecker = new AlgorithmChecker(
-                                        new TrustAnchor(responderCert, null));
-                    algChecker.init(false);
-                    algChecker.check(signerCert,
-                        Collections.emptySet());
-
-                    // Check the date validity
-                    try {
-                        if (dateCheckedAgainst == null) {
-                            signerCert.checkValidity();
-                        } else {
-                            signerCert.checkValidity(dateCheckedAgainst);
-                        }
-                    } catch (GeneralSecurityException e) {
-                        if (DEBUG != null) {
-                            DEBUG.println("Responder's certificate not within" +
-                            " the validity period " + e);
+                        if (ridKeyId.equals(certKeyId)) {
+                            signerCert = cert;
+                            break;
                         }
-                        continue; // try next cert
-                    }
-
-                    // Check for revocation
-                    //
-                    // A CA may specify that an OCSP client can trust a
-                    // responder for the lifetime of the responder's
-                    // certificate. The CA does so by including the
-                    // extension id-pkix-ocsp-nocheck.
-                    //
-                    Extension noCheck =
-                        signerCert.getExtension(PKIXExtensions.OCSPNoCheck_Id);
-                    if (noCheck != null) {
-                        if (DEBUG != null) {
-                            DEBUG.println("Responder's certificate includes " +
-                                "the extension id-pkix-ocsp-nocheck.");
-                        }
-                    } else {
-                        // we should do the revocation checking of the
-                        // authorized responder in a future update.
-                    }
-
-                    // Verify the signature
-                    try {
-                        signerCert.verify(responderCert.getPublicKey());
-                        trustedResponderCert = signerCert;
-                        // cert is trusted, now verify the signed response
-                        if (DEBUG != null) {
-                            DEBUG.println("Signer certificate was issued by " +
-                                "a trusted responder");
-                        }
-                        break;
-
-                    } catch (GeneralSecurityException e) {
-                        trustedResponderCert = null;
                     }
                 }
             }
         }
 
+        // Check whether the signer cert returned by the responder is trusted
+        if (signerCert != null) {
+            // Check if the response is signed by the issuing CA
+            if (signerCert.getSubjectX500Principal().equals(
+                    issuerInfo.getName()) &&
+                    signerCert.getPublicKey().equals(
+                            issuerInfo.getPublicKey())) {
+                if (debug != null) {
+                    debug.println("OCSP response is signed by the target's " +
+                        "Issuing CA");
+                }
+                // cert is trusted, now verify the signed response
+
+            // Check if the response is signed by a trusted responder
+            } else if (signerCert.equals(responderCert)) {
+                if (debug != null) {
+                    debug.println("OCSP response is signed by a Trusted " +
+                        "Responder");
+                }
+                // cert is trusted, now verify the signed response
+
+            // Check if the response is signed by an authorized responder
+            } else if (signerCert.getIssuerX500Principal().equals(
+                    issuerInfo.getName())) {
+
+                // Check for the OCSPSigning key purpose
+                try {
+                    List keyPurposes = signerCert.getExtendedKeyUsage();
+                    if (keyPurposes == null ||
+                        !keyPurposes.contains(KP_OCSP_SIGNING_OID)) {
+                        throw new CertPathValidatorException(
+                            "Responder's certificate not valid for signing " +
+                            "OCSP responses");
+                    }
+                } catch (CertificateParsingException cpe) {
+                    // assume cert is not valid for signing
+                    throw new CertPathValidatorException(
+                        "Responder's certificate not valid for signing " +
+                        "OCSP responses", cpe);
+                }
+
+                // Check algorithm constraints specified in security property
+                // "jdk.certpath.disabledAlgorithms".
+                AlgorithmChecker algChecker =
+                        new AlgorithmChecker(issuerInfo.getAnchor(), date,
+                                variant);
+                algChecker.init(false);
+                algChecker.check(signerCert, Collections.emptySet());
+
+                // check the validity
+                try {
+                    if (date == null) {
+                        signerCert.checkValidity();
+                    } else {
+                        signerCert.checkValidity(date);
+                    }
+                } catch (CertificateException e) {
+                    throw new CertPathValidatorException(
+                        "Responder's certificate not within the " +
+                        "validity period", e);
+                }
+
+                // check for revocation
+                //
+                // A CA may specify that an OCSP client can trust a
+                // responder for the lifetime of the responder's
+                // certificate. The CA does so by including the
+                // extension id-pkix-ocsp-nocheck.
+                //
+                Extension noCheck =
+                    signerCert.getExtension(PKIXExtensions.OCSPNoCheck_Id);
+                if (noCheck != null) {
+                    if (debug != null) {
+                        debug.println("Responder's certificate includes " +
+                            "the extension id-pkix-ocsp-nocheck.");
+                    }
+                } else {
+                    // we should do the revocation checking of the
+                    // authorized responder in a future update.
+                }
+
+                // verify the signature
+                try {
+                    signerCert.verify(issuerInfo.getPublicKey());
+                    if (debug != null) {
+                        debug.println("OCSP response is signed by an " +
+                            "Authorized Responder");
+                    }
+                    // cert is trusted, now verify the signed response
+
+                } catch (GeneralSecurityException e) {
+                    signerCert = null;
+                }
+            } else {
+                throw new CertPathValidatorException(
+                    "Responder's certificate is not authorized to sign " +
+                    "OCSP responses");
+            }
+        }
+
         // Confirm that the signed response was generated using the public
         // key from the trusted responder cert
-        if (trustedResponderCert != null) {
+        if (signerCert != null) {
             // Check algorithm constraints specified in security property
             // "jdk.certpath.disabledAlgorithms".
-            AlgorithmChecker.check(trustedResponderCert.getPublicKey(),
-                sigAlgId);
+            AlgorithmChecker.check(signerCert.getPublicKey(), sigAlgId, variant);
 
-            if (!verifyResponse(responseDataDer, trustedResponderCert,
-                sigAlgId, signature)) {
+            if (!verifySignature(signerCert)) {
                 throw new CertPathValidatorException(
-                    "Error verifying OCSP Responder's signature");
+                    "Error verifying OCSP Response's signature");
             }
         } else {
             // Need responder's cert in order to verify the signature
             throw new CertPathValidatorException(
-                "Responder's certificate is not trusted for signing " +
-                "OCSP responses");
+                "Unable to verify OCSP Response's signature");
+        }
+
+        if (nonce != null) {
+            if (responseNonce != null && !Arrays.equals(nonce, responseNonce)) {
+                throw new CertPathValidatorException("Nonces don't match");
+            }
+        }
+
+        // Check freshness of OCSPResponse
+        long now = (date == null) ? System.currentTimeMillis() : date.getTime();
+        Date nowPlusSkew = new Date(now + MAX_CLOCK_SKEW);
+        Date nowMinusSkew = new Date(now - MAX_CLOCK_SKEW);
+        for (SingleResponse sr : singleResponseMap.values()) {
+            if (debug != null) {
+                String until = "";
+                if (sr.nextUpdate != null) {
+                    until = " until " + sr.nextUpdate;
+                }
+                debug.println("OCSP response validity interval is from " +
+                        sr.thisUpdate + until);
+                debug.println("Checking validity of OCSP response on: " +
+                        new Date(now));
+            }
+
+            // Check that the test date is within the validity interval:
+            //   [ thisUpdate - MAX_CLOCK_SKEW,
+            //     MAX(thisUpdate, nextUpdate) + MAX_CLOCK_SKEW ]
+            if (nowPlusSkew.before(sr.thisUpdate) ||
+                    nowMinusSkew.after(
+                    sr.nextUpdate != null ? sr.nextUpdate : sr.thisUpdate))
+            {
+                throw new CertPathValidatorException(
+                                      "Response is unreliable: its validity " +
+                                      "interval is out-of-date");
+            }
         }
     }
 
     /**
      * Returns the OCSP ResponseStatus.
+     *
+     * @return the {@code ResponseStatus} for this OCSP response
      */
-    ResponseStatus getResponseStatus() {
+    public ResponseStatus getResponseStatus() {
         return responseStatus;
     }
 
     /*
      * Verify the signature of the OCSP response.
-     * The responder's cert is implicitly trusted.
      */
-    private boolean verifyResponse(byte[] responseData, X509Certificate cert,
-        AlgorithmId sigAlgId, byte[] signBytes)
+    private boolean verifySignature(X509Certificate cert)
         throws CertPathValidatorException {
 
         try {
             Signature respSignature = Signature.getInstance(sigAlgId.getName());
             respSignature.initVerify(cert.getPublicKey());
-            respSignature.update(responseData);
+            respSignature.update(tbsResponseData);
 
-            if (respSignature.verify(signBytes)) {
-                if (DEBUG != null) {
-                    DEBUG.println("Verified signature of OCSP Responder");
+            if (respSignature.verify(signature)) {
+                if (debug != null) {
+                    debug.println("Verified signature of OCSP Response");
                 }
                 return true;
 
             } else {
-                if (DEBUG != null) {
-                    DEBUG.println(
-                        "Error verifying signature of OCSP Responder");
+                if (debug != null) {
+                    debug.println(
+                        "Error verifying signature of OCSP Response");
                 }
                 return false;
             }
-        } catch (InvalidKeyException ike) {
-            throw new CertPathValidatorException(ike);
-        } catch (NoSuchAlgorithmException nsae) {
-            throw new CertPathValidatorException(nsae);
-        } catch (SignatureException se) {
-            throw new CertPathValidatorException(se);
+        } catch (InvalidKeyException | NoSuchAlgorithmException |
+                 SignatureException e)
+        {
+            throw new CertPathValidatorException(e);
         }
     }
 
     /**
      * Returns the SingleResponse of the specified CertId, or null if
      * there is no response for that CertId.
+     *
+     * @param certId the {@code CertId} for a {@code SingleResponse} to be
+     * searched for in the OCSP response.
+     *
+     * @return the {@code SingleResponse} for the provided {@code CertId},
+     * or {@code null} if it is not found.
      */
-    SingleResponse getSingleResponse(CertId certId) {
+    public SingleResponse getSingleResponse(CertId certId) {
         return singleResponseMap.get(certId);
     }
 
+    /**
+     * Return a set of all CertIds in this {@code OCSPResponse}
+     *
+     * @return an unmodifiable set containing every {@code CertId} in this
+     *      response.
+     */
+    public Set getCertIds() {
+        return Collections.unmodifiableSet(singleResponseMap.keySet());
+    }
+
+    /*
+     * Returns the certificate for the authority that signed the OCSP response.
+     */
+    X509Certificate getSignerCertificate() {
+        return signerCert; // set in verify()
+    }
+
+    /**
+     * Get the {@code ResponderId} from this {@code OCSPResponse}
+     *
+     * @return the {@code ResponderId} from this response or {@code null}
+     *      if no responder ID is in the body of the response (e.g. a
+     *      response with a status other than SUCCESS.
+     */
+    public ResponderId getResponderId() {
+        return respId;
+    }
+
+    /**
+     * Provide a String representation of an OCSPResponse
+     *
+     * @return a human-readable representation of the OCSPResponse
+     */
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("OCSP Response:\n");
+        sb.append("Response Status: ").append(responseStatus).append("\n");
+        sb.append("Responder ID: ").append(respId).append("\n");
+        sb.append("Produced at: ").append(producedAtDate).append("\n");
+        int count = singleResponseMap.size();
+        sb.append(count).append(count == 1 ?
+                " response:\n" : " responses:\n");
+        for (SingleResponse sr : singleResponseMap.values()) {
+            sb.append(sr).append("\n");
+        }
+        if (responseExtensions != null && responseExtensions.size() > 0) {
+            count = responseExtensions.size();
+            sb.append(count).append(count == 1 ?
+                    " extension:\n" : " extensions:\n");
+            for (String extId : responseExtensions.keySet()) {
+                sb.append(responseExtensions.get(extId)).append("\n");
+            }
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Build a String-Extension map from DER encoded data.
+     * @param derVal A {@code DerValue} object built from a SEQUENCE of
+     *      extensions
+     *
+     * @return a {@code Map} using the OID in string form as the keys.  If no
+     *      extensions are found or an empty SEQUENCE is passed in, then
+     *      an empty {@code Map} will be returned.
+     *
+     * @throws IOException if any decoding errors occur.
+     */
+    private static Map
+        parseExtensions(DerValue derVal) throws IOException {
+        DerValue[] extDer = derVal.data.getSequence(3);
+        Map extMap =
+                new HashMap<>(extDer.length);
+
+        for (DerValue extDerVal : extDer) {
+            Extension ext = new Extension(extDerVal);
+            if (debug != null) {
+                debug.println("Extension: " + ext);
+            }
+            // We don't support any extensions yet. Therefore, if it
+            // is critical we must throw an exception because we
+            // don't know how to process it.
+            if (ext.isCritical()) {
+                throw new IOException("Unsupported OCSP critical extension: " +
+                        ext.getExtensionId());
+            }
+            extMap.put(ext.getId(), ext);
+        }
+
+        return extMap;
+    }
+
     /*
      * A class representing a single OCSP response.
      */
-    final static class SingleResponse implements OCSP.RevocationStatus {
+    public static final class SingleResponse implements OCSP.RevocationStatus {
         private final CertId certId;
         private final CertStatus certStatus;
         private final Date thisUpdate;
@@ -633,13 +802,13 @@
                     revocationReason = CRLReason.UNSPECIFIED;
                 }
                 // RevokedInfo
-                if (DEBUG != null) {
-                    DEBUG.println("Revocation time: " + revocationTime);
-                    DEBUG.println("Revocation reason: " + revocationReason);
+                if (debug != null) {
+                    debug.println("Revocation time: " + revocationTime);
+                    debug.println("Revocation reason: " + revocationReason);
                 }
             } else {
                 revocationTime = null;
-                revocationReason = CRLReason.UNSPECIFIED;
+                revocationReason = null;
                 if (tag == CERT_STATUS_GOOD) {
                     certStatus = CertStatus.GOOD;
                 } else if (tag == CERT_STATUS_UNKNOWN) {
@@ -650,105 +819,131 @@
             }
 
             thisUpdate = tmp.getGeneralizedTime();
-
-            if (tmp.available() == 0)  {
-                // we are done
-                nextUpdate = null;
-            } else {
-                derVal = tmp.getDerValue();
-                tag = (byte)(derVal.tag & 0x1f);
-                if (tag == 0) {
-                    // next update
-                    nextUpdate = derVal.data.getGeneralizedTime();
+            if (debug != null) {
+                debug.println("thisUpdate: " + thisUpdate);
+            }
 
-                    if (tmp.available() == 0)  {
-                        // we are done
-                    } else {
-                        derVal = tmp.getDerValue();
-                        tag = (byte)(derVal.tag & 0x1f);
-                    }
-                } else {
-                    nextUpdate = null;
-                }
-            }
-            // singleExtensions
+            // Parse optional fields like nextUpdate and singleExtensions
+            Date tmpNextUpdate = null;
+            Map tmpMap = null;
+
+            // Check for the first optional item, it could be nextUpdate
+            // [CONTEXT 0] or singleExtensions [CONTEXT 1]
             if (tmp.available() > 0) {
                 derVal = tmp.getDerValue();
-                if (derVal.isContextSpecific((byte)1)) {
-                    DerValue[] singleExtDer = derVal.data.getSequence(3);
-                    singleExtensions =
-                        new HashMap
-                            (singleExtDer.length);
-                    for (int i = 0; i < singleExtDer.length; i++) {
-                        Extension ext = new Extension(singleExtDer[i]);
-                        if (DEBUG != null) {
-                            DEBUG.println("OCSP single extension: " + ext);
+
+                // nextUpdate processing
+                if (derVal.isContextSpecific((byte)0)) {
+                    tmpNextUpdate = derVal.data.getGeneralizedTime();
+                    if (debug != null) {
+                        debug.println("nextUpdate: " + tmpNextUpdate);
+                    }
+
+                    // If more data exists in the singleResponse, it
+                    // can only be singleExtensions.  Get this DER value
+                    // for processing in the next block
+                    derVal = tmp.available() > 0 ? tmp.getDerValue() : null;
+                }
+
+                // singleExtensions processing
+                if (derVal != null) {
+                    if (derVal.isContextSpecific((byte)1)) {
+                        tmpMap = parseExtensions(derVal);
+
+                        // There should not be any other items in the
+                        // singleResponse at this point.
+                        if (tmp.available() > 0) {
+                            throw new IOException(tmp.available() +
+                                " bytes of additional data in singleResponse");
                         }
-                        // We don't support any extensions yet. Therefore, if it
-                        // is critical we must throw an exception because we
-                        // don't know how to process it.
-                        if (ext.isCritical()) {
-                            throw new IOException(
-                                "Unsupported OCSP critical extension: " +
-                                ext.getExtensionId());
-                        }
-                        singleExtensions.put(ext.getId(), ext);
+                    } else {
+                        // Unknown item in the singleResponse
+                        throw new IOException("Unsupported singleResponse " +
+                            "item, tag = " + String.format("%02X", derVal.tag));
                     }
-                } else {
-                    singleExtensions = Collections.emptyMap();
                 }
-            } else {
-                singleExtensions = Collections.emptyMap();
             }
 
-            long now = System.currentTimeMillis();
-            Date nowPlusSkew = new Date(now + MAX_CLOCK_SKEW);
-            Date nowMinusSkew = new Date(now - MAX_CLOCK_SKEW);
-            if (DEBUG != null) {
-                String until = "";
-                if (nextUpdate != null) {
-                    until = " until " + nextUpdate;
+            nextUpdate = tmpNextUpdate;
+            singleExtensions = (tmpMap != null) ? tmpMap :
+                    Collections.emptyMap();
+            if (debug != null) {
+                for (java.security.cert.Extension ext :
+                        singleExtensions.values()) {
+                   debug.println("singleExtension: " + ext);
                 }
-                DEBUG.println("OCSP response validity interval is from " +
-                              thisUpdate + until);
-                DEBUG.println("Checking validity of OCSP response on: " +
-                    new Date(now));
-            }
-            // Check that the test date is within the validity interval:
-            //   [ thisUpdate - MAX_CLOCK_SKEW,
-            //     MAX(thisUpdate, nextUpdate) + MAX_CLOCK_SKEW ]
-            if (nowPlusSkew.before(thisUpdate) ||
-                nowMinusSkew.after(
-                    nextUpdate != null ? nextUpdate : thisUpdate)) {
-
-                if (DEBUG != null) {
-                    DEBUG.println("Response is unreliable: its validity " +
-                        "interval is out-of-date");
-                }
-                throw new IOException("Response is unreliable: its validity " +
-                    "interval is out-of-date");
             }
         }
 
         /*
          * Return the certificate's revocation status code
          */
-        @Override public CertStatus getCertStatus() {
+        @Override
+        public CertStatus getCertStatus() {
             return certStatus;
         }
 
-        private CertId getCertId() {
+        /**
+         * Get the Cert ID that this SingleResponse is for.
+         *
+         * @return the {@code CertId} for this {@code SingleResponse}
+         */
+        public CertId getCertId() {
             return certId;
         }
 
-        @Override public Date getRevocationTime() {
-            return (Date) revocationTime.clone();
+        /**
+         * Get the {@code thisUpdate} field from this {@code SingleResponse}.
+         *
+         * @return a {@link Date} object containing the thisUpdate date
+         */
+        public Date getThisUpdate() {
+            return (thisUpdate != null ? (Date) thisUpdate.clone() : null);
+        }
+
+        /**
+         * Get the {@code nextUpdate} field from this {@code SingleResponse}.
+         *
+         * @return a {@link Date} object containing the nexUpdate date or
+         * {@code null} if a nextUpdate field is not present in the response.
+         */
+        public Date getNextUpdate() {
+            return (nextUpdate != null ? (Date) nextUpdate.clone() : null);
         }
 
-        @Override public CRLReason getRevocationReason() {
+        /**
+         * Get the {@code revocationTime} field from this
+         * {@code SingleResponse}.
+         *
+         * @return a {@link Date} object containing the revocationTime date or
+         * {@code null} if the {@code SingleResponse} does not have a status
+         * of {@code REVOKED}.
+         */
+        @Override
+        public Date getRevocationTime() {
+            return (revocationTime != null ? (Date) revocationTime.clone() :
+                    null);
+        }
+
+        /**
+         * Get the {@code revocationReason} field for the
+         * {@code SingleResponse}.
+         *
+         * @return a {@link CRLReason} containing the revocation reason, or
+         * {@code null} if a revocation reason was not provided or the
+         * response status is not {@code REVOKED}.
+         */
+        @Override
+        public CRLReason getRevocationReason() {
             return revocationReason;
         }
 
+        /**
+         * Get the {@code singleExtensions} for this {@code SingleResponse}.
+         *
+         * @return a {@link Map} of {@link Extension} objects, keyed by
+         * their OID value in string form.
+         */
         @Override
         public Map getSingleExtensions() {
             return Collections.unmodifiableMap(singleExtensions);
@@ -759,18 +954,117 @@
          */
         @Override public String toString() {
             StringBuilder sb = new StringBuilder();
-            sb.append("SingleResponse:  \n");
+            sb.append("SingleResponse:\n");
             sb.append(certId);
-            sb.append("\nCertStatus: "+ certStatus + "\n");
+            sb.append("\nCertStatus: ").append(certStatus).append("\n");
             if (certStatus == CertStatus.REVOKED) {
-                sb.append("revocationTime is " + revocationTime + "\n");
-                sb.append("revocationReason is " + revocationReason + "\n");
+                sb.append("revocationTime is ");
+                sb.append(revocationTime).append("\n");
+                sb.append("revocationReason is ");
+                sb.append(revocationReason).append("\n");
             }
-            sb.append("thisUpdate is " + thisUpdate + "\n");
+            sb.append("thisUpdate is ").append(thisUpdate).append("\n");
             if (nextUpdate != null) {
-                sb.append("nextUpdate is " + nextUpdate + "\n");
+                sb.append("nextUpdate is ").append(nextUpdate).append("\n");
+            }
+            for (java.security.cert.Extension ext : singleExtensions.values()) {
+                sb.append("singleExtension: ");
+                sb.append(ext.toString()).append("\n");
             }
             return sb.toString();
         }
     }
+
+    /**
+     * Helper class that allows consumers to pass in issuer information.  This
+     * will always consist of the issuer's name and public key, but may also
+     * contain a certificate if the originating data is in that form.  The
+     * trust anchor for the certificate chain will be included for certpath
+     * disabled algorithm checking.
+     */
+    static final class IssuerInfo {
+        private final TrustAnchor anchor;
+        private final X509Certificate certificate;
+        private final X500Principal name;
+        private final PublicKey pubKey;
+
+        IssuerInfo(TrustAnchor anchor) {
+            this(anchor, (anchor != null) ? anchor.getTrustedCert() : null);
+        }
+
+        IssuerInfo(X509Certificate issuerCert) {
+            this(null, issuerCert);
+        }
+
+        IssuerInfo(TrustAnchor anchor, X509Certificate issuerCert) {
+            if (anchor == null && issuerCert == null) {
+                throw new NullPointerException("TrustAnchor and issuerCert " +
+                        "cannot be null");
+            }
+            this.anchor = anchor;
+            if (issuerCert != null) {
+                name = issuerCert.getSubjectX500Principal();
+                pubKey = issuerCert.getPublicKey();
+                certificate = issuerCert;
+            } else {
+                name = anchor.getCA();
+                pubKey = anchor.getCAPublicKey();
+                certificate = anchor.getTrustedCert();
+            }
+        }
+
+        /**
+         * Get the certificate in this IssuerInfo if present.
+         *
+         * @return the {@code X509Certificate} used to create this IssuerInfo
+         * object, or {@code null} if a certificate was not used in its
+         * creation.
+         */
+        X509Certificate getCertificate() {
+            return certificate;
+        }
+
+        /**
+         * Get the name of this issuer.
+         *
+         * @return an {@code X500Principal} corresponding to this issuer's
+         * name.  If derived from an issuer's {@code X509Certificate} this
+         * would be equivalent to the certificate subject name.
+         */
+        X500Principal getName() {
+            return name;
+        }
+
+        /**
+         * Get the public key for this issuer.
+         *
+         * @return a {@code PublicKey} for this issuer.
+         */
+        PublicKey getPublicKey() {
+            return pubKey;
+        }
+
+        /**
+         * Get the TrustAnchor for the certificate chain.
+         *
+         * @return a {@code TrustAnchor}.
+         */
+        TrustAnchor getAnchor() {
+            return anchor;
+        }
+
+        /**
+         * Create a string representation of this IssuerInfo.
+         *
+         * @return a {@code String} form of this IssuerInfo object.
+         */
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append("Issuer Info:\n");
+            sb.append("Name: ").append(name.toString()).append("\n");
+            sb.append("Public Key:\n").append(pubKey.toString()).append("\n");
+            return sb.toString();
+        }
+    }
 }
diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/certpath/PKIX.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/security/provider/certpath/PKIX.java	Sat Feb 03 21:37:28 2018 -0800
@@ -0,0 +1,330 @@
+/*
+ * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package sun.security.provider.certpath;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyStore;
+import java.security.PublicKey;
+import java.security.Timestamp;
+import java.security.cert.*;
+import java.security.interfaces.DSAPublicKey;
+import java.util.*;
+import javax.security.auth.x500.X500Principal;
+
+import sun.security.util.Debug;
+
+/**
+ * Common utility methods and classes used by the PKIX CertPathValidator and
+ * CertPathBuilder implementation.
+ */
+class PKIX {
+
+    private static final Debug debug = Debug.getInstance("certpath");
+
+    private PKIX() { }
+
+    static boolean isDSAPublicKeyWithoutParams(PublicKey publicKey) {
+        return (publicKey instanceof DSAPublicKey &&
+               ((DSAPublicKey)publicKey).getParams() == null);
+    }
+
+    static ValidatorParams checkParams(CertPath cp, CertPathParameters params)
+        throws InvalidAlgorithmParameterException
+    {
+        if (!(params instanceof PKIXParameters)) {
+            throw new InvalidAlgorithmParameterException("inappropriate "
+                + "params, must be an instance of PKIXParameters");
+        }
+        return new ValidatorParams(cp, (PKIXParameters)params);
+    }
+
+    static BuilderParams checkBuilderParams(CertPathParameters params)
+        throws InvalidAlgorithmParameterException
+    {
+        if (!(params instanceof PKIXBuilderParameters)) {
+            throw new InvalidAlgorithmParameterException("inappropriate "
+                + "params, must be an instance of PKIXBuilderParameters");
+        }
+        return new BuilderParams((PKIXBuilderParameters)params);
+    }
+
+    /**
+     * PKIXParameters that are shared by the PKIX CertPathValidator
+     * implementation. Provides additional functionality and avoids
+     * unnecessary cloning.
+     */
+    static class ValidatorParams {
+        private final PKIXParameters params;
+        private CertPath certPath;
+        private List checkers;
+        private List stores;
+        private boolean gotDate;
+        private Date date;
+        private Set policies;
+        private boolean gotConstraints;
+        private CertSelector constraints;
+        private Set anchors;
+        private List certs;
+        private Timestamp timestamp;
+        private String variant;
+
+        ValidatorParams(CertPath cp, PKIXParameters params)
+            throws InvalidAlgorithmParameterException
+        {
+            this(params);
+            if (!cp.getType().equals("X.509") && !cp.getType().equals("X509")) {
+                throw new InvalidAlgorithmParameterException("inappropriate "
+                    + "CertPath type specified, must be X.509 or X509");
+            }
+            this.certPath = cp;
+        }
+
+        ValidatorParams(PKIXParameters params)
+            throws InvalidAlgorithmParameterException
+        {
+            if (params instanceof PKIXExtendedParameters) {
+                timestamp = ((PKIXExtendedParameters) params).getTimestamp();
+                variant = ((PKIXExtendedParameters) params).getVariant();
+            }
+
+            this.anchors = params.getTrustAnchors();
+            // Make sure that none of the trust anchors include name constraints
+            // (not supported).
+            for (TrustAnchor anchor : this.anchors) {
+                if (anchor.getNameConstraints() != null) {
+                    throw new InvalidAlgorithmParameterException
+                        ("name constraints in trust anchor not supported");
+                }
+            }
+            this.params = params;
+        }
+
+        CertPath certPath() {
+            return certPath;
+        }
+        // called by CertPathBuilder after path has been built
+        void setCertPath(CertPath cp) {
+            this.certPath = cp;
+        }
+        List certificates() {
+            if (certs == null) {
+                if (certPath == null) {
+                    certs = Collections.emptyList();
+                } else {
+                    // Reverse the ordering for validation so that the target
+                    // cert is the last certificate
+                    @SuppressWarnings("unchecked")
+                    List xc = new ArrayList<>
+                        ((List)certPath.getCertificates());
+                    Collections.reverse(xc);
+                    certs = xc;
+                }
+            }
+            return certs;
+        }
+        List certPathCheckers() {
+            if (checkers == null)
+                checkers = params.getCertPathCheckers();
+            return checkers;
+        }
+        List certStores() {
+            if (stores == null)
+                stores = params.getCertStores();
+            return stores;
+        }
+        Date date() {
+            if (!gotDate) {
+                date = params.getDate();
+                if (date == null)
+                    date = new Date();
+                gotDate = true;
+            }
+            return date;
+        }
+        Set initialPolicies() {
+            if (policies == null)
+                policies = params.getInitialPolicies();
+            return policies;
+        }
+        CertSelector targetCertConstraints() {
+            if (!gotConstraints) {
+                constraints = params.getTargetCertConstraints();
+                gotConstraints = true;
+            }
+            return constraints;
+        }
+        Set trustAnchors() {
+            return anchors;
+        }
+        boolean revocationEnabled() {
+            return params.isRevocationEnabled();
+        }
+        boolean policyMappingInhibited() {
+            return params.isPolicyMappingInhibited();
+        }
+        boolean explicitPolicyRequired() {
+            return params.isExplicitPolicyRequired();
+        }
+        boolean policyQualifiersRejected() {
+            return params.getPolicyQualifiersRejected();
+        }
+        String sigProvider() { return params.getSigProvider(); }
+        boolean anyPolicyInhibited() { return params.isAnyPolicyInhibited(); }
+
+        // in rare cases we need access to the original params, for example
+        // in order to clone CertPathCheckers before building a new chain
+        PKIXParameters getPKIXParameters() {
+            return params;
+        }
+
+        Timestamp timestamp() {
+            return timestamp;
+        }
+
+        String variant() {
+            return variant;
+        }
+    }
+
+    static class BuilderParams extends ValidatorParams {
+        private PKIXBuilderParameters params;
+        private boolean buildForward = true;
+        private List stores;
+        private X500Principal targetSubject;
+
+        BuilderParams(PKIXBuilderParameters params)
+            throws InvalidAlgorithmParameterException
+        {
+            super(params);
+            checkParams(params);
+        }
+        private void checkParams(PKIXBuilderParameters params)
+            throws InvalidAlgorithmParameterException
+        {
+            CertSelector sel = targetCertConstraints();
+            if (!(sel instanceof X509CertSelector)) {
+                throw new InvalidAlgorithmParameterException("the "
+                    + "targetCertConstraints parameter must be an "
+                    + "X509CertSelector");
+            }
+            if (params instanceof SunCertPathBuilderParameters) {
+                buildForward =
+                    ((SunCertPathBuilderParameters)params).getBuildForward();
+            }
+            this.params = params;
+            this.targetSubject = getTargetSubject(
+                certStores(), (X509CertSelector)targetCertConstraints());
+        }
+        @Override List certStores() {
+            if (stores == null) {
+                // reorder CertStores so that local CertStores are tried first
+                stores = new ArrayList<>(params.getCertStores());
+                Collections.sort(stores, new CertStoreComparator());
+            }
+            return stores;
+        }
+        int maxPathLength() { return params.getMaxPathLength(); }
+        boolean buildForward() { return buildForward; }
+        PKIXBuilderParameters params() { return params; }
+        X500Principal targetSubject() { return targetSubject; }
+
+        /**
+         * Returns the target subject DN from the first X509Certificate that
+         * is fetched that matches the specified X509CertSelector.
+         */
+        private static X500Principal getTargetSubject(List stores,
+                                                      X509CertSelector sel)
+            throws InvalidAlgorithmParameterException
+        {
+            X500Principal subject = sel.getSubject();
+            if (subject != null) {
+                return subject;
+            }
+            X509Certificate cert = sel.getCertificate();
+            if (cert != null) {
+                subject = cert.getSubjectX500Principal();
+            }
+            if (subject != null) {
+                return subject;
+            }
+            for (CertStore store : stores) {
+                try {
+                    Collection certs =
+                        (Collection)
+                            store.getCertificates(sel);
+                    if (!certs.isEmpty()) {
+                        X509Certificate xc =
+                            (X509Certificate)certs.iterator().next();
+                        return xc.getSubjectX500Principal();
+                    }
+                } catch (CertStoreException e) {
+                    // ignore but log it
+                    if (debug != null) {
+                        debug.println("BuilderParams.getTargetSubjectDN: " +
+                            "non-fatal exception retrieving certs: " + e);
+                        e.printStackTrace();
+                    }
+                }
+            }
+            throw new InvalidAlgorithmParameterException
+                ("Could not determine unique target subject");
+        }
+    }
+
+    /**
+     * A CertStoreException with additional information about the type of
+     * CertStore that generated the exception.
+     */
+    static class CertStoreTypeException extends CertStoreException {
+        private static final long serialVersionUID = 7463352639238322556L;
+
+        private final String type;
+
+        CertStoreTypeException(String type, CertStoreException cse) {
+            super(cse.getMessage(), cse.getCause());
+            this.type = type;
+        }
+        String getType() {
+            return type;
+        }
+    }
+
+    /**
+     * Comparator that orders CertStores so that local CertStores come before
+     * remote CertStores.
+     */
+    private static class CertStoreComparator implements Comparator {
+        @Override
+        public int compare(CertStore store1, CertStore store2) {
+            if (store1.getType().equals("Collection") ||
+                store1.getCertStoreParameters() instanceof
+                CollectionCertStoreParameters) {
+                return -1;
+            } else {
+                return 1;
+            }
+        }
+    }
+}
diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java
--- a/src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2015, 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
@@ -25,55 +25,37 @@
 
 package sun.security.provider.certpath;
 
-import java.security.AccessController;
+import java.io.IOException;
 import java.security.InvalidAlgorithmParameterException;
-import java.security.cert.CertPath;
-import java.security.cert.CertPathParameters;
-import java.security.cert.CertPathValidatorException;
-import java.security.cert.CertPathValidatorSpi;
-import java.security.cert.CertPathValidatorResult;
-import java.security.cert.PKIXCertPathChecker;
-import java.security.cert.PKIXCertPathValidatorResult;
-import java.security.cert.PKIXParameters;
-import java.security.cert.PKIXReason;
-import java.security.cert.PolicyNode;
-import java.security.cert.TrustAnchor;
-import java.security.cert.X509Certificate;
-import java.util.Collections;
-import java.util.List;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.Set;
-import sun.security.action.GetBooleanSecurityPropertyAction;
+import java.security.cert.*;
+import java.util.*;
+
+import sun.security.provider.certpath.PKIX.ValidatorParams;
+import sun.security.x509.X509CertImpl;
 import sun.security.util.Debug;
 
-import sun.security.x509.X509CertImpl;
-
-
 /**
  * This class implements the PKIX validation algorithm for certification
  * paths consisting exclusively of X509Certificates. It uses
  * the specified input parameter set (which must be a
- * PKIXParameters object) and signature provider (if any).
+ * PKIXParameters object).
  *
  * @since       1.4
  * @author      Yassir Elley
  */
-public class PKIXCertPathValidator extends CertPathValidatorSpi {
+public final class PKIXCertPathValidator extends CertPathValidatorSpi {
 
     private static final Debug debug = Debug.getInstance("certpath");
-    private Date testDate;
-    private List userCheckers;
-    private String sigProvider;
-    private BasicChecker basicChecker;
-    private boolean ocspEnabled = false;
-    private boolean onlyEECert = false;
 
     /**
      * Default constructor.
      */
     public PKIXCertPathValidator() {}
 
+    public CertPathChecker engineGetRevocationChecker() {
+        return new RevocationChecker();
+    }
+
     /**
      * Validates a certification path consisting exclusively of
      * X509Certificates using the PKIX validation algorithm,
@@ -81,98 +63,67 @@
      * The input parameter set must be a PKIXParameters object.
      *
      * @param cp the X509 certification path
-     * @param param the input PKIX parameter set
+     * @param params the input PKIX parameter set
      * @return the result
-     * @exception CertPathValidatorException Exception thrown if cert path
-     * does not validate.
-     * @exception InvalidAlgorithmParameterException if the specified
-     * parameters are inappropriate for this certification path validator
+     * @throws CertPathValidatorException if cert path does not validate.
+     * @throws InvalidAlgorithmParameterException if the specified
+     *         parameters are inappropriate for this CertPathValidator
      */
+    @Override
     public CertPathValidatorResult engineValidate(CertPath cp,
-        CertPathParameters param)
+                                                  CertPathParameters params)
         throws CertPathValidatorException, InvalidAlgorithmParameterException
     {
+        ValidatorParams valParams = PKIX.checkParams(cp, params);
+        return validate(valParams);
+    }
+
+    private static PKIXCertPathValidatorResult validate(ValidatorParams params)
+        throws CertPathValidatorException
+    {
         if (debug != null)
             debug.println("PKIXCertPathValidator.engineValidate()...");
 
-        if (!(param instanceof PKIXParameters)) {
-            throw new InvalidAlgorithmParameterException("inappropriate "
-                + "parameters, must be an instance of PKIXParameters");
-        }
-
-        if (!cp.getType().equals("X.509") && !cp.getType().equals("X509")) {
-            throw new InvalidAlgorithmParameterException("inappropriate "
-                + "certification path type specified, must be X.509 or X509");
-        }
-
-        PKIXParameters pkixParam = (PKIXParameters) param;
-
-        // Make sure that none of the trust anchors include name constraints
-        // (not supported).
-        Set anchors = pkixParam.getTrustAnchors();
-        for (TrustAnchor anchor : anchors) {
-            if (anchor.getNameConstraints() != null) {
-                throw new InvalidAlgorithmParameterException
-                    ("name constraints in trust anchor not supported");
-            }
-        }
-
-        // the certpath which has been passed in (cp)
-        // has the target cert as the first certificate - we
-        // need to keep this cp so we can return it
-        // in case of an exception and for policy qualifier
-        // processing - however, for certpath validation,
-        // we need to create a reversed path, where we reverse the
-        // ordering so that the target cert is the last certificate
-
-        // Must copy elements of certList into a new modifiable List before
-        // calling Collections.reverse().
-        // If cp is not an X.509 or X509 certpath, an
-        // InvalidAlgorithmParameterException will have been thrown by now.
-        @SuppressWarnings("unchecked")
-        ArrayList certList = new ArrayList
-            ((List)cp.getCertificates());
-        if (debug != null) {
-            if (certList.isEmpty()) {
-                debug.println("PKIXCertPathValidator.engineValidate() "
-                    + "certList is empty");
-            }
-            debug.println("PKIXCertPathValidator.engineValidate() "
-                + "reversing certpath...");
-        }
-        Collections.reverse(certList);
-
-        // now certList has the target cert as the last cert and we
-        // can proceed with normal validation
-
-        populateVariables(pkixParam);
-
         // Retrieve the first certificate in the certpath
         // (to be used later in pre-screening)
-        X509Certificate firstCert = null;
+        AdaptableX509CertSelector selector = null;
+        List certList = params.certificates();
         if (!certList.isEmpty()) {
-            firstCert = certList.get(0);
+            selector = new AdaptableX509CertSelector();
+            X509Certificate firstCert = certList.get(0);
+            // check trusted certificate's subject
+            selector.setSubject(firstCert.getIssuerX500Principal());
+            /*
+             * Facilitate certification path construction with authority
+             * key identifier and subject key identifier.
+             */
+            try {
+                X509CertImpl firstCertImpl = X509CertImpl.toImpl(firstCert);
+                selector.parseAuthorityKeyIdentifierExtension(
+                            firstCertImpl.getAuthorityKeyIdentifierExtension());
+            } catch (CertificateException | IOException e) {
+                // ignore
+            }
         }
 
         CertPathValidatorException lastException = null;
 
         // We iterate through the set of trust anchors until we find
         // one that works at which time we stop iterating
-        for (TrustAnchor anchor : anchors) {
+        for (TrustAnchor anchor : params.trustAnchors()) {
             X509Certificate trustedCert = anchor.getTrustedCert();
             if (trustedCert != null) {
-                if (debug != null) {
-                    debug.println("PKIXCertPathValidator.engineValidate() "
-                        + "anchor.getTrustedCert() != null");
-                }
-
                 // if this trust anchor is not worth trying,
                 // we move on to the next one
-                if (!isWorthTrying(trustedCert, firstCert)) {
+                if (selector != null && !selector.match(trustedCert)) {
+                    if (debug != null) {
+                        debug.println("NO - don't try this trustedCert");
+                    }
                     continue;
                 }
 
                 if (debug != null) {
+                    debug.println("YES - try this trustedCert");
                     debug.println("anchor.getTrustedCert()."
                         + "getSubjectX500Principal() = "
                         + trustedCert.getSubjectX500Principal());
@@ -185,14 +136,7 @@
             }
 
             try {
-                PolicyNodeImpl rootNode = new PolicyNodeImpl(null,
-                    PolicyChecker.ANY_POLICY, null, false,
-                    Collections.singleton(PolicyChecker.ANY_POLICY), false);
-                PolicyNode policyTree =
-                    doValidate(anchor, cp, certList, pkixParam, rootNode);
-                // if this anchor works, return success
-                return new PKIXCertPathValidatorResult(anchor, policyTree,
-                    basicChecker.getPublicKey());
+                return validate(anchor, params);
             } catch (CertPathValidatorException cpe) {
                 // remember this exception
                 lastException = cpe;
@@ -210,148 +154,72 @@
              null, null, -1, PKIXReason.NO_TRUST_ANCHOR);
     }
 
-    /**
-     * Internal method to do some simple checks to see if a given cert is
-     * worth trying to validate in the chain.
-     */
-    private boolean isWorthTrying(X509Certificate trustedCert,
-          X509Certificate firstCert) {
-
-        boolean worthy = false;
-
-        if (debug != null) {
-            debug.println("PKIXCertPathValidator.isWorthTrying() checking "
-                + "if this trusted cert is worth trying ...");
-        }
-
-        if (firstCert == null) {
-            return true;
-        }
-
-        AdaptableX509CertSelector issuerSelector =
-                        new AdaptableX509CertSelector();
-
-        // check trusted certificate's subject
-        issuerSelector.setSubject(firstCert.getIssuerX500Principal());
-
-        /*
-         * Facilitate certification path construction with authority
-         * key identifier and subject key identifier.
-         */
-        try {
-            X509CertImpl firstCertImpl = X509CertImpl.toImpl(firstCert);
-            issuerSelector.parseAuthorityKeyIdentifierExtension(
-                        firstCertImpl.getAuthorityKeyIdentifierExtension());
-
-            worthy = issuerSelector.match(trustedCert);
-        } catch (Exception e) {
-            // It is not worth trying.
-        }
-
-        if (debug != null) {
-            if (worthy) {
-                debug.println("YES - try this trustedCert");
-            } else {
-                debug.println("NO - don't try this trustedCert");
-            }
-        }
-
-        return worthy;
-    }
-
-    /**
-     * Internal method to setup the internal state
-     */
-    private void populateVariables(PKIXParameters pkixParam)
+    private static PKIXCertPathValidatorResult validate(TrustAnchor anchor,
+                                                        ValidatorParams params)
+        throws CertPathValidatorException
     {
-        // default value for testDate is current time
-        testDate = pkixParam.getDate();
-        if (testDate == null) {
-            testDate = new Date(System.currentTimeMillis());
-        }
-
-        userCheckers = pkixParam.getCertPathCheckers();
-        sigProvider = pkixParam.getSigProvider();
-
-        if (pkixParam.isRevocationEnabled()) {
-            // Examine OCSP security property
-            ocspEnabled = AccessController.doPrivileged(
-                new GetBooleanSecurityPropertyAction
-                    (OCSPChecker.OCSP_ENABLE_PROP));
-            onlyEECert = AccessController.doPrivileged(
-                new GetBooleanSecurityPropertyAction
-                    ("com.sun.security.onlyCheckRevocationOfEECert"));
-        }
-    }
-
-    /**
-     * Internal method to actually validate a constructed path.
-     *
-     * @return the valid policy tree
-     */
-    private PolicyNode doValidate(
-            TrustAnchor anchor, CertPath cpOriginal,
-            ArrayList certList, PKIXParameters pkixParam,
-            PolicyNodeImpl rootNode) throws CertPathValidatorException
-    {
-        int certPathLen = certList.size();
-
-        basicChecker = new BasicChecker(anchor, testDate, sigProvider, false);
-        AlgorithmChecker algorithmChecker = new AlgorithmChecker(anchor);
-        KeyChecker keyChecker = new KeyChecker(certPathLen,
-            pkixParam.getTargetCertConstraints());
-        ConstraintsChecker constraintsChecker =
-            new ConstraintsChecker(certPathLen);
-
-        PolicyChecker policyChecker =
-            new PolicyChecker(pkixParam.getInitialPolicies(), certPathLen,
-                              pkixParam.isExplicitPolicyRequired(),
-                              pkixParam.isPolicyMappingInhibited(),
-                              pkixParam.isAnyPolicyInhibited(),
-                              pkixParam.getPolicyQualifiersRejected(),
-                              rootNode);
+        // check if anchor is untrusted
         UntrustedChecker untrustedChecker = new UntrustedChecker();
-        // check if anchor is untrusted
         X509Certificate anchorCert = anchor.getTrustedCert();
         if (anchorCert != null) {
             untrustedChecker.check(anchorCert,
                                    Collections.emptySet());
         }
 
-        ArrayList certPathCheckers =
-            new ArrayList();
+        int certPathLen = params.certificates().size();
+
+        // create PKIXCertPathCheckers
+        List certPathCheckers = new ArrayList<>();
         // add standard checkers that we will be using
         certPathCheckers.add(untrustedChecker);
-        certPathCheckers.add(algorithmChecker);
-        certPathCheckers.add(keyChecker);
-        certPathCheckers.add(constraintsChecker);
-        certPathCheckers.add(policyChecker);
-        certPathCheckers.add(basicChecker);
-
-        // only add a revocationChecker if revocation is enabled
-        if (pkixParam.isRevocationEnabled()) {
-
-            // Use OCSP if it has been enabled
-            if (ocspEnabled) {
-                OCSPChecker ocspChecker =
-                    new OCSPChecker(cpOriginal, pkixParam, onlyEECert);
-                certPathCheckers.add(ocspChecker);
-            }
+        certPathCheckers.add(new AlgorithmChecker(anchor, null, params.date(),
+                params.timestamp(), params.variant()));
+        certPathCheckers.add(new KeyChecker(certPathLen,
+                                            params.targetCertConstraints()));
+        certPathCheckers.add(new ConstraintsChecker(certPathLen));
+        PolicyNodeImpl rootNode =
+            new PolicyNodeImpl(null, PolicyChecker.ANY_POLICY, null, false,
+                               Collections.singleton(PolicyChecker.ANY_POLICY),
+                               false);
+        PolicyChecker pc = new PolicyChecker(params.initialPolicies(),
+                                             certPathLen,
+                                             params.explicitPolicyRequired(),
+                                             params.policyMappingInhibited(),
+                                             params.anyPolicyInhibited(),
+                                             params.policyQualifiersRejected(),
+                                             rootNode);
+        certPathCheckers.add(pc);
+        // default value for date is current time
+        BasicChecker bc;
+        bc = new BasicChecker(anchor,
+                (params.timestamp() == null ? params.date() :
+                        params.timestamp().getTimestamp()),
+                params.sigProvider(), false);
+        certPathCheckers.add(bc);
 
-            // Always use CRLs
-            CrlRevocationChecker revocationChecker = new
-                CrlRevocationChecker(anchor, pkixParam, certList, onlyEECert);
-            certPathCheckers.add(revocationChecker);
+        boolean revCheckerAdded = false;
+        List checkers = params.certPathCheckers();
+        for (PKIXCertPathChecker checker : checkers) {
+            if (checker instanceof PKIXRevocationChecker) {
+                revCheckerAdded = true;
+                // if it's our own, initialize it
+                if (checker instanceof RevocationChecker)
+                    ((RevocationChecker)checker).init(anchor, params);
+            }
         }
-
+        // only add a RevocationChecker if revocation is enabled and
+        // a PKIXRevocationChecker has not already been added
+        if (params.revocationEnabled() && !revCheckerAdded) {
+            certPathCheckers.add(new RevocationChecker(anchor, params));
+        }
         // add user-specified checkers
-        certPathCheckers.addAll(userCheckers);
+        certPathCheckers.addAll(checkers);
 
-        PKIXMasterCertPathValidator masterValidator =
-            new PKIXMasterCertPathValidator(certPathCheckers);
+        PKIXMasterCertPathValidator.validate(params.certPath(),
+                                             params.certificates(),
+                                             certPathCheckers);
 
-        masterValidator.validate(cpOriginal, certList);
-
-        return policyChecker.getPolicyTree();
+        return new PKIXCertPathValidatorResult(anchor, pc.getPolicyTree(),
+                                               bc.getPublicKey());
     }
 }
diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/certpath/PKIXExtendedParameters.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/security/provider/certpath/PKIXExtendedParameters.java	Sat Feb 03 21:37:28 2018 -0800
@@ -0,0 +1,226 @@
+/*
+ * 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
+ * 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.certpath;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.Timestamp;
+import java.security.cert.CertSelector;
+import java.security.cert.CertStore;
+import java.security.cert.PKIXBuilderParameters;
+import java.security.cert.PKIXCertPathChecker;
+import java.security.cert.TrustAnchor;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * This class is a wrapper for PKIXBuilderParameters so that a Timestamp object
+ * and a string for the variant type, can be passed when doing certpath
+ * checking.
+ */
+
+public class PKIXExtendedParameters extends PKIXBuilderParameters {
+
+    private final PKIXBuilderParameters p;
+    private Timestamp jarTimestamp;
+    private final String variant;
+
+    public PKIXExtendedParameters(PKIXBuilderParameters params,
+            Timestamp timestamp, String variant)
+            throws InvalidAlgorithmParameterException {
+        super(params.getTrustAnchors(), null);
+        p = params;
+        jarTimestamp = timestamp;
+        this.variant = variant;
+    }
+
+    public Timestamp getTimestamp() {
+        return jarTimestamp;
+    }
+    public void setTimestamp(Timestamp t) {
+        jarTimestamp = t;
+    }
+
+    public String getVariant() {
+        return variant;
+    }
+
+    @Override
+    public void setDate(Date d) {
+        p.setDate(d);
+    }
+
+    @Override
+    public void addCertPathChecker(PKIXCertPathChecker c) {
+        p.addCertPathChecker(c);
+    }
+
+    @Override
+    public void setMaxPathLength(int maxPathLength) {
+        p.setMaxPathLength(maxPathLength);
+    }
+
+    @Override
+    public int getMaxPathLength() {
+        return p.getMaxPathLength();
+    }
+
+    @Override
+    public String toString() {
+        return p.toString();
+    }
+
+    @Override
+    public Set getTrustAnchors() {
+        return p.getTrustAnchors();
+    }
+
+    @Override
+    public void setTrustAnchors(Set trustAnchors)
+            throws InvalidAlgorithmParameterException {
+        // To avoid problems with PKIXBuilderParameter's constructors
+        if (p == null) {
+            return;
+        }
+        p.setTrustAnchors(trustAnchors);
+    }
+
+    @Override
+    public Set getInitialPolicies() {
+        return p.getInitialPolicies();
+    }
+
+    @Override
+    public void setInitialPolicies(Set initialPolicies) {
+        p.setInitialPolicies(initialPolicies);
+    }
+
+    @Override
+    public void setCertStores(List stores) {
+        p.setCertStores(stores);
+    }
+
+    @Override
+    public void addCertStore(CertStore store) {
+        p.addCertStore(store);
+    }
+
+    @Override
+    public List getCertStores() {
+        return p.getCertStores();
+    }
+
+    @Override
+    public void setRevocationEnabled(boolean val) {
+        p.setRevocationEnabled(val);
+    }
+
+    @Override
+    public boolean isRevocationEnabled() {
+        return p.isRevocationEnabled();
+    }
+
+    @Override
+    public void setExplicitPolicyRequired(boolean val) {
+        p.setExplicitPolicyRequired(val);
+    }
+
+    @Override
+    public boolean isExplicitPolicyRequired() {
+        return p.isExplicitPolicyRequired();
+    }
+
+    @Override
+    public void setPolicyMappingInhibited(boolean val) {
+        p.setPolicyMappingInhibited(val);
+    }
+
+    @Override
+    public boolean isPolicyMappingInhibited() {
+        return p.isPolicyMappingInhibited();
+    }
+
+    @Override
+    public void setAnyPolicyInhibited(boolean val) {
+        p.setAnyPolicyInhibited(val);
+    }
+
+    @Override
+    public boolean isAnyPolicyInhibited() {
+        return p.isAnyPolicyInhibited();
+    }
+
+    @Override
+    public void setPolicyQualifiersRejected(boolean qualifiersRejected) {
+        p.setPolicyQualifiersRejected(qualifiersRejected);
+    }
+
+    @Override
+    public boolean getPolicyQualifiersRejected() {
+        return p.getPolicyQualifiersRejected();
+    }
+
+    @Override
+    public Date getDate() {
+        return p.getDate();
+    }
+
+    @Override
+    public void setCertPathCheckers(List checkers) {
+        p.setCertPathCheckers(checkers);
+    }
+
+    @Override
+    public List getCertPathCheckers() {
+        return p.getCertPathCheckers();
+    }
+
+    @Override
+    public String getSigProvider() {
+        return p.getSigProvider();
+    }
+
+    @Override
+    public void setSigProvider(String sigProvider) {
+        p.setSigProvider(sigProvider);
+    }
+
+    @Override
+    public CertSelector getTargetCertConstraints() {
+        return p.getTargetCertConstraints();
+    }
+
+    @Override
+    public void setTargetCertConstraints(CertSelector selector) {
+        // To avoid problems with PKIXBuilderParameter's constructors
+        if (p == null) {
+            return;
+        }
+        p.setTargetCertConstraints(selector);
+    }
+
+}
diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/certpath/PKIXMasterCertPathValidator.java
--- a/src/share/classes/sun/security/provider/certpath/PKIXMasterCertPathValidator.java	Thu Sep 07 23:37:21 2017 -0700
+++ b/src/share/classes/sun/security/provider/certpath/PKIXMasterCertPathValidator.java	Sat Feb 03 21:37:28 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2009, 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
@@ -30,10 +30,8 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
-import java.security.cert.CertificateRevokedException;
 import java.security.cert.CertPath;
 import java.security.cert.CertPathValidatorException;
-import java.security.cert.CertPathValidatorException.BasicReason;
 import java.security.cert.PKIXCertPathChecker;
 import java.security.cert.PKIXReason;
 import java.security.cert.X509Certificate;
@@ -49,32 +47,22 @@
 class PKIXMasterCertPathValidator {
 
     private static final Debug debug = Debug.getInstance("certpath");
-    private List certPathCheckers;
-
-    /**
-     * Initializes the list of PKIXCertPathCheckers whose checks
-     * will be performed on each certificate in the certpath.
-     *
-     * @param certPathCheckers a List of checkers to use
-     */
-    PKIXMasterCertPathValidator(List certPathCheckers) {
-        this.certPathCheckers = certPathCheckers;
-    }
 
     /**
      * Validates a certification path consisting exclusively of
-     * X509Certificates using the
-     * PKIXCertPathCheckers specified
-     * in the constructor. It is assumed that the
+     * X509Certificates using the specified
+     * PKIXCertPathCheckers. It is assumed that the
      * PKIXCertPathCheckers
      * have been initialized with any input parameters they may need.
      *
      * @param cpOriginal the original X509 CertPath passed in by the user
      * @param reversedCertList the reversed X509 CertPath (as a List)
-     * @exception CertPathValidatorException Exception thrown if cert
-     * path does not validate.
+     * @param certPathCheckers the PKIXCertPathCheckers
+     * @throws CertPathValidatorException if cert path does not validate
      */
-    void validate(CertPath cpOriginal, List reversedCertList)
+    static void validate(CertPath cpOriginal,
+                         List reversedCertList,
+                         List certPathCheckers)
         throws CertPathValidatorException
     {
         // we actually process reversedCertList, but we keep cpOriginal because
@@ -104,20 +92,18 @@
                 debug.println("Checking cert" + (i+1) + " ...");
 
             X509Certificate currCert = reversedCertList.get(i);
-            Set unresolvedCritExts =
-                                        currCert.getCriticalExtensionOIDs();
-            if (unresolvedCritExts == null) {
-                unresolvedCritExts = Collections.emptySet();
+            Set unresCritExts = currCert.getCriticalExtensionOIDs();
+            if (unresCritExts == null) {
+                unresCritExts = Collections.emptySet();
             }
 
-            if (debug != null && !unresolvedCritExts.isEmpty()) {
+            if (debug != null && !unresCritExts.isEmpty()) {
                 debug.println("Set of critical extensions:");
-                for (String oid : unresolvedCritExts) {
+                for (String oid : unresCritExts) {
                     debug.println(oid);
                 }
             }
 
-            CertPathValidatorException ocspCause = null;
             for (int j = 0; j < certPathCheckers.size(); j++) {
 
                 PKIXCertPathChecker currChecker = certPathCheckers.get(j);
@@ -130,96 +116,32 @@
                     currChecker.init(false);
 
                 try {
-                    currChecker.check(currCert, unresolvedCritExts);
+                    currChecker.check(currCert, unresCritExts);
 
-                    // OCSP has validated the cert so skip the CRL check
-                    if (isRevocationCheck(currChecker, j, certPathCheckers)) {
-                        if (debug != null) {
-                            debug.println("-checker" + (j + 1) +
-                                " validation succeeded");
-                        }
-                        j++;
-                        continue; // skip
+                    if (debug != null) {
+                        debug.println("-checker" + (j + 1) +
+                            " validation succeeded");
                     }
 
                 } catch (CertPathValidatorException cpve) {
-                    // Throw the saved OCSP exception unless the CRL
-                    // checker has determined that the cert is revoked
-                    if (ocspCause != null &&
-                            currChecker instanceof CrlRevocationChecker) {
-                        if (cpve.getReason() == BasicReason.REVOKED) {
-                            throw cpve;
-                        } else {
-                            throw ocspCause;
-                        }
-                    }
-                    /*
-                     * Handle failover from OCSP to CRLs
-                     */
-                    CertPathValidatorException currentCause =
-                        new CertPathValidatorException(cpve.getMessage(),
-                        (cpve.getCause() != null) ? cpve.getCause() : cpve,
-                            cpOriginal, cpSize - (i + 1), cpve.getReason());
-
-                    // Check if OCSP has confirmed that the cert was revoked
-                    if (cpve.getReason() == BasicReason.REVOKED) {
-                        throw currentCause;
-                    }
-                    // Check if it is appropriate to failover
-                    if (! isRevocationCheck(currChecker, j, certPathCheckers)) {
-                        // no failover
-                        throw currentCause;
-                    }
-                    // Save the current exception
-                    // (in case the CRL check also fails)
-                    ocspCause = currentCause;
-
-                    // Otherwise, failover to CRLs
-                    if (debug != null) {
-                        debug.println(cpve.getMessage());
-                        debug.println(
-                            "preparing to failover (from OCSP to CRLs)");
-                    }
+                    throw new CertPathValidatorException(cpve.getMessage(),
+                        cpve.getCause(), cpOriginal, cpSize - (i + 1),
+                        cpve.getReason());
                 }
-
-                if (debug != null)
-                    debug.println("-checker" + (j+1) + " validation succeeded");
             }
 
-            if (debug != null)
-                debug.println("checking for unresolvedCritExts");
-            if (!unresolvedCritExts.isEmpty()) {
+            if (!unresCritExts.isEmpty()) {
                 throw new CertPathValidatorException("unrecognized " +
                     "critical extension(s)", null, cpOriginal, cpSize-(i+1),
                     PKIXReason.UNRECOGNIZED_CRIT_EXT);
             }
-
-            if (debug != null)
-                debug.println("\ncert" + (i+1) + " validation succeeded.\n");
         }
 
         if (debug != null) {
             debug.println("Cert path validation succeeded. (PKIX validation "
-                    + "algorithm)");
+                          + "algorithm)");
             debug.println("-------------------------------------------------"
-                    + "-------------");
+                          + "-------------");
         }
     }
-
-    /*
-     * Examines the list of PKIX cert path checkers to determine whether
-     * both the current checker and the next checker are revocation checkers.
-     * OCSPChecker and CrlRevocationChecker are both revocation checkers.
-     */
-    private static boolean isRevocationCheck(PKIXCertPathChecker checker,
-        int index, List checkers) {
-
-        if (checker instanceof OCSPChecker && index + 1 < checkers.size()) {
-            PKIXCertPathChecker nextChecker = checkers.get(index + 1);
-            if (nextChecker instanceof CrlRevocationChecker) {
-                return true;
-            }
-        }
-        return false;
-    }
 }
diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/certpath/PKIXRevocationChecker.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/security/provider/certpath/PKIXRevocationChecker.java	Sat Feb 03 21:37:28 2018 -0800
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 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
+ * 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.certpath;
+
+import java.net.URI;
+import java.security.cert.Certificate;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.Extension;
+import java.security.cert.PKIXCertPathChecker;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * A {@code PKIXCertPathChecker} for checking the revocation status of
+ * certificates with the PKIX algorithm.
+ *
+ * 

A {@code PKIXRevocationChecker} checks the revocation status of + * certificates with the Online Certificate Status Protocol (OCSP) or + * Certificate Revocation Lists (CRLs). OCSP is described in RFC 2560 and + * is a network protocol for determining the status of a certificate. A CRL + * is a time-stamped list identifying revoked certificates, and RFC 5280 + * describes an algorithm for determining the revocation status of certificates + * using CRLs. + * + *

Each {@code PKIXRevocationChecker} must be able to check the revocation + * status of certificates with OCSP and CRLs. By default, OCSP is the + * preferred mechanism for checking revocation status, with CRLs as the + * fallback mechanism. However, this preference can be switched to CRLs with + * the {@link Option.PREFER_CRLS} option. + * + *

A {@code PKIXRevocationChecker} is obtained by calling the + * {@link CertPathValidator#getRevocationChecker getRevocationChecker} method + * of a PKIX {@code CertPathValidator}. Additional parameters and options + * specific to revocation can be set (by calling {@link #setOCSPResponder} + * method for instance). The {@code PKIXRevocationChecker} is added to + * a {@code PKIXParameters} object using the + * {@link PKIXParameters#addCertPathChecker addCertPathChecker} + * or {@link PKIXParameters#setCertPathCheckers setCertPathCheckers} method, + * and then the {@code PKIXParameters} is passed along with the {@code CertPath} + * to be validated to the {@link CertPathValidator#validate validate} method + * of a PKIX {@code CertPathValidator}. When supplying a revocation checker in + * this manner, do not enable the default revocation checking mechanism (by + * calling {@link PKIXParameters#setRevocationEnabled}. + * + *

Note that when a {@code PKIXRevocationChecker} is added to + * {@code PKIXParameters}, it clones the {@code PKIXRevocationChecker}; + * thus any subsequent modifications to the {@code PKIXRevocationChecker} + * have no effect. + * + *

Any parameter that is not set (or is set to {@code null}) will be set to + * the default value for that parameter. + * + *

Concurrent Access + * + *

Unless otherwise specified, the methods defined in this class are not + * thread-safe. Multiple threads that need to access a single object + * concurrently should synchronize amongst themselves and provide the + * necessary locking. Multiple threads each manipulating separate objects + * need not synchronize. + * + * @since 1.8 + */ +public abstract class PKIXRevocationChecker extends PKIXCertPathChecker + implements CertPathChecker { + private URI ocspResponder; + private X509Certificate ocspResponderCert; + private List ocspExtensions = Collections.emptyList(); + private Map ocspStapled = Collections.emptyMap(); + private Set

This implementation calls + * {@code check(cert, java.util.Collections.emptySet())}. + */ + @Override + public void check(Certificate cert) throws CertPathValidatorException { + check(cert, java.util.Collections.emptySet()); + } +} diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/certpath/PolicyChecker.java --- a/src/share/classes/sun/security/provider/certpath/PolicyChecker.java Thu Sep 07 23:37:21 2017 -0700 +++ b/src/share/classes/sun/security/provider/certpath/PolicyChecker.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, 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 @@ -25,9 +25,8 @@ package sun.security.provider.certpath; -import java.util.*; import java.io.IOException; - +import java.security.GeneralSecurityException; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.CertPathValidatorException; @@ -36,13 +35,14 @@ import java.security.cert.PolicyNode; import java.security.cert.PolicyQualifierInfo; import java.security.cert.X509Certificate; +import java.util.*; import sun.security.util.Debug; import sun.security.x509.CertificatePoliciesExtension; import sun.security.x509.PolicyConstraintsExtension; import sun.security.x509.PolicyMappingsExtension; import sun.security.x509.CertificatePolicyMap; -import sun.security.x509.PKIXExtensions; +import static sun.security.x509.PKIXExtensions.*; import sun.security.x509.PolicyInformation; import sun.security.x509.X509CertImpl; import sun.security.x509.InhibitAnyPolicyExtension; @@ -88,7 +88,7 @@ PolicyChecker(Set initialPolicies, int certPathLen, boolean expPolicyRequired, boolean polMappingInhibited, boolean anyPolicyInhibited, boolean rejectPolicyQualifiers, - PolicyNodeImpl rootNode) throws CertPathValidatorException + PolicyNodeImpl rootNode) { if (initialPolicies.isEmpty()) { // if no initialPolicies are specified by user, set @@ -104,18 +104,18 @@ this.anyPolicyInhibited = anyPolicyInhibited; this.rejectPolicyQualifiers = rejectPolicyQualifiers; this.rootNode = rootNode; - init(false); } /** * Initializes the internal state of the checker from parameters * specified in the constructor * - * @param forward a boolean indicating whether this checker should - * be initialized capable of building in the forward direction - * @exception CertPathValidatorException Exception thrown if user - * wants to enable forward checking and forward checking is not supported. + * @param forward a boolean indicating whether this checker should be + * initialized capable of building in the forward direction + * @throws CertPathValidatorException if user wants to enable forward + * checking and forward checking is not supported. */ + @Override public void init(boolean forward) throws CertPathValidatorException { if (forward) { throw new CertPathValidatorException @@ -136,6 +136,7 @@ * * @return true if forward checking is supported, false otherwise */ + @Override public boolean isForwardCheckingSupported() { return false; } @@ -150,13 +151,14 @@ * @return the Set of extensions supported by this PKIXCertPathChecker, * or null if no extensions are supported */ + @Override public Set getSupportedExtensions() { if (supportedExts == null) { - supportedExts = new HashSet(); - supportedExts.add(PKIXExtensions.CertificatePolicies_Id.toString()); - supportedExts.add(PKIXExtensions.PolicyMappings_Id.toString()); - supportedExts.add(PKIXExtensions.PolicyConstraints_Id.toString()); - supportedExts.add(PKIXExtensions.InhibitAnyPolicy_Id.toString()); + supportedExts = new HashSet(4); + supportedExts.add(CertificatePolicies_Id.toString()); + supportedExts.add(PolicyMappings_Id.toString()); + supportedExts.add(PolicyConstraints_Id.toString()); + supportedExts.add(InhibitAnyPolicy_Id.toString()); supportedExts = Collections.unmodifiableSet(supportedExts); } return supportedExts; @@ -168,9 +170,9 @@ * * @param cert the Certificate to be processed * @param unresCritExts the unresolved critical extensions - * @exception CertPathValidatorException Exception thrown if - * the certificate does not verify. + * @throws CertPathValidatorException if the certificate does not verify */ + @Override public void check(Certificate cert, Collection unresCritExts) throws CertPathValidatorException { @@ -178,10 +180,10 @@ checkPolicy((X509Certificate) cert); if (unresCritExts != null && !unresCritExts.isEmpty()) { - unresCritExts.remove(PKIXExtensions.CertificatePolicies_Id.toString()); - unresCritExts.remove(PKIXExtensions.PolicyMappings_Id.toString()); - unresCritExts.remove(PKIXExtensions.PolicyConstraints_Id.toString()); - unresCritExts.remove(PKIXExtensions.InhibitAnyPolicy_Id.toString()); + unresCritExts.remove(CertificatePolicies_Id.toString()); + unresCritExts.remove(PolicyMappings_Id.toString()); + unresCritExts.remove(PolicyConstraints_Id.toString()); + unresCritExts.remove(InhibitAnyPolicy_Id.toString()); } } @@ -290,7 +292,7 @@ if (require == 0) explicitPolicy = require; } - } catch (Exception e) { + } catch (IOException e) { if (debug != null) { debug.println("PolicyChecker.mergeExplicitPolicy " + "unexpected exception"); @@ -339,7 +341,7 @@ policyMapping = inhibit; } } - } catch (Exception e) { + } catch (IOException e) { if (debug != null) { debug.println("PolicyChecker.mergePolicyMapping " + "unexpected exception"); @@ -372,7 +374,7 @@ try { InhibitAnyPolicyExtension inhAnyPolExt = (InhibitAnyPolicyExtension) - currCert.getExtension(PKIXExtensions.InhibitAnyPolicy_Id); + currCert.getExtension(InhibitAnyPolicy_Id); if (inhAnyPolExt == null) return inhibitAnyPolicy; @@ -387,7 +389,7 @@ inhibitAnyPolicy = skipCerts; } } - } catch (Exception e) { + } catch (IOException e) { if (debug != null) { debug.println("PolicyChecker.mergeInhibitAnyPolicy " + "unexpected exception"); @@ -429,7 +431,7 @@ boolean policiesCritical = false; List policyInfo; PolicyNodeImpl rootNode = null; - Set anyQuals = new HashSet(); + Set anyQuals = new HashSet<>(); if (origRootNode == null) rootNode = null; @@ -600,7 +602,7 @@ PolicyNodeImpl parentNode = (PolicyNodeImpl)anyNode.getParent(); parentNode.deleteChild(anyNode); // see if there are any initialPolicies not represented by leaf nodes - Set initial = new HashSet(initPolicies); + Set initial = new HashSet<>(initPolicies); for (PolicyNodeImpl node : rootNode.getPolicyNodes(certIndex)) { initial.remove(node.getValidPolicy()); } @@ -697,7 +699,7 @@ } } - Set expPols = new HashSet(); + Set expPols = new HashSet<>(); expPols.add(curParExpPol); curNode = new PolicyNodeImpl @@ -762,8 +764,7 @@ } boolean childDeleted = false; - for (int j = 0; j < maps.size(); j++) { - CertificatePolicyMap polMap = maps.get(j); + for (CertificatePolicyMap polMap : maps) { String issuerDomain = polMap.getIssuerIdentifier().getIdentifier().toString(); String subjectDomain @@ -816,7 +817,7 @@ PolicyNodeImpl curAnyNodeParent = (PolicyNodeImpl) curAnyNode.getParent(); - Set expPols = new HashSet(); + Set expPols = new HashSet<>(); expPols.add(subjectDomain); PolicyNodeImpl curNode = new PolicyNodeImpl diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/certpath/PolicyNodeImpl.java --- a/src/share/classes/sun/security/provider/certpath/PolicyNodeImpl.java Thu Sep 07 23:37:21 2017 -0700 +++ b/src/share/classes/sun/security/provider/certpath/PolicyNodeImpl.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 @@ -134,30 +134,37 @@ node.mCriticalityIndicator, node.mExpectedPolicySet, false); } + @Override public PolicyNode getParent() { return mParent; } + @Override public Iterator getChildren() { return Collections.unmodifiableSet(mChildren).iterator(); } + @Override public int getDepth() { return mDepth; } + @Override public String getValidPolicy() { return mValidPolicy; } + @Override public Set getPolicyQualifiers() { return Collections.unmodifiableSet(mQualifierSet); } + @Override public Set getExpectedPolicies() { return Collections.unmodifiableSet(mExpectedPolicySet); } + @Override public boolean isCritical() { return mCriticalityIndicator; } @@ -169,12 +176,12 @@ * * @return a String describing the contents of the Policy Node */ + @Override public String toString() { - StringBuffer buffer = new StringBuffer(this.asString()); + StringBuilder buffer = new StringBuilder(this.asString()); - Iterator it = getChildren(); - while (it.hasNext()) { - buffer.append(it.next()); + for (PolicyNodeImpl node : mChildren) { + buffer.append(node); } return buffer.toString(); } @@ -293,7 +300,7 @@ * @return a Set of all nodes at the specified depth */ Set getPolicyNodes(int depth) { - Set set = new HashSet(); + Set set = new HashSet<>(); getPolicyNodes(depth, set); return set; } @@ -337,7 +344,7 @@ private Set getPolicyNodesExpectedHelper(int depth, String expectedOID, boolean matchAny) { - HashSet set = new HashSet(); + HashSet set = new HashSet<>(); if (mDepth < depth) { for (PolicyNodeImpl node : mChildren) { @@ -367,7 +374,7 @@ * @return a Set of matched PolicyNodes */ Set getPolicyNodesValid(int depth, String validOID) { - HashSet set = new HashSet(); + HashSet set = new HashSet<>(); if (mDepth < depth) { for (PolicyNodeImpl node : mChildren) { @@ -396,7 +403,7 @@ if (mParent == null) { return "anyPolicy ROOT\n"; } else { - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); for (int i = 0, n = getDepth(); i < n; i++) { sb.append(" "); } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/certpath/ResponderId.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/sun/security/provider/certpath/ResponderId.java Sat Feb 03 21:37:28 2018 -0800 @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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.certpath; + +import java.util.Arrays; +import java.io.IOException; +import java.security.PublicKey; +import javax.security.auth.x500.X500Principal; +import sun.security.x509.KeyIdentifier; +import sun.security.util.DerValue; + +/** + * Class for ResponderId entities as described in RFC6960. ResponderId objects + * are used to uniquely identify OCSP responders. + *

+ * The RFC 6960 defines a ResponderID structure as: + *

+ * ResponderID ::= CHOICE {
+ *      byName              [1] Name,
+ *      byKey               [2] KeyHash }
+ *
+ * KeyHash ::= OCTET STRING -- SHA-1 hash of responder's public key
+ * (excluding the tag and length fields)
+ *
+ * Name is defined in RFC 5280.
+ * 
+ * + * @see ResponderId.Type + * @since 9 + */ +public final class ResponderId { + + /** + * A {@code ResponderId} enumeration describing the accepted forms for a + * {@code ResponderId}. + * + * @see ResponderId + * @since 9 + */ + public static enum Type { + /** + * A BY_NAME {@code ResponderId} will be built from a subject name, + * either as an {@code X500Principal} or a DER-encoded byte array. + */ + BY_NAME(1, "byName"), + + /** + * A BY_KEY {@code ResponderId} will be built from a public key + * identifier, either derived from a {@code PublicKey} or directly + * from a DER-encoded byte array containing the key identifier. + */ + BY_KEY(2, "byKey"); + + private final int tagNumber; + private final String ridTypeName; + + private Type(int value, String name) { + this.tagNumber = value; + this.ridTypeName = name; + } + + public int value() { + return tagNumber; + } + + @Override + public String toString() { + return ridTypeName; + } + } + + private Type type; + private X500Principal responderName; + private KeyIdentifier responderKeyId; + private byte[] encodedRid; + + /** + * Constructs a {@code ResponderId} object using an {@code X500Principal}. + * When encoded in DER this object will use the BY_NAME option. + * + * @param subjectName the subject name of the certificate used + * to sign OCSP responses. + * + * @throws IOException if the internal DER-encoding of the + * {@code X500Principal} fails. + */ + public ResponderId(X500Principal subjectName) throws IOException { + responderName = subjectName; + responderKeyId = null; + encodedRid = principalToBytes(); + type = Type.BY_NAME; + } + + /** + * Constructs a {@code ResponderId} object using a {@code PublicKey}. + * When encoded in DER this object will use the byKey option, a + * SHA-1 hash of the responder's public key. + * + * @param pubKey the the OCSP responder's public key + * + * @throws IOException if the internal DER-encoding of the + * {@code KeyIdentifier} fails. + */ + public ResponderId(PublicKey pubKey) throws IOException { + responderKeyId = new KeyIdentifier(pubKey); + responderName = null; + encodedRid = keyIdToBytes(); + type = Type.BY_KEY; + } + + /** + * Constructs a {@code ResponderId} object from its DER-encoding. + * + * @param encodedData the DER-encoded bytes + * + * @throws IOException if the encodedData is not properly DER encoded + */ + public ResponderId(byte[] encodedData) throws IOException { + DerValue outer = new DerValue(encodedData); + + if (outer.isContextSpecific((byte)Type.BY_NAME.value()) + && outer.isConstructed()) { + // Use the X500Principal constructor as a way to sanity + // check the incoming data. + responderName = new X500Principal(outer.getDataBytes()); + encodedRid = principalToBytes(); + type = Type.BY_NAME; + } else if (outer.isContextSpecific((byte)Type.BY_KEY.value()) + && outer.isConstructed()) { + // Use the KeyIdentifier constructor as a way to sanity + // check the incoming data. + responderKeyId = + new KeyIdentifier(new DerValue(outer.getDataBytes())); + encodedRid = keyIdToBytes(); + type = Type.BY_KEY; + } else { + throw new IOException("Invalid ResponderId content"); + } + } + + /** + * Encode a {@code ResponderId} in DER form + * + * @return a byte array containing the DER-encoded representation for this + * {@code ResponderId} + */ + public byte[] getEncoded() { + return encodedRid.clone(); + } + + /** + * Return the type of {@ResponderId} + * + * @return a number corresponding to the context-specific tag number + * used in the DER-encoding for a {@code ResponderId} + */ + public ResponderId.Type getType() { + return type; + } + + /** + * Get the length of the encoded {@code ResponderId} (including the tag and + * length of the explicit tagging from the outer ASN.1 CHOICE). + * + * @return the length of the encoded {@code ResponderId} + */ + public int length() { + return encodedRid.length; + } + + /** + * Obtain the underlying {@code X500Principal} from a {@code ResponderId} + * + * @return the {@code X500Principal} for this {@code ResponderId} if it + * is a BY_NAME variant. If the {@code ResponderId} is a BY_KEY + * variant, this routine will return {@code null}. + */ + public X500Principal getResponderName() { + return responderName; + } + + /** + * Obtain the underlying key identifier from a {@code ResponderId} + * + * @return the {@code KeyIdentifier} for this {@code ResponderId} if it + * is a BY_KEY variant. If the {@code ResponderId} is a BY_NAME + * variant, this routine will return {@code null}. + */ + public KeyIdentifier getKeyIdentifier() { + return responderKeyId; + } + + /** + * Compares the specified object with this {@code ResponderId} for equality. + * A ResponderId will only be considered equivalent if both the type and + * data value are equal. Two ResponderIds initialized by name and + * key ID, respectively, will not be equal even if the + * ResponderId objects are created from the same source certificate. + * + * @param obj the object to be compared against + * + * @return true if the specified object is equal to this {@code Responderid} + */ + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + + if (this == obj) { + return true; + } + + if (obj instanceof ResponderId) { + ResponderId respObj = (ResponderId)obj; + return Arrays.equals(encodedRid, respObj.getEncoded()); + } + + return false; + } + + /** + * Returns the hash code value for this {@code ResponderId} + * + * @return the hash code value for this {@code ResponderId} + */ + @Override + public int hashCode() { + return Arrays.hashCode(encodedRid); + } + + /** + * Create a String representation of this {@code ResponderId} + * + * @return a String representation of this {@code ResponderId} + */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + switch (type) { + case BY_NAME: + sb.append(type).append(": ").append(responderName); + break; + case BY_KEY: + sb.append(type).append(": "); + for (byte keyIdByte : responderKeyId.getIdentifier()) { + sb.append(String.format("%02X", keyIdByte)); + } + break; + default: + sb.append("Unknown ResponderId Type: ").append(type); + } + return sb.toString(); + } + + /** + * Convert the responderName data member into its DER-encoded form + * + * @return the DER encoding for a responder ID byName option, including + * explicit context-specific tagging. + * + * @throws IOException if any encoding error occurs + */ + private byte[] principalToBytes() throws IOException { + DerValue dv = new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, + true, (byte)Type.BY_NAME.value()), + responderName.getEncoded()); + return dv.toByteArray(); + } + + /** + * Convert the responderKeyId data member into its DER-encoded form + * + * @return the DER encoding for a responder ID byKey option, including + * explicit context-specific tagging. + * + * @throws IOException if any encoding error occurs + */ + private byte[] keyIdToBytes() throws IOException { + // Place the KeyIdentifier bytes into an OCTET STRING + DerValue inner = new DerValue(DerValue.tag_OctetString, + responderKeyId.getIdentifier()); + + // Mark the OCTET STRING-wrapped KeyIdentifier bytes + // as EXPLICIT CONTEXT 2 + DerValue outer = new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, + true, (byte)Type.BY_KEY.value()), inner.toByteArray()); + + return outer.toByteArray(); + } + +} diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/certpath/ReverseBuilder.java --- a/src/share/classes/sun/security/provider/certpath/ReverseBuilder.java Thu Sep 07 23:37:21 2017 -0700 +++ b/src/share/classes/sun/security/provider/certpath/ReverseBuilder.java Sat Feb 03 21:37:28 2018 -0800 @@ -51,9 +51,10 @@ import javax.security.auth.x500.X500Principal; +import sun.security.provider.certpath.PKIX.BuilderParams; import sun.security.util.Debug; import sun.security.x509.Extension; -import sun.security.x509.PKIXExtensions; +import static sun.security.x509.PKIXExtensions.*; import sun.security.x509.X500Name; import sun.security.x509.X509CertImpl; import sun.security.x509.PolicyMappingsExtension; @@ -72,28 +73,24 @@ private Debug debug = Debug.getInstance("certpath"); - Set initPolicies; + private final Set initPolicies; /** * Initialize the builder with the input parameters. * * @param params the parameter set used to build a certification path */ - ReverseBuilder(PKIXBuilderParameters buildParams, - X500Principal targetSubjectDN) { + ReverseBuilder(BuilderParams buildParams) { + super(buildParams); - super(buildParams, targetSubjectDN); - - Set initialPolicies = buildParams.getInitialPolicies(); + Set initialPolicies = buildParams.initialPolicies(); initPolicies = new HashSet(); if (initialPolicies.isEmpty()) { // if no initialPolicies are specified by user, set // initPolicies to be anyPolicy by default initPolicies.add(PolicyChecker.ANY_POLICY); } else { - for (String policy : initialPolicies) { - initPolicies.add(policy); - } + initPolicies.addAll(initialPolicies); } } @@ -106,6 +103,7 @@ * Must be an instance of ReverseState * @param certStores list of CertStores */ + @Override Collection getMatchingCerts (State currState, List certStores) throws CertStoreException, CertificateException, IOException @@ -138,56 +136,56 @@ (ReverseState currentState, List certStores) throws CertStoreException, CertificateException, IOException { - /* - * Compose a CertSelector to filter out - * certs which do not satisfy requirements. - * - * First, retrieve clone of current target cert constraints, - * and then add more selection criteria based on current validation state. - */ - X509CertSelector sel = (X509CertSelector) targetCertConstraints.clone(); + /* + * Compose a CertSelector to filter out + * certs which do not satisfy requirements. + * + * First, retrieve clone of current target cert constraints, and + * then add more selection criteria based on current validation state. + */ + X509CertSelector sel = (X509CertSelector) targetCertConstraints.clone(); - /* - * Match on issuer (subject of previous cert) - */ - sel.setIssuer(currentState.subjectDN); + /* + * Match on issuer (subject of previous cert) + */ + sel.setIssuer(currentState.subjectDN); - /* - * Match on certificate validity date. - */ - sel.setCertificateValid(date); + /* + * Match on certificate validity date. + */ + sel.setCertificateValid(buildParams.date()); - /* - * Policy processing optimizations - */ - if (currentState.explicitPolicy == 0) - sel.setPolicy(getMatchingPolicies()); + /* + * Policy processing optimizations + */ + if (currentState.explicitPolicy == 0) + sel.setPolicy(getMatchingPolicies()); - /* - * If previous cert has a subject key identifier extension, - * use it to match on authority key identifier extension. - */ - /*if (currentState.subjKeyId != null) { - AuthorityKeyIdentifierExtension authKeyId = new AuthorityKeyIdentifierExtension( + /* + * If previous cert has a subject key identifier extension, + * use it to match on authority key identifier extension. + */ + /*if (currentState.subjKeyId != null) { + AuthorityKeyIdentifierExtension authKeyId = new AuthorityKeyIdentifierExtension( (KeyIdentifier) currentState.subjKeyId.get(SubjectKeyIdentifierExtension.KEY_ID), null, null); sel.setAuthorityKeyIdentifier(authKeyId.getExtensionValue()); - }*/ + }*/ - /* - * Require EE certs - */ - sel.setBasicConstraints(-2); + /* + * Require EE certs + */ + sel.setBasicConstraints(-2); - /* Retrieve matching certs from CertStores */ - HashSet eeCerts = new HashSet(); - addMatchingCerts(sel, certStores, eeCerts, true); + /* Retrieve matching certs from CertStores */ + HashSet eeCerts = new HashSet<>(); + addMatchingCerts(sel, certStores, eeCerts, true); - if (debug != null) { - debug.println("ReverseBuilder.getMatchingEECerts got " + eeCerts.size() - + " certs."); - } - return eeCerts; + if (debug != null) { + debug.println("ReverseBuilder.getMatchingEECerts got " + + eeCerts.size() + " certs."); + } + return eeCerts; } /* @@ -198,63 +196,71 @@ (ReverseState currentState, List certStores) throws CertificateException, CertStoreException, IOException { - /* - * Compose a CertSelector to filter out - * certs which do not satisfy requirements. - */ - X509CertSelector sel = new X509CertSelector(); + /* + * Compose a CertSelector to filter out + * certs which do not satisfy requirements. + */ + X509CertSelector sel = new X509CertSelector(); - /* - * Match on issuer (subject of previous cert) - */ - sel.setIssuer(currentState.subjectDN); + /* + * Match on issuer (subject of previous cert) + */ + sel.setIssuer(currentState.subjectDN); - /* - * Match on certificate validity date. - */ - sel.setCertificateValid(date); + /* + * Match on certificate validity date. + */ + sel.setCertificateValid(buildParams.date()); - /* - * Match on target subject name (checks that current cert's - * name constraints permit it to certify target). - * (4 is the integer type for DIRECTORY name). - */ - sel.addPathToName(4, targetCertConstraints.getSubjectAsBytes()); + /* + * Match on target subject name (checks that current cert's + * name constraints permit it to certify target). + * (4 is the integer type for DIRECTORY name). + */ + byte[] subject = targetCertConstraints.getSubjectAsBytes(); + if (subject != null) { + sel.addPathToName(4, subject); + } else { + X509Certificate cert = targetCertConstraints.getCertificate(); + if (cert != null) { + sel.addPathToName(4, + cert.getSubjectX500Principal().getEncoded()); + } + } - /* - * Policy processing optimizations - */ - if (currentState.explicitPolicy == 0) - sel.setPolicy(getMatchingPolicies()); + /* + * Policy processing optimizations + */ + if (currentState.explicitPolicy == 0) + sel.setPolicy(getMatchingPolicies()); - /* - * If previous cert has a subject key identifier extension, - * use it to match on authority key identifier extension. - */ - /*if (currentState.subjKeyId != null) { - AuthorityKeyIdentifierExtension authKeyId = new AuthorityKeyIdentifierExtension( + /* + * If previous cert has a subject key identifier extension, + * use it to match on authority key identifier extension. + */ + /*if (currentState.subjKeyId != null) { + AuthorityKeyIdentifierExtension authKeyId = new AuthorityKeyIdentifierExtension( (KeyIdentifier) currentState.subjKeyId.get(SubjectKeyIdentifierExtension.KEY_ID), null, null); - sel.setAuthorityKeyIdentifier(authKeyId.getExtensionValue()); - }*/ + sel.setAuthorityKeyIdentifier(authKeyId.getExtensionValue()); + }*/ - /* - * Require CA certs - */ - sel.setBasicConstraints(0); + /* + * Require CA certs + */ + sel.setBasicConstraints(0); - /* Retrieve matching certs from CertStores */ - ArrayList reverseCerts = - new ArrayList(); - addMatchingCerts(sel, certStores, reverseCerts, true); + /* Retrieve matching certs from CertStores */ + ArrayList reverseCerts = new ArrayList<>(); + addMatchingCerts(sel, certStores, reverseCerts, true); - /* Sort remaining certs using name constraints */ - Collections.sort(reverseCerts, new PKIXCertComparator()); + /* Sort remaining certs using name constraints */ + Collections.sort(reverseCerts, new PKIXCertComparator()); - if (debug != null) - debug.println("ReverseBuilder.getMatchingCACerts got " + - reverseCerts.size() + " certs."); - return reverseCerts; + if (debug != null) + debug.println("ReverseBuilder.getMatchingCACerts got " + + reverseCerts.size() + " certs."); + return reverseCerts; } /* @@ -269,23 +275,25 @@ private Debug debug = Debug.getInstance("certpath"); + @Override public int compare(X509Certificate cert1, X509Certificate cert2) { /* * if either cert certifies the target, always * put at head of list. */ - if (cert1.getSubjectX500Principal().equals(targetSubjectDN)) { + X500Principal targetSubject = buildParams.targetSubject(); + if (cert1.getSubjectX500Principal().equals(targetSubject)) { return -1; } - if (cert2.getSubjectX500Principal().equals(targetSubjectDN)) { + if (cert2.getSubjectX500Principal().equals(targetSubject)) { return 1; } int targetDist1; int targetDist2; try { - X500Name targetSubjectName = X500Name.asX500Name(targetSubjectDN); + X500Name targetSubjectName = X500Name.asX500Name(targetSubject); targetDist1 = Builder.targetDistance( null, cert1, targetSubjectName); targetDist2 = Builder.targetDistance( @@ -330,6 +338,7 @@ * @param currentState the current state against which the cert is verified * @param certPathList the certPathList generated thus far */ + @Override void verifyCert(X509Certificate cert, State currState, List certPathList) throws GeneralSecurityException @@ -362,8 +371,7 @@ * of the same certificate, we reverse the certpathlist first */ if ((certPathList != null) && (!certPathList.isEmpty())) { - List reverseCertList = - new ArrayList(); + List reverseCertList = new ArrayList<>(); for (X509Certificate c : certPathList) { reverseCertList.add(0, c); } @@ -378,8 +386,8 @@ } if (debug != null) debug.println("policyMappingFound = " + policyMappingFound); - if (cert.equals(cpListCert)){ - if ((buildParams.isPolicyMappingInhibited()) || + if (cert.equals(cpListCert)) { + if ((buildParams.policyMappingInhibited()) || (!policyMappingFound)){ if (debug != null) debug.println("loop detected!!"); @@ -390,7 +398,7 @@ } /* check if target cert */ - boolean finalCert = cert.getSubjectX500Principal().equals(targetSubjectDN); + boolean finalCert = cert.getSubjectX500Principal().equals(buildParams.targetSubject()); /* check if CA cert */ boolean caCert = (cert.getBasicConstraints() != -1 ? true : false); @@ -431,23 +439,20 @@ /* * Check revocation. */ - if (buildParams.isRevocationEnabled()) { - - currentState.crlChecker.check(cert, - currentState.pubKey, - currentState.crlSign); + if (buildParams.revocationEnabled() && currentState.revChecker != null) { + currentState.revChecker.check(cert, Collections.emptySet()); } /* Check name constraints if this is not a self-issued cert */ if (finalCert || !X509CertImpl.isSelfIssued(cert)){ - if (currentState.nc != null){ + if (currentState.nc != null) { try { if (!currentState.nc.verify(cert)){ throw new CertPathValidatorException ("name constraints check failed", null, null, -1, PKIXReason.INVALID_NAME); } - } catch (IOException ioe){ + } catch (IOException ioe) { throw new CertPathValidatorException(ioe); } } @@ -461,7 +466,7 @@ (currentState.certIndex, initPolicies, currentState.explicitPolicy, currentState.policyMapping, currentState.inhibitAnyPolicy, - buildParams.getPolicyQualifiersRejected(), currentState.rootNode, + buildParams.policyQualifiersRejected(), currentState.rootNode, certImpl, finalCert); /* @@ -486,15 +491,15 @@ * already checked. If there are any left, throw an exception! */ if (!unresolvedCritExts.isEmpty()) { - unresolvedCritExts.remove(PKIXExtensions.BasicConstraints_Id.toString()); - unresolvedCritExts.remove(PKIXExtensions.NameConstraints_Id.toString()); - unresolvedCritExts.remove(PKIXExtensions.CertificatePolicies_Id.toString()); - unresolvedCritExts.remove(PKIXExtensions.PolicyMappings_Id.toString()); - unresolvedCritExts.remove(PKIXExtensions.PolicyConstraints_Id.toString()); - unresolvedCritExts.remove(PKIXExtensions.InhibitAnyPolicy_Id.toString()); - unresolvedCritExts.remove(PKIXExtensions.SubjectAlternativeName_Id.toString()); - unresolvedCritExts.remove(PKIXExtensions.KeyUsage_Id.toString()); - unresolvedCritExts.remove(PKIXExtensions.ExtendedKeyUsage_Id.toString()); + unresolvedCritExts.remove(BasicConstraints_Id.toString()); + unresolvedCritExts.remove(NameConstraints_Id.toString()); + unresolvedCritExts.remove(CertificatePolicies_Id.toString()); + unresolvedCritExts.remove(PolicyMappings_Id.toString()); + unresolvedCritExts.remove(PolicyConstraints_Id.toString()); + unresolvedCritExts.remove(InhibitAnyPolicy_Id.toString()); + unresolvedCritExts.remove(SubjectAlternativeName_Id.toString()); + unresolvedCritExts.remove(KeyUsage_Id.toString()); + unresolvedCritExts.remove(ExtendedKeyUsage_Id.toString()); if (!unresolvedCritExts.isEmpty()) throw new CertPathValidatorException @@ -505,8 +510,8 @@ /* * Check signature. */ - if (buildParams.getSigProvider() != null) { - cert.verify(currentState.pubKey, buildParams.getSigProvider()); + if (buildParams.sigProvider() != null) { + cert.verify(currentState.pubKey, buildParams.sigProvider()); } else { cert.verify(currentState.pubKey); } @@ -519,8 +524,9 @@ * @param cert the certificate to test * @return a boolean value indicating whether the cert completes the path. */ + @Override boolean isPathCompleted(X509Certificate cert) { - return cert.getSubjectX500Principal().equals(targetSubjectDN); + return cert.getSubjectX500Principal().equals(buildParams.targetSubject()); } /** Adds the certificate to the certPathList @@ -528,6 +534,7 @@ * @param cert the certificate to be added * @param certPathList the certification path list */ + @Override void addCertToPath(X509Certificate cert, LinkedList certPathList) { certPathList.addLast(cert); @@ -537,6 +544,7 @@ * * @param certPathList the certification path list */ + @Override void removeFinalCertFromPath(LinkedList certPathList) { certPathList.removeLast(); } diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/certpath/ReverseState.java --- a/src/share/classes/sun/security/provider/certpath/ReverseState.java Thu Sep 07 23:37:21 2017 -0700 +++ b/src/share/classes/sun/security/provider/certpath/ReverseState.java Sat Feb 03 21:37:28 2018 -0800 @@ -32,7 +32,6 @@ import java.security.cert.PKIXCertPathChecker; import java.security.cert.TrustAnchor; import java.security.cert.X509Certificate; -import java.security.interfaces.DSAPublicKey; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -40,6 +39,7 @@ import java.util.Set; import javax.security.auth.x500.X500Principal; +import sun.security.provider.certpath.PKIX.BuilderParams; import sun.security.util.Debug; import sun.security.x509.NameConstraintsExtension; import sun.security.x509.SubjectKeyIdentifierExtension; @@ -94,7 +94,7 @@ private boolean init = true; /* the checker used for revocation status */ - public CrlRevocationChecker crlChecker; + RevocationChecker revChecker; /* the algorithm checker */ AlgorithmChecker algorithmChecker; @@ -108,7 +108,7 @@ /* Flag indicating if current cert can vouch for the CRL for * the next cert */ - public boolean crlSign = true; + boolean crlSign = true; /** * Returns a boolean flag indicating if the state is initial @@ -116,6 +116,7 @@ * * @return boolean flag indicating if the state is initial (just starting) */ + @Override public boolean isInitial() { return init; } @@ -123,44 +124,32 @@ /** * Display state for debugging purposes */ + @Override public String toString() { - StringBuffer sb = new StringBuffer(); - try { - sb.append("State ["); - sb.append("\n subjectDN of last cert: " + subjectDN); - sb.append("\n subjectKeyIdentifier: " + String.valueOf(subjKeyId)); - sb.append("\n nameConstraints: " + String.valueOf(nc)); - sb.append("\n certIndex: " + certIndex); - sb.append("\n explicitPolicy: " + explicitPolicy); - sb.append("\n policyMapping: " + policyMapping); - sb.append("\n inhibitAnyPolicy: " + inhibitAnyPolicy); - sb.append("\n rootNode: " + rootNode); - sb.append("\n remainingCACerts: " + remainingCACerts); - sb.append("\n crlSign: " + crlSign); - sb.append("\n init: " + init); - sb.append("\n]\n"); - } catch (Exception e) { - if (debug != null) { - debug.println("ReverseState.toString() unexpected exception"); - e.printStackTrace(); - } - } + StringBuilder sb = new StringBuilder(); + sb.append("State ["); + sb.append("\n subjectDN of last cert: ").append(subjectDN); + sb.append("\n subjectKeyIdentifier: ").append + (String.valueOf(subjKeyId)); + sb.append("\n nameConstraints: ").append(String.valueOf(nc)); + sb.append("\n certIndex: ").append(certIndex); + sb.append("\n explicitPolicy: ").append(explicitPolicy); + sb.append("\n policyMapping: ").append(policyMapping); + sb.append("\n inhibitAnyPolicy: ").append(inhibitAnyPolicy); + sb.append("\n rootNode: ").append(rootNode); + sb.append("\n remainingCACerts: ").append(remainingCACerts); + sb.append("\n crlSign: ").append(crlSign); + sb.append("\n init: ").append(init); + sb.append("\n]\n"); return sb.toString(); } /** * Initialize the state. * - * @param maxPathLen The maximum number of CA certs in a path, where -1 - * means unlimited and 0 means only a single EE cert is allowed. - * @param explicitPolicyRequired True, if explicit policy is required. - * @param policyMappingInhibited True, if policy mapping is inhibited. - * @param anyPolicyInhibited True, if any policy is inhibited. - * @param certPathCheckers the list of user-defined PKIXCertPathCheckers + * @param buildParams builder parameters */ - public void initState(int maxPathLen, boolean explicitPolicyRequired, - boolean policyMappingInhibited, boolean anyPolicyInhibited, - List certPathCheckers) + public void initState(BuilderParams buildParams) throws CertPathValidatorException { /* @@ -168,60 +157,52 @@ * Note that -1 maxPathLen implies unlimited. * 0 implies only an EE cert is acceptable. */ - remainingCACerts = (maxPathLen == -1 ? Integer.MAX_VALUE : maxPathLen); + int maxPathLen = buildParams.maxPathLength(); + remainingCACerts = (maxPathLen == -1) ? Integer.MAX_VALUE + : maxPathLen; /* Initialize explicit policy state variable */ - if (explicitPolicyRequired) { + if (buildParams.explicitPolicyRequired()) { explicitPolicy = 0; } else { // unconstrained if maxPathLen is -1, // otherwise, we want to initialize this to the value of the // longest possible path + 1 (i.e. maxpathlen + finalcert + 1) - explicitPolicy = (maxPathLen == -1) - ? maxPathLen - : maxPathLen + 2; + explicitPolicy = (maxPathLen == -1) ? maxPathLen : maxPathLen + 2; } /* Initialize policy mapping state variable */ - if (policyMappingInhibited) { + if (buildParams.policyMappingInhibited()) { policyMapping = 0; } else { - policyMapping = (maxPathLen == -1) - ? maxPathLen - : maxPathLen + 2; + policyMapping = (maxPathLen == -1) ? maxPathLen : maxPathLen + 2; } /* Initialize inhibit any policy state variable */ - if (anyPolicyInhibited) { + if (buildParams.anyPolicyInhibited()) { inhibitAnyPolicy = 0; } else { - inhibitAnyPolicy = (maxPathLen == -1) - ? maxPathLen - : maxPathLen + 2; + inhibitAnyPolicy = (maxPathLen == -1) ? maxPathLen : maxPathLen + 2; } /* Initialize certIndex */ certIndex = 1; /* Initialize policy tree */ - Set initExpPolSet = new HashSet(1); + Set initExpPolSet = new HashSet<>(1); initExpPolSet.add(PolicyChecker.ANY_POLICY); - rootNode = new PolicyNodeImpl - (null, PolicyChecker.ANY_POLICY, null, false, initExpPolSet, false); + rootNode = new PolicyNodeImpl(null, PolicyChecker.ANY_POLICY, null, + false, initExpPolSet, false); /* * Initialize each user-defined checker + * Shallow copy the checkers */ - if (certPathCheckers != null) { - /* Shallow copy the checkers */ - userCheckers = new ArrayList(certPathCheckers); - /* initialize each checker (just in case) */ - for (PKIXCertPathChecker checker : certPathCheckers) { - checker.init(false); - } - } else { - userCheckers = new ArrayList(); + userCheckers = new ArrayList<>(buildParams.certPathCheckers()); + /* initialize each checker (just in case) */ + for (PKIXCertPathChecker checker : userCheckers) { + checker.init(false); } /* Start by trusting the cert to sign CRLs */ @@ -234,8 +215,9 @@ * Update the state with the specified trust anchor. * * @param anchor the most-trusted CA + * @param buildParams builder parameters */ - public void updateState(TrustAnchor anchor) + public void updateState(TrustAnchor anchor, BuilderParams buildParams) throws CertificateException, IOException, CertPathValidatorException { trustAnchor = anchor; @@ -255,6 +237,12 @@ } } + // only create a RevocationChecker if revocation is enabled + if (buildParams.revocationEnabled()) { + revChecker = new RevocationChecker(anchor, buildParams); + revChecker.init(false); + } + init = false; } @@ -292,8 +280,7 @@ /* check for key needing to inherit alg parameters */ X509CertImpl icert = X509CertImpl.toImpl(cert); PublicKey newKey = cert.getPublicKey(); - if (newKey instanceof DSAPublicKey && - (((DSAPublicKey)newKey).getParams() == null)) { + if (PKIX.isDSAPublicKeyWithoutParams(newKey)) { newKey = BasicChecker.makeInheritedParamsKey(newKey, pubKey); } @@ -313,7 +300,7 @@ subjKeyId = icert.getSubjectKeyIdentifierExtension(); /* update crlSign */ - crlSign = CrlRevocationChecker.certCanSignCrl(cert); + crlSign = RevocationChecker.certCanSignCrl(cert); /* update current name constraints */ if (nc != null) { @@ -352,6 +339,7 @@ * * @return boolean flag indicating if key lacking parameters encountered. */ + @Override public boolean keyParamsNeeded() { /* when building in reverse, we immediately get parameters needed * or else throw an exception @@ -368,6 +356,7 @@ * because some of them (e.g., subjKeyId) will * not have their contents modified by subsequent calls to updateState. */ + @Override @SuppressWarnings("unchecked") // Safe casts assuming clone() works correctly public Object clone() { try { diff -r 6b21d823f6e6 -r 1d98f0be7c8d src/share/classes/sun/security/provider/certpath/RevocationChecker.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/sun/security/provider/certpath/RevocationChecker.java Sat Feb 03 21:37:28 2018 -0800 @@ -0,0 +1,1150 @@ +/* + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.provider.certpath; + +import java.io.IOException; +import java.math.BigInteger; +import java.net.URI; +import java.net.URISyntaxException; +import java.security.AccessController; +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivilegedAction; +import java.security.PublicKey; +import java.security.Security; +import java.security.cert.CertPathValidatorException.BasicReason; +import java.security.cert.Extension; +import java.security.cert.*; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.security.auth.x500.X500Principal; + +import static sun.security.provider.certpath.OCSP.*; +import static sun.security.provider.certpath.PKIX.*; +import sun.security.x509.*; +import static sun.security.x509.PKIXExtensions.*; +import sun.security.util.Debug; + +class RevocationChecker extends PKIXRevocationChecker { + + private static final Debug debug = Debug.getInstance("certpath"); + + private TrustAnchor anchor; + private ValidatorParams params; + private boolean onlyEE; + private boolean softFail; + private boolean crlDP; + private URI responderURI; + private X509Certificate responderCert; + private List certStores; + private Map ocspStapled; + private List ocspExtensions; + private final boolean legacy; + + // state variables + private OCSPResponse.IssuerInfo issuerInfo; + private PublicKey prevPubKey; + private boolean crlSignFlag; + + private enum Mode { PREFER_OCSP, PREFER_CRLS, ONLY_CRLS }; + private Mode mode = Mode.PREFER_OCSP; + + private static class RevocationProperties { + boolean onlyEE; + boolean ocspEnabled; + boolean crlDPEnabled; + String ocspUrl; + String ocspSubject; + String ocspIssuer; + String ocspSerial; + } + + RevocationChecker() { + legacy = false; + } + + RevocationChecker(TrustAnchor anchor, ValidatorParams params) + throws CertPathValidatorException + { + legacy = true; + init(anchor, params); + } + + void init(TrustAnchor anchor, ValidatorParams params) + throws CertPathValidatorException + { + RevocationProperties rp = getRevocationProperties(); + URI uri = getOCSPResponder(); + responderURI = (uri == null) ? toURI(rp.ocspUrl) : uri; + X509Certificate cert = getOCSPResponderCert(); + responderCert = (cert == null) + ? getResponderCert(rp, params.trustAnchors(), + params.certStores()) + : cert; + Set