jdk/src/jdk.deploy.osx/macosx/native/libosx/KeystoreImpl.m
changeset 32253 637b00638ed6
parent 32252 78117959e115
parent 32249 ba2c9c7773b6
child 32255 cc8c8786ef91
equal deleted inserted replaced
32252:78117959e115 32253:637b00638ed6
     1 /*
       
     2  * Copyright (c) 2011, 2014, 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 
       
    28 #import <Security/Security.h>
       
    29 #import <Security/SecImportExport.h>
       
    30 #import <CoreServices/CoreServices.h>  // (for require() macros)
       
    31 #import <JavaNativeFoundation/JavaNativeFoundation.h>
       
    32 
       
    33 
       
    34 static JNF_CLASS_CACHE(jc_KeychainStore, "apple/security/KeychainStore");
       
    35 static JNF_MEMBER_CACHE(jm_createTrustedCertEntry, jc_KeychainStore, "createTrustedCertEntry", "(Ljava/lang/String;JJ[B)V");
       
    36 static JNF_MEMBER_CACHE(jm_createKeyEntry, jc_KeychainStore, "createKeyEntry", "(Ljava/lang/String;JJ[J[[B)V");
       
    37 
       
    38 static jstring getLabelFromItem(JNIEnv *env, SecKeychainItemRef inItem)
       
    39 {
       
    40     OSStatus status;
       
    41     jstring returnValue = NULL;
       
    42     char *attribCString = NULL;
       
    43 
       
    44     SecKeychainAttribute itemAttrs[] = { { kSecLabelItemAttr, 0, NULL } };
       
    45     SecKeychainAttributeList attrList = { sizeof(itemAttrs) / sizeof(itemAttrs[0]), itemAttrs };
       
    46 
       
    47     status = SecKeychainItemCopyContent(inItem, NULL, &attrList, NULL, NULL);
       
    48 
       
    49     if(status) {
       
    50         cssmPerror("getLabelFromItem: SecKeychainItemCopyContent", status);
       
    51         goto errOut;
       
    52     }
       
    53 
       
    54     attribCString = malloc(itemAttrs[0].length + 1);
       
    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     do {
       
   288         searchResult = SecIdentitySearchCopyNext(identitySearch, &theIdentity);
       
   289 
       
   290         if (searchResult == noErr) {
       
   291             // Get the cert from the identity, then generate a chain.
       
   292             SecCertificateRef certificate;
       
   293             SecIdentityCopyCertificate(theIdentity, &certificate);
       
   294             CFArrayRef certChain = NULL;
       
   295 
       
   296             // *** Should do something with this error...
       
   297             err = completeCertChain(theIdentity, NULL, TRUE, &certChain);
       
   298 
       
   299             CFIndex i, certCount = CFArrayGetCount(certChain);
       
   300 
       
   301             // Make a java array of certificate data from the chain.
       
   302             jclass byteArrayClass = (*env)->FindClass(env, "[B");
       
   303             if (byteArrayClass == NULL) {
       
   304                 goto errOut;
       
   305             }
       
   306             jobjectArray javaCertArray = (*env)->NewObjectArray(env, certCount, byteArrayClass, NULL);
       
   307             // Cleanup first then check for a NULL return code
       
   308             (*env)->DeleteLocalRef(env, byteArrayClass);
       
   309             if (javaCertArray == NULL) {
       
   310                 goto errOut;
       
   311             }
       
   312 
       
   313             // And, make an array of the certificate refs.
       
   314             jlongArray certRefArray = (*env)->NewLongArray(env, certCount);
       
   315             if (certRefArray == NULL) {
       
   316                 goto errOut;
       
   317             }
       
   318 
       
   319             SecCertificateRef currCertRef = NULL;
       
   320 
       
   321             for (i = 0; i < certCount; i++) {
       
   322                 CSSM_DATA currCertData;
       
   323 
       
   324                 if (i == 0)
       
   325                     currCertRef = certificate;
       
   326                 else
       
   327                     currCertRef = (SecCertificateRef)CFArrayGetValueAtIndex(certChain, i);
       
   328 
       
   329                 bzero(&currCertData, sizeof(CSSM_DATA));
       
   330                 err = SecCertificateGetData(currCertRef, &currCertData);
       
   331                 jbyteArray encodedCertData = (*env)->NewByteArray(env, currCertData.Length);
       
   332                 if (encodedCertData == NULL) {
       
   333                     goto errOut;
       
   334                 }
       
   335                 (*env)->SetByteArrayRegion(env, encodedCertData, 0, currCertData.Length, (jbyte *)currCertData.Data);
       
   336                 (*env)->SetObjectArrayElement(env, javaCertArray, i, encodedCertData);
       
   337                 jlong certRefElement = ptr_to_jlong(currCertRef);
       
   338                 (*env)->SetLongArrayRegion(env, certRefArray, i, 1, &certRefElement);
       
   339             }
       
   340 
       
   341             // Get the private key.  When needed we'll export the data from it later.
       
   342             SecKeyRef privateKeyRef;
       
   343             err = SecIdentityCopyPrivateKey(theIdentity, &privateKeyRef);
       
   344 
       
   345             // Find the label.  It's a 'blob', but we interpret as characters.
       
   346             jstring alias = getLabelFromItem(env, (SecKeychainItemRef)certificate);
       
   347             if (alias == NULL) {
       
   348                 goto errOut;
       
   349             }
       
   350 
       
   351             // Find the creation date.
       
   352             jlong creationDate = getModDateFromItem(env, (SecKeychainItemRef)certificate);
       
   353 
       
   354             // Call back to the Java object to create Java objects corresponding to this security object.
       
   355             jlong nativeKeyRef = ptr_to_jlong(privateKeyRef);
       
   356             JNFCallVoidMethod(env, keyStore, jm_createKeyEntry, alias, creationDate, nativeKeyRef, certRefArray, javaCertArray);
       
   357         }
       
   358     } while (searchResult == noErr);
       
   359 
       
   360 errOut:
       
   361     if (identitySearch != NULL) {
       
   362         CFRelease(identitySearch);
       
   363     }
       
   364 }
       
   365 
       
   366 static void addCertificatesToKeystore(JNIEnv *env, jobject keyStore)
       
   367 {
       
   368     // Search the user keychain list for all X509 certificates.
       
   369     SecKeychainSearchRef keychainItemSearch = NULL;
       
   370     OSStatus err = SecKeychainSearchCreateFromAttributes(NULL, kSecCertificateItemClass, NULL, &keychainItemSearch);
       
   371     SecKeychainItemRef theItem = NULL;
       
   372     OSErr searchResult = noErr;
       
   373 
       
   374     do {
       
   375         searchResult = SecKeychainSearchCopyNext(keychainItemSearch, &theItem);
       
   376 
       
   377         if (searchResult == noErr) {
       
   378             // Make a byte array with the DER-encoded contents of the certificate.
       
   379             SecCertificateRef certRef = (SecCertificateRef)theItem;
       
   380             CSSM_DATA currCertificate;
       
   381             err = SecCertificateGetData(certRef, &currCertificate);
       
   382             jbyteArray certData = (*env)->NewByteArray(env, currCertificate.Length);
       
   383             if (certData == NULL) {
       
   384                 goto errOut;
       
   385             }
       
   386             (*env)->SetByteArrayRegion(env, certData, 0, currCertificate.Length, (jbyte *)currCertificate.Data);
       
   387 
       
   388             // Find the label.  It's a 'blob', but we interpret as characters.
       
   389             jstring alias = getLabelFromItem(env, theItem);
       
   390             if (alias == NULL) {
       
   391                 goto errOut;
       
   392             }
       
   393 
       
   394             // Find the creation date.
       
   395             jlong creationDate = getModDateFromItem(env, theItem);
       
   396 
       
   397             // Call back to the Java object to create Java objects corresponding to this security object.
       
   398             jlong nativeRef = ptr_to_jlong(certRef);
       
   399             JNFCallVoidMethod(env, keyStore, jm_createTrustedCertEntry, alias, nativeRef, creationDate, certData);
       
   400         }
       
   401     } while (searchResult == noErr);
       
   402 
       
   403 errOut:
       
   404     if (keychainItemSearch != NULL) {
       
   405         CFRelease(keychainItemSearch);
       
   406     }
       
   407 }
       
   408 
       
   409 /*
       
   410  * Class:     apple_security_KeychainStore
       
   411  * Method:    _getEncodedKeyData
       
   412  * Signature: (J)[B
       
   413      */
       
   414 JNIEXPORT jbyteArray JNICALL Java_apple_security_KeychainStore__1getEncodedKeyData
       
   415 (JNIEnv *env, jobject this, jlong keyRefLong, jcharArray passwordObj)
       
   416 {
       
   417     SecKeyRef keyRef = (SecKeyRef)jlong_to_ptr(keyRefLong);
       
   418     SecKeyImportExportParameters paramBlock;
       
   419     OSStatus err = noErr;
       
   420     CFDataRef exportedData = NULL;
       
   421     jbyteArray returnValue = NULL;
       
   422     CFStringRef passwordStrRef = NULL;
       
   423 
       
   424     jsize passwordLen = 0;
       
   425     jchar *passwordChars = NULL;
       
   426 
       
   427     if (passwordObj) {
       
   428         passwordLen = (*env)->GetArrayLength(env, passwordObj);
       
   429 
       
   430         if (passwordLen > 0) {
       
   431             passwordChars = (*env)->GetCharArrayElements(env, passwordObj, NULL);
       
   432             if (passwordChars == NULL) {
       
   433                 goto errOut;
       
   434             }
       
   435             passwordStrRef = CFStringCreateWithCharacters(kCFAllocatorDefault, passwordChars, passwordLen);
       
   436         }
       
   437     }
       
   438 
       
   439     paramBlock.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
       
   440     // Note that setting the flags field **requires** you to pass in a password of some kind.  The keychain will not prompt you.
       
   441     paramBlock.flags = 0;
       
   442     paramBlock.passphrase = passwordStrRef;
       
   443     paramBlock.alertTitle = NULL;
       
   444     paramBlock.alertPrompt = NULL;
       
   445     paramBlock.accessRef = NULL;
       
   446     paramBlock.keyUsage = CSSM_KEYUSE_ANY;
       
   447     paramBlock.keyAttributes = CSSM_KEYATTR_RETURN_DEFAULT;
       
   448 
       
   449     err = SecKeychainItemExport(keyRef, kSecFormatPKCS12, 0, &paramBlock, &exportedData);
       
   450 
       
   451     if (err == noErr) {
       
   452         CFIndex size = CFDataGetLength(exportedData);
       
   453         returnValue = (*env)->NewByteArray(env, size);
       
   454         if (returnValue == NULL) {
       
   455             goto errOut;
       
   456         }
       
   457         (*env)->SetByteArrayRegion(env, returnValue, 0, size, (jbyte *)CFDataGetBytePtr(exportedData));
       
   458     }
       
   459 
       
   460 errOut:
       
   461     if (exportedData) CFRelease(exportedData);
       
   462     if (passwordStrRef) CFRelease(passwordStrRef);
       
   463 
       
   464     return returnValue;
       
   465 }
       
   466 
       
   467 
       
   468 /*
       
   469  * Class:     apple_security_KeychainStore
       
   470  * Method:    _scanKeychain
       
   471  * Signature: ()V
       
   472  */
       
   473 JNIEXPORT void JNICALL Java_apple_security_KeychainStore__1scanKeychain
       
   474 (JNIEnv *env, jobject this)
       
   475 {
       
   476     // Look for 'identities' -- private key and certificate chain pairs -- and add those.
       
   477     // Search for these first, because a certificate that's found here as part of an identity will show up
       
   478     // again later as a certificate.
       
   479     addIdentitiesToKeystore(env, this);
       
   480 
       
   481     // Scan current keychain for trusted certificates.
       
   482     addCertificatesToKeystore(env, this);
       
   483 
       
   484 }
       
   485 
       
   486 /*
       
   487  * Class:     apple_security_KeychainStore
       
   488  * Method:    _addItemToKeychain
       
   489  * Signature: (Ljava/lang/String;[B)I
       
   490 */
       
   491 JNIEXPORT jlong JNICALL Java_apple_security_KeychainStore__1addItemToKeychain
       
   492 (JNIEnv *env, jobject this, jstring alias, jboolean isCertificate, jbyteArray rawDataObj, jcharArray passwordObj)
       
   493 {
       
   494     OSStatus err;
       
   495     jlong returnValue = 0;
       
   496 
       
   497 JNF_COCOA_ENTER(env);
       
   498 
       
   499     jsize dataSize = (*env)->GetArrayLength(env, rawDataObj);
       
   500     jbyte *rawData = (*env)->GetByteArrayElements(env, rawDataObj, NULL);
       
   501     if (rawData == NULL) {
       
   502         goto errOut;
       
   503     }
       
   504 
       
   505     CFDataRef cfDataToImport = CFDataCreate(kCFAllocatorDefault, (UInt8 *)rawData, dataSize);
       
   506     CFArrayRef createdItems = NULL;
       
   507 
       
   508     SecKeychainRef defaultKeychain = NULL;
       
   509     SecKeychainCopyDefault(&defaultKeychain);
       
   510 
       
   511     SecExternalItemType dataType = (isCertificate == JNI_TRUE ? kSecFormatX509Cert : kSecFormatWrappedPKCS8);
       
   512 
       
   513     // Convert the password obj into a CFStringRef that the keychain importer can use for encryption.
       
   514     SecKeyImportExportParameters paramBlock;
       
   515     CFStringRef passwordStrRef = NULL;
       
   516 
       
   517     jsize passwordLen = 0;
       
   518     jchar *passwordChars = NULL;
       
   519 
       
   520     if (passwordObj) {
       
   521         passwordLen = (*env)->GetArrayLength(env, passwordObj);
       
   522         passwordChars = (*env)->GetCharArrayElements(env, passwordObj, NULL);
       
   523         passwordStrRef = CFStringCreateWithCharacters(kCFAllocatorDefault, passwordChars, passwordLen);
       
   524     }
       
   525 
       
   526     paramBlock.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
       
   527     // Note that setting the flags field **requires** you to pass in a password of some kind.  The keychain will not prompt you.
       
   528     paramBlock.flags = 0;
       
   529     paramBlock.passphrase = passwordStrRef;
       
   530     paramBlock.alertTitle = NULL;
       
   531     paramBlock.alertPrompt = NULL;
       
   532     paramBlock.accessRef = NULL;
       
   533     paramBlock.keyUsage = CSSM_KEYUSE_ANY;
       
   534     paramBlock.keyAttributes = CSSM_KEYATTR_RETURN_DEFAULT;
       
   535 
       
   536     err = SecKeychainItemImport(cfDataToImport, NULL, &dataType, NULL,
       
   537                                 0, &paramBlock, defaultKeychain, &createdItems);
       
   538 
       
   539     if (err == noErr) {
       
   540         SecKeychainItemRef anItem = (SecKeychainItemRef)CFArrayGetValueAtIndex(createdItems, 0);
       
   541 
       
   542         // Don't bother labeling keys. They become part of an identity, and are not an accessible part of the keychain.
       
   543         if (CFGetTypeID(anItem) == SecCertificateGetTypeID()) {
       
   544             setLabelForItem(JNFJavaToNSString(env, alias), anItem);
       
   545         }
       
   546 
       
   547         // Retain the item, since it will be released once when the array holding it gets released.
       
   548         CFRetain(anItem);
       
   549         returnValue = ptr_to_jlong(anItem);
       
   550     } else {
       
   551         cssmPerror("_addItemToKeychain: SecKeychainItemImport", err);
       
   552     }
       
   553 
       
   554     (*env)->ReleaseByteArrayElements(env, rawDataObj, rawData, JNI_ABORT);
       
   555 
       
   556     if (createdItems != NULL) {
       
   557         CFRelease(createdItems);
       
   558     }
       
   559 
       
   560 errOut: ;
       
   561 
       
   562 JNF_COCOA_EXIT(env);
       
   563 
       
   564     return returnValue;
       
   565 }
       
   566 
       
   567 /*
       
   568  * Class:     apple_security_KeychainStore
       
   569  * Method:    _removeItemFromKeychain
       
   570  * Signature: (J)I
       
   571 */
       
   572 JNIEXPORT jint JNICALL Java_apple_security_KeychainStore__1removeItemFromKeychain
       
   573 (JNIEnv *env, jobject this, jlong keychainItem)
       
   574 {
       
   575     SecKeychainItemRef itemToRemove = jlong_to_ptr(keychainItem);
       
   576     return SecKeychainItemDelete(itemToRemove);
       
   577 }
       
   578 
       
   579 /*
       
   580  * Class:     apple_security_KeychainStore
       
   581  * Method:    _releaseKeychainItemRef
       
   582  * Signature: (J)V
       
   583  */
       
   584 JNIEXPORT void JNICALL Java_apple_security_KeychainStore__1releaseKeychainItemRef
       
   585 (JNIEnv *env, jobject this, jlong keychainItem)
       
   586 {
       
   587     SecKeychainItemRef itemToFree = jlong_to_ptr(keychainItem);
       
   588     CFRelease(itemToFree);
       
   589 }