2011-03-07 62 views
2

我有这个工作实现,但要确保它是安全的。目标是使用SSLStream,并且只接受来自服务器的由特定RSA密钥签名的SSL证书。要求SslStream只接受由特定公钥签名的证书

这里是我的连接代码:

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

** ** public ** key用于普通大众......只有你(带私钥的人)可以解密加密的消息,但。如果您想确保数据来自第三方,请从中获取公钥(他们将使用密钥对数据进行加密)。 – 2011-03-07 21:33:57

回答

0

您可以检查sslPolicyErrors参数其他错误,如过期,或者如果该证书不被信任。如果一切正常,它应该返回SslPolicyErrors.None。从公钥导出私钥在计算上是不可行的,因此您不必担心其他人创建相同的密钥对并对其进行签名。

+0

那么在我的情况下,它显示SslPolicyErrors为“System.Net.Security.SslPolicyErrors.RemoteCertificateNameMismatch | System.Net.Security.SslPolicyErrors.RemoteCertificateChainErrors”。在链状态下它说UntrustedRoot。请注意,我的证书未由CA签名。那么我应该检查一下以确保UntrustedRoot是唯一的链状态? – 2011-03-08 03:08:44

+2

RemoteCertificateNameMismatch意味着您的客户端连接到与证书上的内容不匹配的主机名。如果您连接到“www.myapp.com”,那么证书上的名称也应该与之匹配。由于证书未作为受信任的根CA安装在客户端计算机的证书存储中,因此会出现untrustedRoot错误。您可以在商店中安装该CA或忽略该错误,因为您有另一个明确的公钥检查。 – 2011-03-08 07:39:18

1

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

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

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

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

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; 

东西第一部分(我没有测试或编译这个):

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