Skip to content
Permalink
Browse files

8230318: Better trust store usage

Reviewed-by: weijun, rhalade, ahgross
  • Loading branch information
Sean Mullan committed Oct 22, 2019
1 parent 10b1e75 commit a0f8febb8b9adc1c720ce0764a1c7f9d5e68540a
@@ -32,6 +32,7 @@

import javax.security.auth.x500.X500Principal;
import sun.security.action.GetBooleanAction;
import sun.security.action.GetPropertyAction;
import sun.security.provider.certpath.AlgorithmChecker;
import sun.security.provider.certpath.PKIXExtendedParameters;

@@ -60,6 +61,18 @@
private static final boolean checkTLSRevocation = GetBooleanAction
.privilegedGetProperty("com.sun.net.ssl.checkRevocation");

/**
* System property that if set (or set to "true"), allows trust anchor
* certificates to be used if they do not have the proper CA extensions.
* Set to false if prop is not set, or set to any other value.
*/
private static final boolean ALLOW_NON_CA_ANCHOR = allowNonCaAnchor();
private static boolean allowNonCaAnchor() {
String prop = GetPropertyAction
.privilegedGetProperty("jdk.security.allowNonCaAnchor");
return prop != null && (prop.isEmpty() || prop.equalsIgnoreCase("true"));
}

private final Set<X509Certificate> trustedCerts;
private final PKIXBuilderParameters parameterTemplate;
private int certPathLength = -1;
@@ -311,15 +324,18 @@ private boolean isSignatureValid(List<PublicKey> keys,

private static X509Certificate[] toArray(CertPath path, TrustAnchor anchor)
throws CertificateException {
List<? extends java.security.cert.Certificate> list =
path.getCertificates();
X509Certificate[] chain = new X509Certificate[list.size() + 1];
list.toArray(chain);
X509Certificate trustedCert = anchor.getTrustedCert();
if (trustedCert == null) {
throw new ValidatorException
("TrustAnchor must be specified as certificate");
}

verifyTrustAnchor(trustedCert);

List<? extends java.security.cert.Certificate> list =
path.getCertificates();
X509Certificate[] chain = new X509Certificate[list.size() + 1];
list.toArray(chain);
chain[chain.length - 1] = trustedCert;
return chain;
}
@@ -354,6 +370,41 @@ private void setDate(PKIXBuilderParameters params) {
}
}

/**
* Verify that a trust anchor certificate is a CA certificate.
*/
private static void verifyTrustAnchor(X509Certificate trustedCert)
throws ValidatorException {

// skip check if jdk.security.allowNonCAAnchor system property is set
if (ALLOW_NON_CA_ANCHOR) {
return;
}

// allow v1 trust anchor certificates
if (trustedCert.getVersion() < 3) {
return;
}

// check that the BasicConstraints cA field is not set to false
if (trustedCert.getBasicConstraints() == -1) {
throw new ValidatorException
("TrustAnchor with subject \"" +
trustedCert.getSubjectX500Principal() +
"\" is not a CA certificate");
}

// check that the KeyUsage extension, if included, asserts the
// keyCertSign bit
boolean[] keyUsageBits = trustedCert.getKeyUsage();
if (keyUsageBits != null && !keyUsageBits[5]) {
throw new ValidatorException
("TrustAnchor with subject \"" +
trustedCert.getSubjectX500Principal() +
"\" does not have keyCertSign bit set in KeyUsage extension");
}
}

