Skip to content

Latest commit

 

History

History
267 lines (195 loc) · 17.7 KB

Signing.md

File metadata and controls

267 lines (195 loc) · 17.7 KB

Sign Tool

This is a MSBuild custom task that provides batch signing and simple verification for MicroBuild environments. The tool is intended to be run as a post-build step and is able to automatically infer the files that need to be signed given a list of container files (.nupkg, .vsix, etc) as input. The high level features of this tool are:

  • Performance: It operates as a post-build step and uses the minimum number of requests possible. This can have a dramatic performance improvement over the typical implementation which signs as a post-compile step. For example, in Roslyn it took build + sign times down from 1-2 hours to 8 minutes.
  • Automated: It is able to recursively open container files (like .nupkg, .vsix) and create a list of nested files that need to be signed. Therefore, you don't need to manually specify which files need to be signed.
  • Explicit Signing Info:
    • The tool supports receiving an explicit list of files that need to be signed or ignored from the signing process.
    • The tool support specifying which certificate should be used for each file and is able to identify files based on public key token, target framework, extension and file name.
    • The tool will report an error if a signable file is discovered for which no signing information was found. That means that all signable files will need to be either explicitly ignored or have signing information attributed in one of the many ways explained below.
  • Containers: It can handle the nesting issues that come with container files: both nested PE and nested containers. The tool will correctly sign the inner most content first, repack the containing package with the signed content and then sign the outermost container. Arbitrary levels of nesting are supported.
  • Post signing checks: It takes extra steps to ensure that PE files are properly signed after the signing process completes. This tool parses the signed binary file to make sure the binary was modified and marked as signed.
  • Dual certificates: The tool can receive a list of certificate descriptors which contain a property that can flag a certificate as dual. Dual certificates can be used to sign already signed files.

Arguments

Name Type Description
DryRun bool When true the list of files to be signed will be created but won't be sent to the signing server. Default is false.
TestSign bool When true the binaries will be test signed. The default is to real sign.
DoStrongNameCheck bool When true binaries will be checked for valid strong name signature. The default is false.
ItemsToSign Array This is a list of full path to files that need to be signed. Container files will be expanded to look for nested files that need to be signed.
ItemsToSkipStrongNameCheck Array This is a list of file names that should be skipped when performing strong-name check.
StrongNameSignInfo Array Should store the default certificate name and strong name to be used for a given Public Key Token. See details below.
FileSignInfo Array Used to override the default certificate information for specific files and target frameworks combinations. If not specified default information is used or error occurs. See details below.
FileExtensionSignInfo Array This is a mapping between extension (in the format ".ext") to default sign information for those kind of files. Overriding of the default sign info is done using the other parameters.
CertificatesSignInfo Array List of certificate names that can be flagged using the DualSigningAllowed attribute as dual certificates.
MicroBuildCorePath Dir Path Path to MicroBuild.Core package directory.
MSBuildPath Exe path Path to the MSBuild.exe binary used to run the signing process on MicroBuild.
SNBinaryPath Exe path Path to the sn.exe binary used to strong-name sign / validate signature of managed files.
TempDir Dir path Used to store temporary files during the process of calling MicroBuild signing.
LogDir Dir path MSBuild binary log information from the signing rounds will be stored in this directory.

Note:

​ Items in bold are required: ItemsToSign, MicroBuildCorePath and TempDir.

MSBuildPath, SNBinaryPath and LogDir are only required if DryRun == false.

Arguments Metadata

StrongNameSignInfo - Optional parameter

This field requires the following metadata: PublicKeyToken, CertificateName and the Include field is assumed to hold the Strong Name. This information will be used as the default certificate and strong name information for all PE files that match the PublicKeyToken.

FileExtensionSignInfo - Optional parameter

This field requires two metadata attributes: CertificateName and Include which should be a file extension in the format .ext. This field is used to configure a default certificate for all files that have an specific extension.

CertificatesSignInfo - Optional parameter

This field requires the following metadata: DualSigningAllowed (boolean) and Include which is assumed to hold a valid certificate name. Use this list to explicitly configure the tool to allow the use of the specified certificate as a dual certificate - i.e., be able to use it to sign already signed files.

FileSignInfo - Optional parameter

This field accepts the following metadata: PublicKeyToken (optional), CertificateName, TargetFramework (optional) and the Include field is assumed to hold a file name (including extension; not a full path). The CertificateName attribute accepts the value "None" to flag a file that should not be signed.

All files that match the provided combination will use the Signing information provided. This applies to files discovered during recursive signing.

ItemsToSign - Required parameter

This field only attribute should be Include. This field holds a list of full path to files that need to be considered during the signing process. Path to containers and regular files are accepted. Containers will be opened and their content will be processed recursively.

Signing Info Precedence

