Path: blob/master/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m
67760 views
/*1* Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#import "apple_security_KeychainStore.h"26#import "jni_util.h"27#import <Security/Security.h>28#import <Security/SecImportExport.h>29#import <CoreServices/CoreServices.h> // (for require() macros)30#import <Cocoa/Cocoa.h>3132static jstring getLabelFromItem(JNIEnv *env, SecKeychainItemRef inItem)33{34OSStatus status;35jstring returnValue = NULL;36char *attribCString = NULL;3738SecKeychainAttribute itemAttrs[] = { { kSecLabelItemAttr, 0, NULL } };39SecKeychainAttributeList attrList = { sizeof(itemAttrs) / sizeof(itemAttrs[0]), itemAttrs };4041status = SecKeychainItemCopyContent(inItem, NULL, &attrList, NULL, NULL);4243if(status) {44cssmPerror("getLabelFromItem: SecKeychainItemCopyContent", status);45goto errOut;46}4748attribCString = malloc(itemAttrs[0].length + 1);49if (attribCString == NULL) {50JNU_ThrowOutOfMemoryError(env, "native heap");51goto errOut;52}5354strncpy(attribCString, itemAttrs[0].data, itemAttrs[0].length);55attribCString[itemAttrs[0].length] = '\0';56returnValue = (*env)->NewStringUTF(env, attribCString);5758errOut:59SecKeychainItemFreeContent(&attrList, NULL);60if (attribCString) free(attribCString);61return returnValue;62}6364static jlong getModDateFromItem(JNIEnv *env, SecKeychainItemRef inItem)65{66OSStatus status;67SecKeychainAttribute itemAttrs[] = { { kSecModDateItemAttr, 0, NULL } };68SecKeychainAttributeList attrList = { sizeof(itemAttrs) / sizeof(itemAttrs[0]), itemAttrs };69jlong returnValue = 0;7071status = SecKeychainItemCopyContent(inItem, NULL, &attrList, NULL, NULL);7273if(status) {74// This is almost always missing, so don't dump an error.75// cssmPerror("getModDateFromItem: SecKeychainItemCopyContent", status);76goto errOut;77}7879memcpy(&returnValue, itemAttrs[0].data, itemAttrs[0].length);8081errOut:82SecKeychainItemFreeContent(&attrList, NULL);83return returnValue;84}8586static void setLabelForItem(NSString *inLabel, SecKeychainItemRef inItem)87{88OSStatus status;89const char *labelCString = [inLabel UTF8String];9091// Set up attribute vector (each attribute consists of {tag, length, pointer}):92SecKeychainAttribute attrs[] = {93{ kSecLabelItemAttr, strlen(labelCString), (void *)labelCString }94};9596const SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs };9798// Not changing data here, just attributes.99status = SecKeychainItemModifyContent(inItem, &attributes, 0, NULL);100101if(status) {102cssmPerror("setLabelForItem: SecKeychainItemModifyContent", status);103}104}105106/*107* Given a SecIdentityRef, do our best to construct a complete, ordered, and108* verified cert chain, returning the result in a CFArrayRef. The result is109* can be passed back to Java as a chain for a private key.110*/111static OSStatus completeCertChain(112SecIdentityRef identity,113SecCertificateRef trustedAnchor, // optional additional trusted anchor114bool includeRoot, // include the root in outArray115CFArrayRef *outArray) // created and RETURNED116{117SecTrustRef secTrust = NULL;118SecPolicyRef policy = NULL;119SecPolicySearchRef policySearch = NULL;120SecTrustResultType secTrustResult;121CSSM_TP_APPLE_EVIDENCE_INFO *dummyEv; // not used122CFArrayRef certChain = NULL; // constructed chain, CERTS ONLY123CFMutableArrayRef subjCerts; // passed to SecTrust124CFMutableArrayRef certArray; // returned array starting with125// identity126CFIndex numResCerts;127CFIndex dex;128OSStatus ortn;129SecCertificateRef certRef;130131/* First element in out array is the SecIdentity */132certArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);133CFArrayAppendValue(certArray, identity);134135/* the single element in certs-to-be-evaluated comes from the identity */136ortn = SecIdentityCopyCertificate(identity, &certRef);137if(ortn) {138/* should never happen */139cssmPerror("SecIdentityCopyCertificate", ortn);140return ortn;141}142143/*144* Now use SecTrust to get a complete cert chain, using all of the145* user's keychains to look for intermediate certs.146* NOTE this does NOT handle root certs which are not in the system147* root cert DB.148*/149subjCerts = CFArrayCreateMutable(NULL, 1, &kCFTypeArrayCallBacks);150CFArraySetValueAtIndex(subjCerts, 0, certRef);151152/* the array owns the subject cert ref now */153CFRelease(certRef);154155/* Get a SecPolicyRef for generic X509 cert chain verification */156ortn = SecPolicySearchCreate(CSSM_CERT_X_509v3,157&CSSMOID_APPLE_X509_BASIC,158NULL, // value159&policySearch);160if(ortn) {161/* should never happen */162cssmPerror("SecPolicySearchCreate", ortn);163goto errOut;164}165ortn = SecPolicySearchCopyNext(policySearch, &policy);166if(ortn) {167/* should never happen */168cssmPerror("SecPolicySearchCopyNext", ortn);169goto errOut;170}171172/* build a SecTrustRef for specified policy and certs */173ortn = SecTrustCreateWithCertificates(subjCerts,174policy, &secTrust);175if(ortn) {176cssmPerror("SecTrustCreateWithCertificates", ortn);177goto errOut;178}179180if(trustedAnchor) {181/*182* Tell SecTrust to trust this one in addition to the current183* trusted system-wide anchors.184*/185CFMutableArrayRef newAnchors;186CFArrayRef currAnchors;187188ortn = SecTrustCopyAnchorCertificates(&currAnchors);189if(ortn) {190/* should never happen */191cssmPerror("SecTrustCopyAnchorCertificates", ortn);192goto errOut;193}194newAnchors = CFArrayCreateMutableCopy(NULL,195CFArrayGetCount(currAnchors) + 1,196currAnchors);197CFRelease(currAnchors);198CFArrayAppendValue(newAnchors, trustedAnchor);199ortn = SecTrustSetAnchorCertificates(secTrust, newAnchors);200CFRelease(newAnchors);201if(ortn) {202cssmPerror("SecTrustSetAnchorCertificates", ortn);203goto errOut;204}205}206207/* evaluate: GO */208ortn = SecTrustEvaluate(secTrust, &secTrustResult);209if(ortn) {210cssmPerror("SecTrustEvaluate", ortn);211goto errOut;212}213switch(secTrustResult) {214case kSecTrustResultUnspecified:215/* cert chain valid, no special UserTrust assignments; drop thru */216case kSecTrustResultProceed:217/* cert chain valid AND user explicitly trusts this */218break;219default:220/*221* Cert chain construction failed.222* Just go with the single subject cert we were given; maybe the223* peer can complete the chain.224*/225ortn = noErr;226goto errOut;227}228229/* get resulting constructed cert chain */230ortn = SecTrustGetResult(secTrust, &secTrustResult, &certChain, &dummyEv);231if(ortn) {232cssmPerror("SecTrustEvaluate", ortn);233goto errOut;234}235236/*237* Copy certs from constructed chain to our result array, skipping238* the leaf (which is already there, as a SecIdentityRef) and possibly239* a root.240*/241numResCerts = CFArrayGetCount(certChain);242if(numResCerts < 1) {243/*244* Can't happen: If chain doesn't verify to a root, we'd245* have bailed after SecTrustEvaluate().246*/247ortn = noErr;248goto errOut;249}250if(!includeRoot) {251/* skip the last (root) cert) */252numResCerts--;253}254for(dex=1; dex<numResCerts; dex++) {255certRef = (SecCertificateRef)CFArrayGetValueAtIndex(certChain, dex);256CFArrayAppendValue(certArray, certRef);257}258errOut:259/* clean up */260if(secTrust) {261CFRelease(secTrust);262}263if(subjCerts) {264CFRelease(subjCerts);265}266if(policy) {267CFRelease(policy);268}269if(policySearch) {270CFRelease(policySearch);271}272*outArray = certArray;273return ortn;274}275276static void addIdentitiesToKeystore(JNIEnv *env, jobject keyStore)277{278// Search the user keychain list for all identities. Identities are a certificate/private key association that279// can be chosen for a purpose such as signing or an SSL connection.280SecIdentitySearchRef identitySearch = NULL;281// Pass 0 if you want all identities returned by this search282OSStatus err = SecIdentitySearchCreate(NULL, 0, &identitySearch);283SecIdentityRef theIdentity = NULL;284OSErr searchResult = noErr;285286jclass jc_KeychainStore = (*env)->FindClass(env, "apple/security/KeychainStore");287CHECK_NULL(jc_KeychainStore);288jmethodID jm_createKeyEntry = (*env)->GetMethodID(env, jc_KeychainStore, "createKeyEntry", "(Ljava/lang/String;JJ[J[[B)V");289CHECK_NULL(jm_createKeyEntry);290do {291searchResult = SecIdentitySearchCopyNext(identitySearch, &theIdentity);292293if (searchResult == noErr) {294// Get the cert from the identity, then generate a chain.295SecCertificateRef certificate;296SecIdentityCopyCertificate(theIdentity, &certificate);297CFArrayRef certChain = NULL;298299// *** Should do something with this error...300err = completeCertChain(theIdentity, NULL, TRUE, &certChain);301302CFIndex i, certCount = CFArrayGetCount(certChain);303304// Make a java array of certificate data from the chain.305jclass byteArrayClass = (*env)->FindClass(env, "[B");306if (byteArrayClass == NULL) {307goto errOut;308}309jobjectArray javaCertArray = (*env)->NewObjectArray(env, certCount, byteArrayClass, NULL);310// Cleanup first then check for a NULL return code311(*env)->DeleteLocalRef(env, byteArrayClass);312if (javaCertArray == NULL) {313goto errOut;314}315316// And, make an array of the certificate refs.317jlongArray certRefArray = (*env)->NewLongArray(env, certCount);318if (certRefArray == NULL) {319goto errOut;320}321322SecCertificateRef currCertRef = NULL;323324for (i = 0; i < certCount; i++) {325CSSM_DATA currCertData;326327if (i == 0)328currCertRef = certificate;329else330currCertRef = (SecCertificateRef)CFArrayGetValueAtIndex(certChain, i);331332bzero(&currCertData, sizeof(CSSM_DATA));333err = SecCertificateGetData(currCertRef, &currCertData);334jbyteArray encodedCertData = (*env)->NewByteArray(env, currCertData.Length);335if (encodedCertData == NULL) {336goto errOut;337}338(*env)->SetByteArrayRegion(env, encodedCertData, 0, currCertData.Length, (jbyte *)currCertData.Data);339(*env)->SetObjectArrayElement(env, javaCertArray, i, encodedCertData);340jlong certRefElement = ptr_to_jlong(currCertRef);341(*env)->SetLongArrayRegion(env, certRefArray, i, 1, &certRefElement);342}343344// Get the private key. When needed we'll export the data from it later.345SecKeyRef privateKeyRef;346err = SecIdentityCopyPrivateKey(theIdentity, &privateKeyRef);347348// Find the label. It's a 'blob', but we interpret as characters.349jstring alias = getLabelFromItem(env, (SecKeychainItemRef)certificate);350if (alias == NULL) {351goto errOut;352}353354// Find the creation date.355jlong creationDate = getModDateFromItem(env, (SecKeychainItemRef)certificate);356357// Call back to the Java object to create Java objects corresponding to this security object.358jlong nativeKeyRef = ptr_to_jlong(privateKeyRef);359(*env)->CallVoidMethod(env, keyStore, jm_createKeyEntry, alias, creationDate, nativeKeyRef, certRefArray, javaCertArray);360JNU_CHECK_EXCEPTION(env);361}362} while (searchResult == noErr);363364errOut:365if (identitySearch != NULL) {366CFRelease(identitySearch);367}368}369370#define ADD(list, str) { \371jobject localeObj = (*env)->NewStringUTF(env, [str UTF8String]); \372(*env)->CallBooleanMethod(env, list, jm_listAdd, localeObj); \373(*env)->DeleteLocalRef(env, localeObj); \374}375376#define ADDNULL(list) (*env)->CallBooleanMethod(env, list, jm_listAdd, NULL)377378static void addCertificatesToKeystore(JNIEnv *env, jobject keyStore)379{380// Search the user keychain list for all X509 certificates.381SecKeychainSearchRef keychainItemSearch = NULL;382OSStatus err = SecKeychainSearchCreateFromAttributes(NULL, kSecCertificateItemClass, NULL, &keychainItemSearch);383SecKeychainItemRef theItem = NULL;384OSErr searchResult = noErr;385386jclass jc_KeychainStore = (*env)->FindClass(env, "apple/security/KeychainStore");387CHECK_NULL(jc_KeychainStore);388jmethodID jm_createTrustedCertEntry = (*env)->GetMethodID(389env, jc_KeychainStore, "createTrustedCertEntry", "(Ljava/lang/String;Ljava/util/List;JJ[B)V");390CHECK_NULL(jm_createTrustedCertEntry);391jclass jc_arrayListClass = (*env)->FindClass(env, "java/util/ArrayList");392CHECK_NULL(jc_arrayListClass);393jmethodID jm_arrayListCons = (*env)->GetMethodID(env, jc_arrayListClass, "<init>", "()V");394CHECK_NULL(jm_arrayListCons);395jmethodID jm_listAdd = (*env)->GetMethodID(env, jc_arrayListClass, "add", "(Ljava/lang/Object;)Z");396CHECK_NULL(jm_listAdd);397398do {399searchResult = SecKeychainSearchCopyNext(keychainItemSearch, &theItem);400401if (searchResult == noErr) {402// Make a byte array with the DER-encoded contents of the certificate.403SecCertificateRef certRef = (SecCertificateRef)theItem;404CSSM_DATA currCertificate;405err = SecCertificateGetData(certRef, &currCertificate);406jbyteArray certData = (*env)->NewByteArray(env, currCertificate.Length);407if (certData == NULL) {408goto errOut;409}410(*env)->SetByteArrayRegion(env, certData, 0, currCertificate.Length, (jbyte *)currCertificate.Data);411412// Find the label. It's a 'blob', but we interpret as characters.413jstring alias = getLabelFromItem(env, theItem);414if (alias == NULL) {415goto errOut;416}417418// Only add certificates with trusted settings419CFArrayRef trustSettings;420if (SecTrustSettingsCopyTrustSettings(certRef, kSecTrustSettingsDomainUser, &trustSettings)421== errSecItemNotFound) {422continue;423}424425// See KeychainStore::createTrustedCertEntry for content of inputTrust426jobject inputTrust = (*env)->NewObject(env, jc_arrayListClass, jm_arrayListCons);427CHECK_NULL(inputTrust);428429// Dump everything inside trustSettings into inputTrust430CFIndex count = CFArrayGetCount(trustSettings);431for (int i = 0; i < count; i++) {432CFDictionaryRef oneTrust = (CFDictionaryRef) CFArrayGetValueAtIndex(trustSettings, i);433CFIndex size = CFDictionaryGetCount(oneTrust);434const void * keys [size];435const void * values [size];436CFDictionaryGetKeysAndValues(oneTrust, keys, values);437for (int j = 0; j < size; j++) {438NSString* s = [NSString stringWithFormat:@"%@", keys[j]];439ADD(inputTrust, s);440s = [NSString stringWithFormat:@"%@", values[j]];441ADD(inputTrust, s);442}443SecPolicyRef certPolicy;444certPolicy = (SecPolicyRef)CFDictionaryGetValue(oneTrust, kSecTrustSettingsPolicy);445if (certPolicy != NULL) {446CFDictionaryRef policyDict = SecPolicyCopyProperties(certPolicy);447ADD(inputTrust, @"SecPolicyOid");448NSString* s = [NSString stringWithFormat:@"%@", CFDictionaryGetValue(policyDict, @"SecPolicyOid")];449ADD(inputTrust, s);450CFRelease(policyDict);451}452ADDNULL(inputTrust);453}454CFRelease(trustSettings);455456// Find the creation date.457jlong creationDate = getModDateFromItem(env, theItem);458459// Call back to the Java object to create Java objects corresponding to this security object.460jlong nativeRef = ptr_to_jlong(certRef);461(*env)->CallVoidMethod(env, keyStore, jm_createTrustedCertEntry, alias, inputTrust, nativeRef, creationDate, certData);462JNU_CHECK_EXCEPTION(env);463}464} while (searchResult == noErr);465466errOut:467if (keychainItemSearch != NULL) {468CFRelease(keychainItemSearch);469}470}471472/*473* Class: apple_security_KeychainStore474* Method: _getEncodedKeyData475* Signature: (J)[B476*/477JNIEXPORT jbyteArray JNICALL Java_apple_security_KeychainStore__1getEncodedKeyData478(JNIEnv *env, jobject this, jlong keyRefLong, jcharArray passwordObj)479{480SecKeyRef keyRef = (SecKeyRef)jlong_to_ptr(keyRefLong);481SecKeyImportExportParameters paramBlock;482OSStatus err = noErr;483CFDataRef exportedData = NULL;484jbyteArray returnValue = NULL;485CFStringRef passwordStrRef = NULL;486487jsize passwordLen = 0;488jchar *passwordChars = NULL;489490if (passwordObj) {491passwordLen = (*env)->GetArrayLength(env, passwordObj);492493if (passwordLen > 0) {494passwordChars = (*env)->GetCharArrayElements(env, passwordObj, NULL);495if (passwordChars == NULL) {496goto errOut;497}498499passwordStrRef = CFStringCreateWithCharactersNoCopy(NULL, passwordChars, passwordLen, kCFAllocatorNull);500if (passwordStrRef == NULL) {501goto errOut;502}503}504}505506paramBlock.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;507// Note that setting the flags field **requires** you to pass in a password of some kind. The keychain will not prompt you.508paramBlock.flags = 0;509paramBlock.passphrase = passwordStrRef;510paramBlock.alertTitle = NULL;511paramBlock.alertPrompt = NULL;512paramBlock.accessRef = NULL;513paramBlock.keyUsage = CSSM_KEYUSE_ANY;514paramBlock.keyAttributes = CSSM_KEYATTR_RETURN_DEFAULT;515516err = SecKeychainItemExport(keyRef, kSecFormatPKCS12, 0, ¶mBlock, &exportedData);517518if (err == noErr) {519CFIndex size = CFDataGetLength(exportedData);520returnValue = (*env)->NewByteArray(env, size);521if (returnValue == NULL) {522goto errOut;523}524(*env)->SetByteArrayRegion(env, returnValue, 0, size, (jbyte *)CFDataGetBytePtr(exportedData));525}526527errOut:528if (exportedData) CFRelease(exportedData);529if (passwordStrRef) CFRelease(passwordStrRef);530if (passwordChars) {531// clear the password and release532memset(passwordChars, 0, passwordLen);533(*env)->ReleaseCharArrayElements(env, passwordObj, passwordChars,534JNI_ABORT);535}536return returnValue;537}538539540/*541* Class: apple_security_KeychainStore542* Method: _scanKeychain543* Signature: ()V544*/545JNIEXPORT void JNICALL Java_apple_security_KeychainStore__1scanKeychain546(JNIEnv *env, jobject this)547{548// Look for 'identities' -- private key and certificate chain pairs -- and add those.549// Search for these first, because a certificate that's found here as part of an identity will show up550// again later as a certificate.551addIdentitiesToKeystore(env, this);552553JNU_CHECK_EXCEPTION(env);554555// Scan current keychain for trusted certificates.556addCertificatesToKeystore(env, this);557558}559560NSString* JavaStringToNSString(JNIEnv *env, jstring jstr) {561if (jstr == NULL) {562return NULL;563}564jsize len = (*env)->GetStringLength(env, jstr);565const jchar *chars = (*env)->GetStringChars(env, jstr, NULL);566if (chars == NULL) {567return NULL;568}569NSString *result = [NSString stringWithCharacters:(UniChar *)chars length:len];570(*env)->ReleaseStringChars(env, jstr, chars);571return result;572}573574/*575* Class: apple_security_KeychainStore576* Method: _addItemToKeychain577* Signature: (Ljava/lang/String;Z[B[C)J578*/579JNIEXPORT jlong JNICALL Java_apple_security_KeychainStore__1addItemToKeychain580(JNIEnv *env, jobject this, jstring alias, jboolean isCertificate, jbyteArray rawDataObj, jcharArray passwordObj)581{582OSStatus err;583jlong returnValue = 0;584585NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; \586@try {587jsize dataSize = (*env)->GetArrayLength(env, rawDataObj);588jbyte *rawData = (*env)->GetByteArrayElements(env, rawDataObj, NULL);589if (rawData == NULL) {590goto errOut;591}592593CFDataRef cfDataToImport = CFDataCreate(kCFAllocatorDefault, (UInt8 *)rawData, dataSize);594CFArrayRef createdItems = NULL;595596SecKeychainRef defaultKeychain = NULL;597SecKeychainCopyDefault(&defaultKeychain);598599SecExternalFormat dataFormat = (isCertificate == JNI_TRUE ? kSecFormatX509Cert : kSecFormatWrappedPKCS8);600601// Convert the password obj into a CFStringRef that the keychain importer can use for encryption.602SecKeyImportExportParameters paramBlock;603CFStringRef passwordStrRef = NULL;604605jsize passwordLen = 0;606jchar *passwordChars = NULL;607608if (passwordObj) {609passwordLen = (*env)->GetArrayLength(env, passwordObj);610611if (passwordLen > 0) {612passwordChars = (*env)->GetCharArrayElements(env, passwordObj, NULL);613if (passwordChars == NULL) {614goto errOut;615}616617passwordStrRef = CFStringCreateWithCharactersNoCopy(NULL, passwordChars, passwordLen, kCFAllocatorNull);618if (passwordStrRef == NULL) {619goto errOut;620}621}622}623624paramBlock.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;625// Note that setting the flags field **requires** you to pass in a password of some kind. The keychain will not prompt you.626paramBlock.flags = 0;627paramBlock.passphrase = passwordStrRef;628paramBlock.alertTitle = NULL;629paramBlock.alertPrompt = NULL;630paramBlock.accessRef = NULL;631paramBlock.keyUsage = CSSM_KEYUSE_ANY;632paramBlock.keyAttributes = CSSM_KEYATTR_RETURN_DEFAULT;633634err = SecKeychainItemImport(cfDataToImport, NULL, &dataFormat, NULL,6350, ¶mBlock, defaultKeychain, &createdItems);636if (cfDataToImport != NULL) {637CFRelease(cfDataToImport);638}639640if (err == noErr) {641SecKeychainItemRef anItem = (SecKeychainItemRef)CFArrayGetValueAtIndex(createdItems, 0);642643// Don't bother labeling keys. They become part of an identity, and are not an accessible part of the keychain.644if (CFGetTypeID(anItem) == SecCertificateGetTypeID()) {645setLabelForItem(JavaStringToNSString(env, alias), anItem);646}647648// Retain the item, since it will be released once when the array holding it gets released.649CFRetain(anItem);650returnValue = ptr_to_jlong(anItem);651} else {652cssmPerror("_addItemToKeychain: SecKeychainItemImport", err);653}654655if (createdItems != NULL) {656CFRelease(createdItems);657}658659errOut:660if (rawData) {661(*env)->ReleaseByteArrayElements(env, rawDataObj, rawData, JNI_ABORT);662}663664if (passwordStrRef) CFRelease(passwordStrRef);665if (passwordChars) {666// clear the password and release667memset(passwordChars, 0, passwordLen);668(*env)->ReleaseCharArrayElements(env, passwordObj, passwordChars,669JNI_ABORT);670}671} @catch (NSException *e) {672NSLog(@"%@", [e callStackSymbols]);673} @finally {674[pool drain];675}676return returnValue;677}678679/*680* Class: apple_security_KeychainStore681* Method: _removeItemFromKeychain682* Signature: (J)I683*/684JNIEXPORT jint JNICALL Java_apple_security_KeychainStore__1removeItemFromKeychain685(JNIEnv *env, jobject this, jlong keychainItem)686{687SecKeychainItemRef itemToRemove = jlong_to_ptr(keychainItem);688return SecKeychainItemDelete(itemToRemove);689}690691/*692* Class: apple_security_KeychainStore693* Method: _releaseKeychainItemRef694* Signature: (J)V695*/696JNIEXPORT void JNICALL Java_apple_security_KeychainStore__1releaseKeychainItemRef697(JNIEnv *env, jobject this, jlong keychainItem)698{699SecKeychainItemRef itemToFree = jlong_to_ptr(keychainItem);700CFRelease(itemToFree);701}702703704