使用BouncyCastle生成的证书作为服务器进行身份验证时,"无法识别提供给程序包的凭据"错误

pet*_*eay 25 c# security ssl bouncycastle certificate

我正在尝试使用BouncyCastle.Crypto dll创建证书,然后使用该证书将SslStream作为Windows服务进程中的服务器进行身份验证,该服务在本地系统帐户下运行.

然而,当我到达SslStream.AuthenticateAsServer(证书)调用,它抛出以"提供给包中的凭据无法识别"错误消息的Win32异常.

这里有关于此错误消息的几个问题,但它们似乎都没有描述或解决我的特定问题.

希望有人能够提供一些帮助,我包含我用来创建和安装证书的代码:

// First create a certificate using the BouncyCastle classes
BigInteger serialNumber = BigInteger.ProbablePrime(120, new Random());
AsymmetricCipherKeyPair keyPair = GenerateKeyPair();

X509V1CertificateGenerator generator = new X509V1CertificateGenerator();
generator.SetSerialNumber(serialNumber);
generator.SetIssuerDN(new X509Name("CN=My Issuer"));
generator.SetNotBefore(DateTime.Today);
generator.SetNotAfter(DateTime.Today.AddYears(100));
generator.SetSubjectDN(new X509Name("CN=My Issuer"));
generator.SetPublicKey(keyPair.Public);
generator.SetSignatureAlgorithm("SHA1WITHRSA");

Org.BouncyCastle.X509.X509Certificate cert = generator.Generate(
    keyPair.Private, SecureRandom.GetInstance("SHA1PRNG"));

// Ok, now we have a BouncyCastle certificate, we need to convert it to the 
// System.Security.Cryptography class, by writing it out to disk and reloading
X509Certificate2 dotNetCert;

string tempStorePassword = "Password01"; // In real life I'd use a random password
FileInfo tempStoreFile = new FileInfo(Path.GetTempFileName());

try
{
    Pkcs12Store newStore = new Pkcs12Store();

    X509CertificateEntry entry = new X509CertificateEntry(cert);

    newStore.SetCertificateEntry(Environment.MachineName, entry);

    newStore.SetKeyEntry(
        Environment.MachineName,
        new AsymmetricKeyEntry(keyPair.Private),
        new [] { entry });

    using (FileStream s = tempStoreFile.Create())
    {
        newStore.Save(s, 
            tempStorePassword.ToCharArray(), 
            new SecureRandom(new CryptoApiRandomGenerator()));
    }

    // Reload the certificate from disk
    dotNetCert = new X509Certificate2(tempStoreFile.FullName, tempStorePassword);
}
finally
{
    tempStoreFile.Delete();
}

// Now install it into the required certificate stores
X509Store targetStore = new X509Store(StoreName.My, StoreLocation.LocalMachine);
targetStore.Open(OpenFlags.ReadWrite);
targetStore.Add(dotNetCert);
targetStore.Close();
Run Code Online (Sandbox Code Playgroud)

好的,现在我已经创建并安装了证书.然后,我通过向其提供生成的证书的指纹来配置我的Windows服务以使用此证书.然后我使用这样的证书:

// First load the certificate
X509Certificate2 certificate = null;

X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);

foreach (X509Certificate2 certInStore in store.Certificates)
{
    if (certInStore.Thumbprint == "...value not shown...")
    {
        certificate = certInStore;
        break;
    }
}

SslStream sslStream = new SslStream(new NetworkStream(socket, false), false);

// Now this line throws a Win32Exception 
// "The credentials supplied to the package were not recognized"
sslStream.AuthenticateAsServer(certificate);
Run Code Online (Sandbox Code Playgroud)

有谁知道这里的问题是什么?

如果我安装使用'makecert'创建的证书,但我不会遇到问题,但这不适用于生产证书.

我也尝试创建一个单独的x509v1 CA证书,然后采用X509v3服务器身份验证证书,但我得到了同样的错误,所以我在简单的示例代码移除了这个.

Jim*_*ood 45

该特定错误消息响铃.我猜你要么没有将私钥与证书一起存储,要么Windows服务无法访问私钥.要检查此问题,请打开"证书"MMC管理单元:

  1. 运行mmc(例如从"开始"菜单)
  2. "文件"菜单>"添加/删除管理单元"
  3. 在左窗格中选择"证书",然后单击"添加"
  4. 选择"计算机帐户"(对于LocalMachine),然后单击"下一步",然后单击"完成"

导航到证书,然后双击右窗格.在出现的"常规"选项卡上,您应该在底部看到一个小键图标以及文本"您有一个与此证书对应的私钥".如果没有,那就是问题所在.私钥未保存.

