Bagaimana cara memberikan akses ASP.NET ke kunci pribadi dalam sertifikat di penyimpanan sertifikat?

111

Saya memiliki aplikasi ASP.NET yang mengakses kunci privat dalam sertifikat di penyimpanan sertifikat. Pada Windows Server 2003 saya dapat menggunakan winhttpcertcfg.exe untuk memberikan akses kunci pribadi ke akun LAYANAN JARINGAN. Bagaimana cara memberikan izin untuk mengakses Kunci Pribadi dalam sertifikat di penyimpanan sertifikat (Komputer Lokal \ Pribadi) di Windows Server 2008 R2 di situs web IIS 7.5?

Saya telah mencoba memberikan akses Kepercayaan Penuh ke "Semua Orang", "IIS AppPool \ DefaultAppPool", "IIS_IUSRS", dan semua akun keamanan lain yang dapat saya temukan menggunakan Sertifikat MMC (Server 2008 R2). Namun kode di bawah ini menunjukkan bahwa kode tersebut tidak memiliki akses ke Kunci Pribadi dari sertifikat yang diimpor dengan kunci privat. Kode tersebut malah melempar dan melakukan kesalahan setiap kali properti kunci pribadi diakses.

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";
    }
}

thames
sumber

Jawaban:

195
  1. Buat / Beli sertifikat. Pastikan itu memiliki kunci pribadi.
  2. Impor sertifikat ke akun "Komputer Lokal". Terbaik untuk menggunakan Sertifikat MMC. Pastikan untuk mencentang "Izinkan kunci pribadi untuk diekspor"
  3. Berdasarkan itu, identitas IIS 7.5 Application Pool menggunakan salah satu dari berikut ini.

    • Situs web IIS 7.5 berjalan di bawah ApplicationPoolIdentity. Buka MMC => Tambahkan Sertifikat (Komputer lokal) snap-in => Sertifikat (Komputer Lokal) => Pribadi => Sertifikat => Klik kanan sertifikat yang diminati => Semua tugas => Kelola kunci pribadi => Tambahkan IIS AppPool\AppPoolNamedan berikan Full control. Ganti " AppPoolName " dengan nama pool aplikasi Anda (terkadang IIS_IUSRS)
    • Situs web IIS 7.5 berjalan di bawah LAYANAN JARINGAN. Menggunakan Certificates MMC, menambahkan "NETWORK SERVICE" ke Full Trust on certificate di "Local Computer \ Personal".
    • Situs web IIS 7.5 berjalan di bawah akun pengguna komputer lokal "MyIISUser". Menggunakan Sertifikat MMC, menambahkan "MyIISUser" (akun pengguna komputer lokal baru) ke Kepercayaan Penuh pada sertifikat di "Komputer Lokal \ Pribadi".

Pembaruan berdasarkan komentar @Phil Hale:

Hati-hati, jika Anda menggunakan domain, domain Anda akan dipilih secara default di 'dari kotak lokasi'. Pastikan untuk mengubahnya menjadi "Komputer Lokal". Ubah lokasi menjadi "Komputer Lokal" untuk melihat identitas kumpulan aplikasi.

thames
sumber
3
Bagaimana cara mengkonfigurasi ("XXX" ke Kepercayaan Penuh pada sertifikat di "Komputer Lokal \ Pribadi") di Windows Server 2008 R2? jalankan / mmc / file / tambahkan snap-in / sertifikat dan ??? Terima kasih
Cobaia
7
Ketika Anda memiliki Sertifikat MMC dibuka untuk Komputer Lokal \ Personal, klik pada "sertifikat" untuk melihat sertifikat. (catatan: berikut ini mengasumsikan sertifikat sudah diimpor, jika tidak maka impor sertifikat terlebih dahulu) Klik kanan pada sertifikat yang ingin Anda berikan Kontrol penuh. Di menu konteks, klik "Semua Tugas", lalu di submenu klik "Kelola Kunci Pribadi". Dari sana Anda dapat menambahkan pengguna apa pun yang Anda inginkan untuk memiliki akses 'baca' ke kunci pribadi untuk sertifikat.
thames
5
Pastikan komputer lokal dipilih di kotak "dari lokasi". Ini membuat saya bingung untuk sementara waktu. Domain dipilih secara default sehingga tidak menemukan pengguna identitas pool aplikasi sampai saya mengubah lokasi ke komputer lokal
Phil Hale
3
Pada AWS's Windows 2012 R2 EC2 VM (berbasis IIS 8) Anda perlu memberikan IIS_IUSRSakses ke kunci privat sertifikat
DeepSpace101
4
Ada ide bagaimana melakukan ini melalui PowerShell?
sonjz
43

