Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/287.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用CA证书文件验证远程服务器X509证书_C#_Ssl_Openssl_X509certificate_Sslstream - Fatal编程技术网

C# 使用CA证书文件验证远程服务器X509证书

C# 使用CA证书文件验证远程服务器X509证书,c#,ssl,openssl,x509certificate,sslstream,C#,Ssl,Openssl,X509certificate,Sslstream,我已经使用OpenSSL生成了一个CA和多个证书(由CA签名),我有一个.NET/C#客户端和服务器都使用SslStream,每个都有自己的证书/密钥,相互身份验证被启用,撤销被禁用 我正在使用RemoteCertificateValidationCallbackforSslStream验证远程服务器的证书,我希望我可以在程序中加载CA的公共证书(作为文件),并使用它验证远程证书,而不是在Windows证书存储中实际安装CA。问题是X509Chain不会显示任何其他内容,除非我将CA安装到存储中

我已经使用OpenSSL生成了一个CA和多个证书(由CA签名),我有一个.NET/C#客户端和服务器都使用
SslStream
,每个都有自己的证书/密钥,相互身份验证被启用,撤销被禁用

我正在使用
RemoteCertificateValidationCallback
for
SslStream
验证远程服务器的证书,我希望我可以在程序中加载CA的公共证书(作为文件),并使用它验证远程证书,而不是在Windows证书存储中实际安装CA。问题是
X509Chain
不会显示任何其他内容,除非我将CA安装到存储中,当我打开其中一个证书的PEM版本时,Windows CryptoAPI外壳也不会显示


我的问题是,当
RemoteCertificateValidationCallback
时,如何仅使用CA的公共证书文件而不使用Windows证书存储或WCF来验证证书是否已由我的特定CA签名,
X509Certificate
X509Chain
似乎没有给我任何可以使用的东西?

因为CA证书不在根证书存储中,所以在RemoteCertificateValidationCallback()中有一个错误标志SslPolicyErrors.RemoteCertificateChaineErrors;一种可能性是根据您自己的X509Certificate2Collection明确验证证书链,因为您没有使用本地存储

if(sslPolicyErrors==sslPolicyErrors.RemoteCertificateChaineErrors)
{
X509Chain chain0=新的X509Chain();
chain0.ChainPolicy.RevocationMode=X509RevocationMode.NoCheck;
//添加所有额外的证书链
chain0.ChainPolicy.ExtraStore.Add(新的X509Certificate2(PublicResource.my_ca));
chain0.ChainPolicy.VerificationFlags=X509VerificationFlags.AllowUnknownCertificationAuthority;
isValid=chain0.Build((X509Certificate2)证书);
}
您还可以重新使用在回调中传递的链,在ExtraStore集合中添加额外的证书,并使用AllowUnknownCertificateAuthority标志进行验证,这是因为您将不受信任的证书添加到链中所必需的

您还可以通过在受信任的根存储中以编程方式添加CA证书来防止原始错误(当然,它会打开一个弹出窗口,因为全局添加新的受信任的CA根是一个主要的安全问题):

编辑:对于那些希望使用CA清楚地测试链的人:


另一种可能是使用库
BouncyCastle
构建证书链并验证信任。选项清晰,错误容易理解。在成功的cas中,它将构建链,否则将返回异常。样本如下:

// rootCerts : collection of CA
// currentCertificate : the one you want to test
var builderParams = new PkixBuilderParameters(rootCerts, 
                        new X509CertStoreSelector { Certificate = currentCertificate });
// crls : The certificate revocation list
builderParams.IsRevocationEnabled = crls.Count != 0;
// validationDate : probably "now"
builderParams.Date = new DateTimeObject(validationDate);

// The indermediate certs are items necessary to create the certificate chain
builderParams.AddStore(X509StoreFactory.Create("Certificate/Collection", new X509CollectionStoreParameters(intermediateCerts)));
builderParams.AddStore(X509StoreFactory.Create("CRL/Collection", new X509CollectionStoreParameters(crls)));

