diff -r 13967da712ff -r ba2c9c7773b6 jdk/src/jdk.deploy.osx/macosx/native/libosx/KeystoreImpl.m --- a/jdk/src/jdk.deploy.osx/macosx/native/libosx/KeystoreImpl.m Thu Aug 20 11:38:20 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,589 +0,0 @@ -/* - * Copyright (c) 2011, 2014, 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 -#import -#import // (for require() macros) -#import - - -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; dexFindClass(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); - } - } - - 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); - - SecExternalItemType dataType = (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); - passwordChars = (*env)->GetCharArrayElements(env, passwordObj, NULL); - passwordStrRef = CFStringCreateWithCharacters(kCFAllocatorDefault, passwordChars, passwordLen); - } - - 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, &dataType, 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); -}