In the past I have been making secure TcpListener by exporting a PFX certificate with a password, but would like to know if this step could be skipped.
I'm not using commercial SSL certificates, and have a Root CA, that I use to issue server certificates. These server certificates require additional steps when hosting a TcpListener in C# (I guess because the CSR wasn't used)... but what if I do have the Private Key, and the Certificate that OpenSSL generates/uses.
sslCertificate = new X509Certificate2("myExportedCert.pfx", "1234");
So this is great, however I have to issue an openssl command to make a pfx file from the Certificate and the Private Key, then make up some password. Then include this password in my code.
I was wondering if this step was quite necessary. Is there a way to make up a X509Certificate2 from the Cert, and then apply the Private Key. The constructor arguments allow the Cert only part, but encrypting fails then because there is no private key.
Also, I don't want to rely on OpenSSL or IIS to export the pfx.... seems clumsy.
Ideally i would like:
sslCertificate = new X509Certificate2("myCert.crt");
sslCertificate.ApplyPrivateKey(keyBytes) // <= or "private.key" or whatever
sslStream.AuthenticateAsServer(sslCertificate, false, SslProtocols.Default, false);
There are a couple of different things you're asking for, with different levels of ease.
Starting in .NET Framework 4.7.2 or .NET Core 2.0 you can combine a cert and a key. It doesn't modify the certificate object, but rather produces a new cert object which knows about the key.
using (X509Certificate2 pubOnly = new X509Certificate2("myCert.crt"))
using (X509Certificate2 pubPrivEphemeral = pubOnly.CopyWithPrivateKey(privateKey))
{
// Export as PFX and re-import if you want "normal PFX private key lifetime"
// (this step is currently required for SslStream, but not for most other things
// using certificates)
return new X509Certificate2(pubPrivEphemeral.Export(X509ContentType.Pfx));
}
on .NET Framework (but not .NET Core) if your private key is RSACryptoServiceProvider
or DSACryptoServiceProvider
you can use cert.PrivateKey = key
, but that has complex side-effects and is discouraged.
This one is harder, unless you've already solved it.
For the most part the answer for this is in Digital signature in c# without using BouncyCastle, but if you can move to .NET Core 3.0 things get a lot easier.
Starting in .NET Core 3.0 you can do this relatively simply:
using (RSA rsa = RSA.Create())
{
rsa.ImportPkcs8PrivateKey(binaryEncoding, out _);
// do stuff with the key now
}
(of course, if you had a PEM you need to "de-PEM" it, by extracting the contents between the BEGIN and END delimiters and running it through Convert.FromBase64String
in order to get binaryEncoding
).
Starting in .NET Core 3.0 you can do this relatively simply:
using (RSA rsa = RSA.Create())
{
rsa.ImportEncryptedPkcs8PrivateKey(password, binaryEncoding, out _);
// do stuff with the key now
}
(as above, you need to "de-PEM" it first, if it was PEM).
Starting in .NET Core 3.0 you can do this relatively simply:
using (RSA rsa = RSA.Create())
{
rsa.ImportRSAPrivateKey(binaryEncoding, out _);
// do stuff with the key now
}
(same "de-PEM" if PEM).