Làm cách nào để cấp cho ASP.NET quyền truy cập vào khóa cá nhân trong chứng chỉ trong kho lưu trữ chứng chỉ?


111

Tôi có một ứng dụng ASP.NET truy cập khóa cá nhân trong chứng chỉ trong kho chứng chỉ. Trên Windows Server 2003, tôi có thể sử dụng winhttpcertcfg.exe để cấp quyền truy cập khóa cá nhân vào tài khoản DỊCH VỤ MẠNG. Làm cách nào để cấp quyền truy cập Khóa riêng trong chứng chỉ trong kho lưu trữ chứng chỉ (Máy tính cục bộ \ Cá nhân) trên Windows Server 2008 R2 trong trang web IIS 7.5?

Tôi đã thử cấp cho Full Trust quyền truy cập vào "Mọi người", "IIS AppPool \ DefaultAppPool", "IIS_IUSRS" và mọi tài khoản bảo mật khác mà tôi có thể tìm thấy bằng cách sử dụng Chứng chỉ MMC (Server 2008 R2). Tuy nhiên, đoạn mã dưới đây chứng minh rằng mã không có quyền truy cập vào Khóa riêng tư của chứng chỉ được nhập bằng khóa cá nhân. Thay vào đó, mã sẽ ném và lỗi mỗi khi thuộc tính khóa riêng được truy cập.

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

Câu trả lời:


195
  1. Tạo / Mua chứng chỉ. Đảm bảo rằng nó có khóa riêng.
  2. Nhập chứng chỉ vào tài khoản "Máy tính cục bộ". Tốt nhất nên sử dụng Chứng chỉ MMC. Đảm bảo chọn "Cho phép xuất khóa riêng tư"
  3. Dựa trên đó, danh tính của Nhóm ứng dụng IIS 7.5 sử dụng một trong những điều sau.

    • IIS 7.5 Trang web đang chạy trong ApplicationPoolIdentity. Mở snap-in MMC => Thêm chứng chỉ (Máy tính cục bộ) => Chứng chỉ (Máy tính cục bộ) => Cá nhân => Chứng chỉ => Nhấp chuột phải vào chứng chỉ quan tâm => Tất cả nhiệm vụ => Quản lý khóa cá nhân => Thêm IIS AppPool\AppPoolNamevà cấp nó Full control. Thay thế " AppPoolName " bằng tên của nhóm ứng dụng của bạn (đôi khi IIS_IUSRS)
    • IIS 7.5 Trang web đang chạy trong DỊCH VỤ MẠNG. Sử dụng Chứng chỉ MMC, đã thêm "DỊCH VỤ MẠNG" vào Tin cậy Hoàn toàn trên chứng chỉ trong "Máy tính cục bộ \ Cá nhân".
    • IIS 7.5 Trang web đang chạy trong tài khoản người dùng máy tính cục bộ "MyIISUser". Sử dụng Chứng chỉ MMC, đã thêm "MyIISUser" (tài khoản người dùng máy tính cục bộ mới) vào Full Trust trên chứng chỉ trong "Local Computer \ Personal".

Cập nhật dựa trên nhận xét của @Phil Hale:

Hãy lưu ý, nếu bạn đang ở trên một miền, miền của bạn sẽ được chọn theo mặc định trong 'hộp từ vị trí'. Đảm bảo thay đổi thành "Máy tính cục bộ". Thay đổi vị trí thành "Máy tính cục bộ" để xem danh tính nhóm ứng dụng.


3
Làm cách nào để định cấu hình ("XXX" thành Tin cậy hoàn toàn trên chứng chỉ trong "Máy tính cục bộ \ Cá nhân") trong Windows Server 2008 R2? chạy / mmc / tệp / thêm snap-in / chứng chỉ và ??? Cảm ơn
Cobaia 19/12/11

7
Khi bạn đã mở Chứng chỉ MMC cho Local Computer \ Personal, hãy nhấp vào "chứng chỉ" để xem các chứng chỉ. (lưu ý: phần sau giả sử chứng chỉ đã được nhập, nếu chưa nhập chứng chỉ trước) Nhấp chuột phải vào chứng chỉ bạn muốn cấp Toàn quyền kiểm soát. Trong menu ngữ cảnh, hãy nhấp vào "Tất cả công việc", sau đó trong menu con, nhấp vào "Quản lý khóa riêng". Từ đó, bạn có thể thêm bất kỳ người dùng nào bạn muốn có quyền truy cập 'đọc' vào khóa riêng tư cho chứng chỉ.
thames

5
Đảm bảo rằng máy tính cục bộ được chọn trong hộp "từ vị trí". Điều này làm tôi bối rối trong một thời gian. Miền được chọn theo mặc định vì vậy nó không tìm thấy người dùng nhận dạng nhóm ứng dụng cho đến khi tôi thay đổi vị trí thành máy tính cục bộ
Phil Hale

