Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

bug? in codesign --remove-signature feature

I would like to remove the digital signature from a Mac app that has been signed with codesign. There is an undocumented option to codesign, --remove-signature, which by it's name seems to be what I need. However, I can't get it to work. I realize it is undocumented, but I could really use the functionality. Maybe I'm doing something wrong?

 codesign -s MyIdentity foo.app

works normally, signing the app

 codesign --remove-signature foo.app

does disk activity for several seconds, then says

 foo.app: invalid format for signature

and foo.app has grown to 1.9 GB!!! (Specifically, it is the executable in foo.app/Contents/Resources/MacOS that grows, from 1.1 MB to 1.9 GB.)

The same thing happens when I try to sign/unsign a binary support tool instead of a .app.

Any ideas?


Background: This is my own app; I'm not trying to defeat copy protection or anything like that.

I would like to distribute a signed app so that each update to the app won't need user approval to read/write the app's entries in the Keychain. However, some people need to modify the app by adding their own folder to /Resources. If they do that, the signature becomes invalid, and the app can't use it's own Keychain entries.

The app can easily detect if this situation has happened. If the app could then remove it's signature, everything would be fine. Those people who make this modification would need to give the modified, now-unsigned app permission to use the Keychain, but that's fine with me.

like image 288
user532477 Avatar asked Sep 21 '11 13:09

user532477


1 Answers

I ran into this issue today. I can confirm that the --remove-signature option to Apple's codesign is (and remains, six years after the OP asked this question) seriously buggy.

For a little background, Xcode (and Apple's command line developer tools) include the codesign utility, but there is not included a tool for removing signatures. However, as this is something that needs to be done in certain situations pretty frequently, there is included a completely undocumented option:

codesign --remove-signature which (one assumes, given lack of documentation) should, well, be fairly self-explanatory but unfortunately, it rarely works as intended without some effort. So I ended up writing a script that should take care of the OP's problem, mine, and similar. If enough people find it here and find it useful, let me know and I'll put it on GitHub or something.


#!/bin/sh # codesign_remove_for_real -- working `codesign --remove-signature`
# (c) 2018 G. Nixon. BSD 2-clause minus retain/reproduce license requirements.

total_size(){
  # Why its so damn hard to get decent recursive filesize total in the shell?
  # - Darwin `du` doesn't do *bytes* (or anything less than 512B blocks)
  # - `find` size options are completely non-standardized and doesn't recurse
  # - `stat` is not in POSIX at all, and its options are all over the map...
  # - ... etc. 
  # So: here we just use `find` for a recursive list of *files*, then wc -c
  # and total it all up. Which sucks, because we have to read in every bit
  # of every file. But its the only truly portable solution I think.
  find "$@" -type f -print0 | xargs -0n1 cat | wc -c | tr -d '[:space:]'
}

# Get an accurate byte count before we touch anything. Zero would be bad.
size_total=$(total_size "$@") && [ $size_total -gt 0 ] || exit 1

recursively_repeat_remove_signature(){
  # `codesign --remove-signature` randomly fails in a few ways.
  # If you're lucky, you'll get an error like:
  # [...]/codesign_allocate: can't write output file: [...] (Invalid argument)
  # [...] the codesign_allocate helper tool cannot be found or used
  # or something to that effect, in which case it will return non-zero.
  # So we'll try it (suppressing stderr), and if it fails we'll just try again.
  codesign --remove-signature --deep "$@" 2>/dev/null ||
    recursively_repeat_remove_signature "$@"

  # Unfortunately, the other very common way it fails is to do something? that
  # hugely increases the binary size(s) by a seemingly arbitrary amount and
  # then exits 0. `codesign -v` will tell you that there's no signature, but
  # there are other telltale signs its not completely removed. For example,
  # if you try stripping an executable after this, you'll get something like
  # strip: changes being made to the file will invalidate the code signature
  # So, the solution  (well, my solution) is to do a file size check; once
  # we're finally getting the same result, we've probably been sucessful.
  # We could of course also use checksums, but its much faster this way.
  [ $size_total == $(total_size "$@") ] ||
    recursively_repeat_remove_signature "$@"

  # Finally, remove any leftover _CodeSignature directories.
  find "$@" -type d -name _CodeSignature -print0 | xargs -0n1 rm -rf
} 

signature_info(){
  # Get some info on code signatures. Not really required for anything here.
  for info in "-dr-" "-vv"; do codesign $info "$@";  done # "-dvvvv" 
}

# If we want to be be "verbose", check signature before. Un/comment out:
# echo >&2; echo "Current Signature State:" >&2; echo >&2; signature_info "$@"


# So we first remove any extended attributes and/or ACLs (which are common,
# and tend to interfere with the process here) then run our repeat scheme.
xattr -rc "$@" && chmod -RN "$@" && recursively_repeat_remove_signature "$@"

# Done!


# That's it; at this point, the executable or bundle(s) should sucessfully
# have truly become stripped of any code-signing. To test, one could
# try re-signing it again with an ad-hoc signature, then removing it again:
# (un/comment out below, as you see fit)

# echo >&2 && echo "Testing..." >&2; codesign -vvvvs - "$@" &&
  # signature_info "$@" && recursively_repeat_remove_signature "$@"

# And of course, while it sometimes returns false positives, lets at least:
codesign -dvvvv "$@" || echo "Signature successfully removed!" >&2 && exit 0
like image 59
Geoff Nixon Avatar answered Sep 30 '22 19:09

Geoff Nixon