0

I am writing a C# program that has to call an API endpoint that requires authentication via certificates.

I have got a .pfx file, which I can import in Windows and everything works fine, however the app must run in a Linux environment in a Docker container.

I can import crt files into the /etc/ssl/certs folder in my Docker container just fine using the update-ca-certificates command.

I have tried the following:

  • Use openssl to to convert the pfx file into a crt/pem file that contains both the decrypted private key and the public key
-----BEGIN CERTIFICATE-----
abcd...
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
abcd...
-----END RSA PRIVATE KEY-----
  • Use openssl to split both keys into separate files and import those

  • Leave the bag attributes that openssl spits out in the files

Bag Attributes
    localKeyID: 01 00 00 00 
    friendlyName: XXX
subject=C = GB, O = 1111.1.1, O = XXX Limited, OU = devices, CN = XXX Limited

issuer=C = gb, O = 1111.1.1, O = YYY CAs, OU = YYY CA, OU = YYY Issuing CA

but the API always says I don't have a valid certificate.

Does anybody know what I'm doing wrong? Do the files have to be in a specific format? Perhaps in a different location?

My app finds the certificate just fine, so that's not the issue. The problem seems to be with the certificate itself.

Thanks in advance.

MondQ
  • 3
  • 1
  • How do you send your certificate to the API? I suspect that .NET app won't use OpenSSL certificates from `/etc/ssl` automagically. – AlexD Jul 17 '23 at 15:03
  • I find the certificate by its serial number. I went through the code and can confirm that the certificate is definitely found.wcfClient.ClientCredentials.ClientCertificate.SetCertificate( StoreLocation.LocalMachine, StoreName.CertificateAuthority, X509FindType.FindBySerialNumber, certificateSerial); – MondQ Jul 17 '23 at 15:13
  • One absolutely stupid thing that tripped me on this a long time back was line endings. If the cert file, generated in Windows, has `cr/lf` line endings, some Linux variants can't read it. I ended up loading the certificate in Notepad++, changing line endings from `Windows` to `Linux/Unix`, and saving back, and then it worked. For the same reason, I recommend, if you must transfer using FTP, use binary transfers even though it's supposedly text. – tsc_chazz Jul 17 '23 at 15:51

1 Answers1

1

The certstore loader on Linux will never look at a private key attached on the bottom of a file in /etc/ssl/certs. (If you look at the cert object, you'll see HasPrivateKey is false).

If you want to use a cert with a private key you need to either load it directly from a PFX, load it from a PFX once to then add it to the CurrentUser\My X509Store and then can use it from there, or load it from a multi-PEM intentionally, such as by calling X509Certificate2.CreateFromPemFile(pathToPem) (or X509Certificate2.CreateFromPemFile(pathToCertPem, pathToKeyPem))

// One time, such as by running a standalone tool:

using (X509Certificate2 fromPfx = new X509Certificate2(pfxToLoad, pfxPwd, X509KeyStorageFlags.PersistKeySet))
using (X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser, OpenFlags.ReadWrite))
{
    store.Add(fromPfx);
}

Then change your app to look in CurrentUser\My instead of LocalMachine\CA (or LocalMachine\Root, wherever you happen to be pointing it).

bartonjs
  • 361
  • 1
  • 10