Question

I have Windows application that can run on OS X under Wine. For convenience I want to pack the application as OS X app (ZIP archive of xxx.app folder based on WineBottler).

Note that the main executable of the app (as defined by CFBundleExecutable tag of Info.plist) is a shell script, not a binary.

I want to sign the application to pass through OS X Gatekeeper. As my complete build process runs on Windows (and as I actually do not have Mac at all) I need to sign it on Windows.

I already found that signing the app creates _CodeSignature folder with four files:

CodeDirectory
CodeRequirements
CodeResources
CodeSignature

I have not found any specification describing contents of these files.

Experimentally, I've found that CodeResources is an XML file with SHA-1 hashes of all files in the app. I can generate that.

The contents of CodeRequirements binary file seems to be fixed. It does not seem to change with contents of the app. Confirmation is appreciated. What is this file good for?

As for the binary files CodeDirectory and CodeSignature I have no clue.

Both files change with app contents. It seems that any app file change (including plain text license file) affects them.

The CodeSignature obviously contains the signature. I can see plain-text information about code signing certificate in the file. Is there any tool that can generate the file? As it is a signature, it should be pretty standard. Though there can be some additional binary metadata that can make generation more difficult. Does anyone know what does it specifically sign? I can imagine that it signs only CodeResources file as that describes all other files in the app. Or does it actually sign all the files in the app recursively?

Native OS X apps have CodeResources only. So there's actually no signature in _CodeSignature. I suppose it's because they have embedded signature in the main executable binary. Note that my [Windows] binary (though it's not directly referred to by Info.plist as mentioned above) is code-signed using Windows signtool.exe. Apparently OS X recognizes the signature even without the reference as codesign -d -vvv xxx.app output includes information about the certificate:

Executable=/Applications/WinSCP.app/Contents/MacOS/startwine
Identifier=WinSCP
Format=bundle with generic
CodeDirectory v=20100 size=135 flags=0x0(none) hashes=1+3 location=embedded
Hash type=sha1 size=20
CDHash=a1ef4f04b2c1b4b793788ce3ab9d7881528f3d95
Signature size=4867
Authority=Martin Prikryl
Authority=VeriSign Class 3 Code Signing 2010 CA
Authority=VeriSign Class 3 Public Primary Certification Authority - G5
Signed Time=23.4.2014 23:51:18
Info.plist entries=14
Sealed Resources version=2 rules=12 files=846
Internal requirements count=2 size=136

Confusing is that is does not mention binary name at all. Anyway, it does not make Gatekeeper happy. Note the the above test is run against app that already includes CodeResources file (that's probably what the Sealed Resources version refers too as rules and files counts match with the file contents).

Was it helpful?

Solution

We have tried to reverse-engineer the code signing using source code of libsecurity_codesigning library. Although it seems feasible, it's still too much effort, so we consider giving up. We would like to at least share what we have found so far, so others may build upon.

We have found that when codesign does not find MachO binary, it falls back to "architecture agnostic" signing implemented in SecCodeSigner::Signer::signArchitectureAgnostic.

Key steps there:

  • CodeDirectory file generation. The directory includes few SHA-1 hashes of various pieces of the bundle in addition to file header (including directory version)
  • CodeSignature file generation. The signature signs CodeDirectory file using Cryptographic Message Syntax (CMS) format. The signature can be verified on any platform using OpenSSL:

    openssl cms -verify -in CodeSignature -inform DER
        -content CodeDirectory -noverify -out CodeDirectory.verified
    

    Note that -noverify is needed to skip certificate validation as OpenSSL does not seem to support "code signing" purpose of certificates.

    OpenSSL should be able to create CMS signature using following command:

    openssl cms -sign -in CodeDirectory -out CodeSignature 
        -signer certificate.pem -outform DER
    

    But such signature is not accepted by OS X.

We didn't get any further.

OTHER TIPS

Not strictly signing on Windows, but have you considered Remote Desktop into a friends Mac or renting a Mac in the Cloud? http://www.macincloud.com seems to have fairly reasonable plans.

Could save a lot of the trouble. All you really need access to is the codesign tool and the Terminal.

Edit: You will still need an Apple Developer account to sign the application - Gatekeeper only allows signatures from Apple-issued developer ID certificates.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top