+++ /dev/null
-/*
- * Copyright (c) 2002-2008,2011-2012 Apple Inc. All Rights Reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- *
- * IdentityCursor.cpp -- Working with IdentityCursor
- */
-
-#include <security_keychain/IdentityCursor.h>
-#include <security_keychain/Identity.h>
-#include <security_keychain/Trust.h>
-#include <security_keychain/Item.h>
-#include <security_keychain/Certificate.h>
-#include <security_keychain/KeyItem.h>
-#include <security_keychain/Globals.h>
-#include <security_cdsa_utilities/Schema.h>
-#include <security_cdsa_utilities/KeySchema.h>
-#include <Security/oidsalg.h>
-#include <Security/SecKeychainItemPriv.h>
-#include <security_utilities/simpleprefs.h>
-#include <sys/param.h>
-
-using namespace KeychainCore;
-
-IdentityCursorPolicyAndID::IdentityCursorPolicyAndID(const StorageManager::KeychainList &searchList, CSSM_KEYUSE keyUsage, CFStringRef idString, SecPolicyRef policy, bool returnOnlyValidIdentities) :
- IdentityCursor(searchList, keyUsage),
- mPolicy(policy),
- mIDString(idString),
- mReturnOnlyValidIdentities(returnOnlyValidIdentities),
- mPreferredIdentityChecked(false),
- mPreferredIdentity(nil)
-{
- if (mPolicy)
- CFRetain(mPolicy);
-
- if (mIDString)
- CFRetain(mIDString);
-}
-
-IdentityCursorPolicyAndID::~IdentityCursorPolicyAndID() throw()
-{
- if (mPolicy)
- CFRelease(mPolicy);
-
- if (mIDString)
- CFRelease(mIDString);
-}
-
-void
-IdentityCursorPolicyAndID::findPreferredIdentity()
-{
- char idUTF8[MAXPATHLEN];
- if (!mIDString || !CFStringGetCString(mIDString, idUTF8, sizeof(idUTF8)-1, kCFStringEncodingUTF8))
- idUTF8[0] = (char)'\0';
- uint32_t iprfValue = 'iprf'; // value is specified in host byte order, since kSecTypeItemAttr has type uint32 in the db schema
- SecKeychainAttribute sAttrs[] = {
- { kSecTypeItemAttr, sizeof(uint32_t), &iprfValue },
- { kSecServiceItemAttr, (UInt32)strlen(idUTF8), (char *)idUTF8 }
- };
- SecKeychainAttributeList sAttrList = { sizeof(sAttrs) / sizeof(sAttrs[0]), sAttrs };
-
-// StorageManager::KeychainList keychains;
-// globals().storageManager.optionalSearchList((CFTypeRef)nil, keychains);
-
- Item item;
- KCCursor cursor(mSearchList /*keychains*/, kSecGenericPasswordItemClass, &sAttrList);
- if (!cursor->next(item))
- return;
-
- // get persistent certificate reference
- SecKeychainAttribute itemAttrs[] = { { kSecGenericItemAttr, 0, NULL } };
- SecKeychainAttributeList itemAttrList = { sizeof(itemAttrs) / sizeof(itemAttrs[0]), itemAttrs };
- item->getContent(NULL, &itemAttrList, NULL, NULL);
-
- // find certificate, given persistent reference data
- CFDataRef pItemRef = CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)itemAttrs[0].data, itemAttrs[0].length, kCFAllocatorNull);
- SecKeychainItemRef certItemRef = nil;
- OSStatus status = SecKeychainItemCopyFromPersistentReference(pItemRef, &certItemRef);
- if (pItemRef)
- CFRelease(pItemRef);
- item->freeContent(&itemAttrList, NULL);
- if (status || !certItemRef)
- return;
-
- // create identity reference, given certificate
- Item certItem = ItemImpl::required(SecKeychainItemRef(certItemRef));
- SecPointer<Certificate> certificate(static_cast<Certificate *>(certItem.get()));
- SecPointer<Identity> identity(new Identity(mSearchList /*keychains*/, certificate));
-
- mPreferredIdentity = identity;
-
- if (certItemRef)
- CFRelease(certItemRef);
-}
-
-bool
-IdentityCursorPolicyAndID::next(SecPointer<Identity> &identity)
-{
- SecPointer<Identity> currIdentity;
- Boolean identityOK = true;
-
- if (!mPreferredIdentityChecked)
- {
- try
- {
- findPreferredIdentity();
- }
- catch(...) {}
- mPreferredIdentityChecked = true;
- if (mPreferredIdentity)
- {
- identity = mPreferredIdentity;
- return true;
- }
- }
-
- for (;;)
- {
- bool result = IdentityCursor::next(currIdentity); // base class finds the next identity by keyUsage
- if ( result )
- {
- if (mPreferredIdentity && (currIdentity == mPreferredIdentity))
- {
- identityOK = false; // we already returned this one, move on to the next
- continue;
- }
-
- // If there was no policy specified, we're done.
- if ( !mPolicy )
- {
- identityOK = true; // return this identity
- break;
- }
-
- // To reduce the number of (potentially expensive) trust evaluations performed, we need
- // to do some pre-processing to filter out certs that don't match the search criteria.
- // Rather than try to duplicate the TP's policy logic here, we'll just call the TP with
- // a single-element certificate array, no anchors, and no keychains to search.
-
- SecPointer<Certificate> certificate = currIdentity->certificate();
- CFRef<SecCertificateRef> certRef(certificate->handle());
- CFRef<CFMutableArrayRef> anchorsArray(CFArrayCreateMutable(NULL, 1, NULL));
- CFRef<CFMutableArrayRef> certArray(CFArrayCreateMutable(NULL, 1, NULL));
- if ( !certArray || !anchorsArray )
- {
- identityOK = false; // skip this and move on to the next one
- continue;
- }
- CFArrayAppendValue(certArray, certRef);
-
- SecPointer<Trust> trustLite = new Trust(certArray, mPolicy);
- StorageManager::KeychainList emptyList;
- // Set the anchors and keychain search list to be empty
- trustLite->anchors(anchorsArray);
- trustLite->searchLibs(emptyList);
- trustLite->evaluate();
- SecTrustResultType trustResult = trustLite->result();
-
- if (trustResult == kSecTrustResultRecoverableTrustFailure ||
- trustResult == kSecTrustResultFatalTrustFailure)
- {
- CFArrayRef certChain = NULL;
- CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL, *evInfo = NULL;
- trustLite->buildEvidence(certChain, TPEvidenceInfo::overlayVar(statusChain));
- if (statusChain)
- evInfo = &statusChain[0];
- if (!evInfo || evInfo->NumStatusCodes > 0) // per-cert codes means we can't use this cert for this policy
- trustResult = kSecTrustResultInvalid; // handled below
- if (certChain)
- CFRelease(certChain);
- }
- if (trustResult == kSecTrustResultInvalid)
- {
- identityOK = false; // move on to the next one
- continue;
- }
-
- // If trust evaluation isn't requested, we're done.
- if ( !mReturnOnlyValidIdentities )
- {
- identityOK = true; // return this identity
- break;
- }
-
- // Perform a full trust evaluation on the certificate with the specified policy.
- SecPointer<Trust> trust = new Trust(certArray, mPolicy);
- trust->evaluate();
- trustResult = trust->result();
-
- if (trustResult == kSecTrustResultInvalid ||
- trustResult == kSecTrustResultRecoverableTrustFailure ||
- trustResult == kSecTrustResultFatalTrustFailure)
- {
- identityOK = false; // move on to the next one
- continue;
- }
-
- identityOK = true; // this one was OK; return it.
- break;
- }
- else
- {
- identityOK = false; // no more left.
- break;
- }
- } // for(;;)
-
- if ( identityOK )
- {
- identity = currIdentity; // caller will release the identity
- return true;
- }
- else
- {
- return false;
- }
-}
-
-
-IdentityCursor::IdentityCursor(const StorageManager::KeychainList &searchList, CSSM_KEYUSE keyUsage) :
- mSearchList(searchList),
- mKeyCursor(mSearchList, CSSM_DL_DB_RECORD_PRIVATE_KEY, NULL),
- mMutex(Mutex::recursive)
-{
- StLock<Mutex>_(mMutex);
-
- // If keyUsage is CSSM_KEYUSE_ANY then we need a key that can do everything
- if (keyUsage & CSSM_KEYUSE_ANY)
- keyUsage = CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT
- | CSSM_KEYUSE_DERIVE | CSSM_KEYUSE_SIGN
- | CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_SIGN_RECOVER
- | CSSM_KEYUSE_VERIFY_RECOVER | CSSM_KEYUSE_WRAP
- | CSSM_KEYUSE_UNWRAP;
-
- if (keyUsage & CSSM_KEYUSE_ENCRYPT)
- mKeyCursor->add(CSSM_DB_EQUAL, KeySchema::Encrypt, true);
- if (keyUsage & CSSM_KEYUSE_DECRYPT)
- mKeyCursor->add(CSSM_DB_EQUAL, KeySchema::Decrypt, true);
- if (keyUsage & CSSM_KEYUSE_DERIVE)
- mKeyCursor->add(CSSM_DB_EQUAL, KeySchema::Derive, true);
- if (keyUsage & CSSM_KEYUSE_SIGN)
- mKeyCursor->add(CSSM_DB_EQUAL, KeySchema::Sign, true);
- if (keyUsage & CSSM_KEYUSE_VERIFY)
- mKeyCursor->add(CSSM_DB_EQUAL, KeySchema::Verify, true);
- if (keyUsage & CSSM_KEYUSE_SIGN_RECOVER)
- mKeyCursor->add(CSSM_DB_EQUAL, KeySchema::SignRecover, true);
- if (keyUsage & CSSM_KEYUSE_VERIFY_RECOVER)
- mKeyCursor->add(CSSM_DB_EQUAL, KeySchema::VerifyRecover, true);
- if (keyUsage & CSSM_KEYUSE_WRAP)
- mKeyCursor->add(CSSM_DB_EQUAL, KeySchema::Wrap, true);
- if (keyUsage & CSSM_KEYUSE_UNWRAP)
- mKeyCursor->add(CSSM_DB_EQUAL, KeySchema::Unwrap, true);
-}
-
-IdentityCursor::~IdentityCursor() throw()
-{
-}
-
-CFDataRef
-IdentityCursor::pubKeyHashForSystemIdentity(CFStringRef domain)
-{
- StLock<Mutex>_(mMutex);
-
- CFDataRef entryValue = nil;
- auto_ptr<Dictionary> identDict;
- Dictionary* d = Dictionary::CreateDictionary("com.apple.security.systemidentities", Dictionary::US_System);
- if (d)
- {
- identDict.reset(d);
- entryValue = identDict->getDataValue(domain);
- if (entryValue == nil) {
- /* try for default entry if we're not already looking for default */
- if(!CFEqual(domain, kSecIdentityDomainDefault)) {
- entryValue = identDict->getDataValue(kSecIdentityDomainDefault);
- }
- }
- }
-
- if (entryValue) {
- CFRetain(entryValue);
- }
- return entryValue;
-}
-
-bool
-IdentityCursor::next(SecPointer<Identity> &identity)
-{
- StLock<Mutex>_(mMutex);
-
- for (;;)
- {
- if (!mCertificateCursor)
- {
- Item key;
- if (!mKeyCursor->next(key))
- return false;
-
- mCurrentKey = static_cast<KeyItem *>(key.get());
-
- CssmClient::DbUniqueRecord uniqueId = mCurrentKey->dbUniqueRecord();
- CssmClient::DbAttributes dbAttributes(uniqueId->database(), 1);
- dbAttributes.add(KeySchema::Label);
- uniqueId->get(&dbAttributes, NULL);
- const CssmData &keyHash = dbAttributes[0];
-
- mCertificateCursor = KCCursor(mSearchList, CSSM_DL_DB_RECORD_X509_CERTIFICATE, NULL);
- mCertificateCursor->add(CSSM_DB_EQUAL, Schema::kX509CertificatePublicKeyHash, keyHash);
-
- // if we have entries for the system identities, exclude their public key hashes in the search
- CFDataRef systemDefaultCertPubKeyHash = pubKeyHashForSystemIdentity(kSecIdentityDomainDefault);
- if (systemDefaultCertPubKeyHash) {
- CssmData pkHash((void *)CFDataGetBytePtr(systemDefaultCertPubKeyHash), CFDataGetLength(systemDefaultCertPubKeyHash));
- mCertificateCursor->add(CSSM_DB_NOT_EQUAL, Schema::kX509CertificatePublicKeyHash, pkHash);
- CFRelease(systemDefaultCertPubKeyHash);
- }
- CFDataRef kerbKDCCertPubKeyHash = pubKeyHashForSystemIdentity(kSecIdentityDomainKerberosKDC);
- if (kerbKDCCertPubKeyHash) {
- CssmData pkHash((void *)CFDataGetBytePtr(kerbKDCCertPubKeyHash), CFDataGetLength(kerbKDCCertPubKeyHash));
- mCertificateCursor->add(CSSM_DB_NOT_EQUAL, Schema::kX509CertificatePublicKeyHash, pkHash);
- CFRelease(kerbKDCCertPubKeyHash);
- }
- }
-
- Item cert;
- if (mCertificateCursor->next(cert))
- {
- SecPointer<Certificate> certificate(static_cast<Certificate *>(cert.get()));
- identity = new Identity(mCurrentKey, certificate);
- return true;
- }
- else
- mCertificateCursor = KCCursor();
- }
-}