问SslStream只接受由一个特定的公共密钥签名的证书 [英] Asking SslStream to accept ONLY a certificate signed by a particular public key

查看:443
本文介绍了问SslStream只接受由一个特定的公共密钥签名的证书的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这样一个工作的实施,但要确保它是安全的。的目标是使用SSLStream和只接受SSL证书从由特定的RSA密钥签署的服务器

下面是我的连接code:

  VAR的客户=新的TcpClient(SERVER_ADDRESS,端口号);
        VAR sslStream =新的SslStream(client.GetStream(),假的,
            新RemoteCertificateValidationCallback(ValidateServerCertificate),NULL);
        sslStream.AuthenticateAsClient(SpeechGrid);
 

这里是我的执行ValidateServerCertificate的:

 私有静态布尔ValidateServerCertificate(对象发件人,X509证书证,
            X509Chain链,SslPolicyErrors sslPolicyErrors){

        //只接受我们具体的密钥对
        的foreach(在chain.ChainElements VAR证书){
            如果(cert.Certificate.GetPublicKeyString()== k_prodPublicKey){
                返回true;
            }
        }

        返回false;
    }
 

因为我想确保我不需要检查之类的东西X509ChainStatusFlags.NotSignatureValid等方面的X509Chain对象的丰富性。

例如,才有可能为攻击者索赔通过我的公钥进行签名,发送一个无效签名,而这种攻击会工作,因为.NET假设我检查所有这些标志?

谢谢!

更新:确定,到目前为止,我已经决定把下面的检查上述原来的foreach。注意,这是多少有些具体应用;例如,如果我想的证书过期我会检查NotTimeValid等。

 的foreach(在chain.ChainStatus VAR状态){
            开关(status.Status){
                案例X509ChainStatusFlags.Cyclic:
                案例X509ChainStatusFlags.NotSignatureValid:
                案例X509ChainStatusFlags.PartialChain:
                    返回false;
            }
        }
 

解决方案

我会扭转你的更新添加到您的问题,检查的逻辑。而不是寻找什么可能是错误的,并接受一切:

 的foreach(的东西,我能想到的可能是错误的)
 返回false;

如果(公开密钥匹配无关的其他政策失误)
 返回true;
 

...我不是寻找什么可能是错误尚未接受,并拒绝任何其他政策错误:

 如果(策略错误)
{
 的foreach(误差是可以接受的:远程名称不匹配,不受信任的根,等等)
   政策失误 -  =特定错误
}

如果(左任何政策错误)
 返回false;
否则,如果(公钥匹配)
 返回true;
其他
 返回false;
 

像这样的事情在第一部分(我没有测试或编译本):

  IF((sslPolicyErrors&安培; SslPolicyErrors.RemoteCertificateNameMismatch)== SslPolicyErrors.RemoteCertificateNameMismatch)
{
    sslPolicyErrors和放大器; =〜SslPolicyErrors.RemoteCertificateNameMismatch;
}

如果((sslPolicyErrors&安培; SslPolicyErrors.RemoteCertificateChainErrors)== SslPolicyErrors.RemoteCertificateChainErrors)
{
    VAR otherFlagsFound =
        从我在chain.ChainStatus
        其中(i.Status&安培;〜X509ChainStatusFlags.UntrustedRoot)!= X509ChainStatusFlags.NoError
        选择我;

    如果(otherFlagsFound.Count()== 0)
    {
        sslPolicyErrors和放大器; =〜SslPolicyErrors.RemoteCertificateChainErrors;
    }
}
 

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

解决方案

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:

foreach (thing that I can think of that might be wrong)
 return false;

if (public key matches regardless of other policy errors)
 return true;

...I would instead look for what might be wrong yet acceptable, and reject any other policy errors:

if (policy errors)
{
 foreach (error that is acceptable: remote name mismatch, untrusted root, etc.)
   policy errors -= that particular error
}

if (any policy errors left)
 return false;
else if (public key matches)
 return true;
else
 return false;

Something like this for the first part (I did not test or compile this):

if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateNameMismatch) == SslPolicyErrors.RemoteCertificateNameMismatch)
{
    sslPolicyErrors &= ~SslPolicyErrors.RemoteCertificateNameMismatch;
}

if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateChainErrors) == SslPolicyErrors.RemoteCertificateChainErrors)
{
    var otherFlagsFound =
        from i in chain.ChainStatus
        where (i.Status & ~X509ChainStatusFlags.UntrustedRoot) != X509ChainStatusFlags.NoError
        select i;

    if (otherFlagsFound.Count() == 0)
    {
        sslPolicyErrors &= ~SslPolicyErrors.RemoteCertificateChainErrors;
    }
}

这篇关于问SslStream只接受由一个特定的公共密钥签名的证书的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