Skip to content

8359956: Support algorithm constraints and certificate checks in SunX509 key manager #25016

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 25 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
58cc444
8272875: Change the default key manager to PKIX
artur-oracle Mar 31, 2025
e495e55
Merge branch 'master' into JDK-8272875
artur-oracle Apr 17, 2025
c80fc6a
Use standard PKIX alias
artur-oracle Apr 17, 2025
19a2ad1
Rework unit tests
artur-oracle Apr 18, 2025
e5e8351
Skip explicit KeyPair initialization and let the provider default set it
artur-oracle Apr 24, 2025
2b0c552
Address review comments
artur-oracle Apr 29, 2025
211f0a6
8353113: Peer supported certificate signature algorithms are not bein…
artur-oracle May 2, 2025
3af51b4
Revert SSLHandshake.java. Set SunX509c as default. Update copyright.
artur-oracle May 3, 2025
79aa9fe
Fix constraints check
artur-oracle May 3, 2025
fd04c0a
Adding a system property to skip the constraints checking. Remove Sun…
artur-oracle May 9, 2025
80488f4
Fix open unit tests
artur-oracle May 9, 2025
d0cfbde
Code refactoring
artur-oracle May 9, 2025
7552810
Add unit test
artur-oracle May 12, 2025
88cd401
Add PeerConstraintsCheck unit test
artur-oracle May 12, 2025
5c137c1
Make sure the exception happens during KeyManager's algorithm check
artur-oracle May 12, 2025
451e1ef
Make the test run on TLSv1.3
artur-oracle May 14, 2025
7cf5bae
Merge branch 'master' into JDK-8353113
artur-oracle Jun 6, 2025
5fe3285
Address some review comments
artur-oracle Jun 9, 2025
448442e
Support certificate checks in SunX509 key manager
artur-oracle Jun 13, 2025
eaf343a
Add more unit tests. Some code refactoring and adjustments.
artur-oracle Jun 18, 2025
45a4a48
Make certificate checking toggle specific to SunX509. Update issue nu…
artur-oracle Jun 18, 2025
bcef734
Remove a couple of empty lines
artur-oracle Jun 18, 2025
a83ea8b
Update system property name in one more test
artur-oracle Jun 18, 2025
c5e381e
Update unit tests. Some code refactoring.
artur-oracle Jun 20, 2025
3edca30
Add more unit test cases. Some code tweaks.
artur-oracle Jun 23, 2025
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
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 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
Expand All @@ -26,6 +26,7 @@
package sun.security.ssl;

import java.net.Socket;
import java.security.AlgorithmConstraints;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
Expand All @@ -45,7 +46,6 @@
import java.util.Map;
import java.util.Set;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.X509ExtendedKeyManager;
import javax.security.auth.x500.X500Principal;


