/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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)
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");
{
char *attribCString = NULL;
if(status) {
goto errOut;
}
return returnValue;
}
{
if(status) {
// This is almost always missing, so don't dump an error.
// cssmPerror("getModDateFromItem: SecKeychainItemCopyContent", status);
goto errOut;
}
return returnValue;
}
{
// Set up attribute vector (each attribute consists of {tag, length, pointer}):
SecKeychainAttribute attrs[] = {
};
// Not changing data here, just attributes.
if(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(
{
// identity
/* First element in out array is the SecIdentity */
/* the single element in certs-to-be-evaluated comes from the identity */
if(ortn) {
/* should never happen */
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.
*/
/* the array owns the subject cert ref now */
/* Get a SecPolicyRef for generic X509 cert chain verification */
NULL, // value
&policySearch);
if(ortn) {
/* should never happen */
goto errOut;
}
if(ortn) {
/* should never happen */
goto errOut;
}
/* build a SecTrustRef for specified policy and certs */
if(ortn) {
goto errOut;
}
if(trustedAnchor) {
/*
* Tell SecTrust to trust this one in addition to the current
* trusted system-wide anchors.
*/
if(ortn) {
/* should never happen */
goto errOut;
}
if(ortn) {
goto errOut;
}
}
/* evaluate: GO */
if(ortn) {
goto errOut;
}
switch(secTrustResult) {
/* 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.
*/
goto errOut;
}
/* get resulting constructed cert chain */
if(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.
*/
if(numResCerts < 1) {
/*
* Can't happen: If chain doesn't verify to a root, we'd
* have bailed after SecTrustEvaluate().
*/
goto errOut;
}
if(!includeRoot) {
/* skip the last (root) cert) */
numResCerts--;
}
}
/* clean up */
if(secTrust) {
}
if(subjCerts) {
}
if(policy) {
}
if(policySearch) {
}
return ortn;
}
{
// 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.
do {
if (searchResult == noErr) {
// Get the cert from the identity, then generate a chain.
// *** Should do something with this error...
// Make a java array of certificate data from the chain.
// And, make an array of the certificate refs.
for (i = 0; i < certCount; i++) {
if (i == 0)
else
(*env)->SetByteArrayRegion(env, encodedCertData, 0, currCertData.Length, (jbyte *)currCertData.Data);
}
// Get the private key. When needed we'll export the data from it later.
// Find the label. It's a 'blob', but we interpret as characters.
// Find the creation date.
// Call back to the Java object to create Java objects corresponding to this security object.
JNFCallVoidMethod(env, keyStore, jm_createKeyEntry, alias, creationDate, nativeKeyRef, certRefArray, javaCertArray);
}
} while (searchResult == noErr);
if (identitySearch != NULL) {
}
}
{
// Search the user keychain list for all X509 certificates.
OSStatus err = SecKeychainSearchCreateFromAttributes(NULL, kSecCertificateItemClass, NULL, &keychainItemSearch);
do {
if (searchResult == noErr) {
// Make a byte array with the DER-encoded contents of the certificate.
(*env)->SetByteArrayRegion(env, certData, 0, currCertificate.Length, (jbyte *)currCertificate.Data);
// Find the label. It's a 'blob', but we interpret as characters.
// Find the creation date.
// Call back to the Java object to create Java objects corresponding to this security object.
JNFCallVoidMethod(env, keyStore, jm_createTrustedCertEntry, alias, nativeRef, creationDate, certData);
}
} while (searchResult == noErr);
if (keychainItemSearch != NULL) {
}
}
/*
* Class: apple_security_KeychainStore
* Method: _getEncodedKeyData
* Signature: (J)[B
*/
{
if (passwordObj) {
if (passwordLen > 0) {
}
}
// Note that setting the flags field **requires** you to pass in a password of some kind. The keychain will not prompt you.
}
return returnValue;
}
/*
* Class: apple_security_KeychainStore
* Method: _scanKeychain
* Signature: ()V
*/
{
// 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
*/
(JNIEnv *env, jobject this, jstring alias, jboolean isCertificate, jbyteArray rawDataObj, jcharArray passwordObj)
{
SecExternalItemType dataType = (isCertificate == JNI_TRUE ? kSecFormatX509Cert : kSecFormatWrappedPKCS8);
// Convert the password obj into a CFStringRef that the keychain importer can use for encryption.
if (passwordObj) {
}
// Note that setting the flags field **requires** you to pass in a password of some kind. The keychain will not prompt you.
// Don't bother labeling keys. They become part of an identity, and are not an accessible part of the keychain.
}
// Retain the item, since it will be released once when the array holding it gets released.
} else {
}
if (createdItems != NULL) {
}
return returnValue;
}
/*
* Class: apple_security_KeychainStore
* Method: _removeItemFromKeychain
* Signature: (J)I
*/
{
return SecKeychainItemDelete(itemToRemove);
}
/*
* Class: apple_security_KeychainStore
* Method: _releaseKeychainItemRef
* Signature: (J)V
*/
{
}