I'm signing a .dmg containing a .app with a valid Developer ID profile. Everything is signed, frameworks included. When I run codesign -dvvv, the right certificate appears and satisfies its Designated Requirement. The application runs fine.
However, when I upload and download the .dmg, the signature "disappears". When I run codesign -dvvv, it says code object is not signed at all. And GateKeeper naturally refuses to run the application.
Note: it sounds a lot like this issue but I'm definitely signing with the right Developer ID certificate, and the .dmg does not appear "damaged".
[Note: the situation changed significantly in OS X v10.11.5 and v10.12; this answer has been updated to reflect that.]
In general, the thing you really need to sign is the files (mainly the app) inside the disk image, not the image itself. After the image is downloaded, the signature on the individual items will be checked as they are used. Starting in OS X 10.11.5, signing disk images is properly supported and sometimes required, but that's in addition to signing the relevant items inside it.
Through OS X v10.11.4, you could sign the disk image itself (with codesign -s "Developer ID Application: [your company]" example.dmg), but the signature this creates is stored in the form of extended attributes attached to the image file. Actually, it creates three xattrs, named com.apple.cs.CodeDirectory, com.apple.cs.CodeRequirements, and com.apple.cs.CodeSignature. The critical thing to realize is that these attributes are filesystem metadata -- that is, they're attached to the file, not part of the file's contents. The HTTP protocol has very limited support for filesystem metadata, so when you upload or download via HTTP (or FTP or...), it only transfers the file's contents, and the xattrs are lost.
You can see the xattrs with the ls -l# command (and in even more detail with the xattr command):
$ ls -l# example.dmg
-rw-r--r--# 1 gordon staff 338590 Nov 13 2013 example.dmg
com.apple.cs.CodeDirectory 120
com.apple.cs.CodeRequirements 172
com.apple.cs.CodeSignature 8515
com.apple.diskimages.fsck 20
com.apple.diskimages.recentcksum 81
After downloading, the image will have lost those attributes (and probably gained com.apple.quarantine and com.apple.metadata:kMDItemWhereFroms from the download process), and hence will not be considered signed. The files contained in it, on the other hand, should still be properly signed (since their signatures are part of the image file's contents.)
Starting in OS X v10.11.5, codesign supports embedding the signature into the disk image itself, so that it will survive being downloaded over HTTP. Starting in v10.12, gatekeeper will enforce additional restrictions on apps in unsigned disk images that will prevent the app from loading additional content (mainly dynamic libraries) from the disk image, unless they're contained inside the app itself. If you don't know whether that's relevant to your app, go ahead and sign the disk image (actually, it's a good idea anyway), but be sure to run codesign under 10.11.5 or later or the signature won't be in a useful format!
Related
I have a small project which implements function hooking in MAC using mach_override() by Jonathan 'Wolf' Rentzsch:https://github.com/rentzsch/mach_override
I have hooked one of the functions of kextstat process from mac.
So when I am executing
$kextstat
OSX is killing this process saying below error:
CODE SIGNING: process 2211[kextstat]: rejecting invalid page at
address 0x7fff5132d000 from offset 0xca53000 in file
"/private/var/db/dyld/dyld_shared_cache_x86_64h"
(cs_mtime:1531207073.366350606 == mtime:1531207073.366350606)
(signed:0 validated:0 tainted:0 nx:0 wpmapped:1 dirty:1 depth:2)
my dynamic library is code-signed.
In my initial observation, i could conclude that mach_override() function in failing in following code:
atomic_mov64((uint64_t *)originalFunctionPtr,
jumpRelativeInstruction);
above code could be found : mach_override.c:342
https://github.com/rentzsch/mach_override
Firstly, you should note that public discussion of Apple's Developer Beta software is a breach of Apple's terms and conditions. Such questions should be posted to Apple's forums, which has a specific section for Beta releases.
That being said, the technology and problem you're seeing is SIP, which includes denial of code injection, as well as protecting system files from being overwritten. The detail that follows is nothing new and exists in pre 10.14 macOS builds, though disabled (by default) in those versions.
When an application is signed, it creates a hash of each file page in the binary, and a super hash of all those hashes. During execution of a binary, when a page fault occurs, or a file (e.g. dylib) is mmap'd into the executing process, amfid (Apple Mobile File Integrity daemon) verifies that the new code is signed and that its signature matches that of the executing binary. If the signature or hashes do not match, then the code is denied loading, or in some cases, the process is killed.
In this case, kextstat contains an Apple certificate that does not match the certificate of your code that you're attempting to inject into kextstat. In addition, the certificate of kexstat includes the platform binary flag, which Developer certificates do not have.
Without a zero-day vulnerability, you're not going to be able to hook kextstat in a commercial environment. If it's just research you want to do, then you can either disable SIP, or remove the signature from the kextstat binary, causing amfid to ignore the certificate verification.
OSX El Capitan and Go 1.6
What I want is simpler than it sounds from the title.
The OSX firewall disallows any unknown application from accepting connections. When any such program starts, the user is presented with a dialog whether or not the said executable should be permitted to receive connections. The user's choice is then remembered.
The above works fine when for example one develops with node where the actual executable is a single binary and the user just needs to allow/deny it once.
When developing in go (and any other compiled language) the created executable is different every time. Which means I get the dialog every single time I start my server.
One way to avoid this dialog is to sign the executable with a self-signed certificate one generates in OSX itself. Once we have the certificate we simply sign the executable and allow/deny it once. Code signatures are always remembered even if the executable binary changes.
So, my question is:
Is there a way to make go run the signing command before running the compiled binary?
Even easier: start the server explicitly on localhost, like:
http.ListenAndServe("localhost:8080", nil)
I wrote a little piece on this recently:
suppressing-accept-incoming-network-connections-warnings-on-osx
Silly me. Took me 5 minutes to write the question and 2 minutes to find the answer and write the script that solves it. I'll post it here in case anybody stumbles on the same problem.
binary=$GOPATH/pkg/kliron/hiss/hiss.a
go build -o $binary hiss/main.go
codesign -f -s klironCode $binary --deep
$binary "$#"
Just use go build.
I have a 32-bit windows old application (with the C/Win32 source) that creates its data file in the same folder where the executable is.
Because the application has no installation program and the user can place the executable wherever he/she wants, the application has a dialog to inform the user where its data is located.
But under Microsoft Vista/Seven if the user puts the application in the Program Files or any other system-protected folder the data file gets virtualized and moved to a virtual-store.
If, under Vista/Seven, I still want to inform the user where the data file is located:
(without preventing virtualization in the manifest file)
How can I know (programatically) if the data file is virtualized? Or if the folder where the executable is located implies that data file will be virtualized?
Assuming I know the data file is virtualized, how can I know (programatically) the location of the virtual folder, to show it in the information dialog?
I have found the following question very close to what I'm asking but it doesn't show the solution (if any) of knowing when virtualization is taking place for a file, and where it gets virtualized.
How to detect file redirection to the Windows VirtualStore?
Virtualization is transparent to the app. The only way to know whether it is being virtualized is to ask the OS, per the answer in the question you linked to (use GetTokenInformation() with the TokenVirtualizationEnabled flag), but there is no way (that I know of) of asking the OS where the virtualized items are actually stored, as it may be different from one OS version to the next. You will have to do some research and then hard-code the paths for each given OS that your app detects at runtime.
If you are going to update your code to detect virtualization, then you are better off updating the code to play nicer with UAC instead. Stop storing your files where they do not belong, and start storing them where Microsoft wants you to store them. In this case, within the user's profile instead. Use SHGetFolderPath() or related function to locate the user's CSIDL_LOCAL_APPDATA folder (or SHGetKnownFolderPath() on Vista+ to locate the FOLDERID_LocalAppData folder), then create a subfolder underneath it for your app to store its data files in.
I've written a program in the Mac App store which displays some graphics. Occasionally it updates these off the internet. As with most folks, I'm having to Sandbox my app now.
Almost everything is working, but when updating it saves a file in my app's own bundle and fails with 'sandboxd: deny file-write-create'
I just use fopen(..., "wb")
The path passed into fopen is:
/Users/MyUser/Library/Developer/Xcode/DerivedData/MyApp-czuwveatgjffaggwqjdqpobjqqop/Build/Products/Debug/My.app/Contents/Resources/the_file.foo
The path is created using:
CFBundleRef bundle = CFBundleGetMainBundle();
CFURLRef url = CFBundleCopyResourcesDirectoryURL(bundle);
CFURLGetFileSystemRepresentation(url, true, (UInt8*)buf, sizeof(buf));
Am I doing something obviously wrong here? My app is multi-platform so ideally I'd keep using fopen/etc. As I understood, the app should be allowed to write into its own bundle, even if it is blocked from doing anything elsewhere?
thanks!
OS X apps should never write into the app bundle (even if they aren't sandboxed). In OS X, the application doesn't have any more access to the file system than the user does on their own, and the user (generally) won't have permissions to modify anything in /Applications. Note that this is quite different from iOS apps, which normally store their data inside the app bundle.
In OS X, application data is generally stored in each user's Library folder, in one of a number of subfolders depending on the type of data it is; see Apple's note on "The Library Directory Stores App-Specific Files" for the primary ones. Sandboxing complicates this, because each app gets its own Container inside the user's Library. Apple provides a number of methods for determining the correct location for various kinds of data; see "Determining Where to Store Your App-Specific Files".
I've just submitted an app to the Mac App Store that uses some external dynamic libraries.
I got an email from Apple saying that:
Invalid Signature - the executable something.app/Contents/Frameworks/some.dylib is not signed, the signature is invalid, or it is not signed with an Apple submission certificate. Refer to the Code Signing and Application Sandboxing Guide for more information.
The problem is of course caused by the fact that I only signed "my" executable, not the libraries.
Is it common/good practice to also sign the libraries, even though they're not written by me?
Think of digitally signing a file as:
A means of verifying the integrity of that file, thus making it possible to detect whether it’s been modified;
A means of verifying who published that file, which is not the same as writing the corresponding source code. You’re attesting that it was really you who’s shipped that file.
Since dynamic libraries contain executable code, it’s good practice (and in some cases, such as the MAS, mandatory) to digitally sign them for the same reason you sign the main executable file: guaranteeing that your application is exactly what you (and only you) have shipped from your build machine, no changes whatsoever. A running program includes the main executable file and all loaded libraries. If you sign the main executable file only, leaving the dynamic libraries unsigned, it would be possible to alter the dynamic libraries (or even replace them), thus changing what your program does.