How to get csreq of macOS application on command line? How to get csreq of macOS application on command line? sqlite sqlite

How to get csreq of macOS application on command line?


Background

The format of the csreq blob itself doesn't appear too complicated, and the source code found in the Security.Framework can assist in decoding the meaning if you want to get fancy.[1] It's basically a magic header(the 0xFADE0C00) followed by a 32bit length(the size of the blob) and then some number of different "operations".

Thankfully there are already utilities we can use to manipulate the csreq blob, so we don't need to dig too deep into this.

Decoding the csreq blob, and finding where it comes from

Let me take your example above for Terminal.app. Apple ships a tool called csreq that can be used to convert the requirement from it's binary representation to a text representation(and back again).

# Convert the hex string into a binary blob$ BLOB="FADE0C000000003000000001000000060000000200000012636F6D2E6170706C652E5465726D696E616C000000000003"$ echo "$BLOB" | xxd -r -p > terminal-csreq.bin# Ask csreq to tell us what it means$ csreq -r- -t < terminal-csreq.binidentifier "com.apple.Terminal" and anchor apple

So that csreq blob just says it wants to match the application with identifier "com.apple.Terminal" and anchor apple. We can inspect Terminal.app and find the same requirements string(under "designated")

$ codesign -d -r- /Applications/Utilities/Terminal.appExecutable=/Applications/Utilities/Terminal.app/Contents/MacOS/Terminaldesignated => identifier "com.apple.Terminal" and anchor apple

Lets look at another example, this time for virtualbox from your repository[2]:

# Convert the hex string into a binary blobBLOB="FADE0C00000000AC0000000100000006000000020000001D6F72672E7669727475616C626F782E6170702E5669727475616C426F78000000000000060000000F000000060000000E000000010000000A2A864886F76364060206000000000000000000060000000E000000000000000A2A864886F7636406010D0000000000000000000B000000000000000A7375626A6563742E4F550000000000010000000A564235453254563936330000"$ echo "$BLOB" | xxd -r -p > vbox-csreq.bin# Ask csreq to tell us what it means$ csreq -r- -t < vbox-csreq.binidentifier "org.virtualbox.app.VirtualBox" and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = VB5E2TV963# ask codesign what the requirement text from the application itself is$ codesign -d -r- /Applications/VirtualBox.appExecutable=/Applications/VirtualBox.app/Contents/MacOS/VirtualBoxdesignated => identifier "org.virtualbox.app.VirtualBox" and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = VB5E2TV963

Again we can see that the designated field codesign returns is the same as what the csreq blob contains.

If you're curious about the actual meaning of the requirements string, apple has some documentation[3] on that.


Building a new csreq blob

Now we know what the csreq blob contains and where to find equivalent information, we need to convert it to the binary format the tcc database requires. The csreq tool we used above for decoding the binary blob is also capable of converting the text representation into binary.

# Get the requirement string from codesign$ REQ_STR=$(codesign -d -r- /Applications/Utilities/Terminal.app/ 2>&1 | awk -F ' => ' '/designated/{print $2}')# Convert the requirements string into it's binary representation(sadly it seems csreq requires the output to be a file; so we just throw it in /tmp)$ echo "$REQ_STR" | csreq -r- -b /tmp/csreq.bin# Convert the binary form to hex, and print it nicely for use in sqlite$ REQ_HEX=$(xxd -p /tmp/csreq.bin  | tr -d '\n')$ echo "X'$REQ_HEX'"X'fade0c000000003000000001000000060000000200000012636f6d2e6170706c652e5465726d696e616c000000000003'

This hex string is identical to what you had above from the tcc database.


Bonus: Unsigned binaries

If you want to trust a script/binary that is unsigned and try to use the above method, you'll run into some issues:

$ codesign -d -r- ./hello.sh./hello.sh: code object is not signed at all

Reading the documentation about the Code Signing Requirement Language[3], there is a small note under Code Directory Hash(emphasis mine)

Because the code directory changes whenever the program changes in a nontrivial way, this test can be used to unambiguously identify one specific version of a program. When the operating system signs an otherwise unsigned program (so that the keychain or Parental Controls can recognize the program, for example), it uses this requirement.

So for unsigned programs, an ad-hoc signature is generated and used for identification for things like TCC(among others).

The codesign tool can be used to create an ad-hoc signature which we can get the requirement string from.

$ cat hello.sh #!/bin/bashecho "Hello World"# Create a detached signature(so as not to modify the original binary)$ codesign --detached ./hello.sh.sig -s - ./hello.sh# Display the designated identifier from the detached signature$ codesign -d -r- --detached ./hello.sh.sig ./hello.sh Executable=/Users/keith/hello.shhost => identifier "com.apple.bash" and anchor apple# designated => cdhash H"70212a41efea9849e7a88afa946afa3e1b559cbe" or cdhash H"9044184bcced89d2f4bf1d75ec61a7537871eee7"

From here we can continue with the same process given above.


[1] https://github.com/toriningen/apple-security-framework/blob/eb36592b951817622c07a7cff65854f477054b0b/OSX/libsecurity_codesigning/lib/requirement.h#L54

[2] https://github.com/tiiiecherle/osx_install_config/blob/master/11_system_and_app_preferences/11a_app_profiles/VirtualBox.txt

[3] https://developer.apple.com/library/archive/documentation/Security/Conceptual/CodeSigningGuide/RequirementLang/RequirementLang.html