Skip to content

Commit e763b3a

Browse files
committed
Guard NSStrings
Fixes cryptomator/cryptomator#3932
1 parent 0dae879 commit e763b3a

File tree

1 file changed

+88
-62
lines changed

1 file changed

+88
-62
lines changed

src/main/native/org_cryptomator_macos_keychain_MacKeychain_Native.m

Lines changed: 88 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -26,41 +26,50 @@ JNIEXPORT jint JNICALL Java_org_cryptomator_macos_keychain_MacKeychain_00024Nati
2626
jbyte *pwStr = (*env)->GetByteArrayElements(env, password, NULL);
2727
jsize length = (*env)->GetArrayLength(env, password);
2828

29-
// find existing:
30-
NSMutableDictionary *query = [@{
31-
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
32-
(__bridge id)kSecAttrService: [NSString stringWithCString:(char *)serviceStr encoding:NSUTF8StringEncoding],
33-
(__bridge id)kSecAttrAccount: [NSString stringWithCString:(char *)keyStr encoding:NSUTF8StringEncoding],
34-
(__bridge id)kSecReturnAttributes: @YES,
35-
(__bridge id)kSecReturnData: @YES,
36-
(__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitOne
37-
} mutableCopy];
38-
if (requireOsAuthentication) {
39-
LAContext *context = getSharedLAContext();
40-
query[(__bridge id)kSecUseAuthenticationContext] = context;
41-
}
42-
CFDictionaryRef result = NULL;
43-
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&result);
44-
if (status == errSecSuccess && result != NULL) {
45-
// update existing:
46-
NSDictionary *attributesToUpdate = @{
47-
(__bridge id)kSecValueData: [NSData dataWithBytes:pwStr length:length]
48-
};
49-
status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)attributesToUpdate);
50-
} else if (status == errSecItemNotFound) {
51-
// add new:
52-
NSMutableDictionary *attributes = [@{
29+
NSString *serviceString = [NSString stringWithCString:(char *)serviceStr encoding:NSUTF8StringEncoding];
30+
NSString *keyString = [NSString stringWithCString:(char *)keyStr encoding:NSUTF8StringEncoding];
31+
32+
OSStatus status = errSecParam;
33+
34+
if (serviceString && keyString) { // guard both NSStrings not to be NIL
35+
// find existing:
36+
NSMutableDictionary *query = [@{
5337
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
54-
(__bridge id)kSecAttrService: [NSString stringWithCString:(char *)serviceStr encoding:NSUTF8StringEncoding],
55-
(__bridge id)kSecAttrAccount: [NSString stringWithCString:(char *)keyStr encoding:NSUTF8StringEncoding],
56-
(__bridge id)kSecValueData: [NSData dataWithBytes:pwStr length:length]
38+
(__bridge id)kSecAttrService: serviceString,
39+
(__bridge id)kSecAttrAccount: keyString,
40+
(__bridge id)kSecReturnAttributes: @YES,
41+
(__bridge id)kSecReturnData: @YES,
42+
(__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitOne
5743
} mutableCopy];
5844
if (requireOsAuthentication) {
59-
attributes[(__bridge id)kSecAttrAccessControl] = (__bridge_transfer id)SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenUnlocked, kSecAccessControlUserPresence, NULL);
45+
LAContext *context = getSharedLAContext();
46+
query[(__bridge id)kSecUseAuthenticationContext] = context;
47+
}
48+
CFDictionaryRef result = NULL;
49+
status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&result);
50+
if (status == errSecSuccess && result != NULL) {
51+
// update existing:
52+
NSDictionary *attributesToUpdate = @{
53+
(__bridge id)kSecValueData: [NSData dataWithBytes:pwStr length:length]
54+
};
55+
status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)attributesToUpdate);
56+
} else if (status == errSecItemNotFound) {
57+
// add new:
58+
NSMutableDictionary *attributes = [@{
59+
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
60+
(__bridge id)kSecAttrService: serviceString,
61+
(__bridge id)kSecAttrAccount: keyString,
62+
(__bridge id)kSecValueData: [NSData dataWithBytes:pwStr length:length]
63+
} mutableCopy];
64+
if (requireOsAuthentication) {
65+
attributes[(__bridge id)kSecAttrAccessControl] = (__bridge_transfer id)SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenUnlocked, kSecAccessControlUserPresence, NULL);
66+
}
67+
status = SecItemAdd((__bridge CFDictionaryRef)attributes, NULL);
68+
} else {
69+
NSLog(@"Error storing item in keychain. Status code: %d", (int)status);
6070
}
61-
status = SecItemAdd((__bridge CFDictionaryRef)attributes, NULL);
6271
} else {
63-
NSLog(@"Error storing item in keychain. Status code: %d", (int)status);
72+
NSLog(@"Invalid UTF-8 input: service or key string conversion failed");
6473
}
6574

6675
(*env)->ReleaseByteArrayElements(env, service, serviceStr, JNI_ABORT);
@@ -73,28 +82,36 @@ JNIEXPORT jbyteArray JNICALL Java_org_cryptomator_macos_keychain_MacKeychain_000
7382
jbyte *serviceStr = (*env)->GetByteArrayElements(env, service, NULL);
7483
jbyte *keyStr = (*env)->GetByteArrayElements(env, key, NULL);
7584

