Checking legitimacy of process

I want to evaluate whether processes installed and running on a macOS system are legitimate.


I understand (thanks Eskimo) that checking their identifier is not a good way to identify processes, as any developer can use any identifier. I also understand that I should use DesignatedRequirements.


I have the following code at the moment:

// Get code signing information.
var infoOpt: CFDictionary? = nil
err = SecCodeCopySigningInformation(staticCode, SecCSFlags(rawValue:kSecCSRequirementInformation), &infoOpt)
guard err == errSecSuccess, let info = infoOpt as? [String:Any] else {
    return nil
}

let processId = info[kSecCodeInfoIdentifier as String] as? String // nil iif code is not signed
let designatedRequirement = info[kSecCodeInfoDesignatedRequirement as String] as! SecRequirement
var designatedRequirementCFStr : CFString?
SecRequirementCopyString(designatedRequirement, [], &designatedRequirementCFStr)
let designatedRequirementStr = designatedRequirementCFStr as String?



But how can I use the designated requirement to ensure that the app is legitimate ?


More specifically :


- If I want the anchor (root certificate) to be Apple's, how can I programatically check it ? There must be something better than parsing the string above.

- I am not very familair with the certificate process. What is the anchor "apple generic" ?

- What is a reasonable rule to accept the process as legitimate? Is it all about the anchor and I can disregard the certificate leaf?



Thanks!

Here is what I do:

  1. Call SecStaticCodeCreateWithPath
  2. Create a SecRequirementRef using SecRequirementCreateWithStringAndErrors using the string "anchor apple generic"
  3. Setup a SecCSFlags set to kSecCSCheckAllArchitectures
  4. And finally call SecStaticCodeCheckValidity
  5. All of this works in the Sandbox, with some caveats
  6. If you want to go the extra mile, you can call SecCodeCopySigningInformation and parse the "certificate" values. This will give you the name of the developer, or just "Apple" or just "App Store".


All of my code is Objective-C.


However, determining from the above whether or not a process is legitimate is tricky for many reasons.

  1. I am starting with a path to an executable. You are coming from a different place with processes in a network filter. Do you have paths available? Can you access all of those paths from the sandbox? (Trick question - you can't.)
  2. The string "anchor apple generic" is for quasi-Apple-signed apps. This is Developer ID, Mac App Store, and some "other" Apple apps. To check the validity of a genuine Apple app, use just "anchor apple".
  3. There are many possible results from SecStaticCodeCheckValidity. A "failure" is not necessarily straightforward. For example, Apple regularly breaks its signatures. The current Safari on a fully-patched, up-to-date Mojave install fails codesign with errSecCSBadResource. You can verify this with Apple's own "codesign" tool.
  4. You can use the launchd database to find (almost) all running processes and (almost) their paths. This, too, is tricky. First of all, there is no launchd database. You have to parse the output of "launchctl print". (Cue the Apple engineers screaming.)
  5. You can also use the launch services database to find out if a bundle is signed or not. Did I mention any of this being tricky. Again, no database here. You have to parse the output of "lsregister --dump". (Cue the Apple engineers sobbing.) Note that Apple changes this output with virtually every OS release. Consider yourself warned. Also, this data is not very reliable. You only get a "Team ID" and it can be out of date. Use it only when other methods fail.

Thanks a lot John for this very detailed and helpful answer! I will do this.

Your point about apple breaking its own signature is interesting. I assume this happens only for old mac os versions ?

Your point about apple breaking its own signature is interesting. I assume this happens only for old mac os versions ?


Not necessarily. I only noticed it with Safari the other day by accident. There are always a handful of Apple executables with invalid signatures. I also have a database of expected Apple signature result for each executable, per OS version. This is a delicate topic when you are building something with a "security" aspect. If you tell the user there is a problem, they expect it to be fixed. If you tell users there is a problem somewhere, they will do anything in their power to delete the offending file. As a developer, don't start something you can't finish.


Apple, by virtue of its power and control over the OS and platform, gets a pass on things that other developers would not. But don't take this the wrong way. I'm not one of those "internet security researchers" accusing Apple of every malfeasance under the sun. Since 10.9, less than 1% of core Apple launchd executables have had a signature problem. But a number of popular 3rd party security apps don't sign their software at all. At least of them installs a man-in-the-middle that overrides core OS networking security. How is your network filter going to handle that? 😉

That's very interesting. On MacOS Catalina, Safari's signature is not broken at least.


In my opinion, an unsigned third party security software that installs a man in the middle is a big NO-NO, and it would be reasonable for a network filter to block network access of such an app. If a third party developer does not bother signing its own app, they are not a serious security app. Even if the app itself is not outright malicious, it's too easy for a malware to impersonate a non-signed app.

Do you know what "checkTrustedAnchors" does exactly ?

It seems great, but I can't find documentation on exactly what it does (beyond the header).

Checking legitimacy of process
 
 
Q