8140422: Add mechanism to allow non default root CAs to be not subject to algorithm restrictions
Reviewed-by: mullan, xuelei
This commit is contained in:
parent
4b69b86a7f
commit
b3854d5830
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2011, 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
|
||||
@ -41,7 +41,7 @@ include GendataPolicyJars.gmk
|
||||
GENDATA_UNINAME := $(JDK_OUTPUTDIR)/modules/java.base/java/lang/uniName.dat
|
||||
|
||||
$(GENDATA_UNINAME): $(JDK_TOPDIR)/make/data/unicodedata/UnicodeData.txt $(BUILD_TOOLS_JDK)
|
||||
$(MKDIR) -p $(@D)
|
||||
$(call MakeDir, $(@D))
|
||||
$(TOOL_CHARACTERNAME) $< $@
|
||||
|
||||
TARGETS += $(GENDATA_UNINAME)
|
||||
@ -51,7 +51,7 @@ TARGETS += $(GENDATA_UNINAME)
|
||||
GENDATA_CURDATA := $(JDK_OUTPUTDIR)/modules/java.base/java/util/currency.data
|
||||
|
||||
$(GENDATA_CURDATA): $(JDK_TOPDIR)/make/data/currency/CurrencyData.properties $(BUILD_TOOLS_JDK)
|
||||
$(MKDIR) -p $(@D)
|
||||
$(call MakeDir, $(@D))
|
||||
$(RM) $@
|
||||
$(TOOL_GENERATECURRENCYDATA) -o $@.tmp < $<
|
||||
$(MV) $@.tmp $@
|
||||
@ -67,10 +67,10 @@ GENDATA_JAVA_SECURITY := $(SUPPORT_OUTPUTDIR)/modules_conf/java.base/security/ja
|
||||
# RESTRICTED_PKGS_SRC is optionally set in custom extension for this makefile
|
||||
|
||||
$(GENDATA_JAVA_SECURITY): $(BUILD_TOOLS) $(GENDATA_JAVA_SECURITY_SRC) $(RESTRICTED_PKGS_SRC)
|
||||
$(ECHO) "Generating java.security"
|
||||
$(MKDIR) -p $(@D)
|
||||
$(call LogInfo, Generating java.security)
|
||||
$(call MakeDir, $(@D))
|
||||
$(TOOL_MAKEJAVASECURITY) $(GENDATA_JAVA_SECURITY_SRC) $@ $(OPENJDK_TARGET_OS) \
|
||||
$(OPENJDK_TARGET_CPU_ARCH) $(RESTRICTED_PKGS_SRC) || exit 1
|
||||
$(OPENJDK_TARGET_CPU_ARCH) $(RESTRICTED_PKGS_SRC)
|
||||
|
||||
TARGETS += $(GENDATA_JAVA_SECURITY)
|
||||
|
||||
@ -78,7 +78,7 @@ TARGETS += $(GENDATA_JAVA_SECURITY)
|
||||
|
||||
$(SUPPORT_OUTPUTDIR)/modules_libs/java.base/classlist: \
|
||||
$(JDK_TOPDIR)/make/data/classlist/classlist.$(OPENJDK_TARGET_OS)
|
||||
$(MKDIR) -p $(@D)
|
||||
$(call MakeDir, $(@D))
|
||||
$(RM) $@ $@.tmp
|
||||
$(TOOL_ADDJSUM) $< $@.tmp
|
||||
$(MV) $@.tmp $@
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -31,12 +31,10 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashSet;
|
||||
import java.math.BigInteger;
|
||||
import java.security.PublicKey;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.AlgorithmParameters;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.X509CRL;
|
||||
@ -48,10 +46,13 @@ import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertPathValidatorException;
|
||||
import java.security.cert.CertPathValidatorException.BasicReason;
|
||||
import java.security.cert.PKIXReason;
|
||||
import java.io.IOException;
|
||||
import java.security.interfaces.*;
|
||||
import java.security.spec.*;
|
||||
import java.security.interfaces.DSAParams;
|
||||
import java.security.interfaces.DSAPublicKey;
|
||||
import java.security.spec.DSAPublicKeySpec;
|
||||
|
||||
import sun.security.util.AnchorCertificates;
|
||||
import sun.security.util.CertConstraintParameters;
|
||||
import sun.security.util.Debug;
|
||||
import sun.security.util.DisabledAlgorithmConstraints;
|
||||
import sun.security.x509.X509CertImpl;
|
||||
import sun.security.x509.X509CRLImpl;
|
||||
@ -69,6 +70,7 @@ import sun.security.x509.AlgorithmId;
|
||||
* @see PKIXParameters
|
||||
*/
|
||||
public final class AlgorithmChecker extends PKIXCertPathChecker {
|
||||
private static final Debug debug = Debug.getInstance("certpath");
|
||||
|
||||
private final AlgorithmConstraints constraints;
|
||||
private final PublicKey trustedPubKey;
|
||||
@ -88,6 +90,14 @@ public final class AlgorithmChecker extends PKIXCertPathChecker {
|
||||
certPathDefaultConstraints = new DisabledAlgorithmConstraints(
|
||||
DisabledAlgorithmConstraints.PROPERTY_CERTPATH_DISABLED_ALGS);
|
||||
|
||||
// If there is no "cacerts" keyword, then disable anchor checking
|
||||
private static final boolean publicCALimits =
|
||||
certPathDefaultConstraints.checkProperty("jdkCA");
|
||||
|
||||
// If anchor checking enabled, this will be true if the trust anchor
|
||||
// has a match in the cacerts file
|
||||
private boolean trustedMatch = false;
|
||||
|
||||
/**
|
||||
* Create a new <code>AlgorithmChecker</code> with the algorithm
|
||||
* constraints specified in security property
|
||||
@ -136,6 +146,11 @@ public final class AlgorithmChecker extends PKIXCertPathChecker {
|
||||
|
||||
if (anchor.getTrustedCert() != null) {
|
||||
this.trustedPubKey = anchor.getTrustedCert().getPublicKey();
|
||||
// Check for anchor certificate restrictions
|
||||
trustedMatch = checkFingerprint(anchor.getTrustedCert());
|
||||
if (trustedMatch && debug != null) {
|
||||
debug.println("trustedMatch = true");
|
||||
}
|
||||
} else {
|
||||
this.trustedPubKey = anchor.getCAPublicKey();
|
||||
}
|
||||
@ -144,6 +159,19 @@ public final class AlgorithmChecker extends PKIXCertPathChecker {
|
||||
this.constraints = constraints;
|
||||
}
|
||||
|
||||
// Check this 'cert' for restrictions in the AnchorCertificates
|
||||
// trusted certificates list
|
||||
private static boolean checkFingerprint(X509Certificate cert) {
|
||||
if (!publicCALimits) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (debug != null) {
|
||||
debug.println("AlgorithmChecker.contains: " + cert.getSigAlgName());
|
||||
}
|
||||
return AnchorCertificates.contains(cert);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(boolean forward) throws CertPathValidatorException {
|
||||
// Note that this class does not support forward mode.
|
||||
@ -181,36 +209,8 @@ public final class AlgorithmChecker extends PKIXCertPathChecker {
|
||||
return;
|
||||
}
|
||||
|
||||
X509CertImpl x509Cert = null;
|
||||
try {
|
||||
x509Cert = X509CertImpl.toImpl((X509Certificate)cert);
|
||||
} catch (CertificateException ce) {
|
||||
throw new CertPathValidatorException(ce);
|
||||
}
|
||||
|
||||
PublicKey currPubKey = x509Cert.getPublicKey();
|
||||
String currSigAlg = x509Cert.getSigAlgName();
|
||||
|
||||
AlgorithmId algorithmId = null;
|
||||
try {
|
||||
algorithmId = (AlgorithmId)x509Cert.get(X509CertImpl.SIG_ALG);
|
||||
} catch (CertificateException ce) {
|
||||
throw new CertPathValidatorException(ce);
|
||||
}
|
||||
|
||||
AlgorithmParameters currSigAlgParams = algorithmId.getParameters();
|
||||
|
||||
// Check the current signature algorithm
|
||||
if (!constraints.permits(
|
||||
SIGNATURE_PRIMITIVE_SET,
|
||||
currSigAlg, currSigAlgParams)) {
|
||||
throw new CertPathValidatorException(
|
||||
"Algorithm constraints check failed: " + currSigAlg,
|
||||
null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
|
||||
}
|
||||
|
||||
// check the key usage and key size
|
||||
boolean[] keyUsage = x509Cert.getKeyUsage();
|
||||
boolean[] keyUsage = ((X509Certificate) cert).getKeyUsage();
|
||||
if (keyUsage != null && keyUsage.length < 9) {
|
||||
throw new CertPathValidatorException(
|
||||
"incorrect KeyUsage extension",
|
||||
@ -248,27 +248,67 @@ public final class AlgorithmChecker extends PKIXCertPathChecker {
|
||||
|
||||
if (primitives.isEmpty()) {
|
||||
throw new CertPathValidatorException(
|
||||
"incorrect KeyUsage extension",
|
||||
"incorrect KeyUsage extension bits",
|
||||
null, null, -1, PKIXReason.INVALID_KEY_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
if (!constraints.permits(primitives, currPubKey)) {
|
||||
throw new CertPathValidatorException(
|
||||
"algorithm constraints check failed",
|
||||
null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
|
||||
PublicKey currPubKey = cert.getPublicKey();
|
||||
|
||||
// Check against DisabledAlgorithmConstraints certpath constraints.
|
||||
// permits() will throw exception on failure.
|
||||
certPathDefaultConstraints.permits(primitives,
|
||||
new CertConstraintParameters((X509Certificate)cert,
|
||||
trustedMatch));
|
||||
// new CertConstraintParameters(x509Cert, trustedMatch));
|
||||
// If there is no previous key, set one and exit
|
||||
if (prevPubKey == null) {
|
||||
prevPubKey = currPubKey;
|
||||
return;
|
||||
}
|
||||
|
||||
X509CertImpl x509Cert;
|
||||
AlgorithmId algorithmId;
|
||||
try {
|
||||
x509Cert = X509CertImpl.toImpl((X509Certificate)cert);
|
||||
algorithmId = (AlgorithmId)x509Cert.get(X509CertImpl.SIG_ALG);
|
||||
} catch (CertificateException ce) {
|
||||
throw new CertPathValidatorException(ce);
|
||||
}
|
||||
|
||||
AlgorithmParameters currSigAlgParams = algorithmId.getParameters();
|
||||
String currSigAlg = x509Cert.getSigAlgName();
|
||||
|
||||
// If 'constraints' is not of DisabledAlgorithmConstraints, check all
|
||||
// everything individually
|
||||
if (!(constraints instanceof DisabledAlgorithmConstraints)) {
|
||||
// Check the current signature algorithm
|
||||
if (!constraints.permits(
|
||||
SIGNATURE_PRIMITIVE_SET,
|
||||
currSigAlg, currSigAlgParams)) {
|
||||
throw new CertPathValidatorException(
|
||||
"Algorithm constraints check failed on signature " +
|
||||
"algorithm: " + currSigAlg, null, null, -1,
|
||||
BasicReason.ALGORITHM_CONSTRAINED);
|
||||
}
|
||||
|
||||
if (!constraints.permits(primitives, currPubKey)) {
|
||||
throw new CertPathValidatorException(
|
||||
"Algorithm constraints check failed on keysize: " +
|
||||
sun.security.util.KeyUtil.getKeySize(currPubKey),
|
||||
null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
|
||||
}
|
||||
}
|
||||
|
||||
// Check with previous cert for signature algorithm and public key
|
||||
if (prevPubKey != null) {
|
||||
if (currSigAlg != null) {
|
||||
if (!constraints.permits(
|
||||
SIGNATURE_PRIMITIVE_SET,
|
||||
currSigAlg, prevPubKey, currSigAlgParams)) {
|
||||
throw new CertPathValidatorException(
|
||||
"Algorithm constraints check failed: " + currSigAlg,
|
||||
null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
// Inherit key parameters from previous key
|
||||
@ -282,7 +322,7 @@ public final class AlgorithmChecker extends PKIXCertPathChecker {
|
||||
DSAParams params = ((DSAPublicKey)prevPubKey).getParams();
|
||||
if (params == null) {
|
||||
throw new CertPathValidatorException(
|
||||
"Key parameters missing");
|
||||
"Key parameters missing from public key.");
|
||||
}
|
||||
|
||||
try {
|
||||
@ -330,6 +370,11 @@ public final class AlgorithmChecker extends PKIXCertPathChecker {
|
||||
// Don't bother to change the trustedPubKey.
|
||||
if (anchor.getTrustedCert() != null) {
|
||||
prevPubKey = anchor.getTrustedCert().getPublicKey();
|
||||
// Check for anchor certificate restrictions
|
||||
trustedMatch = checkFingerprint(anchor.getTrustedCert());
|
||||
if (trustedMatch && debug != null) {
|
||||
debug.println("trustedMatch = true");
|
||||
}
|
||||
} else {
|
||||
prevPubKey = anchor.getCAPublicKey();
|
||||
}
|
||||
@ -370,7 +415,8 @@ public final class AlgorithmChecker extends PKIXCertPathChecker {
|
||||
if (!certPathDefaultConstraints.permits(
|
||||
SIGNATURE_PRIMITIVE_SET, sigAlgName, key, sigAlgParams)) {
|
||||
throw new CertPathValidatorException(
|
||||
"algorithm check failed: " + sigAlgName + " is disabled",
|
||||
"Algorithm constraints check failed on signature algorithm: " +
|
||||
sigAlgName + " is disabled",
|
||||
null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
|
||||
}
|
||||
}
|
||||
|
@ -131,8 +131,8 @@ class PKIXMasterCertPathValidator {
|
||||
|
||||
} catch (CertPathValidatorException cpve) {
|
||||
throw new CertPathValidatorException(cpve.getMessage(),
|
||||
cpve.getCause(), cpOriginal, cpSize - (i + 1),
|
||||
cpve.getReason());
|
||||
(cpve.getCause() != null) ? cpve.getCause() : cpve,
|
||||
cpOriginal, cpSize - (i + 1), cpve.getReason());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2016 Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -29,7 +29,6 @@ import java.security.AccessController;
|
||||
import java.security.AlgorithmConstraints;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.Security;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@ -45,8 +44,7 @@ public abstract class AbstractAlgorithmConstraints
|
||||
}
|
||||
|
||||
// Get algorithm constraints from the specified security property.
|
||||
private static void loadAlgorithmsMap(Map<String, String[]> algorithmsMap,
|
||||
String propertyName) {
|
||||
static String[] getAlgorithms(String propertyName) {
|
||||
String property = AccessController.doPrivileged(
|
||||
(PrivilegedAction<String>) () -> Security.getProperty(
|
||||
propertyName));
|
||||
@ -68,18 +66,7 @@ public abstract class AbstractAlgorithmConstraints
|
||||
if (algorithmsInProperty == null) {
|
||||
algorithmsInProperty = new String[0];
|
||||
}
|
||||
algorithmsMap.put(propertyName, algorithmsInProperty);
|
||||
}
|
||||
|
||||
static String[] getAlgorithms(Map<String, String[]> algorithmsMap,
|
||||
String propertyName) {
|
||||
synchronized (algorithmsMap) {
|
||||
if (!algorithmsMap.containsKey(propertyName)) {
|
||||
loadAlgorithmsMap(algorithmsMap, propertyName);
|
||||
}
|
||||
|
||||
return algorithmsMap.get(propertyName);
|
||||
}
|
||||
return algorithmsInProperty;
|
||||
}
|
||||
|
||||
static boolean checkAlgorithm(String[] algorithms, String algorithm,
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -40,19 +40,7 @@ public class AlgorithmDecomposer {
|
||||
private static final Pattern pattern =
|
||||
Pattern.compile("with|and|(?<!padd)in", Pattern.CASE_INSENSITIVE);
|
||||
|
||||
/**
|
||||
* Decompose the standard algorithm name into sub-elements.
|
||||
* <p>
|
||||
* For example, we need to decompose "SHA1WithRSA" into "SHA1" and "RSA"
|
||||
* so that we can check the "SHA1" and "RSA" algorithm constraints
|
||||
* separately.
|
||||
* <p>
|
||||
* Please override the method if need to support more name pattern.
|
||||
*/
|
||||
public Set<String> decompose(String algorithm) {
|
||||
if (algorithm == null || algorithm.length() == 0) {
|
||||
return new HashSet<>();
|
||||
}
|
||||
private static Set<String> decomposeImpl(String algorithm) {
|
||||
|
||||
// algorithm/mode/padding
|
||||
String[] transTockens = transPattern.split(algorithm);
|
||||
@ -79,6 +67,24 @@ public class AlgorithmDecomposer {
|
||||
elements.add(token);
|
||||
}
|
||||
}
|
||||
return elements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decompose the standard algorithm name into sub-elements.
|
||||
* <p>
|
||||
* For example, we need to decompose "SHA1WithRSA" into "SHA1" and "RSA"
|
||||
* so that we can check the "SHA1" and "RSA" algorithm constraints
|
||||
* separately.
|
||||
* <p>
|
||||
* Please override the method if need to support more name pattern.
|
||||
*/
|
||||
public Set<String> decompose(String algorithm) {
|
||||
if (algorithm == null || algorithm.length() == 0) {
|
||||
return new HashSet<>();
|
||||
}
|
||||
|
||||
Set<String> elements = decomposeImpl(algorithm);
|
||||
|
||||
// In Java standard algorithm name specification, for different
|
||||
// purpose, the SHA-1 and SHA-2 algorithm names are different. For
|
||||
@ -130,4 +136,40 @@ public class AlgorithmDecomposer {
|
||||
return elements;
|
||||
}
|
||||
|
||||
private static void hasLoop(Set<String> elements, String find, String replace) {
|
||||
if (elements.contains(find)) {
|
||||
if (!elements.contains(replace)) {
|
||||
elements.add(replace);
|
||||
}
|
||||
elements.remove(find);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This decomposes a standard name into sub-elements with a consistent
|
||||
* message digest algorithm name to avoid overly complicated checking.
|
||||
*/
|
||||
public static Set<String> decomposeOneHash(String algorithm) {
|
||||
if (algorithm == null || algorithm.length() == 0) {
|
||||
return new HashSet<>();
|
||||
}
|
||||
|
||||
Set<String> elements = decomposeImpl(algorithm);
|
||||
|
||||
hasLoop(elements, "SHA-1", "SHA1");
|
||||
hasLoop(elements, "SHA-224", "SHA224");
|
||||
hasLoop(elements, "SHA-256", "SHA256");
|
||||
hasLoop(elements, "SHA-384", "SHA384");
|
||||
hasLoop(elements, "SHA-512", "SHA512");
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
||||
/*
|
||||
* The provided message digest algorithm name will return a consistent
|
||||
* naming scheme.
|
||||
*/
|
||||
public static String hashName(String algorithm) {
|
||||
return algorithm.replace("-", "");
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.security.AccessController;
|
||||
import java.security.KeyStore;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
|
||||
import sun.security.x509.X509CertImpl;
|
||||
|
||||
/**
|
||||
* The purpose of this class is to determine the trust anchor certificates is in
|
||||
* the cacerts file. This is used for PKIX CertPath checking.
|
||||
*/
|
||||
public class AnchorCertificates {
|
||||
|
||||
private static final Debug debug = Debug.getInstance("certpath");
|
||||
private static final String HASH = "SHA-256";
|
||||
private static HashSet<String> certs;
|
||||
|
||||
static {
|
||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||
@Override
|
||||
public Void run() {
|
||||
File f = new File(System.getProperty("java.home"),
|
||||
"lib/security/cacerts");
|
||||
KeyStore cacerts;
|
||||
try {
|
||||
cacerts = KeyStore.getInstance("JKS");
|
||||
try (FileInputStream fis = new FileInputStream(f)) {
|
||||
cacerts.load(fis, "changeit".toCharArray());
|
||||
certs = new HashSet<>();
|
||||
Enumeration<String> list = cacerts.aliases();
|
||||
String alias;
|
||||
while (list.hasMoreElements()) {
|
||||
alias = list.nextElement();
|
||||
// Check if this cert is labeled a trust anchor.
|
||||
if (alias.contains(" [jdk")) {
|
||||
X509Certificate cert = (X509Certificate) cacerts
|
||||
.getCertificate(alias);
|
||||
certs.add(X509CertImpl.getFingerprint(HASH, cert));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (debug != null) {
|
||||
debug.println("Error parsing cacerts");
|
||||
}
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a certificate is a trust anchor.
|
||||
*
|
||||
* @param cert the certificate to check
|
||||
* @return true if the certificate is trusted.
|
||||
*/
|
||||
public static boolean contains(X509Certificate cert) {
|
||||
String key = X509CertImpl.getFingerprint(HASH, cert);
|
||||
boolean result = certs.contains(key);
|
||||
if (result && debug != null) {
|
||||
debug.println("AnchorCertificate.contains: matched " +
|
||||
cert.getSubjectDN());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private AnchorCertificates() {}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.util;
|
||||
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
/**
|
||||
* This class is a wrapper for keeping state and passing objects between PKIX,
|
||||
* AlgorithmChecker, and DisabledAlgorithmConstraints.
|
||||
*/
|
||||
public class CertConstraintParameters {
|
||||
// A certificate being passed to check against constraints.
|
||||
private final X509Certificate cert;
|
||||
|
||||
// This is true if the trust anchor in the certificate chain matches a cert
|
||||
// in AnchorCertificates
|
||||
private final boolean trustedMatch;
|
||||
|
||||
public CertConstraintParameters(X509Certificate c, boolean match) {
|
||||
cert = c;
|
||||
trustedMatch = match;
|
||||
}
|
||||
|
||||
public CertConstraintParameters(X509Certificate c) {
|
||||
this(c, false);
|
||||
}
|
||||
|
||||
// Returns if the trust anchor has a match if anchor checking is enabled.
|
||||
public boolean isTrustedMatch() {
|
||||
return trustedMatch;
|
||||
}
|
||||
|
||||
public X509Certificate getCertificate() {
|
||||
return cert;
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -28,12 +28,14 @@ package sun.security.util;
|
||||
import java.security.CryptoPrimitive;
|
||||
import java.security.AlgorithmParameters;
|
||||
import java.security.Key;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.security.cert.CertPathValidatorException;
|
||||
import java.security.cert.CertPathValidatorException.BasicReason;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
@ -44,6 +46,7 @@ import java.util.regex.Matcher;
|
||||
* for the syntax of the disabled algorithm string.
|
||||
*/
|
||||
public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
|
||||
private static final Debug debug = Debug.getInstance("certpath");
|
||||
|
||||
// the known security property, jdk.certpath.disabledAlgorithms
|
||||
public static final String PROPERTY_CERTPATH_DISABLED_ALGS =
|
||||
@ -53,13 +56,8 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
|
||||
public static final String PROPERTY_TLS_DISABLED_ALGS =
|
||||
"jdk.tls.disabledAlgorithms";
|
||||
|
||||
private static final Map<String, String[]> disabledAlgorithmsMap =
|
||||
new HashMap<>();
|
||||
private static final Map<String, KeySizeConstraints> keySizeConstraintsMap =
|
||||
new HashMap<>();
|
||||
|
||||
private final String[] disabledAlgorithms;
|
||||
private final KeySizeConstraints keySizeConstraints;
|
||||
private final Constraints algorithmConstraints;
|
||||
|
||||
/**
|
||||
* Initialize algorithm constraints with the specified security property.
|
||||
@ -74,11 +72,14 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
|
||||
public DisabledAlgorithmConstraints(String propertyName,
|
||||
AlgorithmDecomposer decomposer) {
|
||||
super(decomposer);
|
||||
disabledAlgorithms = getAlgorithms(disabledAlgorithmsMap, propertyName);
|
||||
keySizeConstraints = getKeySizeConstraints(disabledAlgorithms,
|
||||
propertyName);
|
||||
disabledAlgorithms = getAlgorithms(propertyName);
|
||||
algorithmConstraints = new Constraints(disabledAlgorithms);
|
||||
}
|
||||
|
||||
/*
|
||||
* This only checks if the algorithm has been completely disabled. If
|
||||
* there are keysize or other limit, this method allow the algorithm.
|
||||
*/
|
||||
@Override
|
||||
public final boolean permits(Set<CryptoPrimitive> primitives,
|
||||
String algorithm, AlgorithmParameters parameters) {
|
||||
@ -91,11 +92,19 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
|
||||
return checkAlgorithm(disabledAlgorithms, algorithm, decomposer);
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if the key algorithm has been disabled or constraints have been
|
||||
* placed on the key.
|
||||
*/
|
||||
@Override
|
||||
public final boolean permits(Set<CryptoPrimitive> primitives, Key key) {
|
||||
return checkConstraints(primitives, "", key, null);
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if the key algorithm has been disabled or if constraints have
|
||||
* been placed on the key.
|
||||
*/
|
||||
@Override
|
||||
public final boolean permits(Set<CryptoPrimitive> primitives,
|
||||
String algorithm, Key key, AlgorithmParameters parameters) {
|
||||
@ -107,7 +116,39 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
|
||||
return checkConstraints(primitives, algorithm, key, parameters);
|
||||
}
|
||||
|
||||
// Check algorithm constraints
|
||||
/*
|
||||
* Check if a x509Certificate object is permitted. Check if all
|
||||
* algorithms are allowed, certificate constraints, and the
|
||||
* public key against key constraints.
|
||||
*
|
||||
* Uses new style permit() which throws exceptions.
|
||||
*/
|
||||
public final void permits(Set<CryptoPrimitive> primitives,
|
||||
CertConstraintParameters cp) throws CertPathValidatorException {
|
||||
checkConstraints(primitives, cp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if Certificate object is within the constraints.
|
||||
* Uses new style permit() which throws exceptions.
|
||||
*/
|
||||
public final void permits(Set<CryptoPrimitive> primitives,
|
||||
X509Certificate cert) throws CertPathValidatorException {
|
||||
checkConstraints(primitives, new CertConstraintParameters(cert));
|
||||
}
|
||||
|
||||
// Check if a string is contained inside the property
|
||||
public boolean checkProperty(String param) {
|
||||
param = param.toLowerCase(Locale.ENGLISH);
|
||||
for (String block : disabledAlgorithms) {
|
||||
if (block.toLowerCase(Locale.ENGLISH).indexOf(param) >= 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check algorithm constraints with key and algorithm
|
||||
private boolean checkConstraints(Set<CryptoPrimitive> primitives,
|
||||
String algorithm, Key key, AlgorithmParameters parameters) {
|
||||
|
||||
@ -116,7 +157,7 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
|
||||
throw new IllegalArgumentException("The key cannot be null");
|
||||
}
|
||||
|
||||
// check the target algorithm
|
||||
// check the signature algorithm
|
||||
if (algorithm != null && algorithm.length() != 0) {
|
||||
if (!permits(primitives, algorithm, parameters)) {
|
||||
return false;
|
||||
@ -129,97 +170,203 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
|
||||
}
|
||||
|
||||
// check the key constraints
|
||||
if (keySizeConstraints.disables(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return algorithmConstraints.permits(key);
|
||||
}
|
||||
|
||||
private static KeySizeConstraints getKeySizeConstraints(
|
||||
String[] disabledAlgorithms, String propertyName) {
|
||||
synchronized (keySizeConstraintsMap) {
|
||||
if(!keySizeConstraintsMap.containsKey(propertyName)) {
|
||||
// map the key constraints
|
||||
KeySizeConstraints keySizeConstraints =
|
||||
new KeySizeConstraints(disabledAlgorithms);
|
||||
keySizeConstraintsMap.put(propertyName, keySizeConstraints);
|
||||
}
|
||||
/*
|
||||
* Check algorithm constraints with Certificate
|
||||
* Uses new style permit() which throws exceptions.
|
||||
*/
|
||||
private void checkConstraints(Set<CryptoPrimitive> primitives,
|
||||
CertConstraintParameters cp) throws CertPathValidatorException {
|
||||
|
||||
return keySizeConstraintsMap.get(propertyName);
|
||||
X509Certificate cert = cp.getCertificate();
|
||||
String algorithm = cert.getSigAlgName();
|
||||
|
||||
// Check signature algorithm is not disabled
|
||||
if (!permits(primitives, algorithm, null)) {
|
||||
throw new CertPathValidatorException(
|
||||
"Algorithm constraints check failed on disabled "+
|
||||
"signature algorithm: " + algorithm,
|
||||
null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
|
||||
}
|
||||
|
||||
// Check key algorithm is not disabled
|
||||
if (!permits(primitives, cert.getPublicKey().getAlgorithm(), null)) {
|
||||
throw new CertPathValidatorException(
|
||||
"Algorithm constraints check failed on disabled "+
|
||||
"public key algorithm: " + algorithm,
|
||||
null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
|
||||
}
|
||||
|
||||
// Check the certificate and key constraints
|
||||
algorithmConstraints.permits(cp);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* key constraints
|
||||
* Key and Certificate Constraints
|
||||
*
|
||||
* The complete disabling of an algorithm is not handled by Constraints or
|
||||
* Constraint classes. That is addressed with
|
||||
* permit(Set<CryptoPrimitive>, String, AlgorithmParameters)
|
||||
*
|
||||
* When passing a Key to permit(), the boolean return values follow the
|
||||
* same as the interface class AlgorithmConstraints.permit(). This is to
|
||||
* maintain compatibility:
|
||||
* 'true' means the operation is allowed.
|
||||
* 'false' means it failed the constraints and is disallowed.
|
||||
*
|
||||
* When passing CertConstraintParameters through permit(), an exception
|
||||
* will be thrown on a failure to better identify why the operation was
|
||||
* disallowed.
|
||||
*/
|
||||
private static class KeySizeConstraints {
|
||||
private static final Pattern pattern = Pattern.compile(
|
||||
"(\\S+)\\s+keySize\\s*(<=|<|==|!=|>|>=)\\s*(\\d+)");
|
||||
|
||||
private Map<String, Set<KeySizeConstraint>> constraintsMap =
|
||||
Collections.synchronizedMap(
|
||||
new HashMap<String, Set<KeySizeConstraint>>());
|
||||
private static class Constraints {
|
||||
private Map<String, Set<Constraint>> constraintsMap = new HashMap<>();
|
||||
private static final Pattern keySizePattern = Pattern.compile(
|
||||
"keySize\\s*(<=|<|==|!=|>|>=)\\s*(\\d+)");
|
||||
|
||||
public KeySizeConstraints(String[] restrictions) {
|
||||
for (String restriction : restrictions) {
|
||||
if (restriction == null || restriction.isEmpty()) {
|
||||
public Constraints(String[] constraintArray) {
|
||||
for (String constraintEntry : constraintArray) {
|
||||
if (constraintEntry == null || constraintEntry.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Matcher matcher = pattern.matcher(restriction);
|
||||
if (matcher.matches()) {
|
||||
String algorithm = matcher.group(1);
|
||||
constraintEntry = constraintEntry.trim();
|
||||
if (debug != null) {
|
||||
debug.println("Constraints: " + constraintEntry);
|
||||
}
|
||||
|
||||
KeySizeConstraint.Operator operator =
|
||||
KeySizeConstraint.Operator.of(matcher.group(2));
|
||||
int length = Integer.parseInt(matcher.group(3));
|
||||
// Check if constraint is a complete disabling of an
|
||||
// algorithm or has conditions.
|
||||
String algorithm;
|
||||
String policy;
|
||||
int space = constraintEntry.indexOf(' ');
|
||||
if (space > 0) {
|
||||
algorithm = AlgorithmDecomposer.hashName(
|
||||
constraintEntry.substring(0, space).
|
||||
toUpperCase(Locale.ENGLISH));
|
||||
policy = constraintEntry.substring(space + 1);
|
||||
} else {
|
||||
constraintsMap.computeIfAbsent(
|
||||
constraintEntry.toUpperCase(Locale.ENGLISH),
|
||||
k -> new HashSet<>());
|
||||
continue;
|
||||
}
|
||||
|
||||
algorithm = algorithm.toLowerCase(Locale.ENGLISH);
|
||||
// Convert constraint conditions into Constraint classes
|
||||
Constraint c, lastConstraint = null;
|
||||
// Allow only one jdkCA entry per constraint entry
|
||||
boolean jdkCALimit = false;
|
||||
|
||||
synchronized (constraintsMap) {
|
||||
if (!constraintsMap.containsKey(algorithm)) {
|
||||
constraintsMap.put(algorithm,
|
||||
new HashSet<KeySizeConstraint>());
|
||||
for (String entry : policy.split("&")) {
|
||||
entry = entry.trim();
|
||||
|
||||
Matcher matcher = keySizePattern.matcher(entry);
|
||||
if (matcher.matches()) {
|
||||
if (debug != null) {
|
||||
debug.println("Constraints set to keySize: " +
|
||||
entry);
|
||||
}
|
||||
c = new KeySizeConstraint(algorithm,
|
||||
KeySizeConstraint.Operator.of(matcher.group(1)),
|
||||
Integer.parseInt(matcher.group(2)));
|
||||
|
||||
Set<KeySizeConstraint> constraintSet =
|
||||
constraintsMap.get(algorithm);
|
||||
KeySizeConstraint constraint =
|
||||
new KeySizeConstraint(operator, length);
|
||||
constraintSet.add(constraint);
|
||||
} else if (entry.equalsIgnoreCase("jdkCA")) {
|
||||
if (debug != null) {
|
||||
debug.println("Constraints set to jdkCA.");
|
||||
}
|
||||
if (jdkCALimit) {
|
||||
throw new IllegalArgumentException("Only one " +
|
||||
"jdkCA entry allowed in property. " +
|
||||
"Constraint: " + constraintEntry);
|
||||
}
|
||||
c = new jdkCAConstraint(algorithm);
|
||||
jdkCALimit = true;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Error in security" +
|
||||
" property. Constraint unknown: " + entry);
|
||||
}
|
||||
|
||||
// Link multiple conditions for a single constraint
|
||||
// into a linked list.
|
||||
if (lastConstraint == null) {
|
||||
if (!constraintsMap.containsKey(algorithm)) {
|
||||
constraintsMap.putIfAbsent(algorithm,
|
||||
new HashSet<>());
|
||||
}
|
||||
constraintsMap.get(algorithm).add(c);
|
||||
} else {
|
||||
lastConstraint.nextConstraint = c;
|
||||
}
|
||||
lastConstraint = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Does this KeySizeConstraints disable the specified key?
|
||||
public boolean disables(Key key) {
|
||||
String algorithm = key.getAlgorithm().toLowerCase(Locale.ENGLISH);
|
||||
synchronized (constraintsMap) {
|
||||
if (constraintsMap.containsKey(algorithm)) {
|
||||
Set<KeySizeConstraint> constraintSet =
|
||||
constraintsMap.get(algorithm);
|
||||
for (KeySizeConstraint constraint : constraintSet) {
|
||||
if (constraint.disables(key)) {
|
||||
return true;
|
||||
}
|
||||
// Get applicable constraints based off the signature algorithm
|
||||
private Set<Constraint> getConstraints(String algorithm) {
|
||||
return constraintsMap.get(algorithm);
|
||||
}
|
||||
|
||||
// Check if KeySizeConstraints permit the specified key
|
||||
public boolean permits(Key key) {
|
||||
Set<Constraint> set = getConstraints(key.getAlgorithm());
|
||||
if (set == null) {
|
||||
return true;
|
||||
}
|
||||
for (Constraint constraint : set) {
|
||||
if (!constraint.permits(key)) {
|
||||
if (debug != null) {
|
||||
debug.println("keySizeConstraint: failed key " +
|
||||
"constraint check " + KeyUtil.getKeySize(key));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
// Check if constraints permit this cert.
|
||||
public void permits(CertConstraintParameters cp)
|
||||
throws CertPathValidatorException {
|
||||
X509Certificate cert = cp.getCertificate();
|
||||
|
||||
if (debug != null) {
|
||||
debug.println("Constraints.permits(): " + cert.getSigAlgName());
|
||||
}
|
||||
|
||||
// Get all signature algorithms to check for constraints
|
||||
Set<String> algorithms =
|
||||
AlgorithmDecomposer.decomposeOneHash(cert.getSigAlgName());
|
||||
if (algorithms == null || algorithms.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Attempt to add the public key algorithm to the set
|
||||
algorithms.add(cert.getPublicKey().getAlgorithm());
|
||||
|
||||
// Check all applicable constraints
|
||||
for (String algorithm : algorithms) {
|
||||
Set<Constraint> set = getConstraints(algorithm);
|
||||
if (set == null) {
|
||||
continue;
|
||||
}
|
||||
for (Constraint constraint : set) {
|
||||
constraint.permits(cp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Key size constraint.
|
||||
*
|
||||
* e.g. "keysize <= 1024"
|
||||
*/
|
||||
private static class KeySizeConstraint {
|
||||
// Abstract class for algorithm constraint checking
|
||||
private abstract static class Constraint {
|
||||
String algorithm;
|
||||
Constraint nextConstraint = null;
|
||||
|
||||
// operator
|
||||
static enum Operator {
|
||||
enum Operator {
|
||||
EQ, // "=="
|
||||
NE, // "!="
|
||||
LT, // "<"
|
||||
@ -243,16 +390,77 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
|
||||
return GE;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(
|
||||
s + " is not a legal Operator");
|
||||
throw new IllegalArgumentException("Error in security " +
|
||||
"property. " + s + " is not a legal Operator");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an algorithm constraint permit this key to be used.
|
||||
* @param key Public key
|
||||
* @return true if constraints do not match
|
||||
*/
|
||||
public boolean permits(Key key) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an algorithm constraint is permit this certificate to
|
||||
* be used.
|
||||
* @param cp CertificateParameter containing certificate and state info
|
||||
* @return true if constraints do not match
|
||||
*/
|
||||
public abstract void permits(CertConstraintParameters cp)
|
||||
throws CertPathValidatorException;
|
||||
}
|
||||
|
||||
/*
|
||||
* This class contains constraints dealing with the certificate chain
|
||||
* of the certificate.
|
||||
*/
|
||||
private static class jdkCAConstraint extends Constraint {
|
||||
jdkCAConstraint(String algo) {
|
||||
algorithm = algo;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if each constraint fails and check if there is a linked
|
||||
* constraint Any permitted constraint will exit the linked list
|
||||
* to allow the operation.
|
||||
*/
|
||||
public void permits(CertConstraintParameters cp)
|
||||
throws CertPathValidatorException {
|
||||
if (debug != null) {
|
||||
debug.println("jdkCAConstraints.permits(): " + algorithm);
|
||||
}
|
||||
|
||||
// Return false if the chain has a trust anchor in cacerts
|
||||
if (cp.isTrustedMatch()) {
|
||||
if (nextConstraint != null) {
|
||||
nextConstraint.permits(cp);
|
||||
return;
|
||||
}
|
||||
throw new CertPathValidatorException(
|
||||
"Algorithm constraints check failed on certificate " +
|
||||
"anchor limits",
|
||||
null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This class contains constraints dealing with the key size
|
||||
* support limits per algorithm. e.g. "keySize <= 1024"
|
||||
*/
|
||||
private static class KeySizeConstraint extends Constraint {
|
||||
|
||||
private int minSize; // the minimal available key size
|
||||
private int maxSize; // the maximal available key size
|
||||
private int prohibitedSize = -1; // unavailable key sizes
|
||||
|
||||
public KeySizeConstraint(Operator operator, int length) {
|
||||
public KeySizeConstraint(String algo, Operator operator, int length) {
|
||||
algorithm = algo;
|
||||
switch (operator) {
|
||||
case EQ: // an unavailable key size
|
||||
this.minSize = 0;
|
||||
@ -286,21 +494,59 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
|
||||
}
|
||||
}
|
||||
|
||||
// Does this key constraint disable the specified key?
|
||||
public boolean disables(Key key) {
|
||||
int size = KeyUtil.getKeySize(key);
|
||||
/*
|
||||
* If we are passed a certificate, extract the public key and use it.
|
||||
*
|
||||
* Check if each constraint fails and check if there is a linked
|
||||
* constraint Any permitted constraint will exit the linked list
|
||||
* to allow the operation.
|
||||
*/
|
||||
public void permits(CertConstraintParameters cp)
|
||||
throws CertPathValidatorException {
|
||||
if (!permitsImpl(cp.getCertificate().getPublicKey())) {
|
||||
if (nextConstraint != null) {
|
||||
nextConstraint.permits(cp);
|
||||
return;
|
||||
}
|
||||
throw new CertPathValidatorException(
|
||||
"Algorithm constraints check failed on keysize limits",
|
||||
null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check if key constraint disable the specified key
|
||||
// Uses old style permit()
|
||||
public boolean permits(Key key) {
|
||||
// If we recursively find a constraint that permits us to use
|
||||
// this key, return true and skip any other constraint checks.
|
||||
if (nextConstraint != null && nextConstraint.permits(key)) {
|
||||
return true;
|
||||
}
|
||||
if (debug != null) {
|
||||
debug.println("KeySizeConstraints.permits(): " + algorithm);
|
||||
}
|
||||
|
||||
return permitsImpl(key);
|
||||
}
|
||||
|
||||
private boolean permitsImpl(Key key) {
|
||||
// Verify this constraint is for this public key algorithm
|
||||
if (algorithm.compareToIgnoreCase(key.getAlgorithm()) != 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int size = KeyUtil.getKeySize(key);
|
||||
if (size == 0) {
|
||||
return true; // we don't allow any key of size 0.
|
||||
return false; // we don't allow any key of size 0.
|
||||
} else if (size > 0) {
|
||||
return ((size < minSize) || (size > maxSize) ||
|
||||
return !((size < minSize) || (size > maxSize) ||
|
||||
(prohibitedSize == size));
|
||||
} // Otherwise, the key size is not accessible. Conservatively,
|
||||
// please don't disable such keys.
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -28,8 +28,6 @@ package sun.security.util;
|
||||
import java.security.AlgorithmParameters;
|
||||
import java.security.CryptoPrimitive;
|
||||
import java.security.Key;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import static sun.security.util.AbstractAlgorithmConstraints.getAlgorithms;
|
||||
|
||||
@ -42,15 +40,12 @@ public class LegacyAlgorithmConstraints extends AbstractAlgorithmConstraints {
|
||||
public static final String PROPERTY_TLS_LEGACY_ALGS =
|
||||
"jdk.tls.legacyAlgorithms";
|
||||
|
||||
private static final Map<String, String[]> legacyAlgorithmsMap =
|
||||
new HashMap<>();
|
||||
|
||||
private final String[] legacyAlgorithms;
|
||||
|
||||
public LegacyAlgorithmConstraints(String propertyName,
|
||||
AlgorithmDecomposer decomposer) {
|
||||
super(decomposer);
|
||||
legacyAlgorithms = getAlgorithms(legacyAlgorithmsMap, propertyName);
|
||||
legacyAlgorithms = getAlgorithms(propertyName);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -1924,17 +1924,18 @@ public class X509CertImpl extends X509Certificate implements DerEncoder {
|
||||
|
||||
public String getFingerprint(String algorithm) {
|
||||
return fingerprints.computeIfAbsent(algorithm,
|
||||
x -> getCertificateFingerPrint(x));
|
||||
x -> getFingerprint(x, this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the requested finger print of the certificate. The result
|
||||
* only contains 0-9 and A-F. No small case, no colon.
|
||||
*/
|
||||
private String getCertificateFingerPrint(String mdAlg) {
|
||||
public static String getFingerprint(String algorithm,
|
||||
X509Certificate cert) {
|
||||
try {
|
||||
byte[] encCertInfo = getEncoded();
|
||||
MessageDigest md = MessageDigest.getInstance(mdAlg);
|
||||
byte[] encCertInfo = cert.getEncoded();
|
||||
MessageDigest md = MessageDigest.getInstance(algorithm);
|
||||
byte[] digest = md.digest(encCertInfo);
|
||||
StringBuilder sb = new StringBuilder(digest.length * 2);
|
||||
for (int i = 0; i < digest.length; i++) {
|
||||
|
@ -497,13 +497,13 @@ krb5.kdc.bad.policy = tryLast
|
||||
# " DisabledAlgorithm { , DisabledAlgorithm } "
|
||||
#
|
||||
# DisabledAlgorithm:
|
||||
# AlgorithmName [Constraint]
|
||||
# AlgorithmName [Constraint] { '&' Constraint }
|
||||
#
|
||||
# AlgorithmName:
|
||||
# (see below)
|
||||
#
|
||||
# Constraint:
|
||||
# KeySizeConstraint
|
||||
# KeySizeConstraint, CertConstraint
|
||||
#
|
||||
# KeySizeConstraint:
|
||||
# keySize Operator DecimalInteger
|
||||
@ -520,6 +520,9 @@ krb5.kdc.bad.policy = tryLast
|
||||
# DecimalDigit: one of
|
||||
# 1 2 3 4 5 6 7 8 9 0
|
||||
#
|
||||
# CertConstraint
|
||||
# jdkCA
|
||||
#
|
||||
# The "AlgorithmName" is the standard algorithm name of the disabled
|
||||
# algorithm. See "Java Cryptography Architecture Standard Algorithm Name
|
||||
# Documentation" for information about Standard Algorithm Names. Matching
|
||||
@ -542,6 +545,29 @@ krb5.kdc.bad.policy = tryLast
|
||||
# be disabled. Note that the "KeySizeConstraint" only makes sense to key
|
||||
# algorithms.
|
||||
#
|
||||
# "CertConstraint" specifies additional constraints for
|
||||
# certificates that contain algorithms that are restricted:
|
||||
#
|
||||
# "jdkCA" prohibits the specified algorithm only if the algorithm is used
|
||||
# in a certificate chain that terminates at a marked trust anchor in the
|
||||
# lib/security/cacerts keystore. All other chains are not affected.
|
||||
# If the jdkCA constraint is not set, then all chains using the
|
||||
# specified algorithm are restricted. jdkCA may only be used once in
|
||||
# a DisabledAlgorithm expression.
|
||||
# Example: To apply this constraint to SHA-1 certificates, include
|
||||
# the following: "SHA1 jdkCA"
|
||||
#
|
||||
# When an algorithm must satisfy more than one constraint, it must be
|
||||
# delimited by an ampersand '&'. For example, to restrict certificates in a
|
||||
# chain that terminate at a distribution provided trust anchor and contain
|
||||
# RSA keys that are less than or equal to 1024 bits, add the following
|
||||
# constraint: "RSA keySize <= 1024 & jdkCA".
|
||||
#
|
||||
# All DisabledAlgorithms expressions are processed in the order defined in the
|
||||
# property. This requires lower keysize constraints to be specified
|
||||
# before larger keysize constraints of the same algorithm. For example:
|
||||
# "RSA keySize < 1024 & jdkCA, RSA keySize < 2048".
|
||||
#
|
||||
# Note: This property is currently used by Oracle's PKIX implementation. It
|
||||
# is not guaranteed to be examined and used by other implementations.
|
||||
#
|
||||
|
@ -89,7 +89,7 @@ public class Warning {
|
||||
issueCert("c");
|
||||
run("jarsigner", "a.jar c")
|
||||
.shouldContain("chain is not validated. " +
|
||||
"Reason: algorithm constraints check failed");
|
||||
"Reason: Algorithm constraints check failed");
|
||||
|
||||
recreateJar();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user