76-
// find existing:
77-
LAContext *context = getSharedLAContext();
78-
NSDictionary *query = @{
79-
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
80-
(__bridge id)kSecAttrService: [NSString stringWithCString:(char *)serviceStr encoding:NSUTF8StringEncoding],
81-
(__bridge id)kSecAttrAccount: [NSString stringWithCString:(char *)keyStr encoding:NSUTF8StringEncoding],
82-
(__bridge id)kSecReturnAttributes: @YES,
83-
(__bridge id)kSecReturnData: @YES,
84-
(__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitOne,
85-
(__bridge id)kSecUseAuthenticationContext: context
86-
};
87-
CFDictionaryRef result = NULL;
88-
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&result);
85+
NSString *serviceString = [NSString stringWithCString:(char *)serviceStr encoding:NSUTF8StringEncoding];
86+
NSString *keyString = [NSString stringWithCString:(char *)keyStr encoding:NSUTF8StringEncoding];
87+
8988
jbyteArray password = NULL;
90-
if (status == errSecSuccess && result != NULL) {
91-
// retrieve password:
92-
NSDictionary *attributes = (__bridge_transfer NSDictionary *)result;
93-
NSData *passwordData = attributes[(__bridge id)kSecValueData];
94-
password = (*env)->NewByteArray(env, (int)passwordData.length);
95-
(*env)->SetByteArrayRegion(env, password, 0, (int)passwordData.length, (jbyte *)passwordData.bytes);
96-
} else if (status != errSecItemNotFound) {
97-
NSLog(@"Error retrieving item from keychain. Status code: %d", (int)status);
89+
90+
if (serviceString && keyString) { // guard both NSStrings not to be NIL
91+
// find existing:
92+
LAContext *context = getSharedLAContext();
93+
NSDictionary *query = @{
94+
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
95+
(__bridge id)kSecAttrService: serviceString,
96+
(__bridge id)kSecAttrAccount: keyString,
97+
(__bridge id)kSecReturnAttributes: @YES,
98+
(__bridge id)kSecReturnData: @YES,
99+
(__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitOne,
100+
(__bridge id)kSecUseAuthenticationContext: context
101+
};
102+
CFDictionaryRef result = NULL;
103+
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&result);
104+
if (status == errSecSuccess && result != NULL) {
105+
// retrieve password:
106+
NSDictionary *attributes = (__bridge_transfer NSDictionary *)result;
107+
NSData *passwordData = attributes[(__bridge id)kSecValueData];
108+
password = (*env)->NewByteArray(env, (int)passwordData.length);
109+
(*env)->SetByteArrayRegion(env, password, 0, (int)passwordData.length, (jbyte *)passwordData.bytes);
110+
} else if (status != errSecItemNotFound) {
111+
NSLog(@"Error retrieving item from keychain. Status code: %d", (int)status);
112+
}
113+
} else {
114+
NSLog(@"Invalid UTF-8 input: service or key string conversion failed");
98115
}
99116

100117
(*env)->ReleaseByteArrayElements(env, service, serviceStr, JNI_ABORT);
@@ -106,17 +123,26 @@ JNIEXPORT jint JNICALL Java_org_cryptomator_macos_keychain_MacKeychain_00024Nati
106123
jbyte *serviceStr = (*env)->GetByteArrayElements(env, service, NULL);
107124
jbyte *keyStr = (*env)->GetByteArrayElements(env, key, NULL);
108125

109-
// find existing:
110-
LAContext *context = getSharedLAContext();
111-
NSDictionary *query = @{
112-
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
113-
(__bridge id)kSecAttrService: [NSString stringWithCString:(char *)serviceStr encoding:NSUTF8StringEncoding],
114-
(__bridge id)kSecAttrAccount: [NSString stringWithCString:(char *)keyStr encoding:NSUTF8StringEncoding],
115-
(__bridge id)kSecUseAuthenticationContext: context
116-
};
117-
OSStatus status = SecItemDelete((__bridge CFDictionaryRef)query);
118-
if (status != errSecSuccess) {
119-
NSLog(@"Error deleting item from keychain. Status code: %d", (int)status);
126+
NSString *serviceString = [NSString stringWithCString:(char *)serviceStr encoding:NSUTF8StringEncoding];
127+
NSString *keyString = [NSString stringWithCString:(char *)keyStr encoding:NSUTF8StringEncoding];
128+
129+
OSStatus status = errSecParam;
130+
131+
if (serviceString && keyString) { // guard both NSStrings not to be NIL
132+
// find existing:
133+
LAContext *context = getSharedLAContext();
134+
NSDictionary *query = @{
135+
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
136+
(__bridge id)kSecAttrService: serviceString,
137+
(__bridge id)kSecAttrAccount: keyString,
138+
(__bridge id)kSecUseAuthenticationContext: context
139+
};
140+
status = SecItemDelete((__bridge CFDictionaryRef)query);
141+
if (status != errSecSuccess) {
142+
NSLog(@"Error deleting item from keychain. Status code: %d", (int)status);
143+
}
144+
} else {
145+
NSLog(@"Invalid UTF-8 input: service or key string conversion failed");
120146
}
121147

122148
(*env)->ReleaseByteArrayElements(env, service, serviceStr, JNI_ABORT);

0 commit comments

Comments
 (0)