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 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..5309050 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,103 @@ // #import "org_cryptomator_macos_keychain_MacKeychain_Native.h" +#import #import 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); + jsize length = (*env)->GetArrayLength(env, password); // 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) { + 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)kSecReturnAttributes: @YES, + (__bridge id)kSecReturnData: @YES, + (__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitOne + }; + CFDictionaryRef result = NULL; + OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&result); + if (status == errSecSuccess && result != NULL) { // update existing: - status = SecKeychainItemModifyAttributesAndData( - itemRef, // the item reference - NULL, // no change to attributes - pwLen, // length of password - pwStr // pointer to password data - ); + NSDictionary *attributesToUpdate = @{ + (__bridge id)kSecValueData: [NSData dataWithBytes:pwStr length:length] + }; + status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)attributesToUpdate); } 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 - ); + 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)attributes, 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); - if (itemRef) { - CFRelease(itemRef); - } 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; + // 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], + (__bridge id)kSecReturnAttributes: @YES, + (__bridge id)kSecReturnData: @YES, + (__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitOne + }; + CFDictionaryRef result = NULL; + 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]; + 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); } + (*env)->ReleaseByteArrayElements(env, service, serviceStr, JNI_ABORT); (*env)->ReleaseByteArrayElements(env, key, keyStr, JNI_ABORT); - if (pwStr) { - SecKeychainItemFreeContent(NULL, pwStr); - } - return result; + return password; } 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 - ); + // 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], + (__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitOne + }; + CFDictionaryRef result = NULL; + OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&result); + if (status == errSecSuccess && result != NULL) { + // 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); - if (itemRef) { - CFRelease(itemRef); - } return status; }