diff --git a/src/java.base/macosx/classes/apple/security/AppleProvider.java b/src/java.base/macosx/classes/apple/security/AppleProvider.java index 8381ffeb891..87efda6ebb1 100644 --- a/src/java.base/macosx/classes/apple/security/AppleProvider.java +++ b/src/java.base/macosx/classes/apple/security/AppleProvider.java @@ -60,7 +60,9 @@ public final class AppleProvider extends Provider { try { if (type.equals("KeyStore")) { if (algo.equals("KeychainStore")) { - return new KeychainStore(); + return new KeychainStore.USER(); + } else if (algo.equals("KeychainStore-ROOT")) { + return new KeychainStore.ROOT(); } } } catch (Exception ex) { @@ -82,7 +84,9 @@ public final class AppleProvider extends Provider { AccessController.doPrivileged(new PrivilegedAction() { public Void run() { 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; } }); diff --git a/src/java.base/macosx/classes/apple/security/KeychainStore.java b/src/java.base/macosx/classes/apple/security/KeychainStore.java index 0b60399990c..c8bb717d8ad 100644 --- a/src/java.base/macosx/classes/apple/security/KeychainStore.java +++ b/src/java.base/macosx/classes/apple/security/KeychainStore.java @@ -42,12 +42,72 @@ import sun.security.util.*; import sun.security.x509.*; /** - * This class provides the keystore implementation referred to as "KeychainStore". - * It uses the current user's keychain as its backing storage, and does NOT support - * a file-based implementation. + * This class provides the keystore implementations referred to as + * "KeychainStore" and "KeychainStore-ROOT". + * 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 // 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. @@ -144,7 +205,9 @@ public final class KeychainStore extends KeyStoreSpi { * @exception SecurityException if fails to verify * its own integrity */ - public KeychainStore() { } + private KeychainStore(String name) { + this.storeName = name; + } /** * Returns the key associated with the given alias, using the given @@ -761,7 +824,7 @@ public final class KeychainStore extends KeyStoreSpi { } entries.clear(); - _scanKeychain(); + _scanKeychain(storeName); if (debug != null) { debug.println("KeychainStore load entry count: " + 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, @@ -807,7 +870,7 @@ public final class KeychainStore extends KeyStoreSpi { // 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 // properties and trust settings - if (entries.contains(alias.toLowerCase(Locale.ROOT))) { + if (entries.containsKey(alias.toLowerCase(Locale.ROOT))) { int uniqueVal = 1; String originalAlias = alias; var co = entries.get(alias.toLowerCase(Locale.ROOT)); diff --git a/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m b/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m index b4f13a80d96..cca343650da 100644 --- a/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m +++ b/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m @@ -274,7 +274,7 @@ errOut: 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 // 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; 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 { 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. SecKeychainSearchRef keychainItemSearch = NULL; OSStatus err = SecKeychainSearchCreateFromAttributes(NULL, kSecCertificateItemClass, NULL, &keychainItemSearch); SecKeychainItemRef theItem = NULL; 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, "", "()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 { searchResult = SecKeychainSearchCopyNext(keychainItemSearch, &theItem); if (searchResult == noErr) { // Make a byte array with the DER-encoded contents of the certificate. 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 // We load trust settings from domains kSecTrustSettingsDomainUser and kSecTrustSettingsDomainAdmin // kSecTrustSettingsDomainSystem is ignored because it seems to only contain data for root certificates jobject inputTrust = NULL; - CFArrayRef trustSettings = NULL; // Load user trustSettings into inputTrust - if (SecTrustSettingsCopyTrustSettings(certRef, kSecTrustSettingsDomainUser, &trustSettings) == errSecSuccess && trustSettings != NULL) { - inputTrust = (*env)->NewObject(env, jc_arrayListClass, jm_arrayListCons); - if (inputTrust == NULL) { - CFRelease(trustSettings); - goto errOut; - } - addTrustSettingsToInputTrust(env, jm_listAdd, trustSettings, inputTrust); - CFRelease(trustSettings); + if (!loadTrustSettings(env, certRef, kSecTrustSettingsDomainUser, + jc_arrayListClass, jm_arrayListCons, jm_listAdd, &inputTrust)) { + goto errOut; } // Load admin trustSettings into inputTrust - trustSettings = NULL; - if (SecTrustSettingsCopyTrustSettings(certRef, kSecTrustSettingsDomainAdmin, &trustSettings) == errSecSuccess && trustSettings != NULL) { - if (inputTrust == NULL) { - inputTrust = (*env)->NewObject(env, jc_arrayListClass, jm_arrayListCons); - } - if (inputTrust == NULL) { - CFRelease(trustSettings); - goto errOut; - } - addTrustSettingsToInputTrust(env, jm_listAdd, trustSettings, inputTrust); - CFRelease(trustSettings); + if (!loadTrustSettings(env, certRef, kSecTrustSettingsDomainAdmin, + jc_arrayListClass, jm_arrayListCons, jm_listAdd, &inputTrust)) { + goto errOut; } // Only add certificates with trust settings @@ -501,13 +497,8 @@ static void addCertificatesToKeystore(JNIEnv *env, jobject keyStore) continue; } - // 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)) { + // Create java object for certificate with trust settings + if (!createTrustedCertEntry(env, keyStore, certRef, jm_createTrustedCertEntry, inputTrust)) { 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 * Method: _getEncodedKeyData @@ -590,21 +665,68 @@ errOut: /* * Class: apple_security_KeychainStore * Method: _scanKeychain - * Signature: ()V + * Signature: (Ljava/lang/String)V */ 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. - // 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); + jboolean isCopy; + const char *name_utf = (*env)->GetStringUTFChars(env, name, &isCopy); + if (name_utf != NULL) { + 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. - addCertificatesToKeystore(env, this); + jmethodID jm_createTrustedCertEntry = (*env)->GetMethodID( + 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, "", "()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) { diff --git a/test/jdk/TEST.groups b/test/jdk/TEST.groups index fa033bff12e..fa868699aab 100644 --- a/test/jdk/TEST.groups +++ b/test/jdk/TEST.groups @@ -252,7 +252,7 @@ jdk_security = \ :jdk_security4 jdk_security_infra = \ - security/infra/java/security/cert/CertPathValidator/certification + security/infra jdk_text = \ java/text \ diff --git a/test/jdk/java/security/KeyStore/CheckMacOSKeyChainTrust.java b/test/jdk/java/security/KeyStore/CheckMacOSKeyChainTrust.java index edad6210195..20b6b312cab 100644 --- a/test/jdk/java/security/KeyStore/CheckMacOSKeyChainTrust.java +++ b/test/jdk/java/security/KeyStore/CheckMacOSKeyChainTrust.java @@ -32,22 +32,32 @@ import jdk.test.lib.process.ProcessTools; /* * @test - * @bug 8303465 + * @bug 8303465 8320362 * @library /test/lib * @requires os.family == "mac" * @summary Check whether loading of certificates from MacOS Keychain correctly * honors trust settings + * @run main CheckMacOSKeyChainTrust KEYCHAINSTORE + * @run main CheckMacOSKeyChainTrust KEYCHAINSTORE-ROOT */ public class CheckMacOSKeyChainTrust { private static Set trusted = new HashSet<>(); private static Set distrusted = new HashSet<>(); public static void main(String[] args) throws Throwable { - loadUser(); - loadAdmin(); + String keystore = args[0]; + 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("Distrusted Certs: " + distrusted); - KeyStore ks = KeyStore.getInstance("KEYCHAINSTORE"); + KeyStore ks = KeyStore.getInstance(keystore); ks.load(null, null); for (String alias : trusted) { if (!ks.containsAlias(alias)) { @@ -61,15 +71,19 @@ public class CheckMacOSKeyChainTrust { } } - private static void loadUser() throws Throwable { - populate(ProcessTools.executeProcess("security", "dump-trust-settings")); + private static void loadUser(boolean addTrusted) throws Throwable { + populate(ProcessTools.executeProcess("security", "dump-trust-settings"), addTrusted); } - private static void loadAdmin() throws Throwable { - populate(ProcessTools.executeProcess("security", "dump-trust-settings", "-d")); + private static void loadAdmin(boolean addTrusted) throws Throwable { + 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) { return; // No Trust Settings were found } @@ -84,7 +98,9 @@ public class CheckMacOSKeyChainTrust { if (!denyFound && !(unspecifiedFound && !(trustRootFound || trustAsRootFound)) && !distrusted.contains(certName)) { - trusted.add(certName); + if (addTrusted) { + trusted.add(certName); + } } else { distrusted.add(certName); trusted.remove(certName); @@ -109,7 +125,9 @@ public class CheckMacOSKeyChainTrust { if (!denyFound && !(unspecifiedFound && !(trustRootFound || trustAsRootFound)) && !distrusted.contains(certName)) { - trusted.add(certName); + if (addTrusted) { + trusted.add(certName); + } } else { distrusted.add(certName); trusted.remove(certName); diff --git a/test/jdk/security/infra/javax/net/ssl/HttpsURLConnectionTest.java b/test/jdk/security/infra/javax/net/ssl/HttpsURLConnectionTest.java new file mode 100644 index 00000000000..7aeb67e842d --- /dev/null +++ b/test/jdk/security/infra/javax/net/ssl/HttpsURLConnectionTest.java @@ -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()); + } + } +}