-
-
-//
-// Perform legacy hash verification.
-// This is the pre-Leopard (Tiger, Panther) code path. Here we only have legacy hashes
-// (called, confusingly, "signatures"), which we're matching against suitably computed
-// "signatures" (hashes) on the requesting application. We consult the CodeEquivalenceDatabase
-// in a doomed attempt to track changes made to applications through updates, and issue
-// equivalence dialogs to users if we have a name match (but hash mismatch). That's all
-// there was before Code Signing; and that's what you'll continue to get if the requesting
-// application is unsigned. Until we throw the whole mess out altogether, hopefully by
-// the Next Big Cat After Leopard.
-//
-bool CodeSignatures::verifyLegacy(Process &process, const CssmData &signature, string path)
-{
- // First of all, if the signature directly matches the client's code, we're obviously fine
- // we don't even need the database for that...
- Identity &clientIdentity = process;
- try {
- if (clientIdentity.getHash() == signature) {
- secdebug("codesign", "direct match: pass");
- return true;
- }
- } catch (...) {
- secdebug("codesign", "exception getting client code hash: fail");
- return false;
- }
-
-#if CONSULT_LEGACY_CODE_EQUIVALENCE_DATABASE
-
- // Ah well. Establish mediator objects for database signature links
- AclIdentity aclIdentity(signature, path);
-
- uid_t user = process.uid();
- {
- StLock<Mutex> _(mDatabaseLock);
- find(aclIdentity, user);
- find(clientIdentity, user);
- }
-
- // if both links exist, we can decide this right now
- if (aclIdentity && clientIdentity) {
- if (aclIdentity.trustedName() == clientIdentity.trustedName()) {
- secdebug("codesign", "app references match: pass");
- return true;
- } else {
- secdebug("codesign", "client/acl links exist but are unequal: fail");
- return false;
- }
- }
-
- // check for name equality
- secdebug("codesign", "matching client %s against acl %s",
- clientIdentity.name().c_str(), aclIdentity.name().c_str());
- if (aclIdentity.name() != clientIdentity.name()) {
- secdebug("codesign", "name/path mismatch: fail");
- return false;
- }
-
- // The names match - we have a possible update.
-
- // Take the UI lock now to serialize "update rushes".
- LongtermStLock uiLocker(mUILock);
-
- // re-read the database in case some other thread beat us to the update
- {
- StLock<Mutex> _(mDatabaseLock);
- find(aclIdentity, user);
- find(clientIdentity, user);
- }
- if (aclIdentity && clientIdentity) {
- if (aclIdentity.trustedName() == clientIdentity.trustedName()) {
- secdebug("codesign", "app references match: pass (on the rematch)");
- return true;
- } else {
- secdebug("codesign", "client/acl links exist but are unequal: fail (on the rematch)");
- return false;
- }
- }
-
- // ask the user
- QueryCodeCheck query;
- query.inferHints(process);
- if (!query(aclIdentity.path().c_str()))
- {
- secdebug("codesign", "user declined equivalence: cancel the access");
- CssmError::throwMe(CSSM_ERRCODE_USER_CANCELED);
- }
-
- // take the database lock back for real
- StLock<Mutex> _(mDatabaseLock);
-
- // user wants us to go ahead and establish trust (if possible)
- if (aclIdentity) {
- // acl is linked but new client: link the client to this application
- makeLink(clientIdentity, aclIdentity.trustedName(), true, user);
- mDb.flush();
- secdebug("codesign", "client %s linked to application %s: pass",
- clientIdentity.path().c_str(), aclIdentity.trustedName().c_str());
- return true;
- }
-
- if (clientIdentity) { // code link exists, acl link missing
- // client is linked but ACL (hash) never seen: link the ACL to this app
- makeLink(aclIdentity, clientIdentity.trustedName(), true, user);
- mDb.flush();
- secdebug("codesign", "acl %s linked to client %s: pass",
- aclIdentity.path().c_str(), clientIdentity.trustedName().c_str());
- return true;
- }
-
- // the De Novo case: no links, must create everything
- string ident = clientIdentity.name();
- makeLink(clientIdentity, ident, true, user);
- makeLink(aclIdentity, ident, true, user);
- mDb.flush();
- secdebug("codesign", "new linkages established: pass");
- return true;
-
-#else /* ignore Code Equivalence Database */
-
- return false;
-
-#endif
-}
-
-
-//
-// Debug dumping support
-//
-#if defined(DEBUGDUMP)
-
-void CodeSignatures::debugDump(const char *how) const
-{
- using namespace Debug;
- using namespace LowLevelMemoryUtilities;
- if (!how)
- how = "dump";
- CssmData key, value;
- if (!mDb.first(key, value)) {
- dump("CODE EQUIVALENTS DATABASE IS EMPTY (%s)\n", how);
- } else {
- dump("CODE EQUIVALENTS DATABASE DUMP (%s)\n", how);
- do {
- const char *header = key.interpretedAs<const char>();
- size_t headerLength = strlen(header) + 1;
- dump("%s:", header);
- dumpData(key.at(headerLength), key.length() - headerLength);
- dump(" => ");
- dumpData(value);
- dump("\n");
- } while (mDb.next(key, value));
- dump("END DUMP\n");
- }
-}
-
-void CodeSignatures::Identity::debugDump(const char *how) const
-{
- using namespace Debug;
- if (!how)
- how = "dump";
- dump("IDENTITY (%s) path=%s", how, getPath().c_str());
- dump(" name=%s hash=", mName.empty() ? "(unset)" : mName.c_str());
- dumpData(getHash());
- dump("\n");
-}
-
-#endif //DEBUGDUMP