Search code examples
pythonc#ssl-certificatedotnet-httpclient

Provide certificate verify CA and certificate .pem and .key to HttpClient C#


I am migrating from perl/python a functionality to upload large files to a REST API in dotNet C#.

I having some problems to feed the certificates: I have three certificates files:

  1. TECHUSER.pem
  2. TECHUSER.key
  3. Server_TrustedCA.pem

where 1. and 2. contains the technical user certificates and 3rd is the Server TrustedCA

my code so far:


X509Certificate2 certificate = new X509Certificate2(@"TECHUSER.pem");

httpClientHandler.ClientCertificates.Clear();
httpClientHandler.ClientCertificates.Add(certificate);
httpClientHandler.SslProtocols = SslProtocols.Tls12;
httpClientHandler.ClientCertificateOptions = ClientCertificateOption.Manual;
using (var content = new MultipartFormDataContent("Upload----" + DateTime.Now.ToString(CultureInfo.InvariantCulture)))
{
         content.Add(new StreamContent(new MemoryStream("OneGbFile.txt")), "file", "OneGbFile.txt");

         HttpClient httpClient = new HttpClient(httpClientHandler);
     HttpResponseMessage result = httpClient.PostAsync("https://myserver.url", content).Result;
         string str = result.Content.ReadAsStringAsync().Result;
 }

This used to be my solution in perl:

#!perl
use warnings;
use IO::Socket::SSL;
use LWP::UserAgent;

my $ua = LWP::UserAgent->new(
    ssl_opts => {
        SSL_ca_file => 'Server_TrustedCA.pem',
        SSL_use_cert => 1,
        SSL_version     => 'TLSv12',
        SSL_verify_mode => SSL_VERIFY_PEER,
        SSL_cert_file   => 'TECHUSER.pem',
        SSL_key_file    => 'TECHUSER.key',
    }
);
my $file_path = "OneGbFile.txt";
my $url = 'https://myserver.url';
my $res = $ua->post($url,
    Content_Type => 'multipart/form-data',
    Accept => 'application/json',
    Content => [
        file => [$file_path],
    ],
);

if ($res -> is_success) {
    print "Success\n";
}
else {
    print "Fail\n";
}

and this my implementation in python:

# Python:
from requests import Request, Session
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.poolmanager import PoolManager

s = Session()
s.mount('https://', SSLAdapter(ssl.PROTOCOL_TLSv1_2))

ufiles= {file: open('OneGbFile.txt','rb')}

req = Request('POST', self.base_url, files=ufiles)

r = s.send(prepped,
    verify='Server_TrustedCA.pem',
    cert=('TECHUSER.pem', 'TECHUSER.key'),
    timeout=54000
)

Now that I am migrating to dotnet C# I am strangling getting it to work in dotNet. Any support will be very appreciated.


Solution

  • X509Certificate2 certificate = new X509Certificate2(@"TECHUSER.pem");
    

    Only loads the public certificate.

    On .NET 5+ you can replace this with a different one-liner:

    X509Certificate2 certificate = X509Certificate2.CreateFromPemFile("TECHUSER.pem", "TECHUSER.key");