The signing information (SI) for a given file is looked up in the order shown below. Later conditions override previous ones.

  1. A default SI is looked up on FileExtensionSignInfo based on the extension of the file.
  2. If the file is a managed PE file, SI based on the file Public Key Token (and only on it) is looked up in the StrongNameSignInfo parameter.
  3. If the file is a PE file (not necessarily managed), SI based on a combination of file name, public key token and target framework is looked up in FileSignInfo. If there is no match, then:
  4. If the file is a PE file (not necessarily managed), SI based on a combination of file name and public key token is looked up in FileSignInfo. If there is no match, then:
  5. SI based only on file name is looked up in FileSignInfo.

Note that the logic starts looking for SI on a broad scope and then looks for specific information for the file. Also, the last three conditions are mutually exclusive.

At the end, if the file is signable but no signing information was determined for the file an error message will be logged and execution is expected to fail.

The Signing.props file

The Arcade SDK include a set of predefined configurations for the SignTool in the Sign.proj file. However, you can override/remove/update any of these configurations by including a file named Signing.props in the \eng\ folder of your repository. See examples on the next section.

Signing 3rd Party Binaries

Any 3rd party assembly which is distributed on public Microsoft feeds is supposed to be signed with the "3PartySHA2" certificate - a dual certificate. Arcade itself use the SignTool and as such the Arcade SDK is configured to dual sign 3rd party libraries that it uses. In case you need to sign 3rd party files take a look at how Arcade does it.

Usage Examples

1. Use the SDK predefined configuration

The Arcade SDK will include all NuGet packages from the $(ArtifactsPackagesDir) and all VSIX packages from the$(VisualStudioSetupOutputPath) folder (these properties are set here) in the list of containers to be looked up for - ItemsToSign. Note that only projects marked with <IsPackable>true</IsPackable> will be packed and copied to these folders.

The default configuration of Arcade SDK + SignTool also assigns default certificates to many signable file types and to all files that have the 31bf3856ad364e35 Public Key Token. Therefore, if all files that your repo need to sign are covered under these conditions you won't need to do any specific setup for the tool.

2. Use a different certificate for an specific Public Key Token

If you repo have signable files that have a different Public Key Token than the one preconfigured in the SDK (i.e., 31bf3856ad364e35) you might add an entry to StrongNameSignInfo to specify the certificate name that should be used for those files. To do that, place an entry like the one show below in your eng\Signing.props file.

<ItemGroup>
	<StrongNameSignInfo Include="StrongName1" PublicKeyToken="4321abcda1b2c3d4" CertificateName="DifferentCertName" />
</ItemGroup>

If that is your only custom configuration all files with that Public Key Token will be signed with the DifferentCertName certificate and StrongName1 strong name.

3. Configure signing information for an specific file

It is possible to override the default signing information or explicitly skip signing for specific files. For that you need to use the FileSignInfo property. For instance, in the snippet below the certificate MyCustomCert will be used for My.Library.dll when it targets .NETStandard,Version=v2.0 and has Public Key Token 31bf3856ad364e35:

<ItemGroup> 
    <FileSignInfo Include="My.Library.dll" TargetFramework=".NETStandard,Version=v2.0" PublicKeyToken="31bf3856ad364e35" CertificateName="MyCustomCert" />
</ItemGroup>

In this snippet the library Other.Library.dll with Public Key Token 31bf3856ad364e35 won't be signed, independent of its target framework:

<ItemGroup>
  <FileSignInfo Include="Other.Library.dll" PublicKeyToken="31bf3856ad364e35" CertificateName="None" />
</ItemGroup>

4. How to remove all preconfigured signing information?

To remove all preconfigured signing information put the following snippet in your eng\Signing.props file:

<ItemGroup>
    <!-- Remove all predefined dual certificate information -->
	<CertificatesSignInfo Remove="@(CertificatesSignInfo)" />
    
    <!-- Remove all automatically included packages -->
	<ItemsToSign Remove="@(ItemsToSign)" />
    
    <!-- Remove default signing for `31bf3856ad364e35` PKT -->
	<StrongNameSignInfo Remove="@(StrongNameSignInfo)" />
    
    <!-- Remove default signing for signable extensions -->
	<FileExtensionSignInfo Remove="@(FileExtensionSignInfo)" />
</ItemGroup>

5. How to explicitly list the certificates for each file to be signed?

Assuming that you don't want to use any of the preconfigured information in the SDK and want to specify by yourself the list of files to be signed and the certificate to be used for each file, take a look at the example below:

<ItemGroup>
    <!-- Remove all preconfigured signing info as shown above in (4). -->
	
	<!-- My custom list of files to be signed -->
	<ItemsToSign Include="c:\build\file1.dll" />
	<ItemsToSign Include="c:\build\file2.ps1" />
	<ItemsToSign Include="c:\build\file3.js" />
	<ItemsToSign Include="c:\build\file4.nupkg" />
		
	<!-- configure the certificate for each file -->
	<FileSignInfo Include="file1.dll" CertificateName="DLLCert" />
	<FileSignInfo Include="file2.ps1" CertificateName="PS1Cert" />
	<FileSignInfo Include="file3.js" CertificateName="JSCert" />
	<FileSignInfo Include="file4.nupkg" CertificateName="NuGet" />
	
	<!-- Assuming this file is present in file4.nupkg -->
	<!-- 
		 If we hadn't specified this information here the signing process 
		 would fail because no signing information would be found for a 
		 signable file (.dll) 
	-->
	<FileSignInfo Include="nested.dll" CertificateName="DeepCert" />
