FAKE - F# Make - A DSL for build tasks and more FAKE
6.0.0
Edit this page

Lookig for older versions of the documentation, pre FAKE v6? See 

v5.fake.build

Sign Files using SignTool

This module is a wrapper around the signtool.exe tool, a command-line tool that digitally signs files, verifies signatures in files, or time stamps files.

The 3 supported functions are:

Additional information:

API Reference:

Open namespace

open Fake.Tools

Signing

Digitally signing files.

A certificate is needed to do this.

When the certificate is located in a .pfx file

Only PFX files are supported by signtool.exe.

// val sign :
//  certificate:SignTool.SignCertificate
//  -> setOptions:(SignTool.SignOptions -> SignTool.SignOptions)
//  -> files:seq<string>
//  -> unit
SignTool.sign
    (SignTool.SignCertificate.FromFile(
        "path/to/certificate-file.pfx",
        fun o -> { o with
                    Password = Some "certificate-password" } ) )
    (fun o -> o)
    ["program.exe"; "library.dll"]

Only a subset of options is shown in the example, see API Reference for all available options: CertificateFromFile, SignOptions.

When the certificate is located in a certificate store

All options are optional, and any combination may be used, depending on specific needs.

If no StoreName is specified, the "My" store is opened.

// val sign :
//  certificate:SignTool.SignCertificate
//  -> setOptions:(SignTool.SignOptions -> SignTool.SignOptions)
//  -> files:seq<string>
//  -> unit
SignTool.sign
    (SignTool.SignCertificate.FromStore(
        fun o -> { o with
                    AutomaticallySelectCertificate = Some true
                    SubjectName = Some "subject"
                    StoreName = Some "My" } ) )
    (fun o -> o)
    ["program.exe"; "library.dll"]

Only a subset of options is shown in the example, see API Reference for all available options: CertificateFromStore, SignOptions.

Custom signing options

Use SHA256 (see SHA1/SHA256) to create file signatures.

// val sign :
//  certificate:SignTool.SignCertificate
//  -> setOptions:(SignTool.SignOptions -> SignTool.SignOptions)
//  -> files:seq<string>
//  -> unit
SignTool.sign
    (SignTool.SignCertificate.From..(..))
    (fun o -> { o with
                    DigestAlgorithm = Some SignTool.DigestAlgorithm.SHA256 } )
    ["program.exe"; "library.dll"]

Only a subset of options is shown in the example, see API Reference for all available options: SignOptions.

Adding a time stamp

Time stamp at the same time as signing.

There is a separate function signWithTimeStamp that, compared to sign, has 2 additional parameters to set time stamping options.

If you want to time stamp previously signed files, use the Time stamping function.

For more information about time stamping see Time stamping.

// val signWithTimeStamp :
//  certificate:SignTool.SignCertificate
//  -> setSignOptions:(SignTool.SignOptions -> SignTool.SignOptions)
//  -> serverUrl:string
//  -> setTimeStampOptions:(SignTool.TimeStampOption -> SignTool.TimeStampOption)
//  -> files:seq<string>
//  -> unit
SignTool.signWithTimeStamp
    (SignTool.SignCertificate.From..(..))
    (fun o -> o)
    "http://timestamp.example-ca.com"
    (fun o -> o)
    ["program.exe"; "library.dll"]

Only a subset of options is shown in the example, see API Reference for all available options: SignOptions, TimeStampOption.

Custom time stamp options

Use SHA256 (see SHA1/SHA256).

// val signWithTimeStamp :
//  certificate:SignTool.SignCertificate
//  -> setSignOptions:(SignTool.SignOptions -> SignTool.SignOptions)
//  -> serverUrl:string
//  -> setTimeStampOptions:(SignTool.TimeStampOption -> SignTool.TimeStampOption)
//  -> files:seq<string>
//  -> unit
SignTool.signWithTimeStamp
    (SignTool.SignCertificate.From..(..))
    (fun o -> o)
    "http://timestamp.example-ca.com"
    (fun o -> { o with
                    Algorithm = Some SignTool.DigestAlgorithm.SHA256 } )
    ["program.exe"; "library.dll"]

Only a subset of options is shown in the example, see API Reference for all available options: SignOptions, TimeStampOption.

Time stamping

Time stamping previously signed files.

When signing a file, the signature is valid only as long as the certificate used to create it is valid. The moment the certificate expires, the signature becomes invalid. Time stamping is used to extend the validity of the signature. A time stamp proves that the signature was created while the certificate was still valid and effectively extends the signature's validity indefinitely.

Default options

Time stamp server does not have to be from the same CA as the certificate.

// val timeStamp :
//  serverUrl:string
//  -> setOptions:(SignTool.TimeStampOptions -> SignTool.TimeStampOptions)
//  -> files:seq<string>
//  -> unit
SignTool.timeStamp
    "http://timestamp.example-ca.com"
    (fun o -> o)
    ["program.exe"; "library.dll"]

