【问题标题】:C# RestSharp Client Certificate getting exception "The SSL connection could not be established"C# RestSharp 客户端证书获取异常“无法建立 SSL 连接”
【发布时间】:2020-04-23 10:38:10
【问题描述】:

我在放置此代码的 C# .Net Core 3.1 和 .Net Standard 库中进行编程。

我没有使用未安装在服务器/计算机上的客户端证书通过 RestSharp 获取我的 http 请求,我将无法访问稍后将要运行的服务器/计算机..

我的代码:

                // Create a RestSharp RestClient objhect with the base URL
                var client = new RestClient(_baseAPIUrl);

                // Create a request object with the path to the payment requests
                var request = new RestRequest("swish-cpcapi/api/v1/paymentrequests");

                // Create up a client certificate collection and import the certificate to it
                X509Certificate2Collection clientCertificates = new X509Certificate2Collection();
                clientCertificates.Import(_certDataBytes, _certificatePassword, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);

                // Add client certificate collection to the RestClient
                client.ClientCertificates = clientCertificates;

                //X509Certificate2 certificates = new X509Certificate2(_certDataBytes, _certificatePassword);

                //client.ClientCertificates = new X509CertificateCollection() { certificates };

                // Add payment request data
                request.AddJsonBody(requestData);

                var response = client.Post(request);
                var content = response.Content;

我已经完成了我在互联网上可以找到的所有内容,并且我使用了带有自己生成证书的服务测试环境,并在生产环境中生成了我自己的证书,结果相同..

我已经测试了设置 TLS 1.1 或 TLS 1.2 进行测试,他们在自己的 curl 示例中指定了 TLS 1.1。

有人知道吗?

更新 2020-01-08 - 我从服务技术支持人员那里得到信息,他们只看到我发送了一个证书,但是当我尝试调试和检查 X509Certificate2Collection 时,我发现了 3 个证书。但他们说他们只看到一个?

【问题讨论】:

标签: c# .net .net-core restsharp client-certificates


【解决方案1】:

我建议您自己生成证书

public static void MakeCert()
{
    var ecdsa = ECDsa.Create(); // generate asymmetric key pair
    var req = new CertificateRequest("cn=foobar", ecdsa, HashAlgorithmName.SHA256);
    var cert = req.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.AddYears(10));

    // Create PFX (PKCS #12) with private key
    File.WriteAllBytes("c:\\temp\\mycert.pfx", cert.Export(X509ContentType.Pfx, "P@55w0rd"));

    // Create Base 64 encoded CER (public key only)
    File.WriteAllText("c:\\temp\\mycert.cer",
        "-----BEGIN CERTIFICATE-----\r\n"
        + Convert.ToBase64String(cert.Export(X509ContentType.Cert), Base64FormattingOptions.InsertLineBreaks)
        + "\r\n-----END CERTIFICATE-----");
}

然后添加到请求中

        var client = new RestClient(url);

        client.ClientCertificates = new X509CertificateCollection();
        client.ClientCertificates.Add(new X509Certificate2("c:\\temp\\mycert.cer"));

【讨论】:

    【解决方案2】:

    恕我直言,如果您尝试访问的服务受到 SSL 证书的保护,并且需要公钥/私钥,那么如果没有证书,您将无法访问它。如果这是要保护服务的意图,我认为您可能只检查服务健康检查或最大检查服务是否可访问(没有客户端证书)

    但是就像 HTTPS 一样,如果您可以从浏览器访问服务 URL,那么您可以尝试从浏览器下载证书,例如,访问它们的元数据或简单的 GET 或其他东西。在 chrome 中,您可能会在 URL 之前看到一个锁定符号(安全图标)。单击它,您可能会下载公共证书。您可以将其安装在您的机器上并尝试一下。

    如果该服务具有 pub 证书并且访问不需要客户端证书,则上述选项可能有效。我希望您正在安装 CERT 并通过您的代码从有权访问证书的帐户访问它。假设您将证书安装在 LocalSystem 下,那么您可能需要从代码/解决方案进行管理员访问才能访问该证书路径。或者将证书安装在 current_user 路径下。

    我会首先检查是否能够从浏览器访问该服务。

    这只是根据我从您的问题中了解到的。同样,如果您可以根据公钥/私钥解释该服务是否是受保护的服务,则您需要具有使用该服务的访问权限/证书。

    更新: 通过创建一个演示 api 和一个演示客户端来使用客户端证书,我已经尝试了几个选项。根据我从您的查询中了解到的情况,我认为以下可能是您可以尝试的一些选项。

    // --- using the cert path if you have the path (instead of the byte[])
    var myCert = new X509Certificate2("<path to the client cert.cer/.pfx>", "secure-password", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);
    X509CertificateCollection clientCerts = new X509CertificateCollection();
    clientCerts.Add(myCert);
    

    var certStore = new X509Store(StoreName.Root, StoreLocation.LocalMachine); //replace with appropriate values based on your cert configuration
    certStore.Open(OpenFlags.ReadOnly);
    
    //option 1 (ideally a client must have the cert thumbprint instead of a password 
    var cert = certStore.Certificates.Find(X509FindType.FindByThumbprint, "<cert Thumbprint>", false);
    
    //option 2 (explore other options based on X509NameTypes
    var cert = certStore.Certificates.OfType<X509Certificate2>()
                        .FirstOrDefault(cert => cert.GetNameInfo(X509NameType.DnsName, false) == "mycompany.dns.name.given in the cert");
    
    client.ClientCertificates = new X509CertificateCollection(cert);
    

    【讨论】:

    • 谢谢,但我确信它有用于身份验证的客户端证书,我需要帮助我可能做错的代码。
    • 我已经尝试了几个选项,通过创建一个演示 api 和一个演示客户端来使用客户端证书。根据我从您的查询中了解到的情况,我假设以下可能是您尝试的一些选项。
    猜你喜欢
    • 2018-07-30
    • 2014-10-19
    • 1970-01-01
    • 2012-08-25
    • 2017-04-20
    • 2016-06-17
    • 1970-01-01
    • 1970-01-01
    • 2019-03-01
    相关资源
    最近更新 更多