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, ¶mBlock, &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, ¶mBlock, 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 }