private X509Certificate[] doBuild(X509Certificate[] chain,
Collection<X509Certificate> otherCerts,
PKIXBuilderParameters params) throws CertificateException {
@@ -244,8 +244,8 @@ public static void main(String[] args) throws Exception {
// ==========================================================

kt("-genkeypair -alias ee -dname CN=ee");
kt("-genkeypair -alias caone -dname CN=caone");
kt("-genkeypair -alias catwo -dname CN=catwo");
kt("-genkeypair -alias caone -dname CN=caone -ext bc:c");
kt("-genkeypair -alias catwo -dname CN=catwo -ext bc:c");

kt("-certreq -alias ee -file ee.req");
kt("-certreq -alias catwo -file catwo.req");
@@ -59,7 +59,7 @@ static OutputAnalyzer keytool(String cmd) throws Throwable {
public static void main(String[] args) throws Throwable {
keytool("-genkeypair -dname CN=A -alias a -keyalg rsa")
.shouldHaveExitValue(0);
keytool("-genkeypair -dname CN=CA -alias ca -keyalg rsa")
keytool("-genkeypair -dname CN=CA -alias ca -keyalg rsa -ext bc:c")
.shouldHaveExitValue(0);
keytool("-alias a -certreq -file a.req");
keytool("-alias ca -gencert -infile a.req -outfile a.cert");
@@ -59,7 +59,7 @@ public static void main(String[] args) throws Exception {
Files.write(Path.of("A"), List.of("A"));
JarUtils.createJarFile(Path.of("a.jar"), Path.of("."), Path.of("A"));

kt("-alias ca -dname CN=ca -keyalg ec -genkey -validity 300")
kt("-alias ca -dname CN=ca -keyalg ec -genkey -validity 300 -ext bc:c")
.shouldHaveExitValue(0);
kt("-alias a -dname CN=a -keyalg ec -genkey")
.shouldHaveExitValue(0);
@@ -90,7 +90,7 @@ public void testAliasCaseStoreHash() throws Exception {
+ " test-alias-storeHash-case.jks -storepass changeit";
SecurityTools.keytool(KEYSTORE_OPTIONS + " -genkeypair -keyalg DSA"
+ " -keypass changeit -alias " + ALIAS + "1 -dname CN=" +
ALIAS + "1").shouldHaveExitValue(0);
ALIAS + "1" + " -ext bc:c").shouldHaveExitValue(0);
SecurityTools.keytool(KEYSTORE_OPTIONS + " -genkeypair -keyalg DSA"
+ " -keypass changeit -alias " + ALIAS + "2 -dname CN="
+ ALIAS + "2").shouldHaveExitValue(0);
@@ -52,7 +52,7 @@ public static void main(String[] args) throws Exception {
Files.write(Path.of("manifest"), List.of("Key: Value"));
SecurityTools.jar("cvfm a.jar manifest");

kt("-alias ca -dname CN=ca -genkey -validity 300")
kt("-alias ca -dname CN=ca -genkey -validity 300 -ext bc:c")
.shouldHaveExitValue(0);
kt("-alias a -dname CN=a -genkey -validity 300")
.shouldHaveExitValue(0);
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2019, 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
@@ -74,6 +74,7 @@ void start() throws Throwable {
"-storepass", PASSWORD,
"-keypass", PASSWORD,
"-dname", "CN=CA",
"-ext", "bc:c",
"-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0);
keytool(
"-genkey",
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2019, 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
@@ -44,7 +44,7 @@ public static void main(String[] args) throws Throwable {

Files.deleteIfExists(Paths.get("ks"));

newCert("ca", "-validity 365000");
newCert("ca", "-validity 365000", "-ext bc:c");

recreateJar();

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2019, 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
@@ -53,7 +53,7 @@ private void start() throws Throwable {
// create a certificate whose signer certificate's
// ExtendedKeyUsage extension doesn't allow code signing
// create key pair for jar signing
createAlias(CA_KEY_ALIAS);
createAlias(CA_KEY_ALIAS, "-ext", "bc:c");
createAlias(KEY_ALIAS);

issueCert(
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2019, 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
@@ -54,7 +54,7 @@ private void start() throws Throwable {
// create a certificate whose signer certificate's
// NetscapeCertType extension doesn't allow code signing
// create key pair for jar signing
createAlias(CA_KEY_ALIAS);
createAlias(CA_KEY_ALIAS, "-ext", "bc:c");
createAlias(KEY_ALIAS);

issueCert(
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2019, 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
@@ -54,7 +54,7 @@ private void start(boolean ca2yes) throws Throwable {
// Root CA is not checked at all. If the intermediate CA has
// BasicConstraints extension set to true, it will be valid.
// Otherwise, chain validation will fail.
createAlias(CA_KEY_ALIAS);
createAlias(CA_KEY_ALIAS, "-ext", "bc:c");
createAlias(CA2_KEY_ALIAS);
issueCert(CA2_KEY_ALIAS,
"-ext",
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2019, 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
@@ -52,7 +52,7 @@ private void start() throws Throwable {
JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE);

// create key pair for jar signing
createAlias(CA_KEY_ALIAS);
createAlias(CA_KEY_ALIAS, "-ext", "bc:c");
createAlias(KEY_ALIAS);

issueCert(
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2019, 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 @@ private void start() throws Throwable {
JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE);

// create key pair for signing
createAlias(CA_KEY_ALIAS);
createAlias(CA_KEY_ALIAS, "-ext", "bc:c");
createAlias(KEY_ALIAS);
issueCert(
KEY_ALIAS,
@@ -72,7 +72,7 @@ private void start() throws Throwable {
JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE);

// create key pair
createAlias(CA_KEY_ALIAS);
createAlias(CA_KEY_ALIAS, "-ext", "bc:c");
createAlias(KEY_ALIAS);
issueCert(KEY_ALIAS,
"-validity", Integer.toString(VALIDITY));
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2019, 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
@@ -49,7 +49,7 @@ protected void start() throws Throwable {
Utils.createFiles(FIRST_FILE);
JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE);

createAlias(CA_KEY_ALIAS);
createAlias(CA_KEY_ALIAS, "-ext", "bc:c");

// create first key pair for signing
createAlias(FIRST_KEY_ALIAS);
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2019, 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 @@
* @summary EndEntityChecker should not process custom extensions
* after PKIX validation
* @modules java.base/sun.security.validator
* @run main/othervm -Djdk.security.allowNonCaAnchor EndEntityExtensionCheck
*/

import java.io.ByteArrayInputStream;

0 comments on commit a0f8feb

Please sign in to comment.