8320362: Load anchor certificates from Keychain keystore
Reviewed-by: weijun, mullan
This commit is contained in:
parent
ab183e437c
commit
4210e507a0
@ -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;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -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));
|
||||||
|
@ -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) {
|
||||||
|
@ -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 \
|
||||||
|
@ -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);
|
||||||
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user