Only a subset of options is shown in the example, see API Reference for all available options: TimeStampOptions.

Custom options

Use SHA256 (see SHA1/SHA256).

// val timeStamp :
//  serverUrl:string
//  -> setOptions:(SignTool.TimeStampOptions -> SignTool.TimeStampOptions)
//  -> files:seq<string>
//  -> unit
SignTool.timeStamp
    "http://timestamp.example-ca.com"
    (fun o -> { o with
                    Algorithm = Some SignTool.DigestAlgorithm.SHA256 } )
    ["program.exe"; "library.dll"]

Only a subset of options is shown in the example, see API Reference for all available options: TimeStampOption, TimeStampOptions.

Verifying

Verify signed files.

The verify command determines whether the signing certificate was issued by a trusted authority, whether the signing certificate has been revoked, and, optionally, whether the signing certificate is valid for a specific policy.

Default options

// val verify :
//  setOptions:(SignTool.VerifyOptions -> SignTool.VerifyOptions)
//  -> files:seq<string>
//  -> unit
SignTool.verify
    (fun o -> o)
    ["program.exe"; "library.dll"]

Only a subset of options is shown in the example, see API Reference for all available options: VerifyOptions.

Custom options

// val verify :
//  setOptions:(SignTool.VerifyOptions -> SignTool.VerifyOptions)
//  -> files:seq<string>
//  -> unit
SignTool.verify
    (fun o ->
        { o with
            AllSignatures = Some true
            RootSubjectName = Some "root subject"
            WarnIfNotTimeStamped = Some true } )
    ["program.exe"; "library.dll"]

Only a subset of options is shown in the example, see API Reference for all available options: VerifyOptions.

Common options

All functions share some common options.

Tool options - path to signtool.exe, execution timeout, working directory. These options are not set by default.

// set path to signtool.exe - if you want to use a specific version or you don't have Windows SDKs installed
// by default, an attempt will be made to locate it automatically in 'Program Files (x86)\Windows Kits'
{ o with
    ToolPath = Some "path/to/signtool.exe" }
// set the timeout
{ o with
    Timeout = Some (TimeSpan.FromMinutes 1.0) }
// set the working directory - uses current directory by default
{ o with
    WorkingDir = Some (Directory.GetCurrentDirectory()) }

Debug - displays debugging information (signtool option: /debug). This option is not set by default.

// display debugging information (/debug)
{ o with
    Debug = Some true }
// do not display debugging information
{ o with
    Debug = Some false }
// use default
{ o with
    Debug = None }

Verbosity - output verbosity (signtool options: /q, /v). This option is not set by default.

// set verbosity to verbose (/v)
{ o with
    Verbosity = Some SignTool.Verbosity.Verbose }
// set verbosity to quiet (/q)
{ o with
    Verbosity = Some SignTool.Verbosity.Quiet }
// use default
{ o with
    Verbosity = None }

API References: SignOptions, TimeStampOptions, VerifyOptions, Verbosity.

Certificates

The SignTool needs a certificate to sign files.

Prod / release

For production / release purposes a proper publicly trusted code signing certificate may be purchased from many CA's.

Dev / test

For dev and testing purposes a certificate can be created using the New-SelfSignedCertificate PowerShell cmdlet:

New-SelfSignedCertificate -CertStoreLocation cert:\currentuser\my `
-Subject "CN=My Company, Inc.;O=My Company, Inc.;L=My City;C=SK" `
-KeyAlgorithm RSA `
-KeyLength 2048 `
-Provider "Microsoft Enhanced RSA and AES Cryptographic Provider" `
-KeyExportPolicy Exportable `
-KeyUsage DigitalSignature `
-Type CodeSigningCert

This creates the certificate under "Certificates - Current User" -> "Personal" -> "Certificates" and prints the certificate Thumbprint. The certificate can be used as-is using the CertificateFromStore option.

If you want to export the certificate to a file, use the Export-PfxCertificate PowerShell cmdlet. Replace {Thumbprint} with the value from New-SelfSignedCertificate output:

$certpwd = ConvertTo-SecureString -String "mycertpassword" -Force -AsPlainText
Get-ChildItem -Path cert:\currentuser\my\{Thumbprint} | Export-PfxCertificate -FilePath C:\certificate.pfx -Password $certpwd

Now the certificate can be used with the CertificateFromFile option.

This certificate should not be used for prod / release purposes as it is self-signed and not trusted.

SHA1/SHA256

If the signed binaries are run on Windows 7 or newer, using SHA256 only is fine - this is also the default value for DigestAlgorithm (/fd and /td options).

If the signed binaries are run on Windows older than Windows 7, SHA1 should be used.

If the signed binaries are run on newer and older versions of Windows, then dual signing is probably the way to go. This means signing all binaries twice - first using SHA1, and then SHA256. Make sure to set AppendSignature to true when signing the second time, otherwise the first signature will be replaced. More information about dual signing.