RickardP
RickardP

Reputation: 2600

C# RestSharp Client Certificate getting exception "The SSL connection could not be established"

I programming in C# .Net Core 3.1 and .Net Standard library where this code is put.

I am not getting my http requests with RestSharp with a client certificate that are NOT installed on the server/computer i am not going to have access to the server/computer where this is going to be running later on..

My code:

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

I have done what ever i can find on internet and i have used the service test environment with there own generated certificate and generated my own in there production environment with the same result..

I have tested set TLS 1.1 or TLS 1.2 to test, they specified TLS 1.1 on there own curl examples.

Anyone got any idea?

Update 2020-01-08 - I have got information from the service tech support that they only see me sending one certificate but when i trying to debug and checking the X509Certificate2Collection i finding 3 certificate. But they saying they only see one?

Upvotes: 1

Views: 9421

Answers (2)

karel be
karel be

Reputation: 11

I recommend generate your own certificate

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

and then add to request

        var client = new RestClient(url);

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

Upvotes: 1

Ak777
Ak777

Reputation: 396

IMHO, if the service you are trying to access is protected via SSL cert with expecting public key/private key, then without the cert, you cant access it. If thats the intent of the service to be protected, i think you may only do to check the service health check or at max, check if the service is accessible (without having the client cert)

But just as HTTPS, then you can try to download the cert from the browser if you can access the service URL from your browser, say, to access their meta or a simple GET or something. In chrome, you may see a lock symbol (security icon) just before to the URL. click that, and you may possibly download the public cert. You can install that on your machine and try that.

In case, if that service has a pub cert and the access doesnt need the client cert, then above option may work. and i hope you are installing the CERT and access that via your code from the account that has access to the cert. Lets say, you install the cert under the LocalSystem, then you may need administrator access from code/solution to access that cert path. Or install the cert under the current_user path.

I would Check if am able to access the service from browser as the first step.

This is, just from what i have understood from your question. again, if you can explain whether the service is a protected service based on public key/private key, you need to have the access/cert to use that service.

UPDATE: I have tried few options on my end, by creating a demo api and a demo client to use client certs. With what i have understood from your query, i assume below may be some of your options to try out.

// --- 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);

OR

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

Upvotes: 1

Related Questions