mirror of
https://github.com/openjdk/jdk9u.git
synced 2025-12-11 11:04:20 -06:00
606 lines
22 KiB
Objective-C
606 lines
22 KiB
Objective-C
/*
|
|
* Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation. Oracle designates this
|
|
* particular file as subject to the "Classpath" exception as provided
|
|
* by Oracle in the LICENSE file that accompanied this code.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
|
|
#import "apple_security_KeychainStore.h"
|
|
|
|
#import <Security/Security.h>
|
|
#import <Security/SecImportExport.h>
|
|
#import <CoreServices/CoreServices.h> // (for require() macros)
|
|
#import <JavaNativeFoundation/JavaNativeFoundation.h>
|
|
|
|
|
|
static JNF_CLASS_CACHE(jc_KeychainStore, "apple/security/KeychainStore");
|
|
static JNF_MEMBER_CACHE(jm_createTrustedCertEntry, jc_KeychainStore, "createTrustedCertEntry", "(Ljava/lang/String;JJ[B)V");
|
|
static JNF_MEMBER_CACHE(jm_createKeyEntry, jc_KeychainStore, "createKeyEntry", "(Ljava/lang/String;JJ[J[[B)V");
|
|
|
|
static jstring getLabelFromItem(JNIEnv *env, SecKeychainItemRef inItem)
|
|
{
|
|
OSStatus status;
|
|
jstring returnValue = NULL;
|
|
char *attribCString = NULL;
|
|
|
|
SecKeychainAttribute itemAttrs[] = { { kSecLabelItemAttr, 0, NULL } };
|
|
SecKeychainAttributeList attrList = { sizeof(itemAttrs) / sizeof(itemAttrs[0]), itemAttrs };
|
|
|
|
status = SecKeychainItemCopyContent(inItem, NULL, &attrList, NULL, NULL);
|
|
|
|
if(status) {
|
|
cssmPerror("getLabelFromItem: SecKeychainItemCopyContent", status);
|
|
goto errOut;
|
|
}
|
|
|
|
attribCString = malloc(itemAttrs[0].length + 1);
|
|
strncpy(attribCString, itemAttrs[0].data, itemAttrs[0].length);
|
|
attribCString[itemAttrs[0].length] = '\0';
|
|
returnValue = (*env)->NewStringUTF(env, attribCString);
|
|
|
|
errOut:
|
|
SecKeychainItemFreeContent(&attrList, NULL);
|
|
if (attribCString) free(attribCString);
|
|
return returnValue;
|
|
}
|
|
|
|
static jlong getModDateFromItem(JNIEnv *env, SecKeychainItemRef inItem)
|
|
{
|
|
OSStatus status;
|
|
SecKeychainAttribute itemAttrs[] = { { kSecModDateItemAttr, 0, NULL } };
|
|
SecKeychainAttributeList attrList = { sizeof(itemAttrs) / sizeof(itemAttrs[0]), itemAttrs };
|
|
jlong returnValue = 0;
|
|
|
|
status = SecKeychainItemCopyContent(inItem, NULL, &attrList, NULL, NULL);
|
|
|
|
if(status) {
|
|
// This is almost always missing, so don't dump an error.
|
|
// cssmPerror("getModDateFromItem: SecKeychainItemCopyContent", status);
|
|
goto errOut;
|
|
}
|
|
|
|
memcpy(&returnValue, itemAttrs[0].data, itemAttrs[0].length);
|
|
|
|
errOut:
|
|
SecKeychainItemFreeContent(&attrList, NULL);
|
|
return returnValue;
|
|
}
|
|
|
|
static void setLabelForItem(NSString *inLabel, SecKeychainItemRef inItem)
|
|
{
|
|
OSStatus status;
|
|
const char *labelCString = [inLabel UTF8String];
|
|
|
|
// Set up attribute vector (each attribute consists of {tag, length, pointer}):
|
|
SecKeychainAttribute attrs[] = {
|
|
{ kSecLabelItemAttr, strlen(labelCString), (void *)labelCString }
|
|
};
|
|
|
|
const SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs };
|
|
|
|
// Not changing data here, just attributes.
|
|
status = SecKeychainItemModifyContent(inItem, &attributes, 0, NULL);
|
|
|
|
if(status) {
|
|
cssmPerror("setLabelForItem: SecKeychainItemModifyContent", status);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Given a SecIdentityRef, do our best to construct a complete, ordered, and
|
|
* verified cert chain, returning the result in a CFArrayRef. The result is
|
|
* can be passed back to Java as a chain for a private key.
|
|
*/
|
|
static OSStatus completeCertChain(
|
|
SecIdentityRef identity,
|
|
SecCertificateRef trustedAnchor, // optional additional trusted anchor
|
|
bool includeRoot, // include the root in outArray
|
|
CFArrayRef *outArray) // created and RETURNED
|
|
{
|
|
SecTrustRef secTrust = NULL;
|
|
SecPolicyRef policy = NULL;
|
|
SecPolicySearchRef policySearch = NULL;
|
|
SecTrustResultType secTrustResult;
|
|
CSSM_TP_APPLE_EVIDENCE_INFO *dummyEv; // not used
|
|
CFArrayRef certChain = NULL; // constructed chain, CERTS ONLY
|
|
CFMutableArrayRef subjCerts; // passed to SecTrust
|
|
CFMutableArrayRef certArray; // returned array starting with
|
|
// identity
|
|
CFIndex numResCerts;
|
|
CFIndex dex;
|
|
OSStatus ortn;
|
|
SecCertificateRef certRef;
|
|
|
|
/* First element in out array is the SecIdentity */
|
|
certArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
|
|
CFArrayAppendValue(certArray, identity);
|
|
|
|
/* the single element in certs-to-be-evaluated comes from the identity */
|
|
ortn = SecIdentityCopyCertificate(identity, &certRef);
|
|
if(ortn) {
|
|
/* should never happen */
|
|
cssmPerror("SecIdentityCopyCertificate", ortn);
|
|
return ortn;
|
|
}
|
|
|
|
/*
|
|
* Now use SecTrust to get a complete cert chain, using all of the
|
|
* user's keychains to look for intermediate certs.
|
|
* NOTE this does NOT handle root certs which are not in the system
|
|
* root cert DB.
|
|
*/
|
|
subjCerts = CFArrayCreateMutable(NULL, 1, &kCFTypeArrayCallBacks);
|
|
CFArraySetValueAtIndex(subjCerts, 0, certRef);
|
|
|
|
/* the array owns the subject cert ref now */
|
|
CFRelease(certRef);
|
|
|
|
/* Get a SecPolicyRef for generic X509 cert chain verification */
|
|
ortn = SecPolicySearchCreate(CSSM_CERT_X_509v3,
|
|
&CSSMOID_APPLE_X509_BASIC,
|
|
NULL, // value
|
|
&policySearch);
|
|
if(ortn) {
|
|
/* should never happen */
|
|
cssmPerror("SecPolicySearchCreate", ortn);
|
|
goto errOut;
|
|
}
|
|
ortn = SecPolicySearchCopyNext(policySearch, &policy);
|
|
if(ortn) {
|
|
/* should never happen */
|
|
cssmPerror("SecPolicySearchCopyNext", ortn);
|
|
goto errOut;
|
|
}
|
|
|
|
/* build a SecTrustRef for specified policy and certs */
|
|
ortn = SecTrustCreateWithCertificates(subjCerts,
|
|
policy, &secTrust);
|
|
if(ortn) {
|
|
cssmPerror("SecTrustCreateWithCertificates", ortn);
|
|
goto errOut;
|
|
}
|
|
|
|
if(trustedAnchor) {
|
|
/*
|
|
* Tell SecTrust to trust this one in addition to the current
|
|
* trusted system-wide anchors.
|
|
*/
|
|
CFMutableArrayRef newAnchors;
|
|
CFArrayRef currAnchors;
|
|
|
|
ortn = SecTrustCopyAnchorCertificates(&currAnchors);
|
|
if(ortn) {
|
|
/* should never happen */
|
|
cssmPerror("SecTrustCopyAnchorCertificates", ortn);
|
|
goto errOut;
|
|
}
|
|
newAnchors = CFArrayCreateMutableCopy(NULL,
|
|
CFArrayGetCount(currAnchors) + 1,
|
|
currAnchors);
|
|
CFRelease(currAnchors);
|
|
CFArrayAppendValue(newAnchors, trustedAnchor);
|
|
ortn = SecTrustSetAnchorCertificates(secTrust, newAnchors);
|
|
CFRelease(newAnchors);
|
|
if(ortn) {
|
|
cssmPerror("SecTrustSetAnchorCertificates", ortn);
|
|
goto errOut;
|
|
}
|
|
}
|
|
|
|
/* evaluate: GO */
|
|
ortn = SecTrustEvaluate(secTrust, &secTrustResult);
|
|
if(ortn) {
|
|
cssmPerror("SecTrustEvaluate", ortn);
|
|
goto errOut;
|
|
}
|
|
switch(secTrustResult) {
|
|
case kSecTrustResultUnspecified:
|
|
/* cert chain valid, no special UserTrust assignments; drop thru */
|
|
case kSecTrustResultProceed:
|
|
/* cert chain valid AND user explicitly trusts this */
|
|
break;
|
|
default:
|
|
/*
|
|
* Cert chain construction failed.
|
|
* Just go with the single subject cert we were given; maybe the
|
|
* peer can complete the chain.
|
|
*/
|
|
ortn = noErr;
|
|
goto errOut;
|
|
}
|
|
|
|
/* get resulting constructed cert chain */
|
|
ortn = SecTrustGetResult(secTrust, &secTrustResult, &certChain, &dummyEv);
|
|
if(ortn) {
|
|
cssmPerror("SecTrustEvaluate", ortn);
|
|
goto errOut;
|
|
}
|
|
|
|
/*
|
|
* Copy certs from constructed chain to our result array, skipping
|
|
* the leaf (which is already there, as a SecIdentityRef) and possibly
|
|
* a root.
|
|
*/
|
|
numResCerts = CFArrayGetCount(certChain);
|
|
if(numResCerts < 1) {
|
|
/*
|
|
* Can't happen: If chain doesn't verify to a root, we'd
|
|
* have bailed after SecTrustEvaluate().
|
|
*/
|
|
ortn = noErr;
|
|
goto errOut;
|
|
}
|
|
if(!includeRoot) {
|
|
/* skip the last (root) cert) */
|
|
numResCerts--;
|
|
}
|
|
for(dex=1; dex<numResCerts; dex++) {
|
|
certRef = (SecCertificateRef)CFArrayGetValueAtIndex(certChain, dex);
|
|
CFArrayAppendValue(certArray, certRef);
|
|
}
|
|
errOut:
|
|
/* clean up */
|
|
if(secTrust) {
|
|
CFRelease(secTrust);
|
|
}
|
|
if(subjCerts) {
|
|
CFRelease(subjCerts);
|
|
}
|
|
if(policy) {
|
|
CFRelease(policy);
|
|
}
|
|
if(policySearch) {
|
|
CFRelease(policySearch);
|
|
}
|
|
*outArray = certArray;
|
|
return ortn;
|
|
}
|
|
|
|
static void addIdentitiesToKeystore(JNIEnv *env, jobject keyStore)
|
|
{
|
|
// Search the user keychain list for all identities. Identities are a certificate/private key association that
|
|
// can be chosen for a purpose such as signing or an SSL connection.
|
|
SecIdentitySearchRef identitySearch = NULL;
|
|
// Pass 0 if you want all identities returned by this search
|
|
OSStatus err = SecIdentitySearchCreate(NULL, 0, &identitySearch);
|
|
SecIdentityRef theIdentity = NULL;
|
|
OSErr searchResult = noErr;
|
|
|
|
do {
|
|
searchResult = SecIdentitySearchCopyNext(identitySearch, &theIdentity);
|
|
|
|
if (searchResult == noErr) {
|
|
// Get the cert from the identity, then generate a chain.
|
|
SecCertificateRef certificate;
|
|
SecIdentityCopyCertificate(theIdentity, &certificate);
|
|
CFArrayRef certChain = NULL;
|
|
|
|
// *** Should do something with this error...
|
|
err = completeCertChain(theIdentity, NULL, TRUE, &certChain);
|
|
|
|
CFIndex i, certCount = CFArrayGetCount(certChain);
|
|
|
|
// Make a java array of certificate data from the chain.
|
|
jclass byteArrayClass = (*env)->FindClass(env, "[B");
|
|
if (byteArrayClass == NULL) {
|
|
goto errOut;
|
|
}
|
|
jobjectArray javaCertArray = (*env)->NewObjectArray(env, certCount, byteArrayClass, NULL);
|
|
// Cleanup first then check for a NULL return code
|
|
(*env)->DeleteLocalRef(env, byteArrayClass);
|
|
if (javaCertArray == NULL) {
|
|
goto errOut;
|
|
}
|
|
|
|
// And, make an array of the certificate refs.
|
|
jlongArray certRefArray = (*env)->NewLongArray(env, certCount);
|
|
if (certRefArray == NULL) {
|
|
goto errOut;
|
|
}
|
|
|
|
SecCertificateRef currCertRef = NULL;
|
|
|
|
for (i = 0; i < certCount; i++) {
|
|
CSSM_DATA currCertData;
|
|
|
|
if (i == 0)
|
|
currCertRef = certificate;
|
|
else
|
|
currCertRef = (SecCertificateRef)CFArrayGetValueAtIndex(certChain, i);
|
|
|
|
bzero(&currCertData, sizeof(CSSM_DATA));
|
|
err = SecCertificateGetData(currCertRef, &currCertData);
|
|
jbyteArray encodedCertData = (*env)->NewByteArray(env, currCertData.Length);
|
|
if (encodedCertData == NULL) {
|
|
goto errOut;
|
|
}
|
|
(*env)->SetByteArrayRegion(env, encodedCertData, 0, currCertData.Length, (jbyte *)currCertData.Data);
|
|
(*env)->SetObjectArrayElement(env, javaCertArray, i, encodedCertData);
|
|
jlong certRefElement = ptr_to_jlong(currCertRef);
|
|
(*env)->SetLongArrayRegion(env, certRefArray, i, 1, &certRefElement);
|
|
}
|
|
|
|
// Get the private key. When needed we'll export the data from it later.
|
|
SecKeyRef privateKeyRef;
|
|
err = SecIdentityCopyPrivateKey(theIdentity, &privateKeyRef);
|
|
|
|
// Find the label. It's a 'blob', but we interpret as characters.
|
|
jstring alias = getLabelFromItem(env, (SecKeychainItemRef)certificate);
|
|
if (alias == NULL) {
|
|
goto errOut;
|
|
}
|
|
|
|
// Find the creation date.
|
|
jlong creationDate = getModDateFromItem(env, (SecKeychainItemRef)certificate);
|
|
|
|
// Call back to the Java object to create Java objects corresponding to this security object.
|
|
jlong nativeKeyRef = ptr_to_jlong(privateKeyRef);
|
|
JNFCallVoidMethod(env, keyStore, jm_createKeyEntry, alias, creationDate, nativeKeyRef, certRefArray, javaCertArray);
|
|
}
|
|
} while (searchResult == noErr);
|
|
|
|
errOut:
|
|
if (identitySearch != NULL) {
|
|
CFRelease(identitySearch);
|
|
}
|
|
}
|
|
|
|
static void addCertificatesToKeystore(JNIEnv *env, jobject keyStore)
|
|
{
|
|
// Search the user keychain list for all X509 certificates.
|
|
SecKeychainSearchRef keychainItemSearch = NULL;
|
|
OSStatus err = SecKeychainSearchCreateFromAttributes(NULL, kSecCertificateItemClass, NULL, &keychainItemSearch);
|
|
SecKeychainItemRef theItem = NULL;
|
|
OSErr searchResult = noErr;
|
|
|
|
do {
|
|
searchResult = SecKeychainSearchCopyNext(keychainItemSearch, &theItem);
|
|
|
|
if (searchResult == noErr) {
|
|
// Make a byte array with the DER-encoded contents of the certificate.
|
|
SecCertificateRef certRef = (SecCertificateRef)theItem;
|
|
CSSM_DATA currCertificate;
|
|
err = SecCertificateGetData(certRef, &currCertificate);
|
|
jbyteArray certData = (*env)->NewByteArray(env, currCertificate.Length);
|
|
if (certData == NULL) {
|
|
goto errOut;
|
|
}
|
|
(*env)->SetByteArrayRegion(env, certData, 0, currCertificate.Length, (jbyte *)currCertificate.Data);
|
|
|
|
// Find the label. It's a 'blob', but we interpret as characters.
|
|
jstring alias = getLabelFromItem(env, theItem);
|
|
if (alias == NULL) {
|
|
goto errOut;
|
|
}
|
|
|
|
// Find the creation date.
|
|
jlong creationDate = getModDateFromItem(env, theItem);
|
|
|
|
// Call back to the Java object to create Java objects corresponding to this security object.
|
|
jlong nativeRef = ptr_to_jlong(certRef);
|
|
JNFCallVoidMethod(env, keyStore, jm_createTrustedCertEntry, alias, nativeRef, creationDate, certData);
|
|
}
|
|
} while (searchResult == noErr);
|
|
|
|
errOut:
|
|
if (keychainItemSearch != NULL) {
|
|
CFRelease(keychainItemSearch);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Class: apple_security_KeychainStore
|
|
* Method: _getEncodedKeyData
|
|
* Signature: (J)[B
|
|
*/
|
|
JNIEXPORT jbyteArray JNICALL Java_apple_security_KeychainStore__1getEncodedKeyData
|
|
(JNIEnv *env, jobject this, jlong keyRefLong, jcharArray passwordObj)
|
|
{
|
|
SecKeyRef keyRef = (SecKeyRef)jlong_to_ptr(keyRefLong);
|
|
SecKeyImportExportParameters paramBlock;
|
|
OSStatus err = noErr;
|
|
CFDataRef exportedData = NULL;
|
|
jbyteArray returnValue = NULL;
|
|
CFStringRef passwordStrRef = NULL;
|
|
|
|
jsize passwordLen = 0;
|
|
jchar *passwordChars = NULL;
|
|
|
|
if (passwordObj) {
|
|
passwordLen = (*env)->GetArrayLength(env, passwordObj);
|
|
|
|
if (passwordLen > 0) {
|
|
passwordChars = (*env)->GetCharArrayElements(env, passwordObj, NULL);
|
|
if (passwordChars == NULL) {
|
|
goto errOut;
|
|
}
|
|
passwordStrRef = CFStringCreateWithCharacters(kCFAllocatorDefault, passwordChars, passwordLen);
|
|
|
|
// clear the password and release
|
|
memset(passwordChars, 0, passwordLen);
|
|
(*env)->ReleaseCharArrayElements(env, passwordObj, passwordChars,
|
|
JNI_ABORT);
|
|
}
|
|
}
|
|
|
|
paramBlock.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
|
|
// Note that setting the flags field **requires** you to pass in a password of some kind. The keychain will not prompt you.
|
|
paramBlock.flags = 0;
|
|
paramBlock.passphrase = passwordStrRef;
|
|
paramBlock.alertTitle = NULL;
|
|
paramBlock.alertPrompt = NULL;
|
|
paramBlock.accessRef = NULL;
|
|
paramBlock.keyUsage = CSSM_KEYUSE_ANY;
|
|
paramBlock.keyAttributes = CSSM_KEYATTR_RETURN_DEFAULT;
|
|
|
|
err = SecKeychainItemExport(keyRef, kSecFormatPKCS12, 0, ¶mBlock, &exportedData);
|
|
|
|
if (err == noErr) {
|
|
CFIndex size = CFDataGetLength(exportedData);
|
|
returnValue = (*env)->NewByteArray(env, size);
|
|
if (returnValue == NULL) {
|
|
goto errOut;
|
|
}
|
|
(*env)->SetByteArrayRegion(env, returnValue, 0, size, (jbyte *)CFDataGetBytePtr(exportedData));
|
|
}
|
|
|
|
errOut:
|
|
if (exportedData) CFRelease(exportedData);
|
|
if (passwordStrRef) CFRelease(passwordStrRef);
|
|
|
|
return returnValue;
|
|
}
|
|
|
|
|
|
/*
|
|
* Class: apple_security_KeychainStore
|
|
* Method: _scanKeychain
|
|
* Signature: ()V
|
|
*/
|
|
JNIEXPORT void JNICALL Java_apple_security_KeychainStore__1scanKeychain
|
|
(JNIEnv *env, jobject this)
|
|
{
|
|
// Look for 'identities' -- private key and certificate chain pairs -- and add those.
|
|
// Search for these first, because a certificate that's found here as part of an identity will show up
|
|
// again later as a certificate.
|
|
addIdentitiesToKeystore(env, this);
|
|
|
|
// Scan current keychain for trusted certificates.
|
|
addCertificatesToKeystore(env, this);
|
|
|
|
}
|
|
|
|
/*
|
|
* Class: apple_security_KeychainStore
|
|
* Method: _addItemToKeychain
|
|
* Signature: (Ljava/lang/String;[B)I
|
|
*/
|
|
JNIEXPORT jlong JNICALL Java_apple_security_KeychainStore__1addItemToKeychain
|
|
(JNIEnv *env, jobject this, jstring alias, jboolean isCertificate, jbyteArray rawDataObj, jcharArray passwordObj)
|
|
{
|
|
OSStatus err;
|
|
jlong returnValue = 0;
|
|
|
|
JNF_COCOA_ENTER(env);
|
|
|
|
jsize dataSize = (*env)->GetArrayLength(env, rawDataObj);
|
|
jbyte *rawData = (*env)->GetByteArrayElements(env, rawDataObj, NULL);
|
|
if (rawData == NULL) {
|
|
goto errOut;
|
|
}
|
|
|
|
CFDataRef cfDataToImport = CFDataCreate(kCFAllocatorDefault, (UInt8 *)rawData, dataSize);
|
|
CFArrayRef createdItems = NULL;
|
|
|
|
SecKeychainRef defaultKeychain = NULL;
|
|
SecKeychainCopyDefault(&defaultKeychain);
|
|
|
|
SecExternalFormat dataFormat = (isCertificate == JNI_TRUE ? kSecFormatX509Cert : kSecFormatWrappedPKCS8);
|
|
|
|
// Convert the password obj into a CFStringRef that the keychain importer can use for encryption.
|
|
SecKeyImportExportParameters paramBlock;
|
|
CFStringRef passwordStrRef = NULL;
|
|
|
|
jsize passwordLen = 0;
|
|
jchar *passwordChars = NULL;
|
|
|
|
if (passwordObj) {
|
|
passwordLen = (*env)->GetArrayLength(env, passwordObj);
|
|
|
|
if (passwordLen > 0) {
|
|
passwordChars = (*env)->GetCharArrayElements(env, passwordObj, NULL);
|
|
if (passwordChars == NULL) {
|
|
goto errOut;
|
|
}
|
|
passwordStrRef = CFStringCreateWithCharacters(kCFAllocatorDefault, passwordChars, passwordLen);
|
|
|
|
// clear the password and release
|
|
memset(passwordChars, 0, passwordLen);
|
|
(*env)->ReleaseCharArrayElements(env, passwordObj, passwordChars,
|
|
JNI_ABORT);
|
|
}
|
|
}
|
|
|
|
paramBlock.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
|
|
// Note that setting the flags field **requires** you to pass in a password of some kind. The keychain will not prompt you.
|
|
paramBlock.flags = 0;
|
|
paramBlock.passphrase = passwordStrRef;
|
|
paramBlock.alertTitle = NULL;
|
|
paramBlock.alertPrompt = NULL;
|
|
paramBlock.accessRef = NULL;
|
|
paramBlock.keyUsage = CSSM_KEYUSE_ANY;
|
|
paramBlock.keyAttributes = CSSM_KEYATTR_RETURN_DEFAULT;
|
|
|
|
err = SecKeychainItemImport(cfDataToImport, NULL, &dataFormat, NULL,
|
|
0, ¶mBlock, defaultKeychain, &createdItems);
|
|
|
|
if (err == noErr) {
|
|
SecKeychainItemRef anItem = (SecKeychainItemRef)CFArrayGetValueAtIndex(createdItems, 0);
|
|
|
|
// Don't bother labeling keys. They become part of an identity, and are not an accessible part of the keychain.
|
|
if (CFGetTypeID(anItem) == SecCertificateGetTypeID()) {
|
|
setLabelForItem(JNFJavaToNSString(env, alias), anItem);
|
|
}
|
|
|
|
// Retain the item, since it will be released once when the array holding it gets released.
|
|
CFRetain(anItem);
|
|
returnValue = ptr_to_jlong(anItem);
|
|
} else {
|
|
cssmPerror("_addItemToKeychain: SecKeychainItemImport", err);
|
|
}
|
|
|
|
(*env)->ReleaseByteArrayElements(env, rawDataObj, rawData, JNI_ABORT);
|
|
|
|
if (createdItems != NULL) {
|
|
CFRelease(createdItems);
|
|
}
|
|
|
|
errOut: ;
|
|
|
|
JNF_COCOA_EXIT(env);
|
|
|
|
return returnValue;
|
|
}
|
|
|
|
/*
|
|
* Class: apple_security_KeychainStore
|
|
* Method: _removeItemFromKeychain
|
|
* Signature: (J)I
|
|
*/
|
|
JNIEXPORT jint JNICALL Java_apple_security_KeychainStore__1removeItemFromKeychain
|
|
(JNIEnv *env, jobject this, jlong keychainItem)
|
|
{
|
|
SecKeychainItemRef itemToRemove = jlong_to_ptr(keychainItem);
|
|
return SecKeychainItemDelete(itemToRemove);
|
|
}
|
|
|
|
/*
|
|
* Class: apple_security_KeychainStore
|
|
* Method: _releaseKeychainItemRef
|
|
* Signature: (J)V
|
|
*/
|
|
JNIEXPORT void JNICALL Java_apple_security_KeychainStore__1releaseKeychainItemRef
|
|
(JNIEnv *env, jobject this, jlong keychainItem)
|
|
{
|
|
SecKeychainItemRef itemToFree = jlong_to_ptr(keychainItem);
|
|
CFRelease(itemToFree);
|
|
}
|