Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/jdk17u
Path: blob/master/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m
67760 views
1
/*
2
* Copyright (c) 2011, 2022, 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
#import "jni_util.h"
28
#import <Security/Security.h>
29
#import <Security/SecImportExport.h>
30
#import <CoreServices/CoreServices.h> // (for require() macros)
31
#import <Cocoa/Cocoa.h>
32
33
static jstring getLabelFromItem(JNIEnv *env, SecKeychainItemRef inItem)
34
{
35
OSStatus status;
36
jstring returnValue = NULL;
37
char *attribCString = NULL;
38
39
SecKeychainAttribute itemAttrs[] = { { kSecLabelItemAttr, 0, NULL } };
40
SecKeychainAttributeList attrList = { sizeof(itemAttrs) / sizeof(itemAttrs[0]), itemAttrs };
41
42
status = SecKeychainItemCopyContent(inItem, NULL, &attrList, NULL, NULL);
43
44
if(status) {
45
cssmPerror("getLabelFromItem: SecKeychainItemCopyContent", status);
46
goto errOut;
47
}
48
49
attribCString = malloc(itemAttrs[0].length + 1);
50
if (attribCString == NULL) {
51
JNU_ThrowOutOfMemoryError(env, "native heap");
52
goto errOut;
53
}
54
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
jclass jc_KeychainStore = (*env)->FindClass(env, "apple/security/KeychainStore");
288
CHECK_NULL(jc_KeychainStore);
289
jmethodID jm_createKeyEntry = (*env)->GetMethodID(env, jc_KeychainStore, "createKeyEntry", "(Ljava/lang/String;JJ[J[[B)V");
290
CHECK_NULL(jm_createKeyEntry);
291
do {
292
searchResult = SecIdentitySearchCopyNext(identitySearch, &theIdentity);
293
294
if (searchResult == noErr) {
295
// Get the cert from the identity, then generate a chain.
296
SecCertificateRef certificate;
297
SecIdentityCopyCertificate(theIdentity, &certificate);
298
CFArrayRef certChain = NULL;
299
300
// *** Should do something with this error...
301
err = completeCertChain(theIdentity, NULL, TRUE, &certChain);
302
303
CFIndex i, certCount = CFArrayGetCount(certChain);
304
305
// Make a java array of certificate data from the chain.
306
jclass byteArrayClass = (*env)->FindClass(env, "[B");
307
if (byteArrayClass == NULL) {
308
goto errOut;
309
}
310
jobjectArray javaCertArray = (*env)->NewObjectArray(env, certCount, byteArrayClass, NULL);
311
// Cleanup first then check for a NULL return code
312
(*env)->DeleteLocalRef(env, byteArrayClass);
313
if (javaCertArray == NULL) {
314
goto errOut;
315
}
316
317
// And, make an array of the certificate refs.
318
jlongArray certRefArray = (*env)->NewLongArray(env, certCount);
319
if (certRefArray == NULL) {
320
goto errOut;
321
}
322
323
SecCertificateRef currCertRef = NULL;
324
325
for (i = 0; i < certCount; i++) {
326
CSSM_DATA currCertData;
327
328
if (i == 0)
329
currCertRef = certificate;
330
else
331
currCertRef = (SecCertificateRef)CFArrayGetValueAtIndex(certChain, i);
332
333
bzero(&currCertData, sizeof(CSSM_DATA));
334
err = SecCertificateGetData(currCertRef, &currCertData);
335
jbyteArray encodedCertData = (*env)->NewByteArray(env, currCertData.Length);
336
if (encodedCertData == NULL) {
337
goto errOut;
338
}
339
(*env)->SetByteArrayRegion(env, encodedCertData, 0, currCertData.Length, (jbyte *)currCertData.Data);
340
(*env)->SetObjectArrayElement(env, javaCertArray, i, encodedCertData);
341
jlong certRefElement = ptr_to_jlong(currCertRef);
342
(*env)->SetLongArrayRegion(env, certRefArray, i, 1, &certRefElement);
343
}
344
345
// Get the private key. When needed we'll export the data from it later.
346
SecKeyRef privateKeyRef;
347
err = SecIdentityCopyPrivateKey(theIdentity, &privateKeyRef);
348
349
// Find the label. It's a 'blob', but we interpret as characters.
350
jstring alias = getLabelFromItem(env, (SecKeychainItemRef)certificate);
351
if (alias == NULL) {
352
goto errOut;
353
}
354
355
// Find the creation date.
356
jlong creationDate = getModDateFromItem(env, (SecKeychainItemRef)certificate);
357
358
// Call back to the Java object to create Java objects corresponding to this security object.
359
jlong nativeKeyRef = ptr_to_jlong(privateKeyRef);
360
(*env)->CallVoidMethod(env, keyStore, jm_createKeyEntry, alias, creationDate, nativeKeyRef, certRefArray, javaCertArray);
361
JNU_CHECK_EXCEPTION(env);
362
}
363
} while (searchResult == noErr);
364
365
errOut:
366
if (identitySearch != NULL) {
367
CFRelease(identitySearch);
368
}
369
}
370
371
#define ADD(list, str) { \
372
jobject localeObj = (*env)->NewStringUTF(env, [str UTF8String]); \
373
(*env)->CallBooleanMethod(env, list, jm_listAdd, localeObj); \
374
(*env)->DeleteLocalRef(env, localeObj); \
375
}
376
377
#define ADDNULL(list) (*env)->CallBooleanMethod(env, list, jm_listAdd, NULL)
378
379
static void addCertificatesToKeystore(JNIEnv *env, jobject keyStore)
380
{
381
// Search the user keychain list for all X509 certificates.
382
SecKeychainSearchRef keychainItemSearch = NULL;
383
OSStatus err = SecKeychainSearchCreateFromAttributes(NULL, kSecCertificateItemClass, NULL, &keychainItemSearch);
384
SecKeychainItemRef theItem = NULL;
385
OSErr searchResult = noErr;
386
387
jclass jc_KeychainStore = (*env)->FindClass(env, "apple/security/KeychainStore");
388
CHECK_NULL(jc_KeychainStore);
389
jmethodID jm_createTrustedCertEntry = (*env)->GetMethodID(
390
env, jc_KeychainStore, "createTrustedCertEntry", "(Ljava/lang/String;Ljava/util/List;JJ[B)V");
391
CHECK_NULL(jm_createTrustedCertEntry);
392
jclass jc_arrayListClass = (*env)->FindClass(env, "java/util/ArrayList");
393
CHECK_NULL(jc_arrayListClass);
394
jmethodID jm_arrayListCons = (*env)->GetMethodID(env, jc_arrayListClass, "<init>", "()V");
395
CHECK_NULL(jm_arrayListCons);
396
jmethodID jm_listAdd = (*env)->GetMethodID(env, jc_arrayListClass, "add", "(Ljava/lang/Object;)Z");
397
CHECK_NULL(jm_listAdd);
398
399
do {
400
searchResult = SecKeychainSearchCopyNext(keychainItemSearch, &theItem);
401
402
if (searchResult == noErr) {
403
// Make a byte array with the DER-encoded contents of the certificate.
404
SecCertificateRef certRef = (SecCertificateRef)theItem;
405
CSSM_DATA currCertificate;
406
err = SecCertificateGetData(certRef, &currCertificate);
407
jbyteArray certData = (*env)->NewByteArray(env, currCertificate.Length);
408
if (certData == NULL) {
409
goto errOut;
410
}
411
(*env)->SetByteArrayRegion(env, certData, 0, currCertificate.Length, (jbyte *)currCertificate.Data);
412
413
// Find the label. It's a 'blob', but we interpret as characters.
414
jstring alias = getLabelFromItem(env, theItem);
415
if (alias == NULL) {
416
goto errOut;
417
}
418
419
// Only add certificates with trusted settings
420
CFArrayRef trustSettings;
421
if (SecTrustSettingsCopyTrustSettings(certRef, kSecTrustSettingsDomainUser, &trustSettings)
422
== errSecItemNotFound) {
423
continue;
424
}
425
426
// See KeychainStore::createTrustedCertEntry for content of inputTrust
427
jobject inputTrust = (*env)->NewObject(env, jc_arrayListClass, jm_arrayListCons);
428
CHECK_NULL(inputTrust);
429
430
// Dump everything inside trustSettings into inputTrust
431
CFIndex count = CFArrayGetCount(trustSettings);
432
for (int i = 0; i < count; i++) {
433
CFDictionaryRef oneTrust = (CFDictionaryRef) CFArrayGetValueAtIndex(trustSettings, i);
434
CFIndex size = CFDictionaryGetCount(oneTrust);
435
const void * keys [size];
436
const void * values [size];
437
CFDictionaryGetKeysAndValues(oneTrust, keys, values);
438
for (int j = 0; j < size; j++) {
439
NSString* s = [NSString stringWithFormat:@"%@", keys[j]];
440
ADD(inputTrust, s);
441
s = [NSString stringWithFormat:@"%@", values[j]];
442
ADD(inputTrust, s);
443
}
444
SecPolicyRef certPolicy;
445
certPolicy = (SecPolicyRef)CFDictionaryGetValue(oneTrust, kSecTrustSettingsPolicy);
446
if (certPolicy != NULL) {
447
CFDictionaryRef policyDict = SecPolicyCopyProperties(certPolicy);
448
ADD(inputTrust, @"SecPolicyOid");
449
NSString* s = [NSString stringWithFormat:@"%@", CFDictionaryGetValue(policyDict, @"SecPolicyOid")];
450
ADD(inputTrust, s);
451
CFRelease(policyDict);
452
}
453
ADDNULL(inputTrust);
454
}
455
CFRelease(trustSettings);
456
457
// Find the creation date.
458
jlong creationDate = getModDateFromItem(env, theItem);
459
460
// Call back to the Java object to create Java objects corresponding to this security object.
461
jlong nativeRef = ptr_to_jlong(certRef);
462
(*env)->CallVoidMethod(env, keyStore, jm_createTrustedCertEntry, alias, inputTrust, nativeRef, creationDate, certData);
463
JNU_CHECK_EXCEPTION(env);
464
}
465
} while (searchResult == noErr);
466
467
errOut:
468
if (keychainItemSearch != NULL) {
469
CFRelease(keychainItemSearch);
470
}
471
}
472
473
/*
474
* Class: apple_security_KeychainStore
475
* Method: _getEncodedKeyData
476
* Signature: (J)[B
477
*/
478
JNIEXPORT jbyteArray JNICALL Java_apple_security_KeychainStore__1getEncodedKeyData
479
(JNIEnv *env, jobject this, jlong keyRefLong, jcharArray passwordObj)
480
{
481
SecKeyRef keyRef = (SecKeyRef)jlong_to_ptr(keyRefLong);
482
SecKeyImportExportParameters paramBlock;
483
OSStatus err = noErr;
484
CFDataRef exportedData = NULL;
485
jbyteArray returnValue = NULL;
486
CFStringRef passwordStrRef = NULL;
487
488
jsize passwordLen = 0;
489
jchar *passwordChars = NULL;
490
491
if (passwordObj) {
492
passwordLen = (*env)->GetArrayLength(env, passwordObj);
493
494
if (passwordLen > 0) {
495
passwordChars = (*env)->GetCharArrayElements(env, passwordObj, NULL);
496
if (passwordChars == NULL) {
497
goto errOut;
498
}
499
500
passwordStrRef = CFStringCreateWithCharactersNoCopy(NULL, passwordChars, passwordLen, kCFAllocatorNull);
501
if (passwordStrRef == NULL) {
502
goto errOut;
503
}
504
}
505
}
506
507
paramBlock.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
508
// Note that setting the flags field **requires** you to pass in a password of some kind. The keychain will not prompt you.
509
paramBlock.flags = 0;
510
paramBlock.passphrase = passwordStrRef;
511
paramBlock.alertTitle = NULL;
512
paramBlock.alertPrompt = NULL;
513
paramBlock.accessRef = NULL;
514
paramBlock.keyUsage = CSSM_KEYUSE_ANY;
515
paramBlock.keyAttributes = CSSM_KEYATTR_RETURN_DEFAULT;
516
517
err = SecKeychainItemExport(keyRef, kSecFormatPKCS12, 0, &paramBlock, &exportedData);
518
519
if (err == noErr) {
520
CFIndex size = CFDataGetLength(exportedData);
521
returnValue = (*env)->NewByteArray(env, size);
522
if (returnValue == NULL) {
523
goto errOut;
524
}
525
(*env)->SetByteArrayRegion(env, returnValue, 0, size, (jbyte *)CFDataGetBytePtr(exportedData));
526
}
527
528
errOut:
529
if (exportedData) CFRelease(exportedData);
530
if (passwordStrRef) CFRelease(passwordStrRef);
531
if (passwordChars) {
532
// clear the password and release
533
memset(passwordChars, 0, passwordLen);
534
(*env)->ReleaseCharArrayElements(env, passwordObj, passwordChars,
535
JNI_ABORT);
536
}
537
return returnValue;
538
}
539
540
541
/*
542
* Class: apple_security_KeychainStore
543
* Method: _scanKeychain
544
* Signature: ()V
545
*/
546
JNIEXPORT void JNICALL Java_apple_security_KeychainStore__1scanKeychain
547
(JNIEnv *env, jobject this)
548
{
549
// Look for 'identities' -- private key and certificate chain pairs -- and add those.
550
// Search for these first, because a certificate that's found here as part of an identity will show up
551
// again later as a certificate.
552
addIdentitiesToKeystore(env, this);
553
554
JNU_CHECK_EXCEPTION(env);
555
556
// Scan current keychain for trusted certificates.
557
addCertificatesToKeystore(env, this);
558
559
}
560
561
NSString* JavaStringToNSString(JNIEnv *env, jstring jstr) {
562
if (jstr == NULL) {
563
return NULL;
564
}
565
jsize len = (*env)->GetStringLength(env, jstr);
566
const jchar *chars = (*env)->GetStringChars(env, jstr, NULL);
567
if (chars == NULL) {
568
return NULL;
569
}
570
NSString *result = [NSString stringWithCharacters:(UniChar *)chars length:len];
571
(*env)->ReleaseStringChars(env, jstr, chars);
572
return result;
573
}
574
575
/*
576
* Class: apple_security_KeychainStore
577
* Method: _addItemToKeychain
578
* Signature: (Ljava/lang/String;Z[B[C)J
579
*/
580
JNIEXPORT jlong JNICALL Java_apple_security_KeychainStore__1addItemToKeychain
581
(JNIEnv *env, jobject this, jstring alias, jboolean isCertificate, jbyteArray rawDataObj, jcharArray passwordObj)
582
{
583
OSStatus err;
584
jlong returnValue = 0;
585
586
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; \
587
@try {
588
jsize dataSize = (*env)->GetArrayLength(env, rawDataObj);
589
jbyte *rawData = (*env)->GetByteArrayElements(env, rawDataObj, NULL);
590
if (rawData == NULL) {
591
goto errOut;
592
}
593
594
CFDataRef cfDataToImport = CFDataCreate(kCFAllocatorDefault, (UInt8 *)rawData, dataSize);
595
CFArrayRef createdItems = NULL;
596
597
SecKeychainRef defaultKeychain = NULL;
598
SecKeychainCopyDefault(&defaultKeychain);
599
600
SecExternalFormat dataFormat = (isCertificate == JNI_TRUE ? kSecFormatX509Cert : kSecFormatWrappedPKCS8);
601
602
// Convert the password obj into a CFStringRef that the keychain importer can use for encryption.
603
SecKeyImportExportParameters paramBlock;
604
CFStringRef passwordStrRef = NULL;
605
606
jsize passwordLen = 0;
607
jchar *passwordChars = NULL;
608
609
if (passwordObj) {
610
passwordLen = (*env)->GetArrayLength(env, passwordObj);
611
612
if (passwordLen > 0) {
613
passwordChars = (*env)->GetCharArrayElements(env, passwordObj, NULL);
614
if (passwordChars == NULL) {
615
goto errOut;
616
}
617
618
passwordStrRef = CFStringCreateWithCharactersNoCopy(NULL, passwordChars, passwordLen, kCFAllocatorNull);
619
if (passwordStrRef == NULL) {
620
goto errOut;
621
}
622
}
623
}
624
625
paramBlock.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
626
// Note that setting the flags field **requires** you to pass in a password of some kind. The keychain will not prompt you.
627
paramBlock.flags = 0;
628
paramBlock.passphrase = passwordStrRef;
629
paramBlock.alertTitle = NULL;
630
paramBlock.alertPrompt = NULL;
631
paramBlock.accessRef = NULL;
632
paramBlock.keyUsage = CSSM_KEYUSE_ANY;
633
paramBlock.keyAttributes = CSSM_KEYATTR_RETURN_DEFAULT;
634
635
err = SecKeychainItemImport(cfDataToImport, NULL, &dataFormat, NULL,
636
0, &paramBlock, defaultKeychain, &createdItems);
637
if (cfDataToImport != NULL) {
638
CFRelease(cfDataToImport);
639
}
640
641
if (err == noErr) {
642
SecKeychainItemRef anItem = (SecKeychainItemRef)CFArrayGetValueAtIndex(createdItems, 0);
643
644
// Don't bother labeling keys. They become part of an identity, and are not an accessible part of the keychain.
645
if (CFGetTypeID(anItem) == SecCertificateGetTypeID()) {
646
setLabelForItem(JavaStringToNSString(env, alias), anItem);
647
}
648
649
// Retain the item, since it will be released once when the array holding it gets released.
650
CFRetain(anItem);
651
returnValue = ptr_to_jlong(anItem);
652
} else {
653
cssmPerror("_addItemToKeychain: SecKeychainItemImport", err);
654
}
655
656
if (createdItems != NULL) {
657
CFRelease(createdItems);
658
}
659
660
errOut:
661
if (rawData) {
662
(*env)->ReleaseByteArrayElements(env, rawDataObj, rawData, JNI_ABORT);
663
}
664
665
if (passwordStrRef) CFRelease(passwordStrRef);
666
if (passwordChars) {
667
// clear the password and release
668
memset(passwordChars, 0, passwordLen);
669
(*env)->ReleaseCharArrayElements(env, passwordObj, passwordChars,
670
JNI_ABORT);
671
}
672
} @catch (NSException *e) {
673
NSLog(@"%@", [e callStackSymbols]);
674
} @finally {
675
[pool drain];
676
}
677
return returnValue;
678
}
679
680
/*
681
* Class: apple_security_KeychainStore
682
* Method: _removeItemFromKeychain
683
* Signature: (J)I
684
*/
685
JNIEXPORT jint JNICALL Java_apple_security_KeychainStore__1removeItemFromKeychain
686
(JNIEnv *env, jobject this, jlong keychainItem)
687
{
688
SecKeychainItemRef itemToRemove = jlong_to_ptr(keychainItem);
689
return SecKeychainItemDelete(itemToRemove);
690
}
691
692
/*
693
* Class: apple_security_KeychainStore
694
* Method: _releaseKeychainItemRef
695
* Signature: (J)V
696
*/
697
JNIEXPORT void JNICALL Java_apple_security_KeychainStore__1releaseKeychainItemRef
698
(JNIEnv *env, jobject this, jlong keychainItem)
699
{
700
SecKeychainItemRef itemToFree = jlong_to_ptr(keychainItem);
701
CFRelease(itemToFree);
702
}
703
704