8320362: Load anchor certificates from Keychain keystore

Reviewed-by: weijun, mullan
This commit is contained in:
Alexey Bakhtin 2024-03-21 22:28:02 +00:00
parent ab183e437c
commit 4210e507a0
6 changed files with 365 additions and 109 deletions

View File

@ -60,7 +60,9 @@ public final class AppleProvider extends Provider {
try { try {
if (type.equals("KeyStore")) { if (type.equals("KeyStore")) {
if (algo.equals("KeychainStore")) { if (algo.equals("KeychainStore")) {
return new KeychainStore(); return new KeychainStore.USER();
} else if (algo.equals("KeychainStore-ROOT")) {
return new KeychainStore.ROOT();
} }
} }
} catch (Exception ex) { } catch (Exception ex) {
@ -82,7 +84,9 @@ public final class AppleProvider extends Provider {
AccessController.doPrivileged(new PrivilegedAction<Void>() { AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() { public Void run() {
putService(new ProviderService(p, "KeyStore", putService(new ProviderService(p, "KeyStore",
"KeychainStore", "apple.security.KeychainStore")); "KeychainStore", "apple.security.KeychainStore$USER"));
putService(new ProviderService(p, "KeyStore",
"KeychainStore-ROOT", "apple.security.KeychainStore$ROOT"));
return null; return null;
} }
}); });

View File

@ -42,12 +42,72 @@ import sun.security.util.*;
import sun.security.x509.*; import sun.security.x509.*;
/** /**
* This class provides the keystore implementation referred to as "KeychainStore". * This class provides the keystore implementations referred to as
* It uses the current user's keychain as its backing storage, and does NOT support * "KeychainStore" and "KeychainStore-ROOT".
* a file-based implementation. * They use the current user's and system root keychains accordingly
* as their backing storage, and does NOT support a file-based
* implementation.
*/ */
public final class KeychainStore extends KeyStoreSpi { abstract sealed class KeychainStore extends KeyStoreSpi {
/**
* Current user's keychain
*/
public static final class USER extends KeychainStore {
public USER() {
super("USER");
}
}
/**
* System root read-only keychain
*
*/
public static final class ROOT extends KeychainStore {
public ROOT() {
super("ROOT");
}
/**
* Delete operation is not permitted for trusted anchors
*/
public void engineDeleteEntry(String alias)
throws KeyStoreException
{
throw new KeyStoreException("Trusted entry <" + alias + "> can not be removed");
}
/**
* Changes are not permitted for trusted anchors
*/
public void engineSetKeyEntry(String alias, Key key, char[] password,
Certificate[] chain)
throws KeyStoreException
{
throw new KeyStoreException("Trusted entry <" + alias + "> can not be modified");
}
/**
* Changes are not permitted for trusted anchors
*/
public void engineSetKeyEntry(String alias, byte[] key,
Certificate[] chain)
throws KeyStoreException
{
throw new KeyStoreException("Trusted entry <" + alias + "> can not be modified");
}
/**
* Changes are not permitted for trusted anchors
*/
public void engineStore(OutputStream stream, char[] password)
throws IOException, NoSuchAlgorithmException, CertificateException
{
// do nothing, no changes allowed
}
}
// Private keys and their supporting certificate chains // Private keys and their supporting certificate chains
// If a key came from the keychain it has a SecKeyRef and one or more // If a key came from the keychain it has a SecKeyRef and one or more
@ -137,6 +197,7 @@ public final class KeychainStore extends KeyStoreSpi {
} }
} }
private final String storeName;
/** /**
* Verify the Apple provider in the constructor. * Verify the Apple provider in the constructor.
@ -144,7 +205,9 @@ public final class KeychainStore extends KeyStoreSpi {
* @exception SecurityException if fails to verify * @exception SecurityException if fails to verify
* its own integrity * its own integrity
*/ */
public KeychainStore() { } private KeychainStore(String name) {
this.storeName = name;
}
/** /**
* Returns the key associated with the given alias, using the given * Returns the key associated with the given alias, using the given
@ -761,7 +824,7 @@ public final class KeychainStore extends KeyStoreSpi {
} }
entries.clear(); entries.clear();
_scanKeychain(); _scanKeychain(storeName);
if (debug != null) { if (debug != null) {
debug.println("KeychainStore load entry count: " + debug.println("KeychainStore load entry count: " +
entries.size()); entries.size());
@ -769,7 +832,7 @@ public final class KeychainStore extends KeyStoreSpi {
} }
} }
private native void _scanKeychain(); private native void _scanKeychain(String name);
/** /**
* Callback method from _scanKeychain. If a trusted certificate is found, * Callback method from _scanKeychain. If a trusted certificate is found,
@ -807,7 +870,7 @@ public final class KeychainStore extends KeyStoreSpi {
// Check whether a certificate with same alias already exists and is the same // Check whether a certificate with same alias already exists and is the same
// If yes, we can return here - the existing entry must have the same // If yes, we can return here - the existing entry must have the same
// properties and trust settings // properties and trust settings
if (entries.contains(alias.toLowerCase(Locale.ROOT))) { if (entries.containsKey(alias.toLowerCase(Locale.ROOT))) {
int uniqueVal = 1; int uniqueVal = 1;
String originalAlias = alias; String originalAlias = alias;
var co = entries.get(alias.toLowerCase(Locale.ROOT)); var co = entries.get(alias.toLowerCase(Locale.ROOT));

View File

@ -274,7 +274,7 @@ errOut:
return ortn; return ortn;
} }
static void addIdentitiesToKeystore(JNIEnv *env, jobject keyStore) static void addIdentitiesToKeystore(JNIEnv *env, jobject keyStore, jmethodID jm_createKeyEntry)
{ {
// Search the user keychain list for all identities. Identities are a certificate/private key association that // Search the user keychain list for all identities. Identities are a certificate/private key association that
// can be chosen for a purpose such as signing or an SSL connection. // can be chosen for a purpose such as signing or an SSL connection.
@ -284,15 +284,6 @@ static void addIdentitiesToKeystore(JNIEnv *env, jobject keyStore)
SecIdentityRef theIdentity = NULL; SecIdentityRef theIdentity = NULL;
OSErr searchResult = noErr; OSErr searchResult = noErr;
jclass jc_KeychainStore = (*env)->FindClass(env, "apple/security/KeychainStore");
if (jc_KeychainStore == NULL) {
goto errOut;
}
jmethodID jm_createKeyEntry = (*env)->GetMethodID(env, jc_KeychainStore, "createKeyEntry", "(Ljava/lang/String;JJ[J[[B)V");
if (jm_createKeyEntry == NULL) {
goto errOut;
}
do { do {
searchResult = SecIdentitySearchCopyNext(identitySearch, &theIdentity); searchResult = SecIdentitySearchCopyNext(identitySearch, &theIdentity);
@ -412,88 +403,93 @@ static void addTrustSettingsToInputTrust(JNIEnv *env, jmethodID jm_listAdd, CFAr
} }
} }
static void addCertificatesToKeystore(JNIEnv *env, jobject keyStore) static bool loadTrustSettings(JNIEnv *env,
{ SecCertificateRef certRef,
SecTrustSettingsDomain domain,
jclass jc_arrayListClass,
jmethodID jm_arrayListCons,
jmethodID jm_listAdd,
jobject *inputTrust) {
CFArrayRef trustSettings;
// Load trustSettings into inputTrust
if (SecTrustSettingsCopyTrustSettings(certRef, domain, &trustSettings) == errSecSuccess && trustSettings != NULL) {
if (*inputTrust == NULL) {
*inputTrust = (*env)->NewObject(env, jc_arrayListClass, jm_arrayListCons);
if (*inputTrust == NULL) {
CFRelease(trustSettings);
return false;
}
}
addTrustSettingsToInputTrust(env, jm_listAdd, trustSettings, *inputTrust);
CFRelease(trustSettings);
}
return true;
}
static bool createTrustedCertEntry(JNIEnv *env, jobject keyStore,
SecCertificateRef certRef,
jmethodID jm_createTrustedCertEntry,
jobject inputTrust) {
SecKeychainItemRef theItem = (SecKeychainItemRef)certRef;
CSSM_DATA currCertificate;
OSStatus err = SecCertificateGetData(certRef, &currCertificate);
jbyteArray certData = (*env)->NewByteArray(env, currCertificate.Length);
if (certData == NULL) {
return false;
}
(*env)->SetByteArrayRegion(env, certData, 0, currCertificate.Length, (jbyte *)currCertificate.Data);
// Find the label. It's a 'blob', but we interpret as characters.
jstring alias = getLabelFromItem(env, theItem);
if (alias == NULL) {
return false;
}
// Find the creation date.
jlong creationDate = getModDateFromItem(env, theItem);
// Call back to the Java object to create Java objects corresponding to this security object.
jlong nativeRef = ptr_to_jlong(certRef);
(*env)->CallVoidMethod(env, keyStore, jm_createTrustedCertEntry, alias, inputTrust, nativeRef, creationDate, certData);
if ((*env)->ExceptionCheck(env)) {
return false;
}
return true;
}
static void addCertificatesToKeystore(JNIEnv *env, jobject keyStore,
jmethodID jm_createTrustedCertEntry,
jclass jc_arrayListClass,
jmethodID jm_arrayListCons,
jmethodID jm_listAdd) {
// Search the user keychain list for all X509 certificates. // Search the user keychain list for all X509 certificates.
SecKeychainSearchRef keychainItemSearch = NULL; SecKeychainSearchRef keychainItemSearch = NULL;
OSStatus err = SecKeychainSearchCreateFromAttributes(NULL, kSecCertificateItemClass, NULL, &keychainItemSearch); OSStatus err = SecKeychainSearchCreateFromAttributes(NULL, kSecCertificateItemClass, NULL, &keychainItemSearch);
SecKeychainItemRef theItem = NULL; SecKeychainItemRef theItem = NULL;
OSErr searchResult = noErr; OSErr searchResult = noErr;
jclass jc_KeychainStore = (*env)->FindClass(env, "apple/security/KeychainStore");
if (jc_KeychainStore == NULL) {
goto errOut;
}
jmethodID jm_createTrustedCertEntry = (*env)->GetMethodID(
env, jc_KeychainStore, "createTrustedCertEntry", "(Ljava/lang/String;Ljava/util/List;JJ[B)V");
if (jm_createTrustedCertEntry == NULL) {
goto errOut;
}
jclass jc_arrayListClass = (*env)->FindClass(env, "java/util/ArrayList");
if (jc_arrayListClass == NULL) {
goto errOut;
}
jmethodID jm_arrayListCons = (*env)->GetMethodID(env, jc_arrayListClass, "<init>", "()V");
if (jm_arrayListCons == NULL) {
goto errOut;
}
jmethodID jm_listAdd = (*env)->GetMethodID(env, jc_arrayListClass, "add", "(Ljava/lang/Object;)Z");
if (jm_listAdd == NULL) {
goto errOut;
}
do { do {
searchResult = SecKeychainSearchCopyNext(keychainItemSearch, &theItem); searchResult = SecKeychainSearchCopyNext(keychainItemSearch, &theItem);
if (searchResult == noErr) { if (searchResult == noErr) {
// Make a byte array with the DER-encoded contents of the certificate. // Make a byte array with the DER-encoded contents of the certificate.
SecCertificateRef certRef = (SecCertificateRef)theItem; SecCertificateRef certRef = (SecCertificateRef)theItem;
CSSM_DATA currCertificate;
err = SecCertificateGetData(certRef, &currCertificate);
jbyteArray certData = (*env)->NewByteArray(env, currCertificate.Length);
if (certData == NULL) {
goto errOut;
}
(*env)->SetByteArrayRegion(env, certData, 0, currCertificate.Length, (jbyte *)currCertificate.Data);
// Find the label. It's a 'blob', but we interpret as characters.
jstring alias = getLabelFromItem(env, theItem);
if (alias == NULL) {
goto errOut;
}
// See KeychainStore::createTrustedCertEntry for content of inputTrust // See KeychainStore::createTrustedCertEntry for content of inputTrust
// We load trust settings from domains kSecTrustSettingsDomainUser and kSecTrustSettingsDomainAdmin // We load trust settings from domains kSecTrustSettingsDomainUser and kSecTrustSettingsDomainAdmin
// kSecTrustSettingsDomainSystem is ignored because it seems to only contain data for root certificates // kSecTrustSettingsDomainSystem is ignored because it seems to only contain data for root certificates
jobject inputTrust = NULL; jobject inputTrust = NULL;
CFArrayRef trustSettings = NULL;
// Load user trustSettings into inputTrust // Load user trustSettings into inputTrust
if (SecTrustSettingsCopyTrustSettings(certRef, kSecTrustSettingsDomainUser, &trustSettings) == errSecSuccess && trustSettings != NULL) { if (!loadTrustSettings(env, certRef, kSecTrustSettingsDomainUser,
inputTrust = (*env)->NewObject(env, jc_arrayListClass, jm_arrayListCons); jc_arrayListClass, jm_arrayListCons, jm_listAdd, &inputTrust)) {
if (inputTrust == NULL) { goto errOut;
CFRelease(trustSettings);
goto errOut;
}
addTrustSettingsToInputTrust(env, jm_listAdd, trustSettings, inputTrust);
CFRelease(trustSettings);
} }
// Load admin trustSettings into inputTrust // Load admin trustSettings into inputTrust
trustSettings = NULL; if (!loadTrustSettings(env, certRef, kSecTrustSettingsDomainAdmin,
if (SecTrustSettingsCopyTrustSettings(certRef, kSecTrustSettingsDomainAdmin, &trustSettings) == errSecSuccess && trustSettings != NULL) { jc_arrayListClass, jm_arrayListCons, jm_listAdd, &inputTrust)) {
if (inputTrust == NULL) { goto errOut;
inputTrust = (*env)->NewObject(env, jc_arrayListClass, jm_arrayListCons);
}
if (inputTrust == NULL) {
CFRelease(trustSettings);
goto errOut;
}
addTrustSettingsToInputTrust(env, jm_listAdd, trustSettings, inputTrust);
CFRelease(trustSettings);
} }
// Only add certificates with trust settings // Only add certificates with trust settings
@ -501,13 +497,8 @@ static void addCertificatesToKeystore(JNIEnv *env, jobject keyStore)
continue; continue;
} }
// Find the creation date. // Create java object for certificate with trust settings
jlong creationDate = getModDateFromItem(env, theItem); if (!createTrustedCertEntry(env, keyStore, certRef, jm_createTrustedCertEntry, inputTrust)) {
// Call back to the Java object to create Java objects corresponding to this security object.
jlong nativeRef = ptr_to_jlong(certRef);
(*env)->CallVoidMethod(env, keyStore, jm_createTrustedCertEntry, alias, inputTrust, nativeRef, creationDate, certData);
if ((*env)->ExceptionCheck(env)) {
goto errOut; goto errOut;
} }
} }
@ -519,6 +510,90 @@ errOut:
} }
} }
static void addCertificatesToKeystoreRoot(JNIEnv *env, jobject keyStore,
jmethodID jm_createTrustedCertEntry,
jclass jc_arrayListClass,
jmethodID jm_arrayListCons,
jmethodID jm_listAdd) {
SecKeychainRef keychain = NULL;
CFMutableArrayRef keychainList = NULL;
CFDictionaryRef search = NULL;
CFArrayRef currAnchors = NULL;
// Load predefined root certificates from SystemRootCertificates keychain
// SecTrustCopyAnchorCertificates includes extra root certificates and can not be used here
if( SecKeychainOpen("/System/Library/Keychains/SystemRootCertificates.keychain", &keychain) != errSecSuccess ) {
return;
}
keychainList = CFArrayCreateMutable(kCFAllocatorDefault, 1, &kCFTypeArrayCallBacks);
if (keychainList == NULL) {
goto errOut;
}
CFArrayAppendValue(keychainList, keychain);
CFTypeRef searchKeys[] = { kSecClass, kSecMatchLimit, kSecReturnRef, kSecMatchSearchList };
CFTypeRef searchValues[] = { kSecClassCertificate, kSecMatchLimitAll, kCFBooleanTrue, keychainList };
search = CFDictionaryCreate(kCFAllocatorDefault,
searchKeys, searchValues, 4, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
if (search == NULL) {
goto errOut;
}
if( SecItemCopyMatching( search, (CFTypeRef *)&currAnchors ) == errSecSuccess ){
CFIndex nAnchors = CFArrayGetCount(currAnchors);
for (CFIndex i = 0; i < nAnchors; i++) {
SecCertificateRef certRef = (SecCertificateRef)CFArrayGetValueAtIndex(currAnchors, i);
// See KeychainStore::createTrustedCertEntry for content of inputTrust for system root certs
// This time we load trust settings from domains kSecTrustSettingsDomainUser,
// kSecTrustSettingsDomainAdmin and kSecTrustSettingsDomainSystem
jobject inputTrust = NULL;
// Load user trustSettings into inputTrust
if (!loadTrustSettings(env, certRef, kSecTrustSettingsDomainUser,
jc_arrayListClass, jm_arrayListCons, jm_listAdd, &inputTrust)) {
goto errOut;
}
// Load admin trustSettings into inputTrust
if (!loadTrustSettings(env, certRef, kSecTrustSettingsDomainAdmin,
jc_arrayListClass, jm_arrayListCons, jm_listAdd, &inputTrust)) {
goto errOut;
}
// Load system trustSettings into inputTrust
if (!loadTrustSettings(env, certRef, kSecTrustSettingsDomainSystem,
jc_arrayListClass, jm_arrayListCons, jm_listAdd, &inputTrust)) {
goto errOut;
}
if (inputTrust == NULL) {
continue;
}
// Create java object for certificate with trust settings
if (!createTrustedCertEntry(env, keyStore, certRef, jm_createTrustedCertEntry, inputTrust)) {
goto errOut;
}
CFRetain(certRef);
}
}
errOut:
if (currAnchors != NULL) {
CFRelease(currAnchors);
}
if (search != NULL) {
CFRelease(search);
}
if (keychainList != NULL) {
CFRelease(keychainList);
}
if (keychain != NULL) {
CFRelease(keychain);
}
}
/* /*
* Class: apple_security_KeychainStore * Class: apple_security_KeychainStore
* Method: _getEncodedKeyData * Method: _getEncodedKeyData
@ -590,21 +665,68 @@ errOut:
/* /*
* Class: apple_security_KeychainStore * Class: apple_security_KeychainStore
* Method: _scanKeychain * Method: _scanKeychain
* Signature: ()V * Signature: (Ljava/lang/String)V
*/ */
JNIEXPORT void JNICALL Java_apple_security_KeychainStore__1scanKeychain JNIEXPORT void JNICALL Java_apple_security_KeychainStore__1scanKeychain
(JNIEnv *env, jobject this) (JNIEnv *env, jobject this, jstring name)
{ {
// Look for 'identities' -- private key and certificate chain pairs -- and add those. jboolean isCopy;
// Search for these first, because a certificate that's found here as part of an identity will show up const char *name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
// again later as a certificate. if (name_utf != NULL) {
addIdentitiesToKeystore(env, this); jclass jc_KeychainStore = (*env)->FindClass(env, "apple/security/KeychainStore");
if (jc_KeychainStore == NULL) {
return;
}
JNU_CHECK_EXCEPTION(env); jmethodID jm_createKeyEntry = (*env)->GetMethodID(env, jc_KeychainStore, "createKeyEntry", "(Ljava/lang/String;JJ[J[[B)V");
if (jm_createKeyEntry == NULL) {
return;
}
// Scan current keychain for trusted certificates. jmethodID jm_createTrustedCertEntry = (*env)->GetMethodID(
addCertificatesToKeystore(env, this); env, jc_KeychainStore, "createTrustedCertEntry", "(Ljava/lang/String;Ljava/util/List;JJ[B)V");
if (jm_createTrustedCertEntry == NULL) {
return;
}
jclass jc_arrayListClass = (*env)->FindClass(env, "java/util/ArrayList");
if (jc_arrayListClass == NULL) {
return;
}
jmethodID jm_arrayListCons = (*env)->GetMethodID(env, jc_arrayListClass, "<init>", "()V");
if (jm_arrayListCons == NULL) {
return;
}
jmethodID jm_listAdd = (*env)->GetMethodID(env, jc_arrayListClass, "add", "(Ljava/lang/Object;)Z");
if (jm_listAdd == NULL) {
return;
}
if (strcmp(name_utf, "ROOT") == 0) {
// Scan Trusted Anchors keychain for trusted certificates.
addCertificatesToKeystoreRoot(env, this,
jm_createTrustedCertEntry,
jc_arrayListClass,
jm_arrayListCons,
jm_listAdd);
} else {
// Look for 'identities' -- private key and certificate chain pairs -- and add those.
// Search for these first, because a certificate that's found here as part of an identity will show up
// again later as a certificate.
addIdentitiesToKeystore(env, this, jm_createKeyEntry);
JNU_CHECK_EXCEPTION(env);
// Scan current keychain for trusted certificates.
addCertificatesToKeystore(env, this,
jm_createTrustedCertEntry,
jc_arrayListClass,
jm_arrayListCons,
jm_listAdd);
}
}
} }
NSString* JavaStringToNSString(JNIEnv *env, jstring jstr) { NSString* JavaStringToNSString(JNIEnv *env, jstring jstr) {

View File

@ -252,7 +252,7 @@ jdk_security = \
:jdk_security4 :jdk_security4
jdk_security_infra = \ jdk_security_infra = \
security/infra/java/security/cert/CertPathValidator/certification security/infra
jdk_text = \ jdk_text = \
java/text \ java/text \

View File

@ -32,22 +32,32 @@ import jdk.test.lib.process.ProcessTools;
/* /*
* @test * @test
* @bug 8303465 * @bug 8303465 8320362
* @library /test/lib * @library /test/lib
* @requires os.family == "mac" * @requires os.family == "mac"
* @summary Check whether loading of certificates from MacOS Keychain correctly * @summary Check whether loading of certificates from MacOS Keychain correctly
* honors trust settings * honors trust settings
* @run main CheckMacOSKeyChainTrust KEYCHAINSTORE
* @run main CheckMacOSKeyChainTrust KEYCHAINSTORE-ROOT
*/ */
public class CheckMacOSKeyChainTrust { public class CheckMacOSKeyChainTrust {
private static Set<String> trusted = new HashSet<>(); private static Set<String> trusted = new HashSet<>();
private static Set<String> distrusted = new HashSet<>(); private static Set<String> distrusted = new HashSet<>();
public static void main(String[] args) throws Throwable { public static void main(String[] args) throws Throwable {
loadUser(); String keystore = args[0];
loadAdmin(); if (keystore.equals("KEYCHAINSTORE")) {
loadUser(true);
loadAdmin(true);
} else {
// check user and admin trustsettings to find distrusted certs
loadUser(false);
loadAdmin(false);
loadSystem(true);
}
System.out.println("Trusted Certs: " + trusted); System.out.println("Trusted Certs: " + trusted);
System.out.println("Distrusted Certs: " + distrusted); System.out.println("Distrusted Certs: " + distrusted);
KeyStore ks = KeyStore.getInstance("KEYCHAINSTORE"); KeyStore ks = KeyStore.getInstance(keystore);
ks.load(null, null); ks.load(null, null);
for (String alias : trusted) { for (String alias : trusted) {
if (!ks.containsAlias(alias)) { if (!ks.containsAlias(alias)) {
@ -61,15 +71,19 @@ public class CheckMacOSKeyChainTrust {
} }
} }
private static void loadUser() throws Throwable { private static void loadUser(boolean addTrusted) throws Throwable {
populate(ProcessTools.executeProcess("security", "dump-trust-settings")); populate(ProcessTools.executeProcess("security", "dump-trust-settings"), addTrusted);
} }
private static void loadAdmin() throws Throwable { private static void loadAdmin(boolean addTrusted) throws Throwable {
populate(ProcessTools.executeProcess("security", "dump-trust-settings", "-d")); populate(ProcessTools.executeProcess("security", "dump-trust-settings", "-d"), addTrusted);
} }
private static void populate(OutputAnalyzer output) throws Throwable { private static void loadSystem(boolean addTrusted) throws Throwable {
populate(ProcessTools.executeProcess("security", "dump-trust-settings", "-s"), addTrusted);
}
private static void populate(OutputAnalyzer output, boolean addTrusted) throws Throwable {
if (output.getExitValue() != 0) { if (output.getExitValue() != 0) {
return; // No Trust Settings were found return; // No Trust Settings were found
} }
@ -84,7 +98,9 @@ public class CheckMacOSKeyChainTrust {
if (!denyFound && if (!denyFound &&
!(unspecifiedFound && !(trustRootFound || trustAsRootFound)) && !(unspecifiedFound && !(trustRootFound || trustAsRootFound)) &&
!distrusted.contains(certName)) { !distrusted.contains(certName)) {
trusted.add(certName); if (addTrusted) {
trusted.add(certName);
}
} else { } else {
distrusted.add(certName); distrusted.add(certName);
trusted.remove(certName); trusted.remove(certName);
@ -109,7 +125,9 @@ public class CheckMacOSKeyChainTrust {
if (!denyFound && if (!denyFound &&
!(unspecifiedFound && !(trustRootFound || trustAsRootFound)) && !(unspecifiedFound && !(trustRootFound || trustAsRootFound)) &&
!distrusted.contains(certName)) { !distrusted.contains(certName)) {
trusted.add(certName); if (addTrusted) {
trusted.add(certName);
}
} else { } else {
distrusted.add(certName); distrusted.add(certName);
trusted.remove(certName); trusted.remove(certName);

View File

@ -0,0 +1,49 @@
/*
* Copyright (c) 2024, 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.
*/
/**
* @test
* @bug 8320362
* @summary Verifies successful connection to external server with
* KEYCHAINSTORE-ROOT trust store
* @library /test/lib
* @requires os.family == "mac"
* @run main/othervm HttpsURLConnectionTest https://github.com KeychainStore-Root
*/
import java.io.*;
import java.net.*;
import javax.net.ssl.*;
public class HttpsURLConnectionTest {
public static void main(String[] args) {
System.setProperty( "javax.net.ssl.trustStoreType", args[1]);
try {
HttpsURLConnection httpsCon = (HttpsURLConnection) new URL(args[0]).openConnection();
if(httpsCon.getResponseCode() != 200) {
throw new RuntimeException("Test failed : bad http response code : "+ httpsCon.getResponseCode());
}
} catch(IOException ioe) {
throw new RuntimeException("Test failed: " + ioe.getMessage());
}
}
}