0

I am working in Unity C# and I would like to combine 3 files into a .pfx file programmatically for an MQTT connection. I have found several posts on SO that are similar to what I am looking for, but I have not been able to modify them and get my desired result. Here are a few of the pages that I have been looking at:

Associate a private key with the X509Certificate2 class in .net

Create X509Certificate2 from Cert and Key, without making a PFX file

How to create .pfx file from certificate and private key?

This is the terminal command that I want to replicate in Unity C#:

openssl pkcs12 -export -out final.pfx -inkey private.pem.key -in AmazonRootCA1.pem -in certificate.pem.crt  

I thought something like this might work, but .pfx file is not getting created:

X509Certificate2 GetPFX(string certPath, string keyFile, string caFile, string certFile, string pfxFile, string pfxPassword)
{
    if (!File.Exists(pfxFile))
    {
        // Generate PFX
        //openssl pkcs12 -export -out final.pfx -inkey private.pem.key -in AmazonRootCA1.pem -in certificate.pem.crt
        string arguments = "openssl pkcs12 -export -out " + certPath + "" + pfxFile + " -inkey " + certPath + "" + keyFile + " -in " + certPath + "" + caFile + " -in " + certPath + "" + certFile;
        ProcessStartInfo opensslPsi = new ProcessStartInfo("sudo", arguments);
        opensslPsi.UseShellExecute = false;
        opensslPsi.RedirectStandardOutput = true;
        using (Process p = Process.Start(opensslPsi))
        {
            p.WaitForExit();
        }
        // Set Permission
        ProcessStartInfo chmodPsi1 = new ProcessStartInfo("sudo", "chmod 644 " + certPath + "" + keyFile);
        ProcessStartInfo chmodPsi2 = new ProcessStartInfo("sudo", "chmod 644 " + certPath + "" + caFile);
        ProcessStartInfo chmodPsi3 = new ProcessStartInfo("sudo", "chmod 644 " + certPath + "" + certFile);
        chmodPsi1.UseShellExecute = false;
        chmodPsi1.RedirectStandardOutput = true;
        using (Process p = Process.Start(chmodPsi1))
        {
            p.WaitForExit();
        }
        chmodPsi2.UseShellExecute = false;
        chmodPsi2.RedirectStandardOutput = true;
        using (Process p = Process.Start(chmodPsi2))
        {
            p.WaitForExit();
        }
        chmodPsi3.UseShellExecute = false;
        chmodPsi3.RedirectStandardOutput = true;
        using (Process p = Process.Start(chmodPsi3))
        {
            p.WaitForExit();
        }
    }
    return new X509Certificate2(certPath + "" + pfxFile, pfxPassword);
}

I have also tried converting each file into a X509Certificate:

//ca
X509Certificate2 ca = new X509Certificate2();
byte[] rawData_ca = ReadFile(@"Assets/DevAppCerts/AmazonRootCA1.pem");
ca.Import(rawData_ca);

//certificate.pem.crt
X509Certificate2 certPem = new X509Certificate2(Encoding.UTF8.GetBytes(certificatePem_str));

//private
X509Certificate2 privateKeyCert = new X509Certificate2(Encoding.UTF8.GetBytes(privateKey_str));

But when I do this I get an exception on the private key that says, "Unable to decode certificate."

If I add the password as the second parameter (X509Certificate2 privateKeyCert = new X509Certificate2(Encoding.UTF8.GetBytes(privateKey_str), "");) I get an exception that says, "Input data cannot be coded as a valid certificate. ---> System.ArgumentOutOfRangeException: Length cannot be less than zero."

The privateKey_str variable is a String formatted with a "-----BEGIN RSA PRIVATE KEY-----" header and a "-----END RSA PRIVATE KEY-----" footer. If I try removing the header and footer first I get an exception that says, "Input data cannot be coded as a valid certificate."

At the end of the day I want to have either a List<X509Certificate> with either a element (from the .pfx) or multiple X509Certificates that I can send the request with these options:

_mqttCerts = new List<X509Certificate>
{
    //1 pfx or multiple X509Certificate
};

_mqttClientOptions = new MqttClientOptionsBuilder()
    .WithTcpServer(brokerHostname, brokerPort)
    .WithKeepAlivePeriod(new TimeSpan(0, 0, 0, 300))
    .WithTls(new MqttClientOptionsBuilderTlsParameters
    {
        Certificates = _mqttCerts,
        SslProtocol = System.Security.Authentication.SslProtocols.Tls12,
        UseTls = true,
        AllowUntrustedCertificates = true,
        CertificateValidationHandler = rootCertificateTrust.VerifyServerCertificate
    })
    .WithClientId(_mqttClientId)
    .Build();

Can anyone help me determine what I need to be doing differently?

hardillb
  • 47,764
  • 9
  • 59
  • 93
Ryan Tensmeyer
  • 845
  • 10
  • 26

0 Answers0