0 votes
by (120 points)

Hi,

I'm experiencing an issue when extracting certificate on deployed Azure application. Exception "No certificate with private key found in PFX" is thrown every time when executing Certificate.LoadPfx function.

The most important thing is that everything works without problems when ran locally, an error occurs only when app is deployed on Azure.

Here is my code example:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public IActionResult SomeAction(IFormFile file, string filePassword)
    {
        try
        {
            byte[] fileBytes;
            using (var ms = new MemoryStream())
            {
                file.CopyTo(ms);
                fileBytes = ms.ToArray();
                string s = Convert.ToBase64String(fileBytes);
            }

            Certificate certificate = Certificate.LoadPfx(fileBytes, filePassword);
            ViewData["Message"] = certificate.GetIssuerName();
        }
        catch (Exception e)
        {
            ViewData["Message"] = e.ToString();
        }
        return View();
    }

The certificate is passed as a byte array. Uploaded certificate file is valid (I had even verified it by downloading the same uploaded file). The same error occurs even when providing a filePath string of file which is stored on the server.

Here is an example of .p12 certificate which i used: https://itv.mit-xperts.com/clientssl/issue/dload/index.php?id=1571753451

Thank you

1 Answer

0 votes
by (144k points)

Hi,

I'm not quite sure whether this is even supposed to work on Azure. We'll look into that.

Possible workaround: Add the .PFX file into certificate store and access it via CertificateStore class (similar to .NET's X509Store).

Another possible workaround: Instead of .PFX files, use .P7B/.KEY pair where the .P7B file contains the certificate chain and the .KEY file contains the encrypted private key. To convert .PFX file to .P7B/.KEY, use the following code:

public static void ConvertPfx(string pfxPath, string password)
{
    // convert a .pfx or .p12 file to .p7b/.key file pair (retains the original password)
    string name = Path.GetFileNameWithoutExtension(pfxPath);
    var certChain = CertificateChain.LoadPfx(pfxPath, password);
    certChain.Save(Path.ChangeExtension(name, ".p7b"));
    certChain.LeafCertificate.SavePrivateKey(Path.ChangeExtension(name, ".key"), password, PrivateKeyFormat.OpenSsh, true);
}

And to load the .P7B/.KEY files, use this code:

public static CertificateChain LoadChain(string chainPath, string keyPath, string password)
{
    var chain = CertificateChain.LoadP7b(chainPath);
    var key = new PrivateKeyInfo();
    key.Load(keyPath, password);
    chain.LeafCertificate.Associate(key);
    return chain;
 }
...