+//
+// Whitelist pre-screen processing.
+// Whitelist-matching unsigned code is expensive since we have to generate a full code signature
+// just to see if we match a whitelist authority entry. This class generates a light(er)-weight
+// prescreen and matches it against a hint in an authority record generated from the (detached recorded)
+// code signature at time of whitelist recording.
+// This is just a heuristic to cheaply rule out guaranteed mismatches. When in doubt, we go ahead
+// and do the full work.
+//
+class WhitelistPrescreen {
+public:
+ WhitelistPrescreen(SecStaticCodeRef code)
+ : mRep(SecStaticCode::requiredStatic(code)->diskRep()) { }
+
+ bool reject(const char *screen, const char *remarks);
+
+private:
+ std::string create(char type, SHA1 &hash);
+
+ RefPointer<DiskRep> mRep; // DiskRep representing the code
+ std::string mScreen; // calculated screen (on demand)
+};
+
+bool WhitelistPrescreen::reject(const char *screen, const char *remarks)
+{
+ if (!screen) { // authority record has no screen to match - apply heuristic
+ if (remarks && mRep->mainExecutablePath() != remarks) // not an allow record (or moved)
+ return true;
+ else
+ return false; // can't rule out; proceed
+ }
+
+ if (mScreen.empty()) {
+ if (CFRef<CFDataRef> info = mRep->component(cdInfoSlot)) {
+ SHA1 hash;
+ hash.update(CFDataGetBytePtr(info), CFDataGetLength(info));
+ mScreen = create('I', hash);
+ } else if (mRep->mainExecutableImage()) {
+ mScreen = "N";
+ } else {
+ SHA1 hash;
+ hashFileData(mRep->mainExecutablePath().c_str(), &hash);
+ mScreen = create('M', hash);
+ }
+ }
+
+ return screen != mScreen;
+}
+
+std::string WhitelistPrescreen::create(char type, SHA1 &hash)
+{
+ SHA1::Digest digest;
+ hash.finish(digest);
+ char buffer[2*SHA1::digestLength + 2] = { type };
+ for (size_t n = 0; n < SHA1::digestLength; n++)
+ sprintf(buffer + 1 + 2*n, "%02.2x", digest[n]);
+ return buffer;
+}
+
+