要求 SslStream 仅接受由特定公钥签名的证书
我有一个有效的实现,但想确保它是安全的。目标是使用 SSLStream 并仅接受来自服务器的由特定 RSA 密钥签名的 SSL 证书。
这是我的连接代码:
var client = new TcpClient("server_address", port_number);
var sslStream = new SslStream(client.GetStream(), false,
new RemoteCertificateValidationCallback(ValidateServerCertificate), null);
sslStream.AuthenticateAsClient("SpeechGrid");
这是我的 ValidateServerCertificate 实现:
private static bool ValidateServerCertificate(object sender, X509Certificate certificate,
X509Chain chain, SslPolicyErrors sslPolicyErrors) {
// Only accept our specific key pair
foreach (var cert in chain.ChainElements) {
if (cert.Certificate.GetPublicKeyString() == k_prodPublicKey) {
return true;
}
}
return false;
}
由于 X509Chain 对象的丰富性,我想确保我不需要检查 X509ChainStatusFlags.NotSignatureValid 等内容。
例如,它会是攻击者是否有可能“声称”由我的公钥签名,发送无效签名,并且此攻击会起作用,因为 .NET 假设我正在检查所有这些标志?
谢谢!!
更新:好的,到目前为止,我决定将以下检查放在原始的 foreach 之上。请注意,这在某种程度上是特定于应用程序的;例如,如果我希望证书过期,我会检查 NotTimeValid 等。
foreach (var status in chain.ChainStatus) {
switch (status.Status) {
case X509ChainStatusFlags.Cyclic:
case X509ChainStatusFlags.NotSignatureValid:
case X509ChainStatusFlags.PartialChain:
return false;
}
}
I have a working implementation of this but want to make sure it is secure. The goal is to use SSLStream and only accept SSL certificates from the server that are signed by a particular RSA key.
Here is my connection code:
var client = new TcpClient("server_address", port_number);
var sslStream = new SslStream(client.GetStream(), false,
new RemoteCertificateValidationCallback(ValidateServerCertificate), null);
sslStream.AuthenticateAsClient("SpeechGrid");
And here is my implementation of ValidateServerCertificate:
private static bool ValidateServerCertificate(object sender, X509Certificate certificate,
X509Chain chain, SslPolicyErrors sslPolicyErrors) {
// Only accept our specific key pair
foreach (var cert in chain.ChainElements) {
if (cert.Certificate.GetPublicKeyString() == k_prodPublicKey) {
return true;
}
}
return false;
}
Because of the richness of the X509Chain object I want to make sure that I don't need to check for things like X509ChainStatusFlags.NotSignatureValid, etc.
For example, would it be possible for an attacker to "claim" to be signed by my public key, send an invalid signature, and this attack would work because .NET assumes I'm checking all of these flags?
Thanks!!
UPDATE: Ok, so far I've decided to put the following checks above the original foreach. Note that this is somewhat application specific; for example if I wanted certificates to expire I would check for NotTimeValid, etc.
foreach (var status in chain.ChainStatus) {
switch (status.Status) {
case X509ChainStatusFlags.Cyclic:
case X509ChainStatusFlags.NotSignatureValid:
case X509ChainStatusFlags.PartialChain:
return false;
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我会反转您在问题更新中添加的检查的逻辑。与其寻找可能错误的地方并接受其他一切:
...我会寻找可能错误但可以接受的地方,并拒绝任何其他政策错误:
第一部分是这样的(我没有测试或编译这个):
I would reverse the logic of the check you added in the update to your question. Instead of looking for what might be wrong and accepting everything else:
...I would instead look for what might be wrong yet acceptable, and reject any other policy errors:
Something like this for the first part (I did not test or compile this):
您可以检查 sslPolicyErrors 参数是否有其他错误,例如过期或证书是否不受信任。如果一切正常,它应该返回 SslPolicyErrors.None。从公钥导出私钥在计算上是不可行的,因此您无需担心其他人创建相同的密钥对并对其进行签名。
You can check the sslPolicyErrors parameter for additional errors such as expired, or if the certificates are not trusted. If everything is ok it should return SslPolicyErrors.None. It is computationally unfeasible to derive a private key from a public key so you don't need to worry about someone else creating the same key pair and signing it.