Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,22 @@ void checkDistrust(String variant, X509Certificate[] chain)
}
CamerfirmaTLSPolicy.checkDistrust(chain);
}
},

/**
* Distrust TLS Server certificates anchored by a Chunghwa ePKI root CA and
* issued after March 17, 2026. If enabled, this policy is currently
* enforced by the PKIX and SunX509 TrustManager implementations
* of the SunJSSE provider implementation.
*/
CHUNGHWA_TLS {
void checkDistrust(String variant, X509Certificate[] chain)
throws ValidatorException {
if (!variant.equals(Validator.VAR_TLS_SERVER)) {
return;
}
ChunghwaTLSPolicy.checkDistrust(chain);
}
};

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* Copyright (c) 2025, 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.validator;

import java.security.cert.X509Certificate;
import java.time.LocalDate;
import java.time.Month;
import java.time.ZoneOffset;
import java.util.Date;
import java.util.Map;
import java.util.Set;

import sun.security.util.Debug;
import sun.security.x509.X509CertImpl;

/**
* This class checks if Chunghwa issued TLS Server certificates should be
* restricted.
*/
final class ChunghwaTLSPolicy {

private static final Debug debug = Debug.getInstance("certpath");

// SHA-256 certificate fingerprints of distrusted root for TLS
// cacerts alias: chunghwaepkirootca
// DN: OU=ePKI Root Certification Authority,
// O="Chunghwa Telecom Co., Ltd.", C=TW
private static final String FINGERPRINT =
"C0A6F4DC63A24BFDCF54EF2A6A082A0A72DE35803E2FF5FF527AE5D87206DFD5";

// Any TLS Server certificate that is anchored by one of the Chunghwa
// roots above and is issued after this date will be distrusted.
private static final LocalDate MARCH_17_2026 =
LocalDate.of(2026, Month.MARCH, 17);

/**
* This method assumes the eeCert is a TLS Server Cert and chains back to
* the anchor.
*
* @param chain the end-entity's certificate chain. The end entity cert
* is at index 0, the trust anchor at index n-1.
* @throws ValidatorException if the certificate is distrusted
*/
static void checkDistrust(X509Certificate[] chain)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: checkDistrust is an odd name for a method throwing an error and not returning anything in my opinion. But since it's used in other files and behaves the same I think it's fine.

throws ValidatorException {
X509Certificate anchor = chain[chain.length-1];
String fp = fingerprint(anchor);
if (fp == null) {
throw new ValidatorException("Cannot generate fingerprint for "
+ "trust anchor of TLS server certificate");
}
if (FINGERPRINT.equalsIgnoreCase(fp)) {
Date notBefore = chain[0].getNotBefore();
LocalDate ldNotBefore = LocalDate.ofInstant(notBefore.toInstant(),
ZoneOffset.UTC);
// reject if certificate is issued after March 17, 2026
checkNotBefore(ldNotBefore, MARCH_17_2026, anchor);
}
}

private static String fingerprint(X509Certificate cert) {
return X509CertImpl.getFingerprint("SHA-256", cert, debug);
}

// Check whether the certificate's notBeforeDate is after the
// distrust date for the anchor (root CA). Throw ValidatorException
// if it is after the distrust date.
private static void checkNotBefore(LocalDate notBeforeDate,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might be wrong, but wouldn't 'Not Before' mean that it would also include the date ('Equals or After'). I think renaming it to checkIsAfter would be better, what do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. However, notBefore was probably chosen because it is also a field in the X509Certificate. The name appears in many places. What about adding a comment:
Check whether the certificate's notBeforeDate is after the distrust date for the anchor (root CA).
Throw ValidatorException if it is after the distrust date.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be fine with me and I think would be helpful. Thank you!

LocalDate distrustDate, X509Certificate anchor)
throws ValidatorException {
if (notBeforeDate.isAfter(distrustDate)) {
throw new ValidatorException
("TLS Server certificate issued after " + distrustDate +
" and anchored by a distrusted legacy Chunghwa root CA: "
+ anchor.getSubjectX500Principal(),
ValidatorException.T_UNTRUSTED_CERT, anchor);
}
}

private ChunghwaTLSPolicy() {}
}
6 changes: 5 additions & 1 deletion src/java.base/share/conf/security/java.security
Original file line number Diff line number Diff line change
Expand Up @@ -1437,6 +1437,9 @@ jdk.sasl.disabledMechanisms=
# CAMERFIRMA_TLS : Distrust TLS Server certificates anchored by
# a Camerfirma root CA and issued after April 15, 2025.
#
# CHUNGHWA_TLS : Distrust TLS Server certificates anchored by
# a Chunghwa root CA and issued after March 17, 2026.
#
# Leading and trailing whitespace surrounding each value are ignored.
# Unknown values are ignored. If the property is commented out or set to the
# empty String, no policies are enforced.
Expand All @@ -1448,7 +1451,8 @@ jdk.sasl.disabledMechanisms=
# jdk.certpath.disabledAlgorithms; those restrictions are still enforced even
# if this property is not enabled.
#
jdk.security.caDistrustPolicies=SYMANTEC_TLS,ENTRUST_TLS,CAMERFIRMA_TLS
jdk.security.caDistrustPolicies=SYMANTEC_TLS,ENTRUST_TLS,CAMERFIRMA_TLS,\
CHUNGHWA_TLS

