Qba
Qba

Reputation: 128

Loading X509Certificate2 ends with An internal error occurred on Windows server 2012

I`m trying to load certificate from path and getting internal server error on windows server. While I do it on windows 10 everything works fine.

Not working console application Code

var path = args[0];
var password = args[1];
var certificate2 = new X509Certificate2(path, password);

But getting error

Unhandled exception. Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: An internal error occurred.
   at Internal.Cryptography.Pal.CertificatePal.FilterPFXStore(Byte[] rawData, SafePasswordHandle password, PfxCertStoreFlags pfxCertStoreFlags)
   at Internal.Cryptography.Pal.CertificatePal.FromBlobOrFile(Byte[] rawData, String fileName, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags)
   at System.Security.Cryptography.X509Certificates.X509Certificate..ctor(String fileName, String password, X509KeyStorageFlags keyStorageFlags)
   at System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(String fileName, String password)
   at CertCoreTest.Program.Main(String[] args) in C:\Users\Admin\Documents\Visual Studio 2019\Projects\CertTest\CertCoreTest\Program.cs:line 12

Hack working code (not sure why it works)

var path = args[0];
var password = args[1];

Chilkat.Cert cert = new Chilkat.Cert();
var success = cert.LoadPfxData(File.ReadAllBytes(path), password);
if (success == false)
{
    throw new Exception(cert.LastErrorText);
}

var bytes = cert.ExportToPfxData(password, true);
var ceeert = new X509Certificate2(bytes, password);

How to make it work on windows server without using chilkat library?

Upvotes: 3

Views: 7049

Answers (4)

Danut Radoaica
Danut Radoaica

Reputation: 2000

If your code is running in a web application under IIS:

  1. Go to IIS Manager
  2. Go to the application pool instance
  3. Click advanced settings
  4. Under Process model, set Load User Profile to true

Else, try specifying the UserKeySet (it's possible that the PFX contains the "use the machine store" marker internally):

var path = args[0];
var password = args[1];
var certificate2 = new X509Certificate2(path, password, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.EphemeralKeySet);

Else, install the certificate on the local machine and try to load from store via thumbprint:

string certificateThumbprint = "<...thumbprint...>";
X509Certificate2 certificate = null;
using (X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine)) {
    store.Open(OpenFlags.ReadOnly);
    X509Certificate2Collection certificates = 
    store.Certificates.Find(X509FindType.FindByThumbprint, 
    certificateThumbprint, false);
    if (certificates.Count > 0)
        certificate = certificates[0];
}

If the above fails, then the .p12 file probably cannot be imported into Windows 2012 using the built-in Windows 2012 tools. To check that: For each of your PKCS #12 files, you could try the following: issue the command certutil -asn <filename> | findstr /i "pb aes des sha" (replacing "" with the name of the PKCS #12 file).

If the output starts like:

| | | | | ; 1.2.840.113549.1.12.1.3 szOID_PKCS_12_pbeWithSHA1And3KeyTripleDES

then it should be possible to import the PKCS #12 file into Windows 2016.

If the output starts like:

| | | | | ; 1.2.840.113549.1.5.13 szOID_PKCS_5_PBES2
| | | | | | ; 1.2.840.113549.1.5.12 szOID_PKCS_5_PBKDF2
| | | | | ; 2.16.840.1.101.3.4.1.42 aes256

or similar, then the PKCS #12 file probably cannot be imported into Windows 2016 using the built-in Windows 2016 tools. You will have to recreate the PKCS #12 file using TripleDES and SHA1." - see thread: https://learn.microsoft.com/en-us/answers/questions/518605/importing-a-pkcs12-to-windows-server-2016.html

Upvotes: 7

bgman
bgman

Reputation: 334

Setting the MachineKeySet flag will solve the problem of loading the certificate but you'll end up getting "Access denied" error when trying to use it to sign or decrypt, so you will switch to BoucyCastle.

Upvotes: 0

MD. RAKIB HASAN
MD. RAKIB HASAN

Reputation: 3956

Use local computer store for the private key:

X509Certificate2 cert = new X509Certificate2("yourhost.pfx", "password", X509KeyStorageFlags.MachineKeySet);

MachineKeySet is described as private keys are stored in the local computer store rather than the current user store. The default with no flags is to place in the user store.

Even though you are reading the certificate from disk and storing it in an object the private keys are still stored in the Microsoft Cryptographic API Cryptographic Service Provider key database. On the hosting server the ASP.NET process does not have permission to access the user store.

Another approach: (If you change your application console to web)
Modify the IIS Configuration or App Pool identity-- which do work. However, this assumes that there is access to these configuration items which may not be the case (e.g. in shared hosting environment).

You can read more about MSDN.System.Security.Cryptography.X509Certificates

Upvotes: 1

cdev
cdev

Reputation: 5391

Have you tried to pass byte data into X509Certificate2 instead of passing path? check below src from the official document.

I have faced a similar problem when loading from HTTP call. I had to pass cert.GetRawCertData() (Not similar to your case, but seems cause is similar)

using System;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.IO;
using System.Security.Cryptography.X509Certificates;

class CertInfo
{
    //Reads a file.
    internal static byte[] ReadFile (string fileName)
    {
        FileStream f = new FileStream(fileName, FileMode.Open, FileAccess.Read);
        int size = (int)f.Length;
        byte[] data = new byte[size];
        size = f.Read(data, 0, size);
        f.Close();
        return data;
    }
    //Main method begins here.
    static void Main(string[] args)
    {
        //Test for correct number of arguments.
        if (args.Length < 1)
        {
            Console.WriteLine("Usage: CertInfo <filename>");
            return;
        }
        try
        {
            X509Certificate2 x509 = new X509Certificate2();
            //Create X509Certificate2 object from .cer file.
            byte[] rawData = ReadFile(args[0]);
            x509.Import(rawData);

            //Print to console information contained in the certificate.
            Console.WriteLine("{0}Subject: {1}{0}", Environment.NewLine, x509.Subject);
            Console.WriteLine("{0}Issuer: {1}{0}", Environment.NewLine, x509.Issuer);
            Console.WriteLine("{0}Version: {1}{0}", Environment.NewLine, x509.Version);
            Console.WriteLine("{0}Valid Date: {1}{0}", Environment.NewLine, x509.NotBefore);
            Console.WriteLine("{0}Expiry Date: {1}{0}", Environment.NewLine, x509.NotAfter);
            Console.WriteLine("{0}Thumbprint: {1}{0}", Environment.NewLine, x509.Thumbprint);
            Console.WriteLine("{0}Serial Number: {1}{0}", Environment.NewLine, x509.SerialNumber);
            Console.WriteLine("{0}Friendly Name: {1}{0}", Environment.NewLine, x509.PublicKey.Oid.FriendlyName);
            Console.WriteLine("{0}Public Key Format: {1}{0}", Environment.NewLine, x509.PublicKey.EncodedKeyValue.Format(true));
            Console.WriteLine("{0}Raw Data Length: {1}{0}", Environment.NewLine, x509.RawData.Length);
            Console.WriteLine("{0}Certificate to string: {1}{0}", Environment.NewLine, x509.ToString(true));
            Console.WriteLine("{0}Certificate to XML String: {1}{0}", Environment.NewLine, x509.PublicKey.Key.ToXmlString(false));

            //Add the certificate to a X509Store.
            X509Store store = new X509Store();
            store.Open(OpenFlags.MaxAllowed);
            store.Add(x509);
            store.Close();
        }
        catch (DirectoryNotFoundException)
        {
               Console.WriteLine("Error: The directory specified could not be found.");
        }
        catch (IOException)
        {
            Console.WriteLine("Error: A file in the directory could not be accessed.");
        }
        catch (NullReferenceException)
        {
            Console.WriteLine("File must be a .cer file. Program does not have access to that type of file.");
        }
    }
}

Upvotes: 0

Related Questions