How to give ASP.NET access to a private key in a certificate in the certificate store?
I have an ASP.NET application that accesses private key in a certificate in the certificates store. On Windows Server 2003 I was able to use winhttpcertcfg.exe to give private key access to the NETWORK SERVICE account. How do I give permissions to access a Private Key in a certificate in the certificate store (Local Computer\Personal) on a Windows Server 2008 R2 in an IIS 7.5 website?
I've tried giving Full Trust access to "Everyone", "IIS AppPool\DefaultAppPool", "IIS_IUSRS", and everyother security account I could find using the Certificates MMC (Server 2008 R2). However the below code demonstrates that the code does not have access to the Private Key of a certificate that was imported with the private key. The code instead throws and error everytime the private key property is accessed.
Default.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<%@ Import Namespace="System.Security.Cryptography.X509Certificates" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Repeater ID="repeater1" runat="server">
<HeaderTemplate>
<table>
<tr>
<td>
Cert
</td>
<td>
Public Key
</td>
<td>
Private Key
</td>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td>
<%#((X509Certificate2)Container.DataItem).GetNameInfo(X509NameType.SimpleName, false) %>
</td>
<td>
<%#((X509Certificate2)Container.DataItem).HasPublicKeyAccess() %>
</td>
<td>
<%#((X509Certificate2)Container.DataItem).HasPrivateKeyAccess() %>
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table></FooterTemplate>
</asp:Repeater>
</div>
</form>
</body>
</html>
Default.aspx.cs
using System;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Web.UI;
public partial class _Default : Page
{
public X509Certificate2Collection Certificates;
protected void Page_Load(object sender, EventArgs e)
{
// Local Computer\Personal
var store = new X509Store(StoreLocation.LocalMachine);
// create and open store for read-only access
store.Open(OpenFlags.ReadOnly);
Certificates = store.Certificates;
repeater1.DataSource = Certificates;
repeater1.DataBind();
}
}
public static class Extensions
{
public static string HasPublicKeyAccess(this X509Certificate2 cert)
{
try
{
AsymmetricAlgorithm algorithm = cert.PublicKey.Key;
}
catch (Exception ex)
{
return "No";
}
return "Yes";
}
public static string HasPrivateKeyAccess(this X509Certificate2 cert)
{
try
{
string algorithm = cert.PrivateKey.KeyExchangeAlgorithm;
}
catch (Exception ex)
{
return "No";
}
return "Yes";
}
}
- Create / Purchase certificate. Make sure it has a private key.
- Import the certificate into the "Local Computer" account. Best to use Certificates MMC. Make sure to check "Allow private key to be exported"
-
Based upon which, IIS 7.5 Application Pool's identity use one of the following.
- IIS 7.5 Website is running under ApplicationPoolIdentity. Open MMC => Add Certificates (Local computer) snap-in => Certificates (Local Computer) => Personal => Certificates => Right click the certificate of interest => All tasks => Manage private key => Add
IIS AppPool\AppPoolName
and grant itFull control
. Replace "AppPoolName" with the name of your application pool (sometimesIIS_IUSRS
) - IIS 7.5 Website is running under NETWORK SERVICE. Using Certificates MMC, added "NETWORK SERVICE" to Full Trust on certificate in "Local Computer\Personal".
- IIS 7.5 Website is running under "MyIISUser" local computer user account. Using Certificates MMC, added "MyIISUser" (a new local computer user account) to Full Trust on certificate in "Local Computer\Personal".
- IIS 7.5 Website is running under ApplicationPoolIdentity. Open MMC => Add Certificates (Local computer) snap-in => Certificates (Local Computer) => Personal => Certificates => Right click the certificate of interest => All tasks => Manage private key => Add
Update based upon @Phil Hale comment:
Beware, if you're on a domain, your domain will be selected by default in the 'from location box'. Make sure to change that to "Local Computer". Change the location to "Local Computer" to view the app pool identities.
Note on granting permissions via MMC, Certs, Select Cert, right-click, all-tasks, "Manage Private Keys"
Manage Private Keys is only on the menu list for Personal... So if you've put your cert in Trusted People, etc. you're out of luck.
We found a way around this which worked for us. Drag and drop the cert to Personal, do the Manage Private Keys thing to grant permissions. Remember to set to use object-type built-ins and use the local machine not domain. We granted rights to the DefaultAppPool user and left it at that.
Once you're done, drag and drop the cert back where ever you originally had it. Presto.