Catatan tentang pemberian izin melalui MMC, Certs, Pilih Cert, klik kanan, semua-tugas, "Kelola Kunci Pribadi"

Kelola Kunci Pribadi hanya ada di daftar menu untuk Pribadi ... Jadi jika Anda telah memasukkan sertifikat Anda ke Orang Terpercaya, dll. Anda kurang beruntung.

Kami menemukan jalan keluar yang berhasil bagi kami. Seret dan lepas sertifikat ke Pribadi, lakukan hal Kelola Kunci Pribadi untuk memberikan izin. Ingatlah untuk mengatur untuk menggunakan built-in tipe objek dan menggunakan mesin lokal bukan domain. Kami memberikan hak kepada pengguna DefaultAppPool dan berhenti di situ.

Setelah Anda selesai, seret dan lepas sertifikat kembali ke tempat asal Anda memilikinya. Presto.

Garrett Goebel
sumber
ya ini bekerja dengan baik. Saya sebutkan dalam jawaban di posting berikut namun jawaban lain diterima meskipun jawaban yang diterima lebih lama dan perlu mengunduh file WCF. stackoverflow.com/questions/10580326/…
thames
2
solusi apa pun untuk server win2003? itu tidak memiliki Kelola Kunci Pribadi sebagai opsi seperti windows 7
sonjz
1
@sonjz - lihat technet ini , itu menyebutkan menggunakan baris perintahwinhttpcertcfg
mlhDev
Jika Anda memerlukan kunci privat untuk sertifikat untuk apa pun selain personnal, kemungkinan besar Anda melakukan kesalahan ... Semua lokasi lain adalah untuk entitas lain / eksternal yang Anda percayai. Anda tidak boleh memiliki kunci pribadi mereka. Kunci publik (sertifikat) mereka sudah cukup. Saya bahkan berani mengatakan bahwa jika Anda memiliki kunci pribadi mereka, Anda tidak boleh mempercayai mereka.
Martin
15

Jika Anda mencoba memuat sertifikat dari file .pfx di IIS, solusinya mungkin sesederhana mengaktifkan opsi ini untuk Application Pool .

Klik kanan pada App Pool dan pilih Advanced Settings .

Kemudian aktifkan Load User Profile


masukkan deskripsi gambar di sini

Simon_Weaver
sumber
1
Mengapa ini membuat perbedaan?
MichaelD
3
Itu hanya harus menjadi cara jendela dihubungkan. Itu mungkin untuk sementara memuat profil ke profil pengguna sehingga membutuhkan opsi ini. Saya setuju itu aneh bahwa ini diperlukan ketika memuat dari file yang dapat diakses oleh IIS.
Simon_Weaver
Ini membantu saya ketika saya menyiapkan tanda tangan digital untuk PDF.
Fred Wilson
7

Saya menemukan cara melakukan ini di Powershell yang ditanyakan seseorang:

$keyname=(((gci cert:\LocalMachine\my | ? {$_.thumbprint -like $thumbprint}).PrivateKey).CspKeyContainerInfo).UniqueKeyContainerName
$keypath = $env:ProgramData + \Microsoft\Crypto\RSA\MachineKeys\”
$fullpath=$keypath+$keyname

