我正在尝试使用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();
好的,现在我已经创建并安装了证书。然后,我通过向其提供生成的证书的指纹来配置我的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);
有谁知道这里的问题是什么?
如果我安装了使用'makecert'创建的证书,但我不会遇到问题,但这不适合生产证书。
我还尝试创建一个单独的x509v1 CA证书,然后创建x509v3证书进行服务器身份验证,但是我得到了同样的错误,所以为了简单起见,我在示例代码中将其删除了。
答案 0 :(得分:38)
该特定错误消息响铃。我猜你要么没有将私钥与证书一起存储,要么Windows服务无法访问私钥。要进行检查,请打开“证书MMC”管理单元:
导航到证书并双击右窗格。在出现的“常规”选项卡上,您应该在底部看到一个小键图标以及文本“您有一个与此证书对应的私钥”。如果没有,那就是问题所在。私钥未保存。
如果私钥 ,请单击“确定”关闭此对话框,然后右键单击右侧窗格中的证书,并在弹出菜单上选择:“所有任务”>管理私钥。在该对话框中,确保运行该服务的Windows帐户具有对私钥的读取权限。如果没有,那就是问题。
编辑:糟糕,您写道该服务作为本地系统运行,因此它必须是缺少的私钥,如果它是这两个问题之一。无论如何,我会将密钥访问检查留在我的答案中,对于任何其他人来说都是这样,而不是作为本地系统运行。
答案 1 :(得分:10)
有时,当应用程序尝试访问证书时没有足够的权限访问证书时会出现问题,可以通过以管理员身份运行应用程序来解决该问题。
答案 2 :(得分:6)
在线找到此解决方案,但我找不到信用来源。
由于我遇到AuthenticateAsClient()(用于客户端验证)的“提供给包的凭据无法识别”的问题,我想记录我是如何解决它的。这是一种具有相同目标的不同方法。因为它可能对AuthenticateAsServer()有用,所以不知道为什么。
这里我将BC证书转换为.NET证书。添加一个额外的步骤,将其转换为.NET X509Certificate2以存储它的PrivateKey属性。
Org.BouncyCastle.X509.X509Certificate bcCert;
X509Certificate dotNetCert = DotNetUtilities.ToX509Certificate(bcCert);
X509Certificate2 dotNetCert2 = new X509Certificate2(dotNetCert);
向.NET私钥添加BouncyCastle私钥时出现问题。 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;
之后,我能够将X509Certificate2对象直接保存到密钥库。我不需要实际的文件,所以我跳过了那一步。
答案 3 :(得分:3)
我遇到了同样的问题,尝试了许多帖子中的所有内容,以及Google进行了研究。 但看起来我找到了解决办法。 当我将识别从 ApplicationPoolIdentity 更改为 LocalSystem 时,一切开始正常运行。
可能会对某人有所帮助。
答案 4 :(得分:2)
对我来说,适用于Windows Server 2012 R2(.net 4.6.1) - "所有任务>管理私钥"并设置对Everyone的访问权限(设置为IS_IUSRS是不够的)
答案 5 :(得分:1)
以前,每次遇到此问题时,我都必须从本地计算机证书库中删除证书并重新导入。然后一切似乎都很开心。如果只是重新导入它就无法看到全局权限问题或无效证书如何解决问题。
我最终如何修复它是使用Windows资源工具包中的winhttpcertcfg工具向使用该证书的特定用户授予权限。
语法为:
"C:\Program Files (x86)\Windows Resource Kits\Tools\winhttpcertcfg" -i cert.p12 -c LOCAL_MACHINE\My -a UserWhoUsesTheCert -p passwordforp12
答案 6 :(得分:1)
从.NET应用程序调用WCF REST服务时我遇到了类似的问题,我需要附加客户端证书;我所要做的就是提供对证书存储[mmc console]中的证书访问“NETWORKSERVICE”的权限,当然我的IIS池是默认池,表明它使用的是NETWORKService用户帐户。
我犯的错误是,我将证书从另一家商店复制到本地 机器 - >证书受密码保护的人员商店。应该在必需的商店中明确导入证书。
答案 7 :(得分:0)
我不记得这个错误,但您创建的证书无效用于SSL / TLS,包括:
有几个RFC讨论此问题,包括TLS(1.2)上的RFC5246。
最后制作拥有证书并不比使用makecert
制作的更合适(但最后一个可以生成最小的可用设置)对于SSL / TLS服务器证书)。
我强烈建议您从知名证书颁发机构(CA)购买生产的SSL / TLS证书。这将为您提供大多数浏览器和工具认可的工作证书。