Expand Down Expand Up @@ -77,17 +77,17 @@
*
* Chains that fail any of these criteria will probably be rejected by
* the remote peer.
*
*/
final class SunX509KeyManagerImpl extends X509ExtendedKeyManager {

final class SunX509KeyManagerImpl extends X509KeyManagerConstraints {

private static final String[] STRING0 = new String[0];

/*
* The credentials from the KeyStore as
* Map: String(alias) -> X509Credentials(credentials)
*/
private final Map<String,X509Credentials> credentialsMap;
private final Map<String, X509Credentials> credentialsMap;

/*
* Cached server aliases for the case issuers == null.
Expand All @@ -96,12 +96,13 @@ final class SunX509KeyManagerImpl extends X509ExtendedKeyManager {
*
* Map: String(keyType) -> String[](alias)
*/
private final Map<String,String[]> serverAliasCache;
private final Map<String, String[]> serverAliasCache;

/*
* Basic container for credentials implemented as an inner class.
*/
private static class X509Credentials {

final PrivateKey privateKey;
final X509Certificate[] certificates;
private final Set<X500Principal> issuerX500Principals;
Expand All @@ -124,7 +125,6 @@ Set<X500Principal> getIssuerX500Principals() {
SunX509KeyManagerImpl(KeyStore ks, char[] password)
throws KeyStoreException,
NoSuchAlgorithmException, UnrecoverableKeyException {

credentialsMap = new HashMap<>();
serverAliasCache = Collections.synchronizedMap(
new HashMap<>());
Expand All @@ -133,7 +133,7 @@ Set<X500Principal> getIssuerX500Principals() {
}

for (Enumeration<String> aliases = ks.aliases();
aliases.hasMoreElements(); ) {
aliases.hasMoreElements(); ) {
String alias = aliases.nextElement();
if (!ks.isKeyEntry(alias)) {
continue;
Expand All @@ -153,11 +153,11 @@ Set<X500Principal> getIssuerX500Principals() {
certs = tmp;
}

X509Credentials cred = new X509Credentials((PrivateKey)key,
(X509Certificate[])certs);
X509Credentials cred = new X509Credentials((PrivateKey) key,
(X509Certificate[]) certs);
credentialsMap.put(alias, cred);
if (SSLLogger.isOn && SSLLogger.isOn("keymanager")) {
SSLLogger.fine("found key for : " + alias, (Object[])certs);
SSLLogger.fine("found key for : " + alias, (Object[]) certs);
}
}
}
Expand Down Expand Up @@ -205,24 +205,8 @@ public PrivateKey getPrivateKey(String alias) {
@Override
public String chooseClientAlias(String[] keyTypes, Principal[] issuers,
Socket socket) {
/*
* We currently don't do anything with socket, but
* someday we might. It might be a useful hint for
* selecting one of the aliases we get back from
* getClientAliases().
*/

if (keyTypes == null) {
return null;
}

for (int i = 0; i < keyTypes.length; i++) {
String[] aliases = getClientAliases(keyTypes[i], issuers);
if ((aliases != null) && (aliases.length > 0)) {
return aliases[0];
}
}
return null;
return chooseClientAlias(keyTypes, issuers,
getAlgorithmConstraints(socket));
}

/*
Expand All @@ -236,11 +220,27 @@ public String chooseClientAlias(String[] keyTypes, Principal[] issuers,
@Override
public String chooseEngineClientAlias(String[] keyType,
Principal[] issuers, SSLEngine engine) {
/*
* If we ever start using socket as a selection criteria,
* we'll need to adjust this.
*/
return chooseClientAlias(keyType, issuers, null);
return chooseClientAlias(
keyType, issuers, getAlgorithmConstraints(engine));
}

private String chooseClientAlias(String[] keyTypes, Principal[] issuers,
AlgorithmConstraints constraints) {

if (keyTypes == null) {
return null;
}

for (String keyType : keyTypes) {
String[] aliases = getAliases(
keyType, issuers, CheckType.CLIENT, constraints);

if ((aliases != null) && (aliases.length > 0)) {
return aliases[0];
}
}

return null;
}

/*
Expand All @@ -251,12 +251,28 @@ public String chooseEngineClientAlias(String[] keyType,
@Override
public String chooseServerAlias(String keyType,
Principal[] issuers, Socket socket) {
/*
* We currently don't do anything with socket, but
* someday we might. It might be a useful hint for
* selecting one of the aliases we get back from
* getServerAliases().
*/
return chooseServerAlias(
keyType, issuers, getAlgorithmConstraints(socket));
}

/*
* Choose an alias to authenticate the server side of an
* <code>SSLEngine</code> connection given the public key type
* and the list of certificate issuer authorities recognized by
* the peer (if any).
*
* @since 1.5
*/
@Override
public String chooseEngineServerAlias(String keyType,
Principal[] issuers, SSLEngine engine) {
return chooseServerAlias(
keyType, issuers, getAlgorithmConstraints(engine));
}

private String chooseServerAlias(String keyType,
Principal[] issuers, AlgorithmConstraints constraints) {

if (keyType == null) {
return null;
}
Expand All @@ -266,7 +282,8 @@ public String chooseServerAlias(String keyType,
if (issuers == null || issuers.length == 0) {
aliases = serverAliasCache.get(keyType);
if (aliases == null) {
aliases = getServerAliases(keyType, issuers);
aliases = getAliases(keyType, issuers,
CheckType.SERVER, constraints);
// Cache the result (positive and negative lookups)
if (aliases == null) {
aliases = STRING0;
Expand All @@ -276,28 +293,12 @@ public String chooseServerAlias(String keyType,
} else {
aliases = getServerAliases(keyType, issuers);
}

if ((aliases != null) && (aliases.length > 0)) {
return aliases[0];
}
return null;
}

/*
* Choose an alias to authenticate the server side of an
* <code>SSLEngine</code> connection given the public key type
* and the list of certificate issuer authorities recognized by
* the peer (if any).
*
* @since 1.5
*/
@Override
public String chooseEngineServerAlias(String keyType,
Principal[] issuers, SSLEngine engine) {
/*
* If we ever start using socket as a selection criteria,
* we'll need to adjust this.
*/
return chooseServerAlias(keyType, issuers, null);
return null;
}

/*
Expand All @@ -307,7 +308,7 @@ public String chooseEngineServerAlias(String keyType,
*/
@Override
public String[] getClientAliases(String keyType, Principal[] issuers) {
return getAliases(keyType, issuers);
return getAliases(keyType, issuers, CheckType.CLIENT, null);
}

/*
Expand All @@ -317,7 +318,7 @@ public String[] getClientAliases(String keyType, Principal[] issuers) {
*/
@Override
public String[] getServerAliases(String keyType, Principal[] issuers) {
return getAliases(keyType, issuers);
return getAliases(keyType, issuers, CheckType.SERVER, null);
}

/*
Expand All @@ -327,7 +328,8 @@ public String[] getServerAliases(String keyType, Principal[] issuers) {
*
* Issuers come to us in the form of X500Principal[].
*/
private String[] getAliases(String keyType, Principal[] issuers) {
private String[] getAliases(String keyType, Principal[] issuers,
CheckType checkType, AlgorithmConstraints constraints) {
if (keyType == null) {
return null;
}
Expand All @@ -347,12 +349,12 @@ private String[] getAliases(String keyType, Principal[] issuers) {
sigType = null;
}

X500Principal[] x500Issuers = (X500Principal[])issuers;
X500Principal[] x500Issuers = (X500Principal[]) issuers;
// the algorithm below does not produce duplicates, so avoid Set
List<String> aliases = new ArrayList<>();

for (Map.Entry<String,X509Credentials> entry :
credentialsMap.entrySet()) {
for (Map.Entry<String, X509Credentials> entry :
credentialsMap.entrySet()) {

String alias = entry.getKey();
X509Credentials credentials = entry.getValue();
Expand All @@ -361,6 +363,7 @@ private String[] getAliases(String keyType, Principal[] issuers) {
if (!keyType.equals(certs[0].getPublicKey().getAlgorithm())) {
continue;
}

if (sigType != null) {
if (certs.length > 1) {
// if possible, check the public key in the issuer cert
Expand All @@ -372,15 +375,30 @@ private String[] getAliases(String keyType, Principal[] issuers) {
// Check the signature algorithm of the certificate itself.
// Look for the "withRSA" in "SHA1withRSA", etc.
String sigAlgName =
certs[0].getSigAlgName().toUpperCase(Locale.ENGLISH);
certs[0].getSigAlgName()
.toUpperCase(Locale.ENGLISH);
String pattern = "WITH" +
sigType.toUpperCase(Locale.ENGLISH);
sigType.toUpperCase(Locale.ENGLISH);
if (!sigAlgName.contains(pattern)) {
continue;
}
}
}

// check the algorithm constraints
if (constraints != null &&
!conformsToAlgorithmConstraints(constraints, certs,
checkType.getValidator())) {

if (SSLLogger.isOn && SSLLogger.isOn("keymanager")) {
SSLLogger.fine("Ignore alias " + alias +
": certificate list does not conform to " +
"algorithm constraints");
}

continue;
}

if (issuers.length == 0) {
// no issuer specified, match all
aliases.add(alias);
Expand All @@ -389,7 +407,7 @@ private String[] getAliases(String keyType, Principal[] issuers) {
}
} else {
Set<X500Principal> certIssuers =
credentials.getIssuerX500Principals();
credentials.getIssuerX500Principals();
for (int i = 0; i < x500Issuers.length; i++) {
if (certIssuers.contains(issuers[i])) {
aliases.add(alias);
Expand All @@ -415,7 +433,7 @@ private static X500Principal[] convertPrincipals(Principal[] principals) {
for (int i = 0; i < principals.length; i++) {
Principal p = principals[i];
if (p instanceof X500Principal) {
list.add((X500Principal)p);
list.add((X500Principal) p);
} else {
try {
list.add(new X500Principal(p.getName()));
Expand Down
Loading