$Acl = Get-Acl $fullpath
$Ar = New-Object System.Security.AccessControl.FileSystemAccessRule("IIS AppPool\$iisAppPoolName", "Read", "Allow")
$Acl.SetAccessRule($Ar)
Set-Acl $fullpath $Acl
Ian Robertson
sumber
6

Bagi saya, itu tidak lebih dari mengimpor ulang sertifikat dengan centang "Izinkan kunci pribadi untuk diekspor".

Saya kira itu perlu, tetapi itu membuat saya gugup karena ini adalah aplikasi pihak ketiga yang mengakses sertifikat ini.

Nathan Hartley
sumber
terima kasih Saya melakukannya dengan cara ini X509Certificate2 cert = new X509Certificate2 (certBytes, password, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet);
Juan Lozoya
1

Melengkapi jawaban ini adalah panduan untuk menemukan kunci privat dari sertifikat dan menambahkan izin.

Ini adalah panduan untuk mendapatkan FindPrivateKey.exe yang ditemukan di panduan untuk menemukan kunci privat sertifikat.

Juan Lozoya
sumber
0

Meskipun saya telah menghadiri yang di atas, saya telah sampai pada titik ini setelah banyak upaya. 1- Jika Anda ingin mengakses sertifikat dari toko, Anda dapat melakukan ini sebagai contoh 2- Jauh lebih mudah dan lebih bersih untuk membuat sertifikat dan menggunakannya melalui jalur

Asp.net Core 2.2 OR1:

using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Operators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Prng;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.X509;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;

namespace Tursys.Pool.Storage.Api.Utility
{
    class CertificateManager
    {
        public static X509Certificate2 GetCertificate(string caller)
        {
            AsymmetricKeyParameter caPrivateKey = null;
            X509Certificate2 clientCert;
            X509Certificate2 serverCert;

            clientCert = GetCertificateIfExist("CN=127.0.0.1", StoreName.My, StoreLocation.LocalMachine);
            serverCert = GetCertificateIfExist("CN=MyROOTCA", StoreName.Root, StoreLocation.LocalMachine);
            if (clientCert == null || serverCert == null)
            {
                var caCert = GenerateCACertificate("CN=MyROOTCA", ref caPrivateKey);
                addCertToStore(caCert, StoreName.Root, StoreLocation.LocalMachine);

                clientCert = GenerateSelfSignedCertificate("CN=127.0.0.1", "CN=MyROOTCA", caPrivateKey);
                var p12 = clientCert.Export(X509ContentType.Pfx);

                addCertToStore(new X509Certificate2(p12, (string)null, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet), StoreName.My, StoreLocation.LocalMachine);
            }

            if (caller == "client")
                return clientCert;

            return serverCert;
        }

        public static X509Certificate2 GenerateSelfSignedCertificate(string subjectName, string issuerName, AsymmetricKeyParameter issuerPrivKey)
        {
            const int keyStrength = 2048;

            // Generating Random Numbers
            CryptoApiRandomGenerator randomGenerator = new CryptoApiRandomGenerator();
            SecureRandom random = new SecureRandom(randomGenerator);

            // The Certificate Generator
            X509V3CertificateGenerator certificateGenerator = new X509V3CertificateGenerator();

            // Serial Number
            BigInteger serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random);
            certificateGenerator.SetSerialNumber(serialNumber);

            // Signature Algorithm
            //const string signatureAlgorithm = "SHA256WithRSA";
            //certificateGenerator.SetSignatureAlgorithm(signatureAlgorithm);

            // Issuer and Subject Name
            X509Name subjectDN = new X509Name(subjectName);
            X509Name issuerDN = new X509Name(issuerName);
            certificateGenerator.SetIssuerDN(issuerDN);
            certificateGenerator.SetSubjectDN(subjectDN);

            // Valid For
            DateTime notBefore = DateTime.UtcNow.Date;
            DateTime notAfter = notBefore.AddYears(2);

            certificateGenerator.SetNotBefore(notBefore);
            certificateGenerator.SetNotAfter(notAfter);

