//
// Set an individual trust element
//
void TrustStore::assign(Certificate *cert, Policy *policy, SecTrustUserSetting trust)
{
	StLock<Mutex> _(mMutex);

	TrustData trustData = { UserTrustItem::currentVersion, trust };
	Keychain defaultKeychain = Keychain::optional(NULL);
	Keychain trustLocation = defaultKeychain;	// default keychain, unless trust entry found
	StorageManager::KeychainList searchList;
	globals().storageManager.getSearchList(searchList);

	if (Item item = findItem(cert, policy, searchList)) {
		// user has a trust setting in a keychain - modify that
		trustLocation = item->keychain();
		if (trust == kSecTrustResultUnspecified)
			item->keychain()->deleteItem(item);
		else
			item->modifyContent(NULL, sizeof(trustData), &trustData);
	} else {
		// no trust entry: make one
		if (trust != kSecTrustResultUnspecified) {
			Item item = new UserTrustItem(cert, policy, trustData);
			if (Keychain location = cert->keychain()) {
				try {
					location->add(item);				// try the cert's keychain first
					trustLocation = location;
				} catch (...) {
					if (&*location != &*defaultKeychain)
						defaultKeychain->add(item);		// try the default (if it's not the same)
				}
			} else {
				defaultKeychain->add(item);				// raw cert - use default keychain
			}
		}
	}

	// Make sure that the certificate is available in some keychain,
	// to provide a basis for editing the trust setting that we're assigning.
	if (cert->keychain() == NULL) {
		if (cert->findInKeychain(searchList) == NULL) {
			try {
				cert->copyTo(trustLocation);	// add cert to the trust item's keychain
			} catch (...) {
				secdebug("trusteval", "failed to add certificate %p to keychain \"%s\"",
					cert, trustLocation->name());
				try {
					if (&*trustLocation != &*defaultKeychain)
						cert->copyTo(defaultKeychain);	// try the default (if it's not the same)
				} catch (...) {
					// unable to add the certificate
					secdebug("trusteval", "failed to add certificate %p to keychain \"%s\"",
						cert, defaultKeychain->name());
				}
			}
		}
	}
}
//
// Retrieve the trust setting for a (certificate, policy) pair.
//
SecTrustUserSetting TrustStore::find(Certificate *cert, Policy *policy,
	StorageManager::KeychainList &keychainList)
{
	StLock<Mutex> _(mMutex);

	if (Item item = findItem(cert, policy, keychainList)) {
		// Make sure that the certificate is available in some keychain,
		// to provide a basis for editing the trust setting that we're returning.
		if (cert->keychain() == NULL) {
			if (cert->findInKeychain(keychainList) == NULL) {
				Keychain defaultKeychain = Keychain::optional(NULL);
				if (Keychain location = item->keychain()) {
					try {
						cert->copyTo(location);	// add cert to the trust item's keychain
					} catch (...) {
						secdebug("trusteval", "failed to add certificate %p to keychain \"%s\"",
							cert, location->name());
						try {
							if (&*location != &*defaultKeychain)
								cert->copyTo(defaultKeychain);	// try the default (if it's not the same)
						} catch (...) {
							// unable to add the certificate
							secdebug("trusteval", "failed to add certificate %p to keychain \"%s\"",
								cert, defaultKeychain->name());
						}
					}
				}
			}
		}
		CssmDataContainer data;
		item->getData(data);
		if (data.length() != sizeof(TrustData))
			MacOSError::throwMe(errSecInvalidTrustSetting);
		TrustData &trust = *data.interpretedAs<TrustData>();
		if (trust.version != UserTrustItem::currentVersion)
			MacOSError::throwMe(errSecInvalidTrustSetting);
		return trust.trust;
	} else {
		return kSecTrustResultUnspecified;
	}
}