인증서 저장소에있는 인증서의 개인 키에 대한 ASP.NET 액세스 권한을 부여하는 방법은 무엇입니까?


111

인증서 저장소에있는 인증서의 개인 키에 액세스하는 ASP.NET 응용 프로그램이 있습니다. Windows Server 2003에서는 winhttpcertcfg.exe를 사용하여 NETWORK SERVICE 계정에 대한 개인 키 액세스 권한을 부여 할 수있었습니다. IIS 7.5 웹 사이트에서 Windows Server 2008 R2의 인증서 저장소 (로컬 컴퓨터 \ 개인)에있는 인증서의 개인 키에 액세스 할 수있는 권한을 부여하려면 어떻게해야합니까?

"Everyone", "IIS AppPool \ DefaultAppPool", "IIS_IUSRS"및 인증서 MMC (Server 2008 R2)를 사용하여 찾을 수있는 다른 모든 보안 계정에 완전 신뢰 액세스 권한을 부여해 보았습니다. 그러나 아래 코드는 코드가 개인 키로 가져온 인증서의 개인 키에 액세스 할 수 없음을 보여줍니다. 대신 개인 키 속성에 액세스 할 때마다 코드가 발생하고 오류가 발생합니다.

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

답변:


195
  1. 인증서 생성 / 구매. 개인 키가 있는지 확인하십시오.
  2. 인증서를 "로컬 컴퓨터"계정으로 가져옵니다. 인증서 MMC를 사용하는 것이 가장 좋습니다. "개인 키를 내보낼 수 있음"을 선택했는지 확인하십시오.
  3. 이를 기반으로 IIS 7.5 응용 프로그램 풀의 ID는 다음 중 하나를 사용합니다.

    • IIS 7.5 웹 사이트는 ApplicationPoolIdentity에서 실행됩니다. MMC 열기 => 인증서 추가 (로컬 컴퓨터) 스냅인 => 인증서 (로컬 컴퓨터) => 개인 => 인증서 => 원하는 인증서를 마우스 오른쪽 버튼으로 클릭 => 모든 작업 => 개인 키 관리 => 추가 IIS AppPool\AppPoolName및 부여 Full control. " AppPoolName "을 응용 프로그램 풀의 이름으로 바꿉니다 (경우에 따라 IIS_IUSRS).
    • IIS 7.5 웹 사이트는 NETWORK SERVICE에서 실행됩니다. 인증서 MMC를 사용하여 "로컬 컴퓨터 \ 개인"의 인증서에 대한 완전 신뢰에 "네트워크 서비스"를 추가했습니다.
    • IIS 7.5 웹 사이트는 "MyIISUser"로컬 컴퓨터 사용자 계정으로 실행됩니다. 인증서 MMC를 사용하여 "로컬 컴퓨터 \ 개인"의 인증서에 대한 완전 신뢰에 "MyIISUser"(새 로컬 컴퓨터 사용자 계정)를 추가했습니다.

@Phil Hale 주석을 기반으로 업데이트 :

도메인에있는 경우 기본적으로 '위치 상자'에서 도메인이 선택됩니다. "로컬 컴퓨터"로 변경해야합니다. 앱 풀 ID를 보려면 위치를 "로컬 컴퓨터"로 변경하십시오.


3
Windows Server 2008 R2에서 "로컬 컴퓨터 \ 개인"의 인증서에서 "XXX"를 완전 신뢰로 구성하는 방법은 무엇입니까? run / mmc / file / add snap-in / certificates 및 ??? 감사합니다
Cobaia

7
MMC 인증서를 로컬 컴퓨터 \ 개인에 열었 으면 "인증서"를 클릭하여 인증서를 봅니다. (참고 : 다음은 인증서를 이미 가져온 것으로 가정하고 그렇지 않은 경우 먼저 인증서를 가져옵니다.) 모든 권한을 부여 할 인증서를 마우스 오른쪽 버튼으로 클릭합니다. 상황에 맞는 메뉴에서 "모든 작업"을 클릭 한 다음 하위 메뉴에서 "개인 키 관리"를 클릭합니다. 여기에서 인증서의 개인 키에 대한 '읽기'액세스 권한을 원하는 사용자를 추가 할 수 있습니다.
thames

5
"위치에서"상자에서 로컬 컴퓨터가 선택되어 있는지 확인하십시오. 이것은 한동안 나를 어리둥절하게 만들었다. 내가 로컬 컴퓨터의 위치를 변경할 때까지 응용 프로그램 풀 ID 사용자를 찾을 수 없습니다 있도록 도메인은 기본적으로 선택되었다
필 헤일

