annotate src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m @ 17467:f8e75da258cd

8205124: aarch32: make build work again with jvm-variant=core Reviewed-by: duke
author enevill
date Fri, 15 Jun 2018 21:24:39 +0100
parents f98d9515afea
children
rev   line source
michaelm@5116 1 /*
vinnie@17411 2 * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
michaelm@5116 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
michaelm@5116 4 *
michaelm@5116 5 * This code is free software; you can redistribute it and/or modify it
michaelm@5116 6 * under the terms of the GNU General Public License version 2 only, as
michaelm@5116 7 * published by the Free Software Foundation. Oracle designates this
michaelm@5116 8 * particular file as subject to the "Classpath" exception as provided
michaelm@5116 9 * by Oracle in the LICENSE file that accompanied this code.
michaelm@5116 10 *
michaelm@5116 11 * This code is distributed in the hope that it will be useful, but WITHOUT
michaelm@5116 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
michaelm@5116 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
michaelm@5116 14 * version 2 for more details (a copy is included in the LICENSE file that
michaelm@5116 15 * accompanied this code).
michaelm@5116 16 *
michaelm@5116 17 * You should have received a copy of the GNU General Public License version
michaelm@5116 18 * 2 along with this work; if not, write to the Free Software Foundation,
michaelm@5116 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
michaelm@5116 20 *
michaelm@5116 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
michaelm@5116 22 * or visit www.oracle.com if you need additional information or have any
michaelm@5116 23 * questions.
michaelm@5116 24 */
michaelm@5116 25
michaelm@5116 26 #import "apple_security_KeychainStore.h"
michaelm@5116 27
michaelm@5116 28 #import <Security/Security.h>
michaelm@5116 29 #import <Security/SecImportExport.h>
michaelm@5116 30 #import <CoreServices/CoreServices.h> // (for require() macros)
michaelm@5116 31 #import <JavaNativeFoundation/JavaNativeFoundation.h>
michaelm@5116 32
michaelm@5116 33
michaelm@5116 34 static JNF_CLASS_CACHE(jc_KeychainStore, "apple/security/KeychainStore");
michaelm@5116 35 static JNF_MEMBER_CACHE(jm_createTrustedCertEntry, jc_KeychainStore, "createTrustedCertEntry", "(Ljava/lang/String;JJ[B)V");
michaelm@5116 36 static JNF_MEMBER_CACHE(jm_createKeyEntry, jc_KeychainStore, "createKeyEntry", "(Ljava/lang/String;JJ[J[[B)V");
michaelm@5116 37
michaelm@5116 38 static jstring getLabelFromItem(JNIEnv *env, SecKeychainItemRef inItem)
michaelm@5116 39 {
michaelm@5116 40 OSStatus status;
michaelm@5116 41 jstring returnValue = NULL;
michaelm@5116 42 char *attribCString = NULL;
michaelm@5116 43
michaelm@5116 44 SecKeychainAttribute itemAttrs[] = { { kSecLabelItemAttr, 0, NULL } };
michaelm@5116 45 SecKeychainAttributeList attrList = { sizeof(itemAttrs) / sizeof(itemAttrs[0]), itemAttrs };
michaelm@5116 46
michaelm@5116 47 status = SecKeychainItemCopyContent(inItem, NULL, &attrList, NULL, NULL);
michaelm@5116 48
michaelm@5116 49 if(status) {
michaelm@5116 50 cssmPerror("getLabelFromItem: SecKeychainItemCopyContent", status);
michaelm@5116 51 goto errOut;
michaelm@5116 52 }
michaelm@5116 53
michaelm@5116 54 attribCString = malloc(itemAttrs[0].length + 1);
michaelm@5116 55 strncpy(attribCString, itemAttrs[0].data, itemAttrs[0].length);
michaelm@5116 56 attribCString[itemAttrs[0].length] = '\0';
michaelm@5116 57 returnValue = (*env)->NewStringUTF(env, attribCString);
michaelm@5116 58
michaelm@5116 59 errOut:
michaelm@5116 60 SecKeychainItemFreeContent(&attrList, NULL);
michaelm@5116 61 if (attribCString) free(attribCString);
michaelm@5116 62 return returnValue;
michaelm@5116 63 }
michaelm@5116 64
michaelm@5116 65 static jlong getModDateFromItem(JNIEnv *env, SecKeychainItemRef inItem)
michaelm@5116 66 {
michaelm@5116 67 OSStatus status;
michaelm@5116 68 SecKeychainAttribute itemAttrs[] = { { kSecModDateItemAttr, 0, NULL } };
michaelm@5116 69 SecKeychainAttributeList attrList = { sizeof(itemAttrs) / sizeof(itemAttrs[0]), itemAttrs };
michaelm@5116 70 jlong returnValue = 0;
michaelm@5116 71
michaelm@5116 72 status = SecKeychainItemCopyContent(inItem, NULL, &attrList, NULL, NULL);
michaelm@5116 73
michaelm@5116 74 if(status) {
michaelm@5116 75 // This is almost always missing, so don't dump an error.
michaelm@5116 76 // cssmPerror("getModDateFromItem: SecKeychainItemCopyContent", status);
michaelm@5116 77 goto errOut;
michaelm@5116 78 }
michaelm@5116 79
michaelm@5116 80 memcpy(&returnValue, itemAttrs[0].data, itemAttrs[0].length);
michaelm@5116 81
michaelm@5116 82 errOut:
michaelm@5116 83 SecKeychainItemFreeContent(&attrList, NULL);
michaelm@5116 84 return returnValue;
michaelm@5116 85 }
michaelm@5116 86
michaelm@5116 87 static void setLabelForItem(NSString *inLabel, SecKeychainItemRef inItem)
michaelm@5116 88 {
michaelm@5116 89 OSStatus status;
michaelm@5116 90 const char *labelCString = [inLabel UTF8String];
michaelm@5116 91
michaelm@5116 92 // Set up attribute vector (each attribute consists of {tag, length, pointer}):
michaelm@5116 93 SecKeychainAttribute attrs[] = {
michaelm@5116 94 { kSecLabelItemAttr, strlen(labelCString), (void *)labelCString }
michaelm@5116 95 };
michaelm@5116 96
michaelm@5116 97 const SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs };
michaelm@5116 98
michaelm@5116 99 // Not changing data here, just attributes.
michaelm@5116 100 status = SecKeychainItemModifyContent(inItem, &attributes, 0, NULL);
michaelm@5116 101
michaelm@5116 102 if(status) {
michaelm@5116 103 cssmPerror("setLabelForItem: SecKeychainItemModifyContent", status);
michaelm@5116 104 }
michaelm@5116 105 }
michaelm@5116 106
michaelm@5116 107 /*
michaelm@5116 108 * Given a SecIdentityRef, do our best to construct a complete, ordered, and
michaelm@5116 109 * verified cert chain, returning the result in a CFArrayRef. The result is
michaelm@5116 110 * can be passed back to Java as a chain for a private key.
michaelm@5116 111 */
michaelm@5116 112 static OSStatus completeCertChain(
michaelm@5116 113 SecIdentityRef identity,
michaelm@5116 114 SecCertificateRef trustedAnchor, // optional additional trusted anchor
michaelm@5116 115 bool includeRoot, // include the root in outArray
michaelm@5116 116 CFArrayRef *outArray) // created and RETURNED
michaelm@5116 117 {
michaelm@5116 118 SecTrustRef secTrust = NULL;
michaelm@5116 119 SecPolicyRef policy = NULL;
michaelm@5116 120 SecPolicySearchRef policySearch = NULL;
michaelm@5116 121 SecTrustResultType secTrustResult;
michaelm@5116 122 CSSM_TP_APPLE_EVIDENCE_INFO *dummyEv; // not used
michaelm@5116 123 CFArrayRef certChain = NULL; // constructed chain, CERTS ONLY
michaelm@5116 124 CFMutableArrayRef subjCerts; // passed to SecTrust
michaelm@5116 125 CFMutableArrayRef certArray; // returned array starting with
michaelm@5116 126 // identity
michaelm@5116 127 CFIndex numResCerts;
michaelm@5116 128 CFIndex dex;
michaelm@5116 129 OSStatus ortn;
michaelm@5116 130 SecCertificateRef certRef;
michaelm@5116 131
michaelm@5116 132 /* First element in out array is the SecIdentity */
michaelm@5116 133 certArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
michaelm@5116 134 CFArrayAppendValue(certArray, identity);
michaelm@5116 135
michaelm@5116 136 /* the single element in certs-to-be-evaluated comes from the identity */
michaelm@5116 137 ortn = SecIdentityCopyCertificate(identity, &certRef);
michaelm@5116 138 if(ortn) {
michaelm@5116 139 /* should never happen */
michaelm@5116 140 cssmPerror("SecIdentityCopyCertificate", ortn);
michaelm@5116 141 return ortn;
michaelm@5116 142 }
michaelm@5116 143
michaelm@5116 144 /*
michaelm@5116 145 * Now use SecTrust to get a complete cert chain, using all of the
michaelm@5116 146 * user's keychains to look for intermediate certs.
michaelm@5116 147 * NOTE this does NOT handle root certs which are not in the system
michaelm@5116 148 * root cert DB.
michaelm@5116 149 */
michaelm@5116 150 subjCerts = CFArrayCreateMutable(NULL, 1, &kCFTypeArrayCallBacks);
michaelm@5116 151 CFArraySetValueAtIndex(subjCerts, 0, certRef);
michaelm@5116 152
michaelm@5116 153 /* the array owns the subject cert ref now */
michaelm@5116 154 CFRelease(certRef);
michaelm@5116 155
michaelm@5116 156 /* Get a SecPolicyRef for generic X509 cert chain verification */
michaelm@5116 157 ortn = SecPolicySearchCreate(CSSM_CERT_X_509v3,
michaelm@5116 158 &CSSMOID_APPLE_X509_BASIC,
michaelm@5116 159 NULL, // value
michaelm@5116 160 &policySearch);
michaelm@5116 161 if(ortn) {
michaelm@5116 162 /* should never happen */
michaelm@5116 163 cssmPerror("SecPolicySearchCreate", ortn);
michaelm@5116 164 goto errOut;
michaelm@5116 165 }
michaelm@5116 166 ortn = SecPolicySearchCopyNext(policySearch, &policy);
michaelm@5116 167 if(ortn) {
michaelm@5116 168 /* should never happen */
michaelm@5116 169 cssmPerror("SecPolicySearchCopyNext", ortn);
michaelm@5116 170 goto errOut;
michaelm@5116 171 }
michaelm@5116 172
michaelm@5116 173 /* build a SecTrustRef for specified policy and certs */
michaelm@5116 174 ortn = SecTrustCreateWithCertificates(subjCerts,
michaelm@5116 175 policy, &secTrust);
michaelm@5116 176 if(ortn) {
michaelm@5116 177 cssmPerror("SecTrustCreateWithCertificates", ortn);
michaelm@5116 178 goto errOut;
michaelm@5116 179 }
michaelm@5116 180
michaelm@5116 181 if(trustedAnchor) {
michaelm@5116 182 /*
michaelm@5116 183 * Tell SecTrust to trust this one in addition to the current
michaelm@5116 184 * trusted system-wide anchors.
michaelm@5116 185 */
michaelm@5116 186 CFMutableArrayRef newAnchors;
michaelm@5116 187 CFArrayRef currAnchors;
michaelm@5116 188
michaelm@5116 189 ortn = SecTrustCopyAnchorCertificates(&currAnchors);
michaelm@5116 190 if(ortn) {
michaelm@5116 191 /* should never happen */
michaelm@5116 192 cssmPerror("SecTrustCopyAnchorCertificates", ortn);
michaelm@5116 193 goto errOut;
michaelm@5116 194 }
michaelm@5116 195 newAnchors = CFArrayCreateMutableCopy(NULL,
michaelm@5116 196 CFArrayGetCount(currAnchors) + 1,
michaelm@5116 197 currAnchors);
michaelm@5116 198 CFRelease(currAnchors);
michaelm@5116 199 CFArrayAppendValue(newAnchors, trustedAnchor);
michaelm@5116 200 ortn = SecTrustSetAnchorCertificates(secTrust, newAnchors);
michaelm@5116 201 CFRelease(newAnchors);
michaelm@5116 202 if(ortn) {
michaelm@5116 203 cssmPerror("SecTrustSetAnchorCertificates", ortn);
michaelm@5116 204 goto errOut;
michaelm@5116 205 }
michaelm@5116 206 }
michaelm@5116 207
michaelm@5116 208 /* evaluate: GO */
michaelm@5116 209 ortn = SecTrustEvaluate(secTrust, &secTrustResult);
michaelm@5116 210 if(ortn) {
michaelm@5116 211 cssmPerror("SecTrustEvaluate", ortn);
michaelm@5116 212 goto errOut;
michaelm@5116 213 }
michaelm@5116 214 switch(secTrustResult) {
michaelm@5116 215 case kSecTrustResultUnspecified:
michaelm@5116 216 /* cert chain valid, no special UserTrust assignments; drop thru */
michaelm@5116 217 case kSecTrustResultProceed:
michaelm@5116 218 /* cert chain valid AND user explicitly trusts this */
michaelm@5116 219 break;
michaelm@5116 220 default:
michaelm@5116 221 /*
michaelm@5116 222 * Cert chain construction failed.
michaelm@5116 223 * Just go with the single subject cert we were given; maybe the
michaelm@5116 224 * peer can complete the chain.
michaelm@5116 225 */
michaelm@5116 226 ortn = noErr;
michaelm@5116 227 goto errOut;
michaelm@5116 228 }
michaelm@5116 229
michaelm@5116 230 /* get resulting constructed cert chain */
michaelm@5116 231 ortn = SecTrustGetResult(secTrust, &secTrustResult, &certChain, &dummyEv);
michaelm@5116 232 if(ortn) {
michaelm@5116 233 cssmPerror("SecTrustEvaluate", ortn);
michaelm@5116 234 goto errOut;
michaelm@5116 235 }
michaelm@5116 236
michaelm@5116 237 /*
michaelm@5116 238 * Copy certs from constructed chain to our result array, skipping
michaelm@5116 239 * the leaf (which is already there, as a SecIdentityRef) and possibly
michaelm@5116 240 * a root.
michaelm@5116 241 */
michaelm@5116 242 numResCerts = CFArrayGetCount(certChain);
michaelm@5116 243 if(numResCerts < 1) {
michaelm@5116 244 /*
michaelm@5116 245 * Can't happen: If chain doesn't verify to a root, we'd
michaelm@5116 246 * have bailed after SecTrustEvaluate().
michaelm@5116 247 */
michaelm@5116 248 ortn = noErr;
michaelm@5116 249 goto errOut;
michaelm@5116 250 }
michaelm@5116 251 if(!includeRoot) {
michaelm@5116 252 /* skip the last (root) cert) */
michaelm@5116 253 numResCerts--;
michaelm@5116 254 }
michaelm@5116 255 for(dex=1; dex<numResCerts; dex++) {
michaelm@5116 256 certRef = (SecCertificateRef)CFArrayGetValueAtIndex(certChain, dex);
michaelm@5116 257 CFArrayAppendValue(certArray, certRef);
michaelm@5116 258 }
michaelm@5116 259 errOut:
michaelm@5116 260 /* clean up */
michaelm@5116 261 if(secTrust) {
michaelm@5116 262 CFRelease(secTrust);
michaelm@5116 263 }
michaelm@5116 264 if(subjCerts) {
michaelm@5116 265 CFRelease(subjCerts);
michaelm@5116 266 }
michaelm@5116 267 if(policy) {
michaelm@5116 268 CFRelease(policy);
michaelm@5116 269 }
michaelm@5116 270 if(policySearch) {
michaelm@5116 271 CFRelease(policySearch);
michaelm@5116 272 }
michaelm@5116 273 *outArray = certArray;
michaelm@5116 274 return ortn;
michaelm@5116 275 }
michaelm@5116 276
michaelm@5116 277 static void addIdentitiesToKeystore(JNIEnv *env, jobject keyStore)
michaelm@5116 278 {
michaelm@5116 279 // Search the user keychain list for all identities. Identities are a certificate/private key association that
michaelm@5116 280 // can be chosen for a purpose such as signing or an SSL connection.
michaelm@5116 281 SecIdentitySearchRef identitySearch = NULL;
vinnie@10947 282 // Pass 0 if you want all identities returned by this search
vinnie@10947 283 OSStatus err = SecIdentitySearchCreate(NULL, 0, &identitySearch);
michaelm@5116 284 SecIdentityRef theIdentity = NULL;
michaelm@5116 285 OSErr searchResult = noErr;
michaelm@5116 286
michaelm@5116 287 do {
michaelm@5116 288 searchResult = SecIdentitySearchCopyNext(identitySearch, &theIdentity);
michaelm@5116 289
michaelm@5116 290 if (searchResult == noErr) {
michaelm@5116 291 // Get the cert from the identity, then generate a chain.
michaelm@5116 292 SecCertificateRef certificate;
michaelm@5116 293 SecIdentityCopyCertificate(theIdentity, &certificate);
michaelm@5116 294 CFArrayRef certChain = NULL;
michaelm@5116 295
michaelm@5116 296 // *** Should do something with this error...
michaelm@5116 297 err = completeCertChain(theIdentity, NULL, TRUE, &certChain);
michaelm@5116 298
michaelm@5116 299 CFIndex i, certCount = CFArrayGetCount(certChain);
michaelm@5116 300
michaelm@5116 301 // Make a java array of certificate data from the chain.
michaelm@5116 302 jclass byteArrayClass = (*env)->FindClass(env, "[B");
vinnie@10970 303 if (byteArrayClass == NULL) {
vinnie@10970 304 goto errOut;
vinnie@10970 305 }
michaelm@5116 306 jobjectArray javaCertArray = (*env)->NewObjectArray(env, certCount, byteArrayClass, NULL);
vinnie@10970 307 // Cleanup first then check for a NULL return code
michaelm@5116 308 (*env)->DeleteLocalRef(env, byteArrayClass);
vinnie@10970 309 if (javaCertArray == NULL) {
vinnie@10970 310 goto errOut;
vinnie@10970 311 }
michaelm@5116 312
michaelm@5116 313 // And, make an array of the certificate refs.
michaelm@5116 314 jlongArray certRefArray = (*env)->NewLongArray(env, certCount);
vinnie@10970 315 if (certRefArray == NULL) {
vinnie@10970 316 goto errOut;
vinnie@10970 317 }
michaelm@5116 318
michaelm@5116 319 SecCertificateRef currCertRef = NULL;
michaelm@5116 320
michaelm@5116 321 for (i = 0; i < certCount; i++) {
michaelm@5116 322 CSSM_DATA currCertData;
michaelm@5116 323
michaelm@5116 324 if (i == 0)
michaelm@5116 325 currCertRef = certificate;
michaelm@5116 326 else
michaelm@5116 327 currCertRef = (SecCertificateRef)CFArrayGetValueAtIndex(certChain, i);
michaelm@5116 328
michaelm@5116 329 bzero(&currCertData, sizeof(CSSM_DATA));
michaelm@5116 330 err = SecCertificateGetData(currCertRef, &currCertData);
michaelm@5116 331 jbyteArray encodedCertData = (*env)->NewByteArray(env, currCertData.Length);
vinnie@10970 332 if (encodedCertData == NULL) {
vinnie@10970 333 goto errOut;
vinnie@10970 334 }
michaelm@5116 335 (*env)->SetByteArrayRegion(env, encodedCertData, 0, currCertData.Length, (jbyte *)currCertData.Data);
michaelm@5116 336 (*env)->SetObjectArrayElement(env, javaCertArray, i, encodedCertData);
michaelm@5116 337 jlong certRefElement = ptr_to_jlong(currCertRef);
michaelm@5116 338 (*env)->SetLongArrayRegion(env, certRefArray, i, 1, &certRefElement);
michaelm@5116 339 }
michaelm@5116 340
michaelm@5116 341 // Get the private key. When needed we'll export the data from it later.
michaelm@5116 342 SecKeyRef privateKeyRef;
michaelm@5116 343 err = SecIdentityCopyPrivateKey(theIdentity, &privateKeyRef);
michaelm@5116 344
michaelm@5116 345 // Find the label. It's a 'blob', but we interpret as characters.
michaelm@5116 346 jstring alias = getLabelFromItem(env, (SecKeychainItemRef)certificate);
vinnie@10970 347 if (alias == NULL) {
vinnie@10970 348 goto errOut;
vinnie@10970 349 }
michaelm@5116 350
michaelm@5116 351 // Find the creation date.
michaelm@5116 352 jlong creationDate = getModDateFromItem(env, (SecKeychainItemRef)certificate);
michaelm@5116 353
michaelm@5116 354 // Call back to the Java object to create Java objects corresponding to this security object.
michaelm@5116 355 jlong nativeKeyRef = ptr_to_jlong(privateKeyRef);
michaelm@5116 356 JNFCallVoidMethod(env, keyStore, jm_createKeyEntry, alias, creationDate, nativeKeyRef, certRefArray, javaCertArray);
michaelm@5116 357 }
michaelm@5116 358 } while (searchResult == noErr);
michaelm@5116 359
vinnie@10970 360 errOut:
michaelm@5116 361 if (identitySearch != NULL) {
michaelm@5116 362 CFRelease(identitySearch);
michaelm@5116 363 }
michaelm@5116 364 }
michaelm@5116 365
michaelm@5116 366 static void addCertificatesToKeystore(JNIEnv *env, jobject keyStore)
michaelm@5116 367 {
michaelm@5116 368 // Search the user keychain list for all X509 certificates.
michaelm@5116 369 SecKeychainSearchRef keychainItemSearch = NULL;
michaelm@5116 370 OSStatus err = SecKeychainSearchCreateFromAttributes(NULL, kSecCertificateItemClass, NULL, &keychainItemSearch);
michaelm@5116 371 SecKeychainItemRef theItem = NULL;
michaelm@5116 372 OSErr searchResult = noErr;
michaelm@5116 373
michaelm@5116 374 do {
michaelm@5116 375 searchResult = SecKeychainSearchCopyNext(keychainItemSearch, &theItem);
michaelm@5116 376
michaelm@5116 377 if (searchResult == noErr) {
michaelm@5116 378 // Make a byte array with the DER-encoded contents of the certificate.
michaelm@5116 379 SecCertificateRef certRef = (SecCertificateRef)theItem;
michaelm@5116 380 CSSM_DATA currCertificate;
michaelm@5116 381 err = SecCertificateGetData(certRef, &currCertificate);
michaelm@5116 382 jbyteArray certData = (*env)->NewByteArray(env, currCertificate.Length);
vinnie@10970 383 if (certData == NULL) {
vinnie@10970 384 goto errOut;
vinnie@10970 385 }
michaelm@5116 386 (*env)->SetByteArrayRegion(env, certData, 0, currCertificate.Length, (jbyte *)currCertificate.Data);
michaelm@5116 387
michaelm@5116 388 // Find the label. It's a 'blob', but we interpret as characters.
michaelm@5116 389 jstring alias = getLabelFromItem(env, theItem);
vinnie@10970 390 if (alias == NULL) {
vinnie@10970 391 goto errOut;
vinnie@10970 392 }
michaelm@5116 393
michaelm@5116 394 // Find the creation date.
michaelm@5116 395 jlong creationDate = getModDateFromItem(env, theItem);
michaelm@5116 396
michaelm@5116 397 // Call back to the Java object to create Java objects corresponding to this security object.
michaelm@5116 398 jlong nativeRef = ptr_to_jlong(certRef);
michaelm@5116 399 JNFCallVoidMethod(env, keyStore, jm_createTrustedCertEntry, alias, nativeRef, creationDate, certData);
michaelm@5116 400 }
michaelm@5116 401 } while (searchResult == noErr);
michaelm@5116 402
vinnie@10970 403 errOut:
michaelm@5116 404 if (keychainItemSearch != NULL) {
michaelm@5116 405 CFRelease(keychainItemSearch);
michaelm@5116 406 }
michaelm@5116 407 }
michaelm@5116 408
michaelm@5116 409 /*
michaelm@5116 410 * Class: apple_security_KeychainStore
michaelm@5116 411 * Method: _getEncodedKeyData
michaelm@5116 412 * Signature: (J)[B
michaelm@5116 413 */
michaelm@5116 414 JNIEXPORT jbyteArray JNICALL Java_apple_security_KeychainStore__1getEncodedKeyData
michaelm@5116 415 (JNIEnv *env, jobject this, jlong keyRefLong, jcharArray passwordObj)
michaelm@5116 416 {
michaelm@5116 417 SecKeyRef keyRef = (SecKeyRef)jlong_to_ptr(keyRefLong);
michaelm@5116 418 SecKeyImportExportParameters paramBlock;
michaelm@5116 419 OSStatus err = noErr;
michaelm@5116 420 CFDataRef exportedData = NULL;
michaelm@5116 421 jbyteArray returnValue = NULL;
michaelm@5116 422 CFStringRef passwordStrRef = NULL;
michaelm@5116 423
michaelm@5116 424 jsize passwordLen = 0;
michaelm@5116 425 jchar *passwordChars = NULL;
michaelm@5116 426
michaelm@5116 427 if (passwordObj) {
michaelm@5116 428 passwordLen = (*env)->GetArrayLength(env, passwordObj);
michaelm@5116 429
michaelm@5116 430 if (passwordLen > 0) {
michaelm@5116 431 passwordChars = (*env)->GetCharArrayElements(env, passwordObj, NULL);
vinnie@10970 432 if (passwordChars == NULL) {
vinnie@10970 433 goto errOut;
vinnie@10970 434 }
michaelm@5116 435 passwordStrRef = CFStringCreateWithCharacters(kCFAllocatorDefault, passwordChars, passwordLen);
vinnie@17411 436
vinnie@17411 437 // clear the password and release
vinnie@17411 438 memset(passwordChars, 0, passwordLen);
vinnie@17411 439 (*env)->ReleaseCharArrayElements(env, passwordObj, passwordChars,
vinnie@17411 440 JNI_ABORT);
michaelm@5116 441 }
michaelm@5116 442 }
michaelm@5116 443
michaelm@5116 444 paramBlock.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
michaelm@5116 445 // Note that setting the flags field **requires** you to pass in a password of some kind. The keychain will not prompt you.
michaelm@5116 446 paramBlock.flags = 0;
michaelm@5116 447 paramBlock.passphrase = passwordStrRef;
michaelm@5116 448 paramBlock.alertTitle = NULL;
michaelm@5116 449 paramBlock.alertPrompt = NULL;
michaelm@5116 450 paramBlock.accessRef = NULL;
michaelm@5116 451 paramBlock.keyUsage = CSSM_KEYUSE_ANY;
michaelm@5116 452 paramBlock.keyAttributes = CSSM_KEYATTR_RETURN_DEFAULT;
michaelm@5116 453
michaelm@5116 454 err = SecKeychainItemExport(keyRef, kSecFormatPKCS12, 0, &paramBlock, &exportedData);
michaelm@5116 455
michaelm@5116 456 if (err == noErr) {
michaelm@5116 457 CFIndex size = CFDataGetLength(exportedData);
michaelm@5116 458 returnValue = (*env)->NewByteArray(env, size);
vinnie@10970 459 if (returnValue == NULL) {
vinnie@10970 460 goto errOut;
vinnie@10970 461 }
michaelm@5116 462 (*env)->SetByteArrayRegion(env, returnValue, 0, size, (jbyte *)CFDataGetBytePtr(exportedData));
michaelm@5116 463 }
michaelm@5116 464
vinnie@10970 465 errOut:
michaelm@5116 466 if (exportedData) CFRelease(exportedData);
michaelm@5116 467 if (passwordStrRef) CFRelease(passwordStrRef);
michaelm@5116 468
michaelm@5116 469 return returnValue;
michaelm@5116 470 }
michaelm@5116 471
michaelm@5116 472
michaelm@5116 473 /*
michaelm@5116 474 * Class: apple_security_KeychainStore
michaelm@5116 475 * Method: _scanKeychain
michaelm@5116 476 * Signature: ()V
michaelm@5116 477 */
michaelm@5116 478 JNIEXPORT void JNICALL Java_apple_security_KeychainStore__1scanKeychain
michaelm@5116 479 (JNIEnv *env, jobject this)
michaelm@5116 480 {
michaelm@5116 481 // Look for 'identities' -- private key and certificate chain pairs -- and add those.
michaelm@5116 482 // Search for these first, because a certificate that's found here as part of an identity will show up
michaelm@5116 483 // again later as a certificate.
michaelm@5116 484 addIdentitiesToKeystore(env, this);
michaelm@5116 485
michaelm@5116 486 // Scan current keychain for trusted certificates.
michaelm@5116 487 addCertificatesToKeystore(env, this);
michaelm@5116 488
michaelm@5116 489 }
michaelm@5116 490
michaelm@5116 491 /*
michaelm@5116 492 * Class: apple_security_KeychainStore
michaelm@5116 493 * Method: _addItemToKeychain
michaelm@5116 494 * Signature: (Ljava/lang/String;[B)I
michaelm@5116 495 */
michaelm@5116 496 JNIEXPORT jlong JNICALL Java_apple_security_KeychainStore__1addItemToKeychain
michaelm@5116 497 (JNIEnv *env, jobject this, jstring alias, jboolean isCertificate, jbyteArray rawDataObj, jcharArray passwordObj)
michaelm@5116 498 {
michaelm@5116 499 OSStatus err;
michaelm@5116 500 jlong returnValue = 0;
michaelm@5116 501
michaelm@5116 502 JNF_COCOA_ENTER(env);
michaelm@5116 503
michaelm@5116 504 jsize dataSize = (*env)->GetArrayLength(env, rawDataObj);
michaelm@5116 505 jbyte *rawData = (*env)->GetByteArrayElements(env, rawDataObj, NULL);
vinnie@10970 506 if (rawData == NULL) {
vinnie@10970 507 goto errOut;
vinnie@10970 508 }
michaelm@5116 509
michaelm@5116 510 CFDataRef cfDataToImport = CFDataCreate(kCFAllocatorDefault, (UInt8 *)rawData, dataSize);
michaelm@5116 511 CFArrayRef createdItems = NULL;
michaelm@5116 512
michaelm@5116 513 SecKeychainRef defaultKeychain = NULL;
michaelm@5116 514 SecKeychainCopyDefault(&defaultKeychain);
michaelm@5116 515
weijun@12729 516 SecExternalFormat dataFormat = (isCertificate == JNI_TRUE ? kSecFormatX509Cert : kSecFormatWrappedPKCS8);
michaelm@5116 517
michaelm@5116 518 // Convert the password obj into a CFStringRef that the keychain importer can use for encryption.
michaelm@5116 519 SecKeyImportExportParameters paramBlock;
michaelm@5116 520 CFStringRef passwordStrRef = NULL;
michaelm@5116 521
michaelm@5116 522 jsize passwordLen = 0;
michaelm@5116 523 jchar *passwordChars = NULL;
michaelm@5116 524
michaelm@5116 525 if (passwordObj) {
michaelm@5116 526 passwordLen = (*env)->GetArrayLength(env, passwordObj);
vinnie@17411 527
vinnie@17411 528 if (passwordLen > 0) {
vinnie@17411 529 passwordChars = (*env)->GetCharArrayElements(env, passwordObj, NULL);
vinnie@17411 530 if (passwordChars == NULL) {
vinnie@17411 531 goto errOut;
vinnie@17411 532 }
vinnie@17411 533 passwordStrRef = CFStringCreateWithCharacters(kCFAllocatorDefault, passwordChars, passwordLen);
vinnie@17411 534
vinnie@17411 535 // clear the password and release
vinnie@17411 536 memset(passwordChars, 0, passwordLen);
vinnie@17411 537 (*env)->ReleaseCharArrayElements(env, passwordObj, passwordChars,
vinnie@17411 538 JNI_ABORT);
vinnie@17411 539 }
michaelm@5116 540 }
michaelm@5116 541
michaelm@5116 542 paramBlock.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
michaelm@5116 543 // Note that setting the flags field **requires** you to pass in a password of some kind. The keychain will not prompt you.
michaelm@5116 544 paramBlock.flags = 0;
michaelm@5116 545 paramBlock.passphrase = passwordStrRef;
michaelm@5116 546 paramBlock.alertTitle = NULL;
michaelm@5116 547 paramBlock.alertPrompt = NULL;
michaelm@5116 548 paramBlock.accessRef = NULL;
michaelm@5116 549 paramBlock.keyUsage = CSSM_KEYUSE_ANY;
michaelm@5116 550 paramBlock.keyAttributes = CSSM_KEYATTR_RETURN_DEFAULT;
michaelm@5116 551
weijun@12729 552 err = SecKeychainItemImport(cfDataToImport, NULL, &dataFormat, NULL,
michaelm@5116 553 0, &paramBlock, defaultKeychain, &createdItems);
michaelm@5116 554
michaelm@5116 555 if (err == noErr) {
michaelm@5116 556 SecKeychainItemRef anItem = (SecKeychainItemRef)CFArrayGetValueAtIndex(createdItems, 0);
michaelm@5116 557
michaelm@5116 558 // Don't bother labeling keys. They become part of an identity, and are not an accessible part of the keychain.
michaelm@5116 559 if (CFGetTypeID(anItem) == SecCertificateGetTypeID()) {
michaelm@5116 560 setLabelForItem(JNFJavaToNSString(env, alias), anItem);
michaelm@5116 561 }
michaelm@5116 562
michaelm@5116 563 // Retain the item, since it will be released once when the array holding it gets released.
michaelm@5116 564 CFRetain(anItem);
michaelm@5116 565 returnValue = ptr_to_jlong(anItem);
michaelm@5116 566 } else {
michaelm@5116 567 cssmPerror("_addItemToKeychain: SecKeychainItemImport", err);
michaelm@5116 568 }
michaelm@5116 569
michaelm@5116 570 (*env)->ReleaseByteArrayElements(env, rawDataObj, rawData, JNI_ABORT);
michaelm@5116 571
michaelm@5116 572 if (createdItems != NULL) {
michaelm@5116 573 CFRelease(createdItems);
michaelm@5116 574 }
michaelm@5116 575
vinnie@10970 576 errOut: ;
vinnie@10970 577
michaelm@5116 578 JNF_COCOA_EXIT(env);
michaelm@5116 579
michaelm@5116 580 return returnValue;
michaelm@5116 581 }
michaelm@5116 582
michaelm@5116 583 /*
michaelm@5116 584 * Class: apple_security_KeychainStore
michaelm@5116 585 * Method: _removeItemFromKeychain
michaelm@5116 586 * Signature: (J)I
michaelm@5116 587 */
michaelm@5116 588 JNIEXPORT jint JNICALL Java_apple_security_KeychainStore__1removeItemFromKeychain
michaelm@5116 589 (JNIEnv *env, jobject this, jlong keychainItem)
michaelm@5116 590 {
michaelm@5116 591 SecKeychainItemRef itemToRemove = jlong_to_ptr(keychainItem);
michaelm@5116 592 return SecKeychainItemDelete(itemToRemove);
michaelm@5116 593 }
michaelm@5116 594
michaelm@5116 595 /*
michaelm@5116 596 * Class: apple_security_KeychainStore
michaelm@5116 597 * Method: _releaseKeychainItemRef
michaelm@5116 598 * Signature: (J)V
michaelm@5116 599 */
michaelm@5116 600 JNIEXPORT void JNICALL Java_apple_security_KeychainStore__1releaseKeychainItemRef
michaelm@5116 601 (JNIEnv *env, jobject this, jlong keychainItem)
michaelm@5116 602 {
michaelm@5116 603 SecKeychainItemRef itemToFree = jlong_to_ptr(keychainItem);
michaelm@5116 604 CFRelease(itemToFree);
michaelm@5116 605 }