try
{
    PkixCertPathBuilderResult result = builder.Build(builderParams);
    return result.CertPath.Certificates.Cast<X509Certificate>();
    ...
//根证书:CA的集合
//currentCertificate:要测试的证书
var builderParams=新的PkixBuilderParameters(rootCerts,
新X509CertStoreSelector{Certificate=currentCertificate});
//crls:证书吊销列表
builderParams.IsRevocationEnabled=crls.Count!=0;
//验证日期:可能是“现在”
builderParams.Date=新的DateTimeObject(validationDate);
//indermediate证书是创建证书链所必需的项目
AddStore(X509StoreFactory.Create(“证书/集合”,新的X509CollectionStoreParameters(intermediateCerts));
AddStore(X509StoreFactory.Create(“CRL/Collection”,新的X509CollectionStoreParameters(CRL));
尝试
{
PkixCertPathBuilderResult结果=builder.Build(builderParams);
返回result.CertPath.Certificates.Cast();
...
当RemoteCertificateValidationCallback、X509Certificate和X509Chain似乎没有给我提供任何可使用的信息时,我如何仅使用CA的公共证书文件而不使用Windows证书存储或WCF来验证证书是否已由我的特定CA签名

下面的代码将避免Windows证书存储并验证链。它与JB的代码略有不同,尤其是在标志的使用方面。下面的代码不需要
AllowUnknownCertificateAuthority
(但它使用
X509RevocationMode.NoCheck
,因为我没有CRL)

函数的名称无关紧要。下面,
VerifyServerCertificate
是与
SslStream
类中的
RemoteCertificateValidationCallback
相同的回调。您也可以将其用于
ServicePointManager
中的
ServerCertificateValidationCallback

static bool VerifyServerCertificate(object sender, X509Certificate certificate,
    X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
    try
    {
        String CA_FILE = "ca-cert.der";
        X509Certificate2 ca = new X509Certificate2(CA_FILE);

        X509Chain chain2 = new X509Chain();
        chain2.ChainPolicy.ExtraStore.Add(ca);

        // Check all properties
        chain2.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag;

        // This setup does not have revocation information
        chain2.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;

        // Build the chain
        chain2.Build(new X509Certificate2(certificate));

        // Are there any failures from building the chain?
        if (chain2.ChainStatus.Length == 0)
            return true;

        // If there is a status, verify the status is NoError
        bool result = chain2.ChainStatus[0].Status == X509ChainStatusFlags.NoError;
        Debug.Assert(result == true);

        return result;
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex);
    }

    return false;
}

我还没有弄清楚如何在默认情况下使用此链(
chain2
),这样就不需要回调。也就是说,将其安装在ssl套接字上,连接将“正常工作”。我还没有弄清楚如何安装它,以便将其传递到回调中。也就是说,我必须为每次回调调用构建链。我认为这些是.Net中的体系结构缺陷,但我可能遗漏了一些明显的东西。

我不明白为什么将CA证书添加到Windows应用商店会导致X509Chain将其显示为In链,但如果我没有,它不是链的一部分。是否有人在RemoteCertificateValidationCallback中将CA证书添加到链中?我仍然找不到此问题的答案:(看起来没问题。
chain2
将是测试证书和根证书之间的证书信任列表。现在,如果对证书执行高级操作,您可能希望使用BouncyCastle库。另一种可能是使用库
BouncyCastle
来构建证书链并验证信任。选项清晰,错误容易理解。请参阅此处的响应以正确检查您自己的CA。上述方法将接受每个CA(不检查有效性)。
static bool VerifyServerCertificate(object sender, X509Certificate certificate,
    X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
    try
    {
        String CA_FILE = "ca-cert.der";
        X509Certificate2 ca = new X509Certificate2(CA_FILE);

        X509Chain chain2 = new X509Chain();
        chain2.ChainPolicy.ExtraStore.Add(ca);

        // Check all properties
        chain2.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag;

        // This setup does not have revocation information
        chain2.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;

        // Build the chain
        chain2.Build(new X509Certificate2(certificate));

        // Are there any failures from building the chain?
        if (chain2.ChainStatus.Length == 0)
            return true;

        // If there is a status, verify the status is NoError
        bool result = chain2.ChainStatus[0].Status == X509ChainStatusFlags.NoError;
        Debug.Assert(result == true);

        return result;
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex);
    }

    return false;
}