3
AWS의 Windows 2012 R2 EC2 VM (IIS 8 기반) IIS_IUSRS에서 인증서 개인 키에 대한 액세스 권한을 부여해야합니다
DeepSpace101 2014

4
powershell을 통해 이것을 수행하는 방법을 아십니까?
sonjz 17:07에

43

MMC, 인증서, 인증서 선택, 오른쪽 클릭, 모든 작업, "개인 키 관리"를 통한 권한 부여에 대한 참고 사항

개인 키 관리는 개인용 메뉴 목록에만 있습니다. 따라서 신뢰할 수있는 사람 등에 인증서를 입력했다면 운이 좋지 않습니다.

우리는이 문제를 해결하는 방법을 찾았습니다. 인증서를 개인으로 끌어다 놓고 개인 키 관리 작업을 수행하여 권한을 부여하십시오. 객체 유형 내장을 사용하도록 설정하고 도메인이 아닌 로컬 시스템을 사용하도록 설정해야합니다. DefaultAppPool 사용자에게 권한을 부여하고 그대로 두었습니다.

완료되면 인증서를 원래 있던 곳으로 끌어다 놓습니다. 프레스토 악장.


네, 잘 작동합니다. 나는 다음 게시물의 답변에서 언급했지만 수락 된 답변이 훨씬 길고 WCF 파일을 다운로드해야하더라도 다른 답변이 수락되었습니다. stackoverflow.com/questions/10580326/...
템즈

2
win2003 서버에 대한 솔루션이 있습니까? 그것은 윈도우 7과 같은 옵션으로 개인 키 관리가 없습니다
sonjz

1
@sonjz - 체크 아웃 이 TechNet이 , 명령 행 사용하여 언급winhttpcertcfg
mlhDev

개인 이외의 인증서에 대한 개인 키가 필요한 경우, 아마도 잘못된 일을하고있을 가능성이 높습니다. 다른 모든 위치는 신뢰할 수있는 기타 / 외부 엔티티를위한 것입니다. 개인 키가 없어야합니다. 그들의 공개 키 (인증서)는 충분해야합니다. 개인 키가 있다면 신뢰해서는 안된다고 감히 말할 수 있습니다.
Martin

15

IIS의 .pfx 파일에서 인증서를로드하려는 경우 솔루션은 Application Pool.

앱 풀을 마우스 오른쪽 버튼으로 클릭하고을 선택 Advanced Settings합니다.

그런 다음 활성화 Load User Profile


여기에 이미지 설명 입력


1
이것이 차이를 만드는 이유는 무엇입니까?
MichaelD

3
창문을 연결하는 방식 일뿐입니다. 프로필을 사용자 프로필에 일시적으로로드 할 수 있으므로이 옵션이 필요합니다. IIS가 액세스 할 수있는 파일에서로드 할 때 이것이 필요하다는 점에 동의합니다.
Simon_Weaver 2018

이것은 PDF에 대한 디지털 서명을 설정할 때 도움이되었습니다.
Fred Wilson

7

누군가가 물어 본 Powershell에서이 작업을 수행하는 방법을 알아 냈습니다.

$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

저에게는 "개인 키를 내보낼 수 있도록 허용"을 선택한 상태에서 인증서를 다시 가져 오는 것이 전부였습니다.

필요한 것 같지만이 인증서에 액세스하는 타사 앱이므로 긴장이됩니다.


감사합니다. X509Certificate2 cert = new X509Certificate2 (certBytes, password, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet);
Juan Lozoya 19


0

위의 내용에 참석했지만 많은 시도 끝에 지금까지 왔습니다. 1- 상점에서 인증서에 액세스하려면 예제로이를 수행 할 수 있습니다. 2- 인증서를 생성하고 경로를 통해 사용하는 것이 훨씬 쉽고 깔끔합니다.

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

    }
}

또는 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

인증서 패널에서 일부 인증서-> 모든 작업-> 개인 키 관리-> 모든 권한이있는 IIS_IUSRS 사용자 추가를 마우스 오른쪽 버튼으로 클릭합니다.

제 경우에는 다른 답변에서 말한 것처럼 "개인 키를 내보낼 수 있도록 허용"옵션을 선택하여 인증서를 설치할 필요가 없었습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.