--- 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 <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);
- }
- }
-
- 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);
-}