#
# FilePermission path canonicalization
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

import javax.net.ssl.X509TrustManager;
import java.io.File;
import java.security.Security;
import java.time.LocalDate;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Date;

/*
* @test
* @bug 8369282
* @summary Check that TLS Server certificates chaining back to distrusted
* Chunghwa root are invalid
* @library /test/lib
* @modules java.base/sun.security.validator
* @run main/othervm Chunghwa after policyOn invalid
* @run main/othervm Chunghwa after policyOff valid
* @run main/othervm Chunghwa before policyOn valid
* @run main/othervm Chunghwa before policyOff valid
*/

public class Chunghwa {

private static final String CERT_PATH = "chains" + File.separator + "chunghwa";

// Each of the roots have a test certificate chain stored in a file
// named "<root>-chain.pem".
private static final String ROOT_TO_TEST = "chunghwaepkirootca";

// Date after the restrictions take effect
private static final ZonedDateTime DISTRUST_DATE =
LocalDate.of(2026, 03, 18).atStartOfDay(ZoneOffset.UTC);

public static void main(String[] args) throws Exception {

// All the test certificates are signed with SHA-1, so we need
// to remove the constraint that disallows SHA-1 certificates.
String prop = Security.getProperty("jdk.certpath.disabledAlgorithms");
String newProp = prop.replace(", SHA1 jdkCA & usage TLSServer", "");
Security.setProperty("jdk.certpath.disabledAlgorithms", newProp);

Distrust distrust = new Distrust(args);

X509TrustManager[] tms = new X509TrustManager[]{
distrust.getTMF("PKIX", null),
distrust.getTMF("SunX509", null)
};

Date notBefore = distrust.getNotBefore(DISTRUST_DATE);
distrust.testCertificateChain(CERT_PATH, notBefore, tms, ROOT_TO_TEST);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
-----BEGIN CERTIFICATE-----
MIIGjDCCBHSgAwIBAgIQI/umSDYOFekrp4rttnoK5TANBgkqhkiG9w0BAQsFADBe
MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0
ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe
Fw0yMzEyMjEwMjExMjNaFw0zNDEyMTkxNTU5NTlaME8xCzAJBgNVBAYTAlRXMSMw
IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEbMBkGA1UEAwwSSGlQ
S0kgUm9vdCBDQSAtIEcxMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA
9B5/UnMyDHPkvRN0o9QwqNCuS9i233VHZvR85zkEHmpwINJaR3JnVfSl6J3VHiGh
8Ge6zCFovkRTv4354twvVcg3Px+kwJyz5HdcoEb+d/oaoDjq7Zpy3iu9lFc6uux5
5199QmQ5eiY29yTw1S+6lZgRZq2XNdZ1AYDgr/SEYYwNHl98h5ZeQa/rh+r4XfEu
iAU+TCK72h8q3VJGZDnzQs7ZngyzsHeXZJzA9KMuH5UHsBffMNsAGJZMoYFL3QRt
U6M9/Aes1MU3guvklQgZKILSQjqj2FPseYlgSGDIcpJQ3AOPgz+yQlda22rpEZfd
hSi8MEyr48KxRURHH+CKFgeW0iEPU8DtqX7UTuybCeyvQqww1r/REEXgphaypcXT
T3OUM3ECoWqj1jOXTyFjHluP2cFeRXF3D4FdXyGarYPM+l7WjSNfGz1BryB1ZlpK
9p/7qxj3ccC2HTHsOyDry+K49a6SsvfhhEvyovKTmiKe0xRvNlS9H15ZFblzqMF8
b3ti6RZsR1pl8w4Rm0bZ/W3c1pzAtH2lsN0/Vm+h+fbkEkj9Bn8SV7apI09bA8Pg
cSojt/ewsTu8mL3WmKgMa/aOEmem8rJY5AIJEzypuxC00jBF8ez3ABHfZfjcK0NV
vxaXxA/VLGGEqnKG/uY6fsI/fe78LxQ+5oXdUG+3Se0CAwEAAaOCAVMwggFPMB8G
A1UdIwQYMBaAFB4M97Zn8uGSJglFwFU5Lnc/QkqiMB0GA1UdDgQWBBTydxf6Xqj+
9j1x1Wi6yUYMONivsDAOBgNVHQ8BAf8EBAMCAYYwQAYDVR0fBDkwNzA1oDOgMYYv
aHR0cDovL2VjYS5oaW5ldC5uZXQvcmVwb3NpdG9yeS9DUkxfU0hBMi9DQS5jcmww
gYIGCCsGAQUFBwEBBHYwdDA7BggrBgEFBQcwAoYvaHR0cDovL2VjYS5oaW5ldC5u
ZXQvcmVwb3NpdG9yeS9DZXJ0cy9lQ0FHMS5jcnQwNQYIKwYBBQUHMAGGKWh0dHA6
Ly9vY3NwLmVjYS5oaW5ldC5uZXQvT0NTUC9vY3NwRzFzaGEyMBIGA1UdEwEB/wQI
MAYBAf8CAQEwIgYDVR0gBBswGTAIBgZngQwBAgIwDQYLKwYBBAGBtyNkAAMwDQYJ
KoZIhvcNAQELBQADggIBACY9pps8fqk3p8Xqv/qr26I1aFA4jOEG3VWd2bqn68Y9
InOMZozTMVh7iOnOfat7mEqn/RNhikvR5MOV3qAeg4gwgNb1OMuGltwfXWGiuGeT
vhimsV6E2hhJFAmZyXtfuoV9vSrnr1a5pCWqhVYWSCvoAQ/8Kv0tATKbIe21CYXz
NIo7O9QBSXt0BiaP9+CVQtJAYYuy2MNAcXgzgL4rownrYYAixhPmkxQE0Dt1gVbW
s2htBLJGse0z1fJDblY0Zar4t2ly+kIScx5DhRrrd8XKMK0YvID9Ythb+ao8m7Wd
Kymqr36benGL3GsvmSypLPlqZtfEqVITFhXwQiL8ruxoL+3WfNQJ09x0iV4xaP+E
bZSLLVzIiyhU49YdFHaqKyAJQvzgF2Za3DOwQWlP7OngtUx0ScEGHsoo78AM+Y0T
eLFxmr82kuyH18wZkUT9bLZlot11P2aC8VTprBGr+jEAMJjpmEjSA83ja/ttmqgh
qjj29Jnw3Lgy91XIhzBFMxMYo+hhYeBRmBFWl5+Y5oxBgPVLZpDJvg2rKa8xdqim
KgvF0DMKHntE0hhVy7JfUCnKovNQ0pf0NodLfjpqcCS2GBZ1mNcsW2MG2uBPANcn
LRXmt7N4XX11mctQTADwt8yZZ+2HDrST4kghOz+FXgftrPBdtDtM0T6WJcHWR1uS
-----END CERTIFICATE-----