Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m
41119 views
1
/*
2
* Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
#import "apple_security_KeychainStore.h"
27
#import "jni_util.h"
28
#import <Security/Security.h>
29
#import <Security/SecImportExport.h>
30
#import <CoreServices/CoreServices.h> // (for require() macros)
31
#import <Cocoa/Cocoa.h>
32
33
static jstring getLabelFromItem(JNIEnv *env, SecKeychainItemRef inItem)
34
{
35
OSStatus status;
36
jstring returnValue = NULL;
37
char *attribCString = NULL;
38
39
SecKeychainAttribute itemAttrs[] = { { kSecLabelItemAttr, 0, NULL } };
40
SecKeychainAttributeList attrList = { sizeof(itemAttrs) / sizeof(itemAttrs[0]), itemAttrs };
41
42
status = SecKeychainItemCopyContent(inItem, NULL, &attrList, NULL, NULL);
43
44
if(status) {
45
cssmPerror("getLabelFromItem: SecKeychainItemCopyContent", status);
46
goto errOut;
47
}
48
49
attribCString = malloc(itemAttrs[0].length + 1);
50
if (attribCString == NULL) {
51
JNU_ThrowOutOfMemoryError(env, "native heap");
52
goto errOut;
53
}
54
55
strncpy(attribCString, itemAttrs[0].data, itemAttrs[0].length);
56
attribCString[itemAttrs[0].length] = '\0';
57
returnValue = (*env)->NewStringUTF(env, attribCString);
58
59
errOut:
60
SecKeychainItemFreeContent(&attrList, NULL);
61
if (attribCString) free(attribCString);
62
return returnValue;
63
}
64
65
static jlong getModDateFromItem(JNIEnv *env, SecKeychainItemRef inItem)
66
{
67
OSStatus status;
68
SecKeychainAttribute itemAttrs[] = { { kSecModDateItemAttr, 0, NULL } };
69
SecKeychainAttributeList attrList = { sizeof(itemAttrs) / sizeof(itemAttrs[0]), itemAttrs };
70
jlong returnValue = 0;
71
72
status = SecKeychainItemCopyContent(inItem, NULL, &attrList, NULL, NULL);
73
74
if(status) {
75
// This is almost always missing, so don't dump an error.
76
// cssmPerror("getModDateFromItem: SecKeychainItemCopyContent", status);
77
goto errOut;
78
}
79
80
memcpy(&returnValue, itemAttrs[0].data, itemAttrs[0].length);
81
82
errOut:
83
SecKeychainItemFreeContent(&attrList, NULL);
84
return returnValue;
85
}
86
87
static void setLabelForItem(NSString *inLabel, SecKeychainItemRef inItem)
88
{
89
OSStatus status;
90
const char *labelCString = [inLabel UTF8String];
91
92
// Set up attribute vector (each attribute consists of {tag, length, pointer}):
93
SecKeychainAttribute attrs[] = {
94
{ kSecLabelItemAttr, strlen(labelCString), (void *)labelCString }
95
};
96
97
const SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs };
98
99
// Not changing data here, just attributes.
100
status = SecKeychainItemModifyContent(inItem, &attributes, 0, NULL);
101
102
if(status) {
103
cssmPerror("setLabelForItem: SecKeychainItemModifyContent", status);
104
}
105
}
106
107
/*
108
* Given a SecIdentityRef, do our best to construct a complete, ordered, and
109
* verified cert chain, returning the result in a CFArrayRef. The result is
110
* can be passed back to Java as a chain for a private key.
111
*/
112
static OSStatus completeCertChain(
113
SecIdentityRef identity,
114
SecCertificateRef trustedAnchor, // optional additional trusted anchor
115
bool includeRoot, // include the root in outArray
116
CFArrayRef *outArray) // created and RETURNED
117
{
118
SecTrustRef secTrust = NULL;
119
SecPolicyRef policy = NULL;
120
SecPolicySearchRef policySearch = NULL;
121
SecTrustResultType secTrustResult;
122
CSSM_TP_APPLE_EVIDENCE_INFO *dummyEv; // not used
123
CFArrayRef certChain = NULL; // constructed chain, CERTS ONLY
124
CFMutableArrayRef subjCerts; // passed to SecTrust
125
CFMutableArrayRef certArray; // returned array starting with
126
// identity
127
CFIndex numResCerts;
128
CFIndex dex;
129
OSStatus ortn;
130
SecCertificateRef certRef;
131
132
/* First element in out array is the SecIdentity */
133
certArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
134
CFArrayAppendValue(certArray, identity);
135
136
/* the single element in certs-to-be-evaluated comes from the identity */
137
ortn = SecIdentityCopyCertificate(identity, &certRef);
138
if(ortn) {
139
/* should never happen */
140
cssmPerror("SecIdentityCopyCertificate", ortn);
141
return ortn;
142
}
143
144
/*
145
* Now use SecTrust to get a complete cert chain, using all of the
146
* user's keychains to look for intermediate certs.
147
* NOTE this does NOT handle root certs which are not in the system
148
* root cert DB.
149
*/
150
subjCerts = CFArrayCreateMutable(NULL, 1, &kCFTypeArrayCallBacks);
151
CFArraySetValueAtIndex(subjCerts, 0, certRef);
152
153
/* the array owns the subject cert ref now */
154
CFRelease(certRef);
155
156
/* Get a SecPolicyRef for generic X509 cert chain verification */
157
ortn = SecPolicySearchCreate(CSSM_CERT_X_509v3,
158
&CSSMOID_APPLE_X509_BASIC,
159
NULL, // value
160
&policySearch);
161
if(ortn) {
162
/* should never happen */
163
cssmPerror("SecPolicySearchCreate", ortn);
164
goto errOut;
165
}
166
ortn = SecPolicySearchCopyNext(policySearch, &policy);
167
if(ortn) {
168
/* should never happen */
169
cssmPerror("SecPolicySearchCopyNext", ortn);
170
goto errOut;
171
}
172
173
/* build a SecTrustRef for specified policy and certs */
174
ortn = SecTrustCreateWithCertificates(subjCerts,
175
policy, &secTrust);
176
if(ortn) {
177
cssmPerror("SecTrustCreateWithCertificates", ortn);
178
goto errOut;
179
}
180
181
if(trustedAnchor) {
182
/*
183
* Tell SecTrust to trust this one in addition to the current
184
* trusted system-wide anchors.
185
*/
186
CFMutableArrayRef newAnchors;
187
CFArrayRef currAnchors;
188
189
ortn = SecTrustCopyAnchorCertificates(&currAnchors);
190
if(ortn) {
191
/* should never happen */
192
cssmPerror("SecTrustCopyAnchorCertificates", ortn);
193
goto errOut;
194
}
195
newAnchors = CFArrayCreateMutableCopy(NULL,
196
CFArrayGetCount(currAnchors) + 1,
197
currAnchors);
198
CFRelease(currAnchors);
199
CFArrayAppendValue(newAnchors, trustedAnchor);
200
ortn = SecTrustSetAnchorCertificates(secTrust, newAnchors);
201
CFRelease(newAnchors);
202
if(ortn) {
203
cssmPerror("SecTrustSetAnchorCertificates", ortn);
204
goto errOut;
205
}
206
}
207
208
/* evaluate: GO */
209
ortn = SecTrustEvaluate(secTrust, &secTrustResult);
210
if(ortn) {
211
cssmPerror("SecTrustEvaluate", ortn);
212
goto errOut;
213
}
214
switch(secTrustResult) {
215
case kSecTrustResultUnspecified:
216
/* cert chain valid, no special UserTrust assignments; drop thru */
217
case kSecTrustResultProceed:
218
/* cert chain valid AND user explicitly trusts this */
219
break;
220
default:
221
/*
222
* Cert chain construction failed.
223
* Just go with the single subject cert we were given; maybe the
224
* peer can complete the chain.
225
*/
226
ortn = noErr;
227
goto errOut;
228
}
229
230
/* get resulting constructed cert chain */
231
ortn = SecTrustGetResult(secTrust, &secTrustResult, &certChain, &dummyEv);
232
if(ortn) {
233
cssmPerror("SecTrustEvaluate", ortn);
234
goto errOut;
235
}
236
237
/*
238
* Copy certs from constructed chain to our result array, skipping
239
* the leaf (which is already there, as a SecIdentityRef) and possibly
240
* a root.
241
*/
242
numResCerts = CFArrayGetCount(certChain);
243
if(numResCerts < 1) {
244
/*
245
* Can't happen: If chain doesn't verify to a root, we'd
246
* have bailed after SecTrustEvaluate().
247
*/
248
ortn = noErr;
249
goto errOut;
250
}
251
if(!includeRoot) {
252
/* skip the last (root) cert) */
253
numResCerts--;
254
}
255
for(dex=1; dex<numResCerts; dex++) {
256
certRef = (SecCertificateRef)CFArrayGetValueAtIndex(certChain, dex);
257
CFArrayAppendValue(certArray, certRef);
258
}
259
errOut:
260
/* clean up */
261
if(secTrust) {
262
CFRelease(secTrust);
263
}
264
if(subjCerts) {
265
CFRelease(subjCerts);
266
}
267
if(policy) {
268
CFRelease(policy);
269
}
270
if(policySearch) {
271
CFRelease(policySearch);
272
}
273
*outArray = certArray;
274
return ortn;
275
}
276
277
static void addIdentitiesToKeystore(JNIEnv *env, jobject keyStore)
278
{
279
// Search the user keychain list for all identities. Identities are a certificate/private key association that
280
// can be chosen for a purpose such as signing or an SSL connection.
281
SecIdentitySearchRef identitySearch = NULL;
282
// Pass 0 if you want all identities returned by this search
283
OSStatus err = SecIdentitySearchCreate(NULL, 0, &identitySearch);
284
SecIdentityRef theIdentity = NULL;
285
OSErr searchResult = noErr;
286
287
jclass jc_KeychainStore = (*env)->FindClass(env, "apple/security/KeychainStore");
288
CHECK_NULL(jc_KeychainStore);
289
jmethodID jm_createKeyEntry = (*env)->GetMethodID(env, jc_KeychainStore, "createKeyEntry", "(Ljava/lang/String;JJ[J[[B)V");
290
CHECK_NULL(jm_createKeyEntry);
291
do {
292
searchResult = SecIdentitySearchCopyNext(identitySearch, &theIdentity);
293
294
if (searchResult == noErr) {
295
// Get the cert from the identity, then generate a chain.
296
SecCertificateRef certificate;
297
SecIdentityCopyCertificate(theIdentity, &certificate);
298
CFArrayRef certChain = NULL;
299
300
// *** Should do something with this error...
301
err = completeCertChain(theIdentity, NULL, TRUE, &certChain);
302
303
CFIndex i, certCount = CFArrayGetCount(certChain);
304
305
// Make a java array of certificate data from the chain.
306
jclass byteArrayClass = (*env)->FindClass(env, "[B");
307
if (byteArrayClass == NULL) {
308
goto errOut;
309
}
310
jobjectArray javaCertArray = (*env)->NewObjectArray(env, certCount, byteArrayClass, NULL);
311
// Cleanup first then check for a NULL return code
312
(*env)->DeleteLocalRef(env, byteArrayClass);
313
if (javaCertArray == NULL) {
314
goto errOut;
315
}
316
317
// And, make an array of the certificate refs.
318
jlongArray certRefArray = (*env)->NewLongArray(env, certCount);
319
if (certRefArray == NULL) {
320
goto errOut;
321
}
322
323
SecCertificateRef currCertRef = NULL;
324
325
for (i = 0; i < certCount; i++) {
326
CSSM_DATA currCertData;
327
328
if (i == 0)
329
currCertRef = certificate;
330
else
331
currCertRef = (SecCertificateRef)CFArrayGetValueAtIndex(certChain, i);
332
333
bzero(&currCertData, sizeof(CSSM_DATA));
334
err = SecCertificateGetData(currCertRef, &currCertData);
335
jbyteArray encodedCertData = (*env)->NewByteArray(env, currCertData.Length);
336
if (encodedCertData == NULL) {
337
goto errOut;
338
}
339
(*env)->SetByteArrayRegion(env, encodedCertData, 0, currCertData.Length, (jbyte *)currCertData.Data);
340
(*env)->SetObjectArrayElement(env, javaCertArray, i, encodedCertData);
341
jlong certRefElement = ptr_to_jlong(currCertRef);
342
(*env)->SetLongArrayRegion(env, certRefArray, i, 1, &certRefElement);
343
}
344
345
// Get the private key. When needed we'll export the data from it later.
346
SecKeyRef privateKeyRef;
347
err = SecIdentityCopyPrivateKey(theIdentity, &privateKeyRef);
348
349
// Find the label. It's a 'blob', but we interpret as characters.
350
jstring alias = getLabelFromItem(env, (SecKeychainItemRef)certificate);
351
if (alias == NULL) {
352
goto errOut;
353
}
354
355
// Find the creation date.
356
jlong creationDate = getModDateFromItem(env, (SecKeychainItemRef)certificate);
357
358
// Call back to the Java object to create Java objects corresponding to this security object.
359
jlong nativeKeyRef = ptr_to_jlong(privateKeyRef);
360
(*env)->CallVoidMethod(env, keyStore, jm_createKeyEntry, alias, creationDate, nativeKeyRef, certRefArray, javaCertArray);
361
JNU_CHECK_EXCEPTION(env);
362
}
363
} while (searchResult == noErr);
364
365
errOut:
366
if (identitySearch != NULL) {
367
CFRelease(identitySearch);
368
}
369
}
370
371
static void addCertificatesToKeystore(JNIEnv *env, jobject keyStore)
372
{
373
// Search the user keychain list for all X509 certificates.
374
SecKeychainSearchRef keychainItemSearch = NULL;
375
OSStatus err = SecKeychainSearchCreateFromAttributes(NULL, kSecCertificateItemClass, NULL, &keychainItemSearch);
376
SecKeychainItemRef theItem = NULL;
377
OSErr searchResult = noErr;
378
379
jclass jc_KeychainStore = (*env)->FindClass(env, "apple/security/KeychainStore");
380
CHECK_NULL(jc_KeychainStore);
381
jmethodID jm_createTrustedCertEntry = (*env)->GetMethodID(
382
env, jc_KeychainStore, "createTrustedCertEntry", "(Ljava/lang/String;JJ[B)V");
383
CHECK_NULL(jm_createTrustedCertEntry);
384
do {
385
searchResult = SecKeychainSearchCopyNext(keychainItemSearch, &theItem);
386
387
if (searchResult == noErr) {
388
// Make a byte array with the DER-encoded contents of the certificate.
389
SecCertificateRef certRef = (SecCertificateRef)theItem;
390
CSSM_DATA currCertificate;
391
err = SecCertificateGetData(certRef, &currCertificate);
392
jbyteArray certData = (*env)->NewByteArray(env, currCertificate.Length);
393
if (certData == NULL) {
394
goto errOut;
395
}
396
(*env)->SetByteArrayRegion(env, certData, 0, currCertificate.Length, (jbyte *)currCertificate.Data);
397
398
// Find the label. It's a 'blob', but we interpret as characters.
399
jstring alias = getLabelFromItem(env, theItem);
400
if (alias == NULL) {
401
goto errOut;
402
}
403
404
// Find the creation date.
405
jlong creationDate = getModDateFromItem(env, theItem);
406
407
// Call back to the Java object to create Java objects corresponding to this security object.
408
jlong nativeRef = ptr_to_jlong(certRef);
409
(*env)->CallVoidMethod(env, keyStore, jm_createTrustedCertEntry, alias, nativeRef, creationDate, certData);
410
JNU_CHECK_EXCEPTION(env);
411
}
412
} while (searchResult == noErr);
413
414
errOut:
415
if (keychainItemSearch != NULL) {
416
CFRelease(keychainItemSearch);
417
}
418
}
419
420
/*
421
* Class: apple_security_KeychainStore
422
* Method: _getEncodedKeyData
423
* Signature: (J)[B
424
*/
425
JNIEXPORT jbyteArray JNICALL Java_apple_security_KeychainStore__1getEncodedKeyData
426
(JNIEnv *env, jobject this, jlong keyRefLong, jcharArray passwordObj)
427
{
428
SecKeyRef keyRef = (SecKeyRef)jlong_to_ptr(keyRefLong);
429
SecKeyImportExportParameters paramBlock;
430
OSStatus err = noErr;
431
CFDataRef exportedData = NULL;
432
jbyteArray returnValue = NULL;
433
CFStringRef passwordStrRef = NULL;
434
435
jsize passwordLen = 0;
436
jchar *passwordChars = NULL;
437
438
if (passwordObj) {
439
passwordLen = (*env)->GetArrayLength(env, passwordObj);
440
441
if (passwordLen > 0) {
442
passwordChars = (*env)->GetCharArrayElements(env, passwordObj, NULL);
443
if (passwordChars == NULL) {
444
goto errOut;
445
}
446
447
passwordStrRef = CFStringCreateWithCharactersNoCopy(NULL, passwordChars, passwordLen, kCFAllocatorNull);
448
if (passwordStrRef == NULL) {
449
goto errOut;
450
}
451
}
452
}
453
454
paramBlock.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
455
// Note that setting the flags field **requires** you to pass in a password of some kind. The keychain will not prompt you.
456
paramBlock.flags = 0;
457
paramBlock.passphrase = passwordStrRef;
458
paramBlock.alertTitle = NULL;
459
paramBlock.alertPrompt = NULL;
460
paramBlock.accessRef = NULL;
461
paramBlock.keyUsage = CSSM_KEYUSE_ANY;
462
paramBlock.keyAttributes = CSSM_KEYATTR_RETURN_DEFAULT;
463
464
err = SecKeychainItemExport(keyRef, kSecFormatPKCS12, 0, &paramBlock, &exportedData);
465
466
if (err == noErr) {
467
CFIndex size = CFDataGetLength(exportedData);
468
returnValue = (*env)->NewByteArray(env, size);
469
if (returnValue == NULL) {
470
goto errOut;
471
}
472
(*env)->SetByteArrayRegion(env, returnValue, 0, size, (jbyte *)CFDataGetBytePtr(exportedData));
473
}
474
475
errOut:
476
if (exportedData) CFRelease(exportedData);
477
if (passwordStrRef) CFRelease(passwordStrRef);
478
if (passwordChars) {
479
// clear the password and release
480
memset(passwordChars, 0, passwordLen);
481
(*env)->ReleaseCharArrayElements(env, passwordObj, passwordChars,
482
JNI_ABORT);
483
}
484
return returnValue;
485
}
486
487
488
/*
489
* Class: apple_security_KeychainStore
490
* Method: _scanKeychain
491
* Signature: ()V
492
*/
493
JNIEXPORT void JNICALL Java_apple_security_KeychainStore__1scanKeychain
494
(JNIEnv *env, jobject this)
495
{
496
// Look for 'identities' -- private key and certificate chain pairs -- and add those.
497
// Search for these first, because a certificate that's found here as part of an identity will show up
498
// again later as a certificate.
499
addIdentitiesToKeystore(env, this);
500
501
JNU_CHECK_EXCEPTION(env);
502
503
// Scan current keychain for trusted certificates.
504
addCertificatesToKeystore(env, this);
505
506
}
507
508
NSString* JavaStringToNSString(JNIEnv *env, jstring jstr) {
509
if (jstr == NULL) {
510
return NULL;
511
}
512
jsize len = (*env)->GetStringLength(env, jstr);
513
const jchar *chars = (*env)->GetStringChars(env, jstr, NULL);
514
if (chars == NULL) {
515
return NULL;
516
}
517
NSString *result = [NSString stringWithCharacters:(UniChar *)chars length:len];
518
(*env)->ReleaseStringChars(env, jstr, chars);
519
return result;
520
}
521
522
/*
523
* Class: apple_security_KeychainStore
524
* Method: _addItemToKeychain
525
* Signature: (Ljava/lang/String;[B)I
526
*/
527
JNIEXPORT jlong JNICALL Java_apple_security_KeychainStore__1addItemToKeychain
528
(JNIEnv *env, jobject this, jstring alias, jboolean isCertificate, jbyteArray rawDataObj, jcharArray passwordObj)
529
{
530
OSStatus err;
531
jlong returnValue = 0;
532
533
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; \
534
@try {
535
jsize dataSize = (*env)->GetArrayLength(env, rawDataObj);
536
jbyte *rawData = (*env)->GetByteArrayElements(env, rawDataObj, NULL);
537
if (rawData == NULL) {
538
goto errOut;
539
}
540
541
CFDataRef cfDataToImport = CFDataCreate(kCFAllocatorDefault, (UInt8 *)rawData, dataSize);
542
CFArrayRef createdItems = NULL;
543
544
SecKeychainRef defaultKeychain = NULL;
545
SecKeychainCopyDefault(&defaultKeychain);
546
547
SecExternalFormat dataFormat = (isCertificate == JNI_TRUE ? kSecFormatX509Cert : kSecFormatWrappedPKCS8);
548
549
// Convert the password obj into a CFStringRef that the keychain importer can use for encryption.
550
SecKeyImportExportParameters paramBlock;
551
CFStringRef passwordStrRef = NULL;
552
553
jsize passwordLen = 0;
554
jchar *passwordChars = NULL;
555
556
if (passwordObj) {
557
passwordLen = (*env)->GetArrayLength(env, passwordObj);
558
559
if (passwordLen > 0) {
560
passwordChars = (*env)->GetCharArrayElements(env, passwordObj, NULL);
561
if (passwordChars == NULL) {
562
goto errOut;
563
}
564
565
passwordStrRef = CFStringCreateWithCharactersNoCopy(NULL, passwordChars, passwordLen, kCFAllocatorNull);
566
if (passwordStrRef == NULL) {
567
goto errOut;
568
}
569
}
570
}
571
572
paramBlock.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
573
// Note that setting the flags field **requires** you to pass in a password of some kind. The keychain will not prompt you.
574
paramBlock.flags = 0;
575
paramBlock.passphrase = passwordStrRef;
576
paramBlock.alertTitle = NULL;
577
paramBlock.alertPrompt = NULL;
578
paramBlock.accessRef = NULL;
579
paramBlock.keyUsage = CSSM_KEYUSE_ANY;
580
paramBlock.keyAttributes = CSSM_KEYATTR_RETURN_DEFAULT;
581
582
err = SecKeychainItemImport(cfDataToImport, NULL, &dataFormat, NULL,
583
0, &paramBlock, defaultKeychain, &createdItems);
584
if (cfDataToImport != NULL) {
585
CFRelease(cfDataToImport);
586
}
587
588
if (err == noErr) {
589
SecKeychainItemRef anItem = (SecKeychainItemRef)CFArrayGetValueAtIndex(createdItems, 0);
590
591
// Don't bother labeling keys. They become part of an identity, and are not an accessible part of the keychain.
592
if (CFGetTypeID(anItem) == SecCertificateGetTypeID()) {
593
setLabelForItem(JavaStringToNSString(env, alias), anItem);
594
}
595
596
// Retain the item, since it will be released once when the array holding it gets released.
597
CFRetain(anItem);
598
returnValue = ptr_to_jlong(anItem);
599
} else {
600
cssmPerror("_addItemToKeychain: SecKeychainItemImport", err);
601
}
602
603
if (createdItems != NULL) {
604
CFRelease(createdItems);
605
}
606
607
errOut:
608
if (rawData) {
609
(*env)->ReleaseByteArrayElements(env, rawDataObj, rawData, JNI_ABORT);
610
}
611
612
if (passwordStrRef) CFRelease(passwordStrRef);
613
if (passwordChars) {
614
// clear the password and release
615
memset(passwordChars, 0, passwordLen);
616
(*env)->ReleaseCharArrayElements(env, passwordObj, passwordChars,
617
JNI_ABORT);
618
}
619
} @catch (NSException *e) {
620
NSLog(@"%@", [e callStackSymbols]);
621
} @finally {
622
[pool drain];
623
}
624
return returnValue;
625
}
626
627
/*
628
* Class: apple_security_KeychainStore
629
* Method: _removeItemFromKeychain
630
* Signature: (J)I
631
*/
632
JNIEXPORT jint JNICALL Java_apple_security_KeychainStore__1removeItemFromKeychain
633
(JNIEnv *env, jobject this, jlong keychainItem)
634
{
635
SecKeychainItemRef itemToRemove = jlong_to_ptr(keychainItem);
636
return SecKeychainItemDelete(itemToRemove);
637
}
638
639
/*
640
* Class: apple_security_KeychainStore
641
* Method: _releaseKeychainItemRef
642
* Signature: (J)V
643
*/
644
JNIEXPORT void JNICALL Java_apple_security_KeychainStore__1releaseKeychainItemRef
645
(JNIEnv *env, jobject this, jlong keychainItem)
646
{
647
SecKeychainItemRef itemToFree = jlong_to_ptr(keychainItem);
648
CFRelease(itemToFree);
649
}
650
651