            // Subject Public Key
            AsymmetricCipherKeyPair subjectKeyPair;
            var keyGenerationParameters = new KeyGenerationParameters(random, keyStrength);
            var keyPairGenerator = new RsaKeyPairGenerator();
            keyPairGenerator.Init(keyGenerationParameters);
            subjectKeyPair = keyPairGenerator.GenerateKeyPair();

            certificateGenerator.SetPublicKey(subjectKeyPair.Public);

            // Generating the Certificate
            AsymmetricCipherKeyPair issuerKeyPair = subjectKeyPair;

            ISignatureFactory signatureFactory = new Asn1SignatureFactory("SHA512WITHRSA", issuerKeyPair.Private, random);
            // selfsign certificate
            Org.BouncyCastle.X509.X509Certificate certificate = certificateGenerator.Generate(signatureFactory);


            // correcponding private key
            PrivateKeyInfo info = PrivateKeyInfoFactory.CreatePrivateKeyInfo(subjectKeyPair.Private);


            // merge into X509Certificate2
            X509Certificate2 x509 = new System.Security.Cryptography.X509Certificates.X509Certificate2(certificate.GetEncoded());

            Asn1Sequence seq = (Asn1Sequence)Asn1Object.FromByteArray(info.PrivateKeyAlgorithm.GetDerEncoded());
            if (seq.Count != 9)
            {
                //throw new PemException("malformed sequence in RSA private key");
            }

            RsaPrivateKeyStructure rsa = RsaPrivateKeyStructure.GetInstance(info.ParsePrivateKey());
            RsaPrivateCrtKeyParameters rsaparams = new RsaPrivateCrtKeyParameters(
                rsa.Modulus, rsa.PublicExponent, rsa.PrivateExponent, rsa.Prime1, rsa.Prime2, rsa.Exponent1, rsa.Exponent2, rsa.Coefficient);

            try
            {
                var rsap = DotNetUtilities.ToRSA(rsaparams);
                x509 = x509.CopyWithPrivateKey(rsap);

                //x509.PrivateKey = ToDotNetKey(rsaparams);
            }
            catch(Exception ex)
            {
                ;
            }
            //x509.PrivateKey = DotNetUtilities.ToRSA(rsaparams);
            return x509;

        }

        public static AsymmetricAlgorithm ToDotNetKey(RsaPrivateCrtKeyParameters privateKey)
        {
            var cspParams = new CspParameters
            {
                KeyContainerName = Guid.NewGuid().ToString(),
                KeyNumber = (int)KeyNumber.Exchange,
                Flags = CspProviderFlags.UseMachineKeyStore
            };

            var rsaProvider = new RSACryptoServiceProvider(cspParams);
            var parameters = new RSAParameters
            {
                Modulus = privateKey.Modulus.ToByteArrayUnsigned(),
                P = privateKey.P.ToByteArrayUnsigned(),
                Q = privateKey.Q.ToByteArrayUnsigned(),
                DP = privateKey.DP.ToByteArrayUnsigned(),
                DQ = privateKey.DQ.ToByteArrayUnsigned(),
                InverseQ = privateKey.QInv.ToByteArrayUnsigned(),
                D = privateKey.Exponent.ToByteArrayUnsigned(),
                Exponent = privateKey.PublicExponent.ToByteArrayUnsigned()
            };

            rsaProvider.ImportParameters(parameters);
            return rsaProvider;
        }

        public static X509Certificate2 GenerateCACertificate(string subjectName, ref AsymmetricKeyParameter CaPrivateKey)
        {
            const int keyStrength = 2048;

            // Generating Random Numbers
            CryptoApiRandomGenerator randomGenerator = new CryptoApiRandomGenerator();
            SecureRandom random = new SecureRandom(randomGenerator);

            // The Certificate Generator
            X509V3CertificateGenerator certificateGenerator = new X509V3CertificateGenerator();

            // Serial Number
            BigInteger serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random);
            certificateGenerator.SetSerialNumber(serialNumber);