3
Trên Windows AWS 2012 R2 EC2 của VM (IIS 8 dựa), bạn cần phải cung cấp IIS_IUSRSquyền truy cập vào các khóa riêng giấy chứng nhận
DeepSpace101

4
Bất kỳ ý tưởng làm thế nào để làm điều này thông qua powershell?
sonjz

43

Lưu ý về việc cấp quyền qua MMC, Certs, Select Cert, nhấp chuột phải, tất cả các tác vụ, "Quản lý khóa riêng"

Quản lý Khóa riêng tư chỉ có trong danh sách menu cho Cá nhân ... Vì vậy, nếu bạn đã đặt chứng chỉ của mình cho Người đáng tin cậy, v.v. thì bạn đã gặp may.

Chúng tôi đã tìm ra cách giải quyết vấn đề này phù hợp với chúng tôi. Kéo và thả chứng chỉ vào Cá nhân, thực hiện việc Quản lý Khóa riêng tư để cấp quyền. Hãy nhớ đặt để sử dụng tích hợp kiểu đối tượng và sử dụng máy cục bộ không phải miền. Chúng tôi đã cấp quyền cho người dùng DefaultAppPool và để nó ở đó.

Khi bạn đã hoàn tất, hãy kéo và thả chứng chỉ trở lại vị trí ban đầu bạn có. Mau.


có điều này hoạt động tốt. Tôi đã đề cập đến nó trong một câu trả lời trên bài đăng sau tuy nhiên một câu trả lời khác đã được chấp nhận mặc dù câu trả lời được chấp nhận dài hơn nhiều và yêu cầu tải xuống tệp WCF. stackoverflow.com/questions/10580326/…
thames

2
bất kỳ giải pháp cho máy chủ win2003? nó không có Quản lý khóa riêng tư như một tùy chọn như windows 7
sonjz 21/09/12

1
@sonjz - kiểm tra TechNet này , nó đề cập đến việc sử dụng dòng lệnhwinhttpcertcfg
mlhDev

Nếu bạn cần khóa cá nhân cho chứng chỉ cho bất kỳ thứ gì ngoại trừ cá nhân, rất có thể bạn đang làm sai ... Tất cả các vị trí khác đều dành cho các thực thể khác / bên ngoài mà bạn tin tưởng. Bạn không nên có khóa riêng của họ. Khóa công khai (chứng chỉ) của họ phải đủ. Tôi thậm chí còn dám nói rằng nếu bạn có khóa riêng của họ, bạn không nên tin tưởng vào họ.
Martin

15

Nếu bạn đang cố gắng tải một chứng chỉ từ tệp .pfx trong IIS, giải pháp có thể đơn giản là bật tùy chọn này cho Application Pool.

Nhấp chuột phải vào Nhóm ứng dụng và chọn Advanced Settings.

Sau đó kích hoạt Load User Profile


nhập mô tả hình ảnh ở đây


1
Tại sao điều này tạo ra sự khác biệt?
MichaelD

3
Nó chỉ phải là cách mà các cửa sổ được kết nối. Đó là nó có thể đang tạm thời tải hồ sơ vào hồ sơ người dùng nên nó cần tùy chọn này. Tôi đồng ý rằng điều này là cần thiết khi tải từ một tệp mà IIS có quyền truy cập vào.
Simon_Weaver

Điều này đã giúp tôi khi tôi thiết lập chữ ký số cho các tệp PDF.
Fred Wilson,

7

Tôi đã tìm ra cách thực hiện việc này trong Powershell mà ai đó đã hỏi:

$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

6

Đối với tôi, không có gì khác hơn là nhập lại chứng chỉ với "Cho phép xuất khóa riêng tư" được chọn.

Tôi đoán điều đó là cần thiết, nhưng nó khiến tôi lo lắng vì đây là ứng dụng của bên thứ ba truy cập chứng chỉ này.


cảm ơn bạn Tôi đã làm theo cách này X509Certificate2 cert = new X509Certificate2 (certBytes, mật khẩu, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet);
Juan Lozoya


0

Mặc dù tôi đã tham dự những điều trên, tôi đã đi đến thời điểm này sau nhiều cố gắng. 1- Nếu bạn muốn truy cập vào chứng chỉ từ cửa hàng, bạn có thể làm điều này như một ví dụ 2- Việc tạo chứng chỉ và sử dụng chứng chỉ thông qua một đường dẫn dễ dàng và sạch sẽ hơn nhiều

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

    }
}

HOẶC 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")
        );

0

Trong Bảng chứng chỉ, nhấp chuột phải vào một số chứng chỉ -> Tất cả tác vụ -> Quản lý khóa cá nhân -> Thêm Người dùng IIS_IUSRS với toàn quyền kiểm soát

Trong trường hợp của tôi, tôi không cần cài đặt chứng chỉ của mình với tùy chọn "Cho phép xuất khóa riêng tư" được chọn, như đã nói trong các câu trả lời khác.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.