</ItemGroup>

6. How to sign different files that have same name?

The tool assumes that you will be able to differentiate the files using name, public key token or target framework. If you have two files with the same name your only option (currently) is to differentiate them using public key token or target framework as below:

<ItemGroup>
    <!-- Note that these are full paths -->
	<ItemsToSign Include="c:\build\pack1\lib.dll" />
	<ItemsToSign Include="c:\build\pack2\lib.dll" />
	<ItemsToSign Include="c:\build\pack3\lib.dll" />
	
    <!-- Note that here only file names + extension are used -->
	<FileSignInfo Include="lib.dll" 
                  CertificateName="File1Cert" 
                  PublicKeyToken="a1b2c3d4e5f6g7h8" 
                  TargetFramework=".NETStandard,Version=v2.0" />
	
    <FileSignInfo Include="lib.dll" 
                  CertificateName="File2Cert" 
                  PublicKeyToken="abcdefghi12345678" 
                  TargetFramework=".NETCore,Version=v2.0" />
	
    <FileSignInfo Include="lib.dll" 
                  CertificateName="File3Cert" 
                  PublicKeyToken="abcdefghi12345678" 
                  TargetFramework=".NETStandard,Version=v2.0" />
</ItemGroup>

7. How should I call the SignToolTask?

Click here to see how the Arcade SDK calls the SignToolTask. Here's a snippet:

...
<Microsoft.DotNet.SignTool.SignToolTask
    DryRun="$(DryRun)"
    TestSign="$(TestSign)"
    CertificatesSignInfo="$(CertificatesSignInfo)"
    ItemsToSign="@(ItemsToSign)"
    StrongNameSignInfo="@(StrongNameSignInfo)"
    FileSignInfo="@(FileSignInfo)"
    FileExtensionSignInfo="@(FileExtensionSignInfo)"
    TempDir="$(ArtifactsTmpDir)"
    LogDir="$(ArtifactsLogDir)"
    MSBuildPath="$(DesktopMSBuildPath)"
    MicroBuildCorePath="$(NuGetPackageRoot)microbuild.core\$(MicroBuildCoreVersion)"/>
...

8. How can I use the .NET specific certificate for executable files?

By default, Microsoft400 is the cert used by default for most executable files (e.g .dll, .js, .exe). To use the .NET specific cert (MicrosoftDotNet500), use one of the following approaches:

  1. Update the existing FileExtensionSignInfo and StrongNameSignInfo metadata in Sign.props to use MicrosoftDotNet500. This approach must be used if some files still need to be signed with Microsoft400.
    <ItemGroup>
      <FileExtensionSignInfo Update=".js;.ps1;.psd1;.psm1;.psc1;.py;.dll;.exe" CertificateName="MicrosoftDotNet500" />
      <StrongNameSignInfo Update="MsSharedLib72" PublicKeyToken="31bf3856ad364e35" CertificateName="MicrosoftDotNet500" />
      <StrongNameSignInfo Update="SilverlightCert121" PublicKeyToken="7cec85d7bea7798e" CertificateName="MicrosoftDotNet500" />
      <StrongNameSignInfo Update="StrongName" PublicKeyToken="b77a5c561934e089" CertificateName="MicrosoftDotNet500" />
      <StrongNameSignInfo Update="StrongName" PublicKeyToken="b03f5f7f11d50a3a" CertificateName="MicrosoftDotNet500" />
      <StrongNameSignInfo Update="$(MSBuildThisFileDirectory)snk\Open.snk" PublicKeyToken="cc7b13ffcd2ddd51" CertificateName="MicrosoftDotNet500" />
    </ItemGroup>
    
  2. Specify the property UseDotNetCertificate with value true in your eng/Signing.props file. This replaces all existing use of Microsoft400 with MicrosoftDotNet500.
    <PropertyGroup>
      <UseDotNetCertificate>f</UseDotNetCertificate>
    </PropertyGroup>
    

Logs & MicroBuild configuration files

The log messages from the SignToolTask itself will be included in the log (+.binlog) of the original build process. The binary log of executing the MicroBuild signing plugin will be stored in files named SigningX.binlog in the LogDir folder. The project files used to call the MicroBuild plugin will be stored in files named RoundX.proj in the TempDir folder. In both cases the X in the name refers to a signing round.

Valid Argument Values

Certificate Name: name of the Authenticode certificate to use for signing. Valid values include Microsoft402, WindowsPhone623, MicrosoftSHA1Win8WinBlue and VsixSHA2.

Strong Name: name of the key to use when strong naming the binary. This can be null for values which do not require strong name signing such as VSIX files.

Target Framework: valid values include (but are not limited to): .NETStandard,Version=v2.0, .NETFramework,Version=v4.6.1, .NET Core,Version=v2.0, etc.

Public Key Token: valid values are 16 characters in length comprising values between [0-9] and [a-Z].

Was this helpful? Yes No