From 8c73db9097fad4a648735ad6c48df7c13175a83a Mon Sep 17 00:00:00 2001 From: Ralph Plawetzki Date: Sun, 18 Feb 2024 09:51:19 +0100 Subject: [PATCH 1/7] Implement MacSystemKeychainAccess using SecItem API --- ...omator_macos_keychain_MacKeychain_Native.m | 222 ++++++++++-------- 1 file changed, 125 insertions(+), 97 deletions(-) diff --git a/src/main/native/org_cryptomator_macos_keychain_MacKeychain_Native.m b/src/main/native/org_cryptomator_macos_keychain_MacKeychain_Native.m index e04bb0a..85731fc 100644 --- a/src/main/native/org_cryptomator_macos_keychain_MacKeychain_Native.m +++ b/src/main/native/org_cryptomator_macos_keychain_MacKeychain_Native.m @@ -7,117 +7,145 @@ // #import "org_cryptomator_macos_keychain_MacKeychain_Native.h" +#import #import +// the kServiceName must be the same as in the project settings > Keychain Sharing > Keychain Groups + +SecAccessControlRef createAccessControl(void) { + SecAccessControlCreateFlags flags = kSecAccessControlUserPresence; + + SecAccessControlRef accessControl = SecAccessControlCreateWithFlags( + kCFAllocatorDefault, + kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, + flags, + NULL // Ignore any error + ); + + return accessControl; +} + JNIEXPORT jint JNICALL Java_org_cryptomator_macos_keychain_MacKeychain_00024Native_storePassword(JNIEnv *env, jobject thisObj, jbyteArray service, jbyteArray key, jbyteArray password) { - const int serviceLen = (*env)->GetArrayLength(env, service); jbyte *serviceStr = (*env)->GetByteArrayElements(env, service, NULL); - const int keyLen = (*env)->GetArrayLength(env, key); jbyte *keyStr = (*env)->GetByteArrayElements(env, key, NULL); - const int pwLen = (*env)->GetArrayLength(env, password); jbyte *pwStr = (*env)->GetByteArrayElements(env, password, NULL); // find existing: - SecKeychainItemRef itemRef = NULL; - OSStatus status = SecKeychainFindGenericPassword( - NULL, // default keychain - serviceLen, // length of service name - (char *)serviceStr, // service name - keyLen, // length of account name - (char *)keyStr, // account name - NULL, // length of password - NULL, // pointer to password data - &itemRef // the item reference - ); - if (status == errSecSuccess) { - // update existing: - status = SecKeychainItemModifyAttributesAndData( - itemRef, // the item reference - NULL, // no change to attributes - pwLen, // length of password - pwStr // pointer to password data - ); - } else if (status == errSecItemNotFound) { - // add new: - status = SecKeychainAddGenericPassword( - NULL, // default keychain - serviceLen, // length of service name - (char *)serviceStr, // service name - keyLen, // length of account name - (char *)keyStr, // account name - pwLen, // length of password - pwStr, // pointer to password data - NULL // the item reference - ); - } - - (*env)->ReleaseByteArrayElements(env, key, keyStr, JNI_ABORT); - (*env)->ReleaseByteArrayElements(env, password, pwStr, JNI_ABORT); - if (itemRef) { - CFRelease(itemRef); - } - return status; + NSDictionary *searchAttributes = @{ + (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, + (__bridge id)kSecAttrService: [NSString stringWithCString:(char *)serviceStr encoding:NSUTF8StringEncoding], + (__bridge id)kSecAttrAccount: [NSString stringWithCString:(char *)keyStr encoding:NSUTF8StringEncoding], + (__bridge id)kSecReturnAttributes: @YES, + (__bridge id)kSecReturnData: @YES, + (__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitOne + }; + + CFDictionaryRef result = NULL; + OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)searchAttributes, (CFTypeRef *)&result); + + if (status == errSecSuccess && result != NULL) { + NSLog(@"Item found in keychain, updating it."); + + // update existing: + NSDictionary *changeAttributes = @{ + (__bridge id)kSecValueData: [NSString stringWithCString:(char *)pwStr encoding:NSUTF8StringEncoding] + }; + + status = SecItemUpdate((__bridge CFDictionaryRef)searchAttributes, (__bridge CFDictionaryRef)changeAttributes); + + } else if (status == errSecItemNotFound) { + NSLog(@"Adding item to keychain."); + + // add new: + NSDictionary *keychainAttributes = @{ + (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, + (__bridge id)kSecAttrService: [NSString stringWithCString:(char *)serviceStr encoding:NSUTF8StringEncoding], + (__bridge id)kSecAttrAccessControl: (__bridge_transfer id)createAccessControl(), + (__bridge id)kSecAttrAccount: [NSString stringWithCString:(char *)keyStr encoding:NSUTF8StringEncoding], + (__bridge id)kSecValueData: [NSString stringWithCString:(char *)pwStr encoding:NSUTF8StringEncoding] + }; + + status = SecItemAdd((__bridge CFDictionaryRef)keychainAttributes, NULL); + + } else { + NSLog(@"Error storing item in keychain. Status code: %d", (int)status); + } + + (*env)->ReleaseByteArrayElements(env, key, keyStr, JNI_ABORT); + (*env)->ReleaseByteArrayElements(env, password, pwStr, JNI_ABORT); + + return status; } JNIEXPORT jbyteArray JNICALL Java_org_cryptomator_macos_keychain_MacKeychain_00024Native_loadPassword(JNIEnv *env, jobject thisObj, jbyteArray service, jbyteArray key) { - const int serviceLen = (*env)->GetArrayLength(env, service); jbyte *serviceStr = (*env)->GetByteArrayElements(env, service, NULL); - const int keyLen = (*env)->GetArrayLength(env, key); jbyte *keyStr = (*env)->GetByteArrayElements(env, key, NULL); - void *pwStr = NULL; - UInt32 pwLen; - OSStatus status = SecKeychainFindGenericPassword( - NULL, // default keychain - serviceLen, // length of service name - (char *)serviceStr, // service name - keyLen, // length of account name - (char *)keyStr, // account name - &pwLen, // length of password - &pwStr, // pointer to password data - NULL // the item reference - ); - - jbyteArray result; - if (status == errSecSuccess) { - result = (*env)->NewByteArray(env, pwLen); - (*env)->SetByteArrayRegion(env, result, 0, pwLen, pwStr); - } else { - result = NULL; - } - - (*env)->ReleaseByteArrayElements(env, key, keyStr, JNI_ABORT); - if (pwStr) { - SecKeychainItemFreeContent(NULL, pwStr); - } - return result; + + // Create a dictionary of search attributes to find the item in the keychain + NSDictionary *searchAttributes = @{ + (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, + (__bridge id)kSecAttrService: [NSString stringWithCString:(char *)serviceStr encoding:NSUTF8StringEncoding], + (__bridge id)kSecAttrAccount: [NSString stringWithCString:(char *)keyStr encoding:NSUTF8StringEncoding], + (__bridge id)kSecReturnAttributes: @YES, + (__bridge id)kSecReturnData: @YES, + (__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitOne + }; + + CFDictionaryRef result = NULL; + OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)searchAttributes, (CFTypeRef *)&result); + + (*env)->ReleaseByteArrayElements(env, key, keyStr, JNI_ABORT); + + if (status == errSecSuccess && result != NULL) { + NSDictionary *attributes = (__bridge_transfer NSDictionary *)result; + NSData *passwordData = attributes[(__bridge id)kSecValueData]; + NSLog(@"Item found in keychain."); + + NSUInteger pwLen = [passwordData length]; + const void *pwBytes = [passwordData bytes]; + + jbyteArray password = (*env)->NewByteArray(env, (int)pwLen); + (*env)->SetByteArrayRegion(env, password, 0, (int)pwLen, (jbyte *)pwBytes); + + return password; + + } else if (status == errSecItemNotFound) { + NSLog(@"No matching item found in the keychain."); + } else { + NSLog(@"Error retrieving item from keychain. Status code: %d", (int)status); + } + + return NULL; // empty } JNIEXPORT jint JNICALL Java_org_cryptomator_macos_keychain_MacKeychain_00024Native_deletePassword(JNIEnv *env, jobject thisObj, jbyteArray service, jbyteArray key) { - const int serviceLen = (*env)->GetArrayLength(env, service); - jbyte *serviceStr = (*env)->GetByteArrayElements(env, service, NULL); - const int keyLen = (*env)->GetArrayLength(env, key); - jbyte *keyStr = (*env)->GetByteArrayElements(env, key, NULL); - SecKeychainItemRef itemRef = NULL; - OSStatus status = SecKeychainFindGenericPassword( - NULL, // default keychain - serviceLen, // length of service name - (char *)serviceStr, // service name - keyLen, // length of account name - (char *)keyStr, // account name - NULL, // length of password - NULL, // pointer to password data - &itemRef // the item reference - ); - - if (status == errSecSuccess) { - status = SecKeychainItemDelete( - itemRef // the item reference - ); - } - - (*env)->ReleaseByteArrayElements(env, key, keyStr, JNI_ABORT); - if (itemRef) { - CFRelease(itemRef); - } - return status; + jbyte *serviceStr = (*env)->GetByteArrayElements(env, service, NULL); + jbyte *keyStr = (*env)->GetByteArrayElements(env, key, NULL); + + // find existing: + NSDictionary *searchAttributes = @{ + (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, + (__bridge id)kSecAttrService: [NSString stringWithCString:(char *)serviceStr encoding:NSUTF8StringEncoding], + (__bridge id)kSecAttrAccount: [NSString stringWithCString:(char *)keyStr encoding:NSUTF8StringEncoding], + (__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitOne + }; + + CFDictionaryRef result = NULL; + OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)searchAttributes, (CFTypeRef *)&result); + + if (status == errSecSuccess && result != NULL) { + NSLog(@"Item found in keychain, deleting it."); + + status = SecItemDelete((__bridge CFDictionaryRef)searchAttributes); + + } else if (status == errSecItemNotFound) { + NSLog(@"No matching item found in the keychain."); + + } else { + NSLog(@"Error deleting item from keychain. Status code: %d", (int)status); + } + + (*env)->ReleaseByteArrayElements(env, key, keyStr, JNI_ABORT); + + return status; } From 9fc29cef1dd812bf0a6cc35e86ffaad6a54b9672 Mon Sep 17 00:00:00 2001 From: Ralph Plawetzki Date: Sun, 26 May 2024 08:36:03 +0200 Subject: [PATCH 2/7] kSecValueData must be of type NSData Add missing ReleaseByteArrayElements releases --- ...omator_macos_keychain_MacKeychain_Native.m | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/main/native/org_cryptomator_macos_keychain_MacKeychain_Native.m b/src/main/native/org_cryptomator_macos_keychain_MacKeychain_Native.m index 85731fc..e21a460 100644 --- a/src/main/native/org_cryptomator_macos_keychain_MacKeychain_Native.m +++ b/src/main/native/org_cryptomator_macos_keychain_MacKeychain_Native.m @@ -12,7 +12,7 @@ // the kServiceName must be the same as in the project settings > Keychain Sharing > Keychain Groups -SecAccessControlRef createAccessControl(void) { +static SecAccessControlRef createAccessControl(void) { SecAccessControlCreateFlags flags = kSecAccessControlUserPresence; SecAccessControlRef accessControl = SecAccessControlCreateWithFlags( @@ -29,6 +29,7 @@ JNIEXPORT jint JNICALL Java_org_cryptomator_macos_keychain_MacKeychain_00024Nati jbyte *serviceStr = (*env)->GetByteArrayElements(env, service, NULL); jbyte *keyStr = (*env)->GetByteArrayElements(env, key, NULL); jbyte *pwStr = (*env)->GetByteArrayElements(env, password, NULL); + jsize length = (*env)->GetArrayLength(env, password); // find existing: NSDictionary *searchAttributes = @{ @@ -48,7 +49,7 @@ JNIEXPORT jint JNICALL Java_org_cryptomator_macos_keychain_MacKeychain_00024Nati // update existing: NSDictionary *changeAttributes = @{ - (__bridge id)kSecValueData: [NSString stringWithCString:(char *)pwStr encoding:NSUTF8StringEncoding] + (__bridge id)kSecValueData: [NSData dataWithBytes:pwStr length:length] }; status = SecItemUpdate((__bridge CFDictionaryRef)searchAttributes, (__bridge CFDictionaryRef)changeAttributes); @@ -60,9 +61,9 @@ JNIEXPORT jint JNICALL Java_org_cryptomator_macos_keychain_MacKeychain_00024Nati NSDictionary *keychainAttributes = @{ (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, (__bridge id)kSecAttrService: [NSString stringWithCString:(char *)serviceStr encoding:NSUTF8StringEncoding], - (__bridge id)kSecAttrAccessControl: (__bridge_transfer id)createAccessControl(), + //(__bridge id)kSecAttrAccessControl: (__bridge_transfer id)createAccessControl(), (__bridge id)kSecAttrAccount: [NSString stringWithCString:(char *)keyStr encoding:NSUTF8StringEncoding], - (__bridge id)kSecValueData: [NSString stringWithCString:(char *)pwStr encoding:NSUTF8StringEncoding] + (__bridge id)kSecValueData: [NSData dataWithBytes:pwStr length:length] }; status = SecItemAdd((__bridge CFDictionaryRef)keychainAttributes, NULL); @@ -71,6 +72,7 @@ JNIEXPORT jint JNICALL Java_org_cryptomator_macos_keychain_MacKeychain_00024Nati NSLog(@"Error storing item in keychain. Status code: %d", (int)status); } + (*env)->ReleaseByteArrayElements(env, service, serviceStr, JNI_ABORT); (*env)->ReleaseByteArrayElements(env, key, keyStr, JNI_ABORT); (*env)->ReleaseByteArrayElements(env, password, pwStr, JNI_ABORT); @@ -82,18 +84,19 @@ JNIEXPORT jbyteArray JNICALL Java_org_cryptomator_macos_keychain_MacKeychain_000 jbyte *keyStr = (*env)->GetByteArrayElements(env, key, NULL); // Create a dictionary of search attributes to find the item in the keychain - NSDictionary *searchAttributes = @{ - (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, - (__bridge id)kSecAttrService: [NSString stringWithCString:(char *)serviceStr encoding:NSUTF8StringEncoding], - (__bridge id)kSecAttrAccount: [NSString stringWithCString:(char *)keyStr encoding:NSUTF8StringEncoding], - (__bridge id)kSecReturnAttributes: @YES, - (__bridge id)kSecReturnData: @YES, - (__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitOne - }; + NSDictionary *searchAttributes = @{ + (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, + (__bridge id)kSecAttrService: [NSString stringWithCString:(char *)serviceStr encoding:NSUTF8StringEncoding], + (__bridge id)kSecAttrAccount: [NSString stringWithCString:(char *)keyStr encoding:NSUTF8StringEncoding], + (__bridge id)kSecReturnAttributes: @YES, + (__bridge id)kSecReturnData: @YES, + (__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitOne + }; - CFDictionaryRef result = NULL; - OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)searchAttributes, (CFTypeRef *)&result); + CFDictionaryRef result = NULL; + OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)searchAttributes, (CFTypeRef *)&result); + (*env)->ReleaseByteArrayElements(env, service, serviceStr, JNI_ABORT); (*env)->ReleaseByteArrayElements(env, key, keyStr, JNI_ABORT); if (status == errSecSuccess && result != NULL) { @@ -145,6 +148,7 @@ JNIEXPORT jint JNICALL Java_org_cryptomator_macos_keychain_MacKeychain_00024Nati NSLog(@"Error deleting item from keychain. Status code: %d", (int)status); } + (*env)->ReleaseByteArrayElements(env, service, serviceStr, JNI_ABORT); (*env)->ReleaseByteArrayElements(env, key, keyStr, JNI_ABORT); return status; From 372d4fe66b19eb2aec28798bdc5c8b8369c2aed6 Mon Sep 17 00:00:00 2001 From: Ralph Plawetzki Date: Sun, 26 May 2024 16:21:01 +0200 Subject: [PATCH 3/7] Set access control to default for testing purposes --- .../native/org_cryptomator_macos_keychain_MacKeychain_Native.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/native/org_cryptomator_macos_keychain_MacKeychain_Native.m b/src/main/native/org_cryptomator_macos_keychain_MacKeychain_Native.m index e21a460..09f4905 100644 --- a/src/main/native/org_cryptomator_macos_keychain_MacKeychain_Native.m +++ b/src/main/native/org_cryptomator_macos_keychain_MacKeychain_Native.m @@ -17,7 +17,7 @@ static SecAccessControlRef createAccessControl(void) { SecAccessControlRef accessControl = SecAccessControlCreateWithFlags( kCFAllocatorDefault, - kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, + kSecAttrAccessibleWhenUnlocked, flags, NULL // Ignore any error ); From cd0cb404262ea9f24922707c7747c3f92b9db0fd Mon Sep 17 00:00:00 2001 From: Ralph Plawetzki Date: Mon, 27 May 2024 18:38:33 +0200 Subject: [PATCH 4/7] Reduce to code without access control --- ...omator_macos_keychain_MacKeychain_Native.m | 31 ++----------------- 1 file changed, 2 insertions(+), 29 deletions(-) diff --git a/src/main/native/org_cryptomator_macos_keychain_MacKeychain_Native.m b/src/main/native/org_cryptomator_macos_keychain_MacKeychain_Native.m index 09f4905..d4e1144 100644 --- a/src/main/native/org_cryptomator_macos_keychain_MacKeychain_Native.m +++ b/src/main/native/org_cryptomator_macos_keychain_MacKeychain_Native.m @@ -10,21 +10,6 @@ #import #import -// the kServiceName must be the same as in the project settings > Keychain Sharing > Keychain Groups - -static SecAccessControlRef createAccessControl(void) { - SecAccessControlCreateFlags flags = kSecAccessControlUserPresence; - - SecAccessControlRef accessControl = SecAccessControlCreateWithFlags( - kCFAllocatorDefault, - kSecAttrAccessibleWhenUnlocked, - flags, - NULL // Ignore any error - ); - - return accessControl; -} - JNIEXPORT jint JNICALL Java_org_cryptomator_macos_keychain_MacKeychain_00024Native_storePassword(JNIEnv *env, jobject thisObj, jbyteArray service, jbyteArray key, jbyteArray password) { jbyte *serviceStr = (*env)->GetByteArrayElements(env, service, NULL); jbyte *keyStr = (*env)->GetByteArrayElements(env, key, NULL); @@ -45,8 +30,6 @@ JNIEXPORT jint JNICALL Java_org_cryptomator_macos_keychain_MacKeychain_00024Nati OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)searchAttributes, (CFTypeRef *)&result); if (status == errSecSuccess && result != NULL) { - NSLog(@"Item found in keychain, updating it."); - // update existing: NSDictionary *changeAttributes = @{ (__bridge id)kSecValueData: [NSData dataWithBytes:pwStr length:length] @@ -55,13 +38,10 @@ JNIEXPORT jint JNICALL Java_org_cryptomator_macos_keychain_MacKeychain_00024Nati status = SecItemUpdate((__bridge CFDictionaryRef)searchAttributes, (__bridge CFDictionaryRef)changeAttributes); } else if (status == errSecItemNotFound) { - NSLog(@"Adding item to keychain."); - // add new: NSDictionary *keychainAttributes = @{ (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, (__bridge id)kSecAttrService: [NSString stringWithCString:(char *)serviceStr encoding:NSUTF8StringEncoding], - //(__bridge id)kSecAttrAccessControl: (__bridge_transfer id)createAccessControl(), (__bridge id)kSecAttrAccount: [NSString stringWithCString:(char *)keyStr encoding:NSUTF8StringEncoding], (__bridge id)kSecValueData: [NSData dataWithBytes:pwStr length:length] }; @@ -102,7 +82,6 @@ JNIEXPORT jbyteArray JNICALL Java_org_cryptomator_macos_keychain_MacKeychain_000 if (status == errSecSuccess && result != NULL) { NSDictionary *attributes = (__bridge_transfer NSDictionary *)result; NSData *passwordData = attributes[(__bridge id)kSecValueData]; - NSLog(@"Item found in keychain."); NSUInteger pwLen = [passwordData length]; const void *pwBytes = [passwordData bytes]; @@ -112,9 +91,7 @@ JNIEXPORT jbyteArray JNICALL Java_org_cryptomator_macos_keychain_MacKeychain_000 return password; - } else if (status == errSecItemNotFound) { - NSLog(@"No matching item found in the keychain."); - } else { + } else if (status != errSecItemNotFound) { NSLog(@"Error retrieving item from keychain. Status code: %d", (int)status); } @@ -137,14 +114,10 @@ JNIEXPORT jint JNICALL Java_org_cryptomator_macos_keychain_MacKeychain_00024Nati OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)searchAttributes, (CFTypeRef *)&result); if (status == errSecSuccess && result != NULL) { - NSLog(@"Item found in keychain, deleting it."); status = SecItemDelete((__bridge CFDictionaryRef)searchAttributes); - } else if (status == errSecItemNotFound) { - NSLog(@"No matching item found in the keychain."); - - } else { + } else if (status != errSecItemNotFound) { NSLog(@"Error deleting item from keychain. Status code: %d", (int)status); } From 77c6e1084c5f4bc12c029e5a3a5d426b24823a9d Mon Sep 17 00:00:00 2001 From: Ralph Plawetzki Date: Thu, 30 May 2024 14:29:48 +0200 Subject: [PATCH 5/7] Fix indentation --- ...omator_macos_keychain_MacKeychain_Native.m | 172 +++++++++--------- 1 file changed, 86 insertions(+), 86 deletions(-) diff --git a/src/main/native/org_cryptomator_macos_keychain_MacKeychain_Native.m b/src/main/native/org_cryptomator_macos_keychain_MacKeychain_Native.m index d4e1144..679b757 100644 --- a/src/main/native/org_cryptomator_macos_keychain_MacKeychain_Native.m +++ b/src/main/native/org_cryptomator_macos_keychain_MacKeychain_Native.m @@ -17,112 +17,112 @@ JNIEXPORT jint JNICALL Java_org_cryptomator_macos_keychain_MacKeychain_00024Nati jsize length = (*env)->GetArrayLength(env, password); // find existing: - NSDictionary *searchAttributes = @{ - (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, - (__bridge id)kSecAttrService: [NSString stringWithCString:(char *)serviceStr encoding:NSUTF8StringEncoding], - (__bridge id)kSecAttrAccount: [NSString stringWithCString:(char *)keyStr encoding:NSUTF8StringEncoding], - (__bridge id)kSecReturnAttributes: @YES, - (__bridge id)kSecReturnData: @YES, - (__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitOne - }; - - CFDictionaryRef result = NULL; - OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)searchAttributes, (CFTypeRef *)&result); - - if (status == errSecSuccess && result != NULL) { - // update existing: - NSDictionary *changeAttributes = @{ - (__bridge id)kSecValueData: [NSData dataWithBytes:pwStr length:length] - }; - - status = SecItemUpdate((__bridge CFDictionaryRef)searchAttributes, (__bridge CFDictionaryRef)changeAttributes); - - } else if (status == errSecItemNotFound) { - // add new: - NSDictionary *keychainAttributes = @{ - (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, - (__bridge id)kSecAttrService: [NSString stringWithCString:(char *)serviceStr encoding:NSUTF8StringEncoding], - (__bridge id)kSecAttrAccount: [NSString stringWithCString:(char *)keyStr encoding:NSUTF8StringEncoding], - (__bridge id)kSecValueData: [NSData dataWithBytes:pwStr length:length] - }; - - status = SecItemAdd((__bridge CFDictionaryRef)keychainAttributes, NULL); - - } else { - NSLog(@"Error storing item in keychain. Status code: %d", (int)status); - } - - (*env)->ReleaseByteArrayElements(env, service, serviceStr, JNI_ABORT); - (*env)->ReleaseByteArrayElements(env, key, keyStr, JNI_ABORT); - (*env)->ReleaseByteArrayElements(env, password, pwStr, JNI_ABORT); - - return status; + NSDictionary *searchAttributes = @{ + (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, + (__bridge id)kSecAttrService: [NSString stringWithCString:(char *)serviceStr encoding:NSUTF8StringEncoding], + (__bridge id)kSecAttrAccount: [NSString stringWithCString:(char *)keyStr encoding:NSUTF8StringEncoding], + (__bridge id)kSecReturnAttributes: @YES, + (__bridge id)kSecReturnData: @YES, + (__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitOne + }; + + CFDictionaryRef result = NULL; + OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)searchAttributes, (CFTypeRef *)&result); + + if (status == errSecSuccess && result != NULL) { + // update existing: + NSDictionary *changeAttributes = @{ + (__bridge id)kSecValueData: [NSData dataWithBytes:pwStr length:length] + }; + + status = SecItemUpdate((__bridge CFDictionaryRef)searchAttributes, (__bridge CFDictionaryRef)changeAttributes); + + } else if (status == errSecItemNotFound) { + // add new: + NSDictionary *keychainAttributes = @{ + (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, + (__bridge id)kSecAttrService: [NSString stringWithCString:(char *)serviceStr encoding:NSUTF8StringEncoding], + (__bridge id)kSecAttrAccount: [NSString stringWithCString:(char *)keyStr encoding:NSUTF8StringEncoding], + (__bridge id)kSecValueData: [NSData dataWithBytes:pwStr length:length] + }; + + status = SecItemAdd((__bridge CFDictionaryRef)keychainAttributes, NULL); + + } else { + NSLog(@"Error storing item in keychain. Status code: %d", (int)status); + } + + (*env)->ReleaseByteArrayElements(env, service, serviceStr, JNI_ABORT); + (*env)->ReleaseByteArrayElements(env, key, keyStr, JNI_ABORT); + (*env)->ReleaseByteArrayElements(env, password, pwStr, JNI_ABORT); + + return status; } JNIEXPORT jbyteArray JNICALL Java_org_cryptomator_macos_keychain_MacKeychain_00024Native_loadPassword(JNIEnv *env, jobject thisObj, jbyteArray service, jbyteArray key) { jbyte *serviceStr = (*env)->GetByteArrayElements(env, service, NULL); jbyte *keyStr = (*env)->GetByteArrayElements(env, key, NULL); - // Create a dictionary of search attributes to find the item in the keychain - NSDictionary *searchAttributes = @{ - (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, - (__bridge id)kSecAttrService: [NSString stringWithCString:(char *)serviceStr encoding:NSUTF8StringEncoding], - (__bridge id)kSecAttrAccount: [NSString stringWithCString:(char *)keyStr encoding:NSUTF8StringEncoding], - (__bridge id)kSecReturnAttributes: @YES, - (__bridge id)kSecReturnData: @YES, - (__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitOne - }; - - CFDictionaryRef result = NULL; - OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)searchAttributes, (CFTypeRef *)&result); + // Create a dictionary of search attributes to find the item in the keychain + NSDictionary *searchAttributes = @{ + (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, + (__bridge id)kSecAttrService: [NSString stringWithCString:(char *)serviceStr encoding:NSUTF8StringEncoding], + (__bridge id)kSecAttrAccount: [NSString stringWithCString:(char *)keyStr encoding:NSUTF8StringEncoding], + (__bridge id)kSecReturnAttributes: @YES, + (__bridge id)kSecReturnData: @YES, + (__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitOne + }; + + CFDictionaryRef result = NULL; + OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)searchAttributes, (CFTypeRef *)&result); - (*env)->ReleaseByteArrayElements(env, service, serviceStr, JNI_ABORT); - (*env)->ReleaseByteArrayElements(env, key, keyStr, JNI_ABORT); + (*env)->ReleaseByteArrayElements(env, service, serviceStr, JNI_ABORT); + (*env)->ReleaseByteArrayElements(env, key, keyStr, JNI_ABORT); - if (status == errSecSuccess && result != NULL) { - NSDictionary *attributes = (__bridge_transfer NSDictionary *)result; - NSData *passwordData = attributes[(__bridge id)kSecValueData]; + if (status == errSecSuccess && result != NULL) { + NSDictionary *attributes = (__bridge_transfer NSDictionary *)result; + NSData *passwordData = attributes[(__bridge id)kSecValueData]; - NSUInteger pwLen = [passwordData length]; - const void *pwBytes = [passwordData bytes]; + NSUInteger pwLen = [passwordData length]; + const void *pwBytes = [passwordData bytes]; - jbyteArray password = (*env)->NewByteArray(env, (int)pwLen); - (*env)->SetByteArrayRegion(env, password, 0, (int)pwLen, (jbyte *)pwBytes); + jbyteArray password = (*env)->NewByteArray(env, (int)pwLen); + (*env)->SetByteArrayRegion(env, password, 0, (int)pwLen, (jbyte *)pwBytes); - return password; + return password; - } else if (status != errSecItemNotFound) { - NSLog(@"Error retrieving item from keychain. Status code: %d", (int)status); - } + } else if (status != errSecItemNotFound) { + NSLog(@"Error retrieving item from keychain. Status code: %d", (int)status); + } - return NULL; // empty + return NULL; // empty } JNIEXPORT jint JNICALL Java_org_cryptomator_macos_keychain_MacKeychain_00024Native_deletePassword(JNIEnv *env, jobject thisObj, jbyteArray service, jbyteArray key) { - jbyte *serviceStr = (*env)->GetByteArrayElements(env, service, NULL); - jbyte *keyStr = (*env)->GetByteArrayElements(env, key, NULL); + jbyte *serviceStr = (*env)->GetByteArrayElements(env, service, NULL); + jbyte *keyStr = (*env)->GetByteArrayElements(env, key, NULL); - // find existing: - NSDictionary *searchAttributes = @{ - (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, - (__bridge id)kSecAttrService: [NSString stringWithCString:(char *)serviceStr encoding:NSUTF8StringEncoding], - (__bridge id)kSecAttrAccount: [NSString stringWithCString:(char *)keyStr encoding:NSUTF8StringEncoding], - (__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitOne - }; - - CFDictionaryRef result = NULL; - OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)searchAttributes, (CFTypeRef *)&result); + // find existing: + NSDictionary *searchAttributes = @{ + (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, + (__bridge id)kSecAttrService: [NSString stringWithCString:(char *)serviceStr encoding:NSUTF8StringEncoding], + (__bridge id)kSecAttrAccount: [NSString stringWithCString:(char *)keyStr encoding:NSUTF8StringEncoding], + (__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitOne + }; + + CFDictionaryRef result = NULL; + OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)searchAttributes, (CFTypeRef *)&result); - if (status == errSecSuccess && result != NULL) { + if (status == errSecSuccess && result != NULL) { - status = SecItemDelete((__bridge CFDictionaryRef)searchAttributes); + status = SecItemDelete((__bridge CFDictionaryRef)searchAttributes); - } else if (status != errSecItemNotFound) { - NSLog(@"Error deleting item from keychain. Status code: %d", (int)status); - } + } else if (status != errSecItemNotFound) { + NSLog(@"Error deleting item from keychain. Status code: %d", (int)status); + } - (*env)->ReleaseByteArrayElements(env, service, serviceStr, JNI_ABORT); - (*env)->ReleaseByteArrayElements(env, key, keyStr, JNI_ABORT); + (*env)->ReleaseByteArrayElements(env, service, serviceStr, JNI_ABORT); + (*env)->ReleaseByteArrayElements(env, key, keyStr, JNI_ABORT); - return status; + return status; } From 85a1a502838abd4209a39478a9f84aba98ee614a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Jun 2024 09:10:04 +0000 Subject: [PATCH 6/7] Bump the maven-build-plugins group across 1 directory with 8 updates (#49) (cherry picked from commit b9d062fa1f226de05fd3772024805727db9c8d08) --- pom.xml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index a092906..34872fa 100644 --- a/pom.xml +++ b/pom.xml @@ -38,8 +38,8 @@ 5.11.0 - 9.1.0 - 1.6.13 + 9.2.0 + 1.6.14 @@ -116,7 +116,7 @@ org.apache.maven.plugins maven-enforcer-plugin - 3.4.1 + 3.5.0 check-preconditions @@ -145,7 +145,7 @@ org.codehaus.mojo exec-maven-plugin - 3.2.0 + 3.3.0 @@ -203,7 +203,7 @@ maven-source-plugin - 3.3.0 + 3.3.1 attach-sources @@ -215,7 +215,7 @@ maven-javadoc-plugin - 3.6.3 + 3.7.0 attach-javadocs @@ -307,7 +307,7 @@ maven-gpg-plugin - 3.2.2 + 3.2.4 sign-artifacts @@ -368,7 +368,7 @@ org.apache.maven.plugins maven-deploy-plugin - 3.1.1 + 3.1.2 From 0fcd4054aa384bc0a7a4cab5ae46917d96d0727a Mon Sep 17 00:00:00 2001 From: Tobias Hagemann Date: Mon, 1 Jul 2024 16:46:30 +0200 Subject: [PATCH 7/7] Minor refactorings --- ...omator_macos_keychain_MacKeychain_Native.m | 59 +++++++------------ 1 file changed, 20 insertions(+), 39 deletions(-) diff --git a/src/main/native/org_cryptomator_macos_keychain_MacKeychain_Native.m b/src/main/native/org_cryptomator_macos_keychain_MacKeychain_Native.m index 679b757..5309050 100644 --- a/src/main/native/org_cryptomator_macos_keychain_MacKeychain_Native.m +++ b/src/main/native/org_cryptomator_macos_keychain_MacKeychain_Native.m @@ -17,7 +17,7 @@ JNIEXPORT jint JNICALL Java_org_cryptomator_macos_keychain_MacKeychain_00024Nati jsize length = (*env)->GetArrayLength(env, password); // find existing: - NSDictionary *searchAttributes = @{ + NSDictionary *query = @{ (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, (__bridge id)kSecAttrService: [NSString stringWithCString:(char *)serviceStr encoding:NSUTF8StringEncoding], (__bridge id)kSecAttrAccount: [NSString stringWithCString:(char *)keyStr encoding:NSUTF8StringEncoding], @@ -25,29 +25,23 @@ JNIEXPORT jint JNICALL Java_org_cryptomator_macos_keychain_MacKeychain_00024Nati (__bridge id)kSecReturnData: @YES, (__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitOne }; - CFDictionaryRef result = NULL; - OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)searchAttributes, (CFTypeRef *)&result); - + OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&result); if (status == errSecSuccess && result != NULL) { // update existing: - NSDictionary *changeAttributes = @{ + NSDictionary *attributesToUpdate = @{ (__bridge id)kSecValueData: [NSData dataWithBytes:pwStr length:length] }; - - status = SecItemUpdate((__bridge CFDictionaryRef)searchAttributes, (__bridge CFDictionaryRef)changeAttributes); - + status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)attributesToUpdate); } else if (status == errSecItemNotFound) { // add new: - NSDictionary *keychainAttributes = @{ + NSDictionary *attributes = @{ (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, (__bridge id)kSecAttrService: [NSString stringWithCString:(char *)serviceStr encoding:NSUTF8StringEncoding], (__bridge id)kSecAttrAccount: [NSString stringWithCString:(char *)keyStr encoding:NSUTF8StringEncoding], (__bridge id)kSecValueData: [NSData dataWithBytes:pwStr length:length] }; - - status = SecItemAdd((__bridge CFDictionaryRef)keychainAttributes, NULL); - + status = SecItemAdd((__bridge CFDictionaryRef)attributes, NULL); } else { NSLog(@"Error storing item in keychain. Status code: %d", (int)status); } @@ -55,7 +49,6 @@ JNIEXPORT jint JNICALL Java_org_cryptomator_macos_keychain_MacKeychain_00024Nati (*env)->ReleaseByteArrayElements(env, service, serviceStr, JNI_ABORT); (*env)->ReleaseByteArrayElements(env, key, keyStr, JNI_ABORT); (*env)->ReleaseByteArrayElements(env, password, pwStr, JNI_ABORT); - return status; } @@ -63,8 +56,8 @@ JNIEXPORT jbyteArray JNICALL Java_org_cryptomator_macos_keychain_MacKeychain_000 jbyte *serviceStr = (*env)->GetByteArrayElements(env, service, NULL); jbyte *keyStr = (*env)->GetByteArrayElements(env, key, NULL); - // Create a dictionary of search attributes to find the item in the keychain - NSDictionary *searchAttributes = @{ + // find existing: + NSDictionary *query = @{ (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, (__bridge id)kSecAttrService: [NSString stringWithCString:(char *)serviceStr encoding:NSUTF8StringEncoding], (__bridge id)kSecAttrAccount: [NSString stringWithCString:(char *)keyStr encoding:NSUTF8StringEncoding], @@ -72,30 +65,22 @@ JNIEXPORT jbyteArray JNICALL Java_org_cryptomator_macos_keychain_MacKeychain_000 (__bridge id)kSecReturnData: @YES, (__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitOne }; - CFDictionaryRef result = NULL; - OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)searchAttributes, (CFTypeRef *)&result); - - (*env)->ReleaseByteArrayElements(env, service, serviceStr, JNI_ABORT); - (*env)->ReleaseByteArrayElements(env, key, keyStr, JNI_ABORT); - + OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&result); + jbyteArray password = NULL; if (status == errSecSuccess && result != NULL) { + // retrieve password: NSDictionary *attributes = (__bridge_transfer NSDictionary *)result; NSData *passwordData = attributes[(__bridge id)kSecValueData]; - - NSUInteger pwLen = [passwordData length]; - const void *pwBytes = [passwordData bytes]; - - jbyteArray password = (*env)->NewByteArray(env, (int)pwLen); - (*env)->SetByteArrayRegion(env, password, 0, (int)pwLen, (jbyte *)pwBytes); - - return password; - + password = (*env)->NewByteArray(env, (int)passwordData.length); + (*env)->SetByteArrayRegion(env, password, 0, (int)passwordData.length, (jbyte *)passwordData.bytes); } else if (status != errSecItemNotFound) { NSLog(@"Error retrieving item from keychain. Status code: %d", (int)status); } - return NULL; // empty + (*env)->ReleaseByteArrayElements(env, service, serviceStr, JNI_ABORT); + (*env)->ReleaseByteArrayElements(env, key, keyStr, JNI_ABORT); + return password; } JNIEXPORT jint JNICALL Java_org_cryptomator_macos_keychain_MacKeychain_00024Native_deletePassword(JNIEnv *env, jobject thisObj, jbyteArray service, jbyteArray key) { @@ -103,26 +88,22 @@ JNIEXPORT jint JNICALL Java_org_cryptomator_macos_keychain_MacKeychain_00024Nati jbyte *keyStr = (*env)->GetByteArrayElements(env, key, NULL); // find existing: - NSDictionary *searchAttributes = @{ + NSDictionary *query = @{ (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, (__bridge id)kSecAttrService: [NSString stringWithCString:(char *)serviceStr encoding:NSUTF8StringEncoding], (__bridge id)kSecAttrAccount: [NSString stringWithCString:(char *)keyStr encoding:NSUTF8StringEncoding], (__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitOne }; - CFDictionaryRef result = NULL; - OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)searchAttributes, (CFTypeRef *)&result); - + OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&result); if (status == errSecSuccess && result != NULL) { - - status = SecItemDelete((__bridge CFDictionaryRef)searchAttributes); - + // delete: + status = SecItemDelete((__bridge CFDictionaryRef)query); } else if (status != errSecItemNotFound) { NSLog(@"Error deleting item from keychain. Status code: %d", (int)status); } (*env)->ReleaseByteArrayElements(env, service, serviceStr, JNI_ABORT); (*env)->ReleaseByteArrayElements(env, key, keyStr, JNI_ABORT); - return status; }