            // Signature Algorithm
            //const string signatureAlgorithm = "SHA256WithRSA";
            //certificateGenerator.SetSignatureAlgorithm(signatureAlgorithm);

            // Issuer and Subject Name
            X509Name subjectDN = new X509Name(subjectName);
            X509Name issuerDN = subjectDN;
            certificateGenerator.SetIssuerDN(issuerDN);
            certificateGenerator.SetSubjectDN(subjectDN);

            // Valid For
            DateTime notBefore = DateTime.UtcNow.Date;
            DateTime notAfter = notBefore.AddYears(2);

            certificateGenerator.SetNotBefore(notBefore);
            certificateGenerator.SetNotAfter(notAfter);

            // Subject Public Key
            AsymmetricCipherKeyPair subjectKeyPair;
            KeyGenerationParameters keyGenerationParameters = new KeyGenerationParameters(random, keyStrength);
            RsaKeyPairGenerator keyPairGenerator = new RsaKeyPairGenerator();
            keyPairGenerator.Init(keyGenerationParameters);
            subjectKeyPair = keyPairGenerator.GenerateKeyPair();

            certificateGenerator.SetPublicKey(subjectKeyPair.Public);

            // Generating the Certificate
            AsymmetricCipherKeyPair issuerKeyPair = subjectKeyPair;

            // selfsign certificate
            //Org.BouncyCastle.X509.X509Certificate certificate = certificateGenerator.Generate(issuerKeyPair.Private, random);

            ISignatureFactory signatureFactory = new Asn1SignatureFactory("SHA512WITHRSA", issuerKeyPair.Private, random);
            // selfsign certificate
            Org.BouncyCastle.X509.X509Certificate certificate = certificateGenerator.Generate(signatureFactory);


            X509Certificate2 x509 = new System.Security.Cryptography.X509Certificates.X509Certificate2(certificate.GetEncoded());

            CaPrivateKey = issuerKeyPair.Private;

            return x509;
            //return issuerKeyPair.Private;

        }

        public static bool addCertToStore(System.Security.Cryptography.X509Certificates.X509Certificate2 cert, System.Security.Cryptography.X509Certificates.StoreName st, System.Security.Cryptography.X509Certificates.StoreLocation sl)
        {
            bool bRet = false;

            try
            {
                X509Store store = new X509Store(st, sl);
                store.Open(OpenFlags.ReadWrite);
                store.Add(cert);

                store.Close();
            }
            catch
            {

            }

            return bRet;
        }

        protected internal static X509Certificate2 GetCertificateIfExist(string subjectName, StoreName store, StoreLocation location)
        {
            using (var certStore = new X509Store(store, location))
            {
                certStore.Open(OpenFlags.ReadOnly);
                var certCollection = certStore.Certificates.Find(
                                           X509FindType.FindBySubjectDistinguishedName, subjectName, false);
                X509Certificate2 certificate = null;
                if (certCollection.Count > 0)
                {
                    certificate = certCollection[0];
                }
                return certificate;
            }
        }

    }
}

ATAU 2:

    services.AddDataProtection()
//.PersistKeysToFileSystem(new DirectoryInfo(@"c:\temp-keys"))
.ProtectKeysWithCertificate(
        new X509Certificate2(Path.Combine(Directory.GetCurrentDirectory(), "clientCert.pfx"), "Password")
        )
.UnprotectKeysWithAnyCertificate(
        new X509Certificate2(Path.Combine(Directory.GetCurrentDirectory(), "clientCert.pfx"), "Password")
        );
Hamit YILDIRIM
sumber
0

Di Panel Sertifikat, klik kanan beberapa sertifikat -> Semua tugas -> Kelola kunci pribadi -> Tambahkan Pengguna IIS_IUSRS dengan kontrol penuh

Dalam kasus saya, saya tidak perlu menginstal sertifikat saya dengan opsi "Izinkan kunci pribadi untuk diekspor", seperti yang dikatakan di jawaban lain.

Fernando Meneses Gomes
sumber