4

For signing an assembly with sn.exe in .NET, is it possible to specify a public key for which the private key is contained only within the Windows CryptoAPI keystore?

I see the option for specifying the CSP name, and the container name.

Are there values to use to access the Windows certificates? (i.e. those accessible from Windows EFS, Outlook, Internet Explorer, etc.)

Thank you.

Comment: Specifically, I am asking this because there are a few keys which do not have the private key marked as exportable, so I cannot export a .pfx and follow that route.

Johannes Rudolph
  • 35,298
  • 14
  • 114
  • 172
maxwellb
  • 13,366
  • 2
  • 25
  • 35
  • I found the MSDN article on Machine Stores, but this is dealing with ActiveDirectory Rights Management. I also cannot find the DRM directory it talks about. Though, there was a directory Application Data\Microsoft\Crypto\RSA\MachineKeys, and several files named with just a serial number or GUID. (256bit-hex)_(32bit)-(16bit)-(16bit)-(16-bit)-(48bit) is the format of the filename. Are these usable/addressable to identify the public key to sn.exe? – maxwellb Jun 15 '09 at 22:22

1 Answers1

0

I had the same question at the end of this week.

YES, it can be configured to use the Windows Certificate store and if you're being truly security conscious you should absolutely do this. It makes it very hard to accidentally leak the private key (and if you use a Smart Card like a Yubikey, it makes it impossible to leak the private key -- the OS never sees it).

I documented how to do this in two different, but related, manners in posts on my blog.

If you're just using a certificate in your personal certificate store, but not using a Smart Card, it's relatively easy.

In PowerShell, you need to get the details of your certificate:

Set-Location "cert:\Path\To\Your\Certificate"
# Usually "cert:\CurrentUser\My" is what you want
$cert=Get-Item ".\(your-certificate-thumbprint)"

You need to determine the Key Container Name and CSP that's used to access that key container (if it's not a smart card, the default CSP works)

$cert=Get-Item .\(ThumbprintOfYourKey)
$cert.PrivateKey.CspKeyContainerInfo | fl *

This will produce something similar to the following:

MachineKeyStore        : False
ProviderName           : Microsoft Base Smart Card Crypto Provider
ProviderType           : 1
KeyContainerName       : c0f031c2-0b5e-171b-d552-fab7345fc10a
UniqueKeyContainerName : c0f031c2-0b5e-171b-d552-fab7345fc10a
KeyNumber              : Signature
Exportable             : False
HardwareDevice         : True
Removable              : True
Accessible             : True
Protected              : True
CryptoKeySecurity      : System.Security.AccessControl.CryptoKeySecurity
RandomlyGenerated      : False

In my case, I'm using a Yubikey, so the CSP is "Microsoft Base Smart Card Crypto Provider". This means in order to strong name sign my code, I need to run:

sn.exe -c "Microsoft Base Smart Card Crypto Provider"

At some point before I build (only once, it needn't be run every build, however I have linked to some scripts to help with that in the second post on this subject).

There are two options from here: you tell sn.exe to create a key that contains only the public key and delay sign with that key (check the box at the bottom of the "Signing" tab in the project properties), then post-build, sign using sn.exe -Rc "your-container-name" "key.snk" or you can use the easy way: AssemblyKeyNameAttribute in the AssemblyInfo.cs file as follows:

[assembly: AssemblyKeyNameAttribute("Your Key Container Name")]

The compiler will handle everything else for you. Just bear in mind that you need to make sure your CSP is set using sn.exe -c before you try to build or you will get a Keyset not found error on build (along with the name of your key container).

mdip
  • 600
  • 4
  • 10