如果私钥存在,单击确定关闭此对话框,然后在证书上在右窗格中单击鼠标右键,选择弹出菜单中:所有任务>管理私钥.在该对话框中,确保运行该服务的Windows帐户具有对私钥的读取权限.如果没有,那就是问题所在.

编辑:糟糕,您写道该服务作为本地系统运行,因此它必须是缺少私钥,如果它是这两个问题之一.无论如何,我会在我的答案中留下密钥访问检查,对于任何其他人来说,并且不是作为本地系统运行.

  • "所有任务>管理私钥"+1(并选择IIS_IUSRS). (4认同)
  • 我今天刚刚遇到此错误(至少是相同的错误消息),该错误的证书在MMC管理单元中显示了一个私钥。我删除了它,然后从管理单元中将其重新导入,然后它起作用了。尝试删除证书,然后使用MMC管理单元将其从pfx文件格式导入,看看是否可以避免该错误。 (2认同)
  • 前 4 个步骤可以通过按 Windows 键并键入“管理计算机证书”或足够的字符来显示该选项,然后按 Enter 键来完成 (2认同)

小智 13

有时,当应用程序尝试访问证书时没有足够的权限来访问证书时,问题可能通过以管理员身份运行应用程序来解决.

  • 这在我的情况下是完全正确的:以管理模式启动 Visual Studio =) 应该获得正确答案;-) (2认同)

小智 12

我有同样的问题,尝试了许多帖子中的所有内容,并进行了谷歌研究。但看起来我找到了解决办法。当我将IdentityApplicationPoolIdentity更改为LocalSystem 时,一切都开始完美运行。

可能会对某人有所帮助。


小智 7

对我来说,在 Windows Server 2012 R2 (.net 4.6.1) 上工作 - “所有任务 > 管理私钥”并设置对所有人的访问权限(设置为 IS_IUSRS 是不够的)


小智 7

如果您从 IIS 运行,请确保应用程序池的“加载用户配置文件”设置为 true。这是我唯一的解决方案。


Mig*_*oll 6

在网上找到了这个解决方案,但我找不到信用的来源.

由于我遇到了"提供给包的凭据无法识别"的问题,因为AuthenticateAsClient()(用于客户端验证),我想记录我是如何解决它的.这是一种具有相同目标的不同方法.因为它可能对AuthenticateAsServer()有用,所以不知道为什么不这样做.

在这里,我将BC证书转换为.NET证书.添加一个额外的步骤,将其转换为.NET X509Certificate2以存储它的PrivateKey属性.

Org.BouncyCastle.X509.X509Certificate bcCert;

X509Certificate dotNetCert = DotNetUtilities.ToX509Certificate(bcCert);
X509Certificate2 dotNetCert2 = new X509Certificate2(dotNetCert);
Run Code Online (Sandbox Code Playgroud)

将BouncyCastle私钥添加到.NET私钥时出现问题.X509证书转换正常但不是私钥.我使用提供的DotNetUtilities将BC私钥转换为RSACryptoServiceProvider.不幸的是,转换似乎并不完整.所以我创建了另一个RSACryptoServiceProvider,然后我进行了初始化.然后我将私钥导入到我创建的私钥中.

// Apparently, using DotNetUtilities to convert the private key is a little iffy. Have to do some init up front.
RSACryptoServiceProvider tempRcsp = (RSACryptoServiceProvider)DotNetUtilities.ToRSA((RsaPrivateCrtKeyParameters)ackp.Private);
RSACryptoServiceProvider rcsp = new RSACryptoServiceProvider(new CspParameters(1, "Microsoft Strong Cryptographic Provider", 
            new Guid().ToString(), 
            new CryptoKeySecurity(), null));

rcsp.ImportCspBlob(tempRcsp.ExportCspBlob(true));
dotNetCert2.PrivateKey = rcsp;
Run Code Online (Sandbox Code Playgroud)

之后,我能够将X509Certificate2对象直接保存到密钥库.我不需要实际的文件所以我跳过了那一步.


pou*_*pou 0

我不记得这个错误,但您创建的证书不是用于 SSL/TLS 的有效证书,包括:

  • v1(不是 v3)证书;
  • 缺少扩展名;
  • CN 无效;
  • ...

有几个 RFC 讨论了这一点,包括关于 TLS (1.2) 的RFC5246

最后,制作自己的证书并不比使用 制作的证书更合适makecert(但最后一个可以生成可用于 SSL/TLS 服务器证书的最小集合)。

强烈建议您从知名的证书颁发机构 (CA) 购买用于生产的SSL/TLS 证书。这将为您提供大多数浏览器和工具认可的工作证书。