16. Code Signing

## 16. Code Signing

### 16.1. OS X

Starting with OS X 10.8, Apple has tightened its security policies through the inclusion of "Gatekeeper". This new feature is intended to protect users from malicious software by only allowing applications from the Apple Store or signed by a registered Apple Developer to be installed. This security policy (the default one) can be relaxed to allow any application to be installed but the process is not straightforward and most users will not be willing to do that.

This milestone in the story of OS X makes it mandatory for you to sign your installers and InstallBuilder makes this process easy.

The first step in the process is for you to become a registered Apple Developer and request a signing certificate. You can follow the steps to request and install your certificates in the Apple Documentation: developer.apple.com/library/mac/. After installing your certificate, you can proceed to integrate it into the build process.

InstallBuilder supports two modes of signing OS X installers. When building on OS X, if you provide the `<osxSigningIdentity>` setting, the builder will try to use the installed `codesign` tool in the system. If you are building on a different platform, or the builder fails to validate the provided signing identity, it will check if `<osxSigningPkcs12File>` is provided, and use the built in signing mechanism, not dependant on installed tools, it if it is.

As as summary, on OS X, `<osxSigningIdentity>` takes precedence over `<osxSigningPkcs12File>`, and is completely ignored in other supported platforms (Windows and Linux).

#### Built-in signing code

When providing the `<osxSigningPkcs12File>` setting, InstallBuilder will use its multiplatorm built-in signing mechanism. The advantage of this mode of operation is that it allows building and signing your OS X installers in any of the supported platforms: Linux, OS X and Windows. You could even combine it with the Native codesign Mode so the builder will use it on OS X and fallback to the built-in mode on the rest of platforms.

