How to sign assembly with as strong name in Visual Studio Team Services?

I have self generated password protected key.pfx. That key.pfx file is used to sign some assemblies in my solution. I tried to build that solution in Visual Studio Team Services and it failed right away with the following error:

Error MSB3325: Cannot import the following key file: key.pfx. The key file may be password protected. To correct this, try to import the certificate again or manually install the certificate to the Strong Name CSP with the following key container name: VS_KEY_9000008CC1777

Quick googling shows that I need to run:

sn -i key.pfx VS_KEY_9000008CC1777

However this command will prompt a password, so this would not work for on a build server. I tried to use automated solution for the above command using following powershell script:


param($PfxFilePath, $Password)

$absolutePfxFilePath = Resolve-Path -Path $PfxFilePath
Write-Output "Importing store certificate '$absolutePfxFilePath'..."

Add-Type -AssemblyName System.Security
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
$cert.Import($absolutePfxFilePath, $Password, [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]"PersistKeySet")
$store = new-object system.security.cryptography.X509Certificates.X509Store -argumentlist "MY", CurrentUser
$store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::"ReadWrite")
$store.Add($cert)
$store.Close()

However this didn't work for Visual Studio Teams Services hosted build agent. I suspect that hosted build server has some kind of environment protection and above certificate installation fails silently. Then I decided to extract key.snk file from key.pfx and use that file to sign assemblies. This approach works, but it is not secure, since I would need to store private unprotected key file in source control. So, I came up with the idea to dynamically extract key.snk using following powershell script:

Param(
    [Parameter(Mandatory=$True,Position=1)]
    [string] $PfxFilePath,
    [string] $PfxPassword
)

# The path to the snk file we're creating
[string] $snkFilePath = [IO.Path]::GetFileNameWithoutExtension($PfxFilePath) + ".snk";

# Read in the bytes of the pfx file
[byte[]] $pfxBytes = Get-Content $PfxFilePath -Encoding Byte;

# Get a cert object from the pfx bytes with the private key marked as exportable
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2(
    $pfxBytes,
    $PfxPassword,
    [Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable);

# Export a CSP blob from the cert (which is the same format as an SNK file)
[byte[]] $snkBytes = ([Security.Cryptography.RSACryptoServiceProvider]$cert.PrivateKey).ExportCspBlob($true);

# Write the CSP blob/SNK bytes to the snk file
[IO.File]::WriteAllBytes([IO.Path]::Combine([IO.Path]::GetDirectoryName($PfxFilePath), $snkFilePath), $snkBytes);

Then I added two variables to build definition:

CertPath = $(Build.SourcesDirectory)\key.pfx
CertPass = password (clicked on a lock to secure value of variable)

After that I added powershell task with following arguments:

Sign assembly PowerShell task

This time the build passed and assemblies were signed successfully.


Posted on Monday, July 24, 2017 by | Comments (3) | Add Comment

Comments

Gravatar

Re: How to sign assembly with as strong name in Visual Studio Team Services?

The two powershell scripts above look identical, which one ended up working for you and which didn't - are the two scripts (which are the same) the good script or the one that didn't work for you?

Posted on 8/17/2017 10:45:54 PM by Brett Hitnon #
Gravatar

Thank you for noticing. I corrected the first script, so scripts don't look the same. I ended up using the second powershell script.

Gravatar

Re: How to sign assembly with as strong name in Visual Studio Team Services?

Viktar,

Thank for the info. One more follow up question, how did you get the signing process to use the .snk file instead of the .pfx file?

Did you just have to "point" the solution/project to sign using the .snk file instead of the .pfx file so it would pick it up at build time?

Is that what you were referring to when you said "Then I decided to extract key.snk file from key.pfx and use that file to sign assemblies" in your blog post?

Posted on 8/25/2017 10:27:48 AM by Brett Hinton #
Gravatar

Yes, I pointed my solution/project file to key.snk file for Release configuration, which is only used by CI.

Gravatar

Re: How to sign assembly with as strong name in Visual Studio Team Services?

Hello Viktar :) "After that I added powershell task with following arguments" you use Inline script? if yes, what you put to the field "Inline script"? (500 symbols max). could you provide please screenshot of this two tasks?

Posted on 11/27/2017 6:44:36 AM by Dmitry #
Gravatar

I am sorry for such delayed reply. I updated the article with screenshot. I didn't inline PowerShell script, I committed it to the Git repository.

New Comment

Your Name:
Email (for internal use only):
Comment:
 
Code above:

Categories

Recent Tweets

  • Simon Ince's Blog: Hierarchies with HierarchyID in SQL 2008 http://t.co/xSDwiF6rRS.
  • Visual Studio 2010 WAS painfully slow - CodeProject http://t.co/Usba1x6CZy

Valid HTML5