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 }