To enable it, you just need to provide the path to the `PKKS#12` file containing your signing certificate (check How to export your signing certificate as a PKCS#12 file for a detailed explanation about how to get it from your Keychain):

    <project>
       ...
       <osxSigningPkcs12File>${build_project_directory}/osx-signing.p12</osxSigningPkcs12File>
       ...
    </project>

When building, the builder will prompt you to enter the password to unlock the `PKCS#12` file, and sing the installer. You could also provide the password through the `<osxSigningPkcs12Password>` tag.

    <project>
       ...
       <osxSigningPkcs12File>${build_project_directory}/osx-signing.p12</osxSigningPkcs12File>
       <osxSigningPkcs12Password>somEPa55woRd!</osxSigningPkcs12Password>
       ...
    </project>

However, providing the hardcoded password is discouraged. This method is intended to ease the automation of the process, for example, providing the password as an environment variable. For example, if you define an environment variable OSX_SIGNING_PASSWORD with the value of your password, you could then use the below code:

    <project>
       ...
       <osxSigningPkcs12File>${build_project_directory}/osx-signing.p12</osxSigningPkcs12File>
       <osxSigningPkcs12Password>${env(OSX_SIGNING_PASSWORD)}</osxSigningPkcs12Password>
       ...
    </project>

The builder will then use the value instead of asking you to enter the password interactively. If then you try to build without defining the variable, the builder will simply ask for it.

Finally, you can also configure whether to timestamp or not the signature and which server to use using the `<osxSigningTimestampServer>` tag. OS X signatures are timestamped by default so its default value is set to `http://timestamp.apple.com/ts01` even if no value is provided but you could set it any other server supporting RFC 3161 standard:

    <project>
       ...
       <osxSigningPkcs12File>${build_project_directory}/osx-signing.p12</osxSigningPkcs12File>
       <osxSigningPkcs12Password>${env(OSX_SIGNING_PASSWORD)}</osxSigningPkcs12Password>
       <osxSigningTimestampServer>http://timestamp.example.org/req</osxSigningTimestampServer>
       ...
    </project>

Or even disable it by emptying it:

    <project>
       ...
       <osxSigningPkcs12File>${build_project_directory}/osx-signing.p12</osxSigningPkcs12File>
       <osxSigningPkcs12Password>${env(OSX_SIGNING_PASSWORD)}</osxSigningPkcs12Password>
       <osxSigningTimestampServer></osxSigningTimestampServer>
       ...
    </project>

##### How to export your signing certificate as a PKCS#12 file

The first step will be to locate your signing certificate on the `Keychain Access` application. If you did not create a separated keychain for it, it will be typically located in your `login` keychain. The certificate to export should be named similar to `Developer ID Application: Your Company (XXXXXXXXXX)`, where the string between the parentheses will be your `Team ID`. You may also have another certificate named `Developer ID Installer: Your Company (XXXXXXXXXX)` but we are not interested in that one.

Figure 69. Export Keychain 1

Right-click on the `Developer ID Application` certificate and select `Export` from the contextual menu:

Figure 70. Export Keychain 2

In the new popup, make sure you select "Personal Information Exchange (.p12)" as the file format, select a path to save it, and click save:

Figure 71. Export Keychain 3

You will now be promted to enter a new password for the exported `PKCS#12` file. This password will protect your signing certificate and private key so you should select an strong password:

Figure 72. Export Keychain 4

The new PKCS#12 file is now ready to be used in InstallBuilder

#### Native codesign mode

This mode of signing is only supported on OS X and requires a working `codesign` installation (with usually requires a modern Xcode plus the command line tools add-on). As this mthod calls `codesign` internally, it has the advantage of being able to adapt to future changes in the signature format by Apple (if those changes do not affect how the tool should be called). This is the recommended method if you are building on OS X.

InstallBuilder defines a set of properties to configure for the signing process. The minimum set of properties you should configure in your project is:

- `<osxSigningIdentity>`: This is the "Common Name" of your Apple Developer certificate. It is usually called `Developer ID Application: Name of Your Company`. The signing process is enabled by completing this field and is the only one truly mandatory.
- `<osxApplicationBundleIdentifier>`: The unique identifier of the application, formatted in reverse-DNS format. It is not required to be customized to allow the singing of your application but InstallBuilder uses the same one for all generated installers (`com.bitrock.appinstaller`) so you should provide one that matches your company name and application. For example, if your company domain name is `example.com`, and your application is named "Foo Bar Editor", you should use `com.example.foo-bar-editor`. This identifier can be also registered using the `Developer Certificate Utility`.

    <project>
       ...
       <osxSigningIdentity>Developer ID Application: Name of Your Company</osxSigningIdentity>
       <osxApplicationBundleIdentifier>com.example.foo-bar-editor</osxApplicationBundleIdentifier>
       ...
    </project>

You can now launch the build process and the builder will try to sign the installer (please note that this process is only allowed on OS X). If your keychain requires a password to access your keys, you will get a dialog requesting it. After introducing it, the build process will continue.

The builder will attempt to sign all of the InstallBuilder binaries under `sample.app/Contents/MacOS` and the full application bundle after the `<postBuildActionList>`. This gives you the opportunity to modify the generated installer before the application is signed and sealed. For example, you could add a `README` file:

    <project>
       ...
       <osxSigningIdentity>Developer ID Application: Name of Your Company</osxSigningIdentity>
       <osxApplicationBundleIdentifier>com.example.foo-bar-editor</osxApplicationBundleIdentifier>
       ...
        <postBuildActionList>
           <copyFile origin="${build_project_directory}/README" destination="${installbuilder_install_root}/output/${project.installerFilename}/Contents/Resources/"/>
        </postBuildActionList>
    </project>

The signing of the bundle will be performed after copying the file so that the signature won’t be broken.

##### Configuring the resource rules

With the default settings, only files under `sample.app/Contents/Resources/` and the bundle executable (`Contents/MacOS/installbuilder.sh`) are sealed so files under `sample.app/Contents/MacOS/` can be modified, added or deleted and the signature will still be valid. You can view which files were sealed by checking the `CodeResources` file:

    $ cat sample.app/Contents/_CodeSignature/CodeResources
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
       <key>files</key>
       <dict>
            <key>Resources/installbuilder.icns</key>
            <data>
                kn13x4a9iiwHbg2lZg9vrUK9Hus=
            </data>
       </dict>
       <key>rules</key>
       <dict>
            <key>^Resources/</key>
            <true/>
            ...
       </dict>
    </dict>
    </plist>

To resolve this, you must provide your own resource rules when signing using the `<osxSigningResourceRulesFile>`:

    <project>
       ...
       <osxSigningIdentity>Developer ID Application: Name of Your Company</osxSigningIdentity>
       <osxApplicationBundleIdentifier>com.example.foo-bar-editor</osxApplicationBundleIdentifier>
       <osxSigningResourceRulesFile>${build_project_directory}/resource-rules.plist</osxSigningResourceRulesFile>
       ...
    </project>

To also seal the runtimes, you may use the following:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
      <key>rules</key>
      <dict>
        <key>^MacOS/</key>
        <true/>
        <key>^Resources/</key>
        <true/>
        <key>^Resources/.*\.lproj/</key>
        <dict>
          <key>optional</key>
          <true/>
          <key>weight</key>
          <real>1000</real>
        </dict>
        <key>^Resources/.*\.lproj/locversion.plist$</key>
        <dict>
          <key>omit</key>
          <true/>
          <key>weight</key>
          <real>1100</real>
        </dict>
        <key>^version.plist$</key>
        <true/>
      </dict>
    </dict>
    </plist>

By using these new rules you ensure that no one can modify your application. For example, just adding a new file will invalidate the signature:

    $ codesign -vvv sample-1.0-osx-installer.app
    sample-1.0-osx-installer.app: valid on disk
    sample-1.0-osx-installer.app: satisfies its Designated Requirement
    $ echo foo >> sample-1.0-osx-installer.app/Contents/MacOS/bar
    $ codesign -vvv sample-1.0-osx-installer.app
    sample-1.0-osx-installer.app: a sealed resource is missing or invalid
    resource added: sample-1.0-osx-installer.app/Contents/MacOS/bar

##### Configuring the Keychain

By default, InstallBuilder will try to locate your keys under the system keychain paths but you can also configure your project to use a custom one. This is very useful when, for example, you don’t want to install your keys on any machine and instead keep them in a safe location, such as a USB drive. To do that, use `<osxSigningKeychainFile>`:

    <project>
       ...
       <osxSigningIdentity>Developer ID Application: Name of Your Company</osxSigningIdentity>
       <osxApplicationBundleIdentifier>com.example.foo-bar-editor</osxApplicationBundleIdentifier>
       <osxSigningResourceRulesFile>${build_project_directory}/resource-rules.plist</osxSigningResourceRulesFile>
       <osxSigningKeychainFile>/Volumes/secure/secure.keychain</osxSigningKeychainFile>
       ...
    </project>

It is also recommended that you password-protect the keychain with a strong password. Note that if you are using a headless server, OS X won’t be able to show the password dialog and the process will fail:

    Builder.app/Contents/MacOS/installbuilder.sh build ~/sample.xml

     Building Sample Project osx
     0% ______________ 50% ______________ 100%
     ##############################
    Warning: Error signing installer: sample-1.0-osx-installer.app: User interaction is not allowed.

To resolve this, you can unlock the keychain from the command line in the `<preBuildActionList>`:

    <project>
       ...
       <osxSigningIdentity>Developer ID Application: Name of Your Company</osxSigningIdentity>
       <osxApplicationBundleIdentifier>com.example.foo-bar-editor</osxApplicationBundleIdentifier>
       <osxSigningResourceRulesFile>${build_project_directory}/resource-rules.plist</osxSigningResourceRulesFile>
       <osxSigningKeychainFile>/Volumes/secure/secure.keychain</osxSigningKeychainFile>
       ...
       <preBuildActionList>
         <runProgram>
            <program>security</program>
            <programArguments>unlock-keychain -p '${password.password}' "${project.osxSigningKeychainFile}"</programArguments>
         </runProgram>
       </preBuildActionList>
       ...
    </project>

And then launch the process as:

    Builder.app/Contents/MacOS/installbuilder.sh build ~/sample.xml --setvars password='Th1s1sav3ry&5ecur3pa55w0rd!'

     Building Sample Project osx
     0% ______________ 50% ______________ 100%
     #########################################

#### Validating the signature

You can validate that the application was properly signed by executing the following command:

    $ codesign -vvv sample-1.0-osx-installer.app
    sample-1.0-osx-installer.app: valid on disk
    sample-1.0-osx-installer.app: satisfies its Designated Requirement

You can also check that all of the runtimes have been signed:

    $ codesign -vvv sample-1.0-osx-installer.app/Contents/MacOS/*
    sample-1.0-osx-installer.app/Contents/MacOS/installbuilder: valid on disk
    sample-1.0-osx-installer.app/Contents/MacOS/installbuilder: satisfies its Designated Requirement
    sample-1.0-osx-installer.app/Contents/MacOS/installbuilder.sh: valid on disk
    sample-1.0-osx-installer.app/Contents/MacOS/installbuilder.sh: satisfies its Designated Requirement
    sample-1.0-osx-installer.app/Contents/MacOS/osx-10.2: valid on disk
    sample-1.0-osx-installer.app/Contents/MacOS/osx-10.2: satisfies its Designated Requirement
    sample-1.0-osx-installer.app/Contents/MacOS/osx-intel: valid on disk
    sample-1.0-osx-installer.app/Contents/MacOS/osx-intel: satisfies its Designated Requirement
    sample-1.0-osx-installer.app/Contents/MacOS/osx-ppc: valid on disk
    sample-1.0-osx-installer.app/Contents/MacOS/osx-ppc: satisfies its Designated Requirement

You can also make sure the signed bundle is valid using the `spctl` tool on OS X:

    $ spctl -a -t exec -vvvv sample-1.0-osx-installer.app
    /Users/bitrock/sample-1.0-osx-installer.app: accepted
    source=Developer ID
    origin=Developer ID Application: Name of Your Company

| object file format unrecognized, invalid, or unsuitable
If you get this error while signing your installer you will need to upgrade your Xcode version to 4.4 and install the "Command Line Tools" add-on

| The signing process is just allowed on OS X
The OS X `codesign` tool is required for the signing so the signing process is only allowed on OS X.

#### Signing an already-built installer

InstallBuilder also includes a command line tool to simplify the process of signing already-built installers. You can find it under the `tools` folder in the installation directory. Executing it without arguments will display the help menu:

    $ tools/code-signing/osx/osxsigner

    Usage:

    /Applications/BitRock InstallBuilder for Qt 8.5.0/tools/code-signing/osx/osxsigner [options] /path/to/application.app

     --help                         Display the list of valid options

     --identity <identity>          Identity used to sign the application bundle
                                    Default:

     --identifier <identifier>      Identifier used to sign the installer. If empty, the CFBundleIdentifier of the bundle will be used
                                    Default:

     --keychain <keychain>          External keychain used to look for the identity
                                    Default:

     --keychain-password <keychain-password> Password to unlock the specified keychain
                                    Default:

     --output <output>              Directory in which to write the signed application. If empty, the application will be written in the same directory as the original with the '-signed' suffix appended
                                    Default:

     --skip-runtimes                Just sign the Application Bundle and not the runtimes under Contents/MacOS

     --debuglevel <debuglevel>      Debug information level of verbosity
                                    Default: 2
                                    Allowed: 0 1 2 3 4

     --resource-rules <resource-rules> Path to a .plist file containing custom  resource rules

You can replicate the same settings used in the previous section project by executing:

    $ tools/code-signing/osx/osxsigner --identity "Developer ID Application: Name of Your Company" --identifier "com.example.foo-bar-editor" \
       --keychain "/Volumes/secure/secure.keychain" --keychain-password 'Th1s1sav3ry&5ecur3pa55w0rd!' --output /tmp/signed \
       --resource-rules "resource-rules.plist" sample-1.0-installer.app
    Signing app bundle /Applications/BitRock InstallBuilder for Qt 8.3.0/output/sample-1.0-osx-installer-signed.app
    Done!

### 16.2. Microsoft Windows

InstallBuilder is also able to sign Windows installers provided with a `PKCS#12` or `PFX` file containing your signing certificate and keys. Windows, Linux and OS X build platforms are currently supported so you are not longer forced to use Windows to integrate the build and signing of your installers.

To use it, you just need to add the `<windowsSigningPkcs12File>` tag:

    <project>
       ...
       <windowsSigningPkcs12File>${build_project_directory}/windows-signing.p12</windowsSigningPkcs12File>
       ...
    </project>

When building, the builder will ask you to enter the password to unlock the certificate. Similarly to the built-in OS X signing, you can also provide it using the `<windowsSigningPkcs12Password>` tag, either by hardcoding it (NOT RECOMMENDED!) or by setting and environment variable to look for the password when building:

    <project>
       ...
       <windowsSigningPkcs12File>${build_project_directory}/windows-signing.p12</windowsSigningPkcs12File>
       <windowsSigningPkcs12Password>${env(WINDOWS_SIGNING_PASSWORD)}</windowsSigningPkcs12Password>
       ...
    </project>

You can also specify a timestamp server supporting RFC 3161 standard. For example, you could try tsa.safecreative.org, which allows a limited usage of 5 timestamps per day and IP:

    <project>
       ...
       <windowsSigningPkcs12File>${build_project_directory}/windows-signing.p12</windowsSigningPkcs12File>
       <windowsSigningPkcs12Password>${env(WINDOWS_SIGNING_PASSWORD)}</windowsSigningPkcs12Password>
       <windowsSigningTimestampServer>http://tsa.safecreative.org</windowsSigningTimestampServer>
       ...
    </project>

| InstallBuilder and OSSLsigncode
InstallBuilder uses OSSLsigncode tool to sign Windows installers. The tool can be found in the installation directory, in the tools folder.

#### Manually signing Windows Installers

If you want to further customize the signing settings, you could also call either `osslsigncode` tool or Microsoft `signtool` command-line utility (part of the Visual Studio and Windows SDK packages) in the `<postBuildActionList>`:

    <postBuildActionList>
        <runProgram>
            <program>${installbuilder_install_root}/tools/osslsigncode/bin/osslsigncode.exe</program>
            <programArguments>-in "${installbuilder_install_root}/${project.installerFilename}" -out "${installbuilder_install_root}/signed/${project.installerFilename}" -pkcs12 certfile.pfx -readpass /path/to/passwordfile</programArguments>
        </runProgram>
    </postBuildActionList>

You can find a detailed explanation about its usage in its `README`: http://sourceforge.net/projects/osslsigncode/files/osslsigncode/

The following example shows how `signtool` can be used to digitally sign an installer as part of the `<postBuildActionList>`:

    <postBuildActionList>
        <runProgram>
            <program>/path/to/signtool</program>
            <programArguments>sign /d "${project.fullName}" /f certfile.pfx  "${installbuilder_install_root}/${project.installerFilename}"</programArguments>
        </runProgram>
    </postBuildActionList>

The detailed syntax of the signtool command can be found on MSDN:

http://msdn.microsoft.com/en-us/library/8s9b9yaz.aspx

A limitation of this tool is that it does not allow re-signing an installer. Therefore, performing multiple quick builds would fail, as the tool would try to sign the same installer multiple times. For testing purposes, it may be convenient to only sign the output binary if certain flag is set - such as:

    <postBuildActionList>
        <runProgram>
            <program>/path/to/signtool</program>
            <programArguments>sign /d "${project.fullName}" /f certfile.pfx  "${installbuilder_install_root}/${project.installerFilename}"</programArguments>
            <ruleList>
                <isTrue value="${runSignTool}" />
            </ruleList>
        </runProgram>
    </postBuildActionList>

This will only sign the binary if the `runSignTool` variable is set. A final build could be then run in the following way:

    C:\Program Files\Bitrock InstallBuilder\bin/builder-cli.exe build /path/to/project.xml windows --setvars runSignTool=1

While regular use of the builder GUI and CLI modes will not cause the target binary to be signed.

15. Services |  | 17. File associations